454 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			454 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|  | /*
 | ||
|  |  * Copyright (c) 2006-2018, RT-Thread Development Team | ||
|  |  * | ||
|  |  * SPDX-License-Identifier: Apache-2.0 | ||
|  |  * | ||
|  |  * Change Logs: | ||
|  |  * Date           Author       Notes | ||
|  |  * 2013-04-15     Bernard      the first version | ||
|  |  * 2013-05-05     Bernard      remove CRC for ramfs persistence | ||
|  |  * 2013-05-22     Bernard      fix the no entry issue. | ||
|  |  */ | ||
|  | 
 | ||
|  | #include <rtthread.h>
 | ||
|  | #include <dfs.h>
 | ||
|  | #include <dfs_fs.h>
 | ||
|  | #include <dfs_file.h>
 | ||
|  | 
 | ||
|  | #include "dfs_ramfs.h"
 | ||
|  | 
 | ||
|  | int dfs_ramfs_mount(struct dfs_filesystem *fs, | ||
|  |                     unsigned long          rwflag, | ||
|  |                     const void            *data) | ||
|  | { | ||
|  |     struct dfs_ramfs* ramfs; | ||
|  | 
 | ||
|  |     if (data == NULL) | ||
|  |         return -EIO; | ||
|  | 
 | ||
|  |     ramfs = (struct dfs_ramfs *)data; | ||
|  |     fs->data = ramfs; | ||
|  |      | ||
|  |     return RT_EOK; | ||
|  | } | ||
|  | 
 | ||
|  | int dfs_ramfs_unmount(struct dfs_filesystem *fs) | ||
|  | { | ||
|  |     fs->data = NULL; | ||
|  | 
 | ||
|  |     return RT_EOK; | ||
|  | } | ||
|  | 
 | ||
|  | int dfs_ramfs_statfs(struct dfs_filesystem *fs, struct statfs *buf) | ||
|  | { | ||
|  |     struct dfs_ramfs *ramfs; | ||
|  | 
 | ||
|  |     ramfs = (struct dfs_ramfs *)fs->data; | ||
|  |     RT_ASSERT(ramfs != NULL); | ||
|  |     RT_ASSERT(buf != NULL); | ||
|  | 
 | ||
|  |     buf->f_bsize  = 512; | ||
|  |     buf->f_blocks = ramfs->memheap.pool_size/512; | ||
|  |     buf->f_bfree  = ramfs->memheap.available_size/512; | ||
|  | 
 | ||
|  |     return RT_EOK; | ||
|  | } | ||
|  | 
 | ||
|  | int dfs_ramfs_ioctl(struct dfs_fd *file, int cmd, void *args) | ||
|  | { | ||
|  |     return -EIO; | ||
|  | } | ||
|  | 
 | ||
