private void _backupPerformer_StartedCopyingItem(FolderFileItem item) { if (_copyDataToProgressMap.ContainsKey(item)) { var progressInfo = _copyDataToProgressMap[item]; progressInfo.IsCopyInProgress = true; } }
private void _backupPerformer_CalculatedBytesOfItem(FolderFileItem item, ulong bytes) { if (_copyDataToProgressMap.ContainsKey(item)) { item.ByteSize = bytes; var progressInfo = _copyDataToProgressMap[item]; progressInfo.TotalBytesToCopy = bytes; _totalBackupSize += bytes; } }
private void _backupPerformer_CopiedBytesOfItem(FolderFileItem item, ulong bytes) { if (_copyDataToProgressMap.ContainsKey(item)) { var progressInfo = _copyDataToProgressMap[item]; progressInfo.BytesCopied += bytes; _bytesCopiedSoFar += bytes; _currentProgress = Math.Min((double)_bytesCopiedSoFar / (double)_totalBackupSize * 100, 100); NotifyPropertyChanged(nameof(CurrentProgressString)); } }
public ExcludeFilesFoldersViewModel(IChangeViewModel viewModelChanger, FolderFileItem itemBeingEdited) : base(viewModelChanger) { _itemBeingEdited = itemBeingEdited; _items = new ObservableCollection <FolderFileItem>(); foreach (var path in itemBeingEdited.ExcludedPaths) { Items.Add(new FolderFileItem() { Path = path, IsDirectory = Directory.Exists(path) }); } }
// Modified from https://stackoverflow.com/a/33726939/3938401 private void CopySingleFile(FolderFileItem itemBeingCopied, string source, string destination) { if (File.Exists(source)) { if (HasBeenCanceled) { return; } if (UsesCompressedFile) { } else { using (var outStream = new FileStream(destination, FileMode.CreateNew, FileAccess.Write, FileShare.Read)) { using (var inStream = new FileStream(source, FileMode.Open, FileAccess.Read, FileShare.Read)) { int buffer_size = 10240; byte[] buffer = new byte[buffer_size]; long total_read = 0; while (total_read < inStream.Length) { if (HasBeenCanceled) { break; } int read = inStream.Read(buffer, 0, buffer_size); outStream.Write(buffer, 0, read); CopiedBytesOfItem(itemBeingCopied, (ulong)read); total_read += read; } } } } } }
// Modified from https://docs.microsoft.com/en-us/dotnet/standard/io/how-to-copy-directories private void CopyDirectory(FolderFileItem itemBeingCopied, string sourceDirName, string destDirName, bool copySubDirs, List <string> excludedPaths = null) { if (HasBeenCanceled) { return; } // Get the subdirectories for the specified directory. DirectoryInfo dir = new DirectoryInfo(sourceDirName); if (!dir.Exists) { throw new DirectoryNotFoundException( "Source directory does not exist or could not be found: " + sourceDirName); } _directoryPathsSeen.Add(sourceDirName); // If the destination directory doesn't exist, create it. if (!Directory.Exists(destDirName) && !_isCalculatingFileSize) { Directory.CreateDirectory(destDirName); } // Get the files in the directory and copy them to the new location. FileInfo[] files = dir.GetFiles(); foreach (FileInfo file in files) { if (HasBeenCanceled) { return; } string tempPath = Path.Combine(destDirName, file.Name); bool shouldAllow = ShouldAllowPath(excludedPaths, file.FullName); if (_isCalculatingFileSize && shouldAllow) { _currentDirectorySize += (ulong)file.Length; } else if (shouldAllow) { CopySingleFile(itemBeingCopied, file.FullName, tempPath); } } // If copying subdirectories, copy them and their contents to new location. if (copySubDirs) { DirectoryInfo[] dirs = dir.GetDirectories(); foreach (DirectoryInfo subDir in dirs) { if (HasBeenCanceled) { return; } if (!_directoryPathsSeen.Contains(subDir.FullName)) { string temppath = Path.Combine(destDirName, subDir.Name); if (ShouldAllowPath(excludedPaths, subDir.FullName)) { CopyDirectory(itemBeingCopied, subDir.FullName, temppath, copySubDirs, excludedPaths); } _directoryPathsSeen.Add(subDir.FullName); } } } }
private void BackupToCompressedFile(string destination, List <string> filePaths, Dictionary <string, FolderFileItem> pathsToFolderFileItem, Dictionary <string, ulong> pathsToFileSize) { var quotedFilePaths = new List <string>(); foreach (string filePath in filePaths) { quotedFilePaths.Add("\"" + filePath + "\""); } var is64BitOS = Utilities.Is64BitOS(); Process process = new Process(); var currentDir = Directory.GetParent(Assembly.GetExecutingAssembly().Location).FullName; var exePath = is64BitOS ? currentDir + "/tools/x64/7za.exe" : currentDir + "/tools/x86/7za.exe"; process.StartInfo.FileName = exePath; process.StartInfo.WorkingDirectory = Directory.GetParent(Assembly.GetExecutingAssembly().Location).FullName; // https://stackoverflow.com/a/6522928/3938401 process.StartInfo.UseShellExecute = false; process.StartInfo.CreateNoWindow = true; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.StandardOutputEncoding = Encoding.UTF8; //process.StartInfo.RedirectStandardError = true; process.EnableRaisingEvents = true; var didError = false; var sizeInBytes = 0UL; var remainingBytes = 0UL; var didStartCompressingFile = false; var lastPercent = 0.0; string currentFilePath = ""; FolderFileItem currentItem = null; var bytesCopiedForItem = new Dictionary <FolderFileItem, ulong>(); var didFinishCancel = false; var nextMessageIsError = false; string errorMessage = ""; process.OutputDataReceived += new DataReceivedEventHandler(delegate(object sender, DataReceivedEventArgs e) { if (string.IsNullOrWhiteSpace(e.Data) || didFinishCancel) // in case more events come through { return; } if (HasBeenCanceled || didError) { // ONLY WORKS IF YOU AREN'T ALREADY SHOWING A CONSOLE! // https://stackoverflow.com/a/29274238/3938401 if (AttachConsole((uint)process.Id)) { SetConsoleCtrlHandler(null, true); try { GenerateConsoleCtrlEvent(ConsoleCtrlEvent.CTRL_C, process.SessionId); // ends the process process.Kill(); // process is canned, so OK to kill } catch { } finally { FreeConsole(); SetConsoleCtrlHandler(null, false); didFinishCancel = true; } return; } } if (e.Data.StartsWith("+ ") && e.Data.Trim() != "+") { didStartCompressingFile = true; currentFilePath = e.Data.Substring(2); if (currentItem != null && remainingBytes > 0) { CopiedBytesOfItem(currentItem, remainingBytes); bytesCopiedForItem[currentItem] += remainingBytes; if (!currentItem.IsDirectory) { FinishedCopyingItem?.Invoke(currentItem); } else { if (bytesCopiedForItem[currentItem] == currentItem.ByteSize) { FinishedCopyingItem?.Invoke(currentItem); } } } if (pathsToFolderFileItem.ContainsKey(currentFilePath)) { currentItem = pathsToFolderFileItem[currentFilePath]; } else { currentItem = null; } if (currentItem != null && !bytesCopiedForItem.ContainsKey(currentItem)) { bytesCopiedForItem[currentItem] = 0; } if (pathsToFileSize.ContainsKey(currentFilePath)) { sizeInBytes = remainingBytes = pathsToFileSize[currentFilePath]; } else { sizeInBytes = remainingBytes = 0; } } else if (e.Data.Contains("%") && didStartCompressingFile) { var percent = double.Parse(e.Data.Trim().Split('%')[0]); var actualPercent = percent - lastPercent; lastPercent = percent; var copiedBytes = Math.Floor((actualPercent / 100.0) * sizeInBytes); // floor -- would rather underestimate than overestimate if (currentItem != null) { CopiedBytesOfItem(currentItem, (ulong)copiedBytes); bytesCopiedForItem[currentItem] += (ulong)copiedBytes; } remainingBytes -= (ulong)copiedBytes; } else if (e.Data.Contains("Error:")) { nextMessageIsError = true; } else if (nextMessageIsError) { errorMessage = e.Data; didError = true; nextMessageIsError = false; } }); /** * Command line params: * -y (yes to prompts) * -ssw (Compresses files open for writing by another applications) * -bsp1 (output for progress to stdout) * -bse1 (output for errors to stdout) * -bb1 (log level 1) * -spf (Use fully qualified file paths) * -mx1 (compression level to fastest) * -v2g (split into 2 gb volumes -- https://superuser.com/a/184601) * -sccUTF-8 (set console output to UTF-8) * -p (set password for file) * */ var args = "-y -ssw -bsp1 -bse1 -bb1 -spf -mx1 -v2g -sccUTF-8"; if (UsesPasswordForCompressedFile) { var pass = Utilities.SecureStringToString(CompressedFilePassword); if (!string.IsNullOrWhiteSpace(pass)) { args = "-p" + pass + " " + args; // add password flag } } string inputPaths = string.Join("\n", quotedFilePaths); // to circumvent issue where inputPaths is too long for command line, need to write them to a file // and then load the file into 7z via command line params (@fileName as last param -- https://superuser.com/a/940894) var tmpFileName = Path.GetTempFileName(); using (StreamWriter sw = new StreamWriter(tmpFileName)) { sw.Write(inputPaths); } args = "a " + args + " \"" + destination + "\" @\"" + tmpFileName + "\""; // a = add file process.StartInfo.Arguments = args; process.Start(); process.BeginOutputReadLine(); //process.BeginErrorReadLine(); process.WaitForExit(); // make sure last item is handled properly if (!HasBeenCanceled && currentItem != null && remainingBytes > 0) { CopiedBytesOfItem(currentItem, remainingBytes); FinishedCopyingItem?.Invoke(currentItem); } if (HasBeenCanceled) { File.Delete(destination); } if (didError) { if (string.IsNullOrWhiteSpace(errorMessage)) { errorMessage = "Compression operation failed"; } throw new Exception(errorMessage); } }
private void ShowEditDirectoryExclusionsScreen(FolderFileItem item) { PushViewModel(new ExcludeFilesFoldersViewModel(this, item)); }
private void BackupPerformer_CalculatedBytesOfItem(FolderFileItem item, ulong bytes) { _totalBackupSize += bytes; }