ext2: Read inode type and length
diff --git a/src/filo-fs-ext2.adb b/src/filo-fs-ext2.adb
index cb3f7bf..06909c0 100644
--- a/src/filo-fs-ext2.adb
+++ b/src/filo-fs-ext2.adb
@@ -589,6 +589,9 @@
Inodes_Per_Block : constant Inode_Index := Inode_Index (Block_Size / State.Inode_Size);
Desc_Per_Block : constant Group_Index := Group_Index (Block_Size / State.Desc_Size);
+ ------------------------
+ -- Group deserialization
+
subtype Group_Off is Natural range 0 .. Desc_Size'Last;
function Group_Byte_Offset (Idx : Group_Index; Off : Group_Off) return Natural
is
@@ -605,17 +608,47 @@
with
Pre => Buf'Length >= Group_Byte_Offset (Idx, 44);
+ ------------------------
+ -- Inode deserialization
+
subtype Inode_Off is Natural range 0 .. Inode_Size'Last;
function Inode_Byte_Offset (Idx : Inode_Index; Off : Inode_Off) return Natural
is
(Natural (Idx) * State.Inode_Size + Off);
+ function Inode_Mode (Buf : Buffer_Type; Idx : Inode_Index) return Unsigned_16
+ is
+ (Read_LE16 (Buf, Inode_Byte_Offset (Idx, 0)))
+ with
+ Pre => Buf'Length >= Inode_Byte_Offset (Idx, 2);
+
+ function Inode_Size (Buf : Buffer_Type; Idx : Inode_Index; Mode : Inode_Type) return Unsigned_64
+ is
+ ((if Mode = Regular
+ then Shift_Left (Unsigned_64 (Read_LE32 (Buf, Inode_Byte_Offset (Idx, 108))), 32)
+ else 0) or
+ Unsigned_64 (Read_LE32 (Buf, Inode_Byte_Offset (Idx, 4))))
+ with
+ Pre => Buf'Length >= Inode_Byte_Offset (Idx, 112);
+
+ function Inode_Blocks (Buf : Buffer_Type; Idx : Inode_Index) return Unsigned_32
+ is
+ (Read_LE32 (Buf, Inode_Byte_Offset (Idx, 28)))
+ with
+ Pre => Buf'Length >= Inode_Byte_Offset (Idx, 32);
+
function Inode_Flags (Buf : Buffer_Type; Idx : Inode_Index) return Unsigned_32
is
(Read_LE32 (Buf, Inode_Byte_Offset (Idx, 32)))
with
Pre => Buf'Length >= Inode_Byte_Offset (Idx, 36);
+ function Inode_File_ACL (Buf : Buffer_Type; Idx : Inode_Index) return Unsigned_32
+ is
+ (Read_LE32 (Buf, Inode_Byte_Offset (Idx, 104)))
+ with
+ Pre => Buf'Length >= Inode_Byte_Offset (Idx, 108);
+
Group : constant Group_Index := Group_Index ((Inode - 1) / State.Inodes_Per_Group);
Desc_Block : constant FSBlock_Offset :=
1 + State.First_Data_Block + FSBlock_Offset (Group / Desc_Per_Block);
@@ -651,10 +684,47 @@
end if;
declare
+ S_IFMT : constant := 8#170000#;
+ S_IFDIR : constant := 8#040000#;
+ S_IFREG : constant := 8#100000#;
+ S_IFLNK : constant := 8#120000#;
+
Inode_In_Block : constant Inode_Index := Inode_In_Group mod Inodes_Per_Block;
+ I_Mode : constant Unsigned_16 :=
+ Inode_Mode (State.Block_Cache (Cache_Start .. Cache_End), Inode_In_Block);
I_Flags : constant Unsigned_32 :=
Inode_Flags (State.Block_Cache (Cache_Start .. Cache_End), Inode_In_Block);
begin
+ case I_Mode and S_IFMT is
+ when S_IFDIR => State.Inode.Mode := Dir;
+ when S_IFREG => State.Inode.Mode := Regular;
+ when S_IFLNK => State.Inode.Mode := Link;
+ when others => Success := False; return;
+ end case;
+ if State.Inode.Mode = Link then
+ declare
+ I_File_ACL : constant Unsigned_32 := Inode_File_ACL (
+ State.Block_Cache (Cache_Start .. Cache_End), Inode_In_Block);
+ I_Blocks : constant Unsigned_32 := Inode_Blocks (
+ State.Block_Cache (Cache_Start .. Cache_End), Inode_In_Block);
+ begin
+ if (I_File_ACL = 0 and I_Blocks = 0) or
+ (I_File_ACL /= 0 and I_Blocks = 2 ** (State.Block_Size_Bits - 9))
+ then
+ State.Inode.Mode := Fast_Link;
+ end if;
+ end;
+ end if;
+ declare
+ I_Size : constant Unsigned_64 := Inode_Size (
+ State.Block_Cache (Cache_Start .. Cache_End), Inode_In_Block, State.Inode.Mode);
+ begin
+ if I_Size <= Unsigned_64 (Inode_Length'Last) then
+ State.Inode.Size := Inode_Length (I_Size);
+ else
+ Success := False;
+ end if;
+ end;
State.Inode.Use_Extents := State.Feature_Extents and (I_Flags and EXT4_EXTENTS_FL) /= 0;
State.Inode.Inline := State.Block_Cache (Cache_Start + 40 .. Cache_Start + 100 - 1);
Reset_Cache_Logical (State);