ext2: Implement Open() for an inode by number
diff --git a/src/filo-fs-ext2.adb b/src/filo-fs-ext2.adb
index 1a151b9..00a5985 100644
--- a/src/filo-fs-ext2.adb
+++ b/src/filo-fs-ext2.adb
@@ -34,6 +34,8 @@
FEATURE_INCOMPAT_EXTENTS : constant := 16#0040#;
FEATURE_INCOMPAT_64BIT : constant := 16#0080#;
+ EXT4_EXTENTS_FL : constant := 16#8_0000#;
+
procedure Mount
(State : in out T;
Part_Len : in Partition_Length;
@@ -73,8 +75,8 @@
declare
S_Inodes_Per_Group : constant Unsigned_32 := Read_LE32 (Super_Block, 10 * 4);
begin
- if S_Inodes_Per_Group in 1 .. Unsigned_32 (Positive'Last) then
- State.Inodes_Per_Group := Positive (S_Inodes_Per_Group);
+ if S_Inodes_Per_Group in 1 .. Unsigned_32'Last then
+ State.Inodes_Per_Group := Inode_Index (S_Inodes_Per_Group);
else
Success := False;
return;
@@ -570,6 +572,97 @@
end Extent_Block_Map;
procedure Open
+ (State : in out T;
+ Inode : in Inode_Index;
+ Success : out Boolean)
+ with
+ Pre => Is_Mounted (State) and not Is_Open (State),
+ Post => Success = Is_Open (State)
+ is
+ type Group_Index is new Natural;
+ subtype Desc_In_Block_Index is Group_Index
+ range 0 .. Group_Index (2 ** Log_Block_Size'Last / Desc_Size'First - 1);
+
+ Block_Size : constant Natural := 2 ** State.Block_Size_Bits;
+
+ 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);
+
+ subtype Group_Off is Natural range 0 .. Desc_Size'Last;
+ function Group_Byte_Offset (Idx : Group_Index; Off : Group_Off) return Natural
+ is
+ (Natural (Idx) * State.Desc_Size + Off);
+
+ function Group_Inode_Table (Buf : Buffer_Type; Idx : Group_Index) return FSBlock_Offset
+ is
+ (FSBlock_Offset (
+ (if State.Feature_64Bit
+ then Shift_Left (Unsigned_64 (Read_LE32 (Buf, Group_Byte_Offset (Idx, 40))), 32)
+ else 0)
+ or
+ Unsigned_64 (Read_LE32 (Buf, Group_Byte_Offset (Idx, 8)))))
+ with
+ Pre => Buf'Length >= Group_Byte_Offset (Idx, 44);
+
+ 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_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);
+
+ 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);
+ Cache_Start, Cache_End : Max_Block_Index;
+ begin
+ Cache_FSBlock
+ (State => State,
+ Phys => Desc_Block,
+ Level => Natural'Min (Natural (Group / Desc_Per_Block), Block_Cache_Index'Last),
+ Cache_Start => Cache_Start,
+ Cache_End => Cache_End,
+ Success => Success);
+ if not Success then
+ return;
+ end if;
+
+ declare
+ Desc : constant Desc_In_Block_Index := Group mod Desc_Per_Block;
+ Inode_In_Group : constant Inode_Index := (Inode - 1) mod State.Inodes_Per_Group;
+ Inode_Block : constant FSBlock_Offset :=
+ Group_Inode_Table (State.Block_Cache (Cache_Start .. Cache_End), Group) +
+ FSBlock_Offset (Inode_In_Group / Inodes_Per_Block);
+ begin
+ Cache_FSBlock
+ (State => State,
+ Phys => Inode_Block,
+ Level => Block_Cache_Index'Last,
+ Cache_Start => Cache_Start,
+ Cache_End => Cache_End,
+ Success => Success);
+ if not Success then
+ return;
+ end if;
+
+ declare
+ Inode_In_Block : constant Inode_Index := Inode_In_Group mod Inodes_Per_Block;
+ I_Flags : constant Unsigned_32 :=
+ Inode_Flags (State.Block_Cache (Cache_Start .. Cache_End), Inode_In_Block);
+ begin
+ State.Inode.Use_Extents := State.Feature_Extents and (I_Flags and EXT4_EXTENTS_FL) /= 0;
+ State.Inode.Extents := State.Block_Cache (Cache_Start + 40 .. Cache_Start + 100 - 1);
+ Reset_Cache_Logical (State);
+ State.S := File_Opened;
+ end;
+ end;
+ end Open;
+
+ procedure Open
(State : in out T;
File_Len : out File_Length;
File_Path : in String;