Support writing data to a cpio file.

This commit is contained in:
Frederik Carlier
2017-04-29 22:46:46 +02:00
parent 4be40f1ecf
commit 74ca861d2b
5 changed files with 403 additions and 40 deletions

View File

@@ -104,6 +104,72 @@ namespace Packaging.Targets.IO
get { return this.entryDataLength == 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);
// 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);
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((int)data.Length);
for (int i = 0; i < paddingSize; i++)
{
this.stream.WriteByte(0);
}
}
/// <summary>
/// Writes the trailer entry.
/// </summary>
public void WriteTrailer()
{
this.Write(CpioHeader.Empty, "TRAILER!!!", new MemoryStream(Array.Empty<byte>()));
}
/// <summary>
/// Reads the next entry in the <see cref="CpioFile"/>.
/// </summary>

View File

@@ -15,7 +15,7 @@ namespace Packaging.Targets.IO
/// whether this archive is written with little-endian or big-endian integers,
/// or ASCII.
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 6)]
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 6)] // 0 through 5
private char[] signature;
/// <summary>
@@ -24,25 +24,25 @@ namespace Packaging.Targets.IO
/// refer to the same file. Programs that synthesize cpio archives
/// should be careful to set these to distinct values for each entry.
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 8)]
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 8)] // 6 through 13
private char[] ino;
/// <summary>
/// The mode specifies both the regular permissions and the file type.
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 8)]
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 8)] // 14 through 21
private char[] mode;
/// <summary>
/// The numeric user id of the owner.
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 8)]
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 8)] // 22 through 29
private char[] uid;
/// <summary>
/// The numeric group id of the owner.
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 8)]
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 8)] // 30 through 37
private char[] gid;
/// <summary>
@@ -50,7 +50,7 @@ namespace Packaging.Targets.IO
/// value of at least two here. Note that hardlinked files include
/// file data with every copy in the archive.
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 8)]
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 8)] // 38 through 45
private char[] nlink;
/// <summary>
@@ -60,7 +60,7 @@ namespace Packaging.Targets.IO
/// first followed by the least-significant 16 bits.Each of the two
/// 16 bit values are stored in machine-native byte order.
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 8)]
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 8)] // 46 through 53
private char[] mtime;
/// <summary>
@@ -68,13 +68,13 @@ namespace Packaging.Targets.IO
/// to four gigabyte file sizes.See mtime above for a description
/// of the storage of four-byte integers.
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 8)]
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 8)] // 54 through 61
private char[] filesize;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 8)]
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 8)] // 62 through 69
private char[] devMajor;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 8)]
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 8)] // 70 through 77
private char[] devMinor;
/// <summary>
@@ -82,135 +82,176 @@ namespace Packaging.Targets.IO
/// the associated device number. For all other entry types,
/// it should be set to zero by writers and ignored by readers.
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 8)]
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 8)] // 78 through 85
private char[] rdevMajor;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 8)]
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 8)] // 86 through 93
private char[] rdevMinor;
/// <summary>
/// The number of bytes in the pathname that follows the header.
/// This count includes the trailing NUL byte.
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 8)]
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 8)] // 94 through 101
private char[] namesize;
/// <summary>
/// This field is always set to zero by writers and ignored by readers.
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 8)]
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 8)] // 102 through 109
private char[] check;
/// <summary>
/// Gets the value of the <see cref="signature"/> field as a <see cref="string"/>.
/// Gets an empty <see cref="CpioHeader"/> entry.
/// </summary>
public static CpioHeader Empty
{
get
{
return new CpioHeader()
{
Check = 0,
DevMajor = 0,
DevMinor = 0,
FileSize = 0,
Gid = 0,
Ino = 0,
Mode = 0,
Mtime = 0,
NameSize = 0,
Nlink = 1,
RDevMajor = 0,
RDevMinor = 0,
Signature = "070701",
Uid = 0
};
}
}
/// <summary>
/// Gets or sets the value of the <see cref="signature"/> field as a <see cref="string"/>.
/// </summary>
public string Signature
{
get { return new string(this.signature); }
set { this.signature = value.ToCharArray(); }
}
/// <summary>
/// Gets the value of the <see cref="ino"/> field as a <see cref="uint"/>.
/// Gets or sets the value of the <see cref="ino"/> field as a <see cref="uint"/>.
/// </summary>
public uint Ino
{
get { return Convert.ToUInt32(new string(this.ino), 16); }
set { this.ino = value.ToString("x8").ToCharArray(); }
}
/// <summary>
/// Gets the value of the <see cref="mode"/> field as a <see cref="uint"/>.
/// Gets or sets the value of the <see cref="mode"/> field as a <see cref="uint"/>.
/// </summary>
public uint Mode
{
get { return Convert.ToUInt32(new string(this.mode), 16); }
set { this.mode = value.ToString("x8").ToCharArray(); }
}
/// <summary>
/// Gets the value of the <see cref="uid"/> field as a <see cref="uint"/>.
/// Gets or sets the value of the <see cref="uid"/> field as a <see cref="uint"/>.
/// </summary>
public uint Uid
{
get { return Convert.ToUInt32(new string(this.uid), 16); }
set { this.uid = value.ToString("x8").ToCharArray(); }
}
/// <summary>
/// Gets the value of the <see cref="gid"/> field as a <see cref="uint"/>.
/// Gets or sets the value of the <see cref="gid"/> field as a <see cref="uint"/>.
/// </summary>
public uint Gid
{
get { return Convert.ToUInt32(new string(this.gid), 16); }
set { this.gid = value.ToString("x8").ToCharArray(); }
}
/// <summary>
/// Gets the value of the <see cref="nlink"/> field as a <see cref="uint"/>.
/// Gets or sets the value of the <see cref="nlink"/> field as a <see cref="uint"/>.
/// </summary>
public uint Nlink
{
get { return Convert.ToUInt32(new string(this.nlink), 16); }
set { this.nlink = value.ToString("x8").ToCharArray(); }
}
/// <summary>
/// Gets the value of the <see cref="mtime"/> field as a <see cref="uint"/>.
/// Gets or sets the value of the <see cref="mtime"/> field as a <see cref="uint"/>.
/// </summary>
public uint Mtime
{
get { return Convert.ToUInt32(new string(this.mtime), 16); }
set { this.mtime = value.ToString("x8").ToCharArray(); }
}
/// <summary>
/// Gets the value of the <see cref="filesize"/> field as a <see cref="uint"/>.
/// Gets or sets the value of the <see cref="filesize"/> field as a <see cref="uint"/>.
/// </summary>
public uint FileSize
{
get { return Convert.ToUInt32(new string(this.filesize), 16); }
set { this.filesize = value.ToString("x8").ToCharArray(); }
}
/// <summary>
/// Gets the value of the <see cref="devMajor"/> field as a <see cref="uint"/>.
/// Gets or sets the value of the <see cref="devMajor"/> field as a <see cref="uint"/>.
/// </summary>
public uint DevMajor
{
get { return Convert.ToUInt32(new string(this.devMajor), 16); }
set { this.devMajor = value.ToString("x8").ToCharArray(); }
}
/// <summary>
/// Gets the value of the <see cref="devMinor"/> field as a <see cref="uint"/>.
/// Gets or sets the value of the <see cref="devMinor"/> field as a <see cref="uint"/>.
/// </summary>
public uint DevMinor
{
get { return Convert.ToUInt32(new string(this.devMinor), 16); }
set { this.devMinor = value.ToString("x8").ToCharArray(); }
}
/// <summary>
/// Gets the value of the <see cref="rdevMajor"/> field as a <see cref="uint"/>.
/// Gets or sets the value of the <see cref="rdevMajor"/> field as a <see cref="uint"/>.
/// </summary>
public uint RDevMajor
{
get { return Convert.ToUInt32(new string(this.rdevMajor), 16); }
set { this.rdevMajor = value.ToString("x8").ToCharArray(); }
}
/// <summary>
/// Gets the value of the <see cref="rdevMinor"/> field as a <see cref="uint"/>.
/// Gets or sets the value of the <see cref="rdevMinor"/> field as a <see cref="uint"/>.
/// </summary>
public uint RDevMinor
{
get { return Convert.ToUInt32(new string(this.rdevMinor), 16); }
set { this.rdevMinor = value.ToString("x8").ToCharArray(); }
}
/// <summary>
/// Gets the value of the <see cref="namesize"/> field as a <see cref="uint"/>.
/// Gets or sets the value of the <see cref="namesize"/> field as a <see cref="uint"/>.
/// </summary>
public uint NameSize
{
get { return Convert.ToUInt32(new string(this.namesize), 16); }
set { this.namesize = value.ToString("x8").ToCharArray(); }
}
/// <summary>
/// Gets the value of the <see cref="check"/> field as a <see cref="uint"/>.
/// Gets or sets the value of the <see cref="check"/> field as a <see cref="uint"/>.
/// </summary>
public uint Check
{
get { return Convert.ToUInt32(new string(this.check), 16); }
set { this.check = value.ToString("x8").ToCharArray(); }
}
}
}