Hongmeng light kernel source code analysis: file system LittleFS

Posted by Dave3765 on Tue, 08 Feb 2022 06:58:02 +0100

Abstract: This paper first introduces the structure and global variables of the lower LFS file system structure, and then analyzes the lower LFS file operation interface.

This article is shared from Huawei cloud community< #Hongmeng light kernel M core source code analysis series II-02 file system LittleFS >, author: zhushy.

LittleFS is a small Flash file system. It combines the idea of log structured file system and COW (copy on write) file system. It stores metadata in log structure and data in COW structure. This special storage mode enables LittleFS to have powerful power loss resilience. When allocating COW data blocks, LittleFS adopts a dynamic loss equalization algorithm called statistical loss equalization, which effectively ensures the service life of Flash devices. At the same time, LittleFS is designed for small devices that are short of resources, with extremely limited ROM and ram occupation, and all RAM usage is allocated through a configurable fixed size buffer, which will not occupy more system resources with the expansion of the file system. LittleFS is a better choice when looking for a Flash file system with power down recovery capability and balanced loss on a small device with very scarce resources. This paper first introduces the structure and global variables of the lower LFS file system structure, and then analyzes the lower LFS file operation interface. The source code involved in this paper can be found on the open source site kernel_liteos_m: LiteOS kernel for devices with few resources, such as the MCU Get.

1. Introduction to LFS file system structure

The structure part will be introduced in two parts. First, the structure of LittleFS file system will be introduced, and then some structures related to LittleFS provided in LiteOS-M kernel will be introduced.

1.1 enumeration structure of littlefs

In openharmony / third_ party/LittleFS/lfs. The enumeration and structure of LittleFS are defined in the H header file. We will briefly understand it first and use it later.

Enumerate lfs_type defines the file type. Learn about the common file LFS_TYPE_REG and LFS_TYPE_DIR is enough. Enumerate lfs_open_flags defines the open tag attribute information of the file system. You need to be familiar with the commonly used read-only LFS_O_RDONLY, write LFS only_ O_ Wronly, read / write LFS_O_RDWR, wait.

// File types
enum lfs_type {
    // file types
    LFS_TYPE_REG            = 0x001,
    LFS_TYPE_DIR            = 0x002,

    // internally used types
    LFS_TYPE_SPLICE         = 0x400,
    LFS_TYPE_NAME           = 0x000,
    LFS_TYPE_STRUCT         = 0x200,
    LFS_TYPE_USERATTR       = 0x300,
    LFS_TYPE_FROM           = 0x100,
    LFS_TYPE_TAIL           = 0x600,
    LFS_TYPE_GLOBALS        = 0x700,
    LFS_TYPE_CRC            = 0x500,

    // internally used type specializations
    LFS_TYPE_CREATE         = 0x401,
    LFS_TYPE_DELETE         = 0x4ff,
    LFS_TYPE_SUPERBLOCK     = 0x0ff,
    LFS_TYPE_DIRSTRUCT      = 0x200,
    LFS_TYPE_CTZSTRUCT      = 0x202,
    LFS_TYPE_INLINESTRUCT   = 0x201,
    LFS_TYPE_SOFTTAIL       = 0x600,
    LFS_TYPE_HARDTAIL       = 0x601,
    LFS_TYPE_MOVESTATE      = 0x7ff,

    // internal chip sources
    LFS_FROM_NOOP           = 0x000,
    LFS_FROM_MOVE           = 0x101,
    LFS_FROM_USERATTRS      = 0x102,
};

// File open flags
enum lfs_open_flags {
    // open flags
    LFS_O_RDONLY = 1,         // Open a file as read only
#ifndef LFS_READONLY
    LFS_O_WRONLY = 2,         // Open a file as write only
    LFS_O_RDWR   = 3,         // Open a file as read and write
    LFS_O_CREAT  = 0x0100,    // Create a file if it does not exist
    LFS_O_EXCL   = 0x0200,    // Fail if a file already exists
    LFS_O_TRUNC  = 0x0400,    // Truncate the existing file to zero size
    LFS_O_APPEND = 0x0800,    // Move to end of file on every write
#endif

