659 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			659 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2006-2018, RT-Thread Development Team
 | |
|  *
 | |
|  * SPDX-License-Identifier: Apache-2.0
 | |
|  *
 | |
|  * Change Logs:
 | |
|  * Date           Author       Notes
 | |
|  * 2011-10-22     prife        the first version
 | |
|  * 2012-03-28     prife        use mtd device interface
 | |
|  * 2012-04-05     prife        update uffs with official repo and use uffs_UnMount/Mount
 | |
|  * 2017-04-12     lizhen9880   fix the f_bsize and f_blocks issue in function dfs_uffs_statfs
 | |
|  */
 | |
| 
 | |
| #include <rtthread.h>
 | |
| 
 | |
| #include <dfs_fs.h>
 | |
| #include <dfs_file.h>
 | |
| #include <rtdevice.h>
 | |
| 
 | |
| #include "dfs_uffs.h"
 | |
| 
 | |
| #include "uffs/uffs_fd.h" /* posix file api is here */
 | |
| #include "uffs/uffs_mtb.h"
 | |
| #include "uffs/uffs_mem.h"
 | |
| #include "uffs/uffs_utils.h"
 | |
| 
 | |
| /*
 | |
|  * RT-Thread DFS Interface for uffs
 | |
|  */
 | |
| #define UFFS_DEVICE_MAX         2    /* the max partions on a nand deivce*/
 | |
| #define UFFS_MOUNT_PATH_MAX     128  /* the mount point max length */
 | |
| #define FILE_PATH_MAX           256  /* the longest file path */
 | |
| 
 | |
| struct _nand_dev
 | |
| {
 | |
|     struct rt_mtd_nand_device * dev;
 | |
|     struct uffs_StorageAttrSt storage;
 | |
|     uffs_Device uffs_dev;
 | |
|     uffs_MountTable mount_table;
 | |
|     char mount_path[UFFS_MOUNT_PATH_MAX];
 | |
|     void * data;  /* when uffs use static buf, it will save ptr here */ 
 | |
| };
 | |
| /* make sure the following struct var had been initilased to 0! */
 | |
| static struct _nand_dev nand_part[UFFS_DEVICE_MAX] = {0};
 | |
| 
 | |
| static int uffs_result_to_dfs(int result)
 | |
| {
 | |
|     int status = -1;
 | |
| 
 | |
|     result = result < 0 ? -result : result;
 | |
|     switch (result)
 | |
|     {
 | |
|     case UENOERR:/** no error */
 | |
|         break;
 | |
|     case UEACCES:/** Tried to open read-only file for writing, or files sharing mode
 | |
|                    does not allow specified operations, or given path is directory */
 | |
|         status = -EINVAL;
 | |
|         break;/* no suitable */
 | |
|     case UEEXIST:   /** _O_CREAT and _O_EXCL flags specified, but filename already exists */
 | |
|         status = -EEXIST;
 | |
|         break;
 | |
|     case UEINVAL:  /** Invalid oflag or pmode argument */
 | |
|         status = -EINVAL;
 | |
|         break;
 | |
|     case UEMFILE: /** No more file handles available(too many open files)  */
 | |
|         status = -1;
 | |
|         break;
 | |
|     case UENOENT: /** file or path not found */
 | |
|         status = -ENOENT;
 | |
|         break;
 | |
|     case UETIME: /** can't set file time */
 | |
|         status = -1;
 | |
|         break;
 | |
|     case UEBADF: /** invalid file handle */
 | |
|         status = -EBADF;
 | |
|         break;
 | |
|     case UENOMEM:/** no enough memory */
 | |
|         status = -ENOSPC;
 | |
|         break;
 | |
|     case UEIOERR: /** I/O error from lower level flash operation */
 | |
|         status = -EIO;
 | |
|         break;
 | |
|     case UENOTDIR: /** Not a directory */
 | |
|         status = -ENOTDIR;
 | |
|         break;
 | |
|     case UEISDIR: /** Is a directory */
 | |
|         status = -EISDIR;
 | |
|         break;
 | |
|     case UEUNKNOWN_ERR:
 | |
|     default:
 | |
|         status = -1;
 | |
|         break; /* unknown error! */
 | |
|     }
 | |
| 
 | |
|     return status;
 | |
| }
 | |
