Exemplo n.º 1
0
/**
 * Recursive worker for rtDbgSymCacheAddDir, for minimal stack wasting.
 *
 * @returns IPRT status code (fully bitched).
 * @param   pszPath             Pointer to a RTPATH_MAX size buffer containing
 *                              the path to the current directory ending with a
 *                              slash.
 * @param   cchPath             The size of the current directory path.
 * @param   pDirEntry           Pointer to the RTDIRENTRYEX structure to use.
 * @param   pCfg                The configuration.
 */
static int rtDbgSymCacheAddDirWorker(char *pszPath, size_t cchPath, PRTDIRENTRYEX pDirEntry, PCRTDBGSYMCACHEADDCFG pCfg)
{
    /*
     * Open the directory.
     */
    PRTDIR pDir;
    int rc, rc2;
    if (pCfg->pszFilter)
    {
        rc = RTStrCopy(&pszPath[cchPath], RTPATH_MAX - cchPath, pCfg->pszFilter);
        if (RT_FAILURE(rc))
        {
            pszPath[cchPath] = '\0';
            return RTMsgErrorRc(rc, "Filename too long (%Rrc): '%s" RTPATH_SLASH_STR "%s'", rc, pszPath, pCfg->pszFilter);
        }
        rc = RTDirOpenFiltered(&pDir, pszPath, RTDIRFILTER_WINNT, 0 /*fFlags*/);
    }
    else
        rc = RTDirOpen(&pDir, pszPath);
    if (RT_FAILURE(rc))
        return RTMsgErrorRc(rc, "RTDirOpen%s failed on '%s': %Rrc", pCfg->pszFilter ? "Filtered" : "", pszPath, rc);

    /*
     * Enumerate the files.
     */
    for (;;)
    {
        rc2 = RTDirReadEx(pDir, pDirEntry, NULL, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK);
        if (RT_FAILURE(rc2))
        {
            pszPath[cchPath] = '\0';
            if (rc2 != VERR_NO_MORE_FILES)
            {
                RTMsgError("RTDirReadEx failed in '%s': %Rrc\n", pszPath, rc2);
                rc = rc2;
            }
            break;
        }

        /* Skip dot and dot-dot. */
        if (RTDirEntryExIsStdDotLink(pDirEntry))
            continue;

        /* Construct a full path. */
        rc = RTStrCopy(&pszPath[cchPath], RTPATH_MAX, pDirEntry->szName);
        if (RT_FAILURE(rc))
        {
            pszPath[cchPath] = '\0';
            RTMsgError("File name too long in '%s': '%s' (%Rrc)", pszPath, pDirEntry->szName, rc);
            break;
        }

        switch (rtDbgSymCacheFigureType2(pszPath, &pDirEntry->Info))
        {
            case RTDBGSYMCACHEFILETYPE_DIR:
                if (!pCfg->fRecursive)
                    RTMsgInfo("Skipping directory '%s'...", pszPath);
                else
                {
                    if (cchPath + pDirEntry->cbName + 3 <= RTPATH_MAX)
                    {
                        pszPath[cchPath + pDirEntry->cbName] = RTPATH_SLASH;
                        pszPath[cchPath + pDirEntry->cbName + 1] = '\0';
                        rc2 = rtDbgSymCacheAddDirWorker(pszPath, cchPath + pDirEntry->cbName + 1, pDirEntry, pCfg);
                    }
                    else
                    {
                        RTMsgError("File name too long in '%s': '%s' (%Rrc)", pszPath, pDirEntry->szName, rc);
                        rc2 = VERR_FILENAME_TOO_LONG;
                    }
                }
                break;

            case RTDBGSYMCACHEFILETYPE_DEBUG_FILE:
                rc2 = rtDbgSymCacheAddDebugFile(pszPath, pCfg);
                break;

            case RTDBGSYMCACHEFILETYPE_IMAGE_FILE:
                rc2 = rtDbgSymCacheAddImageFile(pszPath, NULL /*pszExtraSuff*/, RTDBG_CACHE_UUID_MAP_DIR_IMAGES, pCfg);
                break;

            case RTDBGSYMCACHEFILETYPE_DEBUG_BUNDLE:
                rc2 = rtDbgSymCacheAddDebugBundle(pszPath, cchPath, pDirEntry->cbName, pCfg);
                break;

            case RTDBGSYMCACHEFILETYPE_IMAGE_BUNDLE:
                rc2 = rtDbgSymCacheAddImageBundle(pszPath, cchPath, pDirEntry->cbName, pDirEntry, pCfg);
                break;

            case RTDBGSYMCACHEFILETYPE_DIR_FILTER:
            case RTDBGSYMCACHEFILETYPE_INVALID:
                rc2 = RTMsgErrorRc(VERR_INTERNAL_ERROR_2, "Invalid: '%s'", pszPath);
                break;

            case RTDBGSYMCACHEFILETYPE_IGNORE:
                rc2 = VINF_SUCCESS;
                break;
        }

        if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
            rc = rc2;
    }

    /*
     * Clean up.
     */
    rc2 = RTDirClose(pDir);
    if (RT_FAILURE(rc2))
    {
        RTMsgError("RTDirClose failed in '%s': %Rrc", pszPath, rc);
        rc = rc2;
    }
    return rc;
}
Exemplo n.º 2
0
int main(int argc, char **argv)
{
    int rcRet = 0;
    RTR3InitExe(argc, &argv, 0);

    /*
     * Iterate arguments.
     */
    bool fLong = false;
    bool fShortName = false;
    for (int i = 1; i < argc; i++)
    {
        if (argv[i][0] == '-')
        {
            for (int j = 1; argv[i][j]; j++)
            {
                switch (argv[i][j])
                {
                    case 'l':
                        fLong = true;
                        break;
                    case 's':
                        fShortName = true;
                        break;
                    default:
                        RTPrintf("Unknown option '%c' ignored!\n", argv[i][j]);
                        break;
                }
            }
        }
        else
        {
            /* open */
            PRTDIR pDir;
            int rc = RTDirOpen(&pDir, argv[i]);
            if (RT_SUCCESS(rc))
            {
                /* list */
                if (!fLong)
                {
                    for (;;)
                    {
                        RTDIRENTRY DirEntry;
                        rc = RTDirRead(pDir, &DirEntry, NULL);
                        if (RT_FAILURE(rc))
                            break;
                        switch (DirEntry.enmType)
                        {
                            case RTDIRENTRYTYPE_UNKNOWN:     RTPrintf("u"); break;
                            case RTDIRENTRYTYPE_FIFO:        RTPrintf("f"); break;
                            case RTDIRENTRYTYPE_DEV_CHAR:    RTPrintf("c"); break;
                            case RTDIRENTRYTYPE_DIRECTORY:   RTPrintf("d"); break;
                            case RTDIRENTRYTYPE_DEV_BLOCK:   RTPrintf("b"); break;
                            case RTDIRENTRYTYPE_FILE:        RTPrintf("-"); break;
                            case RTDIRENTRYTYPE_SYMLINK:     RTPrintf("l"); break;
                            case RTDIRENTRYTYPE_SOCKET:      RTPrintf("s"); break;
                            case RTDIRENTRYTYPE_WHITEOUT:    RTPrintf("w"); break;
                            default:
                                rcRet = 1;
                                RTPrintf("?");
                                break;
                        }
                        RTPrintf(" %#18llx  %3d %s\n", (uint64_t)DirEntry.INodeId,
                                 DirEntry.cbName, DirEntry.szName);
                    }
                }
                else
                {
                    for (;;)
                    {
                        RTDIRENTRYEX DirEntry;
                        rc = RTDirReadEx(pDir, &DirEntry, NULL, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK);
                        if (RT_FAILURE(rc))
                            break;

                        RTFMODE fMode = DirEntry.Info.Attr.fMode;
                        switch (fMode & RTFS_TYPE_MASK)
                        {
                            case RTFS_TYPE_FIFO:        RTPrintf("f"); break;
                            case RTFS_TYPE_DEV_CHAR:    RTPrintf("c"); break;
                            case RTFS_TYPE_DIRECTORY:   RTPrintf("d"); break;
                            case RTFS_TYPE_DEV_BLOCK:   RTPrintf("b"); break;
                            case RTFS_TYPE_FILE:        RTPrintf("-"); break;
                            case RTFS_TYPE_SYMLINK:     RTPrintf("l"); break;
                            case RTFS_TYPE_SOCKET:      RTPrintf("s"); break;
                            case RTFS_TYPE_WHITEOUT:    RTPrintf("w"); break;
                            default:
                                rcRet = 1;
                                RTPrintf("?");
                                break;
                        }
                        /** @todo sticy bits++ */
                        RTPrintf("%c%c%c",
                                 fMode & RTFS_UNIX_IRUSR ? 'r' : '-',
                                 fMode & RTFS_UNIX_IWUSR ? 'w' : '-',
                                 fMode & RTFS_UNIX_IXUSR ? 'x' : '-');
                        RTPrintf("%c%c%c",
                                 fMode & RTFS_UNIX_IRGRP ? 'r' : '-',
                                 fMode & RTFS_UNIX_IWGRP ? 'w' : '-',
                                 fMode & RTFS_UNIX_IXGRP ? 'x' : '-');
                        RTPrintf("%c%c%c",
                                 fMode & RTFS_UNIX_IROTH ? 'r' : '-',
                                 fMode & RTFS_UNIX_IWOTH ? 'w' : '-',
                                 fMode & RTFS_UNIX_IXOTH ? 'x' : '-');
                        RTPrintf(" %c%c%c%c%c%c%c%c%c%c%c%c%c%c",
                                 fMode & RTFS_DOS_READONLY          ? 'R' : '-',
                                 fMode & RTFS_DOS_HIDDEN            ? 'H' : '-',
                                 fMode & RTFS_DOS_SYSTEM            ? 'S' : '-',
                                 fMode & RTFS_DOS_DIRECTORY         ? 'D' : '-',
                                 fMode & RTFS_DOS_ARCHIVED          ? 'A' : '-',
                                 fMode & RTFS_DOS_NT_DEVICE         ? 'd' : '-',
                                 fMode & RTFS_DOS_NT_NORMAL         ? 'N' : '-',
                                 fMode & RTFS_DOS_NT_TEMPORARY      ? 'T' : '-',
                                 fMode & RTFS_DOS_NT_SPARSE_FILE    ? 'P' : '-',
                                 fMode & RTFS_DOS_NT_REPARSE_POINT  ? 'J' : '-',
                                 fMode & RTFS_DOS_NT_COMPRESSED     ? 'C' : '-',
                                 fMode & RTFS_DOS_NT_OFFLINE        ? 'O' : '-',
                                 fMode & RTFS_DOS_NT_NOT_CONTENT_INDEXED ? 'I' : '-',
                                 fMode & RTFS_DOS_NT_ENCRYPTED      ? 'E' : '-');
                        RTPrintf(" %d %4d %4d %10lld %10lld %#llx %#llx %#llx %#llx",
                                 DirEntry.Info.Attr.u.Unix.cHardlinks,
                                 DirEntry.Info.Attr.u.Unix.uid,
                                 DirEntry.Info.Attr.u.Unix.gid,
                                 DirEntry.Info.cbObject,
                                 DirEntry.Info.cbAllocated,
                                 DirEntry.Info.BirthTime,
                                 DirEntry.Info.ChangeTime,
                                 DirEntry.Info.ModificationTime,
                                 DirEntry.Info.AccessTime);
                        if (fShortName && DirEntry.cwcShortName)
                            RTPrintf(" %2d %ls\n", DirEntry.cwcShortName, DirEntry.wszShortName);
                        else
                            RTPrintf(" %2d %s\n", DirEntry.cbName, DirEntry.szName);
                        if (rc != VINF_SUCCESS)
                            RTPrintf("^^ %Rrc\n", rc);
                    }
                }

                if (rc != VERR_NO_MORE_FILES)
                {
                    RTPrintf("tstDir: Enumeration failed! rc=%Rrc\n", rc);
                    rcRet = 1;
                }

                /* close up */
                rc = RTDirClose(pDir);
                if (RT_FAILURE(rc))
                {
                    RTPrintf("tstDir: Failed to close dir! rc=%Rrc\n", rc);
                    rcRet = 1;
                }
            }
            else
            {
                RTPrintf("tstDir: Failed to open '%s', rc=%Rrc\n", argv[i], rc);
                rcRet = 1;
            }
        }
    }

    return rcRet;
}
/**
 * Corrects the casing of the final component
 *
 * @returns
 * @param   pClient             .
 * @param   pszFullPath         .
 * @param   pszStartComponent   .
 */
