STATUS traverseDirectory()

in src/utils/src/Directory.c [57:205]


STATUS traverseDirectory(PCHAR dirPath, UINT64 userData, BOOL iterate, DirectoryEntryCallbackFunc entryFn)
{
    STATUS retStatus = STATUS_SUCCESS;
    CHAR tempFileName[MAX_PATH_LEN];
    UINT32 pathLen;

#if defined __WINDOWS_BUILD__
    WIN32_FIND_DATA findData;
    HANDLE hFind = INVALID_HANDLE_VALUE;
    UINT32 error = 0;
#else
    UINT32 dirPathLen;
    DIR* pDir = NULL;
    struct dirent* pDirEnt = NULL;
    struct stat entryStat;
#endif

    CHK(dirPath != NULL && entryFn != NULL && dirPath[0] != '\0', STATUS_INVALID_ARG);

    // Ensure we don't get a very long paths. Need at least a separator and a null terminator.
    pathLen = (UINT32) STRLEN(dirPath);
    CHK(pathLen + 2 < MAX_PATH_LEN, STATUS_PATH_TOO_LONG);

    // Ensure the path is appended with the separator
    STRCPY(tempFileName, dirPath);

#if defined __WINDOWS_BUILD__
    // Open the find

    if (tempFileName[pathLen - 1] != '*') {
        tempFileName[pathLen] = FPATHSEPARATOR;
        tempFileName[pathLen + 1] = '*';
        tempFileName[pathLen + 2] = '\0';
    }

    hFind = FindFirstFile(tempFileName, &findData);

    CHK(INVALID_HANDLE_VALUE != hFind, STATUS_DIRECTORY_OPEN_FAILED);

    do {
        if ((0 == STRCMP(findData.cFileName, ".")) || (0 == STRCMP(findData.cFileName, ".."))) {
            continue;
        }

        // Prepare the path
        tempFileName[pathLen] = '\0';

        // Check if it's a directory, link, file or unknown
        tempFileName[pathLen] = FPATHSEPARATOR;
        tempFileName[pathLen + 1] = '\0';
        STRNCAT(tempFileName, findData.cFileName, MAX_PATH_LEN - pathLen - 2);

        if ((findData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) {
            CHK_STATUS(entryFn(userData, DIR_ENTRY_TYPE_LINK, tempFileName, findData.cFileName));
        } else if ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
            // Iterate into sub-directories if specified
            if (iterate) {
                DLOGE("\r\nDir Path %s, tempFile %s find %s\r\n", dirPath, tempFileName, findData.cFileName);

                // Recurse into the directory
                CHK_STATUS(traverseDirectory(tempFileName, userData, iterate, entryFn));
            }

            // Call the callback
            CHK_STATUS(entryFn(userData, DIR_ENTRY_TYPE_DIRECTORY, tempFileName, findData.cFileName));
        } else {
            // Treat as if a normal file
            CHK_STATUS(entryFn(userData, DIR_ENTRY_TYPE_FILE, tempFileName, findData.cFileName));
        }

    } while (FindNextFile(hFind, &findData));

CleanUp:

    if (hFind != INVALID_HANDLE_VALUE) {
        FindClose(hFind);
    }

#else

    if (tempFileName[pathLen - 1] != FPATHSEPARATOR) {
        tempFileName[pathLen] = FPATHSEPARATOR;
        pathLen++;
        tempFileName[pathLen] = '\0';
    }

    pDir = FOPENDIR(tempFileName);

    // Need to make a distinction between various types of failures
    if (pDir == NULL) {
        switch (errno) {
            case EACCES:
                CHK(FALSE, STATUS_DIRECTORY_ACCESS_DENIED);
            case ENOENT:
                CHK(FALSE, STATUS_DIRECTORY_MISSING_PATH);
            default:
                CHK(FALSE, STATUS_DIRECTORY_OPEN_FAILED);
        }
    }

    while (NULL != (pDirEnt = FREADDIR(pDir))) {
        if ((0 == STRCMP(pDirEnt->d_name, ".")) || (0 == STRCMP(pDirEnt->d_name, ".."))) {
            continue;
        }

        // Prepare the path
        tempFileName[pathLen] = '\0';

        // Check if it's a directory, link, file or unknown
        STRNCAT(tempFileName, pDirEnt->d_name, MAX_PATH_LEN - pathLen);
        CHK(0 == FSTAT(tempFileName, &entryStat), STATUS_DIRECTORY_ENTRY_STAT_ERROR);

        if (S_ISREG(entryStat.st_mode)) {
            CHK_STATUS(entryFn(userData, DIR_ENTRY_TYPE_FILE, tempFileName, pDirEnt->d_name));
        } else if (S_ISLNK(entryStat.st_mode)) {
            CHK_STATUS(entryFn(userData, DIR_ENTRY_TYPE_LINK, tempFileName, pDirEnt->d_name));
        } else if (S_ISDIR(entryStat.st_mode)) {
            // Append the path separator and null terminate
            dirPathLen = STRLEN(tempFileName);
            CHK(dirPathLen + 2 < MAX_PATH_LEN, STATUS_PATH_TOO_LONG);

            // Iterate into sub-directories if specified
            if (iterate) {
                tempFileName[dirPathLen] = FPATHSEPARATOR;
                tempFileName[dirPathLen + 1] = '\0';

                // Recurse into the directory
                CHK_STATUS(traverseDirectory(tempFileName, userData, iterate, entryFn));
            }

            // Remove the path separator
            tempFileName[dirPathLen] = '\0';
            CHK_STATUS(entryFn(userData, DIR_ENTRY_TYPE_DIRECTORY, tempFileName, pDirEnt->d_name));
        } else {
            // We treat this as unknown
            CHK_STATUS(entryFn(userData, DIR_ENTRY_TYPE_UNKNOWN, tempFileName, pDirEnt->d_name));
        }
    }

CleanUp:

    if (pDir != NULL) {
        FCLOSEDIR(pDir);
        pDir = NULL;
    }

#endif
    return retStatus;
}