    // internally used flags
#ifndef LFS_READONLY
    LFS_F_DIRTY   = 0x010000, // File does not match storage
    LFS_F_WRITING = 0x020000, // File has been written since last flush
#endif
    LFS_F_READING = 0x040000, // File has been read since last flush
#ifndef LFS_READONLY
    LFS_F_ERRED   = 0x080000, // An error occurred during write
#endif
    LFS_F_INLINE  = 0x100000, // Currently inlined in directory entry
};

Structure lfs_t is the structure of littlefs file system type, and the first parameter of lfs file system operation interface is generally this structure. Member variable struct lfs_config *cfg will be covered later, and other member variables can not be understood for the time being.

// The littlefs filesystem type
typedef struct lfs {
    lfs_cache_t rcache;
    lfs_cache_t pcache;

    lfs_block_t root[2];
    struct lfs_mlist {
        struct lfs_mlist *next;
        uint16_t id;
        uint8_t type;
        lfs_mdir_t m;
    } *mlist;
    uint32_t seed;

    lfs_gstate_t gstate;
    lfs_gstate_t gdisk;
    lfs_gstate_t gdelta;

    struct lfs_free {
        lfs_block_t off;
        lfs_block_t size;
        lfs_block_t i;
        lfs_block_t ack;
        uint32_t *buffer;
    } free;

    const struct lfs_config *cfg;
    lfs_size_t name_max;
    lfs_size_t file_max;
    lfs_size_t attr_max;

#ifdef LFS_MIGRATE
    struct lfs1 *lfs1;
#endif
} lfs_t;

Structure lfs_file_t,lfs_dir_t is the file and directory type structure of littlefs respectively. You don't need to care about the details of member variables temporarily. You can know the purpose of the structure.

// littlefs directory type
typedef struct lfs_dir {
    struct lfs_dir *next;
    uint16_t id;
    uint8_t type;
    lfs_mdir_t m;

    lfs_off_t pos;
    lfs_block_t head[2];
} lfs_dir_t;

// littlefs file type
typedef struct lfs_file {
    struct lfs_file *next;
    uint16_t id;
    uint8_t type;
    lfs_mdir_t m;

    struct lfs_ctz {
        lfs_block_t head;
        lfs_size_t size;
    } ctz;

    uint32_t flags;
    lfs_off_t pos;
    lfs_block_t block;
    lfs_off_t off;
    lfs_cache_t cache;

    const struct lfs_file_config *cfg;
} lfs_file_t;

Structure lfs_config is used to provide some configuration for initializing the littlefs file system. Among them read,. prog,. erase,. sync corresponds to the underlying read-write, erase, synchronization and other interfaces on the hardware platform.

  • read_size the number of bytes read each time can be larger than the physical read unit to improve performance. This value determines the size of the read cache, but if the value is too large, it will lead to more memory consumption.
  • prog_size the number of bytes written each time can be larger than the physical write unit to improve performance. This value determines the size of the write cache and must be read_size, but if the value is too large, it will lead to more memory consumption.
  • block_size the number of bytes of each erasing block can be larger than the physical erasing unit, but this value should be as small as possible because each file will occupy at least one block. Must be prog_ An integer multiple of size.
  • block_count the number of blocks that can be erased, which depends on the capacity of the block device and the size of the erased block.
// Configuration provided during initialization of the littlefs
struct lfs_config {
    // Opaque user provided context that can be used to pass
    // information to the block device operations
    void *context;

    int (*read)(const struct lfs_config *c, lfs_block_t block,
            lfs_off_t off, void *buffer, lfs_size_t size);
    int (*prog)(const struct lfs_config *c, lfs_block_t block,
            lfs_off_t off, const void *buffer, lfs_size_t size);
    int (*erase)(const struct lfs_config *c, lfs_block_t block);
    int (*sync)(const struct lfs_config *c);

#ifdef LFS_THREADSAFE
    int (*lock)(const struct lfs_config *c);
    int (*unlock)(const struct lfs_config *c);
#endif

    lfs_size_t read_size;
    lfs_size_t prog_size;
    lfs_size_t block_size;
    lfs_size_t block_count;

