blob: 31a679e9fb067afad971b160f5fade1c3d36ce54 [file] [log] [blame]
Thomas Heijligen5c43abc2023-12-11 15:24:36 +00001package FILO.FS.Ext2 is
Nico Huber1d7727f2023-11-30 15:58:46 +01002
Nico Huber57d3a852023-12-04 15:42:40 +01003 type T is private;
Nico Huber1d7727f2023-11-30 15:58:46 +01004
Nico Huber57d3a852023-12-04 15:42:40 +01005 function Is_Mounted (State : T) return Boolean;
6 function Is_Open (State : T) return Boolean
Nico Huber1d7727f2023-11-30 15:58:46 +01007 with
Nico Huber57d3a852023-12-04 15:42:40 +01008 Post => (if Is_Open'Result then Is_Mounted (State));
Nico Huber1d7727f2023-11-30 15:58:46 +01009
Nico Huber57d3a852023-12-04 15:42:40 +010010 procedure Mount
11 (State : in out T;
12 Part_Len : in Partition_Length;
13 Success : out Boolean)
Nico Huber1d7727f2023-11-30 15:58:46 +010014 with
Nico Huber57d3a852023-12-04 15:42:40 +010015 Pre => not Is_Mounted (State),
16 Post => Success = Is_Mounted (State);
Nico Huber1d7727f2023-11-30 15:58:46 +010017
Nico Huber57d3a852023-12-04 15:42:40 +010018 procedure Open
19 (State : in out T;
20 File_Len : out File_Length;
Nico Huberb1cb2d32023-12-17 01:45:47 +010021 File_Type : out FS.File_Type;
22 File_Name : in String;
23 In_Root : in Boolean;
Nico Huber57d3a852023-12-04 15:42:40 +010024 Success : out Boolean)
Nico Huber1d7727f2023-11-30 15:58:46 +010025 with
Nico Huberb1cb2d32023-12-17 01:45:47 +010026 Pre => Is_Mounted (State),
Nico Huber53df7852024-01-15 18:36:04 +010027 Post => (if Success then Is_Open (State) else Is_Mounted (State));
Nico Huber57d3a852023-12-04 15:42:40 +010028
29 procedure Close (State : in out T)
30 with
31 Pre => Is_Open (State),
32 Post => Is_Mounted (State);
33
34 procedure Read
35 (State : in out T;
Nico Huber57d3a852023-12-04 15:42:40 +010036 File_Pos : in out File_Offset;
37 Buf : out Buffer_Type;
38 Len : out Natural)
39 with
Nico Huberb735a1d2024-02-05 11:43:12 +010040 Relaxed_Initialization => Buf,
Nico Huber53df7852024-01-15 18:36:04 +010041 Pre => Is_Open (State) and Buf'Length > 0,
Nico Huberb735a1d2024-02-05 11:43:12 +010042 Post => Is_Open (State) and Buf'Initialized;
Nico Huber57d3a852023-12-04 15:42:40 +010043
44private
45 type State is (Unmounted, Mounted, File_Opened);
46
Nico Huber26f71832023-12-05 16:26:56 +010047 -- maximum block size is 64KiB (2^16):
48 subtype Log_Block_Size is Positive range 10 .. 16;
Nico Huber700a4112024-01-08 15:50:09 +010049 subtype Block_Size is Natural range 2 ** Log_Block_Size'First .. 2 ** Log_Block_Size'Last;
Nico Huber6623c982023-12-12 16:35:46 +010050 subtype Max_Block_Index is Index_Type range 0 .. 2 ** Log_Block_Size'Last - 1;
51
Nico Huber5a042fd2024-01-08 15:54:57 +010052 -- Extent physical addresses are 48 bits.
53 type FSBlock_Offset is new Block_Offset range 0 .. 2 ** 48 - 1;
54 -- Logical block addresses are 32 bits.
55 type FSBlock_Logical is new Block_Offset range 0 .. 2 ** 32 - 1;
Nico Huber6623c982023-12-12 16:35:46 +010056
Nico Huberfe897122023-12-12 21:33:36 +010057 -- We use a 64KiB cache which fits at least one ext2 block. If a lower
58 -- block size is encountered (likely), we partition the cache into up
59 -- to 64 1KiB blocks.
Nico Huberfe897122023-12-12 21:33:36 +010060 subtype Block_Cache_Index is Natural range 0 .. 63;
Nico Huber6bef9242024-01-26 23:47:49 +010061 File_Cache_Level : constant := 0; -- Use a single cache block each for
62 Inode_Cache_Level : constant := 1; -- file contents, the inode block,
63 Group_Cache_Level : constant := 2; -- the group block.
64 Block_Map_Cache_Level : constant := 3; -- Use all other cache blocks for
65 -- mapping file content blocks.
66 type Cache_Label is array (Block_Cache_Index) of FSBlock_Offset;
Nico Huber52f4c8d2024-01-09 13:57:33 +010067 subtype Cache_Buffer is Buffer_Type (Max_Block_Index);
Nico Huber6623c982023-12-12 16:35:46 +010068
Nico Huberfffc8c12023-12-13 12:44:12 +010069 -- Same as the 12 direct + 3 indirect blocks times 4B:
70 subtype Inode_Extents_Index is Natural range 0 .. 59;
Nico Huber5a042fd2024-01-08 15:54:57 +010071 subtype Inode_Extents is Buffer_Type (Inode_Extents_Index)
72 with
73 Object_Size => (Inode_Extents_Index'Last + 1) * 8;
Nico Huberfffc8c12023-12-13 12:44:12 +010074
Nico Huberfe260322024-01-10 17:59:57 +010075 -- TODO: Could use modular Unsigned_32 if GNATprove wouldn't stumble as much:
76 type Inode_0_Index is new Integer_64 range 0 .. Integer_64 (Unsigned_32'Last);
Nico Huber925326e2024-01-09 18:46:26 +010077 subtype Inode_Index is Inode_0_Index range 2 .. Inode_0_Index'Last;
Nico Huber26f71832023-12-05 16:26:56 +010078 subtype Inode_Size is Positive range 128 .. Positive (Unsigned_16'Last);
Nico Huber7eb56922024-01-10 17:22:54 +010079 subtype Group_Desc_Size is Positive range 32 .. 2 ** 15; -- power-of-2 that fits in 16 bits
Nico Huber26f71832023-12-05 16:26:56 +010080
Nico Huber022e2262023-12-15 23:15:17 +010081 type Inode_Type is (Dir, Regular, Link, Fast_Link);
82 type Inode_Length is range 0 .. 2 ** 46;
83
Nico Huberea1de112024-01-27 18:52:12 +010084 type Inode_Map_Cache is record
85 Phys : FSBlock_Offset := 0;
86 Logical : Block_Offset := Block_Offset'Last;
87 end record;
88
Nico Huber33f6d952023-12-13 23:16:42 +010089 type Inode_Info is record
Nico Huber89d05942023-12-18 12:12:00 +010090 I : Inode_Index := Inode_Index'First;
Nico Huber022e2262023-12-15 23:15:17 +010091 Mode : Inode_Type := Inode_Type'First;
92 Size : Inode_Length := 0;
Nico Hubercdc03512023-12-13 23:32:54 +010093 Use_Extents : Boolean := False;
Nico Huber5a042fd2024-01-08 15:54:57 +010094 Inline : Inode_Extents := (others => 16#00#);
Nico Huberea1de112024-01-27 18:52:12 +010095 Map_Cache : Inode_Map_Cache := (others => <>);
Nico Huber33f6d952023-12-13 23:16:42 +010096 end record;
97
Nico Huber925326e2024-01-09 18:46:26 +010098 type Group_Index is new Inode_0_Index;
Nico Huberecafb8f2024-01-09 15:45:49 +010099 subtype Group_In_Block_Count is Group_Index
Nico Huber7eb56922024-01-10 17:22:54 +0100100 range 1 .. Group_Index (Block_Size'Last / Group_Desc_Size'First);
101 type Group_In_Block_Index is new Natural range 0 .. Natural (Group_In_Block_Count'Last - 1);
Nico Huberecafb8f2024-01-09 15:45:49 +0100102
Nico Huber925326e2024-01-09 18:46:26 +0100103 subtype Inode_In_Group_Count is Inode_0_Index range 1 .. Inode_0_Index'Last;
104 type Inode_In_Group_Index is new Inode_0_Index range 0 .. Inode_In_Group_Count'Last - 1;
Nico Huberecafb8f2024-01-09 15:45:49 +0100105 subtype Inode_In_Block_Count is Inode_In_Group_Index
106 range 1 .. Inode_In_Group_Index (Block_Size'Last / Inode_Size'First);
107 type Inode_In_Block_Index is new Natural range 0 .. Natural (Inode_In_Block_Count'Last - 1);
108
Nico Huber52f4c8d2024-01-09 13:57:33 +0100109 type Mount_State is record
Nico Huber57dfbfb2023-12-13 23:24:16 +0100110 Part_Len : Partition_Length := 0;
Nico Huber39f086c2024-01-09 17:43:06 +0100111 First_Data_Block : Unsigned_32 := Unsigned_32'First;
Nico Huber700a4112024-01-08 15:50:09 +0100112 Block_Size_Bits : Log_Block_Size := Log_Block_Size'First;
113 Block_Size : Ext2.Block_Size := Ext2.Block_Size'First;
Nico Huber925326e2024-01-09 18:46:26 +0100114 Inodes_Per_Group : Inode_In_Group_Count := Inode_In_Group_Count'First;
Nico Huber57dfbfb2023-12-13 23:24:16 +0100115 Inode_Size : Ext2.Inode_Size := Ext2.Inode_Size'First;
Nico Huberecafb8f2024-01-09 15:45:49 +0100116 Inodes_Per_Block : Inode_In_Block_Count := Inode_In_Block_Count'First;
Nico Huber7eb56922024-01-10 17:22:54 +0100117 Group_Desc_Size : Ext2.Group_Desc_Size := Ext2.Group_Desc_Size'First;
118 Group_Desc_Per_Block : Group_In_Block_Count := Group_In_Block_Count'First;
Nico Huber57dfbfb2023-12-13 23:24:16 +0100119 Feature_Extents : Boolean := False;
120 Feature_64Bit : Boolean := False;
Nico Huber52f4c8d2024-01-09 13:57:33 +0100121 end record;
122
123 type Block_Cache is record
Nico Huber6bef9242024-01-26 23:47:49 +0100124 Phys : Cache_Label := (others => 0);
Nico Huber52f4c8d2024-01-09 13:57:33 +0100125 Buffer : Cache_Buffer := (others => 16#00#);
126 end record;
127
128 type T is record
129 Static : Mount_State := (others => <>);
130 S : State;
131 Inode : Inode_Info := (others => <>);
132 Cur_Dir : Inode_Index := Inode_Index'First;
133 Cache : Block_Cache := (others => <>);
Nico Huber57d3a852023-12-04 15:42:40 +0100134 end record;
Nico Huber1d7727f2023-11-30 15:58:46 +0100135
Thomas Heijligen5c43abc2023-12-11 15:24:36 +0000136end FILO.FS.Ext2;