blob: b190bd7c6a042e945337b4629320c7625fe0cd57 [file] [log] [blame]
Nico Huberb1cb2d32023-12-17 01:45:47 +01001with Ada.Unchecked_Conversion;
Nico Huber0a9591e2023-11-27 16:59:11 +01002
Nico Huber3da21472023-12-18 15:43:35 +01003package body FILO.FS.VFS is
Nico Huber0a9591e2023-11-27 16:59:11 +01004
Nico Huber51f60412023-12-04 14:48:11 +01005 State : T := Initial;
6
Nico Huberb1cb2d32023-12-17 01:45:47 +01007 Path_Max : constant := 4096;
8 Max_Link_Depth : constant := 32;
9
Nico Huber3da21472023-12-18 15:43:35 +010010 subtype Path_Length is Natural range 0 .. Path_Max;
11 subtype Path_Index_Plus is Positive range 1 .. Path_Max + 1;
12 subtype Path_Index is Path_Index_Plus range 1 .. Path_Max;
13
14 subtype Path_Buffer is Buffer_Type (Path_Index)
15 with
16 Object_Size => Path_Max * 8;
Nico Huberb1cb2d32023-12-17 01:45:47 +010017 Path_Buf : Path_Buffer;
18
Nico Huber3da21472023-12-18 15:43:35 +010019 subtype Path_String is String (Path_Index)
20 with
21 Object_Size => Path_Max * 8;
Nico Huberb1cb2d32023-12-17 01:45:47 +010022 Path : Path_String;
23
Nico Huber0a9591e2023-11-27 16:59:11 +010024 function C_Mount return int
Nico Huber3da21472023-12-18 15:43:35 +010025 with
26 SPARK_Mode => Off
Nico Huber0a9591e2023-11-27 16:59:11 +010027 is
28 Success : Boolean;
29 begin
Nico Huber51f60412023-12-04 14:48:11 +010030 if not Is_Mounted (State) then
31 State := Initial; -- Work around not having an unmount in FILO.
32 end if;
33 Mount (State, Part_Len, Success);
Nico Huber0a9591e2023-11-27 16:59:11 +010034 return (if Success then 1 else 0);
35 end C_Mount;
36
Nico Huber3da21472023-12-18 15:43:35 +010037 procedure Open (File_Path : System.Address; Ret : out int)
Nico Huber0a9591e2023-11-27 16:59:11 +010038 is
Nico Huber3da21472023-12-18 15:43:35 +010039 function Str_Len (S : System.Address) return Natural;
40 function Str_Len (S : System.Address) return Natural
41 with
42 SPARK_Mode => Off
43 is
44 Buf : Buffer_Type (1 .. Path_Max + 1)
45 with
46 Convention => C,
47 Address => S;
48 begin
49 for I in Buf'Range loop
50 if Buf (I) = 16#00# then
51 return I - 1;
52 end if;
53 end loop;
54 return Path_Max + 1;
55 end Str_Len;
56
57 procedure Str_Cpy (Dst : out String; Src : in System.Address);
58 procedure Str_Cpy (Dst : out String; Src : in System.Address)
59 with
60 SPARK_Mode => Off
61 is
62 Src_String : String (Dst'Range)
63 with
64 Convention => C,
65 Address => Src;
66 begin
67 Dst := Src_String;
68 end Str_Cpy;
69
70 function Component_Start (Path : Path_String; Pos : Positive) return Path_Index_Plus is
Nico Huberb1cb2d32023-12-17 01:45:47 +010071 begin
72 for I in Pos .. Path'Last loop
73 if Path (I) /= '/' then
74 return I;
75 end if;
76 end loop;
77 return Path'Last + 1;
78 end Component_Start;
79
Nico Huber3da21472023-12-18 15:43:35 +010080 function Component_End (Path : Path_String; Start : Path_Index_Plus; Limit : Path_Index) return Path_Length
81 with
82 Post => Component_End'Result <= Limit
83 is
Nico Huberb1cb2d32023-12-17 01:45:47 +010084 begin
Nico Huber3da21472023-12-18 15:43:35 +010085 for I in Start .. Limit loop
Nico Huberb1cb2d32023-12-17 01:45:47 +010086 if Path (I) = '/' or Is_Space (Path (I)) then
87 return I - 1;
88 end if;
89 end loop;
Nico Huber3da21472023-12-18 15:43:35 +010090 return Limit;
Nico Huberb1cb2d32023-12-17 01:45:47 +010091 end Component_End;
92
Nico Huber3da21472023-12-18 15:43:35 +010093 function Path_End (Path : Path_String; Start : Path_Index) return Path_Length is
Nico Huberb1cb2d32023-12-17 01:45:47 +010094 begin
95 for I in Start .. Path'Last loop
96 if Is_Space (Path (I)) then
97 return I - 1;
98 end if;
99 end loop;
100 return Path'Last;
101 end Path_End;
102
103 procedure Read_Link
104 (Path : in out Path_String;
Nico Huber3da21472023-12-18 15:43:35 +0100105 Rest_First : in Path_Index_Plus;
106 Rest_Last : in Path_Index;
Nico Huber53df7852024-01-15 18:36:04 +0100107 Link_Len : in Positive;
Nico Huberb1cb2d32023-12-17 01:45:47 +0100108 Success : out Boolean)
Nico Huber3da21472023-12-18 15:43:35 +0100109 with
110 Pre =>
111 Is_Open (State) and
112 Rest_First - 1 <= Rest_Last,
113 Post =>
114 Is_Open (State)
Nico Huberb1cb2d32023-12-17 01:45:47 +0100115 is
116 function As_String is new Ada.Unchecked_Conversion (Path_Buffer, Path_String);
117
118 Rest_Len : constant Natural := Rest_Last - Rest_First + 1;
119 File_Pos : File_Offset := 0;
120 Read_Len : Natural;
121 begin
122 if Path_Max - Rest_Len < Link_Len then
123 Success := False;
124 return;
125 end if;
126
Nico Huber53df7852024-01-15 18:36:04 +0100127 pragma Warnings
128 (GNATprove, Off, """File_Pos"" is set*but not used",
129 Reason => "We only read the link at once, during path walks.");
Nico Huberb1cb2d32023-12-17 01:45:47 +0100130 Read
131 (State => State,
132 File_Pos => File_Pos,
133 Buf => Path_Buf (1 .. Link_Len),
134 Len => Read_Len);
Nico Huber53df7852024-01-15 18:36:04 +0100135 pragma Warnings (GNATprove, On, """File_Pos"" is set*but not used");
Nico Huberb1cb2d32023-12-17 01:45:47 +0100136 Success := Read_Len = Link_Len;
137
138 if Success then
139 Path (Link_Len + 1 .. Link_Len + Rest_Len) := Path (Rest_First .. Rest_Last);
140 Path (Link_Len + Rest_Len + 1 .. Path'Last) := (others => ' ');
141 Path (1 .. Link_Len) := As_String (Path_Buf) (1 .. Link_Len);
142 end if;
143 end Read_Link;
144
Nico Huber3da21472023-12-18 15:43:35 +0100145 Path_Len : constant Natural := Str_Len (File_Path);
Nico Huberb1cb2d32023-12-17 01:45:47 +0100146 Root_Dir : Boolean := True;
Nico Huber0a9591e2023-11-27 16:59:11 +0100147 begin
Nico Huber3da21472023-12-18 15:43:35 +0100148 Ret := 0;
149
Nico Huberb1cb2d32023-12-17 01:45:47 +0100150 if not Is_Mounted (State) or Path_Len > Path_Max then
Nico Huber3da21472023-12-18 15:43:35 +0100151 return;
Nico Huber51f60412023-12-04 14:48:11 +0100152 end if;
Nico Huberb1cb2d32023-12-17 01:45:47 +0100153
Nico Huber43314482024-01-23 16:19:33 +0100154 if Is_Open (State) then
155 Close (State);
156 end if;
157
Nico Huber3da21472023-12-18 15:43:35 +0100158 Str_Cpy (Path (1 .. Path_Len), File_Path);
159 Path (Path_Len + 1 .. Path'Last) := (others => ' ');
Nico Huberb1cb2d32023-12-17 01:45:47 +0100160
161 Link_Loop :
162 for I in 1 .. Max_Link_Depth loop
Nico Huber3da21472023-12-18 15:43:35 +0100163 pragma Loop_Invariant (Is_Mounted (State));
Nico Huberb1cb2d32023-12-17 01:45:47 +0100164 declare
Nico Huber3da21472023-12-18 15:43:35 +0100165 Path_Pos : Path_Index_Plus := Path'First;
166 Path_Last : constant Path_Length := Path_End (Path, Path_Pos);
Nico Huberb1cb2d32023-12-17 01:45:47 +0100167 begin
Nico Huber3da21472023-12-18 15:43:35 +0100168 if Path_Last < Path'First then
169 return;
170 end if;
171
Nico Huberb1cb2d32023-12-17 01:45:47 +0100172 Path_Loop :
173 loop
Nico Huber3da21472023-12-18 15:43:35 +0100174 pragma Loop_Invariant
175 (Is_Mounted (State) and
176 Path_Last in Path'Range);
Nico Huberb1cb2d32023-12-17 01:45:47 +0100177 declare
Nico Huber3da21472023-12-18 15:43:35 +0100178 Comp_First : constant Path_Index_Plus := Component_Start (Path, Path_Pos);
179 Comp_Last : constant Path_Length := Component_End (Path, Comp_First, Path_Last);
Nico Huberb1cb2d32023-12-17 01:45:47 +0100180 File_Type : FS.File_Type;
181 File_Len : File_Length;
182 Success : Boolean;
183 begin
184 if Comp_First > Comp_Last then
Nico Huber3da21472023-12-18 15:43:35 +0100185 return;
Nico Huberb1cb2d32023-12-17 01:45:47 +0100186 end if;
187
188 Open
189 (State => State,
190 File_Len => File_Len,
191 File_Type => File_Type,
192 File_Name => Path (Comp_First .. Comp_Last),
193 In_Root => Root_Dir,
194 Success => Success);
195 if not Success then
Nico Huber3da21472023-12-18 15:43:35 +0100196 return;
Nico Huberb1cb2d32023-12-17 01:45:47 +0100197 end if;
198 Root_Dir := False;
199
200 case File_Type is
201 when Dir =>
202 if Comp_Last = Path_Last then
203 Close (State);
Nico Huber3da21472023-12-18 15:43:35 +0100204 return;
Nico Huberb1cb2d32023-12-17 01:45:47 +0100205 end if;
206 Path_Pos := Comp_Last + 1;
207 when Regular =>
208 if Comp_Last = Path_Last then
209 Set_File_Max (File_Len);
Nico Huber3da21472023-12-18 15:43:35 +0100210 Ret := 1;
211 return;
Nico Huberb1cb2d32023-12-17 01:45:47 +0100212 else
213 Close (State);
Nico Huber3da21472023-12-18 15:43:35 +0100214 return;
Nico Huberb1cb2d32023-12-17 01:45:47 +0100215 end if;
216 when Link =>
Nico Huber53df7852024-01-15 18:36:04 +0100217 if File_Len = 0 or File_Len > Path_Max then
Nico Huberb1cb2d32023-12-17 01:45:47 +0100218 Success := False;
219 else
220 Read_Link
221 (Path => Path,
222 Rest_First => Comp_Last + 1,
223 Rest_Last => Path_Last,
Nico Huber53df7852024-01-15 18:36:04 +0100224 Link_Len => Positive (File_Len),
Nico Huberb1cb2d32023-12-17 01:45:47 +0100225 Success => Success);
226 end if;
227 Close (State);
228 if not Success then
Nico Huber3da21472023-12-18 15:43:35 +0100229 return;
Nico Huberb1cb2d32023-12-17 01:45:47 +0100230 end if;
231 Root_Dir := Path (1) = '/';
232 exit Path_Loop; -- continue in Link_Loop
233 end case;
234 end;
235 end loop Path_Loop;
236 end;
237 end loop Link_Loop;
Nico Huber3da21472023-12-18 15:43:35 +0100238 end Open;
Nico Huberb1cb2d32023-12-17 01:45:47 +0100239
Nico Huber3da21472023-12-18 15:43:35 +0100240 function C_Open (File_Path : System.Address) return int
241 with
242 SPARK_Mode => Off
243 is
244 Ret : int;
245 begin
246 if Is_Mounted (State) then
247 Open (File_Path, Ret);
248 else
249 Ret := 0;
250 end if;
251 return Ret;
Nico Huber0a9591e2023-11-27 16:59:11 +0100252 end C_Open;
Nico Huber51f60412023-12-04 14:48:11 +0100253
254 procedure C_Close is
255 begin
256 if Is_Open (State) then
257 Close (State);
258 end if;
259 end C_Close;
Nico Huber0a9591e2023-11-27 16:59:11 +0100260
261 function C_Read (Buf : System.Address; Len : int) return int
Nico Huber3da21472023-12-18 15:43:35 +0100262 with
263 SPARK_Mode => Off
Nico Huber0a9591e2023-11-27 16:59:11 +0100264 is
265 subtype Buffer_Range is Natural range 0 .. Integer (Len) - 1;
266 Buffer : Buffer_Type (Buffer_Range)
267 with
268 Convention => C,
269 Address => Buf;
270
Thomas Heijligen5c43abc2023-12-11 15:24:36 +0000271 File_Pos : File_Offset := FILO.FS.File_Pos;
Nico Huber0a9591e2023-11-27 16:59:11 +0100272 Read_Len : Natural;
273 begin
Nico Huber51f60412023-12-04 14:48:11 +0100274 if Is_Open (State) then
Nico Huber549a1b82023-12-17 01:51:59 +0100275 Read (State, File_Pos, Buffer, Read_Len);
Nico Huber51f60412023-12-04 14:48:11 +0100276 Set_File_Pos (File_Pos);
277 else
278 Read_Len := 0;
279 end if;
Nico Huber0a9591e2023-11-27 16:59:11 +0100280 return int (Read_Len);
281 end C_Read;
282
Thomas Heijligen5c43abc2023-12-11 15:24:36 +0000283end FILO.FS.VFS;