blob: 32a16c33464d4689ad2fbf61fb8c5750d88c206f [file] [log] [blame]
Nico Huber26f71832023-12-05 16:26:56 +01001-- Derived from GRUB -- GRand Unified Bootloader
2-- Copyright (C) 1999, 2001, 2003 Free Software Foundation, Inc.
3-- Copyright (C) 2023 secunet Security Networks AG
4--
5-- This program is free software; you can redistribute it and/or modify
6-- it under the terms of the GNU General Public License as published by
7-- the Free Software Foundation; either version 2 of the License, or
8-- (at your option) any later version.
9
Nico Huber33f6d952023-12-13 23:16:42 +010010with Ada.Unchecked_Conversion;
Nico Huber8ec45a12023-12-04 17:11:08 +010011with System;
Nico Huber1d7727f2023-11-30 15:58:46 +010012with Interfaces;
Nico Huber8ec45a12023-12-04 17:11:08 +010013with Interfaces.C;
14with Interfaces.C.Strings;
Nico Huber1d7727f2023-11-30 15:58:46 +010015
Thomas Heijligen5c43abc2023-12-11 15:24:36 +000016with FILO.Blockdev;
17with FILO.FS.VFS;
Nico Huber8ec45a12023-12-04 17:11:08 +010018
19use Interfaces.C;
Nico Huber1d7727f2023-11-30 15:58:46 +010020
Thomas Heijligen5c43abc2023-12-11 15:24:36 +000021package body FILO.FS.Ext2 is
Nico Huber1d7727f2023-11-30 15:58:46 +010022
Nico Huber57d3a852023-12-04 15:42:40 +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
Nico Huber26f71832023-12-05 16:26:56 +010026 --------------------------------------------------------------------------
27
28 SUPERBLOCK_SIZE : constant := 1024;
29 SUPERBLOCK_BLOCKS : constant := SUPERBLOCK_SIZE / BLOCK_SIZE;
30
31 SUPERBLOCK_MAGIC : constant := 16#ef53#;
32 OLD_REV : constant := 0;
33 DYNAMIC_REV : constant := 1;
34 FEATURE_INCOMPAT_EXTENTS : constant := 16#0040#;
35 FEATURE_INCOMPAT_64BIT : constant := 16#0080#;
36
Nico Huber57d3a852023-12-04 15:42:40 +010037 procedure Mount
38 (State : in out T;
39 Part_Len : in Partition_Length;
40 Success : out Boolean)
Nico Huber1d7727f2023-11-30 15:58:46 +010041 is
Nico Huber26f71832023-12-05 16:26:56 +010042 Super_Block : Buffer_Type (0 .. SUPERBLOCK_SIZE - 1) := (others => 0);
Nico Huber1d7727f2023-11-30 15:58:46 +010043 begin
Nico Huber26f71832023-12-05 16:26:56 +010044 if Part_Len < 2 * SUPERBLOCK_SIZE then
45 Success := False;
46 return;
47 end if;
48
Thomas Heijligen5c43abc2023-12-11 15:24:36 +000049 Blockdev.Read (Super_Block, 1 * SUPERBLOCK_SIZE, Success);
Nico Huber26f71832023-12-05 16:26:56 +010050 if not Success then
51 return;
52 end if;
53
54 if Read_LE16 (Super_Block, 14 * 4) /= 16#ef53# then
55 Success := False;
56 return;
57 end if;
58
59 State.Part_Len := Part_Len;
Nico Hubercd1d5f72023-12-13 16:01:43 +010060 State.First_Data_Block := FSBlock_Offset (Read_LE32 (Super_Block, 5 * 4));
Nico Huber26f71832023-12-05 16:26:56 +010061
62 declare
63 S_Log_Block_Size : constant Unsigned_32 := Read_LE32 (Super_Block, 6 * 4);
64 begin
65 if S_Log_Block_Size <= Unsigned_32 (Log_Block_Size'Last - 10) then
66 State.Block_Size_Bits := Log_Block_Size (S_Log_Block_Size + 10);
67 else
68 Success := False;
69 return;
70 end if;
71 end;
72
73 declare
74 S_Inodes_Per_Group : constant Unsigned_32 := Read_LE32 (Super_Block, 10 * 4);
75 begin
76 if S_Inodes_Per_Group in 1 .. Unsigned_32 (Positive'Last) then
77 State.Inodes_Per_Group := Positive (S_Inodes_Per_Group);
78 else
79 Success := False;
80 return;
81 end if;
82 end;
83
84 declare
85 S_Rev_Level : constant Unsigned_32 := Read_LE32 (Super_Block, 19 * 4);
86 begin
87 if S_Rev_Level >= DYNAMIC_REV then
88 declare
89 S_Inode_Size : constant Unsigned_16 := Read_LE16 (Super_Block, 22 * 4);
90 begin
91 if S_Inode_Size in
92 Unsigned_16 (Inode_Size'First) .. Unsigned_16 (Inode_Size'Last)
93 then
94 State.Inode_Size := Inode_Size (S_Inode_Size);
95 else
96 Success := False;
97 return;
98 end if;
99 end;
100 else
101 State.Inode_Size := Inode_Size'First;
102 end if;
103 end;
104
105 declare
106 S_Feature_Incompat : constant Unsigned_32 := Read_LE32 (Super_Block, 24 * 4);
107 begin
108 State.Feature_Extents := (S_Feature_Incompat and FEATURE_INCOMPAT_EXTENTS) /= 0;
109 State.Feature_64Bit := (S_Feature_Incompat and FEATURE_INCOMPAT_64BIT) /= 0;
110 if State.Feature_64Bit then
111 declare
112 S_Desc_Size : constant Unsigned_16 := Read_LE16 (Super_Block, 63 * 4 + 2);
113 begin
Nico Hubercd1d5f72023-12-13 16:01:43 +0100114 if Is_Power_Of_2 (S_Desc_Size) and then
115 S_Desc_Size in Unsigned_16 (Desc_Size'First) ..
116 Unsigned_16 (Positive'Min (Desc_Size'Last, 2 ** State.Block_Size_Bits))
Nico Huber26f71832023-12-05 16:26:56 +0100117 then
118 State.Desc_Size := Desc_Size (S_Desc_Size);
119 else
120 Success := False;
121 return;
122 end if;
123 end;
Nico Huber77a04d72023-12-13 23:11:40 +0100124 State.Feature_64Bit := State.Feature_64Bit and State.Desc_Size >= 64;
Nico Huber26f71832023-12-05 16:26:56 +0100125 else
126 State.Desc_Size := Desc_Size'First;
127 end if;
128 end;
129
130 State.S := Mounted;
Nico Huber1d7727f2023-11-30 15:58:46 +0100131 end Mount;
132
Nico Huberf5d99d02023-12-12 13:42:55 +0100133 procedure Read_FSBlock
134 (State : in T;
135 Buf : out Buffer_Type;
136 FSBlock : in FSBlock_Offset;
137 Success : out Boolean)
138 with
139 Pre =>
140 Is_Mounted (State) and
141 Buf'Length = 2 ** State.Block_Size_Bits
142 is
143 Block_Size : constant Blockdev_Length := 2 ** State.Block_Size_Bits;
144 Max_Block_Offset : constant FSBlock_Offset :=
145 FSBlock_Offset (State.Part_Len / Block_Size - 1);
146 begin
147 if FSBlock > Max_Block_Offset then
148 Success := False;
149 return;
150 end if;
151 Blockdev.Read (Buf, Blockdev_Length (FSBlock) * Block_Size, Success);
152 end Read_FSBlock;
153
Nico Huber68c86932023-12-13 11:03:11 +0100154 procedure Cache_FSBlock
155 (State : in out T;
156 Phys : in FSBlock_Offset;
157 Level : in Block_Cache_Index;
158 Logical_Off : in FSBlock_Logical;
159 Cache_Start : out Max_Block_Index;
160 Cache_End : out Max_Block_Index;
161 Success : out Boolean)
162 with
163 Post => Cache_End = Cache_Start + 2 ** State.Block_Size_Bits
164 is
165 Block_Size : constant Natural := 2 ** State.Block_Size_Bits;
166 -- Limit cache usage depending on block size:
167 Max_Level : constant Block_Cache_Index :=
168 2 ** (Log_Block_Size'Last - State.Block_Size_Bits) - 1;
169 Cache_Level : constant Block_Cache_Index :=
170 Block_Cache_Index'Min (Level, Max_Level);
171 begin
172 Cache_Start := Cache_Level * Block_Size;
173 Cache_End := Cache_Start + Block_Size - 1;
174 if State.Block_Cache_Index (Cache_Level) = Logical_Off then
175 Success := True;
176 else
177 Read_FSBlock
178 (State => State,
179 Buf => State.Block_Cache (Cache_Start .. Cache_End),
180 FSBlock => Phys,
181 Success => Success);
182 State.Block_Cache_Index (Cache_Level) := Logical_Off;
183 end if;
184 end Cache_FSBlock;
185
Nico Huber6623c982023-12-12 16:35:46 +0100186 procedure Ext2_Block_Map
187 (State : in out T;
188 Logical : in FSBlock_Logical;
189 Physical : out FSBlock_Offset;
190 Success : out Boolean)
191 is
Nico Huber33f6d952023-12-13 23:16:42 +0100192 Direct_Blocks : constant := 12;
193 type Direct_Blocks_Array is array (Natural range 0 .. Direct_Blocks - 1) of Unsigned_32;
194 type Inode_Blocks is record
195 Direct_Blocks : Direct_Blocks_Array;
196 Indirect_Block : Unsigned_32;
197 Double_Indirect : Unsigned_32;
198 Triple_Indirect : Unsigned_32;
199 end record
200 with Size => Inode_Extents'Length * 8;
201
202 function I_Blocks is new Ada.Unchecked_Conversion (Inode_Extents, Inode_Blocks);
203 function I_Blocks (State : T) return Inode_Blocks is (I_Blocks (State.Inode.Extents));
204
Nico Huber6623c982023-12-12 16:35:46 +0100205 Block_Size : constant Natural := 2 ** State.Block_Size_Bits;
206 Addr_Per_Block : constant FSBlock_Logical := FSBlock_Logical (Block_Size / 4);
207 Max_Addr_Per_Block : constant FSBlock_Logical := FSBlock_Logical (2 ** Log_Block_Size'Last / 4);
208 type Addr_In_Block_Range is range 0 .. Max_Addr_Per_Block - 1;
209
210 procedure Indirect_Block_Lookup
211 (Indirect_Block_Phys : in FSBlock_Offset;
212 Addr_In_Block : in Addr_In_Block_Range;
213 Level : in Block_Cache_Index;
214 Logical_Off : in FSBlock_Logical;
215 Next_Physical : out FSBlock_Offset;
216 Success : out Boolean)
217 with
218 Pre => FSBlock_Logical (Addr_In_Block) < Addr_Per_Block
219 is
Nico Huber68c86932023-12-13 11:03:11 +0100220 Cache_Start, Cache_End : Max_Block_Index;
Nico Huber6623c982023-12-12 16:35:46 +0100221 begin
Nico Huber68c86932023-12-13 11:03:11 +0100222 Cache_FSBlock
223 (State => State,
224 Phys => Indirect_Block_Phys,
225 Level => Level,
226 Logical_Off => Logical_Off,
227 Cache_Start => Cache_Start,
228 Cache_End => Cache_End,
229 Success => Success);
Nico Huber6623c982023-12-12 16:35:46 +0100230 Next_Physical := FSBlock_Offset (Read_LE32
Nico Huberfe897122023-12-12 21:33:36 +0100231 (Buf => State.Block_Cache (Cache_Start .. Cache_End),
Nico Huber6623c982023-12-12 16:35:46 +0100232 Off => Natural (Addr_In_Block) * 4));
Nico Huber6623c982023-12-12 16:35:46 +0100233 end Indirect_Block_Lookup;
234
235 Logical_Rest : FSBlock_Logical := Logical;
236 begin
237 if Logical_Rest < Direct_Blocks then
Nico Huber33f6d952023-12-13 23:16:42 +0100238 Physical := FSBlock_Offset (I_Blocks (State).Direct_Blocks (Natural (Logical)));
Nico Huber6623c982023-12-12 16:35:46 +0100239 Success := True;
240 return;
241 end if;
242
243 Logical_Rest := Logical_Rest - Direct_Blocks;
244 if Logical_Rest < Addr_Per_Block then
245 Indirect_Block_Lookup
Nico Huber33f6d952023-12-13 23:16:42 +0100246 (Indirect_Block_Phys => FSBlock_Offset (I_Blocks (State).Indirect_Block),
Nico Huber6623c982023-12-12 16:35:46 +0100247 Addr_In_Block => Addr_In_Block_Range (Logical_Rest),
Nico Huberfe897122023-12-12 21:33:36 +0100248 Level => 0,
Nico Huber6623c982023-12-12 16:35:46 +0100249 Logical_Off => Logical - Logical_Rest,
250 Next_Physical => Physical,
251 Success => Success);
252 return;
253 end if;
254
255 Logical_Rest := Logical_Rest - Addr_Per_Block;
256 if Logical_Rest < Addr_Per_Block ** 2 then
257 Indirect_Block_Lookup
Nico Huber33f6d952023-12-13 23:16:42 +0100258 (Indirect_Block_Phys => FSBlock_Offset (I_Blocks (State).Double_Indirect),
Nico Huber6623c982023-12-12 16:35:46 +0100259 Addr_In_Block => Addr_In_Block_Range (Logical_Rest / Addr_Per_Block),
Nico Huberfe897122023-12-12 21:33:36 +0100260 Level => 1,
Nico Huber6623c982023-12-12 16:35:46 +0100261 Logical_Off => Logical - Logical_Rest,
262 Next_Physical => Physical,
263 Success => Success);
264 if not Success then
265 return;
266 end if;
267
268 Indirect_Block_Lookup
269 (Indirect_Block_Phys => Physical,
270 Addr_In_Block => Addr_In_Block_Range (Logical_Rest mod Addr_Per_Block),
Nico Huberfe897122023-12-12 21:33:36 +0100271 Level => 0,
Nico Huber6623c982023-12-12 16:35:46 +0100272 Logical_Off => Logical - (Logical_Rest mod Addr_Per_Block),
273 Next_Physical => Physical,
274 Success => Success);
275 return;
276 end if;
277
278 Logical_Rest := Logical_Rest - Addr_Per_Block ** 2;
279 if Logical_Rest < Addr_Per_Block ** 3 then
280 Indirect_Block_Lookup
Nico Huber33f6d952023-12-13 23:16:42 +0100281 (Indirect_Block_Phys => FSBlock_Offset (I_Blocks (State).Triple_Indirect),
Nico Huber6623c982023-12-12 16:35:46 +0100282 Addr_In_Block => Addr_In_Block_Range (Logical_Rest / Addr_Per_Block ** 2),
Nico Huberfe897122023-12-12 21:33:36 +0100283 Level => 2,
Nico Huber6623c982023-12-12 16:35:46 +0100284 Logical_Off => Logical - Logical_Rest,
285 Next_Physical => Physical,
286 Success => Success);
287 if not Success then
288 return;
289 end if;
290
291 Indirect_Block_Lookup
292 (Indirect_Block_Phys => Physical,
293 Addr_In_Block => Addr_In_Block_Range (Logical_Rest / Addr_Per_Block mod Addr_Per_Block),
Nico Huberfe897122023-12-12 21:33:36 +0100294 Level => 1,
Nico Huber6623c982023-12-12 16:35:46 +0100295 Logical_Off => Logical - (Logical_Rest mod Addr_Per_Block ** 2),
296 Next_Physical => Physical,
297 Success => Success);
298 if not Success then
299 return;
300 end if;
301
302 Indirect_Block_Lookup
303 (Indirect_Block_Phys => Physical,
304 Addr_In_Block => Addr_In_Block_Range (Logical_Rest mod Addr_Per_Block),
Nico Huberfe897122023-12-12 21:33:36 +0100305 Level => 0,
Nico Huber6623c982023-12-12 16:35:46 +0100306 Logical_Off => Logical - (Logical_Rest mod Addr_Per_Block),
307 Next_Physical => Physical,
308 Success => Success);
309 return;
310 end if;
311
312 -- Logical address was just too high.
313 Success := False;
314 end Ext2_Block_Map;
315
Nico Huberfffc8c12023-12-13 12:44:12 +0100316 procedure Extent_Block_Map
317 (State : in out T;
318 Logical : in FSBlock_Logical;
319 Physical : out FSBlock_Offset;
320 Success : out Boolean)
321 is
322 -- Extent blocks always start with a 12B header and contain 12B entries.
323 -- Every entry starts with the number of the first logical block it
324 -- covers. Entries are sorted by this number.
325 -- Depth > 0 blocks have index entries, referencing further extent blocks.
326 -- Depth = 0 blocks have extent entries, referencing a contiguous range
327 -- of data blocks.
328 --
329 -- +-----------------+
330 -- .-> | Hdr depth=0 |
331 -- | +-----------------+
332 -- | | Extent 0.. 12 |
333 -- +-------------+ | +-----------------+
334 -- | Hdr depth=1 | | | Extent 13.. 13 |
335 -- +-------------+ | +-----------------+
336 -- | Index 0 | --' | Extent 14..122 |
337 -- +-------------+ +-----------------+
338 -- | Index 123 | --.
339 -- +-------------+ | +-----------------+
340 -- `-> | Hdr depth=0 |
341 -- +-----------------+
342 -- | Extent 123..125 |
343 -- +-----------------+
344 -- | Extent 126..234 |
345 -- +-----------------+
346 --
347
348 Extent_Header_Size : constant := 12;
349 Extent_Header_Magic : constant := 16#f03a#;
350 subtype Extent_Off is Natural range 0 .. Extent_Header_Size;
351 subtype Extent_Idx is Natural range 1 .. (Max_Block_Index'Last + 1) / Extent_Header_Size - 1;
352
353 function Extent_Byte_Offset (Idx : Extent_Idx; Off : Extent_Off) return Natural
354 is
355 (Idx * Extent_Header_Size + Off);
356
357 function Header_Magic (Buf : Buffer_Type) return Unsigned_16
358 is
359 (Read_LE16 (Buf, 0))
360 with
361 Pre => Buf'Length >= 2;
362
363 function Header_Entries (Buf : Buffer_Type) return Natural
364 is
365 (Natural (Read_LE16 (Buf, 2)))
366 with
367 Pre => Buf'Length >= 4;
368
369 function Header_Depth (Buf : Buffer_Type) return Natural
370 is
371 (Natural (Read_LE16 (Buf, 6)))
372 with
373 Pre => Buf'Length >= 8;
374
375 function Index_Logical (Buf : Buffer_Type; Idx : Extent_Idx) return FSBlock_Logical
376 is
377 (FSBlock_Logical (Read_LE32 (Buf, Extent_Byte_Offset (Idx, 0))))
378 with
379 Pre => Buf'Length >= Extent_Byte_Offset (Idx, 4);
380
381 function Index_Physical (Buf : Buffer_Type; Idx : Extent_Idx) return FSBlock_Offset
382 is
383 (FSBlock_Offset
384 (Shift_Left (Unsigned_64 (Read_LE16 (Buf, Extent_Byte_Offset (Idx, 8))), 32) or
385 Unsigned_64 (Read_LE32 (Buf, Extent_Byte_Offset (Idx, 4)))))
386 with
387 Pre => Buf'Length >= Extent_Byte_Offset (Idx, 10);
388
389 function Extent_Logical (Buf : Buffer_Type; Idx : Extent_Idx) return FSBlock_Logical
390 renames Index_Logical;
391
392 function Extent_Length (Buf : Buffer_Type; Idx : Extent_Idx) return FSBlock_Logical
393 is
394 (FSBlock_Logical (Read_LE16 (Buf, Extent_Byte_Offset (Idx, 4))))
395 with
396 Pre => Buf'Length >= Extent_Byte_Offset (Idx, 6);
397
398 function Extent_Physical (Buf : Buffer_Type; Idx : Extent_Idx) return FSBlock_Offset
399 is
400 (FSBlock_Offset
401 (Shift_Left (Unsigned_64 (Read_LE16 (Buf, Extent_Byte_Offset (Idx, 6))), 32) or
402 Unsigned_64 (Read_LE32 (Buf, Extent_Byte_Offset (Idx, 8)))))
403 with
404 Pre => Buf'Length >= Extent_Byte_Offset (Idx, 12);
405
406 function Bin_Search (Buf : Buffer_Type; Refs : Extent_Idx) return Extent_Idx
407 with
408 Pre => Refs in 1 .. Extent_Idx (Buf'Length / Extent_Header_Size - 1) and
409 Extent_Logical (Buf, 1) <= Logical,
410 Post => Bin_Search'Result in 1 .. Refs and
411 Extent_Logical (Buf, Bin_Search'Result) <= Logical
412 is
413 Left : Extent_Idx := 1;
414 Right : Extent_Idx := Refs;
415 begin
416 while Left <= Right loop
417 declare
418 Mid : constant Extent_Idx := (Left + Right) / 2;
419 Ext_Logical : constant FSBlock_Logical := Extent_Logical (Buf, Mid);
420 begin
421 if Logical < Ext_Logical then
422 Right := Mid - 1;
423 else
424 Left := Mid + 1;
425 end if;
426 end;
427 end loop;
428 return Left - 1;
429 end Bin_Search;
430
431 procedure Next_Ref
432 (Current : in FSBlock_Offset;
433 Logical_Off : in FSBlock_Logical;
434 Depth : in Natural;
435 Next : out Extent_Idx;
436 Cache_Start : out Max_Block_Index;
437 Cache_End : out Max_Block_Index;
438 Success : out Boolean)
439 with
440 Pre => Logical_Off <= Logical,
441 Post => (if Success then
442 Extent_Logical (State.Block_Cache (Cache_Start .. Cache_End), Next) <= Logical)
443 is
444 Block_Size : constant Natural := 2 ** State.Block_Size_Bits;
445 Dynamic_Max_Index : constant Natural := Block_Size / Extent_Header_Size - 1;
446 begin
447 Cache_FSBlock
448 (State => State,
449 Phys => Current,
450 Level => Depth,
451 Logical_Off => Logical_Off,
452 Cache_Start => Cache_Start,
453 Cache_End => Cache_End,
454 Success => Success);
455 if not Success then
456 Next := 1;
457 return;
458 end if;
459
460 declare
461 Hdr_Magic : constant Unsigned_16 :=
462 Header_Magic (State.Block_Cache (Cache_Start .. Cache_End));
463 Hdr_Entries : constant Natural :=
464 Header_Entries (State.Block_Cache (Cache_Start .. Cache_End));
465 Hdr_Depth : constant Natural :=
466 Header_Depth (State.Block_Cache (Cache_Start .. Cache_End));
467 First_Logical : constant FSBlock_Logical :=
468 Extent_Logical (State.Block_Cache (Cache_Start .. Cache_End), 1);
469 begin
470 Success := Success and then
471 Hdr_Magic = Extent_Header_Magic and then
472 Hdr_Depth = Depth and then
473 Hdr_Entries <= Dynamic_Max_Index and then
474 First_Logical = Logical_Off;
475 if not Success then
476 Next := 1;
477 else
478 Next := Bin_Search (State.Block_Cache (Cache_Start .. Cache_End), Hdr_Entries);
479 end if;
480 end;
481 end Next_Ref;
482
Nico Huber33f6d952023-12-13 23:16:42 +0100483 Inode_Magic : constant Unsigned_16 := Header_Magic (State.Inode.Extents);
484 Inode_Entries : constant Natural := Header_Entries (State.Inode.Extents);
485 First_Logical : constant FSBlock_Logical := Extent_Logical (State.Inode.Extents, 1);
486 Depth : Natural := Header_Depth (State.Inode.Extents);
Nico Huberfffc8c12023-12-13 12:44:12 +0100487
488 Cache_Start, Cache_End : Max_Block_Index;
489 Logical_Off, Length : FSBlock_Logical;
490 Idx : Extent_Idx;
491 begin
492 Success :=
493 Inode_Magic = Extent_Header_Magic and then
494 Inode_Entries > 0 and then
Nico Huber33f6d952023-12-13 23:16:42 +0100495 Inode_Entries < State.Inode.Extents'Length / Extent_Header_Size and then
Nico Huberfffc8c12023-12-13 12:44:12 +0100496 First_Logical <= Logical;
497 if not Success then
498 Physical := 0;
499 return;
500 end if;
501
Nico Huber33f6d952023-12-13 23:16:42 +0100502 Idx := Bin_Search (State.Inode.Extents, Inode_Entries);
Nico Huberfffc8c12023-12-13 12:44:12 +0100503 if Depth = 0 then
Nico Huber33f6d952023-12-13 23:16:42 +0100504 Physical := Extent_Physical (State.Inode.Extents, Idx);
505 Logical_Off := Extent_Logical (State.Inode.Extents, Idx);
506 Length := Extent_Length (State.Inode.Extents, Idx);
Nico Huberfffc8c12023-12-13 12:44:12 +0100507 else
Nico Huber33f6d952023-12-13 23:16:42 +0100508 Physical := Index_Physical (State.Inode.Extents, Idx);
509 Logical_Off := Index_Logical (State.Inode.Extents, Idx);
Nico Huberfffc8c12023-12-13 12:44:12 +0100510 loop
511 Depth := Depth - 1;
512 Next_Ref
513 (Current => Physical,
514 Logical_Off => Logical_Off,
515 Depth => Depth,
516 Next => Idx,
517 Cache_Start => Cache_Start,
518 Cache_End => Cache_End,
519 Success => Success);
520 if not Success then
521 return;
522 end if;
523
524 exit when Depth = 0;
525 Physical := Index_Physical (State.Block_Cache (Cache_Start .. Cache_End), Idx);
526 Logical_Off := Index_Logical (State.Block_Cache (Cache_Start .. Cache_End), Idx);
527 end loop;
528
529 Physical := Extent_Physical (State.Block_Cache (Cache_Start .. Cache_End), Idx);
530 Logical_Off := Extent_Logical (State.Block_Cache (Cache_Start .. Cache_End), Idx);
531 Length := Extent_Length (State.Block_Cache (Cache_Start .. Cache_End), Idx);
532 end if;
533
534 Success :=
535 Length > 0 and then
Nico Huberc4c7a5e2023-12-14 00:08:56 +0100536 Logical_Off <= FSBlock_Logical'Last - Length and then
Nico Huberfffc8c12023-12-13 12:44:12 +0100537 Logical < Logical_Off + Length;
538 if Success then
539 Physical := Physical + FSBlock_Offset (Logical - Logical_Off);
540 end if;
541 end Extent_Block_Map;
542
Nico Huber57d3a852023-12-04 15:42:40 +0100543 procedure Open
544 (State : in out T;
545 File_Len : out File_Length;
546 File_Path : in String;
547 Success : out Boolean)
Nico Huber1d7727f2023-11-30 15:58:46 +0100548 is
549 begin
Nico Huber57d3a852023-12-04 15:42:40 +0100550 File_Len := 0;
Nico Huber1d7727f2023-11-30 15:58:46 +0100551 Success := False;
552 end Open;
553
Nico Huber57d3a852023-12-04 15:42:40 +0100554 procedure Close (State : in out T) is
555 begin
556 State.S := Mounted;
557 end Close;
Nico Huber1d7727f2023-11-30 15:58:46 +0100558
Nico Huber57d3a852023-12-04 15:42:40 +0100559 procedure Read
560 (State : in out T;
561 File_Len : in File_Length;
562 File_Pos : in out File_Offset;
563 Buf : out Buffer_Type;
564 Len : out Natural)
Nico Huber1d7727f2023-11-30 15:58:46 +0100565 is
566 begin
Nico Huber57d3a852023-12-04 15:42:40 +0100567 Buf := (others => 0);
Nico Huber1d7727f2023-11-30 15:58:46 +0100568 Len := 0;
569 end Read;
570
Nico Huber26f71832023-12-05 16:26:56 +0100571 --------------------------------------------------------------------------
572
573 package C is new VFS (T => T, Initial => (S => Unmounted, others => <>));
Nico Huber8ec45a12023-12-04 17:11:08 +0100574
575 function C_Mount return int
576 with
577 Export,
578 Convention => C,
579 External_Name => "ext2fs_mount";
580 function C_Mount return int
581 with
582 SPARK_Mode => Off
583 is
584 begin
585 return C.C_Mount;
586 end C_Mount;
587
588 function C_Open (File_Path : Strings.chars_ptr) return int
589 with
590 Export,
591 Convention => C,
592 External_Name => "ext2fs_dir";
593 function C_Open (File_Path : Strings.chars_ptr) return int
594 with
595 SPARK_Mode => Off
596 is
597 begin
598 return C.C_Open (File_Path);
599 end C_Open;
600
601 function C_Read (Buf : System.Address; Len : int) return int
602 with
603 Export,
604 Convention => C,
605 External_Name => "ext2fs_read";
606 function C_Read (Buf : System.Address; Len : int) return int
607 with
608 SPARK_Mode => Off
609 is
610 begin
611 return C.C_Read (Buf, Len);
612 end C_Read;
613
Thomas Heijligen5c43abc2023-12-11 15:24:36 +0000614end FILO.FS.Ext2;