diff --git a/Duplicati/Library/Main/Database/LocalBackupDatabase.cs b/Duplicati/Library/Main/Database/LocalBackupDatabase.cs index 1b8f87ed9..83eaa42d3 100644 --- a/Duplicati/Library/Main/Database/LocalBackupDatabase.cs +++ b/Duplicati/Library/Main/Database/LocalBackupDatabase.cs @@ -139,7 +139,7 @@ namespace Duplicati.Library.Main.Database using (var cmd = m_connection.CreateCommand()) cmd.ExecuteNonQuery(string.Format(@"CREATE TEMPORARY TABLE ""{0}"" AS SELECT ""FilesetEntry"".""FileID"" AS ""FileID"", MAX(""FilesetEntry"".""Scantime"") AS ""Scantime"", ""File"".""Path"" AS ""Path"" FROM ""FilesetEntry"" INNER JOIN ""File"" ON ""File"".""ID"" = ""FilesetEntry"".""FileID"" GROUP BY ""FilesetEntry"".""FileID"", ""File"".""Path"" ", m_scantimelookupTablename)); - m_selectfileSimpleCommand.CommandText = string.Format(@"SELECT ""FileID"", ""Scantime"" FROM ""{0}"" WHERE ""Path"" = ?", m_scantimelookupTablename); + m_selectfileSimpleCommand.CommandText = string.Format(@"SELECT ""FileID"", CAST(strftime('%s', ""Scantime"") AS INTEGER) AS ""Scantime"" FROM ""{0}"" WHERE ""Path"" = ?", m_scantimelookupTablename); m_selectfileSimpleCommand.AddParameters(1); m_selectfileHashCommand.CommandText = @"SELECT ""Blockset"".""Fullhash"" FROM ""Blockset"", ""File"" WHERE ""Blockset"".""ID"" = ""File"".""BlocksetID"" AND ""File"".""ID"" = ? "; @@ -203,11 +203,11 @@ namespace Duplicati.Library.Main.Database } if (m_fileScantimeLookup != null) - using (var rd = cmd.ExecuteReader(string.Format(@" SELECT ""FileID"", ""Scantime"", ""Path"" FROM ""{0}"" ", m_scantimelookupTablename))) + using (var rd = cmd.ExecuteReader(string.Format(@" SELECT ""FileID"", CAST(strftime('%s', ""Scantime"") AS INTEGER) AS ""Scantime"", ""Path"", ""Scantime"" FROM ""{0}"" ", m_scantimelookupTablename))) while (rd.Read()) { var id = Convert.ToInt64(rd.GetValue(0)); - var scantime = new DateTime(Convert.ToDateTime(rd.GetValue(1)).Ticks, DateTimeKind.Utc); + var scantime = ParseFromEpochSeconds(Convert.ToInt64(rd.GetValue(1))); var path = rd.GetValue(2).ToString(); m_fileScantimeLookup.Add((ulong)path.GetHashCode(), path, new KeyValuePair(id, scantime)); } @@ -622,7 +622,7 @@ namespace Duplicati.Library.Main.Database if (m_fileScantimeLookup != null) m_fileScantimeLookup.NegativeMisses++; - oldScanned = new DateTime(Convert.ToDateTime(rd.GetValue(1)).Ticks, DateTimeKind.Utc); + oldScanned = ParseFromEpochSeconds(Convert.ToInt64(rd.GetValue(1))); var id = Convert.ToInt64(rd.GetValue(0)); // We do not add here, because we will never query the same path twice, @@ -844,12 +844,12 @@ namespace Duplicati.Library.Main.Database using(var cmd = m_connection.CreateCommand()) { cmd.Transaction = transaction; - using(var rd = cmd.ExecuteReader(@"SELECT ""ID"", ""Timestamp"" FROM ""Fileset"" WHERE ""ID"" IN (SELECT ""FilesetID"" FROM ""FilesetEntry"") AND ""VolumeID"" NOT IN (SELECT ""ID"" FROM ""RemoteVolume"")")) + using(var rd = cmd.ExecuteReader(@"SELECT ""ID"", CAST(strftime('%s', ""Timestamp"") AS INTEGER) AS ""Timestamp"" FROM ""Fileset"" WHERE ""ID"" IN (SELECT ""FilesetID"" FROM ""FilesetEntry"") AND ""VolumeID"" NOT IN (SELECT ""ID"" FROM ""RemoteVolume"")")) while(rd.Read()) { yield return new KeyValuePair( Convert.ToInt64(rd.GetValue(0)), - Convert.ToDateTime(rd.GetValue(1)).ToLocalTime() + ParseFromEpochSeconds(Convert.ToInt64(rd.GetValue(1))).ToLocalTime() ); } } diff --git a/Duplicati/Library/Main/Database/LocalDatabase.cs b/Duplicati/Library/Main/Database/LocalDatabase.cs index fe9631dd2..35dc65d22 100644 --- a/Duplicati/Library/Main/Database/LocalDatabase.cs +++ b/Duplicati/Library/Main/Database/LocalDatabase.cs @@ -136,6 +136,19 @@ namespace Duplicati.Library.Main.Database return new DateTime(ticks, DateTimeKind.Utc); } + /// + /// The EPOCH time (unix time) + /// + private static readonly DateTime EPOCH = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + + /// + /// Creates a DateTime instance by adding the specified number of seconds to the EPOCH value + /// + public static DateTime ParseFromEpochSeconds(long seconds) + { + return Library.Utility.Utility.EPOCH.AddSeconds(seconds); + } + public void UpdateRemoteVolume(string name, RemoteVolumeState state, long size, string hash, System.Data.IDbTransaction transaction = null) { m_updateremotevolumeCommand.Transaction = transaction; @@ -157,9 +170,9 @@ namespace Duplicati.Library.Main.Database get { using(var cmd = m_connection.CreateCommand()) - using(var rd = cmd.ExecuteReader(@"SELECT ""ID"", ""Timestamp"" FROM ""Fileset"" ORDER BY ""Timestamp"" DESC")) + using(var rd = cmd.ExecuteReader(@"SELECT ""ID"", CAST(strftime('%s', ""Timestamp"") AS INTEGER) AS ""Timestamp"" FROM ""Fileset"" ORDER BY ""Timestamp"" DESC")) while (rd.Read()) - yield return new KeyValuePair(Convert.ToInt64(rd.GetValue(0)), Convert.ToDateTime(rd.GetValue(1)).ToLocalTime()); + yield return new KeyValuePair(Convert.ToInt64(rd.GetValue(0)), ParseFromEpochSeconds(Convert.ToInt64(rd.GetValue(1))).ToLocalTime()); } } @@ -673,7 +686,7 @@ namespace Duplicati.Library.Main.Database filesetvolume.AddSymlink(path, metahash, metalength); } - cmd.CommandText = @"SELECT ""F"".""Path"", ""F"".""Scantime"", ""F"".""Filelength"", ""F"".""Filehash"", ""F"".""Metahash"", ""F"".""Metalength"", ""G"".""Hash"" FROM (SELECT ""A"".""Path"" AS ""Path"", ""D"".""Scantime"" AS ""Scantime"", ""B"".""Length"" AS ""Filelength"", ""B"".""FullHash"" AS ""Filehash"", ""E"".""FullHash"" AS ""Metahash"", ""E"".""Length"" AS ""Metalength"", ""A"".""BlocksetID"" AS ""BlocksetID"" FROM ""File"" A, ""Blockset"" B, ""Metadataset"" C, ""FilesetEntry"" D, ""Blockset"" E WHERE ""A"".""ID"" = ""D"".""FileID"" AND ""D"".""FilesetID"" = ? AND ""A"".""BlocksetID"" = ""B"".""ID"" AND ""A"".""MetadataID"" = ""C"".""ID"" AND ""E"".""ID"" = ""C"".""BlocksetID"") F LEFT OUTER JOIN ""BlocklistHash"" G ON ""G"".""BlocksetID"" = ""F"".""BlocksetID"" ORDER BY ""F"".""Path"", ""G"".""Index"" "; + cmd.CommandText = @"SELECT ""F"".""Path"", CAST(strftime('%s', ""F"".""Scantime"") AS INTEGER) AS ""Scantime"", ""F"".""Filelength"", ""F"".""Filehash"", ""F"".""Metahash"", ""F"".""Metalength"", ""G"".""Hash"" FROM (SELECT ""A"".""Path"" AS ""Path"", ""D"".""Scantime"" AS ""Scantime"", ""B"".""Length"" AS ""Filelength"", ""B"".""FullHash"" AS ""Filehash"", ""E"".""FullHash"" AS ""Metahash"", ""E"".""Length"" AS ""Metalength"", ""A"".""BlocksetID"" AS ""BlocksetID"" FROM ""File"" A, ""Blockset"" B, ""Metadataset"" C, ""FilesetEntry"" D, ""Blockset"" E WHERE ""A"".""ID"" = ""D"".""FileID"" AND ""D"".""FilesetID"" = ? AND ""A"".""BlocksetID"" = ""B"".""ID"" AND ""A"".""MetadataID"" = ""C"".""ID"" AND ""E"".""ID"" = ""C"".""BlocksetID"") F LEFT OUTER JOIN ""BlocklistHash"" G ON ""G"".""BlocksetID"" = ""F"".""BlocksetID"" ORDER BY ""F"".""Path"", ""G"".""Index"" "; cmd.Parameters.Clear(); cmd.AddParameter(filesetId); @@ -686,7 +699,7 @@ namespace Duplicati.Library.Main.Database var path = rd.GetValue(0).ToString(); var filehash = rd.GetValue(3).ToString(); var size = Convert.ToInt64(rd.GetValue(2)); - var scantime = Convert.ToDateTime(rd.GetValue(1)); + var scantime = ParseFromEpochSeconds(Convert.ToInt64(rd.GetValue(1))); var metahash = rd.GetValue(4).ToString(); var metasize = Convert.ToInt64(rd.GetValue(5)); var blrd = new BlocklistHashEnumerable(rd); diff --git a/Duplicati/Library/Main/Database/LocalRestoreDatabase.cs b/Duplicati/Library/Main/Database/LocalRestoreDatabase.cs index 319639e0a..0781e11d4 100644 --- a/Duplicati/Library/Main/Database/LocalRestoreDatabase.cs +++ b/Duplicati/Library/Main/Database/LocalRestoreDatabase.cs @@ -37,7 +37,7 @@ namespace Duplicati.Library.Main.Database using(var cmd = m_connection.CreateCommand()) { long filesetId = GetFilesetID(NormalizeDateTime(restoretime), versions); - m_restoreTime = Convert.ToDateTime(cmd.ExecuteScalar(@"SELECT ""Timestamp"" FROM ""Fileset"" WHERE ""ID"" = ?", filesetId)); + m_restoreTime = ParseFromEpochSeconds(Convert.ToInt64(cmd.ExecuteScalar(@"SELECT CAST(strftime('%s', ""Timestamp"") AS INTEGER) AS ""Timestamp"" FROM ""Fileset"" WHERE ""ID"" = ?", filesetId))); cmd.Parameters.Clear(); cmd.CommandText = string.Format(@"CREATE TEMPORARY TABLE ""{0}"" (""ID"" INTEGER PRIMARY KEY, ""Path"" TEXT NOT NULL, ""BlocksetID"" INTEGER NOT NULL, ""MetadataID"" INTEGER NOT NULL, ""Targetpath"" TEXT NULL ) ", m_tempfiletable); @@ -87,7 +87,7 @@ namespace Duplicati.Library.Main.Database while (rd.Read()) sb.AppendLine(rd.GetValue(0).ToString()); - DateTime actualrestoretime = Convert.ToDateTime(cmd.ExecuteScalar(@"SELECT ""Timestamp"" FROM ""Fileset"" WHERE ""ID"" = ?", filesetId)); + var actualrestoretime = ParseFromEpochSeconds(Convert.ToInt64(cmd.ExecuteScalar(@"SELECT CAST(strftime('%s', ""Timestamp"") AS INTEGER) AS ""Timestamp"" FROM ""Fileset"" WHERE ""ID"" = ?", filesetId))); log.AddWarning(string.Format("{0} File(s) were not found in list of files for backup at {1}, will not be restored: {2}", p.Length - c, actualrestoretime.ToLocalTime(), sb), null); cmd.Parameters.Clear(); }