FreeCalypso > hg > freecalypso-sw
comparison gsm-fw/services/ffs/ffs.c @ 213:ef7d7da61c56
FFS code integration: remaining C files imported, but not yet integrated
author | Michael Spacefalcon <msokolov@ivan.Harhan.ORG> |
---|---|
date | Mon, 06 Jan 2014 04:20:29 +0000 |
parents | |
children | 30a173257f4a |
comparison
equal
deleted
inserted
replaced
212:3ebe6409e8bc | 213:ef7d7da61c56 |
---|---|
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 |