Browse Source

adapter DFS/memalloc/debug print

xieyangrun 7 years ago
parent
commit
5bd4b48e1e
4 changed files with 979 additions and 0 deletions
  1. 12 0
      SConscript
  2. 804 0
      dfs_lfs.c
  3. 145 0
      lfs_config.h
  4. 18 0
      lfs_crc.c

+ 12 - 0
SConscript

@@ -0,0 +1,12 @@
+# RT-Thread building script for component
+
+from building import *
+
+cwd = GetCurrentDir()
+src = Glob('*.c') + Glob('*.cpp') 
+CPPPATH = [cwd]
+CPPDEFINES = ['LFS_CONFIG=lfs_config.h']
+
+group = DefineGroup('littlefs', src, depend = ['RT_USING_LITTLEFS', 'RT_USING_DFS'], CPPPATH = CPPPATH, CPPDEFINES = CPPDEFINES)
+
+Return('group')

+ 804 - 0
dfs_lfs.c

@@ -0,0 +1,804 @@
+/*
+ * File      : dfs_lfs.c
+ * This file is part of Suzhou Allen
+ * COPYRIGHT (C) 2006 - 2017, Allen Development Team
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018��2��11��     Urey      first version
+ */
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#include <dfs_fs.h>
+#include <dfs_file.h>
+
+#include "lfs.h"
+
+#include <stdio.h>
+#include <string.h>
+
+
+#define RT_DFS_LFS_DRIVES    1
+
+#ifndef LFS_READ_SIZE
+#  define LFS_READ_SIZE   128
+#endif
+
+#ifndef LFS_PROG_SIZE
+#  define LFS_PROG_SIZE   256
+#endif
+
+#ifndef LFS_BLOCK_SIZE
+#  define LFS_BLOCK_SIZE  512
+#endif
+
+#ifndef LFS_LOOKAHEAD
+#  define LFS_LOOKAHEAD   512
+#endif
+
+typedef struct _dfs_lfs_s
+{
+    struct lfs lfs;
+    struct lfs_config cfg;
+} dfs_lfs_t;
+
+typedef struct _dfs_lfs_fd_s
+{
+    struct lfs *lfs;
+    union
+    {
+        struct lfs_file file;
+        struct lfs_dir  dir;
+    } u;
+} dfs_lfs_fd_t;
+
+static struct _dfs_lfs_s* _lfs_mount_tbl[RT_DFS_LFS_DRIVES] = {0};
+
+// Read a region in a block. Negative error codes are propogated
+// to the user.
+int _lfs_flash_read(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size)
+{
+    struct rt_mtd_nor_device* mtd_nor;
+
+    RT_ASSERT(c != RT_NULL);
+    RT_ASSERT(c->context != RT_NULL);
+
+    mtd_nor = (struct rt_mtd_nor_device*)c->context;
+    rt_mtd_nor_read(mtd_nor,block * c->block_size + off,buffer,size);
+
+    return LFS_ERR_OK;
+}
+
+// Program a region in a block. The block must have previously
+// been erased. Negative error codes are propogated to the user.
+// May return LFS_ERR_CORRUPT if the block should be considered bad.
+int _lfs_flash_prog(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size)
+{
+    struct rt_mtd_nor_device* mtd_nor;
+
+    RT_ASSERT(c != RT_NULL);
+    RT_ASSERT(c->context != RT_NULL);
+
+    mtd_nor = (struct rt_mtd_nor_device*)c->context;
+    rt_mtd_nor_write(mtd_nor,block*c->block_size + off,buffer,size);
+
+    return LFS_ERR_OK;
+}
+
+// Erase a block. A block must be erased before being programmed.
+// The state of an erased block is undefined. Negative error codes
+// are propogated to the user.
+// May return LFS_ERR_CORRUPT if the block should be considered bad.
+int _lfs_flash_erase(const struct lfs_config *c, lfs_block_t block)
+{
+    struct rt_mtd_nor_device* mtd_nor;
+
+    RT_ASSERT(c != RT_NULL);
+    RT_ASSERT(c->context != RT_NULL);
+
+    mtd_nor = (struct rt_mtd_nor_device*)c->context;
+    rt_mtd_nor_erase_block(mtd_nor,block * c->block_size,c->block_size);
+
+    return LFS_ERR_OK;
+}
+
+// Sync the state of the underlying block device. Negative error codes
+// are propogated to the user.
+int _lfs_flash_sync(const struct lfs_config *c)
+{
+    return LFS_ERR_OK;
+}
+
+/* results:
+ *  -1, no space to install fatfs driver
+ *  >= 0, there is an space to install fatfs driver
+ */
+static int get_disk(rt_device_t dev_id)
+{
+    int index;
+
+    if (dev_id == RT_NULL)
+    {
+        for (index = 0; index < RT_DFS_LFS_DRIVES; index ++)
+        {
+            if(_lfs_mount_tbl[index] == RT_NULL)
+            {
+                return index;
+            }
+        }
+    }
+    else
+    {
+        for (index = 0; index < RT_DFS_LFS_DRIVES; index ++)
+        {
+            if ((_lfs_mount_tbl[index] != RT_NULL)
+                && (_lfs_mount_tbl[index]->cfg.context == (void *)dev_id))
+            {
+                return index;
+            }
+        }
+    }
+
+    return -1;
+}
+
+static int lfs_result_to_dfs(int result)
+{
+    int status = 0;
+
+    switch (result)
+    {
+    case LFS_ERR_OK:
+        break;
+    case LFS_ERR_IO       : status = -EIO;      break;      // Error during device operation
+    case LFS_ERR_NOENT    : status = -ENOENT;   break;      // No directory entry
+    case LFS_ERR_EXIST    : status = -EEXIST;   break;      // Entry already exists
+    case LFS_ERR_NOTDIR   : status = -ENOTDIR;  break;      // Entry is not a dir
+    case LFS_ERR_ISDIR    : status = -EISDIR;   break;      // Entry is a dir
+    case LFS_ERR_NOTEMPTY : status = -ENOTEMPTY;break;      // Dir is not empty
+    case LFS_ERR_BADF     : status = -EBADF;    break;      // Bad file number
+    case LFS_ERR_INVAL    : status = -EINVAL;   break;      // Invalid parameter
+    case LFS_ERR_NOSPC    : status = -ENOSPC;   break;      // No space left on device
+    case LFS_ERR_NOMEM    : status = -ENOMEM;   break;      // No more memory available
+    case LFS_ERR_CORRUPT  : status = -52;       break;      // Corrupted
+    default               : status = -EIO;      break;
+    }
+
+    return status;
+}
+
+void _dfs_lfs_load_config(dfs_lfs_t *dfs_lfs,struct rt_mtd_nor_device *mtd_nor)
+{
+    dfs_lfs->cfg.context = (void *)mtd_nor;
+
+    //MTD device can access 1 byte....
+    dfs_lfs->cfg.read_size = 1;
+    if (dfs_lfs->cfg.read_size < LFS_READ_SIZE)
+    {
+        dfs_lfs->cfg.read_size = LFS_READ_SIZE;
+    }
+
+    //MTD device can access 1 byte....
+    dfs_lfs->cfg.prog_size = 1;
+    if (dfs_lfs->cfg.prog_size < LFS_PROG_SIZE)
+    {
+        dfs_lfs->cfg.prog_size = LFS_PROG_SIZE;
+    }
+
+    dfs_lfs->cfg.block_size = mtd_nor->block_size;
+    if (dfs_lfs->cfg.block_size < LFS_BLOCK_SIZE)
+    {
+        dfs_lfs->cfg.block_size = LFS_BLOCK_SIZE;
+    }
+
+    dfs_lfs->cfg.block_count = mtd_nor->block_end - mtd_nor->block_start;
+
+    dfs_lfs->cfg.lookahead = 32 * ((dfs_lfs->cfg.block_count + 31) / 32);
+    if (dfs_lfs->cfg.lookahead > LFS_LOOKAHEAD)
+    {
+        dfs_lfs->cfg.lookahead = LFS_LOOKAHEAD;
+    }
+
+    dfs_lfs->cfg.read        = &_lfs_flash_read;
+    dfs_lfs->cfg.prog        = &_lfs_flash_prog;
+    dfs_lfs->cfg.erase       = &_lfs_flash_erase;
+    dfs_lfs->cfg.sync        = &_lfs_flash_sync;
+}
+
+static int dfs_lfs_mount(struct dfs_filesystem *dfs, unsigned long rwflag, const void *data)
+{
+    int result;
+    dfs_lfs_t *dfs_lfs;
+    int index;
+
+    /* Check Device Type */
+    if (dfs->dev_id->type != RT_Device_Class_MTD)
+    {
+        rt_kprintf("The flash device type must be MTD!\n");
+        return -EINVAL;
+    }
+
+    /* get an empty position */
+    index = get_disk(RT_NULL);
+    if (index == -1)
+    {
+        return -EIO;
+    }
+
+    /*create lfs handle */
+    dfs_lfs = rt_malloc(sizeof(dfs_lfs_t));
+    if (dfs_lfs == RT_NULL)
+    {
+        rt_kprintf("ERROR:no memory!\n");
+
+        _lfs_mount_tbl[index] = RT_NULL;
+        return -ENOMEM;
+    }
+    rt_memset(dfs_lfs,0,sizeof(dfs_lfs_t));
+
+    { /* init cfg data */
+        struct rt_mtd_nor_device *mtd_nor = (struct rt_mtd_nor_device *)dfs->dev_id;
+
+        _dfs_lfs_load_config(dfs_lfs,mtd_nor);
+
+    }
+
+    /* mount lfs*/
+    result = lfs_mount(&dfs_lfs->lfs,&dfs_lfs->cfg);
+    if (result == LFS_ERR_OK)
+    {
+        /* save device */
+        _lfs_mount_tbl[index] = dfs_lfs;
+
+        /* mount succeed! */
+        dfs->data = (void *)dfs_lfs;
+
+        return RT_EOK;
+    }
+
+    /* release memory */
+    rt_free(dfs_lfs);
+    _lfs_mount_tbl[index] = RT_NULL;
+    return -EIO;
+}
+
+static int dfs_lfs_unmount(struct dfs_filesystem *dfs)
+{
+    int index;
+    dfs_lfs_t *dfs_lfs = RT_NULL;
+
+    RT_ASSERT(dfs != RT_NULL);
+    RT_ASSERT(dfs->data != RT_NULL);
+
+    dfs_lfs = (dfs_lfs_t *)dfs->data;
+
+    /* find the device index and then umount it */
+    index = get_disk(dfs->dev_id);
+    if (index == -1) /* not found */
+    {
+        return -ENOENT;
+    }
+
+    dfs_lfs = _lfs_mount_tbl[index];
+    _lfs_mount_tbl[index] = RT_NULL;
+    dfs->data = RT_NULL;
+
+    lfs_unmount(&dfs_lfs->lfs);
+    rt_free(dfs_lfs);
+
+    return RT_EOK;
+}
+
+static int dfs_lfs_mkfs(rt_device_t dev_id)
+{
+    dfs_lfs_t *dfs_lfs = RT_NULL;
+    int result;
+    int index;
+
+    if (dev_id == RT_NULL)
+    {
+        return -EINVAL;
+    }
+
+    /* Check Device Type */
+    if (dev_id->type != RT_Device_Class_MTD)
+    {
+        rt_kprintf("The flash device type must be MTD!\n");
+        return -EINVAL;
+    }
+
+    index = get_disk(dev_id);
+    if (index == -1)
+    {
+        /* not found the device id */
+        index = get_disk(RT_NULL);
+        if (index == -1)
+        {
+            /* no space to store an temp driver */
+            rt_kprintf("sorry, there is no space to do mkfs! \n");
+            return -ENOSPC;
+        }
+        else
+        {
+            /*create lfs handle */
+            dfs_lfs = rt_malloc(sizeof(dfs_lfs_t));
+
+            if (dfs_lfs == RT_NULL)
+            {
+                rt_kprintf("ERROR:no memory!\n");
+
+                _lfs_mount_tbl[index] = RT_NULL;
+                return -ENOMEM;
+            }
+            rt_memset(dfs_lfs,0,sizeof(dfs_lfs_t));
+
+            { /* init cfg data */
+                struct rt_mtd_nor_device *mtd_nor = (struct rt_mtd_nor_device *)dev_id;
+
+                _dfs_lfs_load_config(dfs_lfs,mtd_nor);
+            }
+        }
+    }
+    else
+    {
+        dfs_lfs =  _lfs_mount_tbl[index];
+        _lfs_mount_tbl[index] = RT_NULL;
+
+        /* unmount it */
+        lfs_unmount(&dfs_lfs->lfs);
+    }
+
+    /* format flash device */
+    result = lfs_format(&dfs_lfs->lfs,&dfs_lfs->cfg);
+    if (result != LFS_ERR_OK)
+    {
+        return lfs_result_to_dfs(result);
+    }
+
+    /* release rt_spiffs */
+    return RT_EOK;
+}
+
+static int _dfs_lfs_statfs_count(void *p, lfs_block_t b)
+{
+    *(lfs_size_t *) p += 1;
+    return 0;
+}
+
+static int dfs_lfs_statfs(struct dfs_filesystem *dfs, struct statfs *buf)
+{
+    dfs_lfs_t *dfs_lfs ;
+    int result;
+    lfs_size_t in_use = 0;
+
+    RT_ASSERT(buf != RT_NULL);
+    RT_ASSERT(dfs != RT_NULL);
+    RT_ASSERT(dfs->data != RT_NULL);
+
+    dfs_lfs = (dfs_lfs_t *)dfs->data;
+
+    /* Get total sectors and free sectors */
+    result = lfs_traverse(&dfs_lfs->lfs, _dfs_lfs_statfs_count, &in_use);
+    if (result != LFS_ERR_OK)
+    {
+        return lfs_result_to_dfs(result);
+    }
+
+    buf->f_bsize = dfs_lfs->cfg.block_size;
+    buf->f_blocks = dfs_lfs->cfg.block_count;
+    buf->f_bfree  = dfs_lfs->cfg.block_count - in_use;
+
+    return RT_EOK;
+}
+
+static int dfs_lfs_unlink(struct dfs_filesystem *dfs, const char *path)
+{
+    dfs_lfs_t *dfs_lfs;
+    int result;
+
+    RT_ASSERT(dfs != RT_NULL);
+    RT_ASSERT(dfs->data != RT_NULL);
+    dfs_lfs = (dfs_lfs_t *)dfs->data;
+
+    result = lfs_remove(&dfs_lfs->lfs,path);
+    return lfs_result_to_dfs(result);
+}
+
+static void _dfs_lfs_tostat(struct stat *st, struct lfs_info *info)
+{
+    memset(st, 0, sizeof(struct stat));
+
+    /* convert to dfs stat structure */
+    st->st_dev = 0;
+    st->st_size = info->size;
+    st->st_mode = S_IRWXU | S_IRWXG | S_IRWXO;
+
+    switch (info->type)
+    {
+    case LFS_TYPE_DIR:
+        st->st_mode |= S_IFDIR;
+        break;
+
+    case LFS_TYPE_REG:
+        st->st_mode |= S_IFREG;
+        break;
+    }
+
+}
+
+int dfs_lfs_stat(struct dfs_filesystem *dfs, const char *path, struct stat *st)
+{
+    dfs_lfs_t *dfs_lfs;
+    int result;
+    struct lfs_info info;
+
+    RT_ASSERT(dfs != RT_NULL);
+    RT_ASSERT(dfs->data != RT_NULL);
+    dfs_lfs = (dfs_lfs_t *)dfs->data;
+
+    result = lfs_stat(&dfs_lfs->lfs, path, &info);
+    if(result != LFS_ERR_OK)
+    {
+        return lfs_result_to_dfs(result);
+    }
+
+    _dfs_lfs_tostat(st, &info);
+    return 0;
+}
+
+static int dfs_lfs_rename(struct dfs_filesystem *dfs, const char *from, const char *to)
+{
+    dfs_lfs_t *dfs_lfs;
+    int result;
+
+    RT_ASSERT(dfs != RT_NULL);
+    RT_ASSERT(dfs->data != RT_NULL);
+    dfs_lfs = (dfs_lfs_t *)dfs->data;
+
+    result = lfs_rename(&dfs_lfs->lfs, from, to);
+    return lfs_result_to_dfs(result);
+}
+
+
+/******************************************************************************
+ * file operations
+ ******************************************************************************/
+static int dfs_lfs_open(struct dfs_fd *file)
+{
+    struct dfs_filesystem* dfs;
+    dfs_lfs_t* dfs_lfs;
+    int result;
+    int flags = 0;
+
+    RT_ASSERT(file != RT_NULL);
+    RT_ASSERT(file->data != RT_NULL);
+    dfs = (struct dfs_filesystem *) file->data;
+    dfs_lfs = (dfs_lfs_t *)dfs->data;
+
+    if (file->flags & O_DIRECTORY)
+    {
+        dfs_lfs_fd_t*   dfs_lfs_fd  = rt_malloc(sizeof(dfs_lfs_fd_t));
+        if (dfs_lfs_fd == RT_NULL)
+        {
+            rt_kprintf("ERROR:no memory!\n");
+            result = -ENOMEM;
+
+            goto _error_dir;
+        }
+        rt_memset(dfs_lfs_fd,0,sizeof(dfs_lfs_fd_t));
+        dfs_lfs_fd->lfs = &dfs_lfs->lfs;
+
+        if (file->flags & O_CREAT)
+        {
+            result = lfs_mkdir(dfs_lfs_fd->lfs,file->path);
+            if (result != LFS_ERR_OK)
+            {
+                goto _error_dir;
+            }
+        }
+
+        result = lfs_dir_open(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.dir, file->path);
+        if (result != LFS_ERR_OK)
+        {
+            goto _error_dir;
+        }
+        else
+        {
+            file->data = (void *)dfs_lfs_fd;
+            return RT_EOK;
+        }
+
+_error_dir:
+        if (dfs_lfs_fd != RT_NULL)
+        {
+            rt_free(dfs_lfs_fd);
+        }
+
+        return lfs_result_to_dfs(result);
+    }
+    else
+    {
+        dfs_lfs_fd_t*   dfs_lfs_fd  = rt_malloc(sizeof(dfs_lfs_fd_t));
+        if(dfs_lfs_fd == RT_NULL)
+        {
+            rt_kprintf("ERROR:no memory!\n");
+            result = -ENOMEM;
+
+            goto _error_file;
+        }
+        rt_memset(dfs_lfs_fd,0,sizeof(dfs_lfs_fd_t));
+        dfs_lfs_fd->lfs = &dfs_lfs->lfs;
+
+
+        if ((file->flags & 3) == O_RDONLY)  flags |= LFS_O_RDONLY;
+        if ((file->flags & 3) == O_WRONLY)  flags |= LFS_O_WRONLY;
+        if ((file->flags & 3) == O_RDWR)    flags |= LFS_O_RDWR;
+        if (file->flags & O_CREAT)          flags |= LFS_O_CREAT;
+        if (file->flags & O_EXCL)           flags |= LFS_O_EXCL;
+        if (file->flags & O_TRUNC)          flags |= LFS_O_TRUNC;
+        if (file->flags & O_APPEND)         flags |= LFS_O_APPEND;
+
+        result = lfs_file_open(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.file, file->path, flags);
+        if (result != LFS_ERR_OK)
+        {
+            goto _error_file;
+        }
+        else
+        {
+            file->data = (void *)dfs_lfs_fd;
+            return RT_EOK;
+        }
+
+_error_file:
+        if (dfs_lfs_fd != RT_NULL)
+        {
+            rt_free(dfs_lfs_fd);
+        }
+
+        return lfs_result_to_dfs(result);
+    }
+}
+
+static int dfs_lfs_close(struct dfs_fd *file)
+{
+    int result;
+    dfs_lfs_fd_t* dfs_lfs_fd;
+    RT_ASSERT(file != RT_NULL);
+    RT_ASSERT(file->data != RT_NULL);
+
+    dfs_lfs_fd  = (dfs_lfs_fd_t *)file->data;
+
+    if (file->type == FT_DIRECTORY)
+    {
+        result = lfs_dir_close(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.dir);
+    }
+    else
+    {
+        result = lfs_file_close(dfs_lfs_fd->lfs,&dfs_lfs_fd->u.file);
+    }
+
+    rt_free(dfs_lfs_fd);
+
+    return lfs_result_to_dfs(result);
+}
+
+static int dfs_lfs_ioctl(struct dfs_fd *file, int cmd, void *args)
+{
+    return -ENOSYS;
+}
+
+int dfs_lfs_read(struct dfs_fd *file, void *buf, size_t len)
+{
+    lfs_ssize_t ssize;
+    dfs_lfs_fd_t* dfs_lfs_fd;
+    RT_ASSERT(file != RT_NULL);
+    RT_ASSERT(file->data != RT_NULL);
+    dfs_lfs_fd = (dfs_lfs_fd_t*)file->data;
+
+    if (file->type == FT_DIRECTORY)
+    {
+        return -EISDIR;
+    }
+
+    if (lfs_file_tell(dfs_lfs_fd->lfs,&dfs_lfs_fd->u.file) != file->pos)
+    {
+        lfs_soff_t soff = lfs_file_seek(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.file, file->pos, LFS_SEEK_SET);
+        if (soff < 0)
+        {
+            return lfs_result_to_dfs(soff);
+        }
+    }
+
+    ssize = lfs_file_read(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.file,buf,len);
+    if (ssize < 0)
+    {
+        return lfs_result_to_dfs(ssize);
+    }
+
+    /* update position */
+    file->pos  = dfs_lfs_fd->u.file.pos;
+
+    return ssize;
+}
+
+int dfs_lfs_write(struct dfs_fd *file, const void *buf, size_t len)
+{
+    lfs_ssize_t ssize;
+    dfs_lfs_fd_t* dfs_lfs_fd;
+    RT_ASSERT(file != RT_NULL);
+    RT_ASSERT(file->data != RT_NULL);
+
+    if (file->type == FT_DIRECTORY)
+    {
+        return -EISDIR;
+    }
+
+    dfs_lfs_fd = (dfs_lfs_fd_t *)file->data;
+    if (lfs_file_tell(dfs_lfs_fd->lfs,&dfs_lfs_fd->u.file) != file->pos)
+    {
+        lfs_soff_t soff = lfs_file_seek(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.file, file->pos, LFS_SEEK_SET);
+        if (soff < 0)
+        {
+            return lfs_result_to_dfs(soff);
+        }
+    }
+
+    ssize = lfs_file_write(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.file, buf, len);
+    if (ssize < 0)
+    {
+        return lfs_result_to_dfs(ssize);
+    }
+
+    /* update position and file size */
+    file->pos  = dfs_lfs_fd->u.file.pos;
+    file->size = dfs_lfs_fd->u.file.size;
+    return ssize;
+}
+
+int dfs_lfs_flush(struct dfs_fd *file)
+{
+    int result;
+    dfs_lfs_fd_t* dfs_lfs_fd;
+    RT_ASSERT(file != RT_NULL);
+    RT_ASSERT(file->data != RT_NULL);
+
+    dfs_lfs_fd = (dfs_lfs_fd_t *)file->data;
+
+    result = lfs_file_sync(dfs_lfs_fd->lfs,&dfs_lfs_fd->u.file);
+
+    return lfs_result_to_dfs(result);
+}
+
+int dfs_lfs_lseek(struct dfs_fd *file, rt_off_t offset)
+{
+    dfs_lfs_fd_t* dfs_lfs_fd;
+    RT_ASSERT(file != RT_NULL);
+    RT_ASSERT(file->data != RT_NULL);
+
+    dfs_lfs_fd = (dfs_lfs_fd_t *)file->data;
+
+    if (file->type == FT_REGULAR)
+    {
+        lfs_soff_t soff = lfs_file_seek(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.file, offset, LFS_SEEK_SET);
+        if (soff < 0)
+        {
+            return lfs_result_to_dfs(soff);
+        }
+
+        file->pos = dfs_lfs_fd->u.file.pos;
+    }
+    else if (file->type == FT_DIRECTORY)
+    {
+        lfs_soff_t soff = lfs_dir_seek(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.dir, offset);
+        if (soff < 0)
+        {
+            return lfs_result_to_dfs(soff);
+        }
+
+        file->pos = dfs_lfs_fd->u.dir.pos;
+    }
+
+    return (file->pos);
+}
+
+
+int dfs_lfs_getdents(struct dfs_fd *file, struct dirent *dirp, uint32_t count)
+{
+    dfs_lfs_fd_t* dfs_lfs_fd;
+    int result;
+    int index;
+    struct dirent *d;
+    struct lfs_info info;
+
+    RT_ASSERT(file->data != RT_NULL);
+    dfs_lfs_fd = (dfs_lfs_fd_t *)(file->data);
+
+    /* make integer count */
+    count = (count / sizeof(struct dirent)) * sizeof(struct dirent);
+    if (count == 0)
+    {
+        return -EINVAL;
+    }
+
+    index = 0;
+    while (1)
+    {
+        d = dirp + index;
+
+        result = lfs_dir_read(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.dir, &info);
+        if ((result != 1) || (info.name[0] == 0))
+        {
+            return result;
+        }
+
+        d->d_type = DT_UNKNOWN;
+        switch (info.type)
+        {
+            case LFS_TYPE_DIR:
+                d->d_type |= DT_DIR;
+            break;
+            case LFS_TYPE_REG:
+                d->d_type |= DT_REG;
+            break;
+        }
+
+        d->d_namlen = (rt_uint8_t)rt_strlen(info.name);
+        d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
+        rt_strncpy(d->d_name, info.name, rt_strlen(info.name) + 1);
+
+        index ++;
+        if (index * sizeof(struct dirent) >= count)
+        {
+            break;
+        }
+    }
+
+    if (index == 0)
+    {
+        return lfs_result_to_dfs(result);
+    }
+
+    file->pos += index * sizeof(struct dirent);
+
+    return index * sizeof(struct dirent);
+}
+
+static const struct dfs_file_ops _dfs_lfs_fops =
+{
+    dfs_lfs_open,
+    dfs_lfs_close,
+    dfs_lfs_ioctl,
+    dfs_lfs_read,
+    dfs_lfs_write,
+    dfs_lfs_flush,
+    dfs_lfs_lseek,
+    dfs_lfs_getdents,
+//    RT_NULL, /* poll interface */
+};
+
+static const struct dfs_filesystem_ops _dfs_lfs_ops =
+{
+    "lfs",
+    DFS_FS_FLAG_DEFAULT,
+    &_dfs_lfs_fops,
+
+    dfs_lfs_mount,
+    dfs_lfs_unmount,
+
+    dfs_lfs_mkfs,
+    dfs_lfs_statfs,
+    dfs_lfs_unlink,
+    dfs_lfs_stat,
+    dfs_lfs_rename,
+};
+
+int dfs_lfs_init(void)
+{
+    /* register ram file system */
+    dfs_register(&_dfs_lfs_ops);
+
+    return 0;
+}
+INIT_COMPONENT_EXPORT(dfs_lfs_init);
+

