/// <summary> /// Enumerates all files and directories from a given directory (PathTooLong safe, volume guid safe). /// </summary> public static WIN32_FILE[] GetEntries(string path, string searchPattern, SearchOption searchOption) { IEnumerable <WIN32_FILE> IEn = EnumerateEntries(FixPath(path), searchPattern, searchOption); List <WIN32_FILE> lTmp = new List <WIN32_FILE>(IEn); WIN32_FILE[] lEntries = new WIN32_FILE[lTmp.Count]; lTmp.CopyTo(lEntries); return(lEntries); }
// find all differences internal static bool Find(string sSourceRoot, string sDestRoot) { long lTotalSize = 0; // total size of all processed files in bytes List <string> lErrorList = new List <string>(); // list of all errors which occured during process List <string> lFilesSource = new List <string>(); // all relative file pathes from source drive (without drive) List <string> lDirsSource = new List <string>(); // all relative folder pathes from source drive (without drive) // get all entries on drive root (TopDirectoryOnly) // we have to skip volume specific folders here ($RECYCLE.BIN / System Volume Information) List <string> lRootDirs = Directory.GetDirectories(sSourceRoot).Where(s => !s.EndsWith("$RECYCLE.BIN") && !s.EndsWith("System Volume Information")).ToList(); List <WIN32_FILE> lEntries = DLLS.GetEntriesList(sSourceRoot, "*", SearchOption.TopDirectoryOnly).Where(s => !s.Name.EndsWith("$RECYCLE.BIN") && !s.Name.EndsWith("System Volume Information")).ToList(); // get all entries from root directories and append to entries list foreach (var sDir in lRootDirs) { lEntries.AddRange(DLLS.GetEntriesList(sDir, "*", SearchOption.AllDirectories)); } // remove any duplicates? //var xEntries = new HashSet<WIN32_FILE>(lEntries); // HashSet is a lot faster than Distinct().ToList() when > 1*10^6 entries // copy entry list to WIN32_FILE array WIN32_FILE[] aSoureFiles = new WIN32_FILE[lEntries.Count]; lEntries.CopyTo(aSoureFiles); lRootDirs.Clear(); lEntries.Clear(); // IMPORTANT: we will reuse lEntries as a temporary list Print("Found " + aSoureFiles.Length + " entries on source drive."); int iDirs = 0; // count all directories int iFiles = 0; // count all files foreach (var SourceFile in aSoureFiles) { // handle directories if (SourceFile.isDirectory) { iDirs++; if (!lDirsSource.Contains(DLLS.GetPathDirs(SourceFile.FullPath))) { lDirsSource.Add(DLLS.GetPathDirs(SourceFile.FullPath)); } continue; } iFiles++; lTotalSize += SourceFile.Size; // add filesize to total size lFilesSource.Add(DLLS.GetPathDirs(SourceFile.FullPath)); // add full relative path from file string sDestPath = sDestRoot + DLLS.GetPathDirs(SourceFile.FullPath); // create a hypothetically destination path for current file bool bAdd = false; // should the file be synchronized? try { // if file does not exist on destination drive (new file) if (!DLLS.FileExists(sDestPath)) { bAdd = true; } else if (!bOnlyNew) { WIN32_FILE DestFile = DLLS.GetFile(sDestPath); // get file infos if (!bIgnoreSize) // compare filesizes { if (SourceFile.Size != DestFile.Size) { bAdd = true; } } if (!bIgnoreTime && !bAdd) // compare last modification time { if (SourceFile.LastWriteTime != DestFile.LastWriteTime) { bAdd = true; } } if (bCheckHash && !bAdd) // calculate and compare checksums { string sSourceHash = DLLS.GetHashFromFile(SourceFile.FullPath, haChecksumAlgorithm); string sDestHash = DLLS.GetHashFromFile(DestFile.FullPath, haChecksumAlgorithm); if (sSourceHash != sDestHash) { bAdd = true; } } } } catch (Exception ex) { lErrorList.Add(ex.Message); // add any error to error list for now } // add file which will be synchronized to entries list (temporary) if (bAdd) { lEntries.Add(SourceFile); lSyncSize += SourceFile.Size; } UpdateProgress(iFiles + iDirs, aSoureFiles.Length); // show progress } Print(""); Print(""); // copy all file information which shall be synchronized to array FilesToSync = new WIN32_FILE[lEntries.Count]; lEntries.CopyTo(FilesToSync); lEntries.Clear(); // get all entries from destination drive lRootDirs = Directory.GetDirectories(sDestRoot).Where(s => !s.EndsWith("$RECYCLE.BIN") && !s.EndsWith("System Volume Information")).ToList(); lEntries = DLLS.GetEntriesList(sDestRoot, "*", SearchOption.TopDirectoryOnly).Where(s => !s.Name.EndsWith("$RECYCLE.BIN") && !s.Name.EndsWith("System Volume Information")).ToList(); foreach (var sDir in lRootDirs) { lEntries.AddRange(DLLS.GetEntriesList(sDir, "*", SearchOption.AllDirectories)); } WIN32_FILE[] aDestFiles = new WIN32_FILE[lEntries.Count]; lEntries.CopyTo(aDestFiles); lEntries.Clear(); lRootDirs.Clear(); Print("Found " + aDestFiles.Length + " entries on destination drive."); foreach (var DestFile in aDestFiles) { // handle directories if (DestFile.isDirectory) { // mark folder for deletation if relative path of destination dir is not present on source drive if (!lDirsSource.Contains(DLLS.GetPathDirs(DestFile.FullPath))) { if (!lDirsToDelete.Contains(DestFile.FullPath)) { lDirsToDelete.Add(DestFile.FullPath); // fill list with full path from destination drive } } else { lDirsSource.Remove(DLLS.GetPathDirs(DestFile.FullPath)); // remove entry from source dir list so we can speed up future look up } continue; } // handle files if (!lFilesSource.Contains(DLLS.GetPathDirs(DestFile.FullPath))) { lFilesToDelete.Add(DestFile.FullPath); // fill list with full path from destination drive } else { lFilesSource.Remove(DLLS.GetPathDirs(DestFile.FullPath)); // remove entry from source file list so we can speed up future look up } } // print all errors if (lErrorList.Count > 0) { PrintError("ERROR: "); Logger("ERROR: "); foreach (var sErrorMsg in lErrorList) { Print(sErrorMsg); Logger(sErrorMsg); } Print(""); Print(""); Logger(""); } Print("Processed " + iFiles + " files on source drive (" + String.Format("{0:0.00}", lTotalSize / 1073741824f) + " GiB)"); Logger("Processed " + iFiles + " files on source drive (" + String.Format("{0:0.00}", lTotalSize / 1073741824f) + " GiB)"); Print(FilesToSync.Length + " files to sync (" + String.Format("{0:0.00}", lSyncSize / 1073741824f) + " GiB)"); Logger(FilesToSync.Length + " files to sync (" + String.Format("{0:0.00}", lSyncSize / 1073741824f) + " GiB)"); Print(lFilesToDelete.Count + " files to delete on destination drive"); Logger(lFilesToDelete.Count + " files to delete on destination drive"); Print(lDirsToDelete.Count + " folders to delete on destination drive"); Logger(lDirsToDelete.Count + " folders to delete on destination drive"); // return result return(lErrorList.Count < 1); }