Merge pull request #4087 from geky/localfs-fslike-fix

LocalFileSystem: Repair the FileSystemLike hooks
pull/2224/merge
Sam Grove 2017-06-04 08:35:26 -05:00 committed by GitHub
commit 0da63eef2b
13 changed files with 295 additions and 284 deletions

View File

@ -1,4 +1,3 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
@ -21,10 +20,30 @@
FileSystem::FileSystem(const char *name)
: FileBase(name, FileSystemPathType)
: FileSystemLike(name)
{
}
int FileSystem::remove(const char *path)
{
return -ENOSYS;
}
int FileSystem::rename(const char *path, const char *newpath)
{
return -ENOSYS;
}
int FileSystem::stat(const char *path, struct stat *st)
{
return -ENOSYS;
}
int FileSystem::mkdir(const char *path, mode_t mode)
{
return -ENOSYS;
}
int FileSystem::file_sync(fs_file_t file)
{
return 0;
@ -53,11 +72,6 @@ off_t FileSystem::file_size(fs_file_t file)
return size;
}
int FileSystem::mkdir(const char *path, mode_t mode)
{
return -ENOSYS;
}
int FileSystem::dir_open(fs_dir_t *dir, const char *path)
{
return -ENOSYS;
@ -109,3 +123,38 @@ size_t FileSystem::dir_size(fs_dir_t dir)
return size;
}
// Internally used file wrapper that manages memory on close
template <typename F>
class Managed : public F {
public:
virtual int close() {
int err = F::close();
delete this;
return err;
}
};
int FileSystem::open(FileHandle **file, const char *path, int flags)
{
File *f = new Managed<File>;
int err = f->open(this, path, flags);
if (err) {
delete f;
return err;
}
*file = f;
return 0;
}
int FileSystem::open(DirHandle **dir, const char *path) {
Dir *d = new Managed<Dir>;
int err = d->open(this, path);
if (err) {
delete d;
return err;
}
*dir = d;
return 0;
}

View File

