Changeset 69938 in vbox for trunk/src/VBox/Runtime/common/fs
- Timestamp:
- Dec 5, 2017 4:58:50 PM (7 years ago)
- svn:sync-xref-src-repo-rev:
- 119432
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/fs/ntfsvfs.cpp
r69925 r69938 29 29 * Header Files * 30 30 *********************************************************************************************************************************/ 31 #define RTMEM_WRAP_TO_EF_APIS // REMOVE REMOVE REMOVE 31 32 #define LOG_GROUP RTLOGGROUP_FS 32 33 #include <iprt/fsvfs.h> … … 312 313 /** The next entry to process in this stack entry. */ 313 314 uint32_t iNext; 315 /** Set if we need to descend first. */ 316 bool fDescend; 314 317 /** Pointer to the node info for this entry. */ 315 318 PRTFSNTFSIDXNODEINFO pNodeInfo; … … 1135 1138 if (pAttrHdr->fNonResident) 1136 1139 { 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 1137 1162 int64_t const iVcnFirst = RT_LE2H_U64(pAttrHdr->u.NonRes.iVcnFirst); 1138 1163 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)) 1140 1167 return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT, 1141 1168 "Bad MFT record %#RX64: Attribute (@%#x): iVcnFirst (%#RX64) is higher than iVcnLast (%#RX64)", … … 1160 1187 pRec->TreeNode.Key, offRec, pAttrHdr->u.NonRes.uCompressionUnit); 1161 1188 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);1183 1189 if (cbMin >= NTFSATTRIBHDR_SIZE_NONRES_COMPRESSED) 1184 1190 { … … 1199 1205 pRec->TreeNode.Key, offRec, offValue, cbAttrib, RT_LE2H_U32(pAttrHdr->u.Res.cbValue)); 1200 1206 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 1201 1212 return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT, 1202 1213 "Bad MFT record %#RX64: Attribute (@%#x): fFlags (%#RX16) indicate compression of a resident attribute", 1203 1214 pRec->TreeNode.Key, offRec, RT_LE2H_U16(pAttrHdr->fFlags)); 1215 #endif 1216 } 1204 1217 } 1205 1218 … … 1818 1831 1819 1832 /** 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 */ 1840 static 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; 1884 1851 else 1885 1852 { 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; 1943 1854 if ( pFilename 1944 1855 && pFilename->cwcFilename >= 4 1945 && RT_UOFFSETOF(NTFSATFILENAME, wszFilename[pFilename->cwcFilename]) <= pFilenameAttr->cbResident)1856 && RT_UOFFSETOF(NTFSATFILENAME, wszFilename[pFilename->cwcFilename]) <= cbFilename) 1946 1857 { 1947 1858 PCRTUTF16 pwcExt = &pFilename->wszFilename[pFilename->cwcFilename - 4]; … … 1964 1875 || !memcmp(szExt, "btm", 4) 1965 1876 ) 1966 pObjInfo->Attr.fMode |= RTFS_UNIX_IXUSR | RTFS_UNIX_IXGRP | RTFS_UNIX_IXOTH;1877 fMode |= RTFS_UNIX_IXUSR | RTFS_UNIX_IXGRP | RTFS_UNIX_IXOTH; 1967 1878 } 1968 1879 } … … 1971 1882 1972 1883 /* Is it really a symbolic link? */ 1973 if ( ( pObjInfo->Attr.fMode & RTFS_DOS_NT_REPARSE_POINT)1884 if ( (fMode & RTFS_DOS_NT_REPARSE_POINT) 1974 1885 && pFilename 1975 1886 && 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; 1977 1888 1978 1889 /* 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 */ 1908 static 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); 1981 2011 1982 2012 return VINF_SUCCESS; … … 2206 2236 uint32_t const offFirstEntry = RT_LE2H_U32(pIndexHdr->offFirstEntry); 2207 2237 if ( offFirstEntry < sizeof(*pIndexHdr) 2208 || offFirstEntry >= cbUsed - sizeof(NTFSIDXENTRYHDR) 2238 || ( offFirstEntry > cbUsed - sizeof(NTFSIDXENTRYHDR) 2239 && offFirstEntry != cbUsed /* empty dir */) 2209 2240 || (offFirstEntry & 7) ) 2210 2241 return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT, … … 2532 2563 rc = VERR_VFS_BOGUS_FORMAT; 2533 2564 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", 2535 2566 iNode, RT_LE2H_U32(pNode->pNode->RecHdr.uMagic) )); 2536 2567 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", 2538 2569 iNode, RT_LE2H_U64(pNode->pNode->iSelfAddress) )); 2539 2570 else … … 2678 2709 2679 2710 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; 2682 2717 } 2683 2718 … … 2783 2818 *ppEntryHdr = papEntries[iEntry]; 2784 2819 *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) )); 2786 2823 return VINF_SUCCESS; 2787 2824 } … … 2829 2866 2830 2867 /** 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 */ 2876 static 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 /** 2831 2916 * Destroys an index node. 2832 2917 * … … 3056 3141 3057 3142 PRTFSNTFSDIRSHRD pSharedToOpen; 3058 if ( pszEntry[1] == '\0' 3059 || pVol->pRootDir == pShared) 3143 if (pszEntry[1] == '\0') 3060 3144 { 3061 3145 pSharedToOpen = pShared; … … 3065 3149 else 3066 3150 { 3067 /* Find a parent mft reference */3068 3151 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); 3083 3153 } 3084 3154 if (RT_SUCCESS(rc)) … … 3239 3309 3240 3310 /** 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 */ 3315 static void rtFsNtfsDir_StackCleanup(PRTFSNTFSDIR pThis) 3316 { 3248 3317 while (pThis->cEnumStackEntries > 0) 3249 3318 { … … 3252 3321 pEntry->pNodeInfo = NULL; 3253 3322 } 3323 if (pThis->paEnumStack) 3324 pThis->paEnumStack[0].iNext = 0; 3325 } 3326 3327 3328 /** 3329 * @interface_method_impl{RTVFSDIROPS,pfnRewindDir} 3330 */ 3331 static DECLCALLBACK(int) rtFsNtfsDir_RewindDir(void *pvThis) 3332 { 3333 PRTFSNTFSDIR pThis = (PRTFSNTFSDIR)pvThis; 3334 LogFlow(("rtFsNtfsDir_RewindDir\n")); 3335 3336 rtFsNtfsDir_StackCleanup(pThis); 3254 3337 pThis->fNoMoreFiles = false; 3255 3338 3256 3339 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 */ 3350 static 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 } 3257 3407 } 3258 3408 … … 3264 3414 RTFSOBJATTRADD enmAddAttr) 3265 3415 { 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 */ 3267 3424 if (pThis->fNoMoreFiles) 3268 3425 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; 3273 3680 } 3274 3681
Note:
See TracChangeset
for help on using the changeset viewer.