    int32_t block_cycles;
    lfs_size_t cache_size;
    lfs_size_t lookahead_size;
    void *read_buffer;
    void *prog_buffer;
    void *lookahead_buffer;
    lfs_size_t name_max;
    lfs_size_t file_max;
    lfs_size_t attr_max;
    lfs_size_t metadata_max;
};

Structure lfs_info is used to maintain file information, including file type, size and file name information.

// File info structure
struct lfs_info {
    // Type of the file, either LFS_TYPE_REG or LFS_TYPE_DIR
    uint8_t type;

    // Size of the file, only valid for REG files. Limited to 32-bits.
    lfs_size_t size;

    // Name of the file stored as a null-terminated string. Limited to
    // LFS_NAME_MAX+1, which can be changed by redefining LFS_NAME_MAX to
    // reduce RAM. LFS_NAME_MAX is stored in superblock and must be
    // respected by other littlefs drivers.
    char name[LFS_NAME_MAX+1];
};

1.2 structure of liteos-m littlefs

Let's look at the file components \ FS \ littlefs \ lfs_ api. Several structures defined in H. Structure LittleFsHandleStruct maintains file related information. The members of the structure include whether to use, file path and lfs file system type structure lfs_t *lfsHandle and file type structure lfs_file_t file. Similarly, the structure FileDirInfo maintains directory related information. The structure members include whether to use, directory name and lfs file system type structure lfs_t *lfsHandle and directory type structure lfs_dir_t dir. Another structure, FileOpInfo, maintains file operation information.

typedef struct {
    uint8_t useFlag;
    const char *pathName;
    lfs_t *lfsHandle;
    lfs_file_t file;
} LittleFsHandleStruct;

struct FileOpInfo {
    uint8_t useFlag;
    const struct FileOps *fsVops;
    char *dirName;
    lfs_t lfsInfo;
};

typedef struct {
    uint8_t useFlag;
    char *dirName;
    lfs_t *lfsHandle;
    lfs_dir_t dir;
} FileDirInfo;

2. Important global variables and operations of LiteOS-M LittleFS

Learn about the following file components \ FS \ littlefs \ LFS_ api. Common global variables defined by C. (1) g at_ The lfsdir array maintains directory information. By default, the number of supported directories is LFS_MAX_OPEN_DIRS, equal to 10. (2) g at_ FSOP array maintains the file operation information for each mount point. The default mount point number is LOSCFG_LFS_MAX_MOUNT_SIZE is 3. (3) g at_ The handle array maintains file information. By default, the number of files is LITTLE_FS_MAX_OPEN_FILES is 100. (4) struct dirent g starting at_ Namevalue is the variable of directory item structure, which is used in the function lfsreadir(); pthread_mutex_t g_FslocalMutex is a mutex variable; g_littlefsMntName is an array of mount point names. (5) mount operation variable g starting at_ Lfsmnt, file operation global variable g_lfsFops is used in virtual file systems.

⑴  FileDirInfo g_lfsDir[LFS_MAX_OPEN_DIRS] = {0};

⑵  struct FileOpInfo g_fsOp[LOSCFG_LFS_MAX_MOUNT_SIZE] = {0};
⑶  static LittleFsHandleStruct g_handle[LITTLE_FS_MAX_OPEN_FILES] = {0};
⑷  struct dirent g_nameValue;
    static pthread_mutex_t g_FslocalMutex = PTHREAD_MUTEX_INITIALIZER;
    static const char *g_littlefsMntName[LOSCFG_LFS_MAX_MOUNT_SIZE] = {"/a", "/b", "/c"};
    ......
⑸  const struct MountOps g_lfsMnt = {
        .Mount = LfsMount,
        .Umount = LfsUmount,
    };

    const struct FileOps g_lfsFops = {
        .Mkdir = LfsMkdir,
        .Unlink = LfsUnlink,
        .Rmdir = LfsRmdir,
        .Opendir = LfsOpendir,
        .Readdir = LfsReaddir,
        .Closedir = LfsClosedir,
        .Open = LfsOpen,
        .Close = LfsClose,
        .Write = LfsWrite,
        .Read = LfsRead,
        .Seek = LfsSeek,
        .Rename = LfsRename,
        .Getattr = LfsStat,
        .Fsync = LfsFsync,
        .Fstat = LfsFstat,
    };

