예제 #1
0
        /// <summary>
        ///     Writes a directory and its contents to the archive. This method is recursive.
        /// </summary>
        /// <param name="path">The path to the directory.</param>
        /// <param name="basePath">The base path  which to remove from the written path names.</param>
        /// <param name="skipDirectory">if set to <c>true</c> skip the directory itself.</param>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="path" /> or <paramref name="basePath" /> is null.</exception>
        /// <exception cref="DirectoryNotFoundException">The specified directory could not be found.</exception>
        private void WriteDirectoryInternal(string path, string basePath, bool skipDirectory)
        {
            if (path == null)
            {
                throw new ArgumentNullException(nameof(path));
            }
            if (basePath == null)
            {
                throw new ArgumentNullException(nameof(basePath));
            }

            AssertNotDisposed();

            // Make sure the directory exists.
            path = PathHelper.Normalize(path);

            if (!Directory.Exists(path))
            {
                throw new DirectoryNotFoundException("The specified directory could not be found.");
            }

            // Write the directory to the archive.
            if (!skipDirectory)
            {
                var dirInfo = new DirectoryInfo(path);
                WriteDirectoryEntry(path.Substring(basePath.Length), dirInfo.LastWriteTimeUtc);
            }

            // Write the files in the directory to the archive.
            foreach (var filePath in Directory.GetFiles(path))
            {
                var fileInfo = new FileInfo(filePath);

                WriteFileEntry(filePath.Substring(basePath.Length), fileInfo.Length, fileInfo.LastWriteTimeUtc, null, null, new FileModeGroup("777"));
                WriteStream(fileInfo.OpenRead());
            }

            // Write directories in the directory to the archive.
            foreach (var directoryPath in Directory.GetDirectories(path))
            {
                WriteDirectoryInternal(directoryPath, basePath, false);
            }
        }
예제 #2
0
        /// <summary>
        ///     Writes the directory with the specified <paramref name="path" /> and its contents to the archive.
        /// </summary>
        /// <param name="path">The path.</param>
        /// <param name="skipTopLevelDirectory">
        ///     If set to <c>true</c>, only the contents of the directory with the specified
        ///     <paramref name="path" /> are written to the archive.
        /// </param>
        /// <exception cref="System.ArgumentNullException">Thrown if <paramref name="path" /> is null.</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException">The specified directory could not be found.</exception>
        public void WriteDirectory(string path, bool skipTopLevelDirectory)
        {
            if (path == null)
            {
                throw new ArgumentNullException(nameof(path));
            }

            AssertNotDisposed();

            // Make sure the directory exists.
            path = PathHelper.Normalize(path);

            if (!Directory.Exists(path))
            {
                throw new DirectoryNotFoundException("The specified directory could not be found.");
            }

            // Compute the base path.
            var basePath = skipTopLevelDirectory ? path : Directory.GetParent(path).FullName;

            basePath = PathHelper.AppendDirectorySeparator(basePath);

            WriteDirectoryInternal(path, basePath, skipTopLevelDirectory);
        }
예제 #3
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.");
                }
            }
        }