iso9660: Refactor Open() to ease extensions
diff --git a/src/filo-fs-iso9660.adb b/src/filo-fs-iso9660.adb
index fd12854..ad462f0 100644
--- a/src/filo-fs-iso9660.adb
+++ b/src/filo-fs-iso9660.adb
@@ -160,25 +160,84 @@
is
File_Name_Max : constant := 255;
- function Str_Buf_Equal (Str : String; Buf : Buffer_Type) return Boolean
+ procedure Match_ISO_Name
+ (ISO_Name_Length : in Natural;
+ Record_Dir_Pos : in File_Offset;
+ Success : in out Boolean)
with
- Pre => Str'Length <= Buf'Length
+ Post => State.Static = State.Static'Old
is
+ function Upper_Case_Equal (Str : String; Buf : Buffer_Type) return Boolean
+ with
+ Pre => Str'Length <= Buf'Length
+ is
+ begin
+ for I in Str'Range loop
+ declare
+ Chr : constant Unsigned_8 :=
+ (if 'a' <= Str (I) and Str (I) <= 'z' then
+ Character'Pos (Str (I)) - Character'Pos ('a') + Character'Pos ('A')
+ else Character'Pos (Str (I)));
+ begin
+ if Chr /= Buf (Buf'First + (I - Str'First)) then
+ return False;
+ end if;
+ end;
+ end loop;
+ return True;
+ end Upper_Case_Equal;
+
+ Dir_Pos : File_Offset := Record_Dir_Pos;
+ ISO_Name : Buffer_Type (0 .. ISO_Name_Length - 1);
+ Name_Len : Natural;
begin
- for I in Str'Range loop
- declare
- Chr : constant Unsigned_8 :=
- (if 'a' <= Str (I) and Str (I) <= 'z' then
- Character'Pos (Str (I)) - Character'Pos ('a') + Character'Pos ('A')
- else Character'Pos (Str (I)));
- begin
- if Chr /= Buf (Buf'First + (I - Str'First)) then
- return False;
- end if;
- end;
- end loop;
- return True;
- end Str_Buf_Equal;
+ -- Check if length could match.
+ -- First for the weird `.' and `..' encoding,
+ -- then for regular file names + `.' and file version `;1'.
+ if not (ISO_Name_Length = 1 and File_Name'Length <= 2) and
+ ISO_Name_Length not in File_Name'Length .. File_Name'Length + 3
+ then
+ return;
+ end if;
+
+ pragma Warnings
+ (GNATprove, Off, """Dir_Pos"" is set*but not used",
+ Reason => "This is the last part of the record we care about.");
+ Read
+ (State => State,
+ File_Pos => Dir_Pos,
+ Buf => ISO_Name,
+ Len => Name_Len);
+ if Name_Len /= ISO_Name_Length then
+ return;
+ end if;
+ pragma Warnings (GNATprove, On, """Dir_Pos"" is set*but not used");
+
+ if (Name_Len = 1 and ISO_Name (0) = 16#00# and File_Name = ".") or
+ (Name_Len = 1 and ISO_Name (0) = 16#01# and File_Name = "..")
+ then
+ Success := True;
+ return;
+ end if;
+
+ -- Ignore file version `;1'
+ if Name_Len >= File_Name'Length + 2 and
+ ISO_Name (Name_Len - 2) = Character'Pos (';') and
+ ISO_Name (Name_Len - 1) = Character'Pos ('1')
+ then
+ Name_Len := Name_Len - 2;
+ end if;
+
+ -- Ignore trailing `.'
+ if Name_Len >= File_Name'Length + 1 and
+ ISO_Name (Name_Len - 1) = Character'Pos ('.')
+ then
+ Name_Len := Name_Len - 1;
+ end if;
+
+ Success := Name_Len = File_Name'Length and then
+ Upper_Case_Equal (File_Name, ISO_Name);
+ end Match_ISO_Name;
Found_Inode : Inode_Index;
Dir_Pos : File_Length;
@@ -222,81 +281,54 @@
(FSBlock_Index (Dir_Pos mod FSBlock_Size) <= Directory_Record_Offset'Last);
declare
- Dir_Rec : Directory_Record;
- Dir_Rec_Name : Buffer_Type (0 .. File_Name_Max - 1);
+ Dir_Rec_Head : Directory_Record;
Record_Dir_Pos : File_Offset := Dir_Pos;
Len : Natural;
begin
Read
(State => State,
File_Pos => Record_Dir_Pos,
- Buf => Dir_Rec,
+ Buf => Dir_Rec_Head,
Len => Len);
- if Len < Dir_Rec'Length then
+ if Len /= Dir_Rec_Head'Length then
return;
end if;
- if File_Name'Length <= Natural (Dir_Rec (32)) and
- Natural (Dir_Rec (32)) <= File_Name'Length + 3
- then
- pragma Warnings
- (GNATprove, Off, """Record_Dir_Pos"" is set*but not used",
- Reason => "We only care about intermedidate values.");
- Read
- (State => State,
- File_Pos => Record_Dir_Pos,
- Buf => Dir_Rec_Name (0 .. Natural (Dir_Rec (32) - 1)),
- Len => Len);
- pragma Warnings (GNATprove, On, """Record_Dir_Pos"" is set*but not used");
-
- if (Len = 1 and Dir_Rec_Name (0) = 16#00# and File_Name = ".") or
- (Len = 1 and Dir_Rec_Name (0) = 16#01# and File_Name = "..")
- then
- Success := True;
- else
- -- Remove file version
- if Len >= File_Name'Length + 2 and
- Dir_Rec_Name (Len - 2) = Character'Pos (';') and
- Dir_Rec_Name (Len - 1) = Character'Pos ('1')
- then
- Len := Len - 2;
- end if;
-
- -- Remove trailing .
- if Len >= File_Name'Length + 1 and
- Dir_Rec_Name (Len - 1) = Character'Pos ('.')
- then
- Len := Len - 1;
- end if;
-
- Success := Len = File_Name'Length and then
- Str_Buf_Equal (File_Name, Dir_Rec_Name);
- end if;
- if Success then
- Found_Inode :=
- (Block => FSBlock (Dir_Pos / FSBlock_Size) + State.Inode.Extents (0).Start,
- Offset => FSBlock_Index (Dir_Pos mod FSBlock_Size));
- exit;
- end if;
- end if;
-
declare
- Dir_Rec_Length : constant File_Length := File_Length (Dir_Rec (0));
- Block_Gap : constant File_Length := FSBlock_Size - (Dir_Pos mod FSBlock_Size);
+ Dir_Rec_Length : constant Natural := Natural (Dir_Rec_Head (0));
+ Dir_Rec_Name_Length : constant Natural := Natural (Dir_Rec_Head (32));
begin
- -- End of block?
- if Dir_Rec_Length = Block_Gap or Dir_Rec_Length = 0 then
- if Unsigned_64 (Dir_Pos) >= Unsigned_64 (State.Inode.Size) - Unsigned_64 (Block_Gap) then
+ if Dir_Rec_Length /= 0 then
+
+ if Unsigned_64 (Dir_Pos) > Unsigned_64 (State.Inode.Size) - Unsigned_64 (Dir_Rec_Length) or
+ Dir_Rec_Name_Length > Dir_Rec_Length - Dir_Rec_Head'Length
+ then
return;
- else
- Dir_Pos := Dir_Pos + Block_Gap;
end if;
+
+
+ Match_ISO_Name (Dir_Rec_Name_Length, Record_Dir_Pos, Success);
+
+ if Success then
+ Found_Inode :=
+ (Block => FSBlock (Dir_Pos / FSBlock_Size) + State.Inode.Extents (0).Start,
+ Offset => FSBlock_Index (Dir_Pos mod FSBlock_Size));
+ exit;
+ end if;
+
+ Dir_Pos := Dir_Pos + File_Length (Dir_Rec_Length);
+
else
- if Unsigned_64 (Dir_Pos) > Unsigned_64 (State.Inode.Size) - Unsigned_64 (Dir_Rec_Length) then
- return;
- else
- Dir_Pos := Dir_Pos + Dir_Rec_Length;
- end if;
+ -- `Dir_Rec_Length = 0` means we have to skip to the next fs block:
+ declare
+ Block_Gap : constant File_Length := FSBlock_Size - (Dir_Pos mod FSBlock_Size);
+ begin
+ if Unsigned_64 (Dir_Pos) >= Unsigned_64 (State.Inode.Size) - Unsigned_64 (Block_Gap) then
+ return;
+ else
+ Dir_Pos := Dir_Pos + Block_Gap;
+ end if;
+ end;
end if;
end;
end;