From 7a90be0ce1fc7d35b2500867475f482daf921a71 Mon Sep 17 00:00:00 2001 From: Deepika Date: Thu, 28 Dec 2017 16:38:20 -0600 Subject: [PATCH 1/4] Added statvfs API to get storage statistics The API is as per posix standard, but does not provide stats for file/directory. Stats buffer (block size, total block count, free block count) is filled for entire mounted filesystem. --- features/filesystem/FileSystem.cpp | 5 ++++ features/filesystem/FileSystem.h | 12 ++++++-- features/filesystem/fat/FATFileSystem.cpp | 28 +++++++++++++++++++ features/filesystem/fat/FATFileSystem.h | 16 ++++++++--- .../filesystem/littlefs/LittleFileSystem.cpp | 3 ++ .../filesystem/littlefs/LittleFileSystem.h | 8 ++++++ platform/FileSystemHandle.cpp | 5 ++++ platform/FileSystemHandle.h | 8 ++++++ platform/mbed_retarget.cpp | 17 +++++++++++ platform/mbed_retarget.h | 21 ++++++++++++-- 10 files changed, 114 insertions(+), 9 deletions(-) diff --git a/features/filesystem/FileSystem.cpp b/features/filesystem/FileSystem.cpp index b356b0a037..99f98d2fe9 100644 --- a/features/filesystem/FileSystem.cpp +++ b/features/filesystem/FileSystem.cpp @@ -51,6 +51,11 @@ int FileSystem::mkdir(const char *path, mode_t mode) return -ENOSYS; } +int FileSystem::statvfs(const char *path, struct statvfs *buf) +{ + return -ENOSYS; +} + int FileSystem::file_sync(fs_file_t file) { return 0; diff --git a/features/filesystem/FileSystem.h b/features/filesystem/FileSystem.h index 06659f3830..9b95e35dd8 100644 --- a/features/filesystem/FileSystem.h +++ b/features/filesystem/FileSystem.h @@ -109,6 +109,14 @@ public: */ virtual int mkdir(const char *path, mode_t mode); + /** Store information about the mounted filesystem in a statvfs structure + * + * @param path The name of the file to find information about + * @param buf The stat buffer to write to + * @return 0 on success, negative error code on failure + */ + virtual int statvfs(const char *path, struct statvfs *buf); + protected: friend class File; friend class Dir; @@ -143,7 +151,7 @@ protected: * * @param file File handle * @param buffer The buffer to write from - * @param size The number of bytes to write + * @param size The number of bytes to write * @return The number of bytes written, negative error on failure */ virtual ssize_t file_write(fs_file_t file, const void *buffer, size_t size) = 0; @@ -240,7 +248,7 @@ protected: */ virtual void dir_rewind(fs_dir_t dir); - /** Get the sizeof the directory + /** Get the sizeof the directory * * @param dir Dir handle * @return Number of files in the directory diff --git a/features/filesystem/fat/FATFileSystem.cpp b/features/filesystem/fat/FATFileSystem.cpp index 152cc96b33..1779e94a1f 100644 --- a/features/filesystem/fat/FATFileSystem.cpp +++ b/features/filesystem/fat/FATFileSystem.cpp @@ -442,6 +442,34 @@ int FATFileSystem::stat(const char *path, struct stat *st) { return 0; } +int FATFileSystem::statvfs(const char *path, struct statvfs *buf) { + + memset(buf, 0, sizeof(struct statvfs)); + FATFS *fs; + DWORD fre_clust; + + lock(); + FRESULT res = f_getfree(_fsid, &fre_clust, &fs); + if (res != FR_OK) { + unlock(); + return fat_error_remap(res); + } + + buf->f_bsize = fs->ssize; + buf->f_frsize = fs->ssize; + buf->f_blocks = (fs->n_fatent - 2) * fs->csize; + buf->f_bfree = fre_clust * fs->csize; + buf->f_bavail = buf->f_bfree; +#if FF_USE_LFN + buf->f_namemax = FF_LFN_BUF; +#else + buf->f_namemax = FF_SFN_BUF; +#endif + + unlock(); + return 0; +} + void FATFileSystem::lock() { _ffs_mutex->lock(); } diff --git a/features/filesystem/fat/FATFileSystem.h b/features/filesystem/fat/FATFileSystem.h index a124232100..29afb9109a 100644 --- a/features/filesystem/fat/FATFileSystem.h +++ b/features/filesystem/fat/FATFileSystem.h @@ -43,7 +43,7 @@ public: */ FATFileSystem(const char *name = NULL, BlockDevice *bd = NULL); virtual ~FATFileSystem(); - + /** Formats a logical drive, FDISK partitioning rule. * * The block device to format should be mounted when this function is called. @@ -57,7 +57,7 @@ public: * cluster_size must be a multiple of the underlying device's allocation unit * and is currently limited to a max of 32,768 bytes. If zero, a cluster size * will be determined from the device's allocation unit. Defaults to zero. - * + * * @return 0 on success, negative error code on failure */ static int format(BlockDevice *bd, bd_size_t cluster_size = 0); @@ -139,6 +139,14 @@ public: */ virtual int mkdir(const char *path, mode_t mode); + /** Store information about the mounted filesystem in a statvfs structure + * + * @param path The name of the file to find information about + * @param buf The stat buffer to write to + * @return 0 on success, negative error code on failure + */ + virtual int statvfs(const char *path, struct statvfs *buf); + protected: /** Open a file on the filesystem * @@ -170,7 +178,7 @@ protected: * * @param file File handle * @param buffer The buffer to write from - * @param len The number of bytes to write + * @param len The number of bytes to write * @return The number of bytes written, negative error on failure */ virtual ssize_t file_write(fs_file_t file, const void *buffer, size_t len); @@ -251,7 +259,7 @@ protected: * @param dir Dir handle */ virtual void dir_rewind(fs_dir_t dir); - + private: FATFS _fs; // Work area (file system object) for logical drive char _fsid[sizeof("0:")]; diff --git a/features/filesystem/littlefs/LittleFileSystem.cpp b/features/filesystem/littlefs/LittleFileSystem.cpp index 56d799b35b..6bb735c077 100644 --- a/features/filesystem/littlefs/LittleFileSystem.cpp +++ b/features/filesystem/littlefs/LittleFileSystem.cpp @@ -336,6 +336,9 @@ int LittleFileSystem::stat(const char *name, struct stat *st) return lfs_toerror(err); } +int LittleFileSystem::statvfs(const char *path, struct statvfs *buf) +{ +} ////// File operations ////// int LittleFileSystem::file_open(fs_file_t *file, const char *path, int flags) diff --git a/features/filesystem/littlefs/LittleFileSystem.h b/features/filesystem/littlefs/LittleFileSystem.h index 0829eb2faa..5ccba43c2d 100644 --- a/features/filesystem/littlefs/LittleFileSystem.h +++ b/features/filesystem/littlefs/LittleFileSystem.h @@ -143,6 +143,14 @@ public: */ virtual int mkdir(const char *path, mode_t mode); + /** Store information about the mounted filesystem in a statvfs structure + * + * @param path The name of the file to find information about + * @param buf The stat buffer to write to + * @return 0 on success, negative error code on failure + */ + virtual int statvfs(const char *path, struct statvfs *buf); + protected: /** Open a file on the filesystem * diff --git a/platform/FileSystemHandle.cpp b/platform/FileSystemHandle.cpp index 3028d409ce..1823f8a43b 100644 --- a/platform/FileSystemHandle.cpp +++ b/platform/FileSystemHandle.cpp @@ -42,3 +42,8 @@ int FileSystemHandle::mkdir(const char *path, mode_t mode) { return -ENOSYS; } + +int FileSystemHandle::statvfs(const char *path, struct statvfs *buf) +{ + return -ENOSYS; +} diff --git a/platform/FileSystemHandle.h b/platform/FileSystemHandle.h index 713d6e5d7a..349e25855e 100644 --- a/platform/FileSystemHandle.h +++ b/platform/FileSystemHandle.h @@ -94,6 +94,14 @@ public: * @return 0 on success, negative error code on failure */ virtual int mkdir(const char *path, mode_t mode); + + /** Store information about the mounted filesystem in a statvfs structure + * + * @param path The name of the file to find information about + * @param buf The stat buffer to write to + * @return 0 on success, negative error code on failure + */ + virtual int statvfs(const char *path, struct statvfs *buf); }; /**@}*/ diff --git a/platform/mbed_retarget.cpp b/platform/mbed_retarget.cpp index 12fcb317a7..ad094b9ff1 100644 --- a/platform/mbed_retarget.cpp +++ b/platform/mbed_retarget.cpp @@ -709,6 +709,23 @@ extern "C" int stat(const char *path, struct stat *st) { } } +extern "C" int statvfs(const char *path, struct statvfs *buf) { + FilePath fp(path); + FileSystemHandle *fs = fp.fileSystem(); + if (fs == NULL) { + errno = ENODEV; + return -1; + } + + int err = fs->statvfs(fp.fileName(), buf); + if (err < 0) { + errno = -err; + return -1; + } else { + return 0; + } +} + #if defined(TOOLCHAIN_GCC) /* prevents the exception handling name demangling code getting pulled in */ #include "mbed_error.h" diff --git a/platform/mbed_retarget.h b/platform/mbed_retarget.h index ac1abc04ed..391ae192ec 100644 --- a/platform/mbed_retarget.h +++ b/platform/mbed_retarget.h @@ -28,8 +28,8 @@ /* We can get the following standard types from sys/types for gcc, but we * need to define the types ourselves for the other compilers that normally * target embedded systems */ -typedef signed int ssize_t; ///< Signed size type, usually encodes negative errors -typedef signed long off_t; ///< Offset in a data stream +typedef signed int ssize_t; ///< Signed size type, usually encodes negative errors +typedef signed long off_t; ///< Offset in a data stream #if defined(__ARMCC_VERSION) || !defined(__GNUC__) typedef unsigned int mode_t; ///< Mode for opening files typedef unsigned int dev_t; ///< Device ID type @@ -37,6 +37,7 @@ typedef unsigned long ino_t; ///< File serial number typedef unsigned int nlink_t; ///< Number of links to a file typedef unsigned int uid_t; ///< User ID typedef unsigned int gid_t; ///< Group ID +typedef unsigned long long fsblkcnt_t; ///< Count of file system blocks #endif #define O_RDONLY 0 ///< Open for reading @@ -62,7 +63,7 @@ typedef unsigned int gid_t; ///< Group ID /* DIR declarations must also be here */ #if __cplusplus namespace mbed { - + class FileHandle; class DirHandle; std::FILE *mbed_fdopen(FileHandle *fh, const char *mode); @@ -415,10 +416,24 @@ struct stat { time_t st_ctime; ///< Time of last status change }; +struct statvfs { + unsigned long f_bsize; ///< Filesystem block size + unsigned long f_frsize; ///< Fragment size (block size) + + fsblkcnt_t f_blocks; ///< Number of blocks + fsblkcnt_t f_bfree; ///< Number of free blocks + fsblkcnt_t f_bavail; ///< Number of free blocks for unprivileged users + + unsigned long f_fsid; ///< Filesystem ID + + unsigned long f_namemax; ///< Maximum filename length +}; + #if __cplusplus extern "C" { #endif int stat(const char *path, struct stat *st); + int statvfs(const char *path, struct statvfs *buf); #if __cplusplus }; #endif From f1a98158762b91b84fc60b9e873ccc9231028066 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Wed, 3 Jan 2018 12:30:50 -0600 Subject: [PATCH 2/4] Moved squiggly bracket placement per mbed style --- features/filesystem/fat/FATFileSystem.cpp | 75 +++++++++++++++-------- 1 file changed, 50 insertions(+), 25 deletions(-) diff --git a/features/filesystem/fat/FATFileSystem.cpp b/features/filesystem/fat/FATFileSystem.cpp index 1779e94a1f..f71e6d3965 100644 --- a/features/filesystem/fat/FATFileSystem.cpp +++ b/features/filesystem/fat/FATFileSystem.cpp @@ -275,12 +275,14 @@ FATFileSystem::~FATFileSystem() unmount(); } -int FATFileSystem::mount(BlockDevice *bd) { +int FATFileSystem::mount(BlockDevice *bd) +{ // requires duplicate definition to allow virtual overload to work return mount(bd, true); } -int FATFileSystem::mount(BlockDevice *bd, bool mount) { +int FATFileSystem::mount(BlockDevice *bd, bool mount) +{ lock(); if (_id != -1) { unlock(); @@ -322,7 +324,8 @@ int FATFileSystem::unmount() /* See http://elm-chan.org/fsw/ff/en/mkfs.html for details of f_mkfs() and * associated arguments. */ -int FATFileSystem::format(BlockDevice *bd, bd_size_t cluster_size) { +int FATFileSystem::format(BlockDevice *bd, bd_size_t cluster_size) +{ FATFileSystem fs; int err = fs.mount(bd, false); if (err) { @@ -345,7 +348,8 @@ int FATFileSystem::format(BlockDevice *bd, bd_size_t cluster_size) { return 0; } -int FATFileSystem::reformat(BlockDevice *bd, int allocation_unit) { +int FATFileSystem::reformat(BlockDevice *bd, int allocation_unit) +{ lock(); if (_id != -1) { if (!bd) { @@ -375,7 +379,8 @@ int FATFileSystem::reformat(BlockDevice *bd, int allocation_unit) { return err; } -int FATFileSystem::remove(const char *path) { +int FATFileSystem::remove(const char *path) +{ Deferred fpath = fat_path_prefix(_id, path); lock(); @@ -388,7 +393,8 @@ int FATFileSystem::remove(const char *path) { return fat_error_remap(res); } -int FATFileSystem::rename(const char *oldpath, const char *newpath) { +int FATFileSystem::rename(const char *oldpath, const char *newpath) +{ Deferred oldfpath = fat_path_prefix(_id, oldpath); Deferred newfpath = fat_path_prefix(_id, newpath); @@ -402,7 +408,8 @@ int FATFileSystem::rename(const char *oldpath, const char *newpath) { return fat_error_remap(res); } -int FATFileSystem::mkdir(const char *path, mode_t mode) { +int FATFileSystem::mkdir(const char *path, mode_t mode) +{ Deferred fpath = fat_path_prefix(_id, path); lock(); @@ -415,7 +422,8 @@ int FATFileSystem::mkdir(const char *path, mode_t mode) { return fat_error_remap(res); } -int FATFileSystem::stat(const char *path, struct stat *st) { +int FATFileSystem::stat(const char *path, struct stat *st) +{ Deferred fpath = fat_path_prefix(_id, path); lock(); @@ -442,7 +450,8 @@ int FATFileSystem::stat(const char *path, struct stat *st) { return 0; } -int FATFileSystem::statvfs(const char *path, struct statvfs *buf) { +int FATFileSystem::statvfs(const char *path, struct statvfs *buf) +{ memset(buf, 0, sizeof(struct statvfs)); FATFS *fs; @@ -470,17 +479,20 @@ int FATFileSystem::statvfs(const char *path, struct statvfs *buf) { return 0; } -void FATFileSystem::lock() { +void FATFileSystem::lock() +{ _ffs_mutex->lock(); } -void FATFileSystem::unlock() { +void FATFileSystem::unlock() +{ _ffs_mutex->unlock(); } ////// File operations ////// -int FATFileSystem::file_open(fs_file_t *file, const char *path, int flags) { +int FATFileSystem::file_open(fs_file_t *file, const char *path, int flags) +{ debug_if(FFS_DBG, "open(%s) on filesystem [%s], drv [%s]\n", path, getName(), _id); FIL *fh = new FIL; @@ -524,7 +536,8 @@ int FATFileSystem::file_open(fs_file_t *file, const char *path, int flags) { return 0; } -int FATFileSystem::file_close(fs_file_t file) { +int FATFileSystem::file_close(fs_file_t file) +{ FIL *fh = static_cast(file); lock(); @@ -535,7 +548,8 @@ int FATFileSystem::file_close(fs_file_t file) { return fat_error_remap(res); } -ssize_t FATFileSystem::file_read(fs_file_t file, void *buffer, size_t len) { +ssize_t FATFileSystem::file_read(fs_file_t file, void *buffer, size_t len) +{ FIL *fh = static_cast(file); lock(); @@ -551,7 +565,8 @@ ssize_t FATFileSystem::file_read(fs_file_t file, void *buffer, size_t len) { } } -ssize_t FATFileSystem::file_write(fs_file_t file, const void *buffer, size_t len) { +ssize_t FATFileSystem::file_write(fs_file_t file, const void *buffer, size_t len) +{ FIL *fh = static_cast(file); lock(); @@ -567,7 +582,8 @@ ssize_t FATFileSystem::file_write(fs_file_t file, const void *buffer, size_t len } } -int FATFileSystem::file_sync(fs_file_t file) { +int FATFileSystem::file_sync(fs_file_t file) +{ FIL *fh = static_cast(file); lock(); @@ -580,7 +596,8 @@ int FATFileSystem::file_sync(fs_file_t file) { return fat_error_remap(res); } -off_t FATFileSystem::file_seek(fs_file_t file, off_t offset, int whence) { +off_t FATFileSystem::file_seek(fs_file_t file, off_t offset, int whence) +{ FIL *fh = static_cast(file); lock(); @@ -602,7 +619,8 @@ off_t FATFileSystem::file_seek(fs_file_t file, off_t offset, int whence) { } } -off_t FATFileSystem::file_tell(fs_file_t file) { +off_t FATFileSystem::file_tell(fs_file_t file) +{ FIL *fh = static_cast(file); lock(); @@ -612,7 +630,8 @@ off_t FATFileSystem::file_tell(fs_file_t file) { return res; } -off_t FATFileSystem::file_size(fs_file_t file) { +off_t FATFileSystem::file_size(fs_file_t file) +{ FIL *fh = static_cast(file); lock(); @@ -624,7 +643,8 @@ off_t FATFileSystem::file_size(fs_file_t file) { ////// Dir operations ////// -int FATFileSystem::dir_open(fs_dir_t *dir, const char *path) { +int FATFileSystem::dir_open(fs_dir_t *dir, const char *path) +{ FATFS_DIR *dh = new FATFS_DIR; Deferred fpath = fat_path_prefix(_id, path); @@ -642,7 +662,8 @@ int FATFileSystem::dir_open(fs_dir_t *dir, const char *path) { return 0; } -int FATFileSystem::dir_close(fs_dir_t dir) { +int FATFileSystem::dir_close(fs_dir_t dir) +{ FATFS_DIR *dh = static_cast(dir); lock(); @@ -653,7 +674,8 @@ int FATFileSystem::dir_close(fs_dir_t dir) { return fat_error_remap(res); } -ssize_t FATFileSystem::dir_read(fs_dir_t dir, struct dirent *ent) { +ssize_t FATFileSystem::dir_read(fs_dir_t dir, struct dirent *ent) +{ FATFS_DIR *dh = static_cast(dir); FILINFO finfo; @@ -681,7 +703,8 @@ ssize_t FATFileSystem::dir_read(fs_dir_t dir, struct dirent *ent) { return 1; } -void FATFileSystem::dir_seek(fs_dir_t dir, off_t offset) { +void FATFileSystem::dir_seek(fs_dir_t dir, off_t offset) +{ FATFS_DIR *dh = static_cast(dir); lock(); @@ -703,7 +726,8 @@ void FATFileSystem::dir_seek(fs_dir_t dir, off_t offset) { unlock(); } -off_t FATFileSystem::dir_tell(fs_dir_t dir) { +off_t FATFileSystem::dir_tell(fs_dir_t dir) +{ FATFS_DIR *dh = static_cast(dir); lock(); @@ -713,7 +737,8 @@ off_t FATFileSystem::dir_tell(fs_dir_t dir) { return offset; } -void FATFileSystem::dir_rewind(fs_dir_t dir) { +void FATFileSystem::dir_rewind(fs_dir_t dir) +{ FATFS_DIR *dh = static_cast(dir); lock(); From 9dd3060d60299dd93ddf37d608d0349c1b8dad7f Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Wed, 3 Jan 2018 12:54:28 -0600 Subject: [PATCH 3/4] Added littlefs statvfs implementation --- .../filesystem/littlefs/LittleFileSystem.cpp | 27 ++++++++++++++++++- .../filesystem/littlefs/LittleFileSystem.h | 2 +- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/features/filesystem/littlefs/LittleFileSystem.cpp b/features/filesystem/littlefs/LittleFileSystem.cpp index 6bb735c077..be11282f81 100644 --- a/features/filesystem/littlefs/LittleFileSystem.cpp +++ b/features/filesystem/littlefs/LittleFileSystem.cpp @@ -336,8 +336,33 @@ int LittleFileSystem::stat(const char *name, struct stat *st) return lfs_toerror(err); } -int LittleFileSystem::statvfs(const char *path, struct statvfs *buf) +static int lfs_statvfs_count(void *p, lfs_block_t b) { + *(lfs_size_t *)p += 1; + return 0; +} + +int LittleFileSystem::statvfs(const char *name, struct statvfs *st) +{ + memset(st, 0, sizeof(struct statvfs)); + + lfs_size_t in_use = 0; + _mutex.lock(); + LFS_INFO("statvfs(\"%s\", %p)", name, st); + int err = lfs_traverse(&_lfs, lfs_statvfs_count, &in_use); + LFS_INFO("statvfs -> %d", lfs_toerror(err)); + _mutex.unlock(); + if (err) { + return err; + } + + st->f_bsize = _config.block_size; + st->f_frsize = _config.block_size; + st->f_blocks = _config.block_count; + st->f_bfree = _config.block_count - in_use; + st->f_bavail = _config.block_count - in_use; + st->f_namemax = LFS_NAME_MAX; + return 0; } ////// File operations ////// diff --git a/features/filesystem/littlefs/LittleFileSystem.h b/features/filesystem/littlefs/LittleFileSystem.h index 5ccba43c2d..6f15a423ba 100644 --- a/features/filesystem/littlefs/LittleFileSystem.h +++ b/features/filesystem/littlefs/LittleFileSystem.h @@ -149,7 +149,7 @@ public: * @param buf The stat buffer to write to * @return 0 on success, negative error code on failure */ - virtual int statvfs(const char *path, struct statvfs *buf); + virtual int statvfs(const char *path, struct statvfs *buf); protected: /** Open a file on the filesystem From d5cf4a6a6ac7ac6e6e7198a78b83db42098d61b1 Mon Sep 17 00:00:00 2001 From: Deepika Date: Mon, 8 Jan 2018 10:42:41 -0600 Subject: [PATCH 4/4] fsblkcnt_t is available in GCC, but adding it for all compilers --- platform/mbed_retarget.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/mbed_retarget.h b/platform/mbed_retarget.h index 391ae192ec..c3e6cbd54d 100644 --- a/platform/mbed_retarget.h +++ b/platform/mbed_retarget.h @@ -30,6 +30,7 @@ * target embedded systems */ typedef signed int ssize_t; ///< Signed size type, usually encodes negative errors typedef signed long off_t; ///< Offset in a data stream +typedef unsigned long long fsblkcnt_t; ///< Count of file system blocks #if defined(__ARMCC_VERSION) || !defined(__GNUC__) typedef unsigned int mode_t; ///< Mode for opening files typedef unsigned int dev_t; ///< Device ID type @@ -37,7 +38,6 @@ typedef unsigned long ino_t; ///< File serial number typedef unsigned int nlink_t; ///< Number of links to a file typedef unsigned int uid_t; ///< User ID typedef unsigned int gid_t; ///< Group ID -typedef unsigned long long fsblkcnt_t; ///< Count of file system blocks #endif #define O_RDONLY 0 ///< Open for reading