Index: /trunk/include/iprt/formats/ext.h
===================================================================
--- /trunk/include/iprt/formats/ext.h	(revision 76298)
+++ /trunk/include/iprt/formats/ext.h	(revision 76299)
@@ -551,9 +551,9 @@
  * @{ */
 /** Inode table and bitmaps are not initialized. */
-#define EXT_GROUP_DESC_F_INODE_UNINIT                RT_BIT_16(0)
+#define EXT_GROUP_DESC_F_INODE_UNINIT                RT_BIT(0)
 /** Block bitmap is not initialized. */
-#define EXT_GROUP_DESC_F_BLOCK_UNINIT                RT_BIT_16(1)
+#define EXT_GROUP_DESC_F_BLOCK_UNINIT                RT_BIT(1)
 /** Inode table is zeroed. */
-#define EXT_GROUP_DESC_F_INODE_ZEROED                RT_BIT_16(2)
+#define EXT_GROUP_DESC_F_INODE_ZEROED                RT_BIT(2)
 /** @} */
 
@@ -576,4 +576,7 @@
 typedef const EXTBLOCKGROUPDESC *PCEXTBLOCKGROUPDESC;
 
+
+/** Number of block entries in the inodes block map. */
+#define EXT_INODE_BLOCK_ENTRIES                      15
 
 /**
@@ -611,5 +614,5 @@
     } Osd1;
     /** 0x28: Block map or extent tree. */
-    uint32_t    au32Block[15];
+    uint32_t    au32Block[EXT_INODE_BLOCK_ENTRIES];
     /** 0x64: File version. */
     uint32_t    u32Version;
@@ -698,27 +701,27 @@
  * @{ */
 /** Others can execute the file. */
-#define EXT_INODE_MODE_EXEC_OTHER                    RT_BIT_16(0)
+#define EXT_INODE_MODE_EXEC_OTHER                    RT_BIT(0)
 /** Others can write to the file. */
-#define EXT_INODE_MODE_WRITE_OTHER                   RT_BIT_16(1)
+#define EXT_INODE_MODE_WRITE_OTHER                   RT_BIT(1)
 /** Others can read the file. */
-#define EXT_INODE_MODE_READ_OTHER                    RT_BIT_16(2)
+#define EXT_INODE_MODE_READ_OTHER                    RT_BIT(2)
 /** Members of the same group can execute the file. */
-#define EXT_INODE_MODE_EXEC_GROUP                    RT_BIT_16(3)
+#define EXT_INODE_MODE_EXEC_GROUP                    RT_BIT(3)
 /** Members of the same group can write to the file. */
-#define EXT_INODE_MODE_WRITE_GROUP                   RT_BIT_16(4)
+#define EXT_INODE_MODE_WRITE_GROUP                   RT_BIT(4)
 /** Members of the same group can read the file. */
-#define EXT_INODE_MODE_READ_GROUP                    RT_BIT_16(5)
+#define EXT_INODE_MODE_READ_GROUP                    RT_BIT(5)
 /** Owner can execute the file. */
-#define EXT_INODE_MODE_EXEC_OWNER                    RT_BIT_16(6)
+#define EXT_INODE_MODE_EXEC_OWNER                    RT_BIT(6)
 /** Owner can write to the file. */
-#define EXT_INODE_MODE_WRITE_OWNER                   RT_BIT_16(7)
+#define EXT_INODE_MODE_WRITE_OWNER                   RT_BIT(7)
 /** Owner can read the file. */
-#define EXT_INODE_MODE_READ_OWNER                    RT_BIT_16(8)
+#define EXT_INODE_MODE_READ_OWNER                    RT_BIT(8)
 /** Sticky file mode. */
-#define EXT_INODE_MODE_STICKY                        RT_BIT_16(9)
+#define EXT_INODE_MODE_STICKY                        RT_BIT(9)
 /** File is set GID. */
-#define EXT_INODE_MODE_SET_GROUP_ID                  RT_BIT_16(10)
+#define EXT_INODE_MODE_SET_GROUP_ID                  RT_BIT(10)
 /** File is set UID. */
-#define EXT_INODE_MODE_SET_USER_ID                   RT_BIT_16(11)
+#define EXT_INODE_MODE_SET_USER_ID                   RT_BIT(11)
 /** @} */
 
@@ -739,4 +742,6 @@
 /** Inode represents a socket. */
 #define EXT_INODE_MODE_TYPE_SOCKET                   UINT16_C(0xc000)
+/** Returns the inode type from the combined mode field. */
+#define EXT_INODE_MODE_TYPE_GET_TYPE(a_Mode)         ((a_Mode) & 0xf000)
 /** @} */
 
Index: /trunk/src/VBox/Runtime/common/fs/extvfs.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/fs/extvfs.cpp	(revision 76298)
+++ /trunk/src/VBox/Runtime/common/fs/extvfs.cpp	(revision 76299)
@@ -103,10 +103,12 @@
     /** Reference counter. */
     volatile uint32_t cRefs;
-    /** Block number where the inode is stored. */
-    uint64_t          iBlockInode;
-    /** Offset in bytes into block where the inode is stored. */
-    uint32_t          offInode;
-    /** Inode data size. */
-    uint64_t          cbData;
+    /** Byte offset in the backing file where the inode is stored.. */
+    uint64_t          offInode;
+    /** Inode data. */
+    RTFSOBJINFO       ObjInfo;
+    /** Inode flags (copied from the on disk inode). */
+    uint32_t          fFlags;
+    /** Copy of the block map/extent tree. */
+    uint32_t          aiBlocks[EXT_INODE_BLOCK_ENTRIES];
 } RTFSEXTINODE;
 /** Pointer to an in-memory inode. */
@@ -121,4 +123,6 @@
     /** Volume this directory belongs to. */
     PRTFSEXTVOL         pVol;
+    /** The underlying inode structure. */
+    PRTFSEXTINODE       pInode;
     /** Set if we've reached the end of the directory enumeration. */
     bool                fNoMoreFiles;
@@ -325,9 +329,9 @@
             Log2(("EXT:   iSnapshotListInode          %#RX32\n", RT_LE2H_U32(pSb->iSnapshotListInode)));
             Log2(("EXT:   cErrorsSeen                 %#RX32\n", RT_LE2H_U32(pSb->cErrorsSeen)));
-            Log2(("EXT:   [...]\n")); /** @todo: Missing fields if becoming interesting. */
+            Log2(("EXT:   [...]\n")); /** @todo Missing fields if becoming interesting. */
             Log2(("EXT:   iInodeLostFound             %#RX32\n", RT_LE2H_U32(pSb->iInodeLostFound)));
             Log2(("EXT:   iInodeProjQuota             %#RX32\n", RT_LE2H_U32(pSb->iInodeProjQuota)));
             Log2(("EXT:   u32ChksumSeed               %#RX32\n", RT_LE2H_U32(pSb->u32ChksumSeed)));
-            Log2(("EXT:   [...]\n")); /** @todo: Missing fields if becoming interesting. */
+            Log2(("EXT:   [...]\n")); /** @todo Missing fields if becoming interesting. */
             Log2(("EXT:   u32Chksum                   %#RX32\n", RT_LE2H_U32(pSb->u32Chksum)));
         }
