/// <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>())); }
/// <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); } }
/// <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))); }
/// <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!!!"); }
/// <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); } }
/// <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!!!"); }