@ -20,6 +20,9 @@
#include "platform/platform.h"
#include "platform/FileBase.h"
#include "platform/FileHandle.h"
#include "platform/DirHandle.h"
#include "platform/FileSystemLike.h"
#include "BlockDevice.h"
namespace mbed {
@ -31,15 +34,19 @@ namespace mbed {
typedef void *fs_file_t;
typedef void *fs_dir_t;
/** A filesystem-like object is one that can be used to open files
* though it by fopen("/name/filename", flags)
// Predeclared classes
class Dir;
class File;
/** A filesystem object provides filesystem operations and file operations
* for the File and Dir classes on a block device.
*
* Implementations must define at least open (the default definitions
* of the rest of the functions just return error values).
* Implementations must provide at minimum file operations and mount
* operations for block devices.
*
* @Note Synchronization level: Set by subclass
* @Note Synchronization level: Set by subclass
*/
class FileSystem : public FileBase {
class FileSystem : public FileSystemLike {
public:
/** FileSystem lifetime
*/
@ -64,7 +71,7 @@ public:
* @param path The name of the file to remove.
* @return 0 on success, negative error code on failure
*/
virtual int remove(const char *path) = 0;
virtual int remove(const char *path);
/** Rename a file in the filesystem.
*
@ -72,7 +79,7 @@ public:
* @param newpath The name to rename it to
* @return 0 on success, negative error code on failure
*/
virtual int rename(const char *path, const char *newpath) = 0;
virtual int rename(const char *path, const char *newpath);
/** Store information about the file in a stat structure
*
@ -80,7 +87,7 @@ public:
* @param st The stat buffer to write to
* @return 0 on success, negative error code on failure
*/
virtual int stat(const char *path, struct stat *st) = 0;
virtual int stat(const char *path, struct stat *st);
/** Create a directory in the filesystem.
*
@ -227,6 +234,11 @@ protected:
* @return Number of files in the directory
*/
virtual size_t dir_size(fs_dir_t dir);
protected:
// Hooks for FileSystemHandle
virtual int open(FileHandle **file, const char *path, int flags);
virtual int open(DirHandle **dir, const char *path);
};

3
mbed.h
View File

@ -86,6 +86,9 @@
#include "platform/mbed_rtc_time.h"
#include "platform/mbed_poll.h"
#include "platform/ATCmdParser.h"
#include "platform/FileSystemHandle.h"
#include "platform/FileHandle.h"
#include "platform/DirHandle.h"
// mbed Non-hardware components
#include "platform/Callback.h"

View File

@ -49,9 +49,9 @@ bool FilePath::isFileSystem(void) {
return (fb->getPathType() == FileSystemPathType);
}
FileSystem* FilePath::fileSystem(void) {
FileSystemLike* FilePath::fileSystem(void) {
if (isFileSystem()) {
return (FileSystem*)fb;
return static_cast<FileSystemLike*>(fb);
}
return NULL;
}

View File

@ -37,7 +37,7 @@ public:
const char* fileName(void);
bool isFileSystem(void);
FileSystem* fileSystem(void);
FileSystemLike* fileSystem(void);
bool isFile(void);
FileLike* file(void);

View File

@ -0,0 +1,44 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "mbed.h"
#include "FileSystemHandle.h"
#include <errno.h>
int FileSystemHandle::open(DirHandle **dir, const char *path)
{
return -ENOSYS;
}
int FileSystemHandle::remove(const char *path)
{
return -ENOSYS;
}
int FileSystemHandle::rename(const char *path, const char *newpath)
{
return -ENOSYS;
}
int FileSystemHandle::stat(const char *path, struct stat *st)
{
return -ENOSYS;
}
int FileSystemHandle::mkdir(const char *path, mode_t mode)
{
return -ENOSYS;
}

View File

@ -0,0 +1,99 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_FILESYSTEMHANDLE_H
#define MBED_FILESYSTEMHANDLE_H
#include "platform/platform.h"
#include "platform/FileBase.h"
#include "platform/FileHandle.h"
#include "platform/DirHandle.h"
namespace mbed {
/** \addtogroup drivers */
/** @{*/
/** A filesystem-like object is one that can be used to open file-like
* objects though it by fopen("/name/filename", mode)
*
* Implementations must define at least open (the default definitions
* of the rest of the functions just return error values).
*
* @Note Synchronization level: Set by subclass
*/
class FileSystemHandle {
public:
/** FileSystemHandle lifetime
*/
virtual ~FileSystemHandle() {}
/** Open a file on the filesystem
*
* @param file Destination for the handle to a newly created file
* @param path The name of the file to open
* @param flags The flags to open the file in, one of O_RDONLY, O_WRONLY, O_RDWR,
* bitwise or'd with one of O_CREAT, O_TRUNC, O_APPEND
* @return 0 on success, negative error code on failure
*/
virtual int open(FileHandle **file, const char *filename, int flags) = 0;
/** Open a directory on the filesystem
*
* @param dir Destination for the handle to the directory
* @param path Name of the directory to open
* @return 0 on success, negative error code on failure
*/
virtual int open(DirHandle **dir, const char *path);
/** Remove a file from the filesystem.
*
* @param path The name of the file to remove.
* @return 0 on success, negative error code on failure
*/
virtual int remove(const char *path);
/** Rename a file in the filesystem.
*
* @param path The name of the file to rename.
* @param newpath The name to rename it to
* @return 0 on success, negative error code on failure
*/
virtual int rename(const char *path, const char *newpath);
/** Store information about the file in a stat structure
*
* @param path The name of the file to find information about
* @param st The stat buffer to write to
* @return 0 on success, negative error code on failure
*/
virtual int stat(const char *path, struct stat *st);
/** Create a directory in the filesystem.
*
* @param path The name of the directory to create.
* @param mode The permissions with which to create the directory
* @return 0 on success, negative error code on failure
*/
virtual int mkdir(const char *path, mode_t mode);
};
} // namespace mbed
#endif
/** @}*/

View File

@ -1,100 +0,0 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "platform/FileSystemLike.h"
namespace mbed {
class BaseDirHandle : public DirHandle {
public:
/*
We keep track of our current location as the n'th object in the
FileSystemLike list. Using a Base* instead would cause problems if that
object were to be destroyed between readdirs.
Using this method does mean though that destroying/creating objects can
give unusual results from readdir.
*/
off_t n;
BaseDirHandle() : DirHandle(), n(0) {
}
virtual int close() {
// No lock can be used in destructor
delete this;
return 0;
}
virtual int read(struct dirent *ent) {
lock();
FileBase *ptr = FileBase::get(n);
if (ptr == NULL) {
unlock();
return -1;
}
/* Increment n, so next readdir gets the next item */
n++;
/* Setup cur entry and return a pointer to it */
std::strncpy(ent->d_name, ptr->getName(), NAME_MAX);
unlock();
return 0;
}
virtual off_t tell() {
lock();
off_t offset = n;
unlock();
return offset;
}
virtual void seek(off_t offset) {
lock();
n = offset;
unlock();
}
virtual void rewind() {
lock();
n = 0;
unlock();
}
protected:
PlatformMutex _mutex;
virtual void lock() {
_mutex.lock();
}
virtual void unlock() {
_mutex.unlock();
}
};
FileSystemLike::FileSystemLike(const char *name) : FileBase(name, FileSystemPathType) {
}
FileSystemLike::~FileSystemLike() {
}
DirHandle *FileSystemLike::opendir() {
return new BaseDirHandle();
}
} // namespace mbed

View File

@ -18,15 +18,16 @@
#include "platform/platform.h"
#include "platform/FileBase.h"
#include "platform/FileSystemHandle.h"
#include "platform/FileHandle.h"
#include "platform/DirHandle.h"
namespace mbed {
/** \addtogroup platform */
/** A filesystem-like object is one that can be used to open files
* though it by fopen("/name/filename", mode)
/** A filesystem-like object is one that can be used to open file-like
* objects though it by fopen("/name/filename", mode)
*
* Implementations must define at least open (the default definitions
* of the rest of the functions just return error values).
@ -34,89 +35,51 @@ namespace mbed {
* @note Synchronization level: Set by subclass
* @ingroup platform
*/
class FileSystemLike : public FileBase {
class FileSystemLike : public FileSystemHandle, public FileBase {
public:
/** FileSystemLike constructor
*
* @param name The name to use for the filesystem.
/** FileSystemLike lifetime
*/
MBED_DEPRECATED_SINCE("mbed-os-5.4",
"The mbed 2 filesystem classes have been superseeded by the FileSystem api, "
"Replaced by FileSystem")
FileSystemLike(const char *name);
FileSystemLike(const char *name = NULL) : FileBase(name, FileSystemPathType) {}
virtual ~FileSystemLike() {}
virtual ~FileSystemLike();
// Inherited functions with name conflicts
using FileSystemHandle::open;
using FileSystemHandle::open;
MBED_DEPRECATED_SINCE("mbed-os-5.4",
"The mbed 2 filesystem classes have been superseeded by the FileSystem api, "
"Replaced by FileSystem")
static DirHandle *opendir();
friend class BaseDirHandle;
/** Opens a file from the filesystem
/** Open a file on the filesystem
*
* @param filename The name of the file to open.
* @param flags One of O_RDONLY, O_WRONLY, or O_RDWR, OR'd with
* zero or more of O_CREAT, O_TRUNC, or O_APPEND.
*
* @returns
* A pointer to a FileHandle object representing the
* file on success, or NULL on failure.
* @param path The name of the file to open
* @param flags The flags to open the file in, one of O_RDONLY, O_WRONLY, O_RDWR,
* bitwise or'd with one of O_CREAT, O_TRUNC, O_APPEND
* @return A file handle on success, NULL on failure
* @deprecated Replaced by `int open(FileHandle **, ...)` for propagating error codes
*/
virtual FileHandle *open(const char *filename, int flags) = 0;
MBED_DEPRECATED_SINCE("mbed-os-5.5",
"Replaced by `int open(FileHandle **, ...)` for propagating error codes")
FileHandle *open(const char *path, int flags)
{
FileHandle *file;
int err = open(&file, path, flags);
return err ? NULL : file;
}
/** Remove a file from the filesystem.
/** Open a directory on the filesystem
*
* @param filename the name of the file to remove.
* @returns 0 on success, -1 on failure.
* @param path Name of the directory to open
* @return A directory handle on success, NULL on failure
* @deprecated Replaced by `int open(DirHandle **, ...)` for propagating error codes
*/
virtual int remove(const char *filename) { (void) filename; return -1; };
/** Rename a file in the filesystem.
*
* @param oldname the name of the file to rename.
* @param newname the name to rename it to.
*
* @returns
* 0 on success,
* -1 on failure.
*/
virtual int rename(const char *oldname, const char *newname) { (void) oldname, (void) newname; return -1; };
/** Opens a directory in the filesystem and returns a DirHandle
* representing the directory stream.
*
* @param name The name of the directory to open.
*
* @returns
* A DirHandle representing the directory stream, or
* NULL on failure.
*/
virtual DirHandle *opendir(const char *name) { (void) name; return NULL; };
/** Creates a directory in the filesystem.
*
* @param name The name of the directory to create.
* @param mode The permissions to create the directory with.
*
* @returns
* 0 on success,
* -1 on failure.
*/
virtual int mkdir(const char *name, mode_t mode) { (void) name, (void) mode; return -1; }
/** Store information about file in stat structure
*
* @param name The name of the file to find information about
* @param st The stat buffer to write to
* @returns
* 0 on success or un-needed,
* -1 on error
*/
virtual int stat(const char *name, struct stat *st) { return -1; };
MBED_DEPRECATED_SINCE("mbed-os-5.5",
"Replaced by `int open(DirHandle **, ...)` for propagating error codes")
DirHandle *opendir(const char *path)
{
DirHandle *dir;
int err = open(&dir, path);
return err ? NULL : dir;
}
};
} // namespace mbed
#endif

View File

@ -20,6 +20,7 @@
#include "platform/mbed_semihost_api.h"
#include <string.h>
#include <stdio.h>
#include <errno.h>
namespace mbed {
@ -235,26 +236,28 @@ protected:
}
};
FileHandle *LocalFileSystem::open(const char* name, int flags) {
int LocalFileSystem::open(FileHandle **file, const char* name, int flags) {
// No global state modified so function is thread safe
/* reject filenames with / in them */
for (const char *tmp = name; *tmp; tmp++) {
if (*tmp == '/') {
return NULL;
return -EINVAL;
}
}
int openmode = posix_to_semihost_open_flags(flags);
if (openmode == OPEN_INVALID) {
return NULL;
return -EINVAL;
}
FILEHANDLE fh = semihost_open(name, openmode);
if (fh == -1) {
return NULL;
return -EIO;
}
return new LocalFileHandle(fh);
*file = new LocalFileHandle(fh);
return 0;
}
int LocalFileSystem::remove(const char *filename) {
@ -263,10 +266,11 @@ int LocalFileSystem::remove(const char *filename) {
return semihost_remove(filename);
}
DirHandle *LocalFileSystem::opendir(const char *name) {
int LocalFileSystem::open(DirHandle **dir, const char *name) {
// No global state modified so function is thread safe
return new LocalDirHandle();
*dir = new LocalDirHandle();
return 0;
}
} // namespace mbed

View File

@ -106,9 +106,9 @@ public:
}
virtual FileHandle *open(const char* name, int flags);
virtual int open(FileHandle **file, const char *path, int flags);
virtual int open(DirHandle **dir, const char *name);
virtual int remove(const char *filename);
virtual DirHandle *opendir(const char *name);
};
} // namespace mbed

View File

@ -24,11 +24,6 @@
#include "platform/mbed_error.h"
#include "platform/mbed_stats.h"
#include "platform/mbed_critical.h"
#if MBED_CONF_FILESYSTEM_PRESENT
#include "filesystem/FileSystem.h"
#include "filesystem/File.h"
#include "filesystem/Dir.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <limits.h>
@ -134,7 +129,6 @@ static int handle_open_errors(int error, unsigned filehandle_idx) {
return -1;
}
#if MBED_CONF_FILESYSTEM_PRESENT
static inline int openmode_to_posix(int openmode) {
int posix = openmode;
#ifdef __ARMCC_VERSION
@ -169,28 +163,25 @@ static inline int openmode_to_posix(int openmode) {
#endif
return posix;
}
#endif
#if MBED_CONF_FILESYSTEM_PRESENT
// Internally used file objects with managed memory on close
class ManagedFile : public File {
class ManagedFile : public FileHandle {
public:
virtual int close() {
int err = File::close();
int err = FileHandle::close();
delete this;
return err;
}
};
class ManagedDir : public Dir {
class ManagedDir : public DirHandle {
public:
virtual int close() {
int err = Dir::close();
int err = DirHandle::close();
delete this;
return err;
}
};
#endif
/* @brief standard c library fopen() retargeting function.
*
@ -261,21 +252,16 @@ extern "C" FILEHANDLE PREFIX(_open)(const char* name, int openmode) {
if (path.isFile()) {
res = path.file();
#if MBED_CONF_FILESYSTEM_PRESENT
} else {
FileSystem *fs = path.fileSystem();
FileSystemHandle *fs = path.fileSystem();
if (fs == NULL) {
return handle_open_errors(-ENOENT, fh_i);
}
int posix_mode = openmode_to_posix(openmode);
File *file = new ManagedFile;
int err = file->open(fs, path.fileName(), posix_mode);
if (err < 0) {
delete file;
int err = fs->open(&res, path.fileName(), posix_mode);
if (err) {
return handle_open_errors(err, fh_i);
}
res = file;
#endif
}
}
@ -532,9 +518,8 @@ extern "C" int _fstat(int fd, struct stat *st) {
namespace std {
extern "C" int remove(const char *path) {
#if MBED_CONF_FILESYSTEM_PRESENT
FilePath fp(path);
FileSystem *fs = fp.fileSystem();
FileSystemHandle *fs = fp.fileSystem();
if (fs == NULL) {
errno = ENOENT;
return -1;
@ -547,18 +532,13 @@ extern "C" int remove(const char *path) {
} else {
return 0;
}
#else
errno = ENOSYS;
return -1;
#endif
}
extern "C" int rename(const char *oldname, const char *newname) {
#if MBED_CONF_FILESYSTEM_PRESENT
FilePath fpOld(oldname);
FilePath fpNew(newname);
FileSystem *fsOld = fpOld.fileSystem();
FileSystem *fsNew = fpNew.fileSystem();
FileSystemHandle *fsOld = fpOld.fileSystem();
FileSystemHandle *fsNew = fpNew.fileSystem();
if (fsOld == NULL) {
errno = ENOENT;
@ -578,10 +558,6 @@ extern "C" int rename(const char *oldname, const char *newname) {
} else {
return 0;
}
#else
errno = ENOSYS;
return -1;
#endif
}
extern "C" char *tmpnam(char *s) {
@ -602,31 +578,24 @@ extern "C" char *_sys_command_string(char *cmd, int len) {
#endif
extern "C" DIR *opendir(const char *path) {
#if MBED_CONF_FILESYSTEM_PRESENT
FilePath fp(path);
FileSystem* fs = fp.fileSystem();
FileSystemHandle* fs = fp.fileSystem();
if (fs == NULL) {
errno = ENOENT;
return NULL;
}
Dir *dir = new ManagedDir;
int err = dir->open(fs, fp.fileName());
DirHandle *dir;
int err = fs->open(&dir, fp.fileName());
if (err < 0) {
errno = -err;
delete dir;
dir = NULL;
return NULL;
}
return dir;
#else
errno = ENOSYS;
return 0;
#endif
}
extern "C" struct dirent *readdir(DIR *dir) {
#if MBED_CONF_FILESYSTEM_PRESENT
static struct dirent ent;
int err = dir->read(&ent);
if (err < 1) {
@ -637,14 +606,9 @@ extern "C" struct dirent *readdir(DIR *dir) {
}
return &ent;
#else
errno = ENOSYS;
return 0;
#endif
}
extern "C" int closedir(DIR *dir) {
#if MBED_CONF_FILESYSTEM_PRESENT
int err = dir->close();
if (err < 0) {
errno = -err;
@ -652,41 +616,23 @@ extern "C" int closedir(DIR *dir) {
} else {
return 0;
}
#else
errno = ENOSYS;
return -1;
#endif
}
extern "C" void rewinddir(DIR *dir) {
#if MBED_CONF_FILESYSTEM_PRESENT
dir->rewind();
#else
errno = ENOSYS;
#endif
}
extern "C" off_t telldir(DIR *dir) {
#if MBED_CONF_FILESYSTEM_PRESENT
return dir->tell();
#else
errno = ENOSYS;
return 0;
#endif
}
extern "C" void seekdir(DIR *dir, off_t off) {
#if MBED_CONF_FILESYSTEM_PRESENT
dir->seek(off);
#else
errno = ENOSYS;
#endif
}
extern "C" int mkdir(const char *path, mode_t mode) {
#if MBED_CONF_FILESYSTEM_PRESENT
FilePath fp(path);
FileSystem *fs = fp.fileSystem();
FileSystemHandle *fs = fp.fileSystem();
if (fs == NULL) return -1;
int err = fs->mkdir(fp.fileName(), mode);
@ -696,16 +642,11 @@ extern "C" int mkdir(const char *path, mode_t mode) {
} else {
return 0;
}
#else
errno = ENOSYS;
return -1;
#endif
}
extern "C" int stat(const char *path, struct stat *st) {
#if MBED_CONF_FILESYSTEM_PRESENT
FilePath fp(path);
FileSystem *fs = fp.fileSystem();
FileSystemHandle *fs = fp.fileSystem();
if (fs == NULL) return -1;
int err = fs->stat(fp.fileName(), st);
@ -715,10 +656,6 @@ extern "C" int stat(const char *path, struct stat *st) {
} else {
return 0;
}
#else
errno = ENOSYS;
return -1;
#endif
}
#if defined(TOOLCHAIN_GCC)

View File

@ -52,11 +52,11 @@ typedef int mode_t; ///< Mode for opening files
/* DIR declarations must also be here */
#if __cplusplus
namespace mbed {
class Dir;
class FileHandle;
class DirHandle;
std::FILE *mbed_fdopen(FileHandle *fh, const char *mode);
}
typedef mbed::Dir DIR;
typedef mbed::DirHandle DIR;
#else
typedef struct Dir DIR;
#endif