private FileObject() { StatusInformation=new FileStatusInformation(FILESTATUS.Unknown,""); }
/// <summary> /// Compare. B is considered the newer one. For syncing, B should be the source and A should be the target. /// </summary> public void CompareAgainstSnapshot() { // Reset the results. ResultUpdates = new Dictionary<string, FileObject>(); ResultNew = new Dictionary<string, FileStatusInformation>(); // Prepare the result list. Get the file objects from the first snapshot. Dictionary<string, FileObject> filesA = SnapshotA.GetFilelist(); // Get the file list from the second one we compare to the first snapshot. Dictionary<string, FileObject> filesB = SnapshotB.GetFilelist(); // Prepare a list for new files and their status information. Dictionary<string, FileStatusInformation> newFiles = new Dictionary<string, FileStatusInformation>(); // Do it! Go through the new version of a directory and check what happened. foreach (string bFile in filesB.Keys) { // Is there a file with that path? if (filesA.ContainsKey(bFile)) { // Are the modifying dates eqal? if (filesA[bFile].ChangeDate == filesB[bFile].ChangeDate) { // Is the file size equal? We have to open the files at this point. That sucks. if (filesA[bFile].Size == filesB[bFile].Size) { // Those files seem to be equal but as we have the hash anyway, we compare it. if (filesA[bFile].Hash.Equals(filesB[bFile].Hash)) filesA[bFile].StatusInformation.Status = FILESTATUS.Unchanged; else { // The content changed, but not the writetime or the file size. // Could happen when files get transferred via an inreliable connection. filesA[bFile].StatusInformation.Status = FILESTATUS.Changed; filesA[bFile].StatusInformation.Information = "Changed without modifying writetime or size"; } } else { // Ah, the filesizes differ. Work with the hash. // Hash existing? string oldpath = SnapshotA.GetFilepath(filesB[bFile].Hash); if (oldpath != null) { // We know that file. That means: // A file was replaced by an existing file with equal lastwritetime that was moved here. filesA[bFile].StatusInformation.Status = FILESTATUS.Replaced; filesA[bFile].StatusInformation.Information = oldpath; // It means also a file was moved. Save that. // WARNING: If there is a new / other file at the old path one of the two might get lost. // TODO: Accept multiple statuses for one path to fix that. filesA[oldpath].StatusInformation.Status = FILESTATUS.Moved; filesA[oldpath].StatusInformation.Information = bFile; } else { // Change without modified writetime. Photo batch processing for example. filesA[bFile].StatusInformation.Status = FILESTATUS.Changed; filesA[bFile].StatusInformation.Information = "Changed without modifying writetime"; } } } else { // Different modified time // Check the hashes of both files if (filesA[bFile].Hash.Equals(filesB[bFile].Hash)) { // Unchanged file with changed modified date. // Happens sometimes when a file is opened and saved but not changed (Access does that all the time) // or if the changes have been reverted meanwhile. filesA[bFile].StatusInformation.Status = FILESTATUS.UnchangedModified; } else { string oldpath = SnapshotA.GetFilepath(filesB[bFile].Hash); if (oldpath != null) { // We know that file. That means: // A file that already existed was overwritten by another file that already existed. filesA[bFile].StatusInformation.Status = FILESTATUS.Replaced; filesA[bFile].StatusInformation.Information = oldpath; // It means also a file was moved. Save that. // WARNING: If there is a new / other file at the old path one of the two might get lost. // TODO: Accept multiple statuses for one path to fix that. filesA[oldpath].StatusInformation.Status = FILESTATUS.Moved; filesA[oldpath].StatusInformation.Information = bFile; } else { // Otherwise, this is a standard change. filesA[bFile].StatusInformation.Status = FILESTATUS.Changed; } } } } else { // File with unknown path. Get Hash! // Hash existing? string oldpath = SnapshotA.GetFilepath(filesB[bFile].Hash); if (oldpath != null) { // We know that one! Is it still there? if (filesB.ContainsKey(oldpath)) { // The new file is a copy of a file that existed already. // TODO: More checking here newFiles[bFile] = new FileStatusInformation(FILESTATUS.NewCopy, oldpath); } else { // Move/rename. // WARNING: If there is a new / other file at the old path one of the two might get lost. // TODO: Accept multiple statuses for one path to fix that. filesA[oldpath].StatusInformation.Status = FILESTATUS.Moved; filesA[oldpath].StatusInformation.Information = bFile; } } else { newFiles[bFile] = new FileStatusInformation(FILESTATUS.New, ""); } } } // Last step: Check unidentified files in snapshot A (most likely, deleted files) foreach (KeyValuePair<string, FileObject> kvp in filesA) { if (kvp.Value.StatusInformation.Status == FILESTATUS.Unknown) { // Let's see if this file's hash is in the second snapshot // We do that all the time in the above procedure but always the other way round string newpath = SnapshotB.GetFilepath(filesA[kvp.Value.Filepath].Hash); if (newpath != null) { // We know that file. That means: // A file that existed before still exists, but we weren't able to identify it yet // Example: A duplicate has been removed, then we only identified the remaining one filesA[kvp.Value.Filepath].StatusInformation.Status = FILESTATUS.Moved; filesA[kvp.Value.Filepath].StatusInformation.Information = newpath; } else { // Now we are sure this file has been deleted. It's hash is gone and there is no longer a file at that path. filesA[kvp.Value.Filepath].StatusInformation.Status = FILESTATUS.Deleted; } } } ResultUpdates = filesA; ResultNew = newFiles; }
public void CompareAgainstFolder() { // Reset the results. ResultUpdates = new Dictionary<string, FileObject>(); ResultNew = new Dictionary<string, FileStatusInformation>(); // Prepare the result list. Get the file objects from the snapshot. Dictionary<string, FileObject> filesSnapshot = BaseSnapshot.GetFilelist(); // Get the file list from the folder we compare to the snapshot. List<string> filesFolder = new List<string>(Directory.EnumerateFiles(Folder, "*", SearchOption.AllDirectories)); // Prepare a list for new files and their status information. Dictionary<string, FileStatusInformation> newFiles = new Dictionary<string, FileStatusInformation>(); // Do it! Go through the new version of a directory and check what happened. foreach (string f in filesFolder) { // Trim basepath string file = f.Substring(Folder.Length); // Should we ignore this file? string filename = Path.GetFileName(file); if (filename.StartsWith(".") || filename.EndsWith(".db") || filename.EndsWith(".ini")) continue; // Is there a file with that path in the snapshot? if (filesSnapshot.ContainsKey(file)) { // Are the modifying dates equal (and we consider them equal, when they differ less than a millisecond)? if (Math.Abs(filesSnapshot[file].ChangeDate - File.GetLastWriteTime(Folder + file).Ticks) < 10000) { // Is the file size equal? We have to open the files at this point. That sucks. long size = -1; using (FileStream fsb = File.OpenRead(Folder + file)) { size = fsb.Length; fsb.Close(); } if (filesSnapshot[file].Size == size) { // Paranoid user stuff goes here (for detecting 1. files that have equal size, // creation time and last write time but different content and are new and 2. files like that // that have been moved. // Otherwise, those files seem to be equal. filesSnapshot[file].StatusInformation.Status = FILESTATUS.Unchanged; } else { // Ah, the filesizes differ. Get the hash. FileObject d = FileObject.Instance(Folder + file); // Hash existing? string oldpath = BaseSnapshot.GetFilepath(d.Hash); if (oldpath != null) { // We know that file. That means: // A file was replaced by an existing file with equal lastwritetime that was moved here. filesSnapshot[file].StatusInformation.Status = FILESTATUS.Replaced; filesSnapshot[file].StatusInformation.Information = oldpath; // It means also a file was moved. Save that. // WARNING: If there is a new / other file at the old path one of the two might get lost. // TODO: Accept multiple statuses for one path to fix that. // TODO: Maybe swapping the infos (old path is now in info) fixed that already. filesSnapshot[oldpath].StatusInformation.Status = FILESTATUS.Moved; filesSnapshot[oldpath].StatusInformation.Information = file; } else { // Change without modified writetime. Photo batch processing for example. filesSnapshot[file].StatusInformation.Status = FILESTATUS.Changed; filesSnapshot[file].StatusInformation.Information = "Changed without modifying writetime"; } } } else { // Different modified time // Get the hashes of both files FileObject b = FileObject.Instance(Folder + file); if (filesSnapshot[file].Hash.Equals(b.Hash)) { // Unchanged file with changed modified date. // Happens sometimes when a file is opened and saved but not changed (Access does that all the time) // or if the changes have been reverted meanwhile. filesSnapshot[file].StatusInformation.Status = FILESTATUS.UnchangedModified; } else { string oldpath = BaseSnapshot.GetFilepath(b.Hash); if (oldpath != null) { // We know that file. That means: // A file that already existed was overwritten by another file that already existed. filesSnapshot[file].StatusInformation.Status = FILESTATUS.Replaced; filesSnapshot[file].StatusInformation.Information = oldpath; // It means also a file was moved. Save that. // WARNING: If there is a new / other file at the old path one of the two might get lost. // TODO: Accept multiple statuses for one path to fix that. filesSnapshot[oldpath].StatusInformation.Status = FILESTATUS.Moved; filesSnapshot[oldpath].StatusInformation.Information = file; } else { // Otherwise, this is a standard change. filesSnapshot[file].StatusInformation.Status = FILESTATUS.Changed; } } } } else { // File with unknown path. Get Hash! FileObject d = FileObject.Instance(Folder + file); // Hash existing? string oldpath = BaseSnapshot.GetFilepath(d.Hash); if (oldpath != null) { // We know that one! Is it still there? if (File.Exists(Folder + oldpath)) { // The new file is a copy of a file that existed already. // TODO: More checking here newFiles[file] = new FileStatusInformation(FILESTATUS.NewCopy, oldpath); } else { // Move/rename. // WARNING: If there is a new / other file at the old path one of the two might get lost. // TODO: Accept multiple statuses for one path to fix that. filesSnapshot[oldpath].StatusInformation.Status = FILESTATUS.Moved; filesSnapshot[oldpath].StatusInformation.Information = file; } } else { newFiles[file] = new FileStatusInformation(FILESTATUS.New, ""); } } } // Last step: Check unidentified files in the snapshot (most likely, deleted files) foreach (KeyValuePair<string, FileObject> kvp in filesSnapshot) { if (kvp.Value.StatusInformation.Status == FILESTATUS.Unknown) { // TODO: } } ResultUpdates = filesSnapshot; ResultNew = newFiles; }