| 
 | |
| static URET _device_init(uffs_Device *dev)
 | |
| {
 | |
|     dev->attr->_private = NULL; // hook nand_chip data structure to attr->_private
 | |
|     dev->ops = (struct uffs_FlashOpsSt *)&nand_ops;
 | |
| 
 | |
|     return U_SUCC;
 | |
| }
 | |
| 
 | |
| static URET _device_release(uffs_Device *dev)
 | |
| {
 | |
|     return U_SUCC;
 | |
| }
 | |
| 
 | |
| static int init_uffs_fs(
 | |
|     struct _nand_dev * nand_part)
 | |
| {
 | |
|     uffs_MountTable * mtb;
 | |
|     struct rt_mtd_nand_device * nand;
 | |
|     struct uffs_StorageAttrSt * flash_storage;
 | |
| 
 | |
|     mtb = &nand_part->mount_table;
 | |
|     nand = nand_part->dev;
 | |
|     flash_storage = &nand_part->storage;
 | |
| 
 | |
|     /* setup nand storage attributes */
 | |
|     uffs_setup_storage(flash_storage, nand);
 | |
| 
 | |
|     /* register mount table */
 | |
|     if(mtb->dev)
 | |
|     {
 | |
|         /* set memory allocator for uffs */
 | |
| #if CONFIG_USE_SYSTEM_MEMORY_ALLOCATOR > 0
 | |
|         uffs_MemSetupSystemAllocator(&mtb->dev->mem);
 | |
| #endif
 | |
|         /* setup device init/release entry */
 | |
|         mtb->dev->Init = _device_init;
 | |
|         mtb->dev->Release = _device_release;
 | |
|         mtb->dev->attr = flash_storage;
 | |
| 
 | |
|         uffs_RegisterMountTable(mtb);
 | |
|     }
 | |
|     /* mount uffs partion on nand device */
 | |
|     return uffs_Mount(nand_part->mount_path) == U_SUCC ? 0 : -1;
 | |
| }
 | |
| 
 | |
| static int dfs_uffs_mount(
 | |
|     struct dfs_filesystem* fs,
 | |
|     unsigned long rwflag,
 | |
|     const void* data)
 | |
