Esempio n. 1
0
        /// <summary>
        ///     Writes the remaining contents of the archive to the directory at the specified <paramref name="targetPath" />.
        /// </summary>
        /// <param name="targetPath">The path to the directory to which to write the remaining contents of the archive.</param>
        /// <param name="skipTopLevelDirectory">if set to <c>true</c>, the top level directory in the archive is skipped.</param>
        /// <exception cref="System.ArgumentNullException">Thrown if <paramref name="targetPath" /> is null.</exception>
        /// <exception cref="TarException">
        ///     Thrown when an entry attempts to write outside of the target path by using parent path
        ///     (../) operators.
        /// </exception>
        /// <exception cref="NotSupportedException">Thrown when an entry contains unsupported flags.</exception>
        public void WriteToDirectory(string targetPath, bool skipTopLevelDirectory)
        {
            if (targetPath == null)
            {
                throw new ArgumentNullException(nameof(targetPath));
            }

            AssertNotDisposed();

            // Collapse target directory.
            targetPath = PathHelper.Normalize(targetPath);
            targetPath = PathHelper.AppendDirectorySeparator(targetPath);

            // Read all files in the archive.
            TarEntryStream stream;

            while ((stream = Next()) != null)
            {
                // Convert all directory separators to the local machine's prefered form.
                var fileName = PathHelper.PartialNormalize(stream.Header.Name);

                // Trim leading directory separators.
                fileName = PathHelper.TrimLeadingDirectorySeparators(fileName);

                // Skip the top level directory.
                if (skipTopLevelDirectory)
                {
                    fileName = PathHelper.RemoveTopLevelFolderFromRelativePath(fileName);

                    // Skip if it was the top level.
                    if (fileName == null)
                    {
                        continue;
                    }
                }

                var filePath = PathHelper.Normalize(Path.Combine(targetPath, fileName));

                if (!filePath.StartsWith(targetPath))
                {
                    throw new TarException($"{Path.Combine(targetPath, fileName)} is outside of the specified target directory.");
                }

                // If it's a directory entry.
                if (fileName.EndsWith(Path.DirectorySeparatorChar.ToString()) || stream.Header.Flag == TarHeaderFlag.Directory)
                {
                    Directory.CreateDirectory(filePath);

                    // TODO: FIXME None of the below set the "last modified" date on windows.
                    Directory.SetCreationTimeUtc(filePath, stream.Header.LastModification.Value);
                    Directory.SetLastWriteTimeUtc(filePath, stream.Header.LastModification.Value);
                    Directory.SetLastAccessTimeUtc(filePath, stream.Header.LastModification.Value);
                }

                // If it's a file entry.
                else if (stream.Header.Flag == TarHeaderFlag.NormalFile || stream.Header.Flag == TarHeaderFlag.NormalFileAlt)
                {
                    using (var fileStream = File.Open(filePath, FileMode.Create, FileAccess.Write))
                    {
                        stream.CopyTo(fileStream);
                    }

                    File.SetCreationTimeUtc(filePath, stream.Header.LastModification.Value);
                    File.SetLastWriteTimeUtc(filePath, stream.Header.LastModification.Value);
                }
                else
                {
                    throw new NotSupportedException(
                              $"File entries of type '{stream.Header.Flag}' are not supported by WriteToDirectory at this time.");
                }
            }
        }