~aleteoryx/muditaos

d4277039d3dbab089ad880129f89f8bce03d95d2 — Lucjan Bryndza 5 years ago 3041597
[EGD-4179] Recursive file list API (#912)

Recursive file list API with callback added
to the freertos FAT implementation

Co-authored-by: Lucjan Bryndza <lucjan.bryndza@mudita.com>
M module-vfs/CMakeLists.txt => module-vfs/CMakeLists.txt +5 -3
@@ 32,11 32,13 @@ endif()
set(PROJECT_INCLUDES
        ${CMAKE_CURRENT_SOURCE_DIR}/board/freeRTOS_FAT/include
        ${CMAKE_CURRENT_SOURCE_DIR}/board/free_rtos_custom/include
        )
        ${CMAKE_CURRENT_SOURCE_DIR}/freertos-fat-custom/include
)

set(FREERTOS_FAT_EXTSOURCES
	${CMAKE_CURRENT_SOURCE_DIR}/freertos-fat-custom/ff_stdio_flush.c
	${CMAKE_CURRENT_SOURCE_DIR}/freertos-fat-custom/ff_file_flush.c
	${CMAKE_CURRENT_SOURCE_DIR}/freertos-fat-custom/src/ff_stdio_flush.c
	${CMAKE_CURRENT_SOURCE_DIR}/freertos-fat-custom/src/ff_file_flush.c
    ${CMAKE_CURRENT_SOURCE_DIR}/freertos-fat-custom/src/ff_stdio_listdir_recursive.c
)

set(SOURCES ""

A module-vfs/freertos-fat-custom/include/ff_stdio_listdir_recursive.h => module-vfs/freertos-fat-custom/include/ff_stdio_listdir_recursive.h +24 -0
@@ 0,0 1,24 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <ff_stdio.h>
#include <stdbool.h>

#ifdef __cplusplus
extern "C"
{
#endif
    /**
     * List all directories recursive
     * @param startPath Starting directory
     * @param callback  Callback handler (ctx, path, isDir)
     * @param context   private context
     * @return  Error code
     */
    int ff_stdio_listdir_recursive(const char *startPath, void (*callback)(void *, const char *, bool), void *context);

#ifdef __cplusplus
}
#endif

R module-vfs/freertos-fat-custom/ff_file_flush.c => module-vfs/freertos-fat-custom/src/ff_file_flush.c +0 -0
R module-vfs/freertos-fat-custom/ff_file_flush.h => module-vfs/freertos-fat-custom/src/ff_file_flush.h +0 -0
R module-vfs/freertos-fat-custom/ff_stdio_flush.c => module-vfs/freertos-fat-custom/src/ff_stdio_flush.c +0 -0
A module-vfs/freertos-fat-custom/src/ff_stdio_listdir_recursive.c => module-vfs/freertos-fat-custom/src/ff_stdio_listdir_recursive.c +121 -0
@@ 0,0 1,121 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <ff_stdio_listdir_recursive.h>

const char *prvABSPath(const char *pcPath);

static int ff_stdio_listdir_recursive_prv(char *startPath, void (*callback)(void *, const char *, bool), void *context)

{
    FF_FindData_t *pxFindData;
    BaseType_t xIsDir, xIsDotDir;
    int iResult, iNext, iNameLength, pass, iCount = 0;

    pxFindData = (FF_FindData_t *)ffconfigMALLOC(sizeof(*pxFindData));
    if (pxFindData != NULL) {
        iNameLength = (int)strlen(startPath);
        for (pass = 0; pass < 2; pass++) {
            for (iResult = ff_findfirst(startPath, pxFindData); iResult == 0; iResult = iNext) {
                xIsDir = (pxFindData->xDirectoryEntry.ucAttrib & FF_FAT_ATTR_DIR) != 0;
                if ((pass == 0) && (xIsDir != pdFALSE)) {
                    /* This entry is a directory.  Don't traverse '.' or '..' */
                    xIsDotDir = 0;

                    if (pxFindData->pcFileName[0] == '.') {
                        if ((pxFindData->pcFileName[1] == '.') && (pxFindData->pcFileName[2] == '\0')) {
                            xIsDotDir = 2;
                        }
                        else if (pxFindData->pcFileName[1] == '\0') {
                            xIsDotDir = 1;
                        }
                    }
                    if (xIsDotDir == 0) {
                        snprintf(startPath + iNameLength,
                                 (size_t)(ffconfigMAX_FILENAME - iNameLength),
                                 "%s%s",
                                 startPath[iNameLength - 1] == '/' ? "" : "/",
                                 pxFindData->pcFileName);

                        /* Let pxFindData point to the next element before
                        the current will get removed. */
                        iNext = ff_findnext(pxFindData);

                        /* Remove the contents of this directory. */
                        iResult = ff_stdio_listdir_recursive_prv(startPath, callback, context);
                        if (iResult < 0) {
                            iCount = -1;
                            break;
                        }
                        iCount += iResult;
                        iCount++;
                        if (callback)
                            callback(context, startPath, true);
                    }
                    else {
                        iNext = ff_findnext(pxFindData);
                    }
                }
                else if ((pass == 1) && (xIsDir == pdFALSE)) {
                    snprintf(startPath + iNameLength,
                             (size_t)(ffconfigMAX_FILENAME - iNameLength),
                             "%s%s",
                             startPath[iNameLength - 1] == '/' ? "" : "/",
                             pxFindData->pcFileName);
                    iNext = ff_findnext(pxFindData);
                    iCount++;
                    if (callback)
                        callback(context, startPath, false);
                }
                else {
                    iNext = ff_findnext(pxFindData);
                }
                startPath[iNameLength] = '\0';
            }

            if (FF_GETERROR(iResult) == FF_ERR_DIR_INVALID_PATH) {
                break;
            }
            if ((FF_GETERROR(iResult) != FF_ERR_DIR_END_OF_DIR) && (FF_GETERROR(iResult) != FF_ERR_FILE_INVALID_PATH)) {
                FF_PRINTF("ff_listdir_recurse[%s]: %s\n", startPath, (const char *)FF_GetErrMessage(iResult));
            }
        }
        ffconfigFREE(pxFindData);
    }
    else {
        iCount = -1;
        stdioSET_ERRNO(pdFREERTOS_ERRNO_ENOMEM);
    }
    return iCount;
}

/**
 * List all directories recursive
 * @param startPath Starting directory
 * @param callback  Callback handler
 * @param context   private context
 * @return  Error code
 */
int ff_stdio_listdir_recursive(const char *startPath, void (*callback)(void *, const char *, bool), void *context)
{
    int iResult;
    char *pcPath;
    pcPath = (char *)ffconfigMALLOC(ffconfigMAX_FILENAME);
    if (pcPath != NULL) {
        /* In case a CWD is used, get the absolute path */
        startPath = prvABSPath(startPath);
        snprintf(pcPath, ffconfigMAX_FILENAME, "%s", startPath);
        /* This recursive function will do all the work */
        iResult = ff_stdio_listdir_recursive_prv(pcPath, callback, context);
        if (iResult >= 0) {
            if (callback)
                callback(context, pcPath, true);
        }
        ffconfigFREE(pcPath);
    }
    else {
        iResult = -1;
        stdioSET_ERRNO(pdFREERTOS_ERRNO_ENOMEM);
    }
    return iResult;
}