Пример #1
0
        // sync files
        internal static bool Sync(string sSourceRoot, WIN32_FILE[] Files, List <string> lFiles_Delete, List <string> lDirs_Delete)
        {
            List <string> lErrorList = new List <string>();

            // copy files
            int  iFilesCopied = 0;
            long lCopiedSize  = 0;

            foreach (var SourceFile in Files)
            {
                string DestPath = sSourceRoot + DLLS.GetPathDirs(SourceFile.FullPath);
                string DestDir  = sSourceRoot + DLLS.GetPathDirs(SourceFile.Path);

                try
                {
                    // create directory recursivle if not existing
                    if (!DLLS.DirExists(DestDir))
                    {
                        DLLS.CreateDirRecursive(DestDir);
                    }
                    DLLS.FileCopy(SourceFile.FullPath, DestPath);
                }
                catch (Exception ex)
                {
                    lErrorList.Add(ex.Message + " - " + SourceFile.FullPath);
                    continue;
                }
                lCopiedSize += SourceFile.Size;
                UpdateProgress(lCopiedSize, lSyncSize);
                iFilesCopied++;
            }

            // delete files
            int iFilesDeleted = 0;

            foreach (var FilePath in lFiles_Delete)
            {
                try
                {
                    DLLS.FileDelete(FilePath);
                }
                catch (Exception ex)
                {
                    lErrorList.Add(ex.Message + " - " + FilePath);
                    continue;
                }
                iFilesDeleted++;
            }


            // sort and reverse dictionary list so dirs will get removed from upper to lower (otherwise DirDelete will fail if directory is not empty - which should not happen but safe is safe)
            lDirs_Delete.Sort();
            lDirs_Delete.Reverse();

            // delete folders
            int iDirsDeleted = 0;

            foreach (var DirPath in lDirs_Delete)
            {
                try
                {
                    DLLS.DirDelete(DirPath);
                }
                catch (Exception)
                {
                    // UGLY CODE
                    // sometimes DirDelete will fail with DirectoryNotEmpty because the system can't keep up with already deleted folders
                    // so we have to wait a few ms and then try again
                    System.Threading.Thread.Sleep(50);
                    try
                    {
                        DLLS.DirDelete(DirPath);
                    }
                    catch (Exception ex)
                    {
                        lErrorList.Add(ex.Message + " - " + DirPath);
                        continue;
                    }
                }
                iDirsDeleted++;
            }

            Print("");
            Print("");

            if (lErrorList.Count > 0)
            {
                PrintError("Error while tring to sync files: ");
                Logger("ERROR: Error while tring to sync files: ");
                foreach (var sErrorMsg in lErrorList)
                {
                    Print(sErrorMsg);
                    Logger(sErrorMsg);
                }
                Print("");
                Print("");
                Logger("");
            }

            Logger("Copied " + iFilesCopied + "/" + Files.Length + " files (" + String.Format("{0:0.00}", lCopiedSize / 1073741824f) + " GiB)");
            Print("Copied " + iFilesCopied + "/" + Files.Length + " files (" + String.Format("{0:0.00}", lCopiedSize / 1073741824f) + " GiB)");
            Logger("Deleted " + iFilesDeleted + "/" + lFilesToDelete.Count + " files");
            Print("Deleted " + iFilesDeleted + "/" + lFilesToDelete.Count + " files");
            Logger("Deleted " + iDirsDeleted + "/" + lDirsToDelete.Count + " folders");
            Print("Deleted " + iDirsDeleted + "/" + lDirsToDelete.Count + " folders");

            return(lErrorList.Count < 1);
        }
