VirtualBox

Changeset 69938 in vbox for trunk/src/VBox/Runtime/common/fs


Ignore:
Timestamp:
Dec 5, 2017 4:58:50 PM (7 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
119432
Message:

iprt/ntfsvfs.cpp: Implemented ReadDir, fixed Open('..') bug.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/common/fs/ntfsvfs.cpp

    r69925 r69938  
    2929*   Header Files                                                                                                                 *
    3030*********************************************************************************************************************************/
     31#define RTMEM_WRAP_TO_EF_APIS // REMOVE REMOVE REMOVE
    3132#define LOG_GROUP RTLOGGROUP_FS
    3233#include <iprt/fsvfs.h>
     
    312313    /** The next entry to process in this stack entry. */
    313314    uint32_t                iNext;
     315    /** Set if we need to descend first. */
     316    bool                    fDescend;
    314317    /** Pointer to the node info for this entry. */
    315318    PRTFSNTFSIDXNODEINFO    pNodeInfo;
     
    11351138        if (pAttrHdr->fNonResident)
    11361139        {
     1140            int64_t const cbAllocated = RT_LE2H_U64(pAttrHdr->u.NonRes.cbAllocated);
     1141            if (cbAllocated < 0)
     1142                return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     1143                                               "Bad MFT record %#RX64: Attribute (@%#x): cbAllocated (%#RX64) is negative",
     1144                                               pRec->TreeNode.Key, offRec, cbAllocated);
     1145            if ((uint64_t)cbAllocated & (pThis->cbCluster - 1))
     1146                return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     1147                                               "Bad MFT record %#RX64: Attribute (@%#x): cbAllocated (%#RX64) isn't cluster aligned (cbCluster=%#x)",
     1148                                               pRec->TreeNode.Key, offRec, cbAllocated, pThis->cbCluster);
     1149
     1150            int64_t const cbData = RT_LE2H_U64(pAttrHdr->u.NonRes.cbData);
     1151            if (cbData < 0)
     1152                return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     1153                                               "Bad MFT record %#RX64: Attribute (@%#x): cbData (%#RX64) is negative",
     1154                                               pRec->TreeNode.Key, offRec, cbData);
     1155
     1156            int64_t const cbInitialized = RT_LE2H_U64(pAttrHdr->u.NonRes.cbInitialized);
     1157            if (cbInitialized < 0)
     1158                return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     1159                                               "Bad MFT record %#RX64: Attribute (@%#x): cbInitialized (%#RX64) is negative",
     1160                                               pRec->TreeNode.Key, offRec, cbInitialized);
     1161
    11371162            int64_t const iVcnFirst = RT_LE2H_U64(pAttrHdr->u.NonRes.iVcnFirst);
    11381163            int64_t const iVcnLast  = RT_LE2H_U64(pAttrHdr->u.NonRes.iVcnLast);
    1139             if (iVcnFirst > iVcnLast)
     1164            if (   iVcnFirst > iVcnLast
     1165                && (   iVcnLast != -1
     1166                    || cbAllocated != 0))
    11401167                return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
    11411168                                               "Bad MFT record %#RX64: Attribute (@%#x): iVcnFirst (%#RX64) is higher than iVcnLast (%#RX64)",
     
    11601187                                               pRec->TreeNode.Key, offRec, pAttrHdr->u.NonRes.uCompressionUnit);
    11611188
    1162             int64_t const cbAllocated = RT_LE2H_U64(pAttrHdr->u.NonRes.cbAllocated);
    1163             if (cbAllocated < 0)
    1164                 return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
    1165                                                "Bad MFT record %#RX64: Attribute (@%#x): cbAllocated (%#RX64) is negative",
    1166                                                pRec->TreeNode.Key, offRec, cbAllocated);
    1167             if ((uint64_t)cbAllocated & (pThis->cbCluster - 1))
    1168                 return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
    1169                                                "Bad MFT record %#RX64: Attribute (@%#x): cbAllocated (%#RX64) isn't cluster aligned (cbCluster=%#x)",
    1170                                                pRec->TreeNode.Key, offRec, cbAllocated, pThis->cbCluster);
    1171 
    1172             int64_t const cbData = RT_LE2H_U64(pAttrHdr->u.NonRes.cbData);
    1173             if (cbData < 0)
    1174                 return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
    1175                                                "Bad MFT record %#RX64: Attribute (@%#x): cbData (%#RX64) is negative",
    1176                                                pRec->TreeNode.Key, offRec, cbData);
    1177 
    1178             int64_t const cbInitialized = RT_LE2H_U64(pAttrHdr->u.NonRes.cbInitialized);
    1179             if (cbInitialized < 0)
    1180                 return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
    1181                                                "Bad MFT record %#RX64: Attribute (@%#x): cbInitialized (%#RX64) is negative",
    1182                                                pRec->TreeNode.Key, offRec, cbInitialized);
    11831189            if (cbMin >= NTFSATTRIBHDR_SIZE_NONRES_COMPRESSED)
    11841190            {
     
    11991205                                               pRec->TreeNode.Key, offRec, offValue, cbAttrib, RT_LE2H_U32(pAttrHdr->u.Res.cbValue));
    12001206            if ((pAttrHdr->fFlags & NTFS_AF_COMPR_FMT_MASK) != NTFS_AF_COMPR_FMT_NONE)
     1207            {
     1208#if 1 /* Seen on INDEX_ROOT of ReportQueue on w7, so turned into debug log warning. */
     1209                Log(("NTFS: Warning! Bad MFT record %#RX64: Attribute (@%#x): fFlags (%#RX16) indicate compression of a resident attribute\n",
     1210                     pRec->TreeNode.Key, offRec, RT_LE2H_U16(pAttrHdr->fFlags) ));
     1211#else
    12011212                return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
    12021213                                               "Bad MFT record %#RX64: Attribute (@%#x): fFlags (%#RX16) indicate compression of a resident attribute",
    12031214                                               pRec->TreeNode.Key, offRec, RT_LE2H_U16(pAttrHdr->fFlags));
     1215#endif
     1216            }
    12041217        }
    12051218
     
    18181831
    18191832/**
    1820  * Worker for various QueryInfo methods.
    1821  *
    1822  * @returns IPRT status code.
    1823  * @param   pThis               The core object structure to return info for.
    1824  * @param   pAttr               The attribute that's being presented.  Take the
    1825  *                              allocation and timestamp info from it, if
    1826  *                              non-resident.
    1827  * @param   pObjInfo            Where to return object info.
    1828  * @param   enmAddAttr          What additional info to return.
    1829  */
    1830 static int rtFsNtfsCore_QueryInfo(PRTFSNTFSCORE pThis, PRTFSNTFSATTR pAttr, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
    1831 {
    1832     /*
    1833      * Wipe the structure and fill in common dummy value.
    1834      */
    1835     RT_ZERO(*pObjInfo);
    1836     switch (enmAddAttr)
    1837     {
    1838         case RTFSOBJATTRADD_UNIX:
    1839             pObjInfo->Attr.u.Unix.uid           = NIL_RTUID;
    1840             pObjInfo->Attr.u.Unix.gid           = NIL_RTGID;
    1841             pObjInfo->Attr.u.Unix.cHardlinks    = 1;
    1842             //pObjInfo->Attr.u.Unix.INodeIdDevice = 0;
    1843             pObjInfo->Attr.u.Unix.INodeId       = pThis->pMftRec->TreeNode.Key;
    1844             //pObjInfo->Attr.u.Unix.fFlags        = 0;
    1845             //pObjInfo->Attr.u.Unix.GenerationId  = 0;
    1846             //pObjInfo->Attr.u.Unix.Device        = 0;
    1847             break;
    1848 
    1849         case RTFSOBJATTRADD_UNIX_OWNER:
    1850             pObjInfo->Attr.u.UnixOwner.uid = NIL_RTUID;
    1851             break;
    1852 
    1853         case RTFSOBJATTRADD_UNIX_GROUP:
    1854             pObjInfo->Attr.u.UnixGroup.gid = NIL_RTGID;
    1855             break;
    1856 
    1857         default:
    1858             break;
    1859     }
    1860 
    1861     /*
    1862      * Look for the standard information attribute and use that as basis.
    1863      */
    1864     uint32_t      fFileAttrs;
    1865     PRTFSNTFSATTR pStdInfoAttr = rtFsNtfsCore_FindUnnamedAttribute(pThis, NTFS_AT_STANDARD_INFORMATION);
    1866     if (   pStdInfoAttr
    1867         && pStdInfoAttr->cbResident >= sizeof(NTFSATSTDINFO) )
    1868     {
    1869         Assert(!pStdInfoAttr->pAttrHdr->fNonResident);
    1870         PCNTFSATSTDINFO pStdInfo = (PCNTFSATSTDINFO)NTFSATTRIBHDR_GET_RES_VALUE_PTR(pStdInfoAttr->pAttrHdr);
    1871         RTTimeSpecSetNtTime(&pObjInfo->BirthTime,        RT_LE2H_U64(pStdInfo->iCreationTime));
    1872         RTTimeSpecSetNtTime(&pObjInfo->ModificationTime, RT_LE2H_U64(pStdInfo->iLastDataModTime));
    1873         RTTimeSpecSetNtTime(&pObjInfo->ChangeTime,       RT_LE2H_U64(pStdInfo->iLastMftModTime));
    1874         RTTimeSpecSetNtTime(&pObjInfo->AccessTime,       RT_LE2H_U64(pStdInfo->iLastAccessTime));
    1875         if (enmAddAttr == RTFSOBJATTRADD_UNIX)
    1876         {
    1877             pObjInfo->Attr.u.Unix.uid          = pStdInfo->idOwner;
    1878             pObjInfo->Attr.u.Unix.GenerationId = pStdInfo->uFileVersion;
    1879         }
    1880         else if (enmAddAttr == RTFSOBJATTRADD_UNIX_OWNER)
    1881             pObjInfo->Attr.u.UnixOwner.uid = pStdInfo->idOwner;
    1882         fFileAttrs = pStdInfo->fFileAttribs;
    1883     }
     1833 * This attribute conversion code is a slightly modified version of rtFsModeFromDos.
     1834 *
     1835 * @returns IPRT fmode mask.
     1836 * @param   fFileAttribs        The NT file attributes.
     1837 * @param   pFilename           The filename attribute structure, optional.
     1838 * @param   cbFilename          The size of the filename attribute structure.
     1839 */
     1840static RTFMODE rtFsNtfsConvertFileattribsToMode(uint32_t fFileAttribs, PCNTFSATFILENAME pFilename, uint32_t cbFilename)
     1841{
     1842    RTFMODE fMode = (fFileAttribs << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_NT;
     1843    if (fFileAttribs & NTFS_FA_DUP_FILE_NAME_INDEX_PRESENT)
     1844        fMode |= RTFS_DOS_DIRECTORY;
     1845
     1846    /* everything is readable. */
     1847    fMode |= RTFS_UNIX_IRUSR | RTFS_UNIX_IRGRP | RTFS_UNIX_IROTH;
     1848    if (fMode & RTFS_DOS_DIRECTORY)
     1849        /* directories are executable. */
     1850        fMode |= RTFS_TYPE_DIRECTORY | RTFS_UNIX_IXUSR | RTFS_UNIX_IXGRP | RTFS_UNIX_IXOTH;
    18841851    else
    18851852    {
    1886         /** @todo check out the filename record?   */
    1887         switch (pAttr->pAttrHdr->uAttrType)
    1888         {
    1889             default:
    1890                 AssertFailed();
    1891             case NTFS_AT_DATA:
    1892                 fFileAttrs = NTFS_FA_NORMAL;
    1893                 break;
    1894 
    1895             case NTFS_AT_INDEX_ROOT:
    1896             case NTFS_AT_INDEX_ALLOCATION:
    1897                 fFileAttrs = NTFS_FA_DIRECTORY;
    1898                 break;
    1899         }
    1900     }
    1901 
    1902     /*
    1903      * Take the allocation info from the destilled attribute data.
    1904      */
    1905     pObjInfo->cbObject    = pAttr->cbValue;
    1906     pObjInfo->cbAllocated = pAttr->Extents.cbData;
    1907     if (   pAttr->pAttrHdr->fNonResident
    1908         && (int64_t)pObjInfo->cbAllocated < (int64_t)RT_LE2H_U64(pAttr->pAttrHdr->u.NonRes.cbAllocated))
    1909         pObjInfo->cbAllocated = RT_LE2H_U64(pAttr->pAttrHdr->u.NonRes.cbAllocated);
    1910 
    1911 
    1912     /*
    1913      * See if we can find a filename record before we try convert the file attributes to mode.
    1914      */
    1915     PCNTFSATFILENAME pFilename     = NULL;
    1916     PRTFSNTFSATTR    pFilenameAttr = rtFsNtfsCore_FindUnnamedAttribute(pThis, NTFS_AT_FILENAME);
    1917     if (   pFilenameAttr
    1918         && pFilenameAttr->cbResident >= RT_UOFFSETOF(NTFSATFILENAME, wszFilename) )
    1919     {
    1920         Assert(!pFilenameAttr->pAttrHdr->fNonResident);
    1921         pFilename = (PCNTFSATFILENAME)NTFSATTRIBHDR_GET_RES_VALUE_PTR(pFilenameAttr->pAttrHdr);
    1922         if (pStdInfoAttr)
    1923             fFileAttrs |= pFilename->fFileAttribs;
    1924         else
    1925             fFileAttrs = pFilename->fFileAttribs;
    1926     }
    1927 
    1928     /*
    1929      * This attribute conversion code is a slightly modified version of rtFsModeFromDos.
    1930      */
    1931     pObjInfo->Attr.fMode = (fFileAttrs << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_NT;
    1932     if (fFileAttrs & NTFS_FA_DUP_FILE_NAME_INDEX_PRESENT)
    1933         pObjInfo->Attr.fMode |= RTFS_DOS_DIRECTORY;
    1934 
    1935     /* everything is readable. */
    1936     pObjInfo->Attr.fMode |= RTFS_UNIX_IRUSR | RTFS_UNIX_IRGRP | RTFS_UNIX_IROTH;
    1937     if (pObjInfo->Attr.fMode & RTFS_DOS_DIRECTORY)
    1938         /* directories are executable. */
    1939         pObjInfo->Attr.fMode |= RTFS_TYPE_DIRECTORY | RTFS_UNIX_IXUSR | RTFS_UNIX_IXGRP | RTFS_UNIX_IXOTH;
    1940     else
    1941     {
    1942         pObjInfo->Attr.fMode |= RTFS_TYPE_FILE;
     1853        fMode |= RTFS_TYPE_FILE;
    19431854        if (   pFilename
    19441855            && pFilename->cwcFilename >= 4
    1945             && RT_UOFFSETOF(NTFSATFILENAME, wszFilename[pFilename->cwcFilename]) <= pFilenameAttr->cbResident)
     1856            && RT_UOFFSETOF(NTFSATFILENAME, wszFilename[pFilename->cwcFilename]) <= cbFilename)
    19461857        {
    19471858            PCRTUTF16 pwcExt = &pFilename->wszFilename[pFilename->cwcFilename - 4];
     
    19641875                        ||  !memcmp(szExt, "btm", 4)
    19651876                       )
    1966                         pObjInfo->Attr.fMode |= RTFS_UNIX_IXUSR | RTFS_UNIX_IXGRP | RTFS_UNIX_IXOTH;
     1877                        fMode |= RTFS_UNIX_IXUSR | RTFS_UNIX_IXGRP | RTFS_UNIX_IXOTH;
    19671878                }
    19681879            }
     
    19711882
    19721883    /* Is it really a symbolic link? */
    1973     if (   (pObjInfo->Attr.fMode & RTFS_DOS_NT_REPARSE_POINT)
     1884    if (   (fMode & RTFS_DOS_NT_REPARSE_POINT)
    19741885        && pFilename
    19751886        && pFilename->u.uReparseTag == RTFSMODE_SYMLINK_REPARSE_TAG)
    1976         pObjInfo->Attr.fMode = (pObjInfo->Attr.fMode & ~RTFS_TYPE_MASK) | RTFS_TYPE_SYMLINK;
     1887        fMode = (fMode & ~RTFS_TYPE_MASK) | RTFS_TYPE_SYMLINK;
    19771888
    19781889    /* writable? */
    1979     if (!(pObjInfo->Attr.fMode & RTFS_DOS_READONLY))
    1980         pObjInfo->Attr.fMode |= RTFS_UNIX_IWUSR | RTFS_UNIX_IWGRP | RTFS_UNIX_IWOTH;
     1890    if (!(fMode & RTFS_DOS_READONLY))
     1891        fMode |= RTFS_UNIX_IWUSR | RTFS_UNIX_IWGRP | RTFS_UNIX_IWOTH;
     1892
     1893    return fMode;
     1894}
     1895
     1896
     1897/**
     1898 * Worker for various QueryInfo methods.
     1899 *
     1900 * @returns IPRT status code.
     1901 * @param   pThis               The core object structure to return info for.
     1902 * @param   pAttr               The attribute that's being presented.  Take the
     1903 *                              allocation and timestamp info from it, if
     1904 *                              non-resident.
     1905 * @param   pObjInfo            Where to return object info.
     1906 * @param   enmAddAttr          What additional info to return.
     1907 */
     1908static int rtFsNtfsCore_QueryInfo(PRTFSNTFSCORE pThis, PRTFSNTFSATTR pAttr, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
     1909{
     1910    /*
     1911     * Wipe the structure and fill in common dummy value.
     1912     */
     1913    RT_ZERO(*pObjInfo);
     1914    switch (enmAddAttr)
     1915    {
     1916        case RTFSOBJATTRADD_UNIX:
     1917            pObjInfo->Attr.u.Unix.uid           = NIL_RTUID;
     1918            pObjInfo->Attr.u.Unix.gid           = NIL_RTGID;
     1919            pObjInfo->Attr.u.Unix.cHardlinks    = 1;
     1920            //pObjInfo->Attr.u.Unix.INodeIdDevice = 0;
     1921            pObjInfo->Attr.u.Unix.INodeId       = pThis->pMftRec->TreeNode.Key;
     1922            //pObjInfo->Attr.u.Unix.fFlags        = 0;
     1923            //pObjInfo->Attr.u.Unix.GenerationId  = 0;
     1924            //pObjInfo->Attr.u.Unix.Device        = 0;
     1925            break;
     1926
     1927        case RTFSOBJATTRADD_UNIX_OWNER:
     1928            pObjInfo->Attr.u.UnixOwner.uid = NIL_RTUID;
     1929            break;
     1930
     1931        case RTFSOBJATTRADD_UNIX_GROUP:
     1932            pObjInfo->Attr.u.UnixGroup.gid = NIL_RTGID;
     1933            break;
     1934
     1935        default:
     1936            break;
     1937    }
     1938
     1939    /*
     1940     * Look for the standard information attribute and use that as basis.
     1941     */
     1942    uint32_t      fFileAttribs;
     1943    PRTFSNTFSATTR pStdInfoAttr = rtFsNtfsCore_FindUnnamedAttribute(pThis, NTFS_AT_STANDARD_INFORMATION);
     1944    if (   pStdInfoAttr
     1945        && pStdInfoAttr->cbResident >= sizeof(NTFSATSTDINFO) )
     1946    {
     1947        Assert(!pStdInfoAttr->pAttrHdr->fNonResident);
     1948        PCNTFSATSTDINFO pStdInfo = (PCNTFSATSTDINFO)NTFSATTRIBHDR_GET_RES_VALUE_PTR(pStdInfoAttr->pAttrHdr);
     1949        RTTimeSpecSetNtTime(&pObjInfo->BirthTime,        RT_LE2H_U64(pStdInfo->iCreationTime));
     1950        RTTimeSpecSetNtTime(&pObjInfo->ModificationTime, RT_LE2H_U64(pStdInfo->iLastDataModTime));
     1951        RTTimeSpecSetNtTime(&pObjInfo->ChangeTime,       RT_LE2H_U64(pStdInfo->iLastMftModTime));
     1952        RTTimeSpecSetNtTime(&pObjInfo->AccessTime,       RT_LE2H_U64(pStdInfo->iLastAccessTime));
     1953        if (enmAddAttr == RTFSOBJATTRADD_UNIX)
     1954        {
     1955            pObjInfo->Attr.u.Unix.uid          = pStdInfo->idOwner;
     1956            pObjInfo->Attr.u.Unix.GenerationId = pStdInfo->uFileVersion;
     1957        }
     1958        else if (enmAddAttr == RTFSOBJATTRADD_UNIX_OWNER)
     1959            pObjInfo->Attr.u.UnixOwner.uid = pStdInfo->idOwner;
     1960        fFileAttribs = pStdInfo->fFileAttribs;
     1961    }
     1962    else
     1963    {
     1964        /** @todo check out the filename record?   */
     1965        switch (pAttr->pAttrHdr->uAttrType)
     1966        {
     1967            default:
     1968                AssertFailed();
     1969            case NTFS_AT_DATA:
     1970                fFileAttribs = NTFS_FA_NORMAL;
     1971                break;
     1972
     1973            case NTFS_AT_INDEX_ROOT:
     1974            case NTFS_AT_INDEX_ALLOCATION:
     1975                fFileAttribs = NTFS_FA_DIRECTORY;
     1976                break;
     1977        }
     1978    }
     1979
     1980    /*
     1981     * Take the allocation info from the destilled attribute data.
     1982     */
     1983    pObjInfo->cbObject    = pAttr->cbValue;
     1984    pObjInfo->cbAllocated = pAttr->Extents.cbData;
     1985    if (   pAttr->pAttrHdr->fNonResident
     1986        && (int64_t)pObjInfo->cbAllocated < (int64_t)RT_LE2H_U64(pAttr->pAttrHdr->u.NonRes.cbAllocated))
     1987        pObjInfo->cbAllocated = RT_LE2H_U64(pAttr->pAttrHdr->u.NonRes.cbAllocated);
     1988
     1989
     1990    /*
     1991     * See if we can find a filename record before we try convert the file attributes to mode.
     1992     */
     1993    PCNTFSATFILENAME pFilename     = NULL;
     1994    PRTFSNTFSATTR    pFilenameAttr = rtFsNtfsCore_FindUnnamedAttribute(pThis, NTFS_AT_FILENAME);
     1995    if (   pFilenameAttr
     1996        && pFilenameAttr->cbResident >= RT_UOFFSETOF(NTFSATFILENAME, wszFilename) )
     1997    {
     1998        Assert(!pFilenameAttr->pAttrHdr->fNonResident);
     1999        pFilename = (PCNTFSATFILENAME)NTFSATTRIBHDR_GET_RES_VALUE_PTR(pFilenameAttr->pAttrHdr);
     2000        if (pStdInfoAttr)
     2001            fFileAttribs |= pFilename->fFileAttribs;
     2002        else
     2003            fFileAttribs = pFilename->fFileAttribs;
     2004    }
     2005
     2006    /*
     2007     * Convert attribs to file mode flags.
     2008     */
     2009    pObjInfo->Attr.fMode = rtFsNtfsConvertFileattribsToMode(fFileAttribs, pFilename,
     2010                                                            pFilenameAttr ? pFilenameAttr->cbResident : 0);
    19812011
    19822012    return VINF_SUCCESS;
     
    22062236    uint32_t const offFirstEntry = RT_LE2H_U32(pIndexHdr->offFirstEntry);
    22072237    if (   offFirstEntry < sizeof(*pIndexHdr)
    2208         || offFirstEntry >= cbUsed - sizeof(NTFSIDXENTRYHDR)
     2238        || (   offFirstEntry > cbUsed - sizeof(NTFSIDXENTRYHDR)
     2239            && offFirstEntry != cbUsed /* empty dir */)
    22092240        || (offFirstEntry & 7) )
    22102241        return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     
    25322563            rc = VERR_VFS_BOGUS_FORMAT;
    25332564            if (pNode->pNode->RecHdr.uMagic != NTFSREC_MAGIC_INDEX_ALLOC)
    2534                 LogRel(("rtFsNtfsIdxRootInfo_QueryNode(iNode=%#x): Invalid node magic %#x\n",
     2565                LogRel(("rtFsNtfsIdxRootInfo_QueryNode(iNode=%#x): Invalid node magic %#x -> VERR_VFS_BOGUS_FORMAT\n",
    25352566                        iNode, RT_LE2H_U32(pNode->pNode->RecHdr.uMagic) ));
    25362567            else if ((int64_t)RT_LE2H_U64(pNode->pNode->iSelfAddress) != iNode)
    2537                 LogRel(("rtFsNtfsIdxRootInfo_QueryNode(iNode=%#x): Wrong iSelfAddress: %#x\n",
     2568                LogRel(("rtFsNtfsIdxRootInfo_QueryNode(iNode=%#x): Wrong iSelfAddress: %#x -> VERR_VFS_BOGUS_FORMAT\n",
    25382569                        iNode, RT_LE2H_U64(pNode->pNode->iSelfAddress) ));
    25392570            else
     
    26782709
    26792710    if (!cwcUpper1)
    2680         return cwcFilename2 ? -1 : 0;
    2681     return cwcFilename2 ? 1 : 0;
     2711    {
     2712        if (!cwcFilename2)
     2713            return 0;
     2714        return -1;
     2715    }
     2716    return 1;
    26822717}
    26832718
     
    27832818                        *ppEntryHdr = papEntries[iEntry];
    27842819                        *ppFilename = pFilename;
    2785                         LogFlow(("rtFsNtfsDirShrd_Lookup(%s): Found it!\n", pszEntry));
     2820                        LogFlow(("rtFsNtfsDirShrd_Lookup(%s): Found it! (iEntry=%u, FileMftRec=%#RX64 sqn %#x)\n",
     2821                                 pszEntry, iEntry, NTFSMFTREF_GET_IDX(&papEntries[iEntry]->u.FileMftRec),
     2822                                 NTFSMFTREF_GET_SEQ(&papEntries[iEntry]->u.FileMftRec) ));
    27862823                        return VINF_SUCCESS;
    27872824                    }
     
    28292866
    28302867/**
     2868 * Gets the shared directory structure for the parent.
     2869 *
     2870 * @returns IPRT status code.
     2871 * @param   pThis       The directory which parent we want.
     2872 * @param   ppDotDot    Where to return the referenced shared parent dir
     2873 *                      structure.
     2874 *
     2875 */
     2876static int rtFsNtfsDirShrd_QueryParent(PRTFSNTFSDIRSHRD pThis, PRTFSNTFSDIRSHRD *ppDotDot)
     2877{
     2878    /*
     2879     * The root directory has no parent from our perspective.
     2880     */
     2881    if (pThis == pThis->RootInfo.NodeInfo.pVol->pRootDir)
     2882    {
     2883        rtFsNtfsDirShrd_Retain(pThis);
     2884        *ppDotDot = pThis;
     2885        return VINF_SUCCESS;
     2886    }
     2887
     2888    /*
     2889     * Look for a filename record so we know where we go from here.
     2890     */
     2891    PRTFSNTFSCORE pCore = pThis->RootInfo.pRootAttr->pCore;
     2892    PRTFSNTFSATTR pCurAttr;
     2893    RTListForEach(&pCore->AttribHead, pCurAttr, RTFSNTFSATTR, ListEntry)
     2894    {
     2895        if (   pCurAttr->pAttrHdr->uAttrType == NTFS_AT_FILENAME
     2896            && pCurAttr->cbResident >= RT_UOFFSETOF(NTFSATFILENAME, wszFilename))
     2897        {
     2898            PCNTFSATFILENAME pFilename = (PCNTFSATFILENAME)NTFSATTRIBHDR_GET_RES_VALUE_PTR(pCurAttr->pAttrHdr);
     2899            int rc = rtFsNtfsVol_QueryOrCreateSharedDirByMftRef(pThis->RootInfo.NodeInfo.pVol, &pFilename->ParentDirMftRec,
     2900                                                                ppDotDot, NULL /*pErrInfo*/, "..");
     2901            if (RT_SUCCESS(rc))
     2902                return VINF_SUCCESS;
     2903            LogRel(("rtFsNtfsDirShrd_QueryParent: rtFsNtfsVol_QueryOrCreateSharedDirByMftRef failed: %Rrc\n", rc));
     2904            return rc;
     2905        }
     2906    }
     2907
     2908    LogRel(("rtFsNtfsDirShrd_QueryParent: Couldn't find '..' filename for MFT record %RX64!\n",
     2909            pThis->RootInfo.pRootAttr->pCore->pMftRec->TreeNode.Key));
     2910    return VERR_VFS_BOGUS_FORMAT;
     2911}
     2912
     2913
     2914
     2915/**
    28312916 * Destroys an index node.
    28322917 *
     
    30563141
    30573142        PRTFSNTFSDIRSHRD pSharedToOpen;
    3058         if (   pszEntry[1] == '\0'
    3059             || pVol->pRootDir == pShared)
     3143        if (pszEntry[1] == '\0')
    30603144        {
    30613145            pSharedToOpen = pShared;
     
    30653149        else
    30663150        {
    3067             /* Find a parent mft reference */
    30683151            pSharedToOpen = NULL;
    3069             rc = VERR_VFS_BOGUS_FORMAT;
    3070             PRTFSNTFSCORE pCore = pShared->RootInfo.pRootAttr->pCore;
    3071             PRTFSNTFSATTR pCurAttr;
    3072             RTListForEach(&pCore->AttribHead, pCurAttr, RTFSNTFSATTR, ListEntry)
    3073             {
    3074                 if (   pCurAttr->pAttrHdr->uAttrType == NTFS_AT_FILENAME
    3075                     && pCurAttr->cbResident >= sizeof(NTFSATFILENAME))
    3076                 {
    3077                     PCNTFSATFILENAME pFilename = (PCNTFSATFILENAME)NTFSATTRIBHDR_GET_RES_VALUE_PTR(pCurAttr->pAttrHdr);
    3078                     rc = rtFsNtfsVol_QueryOrCreateSharedDirByMftRef(pVol, &pFilename->ParentDirMftRec,
    3079                                                                     &pSharedToOpen, NULL /*pErrInfo*/, "..");
    3080                     break;
    3081                 }
    3082             }
     3152            rc = rtFsNtfsDirShrd_QueryParent(pShared, &pSharedToOpen);
    30833153        }
    30843154        if (RT_SUCCESS(rc))
     
    32393309
    32403310/**
    3241  * @interface_method_impl{RTVFSDIROPS,pfnRewindDir}
    3242  */
    3243 static DECLCALLBACK(int) rtFsNtfsDir_RewindDir(void *pvThis)
    3244 {
    3245     PRTFSNTFSDIR pThis = (PRTFSNTFSDIR)pvThis;
    3246     LogFlow(("rtFsNtfsDir_RewindDir\n"));
    3247 
     3311 * Cleans up the directory enumeration stack, releasing all node references.
     3312 *
     3313 * @param   pThis               The open directory instance data.
     3314 */
     3315static void rtFsNtfsDir_StackCleanup(PRTFSNTFSDIR pThis)
     3316{
    32483317    while (pThis->cEnumStackEntries > 0)
    32493318    {
     
    32523321        pEntry->pNodeInfo = NULL;
    32533322    }
     3323    if (pThis->paEnumStack)
     3324        pThis->paEnumStack[0].iNext = 0;
     3325}
     3326
     3327
     3328/**
     3329 * @interface_method_impl{RTVFSDIROPS,pfnRewindDir}
     3330 */
     3331static DECLCALLBACK(int) rtFsNtfsDir_RewindDir(void *pvThis)
     3332{
     3333    PRTFSNTFSDIR pThis = (PRTFSNTFSDIR)pvThis;
     3334    LogFlow(("rtFsNtfsDir_RewindDir\n"));
     3335
     3336    rtFsNtfsDir_StackCleanup(pThis);
    32543337    pThis->fNoMoreFiles = false;
    32553338
    32563339    return VINF_SUCCESS;
     3340}
     3341
     3342/**
     3343 * Descends down @a iSubnode to the first entry in left most leaf node.
     3344 *
     3345 * @returns IPRT status code.
     3346 * @param   pThis               The open directory instance data.
     3347 * @param   pRootInfo           The root info structure.
     3348 * @param   iSubnode            The subnode address to descend thru.
     3349 */
     3350static int rtFsNtfsDir_StackDescend(PRTFSNTFSDIR pThis, PRTFSNTFSIDXROOTINFO pRootInfo, int64_t iSubnode)
     3351{
     3352    for (;;)
     3353    {
     3354        /* Load the node. */
     3355        PRTFSNTFSIDXNODE pNode;
     3356        int rc = rtFsNtfsIdxRootInfo_QueryNode(pRootInfo, iSubnode, &pNode);
     3357        if (RT_SUCCESS(rc))
     3358        { /* likely */ }
     3359        else
     3360        {
     3361            LogFlow(("rtFsNtfsDir_StackDescend: rtFsNtfsIdxRootInfo_QueryNode(%#RX64) error %Rrc!\n", iSubnode, rc));
     3362            return rc;
     3363        }
     3364
     3365        /* Push it onto the stack. */
     3366        uint32_t iStack = pThis->cEnumStackEntries;
     3367        if (iStack + 1 < pThis->cEnumStackMaxDepth)
     3368        { /* likely */ }
     3369        else if (pThis->cEnumStackMaxDepth < 1024)
     3370        {
     3371            Assert(pThis->cEnumStackMaxDepth> 0);
     3372            uint32_t cDepth = pThis->cEnumStackMaxDepth * 2;
     3373            Log5(("rtFsNtfsDir_ReadDir: Growing stack size to %u entries (from %u)\n", cDepth, pThis->cEnumStackMaxDepth));
     3374            void *pvNew = RTMemRealloc(pThis->paEnumStack, cDepth * sizeof(pThis->paEnumStack[0]));
     3375            if (pvNew)
     3376                pThis->paEnumStack = (PRTFSNTFSIDXSTACKENTRY)pvNew;
     3377            else
     3378                return VERR_NO_MEMORY;
     3379            pThis->cEnumStackMaxDepth = cDepth;
     3380        }
     3381        else
     3382        {
     3383            LogRel(("rtFsNtfsDir_StackDescend: Badly unbalanced index! (MFT record #%#RX64) -> VERR_VFS_BOGUS_FORMAT\n",
     3384                    pThis->pShared->RootInfo.pRootAttr->pCore->pMftRec->TreeNode.Key));
     3385            return VERR_VFS_BOGUS_FORMAT;
     3386        }
     3387
     3388        Log5(("rtFsNtfsDir_ReadDir: pushing %#RX64 (cEntries=%u, iStack=%u)\n", iSubnode, pNode->NodeInfo.cEntries, iStack));
     3389        pThis->paEnumStack[iStack].iNext     = 0;
     3390        pThis->paEnumStack[iStack].fDescend  = false;
     3391        pThis->paEnumStack[iStack].pNodeInfo = &pNode->NodeInfo;
     3392        pThis->cEnumStackEntries = iStack + 1;
     3393
     3394        /* Stop if this is a leaf node. */
     3395        if (   !pNode->NodeInfo.fInternal
     3396            || !pNode->NodeInfo.cEntries /* paranoia */)
     3397            return VINF_SUCCESS;
     3398
     3399        /* Get the first entry and check that it's an internal node before trying to following it. */
     3400        PCNTFSIDXENTRYHDR pFirstEntry = pNode->NodeInfo.papEntries[0];
     3401        if (pFirstEntry->fFlags & NTFSIDXENTRYHDR_F_INTERNAL)
     3402        { /* likely */ }
     3403        else
     3404            return VINF_SUCCESS;
     3405        iSubnode = NTFSIDXENTRYHDR_GET_SUBNODE(pFirstEntry);
     3406    }
    32573407}
    32583408
     
    32643414                                            RTFSOBJATTRADD enmAddAttr)
    32653415{
    3266     PRTFSNTFSDIR    pThis   = (PRTFSNTFSDIR)pvThis;
     3416    PRTFSNTFSDIR     pThis   = (PRTFSNTFSDIR)pvThis;
     3417    PRTFSNTFSDIRSHRD pShared = pThis->pShared;
     3418    int              rc;
     3419    Log(("rtFsNtfsDir_ReadDir\n"));
     3420
     3421    /*
     3422     * Return immediately if no files at hand.
     3423     */
    32673424    if (pThis->fNoMoreFiles)
    32683425        return VERR_NO_MORE_FILES;
    3269     Log(("rtFsNtfsDir_ReadDir\n"));
    3270     //PRTFSNTFSDIRSHRD pShared = pThis->pShared;
    3271     NOREF(pvThis); NOREF(pDirEntry); NOREF(pcbDirEntry); NOREF(enmAddAttr);
    3272     return VERR_NOT_IMPLEMENTED;
     3426
     3427    /*
     3428     * Make sure we've got a stack before we jump into the fray.
     3429     */
     3430    if (!pThis->cEnumStackMaxDepth)
     3431    {
     3432        uint32_t cDepth;
     3433        if (!pShared->RootInfo.pAlloc)
     3434            cDepth = 2;
     3435        else
     3436        {
     3437            cDepth = ASMBitFirstSetU64(pShared->RootInfo.pAlloc->cbValue / RT_LE2H_U32(pShared->RootInfo.pRoot->cbIndexNode));
     3438            cDepth += 3;
     3439        }
     3440
     3441        pThis->paEnumStack = (PRTFSNTFSIDXSTACKENTRY)RTMemAllocZ(cDepth * sizeof(pThis->paEnumStack[0]));
     3442        if (!pThis->paEnumStack)
     3443            return VERR_NO_MEMORY;
     3444        pThis->cEnumStackMaxDepth   = cDepth;
     3445        pThis->cEnumStackEntries    = 0;
     3446        Log5(("rtFsNtfsDir_ReadDir: Initial stack size: %u entries\n", cDepth));
     3447        //pThis->paEnumStack[0].iNext = 0;
     3448    }
     3449
     3450    /*
     3451     * Deal with '.' and '..' by using stack entry zero without setting cEnumStack to zero.
     3452     * This is fine because we've got the fNoMoreFiles flag that got checked already.
     3453     */
     3454    size_t const cbDirEntry = *pcbDirEntry;
     3455    if (pThis->cEnumStackEntries == 0)
     3456    {
     3457        if (pThis->paEnumStack[0].iNext <= 1)
     3458        {
     3459
     3460            *pcbDirEntry = RT_UOFFSETOF(RTDIRENTRYEX, szName[pThis->paEnumStack[0].iNext + 2]);
     3461            if (*pcbDirEntry > cbDirEntry)
     3462                return VERR_BUFFER_OVERFLOW;
     3463
     3464            /* Names. */
     3465            pDirEntry->cbName = pThis->paEnumStack[0].iNext + 1;
     3466            pDirEntry->szName[0]                     = '.';
     3467            pDirEntry->szName[pDirEntry->cbName - 1] = '.';
     3468            pDirEntry->szName[pDirEntry->cbName]     = '\0';
     3469            pDirEntry->wszShortName[0]               = '\0';
     3470            pDirEntry->cwcShortName                  = 0;
     3471
     3472            /* Get referenced shared directory structure that we return info about. */
     3473            PRTFSNTFSDIRSHRD pDotShared;
     3474            if (pThis->paEnumStack[0].iNext == 0)
     3475            {
     3476                rtFsNtfsDirShrd_Retain(pShared);
     3477                pDotShared = pShared;
     3478            }
     3479            else
     3480            {
     3481                pDotShared = NULL;
     3482                rc = rtFsNtfsDirShrd_QueryParent(pShared, &pDotShared);
     3483                if (RT_FAILURE(rc))
     3484                {
     3485                    LogRel(("rtFsNtfsDir_ReadDir: couldn't find '..' filename! %Rrc\n", rc));
     3486                    return rc;
     3487                }
     3488            }
     3489
     3490            /* Get the info. */
     3491            rc = rtFsNtfsCore_QueryInfo(pDotShared->RootInfo.pRootAttr->pCore, pDotShared->RootInfo.pRootAttr,
     3492                                        &pDirEntry->Info, enmAddAttr);
     3493            rtFsNtfsDirShrd_Release(pDotShared);
     3494            if (RT_SUCCESS(rc))
     3495                pThis->paEnumStack[0].iNext++;
     3496            Log5(("rtFsNtfsDir_ReadDir: => '%s' (%Rrc)\n", pDirEntry->szName, rc));
     3497            return rc;
     3498        }
     3499
     3500        /*
     3501         * Push the root onto the stack and decend down the left side of the tree.
     3502         */
     3503        PRTFSNTFSIDXNODEINFO pNodeInfo  = &pShared->RootInfo.NodeInfo;
     3504        pThis->paEnumStack[0].pNodeInfo = pNodeInfo;
     3505        pThis->paEnumStack[0].iNext     = 0;
     3506        pThis->cEnumStackEntries        = 1;
     3507        Log5(("rtFsNtfsDir_ReadDir: pushing root\n"));
     3508        if (   pNodeInfo->fInternal
     3509            && pNodeInfo->cEntries > 0
     3510            && (pNodeInfo->papEntries[0]->fFlags & NTFSIDXENTRYHDR_F_INTERNAL) /* parnaoia */ )
     3511        {
     3512            rc = rtFsNtfsDir_StackDescend(pThis, &pShared->RootInfo, NTFSIDXENTRYHDR_GET_SUBNODE(pNodeInfo->papEntries[0]));
     3513            if (RT_FAILURE(rc))
     3514            {
     3515                pThis->fNoMoreFiles = true;
     3516                rtFsNtfsDir_StackCleanup(pThis);
     3517                return rc;
     3518            }
     3519        }
     3520    }
     3521
     3522    /*
     3523     * Work the stack.
     3524     */
     3525    int32_t iStack = pThis->cEnumStackEntries - 1;
     3526    while (iStack >= 0)
     3527    {
     3528        PRTFSNTFSIDXNODEINFO pNodeInfo  = pThis->paEnumStack[iStack].pNodeInfo;
     3529        uint32_t             iNext      = pThis->paEnumStack[iStack].iNext;
     3530        if (iNext < pNodeInfo->cEntries)
     3531        {
     3532            PCNTFSIDXENTRYHDR pEntry = pNodeInfo->papEntries[iNext];
     3533            if (   !(pEntry->fFlags & NTFSIDXENTRYHDR_F_INTERNAL)
     3534                || !pThis->paEnumStack[iStack].fDescend)
     3535            {
     3536                if (!(pEntry->fFlags & NTFSIDXENTRYHDR_F_END))
     3537                {
     3538                    /*
     3539                     * Try return the current entry.
     3540                     */
     3541                    PCNTFSATFILENAME pFilename = (PCNTFSATFILENAME)(pEntry + 1);
     3542
     3543                    /* Deal with the filename. */
     3544                    size_t cchFilename;
     3545                    rc = RTUtf16CalcUtf8LenEx(pFilename->wszFilename, pFilename->cwcFilename, &cchFilename);
     3546                    if (RT_FAILURE(rc))
     3547                    {
     3548                        cchFilename = 48;
     3549                        LogRel(("rtFsNtfsDir_ReadDir: Bad filename (%Rrc) %.*Rhxs\n",
     3550                                rc, pFilename->cwcFilename * sizeof(RTUTF16), pFilename->wszFilename));
     3551                    }
     3552                    *pcbDirEntry = RT_UOFFSETOF(RTDIRENTRYEX, szName[cchFilename + 1]);
     3553                    if (*pcbDirEntry > cbDirEntry)
     3554                    {
     3555                        Log5(("rtFsNtfsDir_ReadDir: returns VERR_BUFFER_OVERFLOW (for '%.*ls')\n",
     3556                              pFilename->cwcFilename, pFilename->wszFilename));
     3557                        return VERR_BUFFER_OVERFLOW;
     3558                    }
     3559
     3560                    char *pszDst = pDirEntry->szName;
     3561                    if (RT_SUCCESS(rc))
     3562                        rc = RTUtf16ToUtf8Ex(pFilename->wszFilename, pFilename->cwcFilename, &pszDst,
     3563                                             cbDirEntry - RT_UOFFSETOF(RTDIRENTRYEX, szName), &cchFilename);
     3564                    if (RT_FAILURE(rc))
     3565                        cchFilename = RTStrPrintf(pDirEntry->szName, cbDirEntry - RT_UOFFSETOF(RTDIRENTRYEX, szName),
     3566                                                  "{invalid-name-%#RX64}", NTFSMFTREF_GET_IDX(&pEntry->u.FileMftRec));
     3567                    pDirEntry->cbName = (uint16_t)cchFilename;
     3568
     3569                    /* Figure out how to detect short names. */
     3570                    pDirEntry->cwcShortName    = 0;
     3571                    pDirEntry->wszShortName[0] = '\0';
     3572
     3573                    /* Standard attributes: file mode, sizes and timestamps. */
     3574                    pDirEntry->Info.cbObject    = RT_LE2H_U64(pFilename->cbData);
     3575                    pDirEntry->Info.cbAllocated = RT_LE2H_U64(pFilename->cbAllocated);
     3576                    RTTimeSpecSetNtTime(&pDirEntry->Info.BirthTime,        RT_LE2H_U64(pFilename->iCreationTime));
     3577                    RTTimeSpecSetNtTime(&pDirEntry->Info.ModificationTime, RT_LE2H_U64(pFilename->iLastDataModTime));
     3578                    RTTimeSpecSetNtTime(&pDirEntry->Info.ChangeTime,       RT_LE2H_U64(pFilename->iLastMftModTime));
     3579                    RTTimeSpecSetNtTime(&pDirEntry->Info.AccessTime,       RT_LE2H_U64(pFilename->iLastAccessTime));
     3580                    pDirEntry->Info.Attr.fMode = rtFsNtfsConvertFileattribsToMode(RT_LE2H_U32(pFilename->fFileAttribs), pFilename,
     3581                                                                                  RT_LE2H_U16(pEntry->cbKey));
     3582
     3583                    /* additional stuff. */
     3584                    switch (enmAddAttr)
     3585                    {
     3586                        case RTFSOBJATTRADD_NOTHING:
     3587                            enmAddAttr = RTFSOBJATTRADD_UNIX;
     3588                            RT_FALL_THRU();
     3589                        case RTFSOBJATTRADD_UNIX:
     3590                            pDirEntry->Info.Attr.u.Unix.uid             = NIL_RTUID;
     3591                            pDirEntry->Info.Attr.u.Unix.gid             = NIL_RTGID;
     3592                            pDirEntry->Info.Attr.u.Unix.cHardlinks      = 1;
     3593                            pDirEntry->Info.Attr.u.Unix.INodeIdDevice   = 0;
     3594                            pDirEntry->Info.Attr.u.Unix.INodeId         = NTFSMFTREF_GET_IDX(&pEntry->u.FileMftRec);
     3595                            pDirEntry->Info.Attr.u.Unix.fFlags          = 0;
     3596                            pDirEntry->Info.Attr.u.Unix.GenerationId    = 0;
     3597                            pDirEntry->Info.Attr.u.Unix.Device          = 0;
     3598                            break;
     3599
     3600                        case RTFSOBJATTRADD_UNIX_OWNER:
     3601                            pDirEntry->Info.Attr.u.UnixOwner.uid = NIL_RTUID;
     3602                            pDirEntry->Info.Attr.u.UnixOwner.szName[0] = '\0';
     3603                            break;
     3604
     3605                        case RTFSOBJATTRADD_UNIX_GROUP:
     3606                            pDirEntry->Info.Attr.u.UnixGroup.gid = NIL_RTGID;
     3607                            pDirEntry->Info.Attr.u.UnixGroup.szName[0] = '\0';
     3608                            break;
     3609
     3610                        case RTFSOBJATTRADD_EASIZE:
     3611                            if (!(pFilename->fFileAttribs & RT_H2LE_U32_C(NTFS_FA_REPARSE_POINT)))
     3612                                pDirEntry->Info.Attr.u.EASize.cb = pFilename->u.cbPackedEas;
     3613                            else
     3614                                pDirEntry->Info.Attr.u.EASize.cb = 0;
     3615                            break;
     3616
     3617                        default:
     3618                            AssertFailed();
     3619                            RT_ZERO(pDirEntry->Info.Attr.u);
     3620                            break;
     3621                    }
     3622                    pDirEntry->Info.Attr.enmAdditional = enmAddAttr;
     3623
     3624                    /*
     3625                     * Advance the stack entry to the next entry and return.
     3626                     */
     3627                    Log5(("rtFsNtfsDir_ReadDir: => iStack=%u iNext=%u - '%.*ls'\n",
     3628                          iStack, iNext, pFilename->cwcFilename,  pFilename->wszFilename));
     3629                    pThis->paEnumStack[iStack].iNext    = iNext + 1;
     3630                    pThis->paEnumStack[iStack].fDescend = true;
     3631                    return VINF_SUCCESS;
     3632                }
     3633
     3634                /*
     3635                 * End node, so pop it.  We join the beoynd-end-of-entries path
     3636                 * further down, forcing the descend code to use continue.
     3637                 */
     3638            }
     3639            else
     3640            {
     3641                /*
     3642                 * Descend.
     3643                 */
     3644                rc = rtFsNtfsDir_StackDescend(pThis, &pShared->RootInfo,
     3645                                              NTFSIDXENTRYHDR_GET_SUBNODE(pNodeInfo->papEntries[iNext]));
     3646                if (RT_SUCCESS(rc))
     3647                {
     3648                    pThis->paEnumStack[iStack].fDescend = false;
     3649                    iStack = pThis->cEnumStackEntries - 1;
     3650                    continue;
     3651                }
     3652                pThis->fNoMoreFiles = true;
     3653                rtFsNtfsDir_StackCleanup(pThis);
     3654                return rc;
     3655            }
     3656        }
     3657
     3658        /*
     3659         * Pop at stack entry.
     3660         */
     3661        Log5(("rtFsNtfsDir_ReadDir: popping %#RX64 (iNext=%u, cEntries=%u, iStack=%u) -> %#RX64 (iNext=%d, cEntries=%u)\n",
     3662              pNodeInfo->pNode ? pNodeInfo->pNode->pNode->iSelfAddress : 0, iNext, pNodeInfo->cEntries, iStack,
     3663              iStack > 0 && pThis->paEnumStack[iStack - 1].pNodeInfo->pNode
     3664              ? pThis->paEnumStack[iStack - 1].pNodeInfo->pNode->pNode->iSelfAddress : UINT64_MAX,
     3665              iStack > 0 ? pThis->paEnumStack[iStack - 1].iNext : -1,
     3666              iStack > 0 ? pThis->paEnumStack[iStack - 1].pNodeInfo->cEntries : 0 ));
     3667        rtFsNtfsIdxNode_Release(pNodeInfo->pNode);
     3668        pThis->paEnumStack[iStack].pNodeInfo = NULL;
     3669        pThis->cEnumStackEntries = iStack;
     3670        iStack--;
     3671        Assert(iStack < 0 || !pThis->paEnumStack[iStack].fDescend);
     3672    }
     3673
     3674    /*
     3675     * The End.
     3676     */
     3677    Log5(("rtFsNtfsDir_ReadDir: no more files\n"));
     3678    pThis->fNoMoreFiles = true;
     3679    return VERR_NO_MORE_FILES;
    32733680}
    32743681
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette