blob: c48ee93d584fe9cd95fedeacf9715c6dfd69e769 [file] [log] [blame]
package FILO.FS.Ext2 is
type T is private;
function Is_Mounted (State : T) return Boolean;
function Is_Open (State : T) return Boolean
with
Post => (if Is_Open'Result then Is_Mounted (State));
procedure Mount
(State : in out T;
Part_Len : in Partition_Length;
Success : out Boolean)
with
Pre => not Is_Mounted (State),
Post => Success = Is_Mounted (State);
procedure Open
(State : in out T;
File_Len : out File_Length;
File_Type : out FS.File_Type;
File_Name : in String;
In_Root : in Boolean;
Success : out Boolean)
with
Pre => Is_Mounted (State),
Post => Success = Is_Open (State);
procedure Close (State : in out T)
with
Pre => Is_Open (State),
Post => Is_Mounted (State);
procedure Read
(State : in out T;
File_Pos : in out File_Offset;
Buf : out Buffer_Type;
Len : out Natural)
with
Pre => Is_Open (State),
Post => Is_Open (State);
private
type State is (Unmounted, Mounted, File_Opened);
-- maximum block size is 64KiB (2^16):
subtype Log_Block_Size is Positive range 10 .. 16;
subtype Block_Size is Natural range 2 ** Log_Block_Size'First .. 2 ** Log_Block_Size'Last;
subtype Max_Block_Index is Index_Type range 0 .. 2 ** Log_Block_Size'Last - 1;
-- Extent physical addresses are 48 bits.
type FSBlock_Offset is new Block_Offset range 0 .. 2 ** 48 - 1;
-- Logical block addresses are 32 bits.
type FSBlock_Logical is new Block_Offset range 0 .. 2 ** 32 - 1;
-- We use a 64KiB cache which fits at least one ext2 block. If a lower
-- block size is encountered (likely), we partition the cache into up
-- to 64 1KiB blocks.
-- Cache entries can be used for blocks that map logical block offets
-- to physical ones. Then we note the first logical block offset mapped
-- by the cached block. Otherwise, we use their physical offset.
type Cache_Label is new Unsigned_64;
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;
subtype Inode_Extents is Buffer_Type (Inode_Extents_Index)
with
Object_Size => (Inode_Extents_Index'Last + 1) * 8;
-- TODO: Could use modular Unsigned_32 if GNATprove wouldn't stumble as much:
type Inode_0_Index is new Integer_64 range 0 .. Integer_64 (Unsigned_32'Last);
subtype Inode_Index is Inode_0_Index range 2 .. Inode_0_Index'Last;
subtype Inode_Size is Positive range 128 .. Positive (Unsigned_16'Last);
subtype Group_Desc_Size is Positive range 32 .. 2 ** 15; -- power-of-2 that fits in 16 bits
type Inode_Type is (Dir, Regular, Link, Fast_Link);
type Inode_Length is range 0 .. 2 ** 46;
type Inode_Info is record
I : Inode_Index := Inode_Index'First;
Mode : Inode_Type := Inode_Type'First;
Size : Inode_Length := 0;
Use_Extents : Boolean := False;
Inline : Inode_Extents := (others => 16#00#);
end record;
type Group_Index is new Inode_0_Index;
subtype Group_In_Block_Count is Group_Index
range 1 .. Group_Index (Block_Size'Last / Group_Desc_Size'First);
type Group_In_Block_Index is new Natural range 0 .. Natural (Group_In_Block_Count'Last - 1);
subtype Inode_In_Group_Count is Inode_0_Index range 1 .. Inode_0_Index'Last;
type Inode_In_Group_Index is new Inode_0_Index range 0 .. Inode_In_Group_Count'Last - 1;
subtype Inode_In_Block_Count is Inode_In_Group_Index
range 1 .. Inode_In_Group_Index (Block_Size'Last / Inode_Size'First);
type Inode_In_Block_Index is new Natural range 0 .. Natural (Inode_In_Block_Count'Last - 1);
type Mount_State is record
Part_Len : Partition_Length := 0;
First_Data_Block : Unsigned_32 := Unsigned_32'First;
Block_Size_Bits : Log_Block_Size := Log_Block_Size'First;
Block_Size : Ext2.Block_Size := Ext2.Block_Size'First;
Inodes_Per_Group : Inode_In_Group_Count := Inode_In_Group_Count'First;
Inode_Size : Ext2.Inode_Size := Ext2.Inode_Size'First;
Inodes_Per_Block : Inode_In_Block_Count := Inode_In_Block_Count'First;
Group_Desc_Size : Ext2.Group_Desc_Size := Ext2.Group_Desc_Size'First;
Group_Desc_Per_Block : Group_In_Block_Count := Group_In_Block_Count'First;
Feature_Extents : Boolean := False;
Feature_64Bit : Boolean := False;
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;