mirror of
https://github.com/aaru-dps/Aaru.git
synced 2026-04-06 14:05:08 +00:00
[efs] Add missing on-disk structures.
This commit is contained in:
@@ -32,8 +32,63 @@ namespace Aaru.Filesystems;
|
||||
/// <summary>Implements identification for the SGI Extent FileSystem</summary>
|
||||
public sealed partial class EFS
|
||||
{
|
||||
const uint EFS_MAGIC = 0x00072959;
|
||||
/// <summary>Original EFS magic number.</summary>
|
||||
const uint EFS_MAGIC = 0x00072959;
|
||||
|
||||
/// <summary>New EFS magic number (IRIX 3.3+).</summary>
|
||||
const uint EFS_MAGIC_NEW = 0x0007295A;
|
||||
|
||||
/// <summary>Filesystem type identifier.</summary>
|
||||
const string FS_TYPE = "efs";
|
||||
|
||||
/// <summary>Number of directly mappable extents in an inode.</summary>
|
||||
const int EFS_DIRECTEXTENTS = 12;
|
||||
|
||||
/// <summary>Maximum number of basic blocks in an indirect extent.</summary>
|
||||
const int EFS_MAXINDIRBBS = 64;
|
||||
|
||||
/// <summary>Maximum number of extents per inode.</summary>
|
||||
const int EFS_MAXEXTENTS = 32767;
|
||||
|
||||
/// <summary>Maximum length of a single extent in basic blocks (256 - 8).</summary>
|
||||
const int EFS_MAXEXTENTLEN = 248;
|
||||
|
||||
/// <summary>Inode size in bytes (128).</summary>
|
||||
const int EFS_INODE_SIZE = 128;
|
||||
|
||||
/// <summary>Inode size shift (log2 of 128 = 7).</summary>
|
||||
const int EFS_EFSINOSHIFT = 7;
|
||||
|
||||
/// <summary>Basic block size (512 bytes).</summary>
|
||||
const int EFS_BBSIZE = 512;
|
||||
|
||||
/// <summary>Directory block size (same as basic block).</summary>
|
||||
const int EFS_DIRBSIZE = EFS_BBSIZE;
|
||||
|
||||
/// <summary>Directory block magic number.</summary>
|
||||
const ushort EFS_DIRBLK_MAGIC = 0xBEEF;
|
||||
|
||||
/// <summary>Maximum filename length (255).</summary>
|
||||
const int EFS_MAXNAMELEN = 255;
|
||||
|
||||
/// <summary>Minimum directory entry size (6 bytes: 4 for inum + 1 for namelen + 1 for min name).</summary>
|
||||
const int EFS_DENTSIZE = 6;
|
||||
|
||||
/// <summary>Size of directory block header.</summary>
|
||||
const int EFS_DIRBLK_HEADERSIZE = 4;
|
||||
|
||||
/// <summary>Superblock location in basic blocks.</summary>
|
||||
const int EFS_SUPERBB = 1;
|
||||
|
||||
/// <summary>Bitmap location in basic blocks (for non-grown filesystems).</summary>
|
||||
const int EFS_BITMAPBB = 2;
|
||||
|
||||
/// <summary>Root inode number.</summary>
|
||||
const uint EFS_ROOTINO = 2;
|
||||
|
||||
/// <summary>Number of inodes per basic block.</summary>
|
||||
const int EFS_INOPBB = EFS_BBSIZE / EFS_INODE_SIZE;
|
||||
|
||||
/// <summary>Maximum inline data size (96 bytes = 12 extents * 8 bytes).</summary>
|
||||
const int EFS_MAX_INLINE = EFS_DIRECTEXTENTS * 8;
|
||||
}
|
||||
135
Aaru.Filesystems/EFS/Enums.cs
Normal file
135
Aaru.Filesystems/EFS/Enums.cs
Normal file
@@ -0,0 +1,135 @@
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Enums.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Extent File System plugin
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2026 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Aaru.Filesystems;
|
||||
|
||||
public sealed partial class EFS
|
||||
{
|
||||
#region Nested type: FileType
|
||||
|
||||
/// <summary>EFS file type flags (from di_mode).</summary>
|
||||
[Flags]
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
enum FileType : ushort
|
||||
{
|
||||
/// <summary>Type mask.</summary>
|
||||
IFMT = 0xF000,
|
||||
/// <summary>Named pipe (FIFO).</summary>
|
||||
IFIFO = 0x1000,
|
||||
/// <summary>Character special device.</summary>
|
||||
IFCHR = 0x2000,
|
||||
/// <summary>Character special link.</summary>
|
||||
IFCHRLNK = 0x3000,
|
||||
/// <summary>Directory.</summary>
|
||||
IFDIR = 0x4000,
|
||||
/// <summary>Block special device.</summary>
|
||||
IFBLK = 0x6000,
|
||||
/// <summary>Block special link.</summary>
|
||||
IFBLKLNK = 0x7000,
|
||||
/// <summary>Regular file.</summary>
|
||||
IFREG = 0x8000,
|
||||
/// <summary>Symbolic link.</summary>
|
||||
IFLNK = 0xA000,
|
||||
/// <summary>Socket.</summary>
|
||||
IFSOCK = 0xC000
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: FilePermissions
|
||||
|
||||
/// <summary>EFS file permission flags (from di_mode).</summary>
|
||||
[Flags]
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
enum FilePermissions : ushort
|
||||
{
|
||||
/// <summary>Set user ID on execution.</summary>
|
||||
ISUID = 0x0800,
|
||||
/// <summary>Set group ID on execution.</summary>
|
||||
ISGID = 0x0400,
|
||||
/// <summary>Sticky bit (save text / restricted deletion).</summary>
|
||||
ISVTX = 0x0200,
|
||||
/// <summary>Owner read permission.</summary>
|
||||
IRUSR = 0x0100,
|
||||
/// <summary>Owner write permission.</summary>
|
||||
IWUSR = 0x0080,
|
||||
/// <summary>Owner execute permission.</summary>
|
||||
IXUSR = 0x0040,
|
||||
/// <summary>Group read permission.</summary>
|
||||
IRGRP = 0x0020,
|
||||
/// <summary>Group write permission.</summary>
|
||||
IWGRP = 0x0010,
|
||||
/// <summary>Group execute permission.</summary>
|
||||
IXGRP = 0x0008,
|
||||
/// <summary>Others read permission.</summary>
|
||||
IROTH = 0x0004,
|
||||
/// <summary>Others write permission.</summary>
|
||||
IWOTH = 0x0002,
|
||||
/// <summary>Others execute permission.</summary>
|
||||
IXOTH = 0x0001
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: InodeVersion
|
||||
|
||||
/// <summary>EFS inode version values.</summary>
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
enum InodeVersion : byte
|
||||
{
|
||||
/// <summary>Standard EFS inode.</summary>
|
||||
EFS_IVER_EFS = 0,
|
||||
/// <summary>AFS special inode.</summary>
|
||||
EFS_IVER_AFSSPEC = 1,
|
||||
/// <summary>AFS normal inode.</summary>
|
||||
EFS_IVER_AFSINO = 2
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: DirtyFlags
|
||||
|
||||
/// <summary>Values for sb_dirty field indicating filesystem state.</summary>
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
enum DirtyFlags : short
|
||||
{
|
||||
/// <summary>Filesystem is clean and unmounted.</summary>
|
||||
EFS_CLEAN = 0x0000,
|
||||
/// <summary>Mounted a dirty filesystem (root only).</summary>
|
||||
EFS_ACTIVEDIRT = 0x0BAD,
|
||||
/// <summary>Filesystem is mounted and clean.</summary>
|
||||
EFS_ACTIVE = 0x7777,
|
||||
/// <summary>Filesystem is dirty.</summary>
|
||||
EFS_DIRTY = 0x1234
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -38,57 +38,200 @@ public sealed partial class EFS
|
||||
{
|
||||
#region Nested type: Superblock
|
||||
|
||||
/// <summary>EFS Superblock structure, 92 bytes. Located at basic block 1.</summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
[SwapEndian]
|
||||
partial struct Superblock
|
||||
{
|
||||
/* 0: fs size incl. bb 0 (in bb) */
|
||||
/// <summary>0x00: Filesystem size including bb 0, in basic blocks.</summary>
|
||||
public int sb_size;
|
||||
/* 4: first cg offset (in bb) */
|
||||
/// <summary>0x04: First cylinder group offset, in basic blocks.</summary>
|
||||
public int sb_firstcg;
|
||||
/* 8: cg size (in bb) */
|
||||
/// <summary>0x08: Cylinder group size, in basic blocks.</summary>
|
||||
public int sb_cgfsize;
|
||||
/* 12: inodes/cg (in bb) */
|
||||
/// <summary>0x0C: Inodes per cylinder group, in basic blocks.</summary>
|
||||
public short sb_cgisize;
|
||||
/* 14: geom: sectors/track */
|
||||
/// <summary>0x0E: Geometry: sectors per track.</summary>
|
||||
public short sb_sectors;
|
||||
/* 16: geom: heads/cylinder (unused) */
|
||||
/// <summary>0x10: Geometry: heads per cylinder (unused).</summary>
|
||||
public short sb_heads;
|
||||
/* 18: num of cg's in the filesystem */
|
||||
/// <summary>0x12: Number of cylinder groups in filesystem.</summary>
|
||||
public short sb_ncg;
|
||||
/* 20: non-0 indicates fsck required */
|
||||
/// <summary>0x14: Non-zero indicates fsck required.</summary>
|
||||
public short sb_dirty;
|
||||
/* 22: */
|
||||
/// <summary>0x16: Padding.</summary>
|
||||
public short sb_pad0;
|
||||
/* 24: superblock ctime */
|
||||
/// <summary>0x18: Superblock creation/modification time.</summary>
|
||||
public int sb_time;
|
||||
/* 28: magic [0] */
|
||||
/// <summary>0x1C: Magic number (EFS_MAGIC or EFS_MAGIC_NEW).</summary>
|
||||
public uint sb_magic;
|
||||
/* 32: name of filesystem */
|
||||
/// <summary>0x20: Filesystem name, 6 bytes.</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
|
||||
public byte[] sb_fname;
|
||||
/* 38: name of filesystem pack */
|
||||
/// <summary>0x26: Filesystem pack name, 6 bytes.</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
|
||||
public byte[] sb_fpack;
|
||||
/* 44: bitmap size (in bytes) */
|
||||
/// <summary>0x2C: Bitmap size in bytes.</summary>
|
||||
public int sb_bmsize;
|
||||
/* 48: total free data blocks */
|
||||
/// <summary>0x30: Total free data blocks.</summary>
|
||||
public int sb_tfree;
|
||||
/* 52: total free inodes */
|
||||
/// <summary>0x34: Total free inodes.</summary>
|
||||
public int sb_tinode;
|
||||
/* 56: bitmap offset (grown fs) */
|
||||
/// <summary>0x38: Bitmap location (for grown filesystems).</summary>
|
||||
public int sb_bmblock;
|
||||
/* 62: repl. superblock offset */
|
||||
/// <summary>0x3C: Replicated superblock location.</summary>
|
||||
public int sb_replsb;
|
||||
/* 64: last allocated inode */
|
||||
/// <summary>0x40: Last allocated inode.</summary>
|
||||
public int sb_lastinode;
|
||||
/* 68: unused */
|
||||
/// <summary>0x44: Spare/unused, 20 bytes (must be zero).</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
|
||||
public byte[] sb_spare;
|
||||
/* 88: checksum (all above) */
|
||||
/// <summary>0x58: Checksum of all above fields.</summary>
|
||||
public uint sb_checksum;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: Extent
|
||||
|
||||
/// <summary>
|
||||
/// EFS Extent structure, 8 bytes. Describes a contiguous range of blocks. The structure uses bit fields packed
|
||||
/// into two 32-bit words.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Layout (big-endian):
|
||||
/// <list type="bullet">
|
||||
/// <item>Bits 63-56: Magic (must be 0)</item>
|
||||
/// <item>Bits 55-32: Block number (24 bits)</item>
|
||||
/// <item>Bits 31-24: Length in basic blocks (8 bits)</item>
|
||||
/// <item>Bits 23-0: Logical offset into file (24 bits)</item>
|
||||
/// </list>
|
||||
/// </remarks>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
[SwapEndian]
|
||||
partial struct Extent
|
||||
{
|
||||
/// <summary>First 32 bits: magic (8 bits, must be 0) + block number (24 bits).</summary>
|
||||
public uint ex_magic_bn;
|
||||
|
||||
/// <summary>Second 32 bits: length (8 bits) + logical offset (24 bits).</summary>
|
||||
public uint ex_length_offset;
|
||||
|
||||
/// <summary>Gets the magic number (must be 0 for valid extent).</summary>
|
||||
public byte Magic => (byte)(ex_magic_bn >> 24 & 0xFF);
|
||||
|
||||
/// <summary>Gets the starting block number (24 bits).</summary>
|
||||
public uint BlockNumber => ex_magic_bn & 0x00FFFFFF;
|
||||
|
||||
/// <summary>Gets the extent length in basic blocks (8 bits, max 248).</summary>
|
||||
public byte Length => (byte)(ex_length_offset >> 24 & 0xFF);
|
||||
|
||||
/// <summary>Gets the logical block offset into file (24 bits).</summary>
|
||||
public uint Offset => ex_length_offset & 0x00FFFFFF;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: DeviceNumbers
|
||||
|
||||
/// <summary>Device numbers for character/block special files. Used in inode di_u union.</summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
[SwapEndian]
|
||||
partial struct DeviceNumbers
|
||||
{
|
||||
/// <summary>Old-style device number (16 bits).</summary>
|
||||
public ushort odev;
|
||||
/// <summary>Padding.</summary>
|
||||
public ushort pad;
|
||||
/// <summary>New-style (extended) device number (32 bits).</summary>
|
||||
public uint ndev;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: Inode
|
||||
|
||||
/// <summary>EFS on-disk inode structure, exactly 128 bytes.</summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
[SwapEndian]
|
||||
partial struct Inode
|
||||
{
|
||||
/// <summary>0x00: Mode and type of file.</summary>
|
||||
public ushort di_mode;
|
||||
/// <summary>0x02: Number of links to file.</summary>
|
||||
public short di_nlink;
|
||||
/// <summary>0x04: Owner's user ID.</summary>
|
||||
public ushort di_uid;
|
||||
/// <summary>0x06: Owner's group ID.</summary>
|
||||
public ushort di_gid;
|
||||
/// <summary>0x08: Number of bytes in file.</summary>
|
||||
public int di_size;
|
||||
/// <summary>0x0C: Time last accessed (Unix timestamp).</summary>
|
||||
public int di_atime;
|
||||
/// <summary>0x10: Time last modified (Unix timestamp).</summary>
|
||||
public int di_mtime;
|
||||
/// <summary>0x14: Time created/changed (Unix timestamp).</summary>
|
||||
public int di_ctime;
|
||||
/// <summary>0x18: Generation number.</summary>
|
||||
public uint di_gen;
|
||||
/// <summary>0x1C: Number of extents.</summary>
|
||||
public short di_numextents;
|
||||
/// <summary>0x1E: Version of inode (0=EFS, 1=AFS special, 2=AFS normal).</summary>
|
||||
public byte di_version;
|
||||
/// <summary>0x1F: Spare byte (used by AFS).</summary>
|
||||
public byte di_spare;
|
||||
/// <summary>0x20: Direct extents array, 12 extents * 8 bytes = 96 bytes.</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = EFS_DIRECTEXTENTS)]
|
||||
public Extent[] di_extents;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: DirectoryBlock
|
||||
|
||||
/// <summary>EFS directory block header, 4 bytes. The rest of the block contains directory entries.</summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
[SwapEndian]
|
||||
partial struct DirectoryBlock
|
||||
{
|
||||
/// <summary>0x00: Magic number (0xBEEF).</summary>
|
||||
public ushort magic;
|
||||
/// <summary>0x02: Offset to first used directory entry byte.</summary>
|
||||
public byte firstused;
|
||||
/// <summary>0x03: Number of offset slots in directory block.</summary>
|
||||
public byte slots;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: DirectoryEntry
|
||||
|
||||
/// <summary>
|
||||
/// EFS directory entry structure. Variable length due to name. The inode number is stored as two 16-bit values
|
||||
/// for alignment reasons.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
[SwapEndian]
|
||||
partial struct DirectoryEntry
|
||||
{
|
||||
/// <summary>0x00: Inode number high word (big-endian: high 16 bits).</summary>
|
||||
public ushort d_inum_high;
|
||||
/// <summary>0x02: Inode number low word (big-endian: low 16 bits).</summary>
|
||||
public ushort d_inum_low;
|
||||
/// <summary>0x04: Length of name string.</summary>
|
||||
public byte d_namelen;
|
||||
|
||||
// Followed by d_name[d_namelen] - variable length name
|
||||
|
||||
/// <summary>Gets the full inode number (big-endian format).</summary>
|
||||
public uint InodeNumber => (uint)(d_inum_high << 16 | d_inum_low);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
Reference in New Issue
Block a user