+ 145 - 0
lfs_config.h

@@ -0,0 +1,145 @@
+#ifndef _LFS_CONFIG_H_
+#define _LFS_CONFIG_H_
+
+#include <rtthread.h>
+
+// System includes
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+
+// Macros, may be replaced by system specific wrappers. Arguments to these
+// macros must not have side-effects as the macros can be removed for a smaller
+// code footprint
+
+// Logging functions
+#ifndef LFS_NO_DEBUG
+#define LFS_DEBUG(fmt, ...) \
+    rt_kprintf("lfs debug:%d: " fmt "\n", __LINE__, __VA_ARGS__)
+#else
+#define LFS_DEBUG(fmt, ...)
+#endif
+
+#ifndef LFS_NO_WARN
+#define LFS_WARN(fmt, ...) \
+    rt_kprintf("lfs warn:%d: " fmt "\n", __LINE__, __VA_ARGS__)
+#else
+#define LFS_WARN(fmt, ...)
+#endif
+
+#ifndef LFS_NO_ERROR
+#define LFS_ERROR(fmt, ...) \
+    rt_kprintf("lfs error:%d: " fmt "\n", __LINE__, __VA_ARGS__)
+#else
+#define LFS_ERROR(fmt, ...)
+#endif
+
+// Runtime assertions
+#ifndef LFS_NO_ASSERT
+#define LFS_ASSERT(test) RT_ASSERT(test)
+#else
+#define LFS_ASSERT(test)
+#endif
+
+
+// Builtin functions, these may be replaced by more efficient
+// toolchain-specific implementations. LFS_NO_INTRINSICS falls back to a more
+// expensive basic C implementation for debugging purposes
+
+// Min/max functions for unsigned 32-bit numbers
+static inline uint32_t lfs_max(uint32_t a, uint32_t b) {
+    return (a > b) ? a : b;
+}
+
+static inline uint32_t lfs_min(uint32_t a, uint32_t b) {
+    return (a < b) ? a : b;
+}
+
+// Find the next smallest power of 2 less than or equal to a
+static inline uint32_t lfs_npw2(uint32_t a) {
+#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM))
+    return 32 - __builtin_clz(a-1);
+#else
+    uint32_t r = 0;
+    uint32_t s;
+    a -= 1;
+    s = (a > 0xffff) << 4; a >>= s; r |= s;
+    s = (a > 0xff  ) << 3; a >>= s; r |= s;
+    s = (a > 0xf   ) << 2; a >>= s; r |= s;
+    s = (a > 0x3   ) << 1; a >>= s; r |= s;
+    return (r | (a >> 1)) + 1;
+#endif
+}
+
+// Count the number of trailing binary zeros in a
+// lfs_ctz(0) may be undefined
+static inline uint32_t lfs_ctz(uint32_t a) {
+#if !defined(LFS_NO_INTRINSICS) && defined(__GNUC__)
+    return __builtin_ctz(a);
+#else
+    return lfs_npw2((a & -a) + 1) - 1;
+#endif
+}
+
+// Count the number of binary ones in a
+static inline uint32_t lfs_popc(uint32_t a) {
+#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM))
+    return __builtin_popcount(a);
+#else
+    a = a - ((a >> 1) & 0x55555555);
+    a = (a & 0x33333333) + ((a >> 2) & 0x33333333);
+    return (((a + (a >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24;
+#endif
+}
+
+// Find the sequence comparison of a and b, this is the distance
+// between a and b ignoring overflow
+static inline int lfs_scmp(uint32_t a, uint32_t b) {
+    return (int)(unsigned)(a - b);
+}
+
+// Convert from 32-bit little-endian to native order
+static inline uint32_t lfs_fromle32(uint32_t a) {
+#if !defined(LFS_NO_INTRINSICS) && ( \
+    (defined(  BYTE_ORDER  ) &&   BYTE_ORDER   ==   ORDER_LITTLE_ENDIAN  ) || \
+    (defined(__BYTE_ORDER  ) && __BYTE_ORDER   == __ORDER_LITTLE_ENDIAN  ) || \
+    (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
+    return a;
+#elif !defined(LFS_NO_INTRINSICS) && ( \
+    (defined(  BYTE_ORDER  ) &&   BYTE_ORDER   ==   ORDER_BIG_ENDIAN  ) || \
+    (defined(__BYTE_ORDER  ) && __BYTE_ORDER   == __ORDER_BIG_ENDIAN  ) || \
+    (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
+    return __builtin_bswap32(a);
+#else
+    return (((uint8_t*)&a)[0] <<  0) |
+           (((uint8_t*)&a)[1] <<  8) |
+           (((uint8_t*)&a)[2] << 16) |
+           (((uint8_t*)&a)[3] << 24);
+#endif
+}
+
+// Convert to 32-bit little-endian from native order
+static inline uint32_t lfs_tole32(uint32_t a) {
+    return lfs_fromle32(a);
+}
+
+// Calculate CRC-32 with polynomial = 0x04c11db7
+void lfs_crc(uint32_t *crc, const void *buffer, size_t size);
+
+// Allocate memory, only used if buffers are not provided to littlefs
+static inline void *lfs_malloc(size_t size) {
+#ifndef LFS_NO_MALLOC
+    return rt_malloc(size);
+#else
+    return NULL;
+#endif
+}
+
+// Deallocate memory, only used if buffers are not provided to littlefs
+static inline void lfs_free(void *p) {
+#ifndef LFS_NO_MALLOC
+    rt_free(p);
+#endif
+}
+
+#endif

+ 18 - 0
lfs_crc.c

@@ -0,0 +1,18 @@
+#include "lfs_util.h"
+
+// Software CRC implementation with small lookup table
+void lfs_crc(uint32_t *restrict crc, const void *buffer, size_t size) {
+    static const uint32_t rtable[16] = {
+        0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
+        0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
+        0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
+        0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c,
+    };
+
+    const uint8_t *data = buffer;
+
+    for (size_t i = 0; i < size; i++) {
+        *crc = (*crc >> 4) ^ rtable[(*crc ^ (data[i] >> 0)) & 0xf];
+        *crc = (*crc >> 4) ^ rtable[(*crc ^ (data[i] >> 4)) & 0xf];
+    }
+}