Esempio n. 1
0
        /// <summary>
        /// Pass in either basedir or s, but not both.
        /// In other words, you can extract to a stream or to a directory (filesystem), but not both!
        /// The Password param is required for encrypted entries.
        /// </summary>
        private static void InternalExtractToBaseDir(this ZipEntry zipEntry, string baseDir, string password)
        {
            if (baseDir == null)
            {
                throw new ArgumentNullException("baseDir");
            }

            var zipFile = zipEntry.GetZipFile();

            // workitem 10355
            if (zipFile == null)
            {
                throw new InvalidOperationException("Use Extract() only with ZipFile.");
            }

            // get the full filename
            var f = ZipEntryInternal.NameInArchive(zipEntry.FileName);
            var targetFileName = zipFile.FlattenFoldersOnExtract
                ? Path.Combine(baseDir, Path.GetFileName(f))
                : Path.Combine(baseDir, f);

            // workitem 10639
            targetFileName = targetFileName.Replace('/', PortablePath.DirectorySeparatorChar);
            var fullTargetPath = ZipFileExtensions.GetFullPath(targetFileName);

            var fileExistsBeforeExtraction = false;

            try
            {
                // check if it is a directory
                if (zipEntry.IsDirectory || zipEntry.FileName.EndsWith("/"))
                {
                    CreateDirectory(fullTargetPath);
                    goto ExitTry; // all done, caller will return
                }

                // it is a file, so start the extraction
                if (FileSystem.Current.GetFileFromPathAsync(fullTargetPath).ExecuteSync() != null)
                {
                    fileExistsBeforeExtraction = true;
                    int rc = zipEntry.CheckExtractExistingFile(baseDir, targetFileName);
                    if (rc == 2)
                    {
                        goto ExitTry;          // cancel
                    }
                    if (rc == 1)
                    {
                        return;          // do not overwrite
                    }
                }

                // set up the output stream
                var tmpName = Path.GetRandomFileName();
                var tmpPath = Path.Combine(Path.GetDirectoryName(fullTargetPath), tmpName);
                var dirName = Path.GetDirectoryName(tmpPath);

                // ensure the target path exists
                var dir = CreateDirectory(dirName, true);

                // extract
                var file = dir.CreateFileAsync(tmpPath, CreationCollisionOption.ReplaceExisting).ExecuteSync();
                using (var output = file.OpenAsync(FileAccess.ReadAndWrite).ExecuteSync())
                {
                    zipEntry.ExtractWithPassword(output, password);
                }
                MoveFileInPlace(fileExistsBeforeExtraction, fullTargetPath, tmpPath);

                ExitTry :;
            }
            catch (Exception)
            {
                zipEntry.SetIOOperationCanceled(true);
                throw;
            }
            finally
            {
                if (zipEntry.IsIOOperationCanceled() && targetFileName != null)
                {
                    // An exception has occurred. If the file exists, check
                    // to see if it existed before we tried extracting.  If
                    // it did not, attempt to remove the target file. There
                    // is a small possibility that the existing file has
                    // been extracted successfully, overwriting a previously
                    // existing file, and an exception was thrown after that
                    // but before final completion (setting times, etc). In
                    // that case the file will remain, even though some
                    // error occurred.  Nothing to be done about it.
                    var file = FileSystem.Current.GetFileFromPathAsync(fullTargetPath).ExecuteSync();
                    if (file != null && !fileExistsBeforeExtraction)
                    {
                        file.DeleteAsync();
                    }
                }
            }
        }