xref: /nrf52832-nimble/rt-thread/components/dfs/filesystems/jffs2/dfs_jffs2.c (revision 104654410c56c573564690304ae786df310c91fc)
1 /*
2  * Copyright (c) 2006-2018, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2012-1-7       prife        the first version
9  */
10 
11 #include <rtthread.h>
12 #include <rtdevice.h>
13 
14 #include "cyg/infra/cyg_type.h"
15 #include "cyg/fileio/fileio.h"
16 #include "port/codes.h"
17 #include "port/fcntl.h"
18 #undef mode_t
19 
20 #include <dfs_fs.h>
21 #include <dfs_file.h>
22 
23 #include "dfs_jffs2.h"
24 #include "jffs2_config.h"
25 #include "porting.h"
26 #include <string.h>
27 
28 #if DEVICE_PART_MAX > 1
29     #error "support only one jffs2 partition on a flash device!"
30 #endif
31 
32 /* make sure the following struct var had been initilased to 0! */
33 struct device_part
34 {
35     struct cyg_mtab_entry * mte;
36     struct rt_mtd_nor_device *dev;
37 };
38 static struct device_part device_partition[DEVICE_PART_MAX] = {0};
39 static struct rt_mutex jffs2_lock;
40 
41 #define jffs2_mount         jffs2_fste.mount
42 #define jffs2_umount        jffs2_fste.umount
43 #define jffs2_open          jffs2_fste.open
44 #define jffs2_file_unlink   jffs2_fste.unlink
45 #define jffs2_mkdir         jffs2_fste.mkdir
46 #define jffs2_rmdir         jffs2_fste.rmdir
47 #define jffs2_rename        jffs2_fste.rename
48 #define jffs2_link          jffs2_fste.link
49 #define jffs2_opendir       jffs2_fste.opendir
50 #define jffs2_chdir         jffs2_fste.chdir
51 #define jffs2_ops_stat      jffs2_fste.stat
52 #define jffs2_getinfo       jffs2_fste.getinfo
53 #define jffs2_setinfo       jffs2_fste.setinfo
54 
55 #define jffs2_file_read     jffs2_fileops.fo_read
56 #define jffs2_file_write    jffs2_fileops.fo_write
57 #define jffs2_file_lseek    jffs2_fileops.fo_lseek
58 #define jffs2_file_ioctl    jffs2_fileops.fo_ioctl
59 #define jffs2_file_select   jffs2_fileops.fo_select
60 #define jffs2_file_fsync    jffs2_fileops.fo_fsync
61 #define jffs2_file_colse    jffs2_fileops.fo_close
62 #define jffs2_file_fstat    jffs2_fileops.fo_fstat
63 #define jffs2_file_getinfo  jffs2_fileops.fo_getinfo
64 #define jffs2_file_setinfo  jffs2_fileops.fo_setinfo
65 
66 #define jffs2_dir_read      jffs2_dirops.fo_read
67 //#define jffs2_dir_write   jffs2_dirops.fo_write
68 #define jffs2_dir_lseek     jffs2_dirops.fo_lseek
69 //#define jffs2_dir_ioctl   jffs2_dirops.fo_ioctl
70 #define jffs2_dir_select    jffs2_dirops.fo_select
71 //#define jffs2_dir_fsync   jffs2_dirops.fo_fsync
72 #define jffs2_dir_colse     jffs2_dirops.fo_close
73 //#define jffs2_dir_fstat   jffs2_dirops.fo_fstat
74 //#define jffs2_dir_getinfo jffs2_dirops.fo_getinfo
75 //#define jffs2_dir_setinfo jffs2_dirops.fo_setinfo
76 
77 /*
78  * RT-Thread Device Interface for jffs2
79  */
80 
81 /* these code is in src/flashio.c */
jffs2_result_to_dfs(int result)82 static int jffs2_result_to_dfs(int result)
83 {
84     if (result < 0) return  result;
85     if (result > 0) return -result;
86 
87     return 0;
88 }
89 
90 /*
91  * RT-Thread DFS Interface for jffs2
92  */
dfs_jffs2_mount(struct dfs_filesystem * fs,unsigned long rwflag,const void * data)93 static int dfs_jffs2_mount(struct dfs_filesystem* fs,
94                     unsigned long rwflag,
95                     const void* data)
96 {
97     unsigned index;
98     struct cyg_mtab_entry * mte;
99     int result;
100 
101     /* find a empty entry in partition table */
102     for (index = 0; index < DEVICE_PART_MAX; index ++)
103     {
104         if (device_partition[index].dev == RT_NULL)
105             break;
106     }
107     if (index == DEVICE_PART_MAX)
108         return -ENOSPC;
109 
110     mte = rt_malloc(sizeof(struct cyg_mtab_entry));
111     if (mte == RT_NULL)
112         return -ENOMEM;
113 
114     mte->name = fs->path;
115     mte->fsname = "jffs2";
116     mte->devname = NULL;
117     /* note that, i use mte->data to store rtt's device
118      * while, in jffs2_mount, mte->data will be copy into
119      * s_dev in struct super_block, and mte->data will be
120      * filled with jffs2_sb(see the source of jffs2_mount.
121      */
122     mte->data = (CYG_ADDRWORD)fs->dev_id;
123 
124     device_partition[index].dev = RT_MTD_NOR_DEVICE(fs->dev_id);
125     /* after jffs2_mount, mte->data will not be dev_id any more */
126     result = jffs2_mount(NULL, mte);
127     if (result != 0)
128     {
129         device_partition[index].dev = NULL;
130         return jffs2_result_to_dfs(result);
131     }
132 
133     /* save this pointer */
134     device_partition[index].mte = mte;
135     return 0;
136 }
137 
_find_fs(struct cyg_mtab_entry ** mte,rt_device_t dev_id)138 static int _find_fs(struct cyg_mtab_entry ** mte, rt_device_t dev_id)
139 {
140     unsigned index;
141 
142     /* find device index */
143     for (index = 0; index < DEVICE_PART_MAX; index++)
144     {
145         if (device_partition[index].dev == RT_MTD_NOR_DEVICE(dev_id))
146         {
147             *mte = device_partition[index].mte;
148             return 0;
149         }
150     }
151 
152     rt_kprintf("error, could not found the fs!");
153     return -1;
154 }
155 
dfs_jffs2_unmount(struct dfs_filesystem * fs)156 static int dfs_jffs2_unmount(struct dfs_filesystem* fs)
157 {
158     int result;
159     unsigned index;
160 
161     /* find device index, then umount it */
162     for (index = 0; index < DEVICE_PART_MAX; index++)
163     {
164         if (device_partition[index].dev == RT_MTD_NOR_DEVICE(fs->dev_id))
165         {
166             result = jffs2_umount(device_partition[index].mte);
167             if (result) return jffs2_result_to_dfs(result);
168 
169             rt_free(device_partition[index].mte);
170             device_partition[index].dev = NULL;
171             device_partition[index].mte = NULL;
172             return RT_EOK;
173         }
174     }
175 
176     return -ENOENT;
177 }
178 
dfs_jffs2_mkfs(rt_device_t dev_id)179 static int dfs_jffs2_mkfs(rt_device_t dev_id)
180 {
181     /* just erase all blocks on this nand partition */
182     return -ENOSYS;
183 }
184 
dfs_jffs2_statfs(struct dfs_filesystem * fs,struct statfs * buf)185 static int dfs_jffs2_statfs(struct dfs_filesystem* fs,
186                      struct statfs *buf)
187 {
188     /* since the limit of unsigned long, so the max size of flash device is 4G */
189     struct cyg_mtab_entry * mte;
190     struct jffs2_fs_info info;
191     int result;
192 
193     result = _find_fs(&mte, fs->dev_id);
194     if (result)
195         return -ENOENT;
196 
197     RT_ASSERT(mte->data != 0);
198 
199     jffs2_get_info_from_sb((void *)mte->data, &info);
200     buf->f_bsize = info.sector_size;
201     buf->f_blocks = info.nr_blocks;
202     buf->f_bfree = info.free_size / info.sector_size;
203 
204     return 0;
205 }
206 
207 static const char jffs2_root_path[] = ".";
208 
dfs_jffs2_open(struct dfs_fd * file)209 static int dfs_jffs2_open(struct dfs_fd* file)
210 {
211     int result;
212     int oflag, mode;
213     const char * name;
214     cyg_file * jffs2_file;
215     struct dfs_filesystem *fs;
216     struct cyg_mtab_entry * mte;
217 
218     oflag = file->flags;
219     fs = (struct dfs_filesystem *)file->data;
220     RT_ASSERT(fs != RT_NULL);
221 
222     jffs2_file = rt_malloc(sizeof(cyg_file));
223     if (jffs2_file == RT_NULL)
224         return -ENOMEM;
225 
226     /* just escape '/' provided by dfs code */
227     name = file->path;
228     if ((name[0] == '/') && (name[1] == 0))
229         name = jffs2_root_path;
230     else /* name[0] still will be '/' */
231         name ++;
232 
233     result = _find_fs(&mte, fs->dev_id);
234     if (result)
235     {
236         rt_free(jffs2_file);
237         return -ENOENT;
238     }
239 
240     /* set mount table */
241     jffs2_file->f_mte = mte;
242 
243     if (oflag & O_DIRECTORY) /* operations about dir */
244     {
245         rt_mutex_take(&jffs2_lock, RT_WAITING_FOREVER);
246         if (oflag & O_CREAT) /* create a dir*/
247         {
248             /* fixme, should test file->path can end with '/' */
249             result = jffs2_mkdir(mte, mte->root, name);
250             if (result)
251             {
252                 rt_mutex_release(&jffs2_lock);
253                 rt_free(jffs2_file);
254                 return jffs2_result_to_dfs(result);
255             }
256         }
257 
258         /* open dir */
259         result = jffs2_opendir(mte, mte->root, name, jffs2_file);
260         rt_mutex_release(&jffs2_lock);
261         if (result)
262         {
263             rt_free(jffs2_file);
264             return jffs2_result_to_dfs(result);
265         }
266 #ifdef  CONFIG_JFFS2_NO_RELATIVEDIR
267         jffs2_file->f_offset = 2;
268 #endif
269         /* save this pointer, it will be used by dfs_jffs2_getdents*/
270         file->data = jffs2_file;
271         return 0;
272     }
273     /* regular file operations */
274     mode = JFFS2_O_RDONLY;
275     if (oflag & O_WRONLY) mode |= JFFS2_O_WRONLY;
276     if (oflag & O_RDWR)   mode |= JFFS2_O_RDWR;
277     /* Opens the file, if it is existing. If not, a new file is created. */
278     if (oflag & O_CREAT) mode |= JFFS2_O_CREAT;
279     /* Creates a new file. If the file is existing, it is truncated and overwritten. */
280     if (oflag & O_TRUNC) mode |= JFFS2_O_TRUNC;
281     /* Creates a new file. The function fails if the file is already existing. */
282     if (oflag & O_EXCL) mode |= JFFS2_O_EXCL;
283 
284     rt_mutex_take(&jffs2_lock, RT_WAITING_FOREVER);
285     result = jffs2_open(mte, 0, name, mode, jffs2_file);
286     if (result != 0)
287     {
288         rt_mutex_release(&jffs2_lock);
289         rt_free(jffs2_file);
290         return jffs2_result_to_dfs(result);
291     }
292 
293     /* save this pointer, it will be used when calling read(), write(),
294     flush(), lessk(), and will be rt_free when calling close()*/
295     file->data = jffs2_file;
296     file->pos = jffs2_file->f_offset;
297     file->size = 0;
298     jffs2_file_lseek(jffs2_file, (off_t *)(&(file->size)), SEEK_END);
299     jffs2_file->f_offset = (off_t)file->pos;
300     rt_mutex_release(&jffs2_lock);
301 
302     if (oflag & O_APPEND)
303     {
304         file->pos = file->size;
305         jffs2_file->f_offset = file->size;
306     }
307 
308     return 0;
309 }
310 
dfs_jffs2_close(struct dfs_fd * file)311 static int dfs_jffs2_close(struct dfs_fd* file)
312 {
313     int result;
314     cyg_file * jffs2_file;
315 
316     RT_ASSERT(file->data != NULL);
317     jffs2_file = (cyg_file *)(file->data);
318 
319     if (file->flags & O_DIRECTORY) /* operations about dir */
320     {
321         rt_mutex_take(&jffs2_lock, RT_WAITING_FOREVER);
322         result = jffs2_dir_colse(jffs2_file);
323         rt_mutex_release(&jffs2_lock);
324         if (result)
325             return jffs2_result_to_dfs(result);
326 
327         rt_free(jffs2_file);
328         return 0;
329     }
330     /* regular file operations */
331     rt_mutex_take(&jffs2_lock, RT_WAITING_FOREVER);
332     result = jffs2_file_colse(jffs2_file);
333     rt_mutex_release(&jffs2_lock);
334     if (result)
335         return jffs2_result_to_dfs(result);
336 
337     /* release memory */
338     rt_free(jffs2_file);
339     return 0;
340 }
341 
dfs_jffs2_ioctl(struct dfs_fd * file,int cmd,void * args)342 static int dfs_jffs2_ioctl(struct dfs_fd* file, int cmd, void* args)
343 {
344     return -ENOSYS;
345 }
346 
dfs_jffs2_read(struct dfs_fd * file,void * buf,size_t len)347 static int dfs_jffs2_read(struct dfs_fd* file, void* buf, size_t len)
348 {
349     cyg_file * jffs2_file;
350     struct CYG_UIO_TAG uio_s;
351     struct CYG_IOVEC_TAG iovec;
352     int char_read;
353     int result;
354 
355     RT_ASSERT(file->data != NULL);
356     jffs2_file = (cyg_file *)(file->data);
357     uio_s.uio_iov = &iovec;
358     uio_s.uio_iov->iov_base = buf;
359     uio_s.uio_iov->iov_len = len;
360     uio_s.uio_iovcnt = 1; //must be 1
361     //uio_s.uio_offset //not used...
362     uio_s.uio_resid = uio_s.uio_iov->iov_len; //seem no use in jffs2;
363 
364     char_read = jffs2_file->f_offset; /* the current offset */
365     rt_mutex_take(&jffs2_lock, RT_WAITING_FOREVER);
366     result = jffs2_file_read(jffs2_file, &uio_s);
367     rt_mutex_release(&jffs2_lock);
368     if (result)
369         return jffs2_result_to_dfs(result);
370 
371     /* update position */
372     file->pos = jffs2_file->f_offset;
373     char_read = jffs2_file->f_offset - char_read;
374     return char_read;
375 }
376 
dfs_jffs2_write(struct dfs_fd * file,const void * buf,size_t len)377 static int dfs_jffs2_write(struct dfs_fd* file,
378                     const void* buf,
379                     size_t len)
380 {
381     cyg_file * jffs2_file;
382     struct CYG_UIO_TAG uio_s;
383     struct CYG_IOVEC_TAG iovec;
384     int char_write;
385     int result;
386 
387     RT_ASSERT(file->data != NULL);
388     jffs2_file = (cyg_file *)(file->data);
389     uio_s.uio_iov = &iovec;
390     uio_s.uio_iov->iov_base = (void *)buf;
391     uio_s.uio_iov->iov_len = len;
392     uio_s.uio_iovcnt = 1; //must be 1
393     //uio_s.uio_offset //not used...
394     uio_s.uio_resid = uio_s.uio_iov->iov_len; //seem no use in jffs2;
395 
396     char_write = jffs2_file->f_offset;
397     rt_mutex_take(&jffs2_lock, RT_WAITING_FOREVER);
398     result = jffs2_file_write(jffs2_file, &uio_s);
399     rt_mutex_release(&jffs2_lock);
400     if (result)
401         return jffs2_result_to_dfs(result);
402 
403     /* update position */
404     file->pos = jffs2_file->f_offset;
405     char_write = jffs2_file->f_offset - char_write;
406     return char_write;
407 }
408 
dfs_jffs2_flush(struct dfs_fd * file)409 static int dfs_jffs2_flush(struct dfs_fd* file)
410 {
411     /* infact, jffs2 not support, jffs2_fo_sync just return ok */
412     return -ENOSYS;
413 }
414 
415 /* fixme warning: the offset is rt_off_t, so maybe the size of a file is must <= 2G*/
dfs_jffs2_lseek(struct dfs_fd * file,rt_off_t offset)416 static int dfs_jffs2_lseek(struct dfs_fd* file,
417                     rt_off_t offset)
418 {
419     cyg_file * jffs2_file;
420     int result;
421 
422     RT_ASSERT(file->data != NULL);
423     jffs2_file = (cyg_file *)(file->data);
424 
425     /* set offset as current offset */
426     rt_mutex_take(&jffs2_lock, RT_WAITING_FOREVER);
427     result = jffs2_file_lseek(jffs2_file, &offset, SEEK_SET);
428     rt_mutex_release(&jffs2_lock);
429     if (result)
430         return jffs2_result_to_dfs(result);
431     /* update file position */
432     file->pos = offset;
433     return offset;
434 }
435 
436 /* return the size of  struct dirent*/
dfs_jffs2_getdents(struct dfs_fd * file,struct dirent * dirp,rt_uint32_t count)437 static int dfs_jffs2_getdents(struct dfs_fd* file,
438                        struct dirent* dirp,
439                        rt_uint32_t count)
440 {
441     cyg_file * jffs2_file;
442     struct CYG_UIO_TAG uio_s;
443     struct CYG_IOVEC_TAG iovec;
444     struct jffs2_dirent jffs2_d;
445     struct dirent * d;
446     rt_uint32_t index;
447 #if !defined (CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE)
448     struct jffs2_stat s;
449     cyg_mtab_entry * mte;
450     char * fullname;
451 #endif
452     int result;
453 
454     RT_ASSERT(file->data != RT_NULL);
455     jffs2_file = (cyg_file*)(file->data);
456     mte = jffs2_file->f_mte;
457 
458     //set jffs2_d
459     memset(&jffs2_d, 0, sizeof(struct jffs2_dirent));
460     //set CYG_UIO_TAG uio_s
461     uio_s.uio_iov = &iovec;
462     uio_s.uio_iov->iov_base = &jffs2_d;
463     uio_s.uio_iov->iov_len = sizeof(struct jffs2_dirent);;
464     uio_s.uio_iovcnt = 1; //must be 1
465     uio_s.uio_offset = 0;//not used...
466     uio_s.uio_resid = uio_s.uio_iov->iov_len; //seem no use in jffs2;
467 
468     /* make integer count, usually count is 1 */
469     count = (count / sizeof(struct dirent)) * sizeof(struct dirent);
470     if (count == 0) return -EINVAL;
471 
472     index = 0;
473     /* usually, the while loop should only be looped only once! */
474     while (1)
475     {
476         d = dirp + index;
477         rt_mutex_take(&jffs2_lock, RT_WAITING_FOREVER);
478         result = jffs2_dir_read(jffs2_file, &uio_s);
479         rt_mutex_release(&jffs2_lock);
480         /* if met a error or all entry are read over, break while*/
481         if (result || jffs2_d.d_name[0] == 0)
482             break;
483 
484 #if defined (CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE)
485         switch(jffs2_d.d_type & JFFS2_S_IFMT)
486         {
487         case JFFS2_S_IFREG: d->d_type = DT_REG; break;
488         case JFFS2_S_IFDIR: d->d_type = DT_DIR; break;
489         default: d->d_type = DT_UNKNOWN; break;
490         }
491 #else
492         fullname = rt_malloc(FILE_PATH_MAX);
493         if(fullname == RT_NULL)
494                 return -ENOMEM;
495 
496         /* make a right entry */
497         if ((file->path[0] == '/') )
498         {
499             if (file->path[1] == 0)
500                 strcpy(fullname, jffs2_d.d_name);
501             else
502                 rt_sprintf(fullname, "%s/%s", file->path+1, jffs2_d.d_name);
503         }
504         else
505             rt_sprintf(fullname, "%s/%s", file->path, jffs2_d.d_name);
506         rt_mutex_take(&jffs2_lock, RT_WAITING_FOREVER);
507         result = jffs2_porting_stat(mte, mte->root, fullname, (void *)&s);
508         rt_mutex_release(&jffs2_lock);
509         if (result)
510             return jffs2_result_to_dfs(result);
511 
512         rt_free(fullname);
513         /* convert to dfs stat structure */
514         switch(s.st_mode & JFFS2_S_IFMT)
515         {
516         case JFFS2_S_IFREG: d->d_type = DT_REG; break;
517         case JFFS2_S_IFDIR: d->d_type = DT_DIR; break;
518         default: d->d_type = DT_UNKNOWN; break;
519         }
520 #endif
521         /* write the rest fields of struct dirent* dirp  */
522         d->d_namlen = rt_strlen(jffs2_d.d_name);
523         d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
524         rt_strncpy(d->d_name, jffs2_d.d_name, d->d_namlen + 1);
525 
526         index ++;
527         if (index * sizeof(struct dirent) >= count)
528             break;
529     }
530     if (result)
531         return jffs2_result_to_dfs(result);
532     return index * sizeof(struct dirent);
533 }
534 
dfs_jffs2_unlink(struct dfs_filesystem * fs,const char * path)535 static int dfs_jffs2_unlink(struct dfs_filesystem* fs, const char* path)
536 {
537     int result;
538     struct jffs2_stat s;
539     cyg_mtab_entry * mte;
540 
541     result = _find_fs(&mte, fs->dev_id);
542     if (result)
543         return -ENOENT;
544 
545     /* deal path */
546     if (path[0] == '/')
547         path++;
548 
549     /* judge file type, dir is to be delete by rmdir, others by unlink */
550     rt_mutex_take(&jffs2_lock, RT_WAITING_FOREVER);
551     result = jffs2_porting_stat(mte, mte->root, path, (void *)&s);
552     if (result)
553     {
554         rt_mutex_release(&jffs2_lock);
555         return jffs2_result_to_dfs(result);
556     }
557 
558     switch(s.st_mode & JFFS2_S_IFMT)
559     {
560     case JFFS2_S_IFREG:
561         result = jffs2_file_unlink(mte, mte->root, path);
562         break;
563     case JFFS2_S_IFDIR:
564         result = jffs2_rmdir(mte, mte->root, path);
565         break;
566     default:
567         /* unknown file type */
568         rt_mutex_release(&jffs2_lock);
569         return -1;
570     }
571     rt_mutex_release(&jffs2_lock);
572     if (result)
573         return jffs2_result_to_dfs(result);
574     return 0;
575 }
576 
dfs_jffs2_rename(struct dfs_filesystem * fs,const char * oldpath,const char * newpath)577 static int dfs_jffs2_rename(struct dfs_filesystem* fs,
578                      const char* oldpath,
579                      const char* newpath)
580 {
581     int result;
582     cyg_mtab_entry * mte;
583 
584     result = _find_fs(&mte, fs->dev_id);
585     if (result)
586         return -ENOENT;
587 
588     if (*oldpath == '/')
589         oldpath += 1;
590     if (*newpath == '/')
591         newpath += 1;
592     rt_mutex_take(&jffs2_lock, RT_WAITING_FOREVER);
593     result = jffs2_rename(mte, mte->root, oldpath, mte->root, newpath);
594     rt_mutex_release(&jffs2_lock);
595     if (result)
596         return jffs2_result_to_dfs(result);
597     return 0;
598 }
599 
dfs_jffs2_stat(struct dfs_filesystem * fs,const char * path,struct stat * st)600 static int dfs_jffs2_stat(struct dfs_filesystem* fs, const char *path, struct stat *st)
601 {
602     int result;
603     struct jffs2_stat s;
604     cyg_mtab_entry * mte;
605 
606     /* deal the path for jffs2 */
607     RT_ASSERT(!((path[0] == '/') && (path[1] == 0)));
608 
609     if (path[0] == '/')
610         path++;
611 
612     result = _find_fs(&mte, fs->dev_id);
613     if (result)
614         return -ENOENT;
615 
616     rt_mutex_take(&jffs2_lock, RT_WAITING_FOREVER);
617     result = jffs2_porting_stat(mte, mte->root, path, (void *)&s);
618     rt_mutex_release(&jffs2_lock);
619 
620     if (result)
621         return jffs2_result_to_dfs(result);
622     /* convert to dfs stat structure */
623     switch(s.st_mode & JFFS2_S_IFMT)
624     {
625     case JFFS2_S_IFREG:
626         st->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH |
627             S_IWUSR | S_IWGRP | S_IWOTH;
628         break;
629 
630     case JFFS2_S_IFDIR:
631         st->st_mode = S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
632         break;
633 
634     default:
635         st->st_mode = DT_UNKNOWN; //fixme
636         break;
637     }
638 
639     st->st_dev  = 0;
640     st->st_size = s.st_size;
641     st->st_mtime = s.st_mtime;
642 
643     return 0;
644 }
645 
646 static const struct dfs_file_ops _jffs2_fops =
647 {
648     dfs_jffs2_open,
649     dfs_jffs2_close,
650     dfs_jffs2_ioctl,
651     dfs_jffs2_read,
652     dfs_jffs2_write,
653     dfs_jffs2_flush,
654     dfs_jffs2_lseek,
655     dfs_jffs2_getdents,
656 };
657 
658 static const struct dfs_filesystem_ops _jffs2_ops =
659 {
660     "jffs2",
661     DFS_FS_FLAG_DEFAULT,
662     &_jffs2_fops,
663 
664     dfs_jffs2_mount,
665     dfs_jffs2_unmount,
666     dfs_jffs2_mkfs,
667     dfs_jffs2_statfs,
668 
669     dfs_jffs2_unlink,
670     dfs_jffs2_stat,
671     dfs_jffs2_rename,
672 };
673 
dfs_jffs2_init(void)674 int dfs_jffs2_init(void)
675 {
676     /* register fatfs file system */
677     dfs_register(&_jffs2_ops);
678 
679     /* initialize mutex */
680     if (rt_mutex_init(&jffs2_lock, "jffs2lock", RT_IPC_FLAG_FIFO) != RT_EOK)
681     {
682         rt_kprintf("init jffs2 lock mutex failed\n");
683     }
684     rt_kprintf("init jffs2 lock mutex okay\n");
685     return 0;
686 }
687 INIT_COMPONENT_EXPORT(dfs_jffs2_init);
688