ext2: Further split our state record
To assist proving that the metadata doesn't change.
diff --git a/src/filo-fs-ext2.adb b/src/filo-fs-ext2.adb
index 4dcde30..deb2d21 100644
--- a/src/filo-fs-ext2.adb
+++ b/src/filo-fs-ext2.adb
@@ -39,6 +39,7 @@
Part_Len : in Partition_Length;
Success : out Boolean)
is
+ Static : Mount_State renames State.Static;
Super_Block : Buffer_Type (0 .. SUPERBLOCK_SIZE - 1) := (others => 0);
begin
if Part_Len < 2 * SUPERBLOCK_SIZE then
@@ -56,15 +57,15 @@
return;
end if;
- State.Part_Len := Part_Len;
- State.First_Data_Block := FSBlock_Offset (Read_LE32 (Super_Block, 5 * 4));
+ Static.Part_Len := Part_Len;
+ Static.First_Data_Block := FSBlock_Offset (Read_LE32 (Super_Block, 5 * 4));
declare
S_Log_Block_Size : constant Unsigned_32 := Read_LE32 (Super_Block, 6 * 4);
begin
if S_Log_Block_Size <= Unsigned_32 (Log_Block_Size'Last - 10) then
- State.Block_Size_Bits := Log_Block_Size (S_Log_Block_Size + 10);
- State.Block_Size := 2 ** Log_Block_Size (S_Log_Block_Size + 10);
+ Static.Block_Size_Bits := Log_Block_Size (S_Log_Block_Size + 10);
+ Static.Block_Size := 2 ** Log_Block_Size (S_Log_Block_Size + 10);
else
Success := False;
return;
@@ -75,7 +76,7 @@
S_Inodes_Per_Group : constant Unsigned_32 := Read_LE32 (Super_Block, 10 * 4);
begin
if S_Inodes_Per_Group in 2 .. Unsigned_32'Last then
- State.Inodes_Per_Group := Inode_Index (S_Inodes_Per_Group);
+ Static.Inodes_Per_Group := Inode_Index (S_Inodes_Per_Group);
else
Success := False;
return;
@@ -90,39 +91,39 @@
S_Inode_Size : constant Unsigned_16 := Read_LE16 (Super_Block, 22 * 4);
begin
if Natural (S_Inode_Size) in Inode_Size then
- State.Inode_Size := Inode_Size (S_Inode_Size);
+ Static.Inode_Size := Inode_Size (S_Inode_Size);
else
Success := False;
return;
end if;
end;
else
- State.Inode_Size := Inode_Size'First;
+ Static.Inode_Size := Inode_Size'First;
end if;
end;
declare
S_Feature_Incompat : constant Unsigned_32 := Read_LE32 (Super_Block, 24 * 4);
begin
- State.Feature_Extents := (S_Feature_Incompat and FEATURE_INCOMPAT_EXTENTS) /= 0;
- State.Feature_64Bit := (S_Feature_Incompat and FEATURE_INCOMPAT_64BIT) /= 0;
- if State.Feature_64Bit then
+ Static.Feature_Extents := (S_Feature_Incompat and FEATURE_INCOMPAT_EXTENTS) /= 0;
+ Static.Feature_64Bit := (S_Feature_Incompat and FEATURE_INCOMPAT_64BIT) /= 0;
+ if Static.Feature_64Bit then
declare
S_Desc_Size : constant Unsigned_16 := Read_LE16 (Super_Block, 63 * 4 + 2);
begin
if Natural (S_Desc_Size) in Desc_Size and
- Natural (S_Desc_Size) <= State.Block_Size and
+ Natural (S_Desc_Size) <= Static.Block_Size and
Is_Power_Of_2 (S_Desc_Size)
then
- State.Desc_Size := Desc_Size (S_Desc_Size);
+ Static.Desc_Size := Desc_Size (S_Desc_Size);
else
Success := False;
return;
end if;
end;
- State.Feature_64Bit := State.Feature_64Bit and State.Desc_Size >= 64;
+ Static.Feature_64Bit := Static.Feature_64Bit and Static.Desc_Size >= 64;
else
- State.Desc_Size := Desc_Size'First;
+ Static.Desc_Size := Desc_Size'First;
end if;
end;
@@ -149,7 +150,8 @@
end Read_FSBlock;
procedure Cache_FSBlock
- (State : in out T;
+ (Static : in Mount_State;
+ Cache : in out Block_Cache;
Phys : in FSBlock_Offset;
Level : in Block_Cache_Index;
Label : in Cache_Label;
@@ -158,50 +160,51 @@
Cache_End : out Max_Block_Index;
Success : out Boolean)
with
- Post => Cache_End = Cache_Start + State.Block_Size - 1
+ Post => Cache_End = Cache_Start + Static.Block_Size - 1
is
-- Limit cache usage depending on block size:
- Max_Level : constant Block_Cache_Index := Block_Size'Last / State.Block_Size - 1;
+ Max_Level : constant Block_Cache_Index := Block_Size'Last / Static.Block_Size - 1;
Cache_Level : constant Block_Cache_Index := Block_Cache_Index'Min (Level, Max_Level);
begin
- Cache_Start := Cache_Level * State.Block_Size;
- Cache_End := Cache_Start + State.Block_Size - 1;
- if State.Block_Cache_Logical (Cache_Level) = Logical and
- State.Block_Cache_Label (Cache_Level) = Label
+ Cache_Start := Cache_Level * Static.Block_Size;
+ Cache_End := Cache_Start + Static.Block_Size - 1;
+ if Cache.Logical (Cache_Level) = Logical and
+ Cache.Label (Cache_Level) = Label
then
Success := True;
else
Read_FSBlock
- (Buf => State.Block_Cache (Cache_Start .. Cache_End),
+ (Buf => Cache.Buffer (Cache_Start .. Cache_End),
FSBlock => Phys,
- Part_Len => State.Part_Len,
+ Part_Len => Static.Part_Len,
Success => Success);
- State.Block_Cache_Logical (Cache_Level) := Logical;
- State.Block_Cache_Label (Cache_Level) := Label;
+ Cache.Logical (Cache_Level) := Logical; -- FIXME: Level needs to be part of Label
+ Cache.Label (Cache_Level) := Label;
end if;
end Cache_FSBlock;
procedure Cache_FSBlock
- (State : in out T;
+ (Static : in Mount_State;
+ Cache : in out Block_Cache;
Phys : in FSBlock_Offset;
Level : in Block_Cache_Index;
Cache_Start : out Max_Block_Index;
Cache_End : out Max_Block_Index;
Success : out Boolean)
with
- Post => Cache_End = Cache_Start + State.Block_Size - 1
+ Post => Cache_End = Cache_Start + Static.Block_Size - 1
is
begin
- Cache_FSBlock (State, Phys, Level, Cache_Label (Phys),
+ Cache_FSBlock (Static, Cache, Phys, Level, Cache_Label (Phys),
False, Cache_Start, Cache_End, Success);
end Cache_FSBlock;
- procedure Reset_Cache_Logical (State : in out T) is
+ procedure Reset_Cache_Logical (Cache : in out Block_Cache) is
begin
for I in Block_Cache_Index loop
- if State.Block_Cache_Logical (I) then
- State.Block_Cache_Logical (I) := False;
- State.Block_Cache_Label (I) := 0;
+ if Cache.Logical (I) then
+ Cache.Logical (I) := False;
+ Cache.Label (I) := 0;
end if;
end loop;
end Reset_Cache_Logical;
@@ -212,6 +215,8 @@
Physical : out FSBlock_Offset;
Success : out Boolean)
is
+ Static : constant Mount_State := State.Static;
+
Direct_Blocks : constant := 12;
type Direct_Blocks_Array is array (Natural range 0 .. Direct_Blocks - 1) of Unsigned_32;
type Inode_Blocks is record
@@ -225,7 +230,7 @@
function I_Blocks is new Ada.Unchecked_Conversion (Inode_Extents, Inode_Blocks);
function I_Blocks (State : T) return Inode_Blocks is (I_Blocks (State.Inode.Inline));
- Addr_Per_Block : constant FSBlock_Logical := FSBlock_Logical (State.Block_Size / 4);
+ Addr_Per_Block : constant FSBlock_Logical := FSBlock_Logical (Static.Block_Size / 4);
Max_Addr_Per_Block : constant FSBlock_Logical := FSBlock_Logical (Block_Size'Last / 4);
type Addr_In_Block_Range is range 0 .. Max_Addr_Per_Block - 1;
@@ -238,13 +243,14 @@
Success : out Boolean)
with
Pre =>
- Addr_Per_Block = FSBlock_Logical (State.Block_Size / 4) and
+ Addr_Per_Block = FSBlock_Logical (Static.Block_Size / 4) and
FSBlock_Logical (Addr_In_Block) < Addr_Per_Block
is
Cache_Start, Cache_End : Max_Block_Index;
begin
Cache_FSBlock
- (State => State,
+ (Static => Static,
+ Cache => State.Cache,
Phys => Indirect_Block_Phys,
Level => Level,
Label => Cache_Label (Logical_Off),
@@ -252,7 +258,7 @@
Cache_End => Cache_End,
Success => Success);
Next_Physical := FSBlock_Offset (Read_LE32
- (Buf => State.Block_Cache (Cache_Start .. Cache_End),
+ (Buf => State.Cache.Buffer (Cache_Start .. Cache_End),
Off => Natural (Addr_In_Block) * 4));
end Indirect_Block_Lookup;
@@ -346,6 +352,8 @@
Physical : out FSBlock_Offset;
Success : out Boolean)
is
+ Cache : Cache_Buffer renames State.Cache.Buffer;
+
-- Extent blocks always start with a 12B header and contain 12B entries.
-- Every entry starts with the number of the first logical block it
-- covers. Entries are sorted by this number.
@@ -376,7 +384,7 @@
Extent_Header_Magic : constant := 16#f03a#;
subtype Extent_Off is Natural range 0 .. Extent_Header_Size;
subtype Extent_Idx is Natural range 1 .. (Max_Block_Index'Last + 1) / Extent_Header_Size - 1;
- Dynamic_Max_Index : constant Extent_Idx := State.Block_Size / Extent_Header_Size - 1;
+ Dynamic_Max_Index : constant Extent_Idx := State.Static.Block_Size / Extent_Header_Size - 1;
subtype Extent_Depth is Natural range 0 .. 32;
function Extent_Byte_Offset (Idx : Extent_Idx; Off : Extent_Off) return Natural
@@ -476,12 +484,13 @@
Pre => Logical_Off <= Logical,
Post => (if Success then
Next <= Dynamic_Max_Index and then
- Cache_End = Cache_Start + State.Block_Size - 1 and then
- Extent_Logical (State.Block_Cache (Cache_Start .. Cache_End), Next) <= Logical)
+ Cache_End = Cache_Start + State.Static.Block_Size - 1 and then
+ Extent_Logical (Cache (Cache_Start .. Cache_End), Next) <= Logical)
is
begin
Cache_FSBlock
- (State => State,
+ (Static => State.Static,
+ Cache => State.Cache,
Phys => Current,
Level => Depth,
Label => Cache_Label (Logical_Off),
@@ -494,14 +503,11 @@
end if;
declare
- Hdr_Magic : constant Unsigned_16 :=
- Header_Magic (State.Block_Cache (Cache_Start .. Cache_End));
- Hdr_Entries : constant Natural :=
- Header_Entries (State.Block_Cache (Cache_Start .. Cache_End));
- Hdr_Depth : constant Natural :=
- Header_Depth (State.Block_Cache (Cache_Start .. Cache_End));
+ Hdr_Magic : constant Unsigned_16 := Header_Magic (Cache (Cache_Start .. Cache_End));
+ Hdr_Entries : constant Natural := Header_Entries (Cache (Cache_Start .. Cache_End));
+ Hdr_Depth : constant Natural := Header_Depth (Cache (Cache_Start .. Cache_End));
First_Logical : constant FSBlock_Logical :=
- Extent_Logical (State.Block_Cache (Cache_Start .. Cache_End), 1);
+ Extent_Logical (Cache (Cache_Start .. Cache_End), 1);
begin
Success := Success and then
Hdr_Magic = Extent_Header_Magic and then
@@ -512,7 +518,7 @@
if not Success then
Next := 1;
else
- Next := Bin_Search (State.Block_Cache (Cache_Start .. Cache_End), Hdr_Entries);
+ Next := Bin_Search (Cache (Cache_Start .. Cache_End), Hdr_Entries);
end if;
end;
end Next_Ref;
@@ -565,13 +571,13 @@
end if;
exit when Depth = 0;
- Physical := Index_Physical (State.Block_Cache (Cache_Start .. Cache_End), Idx);
- Logical_Off := Index_Logical (State.Block_Cache (Cache_Start .. Cache_End), Idx);
+ Physical := Index_Physical (Cache (Cache_Start .. Cache_End), Idx);
+ Logical_Off := Index_Logical (Cache (Cache_Start .. Cache_End), Idx);
end loop;
- Physical := Extent_Physical (State.Block_Cache (Cache_Start .. Cache_End), Idx);
- Logical_Off := Extent_Logical (State.Block_Cache (Cache_Start .. Cache_End), Idx);
- Length := Extent_Length (State.Block_Cache (Cache_Start .. Cache_End), Idx);
+ Physical := Extent_Physical (Cache (Cache_Start .. Cache_End), Idx);
+ Logical_Off := Extent_Logical (Cache (Cache_Start .. Cache_End), Idx);
+ Length := Extent_Length (Cache (Cache_Start .. Cache_End), Idx);
end if;
Success :=
@@ -591,12 +597,15 @@
Pre => Is_Mounted (State) and not Is_Open (State),
Post => Success = Is_Open (State)
is
+ Static : Mount_State renames State.Static;
+ Cache : Cache_Buffer renames State.Cache.Buffer;
+
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);
- Inodes_Per_Block : constant Inode_Index := Inode_Index (State.Block_Size / State.Inode_Size);
- Desc_Per_Block : constant Group_Index := Group_Index (State.Block_Size / State.Desc_Size);
+ Inodes_Per_Block : constant Inode_Index := Inode_Index (Static.Block_Size / Static.Inode_Size);
+ Desc_Per_Block : constant Group_Index := Group_Index (Static.Block_Size / Static.Desc_Size);
------------------------
-- Group deserialization
@@ -604,12 +613,12 @@
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);
+ (Natural (Idx) * Static.Desc_Size + Off);
function Group_Inode_Table (Buf : Buffer_Type; Idx : Group_Index) return FSBlock_Offset
is
(FSBlock_Offset (
- (if State.Feature_64Bit
+ (if Static.Feature_64Bit
then Shift_Left (Unsigned_64 (Read_LE32 (Buf, Group_Byte_Offset (Idx, 40))), 32)
else 0)
or
@@ -623,7 +632,7 @@
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);
+ (Natural (Idx) * Static.Inode_Size + Off);
function Inode_Mode (Buf : Buffer_Type; Idx : Inode_Index) return Unsigned_16
is
@@ -658,13 +667,14 @@
with
Pre => Buf'Length >= Inode_Byte_Offset (Idx, 108);
- Group : constant Group_Index := Group_Index ((Inode - 1) / State.Inodes_Per_Group);
+ Group : constant Group_Index := Group_Index ((Inode - 1) / Static.Inodes_Per_Group);
Desc_Block : constant FSBlock_Offset :=
- 1 + State.First_Data_Block + FSBlock_Offset (Group / Desc_Per_Block);
+ 1 + Static.First_Data_Block + FSBlock_Offset (Group / Desc_Per_Block);
Cache_Start, Cache_End : Max_Block_Index;
begin
Cache_FSBlock
- (State => State,
+ (Static => Static,
+ Cache => State.Cache,
Phys => Desc_Block,
Level => Natural'Min (Natural (Group / Desc_Per_Block), Block_Cache_Index'Last),
Cache_Start => Cache_Start,
@@ -676,13 +686,14 @@
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_In_Group : constant Inode_Index := (Inode - 1) mod Static.Inodes_Per_Group;
Inode_Block : constant FSBlock_Offset :=
- Group_Inode_Table (State.Block_Cache (Cache_Start .. Cache_End), Group) +
+ Group_Inode_Table (Cache (Cache_Start .. Cache_End), Group) +
FSBlock_Offset (Inode_In_Group / Inodes_Per_Block);
begin
Cache_FSBlock
- (State => State,
+ (Static => Static,
+ Cache => State.Cache,
Phys => Inode_Block,
Level => Block_Cache_Index'Last,
Cache_Start => Cache_Start,
@@ -700,9 +711,9 @@
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);
+ Inode_Mode (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);
+ Inode_Flags (Cache (Cache_Start .. Cache_End), Inode_In_Block);
begin
case I_Mode and S_IFMT is
when S_IFDIR => State.Inode.Mode := Dir;
@@ -713,12 +724,12 @@
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);
+ 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);
+ 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))
+ (I_File_ACL /= 0 and I_Blocks = 2 ** (Static.Block_Size_Bits - 9))
then
State.Inode.Mode := Fast_Link;
end if;
@@ -726,7 +737,7 @@
end if;
declare
I_Size : constant Unsigned_64 := Inode_Size (
- State.Block_Cache (Cache_Start .. Cache_End), Inode_In_Block, State.Inode.Mode);
+ 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);
@@ -734,10 +745,10 @@
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);
+ State.Inode.Use_Extents := Static.Feature_Extents and (I_Flags and EXT4_EXTENTS_FL) /= 0;
+ State.Inode.Inline := Cache (Cache_Start + 40 .. Cache_Start + 100 - 1);
State.Inode.I := Inode;
- Reset_Cache_Logical (State);
+ Reset_Cache_Logical (State.Cache);
State.S := File_Opened;
end;
end;
@@ -870,6 +881,9 @@
Buf : out Buffer_Type;
Len : out Natural)
is
+ Static : Mount_State renames State.Static;
+ Cache : Cache_Buffer renames State.Cache.Buffer;
+
Pos : Natural;
begin
if State.Inode.Mode = Fast_Link then
@@ -890,9 +904,9 @@
Pos := Buf'First;
while Pos <= Buf'Last and Inode_Length (File_Pos) < State.Inode.Size loop
declare
- In_Block : constant Max_Block_Index := Natural (File_Pos) mod State.Block_Size;
- Logical : constant FSBlock_Logical := FSBlock_Logical (File_Pos / File_Offset (State.Block_Size));
- In_Block_Space : constant Natural := Natural (State.Block_Size) - In_Block;
+ In_Block : constant Max_Block_Index := Natural (File_Pos) mod Static.Block_Size;
+ Logical : constant FSBlock_Logical := FSBlock_Logical (File_Pos / File_Offset (Static.Block_Size));
+ In_Block_Space : constant Natural := Natural (Static.Block_Size) - In_Block;
In_File_Space : constant Inode_Length := State.Inode.Size - Inode_Length (File_Pos);
In_Buf_Space : constant Natural := Buf'Last - Pos + 1;
Len_Here : Natural;
@@ -918,7 +932,8 @@
end if;
if Success then
Cache_FSBlock
- (State => State,
+ (Static => Static,
+ Cache => State.Cache,
Phys => Physical,
Level => Block_Cache_Index'Last,
Cache_Start => Cache_Start,
@@ -927,7 +942,7 @@
end if;
exit when not Success;
- Buf (Pos .. Last) := State.Block_Cache (
+ Buf (Pos .. Last) := Cache (
Cache_Start + In_Block .. Cache_Start + In_Block + Len_Here - 1);
File_Pos := File_Pos + File_Length (Len_Here);
Pos := Pos + Len_Here;
diff --git a/src/filo-fs-ext2.ads b/src/filo-fs-ext2.ads
index a13b153..7c1e467 100644
--- a/src/filo-fs-ext2.ads
+++ b/src/filo-fs-ext2.ads
@@ -63,6 +63,7 @@
subtype Block_Cache_Index is Natural range 0 .. 63;
type Cache_Label_Logical is array (Block_Cache_Index) of Boolean;
type Cache_Label_Array is array (Block_Cache_Index) of Cache_Label;
+ subtype Cache_Buffer is Buffer_Type (Max_Block_Index);
-- Same as the 12 direct + 3 indirect blocks times 4B:
subtype Inode_Extents_Index is Natural range 0 .. 59;
@@ -85,8 +86,7 @@
Inline : Inode_Extents := (others => 16#00#);
end record;
- type T is record
- S : State;
+ type Mount_State is record
Part_Len : Partition_Length := 0;
First_Data_Block : FSBlock_Offset := 0;
Block_Size_Bits : Log_Block_Size := Log_Block_Size'First;
@@ -96,11 +96,20 @@
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#);
+ end record;
+
+ type Block_Cache is record
+ Logical : Cache_Label_Logical := (others => False);
+ Label : Cache_Label_Array := (others => 0);
+ Buffer : Cache_Buffer := (others => 16#00#);
+ end record;
+
+ type T is record
+ Static : Mount_State := (others => <>);
+ S : State;
+ Inode : Inode_Info := (others => <>);
+ Cur_Dir : Inode_Index := Inode_Index'First;
+ Cache : Block_Cache := (others => <>);
end record;
end FILO.FS.Ext2;