| {
 | |
|     rt_base_t index;
 | |
|     uffs_MountTable * mount_part;
 | |
|     struct rt_mtd_nand_device * dev;
 | |
|     
 | |
|     RT_ASSERT(rt_strlen(fs->path) < (UFFS_MOUNT_PATH_MAX-1));
 | |
|     dev = RT_MTD_NAND_DEVICE(fs->dev_id);
 | |
| 
 | |
|     /*1. find a empty entry in partition table */
 | |
|     for (index = 0; index < UFFS_DEVICE_MAX ; index ++)
 | |
|     {
 | |
|         if (nand_part[index].dev == RT_NULL)
 | |
|             break;
 | |
|     }
 | |
|     if (index == UFFS_DEVICE_MAX)
 | |
|         return -ENOENT;
 | |
| 
 | |
|     /*2. fill partition structure */
 | |
|     nand_part[index].dev = dev;
 | |
| 
 | |
|     /* make a right mount path for uffs, end with '/' */
 | |
|     rt_snprintf(nand_part[index].mount_path, UFFS_MOUNT_PATH_MAX, "%s/", fs->path);
 | |
|     if (nand_part[index].mount_path[1] == '/')
 | |
|         nand_part[index].mount_path[1] = 0;
 | |
| 
 | |
|     mount_part = &(nand_part[index].mount_table);
 | |
|     mount_part->mount   = nand_part[index].mount_path;
 | |
|     mount_part->dev = &(nand_part[index].uffs_dev);
 | |
|     rt_memset(mount_part->dev, 0, sizeof(uffs_Device));//in order to make uffs happy.
 | |
|     mount_part->dev->_private = dev;   /* save dev_id into uffs */
 | |
|     mount_part->start_block = dev->block_start;
 | |
|     mount_part->end_block = dev->block_end;
 | |
|     /*3. mount uffs */
 | |
|     if (init_uffs_fs(&nand_part[index]) < 0)
 | |
|     {
 | |
|         return uffs_result_to_dfs(uffs_get_error());
 | |
|     }
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| static int dfs_uffs_unmount(struct dfs_filesystem* fs)
 | |
| {
 | |
|     rt_base_t index;
 | |
|     int result;
 | |
| 
 | |
|     /* find the device index and then unmount it */
 | |
|     for (index = 0; index < UFFS_DEVICE_MAX; index++)
 | |
|     {
 | |
|         if (nand_part[index].dev == RT_MTD_NAND_DEVICE(fs->dev_id))
 | |
|         {
 | |
|             nand_part[index].dev = RT_NULL;
 | |
|             result = uffs_UnMount(nand_part[index].mount_path);
 | |
|             if (result != U_SUCC)
 | |
|                 break;
 | |
| 
 | |
|             result = uffs_UnRegisterMountTable(& nand_part[index].mount_table);
 | |
|             return (result == U_SUCC) ? RT_EOK : -1;
 | |
|         }
 | |
|     }
 | |
|     return -ENOENT;
 | |
| }
 | |
| 
 | |
| static int dfs_uffs_mkfs(rt_device_t dev_id)
 | |
| {
 | |
|     rt_base_t index;
 | |
|     rt_uint32_t block;
 | |
|     struct rt_mtd_nand_device * mtd;
 | |
| 
 | |
|     /*1. find the device index */
 | |
|     for (index = 0; index < UFFS_DEVICE_MAX; index++)
 | |
|     {
 | |
|         if (nand_part[index].dev == (struct rt_mtd_nand_device *)dev_id)
 | |
|             break;
 | |
|     }
 | |
| 
 | |
|     if (index == UFFS_DEVICE_MAX)
 | |
|     {
 | |
|         /* can't find device driver */
 | |
|         return -ENOENT;
 | |
|     }
 | |
| 
 | |
|     /*2. then unmount the partition */
 | |
|     uffs_Mount(nand_part[index].mount_path);
 | |
|     mtd = nand_part[index].dev;
 | |
| 
 | |
|     /*3. erase all blocks on the partition */
 | |
|     block = mtd->block_start;
 | |
|     for (; block <= mtd->block_end; block++)
 | |
|     {
 | |
|         rt_mtd_nand_erase_block(mtd, block);
 | |
|         if (rt_mtd_nand_check_block(mtd, block) != RT_EOK)
 | |
|         {
 | |
|             rt_kprintf("found bad block %d\n", block);
 | |
|             rt_mtd_nand_mark_badblock(mtd, block);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /*4. remount it */
 | |
|     if (init_uffs_fs(&nand_part[index]) < 0)
 | |
|     {
 | |
|         return uffs_result_to_dfs(uffs_get_error());
 | |
|     }
 | |
|     return RT_EOK;
 | |
| }
 | |
| 
 | |
| static int dfs_uffs_statfs(struct dfs_filesystem* fs,
 | |
|                     struct statfs *buf)
 | |
| {
 | |
|     rt_base_t index;
 | |
|     struct rt_mtd_nand_device * mtd = RT_MTD_NAND_DEVICE(fs->dev_id);
 | |
| 
 | |
|     RT_ASSERT(mtd != RT_NULL);
 | |
| 
 | |
|     /* find the device index */
 | |
|     for (index = 0; index < UFFS_DEVICE_MAX; index++)
 | |
|     {
 | |
|         if (nand_part[index].dev == (void *)mtd)
 | |
|             break;
 | |
|     }
 | |
|     if (index == UFFS_DEVICE_MAX)
 | |
|         return -ENOENT;
 | |
|     
 | |
|     buf->f_bsize = mtd->page_size*mtd->pages_per_block;
 | |
|     buf->f_blocks = (mtd->block_end - mtd->block_start + 1);
 | |
|     buf->f_bfree = uffs_GetDeviceFree(&nand_part[index].uffs_dev)/buf->f_bsize ;
 | |
|     
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| static int dfs_uffs_open(struct dfs_fd* file)
 | |
| {
 | |
|     int fd;
 | |
|     int oflag, mode;
 | |
|     char * file_path;
 | |
| 
 | |
|     oflag = file->flags;
 | |
|     if (oflag & O_DIRECTORY)   /* operations about dir */
 | |
|     {
 | |
|         uffs_DIR * dir;
 | |
| 
 | |
|         if (oflag & O_CREAT)   /* create a dir*/
 | |
|         {
 | |
|             if (uffs_mkdir(file->path) < 0)
 | |
|                 return uffs_result_to_dfs(uffs_get_error());
 | |
|         }
 | |
|         /* open dir */
 | |
|         file_path = rt_malloc(FILE_PATH_MAX);
 | |
|         if(file_path == RT_NULL)
 | |
|             return -ENOMEM;         
 | |
| 
 | |
|         if (file->path[0] == '/' && !(file->path[1] == 0))
 | |
|             rt_snprintf(file_path, FILE_PATH_MAX, "%s/", file->path);
 | |
|         else
 | |
|         {
 | |
|             file_path[0] = '/';
 | |
|             file_path[1] = 0;
 | |
|         }
 | |
| 
 | |
|         dir = uffs_opendir(file_path);
 | |
| 
 | |
|         if (dir == RT_NULL)
 | |
|         {
 | |
|             rt_free(file_path);         
 | |
|             return uffs_result_to_dfs(uffs_get_error());
 | |
|         }
 | |
|         /* save this pointer,will used by  dfs_uffs_getdents*/
 | |
|         file->data = dir;
 | |
|         rt_free(file_path);
 | |
|         return RT_EOK;
 | |
|     }
 | |
|     /* regular file operations */
 | |
|     /* int uffs_open(const char *name, int oflag, ...); what is this?
 | |
|      * uffs_open can open dir!!  **/
 | |
|     mode = 0;
 | |
|     if (oflag & O_RDONLY) mode |= UO_RDONLY;
 | |
|     if (oflag & O_WRONLY) mode |= UO_WRONLY;
 | |
|     if (oflag & O_RDWR)   mode |= UO_RDWR;
 | |
|     /* Opens the file, if it is existing. If not, a new file is created. */
 | |
|     if (oflag & O_CREAT) mode |= UO_CREATE;
 | |
|     /* Creates a new file. If the file is existing, it is truncated and overwritten. */
 | |
|     if (oflag & O_TRUNC) mode |= UO_TRUNC;
 | |
|     /* Creates a new file. The function fails if the file is already existing. */
 | |
|     if (oflag & O_EXCL) mode |= UO_EXCL;
 | |
| 
 | |
|     fd = uffs_open(file->path, mode);
 | |
|     if (fd < 0)
 | |
|     {
 | |
|         return uffs_result_to_dfs(uffs_get_error());
 | |
|     }
 | |
| 
 | |
|     /* save this pointer, it will be used when calling read(), write(),
 | |
|      * flush(), seek(), and will be free when calling close()*/
 | |
| 
 | |
|     file->data = (void *)fd;
 | |
|     file->pos  = uffs_seek(fd, 0, USEEK_CUR);
 | |
|     file->size = uffs_seek(fd, 0, USEEK_END);
 | |
|     uffs_seek(fd, file->pos, USEEK_SET);
 | |
| 
 | |
|     if (oflag & O_APPEND)
 | |
|     {
 | |
|         file->pos = uffs_seek(fd, 0, USEEK_END);
 | |
|     }
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| static int dfs_uffs_close(struct dfs_fd* file)
 | |
| {
 | |
|     int oflag;
 | |
|     int fd;
 | |
| 
 | |
|     oflag = file->flags;
 | |
|     if (oflag & O_DIRECTORY)
 | |
|     {
 | |
|         /* operations about dir */
 | |
|         if (uffs_closedir((uffs_DIR *)(file->data)) < 0)
 | |
|             return uffs_result_to_dfs(uffs_get_error());
 | |
| 
 | |
|         return 0;
 | |
|     }
 | |
|     /* regular file operations */
 | |
|     fd = (int)(file->data);
 | |
| 
 | |
|     if (uffs_close(fd) == 0)
 | |
|         return 0;
 | |
| 
 | |
|     return uffs_result_to_dfs(uffs_get_error());
 | |
| }
 | |
| 
 | |
| static int dfs_uffs_ioctl(struct dfs_fd * file, int cmd, void* args)
 | |
| {
 | |
|     return -ENOSYS;
 | |
| }
 | |
| 
 | |
| static int dfs_uffs_read(struct dfs_fd * file, void* buf, size_t len)
 | |
| {
 | |
|     int fd;
 | |
|     int char_read;
 | |
| 
 | |
|     fd = (int)(file->data);
 | |
|     char_read = uffs_read(fd, buf, len);
 | |
|     if (char_read < 0)
 | |
|         return uffs_result_to_dfs(uffs_get_error());
 | |
| 
 | |
|     /* update position */
 | |
|     file->pos = uffs_seek(fd, 0, USEEK_CUR);
 | |
|     return char_read;
 | |
| }
 | |
| 
 | |
| static int dfs_uffs_write(struct dfs_fd* file,
 | |
|                    const void* buf,
 | |
|                    size_t len)
 | |
| {
 | |
|     int fd;
 | |
|     int char_write;
 | |
| 
 | |
|     fd = (int)(file->data);
 | |
| 
 | |
|     char_write = uffs_write(fd, buf, len);
 | |
|     if (char_write < 0)
 | |
|         return uffs_result_to_dfs(uffs_get_error());
 | |
| 
 | |
|     /* update position */
 | |
|     file->pos = uffs_seek(fd, 0, USEEK_CUR);
 | |
|     return char_write;
 | |
| }
 | |
| 
 | |
| static int dfs_uffs_flush(struct dfs_fd* file)
 | |
| {
 | |
|     int fd;
 | |
|     int result;
 | |
| 
 | |
|     fd = (int)(file->data);
 | |
| 
 | |
|     result = uffs_flush(fd);
 | |
|     if (result < 0 )
 | |
|         return uffs_result_to_dfs(uffs_get_error());
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| int uffs_seekdir(uffs_DIR *dir, long offset)
 | |
| {
 | |
|     int i = 0;
 | |
| 
 | |
|     while(i < offset)
 | |
|     {   
 | |
|         if (uffs_readdir(dir) == RT_NULL)
 | |
|             return -1;
 | |
|         i++;
 | |
|     } 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| static int dfs_uffs_seek(struct dfs_fd* file,
 | |
|                   rt_off_t offset)
 | |
| {
 | |
|     int result;
 | |
| 
 | |
|     /* set offset as current offset */
 | |
|     if (file->type == FT_DIRECTORY)
 | |
|     {
 | |
|         uffs_rewinddir((uffs_DIR *)(file->data));
 | |
|         result = uffs_seekdir((uffs_DIR *)(file->data), offset/sizeof(struct dirent));
 | |
|         if (result >= 0)
 | |
|         {
 | |
|             file->pos = offset; 
 | |
|             return offset;
 | |
|         }
 | |
|     }
 | |
|     else if (file->type == FT_REGULAR)
 | |
|     {
 | |
|         result = uffs_seek((int)(file->data), offset, USEEK_SET);
 | |
|         if (result >= 0)    
 | |
|             return offset;
 | |
|     }
 | |
| 
 | |
|     return uffs_result_to_dfs(uffs_get_error());
 | |
| }
 | |
| 
 | |
| /* return the size of struct dirent*/
 | |
| static int dfs_uffs_getdents(
 | |
|     struct dfs_fd* file,
 | |
|     struct dirent* dirp,
 | |
|     uint32_t count)
 | |
| {
 | |
|     rt_uint32_t index;
 | |
|     char * file_path;
 | |
|     struct dirent* d;
 | |
|     uffs_DIR* dir;
 | |
|     struct uffs_dirent * uffs_d;
 | |
|     
 | |
|     dir = (uffs_DIR*)(file->data);
 | |
|     RT_ASSERT(dir != RT_NULL);
 | |
|     
 | |
|     /* round count, count is always 1 */
 | |
|     count = (count / sizeof(struct dirent)) * sizeof(struct dirent);
 | |
|     if (count == 0) return -EINVAL;
 | |
| 
 | |
|     /* allocate file name */
 | |
|     file_path = rt_malloc(FILE_PATH_MAX);
 | |
|     if (file_path == RT_NULL)
 | |
|         return -ENOMEM;
 | |
|         
 | |
|     index = 0;
 | |
|     /* usually, the while loop should only be looped only once! */
 | |
|     while (1)
 | |
|     {
 | |
|         struct uffs_stat s;
 | |
|         
 | |
|         d = dirp + index;
 | |
| 
 | |
|         uffs_d = uffs_readdir(dir);
 | |
|         if (uffs_d == RT_NULL)
 | |
|         {
 | |
|             rt_free(file_path);
 | |
|             return (uffs_result_to_dfs(uffs_get_error()));
 | |
|         }
 | |
| 
 | |
|         if (file->path[0] == '/' && !(file->path[1] == 0))
 | |
|             rt_snprintf(file_path, FILE_PATH_MAX, "%s/%s", file->path, uffs_d->d_name);
 | |
|         else
 | |
|             rt_strncpy(file_path, uffs_d->d_name, FILE_PATH_MAX);
 | |
| 
 | |
|         uffs_stat(file_path, &s); 
 | |
|         switch(s.st_mode & US_IFMT)   /* file type mark */
 | |
|         {
 | |
|         case US_IFREG: /* directory */
 | |
|             d->d_type = DT_REG;
 | |
|             break;
 | |
|         case US_IFDIR: /* regular file */
 | |
|             d->d_type = DT_DIR;
 | |
|             break;
 | |
|         case US_IFLNK: /* symbolic link */
 | |
|         case US_IREAD: /* read permission */
 | |
|         case US_IWRITE:/* write permission */
 | |
|         default:
 | |
|             d->d_type = DT_UNKNOWN;
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|         /* write the rest args of struct dirent* dirp  */
 | |
|         d->d_namlen = rt_strlen(uffs_d->d_name);
 | |
|         d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
 | |
|         rt_strncpy(d->d_name, uffs_d->d_name, rt_strlen(uffs_d->d_name) + 1);
 | |
| 
 | |
|         index ++;
 | |
|         if (index * sizeof(struct dirent) >= count)
 | |
|             break;
 | |
|     }
 | |
|     
 | |
|     /* free file name buf */
 | |
|     rt_free(file_path);
 | |
|     
 | |
|     if (index == 0)
 | |
|         return uffs_result_to_dfs(uffs_get_error());
 | |
| 
 | |
|     file->pos += index * sizeof(struct dirent);
 | |
| 
 | |
|     return index * sizeof(struct dirent);
 | |
| }
 | |
| 
 | |
| static int dfs_uffs_unlink(struct dfs_filesystem* fs, const char* path)
 | |
| {
 | |
|     int result;
 | |
|     struct uffs_stat s;
 | |
| 
 | |
|     /* judge file type, dir is to be delete by uffs_rmdir, others by uffs_remove */
 | |
|     if (uffs_lstat(path, &s) < 0)
 | |
|     {
 | |
|         return uffs_result_to_dfs(uffs_get_error());
 | |
|     }
 | |
| 
 | |
|     switch(s.st_mode & US_IFMT)
 | |
|     {
 | |
|     case US_IFREG:
 | |
|         result = uffs_remove(path);
 | |
|         break;
 | |
|     case US_IFDIR:
 | |
|         result = uffs_rmdir(path);
 | |
|         break;
 | |
|     default:
 | |
|         /* unknown file type */
 | |
|         return -1;
 | |
|     }
 | |
|     if (result < 0)
 | |
|         return uffs_result_to_dfs(uffs_get_error());
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| static int dfs_uffs_rename(
 | |
|     struct dfs_filesystem* fs,
 | |
|     const char* oldpath,
 | |
|     const char* newpath)
 | |
| {
 | |
|     int result;
 | |
|     
 | |
|     result = uffs_rename(oldpath, newpath);
 | |
|     if (result < 0)
 | |
|         return uffs_result_to_dfs(uffs_get_error());
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| static int dfs_uffs_stat(struct dfs_filesystem* fs, const char *path, struct stat *st)
 | |
| {
 | |
|     int result;
 | |
|     struct uffs_stat s;
 | |
| 
 | |
|     result = uffs_stat(path, &s);
 | |
|     if (result < 0)
 | |
|         return uffs_result_to_dfs(uffs_get_error());
 | |
| 
 | |
|     /* convert uffs stat to dfs stat structure */
 | |
|     /* FIXME, these field may not be the same */
 | |
|     st->st_dev  = 0;
 | |
|     st->st_mode = s.st_mode;
 | |
|     st->st_size = s.st_size;
 | |
|     st->st_mtime = s.st_mtime;
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| static const struct dfs_file_ops dfs_uffs_fops = 
 | |
| {
 | |
|     dfs_uffs_open,
 | |
|     dfs_uffs_close,
 | |
|     dfs_uffs_ioctl,
 | |
|     dfs_uffs_read,
 | |
|     dfs_uffs_write,
 | |
|     dfs_uffs_flush,
 | |
|     dfs_uffs_seek,
 | |
|     dfs_uffs_getdents,
 | |
| };
 | |
| 
 | |
| static const struct dfs_filesystem_ops dfs_uffs_ops =
 | |
| {
 | |
|     "uffs", /* file system type: uffs */
 | |
| #if RTTHREAD_VERSION >= 10100
 | |
|     DFS_FS_FLAG_FULLPATH,
 | |
| #else
 | |
| #error "uffs can only work with rtthread whose version should >= 1.01\n"
 | |
| #endif
 | |
|     &dfs_uffs_fops,
 | |
| 
 | |
|     dfs_uffs_mount,
 | |
|     dfs_uffs_unmount,
 | |
|     dfs_uffs_mkfs,
 | |
|     dfs_uffs_statfs,
 | |
| 
 | |
|     dfs_uffs_unlink,
 | |
|     dfs_uffs_stat,
 | |
|     dfs_uffs_rename,
 | |
| };
 | |
| 
 | |
| int dfs_uffs_init(void)
 | |
| {
 | |
|     /* register uffs file system */
 | |
|     dfs_register(&dfs_uffs_ops);
 | |
| 
 | |
|     if (uffs_InitObjectBuf() == U_SUCC)
 | |
|     {
 | |
|         if (uffs_DirEntryBufInit() == U_SUCC)
 | |
|         {
 | |
|             uffs_InitGlobalFsLock();
 | |
|             return RT_EOK;
 | |
|         }
 | |
|     }
 | |
|     return -RT_ERROR;
 | |
| }
 | |
| INIT_COMPONENT_EXPORT(dfs_uffs_init);
 | |
| 
 |