From 26aa51e8a6de6601a480797b09a2c10f39845338 Mon Sep 17 00:00:00 2001 From: "bernard.xiong@gmail.com" Date: Sun, 18 Jul 2010 16:35:56 +0000 Subject: [PATCH] add flush, statfs, mkfs to device file system interface. git-svn-id: https://rt-thread.googlecode.com/svn/trunk@804 bbd45198-f89e-11dd-88c7-29a3b14d5316 --- components/dfs/filesystems/elmfat/dfs_elm.c | 107 +++- components/dfs/filesystems/elmfat/ff.c | 2 +- components/dfs/filesystems/nfs/dfs_nfs.c | 36 +- components/dfs/include/dfs.h | 37 ++ components/dfs/include/dfs_file.h | 35 ++ components/dfs/src/dfs.c | 336 +++++++++++++ components/dfs/src/dfs_file.c | 519 ++++++++++++++++++++ 7 files changed, 1039 insertions(+), 33 deletions(-) create mode 100644 components/dfs/include/dfs.h create mode 100644 components/dfs/include/dfs_file.h create mode 100644 components/dfs/src/dfs.c create mode 100644 components/dfs/src/dfs_file.c diff --git a/components/dfs/filesystems/elmfat/dfs_elm.c b/components/dfs/filesystems/elmfat/dfs_elm.c index f90298e8c..a93aa3b58 100644 --- a/components/dfs/filesystems/elmfat/dfs_elm.c +++ b/components/dfs/filesystems/elmfat/dfs_elm.c @@ -104,6 +104,63 @@ int dfs_elm_unmount(struct dfs_filesystem* fs) return 0; } +int dfs_elm_mkfs(const char* device_name) +{ + BYTE drv; + rt_device_t dev; + FRESULT result; + + /* find device name */ + for (drv = 0; drv < _DRIVES; drv ++) + { + dev = disk[drv]; + if (rt_strncmp(dev->parent.name, device_name, RT_NAME_MAX) == 0) + { + /* 1: no partition table */ + /* 0: auto selection of cluster size */ + result = f_mkfs(drv, 1, 0); + if ( result != FR_OK) + { + rt_kprintf("format error\n"); + return elm_result_to_dfs(result); + } + + return DFS_STATUS_OK; + } + } + + /* can't find device driver */ + rt_kprintf("can not find device driver: %s\n", device_name); + return -DFS_STATUS_EIO; +} + +int dfs_elm_statfs(struct dfs_filesystem* fs, struct dfs_statfs *buf) +{ + FATFS *f; + FRESULT res; + char driver[4]; + DWORD fre_clust, fre_sect, tot_sect; + + RT_ASSERT(fs != RT_NULL); + RT_ASSERT(buf != RT_NULL); + + f = (FATFS*) fs->data; + + rt_snprintf(driver, sizeof(driver), "%d:", f->drive); + res = f_getfree(driver, &fre_clust, &f); + if (res) return elm_result_to_dfs(res); + + /* Get total sectors and free sectors */ + tot_sect = (f->max_clust - 2) * f->csize; + fre_sect = fre_clust * f->csize; + + buf->f_bfree = fre_sect; + buf->f_blocks = tot_sect; + buf->f_bsize = 512; + + return 0; +} + int dfs_elm_open(struct dfs_fd* file) { FIL* fd; @@ -292,6 +349,18 @@ int dfs_elm_write(struct dfs_fd* file, const void* buf, rt_size_t len) return elm_result_to_dfs(result); } +int dfs_elm_flush(struct dfs_fd* file) +{ + FIL* fd; + FRESULT result; + + fd = (FIL*)(file->data); + RT_ASSERT(fd != RT_NULL); + + result = f_sync(fd); + return elm_result_to_dfs(result); +} + int dfs_elm_lseek(struct dfs_fd* file, rt_off_t offset) { FIL* fd; @@ -491,24 +560,29 @@ int dfs_elm_stat(struct dfs_filesystem* fs, const char *path, struct dfs_stat *s return elm_result_to_dfs(result); } -static struct dfs_filesystem_operation dfs_elm; -int elm_init(void) +static const struct dfs_filesystem_operation dfs_elm = { - rt_strncpy(dfs_elm.name, "elm", DFS_FS_NAME_MAX); - - dfs_elm.mount = dfs_elm_mount; - dfs_elm.unmount = dfs_elm_unmount; - dfs_elm.open = dfs_elm_open; - dfs_elm.close = dfs_elm_close; - dfs_elm.ioctl = dfs_elm_ioctl; - dfs_elm.read = dfs_elm_read; - dfs_elm.write = dfs_elm_write; - dfs_elm.lseek = dfs_elm_lseek; - dfs_elm.getdents= dfs_elm_getdents; - dfs_elm.unlink = dfs_elm_unlink; - dfs_elm.stat = dfs_elm_stat; - dfs_elm.rename = dfs_elm_rename; + "elm", + dfs_elm_mount, + dfs_elm_unmount, + dfs_elm_mkfs, + dfs_elm_statfs, + + dfs_elm_open, + dfs_elm_close, + dfs_elm_ioctl, + dfs_elm_read, + dfs_elm_write, + dfs_elm_flush, + dfs_elm_lseek, + dfs_elm_getdents, + dfs_elm_unlink, + dfs_elm_stat, + dfs_elm_rename, +}; +int elm_init(void) +{ /* register fatfs file system */ dfs_register(&dfs_elm); @@ -577,6 +651,7 @@ DRESULT disk_ioctl (BYTE drv, BYTE ctrl, void *buff) rt_device_control(device, RT_DEVICE_CTRL_BLK_GETGEOME, &geometry); *(DWORD*)buff = geometry.sector_count; + if (geometry.sector_count == 0) return RES_ERROR; } else if (ctrl == GET_SECTOR_SIZE) { diff --git a/components/dfs/filesystems/elmfat/ff.c b/components/dfs/filesystems/elmfat/ff.c index fc6b73bc7..4a3170ca8 100644 --- a/components/dfs/filesystems/elmfat/ff.c +++ b/components/dfs/filesystems/elmfat/ff.c @@ -2772,7 +2772,7 @@ FRESULT f_forward ( /* Create File System on the Drive */ /*-----------------------------------------------------------------------*/ #define N_ROOTDIR 512 /* Multiple of 32 and <= 2048 */ -#define N_FATS 2 /* 1 or 2 */ // my edit +#define N_FATS 2 /* 1 or 2 */ #define MAX_SECTOR 131072000UL /* Maximum partition size */ #define MIN_SECTOR 2000UL /* Minimum partition size */ diff --git a/components/dfs/filesystems/nfs/dfs_nfs.c b/components/dfs/filesystems/nfs/dfs_nfs.c index dd52aca7e..c5cf2820a 100644 --- a/components/dfs/filesystems/nfs/dfs_nfs.c +++ b/components/dfs/filesystems/nfs/dfs_nfs.c @@ -1017,24 +1017,28 @@ int nfs_getdents(struct dfs_fd* file, struct dfs_dirent* dirp, rt_uint32_t count return index * sizeof(struct dfs_dirent); } -static struct dfs_filesystem_operation _nfs; -int nfs_init(void) +static const struct dfs_filesystem_operation _nfs = { - rt_strncpy(_nfs.name, "nfs", DFS_FS_NAME_MAX); - - _nfs.mount = nfs_mount; - _nfs.unmount = nfs_unmount; - _nfs.open = nfs_open; - _nfs.close = nfs_close; - _nfs.ioctl = nfs_ioctl; - _nfs.read = nfs_read; - _nfs.write = nfs_write; - _nfs.lseek = nfs_lseek; - _nfs.getdents = nfs_getdents; - _nfs.unlink = nfs_unlink; - _nfs.stat = nfs_stat; - _nfs.rename = nfs_rename; + "nfs", + nfs_mount, + nfs_unmount, + RT_NULL, /* mkfs */ + RT_NULL, /* statfs */ + nfs_open, + nfs_close, + nfs_ioctl, + nfs_read, + nfs_write, + RT_NULL, /* flush */ + nfs_lseek, + nfs_getdents, + nfs_unlink, + nfs_stat, + nfs_rename, +}; +int nfs_init(void) +{ /* register fatfs file system */ dfs_register(&_nfs); diff --git a/components/dfs/include/dfs.h b/components/dfs/include/dfs.h new file mode 100644 index 000000000..dc5d311bc --- /dev/null +++ b/components/dfs/include/dfs.h @@ -0,0 +1,37 @@ +/* + * File : dfs.h + * This file is part of Device File System in RT-Thread RTOS + * COPYRIGHT (C) 2004-2010, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE. + * + * Change Logs: + * Date Author Notes + * 2005-02-22 Bernard The first version. + */ + +#ifndef __DFS_H__ +#define __DFS_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +char* dfs_normalize_path(const char* directory, const char* filename); +const char* dfs_subdir(const char* directory, const char* filename); + +/* FD APIs */ +int fd_new(void); +struct dfs_fd* fd_get(int fd); +void fd_put(struct dfs_fd* fd); +int fd_is_open(const char* pathname); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/dfs/include/dfs_file.h b/components/dfs/include/dfs_file.h new file mode 100644 index 000000000..4987201aa --- /dev/null +++ b/components/dfs/include/dfs_file.h @@ -0,0 +1,35 @@ +/* ++------------------------------------------------------------------------------ +| Project : Device Filesystem ++------------------------------------------------------------------------------ +| Copyright 2004, 2005 www.fayfayspace.org. +| All rights reserved. +|------------------------------------------------------------------------------ +| File : dfs_raw.h, the raw APIs of Device FileSystem +|------------------------------------------------------------------------------ +| Chang Logs: +| Date Author Notes +| 2005-01-26 ffxz The first version ++------------------------------------------------------------------------------ +*/ + +#ifndef __DFS_RAW_H__ +#define __DFS_RAW_H__ + +#include +#include +#include + +int dfs_file_open(struct dfs_fd* fd, const char *path, int flags); +int dfs_file_close(struct dfs_fd* fd); +int dfs_file_ioctl(struct dfs_fd* fd, int cmd, void *args); +int dfs_file_read(struct dfs_fd* fd, void *buf, rt_size_t len); +int dfs_file_getdents(struct dfs_fd* fd, struct dfs_dirent* dirp, rt_size_t nbytes); +int dfs_file_unlink(const char *path); +int dfs_file_write(struct dfs_fd* fd, const void *buf, rt_size_t len); +int dfs_file_lseek(struct dfs_fd* fd, rt_off_t offset); +int dfs_file_stat(const char *path, struct dfs_stat *buf); +int dfs_file_rename(const char* oldpath, const char* newpath); + +#endif + diff --git a/components/dfs/src/dfs.c b/components/dfs/src/dfs.c new file mode 100644 index 000000000..28dcea086 --- /dev/null +++ b/components/dfs/src/dfs.c @@ -0,0 +1,336 @@ +/* + * File : dfs.c + * This file is part of Device File System in RT-Thread RTOS + * COPYRIGHT (C) 2004-2010, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE. + * + * Change Logs: + * Date Author Notes + * 2005-02-22 Bernard The first version. + * 2010-07-16 + */ + +#include +#include +#include +#include + +/* Global variables */ +const struct dfs_filesystem_operation* filesystem_operation_table[DFS_FILESYSTEM_TYPES_MAX]; +struct dfs_filesystem filesystem_table[DFS_FILESYSTEMS_MAX]; + +/* device filesystem lock */ +static struct rt_mutex fslock; + +#ifdef DFS_USING_WORKDIR +char working_directory[DFS_PATH_MAX]; +#endif + +#ifdef DFS_USING_STDIO +struct dfs_fd fd_table[3 + DFS_FD_MAX]; +#else +struct dfs_fd fd_table[DFS_FD_MAX]; +#endif + +/** + * this function will initialize device file system. + */ +void dfs_init() +{ + /* clear filesystem operations table */ + rt_memset(filesystem_operation_table, 0, sizeof(filesystem_operation_table)); + /* clear filesystem table */ + rt_memset(filesystem_table, 0, sizeof(filesystem_table)); + /* clean fd table */ + rt_memset(fd_table, 0, sizeof(fd_table)); + + /* create device filesystem lock */ + rt_mutex_init(&fslock, "fslock", RT_IPC_FLAG_FIFO); + +#ifdef DFS_USING_WORKDIR + /* set current working directory */ + rt_memset(working_directory, 0, sizeof(working_directory)); + working_directory[0] = '/'; +#endif +} + +/** + * this function will lock device file system. + * + * note: please don't invoke it on ISR. + */ +void dfs_lock() +{ + rt_err_t result; + + result = rt_mutex_take(&fslock, RT_WAITING_FOREVER); + RT_ASSERT(result == RT_EOK); +} + +/** + * this function will lock device file system. + * + * note: please don't invoke it on ISR. + */ +void dfs_unlock() +{ + rt_mutex_release(&fslock); +} + +/** + * this function will allocate a file descriptor. + * + * @return -1 on failed or the allocated file descriptor. + */ +int fd_new(void) +{ + struct dfs_fd* d; + int idx; + + /* lock filesystem */ + dfs_lock(); + + /* find an empty fd entry */ +#ifdef DFS_USING_STDIO + for (idx = 3; idx < DFS_FD_MAX + 3 && fd_table[idx].ref_count > 0; idx++); +#else + for (idx = 0; idx < DFS_FD_MAX && fd_table[idx].ref_count > 0; idx++); +#endif + + /* can't find an empty fd entry */ +#ifdef DFS_USING_STDIO + if (idx == DFS_FD_MAX + 3) +#else + if (idx == DFS_FD_MAX) +#endif + { + idx = -1; + goto __result; + } + + d = &(fd_table[idx]); + d->ref_count = 1; + +__result: + dfs_unlock(); + return idx; +} + +/** + * this function will return a file descriptor structure according to file + * descriptor. + * + * @return NULL on on this file descriptor or the file descriptor structure + * pointer. + */ +struct dfs_fd* fd_get(int fd) +{ + struct dfs_fd* d; + +#ifdef DFS_USING_STDIO + if ( fd < 3 || fd > DFS_FD_MAX + 3) return RT_NULL; +#else + if ( fd < 0 || fd > DFS_FD_MAX ) return RT_NULL; +#endif + + dfs_lock(); + d = &fd_table[fd]; + + /* increase the reference count */ + d->ref_count ++; + dfs_unlock(); + + return d; +} + +/** + * this function will put the file descriptor. + */ +void fd_put(struct dfs_fd* fd) +{ + dfs_lock(); + fd->ref_count --; + + /* clear this fd entry */ + if ( fd->ref_count == 0 ) + { + rt_memset(fd, 0, sizeof(struct dfs_fd)); + } + dfs_unlock(); +}; + +/** + * this function will return whether this file has been opend. + * + * @param pathname the file path name. + * + * @return 0 on file has been open, -1 on not open. + */ +int fd_is_open(const char* pathname) +{ + char *fullpath; + unsigned int index; + struct dfs_filesystem* fs; + struct dfs_fd* fd; + + fullpath = dfs_normalize_path(RT_NULL, pathname); + if (fullpath != RT_NULL) + { + char *mountpath; + fs = dfs_filesystem_lookup(fullpath); + if (fs == RT_NULL) + { + /* can't find mounted file system */ + rt_free(fullpath); + return -1; + } + + /* get file path name under mounted file system */ + if (fs->path[0] == '/' && fs->path[1] == '\0') + mountpath = fullpath; + else mountpath = fullpath + strlen(fs->path); + + dfs_lock(); + for (index = 0; index < DFS_FD_MAX; index++) + { + fd = &(fd_table[index]); + if (fd->fs == RT_NULL) continue; + + if (fd->fs == fs && + strcmp(fd->path, mountpath) == 0) + { + /* found file in file descriptor table */ + rt_free(fullpath); + dfs_unlock(); + return 0; + } + } + dfs_unlock(); + + rt_free(fullpath); + } + + return -1; +} + +/** + * this function will return a sub-path name under directory. + * + * @param directory the parent directory. + * @param filename the filename. + * + * @return the subdir pointer in filename + */ +const char* dfs_subdir(const char* directory, const char* filename) +{ + const char* dir; + + dir = filename + strlen(directory); + if ((*dir != '/') && (dir != filename)) + { + dir --; + } + return dir; +} + +/** + * this function will normalize a path according to specified parent directory and file name. + * + * @param directory the parent path + * @param filename the file name + * + * @return the built full file path (absoluted path) + */ +char* dfs_normalize_path(const char* directory, const char* filename) +{ + char *fullpath; + char *dst0, *dst, *src; + + /* check parameters */ + RT_ASSERT(filename != RT_NULL); + +#ifdef DFS_USING_WORKDIR + if (directory == NULL) /* shall use working directory */ + directory = &working_directory[0]; +#else + if ((directory == NULL) && (filename[0] != '/')) + { + return RT_NULL; + } +#endif + + if (filename[0] != '/') /* it's a absolute path, use it directly */ + { + fullpath = rt_malloc(strlen(directory) + strlen(filename) + 2); + + /* join path and file name */ + rt_snprintf(fullpath, strlen(directory) + strlen(filename) + 2, + "%s/%s", directory, filename); + } + else + { + fullpath = rt_strdup(filename); /* copy string */ + } + + src = fullpath; + dst = fullpath; + while (1) + { + char c = *src; + + if (c == '.') + { + if (!src[1]) src ++; /* '.' and ends */ + else if (src[1] == '/') + { + /* './' case */ + src += 2; + + while ((*src == '/') && (*src != '\0')) src ++; + continue; + } + else if (src[1] == '.') + { + if (!src[2]) + { + /* '..' and ends case */ + src += 2; + goto up_one; + } + else if (src[2] == '/') + { + /* '../' case */ + src += 3; + + while ((*src == '/') && (*src != '\0')) src ++; + goto up_one; + } + } + } + + /* copy up the next '/' and erase all '/' */ + while ((c = *src++) != '\0' && c != '/') *dst ++ = c; + + if (c == '/') + { + *dst ++ = '/'; + while (c == '/') c = *src++; + + src --; + } + else if (!c) break; + + continue; + +up_one: + dst --; + if (dst < dst0) { rt_free(fullpath); return NULL;} + while (dst0 < dst && dst[-1] != '/') dst --; + } + + *dst = '\0'; + return fullpath; +} diff --git a/components/dfs/src/dfs_file.c b/components/dfs/src/dfs_file.c new file mode 100644 index 000000000..f5562dc4a --- /dev/null +++ b/components/dfs/src/dfs_file.c @@ -0,0 +1,519 @@ +/* + * File : dfs_file.c + * This file is part of Device File System in RT-Thread RTOS + * COPYRIGHT (C) 2004-2010, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE. + * + * Change Logs: + * Date Author Notes + * 2005-02-22 Bernard The first version. + */ +#include +#include + +#define NO_WORKING_DIR "system does not support working dir\n" + +/** + * this function will open a file which specified by path with specified flags. + * + * @param fd the file descriptor pointer to return the corresponding result. + * @param path the spaciefied file path. + * @param flags the flags for open operator. + * + * @return 0 on successful, -1 on failed. + */ +int dfs_file_open(struct dfs_fd* fd, const char *path, int flags) +{ + struct dfs_filesystem* fs; + char *fullpath; + int result; + + /* parameter check */ + if ( fd == RT_NULL ) return -DFS_STATUS_EINVAL; + + /* make sure we have an absolute path */ + fullpath = dfs_normalize_path(RT_NULL, path); + if (fullpath == RT_NULL) + { + rt_kprintf(NO_WORKING_DIR); + return -1; + } + + dfs_log(DFS_DEBUG_INFO, ("open file:%s", fullpath)); + + /* find filesystem */ + fs = dfs_filesystem_lookup(fullpath); + if ( fs == RT_NULL ) + { + rt_free(fullpath); /* release path */ + return -DFS_STATUS_ENOENT; + } + + dfs_log(DFS_DEBUG_INFO, ("open in filesystem:%s", fs->ops->name)); + fd->fs = fs; + + /* initilize the fd item */ + fd->type = FT_REGULAR; + fd->flags = flags; + fd->size = 0; + fd->pos = 0; + + fd->path = rt_strdup(dfs_subdir(fs->path, fullpath)); + rt_free(fullpath); + dfs_log(DFS_DEBUG_INFO, ("actul file path: %s\n", fd->path)); + + /* specific file system open routine */ + if (fs->ops->open == RT_NULL) + { + /* clear fd */ + rt_free(fd->path); + rt_memset(fd, 0, sizeof(*fd)); + + return -DFS_STATUS_ENOSYS; + } + + if ((result = fs->ops->open(fd)) < 0) + { + /* clear fd */ + rt_free(fd->path); + rt_memset(fd, 0, sizeof(*fd)); + + dfs_log(DFS_DEBUG_INFO, ("open failed")); + + return result; + } + + fd->flags |= DFS_F_OPEN; + if ( flags & DFS_O_DIRECTORY ) + { + fd->type = FT_DIRECTORY; + fd->flags |= DFS_F_DIRECTORY; + } + + dfs_log(DFS_DEBUG_INFO, ("open successful")); + return 0; +} + +/** + * this function will close a file descriptor. + * + * @param fd the file descriptor to be closed. + * + * @return 0 on successful, -1 on failed. + */ +int dfs_file_close(struct dfs_fd* fd) +{ + int result = 0; + + if (fd != RT_NULL && fd->fs->ops->close != RT_NULL) result = fd->fs->ops->close(fd); + + /* close fd error, return */ + if ( result < 0 ) return result; + + rt_free(fd->path); + rt_memset(fd, 0, sizeof(struct dfs_fd)); + + return result; +} + +/** + * this function will perform a io control on a file descriptor. + * + * @param fd the file descriptor. + * @param cmd the command to send to file descriptor. + * @param args the argument to send to file descriptor. + * + * @return 0 on successful, -1 on failed. + */ +int dfs_file_ioctl(struct dfs_fd* fd, int cmd, void *args) +{ + struct dfs_filesystem* fs; + + if (fd == RT_NULL || fd->type != FT_REGULAR) return -DFS_STATUS_EINVAL; + + fs = fd->fs; + if (fs->ops->ioctl != RT_NULL) return fs->ops->ioctl(fd, cmd, args); + + return -DFS_STATUS_ENOSYS; +} + +/** + * this function will read specified length data from a file descriptor to a buffer. + * + * @param fd the file descriptor. + * @param buf the buffer to save the read data. + * @param len the length of data buffer to be read. + * + * @return the actual read data bytes or 0 on end of file or failed. + */ +int dfs_file_read(struct dfs_fd* fd, void *buf, rt_size_t len) +{ + struct dfs_filesystem* fs; + int result = 0; + + if (fd == RT_NULL) return -DFS_STATUS_EINVAL; + + fs = (struct dfs_filesystem*) fd->fs; + if (fs->ops->read == RT_NULL) return -DFS_STATUS_ENOSYS; + + if ( (result = fs->ops->read(fd, buf, len)) < 0 ) fd->flags |= DFS_F_EOF; + + return result; +} + +/** + * this function will fetch directory entries from a directory descriptor. + * + * @param fd the directory decriptor. + * @param dirp the dirent buffer to save result. + * @param nbytes the aviable room in the buffer. + * + * @return the read dirent, others on failed. + */ +int dfs_file_getdents(struct dfs_fd* fd, struct dfs_dirent* dirp, rt_size_t nbytes) +{ + struct dfs_filesystem* fs; + + /* parameter check */ + if (fd == RT_NULL || fd->type != FT_DIRECTORY) return -DFS_STATUS_EINVAL; + + fs = (struct dfs_filesystem*) fd->fs; + if (fs->ops->getdents != RT_NULL) return fs->ops->getdents(fd, dirp, nbytes); + + return -DFS_STATUS_ENOSYS; +} + +/** + * this function will unlink (remove) a specified path file from file system. + * + * @param path the specified path file to be unlinked. + * + * @return 0 on successful, -1 on failed. + */ +int dfs_file_unlink(const char *path) +{ + int result; + char *fullpath; + struct dfs_filesystem* fs; + + result = DFS_STATUS_OK; + + /* Make sure we have an absolute path */ + fullpath = dfs_normalize_path(RT_NULL, path); + if ( fullpath == RT_NULL) + { + rt_kprintf(NO_WORKING_DIR); + return -DFS_STATUS_EINVAL; + } + + /* get filesystem */ + if ( (fs = dfs_filesystem_lookup(fullpath)) == RT_NULL) + { + result = -DFS_STATUS_ENOENT; + goto __exit; + } + + /* Check whether file is already open */ + if (fd_is_open(fullpath) == 0) + { + result = -DFS_STATUS_EBUSY; + goto __exit; + } + + if (fs->ops->unlink != RT_NULL) + result = fs->ops->unlink(fs, dfs_subdir(fs->path, fullpath)); + else result = -DFS_STATUS_ENOSYS; + +__exit: + rt_free(fullpath); + return result; +} + +/** + * this function will write some specified length data to file system. + * + * @param fd the file descriptor. + * @param buf the data buffer to be written. + * @param len the data buffer length + * + * @return the actual written data length. + */ +int dfs_file_write(struct dfs_fd* fd, const void *buf, rt_size_t len) +{ + struct dfs_filesystem* fs; + + if (fd == RT_NULL) return -DFS_STATUS_EINVAL; + + fs = fd->fs; + if (fs->ops->write == RT_NULL) return -DFS_STATUS_ENOSYS; + + return fs->ops->write(fd, buf, len); +} + +/** + * this function will flush buffer on a file descriptor. + * + * @param fd the file descriptor. + * + * @return 0 on successful, -1 on failed. + */ +int dfs_file_flush(struct dfs_fd* fd) +{ + struct dfs_filesystem* fs; + + if (fd == RT_NULL) return -DFS_STATUS_EINVAL; + + fs = fd->fs; + if (fs->ops->flush == RT_NULL) return -DFS_STATUS_ENOSYS; + + return fs->ops->flush(fd); +} + +/** + * this function will seek the offset for specified file descriptor. + * + * @param fd the file descriptor. + * @param offset the offset to be seeked. + * + * @return the current position after seek. + */ +int dfs_file_lseek(struct dfs_fd* fd, rt_off_t offset) +{ + struct dfs_filesystem* fs = fd->fs; + + if (fd == RT_NULL) return -DFS_STATUS_EINVAL; + if (fs->ops->lseek == RT_NULL) return -DFS_STATUS_ENOSYS; + + return fs->ops->lseek(fd, offset); +} + +/** + * this function will get file information. + * + * @param path the file path. + * @param buf the data buffer to save stat description. + * + * @return 0 on successful, -1 on failed. + */ +int dfs_file_stat(const char *path, struct dfs_stat *buf) +{ + int result; + char* fullpath; + struct dfs_filesystem* fs; + + fullpath = dfs_normalize_path(RT_NULL, path); + if ( fullpath == RT_NULL ) + { + rt_kprintf(NO_WORKING_DIR); + return -1; + } + + if ((fs = dfs_filesystem_lookup(fullpath)) == RT_NULL) + { + dfs_log(DFS_DEBUG_ERROR, ("can't find mounted filesystem on this path:%s", fullpath)); + rt_free(fullpath); + return -DFS_STATUS_ENOENT; + } + + if (fullpath[0] == '/' && fullpath[1] == '\0') + { + /* it's the root directory */ + buf->st_dev = 0; + + buf->st_mode = DFS_S_IRUSR | DFS_S_IRGRP | DFS_S_IROTH | + DFS_S_IWUSR | DFS_S_IWGRP | DFS_S_IWOTH; + buf->st_mode |= DFS_S_IFDIR | DFS_S_IXUSR | DFS_S_IXGRP | DFS_S_IXOTH; + + buf->st_size = 0; + buf->st_mtime = 0; + buf->st_blksize = 512; + + /* release full path */ + rt_free(fullpath); + + return DFS_STATUS_OK; + } + + /* get the real file path */ + + if (fs->ops->stat == RT_NULL) + { + rt_free(fullpath); + dfs_log(DFS_DEBUG_ERROR, ("the filesystem didn't implement this function")); + return -DFS_STATUS_ENOSYS; + } + + result = fs->ops->stat(fs, fullpath, buf); + rt_free(fullpath); + + return result; +} + +/** + * this funciton will rename an old path name to a new path name. + * + * @param oldpath the old path name. + * @param newpath the new path name. + * + * @return 0 on successful, -1 on failed. + */ +int dfs_file_rename(const char* oldpath, const char* newpath) +{ + int result; + struct dfs_filesystem *oldfs, *newfs; + char *oldfullpath, *newfullpath; + + result = DFS_STATUS_OK; + + oldfullpath = dfs_normalize_path(RT_NULL, oldpath); + if ( oldfullpath == RT_NULL ) + { + rt_kprintf(NO_WORKING_DIR); + result = -DFS_STATUS_ENOENT; + goto __exit; + } + + newfullpath = dfs_normalize_path(RT_NULL, newpath); + if ( newfullpath == RT_NULL ) + { + rt_kprintf(NO_WORKING_DIR); + result = -DFS_STATUS_ENOENT; + goto __exit; + } + + if ( (oldfs = dfs_filesystem_lookup(oldfullpath)) == RT_NULL ) + { + result = -DFS_STATUS_ENOENT; + goto __exit; + } + + if ( (newfs = dfs_filesystem_lookup(newfullpath)) == RT_NULL ) + { + result = -DFS_STATUS_ENOENT; + goto __exit; + } + + if ( oldfs == newfs ) + { + if ( oldfs->ops->rename == RT_NULL ) + { + result = -DFS_STATUS_ENOSYS; + goto __exit; + } + + result = oldfs->ops->rename(oldfs, oldfullpath, newfullpath); + goto __exit; + } + + result = -DFS_STATUS_EXDEV; + +__exit: + rt_free(oldfullpath); + rt_free(newfullpath); + + /* not at same file system, return EXDEV */ + return result; +} + +#ifdef RT_USING_FINSH +#include + +static struct dfs_fd fd; +static struct dfs_dirent dirent; +void ls(const char* pathname) +{ + struct dfs_stat stat; + int length; + char* fullpath; + + fullpath = rt_malloc(DFS_PATH_MAX + 1); + if (fullpath == RT_NULL) return; /* out of memory */ + /* list directory */ + if ( dfs_file_open(&fd, pathname, DFS_O_DIRECTORY) == 0 ) + { + rt_kprintf("Directory %s:\n", pathname); + do + { + rt_memset(&dirent, 0, sizeof(struct dfs_dirent)); + length = dfs_file_getdents(&fd, &dirent, sizeof(struct dfs_dirent)); + if ( length > 0 ) + { + rt_memset(&stat, 0, sizeof(struct dfs_stat)); + + /* build full path for each file */ + if (pathname[strlen(pathname) - 1] != '/') + rt_snprintf(fullpath, DFS_PATH_MAX + 1, "%s%c%s", pathname, '/', dirent.d_name); + else + rt_snprintf(fullpath, DFS_PATH_MAX + 1, "%s%s", pathname, dirent.d_name); + + dfs_file_stat(fullpath, &stat); + if ( stat.st_mode & DFS_S_IFDIR ) + { + rt_kprintf("%s\t\t\n", dirent.d_name); + } + else + { + rt_kprintf("%s\t\t%lu\n", dirent.d_name, stat.st_size); + } + } + }while(length > 0); + + dfs_file_close(&fd); + } + else + { + rt_kprintf("No such directory\n"); + } + rt_free(fullpath); +} +FINSH_FUNCTION_EXPORT(ls, list directory contents) + +static void mkdir(const char* pathname) +{ + /* make a new directory */ + if (dfs_file_open(&fd, pathname, DFS_O_DIRECTORY | DFS_O_CREAT) == 0) + { + dfs_file_close(&fd); + } + else rt_kprintf("Can't mkdir %s\n", pathname); +} +FINSH_FUNCTION_EXPORT(mkdir, make a directory) + +void rm(const char* filename) +{ + if (dfs_file_unlink(filename) < 0) + { + rt_kprintf("Delete %s failed\n", filename); + } +} +FINSH_FUNCTION_EXPORT(rm, remove files or directories) + +void cat(const char* filename) +{ + rt_uint32_t length; + char buffer[81]; + + if (dfs_file_open(&fd, filename, DFS_O_RDONLY) < 0) + { + rt_kprintf("Open %s failed\n", filename); + return; + } + + do + { + rt_memset(buffer, 0, sizeof(buffer)); + length = dfs_file_read(&fd, buffer, 81); + if (length > 0) + { + rt_kprintf("%s", buffer); + } + }while (length > 0); + + dfs_file_close(&fd); +} +FINSH_FUNCTION_EXPORT(cat, print file) + +#endif -- GitLab