blob: 388f2cbe4dfe12ed507e2cbe7e115cfe87657c4d [file] [log] [blame]
Nico Huberb1cb2d32023-12-17 01:45:47 +01001with Ada.Unchecked_Conversion;
Nico Huber0a9591e2023-11-27 16:59:11 +01002with Interfaces.C;
3with Interfaces.C.Strings;
4
5use Interfaces.C;
6
Thomas Heijligen5c43abc2023-12-11 15:24:36 +00007package body FILO.FS.VFS
Thomas Heijligend49cb122023-11-29 10:03:02 +00008with
Nico Huber691220d2023-12-04 14:54:01 +01009 SPARK_Mode => Off
Thomas Heijligend49cb122023-11-29 10:03:02 +000010is
Nico Huber0a9591e2023-11-27 16:59:11 +010011
Nico Huber51f60412023-12-04 14:48:11 +010012 State : T := Initial;
13
Nico Huberb1cb2d32023-12-17 01:45:47 +010014 Path_Max : constant := 4096;
15 Max_Link_Depth : constant := 32;
16
17 subtype Path_Buffer is Buffer_Type (1 .. Path_Max);
18 Path_Buf : Path_Buffer;
19
20 subtype Path_String is String (1 .. Path_Max);
21 Path : Path_String;
22
Nico Huber0a9591e2023-11-27 16:59:11 +010023 function C_Mount return int
24 is
25 Success : Boolean;
26 begin
Nico Huber51f60412023-12-04 14:48:11 +010027 if not Is_Mounted (State) then
28 State := Initial; -- Work around not having an unmount in FILO.
29 end if;
30 Mount (State, Part_Len, Success);
Nico Huber0a9591e2023-11-27 16:59:11 +010031 return (if Success then 1 else 0);
32 end C_Mount;
33
34 function C_Open (File_Path : Strings.chars_ptr) return int
35 is
Nico Huberb1cb2d32023-12-17 01:45:47 +010036 function Component_Start (Path : String; Pos : Positive) return Positive is
37 begin
38 for I in Pos .. Path'Last loop
39 if Path (I) /= '/' then
40 return I;
41 end if;
42 end loop;
43 return Path'Last + 1;
44 end Component_Start;
45
46 function Component_End (Path : String; Start : Positive) return Positive is
47 begin
48 for I in Start .. Path'Last loop
49 if Path (I) = '/' or Is_Space (Path (I)) then
50 return I - 1;
51 end if;
52 end loop;
53 return Path'Last;
54 end Component_End;
55
56 function Path_End (Path : String; Start : Positive) return Positive is
57 begin
58 for I in Start .. Path'Last loop
59 if Is_Space (Path (I)) then
60 return I - 1;
61 end if;
62 end loop;
63 return Path'Last;
64 end Path_End;
65
66 procedure Read_Link
67 (Path : in out Path_String;
68 Rest_First : in Positive;
69 Rest_Last : in Positive;
70 Link_Len : in Natural;
71 Success : out Boolean)
72 is
73 function As_String is new Ada.Unchecked_Conversion (Path_Buffer, Path_String);
74
75 Rest_Len : constant Natural := Rest_Last - Rest_First + 1;
76 File_Pos : File_Offset := 0;
77 Read_Len : Natural;
78 begin
79 if Path_Max - Rest_Len < Link_Len then
80 Success := False;
81 return;
82 end if;
83
84 Read
85 (State => State,
86 File_Pos => File_Pos,
87 Buf => Path_Buf (1 .. Link_Len),
88 Len => Read_Len);
89 Success := Read_Len = Link_Len;
90
91 if Success then
92 Path (Link_Len + 1 .. Link_Len + Rest_Len) := Path (Rest_First .. Rest_Last);
93 Path (Link_Len + Rest_Len + 1 .. Path'Last) := (others => ' ');
94 Path (1 .. Link_Len) := As_String (Path_Buf) (1 .. Link_Len);
95 end if;
96 end Read_Link;
97
98 Path_Len : constant size_t := Strings.Strlen (File_Path);
99 Root_Dir : Boolean := True;
Nico Huber0a9591e2023-11-27 16:59:11 +0100100 begin
Nico Huberb1cb2d32023-12-17 01:45:47 +0100101 if not Is_Mounted (State) or Path_Len > Path_Max then
102 return 0;
Nico Huber51f60412023-12-04 14:48:11 +0100103 end if;
Nico Huberb1cb2d32023-12-17 01:45:47 +0100104
105 Path (1 .. Natural (Path_Len)) := Strings.Value (File_Path);
106 Path (Natural (Path_Len + 1) .. Path'Last) := (others => ' ');
107
108 Link_Loop :
109 for I in 1 .. Max_Link_Depth loop
110 declare
111 Path_Pos : Positive := Path'First;
112 Path_Last : constant Positive := Path_End (Path, Path_Pos);
113 begin
114 Path_Loop :
115 loop
116 declare
117 Comp_First : constant Positive := Component_Start (Path, Path_Pos);
118 Comp_Last : constant Positive := Component_End (Path, Comp_First);
119 File_Type : FS.File_Type;
120 File_Len : File_Length;
121 Success : Boolean;
122 begin
123 if Comp_First > Comp_Last then
124 return 0;
125 end if;
126
127 Open
128 (State => State,
129 File_Len => File_Len,
130 File_Type => File_Type,
131 File_Name => Path (Comp_First .. Comp_Last),
132 In_Root => Root_Dir,
133 Success => Success);
134 if not Success then
135 return 0;
136 end if;
137 Root_Dir := False;
138
139 case File_Type is
140 when Dir =>
141 if Comp_Last = Path_Last then
142 Close (State);
143 return 0;
144 end if;
145 Path_Pos := Comp_Last + 1;
146 when Regular =>
147 if Comp_Last = Path_Last then
148 Set_File_Max (File_Len);
149 return 1;
150 else
151 Close (State);
152 return 0;
153 end if;
154 when Link =>
155 if File_Len > Path_Max then
156 Success := False;
157 else
158 Read_Link
159 (Path => Path,
160 Rest_First => Comp_Last + 1,
161 Rest_Last => Path_Last,
162 Link_Len => Natural (File_Len),
163 Success => Success);
164 end if;
165 Close (State);
166 if not Success then
167 return 0;
168 end if;
169 Root_Dir := Path (1) = '/';
170 exit Path_Loop; -- continue in Link_Loop
171 end case;
172 end;
173 end loop Path_Loop;
174 end;
175 end loop Link_Loop;
176
177 return 0;
Nico Huber0a9591e2023-11-27 16:59:11 +0100178 end C_Open;
Nico Huber51f60412023-12-04 14:48:11 +0100179
180 procedure C_Close is
181 begin
182 if Is_Open (State) then
183 Close (State);
184 end if;
185 end C_Close;
Nico Huber0a9591e2023-11-27 16:59:11 +0100186
187 function C_Read (Buf : System.Address; Len : int) return int
188 is
189 subtype Buffer_Range is Natural range 0 .. Integer (Len) - 1;
190 Buffer : Buffer_Type (Buffer_Range)
191 with
192 Convention => C,
193 Address => Buf;
194
Thomas Heijligen5c43abc2023-12-11 15:24:36 +0000195 File_Pos : File_Offset := FILO.FS.File_Pos;
Nico Huber0a9591e2023-11-27 16:59:11 +0100196 Read_Len : Natural;
197 begin
Nico Huber51f60412023-12-04 14:48:11 +0100198 if Is_Open (State) then
Nico Huber549a1b82023-12-17 01:51:59 +0100199 Read (State, File_Pos, Buffer, Read_Len);
Nico Huber51f60412023-12-04 14:48:11 +0100200 Set_File_Pos (File_Pos);
201 else
202 Read_Len := 0;
203 end if;
Nico Huber0a9591e2023-11-27 16:59:11 +0100204 return int (Read_Len);
205 end C_Read;
206
Thomas Heijligen5c43abc2023-12-11 15:24:36 +0000207end FILO.FS.VFS;