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