Implement Ext2.Open()
diff --git a/src/filo-fs-ext2.adb b/src/filo-fs-ext2.adb
index 1d074d4..9cd9c7a 100644
--- a/src/filo-fs-ext2.adb
+++ b/src/filo-fs-ext2.adb
@@ -75,7 +75,7 @@
declare
S_Inodes_Per_Group : constant Unsigned_32 := Read_LE32 (Super_Block, 10 * 4);
begin
- if S_Inodes_Per_Group in 1 .. Unsigned_32'Last then
+ if S_Inodes_Per_Group in 2 .. Unsigned_32'Last then
State.Inodes_Per_Group := Inode_Index (S_Inodes_Per_Group);
else
Success := False;
@@ -727,6 +727,7 @@
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);
+ State.Inode.I := Inode;
Reset_Cache_Logical (State);
State.S := File_Opened;
end;
@@ -741,9 +742,112 @@
In_Root : in Boolean;
Success : out Boolean)
is
+ File_Name_Max : constant := 255;
+ Root_Inode : constant := 2;
+
+ function Str_Buf_Equal (Str : String; Buf : Buffer_Type) return Boolean is
+ begin
+ for I in Str'Range loop
+ if Character'Pos (Str (I)) /= Buf (Buf'First + (I - Str'First)) then
+ return False;
+ end if;
+ end loop;
+ return True;
+ end Str_Buf_Equal;
+
+ File_Inode : Inode_Index;
+ File_Pos : File_Length;
begin
File_Len := 0;
+ File_Type := FS.File_Type'First;
+
+ if File_Name'Length > File_Name_Max then
+ Success := False;
+ return;
+ end if;
+
+ -- Ensure dir is opened:
+ --
+ if State.S = File_Opened then
+ if State.Cur_Dir /= State.Inode.I then
+ Success := False;
+ return;
+ end if;
+ else
+ if In_Root then
+ State.Cur_Dir := Root_Inode;
+ end if;
+ Open (State, State.Cur_Dir, Success);
+ if not Success then
+ return;
+ end if;
+ end if;
+
+ -- Lookup file in opened dir:
+ --
+ File_Pos := 0;
Success := False;
+ while Unsigned_64 (File_Pos) < Unsigned_64 (State.Inode.Size) loop
+ declare
+ Dir_Entry_Header_Length : constant := 4 + 2 + 1 + 1;
+ subtype Dir_Entry_Index is Natural
+ range 0 .. Dir_Entry_Header_Length + File_Name_Max - 1;
+ Dir_Entry : Buffer_Type (Dir_Entry_Index);
+ Entry_File_Pos : File_Offset := File_Pos;
+ Len : Natural;
+ begin
+ Read
+ (State => State,
+ File_Pos => Entry_File_Pos,
+ Buf => Dir_Entry (0 .. 7),
+ Len => Len);
+ if Len < Dir_Entry_Header_Length then
+ return;
+ end if;
+
+ -- Only check filenames of exact same length
+ if Read_LE32 (Dir_Entry, 0) > Root_Inode and then
+ File_Name'Length = Natural (Dir_Entry (6))
+ then
+ Read
+ (State => State,
+ File_Pos => Entry_File_Pos,
+ Buf => Dir_Entry (8 .. 8 + File_Name'Length - 1),
+ Len => Len);
+ if Len < File_Name'Length then
+ return;
+ end if;
+
+ File_Inode := Inode_Index (Read_LE32 (Dir_Entry, 0));
+ Success := Str_Buf_Equal (File_Name, Dir_Entry (8 .. 8 + File_Name'Length - 1));
+ exit when Success;
+ end if;
+
+ File_Pos := File_Pos + File_Length (Read_LE16 (Dir_Entry, 4));
+ end;
+ end loop;
+
+ if Success then
+ Open (State, File_Inode, Success);
+ if not Success then
+ return;
+ end if;
+
+ if State.Inode.Mode = Dir then
+ State.Cur_Dir := File_Inode;
+ end if;
+ end if;
+
+ Success := Unsigned_64 (State.Inode.Size) <= Unsigned_64 (File_Length'Last);
+ if Success then
+ File_Len := File_Length (State.Inode.Size);
+ File_Type := (case State.Inode.Mode is
+ when Dir => FS.Dir,
+ when Regular => FS.Regular,
+ when Link .. Fast_Link => FS.Link);
+ else
+ Close (State);
+ end if;
end Open;
procedure Close (State : in out T) is
diff --git a/src/filo-fs-ext2.ads b/src/filo-fs-ext2.ads
index 2c30e0a..0deefb6 100644
--- a/src/filo-fs-ext2.ads
+++ b/src/filo-fs-ext2.ads
@@ -66,7 +66,7 @@
subtype Inode_Extents_Index is Natural range 0 .. 59;
subtype Inode_Extents is Buffer_Type (Inode_Extents_Index);
- type Inode_Index is new Unsigned_32 range 1 .. Unsigned_32'Last;
+ type Inode_Index is new Unsigned_32 range 2 .. Unsigned_32'Last;
subtype Inode_Size is Positive range 128 .. Positive (Unsigned_16'Last);
subtype Desc_Size is Positive range 32 .. 2 ** 15; -- power-of-2 that fits in 16 bits
@@ -74,6 +74,7 @@
type Inode_Length is range 0 .. 2 ** 46;
type Inode_Info is record
+ I : Inode_Index;
Mode : Inode_Type := Inode_Type'First;
Size : Inode_Length := 0;
Use_Extents : Boolean := False;
@@ -85,12 +86,13 @@
Part_Len : Partition_Length := 0;
First_Data_Block : FSBlock_Offset := 0;
Block_Size_Bits : Log_Block_Size := 10;
- Inodes_Per_Group : Inode_Index := 1;
+ Inodes_Per_Group : Inode_Index := Inode_Index'First;
Inode_Size : Ext2.Inode_Size := Ext2.Inode_Size'First;
Desc_Size : Ext2.Desc_Size := Ext2.Desc_Size'First;
Feature_Extents : Boolean := False;
Feature_64Bit : Boolean := False;
Inode : Inode_Info := (others => <>);
+ Cur_Dir : Inode_Index := Inode_Index'First;
Block_Cache_Logical : Cache_Label_Logical := (others => False);
Block_Cache_Label : Cache_Label_Array := (others => 0);
Block_Cache : Buffer_Type (Max_Block_Index) := (others => 16#00#);