Thomas Heijligen | 5c43abc | 2023-12-11 15:24:36 +0000 | [diff] [blame] | 1 | package FILO.FS.Ext2 is |
Nico Huber | 1d7727f | 2023-11-30 15:58:46 +0100 | [diff] [blame] | 2 | |
Nico Huber | 57d3a85 | 2023-12-04 15:42:40 +0100 | [diff] [blame] | 3 | type T is private; |
Nico Huber | 1d7727f | 2023-11-30 15:58:46 +0100 | [diff] [blame] | 4 | |
Nico Huber | 57d3a85 | 2023-12-04 15:42:40 +0100 | [diff] [blame] | 5 | function Is_Mounted (State : T) return Boolean; |
| 6 | function Is_Open (State : T) return Boolean |
Nico Huber | 1d7727f | 2023-11-30 15:58:46 +0100 | [diff] [blame] | 7 | with |
Nico Huber | 57d3a85 | 2023-12-04 15:42:40 +0100 | [diff] [blame] | 8 | Post => (if Is_Open'Result then Is_Mounted (State)); |
Nico Huber | 1d7727f | 2023-11-30 15:58:46 +0100 | [diff] [blame] | 9 | |
Nico Huber | 57d3a85 | 2023-12-04 15:42:40 +0100 | [diff] [blame] | 10 | procedure Mount |
| 11 | (State : in out T; |
| 12 | Part_Len : in Partition_Length; |
| 13 | Success : out Boolean) |
Nico Huber | 1d7727f | 2023-11-30 15:58:46 +0100 | [diff] [blame] | 14 | with |
Nico Huber | 57d3a85 | 2023-12-04 15:42:40 +0100 | [diff] [blame] | 15 | Pre => not Is_Mounted (State), |
| 16 | Post => Success = Is_Mounted (State); |
Nico Huber | 1d7727f | 2023-11-30 15:58:46 +0100 | [diff] [blame] | 17 | |
Nico Huber | 57d3a85 | 2023-12-04 15:42:40 +0100 | [diff] [blame] | 18 | procedure Open |
| 19 | (State : in out T; |
| 20 | File_Len : out File_Length; |
Nico Huber | b1cb2d3 | 2023-12-17 01:45:47 +0100 | [diff] [blame] | 21 | File_Type : out FS.File_Type; |
| 22 | File_Name : in String; |
| 23 | In_Root : in Boolean; |
Nico Huber | 57d3a85 | 2023-12-04 15:42:40 +0100 | [diff] [blame] | 24 | Success : out Boolean) |
Nico Huber | 1d7727f | 2023-11-30 15:58:46 +0100 | [diff] [blame] | 25 | with |
Nico Huber | b1cb2d3 | 2023-12-17 01:45:47 +0100 | [diff] [blame] | 26 | Pre => Is_Mounted (State), |
Nico Huber | 53df785 | 2024-01-15 18:36:04 +0100 | [diff] [blame] | 27 | Post => (if Success then Is_Open (State) else Is_Mounted (State)); |
Nico Huber | 57d3a85 | 2023-12-04 15:42:40 +0100 | [diff] [blame] | 28 | |
| 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 Huber | 57d3a85 | 2023-12-04 15:42:40 +0100 | [diff] [blame] | 36 | File_Pos : in out File_Offset; |
| 37 | Buf : out Buffer_Type; |
| 38 | Len : out Natural) |
| 39 | with |
Nico Huber | b735a1d | 2024-02-05 11:43:12 +0100 | [diff] [blame^] | 40 | Relaxed_Initialization => Buf, |
Nico Huber | 53df785 | 2024-01-15 18:36:04 +0100 | [diff] [blame] | 41 | Pre => Is_Open (State) and Buf'Length > 0, |
Nico Huber | b735a1d | 2024-02-05 11:43:12 +0100 | [diff] [blame^] | 42 | Post => Is_Open (State) and Buf'Initialized; |
Nico Huber | 57d3a85 | 2023-12-04 15:42:40 +0100 | [diff] [blame] | 43 | |
| 44 | private |
| 45 | type State is (Unmounted, Mounted, File_Opened); |
| 46 | |
Nico Huber | 26f7183 | 2023-12-05 16:26:56 +0100 | [diff] [blame] | 47 | -- maximum block size is 64KiB (2^16): |
| 48 | subtype Log_Block_Size is Positive range 10 .. 16; |
Nico Huber | 700a411 | 2024-01-08 15:50:09 +0100 | [diff] [blame] | 49 | subtype Block_Size is Natural range 2 ** Log_Block_Size'First .. 2 ** Log_Block_Size'Last; |
Nico Huber | 6623c98 | 2023-12-12 16:35:46 +0100 | [diff] [blame] | 50 | subtype Max_Block_Index is Index_Type range 0 .. 2 ** Log_Block_Size'Last - 1; |
| 51 | |
Nico Huber | 5a042fd | 2024-01-08 15:54:57 +0100 | [diff] [blame] | 52 | -- 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 Huber | 6623c98 | 2023-12-12 16:35:46 +0100 | [diff] [blame] | 56 | |
Nico Huber | fe89712 | 2023-12-12 21:33:36 +0100 | [diff] [blame] | 57 | -- 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 Huber | fe89712 | 2023-12-12 21:33:36 +0100 | [diff] [blame] | 60 | subtype Block_Cache_Index is Natural range 0 .. 63; |
Nico Huber | 6bef924 | 2024-01-26 23:47:49 +0100 | [diff] [blame] | 61 | 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 Huber | 52f4c8d | 2024-01-09 13:57:33 +0100 | [diff] [blame] | 67 | subtype Cache_Buffer is Buffer_Type (Max_Block_Index); |
Nico Huber | 6623c98 | 2023-12-12 16:35:46 +0100 | [diff] [blame] | 68 | |
Nico Huber | fffc8c1 | 2023-12-13 12:44:12 +0100 | [diff] [blame] | 69 | -- Same as the 12 direct + 3 indirect blocks times 4B: |
| 70 | subtype Inode_Extents_Index is Natural range 0 .. 59; |
Nico Huber | 5a042fd | 2024-01-08 15:54:57 +0100 | [diff] [blame] | 71 | subtype Inode_Extents is Buffer_Type (Inode_Extents_Index) |
| 72 | with |
| 73 | Object_Size => (Inode_Extents_Index'Last + 1) * 8; |
Nico Huber | fffc8c1 | 2023-12-13 12:44:12 +0100 | [diff] [blame] | 74 | |
Nico Huber | fe26032 | 2024-01-10 17:59:57 +0100 | [diff] [blame] | 75 | -- 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 Huber | 925326e | 2024-01-09 18:46:26 +0100 | [diff] [blame] | 77 | subtype Inode_Index is Inode_0_Index range 2 .. Inode_0_Index'Last; |
Nico Huber | 26f7183 | 2023-12-05 16:26:56 +0100 | [diff] [blame] | 78 | subtype Inode_Size is Positive range 128 .. Positive (Unsigned_16'Last); |
Nico Huber | 7eb5692 | 2024-01-10 17:22:54 +0100 | [diff] [blame] | 79 | subtype Group_Desc_Size is Positive range 32 .. 2 ** 15; -- power-of-2 that fits in 16 bits |
Nico Huber | 26f7183 | 2023-12-05 16:26:56 +0100 | [diff] [blame] | 80 | |
Nico Huber | 022e226 | 2023-12-15 23:15:17 +0100 | [diff] [blame] | 81 | type Inode_Type is (Dir, Regular, Link, Fast_Link); |
| 82 | type Inode_Length is range 0 .. 2 ** 46; |
| 83 | |
Nico Huber | ea1de11 | 2024-01-27 18:52:12 +0100 | [diff] [blame] | 84 | type Inode_Map_Cache is record |
| 85 | Phys : FSBlock_Offset := 0; |
| 86 | Logical : Block_Offset := Block_Offset'Last; |
| 87 | end record; |
| 88 | |
Nico Huber | 33f6d95 | 2023-12-13 23:16:42 +0100 | [diff] [blame] | 89 | type Inode_Info is record |
Nico Huber | 89d0594 | 2023-12-18 12:12:00 +0100 | [diff] [blame] | 90 | I : Inode_Index := Inode_Index'First; |
Nico Huber | 022e226 | 2023-12-15 23:15:17 +0100 | [diff] [blame] | 91 | Mode : Inode_Type := Inode_Type'First; |
| 92 | Size : Inode_Length := 0; |
Nico Huber | cdc0351 | 2023-12-13 23:32:54 +0100 | [diff] [blame] | 93 | Use_Extents : Boolean := False; |
Nico Huber | 5a042fd | 2024-01-08 15:54:57 +0100 | [diff] [blame] | 94 | Inline : Inode_Extents := (others => 16#00#); |
Nico Huber | ea1de11 | 2024-01-27 18:52:12 +0100 | [diff] [blame] | 95 | Map_Cache : Inode_Map_Cache := (others => <>); |
Nico Huber | 33f6d95 | 2023-12-13 23:16:42 +0100 | [diff] [blame] | 96 | end record; |
| 97 | |
Nico Huber | 925326e | 2024-01-09 18:46:26 +0100 | [diff] [blame] | 98 | type Group_Index is new Inode_0_Index; |
Nico Huber | ecafb8f | 2024-01-09 15:45:49 +0100 | [diff] [blame] | 99 | subtype Group_In_Block_Count is Group_Index |
Nico Huber | 7eb5692 | 2024-01-10 17:22:54 +0100 | [diff] [blame] | 100 | 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 Huber | ecafb8f | 2024-01-09 15:45:49 +0100 | [diff] [blame] | 102 | |
Nico Huber | 925326e | 2024-01-09 18:46:26 +0100 | [diff] [blame] | 103 | 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 Huber | ecafb8f | 2024-01-09 15:45:49 +0100 | [diff] [blame] | 105 | 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 Huber | 52f4c8d | 2024-01-09 13:57:33 +0100 | [diff] [blame] | 109 | type Mount_State is record |
Nico Huber | 57dfbfb | 2023-12-13 23:24:16 +0100 | [diff] [blame] | 110 | Part_Len : Partition_Length := 0; |
Nico Huber | 39f086c | 2024-01-09 17:43:06 +0100 | [diff] [blame] | 111 | First_Data_Block : Unsigned_32 := Unsigned_32'First; |
Nico Huber | 700a411 | 2024-01-08 15:50:09 +0100 | [diff] [blame] | 112 | Block_Size_Bits : Log_Block_Size := Log_Block_Size'First; |
| 113 | Block_Size : Ext2.Block_Size := Ext2.Block_Size'First; |
Nico Huber | 925326e | 2024-01-09 18:46:26 +0100 | [diff] [blame] | 114 | Inodes_Per_Group : Inode_In_Group_Count := Inode_In_Group_Count'First; |
Nico Huber | 57dfbfb | 2023-12-13 23:24:16 +0100 | [diff] [blame] | 115 | Inode_Size : Ext2.Inode_Size := Ext2.Inode_Size'First; |
Nico Huber | ecafb8f | 2024-01-09 15:45:49 +0100 | [diff] [blame] | 116 | Inodes_Per_Block : Inode_In_Block_Count := Inode_In_Block_Count'First; |
Nico Huber | 7eb5692 | 2024-01-10 17:22:54 +0100 | [diff] [blame] | 117 | 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 Huber | 57dfbfb | 2023-12-13 23:24:16 +0100 | [diff] [blame] | 119 | Feature_Extents : Boolean := False; |
| 120 | Feature_64Bit : Boolean := False; |
Nico Huber | 52f4c8d | 2024-01-09 13:57:33 +0100 | [diff] [blame] | 121 | end record; |
| 122 | |
| 123 | type Block_Cache is record |
Nico Huber | 6bef924 | 2024-01-26 23:47:49 +0100 | [diff] [blame] | 124 | Phys : Cache_Label := (others => 0); |
Nico Huber | 52f4c8d | 2024-01-09 13:57:33 +0100 | [diff] [blame] | 125 | 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 Huber | 57d3a85 | 2023-12-04 15:42:40 +0100 | [diff] [blame] | 134 | end record; |
Nico Huber | 1d7727f | 2023-11-30 15:58:46 +0100 | [diff] [blame] | 135 | |
Thomas Heijligen | 5c43abc | 2023-12-11 15:24:36 +0000 | [diff] [blame] | 136 | end FILO.FS.Ext2; |