FreeCalypso > hg > freecalypso-citrine
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 } |