@@ -797,5 +801,84 @@
                     rtFsExtInode_Log(pThis, iInode, &Inode);
 #endif
-                    /** @todo Fill in data. */
+                    pInode->offInode            = offRead;
+                    pInode->fFlags              = RT_LE2H_U32(Inode.Core.fFlags);
+                    pInode->ObjInfo.cbObject    =   (uint64_t)RT_LE2H_U32(Inode.Core.cbSizeHigh) << 32
+                                                  | (uint64_t)RT_LE2H_U32(Inode.Core.cbSizeLow);
+                    pInode->ObjInfo.cbAllocated = (  (uint64_t)RT_LE2H_U16(Inode.Core.Osd2.Lnx.cBlocksHigh) << 32
+                                                   | (uint64_t)RT_LE2H_U32(Inode.Core.cBlocksLow)) * pThis->cbBlock;
+                    RTTimeSpecSetSeconds(&pInode->ObjInfo.AccessTime, RT_LE2H_U32(Inode.Core.u32TimeLastAccess));
+                    RTTimeSpecSetSeconds(&pInode->ObjInfo.ModificationTime, RT_LE2H_U32(Inode.Core.u32TimeLastModification));
+                    RTTimeSpecSetSeconds(&pInode->ObjInfo.ChangeTime, RT_LE2H_U32(Inode.Core.u32TimeLastChange));
+                    pInode->ObjInfo.Attr.enmAdditional = RTFSOBJATTRADD_UNIX;
+                    pInode->ObjInfo.Attr.u.Unix.uid    =   (uint32_t)RT_LE2H_U16(Inode.Core.Osd2.Lnx.uUidHigh) << 16
+                                                         | (uint32_t)RT_LE2H_U16(Inode.Core.uUidLow);
+                    pInode->ObjInfo.Attr.u.Unix.gid    =   (uint32_t)RT_LE2H_U16(Inode.Core.Osd2.Lnx.uGidHigh) << 16
+                                                         | (uint32_t)RT_LE2H_U16(Inode.Core.uGidLow);
+                    pInode->ObjInfo.Attr.u.Unix.cHardlinks = RT_LE2H_U16(Inode.Core.cHardLinks);
+                    pInode->ObjInfo.Attr.u.Unix.INodeIdDevice = 0;
+                    pInode->ObjInfo.Attr.u.Unix.INodeId       = iInode;
+                    pInode->ObjInfo.Attr.u.Unix.fFlags        = 0;
+                    pInode->ObjInfo.Attr.u.Unix.GenerationId  = RT_LE2H_U32(Inode.Core.u32Version);
+                    pInode->ObjInfo.Attr.u.Unix.Device        = 0;
+                    if (pThis->cbInode >= sizeof(EXTINODECOMB))
+                        RTTimeSpecSetSeconds(&pInode->ObjInfo.BirthTime, RT_LE2H_U32(Inode.Extra.u32TimeCreation));
+                    else
+                        RTTimeSpecSetSeconds(&pInode->ObjInfo.BirthTime, RT_LE2H_U32(Inode.Core.u32TimeLastChange));
+                    for (unsigned i = 0; i < RT_ELEMENTS(pInode->aiBlocks); i++)
+                        pInode->aiBlocks[i] = RT_LE2H_U32(Inode.Core.au32Block[i]);
+
+                    /* Fill in the mode. */
+                    pInode->ObjInfo.Attr.fMode = 0;
+                    uint32_t fInodeMode = RT_LE2H_U32(Inode.Core.fMode);
+                    switch (EXT_INODE_MODE_TYPE_GET_TYPE(fInodeMode))
+                    {
+                        case EXT_INODE_MODE_TYPE_FIFO: 
+                            pInode->ObjInfo.Attr.fMode |= RTFS_TYPE_FIFO;
+                            break;
+                        case EXT_INODE_MODE_TYPE_CHAR:
+                            pInode->ObjInfo.Attr.fMode |= RTFS_TYPE_DEV_CHAR;
+                            break;
+                        case EXT_INODE_MODE_TYPE_DIR:
+                            pInode->ObjInfo.Attr.fMode |= RTFS_TYPE_DIRECTORY;
+                            break;
+                        case EXT_INODE_MODE_TYPE_BLOCK:
+                            pInode->ObjInfo.Attr.fMode |= RTFS_TYPE_DEV_BLOCK;
+                            break;
+                        case EXT_INODE_MODE_TYPE_REGULAR:
+                            pInode->ObjInfo.Attr.fMode |= RTFS_TYPE_FILE;
+                            break;
+                        case EXT_INODE_MODE_TYPE_SYMLINK:
+                            pInode->ObjInfo.Attr.fMode |= RTFS_TYPE_SYMLINK;
+                            break;
+                        case EXT_INODE_MODE_TYPE_SOCKET:
+                            pInode->ObjInfo.Attr.fMode |= RTFS_TYPE_SOCKET;
+                            break;
+                        default:
+                            rc = VERR_VFS_BOGUS_FORMAT;
+                    }
+                    if (fInodeMode & EXT_INODE_MODE_EXEC_OTHER)
+                        pInode->ObjInfo.Attr.fMode |= RTFS_UNIX_IXOTH;
+                    if (fInodeMode & EXT_INODE_MODE_WRITE_OTHER)
+                        pInode->ObjInfo.Attr.fMode |= RTFS_UNIX_IWOTH;
+                    if (fInodeMode & EXT_INODE_MODE_READ_OTHER)
+                        pInode->ObjInfo.Attr.fMode |= RTFS_UNIX_IROTH;
+                    if (fInodeMode & EXT_INODE_MODE_EXEC_GROUP)
+                        pInode->ObjInfo.Attr.fMode |= RTFS_UNIX_IXGRP;
+                    if (fInodeMode & EXT_INODE_MODE_WRITE_GROUP)
+                        pInode->ObjInfo.Attr.fMode |= RTFS_UNIX_IWGRP;
+                    if (fInodeMode & EXT_INODE_MODE_READ_GROUP)
+                        pInode->ObjInfo.Attr.fMode |= RTFS_UNIX_IRGRP;
+                    if (fInodeMode & EXT_INODE_MODE_EXEC_OWNER)
+                        pInode->ObjInfo.Attr.fMode |= RTFS_UNIX_IXUSR;
+                    if (fInodeMode & EXT_INODE_MODE_WRITE_OWNER)
+                        pInode->ObjInfo.Attr.fMode |= RTFS_UNIX_IWUSR;
+                    if (fInodeMode & EXT_INODE_MODE_READ_OWNER)
+                        pInode->ObjInfo.Attr.fMode |= RTFS_UNIX_IRUSR;
+                    if (fInodeMode & EXT_INODE_MODE_STICKY)
+                        pInode->ObjInfo.Attr.fMode |= RTFS_UNIX_ISTXT;
+                    if (fInodeMode & EXT_INODE_MODE_SET_GROUP_ID)
+                        pInode->ObjInfo.Attr.fMode |= RTFS_UNIX_ISGID;
+                    if (fInodeMode & EXT_INODE_MODE_SET_USER_ID)
+                        pInode->ObjInfo.Attr.fMode |= RTFS_UNIX_ISUID;
                 }
             }
