Changeset 073f550 in mainline for uspace/srv/fs/fat/fat_ops.c
- Timestamp:
- 2009-09-25T11:31:08Z (15 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 12bdc942
- Parents:
- 54e4479
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/fs/fat/fat_ops.c
r54e4479 r073f550 250 250 * Forward declarations of FAT libfs operations. 251 251 */ 252 static fs_node_t *fat_node_get(dev_handle_t, fs_index_t); 253 static void fat_node_put(fs_node_t *); 254 static fs_node_t *fat_create_node(dev_handle_t, int); 252 static int fat_root_get(fs_node_t **, dev_handle_t); 253 static int fat_match(fs_node_t **, fs_node_t *, const char *); 254 static int fat_node_get(fs_node_t **, dev_handle_t, fs_index_t); 255 static int fat_node_put(fs_node_t *); 256 static int fat_create_node(fs_node_t **, dev_handle_t, int); 255 257 static int fat_destroy_node(fs_node_t *); 256 258 static int fat_link(fs_node_t *, fs_node_t *, const char *); 257 259 static int fat_unlink(fs_node_t *, fs_node_t *, const char *); 258 static fs_node_t *fat_match(fs_node_t *, const char*);260 static int fat_has_children(bool *, fs_node_t *); 259 261 static fs_index_t fat_index_get(fs_node_t *); 260 262 static size_t fat_size_get(fs_node_t *); 261 263 static unsigned fat_lnkcnt_get(fs_node_t *); 262 static bool fat_has_children(fs_node_t *);263 static fs_node_t *fat_root_get(dev_handle_t);264 264 static char fat_plb_get_char(unsigned); 265 265 static bool fat_is_directory(fs_node_t *); … … 270 270 */ 271 271 272 /** Instantiate a FAT in-core node. */ 273 fs_node_t *fat_node_get(dev_handle_t dev_handle, fs_index_t index) 274 { 275 fat_node_t *nodep; 276 fat_idx_t *idxp; 277 278 idxp = fat_idx_get_by_index(dev_handle, index); 279 if (!idxp) 280 return NULL; 281 /* idxp->lock held */ 282 nodep = fat_node_get_core(idxp); 283 fibril_mutex_unlock(&idxp->lock); 284 return FS_NODE(nodep); 285 } 286 287 void fat_node_put(fs_node_t *fn) 288 { 289 fat_node_t *nodep = FAT_NODE(fn); 290 bool destroy = false; 291 292 fibril_mutex_lock(&nodep->lock); 293 if (!--nodep->refcnt) { 294 if (nodep->idx) { 295 fibril_mutex_lock(&ffn_mutex); 296 list_append(&nodep->ffn_link, &ffn_head); 297 fibril_mutex_unlock(&ffn_mutex); 298 } else { 299 /* 300 * The node does not have any index structure associated 301 * with itself. This can only mean that we are releasing 302 * the node after a failed attempt to allocate the index 303 * structure for it. 304 */ 305 destroy = true; 306 } 307 } 308 fibril_mutex_unlock(&nodep->lock); 309 if (destroy) { 310 free(nodep->bp); 311 free(nodep); 312 } 313 } 314 315 fs_node_t *fat_create_node(dev_handle_t dev_handle, int flags) 316 { 317 fat_idx_t *idxp; 318 fat_node_t *nodep; 319 fat_bs_t *bs; 320 fat_cluster_t mcl, lcl; 321 uint16_t bps; 322 int rc; 323 324 bs = block_bb_get(dev_handle); 325 bps = uint16_t_le2host(bs->bps); 326 if (flags & L_DIRECTORY) { 327 /* allocate a cluster */ 328 rc = fat_alloc_clusters(bs, dev_handle, 1, &mcl, &lcl); 329 if (rc != EOK) 330 return NULL; 331 } 332 333 nodep = fat_node_get_new(); 334 if (!nodep) { 335 (void) fat_free_clusters(bs, dev_handle, mcl); 336 return NULL; 337 } 338 idxp = fat_idx_get_new(dev_handle); 339 if (!idxp) { 340 (void) fat_free_clusters(bs, dev_handle, mcl); 341 fat_node_put(FS_NODE(nodep)); 342 return NULL; 343 } 344 /* idxp->lock held */ 345 if (flags & L_DIRECTORY) { 346 /* Populate the new cluster with unused dentries. */ 347 rc = fat_zero_cluster(bs, dev_handle, mcl); 348 assert(rc == EOK); 349 nodep->type = FAT_DIRECTORY; 350 nodep->firstc = mcl; 351 nodep->size = bps * bs->spc; 352 } else { 353 nodep->type = FAT_FILE; 354 nodep->firstc = FAT_CLST_RES0; 355 nodep->size = 0; 356 } 357 nodep->lnkcnt = 0; /* not linked anywhere */ 358 nodep->refcnt = 1; 359 nodep->dirty = true; 360 361 nodep->idx = idxp; 362 idxp->nodep = nodep; 363 364 fibril_mutex_unlock(&idxp->lock); 365 return FS_NODE(nodep); 366 } 367 368 int fat_destroy_node(fs_node_t *fn) 369 { 370 fat_node_t *nodep = FAT_NODE(fn); 371 fat_bs_t *bs; 372 int rc = EOK; 373 374 /* 375 * The node is not reachable from the file system. This means that the 376 * link count should be zero and that the index structure cannot be 377 * found in the position hash. Obviously, we don't need to lock the node 378 * nor its index structure. 379 */ 380 assert(nodep->lnkcnt == 0); 381 382 /* 383 * The node may not have any children. 384 */ 385 assert(fat_has_children(fn) == false); 386 387 bs = block_bb_get(nodep->idx->dev_handle); 388 if (nodep->firstc != FAT_CLST_RES0) { 389 assert(nodep->size); 390 /* Free all clusters allocated to the node. */ 391 rc = fat_free_clusters(bs, nodep->idx->dev_handle, 392 nodep->firstc); 393 } 394 395 fat_idx_destroy(nodep->idx); 396 free(nodep->bp); 397 free(nodep); 398 return rc; 399 } 400 401 int fat_link(fs_node_t *pfn, fs_node_t *cfn, const char *name) 402 { 403 fat_node_t *parentp = FAT_NODE(pfn); 404 fat_node_t *childp = FAT_NODE(cfn); 405 fat_dentry_t *d; 406 fat_bs_t *bs; 407 block_t *b; 408 unsigned i, j; 409 uint16_t bps; 410 unsigned dps; 411 unsigned blocks; 412 fat_cluster_t mcl, lcl; 413 int rc; 414 415 fibril_mutex_lock(&childp->lock); 416 if (childp->lnkcnt == 1) { 417 /* 418 * On FAT, we don't support multiple hard links. 419 */ 420 fibril_mutex_unlock(&childp->lock); 421 return EMLINK; 422 } 423 assert(childp->lnkcnt == 0); 424 fibril_mutex_unlock(&childp->lock); 425 426 if (!fat_dentry_name_verify(name)) { 427 /* 428 * Attempt to create unsupported name. 429 */ 430 return ENOTSUP; 431 } 432 433 /* 434 * Get us an unused parent node's dentry or grow the parent and allocate 435 * a new one. 436 */ 437 438 fibril_mutex_lock(&parentp->idx->lock); 439 bs = block_bb_get(parentp->idx->dev_handle); 440 bps = uint16_t_le2host(bs->bps); 441 dps = bps / sizeof(fat_dentry_t); 442 443 blocks = parentp->size / bps; 444 445 for (i = 0; i < blocks; i++) { 446 rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE); 447 if (rc != EOK) { 448 fibril_mutex_unlock(&parentp->idx->lock); 449 return rc; 450 } 451 for (j = 0; j < dps; j++) { 452 d = ((fat_dentry_t *)b->data) + j; 453 switch (fat_classify_dentry(d)) { 454 case FAT_DENTRY_SKIP: 455 case FAT_DENTRY_VALID: 456 /* skipping used and meta entries */ 457 continue; 458 case FAT_DENTRY_FREE: 459 case FAT_DENTRY_LAST: 460 /* found an empty slot */ 461 goto hit; 462 } 463 } 464 rc = block_put(b); 465 if (rc != EOK) { 466 fibril_mutex_unlock(&parentp->idx->lock); 467 return rc; 468 } 469 } 470 j = 0; 471 472 /* 473 * We need to grow the parent in order to create a new unused dentry. 474 */ 475 if (parentp->firstc == FAT_CLST_ROOT) { 476 /* Can't grow the root directory. */ 477 fibril_mutex_unlock(&parentp->idx->lock); 478 return ENOSPC; 479 } 480 rc = fat_alloc_clusters(bs, parentp->idx->dev_handle, 1, &mcl, &lcl); 481 if (rc != EOK) { 482 fibril_mutex_unlock(&parentp->idx->lock); 483 return rc; 484 } 485 rc = fat_zero_cluster(bs, parentp->idx->dev_handle, mcl); 486 if (rc != EOK) { 487 fibril_mutex_unlock(&parentp->idx->lock); 488 return rc; 489 } 490 rc = fat_append_clusters(bs, parentp, mcl); 491 if (rc != EOK) { 492 fibril_mutex_unlock(&parentp->idx->lock); 493 return rc; 494 } 495 parentp->size += bps * bs->spc; 496 parentp->dirty = true; /* need to sync node */ 497 rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE); 498 if (rc != EOK) { 499 fibril_mutex_unlock(&parentp->idx->lock); 500 return rc; 501 } 502 d = (fat_dentry_t *)b->data; 503 504 hit: 505 /* 506 * At this point we only establish the link between the parent and the 507 * child. The dentry, except of the name and the extension, will remain 508 * uninitialized until the corresponding node is synced. Thus the valid 509 * dentry data is kept in the child node structure. 510 */ 511 memset(d, 0, sizeof(fat_dentry_t)); 512 fat_dentry_name_set(d, name); 513 b->dirty = true; /* need to sync block */ 514 rc = block_put(b); 515 fibril_mutex_unlock(&parentp->idx->lock); 516 if (rc != EOK) 517 return rc; 518 519 fibril_mutex_lock(&childp->idx->lock); 520 521 /* 522 * If possible, create the Sub-directory Identifier Entry and the 523 * Sub-directory Parent Pointer Entry (i.e. "." and ".."). These entries 524 * are not mandatory according to Standard ECMA-107 and HelenOS VFS does 525 * not use them anyway, so this is rather a sign of our good will. 526 */ 527 rc = fat_block_get(&b, bs, childp, 0, BLOCK_FLAGS_NONE); 528 if (rc != EOK) { 529 /* 530 * Rather than returning an error, simply skip the creation of 531 * these two entries. 532 */ 533 goto skip_dots; 534 } 535 d = (fat_dentry_t *)b->data; 536 if (fat_classify_dentry(d) == FAT_DENTRY_LAST || 537 str_cmp(d->name, FAT_NAME_DOT) == 0) { 538 memset(d, 0, sizeof(fat_dentry_t)); 539 str_cpy(d->name, 8, FAT_NAME_DOT); 540 str_cpy(d->ext, 3, FAT_EXT_PAD); 541 d->attr = FAT_ATTR_SUBDIR; 542 d->firstc = host2uint16_t_le(childp->firstc); 543 /* TODO: initialize also the date/time members. */ 544 } 545 d++; 546 if (fat_classify_dentry(d) == FAT_DENTRY_LAST || 547 str_cmp(d->name, FAT_NAME_DOT_DOT) == 0) { 548 memset(d, 0, sizeof(fat_dentry_t)); 549 str_cpy(d->name, 8, FAT_NAME_DOT_DOT); 550 str_cpy(d->ext, 3, FAT_EXT_PAD); 551 d->attr = FAT_ATTR_SUBDIR; 552 d->firstc = (parentp->firstc == FAT_CLST_ROOT) ? 553 host2uint16_t_le(FAT_CLST_RES0) : 554 host2uint16_t_le(parentp->firstc); 555 /* TODO: initialize also the date/time members. */ 556 } 557 b->dirty = true; /* need to sync block */ 558 /* 559 * Ignore the return value as we would have fallen through on error 560 * anyway. 561 */ 562 (void) block_put(b); 563 skip_dots: 564 565 childp->idx->pfc = parentp->firstc; 566 childp->idx->pdi = i * dps + j; 567 fibril_mutex_unlock(&childp->idx->lock); 568 569 fibril_mutex_lock(&childp->lock); 570 childp->lnkcnt = 1; 571 childp->dirty = true; /* need to sync node */ 572 fibril_mutex_unlock(&childp->lock); 573 574 /* 575 * Hash in the index structure into the position hash. 576 */ 577 fat_idx_hashin(childp->idx); 578 579 return EOK; 580 } 581 582 int fat_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm) 583 { 584 fat_node_t *parentp = FAT_NODE(pfn); 585 fat_node_t *childp = FAT_NODE(cfn); 586 fat_bs_t *bs; 587 fat_dentry_t *d; 588 uint16_t bps; 589 block_t *b; 590 int rc; 591 592 if (!parentp) 593 return EBUSY; 594 595 if (fat_has_children(cfn)) 596 return ENOTEMPTY; 597 598 fibril_mutex_lock(&parentp->lock); 599 fibril_mutex_lock(&childp->lock); 600 assert(childp->lnkcnt == 1); 601 fibril_mutex_lock(&childp->idx->lock); 602 bs = block_bb_get(childp->idx->dev_handle); 603 bps = uint16_t_le2host(bs->bps); 604 605 rc = _fat_block_get(&b, bs, childp->idx->dev_handle, childp->idx->pfc, 606 (childp->idx->pdi * sizeof(fat_dentry_t)) / bps, 607 BLOCK_FLAGS_NONE); 608 if (rc != EOK) 609 goto error; 610 d = (fat_dentry_t *)b->data + 611 (childp->idx->pdi % (bps / sizeof(fat_dentry_t))); 612 /* mark the dentry as not-currently-used */ 613 d->name[0] = FAT_DENTRY_ERASED; 614 b->dirty = true; /* need to sync block */ 615 rc = block_put(b); 616 if (rc != EOK) 617 goto error; 618 619 /* remove the index structure from the position hash */ 620 fat_idx_hashout(childp->idx); 621 /* clear position information */ 622 childp->idx->pfc = FAT_CLST_RES0; 623 childp->idx->pdi = 0; 624 fibril_mutex_unlock(&childp->idx->lock); 625 childp->lnkcnt = 0; 626 childp->dirty = true; 627 fibril_mutex_unlock(&childp->lock); 628 fibril_mutex_unlock(&parentp->lock); 629 630 return EOK; 631 632 error: 633 fibril_mutex_unlock(&parentp->idx->lock); 634 fibril_mutex_unlock(&childp->lock); 635 fibril_mutex_unlock(&childp->idx->lock); 636 return rc; 637 } 638 639 fs_node_t *fat_match(fs_node_t *pfn, const char *component) 272 int fat_root_get(fs_node_t **rfn, dev_handle_t dev_handle) 273 { 274 return fat_node_get(rfn, dev_handle, 0); 275 } 276 277 int fat_match(fs_node_t **rfn, fs_node_t *pfn, const char *component) 640 278 { 641 279 fat_bs_t *bs; … … 657 295 for (i = 0; i < blocks; i++) { 658 296 rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE); 659 assert(rc == EOK); 297 if (rc != EOK) { 298 fibril_mutex_unlock(&parentp->idx->lock); 299 return rc; 300 } 660 301 for (j = 0; j < dps; j++) { 661 302 d = ((fat_dentry_t *)b->data) + j; … … 666 307 case FAT_DENTRY_LAST: 667 308 rc = block_put(b); 668 assert(rc == EOK); 309 /* expect EOK as b was not dirty */ 310 assert(rc == EOK); 669 311 fibril_mutex_unlock(&parentp->idx->lock); 670 return NULL; 312 *rfn = NULL; 313 return EOK; 671 314 default: 672 315 case FAT_DENTRY_VALID: … … 693 336 */ 694 337 rc = block_put(b); 695 assert(rc == EOK); 696 return NULL; 338 /* expect EOK as b was not dirty */ 339 assert(rc == EOK); 340 return ENOMEM; 697 341 } 698 342 nodep = fat_node_get_core(idx); 699 343 fibril_mutex_unlock(&idx->lock); 700 344 rc = block_put(b); 345 /* expect EOK as b was not dirty */ 701 346 assert(rc == EOK); 702 return FS_NODE(nodep); 347 *rfn = FS_NODE(nodep); 348 return EOK; 703 349 } 704 350 } 705 351 rc = block_put(b); 706 assert(rc == EOK); 352 assert(rc == EOK); /* expect EOK as b was not dirty */ 707 353 } 708 354 709 355 fibril_mutex_unlock(&parentp->idx->lock); 710 return NULL; 711 } 712 713 fs_index_t fat_index_get(fs_node_t *fn) 714 { 715 return FAT_NODE(fn)->idx->index; 716 } 717 718 size_t fat_size_get(fs_node_t *fn) 719 { 720 return FAT_NODE(fn)->size; 721 } 722 723 unsigned fat_lnkcnt_get(fs_node_t *fn) 724 { 725 return FAT_NODE(fn)->lnkcnt; 726 } 727 728 bool fat_has_children(fs_node_t *fn) 356 *rfn = NULL; 357 return EOK; 358 } 359 360 /** Instantiate a FAT in-core node. */ 361 int fat_node_get(fs_node_t **rfn, dev_handle_t dev_handle, fs_index_t index) 362 { 363 fat_node_t *nodep; 364 fat_idx_t *idxp; 365 366 idxp = fat_idx_get_by_index(dev_handle, index); 367 if (!idxp) { 368 *rfn = NULL; 369 return EOK; 370 } 371 /* idxp->lock held */ 372 nodep = fat_node_get_core(idxp); 373 fibril_mutex_unlock(&idxp->lock); 374 *rfn = FS_NODE(nodep); 375 return EOK; 376 } 377 378 int fat_node_put(fs_node_t *fn) 379 { 380 fat_node_t *nodep = FAT_NODE(fn); 381 bool destroy = false; 382 383 fibril_mutex_lock(&nodep->lock); 384 if (!--nodep->refcnt) { 385 if (nodep->idx) { 386 fibril_mutex_lock(&ffn_mutex); 387 list_append(&nodep->ffn_link, &ffn_head); 388 fibril_mutex_unlock(&ffn_mutex); 389 } else { 390 /* 391 * The node does not have any index structure associated 392 * with itself. This can only mean that we are releasing 393 * the node after a failed attempt to allocate the index 394 * structure for it. 395 */ 396 destroy = true; 397 } 398 } 399 fibril_mutex_unlock(&nodep->lock); 400 if (destroy) { 401 free(nodep->bp); 402 free(nodep); 403 } 404 return EOK; 405 } 406 407 int fat_create_node(fs_node_t **rfn, dev_handle_t dev_handle, int flags) 408 { 409 fat_idx_t *idxp; 410 fat_node_t *nodep; 411 fat_bs_t *bs; 412 fat_cluster_t mcl, lcl; 413 uint16_t bps; 414 int rc; 415 416 bs = block_bb_get(dev_handle); 417 bps = uint16_t_le2host(bs->bps); 418 if (flags & L_DIRECTORY) { 419 /* allocate a cluster */ 420 rc = fat_alloc_clusters(bs, dev_handle, 1, &mcl, &lcl); 421 if (rc != EOK) 422 return rc; 423 /* populate the new cluster with unused dentries */ 424 rc = fat_zero_cluster(bs, dev_handle, mcl); 425 if (rc != EOK) { 426 (void) fat_free_clusters(bs, dev_handle, mcl); 427 return rc; 428 } 429 } 430 431 nodep = fat_node_get_new(); 432 if (!nodep) { 433 (void) fat_free_clusters(bs, dev_handle, mcl); 434 return ENOMEM; /* FIXME: determine the true error code */ 435 } 436 idxp = fat_idx_get_new(dev_handle); 437 if (!idxp) { 438 (void) fat_free_clusters(bs, dev_handle, mcl); 439 (void) fat_node_put(FS_NODE(nodep)); 440 return ENOMEM; /* FIXME: determine the true error code */ 441 } 442 /* idxp->lock held */ 443 if (flags & L_DIRECTORY) { 444 nodep->type = FAT_DIRECTORY; 445 nodep->firstc = mcl; 446 nodep->size = bps * bs->spc; 447 } else { 448 nodep->type = FAT_FILE; 449 nodep->firstc = FAT_CLST_RES0; 450 nodep->size = 0; 451 } 452 nodep->lnkcnt = 0; /* not linked anywhere */ 453 nodep->refcnt = 1; 454 nodep->dirty = true; 455 456 nodep->idx = idxp; 457 idxp->nodep = nodep; 458 459 fibril_mutex_unlock(&idxp->lock); 460 *rfn = FS_NODE(nodep); 461 return EOK; 462 } 463 464 int fat_destroy_node(fs_node_t *fn) 465 { 466 fat_node_t *nodep = FAT_NODE(fn); 467 fat_bs_t *bs; 468 bool has_children; 469 int rc; 470 471 /* 472 * The node is not reachable from the file system. This means that the 473 * link count should be zero and that the index structure cannot be 474 * found in the position hash. Obviously, we don't need to lock the node 475 * nor its index structure. 476 */ 477 assert(nodep->lnkcnt == 0); 478 479 /* 480 * The node may not have any children. 481 */ 482 rc = fat_has_children(&has_children, fn); 483 if (rc != EOK) 484 return rc; 485 assert(!has_children); 486 487 bs = block_bb_get(nodep->idx->dev_handle); 488 if (nodep->firstc != FAT_CLST_RES0) { 489 assert(nodep->size); 490 /* Free all clusters allocated to the node. */ 491 rc = fat_free_clusters(bs, nodep->idx->dev_handle, 492 nodep->firstc); 493 } 494 495 fat_idx_destroy(nodep->idx); 496 free(nodep->bp); 497 free(nodep); 498 return rc; 499 } 500 501 int fat_link(fs_node_t *pfn, fs_node_t *cfn, const char *name) 502 { 503 fat_node_t *parentp = FAT_NODE(pfn); 504 fat_node_t *childp = FAT_NODE(cfn); 505 fat_dentry_t *d; 506 fat_bs_t *bs; 507 block_t *b; 508 unsigned i, j; 509 uint16_t bps; 510 unsigned dps; 511 unsigned blocks; 512 fat_cluster_t mcl, lcl; 513 int rc; 514 515 fibril_mutex_lock(&childp->lock); 516 if (childp->lnkcnt == 1) { 517 /* 518 * On FAT, we don't support multiple hard links. 519 */ 520 fibril_mutex_unlock(&childp->lock); 521 return EMLINK; 522 } 523 assert(childp->lnkcnt == 0); 524 fibril_mutex_unlock(&childp->lock); 525 526 if (!fat_dentry_name_verify(name)) { 527 /* 528 * Attempt to create unsupported name. 529 */ 530 return ENOTSUP; 531 } 532 533 /* 534 * Get us an unused parent node's dentry or grow the parent and allocate 535 * a new one. 536 */ 537 538 fibril_mutex_lock(&parentp->idx->lock); 539 bs = block_bb_get(parentp->idx->dev_handle); 540 bps = uint16_t_le2host(bs->bps); 541 dps = bps / sizeof(fat_dentry_t); 542 543 blocks = parentp->size / bps; 544 545 for (i = 0; i < blocks; i++) { 546 rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE); 547 if (rc != EOK) { 548 fibril_mutex_unlock(&parentp->idx->lock); 549 return rc; 550 } 551 for (j = 0; j < dps; j++) { 552 d = ((fat_dentry_t *)b->data) + j; 553 switch (fat_classify_dentry(d)) { 554 case FAT_DENTRY_SKIP: 555 case FAT_DENTRY_VALID: 556 /* skipping used and meta entries */ 557 continue; 558 case FAT_DENTRY_FREE: 559 case FAT_DENTRY_LAST: 560 /* found an empty slot */ 561 goto hit; 562 } 563 } 564 rc = block_put(b); 565 if (rc != EOK) { 566 fibril_mutex_unlock(&parentp->idx->lock); 567 return rc; 568 } 569 } 570 j = 0; 571 572 /* 573 * We need to grow the parent in order to create a new unused dentry. 574 */ 575 if (parentp->firstc == FAT_CLST_ROOT) { 576 /* Can't grow the root directory. */ 577 fibril_mutex_unlock(&parentp->idx->lock); 578 return ENOSPC; 579 } 580 rc = fat_alloc_clusters(bs, parentp->idx->dev_handle, 1, &mcl, &lcl); 581 if (rc != EOK) { 582 fibril_mutex_unlock(&parentp->idx->lock); 583 return rc; 584 } 585 rc = fat_zero_cluster(bs, parentp->idx->dev_handle, mcl); 586 if (rc != EOK) { 587 (void) fat_free_clusters(bs, parentp->idx->dev_handle, mcl); 588 fibril_mutex_unlock(&parentp->idx->lock); 589 return rc; 590 } 591 rc = fat_append_clusters(bs, parentp, mcl); 592 if (rc != EOK) { 593 (void) fat_free_clusters(bs, parentp->idx->dev_handle, mcl); 594 fibril_mutex_unlock(&parentp->idx->lock); 595 return rc; 596 } 597 parentp->size += bps * bs->spc; 598 parentp->dirty = true; /* need to sync node */ 599 rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE); 600 if (rc != EOK) { 601 fibril_mutex_unlock(&parentp->idx->lock); 602 return rc; 603 } 604 d = (fat_dentry_t *)b->data; 605 606 hit: 607 /* 608 * At this point we only establish the link between the parent and the 609 * child. The dentry, except of the name and the extension, will remain 610 * uninitialized until the corresponding node is synced. Thus the valid 611 * dentry data is kept in the child node structure. 612 */ 613 memset(d, 0, sizeof(fat_dentry_t)); 614 fat_dentry_name_set(d, name); 615 b->dirty = true; /* need to sync block */ 616 rc = block_put(b); 617 fibril_mutex_unlock(&parentp->idx->lock); 618 if (rc != EOK) 619 return rc; 620 621 fibril_mutex_lock(&childp->idx->lock); 622 623 /* 624 * If possible, create the Sub-directory Identifier Entry and the 625 * Sub-directory Parent Pointer Entry (i.e. "." and ".."). These entries 626 * are not mandatory according to Standard ECMA-107 and HelenOS VFS does 627 * not use them anyway, so this is rather a sign of our good will. 628 */ 629 rc = fat_block_get(&b, bs, childp, 0, BLOCK_FLAGS_NONE); 630 if (rc != EOK) { 631 /* 632 * Rather than returning an error, simply skip the creation of 633 * these two entries. 634 */ 635 goto skip_dots; 636 } 637 d = (fat_dentry_t *)b->data; 638 if (fat_classify_dentry(d) == FAT_DENTRY_LAST || 639 str_cmp(d->name, FAT_NAME_DOT) == 0) { 640 memset(d, 0, sizeof(fat_dentry_t)); 641 str_cpy(d->name, 8, FAT_NAME_DOT); 642 str_cpy(d->ext, 3, FAT_EXT_PAD); 643 d->attr = FAT_ATTR_SUBDIR; 644 d->firstc = host2uint16_t_le(childp->firstc); 645 /* TODO: initialize also the date/time members. */ 646 } 647 d++; 648 if (fat_classify_dentry(d) == FAT_DENTRY_LAST || 649 str_cmp(d->name, FAT_NAME_DOT_DOT) == 0) { 650 memset(d, 0, sizeof(fat_dentry_t)); 651 str_cpy(d->name, 8, FAT_NAME_DOT_DOT); 652 str_cpy(d->ext, 3, FAT_EXT_PAD); 653 d->attr = FAT_ATTR_SUBDIR; 654 d->firstc = (parentp->firstc == FAT_CLST_ROOT) ? 655 host2uint16_t_le(FAT_CLST_RES0) : 656 host2uint16_t_le(parentp->firstc); 657 /* TODO: initialize also the date/time members. */ 658 } 659 b->dirty = true; /* need to sync block */ 660 /* 661 * Ignore the return value as we would have fallen through on error 662 * anyway. 663 */ 664 (void) block_put(b); 665 skip_dots: 666 667 childp->idx->pfc = parentp->firstc; 668 childp->idx->pdi = i * dps + j; 669 fibril_mutex_unlock(&childp->idx->lock); 670 671 fibril_mutex_lock(&childp->lock); 672 childp->lnkcnt = 1; 673 childp->dirty = true; /* need to sync node */ 674 fibril_mutex_unlock(&childp->lock); 675 676 /* 677 * Hash in the index structure into the position hash. 678 */ 679 fat_idx_hashin(childp->idx); 680 681 return EOK; 682 } 683 684 int fat_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm) 685 { 686 fat_node_t *parentp = FAT_NODE(pfn); 687 fat_node_t *childp = FAT_NODE(cfn); 688 fat_bs_t *bs; 689 fat_dentry_t *d; 690 uint16_t bps; 691 block_t *b; 692 bool has_children; 693 int rc; 694 695 if (!parentp) 696 return EBUSY; 697 698 rc = fat_has_children(&has_children, cfn); 699 if (rc != EOK) 700 return rc; 701 if (has_children) 702 return ENOTEMPTY; 703 704 fibril_mutex_lock(&parentp->lock); 705 fibril_mutex_lock(&childp->lock); 706 assert(childp->lnkcnt == 1); 707 fibril_mutex_lock(&childp->idx->lock); 708 bs = block_bb_get(childp->idx->dev_handle); 709 bps = uint16_t_le2host(bs->bps); 710 711 rc = _fat_block_get(&b, bs, childp->idx->dev_handle, childp->idx->pfc, 712 (childp->idx->pdi * sizeof(fat_dentry_t)) / bps, 713 BLOCK_FLAGS_NONE); 714 if (rc != EOK) 715 goto error; 716 d = (fat_dentry_t *)b->data + 717 (childp->idx->pdi % (bps / sizeof(fat_dentry_t))); 718 /* mark the dentry as not-currently-used */ 719 d->name[0] = FAT_DENTRY_ERASED; 720 b->dirty = true; /* need to sync block */ 721 rc = block_put(b); 722 if (rc != EOK) 723 goto error; 724 725 /* remove the index structure from the position hash */ 726 fat_idx_hashout(childp->idx); 727 /* clear position information */ 728 childp->idx->pfc = FAT_CLST_RES0; 729 childp->idx->pdi = 0; 730 fibril_mutex_unlock(&childp->idx->lock); 731 childp->lnkcnt = 0; 732 childp->dirty = true; 733 fibril_mutex_unlock(&childp->lock); 734 fibril_mutex_unlock(&parentp->lock); 735 736 return EOK; 737 738 error: 739 fibril_mutex_unlock(&parentp->idx->lock); 740 fibril_mutex_unlock(&childp->lock); 741 fibril_mutex_unlock(&childp->idx->lock); 742 return rc; 743 } 744 745 int fat_has_children(bool *has_children, fs_node_t *fn) 729 746 { 730 747 fat_bs_t *bs; … … 737 754 int rc; 738 755 739 if (nodep->type != FAT_DIRECTORY) 740 return false; 756 if (nodep->type != FAT_DIRECTORY) { 757 *has_children = false; 758 return EOK; 759 } 741 760 742 761 fibril_mutex_lock(&nodep->idx->lock); … … 751 770 752 771 rc = fat_block_get(&b, bs, nodep, i, BLOCK_FLAGS_NONE); 753 assert(rc == EOK); 772 if (rc != EOK) { 773 fibril_mutex_unlock(&nodep->idx->lock); 774 return rc; 775 } 754 776 for (j = 0; j < dps; j++) { 755 777 d = ((fat_dentry_t *)b->data) + j; … … 760 782 case FAT_DENTRY_LAST: 761 783 rc = block_put(b); 784 /* expect EOK as b was not dirty */ 762 785 assert(rc == EOK); 763 786 fibril_mutex_unlock(&nodep->idx->lock); 764 return false; 787 *has_children = false; 788 return EOK; 765 789 default: 766 790 case FAT_DENTRY_VALID: 767 791 rc = block_put(b); 792 /* expect EOK as b was not dirty */ 768 793 assert(rc == EOK); 769 794 fibril_mutex_unlock(&nodep->idx->lock); 770 return true; 795 *has_children = true; 796 return EOK; 771 797 } 772 798 rc = block_put(b); 799 /* expect EOK as b was not dirty */ 773 800 assert(rc == EOK); 774 801 fibril_mutex_unlock(&nodep->idx->lock); 775 return true; 802 *has_children = true; 803 return EOK; 776 804 } 777 805 rc = block_put(b); 778 assert(rc == EOK); 806 assert(rc == EOK); /* expect EOK as b was not dirty */ 779 807 } 780 808 781 809 fibril_mutex_unlock(&nodep->idx->lock); 782 return false; 783 } 784 785 fs_node_t *fat_root_get(dev_handle_t dev_handle) 786 { 787 return fat_node_get(dev_handle, 0); 810 *has_children = false; 811 return EOK; 812 } 813 814 815 fs_index_t fat_index_get(fs_node_t *fn) 816 { 817 return FAT_NODE(fn)->idx->index; 818 } 819 820 size_t fat_size_get(fs_node_t *fn) 821 { 822 return FAT_NODE(fn)->size; 823 } 824 825 unsigned fat_lnkcnt_get(fs_node_t *fn) 826 { 827 return FAT_NODE(fn)->lnkcnt; 788 828 } 789 829 … … 805 845 /** libfs operations */ 806 846 libfs_ops_t fat_libfs_ops = { 847 .root_get = fat_root_get, 807 848 .match = fat_match, 808 849 .node_get = fat_node_get, … … 812 853 .link = fat_link, 813 854 .unlink = fat_unlink, 855 .has_children = fat_has_children, 814 856 .index_get = fat_index_get, 815 857 .size_get = fat_size_get, 816 858 .lnkcnt_get = fat_lnkcnt_get, 817 .has_children = fat_has_children,818 .root_get = fat_root_get,819 859 .plb_get_char = fat_plb_get_char, 820 860 .is_directory = fat_is_directory, … … 967 1007 fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request); 968 1008 off_t pos = (off_t)IPC_GET_ARG3(*request); 969 fs_node_t *fn = fat_node_get(dev_handle, index);1009 fs_node_t *fn; 970 1010 fat_node_t *nodep; 971 1011 fat_bs_t *bs; … … 975 1015 int rc; 976 1016 1017 rc = fat_node_get(&fn, dev_handle, index); 1018 if (rc != EOK) { 1019 ipc_answer_0(rid, rc); 1020 return; 1021 } 977 1022 if (!fn) { 978 1023 ipc_answer_0(rid, ENOENT); … … 1052 1097 case FAT_DENTRY_VALID: 1053 1098 fat_dentry_name_get(d, name); 1054 rc = =block_put(b);1099 rc = block_put(b); 1055 1100 assert(rc == EOK); 1056 1101 goto hit; … … 1080 1125 fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request); 1081 1126 off_t pos = (off_t)IPC_GET_ARG3(*request); 1082 fs_node_t *fn = fat_node_get(dev_handle, index);1127 fs_node_t *fn; 1083 1128 fat_node_t *nodep; 1084 1129 fat_bs_t *bs; … … 1092 1137 int rc; 1093 1138 1139 rc = fat_node_get(&fn, dev_handle, index); 1140 if (rc != EOK) { 1141 ipc_answer_0(rid, rc); 1142 return; 1143 } 1094 1144 if (!fn) { 1095 1145 ipc_answer_0(rid, ENOENT); … … 1196 1246 fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request); 1197 1247 size_t size = (off_t)IPC_GET_ARG3(*request); 1198 fs_node_t *fn = fat_node_get(dev_handle, index);1248 fs_node_t *fn; 1199 1249 fat_node_t *nodep; 1200 1250 fat_bs_t *bs; … … 1204 1254 int rc; 1205 1255 1256 rc = fat_node_get(&fn, dev_handle, index); 1257 if (rc != EOK) { 1258 ipc_answer_0(rid, rc); 1259 return; 1260 } 1206 1261 if (!fn) { 1207 1262 ipc_answer_0(rid, ENOENT); … … 1267 1322 dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request); 1268 1323 fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request); 1324 fs_node_t *fn; 1269 1325 int rc; 1270 1326 1271 fs_node_t *fn = fat_node_get(dev_handle, index); 1327 rc = fat_node_get(&fn, dev_handle, index); 1328 if (rc != EOK) { 1329 ipc_answer_0(rid, rc); 1330 return; 1331 } 1272 1332 if (!fn) { 1273 1333 ipc_answer_0(rid, ENOENT);
Note:
See TracChangeset
for help on using the changeset viewer.