The following continues to introduce the internal operation interfaces related to these variables.

2.1 directory information array operation

GetFreeDir() sets the element information of the directory information array. The parameter dirName is the directory name. Traverse the directory information array, traverse to the first unused element, mark it as used, set the directory name, and return the pointer address of the directory information element. If the traversal fails, NULL is returned. The function FreeDirInfo() is the reverse operation of the function GetFreeDir(), set the corresponding array element to unused state according to the directory name, and set GetFreeDir to NULL.

The function CheckDirIsOpen() is used to detect whether the directory is open. If the corresponding directory information is recorded in the directory information array, it indicates that the directory has been opened.

FileDirInfo *GetFreeDir(const char *dirName)
{
    pthread_mutex_lock(&g_FslocalMutex);
    for (int i = 0; i < LFS_MAX_OPEN_DIRS; i++) {
        if (g_lfsDir[i].useFlag == 0) {
            g_lfsDir[i].useFlag = 1;
            g_lfsDir[i].dirName = strdup(dirName);
            pthread_mutex_unlock(&g_FslocalMutex);
            return &(g_lfsDir[i]);
        }
    }
    pthread_mutex_unlock(&g_FslocalMutex);
    return NULL;
}

void FreeDirInfo(const char *dirName)
{
    pthread_mutex_lock(&g_FslocalMutex);
    for (int i = 0; i < LFS_MAX_OPEN_DIRS; i++) {
        if (g_lfsDir[i].useFlag == 1 && strcmp(g_lfsDir[i].dirName, dirName) == 0) {
            g_lfsDir[i].useFlag = 0;
            if (g_lfsDir[i].dirName) {
                free(g_lfsDir[i].dirName);
                g_lfsDir[i].dirName = NULL;
            }
            pthread_mutex_unlock(&g_FslocalMutex);
        }
    }
    pthread_mutex_unlock(&g_FslocalMutex);
}

BOOL CheckDirIsOpen(const char *dirName)
{
    pthread_mutex_lock(&g_FslocalMutex);
    for (int i = 0; i < LFS_MAX_OPEN_DIRS; i++) {
        if (g_lfsDir[i].useFlag == 1) {
            if (strcmp(g_lfsDir[i].dirName, dirName) == 0) {
                pthread_mutex_unlock(&g_FslocalMutex);
                return TRUE;
            }
        }
    }
    pthread_mutex_unlock(&g_FslocalMutex);
    return FALSE;
}

Array file operation information

The function LfsAllocFd() sets the element information of the file information array. The parameter fileName is the file path information, and the outgoing parameter fd is the file descriptor, that is, the array index. Traverse the file information array, traverse to the first unused element, mark it as used, set the file path information, assign the array index to the file descriptor fd, and return the pointer address of the file information element. If the traversal fails, NULL is returned. The function LfsFreeFd() is the reverse operation of the function LfsAllocFd(). Set the corresponding array element to unused state according to the file descriptor, and set the path information to NULL.

The function CheckFileIsOpen() is used to detect whether the file has been opened. If the file has been opened, it means that the file descriptor of the file has been obtained. According to the corresponding fd file descriptor, more operations can be carried out on the file. If the corresponding file path information is recorded in the file information array, it indicates that the file has been opened. The function LfsFdIsValid() is used to determine whether the file descriptor is valid.

LittleFsHandleStruct *LfsAllocFd(const char *fileName, int *fd)
{
    pthread_mutex_lock(&g_FslocalMutex);
    for (int i = 0; i < LITTLE_FS_MAX_OPEN_FILES; i++) {
        if (g_handle[i].useFlag == 0) {
            *fd = i;
            g_handle[i].useFlag = 1;
            g_handle[i].pathName = strdup(fileName);
            pthread_mutex_unlock(&g_FslocalMutex);
            return &(g_handle[i]);
        }
    }
    pthread_mutex_unlock(&g_FslocalMutex);
    *fd = INVALID_FD;
    return NULL;
}

static void LfsFreeFd(int fd)
{
    pthread_mutex_lock(&g_FslocalMutex);
    g_handle[fd].useFlag = 0;
    if (g_handle[fd].pathName != NULL) {
        free((void *)g_handle[fd].pathName);
        g_handle[fd].pathName = NULL;
    }

    if (g_handle[fd].lfsHandle != NULL) {
        g_handle[fd].lfsHandle = NULL;
    }
    pthread_mutex_unlock(&g_FslocalMutex);
}

BOOL CheckFileIsOpen(const char *fileName)
{
    pthread_mutex_lock(&g_FslocalMutex);
    for (int i = 0; i < LITTLE_FS_MAX_OPEN_FILES; i++) {
        if (g_handle[i].useFlag == 1) {
            if (strcmp(g_handle[i].pathName, fileName) == 0) {
                pthread_mutex_unlock(&g_FslocalMutex);
                return TRUE;
            }
        }
    }
    pthread_mutex_unlock(&g_FslocalMutex);
    return FALSE;
}

static BOOL LfsFdIsValid(int fd)
{
    if (fd >= LITTLE_FS_MAX_OPEN_FILES || fd < 0) {
        return FALSE;
    }
    if (g_handle[fd].lfsHandle == NULL) {
        return FALSE;
    }
    return TRUE;
}

2.3 operation related to file operation information of mount point

The function AllocMountRes() is used to set the operation information of the mount point file. The parameter target is the name of the mount point, and the parameter fileOps is the file operation information. Traverse each mount point. If the traversed mount point is not used and the mount point names are equal, set its use flag as used, set the directory name, set the file operation information, and then return the file operation information pointer. If it is not traversed, NULL is returned. Mount point group G_ The elements of littlefsmntname are / a,/b,/c, etc. by default, you can use the function SetDefaultMountPath() to set the mount point name of the specified location.

struct FileOpInfo *AllocMountRes(const char* target, const struct FileOps *fileOps)
{
    pthread_mutex_lock(&g_FslocalMutex);
    for (int i = 0; i < LOSCFG_LFS_MAX_MOUNT_SIZE; i++) {
        if (g_fsOp[i].useFlag == 0 && strcmp(target, g_littlefsMntName[i]) == 0) {
            g_fsOp[i].useFlag = 1;
            g_fsOp[i].fsVops = fileOps;
            g_fsOp[i].dirName = strdup(target);
            pthread_mutex_unlock(&g_FslocalMutex);
            return &(g_fsOp[i]);
        }
    }

    pthread_mutex_unlock(&g_FslocalMutex);
    return NULL;
}

int SetDefaultMountPath(int pathNameIndex, const char* target)
{
    if (pathNameIndex >= LOSCFG_LFS_MAX_MOUNT_SIZE) {
        return VFS_ERROR;
    }

    pthread_mutex_lock(&g_FslocalMutex);
    g_littlefsMntName[pathNameIndex] = strdup(target);
    pthread_mutex_unlock(&g_FslocalMutex);
    return VFS_OK;
}

The function GetMountRes() is used to obtain the index value of a given mount point in the mount point file operation information array. The parameter target is the name of the mount point, and the parameter mountIndex is used to output the index value of the file operation information array. Traverse each mount point. If the traversed mount point has been used and the mount point names are equal, the corresponding array index is returned; otherwise, NULL is returned.

struct FileOpInfo *GetMountRes(const char *target, int *mountIndex)
{
    pthread_mutex_lock(&g_FslocalMutex);
    for (int i = 0; i < LOSCFG_LFS_MAX_MOUNT_SIZE; i++) {
        if (g_fsOp[i].useFlag == 1) {
            if (g_fsOp[i].dirName && strcmp(target, g_fsOp[i].dirName) == 0) {
                *mountIndex = i;
                pthread_mutex_unlock(&g_FslocalMutex);
                return &(g_fsOp[i]);
            }
        }
    }

    pthread_mutex_unlock(&g_FslocalMutex);
    return NULL;
}

The function FreeMountResByIndex() is the reverse operation of the function AllocMountRes(), which is used to release the operation information of the mount point file. The file operation information corresponding to the input parameter mountIndex is marked as unused to free the memory occupied by the mount point name. The function FreeMountRes() implements the same function, and the incoming parameter is the name of the mount point. Traverse each mount point. If there is a mount point with the same parameters as the one passed in, release it.

int FreeMountResByIndex(int mountIndex)
{
    if (mountIndex < 0 || mountIndex >= LOSCFG_LFS_MAX_MOUNT_SIZE) {
        return VFS_ERROR;
    }

    pthread_mutex_lock(&g_FslocalMutex);
    if (g_fsOp[mountIndex].useFlag == 1 && g_fsOp[mountIndex].dirName != NULL) {
        g_fsOp[mountIndex].useFlag = 0;
        free(g_fsOp[mountIndex].dirName);
        g_fsOp[mountIndex].dirName = NULL;
    }
    pthread_mutex_unlock(&g_FslocalMutex);

    return VFS_OK;
}

int FreeMountRes(const char *target)
{
    pthread_mutex_lock(&g_FslocalMutex);
    for (int i = 0; i < LOSCFG_LFS_MAX_MOUNT_SIZE; i++) {
        if (g_fsOp[i].useFlag == 1) {
            if (g_fsOp[i].dirName && strcmp(target, g_fsOp[i].dirName) == 0) {
                g_fsOp[i].useFlag = 0;
                free(g_fsOp[i].dirName);
                g_fsOp[i].dirName = NULL;
                pthread_mutex_unlock(&g_FslocalMutex);
                return VFS_OK;
            }
        }
    }

    pthread_mutex_unlock(&g_FslocalMutex);
    return VFS_ERROR;
}

2.4 whether the path is mounted with CheckPathIsMounted

The function CheckPathIsMounted() is used to check whether the given path has been mounted. If mounted, the file operation information of the corresponding mount point is output by the parameter struct FileOpInfo **fileOpInfo. (1) first obtain the length of the first level directory of the path. (2) traverse the file operation array of each mount point. If the file operation is in use, execute (3) compare whether the corresponding mount point name and the first level directory name of the path are equal. If equal, the file operation information is output and TRUE is returned. Otherwise, FALSE is returned.

int GetFirstLevelPathLen(const char *pathName)
{
    int len = 1;
    for (int i = 1; i < strlen(pathName) + 1; i++) {
        if (pathName[i] == '/') {
            break;
        }
        len++;
    }

    return len;
}

BOOL CheckPathIsMounted(const char *pathName, struct FileOpInfo **fileOpInfo)
{
    char tmpName[LITTLEFS_MAX_LFN_LEN] = {0};
⑴  int len = GetFirstLevelPathLen(pathName);

    pthread_mutex_lock(&g_FslocalMutex);
    for (int i = 0; i < LOSCFG_LFS_MAX_MOUNT_SIZE; i++) {
⑵      if (g_fsOp[i].useFlag == 1) {
            (void)strncpy_s(tmpName, LITTLEFS_MAX_LFN_LEN, pathName, len);
⑶          if (strcmp(tmpName, g_fsOp[i].dirName) == 0) {
                *fileOpInfo = &(g_fsOp[i]);
                pthread_mutex_unlock(&g_FslocalMutex);
                return TRUE;
            }
        }
    }
    pthread_mutex_unlock(&g_FslocalMutex);
    return FALSE;
}

3. File system operation interface of LiteOS-M LittleFS

Quickly record each operation interface, and the purpose and usage of each interface will not be described. You can refer to the previous series of articles, "Hongmeng light kernel M core source code analysis series 19 Musl LibC", which introduces the relevant interfaces. Those interfaces will call the operation interface in the VFS file system, and then further call the LFS file operation interface.

3.1 mount and unload LfsMount

Mounting and unloading operations include two operations: LfsMount and LfsUmounts. For the function LfsMount(), you need to pay attention to the parameter const void *data, which needs to be struct lfs_config pointer type variable. (1) check the input parameters before mounting the file system. (2) judge whether it has been mounted at the, and repeated mounting is not allowed. (3) set the mount point information at (4), and call the LFS function at (4) to realize the mount. If the mount fails, execute (5) try to format, and then mount again.

For the function LfsUmount(), obtain the file operation information and the index value of the mount point according to the mount point at (6). (7) call the LFS function to unload, and then execute (8) to release the operation information of the mount point file.

int LfsMount(const char *source, const char *target, const char *fileSystemType, unsigned long mountflags,
    const void *data)
{
    int ret;
    struct FileOpInfo *fileOpInfo = NULL;

⑴  if (target == NULL || fileSystemType == NULL || data == NULL) {
        errno = EFAULT;
        ret = VFS_ERROR;
        goto errout;
    }

    if (strcmp(fileSystemType, "littlefs") != 0) {
        errno = ENODEV;
        ret = VFS_ERROR;
        goto errout;
    }

⑵  if (CheckPathIsMounted(target, &fileOpInfo)) {
        errno = EBUSY;
        ret = VFS_ERROR;
        goto errout;
    }

    // select free mount resource
⑶  fileOpInfo = AllocMountRes(target, &g_lfsFops);
    if (fileOpInfo == NULL) {
        errno = ENODEV;
        ret = VFS_ERROR;
        goto errout;
    }

⑷  ret = lfs_mount(&(fileOpInfo->lfsInfo), (struct lfs_config*)data);
    if (ret != 0) {
⑸      ret = lfs_format(&(fileOpInfo->lfsInfo), (struct lfs_config*)data);
        if (ret == 0) {
            ret = lfs_mount(&(fileOpInfo->lfsInfo), (struct lfs_config*)data);
        }
    }

    if (ret != 0) {
        errno = LittlefsErrno(ret);
        ret = VFS_ERROR;
    }

errout:
    return ret;
}

int LfsUmount(const char *target)
{
    int ret;
    int mountIndex = -1;
    struct FileOpInfo *fileOpInfo = NULL;

    if (target == NULL) {
        errno = EFAULT;
        return VFS_ERROR;
    }

⑹  fileOpInfo = GetMountRes(target, &mountIndex);
    if (fileOpInfo == NULL) {
        errno = ENOENT;
        return VFS_ERROR;
    }

⑺  ret = lfs_unmount(&(fileOpInfo->lfsInfo));
    if (ret != 0) {
        errno = LittlefsErrno(ret);
        ret = VFS_ERROR;
    }

⑻  (void)FreeMountResByIndex(mountIndex);
    return ret;
}

3.2 file directory operation interface

The file directory operation interface includes LfsMkdir, LfsUnlink, LfsRmdir, lfsreaderdir, LfsClosedir, LfsOpen, LfsClose, etc. it will further call the file directory operation interface of LFS for encapsulation. The code is relatively simple and can be read by yourself. Some code fragments are as follows.

......
int LfsUnlink(const char *fileName)
{
    int ret;
    struct FileOpInfo *fileOpInfo = NULL;

    if (fileName == NULL) {
        errno = EFAULT;
        return VFS_ERROR;
    }

    if (CheckPathIsMounted(fileName, &fileOpInfo) == FALSE || fileOpInfo == NULL) {
        errno = ENOENT;
        return VFS_ERROR;
    }

    ret = lfs_remove(&(fileOpInfo->lfsInfo), fileName);
    if (ret != 0) {
        errno = LittlefsErrno(ret);
        ret = VFS_ERROR;
    }

    return ret;
}

int LfsMkdir(const char *dirName, mode_t mode)
{
    int ret;
    struct FileOpInfo *fileOpInfo = NULL;

    if (dirName == NULL) {
        errno = EFAULT;
        return VFS_ERROR;
    }

    if (CheckPathIsMounted(dirName, &fileOpInfo) == FALSE || fileOpInfo == NULL) {
        errno = ENOENT;
        return VFS_ERROR;
    }

    ret = lfs_mkdir(&(fileOpInfo->lfsInfo), dirName);
    if (ret != 0) {
        errno = LittlefsErrno(ret);
        ret = VFS_ERROR;
    }

    return ret;
}
......

reference material

  • Harmonyos device > documentation Guide > basic capabilities - LittleFS

Click follow to learn about Huawei's new cloud technology for the first time~

Topics: harmonyos Flash