Removed the redundant byte-array-to-string method from the MD5 module, and added a using directive.
Added some additional logging to better diagnose issues with VSS/LVM snapshots.
This commit is contained in:
@@ -214,6 +214,19 @@ namespace Duplicati.Library.Logging
|
||||
WriteMessage(LogMessageType.Verbose, tag, id, null, message, arguments);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a verbose message to the current log destination
|
||||
/// </summary>
|
||||
/// <param name="message">The message to write</param>
|
||||
/// <param name="tag">The tag-type for this message</param>
|
||||
/// <param name="id">The message id</param>
|
||||
/// <param name="ex">The exception to log</param>
|
||||
/// <param name="arguments">The message format arguments</param>
|
||||
public static void WriteVerboseMessage(string tag, string id, Exception ex, string message, params object[] arguments)
|
||||
{
|
||||
WriteMessage(LogMessageType.Verbose, tag, id, ex, message, arguments);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a profiling message to the current log destination
|
||||
/// </summary>
|
||||
|
||||
@@ -82,7 +82,8 @@ namespace Duplicati.Library.Main.Operation.Backup
|
||||
}
|
||||
else
|
||||
{
|
||||
bool AttributeFilter(string root, string path, FileAttributes attr) => AttributeFilterAsync(root, path, attr, snapshot, sourcefilter, hardlinkPolicy, symlinkPolicy, hardlinkmap, attributeFilter, enumeratefilter, ignorenames, mixinqueue).WaitForTask().Result;
|
||||
Library.Utility.Utility.EnumerationFilterDelegate AttributeFilter = (root, path, attr) =>
|
||||
AttributeFilterAsync(root, path, attr, snapshot, sourcefilter, hardlinkPolicy, symlinkPolicy, hardlinkmap, attributeFilter, enumeratefilter, ignorenames, mixinqueue).WaitForTask().Result;
|
||||
|
||||
if (journalService != null)
|
||||
{
|
||||
@@ -90,9 +91,9 @@ namespace Duplicati.Library.Main.Operation.Backup
|
||||
sources = journalService.GetModifiedSources(AttributeFilter);
|
||||
}
|
||||
|
||||
worklist = snapshot.EnumerateFilesAndFolders(sources, AttributeFilter, (rootpath, path, ex) =>
|
||||
worklist = snapshot.EnumerateFilesAndFolders(sources, AttributeFilter, (rootpath, errorpath, ex) =>
|
||||
{
|
||||
Logging.Log.WriteWarningMessage(FILTER_LOGTAG, "FileAccessError", ex, "Error reported while accessing file: {0}", path);
|
||||
Logging.Log.WriteWarningMessage(FILTER_LOGTAG, "FileAccessError", ex, "Error reported while accessing file: {0}", errorpath);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,14 @@ namespace Duplicati.Library.Snapshots
|
||||
/// </summary>
|
||||
public sealed class LinuxSnapshot : SnapshotBase
|
||||
{
|
||||
/// <summary>
|
||||
/// The tag used for logging messages
|
||||
/// </summary>
|
||||
public static readonly string LOGTAG = Logging.Log.LogTagFromType<WindowsSnapshot>();
|
||||
|
||||
/// <summary>
|
||||
/// Helper to have access to the System.IO calls without the interface layer
|
||||
/// </summary>
|
||||
private static SystemIOLinux SYS_IO = new SystemIOLinux();
|
||||
|
||||
/// <summary>
|
||||
@@ -85,9 +93,9 @@ namespace Duplicati.Library.Snapshots
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
// ignored
|
||||
Logging.Log.WriteVerboseMessage(LOGTAG, "SnapshotCleanupError", ex, "Failed to clean up after error");
|
||||
}
|
||||
|
||||
throw;
|
||||
@@ -97,8 +105,6 @@ namespace Duplicati.Library.Snapshots
|
||||
/// <inheritdoc />
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
Exception exs = null;
|
||||
|
||||
if (m_snapShots != null)
|
||||
{
|
||||
if (disposing)
|
||||
@@ -107,7 +113,7 @@ namespace Duplicati.Library.Snapshots
|
||||
foreach(var s in m_snapShots)
|
||||
{
|
||||
try { s.Dispose(); }
|
||||
catch (Exception ex) { exs = ex; }
|
||||
catch (Exception ex) { Logging.Log.WriteVerboseMessage(LOGTAG, "SnapshotCloseError", ex, "Failed to close a snapshot"); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,10 +122,6 @@ namespace Duplicati.Library.Snapshots
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
|
||||
// Report errors, if any
|
||||
if (exs != null)
|
||||
throw exs;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -547,6 +547,7 @@ namespace Duplicati.Library.Snapshots
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class UsnJournalSoftFailureException : Exception
|
||||
{
|
||||
public UsnJournalSoftFailureException()
|
||||
|
||||
@@ -64,7 +64,7 @@ namespace Duplicati.Library.Snapshots
|
||||
|
||||
// get filter identifying current source filter / sources configuration
|
||||
// ReSharper disable once PossibleMultipleEnumeration
|
||||
var configHash = emitFilter.GetFilterHash() + MD5HashHelper.GetHashString(MD5HashHelper.GetHash(m_sources));
|
||||
var configHash = emitFilter.GetFilterHash() + Utility.Utility.ByteArrayAsHexString(MD5HashHelper.GetHash(m_sources));
|
||||
|
||||
// create lookup for journal data
|
||||
var journalDataDict = prevJournalData.ToDictionary(data => data.Volume);
|
||||
|
||||
@@ -37,6 +37,11 @@ namespace Duplicati.Library.Snapshots
|
||||
/// </summary>
|
||||
public sealed class WindowsSnapshot : SnapshotBase
|
||||
{
|
||||
/// <summary>
|
||||
/// The tag used for logging messages
|
||||
/// </summary>
|
||||
public static readonly string LOGTAG = Logging.Log.LogTagFromType<WindowsSnapshot>();
|
||||
|
||||
/// <summary>
|
||||
/// The main reference to the backup controller
|
||||
/// </summary>
|
||||
@@ -161,9 +166,9 @@ namespace Duplicati.Library.Snapshots
|
||||
m_mappedDrives.Add(d = new DefineDosDevice(m_volumeMap[k]));
|
||||
m_volumeMap[k] = Utility.Utility.AppendDirSeparator(d.Drive);
|
||||
}
|
||||
catch
|
||||
catch(Exception ex)
|
||||
{
|
||||
// ignored
|
||||
Logging.Log.WriteVerboseMessage(LOGTAG, "SubstMappingfailed", ex, "Failed to map VSS path {0} to drive", k);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -175,9 +180,9 @@ namespace Duplicati.Library.Snapshots
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
catch
|
||||
catch(Exception ex)
|
||||
{
|
||||
// ignored
|
||||
Logging.Log.WriteVerboseMessage(LOGTAG, "VSSCleanupOnError", ex, "Failed during VSS error cleanup");
|
||||
}
|
||||
|
||||
throw;
|
||||
@@ -387,7 +392,7 @@ namespace Duplicati.Library.Snapshots
|
||||
|
||||
foreach (var kvp in m_volumeReverseMap)
|
||||
{
|
||||
if (snapshotPath.StartsWith(kvp.Key))
|
||||
if (snapshotPath.StartsWith(kvp.Key, Utility.Utility.ClientFilenameStringComparision))
|
||||
return Path.Combine(kvp.Value, snapshotPath.Substring(kvp.Key.Length));
|
||||
}
|
||||
|
||||
@@ -442,40 +447,40 @@ namespace Duplicati.Library.Snapshots
|
||||
m_mappedDrives = null;
|
||||
}
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
m_backup?.BackupComplete();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
Logging.Log.WriteVerboseMessage(LOGTAG, "MappedDriveCleanupError", ex, "Failed during VSS mapped drive unmapping");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
m_backup?.BackupComplete();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log.WriteVerboseMessage(LOGTAG, "VSSTerminateError", ex, "Failed to signal VSS completion");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (m_backup != null)
|
||||
{
|
||||
foreach (var g in m_volumes.Values)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_backup.DeleteSnapshot(g, false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
{
|
||||
try
|
||||
{
|
||||
m_backup.DeleteSnapshot(g, false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log.WriteVerboseMessage(LOGTAG, "VSSSnapShotDeleteError", ex, "Failed to close VSS snapshot");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
// ignored
|
||||
Logging.Log.WriteVerboseMessage(LOGTAG, "VSSSnapShotDeleteCleanError", ex, "Failed during VSS esnapshot closing");
|
||||
}
|
||||
|
||||
if (m_backup != null)
|
||||
|
||||
@@ -352,7 +352,7 @@ namespace Duplicati.Library.Utility
|
||||
public string GetFilterHash()
|
||||
{
|
||||
var hash = MD5HashHelper.GetHash(m_filters.Select(x => x.Filter));
|
||||
return MD5HashHelper.GetHashString(hash);
|
||||
return Utility.ByteArrayAsHexString(hash);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace Duplicati.Library.Utility
|
||||
public string GetFilterHash()
|
||||
{
|
||||
var hash = MD5HashHelper.GetHash(new[] {First.GetFilterHash(), Second.GetFilterHash()});
|
||||
return MD5HashHelper.GetHashString(hash);
|
||||
return Utility.ByteArrayAsHexString(hash);
|
||||
}
|
||||
|
||||
public bool Empty { get { return First.Empty && Second.Empty; } }
|
||||
|
||||
@@ -18,20 +18,34 @@
|
||||
//
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace Duplicati.Library.Utility
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class to compute MD5 hashes
|
||||
/// </summary>
|
||||
public static class MD5HashHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Computes the MD5 hash of the input string
|
||||
/// </summary>
|
||||
/// <returns>The MD5 hash.</returns>
|
||||
/// <param name="inputString">The input string.</param>
|
||||
public static byte[] GetHash(string inputString)
|
||||
{
|
||||
HashAlgorithm algorithm = MD5.Create(); //or use SHA256.Create();
|
||||
return algorithm.ComputeHash(Encoding.UTF8.GetBytes(inputString));
|
||||
using(var algorithm = MD5.Create()) //or use SHA256.Create();
|
||||
return algorithm.ComputeHash(Encoding.UTF8.GetBytes(inputString));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes the MD5 hash of the input strings
|
||||
/// </summary>
|
||||
/// <returns>The MD5 hash.</returns>
|
||||
/// <param name="inputStrings">The input strings.</param>
|
||||
public static byte[] GetHash(IEnumerable<string> inputStrings)
|
||||
{
|
||||
using (var md5 = MD5.Create())
|
||||
@@ -46,14 +60,5 @@ namespace Duplicati.Library.Utility
|
||||
return md5.Hash;
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetHashString(byte[] hash)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
foreach (var b in hash)
|
||||
sb.Append(b.ToString("X2"));
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user