public IEnumerable <IFileversion> SelectFiles(Library.Utility.IFilter filter) { using (var tmpnames = new FilteredFilenameTable(m_connection, filter, null)) using (var cmd = m_connection.CreateCommand()) { //First we trim the filelist to exclude filenames not found in any of the filesets cmd.ExecuteNonQuery(string.Format(@"DELETE FROM ""{0}"" WHERE ""Path"" NOT IN (SELECT DISTINCT ""Path"" FROM ""File"", ""FilesetEntry"" WHERE ""FilesetEntry"".""FileID"" = ""File"".""ID"" AND ""FilesetEntry"".""FilesetID"" IN (SELECT ""FilesetID"" FROM ""{1}"") ) ", tmpnames.Tablename, m_tablename)); //Then we select the matching results var filesets = string.Format(@"SELECT ""FilesetID"", ""Timestamp"" FROM ""{0}"" ORDER BY ""Timestamp"" DESC", m_tablename); var cartesianPathFileset = string.Format(@"SELECT ""A"".""Path"", ""B"".""FilesetID"" FROM ""{0}"" A, (" + filesets + @") B ORDER BY ""A"".""Path"" ASC, ""B"".""Timestamp"" DESC", tmpnames.Tablename, m_tablename); var filesWithSizes = @"SELECT ""Length"", ""FilesetEntry"".""FilesetID"", ""File"".""Path"" FROM ""Blockset"", ""FilesetEntry"", ""File"" WHERE ""File"".""BlocksetID"" = ""Blockset"".""ID"" AND ""FilesetEntry"".""FileID"" = ""File"".""ID"" "; var query = @"SELECT ""C"".""Path"", ""D"".""Length"", ""C"".""FilesetID"" FROM (" + cartesianPathFileset + @") C LEFT OUTER JOIN (" + filesWithSizes + @") D ON ""C"".""FilesetID"" = ""D"".""FilesetID"" AND ""C"".""Path"" = ""D"".""Path"""; using (var rd = cmd.ExecuteReader(query)) if (rd.Read()) { bool more; do { var f = new Fileversion(rd); yield return(f); more = f.More; } while(more); } } }
public IEnumerable <IFileversion> GetLargestPrefix(Library.Utility.IFilter filter) { using (var tmpnames = new FilteredFilenameTable(m_connection, filter, null)) using (var cmd = m_connection.CreateCommand()) { //First we trim the filelist to exclude filenames not found in any of the filesets cmd.ExecuteNonQuery(string.Format(@"DELETE FROM ""{0}"" WHERE ""Path"" NOT IN (SELECT DISTINCT ""Path"" FROM ""File"", ""FilesetEntry"" WHERE ""FilesetEntry"".""FileID"" = ""File"".""ID"" AND ""FilesetEntry"".""FilesetID"" IN (SELECT ""FilesetID"" FROM ""{1}"") ) ", tmpnames.Tablename, m_tablename)); // Then we recursively find the largest prefix cmd.CommandText = string.Format(@"SELECT ""Path"" FROM ""{0}"" ORDER BY LENGTH(""Path"") DESC LIMIT 1", tmpnames.Tablename); var v0 = cmd.ExecuteScalar(); string maxpath = ""; if (v0 != null) { maxpath = v0.ToString(); } cmd.CommandText = string.Format(@"SELECT COUNT(*) FROM ""{0}""", tmpnames.Tablename); var filecount = cmd.ExecuteScalarInt64(0); long foundfiles = -1; //TODO: Handle FS case-sensitive? cmd.CommandText = string.Format(@"SELECT COUNT(*) FROM ""{0}"" WHERE SUBSTR(""Path"", 1, ?) = ?", tmpnames.Tablename); cmd.AddParameter(); cmd.AddParameter(); while (filecount != foundfiles && maxpath.Length > 0) { var mp = Library.Utility.Utility.AppendDirSeparator(maxpath); cmd.SetParameterValue(0, mp.Length); cmd.SetParameterValue(1, mp); foundfiles = cmd.ExecuteScalarInt64(0); if (filecount != foundfiles) { var oldlen = maxpath.Length; maxpath = Library.Snapshots.SnapshotUtility.SystemIO.PathGetDirectoryName(maxpath); if (string.IsNullOrWhiteSpace(maxpath) || maxpath.Length == oldlen) { maxpath = ""; } } } return (new IFileversion[] { new FileversionFixed() { Path = maxpath == "" ? "" : Library.Utility.Utility.AppendDirSeparator(maxpath) } }); } }
public IEnumerable <IFileversion> SelectFolderContents(Library.Utility.IFilter filter) { var tbname = "Filenames-" + Library.Utility.Utility.ByteArrayAsHexString(Guid.NewGuid().ToByteArray()); try { string pathprefix; if (filter == null || filter.Empty) { pathprefix = ""; } else if (filter as Library.Utility.FilterExpression == null || ((Library.Utility.FilterExpression)filter).Type != Duplicati.Library.Utility.FilterType.Simple || ((Library.Utility.FilterExpression)filter).GetSimpleList().Length != 1) { throw new ArgumentException("Filter for list-folder-contents must be a path prefix with no wildcards", "filter"); } else { pathprefix = ((Library.Utility.FilterExpression)filter).GetSimpleList().First(); } var dirsep = Duplicati.Library.Utility.Utility.GuessDirSeparator(pathprefix); if (pathprefix.Length > 0 || dirsep == "/") { pathprefix = Duplicati.Library.Utility.Utility.AppendDirSeparator(pathprefix, dirsep); } using (var tmpnames = new FilteredFilenameTable(m_connection, new Library.Utility.FilterExpression(new string[] { pathprefix + "*" }, true), null)) using (var cmd = m_connection.CreateCommand()) { //First we trim the filelist to exclude filenames not found in any of the filesets cmd.ExecuteNonQuery(string.Format(@"DELETE FROM ""{0}"" WHERE ""Path"" NOT IN (SELECT DISTINCT ""Path"" FROM ""File"", ""FilesetEntry"" WHERE ""FilesetEntry"".""FileID"" = ""File"".""ID"" AND ""FilesetEntry"".""FilesetID"" IN (SELECT ""FilesetID"" FROM ""{1}"") ) ", tmpnames.Tablename, m_tablename)); // If we had instr support this would work: /*var distinctPaths = @"SELECT DISTINCT :1 || " + * @"CASE(INSTR(SUBSTR(""Path"", :2), ""/"")) " + * @"WHEN 0 THEN SUBSTR(""Path"", :2) " + * @"ELSE SUBSTR(""Path"", :2, INSTR(SUBSTR(path, :2), ""/"")) " + * @"END AS ""Path"", ""FilesetID"" " + * @" FROM (" + cartesianPathFileset + @")";*/ // Instead we manually iterate the paths cmd.ExecuteNonQuery(string.Format(@"CREATE TEMPORARY TABLE ""{0}"" (""Path"" TEXT NOT NULL)", tbname)); using (var c2 = m_connection.CreateCommand()) { c2.CommandText = string.Format(@"INSERT INTO ""{0}"" (""Path"") VALUES (?)", tbname); c2.AddParameter(); foreach (var n in SelectFolderEntries(cmd, pathprefix, tmpnames.Tablename).Distinct()) { c2.SetParameterValue(0, n); c2.ExecuteNonQuery(); } c2.ExecuteNonQuery(string.Format(@"CREATE INDEX ""{0}_PathIndex"" ON ""{0}"" (""Path"")", tbname)); } //Then we select the matching results var filesets = string.Format(@"SELECT ""FilesetID"", ""Timestamp"" FROM ""{0}"" ORDER BY ""Timestamp"" DESC", m_tablename); var cartesianPathFileset = string.Format(@"SELECT ""A"".""Path"", ""B"".""FilesetID"" FROM ""{0}"" A, (" + filesets + @") B ORDER BY ""A"".""Path"" ASC, ""B"".""Timestamp"" DESC", tbname, m_tablename); var filesWithSizes = @"SELECT ""Length"", ""FilesetEntry"".""FilesetID"", ""File"".""Path"" FROM ""Blockset"", ""FilesetEntry"", ""File"" WHERE ""File"".""BlocksetID"" = ""Blockset"".""ID"" AND ""FilesetEntry"".""FileID"" = ""File"".""ID"" "; var query = @"SELECT ""C"".""Path"", ""D"".""Length"", ""C"".""FilesetID"" FROM (" + cartesianPathFileset + @") C LEFT OUTER JOIN (" + filesWithSizes + @") D ON ""C"".""FilesetID"" = ""D"".""FilesetID"" AND ""C"".""Path"" = ""D"".""Path"""; cmd.AddParameter(pathprefix, "1"); cmd.AddParameter(pathprefix.Length + 1, "2"); using (var rd = cmd.ExecuteReader(query)) if (rd.Read()) { bool more; do { var f = new Fileversion(rd); if (!(string.IsNullOrWhiteSpace(f.Path) || f.Path == pathprefix)) { yield return(f); more = f.More; } else { more = rd.Read(); } } while(more); } } } finally { try { using (var c = m_connection.CreateCommand()) c.ExecuteNonQuery(string.Format(@"DROP TABLE IF EXISTS ""{0}""", tbname)); } catch { } } }
private IEnumerable <IFileversion> GetLargestPrefix(Library.Utility.IFilter filter, string prefixrule) { using (var tmpnames = new FilteredFilenameTable(m_connection, filter, null)) using (var cmd = m_connection.CreateCommand()) { //First we trim the filelist to exclude filenames not found in any of the filesets cmd.ExecuteNonQuery(string.Format(@"DELETE FROM ""{0}"" WHERE ""Path"" NOT IN (SELECT DISTINCT ""Path"" FROM ""File"", ""FilesetEntry"" WHERE ""FilesetEntry"".""FileID"" = ""File"".""ID"" AND ""FilesetEntry"".""FilesetID"" IN (SELECT ""FilesetID"" FROM ""{1}"") ) ", tmpnames.Tablename, m_tablename)); //If we have a prefix rule, apply it if (!string.IsNullOrWhiteSpace(prefixrule)) { cmd.ExecuteNonQuery(string.Format(@"DELETE FROM ""{0}"" WHERE SUBSTR(""Path"", 1, 1) != ?", tmpnames.Tablename), prefixrule); } // Then we recursively find the largest prefix cmd.CommandText = string.Format(@"SELECT ""Path"" FROM ""{0}"" ORDER BY LENGTH(""Path"") DESC LIMIT 1", tmpnames.Tablename); var v0 = cmd.ExecuteScalar(); string maxpath = ""; if (v0 != null) { maxpath = v0.ToString(); } var dirsep = Duplicati.Library.Utility.Utility.GuessDirSeparator(maxpath); cmd.CommandText = string.Format(@"SELECT COUNT(*) FROM ""{0}""", tmpnames.Tablename); var filecount = cmd.ExecuteScalarInt64(0); long foundfiles = -1; //TODO: Handle FS case-sensitive? cmd.CommandText = string.Format(@"SELECT COUNT(*) FROM ""{0}"" WHERE SUBSTR(""Path"", 1, ?) = ?", tmpnames.Tablename); cmd.AddParameter(); cmd.AddParameter(); while (filecount != foundfiles && maxpath.Length > 0) { var mp = Duplicati.Library.Utility.Utility.AppendDirSeparator(maxpath, dirsep); cmd.SetParameterValue(0, mp.Length); cmd.SetParameterValue(1, mp); foundfiles = cmd.ExecuteScalarInt64(0); if (filecount != foundfiles) { var oldlen = maxpath.Length; var lix = maxpath.LastIndexOf(dirsep, maxpath.Length - 2, StringComparison.Ordinal); maxpath = maxpath.Substring(0, lix + 1); if (string.IsNullOrWhiteSpace(maxpath) || maxpath.Length == oldlen) { maxpath = ""; } } } // Special handling for Windows and multi-drive backups as they do not have a single common root if (string.IsNullOrWhiteSpace(maxpath) && string.IsNullOrWhiteSpace(prefixrule)) { var roots = cmd.ExecuteReaderEnumerable(string.Format(@"SELECT DISTINCT SUBSTR(""Path"", 1, 1) FROM ""{0}""", tmpnames.Tablename)).Select(x => x.ConvertValueToString(0)).ToArray(); return(roots.Select(x => GetLargestPrefix(filter, x).First()).Distinct().ToArray()); } return (new IFileversion[] { new FileversionFixed() { Path = maxpath == "" ? "" : Duplicati.Library.Utility.Utility.AppendDirSeparator(maxpath, dirsep) } }); } }
public IEnumerable<IFileversion> SelectFiles(Library.Utility.IFilter filter) { using(var tmpnames = new FilteredFilenameTable(m_connection, filter, null)) using(var cmd = m_connection.CreateCommand()) { //First we trim the filelist to exclude filenames not found in any of the filesets cmd.ExecuteNonQuery(string.Format(@"DELETE FROM ""{0}"" WHERE ""Path"" NOT IN (SELECT DISTINCT ""Path"" FROM ""File"", ""FilesetEntry"" WHERE ""FilesetEntry"".""FileID"" = ""File"".""ID"" AND ""FilesetEntry"".""FilesetID"" IN (SELECT ""FilesetID"" FROM ""{1}"") ) ", tmpnames.Tablename, m_tablename)); //Then we select the matching results var filesets = string.Format(@"SELECT ""FilesetID"", ""Timestamp"" FROM ""{0}"" ORDER BY ""Timestamp"" DESC", m_tablename); var cartesianPathFileset = string.Format(@"SELECT ""A"".""Path"", ""B"".""FilesetID"" FROM ""{0}"" A, (" + filesets + @") B ORDER BY ""A"".""Path"" ASC, ""B"".""Timestamp"" DESC", tmpnames.Tablename, m_tablename); var filesWithSizes = @"SELECT ""Length"", ""FilesetEntry"".""FilesetID"", ""File"".""Path"" FROM ""Blockset"", ""FilesetEntry"", ""File"" WHERE ""File"".""BlocksetID"" = ""Blockset"".""ID"" AND ""FilesetEntry"".""FileID"" = ""File"".""ID"" "; var query = @"SELECT ""C"".""Path"", ""D"".""Length"", ""C"".""FilesetID"" FROM (" + cartesianPathFileset + @") C LEFT OUTER JOIN (" + filesWithSizes + @") D ON ""C"".""FilesetID"" = ""D"".""FilesetID"" AND ""C"".""Path"" = ""D"".""Path"""; using(var rd = cmd.ExecuteReader(query)) if(rd.Read()) { bool more; do { var f = new Fileversion(rd); yield return f; more = f.More; } while(more); } } }
public IEnumerable<IFileversion> SelectFolderContents(Library.Utility.IFilter filter) { var tbname = "Filenames-" + Library.Utility.Utility.ByteArrayAsHexString(Guid.NewGuid().ToByteArray()); try { string pathprefix; if (filter == null || filter.Empty) pathprefix = ""; else if (filter as Library.Utility.FilterExpression == null || ((Library.Utility.FilterExpression)filter).Type != Duplicati.Library.Utility.FilterType.Simple || ((Library.Utility.FilterExpression)filter).GetSimpleList().Length != 1) throw new ArgumentException("Filter for list-folder-contents must be a path prefix with no wildcards", "filter"); else pathprefix = ((Library.Utility.FilterExpression)filter).GetSimpleList().First(); if (pathprefix.Length > 0 || Duplicati.Library.Utility.Utility.IsClientLinux) pathprefix = Duplicati.Library.Utility.Utility.AppendDirSeparator(pathprefix); using(var tmpnames = new FilteredFilenameTable(m_connection, new Library.Utility.FilterExpression(pathprefix + "*", true), null)) using(var cmd = m_connection.CreateCommand()) { //First we trim the filelist to exclude filenames not found in any of the filesets cmd.ExecuteNonQuery(string.Format(@"DELETE FROM ""{0}"" WHERE ""Path"" NOT IN (SELECT DISTINCT ""Path"" FROM ""File"", ""FilesetEntry"" WHERE ""FilesetEntry"".""FileID"" = ""File"".""ID"" AND ""FilesetEntry"".""FilesetID"" IN (SELECT ""FilesetID"" FROM ""{1}"") ) ", tmpnames.Tablename, m_tablename)); // If we had instr support this would work: /*var distinctPaths = @"SELECT DISTINCT :1 || " + @"CASE(INSTR(SUBSTR(""Path"", :2), ""/"")) " + @"WHEN 0 THEN SUBSTR(""Path"", :2) " + @"ELSE SUBSTR(""Path"", :2, INSTR(SUBSTR(path, :2), ""/"")) " + @"END AS ""Path"", ""FilesetID"" " + @" FROM (" + cartesianPathFileset + @")";*/ // Instead we manually iterate the paths cmd.ExecuteNonQuery(string.Format(@"CREATE TEMPORARY TABLE ""{0}"" (""Path"" TEXT NOT NULL)", tbname)); using(var c2 = m_connection.CreateCommand()) { c2.CommandText = string.Format(@"INSERT INTO ""{0}"" (""Path"") VALUES (?)", tbname); c2.AddParameter(); foreach(var n in SelectFolderEntries(cmd, pathprefix, tmpnames.Tablename).Distinct()) { c2.SetParameterValue(0, n); c2.ExecuteNonQuery(); } c2.ExecuteNonQuery(string.Format(@"CREATE INDEX ""{0}_PathIndex"" ON ""{0}"" (""Path"")", tbname)); } //Then we select the matching results var filesets = string.Format(@"SELECT ""FilesetID"", ""Timestamp"" FROM ""{0}"" ORDER BY ""Timestamp"" DESC", m_tablename); var cartesianPathFileset = string.Format(@"SELECT ""A"".""Path"", ""B"".""FilesetID"" FROM ""{0}"" A, (" + filesets + @") B ORDER BY ""A"".""Path"" ASC, ""B"".""Timestamp"" DESC", tbname, m_tablename); var filesWithSizes = @"SELECT ""Length"", ""FilesetEntry"".""FilesetID"", ""File"".""Path"" FROM ""Blockset"", ""FilesetEntry"", ""File"" WHERE ""File"".""BlocksetID"" = ""Blockset"".""ID"" AND ""FilesetEntry"".""FileID"" = ""File"".""ID"" "; var query = @"SELECT ""C"".""Path"", ""D"".""Length"", ""C"".""FilesetID"" FROM (" + cartesianPathFileset + @") C LEFT OUTER JOIN (" + filesWithSizes + @") D ON ""C"".""FilesetID"" = ""D"".""FilesetID"" AND ""C"".""Path"" = ""D"".""Path"""; cmd.AddParameter(pathprefix, "1"); cmd.AddParameter(pathprefix.Length + 1, "2"); using(var rd = cmd.ExecuteReader(query)) if (rd.Read()) { bool more; do { var f = new Fileversion(rd); if (!(string.IsNullOrWhiteSpace(f.Path) || f.Path == pathprefix)) { yield return f; more = f.More; } else { more = rd.Read(); } } while(more); } } } finally { try { using(var c = m_connection.CreateCommand()) c.ExecuteNonQuery(string.Format(@"DROP TABLE IF EXISTS ""{0}""", tbname)); } catch { } } }
public IEnumerable<IFileversion> GetLargestPrefix(Library.Utility.IFilter filter) { using(var tmpnames = new FilteredFilenameTable(m_connection, filter, null)) using(var cmd = m_connection.CreateCommand()) { //First we trim the filelist to exclude filenames not found in any of the filesets cmd.ExecuteNonQuery(string.Format(@"DELETE FROM ""{0}"" WHERE ""Path"" NOT IN (SELECT DISTINCT ""Path"" FROM ""File"", ""FilesetEntry"" WHERE ""FilesetEntry"".""FileID"" = ""File"".""ID"" AND ""FilesetEntry"".""FilesetID"" IN (SELECT ""FilesetID"" FROM ""{1}"") ) ", tmpnames.Tablename, m_tablename)); // Then we recursively find the largest prefix cmd.CommandText = string.Format(@"SELECT ""Path"" FROM ""{0}"" ORDER BY LENGTH(""Path"") DESC LIMIT 1", tmpnames.Tablename); var v0 = cmd.ExecuteScalar(); string maxpath = ""; if (v0 != null) maxpath = v0.ToString(); cmd.CommandText = string.Format(@"SELECT COUNT(*) FROM ""{0}""", tmpnames.Tablename); var filecount = cmd.ExecuteScalarInt64(0); long foundfiles = -1; //TODO: Handle FS case-sensitive? cmd.CommandText = string.Format(@"SELECT COUNT(*) FROM ""{0}"" WHERE SUBSTR(""Path"", 1, ?) = ?", tmpnames.Tablename); cmd.AddParameter(); cmd.AddParameter(); while (filecount != foundfiles && maxpath.Length > 0) { var mp = Library.Utility.Utility.AppendDirSeparator(maxpath); cmd.SetParameterValue(0, mp.Length); cmd.SetParameterValue(1, mp); foundfiles = cmd.ExecuteScalarInt64(0); if (filecount != foundfiles) { var oldlen = maxpath.Length; maxpath = Library.Snapshots.SnapshotUtility.SystemIO.PathGetDirectoryName(maxpath); if (string.IsNullOrWhiteSpace(maxpath) || maxpath.Length == oldlen) maxpath = ""; } } return new IFileversion[] { new FileversionFixed() { Path = maxpath == "" ? "" : Library.Utility.Utility.AppendDirSeparator(maxpath) } }; } }