コード例 #1
0
        /// <summary>
        /// Asynchronously adds a file to the tar archive.
        /// </summary>
        /// <param name="filename">
        /// The name of the file to add.
        /// </param>
        /// <param name="fileMode">
        /// The <see cref="LinuxFileMode"/> of the file to add.
        /// </param>
        /// <param name="lastModified">
        /// The date and time at which the file was last modified.
        /// </param>
        /// <param name="entryStream">
        /// A <see cref="Stream"/> which represents the data to add.
        /// </param>
        /// <param name="cancellationToken">
        /// A <see cref="CancellationToken"/> which can be used to cancel the asynchronous operation.
        /// </param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        public async Task AddFileAsync(string filename, LinuxFileMode fileMode, DateTimeOffset lastModified, Stream entryStream, CancellationToken cancellationToken)
        {
            if (filename == null)
            {
                throw new ArgumentNullException(nameof(filename));
            }

            if (entryStream == null)
            {
                throw new ArgumentNullException(nameof(entryStream));
            }

            var header = new TarHeader()
            {
                FileName     = filename,
                FileMode     = fileMode,
                UserId       = 0,
                GroupId      = 0,
                FileSize     = (uint)entryStream.Length,
                LastModified = lastModified,
                TypeFlag     = TarTypeFlag.RegType,
                LinkName     = string.Empty,
                Magic        = "ustar\0",
                Version      = 0,
                UserName     = string.Empty,
                GroupName    = string.Empty,
                DevMajor     = 0,
                DevMinor     = 0,
                Prefix       = string.Empty,
            };

            header.Write(this.headerBuffer);

            // Write the header for the current tar entry
            await this.tarStream.WriteAsync(this.headerBuffer, cancellationToken).ConfigureAwait(false);

            // Write the actual entry
            await entryStream.CopyToAsync(this.tarStream, cancellationToken);

            // Align the stream
            if (entryStream.Length % 512 != 0)
            {
                var length = 512 - ((int)entryStream.Length % 512);
                var buffer = this.headerBuffer.AsMemory(0, length);

                buffer.Span.Clear();
                await this.tarStream.WriteAsync(buffer, cancellationToken).ConfigureAwait(false);
            }

            await this.tarStream.FlushAsync(cancellationToken).ConfigureAwait(false);
        }
コード例 #2
0
        public static void WriteEntry(Stream output, string name, LinuxFileMode mode, Stream data)
        {
            var hdr = new ArHeader
            {
                EndChar      = "`\n",
                FileMode     = mode,
                FileName     = name,
                FileSize     = (uint)data.Length,
                GroupId      = 0,
                OwnerId      = 0,
                LastModified = DateTimeOffset.UtcNow
            };

            WriteEntry(output, hdr, data);
        }
コード例 #3
0
        /// <summary>
        /// Reads data from a <see cref="Span{T}"/>.
        /// </summary>
        /// <param name="buffer">
        /// A buffer which contains the header data.
        /// </param>
        /// <returns>
        /// The number of bytes read.
        /// </returns>
        public int ReadFrom(Span <byte> buffer)
        {
            this.Signature = ReadOctalString(buffer.Slice(0, 6));
            this.Dev       = ReadOctalString(buffer.Slice(6, 6));
            this.Ino       = ReadOctalString(buffer.Slice(12, 6));
            this.Mode      = (LinuxFileMode)ReadOctalString(buffer.Slice(18, 6));
            this.Uid       = ReadOctalString(buffer.Slice(24, 6));
            this.Gid       = ReadOctalString(buffer.Slice(30, 6));
            this.Nlink     = ReadOctalString(buffer.Slice(36, 6));
            this.Rdev      = ReadOctalString(buffer.Slice(42, 6));
            this.Mtime     = DateTimeOffset.FromUnixTimeSeconds(ReadOctalString(buffer.Slice(48, 11)));
            this.Namesize  = ReadOctalString(buffer.Slice(59, 6));
            this.Filesize  = ReadOctalString(buffer.Slice(65, 11));

            return(Size);
        }
