diff --git a/fs/littlefs/lfs_vfs.c b/fs/littlefs/lfs_vfs.c index f7ff84b8ee7..cb055a1d94d 100644 --- a/fs/littlefs/lfs_vfs.c +++ b/fs/littlefs/lfs_vfs.c @@ -66,6 +66,17 @@ struct littlefs_mountpt_s struct lfs lfs; }; +struct littlefs_attr_s +{ + uint32_t at_ver; /* For the later extension */ + uint32_t at_mode; /* File type, attributes, and access mode bits */ + uint32_t at_uid; /* User ID of file */ + uint32_t at_gid; /* Group ID of file */ + uint64_t at_atim; /* Time of last access */ + uint64_t at_mtim; /* Time of last modification */ + uint64_t at_ctim; /* Time of last status change */ +}; + /**************************************************************************** * Private Function Prototypes ****************************************************************************/ @@ -90,6 +101,8 @@ 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_fchstat(FAR const struct file *filep, + FAR const struct stat *buf, int flags); static int littlefs_truncate(FAR struct file *filep, off_t length); @@ -121,6 +134,9 @@ static int littlefs_rename(FAR struct inode *mountpt, FAR const char *newrelpath); static int littlefs_stat(FAR struct inode *mountpt, FAR const char *relpath, FAR struct stat *buf); +static int littlefs_chstat(FAR struct inode *mountpt, + FAR const char *relpath, + FAR const struct stat *buf, int flags); /**************************************************************************** * Public Data @@ -143,7 +159,7 @@ const struct mountpt_operations littlefs_operations = littlefs_sync, /* sync */ littlefs_dup, /* dup */ littlefs_fstat, /* fstat */ - NULL, /* fchstat */ + littlefs_fchstat, /* fchstat */ littlefs_truncate, /* truncate */ littlefs_opendir, /* opendir */ @@ -160,7 +176,7 @@ const struct mountpt_operations littlefs_operations = littlefs_rmdir, /* rmdir */ littlefs_rename, /* rename */ littlefs_stat, /* stat */ - NULL /* chstat */ + littlefs_chstat /* chstat */ }; /**************************************************************************** @@ -274,6 +290,25 @@ static int littlefs_open(FAR struct file *filep, FAR const char *relpath, goto errout; } + if (oflags & LFS_O_CREAT) + { + struct littlefs_attr_s attr; + struct timespec time; + + clock_gettime(CLOCK_REALTIME, &time); + memset(&attr, 0, sizeof(attr)); + attr.at_mode = mode; + attr.at_ctim = 1000000000ull * time.tv_sec + time.tv_nsec; + attr.at_atim = attr.at_ctim; + attr.at_mtim = attr.at_ctim; + ret = lfs_setattr(&fs->lfs, relpath, 0, &attr, sizeof(attr)); + if (ret < 0) + { + lfs_remove(&fs->lfs, relpath); + goto errout_with_file; + } + } + /* In append mode, we need to set the file pointer to the end of the * file. */ @@ -620,6 +655,7 @@ static int littlefs_fstat(FAR const struct file *filep, FAR struct stat *buf) FAR struct littlefs_mountpt_s *fs; FAR struct littlefs_file_s *priv; FAR struct inode *inode; + char path[LFS_NAME_MAX]; int ret; memset(buf, 0, sizeof(*buf)); @@ -638,17 +674,57 @@ static int littlefs_fstat(FAR const struct file *filep, FAR struct stat *buf) return ret; } - buf->st_size = lfs_file_size(&fs->lfs, &priv->file); + ret = lfs_file_path(&fs->lfs, &priv->file, path, sizeof(path)); littlefs_semgive(fs); - - if (buf->st_size < 0) + if (ret < 0) { - return buf->st_size; + return ret; } - 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; + ret = littlefs_stat(inode, path, buf); + if (ret < 0) + { + return ret; + } + + return OK; +} + +static int littlefs_fchstat(FAR const struct file *filep, + FAR const struct stat *buf, int flags) +{ + FAR struct littlefs_mountpt_s *fs; + FAR struct littlefs_file_s *priv; + FAR struct inode *inode; + char path[LFS_NAME_MAX]; + 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 get file size */ + + ret = littlefs_semtake(fs); + if (ret < 0) + { + return ret; + } + + ret = lfs_file_path(&fs->lfs, &priv->file, path, sizeof(path)); + littlefs_semgive(fs); + if (ret < 0) + { + return ret; + } + + ret = littlefs_chstat(inode, path, buf, flags); + if (ret < 0) + { + return ret; + } return OK; } @@ -1341,6 +1417,7 @@ static int littlefs_stat(FAR struct inode *mountpt, FAR const char *relpath, { FAR struct littlefs_mountpt_s *fs; struct lfs_info info; + struct littlefs_attr_s attr; int ret; memset(buf, 0, sizeof(*buf)); @@ -1358,27 +1435,109 @@ static int littlefs_stat(FAR struct inode *mountpt, FAR const char *relpath, } ret = lfs_stat(&fs->lfs, relpath, &info); - littlefs_semgive(fs); - - if (ret >= 0) + 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; + goto errout; } + ret = lfs_getattr(&fs->lfs, relpath, 0, &attr, sizeof(attr)); + if (ret < 0) + { + if (ret != LFS_ERR_NOATTR) + { + goto errout; + } + + memset(&attr, 0, sizeof(attr)); + } + + buf->st_mode = attr.at_mode; + buf->st_uid = attr.at_uid; + buf->st_gid = attr.at_gid; + buf->st_atim.tv_sec = attr.at_atim / 1000000000ull; + buf->st_atim.tv_nsec = attr.at_atim % 1000000000ull; + buf->st_mtim.tv_sec = attr.at_mtim / 1000000000ull; + buf->st_mtim.tv_nsec = attr.at_mtim % 1000000000ull; + buf->st_ctim.tv_sec = attr.at_ctim / 1000000000ull; + buf->st_ctim.tv_nsec = attr.at_ctim % 1000000000ull; + 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; + +errout: + littlefs_semgive(fs); + return ret; +} + +static int littlefs_chstat(FAR struct inode *mountpt, + FAR const char *relpath, + FAR const struct stat *buf, int flags) +{ + FAR struct littlefs_mountpt_s *fs; + struct littlefs_attr_s attr; + int ret; + + /* Get the mountpoint private data from the inode structure */ + + fs = mountpt->i_private; + + /* Call LFS to get file size */ + + ret = littlefs_semtake(fs); + if (ret < 0) + { + return ret; + } + + ret = lfs_getattr(&fs->lfs, relpath, 0, &attr, sizeof(attr)); + if (ret < 0) + { + if (ret != LFS_ERR_NOATTR) + { + goto errout; + } + + memset(&attr, 0, sizeof(attr)); + } + + if ((CH_STAT_MODE & flags) == CH_STAT_MODE) + { + attr.at_mode = buf->st_mode; + } + + if ((CH_STAT_UID & flags) == CH_STAT_UID) + { + attr.at_uid = buf->st_uid; + } + + if ((CH_STAT_GID & flags) == CH_STAT_GID) + { + attr.at_gid = buf->st_gid; + } + + attr.at_ctim = 1000000000ull * buf->st_ctim.tv_sec + + buf->st_ctim.tv_nsec; + + if ((CH_STAT_ATIME & flags) == CH_STAT_ATIME) + { + attr.at_atim = 1000000000ull * buf->st_atim.tv_sec + + buf->st_atim.tv_nsec; + } + + if ((CH_STAT_MTIME & flags) == CH_STAT_MTIME) + { + attr.at_mtim = 1000000000ull * buf->st_mtim.tv_sec + + buf->st_mtim.tv_nsec; + } + + ret = lfs_setattr(&fs->lfs, relpath, 0, &attr, sizeof(attr)); + if (ret < 0) + { + goto errout; + } + +errout: + littlefs_semgive(fs); return ret; }