blob: a4af392a43b143566bf6ecbde142b995ddbc4ed4 [file] [log] [blame]
Nico Hubercc960f22024-01-29 01:13:45 +01001-- Copyright (C) 2024 secunet Security Networks AG
2--
3-- This program is free software; you can redistribute it and/or modify
4-- it under the terms of the GNU General Public License as published by
5-- the Free Software Foundation; either version 2 of the License, or
6-- (at your option) any later version.
7
8with System;
9with Interfaces;
10with Interfaces.C;
11
12with FILO.Blockdev;
13with FILO.FS.VFS;
14
15use Interfaces.C;
16
17package body FILO.FS.ISO9660 is
18
Nico Huber780b7f42024-02-08 19:11:37 +010019 subtype SUSP_Signature is String (1 .. 2);
20
21 --------------------------------------------------------------------------
22
Nico Hubercc960f22024-01-29 01:13:45 +010023 function Is_Mounted (State : T) return Boolean is (State.S >= Mounted);
24 function Is_Open (State : T) return Boolean is (State.S = File_Opened);
25
26 --------------------------------------------------------------------------
27
Nico Huber780b7f42024-02-08 19:11:37 +010028 function "+" (Rec : FS_Record; Off : FSBlock_Length) return FS_Record
29 is
30 (Block => Rec.Block, Offset => Rec.Offset + Off, Size => Rec.Size - Off)
31 with
32 Pre => Rec.Size >= Off;
33
Nico Hubercc960f22024-01-29 01:13:45 +010034 procedure Read
Nico Huber4210fcc2024-01-29 16:33:47 +010035 (Buf : out Buffer_Type;
Nico Huber666da672024-02-08 15:30:20 +010036 Rec : in FS_Record;
Nico Hubercc960f22024-01-29 01:13:45 +010037 Success : out Boolean)
38 with
Nico Huber666da672024-02-08 15:30:20 +010039 Pre => Buf'Length <= Rec.Size
Nico Hubercc960f22024-01-29 01:13:45 +010040 is
Nico Huber666da672024-02-08 15:30:20 +010041 Block_64 : constant Integer_64 := Integer_64 (Rec.Block);
42 Offset_64 : constant Integer_64 := Integer_64 (Rec.Offset);
Nico Hubercc960f22024-01-29 01:13:45 +010043 begin
Nico Hubercc960f22024-01-29 01:13:45 +010044 Blockdev.Read (Buf, Blockdev_Length (Block_64 * FSBlock_Size + Offset_64), Success);
45 end Read;
46
47 procedure Mount
48 (State : in out T;
49 Part_Len : in Partition_Length;
50 Success : out Boolean)
51 is
52 D_Type : constant Index_Type := 0;
53 D_Id : constant Index_Type := 1;
54 D_Ver : constant Index_Type := 6;
55
56 D_Type_Primary : constant := 1;
57 D_Type_Terminator : constant := 255;
58
59 CD001 : constant Buffer_Type :=
60 (Character'Pos ('C'), Character'Pos ('D'),
61 Character'Pos ('0'), Character'Pos ('0'), Character'Pos ('1'));
62
63 Static : Mount_State renames State.Static;
64
Nico Huber4210fcc2024-01-29 16:33:47 +010065 Volume_Descriptor : Buffer_Type (0 .. D_Ver);
Nico Huber65f2ea22024-02-06 17:37:35 +010066 Block : FSBlock := 16;
Nico Hubercc960f22024-01-29 01:13:45 +010067 begin
68 loop
69 pragma Loop_Invariant (Block < 1024);
Nico Huber4210fcc2024-01-29 16:33:47 +010070 pragma Loop_Invariant (not Is_Mounted (State));
Nico Hubercc960f22024-01-29 01:13:45 +010071
72 if Part_Len < Partition_Length (Block + 1) * FSBlock_Size then
73 Success := False;
74 return;
75 end if;
Nico Huber666da672024-02-08 15:30:20 +010076 Static.Part_Len := Part_Len;
Nico Hubercc960f22024-01-29 01:13:45 +010077
Nico Huber666da672024-02-08 15:30:20 +010078 Read (Volume_Descriptor, FS_Record'(Block, 0, FSBlock_Size), Success);
Nico Hubercc960f22024-01-29 01:13:45 +010079 if not Success then
80 return;
81 end if;
82
83 if Volume_Descriptor (D_Ver) /= 1 or
84 Volume_Descriptor (D_Id .. D_Ver - 1) /= CD001 or
85 Volume_Descriptor (D_Type) = D_Type_Terminator
86 then
Nico Huber4210fcc2024-01-29 16:33:47 +010087 Success := False;
Nico Hubercc960f22024-01-29 01:13:45 +010088 return;
89 end if;
90
91 exit when Volume_Descriptor (D_Type) = D_Type_Primary;
92
93 Block := Block + 1;
94 if Block >= 1024 then
Nico Huber4210fcc2024-01-29 16:33:47 +010095 Success := False;
Nico Hubercc960f22024-01-29 01:13:45 +010096 return;
97 end if;
98 end loop;
99
Nico Huber666da672024-02-08 15:30:20 +0100100 Static.Root_Inode := (Block, 156, Directory_Record'Length);
Nico Hubercc960f22024-01-29 01:13:45 +0100101
102 State.S := Mounted;
103 end Mount;
104
Nico Huber780b7f42024-02-08 19:11:37 +0100105 procedure Find_SUSP_Record
106 (State : in T;
107 Rec : out FS_Record;
108 Dir_Rec_Pos : in File_Offset;
109 Dir_Rec_Len : in FSBlock_Length;
110 Searched_Sig : in SUSP_Signature)
111 with
Nico Huber8e4b9f82024-02-12 01:13:51 +0100112 Pre =>
113 Dir_Rec_Pos mod FSBlock_Size <= File_Offset (FSBlock_Size - Dir_Rec_Len) and
114 FSBlock_Count (Dir_Rec_Pos / FSBlock_Size) < State.Inode.Extents (0).Count
Nico Huber780b7f42024-02-08 19:11:37 +0100115 is
116 subtype Signature_Buf is Buffer_Type (0 .. 1);
117 function Signature (Str : SUSP_Signature) return Signature_Buf
118 is
119 ((Character'Pos (Str (Str'First)), Character'Pos (Str (Str'First + 1))));
120
121 Cur : FS_Record :=
122 (Block => State.Inode.Extents (0).Start + FSBlock (Dir_Rec_Pos / FSBlock_Size),
123 Offset => FSBlock_Index (Dir_Rec_Pos mod FSBlock_Size),
124 Size => Dir_Rec_Len);
125
Nico Huber8e4b9f82024-02-12 01:13:51 +0100126 Continuation : FS_Record := (Size => 0, others => <>);
Nico Huber780b7f42024-02-08 19:11:37 +0100127
128 SUSP_Head : Buffer_Type (0 .. 3);
129
130 Success : Boolean;
131 begin
132 Rec := (others => <>);
133 if Cur.Size = 0 then
134 return;
135 end if;
136
137 if Cur.Offset mod 2 = 1 then
138 Cur := Cur + 1;
139 end if;
140
141 for I in 1 .. 2**16 loop -- arbitrary limit to avoid endless loop
142 if Cur.Size < SUSP_Head'Length then
Nico Huber8e4b9f82024-02-12 01:13:51 +0100143 if Continuation.Size < SUSP_Head'Length then
Nico Huber780b7f42024-02-08 19:11:37 +0100144 return;
145 else
146 Cur := Continuation;
147 Continuation := (others => <>);
148 end if;
149 end if;
150
151 Read (SUSP_Head, Cur, Success);
152 declare
153 Rec_Len : constant Natural := Natural (SUSP_Head (2));
154 SUSP_CE : Buffer_Type (0 .. 27);
155 begin
156 if not Success or else Rec_Len not in 4 .. Cur.Size then
157 return;
158 end if;
159
160 if SUSP_Head (0 .. 1) = Signature (Searched_Sig) then
161 Rec :=
162 (Block => Cur.Block,
163 Offset => Cur.Offset,
164 Size => Rec_Len);
165 return;
166 elsif SUSP_Head (0 .. 1) = Signature ("CE") then
167 if Rec_Len < SUSP_CE'Length then
168 return;
169 end if;
170
171 Read (SUSP_CE, Cur, Success);
172 if not Success then
173 return;
174 end if;
175 declare
176 CE_Extent : constant Unsigned_32 := Read_LE32 (SUSP_CE, 4);
177 CE_Offset : constant Unsigned_32 := Read_LE32 (SUSP_CE, 12);
178 CE_Size : constant Unsigned_32 := Read_LE32 (SUSP_CE, 20);
179 begin
Nico Huber8e4b9f82024-02-12 01:13:51 +0100180 if CE_Extent > Unsigned_32 (FSBlock'Last) or else
181 (CE_Offset > FSBlock_Size or CE_Size > FSBlock_Size) or else
182 FSBlock_Length (CE_Size) > FSBlock_Size - FSBlock_Length (CE_Offset)
Nico Huber780b7f42024-02-08 19:11:37 +0100183 then
184 return;
185 end if;
186 Continuation :=
187 (Block => FSBlock (CE_Extent),
Nico Huber8e4b9f82024-02-12 01:13:51 +0100188 Offset => FSBlock_Length (CE_Offset),
Nico Huber780b7f42024-02-08 19:11:37 +0100189 Size => FSBlock_Length (CE_Size));
190 end;
191 end if;
192
193 Cur := Cur + Rec_Len;
194 end;
195 end loop;
196 end Find_SUSP_Record;
197
Nico Hubercc960f22024-01-29 01:13:45 +0100198 procedure Open
199 (State : in out T;
200 I : in Inode_Index;
201 Success : out Boolean)
202 with
203 Pre => Is_Mounted (State),
204 Post => Is_Mounted (State) and (Success = Is_Open (State))
205 is
Nico Hubercc960f22024-01-29 01:13:45 +0100206 Inode : Inode_Info renames State.Inode;
207
208 Dir_Rec : Directory_Record;
209 begin
Nico Huber4210fcc2024-01-29 16:33:47 +0100210 State.S := Mounted;
211
Nico Hubercc960f22024-01-29 01:13:45 +0100212 Inode := (I, others => <>);
213
Nico Huber666da672024-02-08 15:30:20 +0100214 Read (Dir_Rec, I, Success);
Nico Hubercc960f22024-01-29 01:13:45 +0100215 if not Success then
216 return;
217 end if;
218
219 declare
220 D_Flag_Dir : constant := 16#02#;
221 D_Flag_Cont : constant := 16#80#;
222 D_Flags : constant Unsigned_8 := Dir_Rec (25);
Nico Huber4210fcc2024-01-29 16:33:47 +0100223 D_Extent : constant Unsigned_32 := Read_LE32 (Dir_Rec, 2);
Nico Hubercc960f22024-01-29 01:13:45 +0100224 begin
Nico Huber4210fcc2024-01-29 16:33:47 +0100225 if D_Extent > Unsigned_32 (FSBlock'Last) then
226 Success := False;
227 return;
228 end if;
Nico Hubercc960f22024-01-29 01:13:45 +0100229 if (D_Flags and D_Flag_Cont) /= 0 then
230 Success := False;
231 return;
232 end if;
Nico Huber4210fcc2024-01-29 16:33:47 +0100233
Nico Hubercc960f22024-01-29 01:13:45 +0100234 if (D_Flags and D_Flag_Dir) /= 0 then
235 Inode.Mode := Dir;
236 else
237 Inode.Mode := Regular;
238 end if;
Nico Huber8e4b9f82024-02-12 01:13:51 +0100239
Nico Hubercc960f22024-01-29 01:13:45 +0100240 Inode.Size := Inode_Length (Read_LE32 (Dir_Rec, 10));
Nico Huber8e4b9f82024-02-12 01:13:51 +0100241 if FSBlock (D_Extent) > FSBlock_Count'Last - FSBlock_Count (Inode.Size / FSBlock_Size)
242 then
243 Success := False;
244 return;
245 end if;
246
Nico Hubercc960f22024-01-29 01:13:45 +0100247 Inode.Extents (0) :=
Nico Huber4210fcc2024-01-29 16:33:47 +0100248 (Start => FSBlock (D_Extent),
Nico Huber8e4b9f82024-02-12 01:13:51 +0100249 Count => FSBlock_Count (Inode.Size / FSBlock_Size));
Nico Hubercc960f22024-01-29 01:13:45 +0100250 State.S := File_Opened;
251 end;
252 end Open;
253
254 procedure Open
255 (State : in out T;
256 File_Len : out File_Length;
257 File_Type : out FS.File_Type;
258 File_Name : in String;
259 In_Root : in Boolean;
260 Success : out Boolean)
261 is
262 File_Name_Max : constant := 255;
263
Nico Huberab933b82024-02-07 11:50:59 +0100264 procedure Match_ISO_Name
Nico Huber8e4b9f82024-02-12 01:13:51 +0100265 (ISO_Name_Length : in Positive;
Nico Huberab933b82024-02-07 11:50:59 +0100266 Record_Dir_Pos : in File_Offset;
267 Success : in out Boolean)
Nico Hubercc960f22024-01-29 01:13:45 +0100268 with
Nico Huber8e4b9f82024-02-12 01:13:51 +0100269 Pre => Is_Open (State) and File_Name'Length <= Natural'Last - 3,
270 Post => Is_Open (State)
Nico Hubercc960f22024-01-29 01:13:45 +0100271 is
Nico Huberab933b82024-02-07 11:50:59 +0100272 function Upper_Case_Equal (Str : String; Buf : Buffer_Type) return Boolean
273 with
274 Pre => Str'Length <= Buf'Length
275 is
276 begin
277 for I in Str'Range loop
278 declare
279 Chr : constant Unsigned_8 :=
280 (if 'a' <= Str (I) and Str (I) <= 'z' then
281 Character'Pos (Str (I)) - Character'Pos ('a') + Character'Pos ('A')
282 else Character'Pos (Str (I)));
283 begin
284 if Chr /= Buf (Buf'First + (I - Str'First)) then
285 return False;
286 end if;
287 end;
288 end loop;
289 return True;
290 end Upper_Case_Equal;
291
292 Dir_Pos : File_Offset := Record_Dir_Pos;
293 ISO_Name : Buffer_Type (0 .. ISO_Name_Length - 1);
294 Name_Len : Natural;
Nico Hubercc960f22024-01-29 01:13:45 +0100295 begin
Nico Huberab933b82024-02-07 11:50:59 +0100296 -- Check if length could match.
297 -- First for the weird `.' and `..' encoding,
298 -- then for regular file names + `.' and file version `;1'.
299 if not (ISO_Name_Length = 1 and File_Name'Length <= 2) and
300 ISO_Name_Length not in File_Name'Length .. File_Name'Length + 3
301 then
302 return;
303 end if;
304
305 pragma Warnings
306 (GNATprove, Off, """Dir_Pos"" is set*but not used",
307 Reason => "This is the last part of the record we care about.");
308 Read
309 (State => State,
310 File_Pos => Dir_Pos,
311 Buf => ISO_Name,
312 Len => Name_Len);
313 if Name_Len /= ISO_Name_Length then
314 return;
315 end if;
316 pragma Warnings (GNATprove, On, """Dir_Pos"" is set*but not used");
317
Nico Huber8e4b9f82024-02-12 01:13:51 +0100318 if (Name_Len = 1 and then (ISO_Name (0) = 16#00# and File_Name = ".")) or
319 (Name_Len = 1 and then (ISO_Name (0) = 16#01# and File_Name = ".."))
Nico Huberab933b82024-02-07 11:50:59 +0100320 then
321 Success := True;
322 return;
323 end if;
324
325 -- Ignore file version `;1'
Nico Huber8e4b9f82024-02-12 01:13:51 +0100326 if Name_Len >= File_Name'Length + 2 and then
327 (ISO_Name (Name_Len - 2) = Character'Pos (';') and
328 ISO_Name (Name_Len - 1) = Character'Pos ('1'))
Nico Huberab933b82024-02-07 11:50:59 +0100329 then
330 Name_Len := Name_Len - 2;
331 end if;
332
333 -- Ignore trailing `.'
Nico Huber8e4b9f82024-02-12 01:13:51 +0100334 if Name_Len >= File_Name'Length + 1 and then
Nico Huberab933b82024-02-07 11:50:59 +0100335 ISO_Name (Name_Len - 1) = Character'Pos ('.')
336 then
337 Name_Len := Name_Len - 1;
338 end if;
339
340 Success := Name_Len = File_Name'Length and then
341 Upper_Case_Equal (File_Name, ISO_Name);
342 end Match_ISO_Name;
Nico Hubercc960f22024-01-29 01:13:45 +0100343
Nico Huber780b7f42024-02-08 19:11:37 +0100344 procedure Match_Rock_Ridge_Name
345 (Pos : in File_Offset;
Nico Huber8e4b9f82024-02-12 01:13:51 +0100346 Len : in FSBlock_Length;
347 Success : out Boolean)
Nico Huber780b7f42024-02-08 19:11:37 +0100348 with
Nico Huber8e4b9f82024-02-12 01:13:51 +0100349 Pre =>
350 Pos mod FSBlock_Size <= File_Offset (FSBlock_Size - Len) and
351 FSBlock_Count (Pos / FSBlock_Size) < State.Inode.Extents (0).Count,
Nico Huber780b7f42024-02-08 19:11:37 +0100352 Post => State = State'Old
353 is
354 Name_Rec : FS_Record;
355 begin
356 Find_SUSP_Record (State, Name_Rec, Pos, Len, "NM");
Nico Huber8e4b9f82024-02-12 01:13:51 +0100357 if Name_Rec.Size - 5 /= File_Name'Length then
Nico Huber780b7f42024-02-08 19:11:37 +0100358 Success := False;
359 return;
360 end if;
361
362 declare
363 RR_Name : Buffer_Type (0 .. File_Name'Length - 1);
364 begin
365 Read (RR_Name, Name_Rec + 5, Success);
366 Success := Success and then Equal (File_Name, RR_Name);
367 end;
368 end Match_Rock_Ridge_Name;
369
Nico Hubercc960f22024-01-29 01:13:45 +0100370 Found_Inode : Inode_Index;
371 Dir_Pos : File_Length;
372 begin
373 File_Len := 0;
374 File_Type := FS.File_Type'First;
375
376 if File_Name'Length > File_Name_Max then
377 Success := False;
378 return;
379 end if;
380
381 -- Ensure dir is opened:
382 --
383 if State.S = File_Opened then
384 if State.Cur_Dir /= State.Inode.I then
385 Success := False;
386 return;
387 end if;
388 else
389 if In_Root then
390 State.Cur_Dir := State.Static.Root_Inode;
391 end if;
392 declare
393 Cur_Dir : constant Inode_Index := State.Cur_Dir;
394 begin
395 Open (State, Cur_Dir, Success);
396 if not Success then
397 return;
398 end if;
399 end;
400 end if;
401
402 -- Lookup file in opened dir:
403 --
404 Dir_Pos := 0;
405 Success := False;
406 loop
407 pragma Loop_Invariant (Is_Open (State) and not Success);
Nico Huber4210fcc2024-01-29 16:33:47 +0100408 pragma Loop_Invariant
409 (FSBlock_Index (Dir_Pos mod FSBlock_Size) <= Directory_Record_Offset'Last);
410
Nico Hubercc960f22024-01-29 01:13:45 +0100411 declare
Nico Huberab933b82024-02-07 11:50:59 +0100412 Dir_Rec_Head : Directory_Record;
Nico Hubercc960f22024-01-29 01:13:45 +0100413 Record_Dir_Pos : File_Offset := Dir_Pos;
Nico Hubercc960f22024-01-29 01:13:45 +0100414 Len : Natural;
415 begin
416 Read
417 (State => State,
418 File_Pos => Record_Dir_Pos,
Nico Huberab933b82024-02-07 11:50:59 +0100419 Buf => Dir_Rec_Head,
Nico Hubercc960f22024-01-29 01:13:45 +0100420 Len => Len);
Nico Huberab933b82024-02-07 11:50:59 +0100421 if Len /= Dir_Rec_Head'Length then
Nico Hubercc960f22024-01-29 01:13:45 +0100422 return;
423 end if;
424
Nico Huberb18691e2024-02-06 17:52:17 +0100425 declare
Nico Huberab933b82024-02-07 11:50:59 +0100426 Dir_Rec_Length : constant Natural := Natural (Dir_Rec_Head (0));
427 Dir_Rec_Name_Length : constant Natural := Natural (Dir_Rec_Head (32));
Nico Huberb18691e2024-02-06 17:52:17 +0100428 begin
Nico Huberab933b82024-02-07 11:50:59 +0100429 if Dir_Rec_Length /= 0 then
430
431 if Unsigned_64 (Dir_Pos) > Unsigned_64 (State.Inode.Size) - Unsigned_64 (Dir_Rec_Length) or
Nico Huber8e4b9f82024-02-12 01:13:51 +0100432 Dir_Rec_Name_Length not in 1 .. Dir_Rec_Length - Dir_Rec_Head'Length
Nico Huberab933b82024-02-07 11:50:59 +0100433 then
Nico Huberb18691e2024-02-06 17:52:17 +0100434 return;
Nico Huberb18691e2024-02-06 17:52:17 +0100435 end if;
Nico Huberab933b82024-02-07 11:50:59 +0100436
Nico Huber780b7f42024-02-08 19:11:37 +0100437 -- First skip ISO name and try Rock Ridge extension:
438 Match_Rock_Ridge_Name
439 (Pos => Record_Dir_Pos + File_Offset (Dir_Rec_Name_Length),
440 Len => Dir_Rec_Length - Dir_Rec_Head'Length - Dir_Rec_Name_Length,
441 Success => Success);
442 if not Success then
443 Match_ISO_Name (Dir_Rec_Name_Length, Record_Dir_Pos, Success);
444 end if;
Nico Huberab933b82024-02-07 11:50:59 +0100445
446 if Success then
447 Found_Inode :=
Nico Huber666da672024-02-08 15:30:20 +0100448 (Block => FSBlock (Dir_Pos / FSBlock_Size) + State.Inode.Extents (0).Start,
449 Offset => FSBlock_Index (Dir_Pos mod FSBlock_Size),
450 Size => Dir_Rec_Length);
Nico Huberab933b82024-02-07 11:50:59 +0100451 exit;
452 end if;
453
454 Dir_Pos := Dir_Pos + File_Length (Dir_Rec_Length);
455
Nico Huberb18691e2024-02-06 17:52:17 +0100456 else
Nico Huberab933b82024-02-07 11:50:59 +0100457 -- `Dir_Rec_Length = 0` means we have to skip to the next fs block:
458 declare
459 Block_Gap : constant File_Length := FSBlock_Size - (Dir_Pos mod FSBlock_Size);
460 begin
461 if Unsigned_64 (Dir_Pos) >= Unsigned_64 (State.Inode.Size) - Unsigned_64 (Block_Gap) then
462 return;
463 else
464 Dir_Pos := Dir_Pos + Block_Gap;
465 end if;
466 end;
Nico Huberb18691e2024-02-06 17:52:17 +0100467 end if;
468 end;
Nico Hubercc960f22024-01-29 01:13:45 +0100469 end;
470 end loop;
471 pragma Assert_And_Cut (Success and Is_Mounted (State));
472
473 Open (State, Found_Inode, Success);
474 if not Success then
475 return;
476 end if;
477
478 if State.Inode.Mode = Dir then
479 State.Cur_Dir := Found_Inode;
480 end if;
481
Nico Huber4210fcc2024-01-29 16:33:47 +0100482 Success := State.Inode.Size <= Inode_Length (File_Length'Last);
Nico Hubercc960f22024-01-29 01:13:45 +0100483 if Success then
484 File_Len := File_Length (State.Inode.Size);
485 File_Type := State.Inode.Mode;
486 else
487 Close (State);
488 end if;
489 end Open;
490
491 procedure Close (State : in out T) is
492 begin
493 State.S := Mounted;
494 end Close;
495
496 procedure Read
497 (State : in out T;
498 File_Pos : in out File_Offset;
499 Buf : out Buffer_Type;
500 Len : out Natural)
501 is
502 Static : Mount_State renames State.Static;
503
504 Pos : Natural range Buf'First .. Buf'Last + 1;
505 begin
506 Len := 0;
507 Pos := Buf'First;
508 while Pos <= Buf'Last and
509 File_Pos < File_Offset'Last and
510 Inode_Length (File_Pos) < State.Inode.Size
511 loop
Nico Huber4210fcc2024-01-29 16:33:47 +0100512 pragma Loop_Invariant (for all I in Buf'First .. Pos - 1 => Buf (I)'Initialized);
Nico Hubercc960f22024-01-29 01:13:45 +0100513 pragma Loop_Invariant (Is_Open (State));
514 declare
515 In_Block : constant FSBlock_Index := Natural (File_Pos mod FSBlock_Size);
516 Logical : constant FSBlock_Logical := FSBlock_Logical (File_Pos / FSBlock_Size);
517 In_Block_Space : constant Positive := Index_Type (FSBlock_Size) - In_Block;
518 In_File_Space : constant Inode_Length := State.Inode.Size - Inode_Length (File_Pos);
519 In_Buf_Space : constant Positive := Buf'Last - Pos + 1;
520 Len_Here : Positive;
521 begin
522 exit when FSBlock (Logical) > FSBlock'Last - State.Inode.Extents (0).Start;
523
524 Len_Here := In_Block_Space;
525 if In_File_Space < Inode_Length (Len_Here) then
526 Len_Here := Positive (In_File_Space);
527 end if;
528 if In_Buf_Space < Len_Here then
529 Len_Here := In_Buf_Space;
530 end if;
531 if File_Offset'Last - File_Pos < File_Length (Len_Here) then
532 Len_Here := Positive (File_Offset'Last - File_Pos);
533 end if;
534
535 declare
536 Last : constant Index_Type := Pos + Len_Here - 1;
537 Physical : constant FSBlock := State.Inode.Extents (0).Start + FSBlock (Logical);
538 Success : Boolean;
539 begin
540 Read
541 (Buf => Buf (Pos .. Last),
Nico Huber666da672024-02-08 15:30:20 +0100542 Rec => FS_Record'(Physical, In_Block, In_Block_Space),
Nico Hubercc960f22024-01-29 01:13:45 +0100543 Success => Success);
544 exit when not Success;
545
546 File_Pos := File_Pos + File_Length (Len_Here);
547 Pos := Pos + Len_Here;
548 Len := Pos - Buf'First;
549 end;
550 end;
551 end loop;
552 Buf (Pos .. Buf'Last) := (others => 16#00#);
553 end Read;
554
555 --------------------------------------------------------------------------
556
557 package C is new VFS (T => T, Initial => (S => Unmounted, others => <>));
558
559 function C_Mount return int
560 with
561 Export,
562 Convention => C,
563 External_Name => "iso9660_mount";
564 function C_Mount return int
565 with
566 SPARK_Mode => Off
567 is
568 begin
569 return C.C_Mount;
570 end C_Mount;
571
572 function C_Open (File_Path : System.Address) return int
573 with
574 Export,
575 Convention => C,
576 External_Name => "iso9660_dir";
577 function C_Open (File_Path : System.Address) return int
578 with
579 SPARK_Mode => Off
580 is
581 begin
582 return C.C_Open (File_Path);
583 end C_Open;
584
585 function C_Read (Buf : System.Address; Len : int) return int
586 with
587 Export,
588 Convention => C,
589 External_Name => "iso9660_read";
590 function C_Read (Buf : System.Address; Len : int) return int
591 with
592 SPARK_Mode => Off
593 is
594 begin
595 return C.C_Read (Buf, Len);
596 end C_Read;
597
598end FILO.FS.ISO9660;