Пример #1
0
        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));
                    }
                }
            }
        }
Пример #2
0
        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();
            });
Пример #3
0
        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));
            }
        }