/**************************************************************************** * fs/littlefs/lfs_vfs.c * * 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. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include "lfs.h" #include "lfs_util.h" /**************************************************************************** * Private Types ****************************************************************************/ /* This structure represents the overall mountpoint state. An instance of this * structure is retained as inode private data on each mountpoint that is * mounted with a littlefs filesystem. */ struct littlefs_mountpt_s { sem_t sem; FAR struct inode *drv; struct mtd_geometry_s geo; struct lfs_config_s cfg; lfs_t lfs; }; /**************************************************************************** * Private Function Prototypes ****************************************************************************/ static void littlefs_semgive(FAR struct littlefs_mountpt_s *fs); static void littlefs_semtake(FAR struct littlefs_mountpt_s *fs); static int littlefs_open(FAR struct file *filep, FAR const char *relpath, int oflags, mode_t mode); static int littlefs_close(FAR struct file *filep); static ssize_t littlefs_read(FAR struct file *filep, FAR char *buffer, size_t buflen); static ssize_t littlefs_write(FAR struct file *filep, FAR const char *buffer, size_t buflen); static off_t littlefs_seek(FAR struct file *filep, off_t offset, int whence); static int littlefs_ioctl(FAR struct file *filep, int cmd, unsigned long arg); static int littlefs_sync(FAR struct file *filep); static int littlefs_dup(FAR const struct file *oldp, FAR struct file *newp); static int littlefs_fstat(FAR const struct file *filep, FAR struct stat *buf); static int littlefs_truncate(FAR struct file *filep, off_t length); static int littlefs_opendir(FAR struct inode *mountpt, FAR const char *relpath, FAR struct fs_dirent_s *dir); static int littlefs_closedir(FAR struct inode *mountpt, FAR struct fs_dirent_s *dir); static int littlefs_readdir(FAR struct inode *mountpt, FAR struct fs_dirent_s *dir); static int littlefs_rewinddir(FAR struct inode *mountpt, FAR struct fs_dirent_s *dir); static int littlefs_bind(FAR struct inode *driver, FAR const void *data, FAR void **handle); static int littlefs_unbind(FAR void *handle, FAR struct inode **driver, unsigned int flags); static int littlefs_statfs(FAR struct inode *mountpt, FAR struct statfs *buf); static int littlefs_unlink(FAR struct inode *mountpt, FAR const char *relpath); static int littlefs_mkdir(FAR struct inode *mountpt, FAR const char *relpath, mode_t mode); static int littlefs_rmdir(FAR struct inode *mountpt, FAR const char *relpath); static int littlefs_rename(FAR struct inode *mountpt, FAR const char *oldrelpath, FAR const char *newrelpath); static int littlefs_stat(FAR struct inode *mountpt, FAR const char *relpath, FAR struct stat *buf); /**************************************************************************** * Public Data ****************************************************************************/ /* See fs_mount.c -- this structure is explicitly extern'ed there. * We use the old-fashioned kind of initializers so that this will compile * with any compiler. */ const struct mountpt_operations littlefs_operations = { littlefs_open, /* open */ littlefs_close, /* close */ littlefs_read, /* read */ littlefs_write, /* write */ littlefs_seek, /* seek */ littlefs_ioctl, /* ioctl */ littlefs_sync, /* sync */ littlefs_dup, /* dup */ littlefs_fstat, /* fstat */ littlefs_truncate, /* truncate */ littlefs_opendir, /* opendir */ littlefs_closedir, /* closedir */ littlefs_readdir, /* readdir */ littlefs_rewinddir, /* rewinddir */ littlefs_bind, /* bind */ littlefs_unbind, /* unbind */ littlefs_statfs, /* statfs */ littlefs_unlink, /* unlink */ littlefs_mkdir, /* mkdir */ littlefs_rmdir, /* rmdir */ littlefs_rename, /* rename */ littlefs_stat /* stat */ }; /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** * Name: littlefs_semtake ****************************************************************************/ static void littlefs_semtake(FAR struct littlefs_mountpt_s *fs) { int ret; do { /* Take the semaphore (perhaps waiting) */ ret = nxsem_wait(&fs->sem); /* The only case that an error should occur here is if the wait was * awakened by a signal. */ DEBUGASSERT(ret == OK || ret == -EINTR); } while (ret == -EINTR); } /**************************************************************************** * Name: littlefs_semgive ****************************************************************************/ static void littlefs_semgive(FAR struct littlefs_mountpt_s *fs) { nxsem_post(&fs->sem); } /**************************************************************************** * Name: littlefs_convert_oflags ****************************************************************************/ static int littlefs_convert_oflags(int oflags) { int ret = 0; if ((oflags & O_RDONLY) != 0) { ret |= LFS_O_RDONLY; } if ((oflags & O_WRONLY) != 0) { ret |= LFS_O_WRONLY; } if ((oflags & O_CREAT) != 0) { ret |= LFS_O_CREAT; } if ((oflags & O_EXCL) != 0) { ret |= LFS_O_EXCL; } if ((oflags & O_APPEND) != 0) { ret |= LFS_O_APPEND; } if ((oflags & O_TRUNC) != 0) { ret |= LFS_O_TRUNC; } return ret; } /**************************************************************************** * Name: littlefs_open ****************************************************************************/ static int littlefs_open(FAR struct file *filep, FAR const char *relpath, int oflags, mode_t mode) { FAR struct littlefs_mountpt_s *fs; FAR struct lfs_file_s *priv; FAR struct inode *inode; int ret; /* Get the mountpoint inode reference from the file structure and the * mountpoint private data from the inode structure */ inode = filep->f_inode; fs = inode->i_private; /* Allocate memory for the open file */ priv = kmm_malloc(sizeof(*priv)); if (priv == NULL) { return -ENOMEM; } /* Take the semaphore */ littlefs_semtake(fs); /* Try to open the file */ oflags = littlefs_convert_oflags(oflags); ret = lfs_file_open(&fs->lfs, priv, relpath, oflags); if (ret < 0) { /* Error opening file */ goto errout; } /* In append mode, we need to set the file pointer to the end of the * file. */ if (oflags & LFS_O_APPEND) { ret = lfs_file_seek(&fs->lfs, priv, 0, LFS_SEEK_END); if (ret >= 0) { filep->f_pos = ret; } else { goto errout_with_file; } } littlefs_semgive(fs); /* Attach the private date to the struct file instance */ filep->f_priv = priv; return OK; errout_with_file: lfs_file_close(&fs->lfs, priv); errout: littlefs_semgive(fs); kmm_free(priv); return ret; } /**************************************************************************** * Name: littlefs_close ****************************************************************************/ static int littlefs_close(FAR struct file *filep) { FAR struct littlefs_mountpt_s *fs; FAR struct lfs_file_s *priv; FAR struct inode *inode; /* Recover our private data from the struct file instance */ priv = filep->f_priv; inode = filep->f_inode; fs = inode->i_private; /* Close the file */ littlefs_semtake(fs); lfs_file_close(&fs->lfs, priv); littlefs_semgive(fs); /* Now free the pointer */ kmm_free(priv); return OK; } /**************************************************************************** * Name: littlefs_read ****************************************************************************/ static ssize_t littlefs_read(FAR struct file *filep, FAR char *buffer, size_t buflen) { FAR struct littlefs_mountpt_s *fs; FAR struct lfs_file_s *priv; FAR struct inode *inode; ssize_t ret; /* Recover our private data from the struct file instance */ priv = filep->f_priv; inode = filep->f_inode; fs = inode->i_private; /* Call LFS to perform the read */ littlefs_semtake(fs); ret = lfs_file_read(&fs->lfs, priv, buffer, buflen); if (ret > 0) { filep->f_pos += ret; } littlefs_semgive(fs); return ret; } /**************************************************************************** * Name: littlefs_write ****************************************************************************/ static ssize_t littlefs_write(FAR struct file *filep, const char *buffer, size_t buflen) { FAR struct littlefs_mountpt_s *fs; FAR struct lfs_file_s *priv; FAR struct inode *inode; ssize_t ret; /* Recover our private data from the struct file instance */ priv = filep->f_priv; inode = filep->f_inode; fs = inode->i_private; /* Call LFS to perform the write */ littlefs_semtake(fs); ret = lfs_file_write(&fs->lfs, priv, buffer, buflen); if (ret > 0) { filep->f_pos += ret; } littlefs_semgive(fs); return ret; } /**************************************************************************** * Name: littlefs_seek ****************************************************************************/ static off_t littlefs_seek(FAR struct file *filep, off_t offset, int whence) { FAR struct littlefs_mountpt_s *fs; FAR struct lfs_file_s *priv; FAR struct inode *inode; off_t ret; /* Recover our private data from the struct file instance */ priv = filep->f_priv; inode = filep->f_inode; fs = inode->i_private; /* Call LFS to perform the seek */ littlefs_semtake(fs); ret = lfs_file_seek(&fs->lfs, priv, offset, whence); if (ret >= 0) { filep->f_pos = ret; } littlefs_semgive(fs); return ret; } /**************************************************************************** * Name: littlefs_ioctl ****************************************************************************/ static int littlefs_ioctl(FAR struct file *filep, int cmd, unsigned long arg) { FAR struct littlefs_mountpt_s *fs; FAR struct inode *inode; FAR struct inode *drv; /* Recover our private data from the struct file instance */ inode = filep->f_inode; fs = inode->i_private; drv = fs->drv; if (INODE_IS_MTD(drv)) { return MTD_IOCTL(drv->u.i_mtd, cmd, arg); } else { return drv->u.i_bops->ioctl(drv, cmd, arg); } } /**************************************************************************** * Name: littlefs_sync * * Description: Synchronize the file state on disk to match internal, in- * memory state. * ****************************************************************************/ static int littlefs_sync(FAR struct file *filep) { FAR struct littlefs_mountpt_s *fs; FAR struct lfs_file_s *priv; FAR struct inode *inode; int ret; /* Recover our private data from the struct file instance */ priv = filep->f_priv; inode = filep->f_inode; fs = inode->i_private; littlefs_semtake(fs); ret = lfs_file_sync(&fs->lfs, priv); littlefs_semgive(fs); return ret; } /**************************************************************************** * Name: littlefs_dup * * Description: Duplicate open file data in the new file structure. * ****************************************************************************/ static int littlefs_dup(FAR const struct file *oldp, FAR struct file *newp) { return -ENOSYS; } /**************************************************************************** * Name: littlefs_fstat * * Description: * Obtain information about an open file associated with the file * descriptor 'fd', and will write it to the area pointed to by 'buf'. * ****************************************************************************/ static int littlefs_fstat(FAR const struct file *filep, FAR struct stat *buf) { FAR struct littlefs_mountpt_s *fs; FAR struct lfs_file_s *priv; FAR struct inode *inode; memset(buf, 0, sizeof(*buf)); /* Recover our private data from the struct file instance */ priv = filep->f_priv; inode = filep->f_inode; fs = inode->i_private; /* Call LFS to get file size */ littlefs_semtake(fs); buf->st_size = lfs_file_size(&fs->lfs, priv); littlefs_semgive(fs); if (buf->st_size < 0) { return buf->st_size; } buf->st_mode = S_IRWXO | S_IRWXG | S_IRWXU | S_IFREG; buf->st_blksize = fs->cfg.block_size; buf->st_blocks = (buf->st_size + buf->st_blksize - 1) / buf->st_blksize; return OK; } /**************************************************************************** * Name: littlefs_truncate * * Description: * Set the length of the open, regular file associated with the file * structure 'filep' to 'length'. * ****************************************************************************/ static int littlefs_truncate(FAR struct file *filep, off_t length) { FAR struct littlefs_mountpt_s *fs; FAR struct lfs_file_s *priv; FAR struct inode *inode; int ret; /* Recover our private data from the struct file instance */ priv = filep->f_priv; inode = filep->f_inode; fs = inode->i_private; /* Call LFS to perform the truncate */ littlefs_semtake(fs); ret = lfs_file_truncate(&fs->lfs, priv, length); littlefs_semgive(fs); return ret; } /**************************************************************************** * Name: littlefs_opendir * * Description: Open a directory for read access * ****************************************************************************/ static int littlefs_opendir(FAR struct inode *mountpt, FAR const char *relpath, FAR struct fs_dirent_s *dir) { FAR struct littlefs_mountpt_s *fs; FAR struct lfs_dir_s *priv; int ret; /* Recover our private data from the inode instance */ fs = mountpt->i_private; /* Allocate memory for the open directory */ priv = kmm_malloc(sizeof(*priv)); if (priv == NULL) { return -ENOMEM; } /* Take the semaphore */ littlefs_semtake(fs); /* Call the LFS's opendir function */ ret = lfs_dir_open(&fs->lfs, priv, relpath); if (ret < 0) { goto errout; } dir->fd_position = lfs_dir_tell(&fs->lfs, priv); littlefs_semgive(fs); dir->u.littlefs = priv; return OK; errout: littlefs_semgive(fs); kmm_free(priv); return ret; } /**************************************************************************** * Name: littlefs_closedir * * Description: Close a directory * ****************************************************************************/ static int littlefs_closedir(FAR struct inode *mountpt, FAR struct fs_dirent_s *dir) { struct littlefs_mountpt_s *fs; FAR struct lfs_dir_s *priv; /* Recover our private data from the inode instance */ priv = dir->u.littlefs; fs = mountpt->i_private; /* Call the LFS's closedir function */ littlefs_semtake(fs); lfs_dir_close(&fs->lfs, priv); littlefs_semgive(fs); kmm_free(priv); return OK; } /**************************************************************************** * Name: littlefs_readdir * * Description: Read the next directory entry * ****************************************************************************/ static int littlefs_readdir(FAR struct inode *mountpt, FAR struct fs_dirent_s *dir) { FAR struct littlefs_mountpt_s *fs; FAR struct lfs_dir_s *priv; struct lfs_info_s info; int ret; /* Recover our private data from the inode instance */ priv = dir->u.littlefs; fs = mountpt->i_private; /* Call the LFS's readdir function */ littlefs_semtake(fs); ret = lfs_dir_read(&fs->lfs, priv, &info); if (ret > 0) { dir->fd_position = lfs_dir_tell(&fs->lfs, priv); if (info.type == LFS_TYPE_REG) { dir->fd_dir.d_type = DTYPE_FILE; } else { dir->fd_dir.d_type = DTYPE_DIRECTORY; } strcpy(dir->fd_dir.d_name, info.name); } else if (ret == 0) { ret = -ENOENT; } littlefs_semgive(fs); return ret; } /**************************************************************************** * Name: littlefs_rewindir * * Description: Reset directory read to the first entry * ****************************************************************************/ static int littlefs_rewinddir(FAR struct inode *mountpt, FAR struct fs_dirent_s *dir) { struct littlefs_mountpt_s *fs; FAR struct lfs_dir_s *priv; int ret; /* Recover our private data from the inode instance */ priv = dir->u.littlefs; fs = mountpt->i_private; /* Call the LFS's rewinddir function */ littlefs_semtake(fs); ret = lfs_dir_rewind(&fs->lfs, priv); if (ret >= 0) { dir->fd_position = lfs_dir_tell(&fs->lfs, priv); } littlefs_semgive(fs); return ret; } /**************************************************************************** * Name: littlefs_bind * * Description: This implements a portion of the mount operation. This * function allocates and initializes the mountpoint private data and * binds the driver inode to the filesystem private data. The final * binding of the private data (containing the driver) to the * mountpoint is performed by mount(). * ****************************************************************************/ static int littlefs_read_block(FAR const struct lfs_config_s *c, lfs_block_t block, lfs_off_t off, FAR void *buffer, lfs_size_t size) { FAR struct littlefs_mountpt_s *fs = c->context; FAR struct mtd_geometry_s *geo = &fs->geo; FAR struct inode *drv = fs->drv; int ret; block = (block * c->block_size + off) / geo->blocksize; size = size / geo->blocksize; if (INODE_IS_MTD(drv)) { ret = MTD_BREAD(drv->u.i_mtd, block, size, buffer); } else { ret = drv->u.i_bops->read(drv, buffer, block, size); } return ret >= 0 ? OK : ret; } /**************************************************************************** * Name: littlefs_write_block ****************************************************************************/ static int littlefs_write_block(FAR const struct lfs_config_s *c, lfs_block_t block, lfs_off_t off, FAR const void *buffer, lfs_size_t size) { FAR struct littlefs_mountpt_s *fs = c->context; FAR struct mtd_geometry_s *geo = &fs->geo; FAR struct inode *drv = fs->drv; int ret; block = (block * c->block_size + off) / geo->blocksize; size = size / geo->blocksize; if (INODE_IS_MTD(drv)) { ret = MTD_BWRITE(drv->u.i_mtd, block, size, buffer); } else { ret = drv->u.i_bops->write(drv, buffer, block, size); } return ret >= 0 ? OK : ret; } /**************************************************************************** * Name: littlefs_erase_block ****************************************************************************/ static int littlefs_erase_block(FAR const struct lfs_config_s *c, lfs_block_t block) { FAR struct littlefs_mountpt_s *fs = c->context; FAR struct inode *drv = fs->drv; int ret = OK; if (INODE_IS_MTD(drv)) { FAR struct mtd_geometry_s *geo = &fs->geo; size_t size = c->block_size / geo->erasesize; block = block * c->block_size / geo->erasesize; ret = MTD_ERASE(drv->u.i_mtd, block, size); } return ret >= 0 ? OK : ret; } /**************************************************************************** * Name: littlefs_sync_block ****************************************************************************/ static int littlefs_sync_block(FAR const struct lfs_config_s *c) { FAR struct littlefs_mountpt_s *fs = c->context; FAR struct inode *drv = fs->drv; int ret; if (INODE_IS_MTD(drv)) { ret = MTD_IOCTL(drv->u.i_mtd, BIOC_FLUSH, 0); } else { ret = drv->u.i_bops->ioctl(drv, BIOC_FLUSH, 0); } return ret == -ENOTTY ? OK : ret; } /**************************************************************************** * Name: littlefs_bind ****************************************************************************/ static int littlefs_bind(FAR struct inode *driver, FAR const void *data, FAR void **handle) { FAR struct littlefs_mountpt_s *fs; int ret; /* Open the block driver */ if (INODE_IS_BLOCK(driver) && driver->u.i_bops->open) { ret = driver->u.i_bops->open(driver); if (ret < 0) { return ret; } } /* Create an instance of the mountpt state structure */ fs = kmm_zalloc(sizeof(*fs)); if (!fs) { ret = -ENOMEM; goto errout_with_block; } /* Initialize the allocated mountpt state structure. The filesystem is * responsible for one reference on the driver inode and does not * have to addref() here (but does have to release in unbind(). */ fs->drv = driver; /* Save the driver reference */ nxsem_init(&fs->sem, 0, 0); /* Initialize the access control semaphore */ if (INODE_IS_MTD(driver)) { /* Get MTD geometry directly */ ret = MTD_IOCTL(driver->u.i_mtd, MTDIOC_GEOMETRY, (unsigned long)&fs->geo); } else { /* Try to get FLT MTD geometry first */ ret = driver->u.i_bops->ioctl(driver, MTDIOC_GEOMETRY, (unsigned long)&fs->geo); if (ret < 0) { struct geometry geometry; /* Not FLT MTD device, get normal block geometry */ ret = driver->u.i_bops->geometry(driver, &geometry); if (ret >= 0) { /* And convert to MTD geometry */ fs->geo.blocksize = geometry.geo_sectorsize; fs->geo.erasesize = geometry.geo_sectorsize; fs->geo.neraseblocks = geometry.geo_nsectors; } } } if (ret < 0) { goto errout_with_fs; } /* Initialize lfs_config structure */ fs->cfg.context = fs; fs->cfg.read = littlefs_read_block; fs->cfg.prog = littlefs_write_block; fs->cfg.erase = littlefs_erase_block; fs->cfg.sync = littlefs_sync_block; fs->cfg.read_size = fs->geo.blocksize; fs->cfg.prog_size = fs->geo.blocksize; fs->cfg.block_size = fs->geo.erasesize; fs->cfg.block_count = fs->geo.neraseblocks; fs->cfg.lookahead = 4 * ((fs->cfg.block_count + 31) / 32); if (fs->cfg.lookahead > fs->cfg.read_size) { fs->cfg.lookahead = fs->cfg.read_size; } /* Then get information about the littlefs filesystem on the devices * managed by this driver. */ /* Force format the device if -o forceformat */ if (data && strcmp(data, "forceformat") == 0) { ret = lfs_format(&fs->lfs, &fs->cfg); if (ret < 0) { goto errout_with_fs; } } ret = lfs_mount(&fs->lfs, &fs->cfg); if (ret < 0) { /* Auto format the device if -o autoformat */ if (ret != LFS_ERR_CORRUPT || !data || strcmp(data, "autoformat")) { goto errout_with_fs; } ret = lfs_format(&fs->lfs, &fs->cfg); if (ret < 0) { goto errout_with_fs; } /* Try to mount the device again */ ret = lfs_mount(&fs->lfs, &fs->cfg); if (ret < 0) { goto errout_with_fs; } } *handle = fs; littlefs_semgive(fs); return OK; errout_with_fs: nxsem_destroy(&fs->sem); kmm_free(fs); errout_with_block: if (INODE_IS_BLOCK(driver) && driver->u.i_bops->close) { driver->u.i_bops->close(driver); } return ret; } /**************************************************************************** * Name: littlefs_unbind * * Description: This implements the filesystem portion of the umount * operation. * ****************************************************************************/ static int littlefs_unbind(FAR void *handle, FAR struct inode **driver, unsigned int flags) { FAR struct littlefs_mountpt_s *fs = handle; FAR struct inode *drv = fs->drv; int ret; /* Unmount */ littlefs_semtake(fs); ret = lfs_unmount(&fs->lfs); littlefs_semgive(fs); if (ret >= 0) { /* Close the block driver */ if (INODE_IS_BLOCK(drv) && drv->u.i_bops->close) { drv->u.i_bops->close(drv); } /* We hold a reference to the driver but should not but * mucking with inodes in this context. So, we will just return * our contained reference to the driver inode and let the * umount logic dispose of it. */ if (driver) { *driver = drv; } /* Release the mountpoint private data */ nxsem_destroy(&fs->sem); kmm_free(fs); } return ret; } /**************************************************************************** * Name: littlefs_used_block ****************************************************************************/ static int littlefs_used_block(void *arg, lfs_block_t block) { FAR struct statfs *buf = arg; buf->f_bfree--; buf->f_bavail--; return 0; } /**************************************************************************** * Name: littlefs_statfs * * Description: Return filesystem statistics * ****************************************************************************/ static int littlefs_statfs(FAR struct inode *mountpt, FAR struct statfs *buf) { FAR struct littlefs_mountpt_s *fs; int ret; /* Get the mountpoint private data from the inode structure */ fs = mountpt->i_private; /* Return something for the file system description */ memset(buf, 0, sizeof(*buf)); buf->f_type = LITTLEFS_SUPER_MAGIC; buf->f_namelen = LFS_NAME_MAX; buf->f_bsize = fs->cfg.block_size; buf->f_blocks = fs->cfg.block_count; buf->f_bfree = fs->cfg.block_count; buf->f_bavail = fs->cfg.block_count; littlefs_semtake(fs); ret = lfs_traverse(&fs->lfs, littlefs_used_block, buf); littlefs_semgive(fs); return ret; } /**************************************************************************** * Name: littlefs_unlink * * Description: Remove a file * ****************************************************************************/ static int littlefs_unlink(FAR struct inode *mountpt, FAR const char *relpath) { FAR struct littlefs_mountpt_s *fs; int ret; /* Get the mountpoint private data from the inode structure */ fs = mountpt->i_private; /* Call the LFS to perform the unlink */ littlefs_semtake(fs); ret = lfs_remove(&fs->lfs, relpath); littlefs_semgive(fs); return ret; } /**************************************************************************** * Name: littlefs_mkdir * * Description: Create a directory * ****************************************************************************/ static int littlefs_mkdir(FAR struct inode *mountpt, FAR const char *relpath, mode_t mode) { FAR struct littlefs_mountpt_s *fs; int ret; /* Get the mountpoint private data from the inode structure */ fs = mountpt->i_private; /* Call LFS to do the mkdir */ littlefs_semtake(fs); ret = lfs_mkdir(&fs->lfs, relpath); littlefs_semgive(fs); return ret; } /**************************************************************************** * Name: littlefs_rmdir * * Description: Remove a directory * ****************************************************************************/ static int littlefs_rmdir(FAR struct inode *mountpt, FAR const char *relpath) { return littlefs_unlink(mountpt, relpath); } /**************************************************************************** * Name: littlefs_rename * * Description: Rename a file or directory * ****************************************************************************/ static int littlefs_rename(FAR struct inode *mountpt, FAR const char *oldrelpath, FAR const char *newrelpath) { FAR struct littlefs_mountpt_s *fs; int ret; /* Get the mountpoint private data from the inode structure */ fs = mountpt->i_private; /* Call LFS to do the rename */ littlefs_semtake(fs); ret = lfs_rename(&fs->lfs, oldrelpath, newrelpath); littlefs_semgive(fs); return ret; } /**************************************************************************** * Name: littlefs_stat * * Description: Return information about a file or directory * ****************************************************************************/ static int littlefs_stat(FAR struct inode *mountpt, FAR const char *relpath, FAR struct stat *buf) { FAR struct littlefs_mountpt_s *fs; struct lfs_info_s info; int ret; memset(buf, 0, sizeof(*buf)); /* Get the mountpoint private data from the inode structure */ fs = mountpt->i_private; /* Call the LFS to do the stat operation */ littlefs_semtake(fs); ret = lfs_stat(&fs->lfs, relpath, &info); littlefs_semgive(fs); if (ret >= 0) { /* Convert info to stat */ buf->st_mode = S_IRWXO | S_IRWXG | S_IRWXU; if (info.type == LFS_TYPE_REG) { buf->st_mode |= S_IFREG; } else { buf->st_mode |= S_IFDIR; } buf->st_size = info.size; buf->st_blksize = fs->cfg.block_size; buf->st_blocks = (buf->st_size + buf->st_blksize - 1) / buf->st_blksize; } return ret; }