xref: /nrf52832-nimble/rt-thread/components/dfs/filesystems/uffs/dfs_uffs.c (revision 104654410c56c573564690304ae786df310c91fc)
1*10465441SEvalZero /*
2*10465441SEvalZero  * Copyright (c) 2006-2018, RT-Thread Development Team
3*10465441SEvalZero  *
4*10465441SEvalZero  * SPDX-License-Identifier: Apache-2.0
5*10465441SEvalZero  *
6*10465441SEvalZero  * Change Logs:
7*10465441SEvalZero  * Date           Author       Notes
8*10465441SEvalZero  * 2011-10-22     prife        the first version
9*10465441SEvalZero  * 2012-03-28     prife        use mtd device interface
10*10465441SEvalZero  * 2012-04-05     prife        update uffs with official repo and use uffs_UnMount/Mount
11*10465441SEvalZero  * 2017-04-12     lizhen9880   fix the f_bsize and f_blocks issue in function dfs_uffs_statfs
12*10465441SEvalZero  */
13*10465441SEvalZero 
14*10465441SEvalZero #include <rtthread.h>
15*10465441SEvalZero 
16*10465441SEvalZero #include <dfs_fs.h>
17*10465441SEvalZero #include <dfs_file.h>
18*10465441SEvalZero #include <rtdevice.h>
19*10465441SEvalZero 
20*10465441SEvalZero #include "dfs_uffs.h"
21*10465441SEvalZero 
22*10465441SEvalZero #include "uffs/uffs_fd.h" /* posix file api is here */
23*10465441SEvalZero #include "uffs/uffs_mtb.h"
24*10465441SEvalZero #include "uffs/uffs_mem.h"
25*10465441SEvalZero #include "uffs/uffs_utils.h"
26*10465441SEvalZero 
27*10465441SEvalZero /*
28*10465441SEvalZero  * RT-Thread DFS Interface for uffs
29*10465441SEvalZero  */
30*10465441SEvalZero #define UFFS_DEVICE_MAX         2    /* the max partions on a nand deivce*/
31*10465441SEvalZero #define UFFS_MOUNT_PATH_MAX     128  /* the mount point max length */
32*10465441SEvalZero #define FILE_PATH_MAX           256  /* the longest file path */
33*10465441SEvalZero 
34*10465441SEvalZero struct _nand_dev
35*10465441SEvalZero {
36*10465441SEvalZero     struct rt_mtd_nand_device * dev;
37*10465441SEvalZero     struct uffs_StorageAttrSt storage;
38*10465441SEvalZero     uffs_Device uffs_dev;
39*10465441SEvalZero     uffs_MountTable mount_table;
40*10465441SEvalZero     char mount_path[UFFS_MOUNT_PATH_MAX];
41*10465441SEvalZero     void * data;  /* when uffs use static buf, it will save ptr here */
42*10465441SEvalZero };
43*10465441SEvalZero /* make sure the following struct var had been initilased to 0! */
44*10465441SEvalZero static struct _nand_dev nand_part[UFFS_DEVICE_MAX] = {0};
45*10465441SEvalZero 
uffs_result_to_dfs(int result)46*10465441SEvalZero static int uffs_result_to_dfs(int result)
47*10465441SEvalZero {
48*10465441SEvalZero     int status = -1;
49*10465441SEvalZero 
50*10465441SEvalZero     result = result < 0 ? -result : result;
51*10465441SEvalZero     switch (result)
52*10465441SEvalZero     {
53*10465441SEvalZero     case UENOERR:/** no error */
54*10465441SEvalZero         break;
55*10465441SEvalZero     case UEACCES:/** Tried to open read-only file for writing, or files sharing mode
56*10465441SEvalZero                    does not allow specified operations, or given path is directory */
57*10465441SEvalZero         status = -EINVAL;
58*10465441SEvalZero         break;/* no suitable */
59*10465441SEvalZero     case UEEXIST:   /** _O_CREAT and _O_EXCL flags specified, but filename already exists */
60*10465441SEvalZero         status = -EEXIST;
61*10465441SEvalZero         break;
62*10465441SEvalZero     case UEINVAL:  /** Invalid oflag or pmode argument */
63*10465441SEvalZero         status = -EINVAL;
64*10465441SEvalZero         break;
65*10465441SEvalZero     case UEMFILE: /** No more file handles available(too many open files)  */
66*10465441SEvalZero         status = -1;
67*10465441SEvalZero         break;
68*10465441SEvalZero     case UENOENT: /** file or path not found */
69*10465441SEvalZero         status = -ENOENT;
70*10465441SEvalZero         break;
71*10465441SEvalZero     case UETIME: /** can't set file time */
72*10465441SEvalZero         status = -1;
73*10465441SEvalZero         break;
74*10465441SEvalZero     case UEBADF: /** invalid file handle */
75*10465441SEvalZero         status = -EBADF;
76*10465441SEvalZero         break;
77*10465441SEvalZero     case UENOMEM:/** no enough memory */
78*10465441SEvalZero         status = -ENOSPC;
79*10465441SEvalZero         break;
80*10465441SEvalZero     case UEIOERR: /** I/O error from lower level flash operation */
81*10465441SEvalZero         status = -EIO;
82*10465441SEvalZero         break;
83*10465441SEvalZero     case UENOTDIR: /** Not a directory */
84*10465441SEvalZero         status = -ENOTDIR;
85*10465441SEvalZero         break;
86*10465441SEvalZero     case UEISDIR: /** Is a directory */
87*10465441SEvalZero         status = -EISDIR;
88*10465441SEvalZero         break;
89*10465441SEvalZero     case UEUNKNOWN_ERR:
90*10465441SEvalZero     default:
91*10465441SEvalZero         status = -1;
92*10465441SEvalZero         break; /* unknown error! */
93*10465441SEvalZero     }
94*10465441SEvalZero 
95*10465441SEvalZero     return status;
96*10465441SEvalZero }
97*10465441SEvalZero 
_device_init(uffs_Device * dev)98*10465441SEvalZero static URET _device_init(uffs_Device *dev)
99*10465441SEvalZero {
100*10465441SEvalZero     dev->attr->_private = NULL; // hook nand_chip data structure to attr->_private
101*10465441SEvalZero     dev->ops = (struct uffs_FlashOpsSt *)&nand_ops;
102*10465441SEvalZero 
103*10465441SEvalZero     return U_SUCC;
104*10465441SEvalZero }
105*10465441SEvalZero 
_device_release(uffs_Device * dev)106*10465441SEvalZero static URET _device_release(uffs_Device *dev)
107*10465441SEvalZero {
108*10465441SEvalZero     return U_SUCC;
109*10465441SEvalZero }
110*10465441SEvalZero 
init_uffs_fs(struct _nand_dev * nand_part)111*10465441SEvalZero static int init_uffs_fs(
112*10465441SEvalZero     struct _nand_dev * nand_part)
113*10465441SEvalZero {
114*10465441SEvalZero     uffs_MountTable * mtb;
115*10465441SEvalZero     struct rt_mtd_nand_device * nand;
116*10465441SEvalZero     struct uffs_StorageAttrSt * flash_storage;
117*10465441SEvalZero 
118*10465441SEvalZero     mtb = &nand_part->mount_table;
119*10465441SEvalZero     nand = nand_part->dev;
120*10465441SEvalZero     flash_storage = &nand_part->storage;
121*10465441SEvalZero 
122*10465441SEvalZero     /* setup nand storage attributes */
123*10465441SEvalZero     uffs_setup_storage(flash_storage, nand);
124*10465441SEvalZero 
125*10465441SEvalZero     /* register mount table */
126*10465441SEvalZero     if(mtb->dev)
127*10465441SEvalZero     {
128*10465441SEvalZero         /* set memory allocator for uffs */
129*10465441SEvalZero #if CONFIG_USE_SYSTEM_MEMORY_ALLOCATOR > 0
130*10465441SEvalZero         uffs_MemSetupSystemAllocator(&mtb->dev->mem);
131*10465441SEvalZero #endif
132*10465441SEvalZero         /* setup device init/release entry */
133*10465441SEvalZero         mtb->dev->Init = _device_init;
134*10465441SEvalZero         mtb->dev->Release = _device_release;
135*10465441SEvalZero         mtb->dev->attr = flash_storage;
136*10465441SEvalZero 
137*10465441SEvalZero         uffs_RegisterMountTable(mtb);
138*10465441SEvalZero     }
139*10465441SEvalZero     /* mount uffs partion on nand device */
140*10465441SEvalZero     return uffs_Mount(nand_part->mount_path) == U_SUCC ? 0 : -1;
141*10465441SEvalZero }
142*10465441SEvalZero 
dfs_uffs_mount(struct dfs_filesystem * fs,unsigned long rwflag,const void * data)143*10465441SEvalZero static int dfs_uffs_mount(
144*10465441SEvalZero     struct dfs_filesystem* fs,
145*10465441SEvalZero     unsigned long rwflag,
146*10465441SEvalZero     const void* data)
147*10465441SEvalZero {
148*10465441SEvalZero     rt_base_t index;
149*10465441SEvalZero     uffs_MountTable * mount_part;
150*10465441SEvalZero     struct rt_mtd_nand_device * dev;
151*10465441SEvalZero 
152*10465441SEvalZero     RT_ASSERT(rt_strlen(fs->path) < (UFFS_MOUNT_PATH_MAX-1));
153*10465441SEvalZero     dev = RT_MTD_NAND_DEVICE(fs->dev_id);
154*10465441SEvalZero 
155*10465441SEvalZero     /*1. find a empty entry in partition table */
156*10465441SEvalZero     for (index = 0; index < UFFS_DEVICE_MAX ; index ++)
157*10465441SEvalZero     {
158*10465441SEvalZero         if (nand_part[index].dev == RT_NULL)
159*10465441SEvalZero             break;
160*10465441SEvalZero     }
161*10465441SEvalZero     if (index == UFFS_DEVICE_MAX)
162*10465441SEvalZero         return -ENOENT;
163*10465441SEvalZero 
164*10465441SEvalZero     /*2. fill partition structure */
165*10465441SEvalZero     nand_part[index].dev = dev;
166*10465441SEvalZero 
167*10465441SEvalZero     /* make a right mount path for uffs, end with '/' */
168*10465441SEvalZero     rt_snprintf(nand_part[index].mount_path, UFFS_MOUNT_PATH_MAX, "%s/", fs->path);
169*10465441SEvalZero     if (nand_part[index].mount_path[1] == '/')
170*10465441SEvalZero         nand_part[index].mount_path[1] = 0;
171*10465441SEvalZero 
172*10465441SEvalZero     mount_part = &(nand_part[index].mount_table);
173*10465441SEvalZero     mount_part->mount   = nand_part[index].mount_path;
174*10465441SEvalZero     mount_part->dev = &(nand_part[index].uffs_dev);
175*10465441SEvalZero     rt_memset(mount_part->dev, 0, sizeof(uffs_Device));//in order to make uffs happy.
176*10465441SEvalZero     mount_part->dev->_private = dev;   /* save dev_id into uffs */
177*10465441SEvalZero     mount_part->start_block = dev->block_start;
178*10465441SEvalZero     mount_part->end_block = dev->block_end;
179*10465441SEvalZero     /*3. mount uffs */
180*10465441SEvalZero     if (init_uffs_fs(&nand_part[index]) < 0)
181*10465441SEvalZero     {
182*10465441SEvalZero         return uffs_result_to_dfs(uffs_get_error());
183*10465441SEvalZero     }
184*10465441SEvalZero     return 0;
185*10465441SEvalZero }
186*10465441SEvalZero 
dfs_uffs_unmount(struct dfs_filesystem * fs)187*10465441SEvalZero static int dfs_uffs_unmount(struct dfs_filesystem* fs)
188*10465441SEvalZero {
189*10465441SEvalZero     rt_base_t index;
190*10465441SEvalZero     int result;
191*10465441SEvalZero 
192*10465441SEvalZero     /* find the device index and then unmount it */
193*10465441SEvalZero     for (index = 0; index < UFFS_DEVICE_MAX; index++)
194*10465441SEvalZero     {
195*10465441SEvalZero         if (nand_part[index].dev == RT_MTD_NAND_DEVICE(fs->dev_id))
196*10465441SEvalZero         {
197*10465441SEvalZero             nand_part[index].dev = RT_NULL;
198*10465441SEvalZero             result = uffs_UnMount(nand_part[index].mount_path);
199*10465441SEvalZero             if (result != U_SUCC)
200*10465441SEvalZero                 break;
201*10465441SEvalZero 
202*10465441SEvalZero             result = uffs_UnRegisterMountTable(& nand_part[index].mount_table);
203*10465441SEvalZero             return (result == U_SUCC) ? RT_EOK : -1;
204*10465441SEvalZero         }
205*10465441SEvalZero     }
206*10465441SEvalZero     return -ENOENT;
207*10465441SEvalZero }
208*10465441SEvalZero 
dfs_uffs_mkfs(rt_device_t dev_id)209*10465441SEvalZero static int dfs_uffs_mkfs(rt_device_t dev_id)
210*10465441SEvalZero {
211*10465441SEvalZero     rt_base_t index;
212*10465441SEvalZero     rt_uint32_t block;
213*10465441SEvalZero     struct rt_mtd_nand_device * mtd;
214*10465441SEvalZero 
215*10465441SEvalZero     /*1. find the device index */
216*10465441SEvalZero     for (index = 0; index < UFFS_DEVICE_MAX; index++)
217*10465441SEvalZero     {
218*10465441SEvalZero         if (nand_part[index].dev == (struct rt_mtd_nand_device *)dev_id)
219*10465441SEvalZero             break;
220*10465441SEvalZero     }
221*10465441SEvalZero 
222*10465441SEvalZero     if (index == UFFS_DEVICE_MAX)
223*10465441SEvalZero     {
224*10465441SEvalZero         /* can't find device driver */
225*10465441SEvalZero         return -ENOENT;
226*10465441SEvalZero     }
227*10465441SEvalZero 
228*10465441SEvalZero     /*2. then unmount the partition */
229*10465441SEvalZero     uffs_Mount(nand_part[index].mount_path);
230*10465441SEvalZero     mtd = nand_part[index].dev;
231*10465441SEvalZero 
232*10465441SEvalZero     /*3. erase all blocks on the partition */
233*10465441SEvalZero     block = mtd->block_start;
234*10465441SEvalZero     for (; block <= mtd->block_end; block++)
235*10465441SEvalZero     {
236*10465441SEvalZero         rt_mtd_nand_erase_block(mtd, block);
237*10465441SEvalZero         if (rt_mtd_nand_check_block(mtd, block) != RT_EOK)
238*10465441SEvalZero         {
239*10465441SEvalZero             rt_kprintf("found bad block %d\n", block);
240*10465441SEvalZero             rt_mtd_nand_mark_badblock(mtd, block);
241*10465441SEvalZero         }
242*10465441SEvalZero     }
243*10465441SEvalZero 
244*10465441SEvalZero     /*4. remount it */
245*10465441SEvalZero     if (init_uffs_fs(&nand_part[index]) < 0)
246*10465441SEvalZero     {
247*10465441SEvalZero         return uffs_result_to_dfs(uffs_get_error());
248*10465441SEvalZero     }
249*10465441SEvalZero     return RT_EOK;
250*10465441SEvalZero }
251*10465441SEvalZero 
dfs_uffs_statfs(struct dfs_filesystem * fs,struct statfs * buf)252*10465441SEvalZero static int dfs_uffs_statfs(struct dfs_filesystem* fs,
253*10465441SEvalZero                     struct statfs *buf)
254*10465441SEvalZero {
255*10465441SEvalZero     rt_base_t index;
256*10465441SEvalZero     struct rt_mtd_nand_device * mtd = RT_MTD_NAND_DEVICE(fs->dev_id);
257*10465441SEvalZero 
258*10465441SEvalZero     RT_ASSERT(mtd != RT_NULL);
259*10465441SEvalZero 
260*10465441SEvalZero     /* find the device index */
261*10465441SEvalZero     for (index = 0; index < UFFS_DEVICE_MAX; index++)
262*10465441SEvalZero     {
263*10465441SEvalZero         if (nand_part[index].dev == (void *)mtd)
264*10465441SEvalZero             break;
265*10465441SEvalZero     }
266*10465441SEvalZero     if (index == UFFS_DEVICE_MAX)
267*10465441SEvalZero         return -ENOENT;
268*10465441SEvalZero 
269*10465441SEvalZero     buf->f_bsize = mtd->page_size*mtd->pages_per_block;
270*10465441SEvalZero     buf->f_blocks = (mtd->block_end - mtd->block_start + 1);
271*10465441SEvalZero     buf->f_bfree = uffs_GetDeviceFree(&nand_part[index].uffs_dev)/buf->f_bsize ;
272*10465441SEvalZero 
273*10465441SEvalZero     return 0;
274*10465441SEvalZero }
275*10465441SEvalZero 
dfs_uffs_open(struct dfs_fd * file)276*10465441SEvalZero static int dfs_uffs_open(struct dfs_fd* file)
277*10465441SEvalZero {
278*10465441SEvalZero     int fd;
279*10465441SEvalZero     int oflag, mode;
280*10465441SEvalZero     char * file_path;
281*10465441SEvalZero 
282*10465441SEvalZero     oflag = file->flags;
283*10465441SEvalZero     if (oflag & O_DIRECTORY)   /* operations about dir */
284*10465441SEvalZero     {
285*10465441SEvalZero         uffs_DIR * dir;
286*10465441SEvalZero 
287*10465441SEvalZero         if (oflag & O_CREAT)   /* create a dir*/
288*10465441SEvalZero         {
289*10465441SEvalZero             if (uffs_mkdir(file->path) < 0)
290*10465441SEvalZero                 return uffs_result_to_dfs(uffs_get_error());
291*10465441SEvalZero         }
292*10465441SEvalZero         /* open dir */
293*10465441SEvalZero         file_path = rt_malloc(FILE_PATH_MAX);
294*10465441SEvalZero         if(file_path == RT_NULL)
295*10465441SEvalZero             return -ENOMEM;
296*10465441SEvalZero 
297*10465441SEvalZero         if (file->path[0] == '/' && !(file->path[1] == 0))
298*10465441SEvalZero             rt_snprintf(file_path, FILE_PATH_MAX, "%s/", file->path);
299*10465441SEvalZero         else
300*10465441SEvalZero         {
301*10465441SEvalZero             file_path[0] = '/';
302*10465441SEvalZero             file_path[1] = 0;
303*10465441SEvalZero         }
304*10465441SEvalZero 
305*10465441SEvalZero         dir = uffs_opendir(file_path);
306*10465441SEvalZero 
307*10465441SEvalZero         if (dir == RT_NULL)
308*10465441SEvalZero         {
309*10465441SEvalZero             rt_free(file_path);
310*10465441SEvalZero             return uffs_result_to_dfs(uffs_get_error());
311*10465441SEvalZero         }
312*10465441SEvalZero         /* save this pointer,will used by  dfs_uffs_getdents*/
313*10465441SEvalZero         file->data = dir;
314*10465441SEvalZero         rt_free(file_path);
315*10465441SEvalZero         return RT_EOK;
316*10465441SEvalZero     }
317*10465441SEvalZero     /* regular file operations */
318*10465441SEvalZero     /* int uffs_open(const char *name, int oflag, ...); what is this?
319*10465441SEvalZero      * uffs_open can open dir!!  **/
320*10465441SEvalZero     mode = 0;
321*10465441SEvalZero     if (oflag & O_RDONLY) mode |= UO_RDONLY;
322*10465441SEvalZero     if (oflag & O_WRONLY) mode |= UO_WRONLY;
323*10465441SEvalZero     if (oflag & O_RDWR)   mode |= UO_RDWR;
324*10465441SEvalZero     /* Opens the file, if it is existing. If not, a new file is created. */
325*10465441SEvalZero     if (oflag & O_CREAT) mode |= UO_CREATE;
326*10465441SEvalZero     /* Creates a new file. If the file is existing, it is truncated and overwritten. */
327*10465441SEvalZero     if (oflag & O_TRUNC) mode |= UO_TRUNC;
328*10465441SEvalZero     /* Creates a new file. The function fails if the file is already existing. */
329*10465441SEvalZero     if (oflag & O_EXCL) mode |= UO_EXCL;
330*10465441SEvalZero 
331*10465441SEvalZero     fd = uffs_open(file->path, mode);
332*10465441SEvalZero     if (fd < 0)
333*10465441SEvalZero     {
334*10465441SEvalZero         return uffs_result_to_dfs(uffs_get_error());
335*10465441SEvalZero     }
336*10465441SEvalZero 
337*10465441SEvalZero     /* save this pointer, it will be used when calling read(), write(),
338*10465441SEvalZero      * flush(), seek(), and will be free when calling close()*/
339*10465441SEvalZero 
340*10465441SEvalZero     file->data = (void *)fd;
341*10465441SEvalZero     file->pos  = uffs_seek(fd, 0, USEEK_CUR);
342*10465441SEvalZero     file->size = uffs_seek(fd, 0, USEEK_END);
343*10465441SEvalZero     uffs_seek(fd, file->pos, USEEK_SET);
344*10465441SEvalZero 
345*10465441SEvalZero     if (oflag & O_APPEND)
346*10465441SEvalZero     {
347*10465441SEvalZero         file->pos = uffs_seek(fd, 0, USEEK_END);
348*10465441SEvalZero     }
349*10465441SEvalZero     return 0;
350*10465441SEvalZero }
351*10465441SEvalZero 
dfs_uffs_close(struct dfs_fd * file)352*10465441SEvalZero static int dfs_uffs_close(struct dfs_fd* file)
353*10465441SEvalZero {
354*10465441SEvalZero     int oflag;
355*10465441SEvalZero     int fd;
356*10465441SEvalZero 
357*10465441SEvalZero     oflag = file->flags;
358*10465441SEvalZero     if (oflag & O_DIRECTORY)
359*10465441SEvalZero     {
360*10465441SEvalZero         /* operations about dir */
361*10465441SEvalZero         if (uffs_closedir((uffs_DIR *)(file->data)) < 0)
362*10465441SEvalZero             return uffs_result_to_dfs(uffs_get_error());
363*10465441SEvalZero 
364*10465441SEvalZero         return 0;
365*10465441SEvalZero     }
366*10465441SEvalZero     /* regular file operations */
367*10465441SEvalZero     fd = (int)(file->data);
368*10465441SEvalZero 
369*10465441SEvalZero     if (uffs_close(fd) == 0)
370*10465441SEvalZero         return 0;
371*10465441SEvalZero 
372*10465441SEvalZero     return uffs_result_to_dfs(uffs_get_error());
373*10465441SEvalZero }
374*10465441SEvalZero 
dfs_uffs_ioctl(struct dfs_fd * file,int cmd,void * args)375*10465441SEvalZero static int dfs_uffs_ioctl(struct dfs_fd * file, int cmd, void* args)
376*10465441SEvalZero {
377*10465441SEvalZero     return -ENOSYS;
378*10465441SEvalZero }
379*10465441SEvalZero 
dfs_uffs_read(struct dfs_fd * file,void * buf,size_t len)380*10465441SEvalZero static int dfs_uffs_read(struct dfs_fd * file, void* buf, size_t len)
381*10465441SEvalZero {
382*10465441SEvalZero     int fd;
383*10465441SEvalZero     int char_read;
384*10465441SEvalZero 
385*10465441SEvalZero     fd = (int)(file->data);
386*10465441SEvalZero     char_read = uffs_read(fd, buf, len);
387*10465441SEvalZero     if (char_read < 0)
388*10465441SEvalZero         return uffs_result_to_dfs(uffs_get_error());
389*10465441SEvalZero 
390*10465441SEvalZero     /* update position */
391*10465441SEvalZero     file->pos = uffs_seek(fd, 0, USEEK_CUR);
392*10465441SEvalZero     return char_read;
393*10465441SEvalZero }
394*10465441SEvalZero 
dfs_uffs_write(struct dfs_fd * file,const void * buf,size_t len)395*10465441SEvalZero static int dfs_uffs_write(struct dfs_fd* file,
396*10465441SEvalZero                    const void* buf,
397*10465441SEvalZero                    size_t len)
398*10465441SEvalZero {
399*10465441SEvalZero     int fd;
400*10465441SEvalZero     int char_write;
401*10465441SEvalZero 
402*10465441SEvalZero     fd = (int)(file->data);
403*10465441SEvalZero 
404*10465441SEvalZero     char_write = uffs_write(fd, buf, len);
405*10465441SEvalZero     if (char_write < 0)
406*10465441SEvalZero         return uffs_result_to_dfs(uffs_get_error());
407*10465441SEvalZero 
408*10465441SEvalZero     /* update position */
409*10465441SEvalZero     file->pos = uffs_seek(fd, 0, USEEK_CUR);
410*10465441SEvalZero     return char_write;
411*10465441SEvalZero }
412*10465441SEvalZero 
dfs_uffs_flush(struct dfs_fd * file)413*10465441SEvalZero static int dfs_uffs_flush(struct dfs_fd* file)
414*10465441SEvalZero {
415*10465441SEvalZero     int fd;
416*10465441SEvalZero     int result;
417*10465441SEvalZero 
418*10465441SEvalZero     fd = (int)(file->data);
419*10465441SEvalZero 
420*10465441SEvalZero     result = uffs_flush(fd);
421*10465441SEvalZero     if (result < 0 )
422*10465441SEvalZero         return uffs_result_to_dfs(uffs_get_error());
423*10465441SEvalZero     return 0;
424*10465441SEvalZero }
425*10465441SEvalZero 
uffs_seekdir(uffs_DIR * dir,long offset)426*10465441SEvalZero int uffs_seekdir(uffs_DIR *dir, long offset)
427*10465441SEvalZero {
428*10465441SEvalZero     int i = 0;
429*10465441SEvalZero 
430*10465441SEvalZero     while(i < offset)
431*10465441SEvalZero     {
432*10465441SEvalZero         if (uffs_readdir(dir) == RT_NULL)
433*10465441SEvalZero             return -1;
434*10465441SEvalZero         i++;
435*10465441SEvalZero     }
436*10465441SEvalZero     return 0;
437*10465441SEvalZero }
438*10465441SEvalZero 
439*10465441SEvalZero 
dfs_uffs_seek(struct dfs_fd * file,rt_off_t offset)440*10465441SEvalZero static int dfs_uffs_seek(struct dfs_fd* file,
441*10465441SEvalZero                   rt_off_t offset)
442*10465441SEvalZero {
443*10465441SEvalZero     int result;
444*10465441SEvalZero 
445*10465441SEvalZero     /* set offset as current offset */
446*10465441SEvalZero     if (file->type == FT_DIRECTORY)
447*10465441SEvalZero     {
448*10465441SEvalZero         uffs_rewinddir((uffs_DIR *)(file->data));
449*10465441SEvalZero         result = uffs_seekdir((uffs_DIR *)(file->data), offset/sizeof(struct dirent));
450*10465441SEvalZero         if (result >= 0)
451*10465441SEvalZero         {
452*10465441SEvalZero             file->pos = offset;
453*10465441SEvalZero             return offset;
454*10465441SEvalZero         }
455*10465441SEvalZero     }
456*10465441SEvalZero     else if (file->type == FT_REGULAR)
457*10465441SEvalZero     {
458*10465441SEvalZero         result = uffs_seek((int)(file->data), offset, USEEK_SET);
459*10465441SEvalZero         if (result >= 0)
460*10465441SEvalZero             return offset;
461*10465441SEvalZero     }
462*10465441SEvalZero 
463*10465441SEvalZero     return uffs_result_to_dfs(uffs_get_error());
464*10465441SEvalZero }
465*10465441SEvalZero 
466*10465441SEvalZero /* return the size of struct dirent*/
dfs_uffs_getdents(struct dfs_fd * file,struct dirent * dirp,uint32_t count)467*10465441SEvalZero static int dfs_uffs_getdents(
468*10465441SEvalZero     struct dfs_fd* file,
469*10465441SEvalZero     struct dirent* dirp,
470*10465441SEvalZero     uint32_t count)
471*10465441SEvalZero {
472*10465441SEvalZero     rt_uint32_t index;
473*10465441SEvalZero     char * file_path;
474*10465441SEvalZero     struct dirent* d;
475*10465441SEvalZero     uffs_DIR* dir;
476*10465441SEvalZero     struct uffs_dirent * uffs_d;
477*10465441SEvalZero 
478*10465441SEvalZero     dir = (uffs_DIR*)(file->data);
479*10465441SEvalZero     RT_ASSERT(dir != RT_NULL);
480*10465441SEvalZero 
481*10465441SEvalZero     /* round count, count is always 1 */
482*10465441SEvalZero     count = (count / sizeof(struct dirent)) * sizeof(struct dirent);
483*10465441SEvalZero     if (count == 0) return -EINVAL;
484*10465441SEvalZero 
485*10465441SEvalZero     /* allocate file name */
486*10465441SEvalZero     file_path = rt_malloc(FILE_PATH_MAX);
487*10465441SEvalZero     if (file_path == RT_NULL)
488*10465441SEvalZero         return -ENOMEM;
489*10465441SEvalZero 
490*10465441SEvalZero     index = 0;
491*10465441SEvalZero     /* usually, the while loop should only be looped only once! */
492*10465441SEvalZero     while (1)
493*10465441SEvalZero     {
494*10465441SEvalZero         struct uffs_stat s;
495*10465441SEvalZero 
496*10465441SEvalZero         d = dirp + index;
497*10465441SEvalZero 
498*10465441SEvalZero         uffs_d = uffs_readdir(dir);
499*10465441SEvalZero         if (uffs_d == RT_NULL)
500*10465441SEvalZero         {
501*10465441SEvalZero             rt_free(file_path);
502*10465441SEvalZero             return (uffs_result_to_dfs(uffs_get_error()));
503*10465441SEvalZero         }
504*10465441SEvalZero 
505*10465441SEvalZero         if (file->path[0] == '/' && !(file->path[1] == 0))
506*10465441SEvalZero             rt_snprintf(file_path, FILE_PATH_MAX, "%s/%s", file->path, uffs_d->d_name);
507*10465441SEvalZero         else
508*10465441SEvalZero             rt_strncpy(file_path, uffs_d->d_name, FILE_PATH_MAX);
509*10465441SEvalZero 
510*10465441SEvalZero         uffs_stat(file_path, &s);
511*10465441SEvalZero         switch(s.st_mode & US_IFMT)   /* file type mark */
512*10465441SEvalZero         {
513*10465441SEvalZero         case US_IFREG: /* directory */
514*10465441SEvalZero             d->d_type = DT_REG;
515*10465441SEvalZero             break;
516*10465441SEvalZero         case US_IFDIR: /* regular file */
517*10465441SEvalZero             d->d_type = DT_DIR;
518*10465441SEvalZero             break;
519*10465441SEvalZero         case US_IFLNK: /* symbolic link */
520*10465441SEvalZero         case US_IREAD: /* read permission */
521*10465441SEvalZero         case US_IWRITE:/* write permission */
522*10465441SEvalZero         default:
523*10465441SEvalZero             d->d_type = DT_UNKNOWN;
524*10465441SEvalZero             break;
525*10465441SEvalZero         }
526*10465441SEvalZero 
527*10465441SEvalZero         /* write the rest args of struct dirent* dirp  */
528*10465441SEvalZero         d->d_namlen = rt_strlen(uffs_d->d_name);
529*10465441SEvalZero         d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
530*10465441SEvalZero         rt_strncpy(d->d_name, uffs_d->d_name, rt_strlen(uffs_d->d_name) + 1);
531*10465441SEvalZero 
532*10465441SEvalZero         index ++;
533*10465441SEvalZero         if (index * sizeof(struct dirent) >= count)
534*10465441SEvalZero             break;
535*10465441SEvalZero     }
536*10465441SEvalZero 
537*10465441SEvalZero     /* free file name buf */
538*10465441SEvalZero     rt_free(file_path);
539*10465441SEvalZero 
540*10465441SEvalZero     if (index == 0)
541*10465441SEvalZero         return uffs_result_to_dfs(uffs_get_error());
542*10465441SEvalZero 
543*10465441SEvalZero     file->pos += index * sizeof(struct dirent);
544*10465441SEvalZero 
545*10465441SEvalZero     return index * sizeof(struct dirent);
546*10465441SEvalZero }
547*10465441SEvalZero 
dfs_uffs_unlink(struct dfs_filesystem * fs,const char * path)548*10465441SEvalZero static int dfs_uffs_unlink(struct dfs_filesystem* fs, const char* path)
549*10465441SEvalZero {
550*10465441SEvalZero     int result;
551*10465441SEvalZero     struct uffs_stat s;
552*10465441SEvalZero 
553*10465441SEvalZero     /* judge file type, dir is to be delete by uffs_rmdir, others by uffs_remove */
554*10465441SEvalZero     if (uffs_lstat(path, &s) < 0)
555*10465441SEvalZero     {
556*10465441SEvalZero         return uffs_result_to_dfs(uffs_get_error());
557*10465441SEvalZero     }
558*10465441SEvalZero 
559*10465441SEvalZero     switch(s.st_mode & US_IFMT)
560*10465441SEvalZero     {
561*10465441SEvalZero     case US_IFREG:
562*10465441SEvalZero         result = uffs_remove(path);
563*10465441SEvalZero         break;
564*10465441SEvalZero     case US_IFDIR:
565*10465441SEvalZero         result = uffs_rmdir(path);
566*10465441SEvalZero         break;
567*10465441SEvalZero     default:
568*10465441SEvalZero         /* unknown file type */
569*10465441SEvalZero         return -1;
570*10465441SEvalZero     }
571*10465441SEvalZero     if (result < 0)
572*10465441SEvalZero         return uffs_result_to_dfs(uffs_get_error());
573*10465441SEvalZero 
574*10465441SEvalZero     return 0;
575*10465441SEvalZero }
576*10465441SEvalZero 
dfs_uffs_rename(struct dfs_filesystem * fs,const char * oldpath,const char * newpath)577*10465441SEvalZero static int dfs_uffs_rename(
578*10465441SEvalZero     struct dfs_filesystem* fs,
579*10465441SEvalZero     const char* oldpath,
580*10465441SEvalZero     const char* newpath)
581*10465441SEvalZero {
582*10465441SEvalZero     int result;
583*10465441SEvalZero 
584*10465441SEvalZero     result = uffs_rename(oldpath, newpath);
585*10465441SEvalZero     if (result < 0)
586*10465441SEvalZero         return uffs_result_to_dfs(uffs_get_error());
587*10465441SEvalZero 
588*10465441SEvalZero     return 0;
589*10465441SEvalZero }
590*10465441SEvalZero 
dfs_uffs_stat(struct dfs_filesystem * fs,const char * path,struct stat * st)591*10465441SEvalZero static int dfs_uffs_stat(struct dfs_filesystem* fs, const char *path, struct stat *st)
592*10465441SEvalZero {
593*10465441SEvalZero     int result;
594*10465441SEvalZero     struct uffs_stat s;
595*10465441SEvalZero 
596*10465441SEvalZero     result = uffs_stat(path, &s);
597*10465441SEvalZero     if (result < 0)
598*10465441SEvalZero         return uffs_result_to_dfs(uffs_get_error());
599*10465441SEvalZero 
600*10465441SEvalZero     /* convert uffs stat to dfs stat structure */
601*10465441SEvalZero     /* FIXME, these field may not be the same */
602*10465441SEvalZero     st->st_dev  = 0;
603*10465441SEvalZero     st->st_mode = s.st_mode;
604*10465441SEvalZero     st->st_size = s.st_size;
605*10465441SEvalZero     st->st_mtime = s.st_mtime;
606*10465441SEvalZero 
607*10465441SEvalZero     return 0;
608*10465441SEvalZero }
609*10465441SEvalZero 
610*10465441SEvalZero static const struct dfs_file_ops dfs_uffs_fops =
611*10465441SEvalZero {
612*10465441SEvalZero     dfs_uffs_open,
613*10465441SEvalZero     dfs_uffs_close,
614*10465441SEvalZero     dfs_uffs_ioctl,
615*10465441SEvalZero     dfs_uffs_read,
616*10465441SEvalZero     dfs_uffs_write,
617*10465441SEvalZero     dfs_uffs_flush,
618*10465441SEvalZero     dfs_uffs_seek,
619*10465441SEvalZero     dfs_uffs_getdents,
620*10465441SEvalZero };
621*10465441SEvalZero 
622*10465441SEvalZero static const struct dfs_filesystem_ops dfs_uffs_ops =
623*10465441SEvalZero {
624*10465441SEvalZero     "uffs", /* file system type: uffs */
625*10465441SEvalZero #if RTTHREAD_VERSION >= 10100
626*10465441SEvalZero     DFS_FS_FLAG_FULLPATH,
627*10465441SEvalZero #else
628*10465441SEvalZero #error "uffs can only work with rtthread whose version should >= 1.01\n"
629*10465441SEvalZero #endif
630*10465441SEvalZero     &dfs_uffs_fops,
631*10465441SEvalZero 
632*10465441SEvalZero     dfs_uffs_mount,
633*10465441SEvalZero     dfs_uffs_unmount,
634*10465441SEvalZero     dfs_uffs_mkfs,
635*10465441SEvalZero     dfs_uffs_statfs,
636*10465441SEvalZero 
637*10465441SEvalZero     dfs_uffs_unlink,
638*10465441SEvalZero     dfs_uffs_stat,
639*10465441SEvalZero     dfs_uffs_rename,
640*10465441SEvalZero };
641*10465441SEvalZero 
dfs_uffs_init(void)642*10465441SEvalZero int dfs_uffs_init(void)
643*10465441SEvalZero {
644*10465441SEvalZero     /* register uffs file system */
645*10465441SEvalZero     dfs_register(&dfs_uffs_ops);
646*10465441SEvalZero 
647*10465441SEvalZero     if (uffs_InitObjectBuf() == U_SUCC)
648*10465441SEvalZero     {
649*10465441SEvalZero         if (uffs_DirEntryBufInit() == U_SUCC)
650*10465441SEvalZero         {
651*10465441SEvalZero             uffs_InitGlobalFsLock();
652*10465441SEvalZero             return RT_EOK;
653*10465441SEvalZero         }
654*10465441SEvalZero     }
655*10465441SEvalZero     return -RT_ERROR;
656*10465441SEvalZero }
657*10465441SEvalZero INIT_COMPONENT_EXPORT(dfs_uffs_init);
658*10465441SEvalZero 
659