예제 #1
0
        /// <summary>
        /// Adds a directory entry to the <see cref="CpioFile"/>.
        /// </summary>
        /// <param name="entry">
        /// The <see cref="ArchiveEntry"/> which represents the directory.
        /// </param>
        /// <param name="cpioFile">
        /// The <see cref="CpioFile"/> to which to add the directory entry.
        /// </param>
        public void AddDirectory(ArchiveEntry entry, CpioFile cpioFile)
        {
            // Write out an entry for the current directory
            CpioHeader directoryHeader = new CpioHeader()
            {
                Check        = 0,
                DevMajor     = 1,
                DevMinor     = 0,
                FileSize     = 0,
                Gid          = 0,
                Ino          = entry.Inode,
                FileMode     = entry.Mode,
                LastModified = entry.Modified,
                Nlink        = 1,
                RDevMajor    = 0,
                RDevMinor    = 0,
                Signature    = "070701",
                Uid          = 0,
                NameSize     = 0
            };

            var targetPath = entry.TargetPath;

            if (!targetPath.StartsWith("."))
            {
                targetPath = "." + targetPath;
            }

            cpioFile.Write(directoryHeader, targetPath, new MemoryStream(Array.Empty <byte>()));
        }
예제 #2
0
        /// <summary>
        /// Adds a file entry to a <see cref="CpioFile"/>.
        /// </summary>
        /// <param name="entry">
        /// The file entry to add.
        /// </param>
        /// <param name="cpioFile">
        /// The <see cref="CpioFile"/> to which to add the entry.
        /// </param>
        public void AddFile(ArchiveEntry entry, CpioFile cpioFile)
        {
            var targetPath = entry.TargetPath;

            if (!targetPath.StartsWith("."))
            {
                targetPath = "." + targetPath;
            }

            using (Stream fileStream = File.OpenRead(entry.SourceFilename))
            {
                CpioHeader cpioHeader = new CpioHeader()
                {
                    Check        = 0,
                    DevMajor     = 1,
                    DevMinor     = 0,
                    FileSize     = entry.FileSize,
                    Gid          = 0, // root
                    Uid          = 0, // root
                    Ino          = entry.Inode,
                    FileMode     = entry.Mode,
                    LastModified = entry.Modified,
                    NameSize     = (uint)entry.TargetPath.Length + 1,
                    Nlink        = 1,
                    RDevMajor    = 0,
                    RDevMinor    = 0,
                    Signature    = "070701",
                };

                cpioFile.Write(cpioHeader, targetPath, fileStream);
            }
        }
예제 #3
0
        /// <summary>
        /// Adds a symlink entry to a <see cref="CpioFile"/>.
        /// </summary>
        /// <param name="entry">
        /// The symlink entry to add.
        /// </param>
        /// <param name="cpioFile">
        /// The <see cref="CpioFile"/> to which to add the entry.
        /// </param>
        public void AddSymlink(ArchiveEntry entry, CpioFile cpioFile)
        {
            var targetPath = entry.TargetPath;

            if (!targetPath.StartsWith("."))
            {
                targetPath = "." + targetPath;
            }

            CpioHeader cpioHeader = new CpioHeader()
            {
                Check        = 0,
                DevMajor     = 1,
                DevMinor     = 0,
                FileSize     = entry.FileSize,
                Gid          = 0, // root
                Uid          = 0, // root
                Ino          = entry.Inode,
                FileMode     = entry.Mode,
                LastModified = entry.Modified,
                NameSize     = (uint)entry.TargetPath.Length + 1,
                Nlink        = 1,
                RDevMajor    = 0,
                RDevMinor    = 0,
                Signature    = "070701",
            };

            cpioFile.Write(cpioHeader, targetPath, new MemoryStream(Encoding.UTF8.GetBytes(entry.LinkTo)));
        }
