comparison services/ffs/ffs.c @ 0:75a11d740a02

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