Skip to content

Commit

Permalink
Prepare internal cpio parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
teplofizik committed Sep 5, 2022
1 parent 46a2921 commit 1d57fd7
Show file tree
Hide file tree
Showing 9 changed files with 507 additions and 3 deletions.
81 changes: 81 additions & 0 deletions NyaFs/Filesystem/Cpio/CpioFsReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using Extension.Array;
using Extension.Packet;
using NyaFs.Filesystem.Universal;
using System;
using System.Collections.Generic;
using System.Text;

namespace NyaFs.Filesystem.Cpio
{
class CpioFsReader : RawPacket, Universal.IFilesystemReader
{
private List<Types.CpioNode> Nodes = new List<Types.CpioNode>();

public CpioFsReader(byte[] Data) : base(Data) { Init(); }

public CpioFsReader(string Filename) : this(System.IO.File.ReadAllBytes(Filename)) { }

private void Init()
{
long Offset = 0;
while (Offset < Data.Length)
{
var FI = new Types.CpioFileInfo(Data, Offset);

if (FI.IsCorrectMagic)
{
var Raw = Data.ReadArray(Offset, FI.FullFileBlockSize);
var F = new Types.CpioNode(Raw);

if (!FI.IsTrailer)
{
Nodes.Add(F);

Offset += FI.FullFileBlockSize;
}
}
else
break;
}
}

private string UnifyPath(string Path)
{
if (Path.Length > 0)
return (Path[0] == '/') ? Path.Substring(1) : Path;
else
return Path;
}

byte[] IFilesystemReader.Read(string Path)
{
foreach (var N in Nodes)
{
if (UnifyPath(N.Path) == UnifyPath(Path))
return N.Content;
}

return null;
}

FilesystemEntry[] IFilesystemReader.ReadDir(string Path)
{
var Res = new List<FilesystemEntry>();
Path = UnifyPath(Path);
foreach (var N in Nodes)
{
var UPath = UnifyPath(N.Path);
int Pos = UPath.IndexOf(Path);
if(Pos == 0)
{
Pos = Pos + Path.Length + 1;
if(UPath.IndexOf('/', Pos) < 0)
{
Res.Add(new FilesystemEntry(N.FsType, UPath, N.UserId, N.GroupId, N.HexMode, Convert.ToUInt32(N.Content.Length)));
}
}
}
return Res.ToArray();
}
}
}
81 changes: 81 additions & 0 deletions NyaFs/Filesystem/Cpio/Types/CpioFileInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using Extension.Array;
using System;
using System.Collections.Generic;
using System.Text;

namespace NyaFs.Filesystem.Cpio.Types
{
class CpioFileInfo
{
private byte[] Raw;
private long Offset;

public CpioFileInfo(byte[] Raw, long Offset)
{
this.Raw = Raw;
this.Offset = Offset;
}

public bool IsCorrectMagic => Magic == "070701";

private UInt32 GetAsciiValue(long HeaderOffset, int Size)
{
var Text = Raw.ReadString(Offset + HeaderOffset, Size);
return Convert.ToUInt32(Text, 16);
}

/// <summary>
/// The string 070701 for new ASCII, the string 070702 for new ASCII with CRC
/// </summary>
public string Magic => Raw.ReadString(Offset, 6);

// https://developer.adobe.com/experience-manager/reference-materials/6-4/javadoc/org/apache/commons/compress/archivers/cpio/CpioArchiveEntry.html
public UInt32 INode => GetAsciiValue(6, 8);
public UInt32 Mode => GetAsciiValue(14, 8);
public UInt32 UserId => GetAsciiValue(22, 8);
public UInt32 GroupId => GetAsciiValue(30, 8);
public UInt32 NumLink => GetAsciiValue(38, 8);
public UInt32 ModificationTime => GetAsciiValue(46, 8);

/// <summary>
/// must be 0 for FIFOs and directories
/// </summary>
public UInt32 FileSize => GetAsciiValue(54, 8);


public UInt32 Major => GetAsciiValue(62, 8);
public UInt32 Minor => GetAsciiValue(70, 8);

/// <summary>
/// only valid for chr and blk special files
/// </summary>
public UInt32 RMajor => GetAsciiValue(78, 8);

/// <summary>
/// only valid for chr and blk special files
/// </summary>
public UInt32 RMinor => GetAsciiValue(86, 8);

/// <summary>
/// count includes terminating NUL in pathname
/// </summary>
public UInt32 NameSize => GetAsciiValue(94, 8);

/// <summary>
/// 0 for "new" portable format; for CRC format, the sum of all the bytes in the file
/// </summary>
public UInt32 Check => GetAsciiValue(102, 8);

public bool IsTrailer => Path == "TRAILER!!!";

public long PathPadding => (110L + NameSize).MakeSizeAligned(4);
public long HeaderWithPathSize => 110 + NameSize + PathPadding;

public string Path => Raw.ReadString(Offset + 110, NameSize - 1);

public long FilePadding => (HeaderWithPathSize + FileSize).MakeSizeAligned(4);

public long FullFileBlockSize => HeaderWithPathSize + FileSize + FilePadding;

}
}
17 changes: 17 additions & 0 deletions NyaFs/Filesystem/Cpio/Types/CpioModeFileType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace NyaFs.Filesystem.Cpio.Types
{
public enum CpioModeFileType {
C_ISDIR = 0x4000, // Directory
C_ISFIFO = 0x1000, // FIFO
C_ISREG = 0x8000, // Regular file
C_ISBLK = 0x6000, // Block special
C_ISCHR = 0x2000, // Character special
C_ISCTG = 0x9000, // Reserved
C_ISLNK = 0xA000, // Symbolic link.
C_ISSOCK = 0xC000, // Socket
}
}
23 changes: 23 additions & 0 deletions NyaFs/Filesystem/Cpio/Types/CpioModeFlags.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace NyaFs.Filesystem.Cpio.Types
{
[Flags]
public enum CpioModeFlags
{
C_IRUSR = 0000400, // Read by owner
C_IWUSR = 0000200, // Write by owner
C_IXUSR = 0000100, // Execute by owner
C_IRGRP = 0000040, // Read by group.
C_IWGRP = 0000020, // Write by group
C_IXGRP = 0000010, // Execute by group
C_IROTH = 0000004, // Read by others
C_IWOTH = 0000002, // Write by others
C_IXOTH = 0000001, // Execute by others
C_ISUID = 0004000, // Set user ID
C_ISGID = 0002000, // Set group ID
C_ISVTX = 0001000 // On directories, restricted deletion flag
}
}
Loading

0 comments on commit 1d57fd7

Please sign in to comment.