/// <summary> /// Returns a possibly-empty list of incorrect entries in this <see cref="FileContentTable" />. /// </summary> /// <remarks> /// In the absence of an incorrect file content table implementation, file system bugs, or disk corruption, the list should /// be empty. /// Hence, this is a diagnostic facility. /// </remarks> public static List <IncorrectFileContentEntry> FindIncorrectEntries(this FileContentTable fileContentTable, IFileContentTableAccessor accessor) { Contract.Requires(fileContentTable != null); Contract.Requires(accessor != null); Contract.Ensures(Contract.Result <List <IncorrectFileContentEntry> >() != null); Contract.Ensures(Contract.ForAll(Contract.Result <List <IncorrectFileContentEntry> >(), e => e != null)); var badEntries = new List <IncorrectFileContentEntry>(); fileContentTable.VisitKnownFiles( accessor, FileShare.Read | FileShare.Delete, // On accessing the entry of file content table, we do not allow concurrent writes; otherwise the content may change as we're hashing it. // To this end, the file needs to be opened with FileShare.Read | FileShare.Delete accesses. (fileIdAndVolumeId, handle, path, knownUsn, knownHash) => { using (var fs = new FileStream(handle, FileAccess.Read)) { ContentHash actualHash = ContentHashingUtilities.HashContentStreamAsync(fs).GetAwaiter().GetResult(); if (knownHash != actualHash) { badEntries.Add(new IncorrectFileContentEntry(path, fileIdAndVolumeId, knownUsn, knownHash, actualHash)); } } return(true); }); return(badEntries); }