static int vbsfCorrectCasing(SHFLCLIENTDATA *pClient, char *pszFullPath, char *pszStartComponent)
{
    Log2(("vbsfCorrectCasing: %s %s\n", pszFullPath, pszStartComponent));

    AssertReturn((uintptr_t)pszFullPath < (uintptr_t)pszStartComponent - 1U, VERR_INTERNAL_ERROR_2);
    AssertReturn(pszStartComponent[-1] == RTPATH_DELIMITER, VERR_INTERNAL_ERROR_5);

    /*
     * Allocate a buffer that can hold really long file name entries as well as
     * the initial search pattern.
     */
    size_t cchComponent = strlen(pszStartComponent);
    size_t cchParentDir = pszStartComponent - pszFullPath;
    size_t cchFullPath  = cchParentDir + cchComponent;
    Assert(strlen(pszFullPath) == cchFullPath);

    size_t cbDirEntry   = 4096;
    if (cchFullPath + 4 > cbDirEntry - RT_OFFSETOF(RTDIRENTRYEX, szName))
        cbDirEntry = RT_OFFSETOF(RTDIRENTRYEX, szName) + cchFullPath + 4;

    PRTDIRENTRYEX pDirEntry = (PRTDIRENTRYEX)RTMemAlloc(cbDirEntry);
    if (pDirEntry == NULL)
        return VERR_NO_MEMORY;

    /*
     * Construct the search criteria in the szName member of pDirEntry.
     */
    /** @todo This is quite inefficient, especially for directories with many
     *        files.  If any of the typically case sensitive host systems start
     *        supporting opendir wildcard filters, it would make sense to build
     *        one here with '?' for case foldable charaters. */
    /** @todo Use RTDirOpen here and drop the whole uncessary path copying? */
    int rc = RTPathJoinEx(pDirEntry->szName, cbDirEntry - RT_OFFSETOF(RTDIRENTRYEX, szName),
                          pszFullPath, cchParentDir,
                          RT_STR_TUPLE("*"));
    AssertRC(rc);
    if (RT_SUCCESS(rc))
    {
        RTDIR hSearch = NULL;
        rc = RTDirOpenFiltered(&hSearch, pDirEntry->szName, RTDIRFILTER_WINNT, 0 /*fFlags*/);
        if (RT_SUCCESS(rc))
        {
            for (;;)
            {
                size_t cbDirEntrySize = cbDirEntry;

                rc = RTDirReadEx(hSearch, pDirEntry, &cbDirEntrySize, RTFSOBJATTRADD_NOTHING, SHFL_RT_LINK(pClient));
                if (rc == VERR_NO_MORE_FILES)
                    break;

                if (   rc != VINF_SUCCESS
                    && rc != VWRN_NO_DIRENT_INFO)
                {
                    if (   rc == VERR_NO_TRANSLATION
                        || rc == VERR_INVALID_UTF8_ENCODING)
                        continue;
                    AssertMsgFailed(("%Rrc\n", rc));
                    break;
                }

                Log2(("vbsfCorrectCasing: found %s\n", &pDirEntry->szName[0]));
                if (    pDirEntry->cbName == cchComponent
                    &&  !RTStrICmp(pszStartComponent, &pDirEntry->szName[0]))
                {
                    Log(("Found original name %s (%s)\n", &pDirEntry->szName[0], pszStartComponent));
                    strcpy(pszStartComponent, &pDirEntry->szName[0]);
                    rc = VINF_SUCCESS;
                    break;
                }
            }

            RTDirClose(hSearch);
        }
    }

    if (RT_FAILURE(rc))
        Log(("vbsfCorrectCasing %s failed with %Rrc\n", pszStartComponent, rc));

    RTMemFree(pDirEntry);

    return rc;
}
Exemplo n.º 4
0
HRESULT VFSExplorer::i_updateFS(TaskVFSExplorer *aTask)
{
    LogFlowFuncEnter();

    AutoCaller autoCaller(this);
    if (FAILED(autoCaller.rc())) return autoCaller.rc();

    AutoWriteLock appLock(this COMMA_LOCKVAL_SRC_POS);

    HRESULT rc = S_OK;

    std::list<VFSExplorer::Data::DirEntry> fileList;
    char *pszPath = NULL;
    PRTDIR pDir = NULL;
    try
    {
        int vrc = RTDirOpen(&pDir, m->strPath.c_str());
        if (RT_FAILURE(vrc))
            throw setError(VBOX_E_FILE_ERROR, tr ("Can't open directory '%s' (%Rrc)"), pszPath, vrc);

        if (aTask->progress)
            aTask->progress->SetCurrentOperationProgress(33);
        RTDIRENTRYEX entry;
        while (RT_SUCCESS(vrc))
        {
            vrc = RTDirReadEx(pDir, &entry, NULL, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
            if (RT_SUCCESS(vrc))
            {
                Utf8Str name(entry.szName);
                if (   name != "."
                    && name != "..")
                    fileList.push_back(VFSExplorer::Data::DirEntry(name, i_RTToVFSFileType(entry.Info.Attr.fMode),
                                       entry.Info.cbObject,
                                       entry.Info.Attr.fMode & (RTFS_UNIX_IRWXU | RTFS_UNIX_IRWXG | RTFS_UNIX_IRWXO)));
            }
        }
        if (aTask->progress)
            aTask->progress->SetCurrentOperationProgress(66);
    }
    catch(HRESULT aRC)
    {
        rc = aRC;
    }

    /* Clean up */
    if (pszPath)
        RTStrFree(pszPath);
    if (pDir)
        RTDirClose(pDir);

    if (aTask->progress)
        aTask->progress->SetCurrentOperationProgress(99);

    /* Assign the result on success (this clears the old list) */
    if (rc == S_OK)
        m->entryList.assign(fileList.begin(), fileList.end());

    aTask->rc = rc;

    if (!aTask->progress.isNull())
        aTask->progress->i_notifyComplete(rc);

    LogFlowFunc(("rc=%Rhrc\n", rc));
    LogFlowFuncLeave();

    return VINF_SUCCESS;
}
Exemplo n.º 5
0
/**
 * Recursively delete a directory.
 *
 * @returns IPRT status code, errors go via rtPathRmError.
 * @param   pOpts               The RM options.
 * @param   pszPath             Pointer to a writable buffer holding the path to
 *                              the directory.
 * @param   cchPath             The length of the path (avoid strlen).
 * @param   pDirEntry           Pointer to a directory entry buffer that is
 *                              RTPATHRM_DIR_MAX_ENTRY_SIZE bytes big.
 */
static int rtPathRmRecursive(PRTPATHRMCMDOPTS pOpts, char *pszPath, size_t cchPath, PRTDIRENTRYEX pDirEntry)
{
    /*
     * Make sure the path ends with a slash.
     */
    if (!cchPath || !RTPATH_IS_SLASH(pszPath[cchPath - 1]))
    {
        if (cchPath + 1 >= RTPATH_MAX)
            return rtPathRmError(pOpts, pszPath, VERR_BUFFER_OVERFLOW, "Buffer overflow fixing up '%s'.\n", pszPath);
        pszPath[cchPath++] = RTPATH_SLASH;
        pszPath[cchPath]   = '\0';
    }

    /*
     * Traverse the directory.
     */
    PRTDIR hDir;
    int rc = RTDirOpen(&hDir, pszPath);
    if (RT_FAILURE(rc))
        return rtPathRmError(pOpts, pszPath, rc, "Error opening directory '%s': %Rrc", pszPath, rc);
    int rcRet = VINF_SUCCESS;
    for (;;)
    {
        /*
         * Read the next entry, constructing an full path for it.
         */
        size_t cbEntry = RTPATHRM_DIR_MAX_ENTRY_SIZE;
        rc = RTDirReadEx(hDir, pDirEntry, &cbEntry, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
        if (rc == VERR_NO_MORE_FILES)
        {
            /*
             * Reached the end of the directory.
             */
            pszPath[cchPath] = '\0';
            rc = RTDirClose(hDir);
            if (RT_FAILURE(rc))
                return rtPathRmError(pOpts, pszPath, rc, "Error closing directory '%s': %Rrc", pszPath, rc);

            /* Delete the directory. */
            int rc2 = rtPathRmOneDir(pOpts, pszPath);
            if (RT_FAILURE(rc2) && RT_SUCCESS(rcRet))
                return rc2;
            return rcRet;
        }

        if (RT_FAILURE(rc))
        {
            rc = rtPathRmError(pOpts, pszPath, rc, "Error reading directory '%s': %Rrc", pszPath, rc);
            break;
        }

        /* Skip '.' and '..'. */
        if (   pDirEntry->szName[0] == '.'
            && (   pDirEntry->cbName == 1
                || (   pDirEntry->cbName == 2
                    && pDirEntry->szName[1] == '.')))
            continue;

        /* Construct full path. */
        if (cchPath + pDirEntry->cbName >= RTPATH_MAX)
        {
            pszPath[cchPath] = '\0';
            rc = rtPathRmError(pOpts, pszPath, VERR_BUFFER_OVERFLOW, "Path buffer overflow in directory '%s'.", pszPath);
            break;
        }
        memcpy(pszPath + cchPath, pDirEntry->szName, pDirEntry->cbName + 1);

        /*
         * Take action according to the type.
         */
        switch (pDirEntry->Info.Attr.fMode & RTFS_TYPE_MASK)
        {
            case RTFS_TYPE_FILE:
                rc = rtPathRmOneFile(pOpts, pszPath, &pDirEntry->Info);
                break;

            case RTFS_TYPE_DIRECTORY:
                rc = rtPathRmRecursive(pOpts, pszPath, cchPath + pDirEntry->cbName, pDirEntry);
                break;

            case RTFS_TYPE_SYMLINK:
                rc = rtPathRmOneSymlink(pOpts, pszPath);
                break;

            case RTFS_TYPE_FIFO:
            case RTFS_TYPE_DEV_CHAR:
            case RTFS_TYPE_DEV_BLOCK:
            case RTFS_TYPE_SOCKET:
                rc = rtPathRmOneFile(pOpts, pszPath, &pDirEntry->Info);
                break;

            case RTFS_TYPE_WHITEOUT:
            default:
                rc = rtPathRmError(pOpts, pszPath, VERR_UNEXPECTED_FS_OBJ_TYPE,
                                   "Object '%s' has an unknown file type: %o\n",
                                   pszPath, pDirEntry->Info.Attr.fMode & RTFS_TYPE_MASK);
                break;
        }
        if (RT_FAILURE(rc) && RT_SUCCESS(rcRet))
            rcRet = rc;
    }

    /*
     * Some error occured, close and return.
     */
    RTDirClose(hDir);
    return rc;
}
Exemplo n.º 6
0
static ssize_t rtLinuxFindDevicePathRecursive(dev_t DevNum, RTFMODE fMode, const char *pszBasePath,
                                              char *pszBuf, size_t cchBuf)
{
    /*
     * Check assumptions made by the code below.
     */
    size_t const cchBasePath = strlen(pszBasePath);
    AssertReturnStmt(cchBasePath < RTPATH_MAX - 10U, errno = ENAMETOOLONG, -1);

    ssize_t rcRet;
    PRTDIR  pDir;
    int rc = RTDirOpen(&pDir, pszBasePath);
    if (RT_SUCCESS(rc))
    {
        char szPath[RTPATH_MAX]; /** @todo 4K per recursion - can easily be optimized away by passing it along pszBasePath
                                           and only remember the length. */
        memcpy(szPath, pszBasePath, cchBasePath + 1);

        for (;;)
        {
            RTDIRENTRYEX Entry;
            rc = RTDirReadEx(pDir, &Entry, NULL, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK);
            if (RT_FAILURE(rc))
            {
                errno = rc == VERR_NO_MORE_FILES
                      ? ENOENT
                      : rc == VERR_BUFFER_OVERFLOW
                      ? EOVERFLOW
                      : EIO;
                rcRet = -1;
                break;
            }
            if (RTFS_IS_SYMLINK(Entry.Info.Attr.fMode))
                continue;

            /* Do the matching. */
            if (   Entry.Info.Attr.u.Unix.Device == DevNum
                && (Entry.Info.Attr.fMode & RTFS_TYPE_MASK) == fMode)
            {
                rcRet = rtLinuxConstructPath(pszBuf, cchBuf, pszBasePath, "%s", Entry.szName);
                break;
            }

            /* Recurse into subdirectories. */
            if (!RTFS_IS_DIRECTORY(Entry.Info.Attr.fMode))
                continue;
            if (Entry.szName[0] == '.')
                continue;

            szPath[cchBasePath] = '\0';
            rc = RTPathAppend(szPath, sizeof(szPath) - 1, Entry.szName); /* -1: for slash */
            if (RT_FAILURE(rc))
            {
                errno = ENAMETOOLONG;
                rcRet = -1;
                break;
            }
            strcat(&szPath[cchBasePath], "/");
            rcRet = rtLinuxFindDevicePathRecursive(DevNum, fMode, szPath, pszBuf, cchBuf);
            if (rcRet >= 0 || errno != ENOENT)
                break;
        }
        RTDirClose(pDir);
    }
    else
    {
        rcRet = -1;
        errno = RTErrConvertToErrno(rc);
    }
    return rcRet;
}