unit ext2fs;
interface
const EXT2_DEFAULT_PREALLOC_BLOCKS = 8;
///* Special Inode Numbers */
const EXT2_BAD_INO = 1;
const EXT2_ROOT_INO = 2;
const EXT2_ACL_IDX_INO = 3;
const EXT2_ACL_DATA_INO = 4;
const EXT2_BOOT_LOADER_INO = 5;
const EXT2_UNDEL_DIR_INO = 6;
const EXT2_GOOD_OLD_FIRST_INO = 11;
const EXT2_SUPER_MAGIC = $EF53; //* EXT2 Fs Magic Number */
const EXT2_LINK_MAX = 32000; //* Max count of links to the file */
//* Block Size Management */
const EXT2_MIN_BLOCK_SIZE = 1024;
const EXT2_MAX_BLOCK_SIZE = 4096;
const EXT2_MIN_BLOCK_LOG_SIZE = 10;
//* EXT2 Fragment Sizes */
const EXT2_MIN_FRAG_SIZE = 1024;
const EXT2_MAX_FRAG_SIZE = 4096;
const EXT2_MIN_FRAG_LOG_SIZE = 10;
//* Constants relative to the data blocks */
const EXT2_NDIR_BLOCKS = 12;
const EXT2_IND_BLOCK = EXT2_NDIR_BLOCKS;
const EXT2_DIND_BLOCK = (EXT2_IND_BLOCK + 1);
const EXT2_TIND_BLOCK = (EXT2_DIND_BLOCK + 1);
const EXT2_N_BLOCKS = (EXT2_TIND_BLOCK + 1);
//* Superblock Flags */
const EXT2_FEATURE_INCOMPAT_COMPRESSION = $0001; //* disk/file compression is used */
//*Inode flags */
const EXT2_SECRM_FL = $00000001; //* Secure deletion */
const EXT2_UNRM_FL = $00000002; //* Undelete */
const EXT2_COMPR_FL = $00000004; //* Compress file */
const EXT2_SYNC_FL = $00000008; //* Synchronous updates */
const EXT2_IMMUTABLE_FL = $00000010; //* Immutable file */
const EXT2_APPEND_FL = $00000020; //* writes to file may only append */
const EXT2_NODUMP_FL = $00000040; //* do not dump file */
const EXT2_NOATIME_FL = $00000080; //* do not update atime */
//* Reserved for compression usage... */
const EXT2_DIRTY_FL = $00000100;
const EXT2_COMPRBLK_FL = $00000200; //* One or more compressed clusters */
const EXT2_NOCOMP_FL = $00000400; //* Don't compress */
const EXT2_ECOMPR_FL = $00000800; //* Compression error */
//* End compression flags --- maybe not all used */
const EXT2_BTREE_FL = $00001000; //* btree format dir */
const EXT2_IMAGIC_FL = $00002000; //* AFS directory */
const EXT2_JOURNAL_DATA_FL = $00004000; //* file data should be journaled */
const EXT2_NOTAIL_FL = $00008000; //* file tail should not be merged */
const EXT2_DIRSYNC_FL = $00010000; //* dirsync behaviour (directories only) */
const EXT2_TOPDIR_FL = $00020000; //* Top of directory hierarchies*/
const EXT2_HUGE_FILE_FL = $00040000; //* Set to each huge file */
const EXT2_EXTENTS_FL = $00080000; //* Inode uses extents */
const EXT2_RESERVED_FL = $80000000; //* reserved for ext2 lib */
const EXT2_FL_USER_VISIBLE = $00001FFF; //* User visible flags */
const EXT2_FL_USER_MODIFIABLE = $000000FF; //* User modifiable flags */
//* Codes for operating systems */
const EXT2_OS_LINUX = 0;
const EXT2_OS_HURD = 1;
const EXT2_OS_MASIX = 2;
const EXT2_OS_FREEBSD = 3;
const EXT2_OS_LITES = 4;
//* Revision levels */
const EXT2_GOOD_OLD_REV = 0; //* The good old (original) format */
const EXT2_DYNAMIC_REV = 1; //* V2 format w/ dynamic inode sizes */
const EXT2_CURRENT_REV = EXT2_GOOD_OLD_REV;
const EXT2_MAX_SUPP_REV = EXT2_DYNAMIC_REV;
const EXT2_GOOD_OLD_INODE_SIZE = 128;
//* Default values for user and/or group using reserved blocks */
const EXT2_DEF_RESUID = 0;
const EXT2_DEF_RESGID = 0;
//* Structure of a directory entry */
const EXT2_NAME_LEN = 255;
const EXT4_EXT_MAGIC = $f30a;
(*
/* In Linux disk is divided into Blocks. These Blocks are divided into Groups. This */
/* Structure shows different types of groups but it is not implemented. Not Necessary */
/*
typedef struct tagBLOCK_GROUP
{
1. The SuperBlock
2. The Group Descriptors
3. The block Bitmap
4. The Inode Bitmap
5. The Inode Table
6. Data Blocks and Fragments
}BLOCK_GROUP;
*/
*)
//* The Super Block comes first in the block group */
type EXT2_SUPER_BLOCK = packed record
s_inodes_count: UInt32; //* total no of inodes */
s_blocks_count: UInt32; //* total no of blocks */
s_r_blocks_count: UInt32; //* total no of blocks reserved for exclusive use of superuser */
s_free_blocks_count: UInt32; //* total no of free blocks */
s_free_inodes_count: UInt32; //* total no of free inodes */
s_first_data_block: UInt32; //* position of the first data block */
s_log_block_size: UInt32; //* used to compute logical block size in bytes */
s_log_frag_size: UInt32; //* used to compute logical fragment size */
s_blocks_per_group: UInt32; //* total number of blocks contained in the group */
s_frags_per_group: UInt32; //* total number of fragments in a group */
s_inodes_per_group: UInt32; //* number of inodes in a group */
s_mtime: UInt32; //* time at which the last mount was performed */
s_wtime: UInt32; //* time at which the last write was performed */
s_mnt_count: UInt16; //* number of time the fs system has been mounted in r/w mode without having checked */
s_max_mnt_count: UInt16; //* the max no of times the fs can be mounted in r/w mode before a check must be done */
s_magic: UInt16; //* a number that identifies the fs (eg. 0xef53 for ext2) */
s_state: UInt16; //* gives the state of fs (eg. 0x001 is Unmounted cleanly) */
s_pad: UInt16; //* unused */
s_minor_rev_level: UInt16; //* */
s_lastcheck: UInt32; //* the time of last check performed */
s_checkinterval: UInt32; //* the max possible time between checks on the fs */
s_creator_os: UInt32; //* os */
s_rev_level: UInt32; //* Revision level */
s_def_resuid: UInt16; //* default uid for reserved blocks */
s_def_regid: UInt16; //* default gid for reserved blocks */
//* for EXT2_DYNAMIC_REV superblocks only */
s_first_ino: UInt32; //* First non-reserved inode */
s_inode_size: UInt16; //* size of inode structure */
s_block_group_nr: UInt16; //* block group # of this superblock */
s_feature_compat: UInt32; //* compatible feature set */
s_feature_incompat: UInt32; //* incompatible feature set */
s_feature_ro_compat: UInt32; //* readonly-compatible feature set */
s_uuid: array [0..15] of UInt8; //* 128-bit uuid for volume */
s_volume_name: array [0..15] of AnsiChar; //* volume name */
s_last_mounted: array [0..63] of AnsiChar; //* directory where last mounted */
s_algorithm_usage_bitmap: UInt32; //* For compression */
s_prealloc_blocks: UInt8; //* Nr of blocks to try to preallocate*/
s_prealloc_dir_blocks: UInt8; //* Nr to preallocate for dirs */
s_padding1: UInt16;
s_reserved: array [0..203] of UInt32; //* unused */
end;
//* The Group Descriptors follow the Super Block. */
type EXT2_GROUP_DESC = packed record
bg_block_bitmap: UInt32; //* points to the blocks bitmap for the group */
bg_inode_bitmap: UInt32; //* points to the inodes bitmap for the group */
bg_inode_table: UInt32; //* points to the inode table first block */
bg_free_blocks_count: UInt16; //* number of free blocks in the group */
bg_free_inodes_count: UInt16; //* number of free inodes in the */
bg_used_dirs_count: UInt16; //* number of inodes allocated to directories */
bg_pad: UInt16; //* padding */
bg_reserved: array [0..2] of UInt32; //* reserved */
end;
type
TUnionType1 = (utLinux, utHurd, utMasix);
TUnionType2 = (utLinux2, utHurd2, utMasix2);
//* Structure of an inode on the disk */
type EXT2_INODE = packed record
i_mode: UInt16; //* File mode */
i_uid: UInt16; //* Low 16 bits of Owner Uid */
i_size: UInt32; //* Size in bytes */
i_atime: UInt32; //* Access time */
i_ctime: UInt32; //* Creation time */
i_mtime: UInt32; //* Modification time */
i_dtime: UInt32; //* Deletion Time */
i_gid: UInt16; //* Low 16 bits of Group Id */
i_links_count: UInt16; //* Links count */
i_blocks: UInt32; //* Blocks count */
i_flags: UInt32; //* File flags */
osd1: packed record //* OS dependent 1 */
case TUnionType1 of
utLinux: (linux1: packed record l_i_reserved1: UInt32; end; );
utHurd: (hurd1: packed record h_i_translator: UInt32; end; );
utMasix: (masix1: packed record m_i_reserved1: UInt32; end; );
end;
i_block: array [0..Pred(EXT2_N_BLOCKS)] of UInt32; //* Pointers to blocks */
i_generation: UInt32; //* File version (for NFS) */
i_file_acl: UInt32; //* File ACL */
// uint32_t i_dir_acl; //* Directory ACL */
i_size_high: UInt32; //* This is used store the high 32 bit of file size in large files */
i_faddr: UInt32; //* Fragment address */
osd2: packed record //* OS dependent 2 */
case TUnionType2 of
utLinux2: (
linux2: packed record
l_i_frag: UInt8; //* Fragment number */
l_i_fsize: UInt8; //* Fragment size */
i_pad1: UInt16;
l_i_uid_high: UInt16; //* these 2 fields */
l_i_gid_high: UInt16; //* were reserved2[0] */
l_i_reserved2: UInt32;
end;
);
utHurd2: (
hurd2: packed record
h_i_frag: UInt8; //* Fragment number */
h_i_fsize: UInt8; //* Fragment size */
h_i_mode_high: UInt16;
h_i_uid_high: UInt16;
h_i_gid_high: UInt16;
h_i_author: UInt16;
end;
);
utMasix2: (
masix2: packed record
m_i_frag: UInt8; //* Fragment number */
m_i_fsize: UInt8; //* Fragment size */
m_pad1: UInt16;
m_i_reserved2: array [0..1] of UInt32;
end;
);
end;
end;
//* EXT2 directory structure */
type EXT2_DIR_ENTRY = packed record
inode: UInt32; //* Inode number */
rec_len: UInt16; //* Directory entry length */
name_len: UInt8; //* Name length */
filetype: UInt8; //* File type */
name: array [0..Pred(EXT2_NAME_LEN)] of AnsiChar; //* File name */
end;
//*
// * This is the extent on-disk structure.
// * It's used at the bottom of the tree.
// */
type EXT4_EXTENT = packed record
ee_block: UInt32; //* first logical block extent covers */
ee_len: UInt16; //* number of blocks covered by extent */
ee_start_hi: UInt16; //* high 16 bits of physical block */
ee_start_lo: UInt32; //* low 32 bits of physical block */
end;
//*
// * This is index on-disk structure.
// * It's used at all the levels except the bottom.
// */
type EXT4_EXTENT_IDX = packed record
ei_block: UInt32; //* index covers logical blocks from 'block' */
ei_leaf_lo: UInt32; //* pointer to the physical block of the next *
//* level. leaf or next index could be there */
ei_leaf_hi: UInt16; ///* high 16 bits of physical block */
ei_unused: UInt16;
end;
//*
// * Each block (leaves and indexes), even inode-stored has header.
// */
type EXT4_EXTENT_HEADER = packed record
eh_magic: UInt16; //* probably will support different formats */
eh_entries: UInt16; //* number of valid entries */
eh_max: UInt16; //* capacity of store in entries */
eh_depth: UInt16; //* has tree real underlying blocks? */
eh_generation: UInt32; //* generation of the tree */
end;
function EXT2_BLOCK_SIZE(S: EXT2_SUPER_BLOCK): UInt32; inline;
function EXT2_ACLE_PER_BLOCK(S: EXT2_SUPER_BLOCK): UInt32; inline;
function EXT2_ADDR_PER_BLOCK(S: EXT2_SUPER_BLOCK): UInt32; inline;
function EXT2_INODE_SIZE(S: EXT2_SUPER_BLOCK): UInt32; inline;
function EXT2_FIRST_INO(S: EXT2_SUPER_BLOCK): UInt32; inline;
function EXT2_FRAG_SIZE(S: EXT2_SUPER_BLOCK): UInt32; inline;
function EXT2_FRAGS_PER_BLOCK(S: EXT2_SUPER_BLOCK): UInt32; inline;
//* Block Group Macros */
function EXT2_BLOCKS_PER_GROUP(S: EXT2_SUPER_BLOCK): UInt32; inline;
function EXT2_DESC_PER_BLOCK(S: EXT2_SUPER_BLOCK): UInt32; inline;
function EXT2_INODES_PER_GROUP(S: EXT2_SUPER_BLOCK): UInt32; inline;
function EXT2_INODES_PER_BLOCK(S: EXT2_SUPER_BLOCK): UInt32; inline;
function EXT2_BLOCK_SIZE_BITS(S: EXT2_SUPER_BLOCK): UInt32; inline;
function get_ext4_header(I: EXT2_INODE): UInt32; inline;
function EXT_FIRST_EXTENT(__hdr__: EXT4_EXTENT_HEADER): UInt32; inline;
function INODE_HAS_EXTENT(i: EXT2_INODE): UInt32; inline;
function ext_to_block(extent: EXT4_EXTENT): UInt64; inline;
function idx_to_block(idx: EXT4_EXTENT_IDX): UInt64; inline;
implementation
{ ext2fs }
function EXT2_BLOCK_SIZE; inline;
begin
Result := EXT2_MIN_BLOCK_SIZE shl S.s_log_block_size;
end;
function EXT2_ACLE_PER_BLOCK; inline;
begin
// Result := EXT2_BLOCK_SIZE(S) div SizeOf(ext2_acl_entry);
end;
function EXT2_ADDR_PER_BLOCK; inline;
begin
Result := EXT2_BLOCK_SIZE(s) div SizeOf(UInt16);
end;
function EXT2_INODE_SIZE; inline;
begin
if S.s_rev_level = EXT2_GOOD_OLD_REV then
Result := EXT2_GOOD_OLD_INODE_SIZE
else
Result := S.s_inode_size;
end;
function EXT2_FIRST_INO; inline;
begin
if S.s_rev_level = EXT2_GOOD_OLD_REV then
Result := EXT2_GOOD_OLD_FIRST_INO
else
Result := S.s_first_ino;
end;
function EXT2_FRAG_SIZE; inline;
begin
Result := (EXT2_MIN_FRAG_SIZE shl S.s_log_frag_size);
end;
function EXT2_FRAGS_PER_BLOCK; inline;
begin
Result := EXT2_BLOCK_SIZE(S) div EXT2_FRAG_SIZE(S);
end;
function EXT2_BLOCKS_PER_GROUP; inline;
begin
Result := S.s_blocks_per_group;
end;
function EXT2_DESC_PER_BLOCK; inline;
begin
Result := EXT2_BLOCK_SIZE(s) div SizeOf(EXT2_GROUP_DESC);
end;
function EXT2_INODES_PER_GROUP; inline;
begin
Result := S.s_inodes_per_group;
end;
function EXT2_INODES_PER_BLOCK; inline;
begin
Result := EXT2_BLOCK_SIZE(s) div SizeOf(EXT2_INODE);
end;
function EXT2_BLOCK_SIZE_BITS; inline;
begin
Result := S.s_log_block_size + 10;
end;
function get_ext4_header; inline;
begin
// Result := (ext4_extent_header((i).i_block));
end;
function ext_to_block; inline;
begin
Result := UInt64(extent.ee_start_lo);
Result := Result or (UInt64(extent.ee_start_hi) shl 31) shl 1;
end;
function idx_to_block; inline;
begin
Result := UInt64(idx.ei_leaf_lo);
Result := Result or (UInt64(idx.ei_leaf_hi) shl 31) shl 1;
end;
function EXT_FIRST_EXTENT; inline;
begin
// Result := ext4_extent(__hdr__) + SizeOf(EXT4_EXTENT_HEADER);
end;
function INODE_HAS_EXTENT; inline;
begin
Result := (i.i_flags and EXT2_EXTENTS_FL);
end;
end.