@@ -839,4 +922,46 @@
 
 
+/**
+ * Worker for various QueryInfo methods.
+ *
+ * @returns IPRT status code.
+ * @param   pInode              The inode structure to return info for.
+ * @param   pObjInfo            Where to return object info.
+ * @param   enmAddAttr          What additional info to return.
+ */
+static int rtFsExtInode_QueryInfo(PRTFSEXTINODE pInode, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
+{
+    RT_ZERO(*pObjInfo);
+
+    pObjInfo->cbObject           = pInode->ObjInfo.cbObject;
+    pObjInfo->cbAllocated        = pInode->ObjInfo.cbAllocated;
+    pObjInfo->AccessTime         = pInode->ObjInfo.AccessTime;
+    pObjInfo->ModificationTime   = pInode->ObjInfo.ModificationTime;
+    pObjInfo->ChangeTime         = pInode->ObjInfo.ChangeTime;
+    pObjInfo->BirthTime          = pInode->ObjInfo.BirthTime;
+    pObjInfo->Attr.fMode         = pInode->ObjInfo.Attr.fMode;
+    pObjInfo->Attr.enmAdditional = enmAddAttr;
+    switch (enmAddAttr)
+    {
+        case RTFSOBJATTRADD_UNIX:
+            memcpy(&pObjInfo->Attr.u.Unix, &pInode->ObjInfo.Attr.u.Unix, sizeof(pInode->ObjInfo.Attr.u.Unix));
+            break;
+
+        case RTFSOBJATTRADD_UNIX_OWNER:
+            pObjInfo->Attr.u.UnixOwner.uid = pInode->ObjInfo.Attr.u.Unix.uid;
+            break;
+
+        case RTFSOBJATTRADD_UNIX_GROUP:
+            pObjInfo->Attr.u.UnixGroup.gid = pInode->ObjInfo.Attr.u.Unix.gid;
+            break;
+
+        default:
+            break;
+    }
+
+    return VINF_SUCCESS;
+}
+
+
 /*
  *
@@ -854,5 +979,6 @@
     PRTFSEXTDIR pThis = (PRTFSEXTDIR)pvThis;
     LogFlowFunc(("pThis=%p\n", pThis));
-    RT_NOREF(pThis);
+    rtFsExtInodeRelease(pThis->pVol, pThis->pInode);
+    pThis->pInode = NULL;
     return VINF_SUCCESS;
 }
@@ -866,6 +992,5 @@
     PRTFSEXTDIR pThis = (PRTFSEXTDIR)pvThis;
     LogFlowFunc(("\n"));
-    RT_NOREF(pThis, pObjInfo, enmAddAttr);
-    return VERR_NOT_IMPLEMENTED;
+    return rtFsExtInode_QueryInfo(pThis->pInode, pObjInfo, enmAddAttr);
 }
 
@@ -1074,5 +1199,24 @@
     int rc = rtFsExtInodeLoad(pThis, iInode, &pInode);
     if (RT_SUCCESS(rc))
-        rtFsExtInodeRelease(pThis, pInode);
+    {
+        if (RTFS_IS_DIRECTORY(pInode->ObjInfo.Attr.fMode))
+        {
+            PRTFSEXTDIR pNewDir;
+            rc = RTVfsNewDir(&g_rtFsExtDirOps, sizeof(*pNewDir), 0 /*fFlags*/, pThis->hVfsSelf, NIL_RTVFSLOCK,
+                             phVfsDir, (void **)&pNewDir);
+            if (RT_SUCCESS(rc))
+            {
+                pNewDir->fNoMoreFiles = false;
+                pNewDir->pVol         = pThis;
+                pNewDir->pInode       = pInode;
+            }
+        }
+        else
+            rc = VERR_VFS_BOGUS_FORMAT;
+
+        if (RT_FAILURE(rc))
+            rtFsExtInodeRelease(pThis, pInode);
+    }
+
     RT_NOREF(phVfsDir, g_rtFsExtDirOps);
     return rc;
@@ -1100,5 +1244,5 @@
 static bool rtFsExtIsBlockRangeInUse(PRTFSEXTBLKGRP pBlkGrpDesc, uint64_t iBlockStart, size_t cBlocks)
 {
-    /** @todo: Optimize with ASMBitFirstSet(). */
+    /** @todo Optimize with ASMBitFirstSet(). */
     while (cBlocks)
     {
