/**************************************************************************** * fs/littlefs/lfs.h * * This file is a part of NuttX: * * Copyright (C) 2019 Gregory Nutt. All rights reserved. * * Ported by: * * Copyright (C) 2019 Pinecone Inc. All rights reserved. * Author: lihaichen * * This port derives from ARM mbed logic which has a compatible 3-clause * BSD license: * * Copyright (c) 2017, Arm Limited. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * 3. Neither the names ARM, NuttX nor the names of its contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************/ #ifndef __FS_LITTLEFS_LFS_H #define __FS_LITTLEFS_LFS_H /**************************************************************************** * Included Files ****************************************************************************/ #include #include /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ /* Version info */ /* Software library version * Major (top-nibble), incremented on backwards incompatible changes * Minor (bottom-nibble), incremented on feature additions */ #define LFS_VERSION 0x00010007 #define LFS_VERSION_MAJOR (0xffff & (LFS_VERSION >> 16)) #define LFS_VERSION_MINOR (0xffff & (LFS_VERSION >> 0)) /* Version of On-disk data structures * Major (top-nibble), incremented on backwards incompatible changes * Minor (bottom-nibble), incremented on feature additions */ #define LFS_DISK_VERSION 0x00010001 #define LFS_DISK_VERSION_MAJOR (0xffff & (LFS_DISK_VERSION >> 16)) #define LFS_DISK_VERSION_MINOR (0xffff & (LFS_DISK_VERSION >> 0)) /* Max name size in bytes */ #ifndef LFS_NAME_MAX # define LFS_NAME_MAX NAME_MAX #endif /* Max file size in bytes */ #ifndef LFS_FILE_MAX # define LFS_FILE_MAX 2147483647 #endif /**************************************************************************** * Public Types ****************************************************************************/ typedef uint32_t lfs_size_t; typedef uint32_t lfs_off_t; typedef int32_t lfs_ssize_t; typedef int32_t lfs_soff_t; typedef uint32_t lfs_block_t; /* Possible error codes, these are negative to allow * valid positive return values */ enum lfs_error_e { LFS_ERR_OK = 0, /* No error */ LFS_ERR_IO = -5, /* Error during device operation */ LFS_ERR_CORRUPT = -52, /* Corrupted */ LFS_ERR_NOENT = -2, /* No directory entry */ LFS_ERR_EXIST = -17, /* Entry already exists */ LFS_ERR_NOTDIR = -20, /* Entry is not a dir */ LFS_ERR_ISDIR = -21, /* Entry is a dir */ LFS_ERR_NOTEMPTY = -39, /* Dir is not empty */ LFS_ERR_BADF = -9, /* Bad file number */ LFS_ERR_FBIG = -27, /* File too large */ LFS_ERR_INVAL = -22, /* Invalid parameter */ LFS_ERR_NOSPC = -28, /* No space left on device */ LFS_ERR_NOMEM = -12, /* No more memory available */ }; /* File types */ enum lfs_type_e { LFS_TYPE_REG = 0x11, LFS_TYPE_DIR = 0x22, LFS_TYPE_SUPERBLOCK = 0x2e, }; /* File open flags */ enum lfs_open_flags_e { /* open flags */ LFS_O_RDONLY = 1, /* Open a file as read only */ 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 */ /* internally used flags */ LFS_F_DIRTY = 0x10000, /* File does not match storage */ LFS_F_WRITING = 0x20000, /* File has been written since last flush */ LFS_F_READING = 0x40000, /* File has been read since last flush */ LFS_F_ERRED = 0x80000, /* An error occured during write */ }; /* File seek flags */ enum lfs_whence_flags_e { LFS_SEEK_SET = 0, /* Seek relative to an absolute position */ LFS_SEEK_CUR = 1, /* Seek relative to the current file position */ LFS_SEEK_END = 2, /* Seek relative to the end of the file */ }; /* Configuration provided during initialization of the littlefs */ struct lfs_config_s { /* Opaque user provided context that can be used to pass * information to the block device operations */ FAR void *context; /* Read a region in a block. Negative error codes are propagated * to the user. */ CODE int (*read)(FAR const struct lfs_config_s *c, lfs_block_t block, lfs_off_t off, FAR void *buffer, lfs_size_t size); /* Program a region in a block. The block must have previously * been erased. Negative error codes are propagated to the user. * May return LFS_ERR_CORRUPT if the block should be considered bad. */ CODE int (*prog)(FAR const struct lfs_config_s *c, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size); /* Erase a block. A block must be erased before being programmed. * The state of an erased block is undefined. Negative error codes * are propagated to the user. * May return LFS_ERR_CORRUPT if the block should be considered bad. */ CODE int (*erase)(FAR const struct lfs_config_s *c, lfs_block_t block); /* Sync the state of the underlying block device. Negative error codes * are propagated to the user. */ CODE int (*sync)(FAR const struct lfs_config_s *c); /* Minimum size of a block read. This determines the size of read buffers. * This may be larger than the physical read size to improve performance * by caching more of the block device. */ lfs_size_t read_size; /* Minimum size of a block program. This determines the size of program * buffers. This may be larger than the physical program size to improve * performance by caching more of the block device. * Must be a multiple of the read size. */ lfs_size_t prog_size; /* Size of an erasable block. This does not impact ram consumption and * may be larger than the physical erase size. However, this should be * kept small as each file currently takes up an entire block. * Must be a multiple of the program size. */ lfs_size_t block_size; /* Number of erasable blocks on the device. */ lfs_size_t block_count; /* Number of blocks to lookahead during block allocation. A larger * lookahead reduces the number of passes required to allocate a block. * The lookahead buffer requires only 1 bit per block so it can be quite * large with little ram impact. Should be a multiple of 32. */ lfs_size_t lookahead; /* Optional, statically allocated read buffer. Must be read sized. */ FAR void *read_buffer; /* Optional, statically allocated program buffer. Must be program sized. */ FAR void *prog_buffer; /* Optional, statically allocated lookahead buffer. Must be 1 bit per * lookahead block. */ FAR void *lookahead_buffer; /* Optional, statically allocated buffer for files. Must be program sized. * If enabled, only one file may be opened at a time. */ FAR void *file_buffer; }; /* Optional configuration provided during lfs_file_opencfg */ struct lfs_file_config_s { /* Optional, statically allocated buffer for files. Must be program sized. * If NULL, malloc will be used by default. */ FAR void *buffer; }; /* File info structure */ struct lfs_info_s { /* Type of the file, either LFS_TYPE_REG or LFS_TYPE_DIR */ uint8_t type; /* Size of the file, only valid for REG files */ lfs_size_t size; /* Name of the file stored as a null-terminated string */ char name[LFS_NAME_MAX+1]; }; /* littlefs data structures */ typedef struct lfs_entry_s { lfs_off_t off; struct lfs_disk_entry_s { uint8_t type; uint8_t elen; uint8_t alen; uint8_t nlen; union { struct { lfs_block_t head; lfs_size_t size; } file; lfs_block_t dir[2]; } u; } d; } lfs_entry_t; typedef struct lfs_cache_s { lfs_block_t block; lfs_off_t off; FAR uint8_t *buffer; } lfs_cache_t; typedef struct lfs_file_s { FAR struct lfs_file_s *next; lfs_block_t pair[2]; lfs_off_t poff; lfs_block_t head; lfs_size_t size; FAR const struct lfs_file_config_s *cfg; uint32_t flags; lfs_off_t pos; lfs_block_t block; lfs_off_t off; lfs_cache_t cache; } lfs_file_t; typedef struct lfs_dir_s { FAR struct lfs_dir_s *next; lfs_block_t pair[2]; lfs_off_t off; lfs_block_t head[2]; lfs_off_t pos; struct lfs_disk_dir_s { uint32_t rev; lfs_size_t size; lfs_block_t tail[2]; } d; } lfs_dir_t; typedef struct lfs_superblock_s { lfs_off_t off; struct lfs_disk_superblock_s { uint8_t type; uint8_t elen; uint8_t alen; uint8_t nlen; lfs_block_t root[2]; uint32_t block_size; uint32_t block_count; uint32_t version; char magic[8]; } d; } lfs_superblock_t; typedef struct lfs_free_s { lfs_block_t off; lfs_block_t size; lfs_block_t i; lfs_block_t ack; FAR uint32_t *buffer; } lfs_free_t; /* The littlefs type */ typedef struct lfs_s { FAR const struct lfs_config_s *cfg; lfs_block_t root[2]; FAR lfs_file_t *files; lfs_dir_t *dirs; lfs_cache_t rcache; lfs_cache_t pcache; lfs_free_t free; bool deorphaned; bool moving; } lfs_t; /**************************************************************************** * Public Data ****************************************************************************/ #ifdef __cplusplus extern "C" { #endif /**************************************************************************** * Public Function Prototypes ****************************************************************************/ /* Filesystem functions */ /* Format a block device with the littlefs * * Requires a littlefs object and config struct. This clobbers the littlefs * object, and does not leave the filesystem mounted. The config struct must * be zeroed for defaults and backwards compatibility. * * Returns a negative error code on failure. */ int lfs_format(FAR lfs_t *lfs, FAR const struct lfs_config_s *config); /* Mounts a littlefs * * Requires a littlefs object and config struct. Multiple filesystems * may be mounted simultaneously with multiple littlefs objects. Both * lfs and config must be allocated while mounted. The config struct must * be zeroed for defaults and backwards compatibility. * * Returns a negative error code on failure. */ int lfs_mount(FAR lfs_t *lfs, FAR const struct lfs_config_s *config); /* Unmounts a littlefs * * Does nothing besides releasing any allocated resources. * Returns a negative error code on failure. */ int lfs_unmount(FAR lfs_t *lfs); /* General operations */ /* Removes a file or directory * * If removing a directory, the directory must be empty. * Returns a negative error code on failure. */ int lfs_remove(FAR lfs_t *lfs, FAR const char *path); /* Rename or move a file or directory * * If the destination exists, it must match the source in type. * If the destination is a directory, the directory must be empty. * * Returns a negative error code on failure. */ int lfs_rename(FAR lfs_t *lfs, FAR const char *oldpath, FAR const char *newpath); /* Find info about a file or directory * * Fills out the info structure, based on the specified file or directory. * Returns a negative error code on failure. */ int lfs_stat(FAR lfs_t *lfs, FAR const char *path, FAR struct lfs_info_s *info); /* File operations */ /* Open a file * * The mode that the file is opened in is determined by the flags, which * are values from the enum lfs_open_flags that are bitwise-ored together. * * Returns a negative error code on failure. */ int lfs_file_open(FAR lfs_t *lfs, FAR lfs_file_t *file, FAR const char *path, int flags); /* Open a file with extra configuration * * The mode that the file is opened in is determined by the flags, which * are values from the enum lfs_open_flags that are bitwise-ored together. * * The config struct provides additional config options per file as described * above. The config struct must be allocated while the file is open, and the * config struct must be zeroed for defaults and backwards compatibility. * * Returns a negative error code on failure. */ int lfs_file_opencfg(FAR lfs_t *lfs, FAR lfs_file_t *file, FAR const char *path, int flags, FAR const struct lfs_file_config_s *config); /* Close a file * * Any pending writes are written out to storage as though * sync had been called and releases any allocated resources. * * Returns a negative error code on failure. */ int lfs_file_close(FAR lfs_t *lfs, FAR lfs_file_t *file); /* Synchronize a file on storage * * Any pending writes are written out to storage. * Returns a negative error code on failure. */ int lfs_file_sync(FAR lfs_t *lfs, FAR lfs_file_t *file); /* Read data from file * * Takes a buffer and size indicating where to store the read data. * Returns the number of bytes read, or a negative error code on failure. */ lfs_ssize_t lfs_file_read(FAR lfs_t *lfs, FAR lfs_file_t *file, FAR void *buffer, lfs_size_t size); /* Write data to file * * Takes a buffer and size indicating the data to write. The file will not * actually be updated on the storage until either sync or close is called. * * Returns the number of bytes written, or a negative error code on failure. */ lfs_ssize_t lfs_file_write(FAR lfs_t *lfs, FAR lfs_file_t *file, FAR const void *buffer, lfs_size_t size); /* Change the position of the file * * The change in position is determined by the offset and whence flag. * Returns the old position of the file, or a negative error code on failure. */ lfs_soff_t lfs_file_seek(FAR lfs_t *lfs, FAR lfs_file_t *file, lfs_soff_t off, int whence); /* Truncates the size of the file to the specified size * * Returns a negative error code on failure. */ int lfs_file_truncate(FAR FAR lfs_t *lfs, FAR lfs_file_t *file, lfs_off_t size); /* Return the position of the file * * Equivalent to lfs_file_seek(lfs, file, 0, LFS_SEEK_CUR) * Returns the position of the file, or a negative error code on failure. */ lfs_soff_t lfs_file_tell(FAR lfs_t *lfs, FAR lfs_file_t *file); /* Change the position of the file to the beginning of the file * * Equivalent to lfs_file_seek(lfs, file, 0, LFS_SEEK_CUR) * Returns a negative error code on failure. */ int lfs_file_rewind(FAR lfs_t *lfs, FAR lfs_file_t *file); /* Return the size of the file * * Similar to lfs_file_seek(lfs, file, 0, LFS_SEEK_END) * Returns the size of the file, or a negative error code on failure. */ lfs_soff_t lfs_file_size(FAR lfs_t *lfs, FAR lfs_file_t *file); /* Directory operations */ /* Create a directory * * Returns a negative error code on failure. */ int lfs_mkdir(FAR lfs_t *lfs, FAR const char *path); /* Open a directory * * Once open a directory can be used with read to iterate over files. * Returns a negative error code on failure. */ int lfs_dir_open(FAR lfs_t *lfs, FAR lfs_dir_t *dir, FAR const char *path); /* Close a directory * * Releases any allocated resources. * Returns a negative error code on failure. */ int lfs_dir_close(FAR lfs_t *lfs, FAR lfs_dir_t *dir); /* Read an entry in the directory * * Fills out the info structure, based on the specified file or directory. * Returns a negative error code on failure. */ int lfs_dir_read(FAR lfs_t *lfs, FAR lfs_dir_t *dir, FAR struct lfs_info_s *info); /* Change the position of the directory * * The new off must be a value previous returned from tell and specifies * an absolute offset in the directory seek. * * Returns a negative error code on failure. */ int lfs_dir_seek(FAR lfs_t *lfs, FAR lfs_dir_t *dir, lfs_off_t off); /* Return the position of the directory * * The returned offset is only meant to be consumed by seek and may not make * sense, but does indicate the current position in the directory iteration. * * Returns the position of the directory, or a negative error code on failure. */ lfs_soff_t lfs_dir_tell(FAR lfs_t *lfs, FAR lfs_dir_t *dir); /* Change the position of the directory to the beginning of the directory * * Returns a negative error code on failure. */ int lfs_dir_rewind(FAR lfs_t *lfs, FAR lfs_dir_t *dir); /* Miscellaneous littlefs specific operations */ /* Traverse through all blocks in use by the filesystem * * The provided callback will be called with each block address that is * currently in use by the filesystem. This can be used to determine which * blocks are in use or how much of the storage is available. * * Returns a negative error code on failure. */ int lfs_traverse(FAR lfs_t *lfs, CODE int (*cb)(FAR void *, lfs_block_t), FAR void *data); /* Prunes any recoverable errors that may have occured in the filesystem * * Not needed to be called by user unless an operation is interrupted * but the filesystem is still mounted. This is already called on first * allocation. * * Returns a negative error code on failure. */ int lfs_deorphan(FAR lfs_t *lfs); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* __FS_LITTLEFS_LFS_H */