blob: 388f2cbe4dfe12ed507e2cbe7e115cfe87657c4d [file] [log] [blame]
with Ada.Unchecked_Conversion;
with Interfaces.C;
with Interfaces.C.Strings;
use Interfaces.C;
package body FILO.FS.VFS
with
SPARK_Mode => Off
is
State : T := Initial;
Path_Max : constant := 4096;
Max_Link_Depth : constant := 32;
subtype Path_Buffer is Buffer_Type (1 .. Path_Max);
Path_Buf : Path_Buffer;
subtype Path_String is String (1 .. Path_Max);
Path : Path_String;
function C_Mount return int
is
Success : Boolean;
begin
if not Is_Mounted (State) then
State := Initial; -- Work around not having an unmount in FILO.
end if;
Mount (State, Part_Len, Success);
return (if Success then 1 else 0);
end C_Mount;
function C_Open (File_Path : Strings.chars_ptr) return int
is
function Component_Start (Path : String; Pos : Positive) return Positive is
begin
for I in Pos .. Path'Last loop
if Path (I) /= '/' then
return I;
end if;
end loop;
return Path'Last + 1;
end Component_Start;
function Component_End (Path : String; Start : Positive) return Positive is
begin
for I in Start .. Path'Last loop
if Path (I) = '/' or Is_Space (Path (I)) then
return I - 1;
end if;
end loop;
return Path'Last;
end Component_End;
function Path_End (Path : String; Start : Positive) return Positive is
begin
for I in Start .. Path'Last loop
if Is_Space (Path (I)) then
return I - 1;
end if;
end loop;
return Path'Last;
end Path_End;
procedure Read_Link
(Path : in out Path_String;
Rest_First : in Positive;
Rest_Last : in Positive;
Link_Len : in Natural;
Success : out Boolean)
is
function As_String is new Ada.Unchecked_Conversion (Path_Buffer, Path_String);
Rest_Len : constant Natural := Rest_Last - Rest_First + 1;
File_Pos : File_Offset := 0;
Read_Len : Natural;
begin
if Path_Max - Rest_Len < Link_Len then
Success := False;
return;
end if;
Read
(State => State,
File_Pos => File_Pos,
Buf => Path_Buf (1 .. Link_Len),
Len => Read_Len);
Success := Read_Len = Link_Len;
if Success then
Path (Link_Len + 1 .. Link_Len + Rest_Len) := Path (Rest_First .. Rest_Last);
Path (Link_Len + Rest_Len + 1 .. Path'Last) := (others => ' ');
Path (1 .. Link_Len) := As_String (Path_Buf) (1 .. Link_Len);
end if;
end Read_Link;
Path_Len : constant size_t := Strings.Strlen (File_Path);
Root_Dir : Boolean := True;
begin
if not Is_Mounted (State) or Path_Len > Path_Max then
return 0;
end if;
Path (1 .. Natural (Path_Len)) := Strings.Value (File_Path);
Path (Natural (Path_Len + 1) .. Path'Last) := (others => ' ');
Link_Loop :
for I in 1 .. Max_Link_Depth loop
declare
Path_Pos : Positive := Path'First;
Path_Last : constant Positive := Path_End (Path, Path_Pos);
begin
Path_Loop :
loop
declare
Comp_First : constant Positive := Component_Start (Path, Path_Pos);
Comp_Last : constant Positive := Component_End (Path, Comp_First);
File_Type : FS.File_Type;
File_Len : File_Length;
Success : Boolean;
begin
if Comp_First > Comp_Last then
return 0;
end if;
Open
(State => State,
File_Len => File_Len,
File_Type => File_Type,
File_Name => Path (Comp_First .. Comp_Last),
In_Root => Root_Dir,
Success => Success);
if not Success then
return 0;
end if;
Root_Dir := False;
case File_Type is
when Dir =>
if Comp_Last = Path_Last then
Close (State);
return 0;
end if;
Path_Pos := Comp_Last + 1;
when Regular =>
if Comp_Last = Path_Last then
Set_File_Max (File_Len);
return 1;
else
Close (State);
return 0;
end if;
when Link =>
if File_Len > Path_Max then
Success := False;
else
Read_Link
(Path => Path,
Rest_First => Comp_Last + 1,
Rest_Last => Path_Last,
Link_Len => Natural (File_Len),
Success => Success);
end if;
Close (State);
if not Success then
return 0;
end if;
Root_Dir := Path (1) = '/';
exit Path_Loop; -- continue in Link_Loop
end case;
end;
end loop Path_Loop;
end;
end loop Link_Loop;
return 0;
end C_Open;
procedure C_Close is
begin
if Is_Open (State) then
Close (State);
end if;
end C_Close;
function C_Read (Buf : System.Address; Len : int) return int
is
subtype Buffer_Range is Natural range 0 .. Integer (Len) - 1;
Buffer : Buffer_Type (Buffer_Range)
with
Convention => C,
Address => Buf;
File_Pos : File_Offset := FILO.FS.File_Pos;
Read_Len : Natural;
begin
if Is_Open (State) then
Read (State, File_Pos, Buffer, Read_Len);
Set_File_Pos (File_Pos);
else
Read_Len := 0;
end if;
return int (Read_Len);
end C_Read;
end FILO.FS.VFS;