コード例 #4
0
        public Collection <ArchiveEntry> FromLinuxFolders(ITaskItem[] metadata)
        {
            Collection <ArchiveEntry> value = new Collection <ArchiveEntry>();

            // This can be null if the user did not define any folders.
            // In that case: nothing to do.
            if (metadata != null)
            {
                foreach (var folder in metadata)
                {
                    var path = folder.ItemSpec.Replace("\\", "/");

                    // Default file mode
                    LinuxFileMode mode = LinuxFileMode.S_IXOTH | LinuxFileMode.S_IROTH | LinuxFileMode.S_IXGRP | LinuxFileMode.S_IRGRP | LinuxFileMode.S_IXUSR | LinuxFileMode.S_IWUSR | LinuxFileMode.S_IRUSR | LinuxFileMode.S_IFDIR;
                    mode = this.GetFileMode(path, folder, mode);

                    // Write out an entry for the directory
                    ArchiveEntry directoryEntry = new ArchiveEntry()
                    {
                        FileSize          = 0x00001000,
                        Sha256            = Array.Empty <byte>(),
                        Mode              = mode,
                        Modified          = DateTime.Now,
                        Group             = folder.GetGroup(),
                        Owner             = folder.GetOwner(),
                        Inode             = this.inode++,
                        TargetPath        = path,
                        LinkTo            = string.Empty,
                        RemoveOnUninstall = folder.GetRemoveOnUninstall()
                    };

                    value.Add(directoryEntry);
                }
            }

            return(value);
        }
コード例 #5
0
        /// <summary>
        /// Gets the file mode for a file or directory entry, based on a default value
        /// and the value of the LinuxFileMode attribute, if set.
        /// </summary>
        /// <param name="name">
        /// The name (path) of the entry. Only used in error messages.
        /// </param>
        /// <param name="metadata">
        /// The metadata for the current entry.
        /// </param>
        /// <param name="defaultMode">
        /// The default mode. This mode is used to determine the file type (directory/file),
        /// and when no LinuxFileMode value is specified.
        /// </param>
        /// <returns>
        /// The <see cref="LinuxFileMode"/> for the current entry.
        /// </returns>
        private LinuxFileMode GetFileMode(string name, ITaskItem metadata, LinuxFileMode defaultMode)
        {
            LinuxFileMode mode = defaultMode;
            LinuxFileMode defaultFileTypeMask = defaultMode & LinuxFileMode.FileTypeMask;

            // If the user has chosen to override the file node, respect that
            var overridenFileMode = metadata?.GetLinuxFileMode();

            if (overridenFileMode != null)
            {
                // We expect the user to specify the file mode in its octal representation,
                // such as 755. We don't expect users to specify the higher bits (e.g.
                // S_IFREG).
                try
                {
                    mode = (LinuxFileMode)Convert.ToUInt32(overridenFileMode, 8);

                    LinuxFileMode fileType = mode & LinuxFileMode.FileTypeMask;

                    if (fileType != LinuxFileMode.None && fileType != defaultFileTypeMask)
                    {
                        this.Log.LogWarning($"An invalid file type of '{fileType}' has been set for file '{name}'. The file type will be reset to {defaultFileTypeMask}.");
                    }

                    // Override the file type mask and hardcode it to the file type mask from the default mode.
                    // In practice this will ensure the S_IFREG or S_IFDIR flag is set.
                    mode = (mode & ~LinuxFileMode.FileTypeMask) | defaultFileTypeMask;
                }
                catch (Exception)
                {
                    throw new Exception($"Could not parse the file mode '{overridenFileMode}' for file '{name}'. Make sure to set the LinuxFileMode attriubute to an octal representation of a Unix file mode.");
                }
            }

            return(mode);
        }
コード例 #6
0
 public static void WriteEntry(Stream output, string name, LinuxFileMode mode, string data)
 => WriteEntry(output, name, mode, new MemoryStream(Encoding.UTF8.GetBytes(data)));