ext2: Factor inode deserialization out
diff --git a/src/filo-fs-ext2.adb b/src/filo-fs-ext2.adb
index c0ced37..d7ee599 100644
--- a/src/filo-fs-ext2.adb
+++ b/src/filo-fs-ext2.adb
@@ -606,6 +606,58 @@
       end if;
    end Extent_Block_Map;
 
+   procedure Parse_Inode
+     (Static   : in     Mount_State;
+      Inode    : in out Inode_Info;
+      Buf      : in     Buffer_Type;
+      Success  :    out Boolean)
+   with
+      Pre => Buf'Length >= Inode_Size'First
+   is
+      S_IFMT   : constant := 8#170000#;
+      S_IFDIR  : constant := 8#040000#;
+      S_IFREG  : constant := 8#100000#;
+      S_IFLNK  : constant := 8#120000#;
+
+      I_Mode      : constant Unsigned_16 := Read_LE16 (Buf, 0);
+      I_Blocks    : constant Unsigned_32 := Read_LE32 (Buf, 28);
+      I_Flags     : constant Unsigned_32 := Read_LE32 (Buf, 32);
+      I_File_ACL  : constant Unsigned_32 := Read_LE32 (Buf, 104);
+   begin
+      case I_Mode and S_IFMT is
+         when S_IFDIR => Inode.Mode := Dir;
+         when S_IFREG => Inode.Mode := Regular;
+         when S_IFLNK => Inode.Mode := Link;
+         when others  => Success := False; return;
+      end case;
+
+      if Inode.Mode = Link and
+         ((I_File_ACL = 0 and I_Blocks = 0) or
+          (I_File_ACL /= 0 and I_Blocks = 2 ** (Static.Block_Size_Bits - 9)))
+      then
+         Inode.Mode := Fast_Link;
+      end if;
+
+      declare
+         I_Size : constant Unsigned_64 :=
+            (if Inode.Mode = Regular
+             then Shift_Left (Unsigned_64 (Read_LE32 (Buf, 108)), 32)
+             else 0) or
+            Unsigned_64 (Read_LE32 (Buf, 4));
+      begin
+         if I_Size > Unsigned_64 (Inode_Length'Last) then
+            Success := False;
+            return;
+         end if;
+         Inode.Size := Inode_Length (I_Size);
+      end;
+
+      Inode.Use_Extents := Static.Feature_Extents and (I_Flags and EXT4_EXTENTS_FL) /= 0;
+      Inode.Inline := Buf (Buf'First + 40 .. Buf'First + 100 - 1);
+
+      Success := True;
+   end Parse_Inode;
+
    procedure Open
      (State    : in out T;
       Inode    : in     Inode_Index;
@@ -635,47 +687,6 @@
       with
          Pre => Buf'Length >= Group_Byte_Offset (Idx, (if Static.Feature_64Bit then 44 else 12));
 
-      ------------------------
-      -- Inode deserialization
-
-      subtype Inode_Off is Natural range 0 .. Inode_Size'Last;
-      function Inode_Byte_Offset (Idx : Inode_In_Block_Index; Off : Inode_Off) return Natural
-      is
-         (Natural (Idx) * Static.Inode_Size + Off);
-
-      function Inode_Mode (Buf : Buffer_Type; Idx : Inode_In_Block_Index) return Unsigned_16
-      is
-        (Read_LE16 (Buf, Inode_Byte_Offset (Idx, 0)))
-      with
-         Pre => Buf'Length >= Inode_Byte_Offset (Idx, 2);
-
-      function Inode_Size (Buf : Buffer_Type; Idx : Inode_In_Block_Index; Mode : Inode_Type) return Unsigned_64
-      is
-        ((if Mode = Regular
-          then Shift_Left (Unsigned_64 (Read_LE32 (Buf, Inode_Byte_Offset (Idx, 108))), 32)
-          else 0) or
-         Unsigned_64 (Read_LE32 (Buf, Inode_Byte_Offset (Idx, 4))))
-      with
-         Pre => Buf'Length >= Inode_Byte_Offset (Idx, 112);
-
-      function Inode_Blocks (Buf : Buffer_Type; Idx : Inode_In_Block_Index) return Unsigned_32
-      is
-        (Read_LE32 (Buf, Inode_Byte_Offset (Idx, 28)))
-      with
-         Pre => Buf'Length >= Inode_Byte_Offset (Idx, 32);
-
-      function Inode_Flags (Buf : Buffer_Type; Idx : Inode_In_Block_Index) return Unsigned_32
-      is
-        (Read_LE32 (Buf, Inode_Byte_Offset (Idx, 32)))
-      with
-         Pre => Buf'Length >= Inode_Byte_Offset (Idx, 36);
-
-      function Inode_File_ACL (Buf : Buffer_Type; Idx : Inode_In_Block_Index) return Unsigned_32
-      is
-        (Read_LE32 (Buf, Inode_Byte_Offset (Idx, 104)))
-      with
-         Pre => Buf'Length >= Inode_Byte_Offset (Idx, 108);
-
       Group : constant Group_Index := Group_Index ((Inode - 1) / Static.Inodes_Per_Group);
       Desc_Block : constant FSBlock_Offset :=
          1 + FSBlock_Offset (Static.First_Data_Block) + FSBlock_Offset (Group / Static.Desc_Per_Block);
@@ -701,6 +712,11 @@
             Inode_In_Group_Index ((Inode - 1) mod Static.Inodes_Per_Group);
          First_Table_Block : constant Unsigned_64 := Group_Inode_Table (Cache (Cache_Start .. Cache_End), Desc);
          Block_Offset : constant Unsigned_64 := Unsigned_64 (Inode_In_Group / Static.Inodes_Per_Block);
+
+         Inode_In_Block : constant Inode_In_Block_Index :=
+            Inode_In_Block_Index (Inode_In_Group mod Static.Inodes_Per_Block);
+         Inode_In_Block_Offset : constant Natural :=
+            Natural (Inode_In_Block) * Static.Inode_Size;
       begin
          if First_Table_Block < Unsigned_64 (Static.First_Data_Block) or
             First_Table_Block > Unsigned_64 (FSBlock_Offset'Last) - Block_Offset
@@ -723,56 +739,18 @@
             return;
          end if;
 
-         declare
-            S_IFMT   : constant := 8#170000#;
-            S_IFDIR  : constant := 8#040000#;
-            S_IFREG  : constant := 8#100000#;
-            S_IFLNK  : constant := 8#120000#;
+         Parse_Inode
+           (Static   => State.Static,
+            Inode    => State.Inode,
+            Buf      => Cache (Cache_Start + Inode_In_Block_Offset ..
+                                 Cache_Start + Inode_In_Block_Offset + Static.Inode_Size - 1),
+            Success  => Success);
 
-            Inode_In_Block : constant Inode_In_Block_Index :=
-               Inode_In_Block_Index (Inode_In_Group mod Static.Inodes_Per_Block);
-            I_Mode : constant Unsigned_16 :=
-               Inode_Mode (Cache (Cache_Start .. Cache_End), Inode_In_Block);
-            I_Flags : constant Unsigned_32 :=
-               Inode_Flags (Cache (Cache_Start .. Cache_End), Inode_In_Block);
-         begin
-            case I_Mode and S_IFMT is
-               when S_IFDIR => State.Inode.Mode := Dir;
-               when S_IFREG => State.Inode.Mode := Regular;
-               when S_IFLNK => State.Inode.Mode := Link;
-               when others  => Success := False; return;
-            end case;
-            if State.Inode.Mode = Link then
-               declare
-                  I_File_ACL : constant Unsigned_32 := Inode_File_ACL (
-                     Cache (Cache_Start .. Cache_End), Inode_In_Block);
-                  I_Blocks : constant Unsigned_32 := Inode_Blocks (
-                     Cache (Cache_Start .. Cache_End), Inode_In_Block);
-               begin
-                  if (I_File_ACL = 0 and I_Blocks = 0) or
-                     (I_File_ACL /= 0 and I_Blocks = 2 ** (Static.Block_Size_Bits - 9))
-                  then
-                     State.Inode.Mode := Fast_Link;
-                  end if;
-               end;
-            end if;
-            declare
-               I_Size : constant Unsigned_64 := Inode_Size (
-                  Cache (Cache_Start .. Cache_End), Inode_In_Block, State.Inode.Mode);
-            begin
-               if I_Size <= Unsigned_64 (Inode_Length'Last) then
-                  State.Inode.Size := Inode_Length (I_Size);
-               else
-                  Success := False;
-                  return;
-               end if;
-            end;
-            State.Inode.Use_Extents := Static.Feature_Extents and (I_Flags and EXT4_EXTENTS_FL) /= 0;
-            State.Inode.Inline := Cache (Cache_Start + 40 .. Cache_Start + 100 - 1);
+         if Success then
             State.Inode.I := Inode;
             Reset_Cache_Logical (State.Cache);
             State.S := File_Opened;
-         end;
+         end if;
       end;
    end Open;