Пример #2
0
        static void Main(string[] args)
        {
            // hide console window if silent option is present
            if (args.Contains("-s") || args.Contains("-S"))
            {
                var handle = GetConsoleWindow();
                ShowWindow(handle, 0);
            }

            Console.Title = "DLLS v1.0.0";
            // ASCII-Art created with http://patorjk.com/software/taag/
            Console.ForegroundColor = ConsoleColor.DarkYellow;
            Console.WriteLine(@"      ____  __    __   _____ ");
            Console.WriteLine(@"     / __ \/ /   / /  / ___/ ");
            Console.WriteLine(@"    / / / / /   / /   \__ \  ");
            Console.WriteLine(@"   / /_/ / /___/ /______/ /  ");
            Console.WriteLine(@"  /_____/_____/_____/____/   ");
            Console.WriteLine(@"                             ");
            Console.WriteLine("[ DriveLetterLessSync v1.0.0 ]");
            Console.WriteLine("      - by Uberhalit -");
            Console.WriteLine();
            Console.ForegroundColor = ConsoleColor.Gray;

            if (args.Length < 1)
            {
                PrintError("No commands specified!");
                Console.ReadLine();
                Environment.Exit(0);
            }

            // skip first two args (drives)
            for (int i = 0; i < args.Length; i++)
            {
                switch (args[i].ToLower())
                {
                case "-?":
                    Console.WriteLine("DLLScli /?");
                    Console.WriteLine("Synchronize files and folders between drives even if unmounted");
                    Console.WriteLine();
                    Console.WriteLine("DLLSCLI SourceDrive DestinationDrive [-S] [-NL] [-NS] [-ON] [-IT] [-IS] [-H Hash]");
                    Console.WriteLine();
                    Console.WriteLine("S / SILENT          suppress all output and window");
                    Console.WriteLine("NL / NO LOG         do not create log-file");
                    Console.WriteLine("NS / NO SYNC        compare files but do not sync");
                    Console.WriteLine("ON / ONLY NEW       only copy new files, do not compare existing files");
                    Console.WriteLine("IT / IGNORE TIME    ignore file modification time");
                    Console.WriteLine("IS / IGNORE SIZE    ignore file size");
                    Console.WriteLine("H Hash / HASH Hash  use checksums to compare files, available hashing algorithms: MD5, SHA1, SHA256");
                    Console.ReadLine();
                    Environment.Exit(0);
                    break;

                case "-d":
                    Drives();
                    Console.ReadLine();
                    Environment.Exit(0);
                    break;

                case "-s":
                    bSilent = true;
                    break;

                case "-nl":
                    bNoLog = true;
                    break;

                case "-ns":
                    bNoSync = true;
                    break;

                case "-on":
                    bOnlyNew = true;
                    break;

                case "-it":
                    bIgnoreTime = true;
                    break;

                case "-is":
                    bIgnoreSize = true;
                    break;

                case "-h":
                    if (args.Length > i + 1)
                    {
                        bCheckHash = true;
                        switch (args[i + 1].ToLower())
                        {
                        case "md5":
                            haChecksumAlgorithm = new MD5CryptoServiceProvider();
                            break;

                        case "sha1":
                            haChecksumAlgorithm = new SHA1Managed();
                            break;

                        case "sha256":
                            haChecksumAlgorithm = new SHA256Managed();
                            break;

                        default:
                            PrintError("'" + args[i + 1] + "' is not a valid option!");
                            Console.ReadLine();
                            Environment.Exit(0);
                            break;
                        }
                    }
                    break;
                }
            }

            // check if provided drive-pathes exist
            try
            {
                // bug: due to a bug or limitation in .NET volume-GUID-pathes won't work in most .NET-functions except we replace '?' with '.'
                // https://msdn.microsoft.com/en-us/library/aa365247.aspx
                if (Directory.Exists(args[0].Replace('?', '.')) && Directory.Exists(args[1].Replace('?', '.')))
                {
                    // get full volume guid path for provied drives
                    sSourceDrive = DLLS.FixDrive(args[0]);
                    sDestDrive   = DLLS.FixDrive(args[1]);
                }
                else
                {
                    PrintError("Unable to find provided drives!");
                    Logger("ERROR: Unable to find provided drives!");
                    if (!bSilent)
                    {
                        Console.ReadLine();
                    }
                    Environment.Exit(0);
                }
            }
            catch (Exception ex)
            {
                PrintError(ex.Message);
                Logger("ERROR: " + ex.Message);
                if (!bSilent)
                {
                    Console.ReadLine();
                }
                Environment.Exit(0);
            }

            PrintInfo("Starting operation...");
            Console.WriteLine();

            if (!bNoLog)
            {
                // get current executable directory and create logs folder if not already present
                string sLogsDir = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location), "logs");
                if (!Directory.Exists(sLogsDir))
                {
                    Directory.CreateDirectory(sLogsDir);
                }

                if (Directory.Exists(sLogsDir))
                {
                    sLogPath = sLogsDir + @"\DLLS_" + DateTime.Today.ToString("d") + ".log";
                }
                else
                {
                    bNoLog = true;
                }

                Logger("DLLScli - Starting operation...");
            }

            Console.CursorVisible = false;
            lFilesToDelete        = new List <string>();
            lDirsToDelete         = new List <string>();

            if (bCheckHash)
            {
                Print("WARNING: hash option detected. This can take a VERY long time.");
                Logger("WARNING: hash option detected. This can take a VERY long time.");
            }

            bool noerror1 = Find(sSourceDrive, sDestDrive);

            if (bNoSync)
            {
                Console.CursorVisible = true;
                // get user input if an error has occured
                if (!bSilent && !noerror1)
                {
                    Console.ReadLine();
                }
                Environment.Exit(0);
            }

            bool noerror2 = Sync(sDestDrive, FilesToSync, lFilesToDelete, lDirsToDelete);

            // get user input if an error has occured
            if (!bSilent && (!noerror1 || !noerror2))
            {
                Console.CursorVisible = true;
                Console.ReadLine();
            }
        }
Пример #3
0
        // 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);
        }