ext2: Read inode type and length
diff --git a/src/filo-fs-ext2.adb b/src/filo-fs-ext2.adb
index cb3f7bf..06909c0 100644
--- a/src/filo-fs-ext2.adb
+++ b/src/filo-fs-ext2.adb
@@ -589,6 +589,9 @@
       Inodes_Per_Block : constant Inode_Index := Inode_Index (Block_Size / State.Inode_Size);
       Desc_Per_Block : constant Group_Index := Group_Index (Block_Size / State.Desc_Size);
 
+      ------------------------
+      -- Group deserialization
+
       subtype Group_Off is Natural range 0 .. Desc_Size'Last;
       function Group_Byte_Offset (Idx : Group_Index; Off : Group_Off) return Natural
       is
@@ -605,17 +608,47 @@
       with
          Pre => Buf'Length >= Group_Byte_Offset (Idx, 44);
 
+      ------------------------
+      -- Inode deserialization
+
       subtype Inode_Off is Natural range 0 .. Inode_Size'Last;
       function Inode_Byte_Offset (Idx : Inode_Index; Off : Inode_Off) return Natural
       is
          (Natural (Idx) * State.Inode_Size + Off);
 
+      function Inode_Mode (Buf : Buffer_Type; Idx : Inode_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_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_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_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_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) / State.Inodes_Per_Group);
       Desc_Block : constant FSBlock_Offset :=
          1 + State.First_Data_Block + FSBlock_Offset (Group / Desc_Per_Block);
@@ -651,10 +684,47 @@
          end if;
 
          declare
+            S_IFMT   : constant := 8#170000#;
+            S_IFDIR  : constant := 8#040000#;
+            S_IFREG  : constant := 8#100000#;
+            S_IFLNK  : constant := 8#120000#;
+
             Inode_In_Block : constant Inode_Index := Inode_In_Group mod Inodes_Per_Block;
+            I_Mode : constant Unsigned_16 :=
+               Inode_Mode (State.Block_Cache (Cache_Start .. Cache_End), Inode_In_Block);
             I_Flags : constant Unsigned_32 :=
                Inode_Flags (State.Block_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 (
+                     State.Block_Cache (Cache_Start .. Cache_End), Inode_In_Block);
+                  I_Blocks : constant Unsigned_32 := Inode_Blocks (
+                     State.Block_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 ** (State.Block_Size_Bits - 9))
+                  then
+                     State.Inode.Mode := Fast_Link;
+                  end if;
+               end;
+            end if;
+            declare
+               I_Size : constant Unsigned_64 := Inode_Size (
+                  State.Block_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;
+               end if;
+            end;
             State.Inode.Use_Extents := State.Feature_Extents and (I_Flags and EXT4_EXTENTS_FL) /= 0;
             State.Inode.Inline := State.Block_Cache (Cache_Start + 40 .. Cache_Start + 100 - 1);
             Reset_Cache_Logical (State);
diff --git a/src/filo-fs-ext2.ads b/src/filo-fs-ext2.ads
index a789d4b..ac78bc1 100644
--- a/src/filo-fs-ext2.ads
+++ b/src/filo-fs-ext2.ads
@@ -69,7 +69,12 @@
    subtype Inode_Size is Positive range 128 .. Positive (Unsigned_16'Last);
    subtype Desc_Size  is Positive range  32 .. 2 ** 15; -- power-of-2 that fits in 16 bits
 
+   type Inode_Type is (Dir, Regular, Link, Fast_Link);
+   type Inode_Length is range 0 .. 2 ** 46;
+
    type Inode_Info is record
+      Mode        : Inode_Type := Inode_Type'First;
+      Size        : Inode_Length := 0;
       Use_Extents : Boolean := False;
       Inline      : Buffer_Type (Inode_Extents_Index) := (others => 16#00#);
    end record;