123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242 |
- /****************************************************************************
- * 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 <li8303@163.com>
- *
- * 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 <nuttx/config.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <string.h>
- #include <nuttx/fs/dirent.h>
- #include <nuttx/fs/fs.h>
- #include <nuttx/mtd/mtd.h>
- #include <nuttx/semaphore.h>
- #include <sys/stat.h>
- #include <sys/statfs.h>
- #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;
- }
|