VirtualBox

Ignore:
Timestamp:
May 3, 2017 10:20:16 PM (8 years ago)
Author:
vboxsync
Message:

iprt: More vfs bits.

Location:
trunk/src/VBox/Runtime/common/vfs
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/common/vfs/vfsbase.cpp

    r66742 r66762  
    14291429 * @param   pPath           The parsed path.  This may be changed as symbolic
    14301430 *                          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.
    14331432 * @param   ppVfsParentDir  Where to return the parent directory handle
    14341433 *                          (referenced).
    14351434 */
    1436 static int rtVfsDirTraverseToParent(RTVFSDIRINTERNAL *pThis, PRTVFSPARSEDPATH pPath, bool fFollowSymlink,
     1435static int rtVfsDirTraverseToParent(RTVFSDIRINTERNAL *pThis, PRTVFSPARSEDPATH pPath, uint32_t fFlags,
    14371436                                    RTVFSDIRINTERNAL **ppVfsParentDir)
    14381437{
     
    14471446    *ppVfsParentDir = NULL;
    14481447    AssertReturn(pPath->cComponents > 0, VERR_INTERNAL_ERROR_3);
     1448    Assert(RTPATH_F_IS_VALID(fFlags, 0));
    14491449
    14501450    /*
     
    14671467         */
    14681468        bool fFinal = iComponent + 1 >= pPath->cComponents;
    1469         if (fFinal && !fFollowSymlink)
     1469        if (fFinal && (fFlags & RTPATH_F_ON_LINK))
    14701470        {
    14711471            *ppVfsParentDir = pCurDir;
     
    15391539            AssertPtr(hSymlink);
    15401540            Assert(hSymlink->uMagic == RTVFSSYMLINK_MAGIC);
     1541            if (fFlags & RTPATH_F_NO_SYMLINKS)
     1542            {
     1543                rc = VERR_SYMLINK_NOT_ALLOWED;
     1544                break;
     1545            }
    15411546            cLinks++;
    15421547            if (cLinks >= RTVFS_MAX_LINKS)
     
    15961601 * @param   pPath           The parsed path.  This may be changed as symbolic
    15971602 *                          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.
    16001604 * @param   ppVfsParentDir  Where to return the parent directory handle
    16011605 *                          (referenced).
    16021606 */
    1603 static int rtVfsTraverseToParent(RTVFSINTERNAL *pThis, PRTVFSPARSEDPATH pPath, bool fFollowSymlink,
    1604                                  RTVFSDIRINTERNAL **ppVfsParentDir)
     1607static int rtVfsTraverseToParent(RTVFSINTERNAL *pThis, PRTVFSPARSEDPATH pPath, uint32_t fFlags, RTVFSDIRINTERNAL **ppVfsParentDir)
    16051608{
    16061609    /*
     
    16141617    *ppVfsParentDir = NULL;
    16151618    AssertReturn(pPath->cComponents > 0, VERR_INTERNAL_ERROR_3);
     1619    Assert(RTPATH_F_IS_VALID(fFlags, 0));
    16161620
    16171621    /*
     
    16251629    if (RT_SUCCESS(rc))
    16261630    {
    1627         rc = rtVfsDirTraverseToParent(pRootDir, pPath, fFollowSymlink, ppVfsParentDir);
     1631        rc = rtVfsDirTraverseToParent(pRootDir, pPath, fFlags, ppVfsParentDir);
    16281632        RTVfsDirRelease(pRootDir);
    16291633    }
     
    18201824
    18211825
     1826RTDECL(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
    18221887
    18231888RTDECL(int) RTVfsIsRangeInUse(RTVFS hVfs, uint64_t off, size_t cb, bool *pfUsed)
     
    20732138    if (RT_SUCCESS(rc))
    20742139    {
    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);
    20922148            if (RT_SUCCESS(rc))
    20932149            {
    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                }
    20962164            }
     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);
    20972174        }
    20982175        RTVfsParsePathFree(pPath);
     
    21212198    if (RT_SUCCESS(rc))
    21222199    {
    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);
    21402208            if (RT_SUCCESS(rc))
    21412209            {
    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                }
    21442224            }
     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);
    21452236        }
    21462237        RTVfsParsePathFree(pPath);
     
    21732264    if (RT_SUCCESS(rc))
    21742265    {
    2175         if (!pPath->fDirSlash)
     2266        if (   !pPath->fDirSlash
     2267            && pPath->cComponents > 0)
    21762268        {
    21772269            /*
     
    21802272             */
    21812273            RTVFSDIRINTERNAL *pVfsParentDir;
    2182             rc = rtVfsDirTraverseToParent(pThis, pPath, true /*fFollowSymlink*/, &pVfsParentDir);
     2274            rc = rtVfsDirTraverseToParent(pThis, pPath, RTPATH_F_FOLLOW_LINK, &pVfsParentDir);
    21832275            if (RT_SUCCESS(rc))
    21842276            {
     
    22002292        }
    22012293        else
    2202             rc = VERR_INVALID_PARAMETER;
     2294            rc = VERR_NOT_A_FILE;
    22032295        RTVfsParsePathFree(pPath);
    22042296    }
     2297    return rc;
     2298}
     2299
     2300
     2301RTDECL(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
     2359RTDECL(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);
    22052387    return rc;
    22062388}
     
    28933075    if (RT_SUCCESS(rc))
    28943076    {
    2895         if (!pPath->fDirSlash)
     3077        if (   !pPath->fDirSlash
     3078            && pPath->cComponents > 0)
    28963079        {
    28973080            /*
     
    29003083             */
    29013084            RTVFSDIRINTERNAL *pVfsParentDir;
    2902             rc = rtVfsTraverseToParent(pThis, pPath, true /*fFollowSymlink*/, &pVfsParentDir);
     3085            rc = rtVfsTraverseToParent(pThis, pPath, RTPATH_F_FOLLOW_LINK, &pVfsParentDir);
    29033086            if (RT_SUCCESS(rc))
    29043087            {
     
    29203103        }
    29213104        else
    2922             rc = VERR_INVALID_PARAMETER;
     3105            rc = VERR_NOT_A_FILE;
    29233106        RTVfsParsePathFree(pPath);
    29243107    }
  • trunk/src/VBox/Runtime/common/vfs/vfschain.cpp

    r66742 r66762  
    430430
    431431/**
    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 */
     437DECLINLINE(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.
    433452 *
    434453 * This differs from RTStrDupN in that it uses RTMemTmpAlloc instead of
     
    462481                {
    463482                    char ch2 = psz[2];
    464                     if (ch2 == '(' || ch2 == ')' || ch2 == '\\' || ch2 == ',')
     483                    if (rtVfsChainSpecIsEscapableChar(ch2))
    465484                    {
    466485                        psz++;
     
    589608
    590609/**
     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 */
     616static 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 */
     641static 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/**
    591651 * Finds the end of the argument string.
    592652 *
     
    596656static size_t rtVfsChainSpecFindArgEnd(const char *psz)
    597657{
    598     char ch;
    599658    size_t off = 0;
     659    char   ch;
    600660    while (  (ch = psz[off]) != '\0'
    601661           && ch != ','
    602662           && ch != ')'
    603            && ch != '(')
    604     {
    605         /* check for escape sequences. */
     663           && ch != '}')
     664    {
    606665        if (   ch == '\\'
    607             && (psz[off+1] == '(' || psz[off+1] == ')' || psz[off+1] == '\\' || psz[off+1] == ','))
     666            && rtVfsChainSpecIsEscapableChar(psz[off+1]))
    608667            off++;
    609668        off++;
     
    674733
    675734        /*
    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.
    678738         */
    679739        size_t cch;
     
    694754        else
    695755        {
    696             if (*pszSrc == '\0')
     756            if (rtVfsChainSpecIsFinalElement(pszSrc, &cch))
     757                rc = rtVfsChainSpecMakeFinalPathElement(pElement, pszSrc, cch);
     758            else if (*pszSrc == '\0')
    697759                rc = VERR_VFS_CHAIN_TRAILING_SEPARATOR;
    698760            else
     
    700762            break;
    701763        }
    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;
    708774            break;
    709775        }
    710         pszSrc = RTStrStripL(pszSrc + 1);
     776        pszSrc = RTStrStripL(pszSrc + cch + 1);
    711777
    712778        /*
     
    739805            break;
    740806
    741         /* Must end with a right parentheses. */
    742         if (*pszSrc != ')')
     807        /* Must end with a right parentheses/curly. */
     808        if (*pszSrc != (chOpenParen == '(' ? ')' : '}'))
    743809        {
    744810            rc = VERR_VFS_CHAIN_EXPECTED_RIGHT_PARENTHESES;
     
    835901
    836902RTDECL(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)
    838904{
    839905    AssertPtrReturn(poffError, VERR_INVALID_POINTER);
     
    841907    AssertPtrReturn(phVfsObj, VERR_INVALID_POINTER);
    842908    *phVfsObj = NIL_RTVFSOBJ;
     909    AssertPtrReturn(ppszFinalPath, VERR_INVALID_POINTER);
     910    *ppszFinalPath = NULL;
    843911    AssertPtrReturn(pSpec, VERR_INVALID_POINTER);
    844912    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;
    845933
    846934    /*
     
    855943         * Resolve and check each element first.
    856944         */
    857         for (uint32_t i = 0; i < pSpec->cElements; i++)
     945        for (uint32_t i = 0; i < cElements; i++)
    858946        {
    859947            PRTVFSCHAINELEMSPEC const pElement = &pSpec->paElements[i];
     
    876964        if (RT_SUCCESS(rc))
    877965        {
    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            {
    881969                if (   pLast->enmType == pSpec->enmDesiredType
     970                    || pSpec->enmDesiredType == RTVFSOBJTYPE_BASE
    882971                    || (   pLast->enmType == RTVFSOBJTYPE_FILE
    883972                        && pSpec->enmDesiredType == RTVFSOBJTYPE_IO_STREAM) )
     
    889978                }
    890979            }
     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;
    891985            else
    892                 rc = VERR_VFS_CHAIN_EMPTY;
     986            {
     987                *poffError = pLast->offSpec;
     988                rc = VERR_VFS_CHAIN_TYPE_MISMATCH_PATH_ONLY;
     989            }
    893990        }
    894991
     
    899996             */
    900997            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++)
    902999            {
    9031000                PRTVFSCHAINELEMSPEC const pElement = &pSpec->paElements[i];
     
    9561053                uint32_t cRefs = RTVfsObjRetain(hPrevVfsObj);
    9571054                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;
    9591057            }
    9601058        }
     
    10091107        RTCritSectRwLeaveExcl(&g_rtVfsChainElementCritSect);
    10101108    return rc;
     1109}
     1110
     1111
     1112RTDECL(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
    10111195}
    10121196
     
    10251209
    10261210    /*
    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.
    10281212     */
    10291213    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);
    10341281        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);
    10671288    return rc;
    10681289}
     
    10821303
    10831304    /*
    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.
    10851306     */
    10861307    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);
    10911385        if (RT_SUCCESS(rc))
    10921386        {
    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 */
     1402RTDECL(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);
    10951436            if (RT_SUCCESS(rc))
    10961437            {
    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                }
    11221445                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                }
    11241465                RTVfsObjRelease(hVfsObj);
    11251466            }
     1467
    11261468            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);
    11291482    return rc;
    11301483}
    1131 
    11321484
    11331485
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