예제 #4
0
        /// <summary>
        /// Reads the next entry in the <see cref="CpioFile"/>.
        /// </summary>
        /// <returns>
        /// <see langword="true"/> if more data is available; otherwise, <see langword="false"/>.
        /// </returns>
        public bool Read()
        {
            if (this.entryStream != null)
            {
                this.entryStream.Dispose();
            }

            if (this.stream.CanSeek)
            {
                // The file data is padded to a multiple of four bytes.
                var nextIndex = this.entryDataOffset + this.entryDataLength;
                nextIndex += PaddingSize((int)this.entryDataLength);
                this.stream.Seek(nextIndex, SeekOrigin.Begin);
            }
            else
            {
                byte[] buffer = new byte[PaddingSize((int)this.entryDataLength)];
                this.stream.Read(buffer, 0, buffer.Length);
            }

            this.entryHeader = this.stream.ReadStruct <CpioHeader>();

            if (this.entryHeader.Signature != "070701")
            {
                throw new InvalidDataException("The magic for the file entry is invalid");
            }

            byte[] nameBytes = new byte[this.entryHeader.NameSize];
            this.stream.Read(nameBytes, 0, nameBytes.Length);

            this.entryName = Encoding.UTF8.GetString(nameBytes, 0, (int)this.entryHeader.NameSize - 1);

            // The pathname is followed by NUL bytes so that the total size of the fixed
            // header plus pathname is a multiple of four.
            var headerSize  = Marshal.SizeOf <CpioHeader>() + nameBytes.Length;
            var paddingSize = PaddingSize(headerSize);

            if (nameBytes.Length < paddingSize)
            {
                nameBytes = new byte[paddingSize];
            }

            this.stream.Read(nameBytes, 0, paddingSize);

            this.entryDataOffset = this.stream.Position;
            this.entryDataLength = this.entryHeader.FileSize;
            this.entryStream     = new SubStream(this.stream, this.entryDataOffset, this.entryDataLength, leaveParentOpen: true);

            return(this.entryName != "TRAILER!!!");
        }
예제 #5
0
        /// <summary>
        /// Adds an entry to the <see cref="CpioFile"/>
        /// </summary>
        /// <param name="header">
        /// A <see cref="CpioHeader"/> with the item metaata. The <see cref="CpioHeader.Signature"/>,
        /// <see cref="CpioHeader.NameSize"/> and <see cref="CpioHeader.Filesize"/> values are overwritten.
        /// </param>
        /// <param name="name">
        /// The file name of the entry.
        /// </param>
        /// <param name="data">
        /// A <see cref="Stream"/> which contains the file data.
        /// </param>
        public void Write(CpioHeader header, string name, Stream data)
        {
            if (name == null)
            {
                throw new ArgumentNullException(nameof(name));
            }

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

            byte[] nameBytes = Encoding.UTF8.GetBytes(name);

            // We make sure the magic and size fields have the correct values. All other fields
            // are the responsibility of the caller.
            header.Signature = "070701";
            header.NameSize  = (uint)(nameBytes.Length + 1);
            header.FileSize  = (uint)data.Length;

            this.Stream.WriteStruct(header);
            this.Stream.Write(nameBytes, 0, nameBytes.Length);
            this.Stream.WriteByte(0); // Trailing 0

            // The pathname is followed by NUL bytes so that the total size of the fixed
            // header plus pathname is a multiple of four.
            var headerSize  = Marshal.SizeOf <CpioHeader>() + (int)header.NameSize;
            var paddingSize = PaddingSize(4, headerSize);

            for (int i = 0; i < paddingSize; i++)
            {
                this.Stream.WriteByte(0);
            }

            data.Position = 0;
            data.CopyTo(this.Stream);

            // The file data is padded to a multiple of four bytes.
            paddingSize = PaddingSize(4, (int)data.Length);

            for (int i = 0; i < paddingSize; i++)
            {
                this.Stream.WriteByte(0);
            }
        }
예제 #6
0
        /// <summary>
        /// Reads the next entry in the <see cref="CpioFile"/>.
        /// </summary>
        /// <returns>
        /// <see langword="true"/> if more data is available; otherwise, <see langword="false"/>.
        /// </returns>
        public override bool Read()
        {
            if (this.EntryStream != null)
            {
                this.EntryStream.Dispose();
            }

            this.Align(4);

            this.entryHeader = this.Stream.ReadStruct <CpioHeader>();
            this.FileHeader  = this.entryHeader;

            if (this.entryHeader.Signature != "070701")
            {
                throw new InvalidDataException("The magic for the file entry is invalid");
            }

            byte[] nameBytes = new byte[this.entryHeader.NameSize];
            this.Stream.Read(nameBytes, 0, nameBytes.Length);

            this.FileName = Encoding.UTF8.GetString(nameBytes, 0, (int)this.entryHeader.NameSize - 1);

            // The pathname is followed by NUL bytes so that the total size of the fixed
            // header plus pathname is a multiple of four.
            var headerSize  = Marshal.SizeOf <CpioHeader>() + nameBytes.Length;
            var paddingSize = PaddingSize(4, headerSize);

            if (nameBytes.Length < paddingSize)
            {
                nameBytes = new byte[paddingSize];
            }

            this.Stream.Read(nameBytes, 0, paddingSize);

            this.entryDataOffset = this.Stream.Position;
            this.entryDataLength = this.entryHeader.FileSize;
            this.EntryStream     = new SubStream(this.Stream, this.entryDataOffset, this.entryDataLength, leaveParentOpen: true);

            return(this.FileName != "TRAILER!!!");
        }