blob: a43edf6454daac0eee9bc0c6af7adc2d1b7422aa [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 Huberb1cb2d32023-12-17 01:45:47 +0100110 Link_Len : in Natural;
111 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
130 Read
131 (State => State,
132 File_Pos => File_Pos,
133 Buf => Path_Buf (1 .. Link_Len),
134 Len => Read_Len);
135 Success := Read_Len = Link_Len;
136
137 if Success then
138 Path (Link_Len + 1 .. Link_Len + Rest_Len) := Path (Rest_First .. Rest_Last);
139 Path (Link_Len + Rest_Len + 1 .. Path'Last) := (others => ' ');
140 Path (1 .. Link_Len) := As_String (Path_Buf) (1 .. Link_Len);
141 end if;
142 end Read_Link;
143
Nico Huber3da21472023-12-18 15:43:35 +0100144 Path_Len : constant Natural := Str_Len (File_Path);
Nico Huberb1cb2d32023-12-17 01:45:47 +0100145 Root_Dir : Boolean := True;
Nico Huber0a9591e2023-11-27 16:59:11 +0100146 begin
Nico Huber3da21472023-12-18 15:43:35 +0100147 Ret := 0;
148
Nico Huberb1cb2d32023-12-17 01:45:47 +0100149 if not Is_Mounted (State) or Path_Len > Path_Max then
Nico Huber3da21472023-12-18 15:43:35 +0100150 return;
Nico Huber51f60412023-12-04 14:48:11 +0100151 end if;
Nico Huberb1cb2d32023-12-17 01:45:47 +0100152
Nico Huber3da21472023-12-18 15:43:35 +0100153 Str_Cpy (Path (1 .. Path_Len), File_Path);
154 Path (Path_Len + 1 .. Path'Last) := (others => ' ');
Nico Huberb1cb2d32023-12-17 01:45:47 +0100155
156 Link_Loop :
157 for I in 1 .. Max_Link_Depth loop
Nico Huber3da21472023-12-18 15:43:35 +0100158 pragma Loop_Invariant (Is_Mounted (State));
Nico Huberb1cb2d32023-12-17 01:45:47 +0100159 declare
Nico Huber3da21472023-12-18 15:43:35 +0100160 Path_Pos : Path_Index_Plus := Path'First;
161 Path_Last : constant Path_Length := Path_End (Path, Path_Pos);
Nico Huberb1cb2d32023-12-17 01:45:47 +0100162 begin
Nico Huber3da21472023-12-18 15:43:35 +0100163 if Path_Last < Path'First then
164 return;
165 end if;
166
Nico Huberb1cb2d32023-12-17 01:45:47 +0100167 Path_Loop :
168 loop
Nico Huber3da21472023-12-18 15:43:35 +0100169 pragma Loop_Invariant
170 (Is_Mounted (State) and
171 Path_Last in Path'Range);
Nico Huberb1cb2d32023-12-17 01:45:47 +0100172 declare
Nico Huber3da21472023-12-18 15:43:35 +0100173 Comp_First : constant Path_Index_Plus := Component_Start (Path, Path_Pos);
174 Comp_Last : constant Path_Length := Component_End (Path, Comp_First, Path_Last);
Nico Huberb1cb2d32023-12-17 01:45:47 +0100175 File_Type : FS.File_Type;
176 File_Len : File_Length;
177 Success : Boolean;
178 begin
179 if Comp_First > Comp_Last then
Nico Huber3da21472023-12-18 15:43:35 +0100180 return;
Nico Huberb1cb2d32023-12-17 01:45:47 +0100181 end if;
182
183 Open
184 (State => State,
185 File_Len => File_Len,
186 File_Type => File_Type,
187 File_Name => Path (Comp_First .. Comp_Last),
188 In_Root => Root_Dir,
189 Success => Success);
190 if not Success then
Nico Huber3da21472023-12-18 15:43:35 +0100191 return;
Nico Huberb1cb2d32023-12-17 01:45:47 +0100192 end if;
193 Root_Dir := False;
194
195 case File_Type is
196 when Dir =>
197 if Comp_Last = Path_Last then
198 Close (State);
Nico Huber3da21472023-12-18 15:43:35 +0100199 return;
Nico Huberb1cb2d32023-12-17 01:45:47 +0100200 end if;
201 Path_Pos := Comp_Last + 1;
202 when Regular =>
203 if Comp_Last = Path_Last then
204 Set_File_Max (File_Len);
Nico Huber3da21472023-12-18 15:43:35 +0100205 Ret := 1;
206 return;
Nico Huberb1cb2d32023-12-17 01:45:47 +0100207 else
208 Close (State);
Nico Huber3da21472023-12-18 15:43:35 +0100209 return;
Nico Huberb1cb2d32023-12-17 01:45:47 +0100210 end if;
211 when Link =>
212 if File_Len > Path_Max then
213 Success := False;
214 else
215 Read_Link
216 (Path => Path,
217 Rest_First => Comp_Last + 1,
218 Rest_Last => Path_Last,
219 Link_Len => Natural (File_Len),
220 Success => Success);
221 end if;
222 Close (State);
223 if not Success then
Nico Huber3da21472023-12-18 15:43:35 +0100224 return;
Nico Huberb1cb2d32023-12-17 01:45:47 +0100225 end if;
226 Root_Dir := Path (1) = '/';
227 exit Path_Loop; -- continue in Link_Loop
228 end case;
229 end;
230 end loop Path_Loop;
231 end;
232 end loop Link_Loop;
Nico Huber3da21472023-12-18 15:43:35 +0100233 end Open;
Nico Huberb1cb2d32023-12-17 01:45:47 +0100234
Nico Huber3da21472023-12-18 15:43:35 +0100235 function C_Open (File_Path : System.Address) return int
236 with
237 SPARK_Mode => Off
238 is
239 Ret : int;
240 begin
241 if Is_Mounted (State) then
242 Open (File_Path, Ret);
243 else
244 Ret := 0;
245 end if;
246 return Ret;
Nico Huber0a9591e2023-11-27 16:59:11 +0100247 end C_Open;
Nico Huber51f60412023-12-04 14:48:11 +0100248
249 procedure C_Close is
250 begin
251 if Is_Open (State) then
252 Close (State);
253 end if;
254 end C_Close;
Nico Huber0a9591e2023-11-27 16:59:11 +0100255
256 function C_Read (Buf : System.Address; Len : int) return int
Nico Huber3da21472023-12-18 15:43:35 +0100257 with
258 SPARK_Mode => Off
Nico Huber0a9591e2023-11-27 16:59:11 +0100259 is
260 subtype Buffer_Range is Natural range 0 .. Integer (Len) - 1;
261 Buffer : Buffer_Type (Buffer_Range)
262 with
263 Convention => C,
264 Address => Buf;
265
Thomas Heijligen5c43abc2023-12-11 15:24:36 +0000266 File_Pos : File_Offset := FILO.FS.File_Pos;
Nico Huber0a9591e2023-11-27 16:59:11 +0100267 Read_Len : Natural;
268 begin
Nico Huber51f60412023-12-04 14:48:11 +0100269 if Is_Open (State) then
Nico Huber549a1b82023-12-17 01:51:59 +0100270 Read (State, File_Pos, Buffer, Read_Len);
Nico Huber51f60412023-12-04 14:48:11 +0100271 Set_File_Pos (File_Pos);
272 else
273 Read_Len := 0;
274 end if;
Nico Huber0a9591e2023-11-27 16:59:11 +0100275 return int (Read_Len);
276 end C_Read;
277
Thomas Heijligen5c43abc2023-12-11 15:24:36 +0000278end FILO.FS.VFS;