|  | struct ramfs_dirent *dfs_ramfs_lookup(struct dfs_ramfs *ramfs, | ||
|  |                                       const char       *path, | ||
|  |                                       rt_size_t        *size) | ||
|  | { | ||
|  |     const char *subpath; | ||
|  |     struct ramfs_dirent *dirent; | ||
|  | 
 | ||
|  |     subpath = path; | ||
|  |     while (*subpath == '/' && *subpath) | ||
|  |         subpath ++; | ||
|  |     if (! *subpath) /* is root directory */ | ||
|  |     { | ||
|  |         *size = 0; | ||
|  | 
 | ||
|  |         return &(ramfs->root); | ||
|  |     } | ||
|  | 
 | ||
|  |     for (dirent = rt_list_entry(ramfs->root.list.next, struct ramfs_dirent, list); | ||
|  |          dirent != &(ramfs->root); | ||
|  |          dirent = rt_list_entry(dirent->list.next, struct ramfs_dirent, list)) | ||
|  |     { | ||
|  |         if (rt_strcmp(dirent->name, subpath) == 0) | ||
|  |         { | ||
|  |             *size = dirent->size; | ||
|  | 
 | ||
|  |             return dirent; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     /* not found */ | ||
|  |     return NULL; | ||
|  | } | ||
|  | 
 | ||
|  | int dfs_ramfs_read(struct dfs_fd *file, void *buf, size_t count) | ||
|  | { | ||
|  |     rt_size_t length; | ||
|  |     struct ramfs_dirent *dirent; | ||
|  | 
 | ||
|  |     dirent = (struct ramfs_dirent *)file->data; | ||
|  |     RT_ASSERT(dirent != NULL); | ||
|  | 
 | ||
|  |     if (count < file->size - file->pos) | ||
|  |         length = count; | ||
|  |     else | ||
|  |         length = file->size - file->pos; | ||
|  | 
 | ||
|  |     if (length > 0) | ||
|  |         memcpy(buf, &(dirent->data[file->pos]), length); | ||
|  | 
 | ||
|  |     /* update file current position */ | ||
|  |     file->pos += length; | ||
|  | 
 | ||
|  |     return length; | ||
|  | } | ||
|  | 
 | ||
|  | int dfs_ramfs_write(struct dfs_fd *fd, const void *buf, size_t count) | ||
|  | { | ||
|  |     struct ramfs_dirent *dirent; | ||
|  |     struct dfs_ramfs *ramfs; | ||
|  | 
 | ||
|  |     dirent = (struct ramfs_dirent*)fd->data; | ||
|  |     RT_ASSERT(dirent != NULL); | ||
|  | 
 | ||
|  |     ramfs = dirent->fs; | ||
|  |     RT_ASSERT(ramfs != NULL); | ||
|  | 
 | ||
|  |     if (count + fd->pos > fd->size) | ||
|  |     { | ||
|  |         rt_uint8_t *ptr; | ||
|  |         ptr = rt_memheap_realloc(&(ramfs->memheap), dirent->data, fd->pos + count); | ||
|  |         if (ptr == NULL) | ||
|  |         { | ||
|  |             rt_set_errno(-ENOMEM); | ||
|  | 
 | ||
|  |             return 0; | ||
|  |         } | ||
|  | 
 | ||
|  |         /* update dirent and file size */ | ||
|  |         dirent->data = ptr; | ||
|  |         dirent->size = fd->pos + count; | ||
|  |         fd->size = dirent->size; | ||
|  |     } | ||
|  | 
 | ||
|  |     if (count > 0) | ||
|  |         memcpy(dirent->data + fd->pos, buf, count); | ||
|  | 
 | ||
|  |     /* update file current position */ | ||
|  |     fd->pos += count; | ||
|  | 
 | ||
|  |     return count; | ||
|  | } | ||
|  | 
 | ||
|  | int dfs_ramfs_lseek(struct dfs_fd *file, off_t offset) | ||
|  | { | ||
|  |     if (offset <= (off_t)file->size) | ||
|  |     { | ||
|  |         file->pos = offset; | ||
|  | 
 | ||
|  |         return file->pos; | ||
|  |     } | ||
|  | 
 | ||
|  |     return -EIO; | ||
|  | } | ||
|  | 
 | ||
|  | int dfs_ramfs_close(struct dfs_fd *file) | ||
|  | { | ||
|  |     file->data = NULL; | ||
|  | 
 | ||
|  |     return RT_EOK; | ||
|  | } | ||
|  | 
 | ||
|  | int dfs_ramfs_open(struct dfs_fd *file) | ||
|  | { | ||
|  |     rt_size_t size; | ||
|  |     struct dfs_ramfs *ramfs; | ||
|  |     struct ramfs_dirent *dirent; | ||
|  |     struct dfs_filesystem *fs; | ||
|  | 
 | ||
|  |     fs = (struct dfs_filesystem *)file->data; | ||
|  | 
 | ||
|  |     ramfs = (struct dfs_ramfs *)fs->data; | ||
|  |     RT_ASSERT(ramfs != NULL); | ||
|  | 
 | ||
|  |     if (file->flags & O_DIRECTORY) | ||
|  |     { | ||
|  |         if (file->flags & O_CREAT) | ||
|  |         { | ||
|  |             return -ENOSPC; | ||
|  |         } | ||
|  | 
 | ||
|  |         /* open directory */ | ||
|  |         dirent = dfs_ramfs_lookup(ramfs, file->path, &size); | ||
|  |         if (dirent == NULL) | ||
|  |             return -ENOENT; | ||
|  |         if (dirent == &(ramfs->root)) /* it's root directory */ | ||
|  |         { | ||
|  |             if (!(file->flags & O_DIRECTORY)) | ||
|  |             { | ||
|  |                 return -ENOENT; | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |         dirent = dfs_ramfs_lookup(ramfs, file->path, &size); | ||
|  |         if (dirent == &(ramfs->root)) /* it's root directory */ | ||
|  |         { | ||
|  |             return -ENOENT; | ||
|  |         } | ||
|  | 
 | ||
|  |         if (dirent == NULL) | ||
|  |         { | ||
|  |             if (file->flags & O_CREAT || file->flags & O_WRONLY) | ||
|  |             { | ||
|  |                 char *name_ptr; | ||
|  | 
 | ||
|  |                 /* create a file entry */ | ||
|  |                 dirent = (struct ramfs_dirent *) | ||
|  |                          rt_memheap_alloc(&(ramfs->memheap), | ||
|  |                                           sizeof(struct ramfs_dirent)); | ||
|  |                 if (dirent == NULL) | ||
|  |                 { | ||
|  |                     return -ENOMEM; | ||
|  |                 } | ||
|  | 
 | ||
|  |                 /* remove '/' separator */ | ||
|  |                 name_ptr = file->path; | ||
|  |                 while (*name_ptr == '/' && *name_ptr) | ||
|  |                     name_ptr ++; | ||
|  |                 strncpy(dirent->name, name_ptr, RAMFS_NAME_MAX); | ||
|  | 
 | ||
|  |                 rt_list_init(&(dirent->list)); | ||
|  |                 dirent->data = NULL; | ||
|  |                 dirent->size = 0; | ||
|  |                 dirent->fs = ramfs; | ||
|  | 
 | ||
|  |                 /* add to the root directory */ | ||
|  |                 rt_list_insert_after(&(ramfs->root.list), &(dirent->list)); | ||
|  |             } | ||
|  |             else | ||
|  |                 return -ENOENT; | ||
|  |         } | ||
|  | 
 | ||
|  |         /* Creates a new file.
 | ||
|  |          * If the file is existing, it is truncated and overwritten. | ||
|  |          */ | ||
|  |         if (file->flags & O_TRUNC) | ||
|  |         { | ||
|  |             dirent->size = 0; | ||
|  |             if (dirent->data != NULL) | ||
|  |             { | ||
|  |                 rt_memheap_free(dirent->data); | ||
|  |                 dirent->data = NULL; | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     file->data = dirent; | ||
|  |     file->size = dirent->size; | ||
|  |     if (file->flags & O_APPEND) | ||
|  |         file->pos = file->size; | ||
|  |     else  | ||
|  |         file->pos = 0; | ||
|  | 
 | ||
|  |     return 0; | ||
|  | } | ||
|  | 
 | ||
|  | int dfs_ramfs_stat(struct dfs_filesystem *fs, | ||
|  |                    const char            *path, | ||
|  |                    struct stat           *st) | ||
|  | { | ||
|  |     rt_size_t size; | ||
|  |     struct ramfs_dirent *dirent; | ||
|  |     struct dfs_ramfs *ramfs; | ||
|  | 
 | ||
|  |     ramfs = (struct dfs_ramfs *)fs->data; | ||
|  |     dirent = dfs_ramfs_lookup(ramfs, path, &size); | ||
|  | 
 | ||
|  |     if (dirent == NULL) | ||
|  |         return -ENOENT; | ||
|  | 
 | ||
|  |     st->st_dev = 0; | ||
|  |     st->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH | | ||
|  |                   S_IWUSR | S_IWGRP | S_IWOTH; | ||
|  | 
 | ||
|  |     st->st_size = dirent->size; | ||
|  |     st->st_mtime = 0; | ||
|  | 
 | ||
|  |     return RT_EOK; | ||
|  | } | ||
|  | 
 | ||
|  | int dfs_ramfs_getdents(struct dfs_fd *file, | ||
|  |                        struct dirent *dirp, | ||
|  |                        uint32_t    count) | ||
|  | { | ||
|  |     rt_size_t index, end; | ||
|  |     struct dirent *d; | ||
|  |     struct ramfs_dirent *dirent; | ||
|  |     struct dfs_ramfs *ramfs; | ||
|  | 
 | ||
|  |     dirent = (struct ramfs_dirent *)file->data; | ||
|  | 
 | ||
|  |     ramfs  = dirent->fs; | ||
|  |     RT_ASSERT(ramfs != RT_NULL); | ||
|  | 
 | ||
|  |     if (dirent != &(ramfs->root)) | ||
|  |         return -EINVAL; | ||
|  | 
 | ||
|  |     /* make integer count */ | ||
|  |     count = (count / sizeof(struct dirent)); | ||
|  |     if (count == 0) | ||
|  |         return -EINVAL; | ||
|  | 
 | ||
|  |     end = file->pos + count; | ||
|  |     index = 0; | ||
|  |     count = 0; | ||
|  |     for (dirent = rt_list_entry(dirent->list.next, struct ramfs_dirent, list); | ||
|  |          dirent != &(ramfs->root) && index < end; | ||
|  |          dirent = rt_list_entry(dirent->list.next, struct ramfs_dirent, list)) | ||
|  |     { | ||
|  |         if (index >= (rt_size_t)file->pos) | ||
|  |         { | ||
|  |             d = dirp + count; | ||
|  |             d->d_type = DT_REG; | ||
|  |             d->d_namlen = RT_NAME_MAX; | ||
|  |             d->d_reclen = (rt_uint16_t)sizeof(struct dirent); | ||
|  |             rt_strncpy(d->d_name, dirent->name, RAMFS_NAME_MAX); | ||
|  | 
 | ||
|  |             count += 1; | ||
|  |             file->pos += 1; | ||
|  |         } | ||
|  |         index += 1; | ||
|  |     } | ||
|  | 
 | ||
|  |     return count * sizeof(struct dirent); | ||
|  | } | ||
|  | 
 | ||
|  | int dfs_ramfs_unlink(struct dfs_filesystem *fs, const char *path) | ||
|  | { | ||
|  |     rt_size_t size; | ||
|  |     struct dfs_ramfs *ramfs; | ||
|  |     struct ramfs_dirent *dirent; | ||
|  | 
 | ||
|  |     ramfs = (struct dfs_ramfs *)fs->data; | ||
|  |     RT_ASSERT(ramfs != NULL); | ||
|  | 
 | ||
|  |     dirent = dfs_ramfs_lookup(ramfs, path, &size); | ||
|  |     if (dirent == NULL) | ||
|  |         return -ENOENT; | ||
|  | 
 | ||
|  |     rt_list_remove(&(dirent->list)); | ||
|  |     if (dirent->data != NULL) | ||
|  |         rt_memheap_free(dirent->data); | ||
|  |     rt_memheap_free(dirent); | ||
|  | 
 | ||
|  |     return RT_EOK; | ||
|  | } | ||
|  | 
 | ||
|  | int dfs_ramfs_rename(struct dfs_filesystem *fs, | ||
|  |                      const char            *oldpath, | ||
|  |                      const char            *newpath) | ||
|  | { | ||
|  |     struct ramfs_dirent *dirent; | ||
|  |     struct dfs_ramfs *ramfs; | ||
|  |     rt_size_t size; | ||
|  | 
 | ||
|  |     ramfs = (struct dfs_ramfs *)fs->data; | ||
|  |     RT_ASSERT(ramfs != NULL); | ||
|  | 
 | ||
|  |     dirent = dfs_ramfs_lookup(ramfs, newpath, &size); | ||
|  |     if (dirent != NULL) | ||
|  |         return -EEXIST; | ||
|  | 
 | ||
|  |     dirent = dfs_ramfs_lookup(ramfs, oldpath, &size); | ||
|  |     if (dirent == NULL) | ||
|  |         return -ENOENT; | ||
|  | 
 | ||
|  |     strncpy(dirent->name, newpath, RAMFS_NAME_MAX); | ||
|  | 
 | ||
|  |     return RT_EOK; | ||
|  | } | ||
|  | 
 | ||
|  | static const struct dfs_file_ops _ram_fops =  | ||
|  | { | ||
|  |     dfs_ramfs_open, | ||
|  |     dfs_ramfs_close, | ||
|  |     dfs_ramfs_ioctl, | ||
|  |     dfs_ramfs_read, | ||
|  |     dfs_ramfs_write, | ||
|  |     NULL, /* flush */ | ||
|  |     dfs_ramfs_lseek, | ||
|  |     dfs_ramfs_getdents, | ||
|  | }; | ||
|  | 
 | ||
|  | static const struct dfs_filesystem_ops _ramfs = | ||
|  | { | ||
|  |     "ram", | ||
|  |     DFS_FS_FLAG_DEFAULT, | ||
|  |     &_ram_fops, | ||
|  | 
 | ||
|  |     dfs_ramfs_mount, | ||
|  |     dfs_ramfs_unmount, | ||
|  |     NULL, /* mkfs */ | ||
|  |     dfs_ramfs_statfs, | ||
|  | 
 | ||
|  |     dfs_ramfs_unlink, | ||
|  |     dfs_ramfs_stat, | ||
|  |     dfs_ramfs_rename, | ||
|  | }; | ||
|  | 
 | ||
|  | int dfs_ramfs_init(void) | ||
|  | { | ||
|  |     /* register ram file system */ | ||
|  |     dfs_register(&_ramfs); | ||
|  | 
 | ||
|  |     return 0; | ||
|  | } | ||
|  | INIT_COMPONENT_EXPORT(dfs_ramfs_init); | ||
|  | 
 | ||
|  | struct dfs_ramfs* dfs_ramfs_create(rt_uint8_t *pool, rt_size_t size) | ||
|  | { | ||
|  |     struct dfs_ramfs *ramfs; | ||
|  |     rt_uint8_t *data_ptr; | ||
|  |     rt_err_t result; | ||
|  | 
 | ||
|  |     size  = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE); | ||
|  |     ramfs = (struct dfs_ramfs *)pool; | ||
|  | 
 | ||
|  |     data_ptr = (rt_uint8_t *)(ramfs + 1); | ||
|  |     size = size - sizeof(struct dfs_ramfs); | ||
|  |     size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE); | ||
|  | 
 | ||
|  |     result = rt_memheap_init(&ramfs->memheap, "ramfs", data_ptr, size); | ||
|  |     if (result != RT_EOK) | ||
|  |         return NULL; | ||
|  |     /* detach this memheap object from the system */ | ||
|  |     rt_object_detach((rt_object_t)&(ramfs->memheap)); | ||
|  | 
 | ||
|  |     /* initialize ramfs object */ | ||
|  |     ramfs->magic = RAMFS_MAGIC; | ||
|  |     ramfs->memheap.parent.type = RT_Object_Class_MemHeap | RT_Object_Class_Static; | ||
|  | 
 | ||
|  |     /* initialize root directory */ | ||
|  |     memset(&(ramfs->root), 0x00, sizeof(ramfs->root)); | ||
|  |     rt_list_init(&(ramfs->root.list)); | ||
|  |     ramfs->root.size = 0; | ||
|  |     strcpy(ramfs->root.name, "."); | ||
|  |     ramfs->root.fs = ramfs; | ||
|  | 
 | ||
|  |     return ramfs; | ||
|  | } | ||
|  | 
 |