comparison src/cs/drivers/drv_app/ffs/board/ffs.c @ 0:b6a5e36de839

src/cs: initial import from Magnetite
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 15 Jul 2018 04:39:26 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:b6a5e36de839
1 /******************************************************************************
2 * Flash File System (ffs)
3 * Idea, design and coding by Mads Meisner-Jensen, mmj@ti.com
4 *
5 * ffs public API functions
6 *
7 * $Id: ffs.c 1.69.1.24.1.40 Thu, 08 Jan 2004 15:05:23 +0100 tsj $
8 *
9 f ******************************************************************************/
10
11 #ifndef TARGET
12 #include "ffs.cfg"
13 #endif
14
15 #if ((TARGET == 1) || (RIV_ENV== 1))
16 #include "ffs/board/task.h"
17 #endif
18
19 #if (TARGET == 0)
20 #include <stdlib.h>
21 #endif
22
23 #include <string.h>
24 #include <limits.h>
25
26 #include "ffs/ffs.h"
27 #include "ffs/board/core.h"
28 #include "ffs/board/ffstrace.h"
29
30 /******************************************************************************
31 *
32 ******************************************************************************/
33
34 extern struct fs_s fs; // defined in core.c
35
36 // These dummy defines and struct are only use to simulate FFS on the
37 // PC. The ones that is used in target are located in task.h
38 #if (TARGET == 0)
39 struct ffs_blocking_s {int x; };
40 #define FFS_BLOCKING_CALL_BEGIN()
41 int result; \
42 struct ffs_blocking_s fb;
43 #define FFS_BLOCKING_CALL_END()
44 #endif
45
46 /******************************************************************************
47 * Create, Read and Write
48 ******************************************************************************/
49
50 req_id_t ffs_file_write_b(const char *pathname, void *src, int size,
51 ffs_options_t option, T_RV_RETURN *cp,
52 struct ffs_blocking_s *fb)
53 {
54 iref_t i, dir;
55 char *name;
56 effs_t error;
57 int chunk_size, size_remaining, bytes_free;
58
59 tw(tr(TR_FUNC, TrApi, "ffs_file_write('%s', 0x%x, %d, %d) ?\n",
60 pathname, (int) src, size, option));
61
62 ttw(ttr(TTrApi, "ffs_file_write('%s', 0x%x, %d, %d) ?" NL,
63 pathname, (int) src, size, option));
64
65 // TASKBEGIN effs_t FILE_WRITE(path=pathname, src=src, size=size, value16=option) iref_t i, dir; char *name; effs_t error; int chunk_size, size_remaining, bytes_free;
66
67 if (fs.initerror)
68 return fs.initerror;
69
70 if (size < 0)
71 return EFFS_INVALID;
72
73 ffs_query(Q_BYTES_FREE, &bytes_free);
74 if (bytes_free < size)
75 return EFFS_NOSPACE;
76
77 chunk_size = (size > fs.chunk_size_max ? fs.chunk_size_max : size);
78
79 if ((i = object_lookup(pathname, &name, &dir)) < 0) {
80 // Object not found, continue like fcreate()
81 if (i != EFFS_NOTFOUND)
82 return i;
83
84 if (!is_open_option(option, FFS_O_CREATE))
85 return EFFS_NOTFOUND;
86
87 journal_begin(0);
88
89 if ((dir = object_create(name, src, chunk_size, -dir)) < 0)
90 return dir;
91
92 journal_end(OT_FILE);
93 }
94
95 else {
96 // Object found, continue like fupdate()
97 if (is_open_option(option, (FFS_O_CREATE))
98 && is_open_option(option, (FFS_O_EXCL)))
99 return EFFS_EXISTS;
100
101 if (get_fdi(i) >= 0)
102 return EFFS_LOCKED;
103
104 // Even though the ffs architecture allows to have data in
105 // directory objects, we don't want to complicate matters, so we
106 // return an error
107 if (is_object(inode_addr(i), OT_DIR) && !(fs.flags & FS_DIR_DATA)) {
108 return EFFS_NOTAFILE;
109 }
110
111 if ((i = is_readonly(i, pathname)) < 0)
112 return i;
113
114 // Save the segment (if any) in the global variable because this
115 // global variable will be updated if the inode is going to be
116 // relocated if an inode_reclaim() is triggeret by the object_create()
117 fs.i_backup = segment_next(i);
118
119 journal_begin(i);
120
121 if ((dir = object_create(name, src, chunk_size, -dir)) < 0)
122 return dir;
123
124 // Do not link child - we are replacing the complete file!
125 fs.link_child = 0;
126 journal_end(0);
127
128 // If any other segments exist then remove them FIXME: If we get a
129 // power failure here then the remaining segments wil not be removed
130 // before inode_reclaim() has been executed
131 if (fs.i_backup > 0)
132 if ((error = object_remove(fs.i_backup)) < 0)
133 return error;
134
135 }
136 // Save dir in fs.i_backup because this will be updated if some of the
137 // chunks below trigger a inode reclaim!
138 fs.i_backup = dir;
139
140 size_remaining = size - chunk_size;
141
142 while (size_remaining > 0) {
143
144 chunk_size = (size_remaining > fs.chunk_size_max ?
145 fs.chunk_size_max : size_remaining);
146
147 journal_begin(0);
148
149 if ((i = segment_create((char*) src + size - size_remaining,
150 chunk_size, fs.i_backup)) < 0)
151 return i;
152
153 journal_end(OT_SEGMENT);
154
155 size_remaining -= chunk_size;
156 }
157
158 tw(tr_bstat());
159
160 return EFFS_OK;
161
162 // TASKEND
163 }
164
165 // Note: ffs_fcreate() is deprecated and should not be used. Use
166 // ffs_file_write(..., FFS_O_CREATE | FFS_O_EXCL) instead.
167 effs_t ffs_fcreate(const char *pathname, void *src, int size)
168 {
169 FFS_BLOCKING_CALL_BEGIN();
170
171 result = ffs_file_write_b(pathname, src, size, FFS_O_CREATE | FFS_O_EXCL,
172 0, &fb);
173
174 FFS_BLOCKING_CALL_END();
175
176 return result;
177 }
178
179 req_id_t ffs_fcreate_nb(const char *pathname, void *src, int size,
180 T_RV_RETURN *cp)
181 {
182 return ffs_file_write_b(pathname, src, size, FFS_O_CREATE | FFS_O_EXCL,
183 cp, 0);
184 }
185
186 // Note: ffs_fupdate() is deprecated and should not be used. Use
187 // ffs_file_write(...,FFS_O_TRUNC) instead.
188 effs_t ffs_fupdate(const char *pathname, void *src, int size)
189 {
190
191 FFS_BLOCKING_CALL_BEGIN();
192
193 result = ffs_file_write_b(pathname, src, size, FFS_O_TRUNC, 0, &fb);
194
195 FFS_BLOCKING_CALL_END();
196
197 return result;
198 }
199
200 req_id_t ffs_fupdate_nb(const char *pathname, void *src, int size,
201 T_RV_RETURN *cp)
202 {
203 return ffs_file_write_b(pathname, src, size, FFS_O_TRUNC, cp, 0);
204 }
205
206 // Note: ffs_fwrite() is deprecated and should not be used. Use
207 // ffs_file_write(...,FFS_O_CREATE | FFS_O_TRUNC) instead.
208 effs_t ffs_fwrite(const char *pathname, void *src, int size)
209 {
210
211 FFS_BLOCKING_CALL_BEGIN();
212
213 result = ffs_file_write_b(pathname, src, size,
214 FFS_O_CREATE | FFS_O_TRUNC, 0, &fb);
215
216 FFS_BLOCKING_CALL_END();
217
218 return result;
219 }
220
221 req_id_t ffs_fwrite_nb(const char *pathname, void *src, int size,
222 T_RV_RETURN *cp)
223 {
224 return ffs_file_write_b(pathname, src, size,
225 FFS_O_CREATE | FFS_O_TRUNC, cp, 0);
226 }
227
228 effs_t ffs_file_write(const char *pathname, void *src, int size,
229 ffs_options_t option)
230 {
231
232 FFS_BLOCKING_CALL_BEGIN();
233
234 result = ffs_file_write_b(pathname, src, size, option, 0, &fb);
235
236 FFS_BLOCKING_CALL_END();
237
238 return result;
239 }
240
241 req_id_t ffs_file_write_nb(const char *pathname, void *src, int size,
242 ffs_options_t option,
243 T_RV_RETURN *cp)
244 {
245 return ffs_file_write_b(pathname, src, size, option, cp, 0);
246 }
247
248 // Note important: ffs_fread() is deprecated and should not be used. Use
249 // ffs_file_read() instead.
250 int ffs_fread(const char *name, void *addr, int size)
251 {
252 return ffs_file_read(name, addr, size);
253 }
254
255
256 int ffs_file_read(const char *name, void *addr, int size)
257 {
258 int error;
259
260 tw(tr(TR_BEGIN, TrApi, "file_read('%s', 0x%x, %d) {\n",
261 name, (int) addr, size));
262
263 if ((error = ffs_begin()) == EFFS_OK)
264 {
265 error = file_read(name, addr, size);
266 }
267
268 tw(tr(TR_END, TrApi, "} %d\n", error));
269
270 return ffs_end(error); // number of bytes read
271 }
272
273 /******************************************************************************
274 * Stat, Symlink, Remove and Rename
275 ******************************************************************************/
276
277 effs_t ffs_stat(const char *name, struct stat_s *stat)
278 {
279 iref_t i;
280
281 tw(tr(TR_FUNC, TrApi, "ffs_stat('%s', ?) ?\n", name));
282 ttw(ttr(TTrApi, "ffs_stat('%s', ?) ?" NL, name));
283
284 if (name == NULL)
285 return EFFS_BADNAME;
286
287 if ((i = ffs_begin()) == EFFS_OK)
288 {
289 if ((i = object_stat(name, (struct xstat_s*) stat, 0, 0, 0)) > 0)
290 i = EFFS_OK;
291 }
292
293 return ffs_end(i);
294 }
295
296 effs_t ffs_lstat(const char *name, struct stat_s *stat)
297 {
298 iref_t i;
299
300 tw(tr(TR_FUNC, TrApi, "ffs_lstat('%s', ?) ?\n", name));
301 ttw(ttr(TTrApi, "ffs_lstat('%s', ?) ?" NL, name));
302
303 if ((i = ffs_begin()) == EFFS_OK) {
304 if ((i = object_stat(name, (struct xstat_s*)stat, 1, 0, 0)) > 0)
305 i = EFFS_OK;
306 }
307
308 return ffs_end(i);
309 }
310
311 effs_t ffs_xlstat(const char *name, struct xstat_s *stat)
312 {
313 iref_t i;
314
315 tw(tr(TR_FUNC, TrApi, "ffs_xlstat('%s', ?) ?\n", name));
316 ttw(ttr(TTrApi, "ffs_xlstat('%s', ?) ?" NL, name));
317
318 if ((i = ffs_begin()) == EFFS_OK) {
319 if ((i = object_stat(name, stat, 1, 0, 1)) > 0)
320 i = EFFS_OK;
321 }
322
323 return ffs_end(i);
324 }
325
326 effs_t ffs_fstat(fd_t fdi, struct stat_s *stat)
327 {
328 iref_t i;
329
330 tw(tr(TR_FUNC, TrApi, "ffs_fstat('%d', ?) ?\n", fdi));
331 ttw(ttr(TTrApi, "ffs_fstat('%d', ?) ?" NL, fdi));
332
333 if ((i = ffs_begin()) == EFFS_OK) {
334 if ((i = object_stat( 0, (struct xstat_s*) stat, 0, fdi, 0)) > 0)
335 i = EFFS_OK;
336 }
337
338 return ffs_end(i);
339 }
340
341 req_id_t ffs_symlink_b(const char *pathname, const char *src,
342 T_RV_RETURN *cp, struct ffs_blocking_s *fb)
343 {
344 iref_t i, dir;
345 char *name;
346 int size;
347
348 tw(tr(TR_FUNC, TrApi, "ffs_symlink('%s', '%s') ?\n", pathname, src));
349 ttw(ttr(TTrApi, "ffs_symlink('%s', '%s') ?" NL, pathname, src));
350
351 // TASKBEGIN effs_t SYMLINK(path=pathname, src=src) iref_t i, dir; int size; char *name;
352
353 if (fs.initerror)
354 return fs.initerror;
355
356 if (src == NULL)
357 return EFFS_BADNAME;
358
359 i = object_lookup(pathname, &name, &dir);
360 if (i > 0)
361 return EFFS_EXISTS;
362 if (i != EFFS_NOTFOUND)
363 return i;
364
365 size = ffs_strlen(src) + 1; // include null-terminator
366
367 journal_begin(0);
368
369 if ((i = object_create(name, src, size, -dir)) < 0)
370 return i;
371
372 journal_end(OT_LINK);
373
374 tw(tr_bstat());
375
376 return EFFS_OK;
377
378 // TASKEND
379 }
380
381 effs_t ffs_symlink(const char *pathname, const char *actualpath)
382 {
383 FFS_BLOCKING_CALL_BEGIN();
384
385 result = ffs_symlink_b(pathname, actualpath, 0, &fb);
386
387 FFS_BLOCKING_CALL_END();
388
389 return result;
390 }
391
392 req_id_t ffs_symlink_nb(const char *pathname, const char *src,
393 T_RV_RETURN *cp)
394 {
395 return ffs_symlink_b(pathname, src, cp, 0);
396 }
397
398 int ffs_readlink(const char *name, char *addr, int size)
399 {
400 int error;
401
402 tw(tr(TR_FUNC, TrApi, "ffs_readlink('%s')\n", name));
403
404 if ((error = ffs_begin()) == EFFS_OK)
405 {
406 error = object_read(name, addr, size, 1);
407 }
408 return ffs_end(error);
409 }
410
411 req_id_t ffs_remove_b(const char *pathname, T_RV_RETURN *cp,
412 struct ffs_blocking_s *fb)
413 {
414 iref_t i;
415
416 tw(tr(TR_FUNC, TrApi, "ffs_remove('%s')\n", pathname));
417 ttw(ttr(TTrApi, "ffs_remove('%s') ?" NL, pathname));
418
419 // TASKBEGIN effs_t REMOVE(path=pathname) iref_t i;
420
421 if (fs.initerror)
422 return fs.initerror;
423
424 if ((i = object_lookup_once(pathname, 0, 0)) < 0)
425 return i;
426
427 if (get_fdi(i) >= 0)
428 return EFFS_LOCKED;
429
430 if ((i = is_readonly(i, pathname)) < 0)
431 return i;
432
433 if ((i = object_remove(i)) < 0)
434 return i;
435
436 tw(tr_bstat());
437
438 return EFFS_OK;
439
440 // TASKEND
441 }
442
443 effs_t ffs_remove(const char *pathname)
444 {
445 FFS_BLOCKING_CALL_BEGIN();
446
447 result = ffs_remove_b(pathname, 0, &fb);
448
449 FFS_BLOCKING_CALL_END();
450
451 return result;
452 }
453
454 req_id_t ffs_remove_nb(const char *pathname, T_RV_RETURN *cp)
455 {
456 return ffs_remove_b(pathname, cp, 0);
457 }
458
459 req_id_t ffs_fcontrol_b(const char *pathname, int8 action, int param,
460 T_RV_RETURN *cp, struct ffs_blocking_s *fb)
461 {
462 iref_t i;
463
464 tw(tr(TR_FUNC, TrApi, "ffs_fcontrol('%s', %d, 0x%x) ?\n",
465 pathname, action, param));
466 ttw(ttr(TTrApi, "ffs_fcontrol('%s', %d, 0x%x) ?" NL,
467 pathname, action, param));
468
469 // TASKBEGIN effs_t FCONTROL(path=pathname, value16=action, size=param) iref_t i;
470
471 if (fs.initerror)
472 return fs.initerror;
473
474 if (pathname == NULL)
475 return EFFS_BADNAME;
476
477 if ((i = ffs_strcmp(pathname, "/dev/ffs")) != 0)
478 {
479 if ((i = object_lookup_once(pathname, 0, 0)) < 0)
480 return i;
481
482 if ((i = is_readonly(i, pathname)) < 0)
483 return i;
484 }
485
486 if ((i = object_control(i, action, param)) < 0)
487 return i;
488
489 tw(tr_bstat());
490
491 return EFFS_OK;
492
493 // TASKEND
494 }
495
496 effs_t ffs_fcontrol(const char *pathname, int8 action, int param)
497 {
498 FFS_BLOCKING_CALL_BEGIN();
499
500 result = ffs_fcontrol_b(pathname, action, param, 0, &fb);
501
502 FFS_BLOCKING_CALL_END();
503
504 return result;
505 }
506
507 req_id_t ffs_fcontrol_nb(const char *pathname, int8 action, int param,
508 T_RV_RETURN *cp)
509 {
510 return ffs_fcontrol_b(pathname, action, param, cp, 0);
511 }
512
513 req_id_t ffs_rename_b(const char *pathname, const char *newname,
514 T_RV_RETURN *cp, struct ffs_blocking_s *fb)
515 {
516 iref_t i, oldi, dir;
517 char *name;
518 struct inode_s *ip;
519
520 tw(tr(TR_FUNC, TrApi, "ffs_rename('%s', '%s') ?\n", pathname, newname));
521 ttw(ttr(TTrApi, "ffs_rename('%s', '%s') ?" NL, pathname, newname));
522
523 // TASKBEGIN effs_t RENAME(path=pathname, src=newname) iref_t i, oldi, dir; char *name; struct inode_s *ip;
524
525 if (fs.initerror)
526 return fs.initerror;
527
528 // pathname MUST exist, not be open and MUST be writable
529 if ((oldi = object_lookup_once(pathname, 0, 0)) < 0)
530 return oldi;
531 if ((oldi = is_readonly(oldi, pathname)) < 0)
532 return oldi;
533 if (get_fdi(oldi) >= 0)
534 return EFFS_LOCKED;
535
536 journal_begin(oldi);
537
538 if ((i = object_lookup_once(newname, &name, &dir)) < 0) {
539 if (i != EFFS_NOTFOUND)
540 return i;
541 }
542 else { // newname obj exist
543 ip = inode_addr(oldi);
544 if (is_object(ip, OT_FILE)) { // is old obj a file?
545 if ((i = is_readonly(i, newname)) < 0)
546 return i;
547
548 ip = inode_addr(i);
549 if (!is_object(ip, OT_FILE)) // newname MUST be a file
550 return EFFS_NOTAFILE;
551
552 fs.journal.repli = i;
553 }
554 else
555 return EFFS_EXISTS;
556 }
557
558 if ((i = object_rename(oldi, name, -dir)) < 0)
559 return i;
560
561 journal_end(0);
562
563 tw(tr_bstat());
564
565 return EFFS_OK;
566
567 // TASKEND
568
569 }
570
571 effs_t ffs_rename(const char *pathname, const char *newname)
572 {
573 FFS_BLOCKING_CALL_BEGIN();
574
575 result = ffs_rename_b(pathname, newname, 0, &fb);
576
577
578 FFS_BLOCKING_CALL_END();
579
580 return result;
581 }
582
583
584 req_id_t ffs_rename_nb(const char *pathname, const char *newname,
585 T_RV_RETURN *cp)
586 {
587 return ffs_rename_b(pathname, newname, cp, 0);
588 }
589
590 /******************************************************************************
591 * Directory Operations
592 ******************************************************************************/
593
594 // All directory operations are more or less similar to unix
595 // semantics.
596 req_id_t ffs_mkdir_b(const char *pathname, T_RV_RETURN *cp,
597 struct ffs_blocking_s *fb)
598 {
599 iref_t i, dir;
600 char *name;
601
602 tw(tr(TR_FUNC, TrApi, "ffs_mkdir('%s')\n", pathname));
603 ttw(ttr(TTrApi, "ffs_mkdir('%s') ?" NL, pathname));
604
605 // TASKBEGIN effs_t MKDIR(path=pathname) iref_t i, dir; char *name;
606
607 if (fs.initerror)
608 return fs.initerror;
609
610 i = object_lookup(pathname, &name, &dir);
611 if (i > 0)
612 return EFFS_EXISTS;
613 if (i != EFFS_NOTFOUND)
614 return i;
615
616 journal_begin(0);
617
618 if ((i = object_create(name, 0, 0, -dir)) < 0)
619 return i;
620
621 journal_end(OT_DIR);
622
623 tw(tr_bstat());
624
625 return EFFS_OK;
626
627 // TASKEND
628 }
629
630 effs_t ffs_mkdir(const char *pathname)
631 {
632 FFS_BLOCKING_CALL_BEGIN();
633
634 result = ffs_mkdir_b(pathname, 0, &fb);
635
636 FFS_BLOCKING_CALL_END();
637
638 return result;
639 }
640
641 req_id_t ffs_mkdir_nb(const char *pathname, T_RV_RETURN *cp)
642 {
643 return ffs_mkdir_b(pathname, cp, 0);
644 }
645
646 int ffs_opendir(const char *name, struct dir_s *dir)
647 {
648 int i;
649
650 tw(tr(TR_FUNC, TrApi, "ffs_opendir('%s', ?)\n", name));
651 ttw(ttr(TTrApi, "ffs_opendir('%s', ?) ?" NL, name));
652
653 if (dir == NULL)
654 return EFFS_INVALID;
655
656 if ((i = ffs_begin()) == EFFS_OK)
657 {
658 if ((i = dir_open(name)) >= 0)
659 {
660 dir->this = i;
661 dir->index = i;
662
663 // Now count the number of entries in the directory
664 dir_traverse(-i, (iref_t *) &i);
665 }
666 }
667 return ffs_end(i);
668 }
669
670 int ffs_readdir(struct dir_s *dir, char *name, int size)
671 {
672 iref_t i;
673
674 tw(tr(TR_BEGIN, TrApi, "ffs_readdir(?, ?, ?) {\n"));
675 ttw(ttr(TTrApi, "ffs_readdir(?, ?, ?) ?" NL));
676
677 if (dir == NULL || name == NULL || size < 0) {
678 tw(tr(TR_END, TrApi, "} %d\n", EFFS_INVALID));
679 return EFFS_INVALID;
680 }
681
682 if ((i = ffs_begin()) == EFFS_OK)
683 {
684 if ((i = dir_next(dir->this, dir->index, name, size)))
685 dir->index = i;
686 }
687 tw(tr(TR_END, TrApi, "} ('%s') %d\n", name, i));
688
689 return ffs_end(i);
690 }
691
692
693 /******************************************************************************
694 * Preformat and Format
695 ******************************************************************************/
696
697 // Note that we do NOT call ffs_begin() because it will just return
698 // EFFS_NOFORMAT!
699 req_id_t ffs_format_b(const char *name, uint16 magic, T_RV_RETURN *cp,
700 struct ffs_blocking_s *fb)
701 {
702 effs_t i;
703
704 tw(tr(TR_BEGIN, TrApi, "ffs_format('%s', 0x%x) {\n", name, magic));
705 ttw(ttr(TTrApi, "ffs_format('%s', 0x%x) ?" NL, name, magic));
706
707 // TASKBEGIN effs_t FORMAT(path=name, size=magic) iref_t i;
708
709 if (magic != 0x2BAD) {
710 tw(tr(TR_END, TrApi, "} %d\n", EFFS_INVALID));
711 return EFFS_INVALID;
712 }
713
714 if (name == NULL) {
715 name = "/ffs-5.54";
716 }
717
718 if (*name != '/') {
719 tw(tr(TR_END, TrApi, "} %d\n", EFFS_BADNAME));
720 return EFFS_BADNAME;
721 }
722
723 if ((i = is_formattable(1)) < 0) {
724 tw(tr(TR_END, TrApi, "} %d\n", i));
725 return i;
726 }
727
728 if ((i = fs_format(name)) < 0)
729 return i;
730
731 tw(tr(TR_END, TrApi, "} %d\n", i));
732
733 tw(tr_bstat());
734
735 return EFFS_OK;
736
737 // TASKEND
738 }
739
740 effs_t ffs_format(const char *name, uint16 magic)
741 {
742 FFS_BLOCKING_CALL_BEGIN();
743
744 result = ffs_format_b(name, magic, 0, &fb);
745
746 FFS_BLOCKING_CALL_END();
747
748 return result;
749 }
750
751 req_id_t ffs_format_nb(const char *name, uint16 magic, T_RV_RETURN *cp)
752 {
753 return ffs_format_b(name, magic, cp, 0);
754 }
755
756 req_id_t ffs_preformat_b(uint16 magic, T_RV_RETURN *cp,
757 struct ffs_blocking_s *fb)
758 {
759 effs_t i;
760
761 tw(tr(TR_BEGIN, TrApi, "ffs_preformat(0x%x) {\n", magic));
762 ttw(ttr(TTrApi, "ffs_preformat(0x%x) ?" NL, magic));
763
764 // TASKBEGIN effs_t PREFORMAT(path="/", size=magic) effs_t i;
765
766 if (magic != 0xDEAD) {
767 tw(tr(TR_END, TrApi, "} %d\n", EFFS_INVALID));
768 return EFFS_INVALID;
769 }
770
771 if (!ffs_is_modifiable("")) {
772 tw(tr(TR_END, TrApi, "} %d\n", EFFS_ACCESS));
773 return EFFS_ACCESS;
774 }
775
776 if ((i = is_formattable(0)) < 0) {
777 tw(tr(TR_END, TrApi, "} %d\n", i));
778 return i;
779 }
780
781 if ((i = fs_preformat()) < 0)
782 return i;
783
784 tw(tr(TR_END, TrApi, "} %d\n", i));
785
786 tw(tr_bstat());
787
788 return EFFS_OK;
789
790 // TASKEND
791 }
792
793 effs_t ffs_preformat(uint16 magic)
794 {
795 FFS_BLOCKING_CALL_BEGIN();
796
797 result = ffs_preformat_b(magic, 0, &fb);
798
799 FFS_BLOCKING_CALL_END();
800
801 return result;
802 }
803
804 req_id_t ffs_preformat_nb(uint16 magic, T_RV_RETURN *cp)
805 {
806 return ffs_preformat_b(magic, cp, 0);
807 }
808
809 /******************************************************************************
810 * Open, Read, Write, Close
811 ******************************************************************************/
812 req_id_t ffs_open_b(const char *pathname, ffs_options_t option,
813 T_RV_RETURN *cp, struct ffs_blocking_s *fb)
814 {
815 iref_t i, dir, dummy;
816 char *name;
817 fd_t other_fdi, fdi = 0;
818 int error;
819 struct inode_s *ip;
820
821 tw(tr(TR_FUNC, TrApi, "ffs_open('%s', 0x%x) ?\n", pathname, option));
822 ttw(ttr(TTrApi, "ffs_open('%s', 0x%x) ?" NL, pathname, option));
823
824 // TASKBEGIN fd_t OPEN(path=pathname, value16=option) iref_t i, dir, dummy; char *name; fd_t other_fdi, fdi = 0; int error; struct inode_s *ip;
825
826 if (fs.initerror)
827 return fs.initerror;
828
829 // Minimum one of the flags RD or WR must be specifyed
830 if (!is_open_option(option, FFS_O_RDONLY) &&
831 !is_open_option(option, FFS_O_WRONLY))
832 return EFFS_INVALID;
833
834 // RDONLY must not be combined with any other options if not together
835 // with WR!
836 if (is_open_option(option, FFS_O_RDONLY) &&
837 !is_open_option(option, FFS_O_WRONLY))
838 if (!(option == FFS_O_RDONLY))
839 return EFFS_INVALID;
840
841 for (fdi = 0; fdi < fs.fd_max; fdi++) { // Find free fd
842 if (fs.fd[fdi].options == 0) {
843 break;
844 }
845 }
846
847 if (fdi >= fs.fd_max)
848 return EFFS_NUMFD; // Too many open files in system
849
850 i = object_lookup(pathname, &name, &dir);
851 if (i < 0 && i != EFFS_NOTFOUND)
852 return i;
853
854 // Open one file several times in RD is okay but only one time in WR
855 if (i != EFFS_NOTFOUND && (other_fdi = get_fdi(i)) >= 0) {
856 if (is_open_option(fs.fd[other_fdi].options, FFS_O_WRONLY) ||
857 is_open_option(option, FFS_O_WRONLY))
858 return EFFS_LOCKED;
859 }
860
861 // Init default values
862 fs.fd[fdi].fp = fs.fd[fdi].size = fs.fd[fdi].wfp = fs.fd[fdi].dirty = 0;
863
864 if (i == EFFS_NOTFOUND) {
865 if (is_open_option(option, (FFS_O_CREATE | FFS_O_WRONLY))) {
866 if ((error = is_filename(name)) < 0)
867 return error;
868
869 // Create segmenthead
870 journal_begin(0);
871
872 if ((i = object_create(name, 0, 0, -dir)) < 0)
873 return i;
874
875 journal_end(OT_FILE);
876 tw(tr_bstat());
877 fs.fd[fdi].seghead = i;
878 }
879 else
880 return EFFS_NOTFOUND;
881 }
882 else {
883 if (is_open_option(option, FFS_O_WRONLY)) {
884 if (is_open_option(option, (FFS_O_CREATE | FFS_O_EXCL)))
885 return EFFS_EXISTS;
886 if ((i = is_readonly(i, pathname)) < 0)
887 return i;
888 }
889 ip = inode_addr(i);
890
891 if (is_object(ip, OT_DIR))
892 return EFFS_NOTAFILE;
893
894 if (is_open_option(option, FFS_O_TRUNC)) {
895 // Save the segment (if any) in the global variable because this
896 // global variable will be updated if the inode is relocated by
897 // an inode_reclaim() triggeret by object_create()
898 fs.i_backup = segment_next(i);
899
900 // Replace old seghead with a new and remove all old segments
901 journal_begin(i);
902
903 if ((i = object_create(name, 0, 0, -dir)) < 0)
904 return i;
905
906 // Do not link child
907 fs.link_child = 0;
908 journal_end(0);
909
910 // If any further segments exist then remove them now
911 if (fs.i_backup > 0)
912 if ((error = object_remove(fs.i_backup)) < 0)
913 return error;
914
915 tw(tr_bstat());
916 }
917
918 else {
919 // Get total size of the file.
920 fs.fd[fdi].size = segfile_seek(i, INT_MAX, &dummy, 0);
921 }
922
923 if (is_open_option(option, FFS_O_APPEND)) {
924 fs.fd[fdi].fp = fs.fd[fdi].size;
925 }
926 }
927
928 if (is_open_option(option, FFS_O_WRONLY)) {
929 #if (TARGET == 1)
930 if ((fs.fd[fdi].buf = (char *) target_malloc(fs.fd_buf_size)) == 0)
931 return EFFS_MEMORY;
932 #else
933 if ((fs.fd[fdi].buf = malloc(fs.fd_buf_size)) == 0)
934 return EFFS_MEMORY;
935 #endif
936 }
937
938 // Save data in file descriptor
939 fs.fd[fdi].seghead = i;
940 fs.fd[fdi].options = option;
941
942 return fdi + FFS_FD_OFFSET;
943
944 // TASKEND
945 }
946
947 fd_t ffs_open(const char *pathname, ffs_options_t option)
948 {
949 FFS_BLOCKING_CALL_BEGIN();
950
951 result = ffs_open_b(pathname, option, 0, &fb);
952
953 FFS_BLOCKING_CALL_END();
954
955 return result;
956 }
957
958
959 req_id_t ffs_open_nb(const char *pathname, ffs_options_t option,
960 T_RV_RETURN *cp)
961 {
962 return ffs_open_b(pathname, option, cp, 0);
963 }
964
965 req_id_t ffs_close_b(fd_t fdi, T_RV_RETURN *cp, struct ffs_blocking_s *fb)
966 {
967 int error;
968
969 tw(tr(TR_FUNC, TrApi, "ffs_close(%d) ?\n", fdi));
970 ttw(ttr(TTrApi, "ffs_close(%d) ?" NL, fdi));
971
972 // TASKBEGIN effs_t CLOSE(fdi=fdi) iref_t i; int error;
973
974 if (fs.initerror)
975 return fs.initerror;
976
977 fdi -= FFS_FD_OFFSET;
978
979 if (!is_fd_valid(fdi))
980 return EFFS_BADFD;
981
982 if (is_open_option(fs.fd[fdi].options, FFS_O_WRONLY )) {
983 if ((error = datasync(fdi)) < 0)
984 return error;
985
986 #if (TARGET == 1)
987 target_free(fs.fd[fdi].buf);
988 #else
989 free(fs.fd[fdi].buf);
990 #endif
991 }
992
993 // Clear all data in file descriptor
994 fs.fd[fdi].seghead = 0;
995 fs.fd[fdi].options = fs.fd[fdi].fp = 0;
996
997 return EFFS_OK;
998
999 // TASKEND
1000 }
1001
1002 effs_t ffs_close(fd_t fdi)
1003 {
1004 FFS_BLOCKING_CALL_BEGIN();
1005
1006 result = ffs_close_b(fdi, 0, &fb);
1007
1008 FFS_BLOCKING_CALL_END();
1009
1010 return result;
1011 }
1012
1013
1014 req_id_t ffs_close_nb(fd_t fdi, T_RV_RETURN *cp)
1015 {
1016 return ffs_close_b( fdi, cp, 0);
1017 }
1018
1019 req_id_t ffs_write_b(fd_t fdi, void *src, int amount,
1020 T_RV_RETURN *cp, struct ffs_blocking_s *fb)
1021 {
1022 effs_t error;
1023 iref_t i;
1024 int size_remaining, fp_offset;
1025 int size, size_done;
1026 offset_t chunk_offset;
1027
1028 tw(tr(TR_BEGIN, TrApi, "ffs_write_b(%d, 0x%x, %d) ?{\n", fdi, src, amount));
1029 ttw(ttr(TTrApi, "ffs_write_b(%d, 0x%x, %d) ?" NL, fdi, src, amount));
1030
1031 // TASKBEGIN int WRITE(fdi=fdi, src=src, size=amount) effs_t error; iref_t i; int size_remaining, fp_offset; int size, size_done; offset_t chunk_offset;
1032
1033 if (fs.initerror)
1034 return fs.initerror;
1035
1036 if (amount < 0 || src == NULL)
1037 return EFFS_INVALID;
1038
1039 fdi -= FFS_FD_OFFSET;
1040
1041 if (!is_fd_valid(fdi))
1042 return EFFS_BADFD;
1043
1044 if (!is_open_option(fs.fd[fdi].options, FFS_O_WRONLY ))
1045 return EFFS_INVALID; // not opened with write flag
1046
1047 // If FFS_O_APPEEND is specified move fp to eof
1048 if (is_open_option(fs.fd[fdi].options, FFS_O_APPEND ))
1049 fs.fd[fdi].fp = fs.fd[fdi].size;
1050
1051 // If fp has been moved outside the write buf (by a read) then flush the
1052 // write buffer.
1053 if (fs.fd[fdi].fp >= (fs.fd[fdi].wfp + fs.chunk_size_max)) {
1054 if ((error = datasync(fdi)) < 0)
1055 return error;
1056 }
1057
1058 size_done = 0;
1059 size_remaining = amount;
1060
1061 do {
1062 if (!fs.fd[fdi].dirty ) {
1063 // Buffer is not dirty so find the chunk that fp points to.
1064 segfile_seek(fs.fd[fdi].seghead, fs.fd[fdi].fp, &i,
1065 &chunk_offset);
1066
1067 if ((fs.fd[fdi].size == fs.fd[fdi].fp &&
1068 chunk_offset == fs.chunk_size_max) || fs.fd[fdi].size == 0 ) {
1069 // End of file and last chunk is full or empty seghead.
1070 fs.fd[fdi].wfp = fs.fd[fdi].size;
1071 fs.fd[fdi].wch = 0; // Create new chunk (not update).
1072 }
1073 else {
1074 // Work on this chunk and update it later by datasyns
1075 segment_read(i, fs.fd[fdi].buf, fs.fd_buf_size, 0);
1076 fs.fd[fdi].wfp = fs.fd[fdi].fp - chunk_offset;
1077 fs.fd[fdi].wch = i;
1078 }
1079 }
1080
1081 fs.fd[fdi].dirty = 1;
1082 fp_offset = fs.fd[fdi].fp - fs.fd[fdi].wfp;
1083
1084 // Fill the buffer to max or just add the rest
1085 size = fs.chunk_size_max - fp_offset;
1086
1087 if (size_remaining <= fs.chunk_size_max - fp_offset)
1088 size = size_remaining;
1089
1090 tw(tr(TR_FUNC, TrApi, "Copy data to buffer (size: %d)\n", size));
1091
1092 memcpy(fs.fd[fdi].buf + fp_offset, (uint8*)src + size_done,
1093 size);
1094
1095 fs.fd[fdi].fp += size;
1096 if (fs.fd[fdi].fp > fs.fd[fdi].size)
1097 fs.fd[fdi].size = fs.fd[fdi].fp;
1098
1099 size_done += size; // FIXME: remove size_done or size_remaining
1100 size_remaining -= size;
1101
1102 // If wrbuf is full (size = chunk_size_max) so create a chunk.
1103 if (fs.fd[fdi].fp >= (fs.fd[fdi].wfp + fs.chunk_size_max)) {
1104 if ((error = datasync(fdi)) < 0)
1105 return error;
1106 }
1107 } while(size_remaining > 0);
1108
1109 tw(tr(TR_END, TrApi, "} %d\n", amount));
1110 return amount;
1111
1112 // TASKEND
1113 }
1114
1115 int ffs_write(fd_t fdi, void *src, int amount)
1116 {
1117 FFS_BLOCKING_CALL_BEGIN();
1118
1119 result = ffs_write_b(fdi, src, amount, 0, &fb);
1120
1121 FFS_BLOCKING_CALL_END();
1122
1123 return result;
1124 }
1125
1126 req_id_t ffs_write_nb(fd_t fdi, void *src, int amount, T_RV_RETURN *cp)
1127 {
1128
1129 tw(tr(TR_FUNC, TrApi, "ffs_write_nb(%d, 0x%x, %d) ?\n", fdi, src, amount));
1130
1131 return ffs_write_b(fdi, src, amount, cp, 0);
1132 }
1133
1134 int ffs_read(fd_t fdi, void *src, int size)
1135 {
1136 int error;
1137
1138 tw(tr(TR_BEGIN, TrApi, "ffs_read(%d, 0x%x, %d) {\n", fdi, src, size));
1139 ttw(ttr(TTrApi, "ffs_read(%d, 0x%x, %d) ?" NL, fdi, src, size));
1140
1141 if ((error = ffs_begin()) == EFFS_OK)
1142 {
1143 error = stream_read(fdi - FFS_FD_OFFSET, src, size);
1144 }
1145
1146 tw(tr(TR_END, TrApi, "} %d\n", error));
1147 return ffs_end(error); // number of bytes read
1148 }
1149
1150 // The seek function will not allow the file offset to be set beyond the end
1151 // of the existing data in the file or the final offset to be negative.
1152 req_id_t ffs_seek_b(fd_t fdi, int offset, int whence, T_RV_RETURN *cp,
1153 struct ffs_blocking_s *fb)
1154 {
1155 effs_t error;
1156 int fp_new;
1157
1158 tw(tr(TR_FUNC, TrApi, "ffs_seek(%d, %d, %d) ?\n", fdi, offset, whence));
1159 ttw(ttr(TTrApi, "ffs_seek(%d, %d, %d) ?" NL, fdi, offset, whence));
1160
1161 // TASKBEGIN int SEEK(fdi=fdi, size=offset, value16=whence) effs_t error; iref_t i; int fp_new, foffset;
1162
1163 if (fs.initerror)
1164 return fs.initerror;
1165
1166 fdi -= FFS_FD_OFFSET;
1167
1168 if (!is_fd_valid(fdi))
1169 return EFFS_BADFD;
1170
1171 switch(whence) {
1172 case FFS_SEEK_SET:
1173 if (offset < 0 || offset > fs.fd[fdi].size)
1174 return EFFS_INVALID;
1175 fp_new = offset;
1176 break;
1177 case FFS_SEEK_CUR:
1178 if (fs.fd[fdi].fp + offset < 0 ||
1179 fs.fd[fdi].fp + offset > fs.fd[fdi].size)
1180 return EFFS_INVALID;
1181 fp_new = fs.fd[fdi].fp + offset;
1182 break;
1183 case FFS_SEEK_END:
1184 if (offset > 0 || fs.fd[fdi].size < -offset)
1185 return EFFS_INVALID;
1186 fp_new = (offset + fs.fd[fdi].size);
1187 break;
1188 default:
1189 return EFFS_INVALID;
1190 }
1191
1192 if (!is_offset_in_buf(fp_new, fdi))
1193 if ((error = datasync(fdi)) < 0)
1194 return error;
1195
1196 return fs.fd[fdi].fp = fp_new;
1197
1198 // TASKEND
1199 }
1200
1201 int ffs_seek(fd_t fdi, int offset, int whence)
1202 {
1203 FFS_BLOCKING_CALL_BEGIN();
1204
1205 result = ffs_seek_b(fdi, offset, whence, 0, &fb);
1206
1207 FFS_BLOCKING_CALL_END();
1208
1209 return result;
1210 }
1211
1212 req_id_t ffs_seek_nb(fd_t fdi, int offset, int whence, T_RV_RETURN *cp)
1213 {
1214 return ffs_seek_b(fdi, offset, whence, cp, 0);
1215 }
1216
1217 req_id_t ffs_truncate_b(const char *path, offset_t length, T_RV_RETURN *cp,
1218 struct ffs_blocking_s *fb)
1219 {
1220 tw(tr(TR_FUNC, TrApi, "ffs_truncate('%s', %d) \n", path, length));
1221 ttw(ttr(TTrApi, "ffs_ftruncate('%s', %d) ?" NL, path, length));
1222
1223 // TASKBEGIN effs_t TRUNC(path=path, size=length) iref_t i;
1224
1225 if (fs.initerror)
1226 return fs.initerror;
1227
1228 if (path == NULL)
1229 return EFFS_BADNAME;
1230
1231 return object_truncate(path, -1, length);
1232
1233 // TASKEND
1234 }
1235
1236 effs_t ffs_truncate(const char *path, offset_t length)
1237 {
1238 FFS_BLOCKING_CALL_BEGIN();
1239
1240 result = ffs_truncate_b(path, length, 0, &fb);
1241
1242 FFS_BLOCKING_CALL_END();
1243
1244 return result;
1245 }
1246
1247 req_id_t ffs_truncate_nb(const char *path, offset_t length, T_RV_RETURN *cp)
1248 {
1249 return ffs_truncate_b(path, length, cp, 0);
1250 }
1251
1252 req_id_t ffs_ftruncate_b(fd_t fdi, offset_t length, T_RV_RETURN *cp,
1253 struct ffs_blocking_s *fb)
1254 {
1255 tw(tr(TR_FUNC, TrApi, "ffs_ftruncate(%d, %d) \n", fdi, length));
1256 ttw(ttr(TTrApi, "ffs_ftruncate(%d, %d) ?" NL, fdi, length));
1257
1258 // TASKBEGIN effs_t FTRUNC(fdi=fdi, size=length) iref_t i;
1259
1260 if (fs.initerror)
1261 return fs.initerror;
1262
1263 return object_truncate(0, fdi - FFS_FD_OFFSET, length);
1264
1265 // TASKEND
1266 }
1267
1268 effs_t ffs_ftruncate(fd_t fdi, offset_t length)
1269 {
1270 FFS_BLOCKING_CALL_BEGIN();
1271
1272 result = ffs_ftruncate_b(fdi, length, 0, &fb);
1273
1274 FFS_BLOCKING_CALL_END();
1275
1276 return result;
1277 }
1278
1279 req_id_t ffs_ftruncate_nb(fd_t fdi, offset_t length, T_RV_RETURN *cp)
1280 {
1281 return ffs_ftruncate_b(fdi, length, cp, 0);
1282 }
1283
1284 req_id_t ffs_fdatasync_b(fd_t fdi, T_RV_RETURN *cp, struct ffs_blocking_s *fb)
1285 {
1286 tw(tr(TR_FUNC, TrApi, "ffs_fdatasync(%d) \n", fdi));
1287 ttw(ttr(TTrApi, "ffs_fdatasync(%d) ?" NL, fdi));
1288
1289 // TASKBEGIN effs_t FDATASYNC(fdi=fdi) effs_t error;
1290
1291 if (fs.initerror)
1292 return fs.initerror;
1293
1294 return datasync(fdi - FFS_FD_OFFSET);
1295
1296 // TASKEND
1297 }
1298
1299 effs_t ffs_fdatasync(fd_t fdi)
1300 {
1301 FFS_BLOCKING_CALL_BEGIN();
1302
1303 result = ffs_fdatasync_b(fdi, 0, &fb);
1304
1305 FFS_BLOCKING_CALL_END();
1306
1307 return result;
1308 }
1309
1310 req_id_t ffs_fdatasync_nb(fd_t fdi, T_RV_RETURN *cp)
1311 {
1312 return ffs_fdatasync_b(fdi, cp, 0);
1313 }
1314