blob: 31abf65806aa2652e7c3feacef4ddb885fbd1e7e [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 Huber43314482024-01-23 16:19:33 +0100157 if Is_Open (State) then
158 Close (State);
159 end if;
160
Nico Huber3da21472023-12-18 15:43:35 +0100161 Str_Cpy (Path (1 .. Path_Len), File_Path);
162 Path (Path_Len + 1 .. Path'Last) := (others => ' ');
Nico Huberb1cb2d32023-12-17 01:45:47 +0100163
164 Link_Loop :
165 for I in 1 .. Max_Link_Depth loop
Nico Huber3da21472023-12-18 15:43:35 +0100166 pragma Loop_Invariant (Is_Mounted (State));
Nico Huberb1cb2d32023-12-17 01:45:47 +0100167 declare
Nico Huber3da21472023-12-18 15:43:35 +0100168 Path_Pos : Path_Index_Plus := Path'First;
169 Path_Last : constant Path_Length := Path_End (Path, Path_Pos);
Nico Huberb1cb2d32023-12-17 01:45:47 +0100170 begin
Nico Huber3da21472023-12-18 15:43:35 +0100171 if Path_Last < Path'First then
172 return;
173 end if;
174
Nico Huberb1cb2d32023-12-17 01:45:47 +0100175 Path_Loop :
176 loop
Nico Huber3da21472023-12-18 15:43:35 +0100177 pragma Loop_Invariant
178 (Is_Mounted (State) and
179 Path_Last in Path'Range);
Nico Huberb1cb2d32023-12-17 01:45:47 +0100180 declare
Nico Huber3da21472023-12-18 15:43:35 +0100181 Comp_First : constant Path_Index_Plus := Component_Start (Path, Path_Pos);
182 Comp_Last : constant Path_Length := Component_End (Path, Comp_First, Path_Last);
Nico Huberb1cb2d32023-12-17 01:45:47 +0100183 File_Type : FS.File_Type;
184 File_Len : File_Length;
185 Success : Boolean;
186 begin
187 if Comp_First > Comp_Last then
Nico Huber3da21472023-12-18 15:43:35 +0100188 return;
Nico Huberb1cb2d32023-12-17 01:45:47 +0100189 end if;
190
191 Open
192 (State => State,
193 File_Len => File_Len,
194 File_Type => File_Type,
195 File_Name => Path (Comp_First .. Comp_Last),
196 In_Root => Root_Dir,
197 Success => Success);
198 if not Success then
Nico Huber3da21472023-12-18 15:43:35 +0100199 return;
Nico Huberb1cb2d32023-12-17 01:45:47 +0100200 end if;
201 Root_Dir := False;
202
203 case File_Type is
204 when Dir =>
205 if Comp_Last = Path_Last then
206 Close (State);
Nico Huber3da21472023-12-18 15:43:35 +0100207 return;
Nico Huberb1cb2d32023-12-17 01:45:47 +0100208 end if;
209 Path_Pos := Comp_Last + 1;
210 when Regular =>
211 if Comp_Last = Path_Last then
212 Set_File_Max (File_Len);
Nico Huber3da21472023-12-18 15:43:35 +0100213 Ret := 1;
214 return;
Nico Huberb1cb2d32023-12-17 01:45:47 +0100215 else
216 Close (State);
Nico Huber3da21472023-12-18 15:43:35 +0100217 return;
Nico Huberb1cb2d32023-12-17 01:45:47 +0100218 end if;
219 when Link =>
Nico Huber53df7852024-01-15 18:36:04 +0100220 if File_Len = 0 or File_Len > Path_Max then
Nico Huberb1cb2d32023-12-17 01:45:47 +0100221 Success := False;
222 else
223 Read_Link
224 (Path => Path,
225 Rest_First => Comp_Last + 1,
226 Rest_Last => Path_Last,
Nico Huber53df7852024-01-15 18:36:04 +0100227 Link_Len => Positive (File_Len),
Nico Huberb1cb2d32023-12-17 01:45:47 +0100228 Success => Success);
229 end if;
230 Close (State);
231 if not Success then
Nico Huber3da21472023-12-18 15:43:35 +0100232 return;
Nico Huberb1cb2d32023-12-17 01:45:47 +0100233 end if;
234 Root_Dir := Path (1) = '/';
235 exit Path_Loop; -- continue in Link_Loop
236 end case;
237 end;
238 end loop Path_Loop;
239 end;
240 end loop Link_Loop;
Nico Huber3da21472023-12-18 15:43:35 +0100241 end Open;
Nico Huberb1cb2d32023-12-17 01:45:47 +0100242
Nico Huber3da21472023-12-18 15:43:35 +0100243 function C_Open (File_Path : System.Address) return int
244 with
245 SPARK_Mode => Off
246 is
247 Ret : int;
248 begin
249 if Is_Mounted (State) then
250 Open (File_Path, Ret);
251 else
252 Ret := 0;
253 end if;
254 return Ret;
Nico Huber0a9591e2023-11-27 16:59:11 +0100255 end C_Open;
Nico Huber51f60412023-12-04 14:48:11 +0100256
257 procedure C_Close is
258 begin
259 if Is_Open (State) then
260 Close (State);
261 end if;
262 end C_Close;
Nico Huber0a9591e2023-11-27 16:59:11 +0100263
264 function C_Read (Buf : System.Address; Len : int) return int
Nico Huber3da21472023-12-18 15:43:35 +0100265 with
266 SPARK_Mode => Off
Nico Huber0a9591e2023-11-27 16:59:11 +0100267 is
268 subtype Buffer_Range is Natural range 0 .. Integer (Len) - 1;
269 Buffer : Buffer_Type (Buffer_Range)
270 with
271 Convention => C,
272 Address => Buf;
273
Thomas Heijligen5c43abc2023-12-11 15:24:36 +0000274 File_Pos : File_Offset := FILO.FS.File_Pos;
Nico Huber0a9591e2023-11-27 16:59:11 +0100275 Read_Len : Natural;
276 begin
Nico Huber51f60412023-12-04 14:48:11 +0100277 if Is_Open (State) then
Nico Huber549a1b82023-12-17 01:51:59 +0100278 Read (State, File_Pos, Buffer, Read_Len);
Nico Huber51f60412023-12-04 14:48:11 +0100279 Set_File_Pos (File_Pos);
280 else
281 Read_Len := 0;
282 end if;
Nico Huber0a9591e2023-11-27 16:59:11 +0100283 return int (Read_Len);
284 end C_Read;
285
Thomas Heijligen5c43abc2023-12-11 15:24:36 +0000286end FILO.FS.VFS;