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 |
