blob: 02e4c5291c8d0863a8f02e7877acb2b6ce9ad7b7 [file] [log] [blame]
Nico Huberb1cb2d32023-12-17 01:45:47 +01001with Ada.Unchecked_Conversion;
Nico Huber0a9591e2023-11-27 16:59:11 +01002with Interfaces.C;
Nico Huber0a9591e2023-11-27 16:59:11 +01003
4use Interfaces.C;
5
Nico Huber3da21472023-12-18 15:43:35 +01006package body FILO.FS.VFS is
Nico Huber0a9591e2023-11-27 16:59:11 +01007
Nico Huber51f60412023-12-04 14:48:11 +01008 State : T := Initial;
9
Nico Huberb1cb2d32023-12-17 01:45:47 +010010 Path_Max : constant := 4096;
11 Max_Link_Depth : constant := 32;
12
Nico Huber3da21472023-12-18 15:43:35 +010013 subtype Path_Length is Natural range 0 .. Path_Max;
14 subtype Path_Index_Plus is Positive range 1 .. Path_Max + 1;
15 subtype Path_Index is Path_Index_Plus range 1 .. Path_Max;
16
17 subtype Path_Buffer is Buffer_Type (Path_Index)
18 with
19 Object_Size => Path_Max * 8;
Nico Huberb1cb2d32023-12-17 01:45:47 +010020 Path_Buf : Path_Buffer;
21
Nico Huber3da21472023-12-18 15:43:35 +010022 subtype Path_String is String (Path_Index)
23 with
24 Object_Size => Path_Max * 8;
Nico Huberb1cb2d32023-12-17 01:45:47 +010025 Path : Path_String;
26
Nico Huber0a9591e2023-11-27 16:59:11 +010027 function C_Mount return int
Nico Huber3da21472023-12-18 15:43:35 +010028 with
29 SPARK_Mode => Off
Nico Huber0a9591e2023-11-27 16:59:11 +010030 is
31 Success : Boolean;
32 begin
Nico Huber51f60412023-12-04 14:48:11 +010033 if not Is_Mounted (State) then
34 State := Initial; -- Work around not having an unmount in FILO.
35 end if;
36 Mount (State, Part_Len, Success);
Nico Huber0a9591e2023-11-27 16:59:11 +010037 return (if Success then 1 else 0);
38 end C_Mount;
39
Nico Huber3da21472023-12-18 15:43:35 +010040 procedure Open (File_Path : System.Address; Ret : out int)
Nico Huber0a9591e2023-11-27 16:59:11 +010041 is
Nico Huber3da21472023-12-18 15:43:35 +010042 function Str_Len (S : System.Address) return Natural;
43 function Str_Len (S : System.Address) return Natural
44 with
45 SPARK_Mode => Off
46 is
47 Buf : Buffer_Type (1 .. Path_Max + 1)
48 with
49 Convention => C,
50 Address => S;
51 begin
52 for I in Buf'Range loop
53 if Buf (I) = 16#00# then
54 return I - 1;
55 end if;
56 end loop;
57 return Path_Max + 1;
58 end Str_Len;
59
60 procedure Str_Cpy (Dst : out String; Src : in System.Address);
61 procedure Str_Cpy (Dst : out String; Src : in System.Address)
62 with
63 SPARK_Mode => Off
64 is
65 Src_String : String (Dst'Range)
66 with
67 Convention => C,
68 Address => Src;
69 begin
70 Dst := Src_String;
71 end Str_Cpy;
72
73 function Component_Start (Path : Path_String; Pos : Positive) return Path_Index_Plus is
Nico Huberb1cb2d32023-12-17 01:45:47 +010074 begin
75 for I in Pos .. Path'Last loop
76 if Path (I) /= '/' then
77 return I;
78 end if;
79 end loop;
80 return Path'Last + 1;
81 end Component_Start;
82
Nico Huber3da21472023-12-18 15:43:35 +010083 function Component_End (Path : Path_String; Start : Path_Index_Plus; Limit : Path_Index) return Path_Length
84 with
85 Post => Component_End'Result <= Limit
86 is
Nico Huberb1cb2d32023-12-17 01:45:47 +010087 begin
Nico Huber3da21472023-12-18 15:43:35 +010088 for I in Start .. Limit loop
Nico Huberb1cb2d32023-12-17 01:45:47 +010089 if Path (I) = '/' or Is_Space (Path (I)) then
90 return I - 1;
91 end if;
92 end loop;
Nico Huber3da21472023-12-18 15:43:35 +010093 return Limit;
Nico Huberb1cb2d32023-12-17 01:45:47 +010094 end Component_End;
95
Nico Huber3da21472023-12-18 15:43:35 +010096 function Path_End (Path : Path_String; Start : Path_Index) return Path_Length is
Nico Huberb1cb2d32023-12-17 01:45:47 +010097 begin
98 for I in Start .. Path'Last loop
99 if Is_Space (Path (I)) then
100 return I - 1;
101 end if;
102 end loop;
103 return Path'Last;
104 end Path_End;
105
106 procedure Read_Link
107 (Path : in out Path_String;
Nico Huber3da21472023-12-18 15:43:35 +0100108 Rest_First : in Path_Index_Plus;
109 Rest_Last : in Path_Index;
Nico Huber53df7852024-01-15 18:36:04 +0100110 Link_Len : in Positive;
Nico Huberb1cb2d32023-12-17 01:45:47 +0100111 Success : out Boolean)
Nico Huber3da21472023-12-18 15:43:35 +0100112 with
113 Pre =>
114 Is_Open (State) and
115 Rest_First - 1 <= Rest_Last,
116 Post =>
117 Is_Open (State)
Nico Huberb1cb2d32023-12-17 01:45:47 +0100118 is
119 function As_String is new Ada.Unchecked_Conversion (Path_Buffer, Path_String);
120
121 Rest_Len : constant Natural := Rest_Last - Rest_First + 1;
122 File_Pos : File_Offset := 0;
123 Read_Len : Natural;
124 begin
125 if Path_Max - Rest_Len < Link_Len then
126 Success := False;
127 return;
128 end if;
129
Nico Huber53df7852024-01-15 18:36:04 +0100130 pragma Warnings
131 (GNATprove, Off, """File_Pos"" is set*but not used",
132 Reason => "We only read the link at once, during path walks.");
Nico Huberb1cb2d32023-12-17 01:45:47 +0100133 Read
134 (State => State,
135 File_Pos => File_Pos,
136 Buf => Path_Buf (1 .. Link_Len),
137 Len => Read_Len);
Nico Huber53df7852024-01-15 18:36:04 +0100138 pragma Warnings (GNATprove, On, """File_Pos"" is set*but not used");
Nico Huberb1cb2d32023-12-17 01:45:47 +0100139 Success := Read_Len = Link_Len;
140
141 if Success then
142 Path (Link_Len + 1 .. Link_Len + Rest_Len) := Path (Rest_First .. Rest_Last);
143 Path (Link_Len + Rest_Len + 1 .. Path'Last) := (others => ' ');
144 Path (1 .. Link_Len) := As_String (Path_Buf) (1 .. Link_Len);
145 end if;
146 end Read_Link;
147
Nico Huber3da21472023-12-18 15:43:35 +0100148 Path_Len : constant Natural := Str_Len (File_Path);
Nico Huberb1cb2d32023-12-17 01:45:47 +0100149 Root_Dir : Boolean := True;
Nico Huber0a9591e2023-11-27 16:59:11 +0100150 begin
Nico Huber3da21472023-12-18 15:43:35 +0100151 Ret := 0;
152
Nico Huberb1cb2d32023-12-17 01:45:47 +0100153 if not Is_Mounted (State) or Path_Len > Path_Max then
Nico Huber3da21472023-12-18 15:43:35 +0100154 return;
Nico Huber51f60412023-12-04 14:48:11 +0100155 end if;
Nico Huberb1cb2d32023-12-17 01:45:47 +0100156
Nico Huber3da21472023-12-18 15:43:35 +0100157 Str_Cpy (Path (1 .. Path_Len), File_Path);
158 Path (Path_Len + 1 .. Path'Last) := (others => ' ');
Nico Huberb1cb2d32023-12-17 01:45:47 +0100159
160 Link_Loop :
161 for I in 1 .. Max_Link_Depth loop
Nico Huber3da21472023-12-18 15:43:35 +0100162 pragma Loop_Invariant (Is_Mounted (State));
Nico Huberb1cb2d32023-12-17 01:45:47 +0100163 declare
Nico Huber3da21472023-12-18 15:43:35 +0100164 Path_Pos : Path_Index_Plus := Path'First;
165 Path_Last : constant Path_Length := Path_End (Path, Path_Pos);
Nico Huberb1cb2d32023-12-17 01:45:47 +0100166 begin
Nico Huber3da21472023-12-18 15:43:35 +0100167 if Path_Last < Path'First then
168 return;
169 end if;
170
Nico Huberb1cb2d32023-12-17 01:45:47 +0100171 Path_Loop :
172 loop
Nico Huber3da21472023-12-18 15:43:35 +0100173 pragma Loop_Invariant
174 (Is_Mounted (State) and
175 Path_Last in Path'Range);
Nico Huberb1cb2d32023-12-17 01:45:47 +0100176 declare
Nico Huber3da21472023-12-18 15:43:35 +0100177 Comp_First : constant Path_Index_Plus := Component_Start (Path, Path_Pos);
178 Comp_Last : constant Path_Length := Component_End (Path, Comp_First, Path_Last);
Nico Huberb1cb2d32023-12-17 01:45:47 +0100179 File_Type : FS.File_Type;
180 File_Len : File_Length;
181 Success : Boolean;
182 begin
183 if Comp_First > Comp_Last then
Nico Huber3da21472023-12-18 15:43:35 +0100184 return;
Nico Huberb1cb2d32023-12-17 01:45:47 +0100185 end if;
186
187 Open
188 (State => State,
189 File_Len => File_Len,
190 File_Type => File_Type,
191 File_Name => Path (Comp_First .. Comp_Last),
192 In_Root => Root_Dir,
193 Success => Success);
194 if not Success then
Nico Huber3da21472023-12-18 15:43:35 +0100195 return;
Nico Huberb1cb2d32023-12-17 01:45:47 +0100196 end if;
197 Root_Dir := False;
198
199 case File_Type is
200 when Dir =>
201 if Comp_Last = Path_Last then
202 Close (State);
Nico Huber3da21472023-12-18 15:43:35 +0100203 return;
Nico Huberb1cb2d32023-12-17 01:45:47 +0100204 end if;
205 Path_Pos := Comp_Last + 1;
206 when Regular =>
207 if Comp_Last = Path_Last then
208 Set_File_Max (File_Len);
Nico Huber3da21472023-12-18 15:43:35 +0100209 Ret := 1;
210 return;
Nico Huberb1cb2d32023-12-17 01:45:47 +0100211 else
212 Close (State);
Nico Huber3da21472023-12-18 15:43:35 +0100213 return;
Nico Huberb1cb2d32023-12-17 01:45:47 +0100214 end if;
215 when Link =>
Nico Huber53df7852024-01-15 18:36:04 +0100216 if File_Len = 0 or File_Len > Path_Max then
Nico Huberb1cb2d32023-12-17 01:45:47 +0100217 Success := False;
218 else
219 Read_Link
220 (Path => Path,
221 Rest_First => Comp_Last + 1,
222 Rest_Last => Path_Last,
Nico Huber53df7852024-01-15 18:36:04 +0100223 Link_Len => Positive (File_Len),
Nico Huberb1cb2d32023-12-17 01:45:47 +0100224 Success => Success);
225 end if;
226 Close (State);
227 if not Success then
Nico Huber3da21472023-12-18 15:43:35 +0100228 return;
Nico Huberb1cb2d32023-12-17 01:45:47 +0100229 end if;
230 Root_Dir := Path (1) = '/';
231 exit Path_Loop; -- continue in Link_Loop
232 end case;
233 end;
234 end loop Path_Loop;
235 end;
236 end loop Link_Loop;
Nico Huber3da21472023-12-18 15:43:35 +0100237 end Open;
Nico Huberb1cb2d32023-12-17 01:45:47 +0100238
Nico Huber3da21472023-12-18 15:43:35 +0100239 function C_Open (File_Path : System.Address) return int
240 with
241 SPARK_Mode => Off
242 is
243 Ret : int;
244 begin
245 if Is_Mounted (State) then
246 Open (File_Path, Ret);
247 else
248 Ret := 0;
249 end if;
250 return Ret;
Nico Huber0a9591e2023-11-27 16:59:11 +0100251 end C_Open;
Nico Huber51f60412023-12-04 14:48:11 +0100252
253 procedure C_Close is
254 begin
255 if Is_Open (State) then
256 Close (State);
257 end if;
258 end C_Close;
Nico Huber0a9591e2023-11-27 16:59:11 +0100259
260 function C_Read (Buf : System.Address; Len : int) return int
Nico Huber3da21472023-12-18 15:43:35 +0100261 with
262 SPARK_Mode => Off
Nico Huber0a9591e2023-11-27 16:59:11 +0100263 is
264 subtype Buffer_Range is Natural range 0 .. Integer (Len) - 1;
265 Buffer : Buffer_Type (Buffer_Range)
266 with
267 Convention => C,
268 Address => Buf;
269
Thomas Heijligen5c43abc2023-12-11 15:24:36 +0000270 File_Pos : File_Offset := FILO.FS.File_Pos;
Nico Huber0a9591e2023-11-27 16:59:11 +0100271 Read_Len : Natural;
272 begin
Nico Huber51f60412023-12-04 14:48:11 +0100273 if Is_Open (State) then
Nico Huber549a1b82023-12-17 01:51:59 +0100274 Read (State, File_Pos, Buffer, Read_Len);
Nico Huber51f60412023-12-04 14:48:11 +0100275 Set_File_Pos (File_Pos);
276 else
277 Read_Len := 0;
278 end if;
Nico Huber0a9591e2023-11-27 16:59:11 +0100279 return int (Read_Len);
280 end C_Read;
281
Thomas Heijligen5c43abc2023-12-11 15:24:36 +0000282end FILO.FS.VFS;