Changeset 66762 in vbox for trunk/src/VBox/Runtime/common/vfs
- Timestamp:
- May 3, 2017 10:20:16 PM (8 years ago)
- Location:
- trunk/src/VBox/Runtime/common/vfs
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/vfs/vfsbase.cpp
r66742 r66762 1429 1429 * @param pPath The parsed path. This may be changed as symbolic 1430 1430 * links are processed during the path traversal. 1431 * @param fFollowSymlink Whether to follow the final component if it is a 1432 * symbolic link. 1431 * @param fFlags RTPATH_F_XXX. 1433 1432 * @param ppVfsParentDir Where to return the parent directory handle 1434 1433 * (referenced). 1435 1434 */ 1436 static int rtVfsDirTraverseToParent(RTVFSDIRINTERNAL *pThis, PRTVFSPARSEDPATH pPath, bool fFollowSymlink,1435 static int rtVfsDirTraverseToParent(RTVFSDIRINTERNAL *pThis, PRTVFSPARSEDPATH pPath, uint32_t fFlags, 1437 1436 RTVFSDIRINTERNAL **ppVfsParentDir) 1438 1437 { … … 1447 1446 *ppVfsParentDir = NULL; 1448 1447 AssertReturn(pPath->cComponents > 0, VERR_INTERNAL_ERROR_3); 1448 Assert(RTPATH_F_IS_VALID(fFlags, 0)); 1449 1449 1450 1450 /* … … 1467 1467 */ 1468 1468 bool fFinal = iComponent + 1 >= pPath->cComponents; 1469 if (fFinal && !fFollowSymlink)1469 if (fFinal && (fFlags & RTPATH_F_ON_LINK)) 1470 1470 { 1471 1471 *ppVfsParentDir = pCurDir; … … 1539 1539 AssertPtr(hSymlink); 1540 1540 Assert(hSymlink->uMagic == RTVFSSYMLINK_MAGIC); 1541 if (fFlags & RTPATH_F_NO_SYMLINKS) 1542 { 1543 rc = VERR_SYMLINK_NOT_ALLOWED; 1544 break; 1545 } 1541 1546 cLinks++; 1542 1547 if (cLinks >= RTVFS_MAX_LINKS) … … 1596 1601 * @param pPath The parsed path. This may be changed as symbolic 1597 1602 * links are processed during the path traversal. 1598 * @param fFollowSymlink Whether to follow the final component if it is a 1599 * symbolic link. 1603 * @param fFlags RTPATH_F_XXX. 1600 1604 * @param ppVfsParentDir Where to return the parent directory handle 1601 1605 * (referenced). 1602 1606 */ 1603 static int rtVfsTraverseToParent(RTVFSINTERNAL *pThis, PRTVFSPARSEDPATH pPath, bool fFollowSymlink, 1604 RTVFSDIRINTERNAL **ppVfsParentDir) 1607 static int rtVfsTraverseToParent(RTVFSINTERNAL *pThis, PRTVFSPARSEDPATH pPath, uint32_t fFlags, RTVFSDIRINTERNAL **ppVfsParentDir) 1605 1608 { 1606 1609 /* … … 1614 1617 *ppVfsParentDir = NULL; 1615 1618 AssertReturn(pPath->cComponents > 0, VERR_INTERNAL_ERROR_3); 1619 Assert(RTPATH_F_IS_VALID(fFlags, 0)); 1616 1620 1617 1621 /* … … 1625 1629 if (RT_SUCCESS(rc)) 1626 1630 { 1627 rc = rtVfsDirTraverseToParent(pRootDir, pPath, fF ollowSymlink, ppVfsParentDir);1631 rc = rtVfsDirTraverseToParent(pRootDir, pPath, fFlags, ppVfsParentDir); 1628 1632 RTVfsDirRelease(pRootDir); 1629 1633 } … … 1820 1824 1821 1825 1826 RTDECL(int) RTVfsQueryPathInfo(RTVFS hVfs, const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr, uint32_t fFlags) 1827 { 1828 RTVFSINTERNAL *pThis = hVfs; 1829 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 1830 AssertReturn(pThis->uMagic == RTVFS_MAGIC, VERR_INVALID_HANDLE); 1831 AssertPtrReturn(pszPath, VERR_INVALID_POINTER); 1832 AssertReturn(*pszPath, VERR_INVALID_PARAMETER); 1833 AssertPtrReturn(pObjInfo, VERR_INVALID_POINTER); 1834 AssertReturn(enmAddAttr >= RTFSOBJATTRADD_NOTHING && enmAddAttr <= RTFSOBJATTRADD_LAST, VERR_INVALID_PARAMETER); 1835 AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER); 1836 1837 /* 1838 * Parse the path, assume current directory is root since we've got no 1839 * caller context here. Then traverse to the parent directory. 1840 */ 1841 PRTVFSPARSEDPATH pPath; 1842 int rc = RTVfsParsePathA(pszPath, "/", &pPath); 1843 if (RT_SUCCESS(rc)) 1844 { 1845 RTVFSDIRINTERNAL *pVfsParentDir; 1846 if (pPath->cComponents > 0) 1847 { 1848 rc = rtVfsTraverseToParent(pThis, pPath, fFlags, &pVfsParentDir); 1849 if (RT_SUCCESS(rc)) 1850 { 1851 /* 1852 * Call the query method on the parent directory. 1853 */ 1854 /** @todo race condition here :/ */ 1855 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]]; 1856 RTVfsLockAcquireRead(pVfsParentDir->Base.hLock); 1857 rc = pVfsParentDir->pOps->pfnQueryEntryInfo(pVfsParentDir->Base.pvThis, pszEntryName, pObjInfo, enmAddAttr); 1858 RTVfsLockReleaseRead(pVfsParentDir->Base.hLock); 1859 1860 RTVfsDirRelease(pVfsParentDir); 1861 } 1862 } 1863 /* 1864 * The path boils down to '.', open the root dir and query its info. 1865 */ 1866 else 1867 { 1868 RTVfsLockAcquireRead(pThis->Base.hLock); 1869 RTVFSDIR hRootDir = NIL_RTVFSDIR; 1870 rc = pThis->pOps->pfnOpenRoot(pThis->Base.pvThis, &hRootDir); 1871 RTVfsLockReleaseRead(pThis->Base.hLock); 1872 if (RT_SUCCESS(rc)) 1873 { 1874 RTVfsLockAcquireRead(hRootDir->Base.hLock); 1875 rc = hRootDir->Base.pOps->pfnQueryInfo(hRootDir->Base.pvThis, pObjInfo, enmAddAttr); 1876 RTVfsLockReleaseRead(hRootDir->Base.hLock); 1877 RTVfsDirRelease(hRootDir); 1878 } 1879 } 1880 1881 RTVfsParsePathFree(pPath); 1882 } 1883 return rc; 1884 } 1885 1886 1822 1887 1823 1888 RTDECL(int) RTVfsIsRangeInUse(RTVFS hVfs, uint64_t off, size_t cb, bool *pfUsed) … … 2073 2138 if (RT_SUCCESS(rc)) 2074 2139 { 2075 /* 2076 * Tranverse the path, resolving the parent node and any symlinks 2077 * in the final element, and ask the directory to open the subdir. 2078 */ 2079 RTVFSDIRINTERNAL *pVfsParentDir; 2080 rc = rtVfsTraverseToParent(pThis, pPath, true /*fFollowSymlink*/, &pVfsParentDir); 2081 if (RT_SUCCESS(rc)) 2082 { 2083 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]]; 2084 2085 /** @todo there is a symlink creation race here. */ 2086 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock); 2087 rc = pVfsParentDir->pOps->pfnOpenDir(pVfsParentDir->Base.pvThis, pszEntryName, fFlags, phVfsDir); 2088 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock); 2089 2090 RTVfsDirRelease(pVfsParentDir); 2091 2140 if (pPath->cComponents > 0) 2141 { 2142 /* 2143 * Tranverse the path, resolving the parent node and any symlinks 2144 * in the final element, and ask the directory to open the subdir. 2145 */ 2146 RTVFSDIRINTERNAL *pVfsParentDir; 2147 rc = rtVfsTraverseToParent(pThis, pPath, RTPATH_F_FOLLOW_LINK, &pVfsParentDir); 2092 2148 if (RT_SUCCESS(rc)) 2093 2149 { 2094 AssertPtr(*phVfsDir); 2095 Assert((*phVfsDir)->uMagic == RTVFSDIR_MAGIC); 2150 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]]; 2151 2152 /** @todo there is a symlink creation race here. */ 2153 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock); 2154 rc = pVfsParentDir->pOps->pfnOpenDir(pVfsParentDir->Base.pvThis, pszEntryName, fFlags, phVfsDir); 2155 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock); 2156 2157 RTVfsDirRelease(pVfsParentDir); 2158 2159 if (RT_SUCCESS(rc)) 2160 { 2161 AssertPtr(*phVfsDir); 2162 Assert((*phVfsDir)->uMagic == RTVFSDIR_MAGIC); 2163 } 2096 2164 } 2165 } 2166 /* 2167 * If the path boils down to '.' return the root directory. 2168 */ 2169 else 2170 { 2171 RTVfsLockAcquireRead(pThis->Base.hLock); 2172 rc = pThis->pOps->pfnOpenRoot(pThis->Base.pvThis, phVfsDir); 2173 RTVfsLockReleaseRead(pThis->Base.hLock); 2097 2174 } 2098 2175 RTVfsParsePathFree(pPath); … … 2121 2198 if (RT_SUCCESS(rc)) 2122 2199 { 2123 /* 2124 * Tranverse the path, resolving the parent node and any symlinks 2125 * in the final element, and ask the directory to open the subdir. 2126 */ 2127 RTVFSDIRINTERNAL *pVfsParentDir; 2128 rc = rtVfsDirTraverseToParent(pThis, pPath, true /*fFollowSymlink*/, &pVfsParentDir); 2129 if (RT_SUCCESS(rc)) 2130 { 2131 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]]; 2132 2133 /** @todo there is a symlink creation race here. */ 2134 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock); 2135 rc = pVfsParentDir->pOps->pfnOpenDir(pVfsParentDir->Base.pvThis, pszEntryName, fFlags, phVfsDir); 2136 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock); 2137 2138 RTVfsDirRelease(pVfsParentDir); 2139 2200 if (pPath->cComponents > 0) 2201 { 2202 /* 2203 * Tranverse the path, resolving the parent node and any symlinks 2204 * in the final element, and ask the directory to open the subdir. 2205 */ 2206 RTVFSDIRINTERNAL *pVfsParentDir; 2207 rc = rtVfsDirTraverseToParent(pThis, pPath, RTPATH_F_FOLLOW_LINK, &pVfsParentDir); 2140 2208 if (RT_SUCCESS(rc)) 2141 2209 { 2142 AssertPtr(*phVfsDir); 2143 Assert((*phVfsDir)->uMagic == RTVFSDIR_MAGIC); 2210 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]]; 2211 2212 /** @todo there is a symlink creation race here. */ 2213 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock); 2214 rc = pVfsParentDir->pOps->pfnOpenDir(pVfsParentDir->Base.pvThis, pszEntryName, fFlags, phVfsDir); 2215 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock); 2216 2217 RTVfsDirRelease(pVfsParentDir); 2218 2219 if (RT_SUCCESS(rc)) 2220 { 2221 AssertPtr(*phVfsDir); 2222 Assert((*phVfsDir)->uMagic == RTVFSDIR_MAGIC); 2223 } 2144 2224 } 2225 } 2226 /* 2227 * The path boils down to '.', call pfnOpenDir on pThis with '.' as input. 2228 * The caller may wish for a new directory instance to enumerate the entries 2229 * in parallel or some such thing. 2230 */ 2231 else 2232 { 2233 RTVfsLockAcquireWrite(pThis->Base.hLock); 2234 rc = pThis->pOps->pfnOpenDir(pThis->Base.pvThis, ".", fFlags, phVfsDir); 2235 RTVfsLockReleaseWrite(pThis->Base.hLock); 2145 2236 } 2146 2237 RTVfsParsePathFree(pPath); … … 2173 2264 if (RT_SUCCESS(rc)) 2174 2265 { 2175 if (!pPath->fDirSlash) 2266 if ( !pPath->fDirSlash 2267 && pPath->cComponents > 0) 2176 2268 { 2177 2269 /* … … 2180 2272 */ 2181 2273 RTVFSDIRINTERNAL *pVfsParentDir; 2182 rc = rtVfsDirTraverseToParent(pThis, pPath, true /*fFollowSymlink*/, &pVfsParentDir);2274 rc = rtVfsDirTraverseToParent(pThis, pPath, RTPATH_F_FOLLOW_LINK, &pVfsParentDir); 2183 2275 if (RT_SUCCESS(rc)) 2184 2276 { … … 2200 2292 } 2201 2293 else 2202 rc = VERR_ INVALID_PARAMETER;2294 rc = VERR_NOT_A_FILE; 2203 2295 RTVfsParsePathFree(pPath); 2204 2296 } 2297 return rc; 2298 } 2299 2300 2301 RTDECL(int) RTVfsDirQueryPathInfo(RTVFSDIR hVfsDir, const char *pszPath, PRTFSOBJINFO pObjInfo, 2302 RTFSOBJATTRADD enmAddAttr, uint32_t fFlags) 2303 { 2304 /* 2305 * Validate input. 2306 */ 2307 RTVFSDIRINTERNAL *pThis = hVfsDir; 2308 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 2309 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE); 2310 AssertPtrReturn(pszPath, VERR_INVALID_POINTER); 2311 AssertReturn(*pszPath, VERR_INVALID_PARAMETER); 2312 AssertPtrReturn(pObjInfo, VERR_INVALID_POINTER); 2313 AssertReturn(enmAddAttr >= RTFSOBJATTRADD_NOTHING && enmAddAttr <= RTFSOBJATTRADD_LAST, VERR_INVALID_PARAMETER); 2314 AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER); 2315 2316 /* 2317 * Parse the path, assume current directory is root since we've got no 2318 * caller context here. Then traverse to the parent directory. 2319 */ 2320 PRTVFSPARSEDPATH pPath; 2321 int rc = RTVfsParsePathA(pszPath, "/", &pPath); 2322 if (RT_SUCCESS(rc)) 2323 { 2324 if (pPath->cComponents > 0) 2325 { 2326 RTVFSDIRINTERNAL *pVfsParentDir; 2327 rc = rtVfsDirTraverseToParent(pThis, pPath, fFlags, &pVfsParentDir); 2328 if (RT_SUCCESS(rc)) 2329 { 2330 /* 2331 * Call the query method on the parent directory. 2332 */ 2333 /** @todo symlink race condition here :/ */ 2334 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]]; 2335 RTVfsLockAcquireRead(pVfsParentDir->Base.hLock); 2336 rc = pVfsParentDir->pOps->pfnQueryEntryInfo(pVfsParentDir->Base.pvThis, pszEntryName, pObjInfo, enmAddAttr); 2337 RTVfsLockReleaseRead(pVfsParentDir->Base.hLock); 2338 2339 RTVfsDirRelease(pVfsParentDir); 2340 } 2341 else 2342 rc = VERR_INVALID_PARAMETER; 2343 } 2344 /* 2345 * The path boils down to '.' so just query the directory. 2346 */ 2347 else 2348 { 2349 RTVfsLockAcquireRead(pThis->Base.hLock); 2350 rc = pThis->Base.pOps->pfnQueryInfo(pThis->Base.pvThis, pObjInfo, enmAddAttr); 2351 RTVfsLockReleaseRead(pThis->Base.hLock); 2352 } 2353 RTVfsParsePathFree(pPath); 2354 } 2355 return rc; 2356 } 2357 2358 2359 RTDECL(int) RTVfsDirReadEx(RTVFSDIR hVfsDir, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry, RTFSOBJATTRADD enmAddAttr) 2360 { 2361 /* 2362 * Validate input. 2363 */ 2364 RTVFSDIRINTERNAL *pThis = hVfsDir; 2365 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 2366 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE); 2367 AssertPtrReturn(pDirEntry, VERR_INVALID_POINTER); 2368 AssertReturn(enmAddAttr >= RTFSOBJATTRADD_NOTHING && enmAddAttr <= RTFSOBJATTRADD_LAST, VERR_INVALID_PARAMETER); 2369 2370 size_t cbDirEntry = sizeof(*pDirEntry); 2371 if (!pcbDirEntry) 2372 pcbDirEntry = &cbDirEntry; 2373 else 2374 { 2375 cbDirEntry = *pcbDirEntry; 2376 AssertMsgReturn(cbDirEntry >= RT_UOFFSETOF(RTDIRENTRYEX, szName[2]), 2377 ("Invalid *pcbDirEntry=%d (min %d)\n", *pcbDirEntry, RT_OFFSETOF(RTDIRENTRYEX, szName[2])), 2378 VERR_INVALID_PARAMETER); 2379 } 2380 2381 /* 2382 * Call the directory method. 2383 */ 2384 RTVfsLockAcquireRead(pThis->Base.hLock); 2385 int rc = pThis->pOps->pfnReadDir(pThis->Base.pvThis, pDirEntry, pcbDirEntry, enmAddAttr); 2386 RTVfsLockReleaseRead(pThis->Base.hLock); 2205 2387 return rc; 2206 2388 } … … 2893 3075 if (RT_SUCCESS(rc)) 2894 3076 { 2895 if (!pPath->fDirSlash) 3077 if ( !pPath->fDirSlash 3078 && pPath->cComponents > 0) 2896 3079 { 2897 3080 /* … … 2900 3083 */ 2901 3084 RTVFSDIRINTERNAL *pVfsParentDir; 2902 rc = rtVfsTraverseToParent(pThis, pPath, true /*fFollowSymlink*/, &pVfsParentDir);3085 rc = rtVfsTraverseToParent(pThis, pPath, RTPATH_F_FOLLOW_LINK, &pVfsParentDir); 2903 3086 if (RT_SUCCESS(rc)) 2904 3087 { … … 2920 3103 } 2921 3104 else 2922 rc = VERR_ INVALID_PARAMETER;3105 rc = VERR_NOT_A_FILE; 2923 3106 RTVfsParsePathFree(pPath); 2924 3107 } -
trunk/src/VBox/Runtime/common/vfs/vfschain.cpp
r66742 r66762 430 430 431 431 /** 432 * Duplicate a spec string. 432 * Checks if @a ch is a character that can be escaped. 433 * 434 * @returns true / false. 435 * @param ch The character to consider. 436 */ 437 DECLINLINE(bool) rtVfsChainSpecIsEscapableChar(char ch) 438 { 439 return ch == '(' 440 || ch == ')' 441 || ch == '{' 442 || ch == '}' 443 || ch == '\\' 444 || ch == ',' 445 || ch == '|' 446 || ch == ':'; 447 } 448 449 450 /** 451 * Duplicate a spec string after unescaping it. 433 452 * 434 453 * This differs from RTStrDupN in that it uses RTMemTmpAlloc instead of … … 462 481 { 463 482 char ch2 = psz[2]; 464 if ( ch2 == '(' || ch2 == ')' || ch2 == '\\' || ch2 == ',')483 if (rtVfsChainSpecIsEscapableChar(ch2)) 465 484 { 466 485 psz++; … … 589 608 590 609 /** 610 * Checks if @a psz is pointing to the final element specification. 611 * 612 * @returns true / false. 613 * @param psz Start of an element or path. 614 * @param pcch Where to return the length. 615 */ 616 static bool rtVfsChainSpecIsFinalElement(const char *psz, size_t *pcch) 617 { 618 size_t off = 0; 619 char ch; 620 while ((ch = psz[off]) != '\0') 621 { 622 if (ch == '|' || ch == ':') 623 return false; 624 if ( ch == '\\' 625 && rtVfsChainSpecIsEscapableChar(psz[off + 1])) 626 off++; 627 off++; 628 } 629 *pcch = off; 630 return off > 0; 631 } 632 633 634 /** 635 * Makes the final path element. 636 * @returns IPRT status code 637 * @param pElement The element. 638 * @param pszPath The path. 639 * @param cchPath The path length. 640 */ 641 static int rtVfsChainSpecMakeFinalPathElement(PRTVFSCHAINELEMSPEC pElement, const char *pszPath, size_t cchPath) 642 { 643 pElement->pszProvider = NULL; 644 pElement->enmType = RTVFSOBJTYPE_END; 645 pElement->cchSpec = (uint16_t)cchPath; 646 return rtVfsChainSpecElementAddArg(pElement, pszPath, cchPath, pElement->offSpec); 647 } 648 649 650 /** 591 651 * Finds the end of the argument string. 592 652 * … … 596 656 static size_t rtVfsChainSpecFindArgEnd(const char *psz) 597 657 { 598 char ch;599 658 size_t off = 0; 659 char ch; 600 660 while ( (ch = psz[off]) != '\0' 601 661 && ch != ',' 602 662 && ch != ')' 603 && ch != '(') 604 { 605 /* check for escape sequences. */ 663 && ch != '}') 664 { 606 665 if ( ch == '\\' 607 && (psz[off+1] == '(' || psz[off+1] == ')' || psz[off+1] == '\\' || psz[off+1] == ','))666 && rtVfsChainSpecIsEscapableChar(psz[off+1])) 608 667 off++; 609 668 off++; … … 674 733 675 734 /* 676 * First up is the VFS object type followed by a parentheses, 677 * or this could be the trailing action. 735 * First up is the VFS object type followed by a parenthesis/curly, or 736 * this could be the trailing action. Alternatively, we could have a 737 * final path-only element here. 678 738 */ 679 739 size_t cch; … … 694 754 else 695 755 { 696 if (*pszSrc == '\0') 756 if (rtVfsChainSpecIsFinalElement(pszSrc, &cch)) 757 rc = rtVfsChainSpecMakeFinalPathElement(pElement, pszSrc, cch); 758 else if (*pszSrc == '\0') 697 759 rc = VERR_VFS_CHAIN_TRAILING_SEPARATOR; 698 760 else … … 700 762 break; 701 763 } 702 pszSrc += cch; 703 704 /* Check and skip the parentheses. */ 705 if (*pszSrc != '(') 706 { 707 rc = VERR_VFS_CHAIN_EXPECTED_LEFT_PARENTHESES; 764 765 /* Check and skip past the parenthesis/curly. If not there, we might 766 have a final path element at our hands. */ 767 char const chOpenParen = pszSrc[cch]; 768 if (chOpenParen != '(' && chOpenParen != '{') 769 { 770 if (rtVfsChainSpecIsFinalElement(pszSrc, &cch)) 771 rc = rtVfsChainSpecMakeFinalPathElement(pElement, pszSrc, cch); 772 else 773 rc = VERR_VFS_CHAIN_EXPECTED_LEFT_PARENTHESES; 708 774 break; 709 775 } 710 pszSrc = RTStrStripL(pszSrc + 1);776 pszSrc = RTStrStripL(pszSrc + cch + 1); 711 777 712 778 /* … … 739 805 break; 740 806 741 /* Must end with a right parentheses . */742 if (*pszSrc != ')')807 /* Must end with a right parentheses/curly. */ 808 if (*pszSrc != (chOpenParen == '(' ? ')' : '}')) 743 809 { 744 810 rc = VERR_VFS_CHAIN_EXPECTED_RIGHT_PARENTHESES; … … 835 901 836 902 RTDECL(int) RTVfsChainSpecCheckAndSetup(PRTVFSCHAINSPEC pSpec, PCRTVFSCHAINSPEC pReuseSpec, 837 PRTVFSOBJ phVfsObj, uint32_t *poffError, PRTERRINFO pErrInfo)903 PRTVFSOBJ phVfsObj, const char **ppszFinalPath, uint32_t *poffError, PRTERRINFO pErrInfo) 838 904 { 839 905 AssertPtrReturn(poffError, VERR_INVALID_POINTER); … … 841 907 AssertPtrReturn(phVfsObj, VERR_INVALID_POINTER); 842 908 *phVfsObj = NIL_RTVFSOBJ; 909 AssertPtrReturn(ppszFinalPath, VERR_INVALID_POINTER); 910 *ppszFinalPath = NULL; 843 911 AssertPtrReturn(pSpec, VERR_INVALID_POINTER); 844 912 AssertPtrNullReturn(pErrInfo, VERR_INVALID_POINTER); 913 914 /* 915 * Check for final path-only component as we will not touch it yet. 916 */ 917 uint32_t cElements = pSpec->cElements; 918 if (cElements > 0) 919 { 920 if (pSpec->paElements[pSpec->cElements - 1].enmType == RTVFSOBJTYPE_END) 921 { 922 if (cElements > 1) 923 cElements--; 924 else 925 { 926 *ppszFinalPath = pSpec->paElements[0].paArgs[0].psz; 927 return VERR_VFS_CHAIN_PATH_ONLY; 928 } 929 } 930 } 931 else 932 return VERR_VFS_CHAIN_EMPTY; 845 933 846 934 /* … … 855 943 * Resolve and check each element first. 856 944 */ 857 for (uint32_t i = 0; i < pSpec->cElements; i++)945 for (uint32_t i = 0; i < cElements; i++) 858 946 { 859 947 PRTVFSCHAINELEMSPEC const pElement = &pSpec->paElements[i]; … … 876 964 if (RT_SUCCESS(rc)) 877 965 { 878 if (pSpec->cElements > 0) /* paranoia */879 {880 PRTVFSCHAINELEMSPEC const pLast = &pSpec->paElements[pSpec->cElements - 1];966 PRTVFSCHAINELEMSPEC const pLast = &pSpec->paElements[cElements - 1]; 967 if (cElements == pSpec->cElements) 968 { 881 969 if ( pLast->enmType == pSpec->enmDesiredType 970 || pSpec->enmDesiredType == RTVFSOBJTYPE_BASE 882 971 || ( pLast->enmType == RTVFSOBJTYPE_FILE 883 972 && pSpec->enmDesiredType == RTVFSOBJTYPE_IO_STREAM) ) … … 889 978 } 890 979 } 980 /* Ends with a path-only element, so check the type of the element preceding it. */ 981 else if ( pLast->enmType == RTVFSOBJTYPE_DIR 982 || pLast->enmType == RTVFSOBJTYPE_VFS 983 || pLast->enmType == RTVFSOBJTYPE_FS_STREAM) 984 rc = VINF_SUCCESS; 891 985 else 892 rc = VERR_VFS_CHAIN_EMPTY; 986 { 987 *poffError = pLast->offSpec; 988 rc = VERR_VFS_CHAIN_TYPE_MISMATCH_PATH_ONLY; 989 } 893 990 } 894 991 … … 899 996 */ 900 997 RTVFSOBJ hPrevVfsObj = NIL_RTVFSOBJ; /* No extra reference, kept in chain structure. */ 901 for (uint32_t i = 0; i < pSpec->cElements; i++)998 for (uint32_t i = 0; i < cElements; i++) 902 999 { 903 1000 PRTVFSCHAINELEMSPEC const pElement = &pSpec->paElements[i]; … … 956 1053 uint32_t cRefs = RTVfsObjRetain(hPrevVfsObj); 957 1054 AssertStmt(cRefs != UINT32_MAX, rc = VERR_VFS_CHAIN_IPE); 958 *phVfsObj = hPrevVfsObj; 1055 *phVfsObj = hPrevVfsObj; 1056 *ppszFinalPath = cElements == pSpec->cElements ? NULL : pSpec->paElements[cElements].paArgs[0].psz; 959 1057 } 960 1058 } … … 1009 1107 RTCritSectRwLeaveExcl(&g_rtVfsChainElementCritSect); 1010 1108 return rc; 1109 } 1110 1111 1112 RTDECL(int) RTVfsChainOpenDir(const char *pszSpec, uint32_t fOpen, 1113 PRTVFSDIR phVfsDir, uint32_t *poffError, PRTERRINFO pErrInfo) 1114 { 1115 uint32_t offErrorIgn; 1116 if (!poffError) 1117 poffError = &offErrorIgn; 1118 *poffError = 0; 1119 AssertPtrReturn(pszSpec, VERR_INVALID_POINTER); 1120 AssertReturn(*pszSpec != '\0', VERR_INVALID_PARAMETER); 1121 AssertPtrReturn(phVfsDir, VERR_INVALID_POINTER); 1122 AssertPtrNullReturn(pErrInfo, VERR_INVALID_POINTER); 1123 1124 /* 1125 * Try for a VFS chain first, falling back on regular file system stuff if it's just a path. 1126 */ 1127 int rc; 1128 PRTVFSCHAINSPEC pSpec = NULL; 1129 if (strncmp(pszSpec, RTVFSCHAIN_SPEC_PREFIX, sizeof(RTVFSCHAIN_SPEC_PREFIX) - 1) == 0) 1130 { 1131 rc = RTVfsChainSpecParse(pszSpec, 0 /*fFlags*/, RTVFSOBJTYPE_DIR, &pSpec, poffError); 1132 if (RT_FAILURE(rc)) 1133 return rc; 1134 1135 Assert(pSpec->cElements > 0); 1136 if ( pSpec->cElements > 1 1137 || pSpec->paElements[0].enmType != RTVFSOBJTYPE_END) 1138 { 1139 1140 const char *pszFinal = NULL; 1141 RTVFSOBJ hVfsObj = NIL_RTVFSOBJ; 1142 pSpec->fOpenFile = fOpen; 1143 rc = RTVfsChainSpecCheckAndSetup(pSpec, NULL /*pReuseSpec*/, &hVfsObj, &pszFinal, poffError, pErrInfo); 1144 if (RT_SUCCESS(rc)) 1145 { 1146 if (!pszFinal) 1147 { 1148 /* Try convert it to a file object and we're done. */ 1149 *phVfsDir = RTVfsObjToDir(hVfsObj); 1150 if (*phVfsDir) 1151 rc = VINF_SUCCESS; 1152 else 1153 rc = VERR_VFS_CHAIN_CAST_FAILED; 1154 } 1155 else 1156 { 1157 /* 1158 * Do a file open with the final path on the returned object. 1159 */ 1160 RTVFS hVfs = RTVfsObjToVfs(hVfsObj); 1161 RTVFSDIR hVfsDir = RTVfsObjToDir(hVfsObj); 1162 RTVFSFSSTREAM hVfsFss = RTVfsObjToFsStream(hVfsObj); 1163 if (hVfs != NIL_RTVFS) 1164 rc = RTVfsDirOpen(hVfs, pszFinal, fOpen, phVfsDir); 1165 else if (hVfsDir != NIL_RTVFSDIR) 1166 rc = RTVfsDirOpenDir(hVfsDir, pszFinal, fOpen, phVfsDir); 1167 else if (hVfsFss != NIL_RTVFSFSSTREAM) 1168 rc = VERR_NOT_IMPLEMENTED; 1169 else 1170 rc = VERR_VFS_CHAIN_TYPE_MISMATCH_PATH_ONLY; 1171 RTVfsRelease(hVfs); 1172 RTVfsDirRelease(hVfsDir); 1173 RTVfsFsStrmRelease(hVfsFss); 1174 } 1175 RTVfsObjRelease(hVfsObj); 1176 } 1177 1178 RTVfsChainSpecFree(pSpec); 1179 return rc; 1180 } 1181 1182 /* Only a path element. */ 1183 pszSpec = pSpec->paElements[0].paArgs[0].psz; 1184 } 1185 1186 /* 1187 * Path to regular file system. 1188 */ 1189 /** @todo implement system specific standard VFS directory class. */ 1190 rc = VERR_NOT_IMPLEMENTED; 1191 1192 RTVfsChainSpecFree(pSpec); 1193 return rc; 1194 1011 1195 } 1012 1196 … … 1025 1209 1026 1210 /* 1027 * If it's not a VFS chain spec, treat it as a file.1211 * Try for a VFS chain first, falling back on regular file system stuff if it's just a path. 1028 1212 */ 1029 1213 int rc; 1030 if (strncmp(pszSpec, RTVFSCHAIN_SPEC_PREFIX, sizeof(RTVFSCHAIN_SPEC_PREFIX) - 1)) 1031 { 1032 RTFILE hFile; 1033 rc = RTFileOpen(&hFile, pszSpec, fOpen); 1214 PRTVFSCHAINSPEC pSpec = NULL; 1215 if (strncmp(pszSpec, RTVFSCHAIN_SPEC_PREFIX, sizeof(RTVFSCHAIN_SPEC_PREFIX) - 1) == 0) 1216 { 1217 rc = RTVfsChainSpecParse(pszSpec, 0 /*fFlags*/, RTVFSOBJTYPE_FILE, &pSpec, poffError); 1218 if (RT_FAILURE(rc)) 1219 return rc; 1220 1221 Assert(pSpec->cElements > 0); 1222 if ( pSpec->cElements > 1 1223 || pSpec->paElements[0].enmType != RTVFSOBJTYPE_END) 1224 { 1225 1226 const char *pszFinal = NULL; 1227 RTVFSOBJ hVfsObj = NIL_RTVFSOBJ; 1228 pSpec->fOpenFile = fOpen; 1229 rc = RTVfsChainSpecCheckAndSetup(pSpec, NULL /*pReuseSpec*/, &hVfsObj, &pszFinal, poffError, pErrInfo); 1230 if (RT_SUCCESS(rc)) 1231 { 1232 if (!pszFinal) 1233 { 1234 /* Try convert it to a file object and we're done. */ 1235 *phVfsFile = RTVfsObjToFile(hVfsObj); 1236 if (*phVfsFile) 1237 rc = VINF_SUCCESS; 1238 else 1239 rc = VERR_VFS_CHAIN_CAST_FAILED; 1240 } 1241 else 1242 { 1243 /* 1244 * Do a file open with the final path on the returned object. 1245 */ 1246 RTVFS hVfs = RTVfsObjToVfs(hVfsObj); 1247 RTVFSDIR hVfsDir = RTVfsObjToDir(hVfsObj); 1248 RTVFSFSSTREAM hVfsFss = RTVfsObjToFsStream(hVfsObj); 1249 if (hVfs != NIL_RTVFS) 1250 rc = RTVfsFileOpen(hVfs, pszFinal, fOpen, phVfsFile); 1251 else if (hVfsDir != NIL_RTVFSDIR) 1252 rc = RTVfsDirOpenFile(hVfsDir, pszFinal, fOpen, phVfsFile); 1253 else if (hVfsFss != NIL_RTVFSFSSTREAM) 1254 rc = VERR_NOT_IMPLEMENTED; 1255 else 1256 rc = VERR_VFS_CHAIN_TYPE_MISMATCH_PATH_ONLY; 1257 RTVfsRelease(hVfs); 1258 RTVfsDirRelease(hVfsDir); 1259 RTVfsFsStrmRelease(hVfsFss); 1260 } 1261 RTVfsObjRelease(hVfsObj); 1262 } 1263 1264 RTVfsChainSpecFree(pSpec); 1265 return rc; 1266 } 1267 1268 /* Only a path element. */ 1269 pszSpec = pSpec->paElements[0].paArgs[0].psz; 1270 } 1271 1272 /* 1273 * Path to regular file system. 1274 */ 1275 RTFILE hFile; 1276 rc = RTFileOpen(&hFile, pszSpec, fOpen); 1277 if (RT_SUCCESS(rc)) 1278 { 1279 RTVFSFILE hVfsFile; 1280 rc = RTVfsFileFromRTFile(hFile, fOpen, false /*fLeaveOpen*/, &hVfsFile); 1034 1281 if (RT_SUCCESS(rc)) 1035 { 1036 RTVFSFILE hVfsFile; 1037 rc = RTVfsFileFromRTFile(hFile, fOpen, false /*fLeaveOpen*/, &hVfsFile); 1038 if (RT_SUCCESS(rc)) 1039 *phVfsFile = hVfsFile; 1040 else 1041 RTFileClose(hFile); 1042 } 1043 } 1044 else 1045 { 1046 PRTVFSCHAINSPEC pSpec; 1047 rc = RTVfsChainSpecParse(pszSpec, 0 /*fFlags*/, RTVFSOBJTYPE_FILE, &pSpec, poffError); 1048 if (RT_SUCCESS(rc)) 1049 { 1050 pSpec->fOpenFile = fOpen; 1051 1052 RTVFSOBJ hVfsObj = NIL_RTVFSOBJ; 1053 rc = RTVfsChainSpecCheckAndSetup(pSpec, NULL /*pReuseSpec*/, &hVfsObj, poffError, pErrInfo); 1054 if (RT_SUCCESS(rc)) 1055 { 1056 *phVfsFile = RTVfsObjToFile(hVfsObj); 1057 if (*phVfsFile) 1058 rc = VINF_SUCCESS; 1059 else 1060 rc = VERR_VFS_CHAIN_CAST_FAILED; 1061 RTVfsObjRelease(hVfsObj); 1062 } 1063 1064 RTVfsChainSpecFree(pSpec); 1065 } 1066 } 1282 *phVfsFile = hVfsFile; 1283 else 1284 RTFileClose(hFile); 1285 } 1286 1287 RTVfsChainSpecFree(pSpec); 1067 1288 return rc; 1068 1289 } … … 1082 1303 1083 1304 /* 1084 * If it's not a VFS chain spec, treat it as a file.1305 * Try for a VFS chain first, falling back on regular file system stuff if it's just a path. 1085 1306 */ 1086 1307 int rc; 1087 if (strncmp(pszSpec, RTVFSCHAIN_SPEC_PREFIX, sizeof(RTVFSCHAIN_SPEC_PREFIX) - 1)) 1088 { 1089 RTFILE hFile; 1090 rc = RTFileOpen(&hFile, pszSpec, fOpen); 1308 PRTVFSCHAINSPEC pSpec = NULL; 1309 if (strncmp(pszSpec, RTVFSCHAIN_SPEC_PREFIX, sizeof(RTVFSCHAIN_SPEC_PREFIX) - 1) == 0) 1310 { 1311 rc = RTVfsChainSpecParse(pszSpec, 0 /*fFlags*/, RTVFSOBJTYPE_IO_STREAM, &pSpec, poffError); 1312 if (RT_FAILURE(rc)) 1313 return rc; 1314 1315 Assert(pSpec->cElements > 0); 1316 if ( pSpec->cElements > 1 1317 || pSpec->paElements[0].enmType != RTVFSOBJTYPE_END) 1318 { 1319 1320 const char *pszFinal = NULL; 1321 RTVFSOBJ hVfsObj = NIL_RTVFSOBJ; 1322 pSpec->fOpenFile = fOpen; 1323 rc = RTVfsChainSpecCheckAndSetup(pSpec, NULL /*pReuseSpec*/, &hVfsObj, &pszFinal, poffError, pErrInfo); 1324 if (RT_SUCCESS(rc)) 1325 { 1326 if (!pszFinal) 1327 { 1328 /* Try convert it to an I/O object and we're done. */ 1329 *phVfsIos = RTVfsObjToIoStream(hVfsObj); 1330 if (*phVfsIos) 1331 rc = VINF_SUCCESS; 1332 else 1333 rc = VERR_VFS_CHAIN_CAST_FAILED; 1334 } 1335 else 1336 { 1337 /* 1338 * Do a file open with the final path on the returned object. 1339 */ 1340 RTVFS hVfs = RTVfsObjToVfs(hVfsObj); 1341 RTVFSDIR hVfsDir = RTVfsObjToDir(hVfsObj); 1342 RTVFSFSSTREAM hVfsFss = RTVfsObjToFsStream(hVfsObj); 1343 RTVFSFILE hVfsFile = NIL_RTVFSFILE; 1344 if (hVfs != NIL_RTVFS) 1345 rc = RTVfsFileOpen(hVfs, pszFinal, fOpen, &hVfsFile); 1346 else if (hVfsDir != NIL_RTVFSDIR) 1347 rc = RTVfsDirOpenFile(hVfsDir, pszFinal, fOpen, &hVfsFile); 1348 else if (hVfsFss != NIL_RTVFSFSSTREAM) 1349 rc = VERR_NOT_IMPLEMENTED; 1350 else 1351 rc = VERR_VFS_CHAIN_TYPE_MISMATCH_PATH_ONLY; 1352 if (RT_SUCCESS(rc)) 1353 { 1354 *phVfsIos = RTVfsFileToIoStream(hVfsFile); 1355 if (*phVfsIos) 1356 rc = VINF_SUCCESS; 1357 else 1358 rc = VERR_VFS_CHAIN_CAST_FAILED; 1359 RTVfsFileRelease(hVfsFile); 1360 } 1361 RTVfsRelease(hVfs); 1362 RTVfsDirRelease(hVfsDir); 1363 RTVfsFsStrmRelease(hVfsFss); 1364 } 1365 RTVfsObjRelease(hVfsObj); 1366 } 1367 1368 RTVfsChainSpecFree(pSpec); 1369 return rc; 1370 } 1371 1372 /* Only a path element. */ 1373 pszSpec = pSpec->paElements[0].paArgs[0].psz; 1374 } 1375 1376 /* 1377 * Path to regular file system. 1378 */ 1379 RTFILE hFile; 1380 rc = RTFileOpen(&hFile, pszSpec, fOpen); 1381 if (RT_SUCCESS(rc)) 1382 { 1383 RTVFSFILE hVfsFile; 1384 rc = RTVfsFileFromRTFile(hFile, fOpen, false /*fLeaveOpen*/, &hVfsFile); 1091 1385 if (RT_SUCCESS(rc)) 1092 1386 { 1093 RTVFSFILE hVfsFile; 1094 rc = RTVfsFileFromRTFile(hFile, fOpen, false /*fLeaveOpen*/, &hVfsFile); 1387 *phVfsIos = RTVfsFileToIoStream(hVfsFile); 1388 RTVfsFileRelease(hVfsFile); 1389 } 1390 else 1391 RTFileClose(hFile); 1392 } 1393 1394 RTVfsChainSpecFree(pSpec); 1395 return rc; 1396 } 1397 1398 1399 /** 1400 * The equivalent of RTPathQueryInfoEx 1401 */ 1402 RTDECL(int) RTVfsChainQueryInfo(const char *pszSpec, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs, 1403 uint32_t fFlags, uint32_t *poffError, PRTERRINFO pErrInfo) 1404 { 1405 uint32_t offErrorIgn; 1406 if (!poffError) 1407 poffError = &offErrorIgn; 1408 *poffError = 0; 1409 AssertPtrReturn(pszSpec, VERR_INVALID_POINTER); 1410 AssertReturn(*pszSpec != '\0', VERR_INVALID_PARAMETER); 1411 AssertPtrReturn(pObjInfo, VERR_INVALID_POINTER); 1412 AssertReturn(enmAdditionalAttribs >= RTFSOBJATTRADD_NOTHING && enmAdditionalAttribs <= RTFSOBJATTRADD_LAST, 1413 VERR_INVALID_PARAMETER); 1414 AssertPtrNullReturn(pErrInfo, VERR_INVALID_POINTER); 1415 1416 /* 1417 * Try for a VFS chain first, falling back on regular file system stuff if it's just a path. 1418 */ 1419 int rc; 1420 PRTVFSCHAINSPEC pSpec = NULL; 1421 if (strncmp(pszSpec, RTVFSCHAIN_SPEC_PREFIX, sizeof(RTVFSCHAIN_SPEC_PREFIX) - 1) == 0) 1422 { 1423 rc = RTVfsChainSpecParse(pszSpec, 0 /*fFlags*/, RTVFSOBJTYPE_BASE, &pSpec, poffError); 1424 if (RT_FAILURE(rc)) 1425 return rc; 1426 1427 Assert(pSpec->cElements > 0); 1428 if ( pSpec->cElements > 1 1429 || pSpec->paElements[0].enmType != RTVFSOBJTYPE_END) 1430 { 1431 1432 const char *pszFinal = NULL; 1433 RTVFSOBJ hVfsObj = NIL_RTVFSOBJ; 1434 pSpec->fOpenFile = RTFILE_O_READ | RTFILE_O_OPEN; 1435 rc = RTVfsChainSpecCheckAndSetup(pSpec, NULL /*pReuseSpec*/, &hVfsObj, &pszFinal, poffError, pErrInfo); 1095 1436 if (RT_SUCCESS(rc)) 1096 1437 { 1097 *phVfsIos = RTVfsFileToIoStream(hVfsFile); 1098 RTVfsFileRelease(hVfsFile); 1099 } 1100 else 1101 RTFileClose(hFile); 1102 } 1103 } 1104 /* 1105 * Do the chain thing. 1106 */ 1107 else 1108 { 1109 PRTVFSCHAINSPEC pSpec; 1110 rc = RTVfsChainSpecParse(pszSpec, 0 /*fFlags*/, RTVFSOBJTYPE_IO_STREAM, &pSpec, poffError); 1111 if (RT_SUCCESS(rc)) 1112 { 1113 pSpec->fOpenFile = fOpen; 1114 1115 RTVFSOBJ hVfsObj = NIL_RTVFSOBJ; 1116 rc = RTVfsChainSpecCheckAndSetup(pSpec, NULL /*pReuseSpec*/, &hVfsObj, poffError, pErrInfo); 1117 if (RT_SUCCESS(rc)) 1118 { 1119 *phVfsIos = RTVfsObjToIoStream(hVfsObj); 1120 if (*phVfsIos) 1121 rc = VINF_SUCCESS; 1438 if (!pszFinal) 1439 { 1440 /* 1441 * Do the job on the final object. 1442 */ 1443 rc = RTVfsObjQueryInfo(hVfsObj, pObjInfo, enmAdditionalAttribs); 1444 } 1122 1445 else 1123 rc = VERR_VFS_CHAIN_CAST_FAILED; 1446 { 1447 /* 1448 * Do a path query operation on the penultimate object. 1449 */ 1450 RTVFS hVfs = RTVfsObjToVfs(hVfsObj); 1451 RTVFSDIR hVfsDir = RTVfsObjToDir(hVfsObj); 1452 RTVFSFSSTREAM hVfsFss = RTVfsObjToFsStream(hVfsObj); 1453 if (hVfs != NIL_RTVFS) 1454 rc = RTVfsQueryPathInfo(hVfs, pszFinal, pObjInfo, enmAdditionalAttribs, fFlags); 1455 else if (hVfsDir != NIL_RTVFSDIR) 1456 rc = RTVfsDirQueryPathInfo(hVfsDir, pszFinal, pObjInfo, enmAdditionalAttribs, fFlags); 1457 else if (hVfsFss != NIL_RTVFSFSSTREAM) 1458 rc = VERR_NOT_SUPPORTED; 1459 else 1460 rc = VERR_VFS_CHAIN_TYPE_MISMATCH_PATH_ONLY; 1461 RTVfsRelease(hVfs); 1462 RTVfsDirRelease(hVfsDir); 1463 RTVfsFsStrmRelease(hVfsFss); 1464 } 1124 1465 RTVfsObjRelease(hVfsObj); 1125 1466 } 1467 1126 1468 RTVfsChainSpecFree(pSpec); 1127 } 1128 } 1469 return rc; 1470 } 1471 1472 /* Only a path element. */ 1473 pszSpec = pSpec->paElements[0].paArgs[0].psz; 1474 } 1475 1476 /* 1477 * Path to regular file system. 1478 */ 1479 rc = RTPathQueryInfoEx(pszSpec, pObjInfo, enmAdditionalAttribs, fFlags); 1480 1481 RTVfsChainSpecFree(pSpec); 1129 1482 return rc; 1130 1483 } 1131 1132 1484 1133 1485
Note:
See TracChangeset
for help on using the changeset viewer.