00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00038 #include "fat.h"
00039 #include "fat_dentry.h"
00040 #include "fat_fat.h"
00041 #include "../../vfs/vfs.h"
00042 #include <libfs.h>
00043 #include <libblock.h>
00044 #include <ipc/services.h>
00045 #include <ipc/devmap.h>
00046 #include <macros.h>
00047 #include <async.h>
00048 #include <errno.h>
00049 #include <str.h>
00050 #include <byteorder.h>
00051 #include <adt/hash_table.h>
00052 #include <adt/list.h>
00053 #include <assert.h>
00054 #include <fibril_synch.h>
00055 #include <sys/mman.h>
00056 #include <align.h>
00057 #include <malloc.h>
00058
00059 #define FAT_NODE(node) ((node) ? (fat_node_t *) (node)->data : NULL)
00060 #define FS_NODE(node) ((node) ? (node)->bp : NULL)
00061
00062 #define DPS(bs) (BPS((bs)) / sizeof(fat_dentry_t))
00063 #define BPC(bs) (BPS((bs)) * SPC((bs)))
00064
00066 static FIBRIL_MUTEX_INITIALIZE(ffn_mutex);
00067
00069 static LIST_INITIALIZE(ffn_head);
00070
00071
00072
00073
00074 static int fat_root_get(fs_node_t **, devmap_handle_t);
00075 static int fat_match(fs_node_t **, fs_node_t *, const char *);
00076 static int fat_node_get(fs_node_t **, devmap_handle_t, fs_index_t);
00077 static int fat_node_open(fs_node_t *);
00078 static int fat_node_put(fs_node_t *);
00079 static int fat_create_node(fs_node_t **, devmap_handle_t, int);
00080 static int fat_destroy_node(fs_node_t *);
00081 static int fat_link(fs_node_t *, fs_node_t *, const char *);
00082 static int fat_unlink(fs_node_t *, fs_node_t *, const char *);
00083 static int fat_has_children(bool *, fs_node_t *);
00084 static fs_index_t fat_index_get(fs_node_t *);
00085 static aoff64_t fat_size_get(fs_node_t *);
00086 static unsigned fat_lnkcnt_get(fs_node_t *);
00087 static char fat_plb_get_char(unsigned);
00088 static bool fat_is_directory(fs_node_t *);
00089 static bool fat_is_file(fs_node_t *node);
00090 static devmap_handle_t fat_device_get(fs_node_t *node);
00091
00092
00093
00094
00095 static void fat_node_initialize(fat_node_t *node)
00096 {
00097 fibril_mutex_initialize(&node->lock);
00098 node->bp = NULL;
00099 node->idx = NULL;
00100 node->type = 0;
00101 link_initialize(&node->ffn_link);
00102 node->size = 0;
00103 node->lnkcnt = 0;
00104 node->refcnt = 0;
00105 node->dirty = false;
00106 node->lastc_cached_valid = false;
00107 node->lastc_cached_value = FAT_CLST_LAST1;
00108 node->currc_cached_valid = false;
00109 node->currc_cached_bn = 0;
00110 node->currc_cached_value = FAT_CLST_LAST1;
00111 }
00112
00113 static int fat_node_sync(fat_node_t *node)
00114 {
00115 block_t *b;
00116 fat_bs_t *bs;
00117 fat_dentry_t *d;
00118 int rc;
00119
00120 assert(node->dirty);
00121
00122 bs = block_bb_get(node->idx->devmap_handle);
00123
00124
00125 rc = _fat_block_get(&b, bs, node->idx->devmap_handle, node->idx->pfc,
00126 NULL, (node->idx->pdi * sizeof(fat_dentry_t)) / BPS(bs),
00127 BLOCK_FLAGS_NONE);
00128 if (rc != EOK)
00129 return rc;
00130
00131 d = ((fat_dentry_t *)b->data) + (node->idx->pdi % DPS(bs));
00132
00133 d->firstc = host2uint16_t_le(node->firstc);
00134 if (node->type == FAT_FILE) {
00135 d->size = host2uint32_t_le(node->size);
00136 } else if (node->type == FAT_DIRECTORY) {
00137 d->attr = FAT_ATTR_SUBDIR;
00138 }
00139
00140
00141
00142 b->dirty = true;
00143 rc = block_put(b);
00144 return rc;
00145 }
00146
00147 static int fat_node_fini_by_devmap_handle(devmap_handle_t devmap_handle)
00148 {
00149 link_t *lnk;
00150 fat_node_t *nodep;
00151 int rc;
00152
00153
00154
00155
00156
00157
00158
00159 restart:
00160 fibril_mutex_lock(&ffn_mutex);
00161 for (lnk = ffn_head.next; lnk != &ffn_head; lnk = lnk->next) {
00162 nodep = list_get_instance(lnk, fat_node_t, ffn_link);
00163 if (!fibril_mutex_trylock(&nodep->lock)) {
00164 fibril_mutex_unlock(&ffn_mutex);
00165 goto restart;
00166 }
00167 if (!fibril_mutex_trylock(&nodep->idx->lock)) {
00168 fibril_mutex_unlock(&nodep->lock);
00169 fibril_mutex_unlock(&ffn_mutex);
00170 goto restart;
00171 }
00172 if (nodep->idx->devmap_handle != devmap_handle) {
00173 fibril_mutex_unlock(&nodep->idx->lock);
00174 fibril_mutex_unlock(&nodep->lock);
00175 continue;
00176 }
00177
00178 list_remove(&nodep->ffn_link);
00179 fibril_mutex_unlock(&ffn_mutex);
00180
00181
00182
00183
00184
00185
00186 fibril_mutex_unlock(&nodep->idx->lock);
00187 fibril_mutex_unlock(&nodep->lock);
00188
00189 if (nodep->dirty) {
00190 rc = fat_node_sync(nodep);
00191 if (rc != EOK)
00192 return rc;
00193 }
00194 nodep->idx->nodep = NULL;
00195 free(nodep->bp);
00196 free(nodep);
00197
00198
00199 goto restart;
00200 }
00201 fibril_mutex_unlock(&ffn_mutex);
00202
00203 return EOK;
00204 }
00205
00206 static int fat_node_get_new(fat_node_t **nodepp)
00207 {
00208 fs_node_t *fn;
00209 fat_node_t *nodep;
00210 int rc;
00211
00212 fibril_mutex_lock(&ffn_mutex);
00213 if (!list_empty(&ffn_head)) {
00214
00215 fat_idx_t *idxp_tmp;
00216 nodep = list_get_instance(ffn_head.next, fat_node_t, ffn_link);
00217 if (!fibril_mutex_trylock(&nodep->lock))
00218 goto skip_cache;
00219 idxp_tmp = nodep->idx;
00220 if (!fibril_mutex_trylock(&idxp_tmp->lock)) {
00221 fibril_mutex_unlock(&nodep->lock);
00222 goto skip_cache;
00223 }
00224 list_remove(&nodep->ffn_link);
00225 fibril_mutex_unlock(&ffn_mutex);
00226 if (nodep->dirty) {
00227 rc = fat_node_sync(nodep);
00228 if (rc != EOK) {
00229 idxp_tmp->nodep = NULL;
00230 fibril_mutex_unlock(&nodep->lock);
00231 fibril_mutex_unlock(&idxp_tmp->lock);
00232 free(nodep->bp);
00233 free(nodep);
00234 return rc;
00235 }
00236 }
00237 idxp_tmp->nodep = NULL;
00238 fibril_mutex_unlock(&nodep->lock);
00239 fibril_mutex_unlock(&idxp_tmp->lock);
00240 fn = FS_NODE(nodep);
00241 } else {
00242 skip_cache:
00243
00244 fibril_mutex_unlock(&ffn_mutex);
00245 fn = (fs_node_t *)malloc(sizeof(fs_node_t));
00246 if (!fn)
00247 return ENOMEM;
00248 nodep = (fat_node_t *)malloc(sizeof(fat_node_t));
00249 if (!nodep) {
00250 free(fn);
00251 return ENOMEM;
00252 }
00253 }
00254 fat_node_initialize(nodep);
00255 fs_node_initialize(fn);
00256 fn->data = nodep;
00257 nodep->bp = fn;
00258
00259 *nodepp = nodep;
00260 return EOK;
00261 }
00262
00267 static int fat_node_get_core(fat_node_t **nodepp, fat_idx_t *idxp)
00268 {
00269 block_t *b;
00270 fat_bs_t *bs;
00271 fat_dentry_t *d;
00272 fat_node_t *nodep = NULL;
00273 int rc;
00274
00275 if (idxp->nodep) {
00276
00277
00278
00279
00280 fibril_mutex_lock(&idxp->nodep->lock);
00281 if (!idxp->nodep->refcnt++) {
00282 fibril_mutex_lock(&ffn_mutex);
00283 list_remove(&idxp->nodep->ffn_link);
00284 fibril_mutex_unlock(&ffn_mutex);
00285 }
00286 fibril_mutex_unlock(&idxp->nodep->lock);
00287 *nodepp = idxp->nodep;
00288 return EOK;
00289 }
00290
00291
00292
00293
00294
00295 assert(idxp->pfc);
00296
00297 rc = fat_node_get_new(&nodep);
00298 if (rc != EOK)
00299 return rc;
00300
00301 bs = block_bb_get(idxp->devmap_handle);
00302
00303
00304 rc = _fat_block_get(&b, bs, idxp->devmap_handle, idxp->pfc, NULL,
00305 (idxp->pdi * sizeof(fat_dentry_t)) / BPS(bs), BLOCK_FLAGS_NONE);
00306 if (rc != EOK) {
00307 (void) fat_node_put(FS_NODE(nodep));
00308 return rc;
00309 }
00310
00311 d = ((fat_dentry_t *)b->data) + (idxp->pdi % DPS(bs));
00312 if (d->attr & FAT_ATTR_SUBDIR) {
00313
00314
00315
00316
00317
00318 nodep->type = FAT_DIRECTORY;
00319
00320
00321
00322
00323
00324 uint16_t clusters;
00325 rc = fat_clusters_get(&clusters, bs, idxp->devmap_handle,
00326 uint16_t_le2host(d->firstc));
00327 if (rc != EOK) {
00328 (void) block_put(b);
00329 (void) fat_node_put(FS_NODE(nodep));
00330 return rc;
00331 }
00332 nodep->size = BPS(bs) * SPC(bs) * clusters;
00333 } else {
00334 nodep->type = FAT_FILE;
00335 nodep->size = uint32_t_le2host(d->size);
00336 }
00337 nodep->firstc = uint16_t_le2host(d->firstc);
00338 nodep->lnkcnt = 1;
00339 nodep->refcnt = 1;
00340
00341 rc = block_put(b);
00342 if (rc != EOK) {
00343 (void) fat_node_put(FS_NODE(nodep));
00344 return rc;
00345 }
00346
00347
00348 nodep->idx = idxp;
00349 idxp->nodep = nodep;
00350
00351 *nodepp = nodep;
00352 return EOK;
00353 }
00354
00355
00356
00357
00358
00359 int fat_root_get(fs_node_t **rfn, devmap_handle_t devmap_handle)
00360 {
00361 return fat_node_get(rfn, devmap_handle, 0);
00362 }
00363
00364 int fat_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
00365 {
00366 fat_bs_t *bs;
00367 fat_node_t *parentp = FAT_NODE(pfn);
00368 char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
00369 unsigned i, j;
00370 unsigned blocks;
00371 fat_dentry_t *d;
00372 devmap_handle_t devmap_handle;
00373 block_t *b;
00374 int rc;
00375
00376 fibril_mutex_lock(&parentp->idx->lock);
00377 devmap_handle = parentp->idx->devmap_handle;
00378 fibril_mutex_unlock(&parentp->idx->lock);
00379
00380 bs = block_bb_get(devmap_handle);
00381 blocks = parentp->size / BPS(bs);
00382 for (i = 0; i < blocks; i++) {
00383 rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE);
00384 if (rc != EOK)
00385 return rc;
00386 for (j = 0; j < DPS(bs); j++) {
00387 d = ((fat_dentry_t *)b->data) + j;
00388 switch (fat_classify_dentry(d)) {
00389 case FAT_DENTRY_SKIP:
00390 case FAT_DENTRY_FREE:
00391 continue;
00392 case FAT_DENTRY_LAST:
00393
00394 rc = block_put(b);
00395 *rfn = NULL;
00396 return rc;
00397 default:
00398 case FAT_DENTRY_VALID:
00399 fat_dentry_name_get(d, name);
00400 break;
00401 }
00402 if (fat_dentry_namecmp(name, component) == 0) {
00403
00404 fat_node_t *nodep;
00405 fat_idx_t *idx = fat_idx_get_by_pos(devmap_handle,
00406 parentp->firstc, i * DPS(bs) + j);
00407 if (!idx) {
00408
00409
00410
00411
00412 rc = block_put(b);
00413 return (rc == EOK) ? ENOMEM : rc;
00414 }
00415 rc = fat_node_get_core(&nodep, idx);
00416 fibril_mutex_unlock(&idx->lock);
00417 if (rc != EOK) {
00418 (void) block_put(b);
00419 return rc;
00420 }
00421 *rfn = FS_NODE(nodep);
00422 rc = block_put(b);
00423 if (rc != EOK)
00424 (void) fat_node_put(*rfn);
00425 return rc;
00426 }
00427 }
00428 rc = block_put(b);
00429 if (rc != EOK)
00430 return rc;
00431 }
00432
00433 *rfn = NULL;
00434 return EOK;
00435 }
00436
00438 int fat_node_get(fs_node_t **rfn, devmap_handle_t devmap_handle, fs_index_t index)
00439 {
00440 fat_node_t *nodep;
00441 fat_idx_t *idxp;
00442 int rc;
00443
00444 idxp = fat_idx_get_by_index(devmap_handle, index);
00445 if (!idxp) {
00446 *rfn = NULL;
00447 return EOK;
00448 }
00449
00450 rc = fat_node_get_core(&nodep, idxp);
00451 fibril_mutex_unlock(&idxp->lock);
00452 if (rc == EOK)
00453 *rfn = FS_NODE(nodep);
00454 return rc;
00455 }
00456
00457 int fat_node_open(fs_node_t *fn)
00458 {
00459
00460
00461
00462
00463 return EOK;
00464 }
00465
00466 int fat_node_put(fs_node_t *fn)
00467 {
00468 fat_node_t *nodep = FAT_NODE(fn);
00469 bool destroy = false;
00470
00471 fibril_mutex_lock(&nodep->lock);
00472 if (!--nodep->refcnt) {
00473 if (nodep->idx) {
00474 fibril_mutex_lock(&ffn_mutex);
00475 list_append(&nodep->ffn_link, &ffn_head);
00476 fibril_mutex_unlock(&ffn_mutex);
00477 } else {
00478
00479
00480
00481
00482
00483
00484 destroy = true;
00485 }
00486 }
00487 fibril_mutex_unlock(&nodep->lock);
00488 if (destroy) {
00489 free(nodep->bp);
00490 free(nodep);
00491 }
00492 return EOK;
00493 }
00494
00495 int fat_create_node(fs_node_t **rfn, devmap_handle_t devmap_handle, int flags)
00496 {
00497 fat_idx_t *idxp;
00498 fat_node_t *nodep;
00499 fat_bs_t *bs;
00500 fat_cluster_t mcl, lcl;
00501 int rc;
00502
00503 bs = block_bb_get(devmap_handle);
00504 if (flags & L_DIRECTORY) {
00505
00506 rc = fat_alloc_clusters(bs, devmap_handle, 1, &mcl, &lcl);
00507 if (rc != EOK)
00508 return rc;
00509
00510 rc = fat_zero_cluster(bs, devmap_handle, mcl);
00511 if (rc != EOK) {
00512 (void) fat_free_clusters(bs, devmap_handle, mcl);
00513 return rc;
00514 }
00515 }
00516
00517 rc = fat_node_get_new(&nodep);
00518 if (rc != EOK) {
00519 (void) fat_free_clusters(bs, devmap_handle, mcl);
00520 return rc;
00521 }
00522 rc = fat_idx_get_new(&idxp, devmap_handle);
00523 if (rc != EOK) {
00524 (void) fat_free_clusters(bs, devmap_handle, mcl);
00525 (void) fat_node_put(FS_NODE(nodep));
00526 return rc;
00527 }
00528
00529 if (flags & L_DIRECTORY) {
00530 nodep->type = FAT_DIRECTORY;
00531 nodep->firstc = mcl;
00532 nodep->size = BPS(bs) * SPC(bs);
00533 } else {
00534 nodep->type = FAT_FILE;
00535 nodep->firstc = FAT_CLST_RES0;
00536 nodep->size = 0;
00537 }
00538 nodep->lnkcnt = 0;
00539 nodep->refcnt = 1;
00540 nodep->dirty = true;
00541
00542 nodep->idx = idxp;
00543 idxp->nodep = nodep;
00544
00545 fibril_mutex_unlock(&idxp->lock);
00546 *rfn = FS_NODE(nodep);
00547 return EOK;
00548 }
00549
00550 int fat_destroy_node(fs_node_t *fn)
00551 {
00552 fat_node_t *nodep = FAT_NODE(fn);
00553 fat_bs_t *bs;
00554 bool has_children;
00555 int rc;
00556
00557
00558
00559
00560
00561
00562
00563 assert(nodep->lnkcnt == 0);
00564
00565
00566
00567
00568 rc = fat_has_children(&has_children, fn);
00569 if (rc != EOK)
00570 return rc;
00571 assert(!has_children);
00572
00573 bs = block_bb_get(nodep->idx->devmap_handle);
00574 if (nodep->firstc != FAT_CLST_RES0) {
00575 assert(nodep->size);
00576
00577 rc = fat_free_clusters(bs, nodep->idx->devmap_handle,
00578 nodep->firstc);
00579 }
00580
00581 fat_idx_destroy(nodep->idx);
00582 free(nodep->bp);
00583 free(nodep);
00584 return rc;
00585 }
00586
00587 int fat_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
00588 {
00589 fat_node_t *parentp = FAT_NODE(pfn);
00590 fat_node_t *childp = FAT_NODE(cfn);
00591 fat_dentry_t *d;
00592 fat_bs_t *bs;
00593 block_t *b;
00594 unsigned i, j;
00595 unsigned blocks;
00596 fat_cluster_t mcl, lcl;
00597 int rc;
00598
00599 fibril_mutex_lock(&childp->lock);
00600 if (childp->lnkcnt == 1) {
00601
00602
00603
00604 fibril_mutex_unlock(&childp->lock);
00605 return EMLINK;
00606 }
00607 assert(childp->lnkcnt == 0);
00608 fibril_mutex_unlock(&childp->lock);
00609
00610 if (!fat_dentry_name_verify(name)) {
00611
00612
00613
00614 return ENOTSUP;
00615 }
00616
00617
00618
00619
00620
00621
00622 fibril_mutex_lock(&parentp->idx->lock);
00623 bs = block_bb_get(parentp->idx->devmap_handle);
00624
00625 blocks = parentp->size / BPS(bs);
00626
00627 for (i = 0; i < blocks; i++) {
00628 rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE);
00629 if (rc != EOK) {
00630 fibril_mutex_unlock(&parentp->idx->lock);
00631 return rc;
00632 }
00633 for (j = 0; j < DPS(bs); j++) {
00634 d = ((fat_dentry_t *)b->data) + j;
00635 switch (fat_classify_dentry(d)) {
00636 case FAT_DENTRY_SKIP:
00637 case FAT_DENTRY_VALID:
00638
00639 continue;
00640 case FAT_DENTRY_FREE:
00641 case FAT_DENTRY_LAST:
00642
00643 goto hit;
00644 }
00645 }
00646 rc = block_put(b);
00647 if (rc != EOK) {
00648 fibril_mutex_unlock(&parentp->idx->lock);
00649 return rc;
00650 }
00651 }
00652 j = 0;
00653
00654
00655
00656
00657 if (parentp->firstc == FAT_CLST_ROOT) {
00658
00659 fibril_mutex_unlock(&parentp->idx->lock);
00660 return ENOSPC;
00661 }
00662 rc = fat_alloc_clusters(bs, parentp->idx->devmap_handle, 1, &mcl, &lcl);
00663 if (rc != EOK) {
00664 fibril_mutex_unlock(&parentp->idx->lock);
00665 return rc;
00666 }
00667 rc = fat_zero_cluster(bs, parentp->idx->devmap_handle, mcl);
00668 if (rc != EOK) {
00669 (void) fat_free_clusters(bs, parentp->idx->devmap_handle, mcl);
00670 fibril_mutex_unlock(&parentp->idx->lock);
00671 return rc;
00672 }
00673 rc = fat_append_clusters(bs, parentp, mcl, lcl);
00674 if (rc != EOK) {
00675 (void) fat_free_clusters(bs, parentp->idx->devmap_handle, mcl);
00676 fibril_mutex_unlock(&parentp->idx->lock);
00677 return rc;
00678 }
00679 parentp->size += BPS(bs) * SPC(bs);
00680 parentp->dirty = true;
00681 rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE);
00682 if (rc != EOK) {
00683 fibril_mutex_unlock(&parentp->idx->lock);
00684 return rc;
00685 }
00686 d = (fat_dentry_t *)b->data;
00687
00688 hit:
00689
00690
00691
00692
00693
00694
00695 memset(d, 0, sizeof(fat_dentry_t));
00696 fat_dentry_name_set(d, name);
00697 b->dirty = true;
00698 rc = block_put(b);
00699 fibril_mutex_unlock(&parentp->idx->lock);
00700 if (rc != EOK)
00701 return rc;
00702
00703 fibril_mutex_lock(&childp->idx->lock);
00704
00705 if (childp->type == FAT_DIRECTORY) {
00706
00707
00708
00709
00710
00711
00712
00713 rc = fat_block_get(&b, bs, childp, 0, BLOCK_FLAGS_NONE);
00714 if (rc != EOK) {
00715
00716
00717
00718
00719 goto skip_dots;
00720 }
00721 d = (fat_dentry_t *) b->data;
00722 if ((fat_classify_dentry(d) == FAT_DENTRY_LAST) ||
00723 (str_cmp((char *) d->name, FAT_NAME_DOT)) == 0) {
00724 memset(d, 0, sizeof(fat_dentry_t));
00725 memcpy(d->name, FAT_NAME_DOT, FAT_NAME_LEN);
00726 memcpy(d->ext, FAT_EXT_PAD, FAT_EXT_LEN);
00727 d->attr = FAT_ATTR_SUBDIR;
00728 d->firstc = host2uint16_t_le(childp->firstc);
00729
00730 }
00731 d++;
00732 if ((fat_classify_dentry(d) == FAT_DENTRY_LAST) ||
00733 (str_cmp((char *) d->name, FAT_NAME_DOT_DOT) == 0)) {
00734 memset(d, 0, sizeof(fat_dentry_t));
00735 memcpy(d->name, FAT_NAME_DOT_DOT, FAT_NAME_LEN);
00736 memcpy(d->ext, FAT_EXT_PAD, FAT_EXT_LEN);
00737 d->attr = FAT_ATTR_SUBDIR;
00738 d->firstc = (parentp->firstc == FAT_CLST_ROOT) ?
00739 host2uint16_t_le(FAT_CLST_RES0) :
00740 host2uint16_t_le(parentp->firstc);
00741
00742 }
00743 b->dirty = true;
00744
00745
00746
00747
00748 (void) block_put(b);
00749 }
00750 skip_dots:
00751
00752 childp->idx->pfc = parentp->firstc;
00753 childp->idx->pdi = i * DPS(bs) + j;
00754 fibril_mutex_unlock(&childp->idx->lock);
00755
00756 fibril_mutex_lock(&childp->lock);
00757 childp->lnkcnt = 1;
00758 childp->dirty = true;
00759 fibril_mutex_unlock(&childp->lock);
00760
00761
00762
00763
00764 fat_idx_hashin(childp->idx);
00765
00766 return EOK;
00767 }
00768
00769 int fat_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
00770 {
00771 fat_node_t *parentp = FAT_NODE(pfn);
00772 fat_node_t *childp = FAT_NODE(cfn);
00773 fat_bs_t *bs;
00774 fat_dentry_t *d;
00775 block_t *b;
00776 bool has_children;
00777 int rc;
00778
00779 if (!parentp)
00780 return EBUSY;
00781
00782 rc = fat_has_children(&has_children, cfn);
00783 if (rc != EOK)
00784 return rc;
00785 if (has_children)
00786 return ENOTEMPTY;
00787
00788 fibril_mutex_lock(&parentp->lock);
00789 fibril_mutex_lock(&childp->lock);
00790 assert(childp->lnkcnt == 1);
00791 fibril_mutex_lock(&childp->idx->lock);
00792 bs = block_bb_get(childp->idx->devmap_handle);
00793
00794 rc = _fat_block_get(&b, bs, childp->idx->devmap_handle, childp->idx->pfc,
00795 NULL, (childp->idx->pdi * sizeof(fat_dentry_t)) / BPS(bs),
00796 BLOCK_FLAGS_NONE);
00797 if (rc != EOK)
00798 goto error;
00799 d = (fat_dentry_t *)b->data +
00800 (childp->idx->pdi % (BPS(bs) / sizeof(fat_dentry_t)));
00801
00802 d->name[0] = FAT_DENTRY_ERASED;
00803 b->dirty = true;
00804 rc = block_put(b);
00805 if (rc != EOK)
00806 goto error;
00807
00808
00809 fat_idx_hashout(childp->idx);
00810
00811 childp->idx->pfc = FAT_CLST_RES0;
00812 childp->idx->pdi = 0;
00813 fibril_mutex_unlock(&childp->idx->lock);
00814 childp->lnkcnt = 0;
00815 childp->refcnt++;
00816 childp->dirty = true;
00817 fibril_mutex_unlock(&childp->lock);
00818 fibril_mutex_unlock(&parentp->lock);
00819
00820 return EOK;
00821
00822 error:
00823 fibril_mutex_unlock(&parentp->idx->lock);
00824 fibril_mutex_unlock(&childp->lock);
00825 fibril_mutex_unlock(&childp->idx->lock);
00826 return rc;
00827 }
00828
00829 int fat_has_children(bool *has_children, fs_node_t *fn)
00830 {
00831 fat_bs_t *bs;
00832 fat_node_t *nodep = FAT_NODE(fn);
00833 unsigned blocks;
00834 block_t *b;
00835 unsigned i, j;
00836 int rc;
00837
00838 if (nodep->type != FAT_DIRECTORY) {
00839 *has_children = false;
00840 return EOK;
00841 }
00842
00843 fibril_mutex_lock(&nodep->idx->lock);
00844 bs = block_bb_get(nodep->idx->devmap_handle);
00845
00846 blocks = nodep->size / BPS(bs);
00847
00848 for (i = 0; i < blocks; i++) {
00849 fat_dentry_t *d;
00850
00851 rc = fat_block_get(&b, bs, nodep, i, BLOCK_FLAGS_NONE);
00852 if (rc != EOK) {
00853 fibril_mutex_unlock(&nodep->idx->lock);
00854 return rc;
00855 }
00856 for (j = 0; j < DPS(bs); j++) {
00857 d = ((fat_dentry_t *)b->data) + j;
00858 switch (fat_classify_dentry(d)) {
00859 case FAT_DENTRY_SKIP:
00860 case FAT_DENTRY_FREE:
00861 continue;
00862 case FAT_DENTRY_LAST:
00863 rc = block_put(b);
00864 fibril_mutex_unlock(&nodep->idx->lock);
00865 *has_children = false;
00866 return rc;
00867 default:
00868 case FAT_DENTRY_VALID:
00869 rc = block_put(b);
00870 fibril_mutex_unlock(&nodep->idx->lock);
00871 *has_children = true;
00872 return rc;
00873 }
00874 }
00875 rc = block_put(b);
00876 if (rc != EOK) {
00877 fibril_mutex_unlock(&nodep->idx->lock);
00878 return rc;
00879 }
00880 }
00881
00882 fibril_mutex_unlock(&nodep->idx->lock);
00883 *has_children = false;
00884 return EOK;
00885 }
00886
00887
00888 fs_index_t fat_index_get(fs_node_t *fn)
00889 {
00890 return FAT_NODE(fn)->idx->index;
00891 }
00892
00893 aoff64_t fat_size_get(fs_node_t *fn)
00894 {
00895 return FAT_NODE(fn)->size;
00896 }
00897
00898 unsigned fat_lnkcnt_get(fs_node_t *fn)
00899 {
00900 return FAT_NODE(fn)->lnkcnt;
00901 }
00902
00903 char fat_plb_get_char(unsigned pos)
00904 {
00905 return fat_reg.plb_ro[pos % PLB_SIZE];
00906 }
00907
00908 bool fat_is_directory(fs_node_t *fn)
00909 {
00910 return FAT_NODE(fn)->type == FAT_DIRECTORY;
00911 }
00912
00913 bool fat_is_file(fs_node_t *fn)
00914 {
00915 return FAT_NODE(fn)->type == FAT_FILE;
00916 }
00917
00918 devmap_handle_t fat_device_get(fs_node_t *node)
00919 {
00920 return 0;
00921 }
00922
00924 libfs_ops_t fat_libfs_ops = {
00925 .root_get = fat_root_get,
00926 .match = fat_match,
00927 .node_get = fat_node_get,
00928 .node_open = fat_node_open,
00929 .node_put = fat_node_put,
00930 .create = fat_create_node,
00931 .destroy = fat_destroy_node,
00932 .link = fat_link,
00933 .unlink = fat_unlink,
00934 .has_children = fat_has_children,
00935 .index_get = fat_index_get,
00936 .size_get = fat_size_get,
00937 .lnkcnt_get = fat_lnkcnt_get,
00938 .plb_get_char = fat_plb_get_char,
00939 .is_directory = fat_is_directory,
00940 .is_file = fat_is_file,
00941 .device_get = fat_device_get
00942 };
00943
00944
00945
00946
00947
00948 void fat_mounted(ipc_callid_t rid, ipc_call_t *request)
00949 {
00950 devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
00951 enum cache_mode cmode;
00952 fat_bs_t *bs;
00953
00954
00955 char *opts;
00956 int rc = async_data_write_accept((void **) &opts, true, 0, 0, 0, NULL);
00957
00958 if (rc != EOK) {
00959 async_answer_0(rid, rc);
00960 return;
00961 }
00962
00963
00964 if (str_cmp(opts, "wtcache") == 0)
00965 cmode = CACHE_MODE_WT;
00966 else
00967 cmode = CACHE_MODE_WB;
00968
00969 free(opts);
00970
00971
00972 rc = block_init(devmap_handle, BS_SIZE);
00973 if (rc != EOK) {
00974 async_answer_0(rid, rc);
00975 return;
00976 }
00977
00978
00979 rc = block_bb_read(devmap_handle, BS_BLOCK);
00980 if (rc != EOK) {
00981 block_fini(devmap_handle);
00982 async_answer_0(rid, rc);
00983 return;
00984 }
00985
00986
00987 bs = block_bb_get(devmap_handle);
00988
00989 if (BPS(bs) != BS_SIZE) {
00990 block_fini(devmap_handle);
00991 async_answer_0(rid, ENOTSUP);
00992 return;
00993 }
00994
00995
00996 rc = block_cache_init(devmap_handle, BPS(bs), 0 , cmode);
00997 if (rc != EOK) {
00998 block_fini(devmap_handle);
00999 async_answer_0(rid, rc);
01000 return;
01001 }
01002
01003
01004 rc = fat_sanity_check(bs, devmap_handle);
01005 if (rc != EOK) {
01006 (void) block_cache_fini(devmap_handle);
01007 block_fini(devmap_handle);
01008 async_answer_0(rid, rc);
01009 return;
01010 }
01011
01012 rc = fat_idx_init_by_devmap_handle(devmap_handle);
01013 if (rc != EOK) {
01014 (void) block_cache_fini(devmap_handle);
01015 block_fini(devmap_handle);
01016 async_answer_0(rid, rc);
01017 return;
01018 }
01019
01020
01021 fs_node_t *rfn = (fs_node_t *)malloc(sizeof(fs_node_t));
01022 if (!rfn) {
01023 (void) block_cache_fini(devmap_handle);
01024 block_fini(devmap_handle);
01025 fat_idx_fini_by_devmap_handle(devmap_handle);
01026 async_answer_0(rid, ENOMEM);
01027 return;
01028 }
01029 fs_node_initialize(rfn);
01030 fat_node_t *rootp = (fat_node_t *)malloc(sizeof(fat_node_t));
01031 if (!rootp) {
01032 free(rfn);
01033 (void) block_cache_fini(devmap_handle);
01034 block_fini(devmap_handle);
01035 fat_idx_fini_by_devmap_handle(devmap_handle);
01036 async_answer_0(rid, ENOMEM);
01037 return;
01038 }
01039 fat_node_initialize(rootp);
01040
01041 fat_idx_t *ridxp = fat_idx_get_by_pos(devmap_handle, FAT_CLST_ROOTPAR, 0);
01042 if (!ridxp) {
01043 free(rfn);
01044 free(rootp);
01045 (void) block_cache_fini(devmap_handle);
01046 block_fini(devmap_handle);
01047 fat_idx_fini_by_devmap_handle(devmap_handle);
01048 async_answer_0(rid, ENOMEM);
01049 return;
01050 }
01051 assert(ridxp->index == 0);
01052
01053
01054 rootp->type = FAT_DIRECTORY;
01055 rootp->firstc = FAT_CLST_ROOT;
01056 rootp->refcnt = 1;
01057 rootp->lnkcnt = 0;
01058 rootp->size = RDE(bs) * sizeof(fat_dentry_t);
01059 rootp->idx = ridxp;
01060 ridxp->nodep = rootp;
01061 rootp->bp = rfn;
01062 rfn->data = rootp;
01063
01064 fibril_mutex_unlock(&ridxp->lock);
01065
01066 async_answer_3(rid, EOK, ridxp->index, rootp->size, rootp->lnkcnt);
01067 }
01068
01069 void fat_mount(ipc_callid_t rid, ipc_call_t *request)
01070 {
01071 libfs_mount(&fat_libfs_ops, fat_reg.fs_handle, rid, request);
01072 }
01073
01074 void fat_unmounted(ipc_callid_t rid, ipc_call_t *request)
01075 {
01076 devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
01077 fs_node_t *fn;
01078 fat_node_t *nodep;
01079 int rc;
01080
01081 rc = fat_root_get(&fn, devmap_handle);
01082 if (rc != EOK) {
01083 async_answer_0(rid, rc);
01084 return;
01085 }
01086 nodep = FAT_NODE(fn);
01087
01088
01089
01090
01091
01092 if (nodep->refcnt != 2) {
01093 (void) fat_node_put(fn);
01094 async_answer_0(rid, EBUSY);
01095 return;
01096 }
01097
01098
01099
01100
01101 (void) fat_node_put(fn);
01102 (void) fat_node_put(fn);
01103
01104
01105
01106
01107
01108
01109 (void) fat_node_fini_by_devmap_handle(devmap_handle);
01110 fat_idx_fini_by_devmap_handle(devmap_handle);
01111 (void) block_cache_fini(devmap_handle);
01112 block_fini(devmap_handle);
01113
01114 async_answer_0(rid, EOK);
01115 }
01116
01117 void fat_unmount(ipc_callid_t rid, ipc_call_t *request)
01118 {
01119 libfs_unmount(&fat_libfs_ops, rid, request);
01120 }
01121
01122 void fat_lookup(ipc_callid_t rid, ipc_call_t *request)
01123 {
01124 libfs_lookup(&fat_libfs_ops, fat_reg.fs_handle, rid, request);
01125 }
01126
01127 void fat_read(ipc_callid_t rid, ipc_call_t *request)
01128 {
01129 devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
01130 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
01131 aoff64_t pos =
01132 (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
01133 fs_node_t *fn;
01134 fat_node_t *nodep;
01135 fat_bs_t *bs;
01136 size_t bytes;
01137 block_t *b;
01138 int rc;
01139
01140 rc = fat_node_get(&fn, devmap_handle, index);
01141 if (rc != EOK) {
01142 async_answer_0(rid, rc);
01143 return;
01144 }
01145 if (!fn) {
01146 async_answer_0(rid, ENOENT);
01147 return;
01148 }
01149 nodep = FAT_NODE(fn);
01150
01151 ipc_callid_t callid;
01152 size_t len;
01153 if (!async_data_read_receive(&callid, &len)) {
01154 fat_node_put(fn);
01155 async_answer_0(callid, EINVAL);
01156 async_answer_0(rid, EINVAL);
01157 return;
01158 }
01159
01160 bs = block_bb_get(devmap_handle);
01161
01162 if (nodep->type == FAT_FILE) {
01163
01164
01165
01166
01167
01168 if (pos >= nodep->size) {
01169
01170 bytes = 0;
01171 (void) async_data_read_finalize(callid, NULL, 0);
01172 } else {
01173 bytes = min(len, BPS(bs) - pos % BPS(bs));
01174 bytes = min(bytes, nodep->size - pos);
01175 rc = fat_block_get(&b, bs, nodep, pos / BPS(bs),
01176 BLOCK_FLAGS_NONE);
01177 if (rc != EOK) {
01178 fat_node_put(fn);
01179 async_answer_0(callid, rc);
01180 async_answer_0(rid, rc);
01181 return;
01182 }
01183 (void) async_data_read_finalize(callid,
01184 b->data + pos % BPS(bs), bytes);
01185 rc = block_put(b);
01186 if (rc != EOK) {
01187 fat_node_put(fn);
01188 async_answer_0(rid, rc);
01189 return;
01190 }
01191 }
01192 } else {
01193 unsigned bnum;
01194 aoff64_t spos = pos;
01195 char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
01196 fat_dentry_t *d;
01197
01198 assert(nodep->type == FAT_DIRECTORY);
01199 assert(nodep->size % BPS(bs) == 0);
01200 assert(BPS(bs) % sizeof(fat_dentry_t) == 0);
01201
01202
01203
01204
01205
01206
01207
01208 bnum = (pos * sizeof(fat_dentry_t)) / BPS(bs);
01209 while (bnum < nodep->size / BPS(bs)) {
01210 aoff64_t o;
01211
01212 rc = fat_block_get(&b, bs, nodep, bnum,
01213 BLOCK_FLAGS_NONE);
01214 if (rc != EOK)
01215 goto err;
01216 for (o = pos % (BPS(bs) / sizeof(fat_dentry_t));
01217 o < BPS(bs) / sizeof(fat_dentry_t);
01218 o++, pos++) {
01219 d = ((fat_dentry_t *)b->data) + o;
01220 switch (fat_classify_dentry(d)) {
01221 case FAT_DENTRY_SKIP:
01222 case FAT_DENTRY_FREE:
01223 continue;
01224 case FAT_DENTRY_LAST:
01225 rc = block_put(b);
01226 if (rc != EOK)
01227 goto err;
01228 goto miss;
01229 default:
01230 case FAT_DENTRY_VALID:
01231 fat_dentry_name_get(d, name);
01232 rc = block_put(b);
01233 if (rc != EOK)
01234 goto err;
01235 goto hit;
01236 }
01237 }
01238 rc = block_put(b);
01239 if (rc != EOK)
01240 goto err;
01241 bnum++;
01242 }
01243 miss:
01244 rc = fat_node_put(fn);
01245 async_answer_0(callid, rc != EOK ? rc : ENOENT);
01246 async_answer_1(rid, rc != EOK ? rc : ENOENT, 0);
01247 return;
01248
01249 err:
01250 (void) fat_node_put(fn);
01251 async_answer_0(callid, rc);
01252 async_answer_0(rid, rc);
01253 return;
01254
01255 hit:
01256 (void) async_data_read_finalize(callid, name, str_size(name) + 1);
01257 bytes = (pos - spos) + 1;
01258 }
01259
01260 rc = fat_node_put(fn);
01261 async_answer_1(rid, rc, (sysarg_t)bytes);
01262 }
01263
01264 void fat_write(ipc_callid_t rid, ipc_call_t *request)
01265 {
01266 devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
01267 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
01268 aoff64_t pos =
01269 (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
01270 fs_node_t *fn;
01271 fat_node_t *nodep;
01272 fat_bs_t *bs;
01273 size_t bytes, size;
01274 block_t *b;
01275 aoff64_t boundary;
01276 int flags = BLOCK_FLAGS_NONE;
01277 int rc;
01278
01279 rc = fat_node_get(&fn, devmap_handle, index);
01280 if (rc != EOK) {
01281 async_answer_0(rid, rc);
01282 return;
01283 }
01284 if (!fn) {
01285 async_answer_0(rid, ENOENT);
01286 return;
01287 }
01288 nodep = FAT_NODE(fn);
01289
01290 ipc_callid_t callid;
01291 size_t len;
01292 if (!async_data_write_receive(&callid, &len)) {
01293 (void) fat_node_put(fn);
01294 async_answer_0(callid, EINVAL);
01295 async_answer_0(rid, EINVAL);
01296 return;
01297 }
01298
01299 bs = block_bb_get(devmap_handle);
01300
01301
01302
01303
01304
01305
01306
01307
01308 bytes = min(len, BPS(bs) - pos % BPS(bs));
01309 if (bytes == BPS(bs))
01310 flags |= BLOCK_FLAGS_NOREAD;
01311
01312 boundary = ROUND_UP(nodep->size, BPC(bs));
01313 if (pos < boundary) {
01314
01315
01316
01317
01318
01319
01320 rc = fat_fill_gap(bs, nodep, FAT_CLST_RES0, pos);
01321 if (rc != EOK) {
01322 (void) fat_node_put(fn);
01323 async_answer_0(callid, rc);
01324 async_answer_0(rid, rc);
01325 return;
01326 }
01327 rc = fat_block_get(&b, bs, nodep, pos / BPS(bs), flags);
01328 if (rc != EOK) {
01329 (void) fat_node_put(fn);
01330 async_answer_0(callid, rc);
01331 async_answer_0(rid, rc);
01332 return;
01333 }
01334 (void) async_data_write_finalize(callid,
01335 b->data + pos % BPS(bs), bytes);
01336 b->dirty = true;
01337 rc = block_put(b);
01338 if (rc != EOK) {
01339 (void) fat_node_put(fn);
01340 async_answer_0(rid, rc);
01341 return;
01342 }
01343 if (pos + bytes > nodep->size) {
01344 nodep->size = pos + bytes;
01345 nodep->dirty = true;
01346 }
01347 size = nodep->size;
01348 rc = fat_node_put(fn);
01349 async_answer_2(rid, rc, bytes, nodep->size);
01350 return;
01351 } else {
01352
01353
01354
01355
01356 unsigned nclsts;
01357 fat_cluster_t mcl, lcl;
01358
01359 nclsts = (ROUND_UP(pos + bytes, BPC(bs)) - boundary) / BPC(bs);
01360
01361 rc = fat_alloc_clusters(bs, devmap_handle, nclsts, &mcl, &lcl);
01362 if (rc != EOK) {
01363
01364 (void) fat_node_put(fn);
01365 async_answer_0(callid, rc);
01366 async_answer_0(rid, rc);
01367 return;
01368 }
01369
01370 rc = fat_fill_gap(bs, nodep, mcl, pos);
01371 if (rc != EOK) {
01372 (void) fat_free_clusters(bs, devmap_handle, mcl);
01373 (void) fat_node_put(fn);
01374 async_answer_0(callid, rc);
01375 async_answer_0(rid, rc);
01376 return;
01377 }
01378 rc = _fat_block_get(&b, bs, devmap_handle, lcl, NULL,
01379 (pos / BPS(bs)) % SPC(bs), flags);
01380 if (rc != EOK) {
01381 (void) fat_free_clusters(bs, devmap_handle, mcl);
01382 (void) fat_node_put(fn);
01383 async_answer_0(callid, rc);
01384 async_answer_0(rid, rc);
01385 return;
01386 }
01387 (void) async_data_write_finalize(callid,
01388 b->data + pos % BPS(bs), bytes);
01389 b->dirty = true;
01390 rc = block_put(b);
01391 if (rc != EOK) {
01392 (void) fat_free_clusters(bs, devmap_handle, mcl);
01393 (void) fat_node_put(fn);
01394 async_answer_0(rid, rc);
01395 return;
01396 }
01397
01398
01399
01400
01401 rc = fat_append_clusters(bs, nodep, mcl, lcl);
01402 if (rc != EOK) {
01403 (void) fat_free_clusters(bs, devmap_handle, mcl);
01404 (void) fat_node_put(fn);
01405 async_answer_0(rid, rc);
01406 return;
01407 }
01408 nodep->size = size = pos + bytes;
01409 nodep->dirty = true;
01410 rc = fat_node_put(fn);
01411 async_answer_2(rid, rc, bytes, size);
01412 return;
01413 }
01414 }
01415
01416 void fat_truncate(ipc_callid_t rid, ipc_call_t *request)
01417 {
01418 devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
01419 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
01420 aoff64_t size =
01421 (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
01422 fs_node_t *fn;
01423 fat_node_t *nodep;
01424 fat_bs_t *bs;
01425 int rc;
01426
01427 rc = fat_node_get(&fn, devmap_handle, index);
01428 if (rc != EOK) {
01429 async_answer_0(rid, rc);
01430 return;
01431 }
01432 if (!fn) {
01433 async_answer_0(rid, ENOENT);
01434 return;
01435 }
01436 nodep = FAT_NODE(fn);
01437
01438 bs = block_bb_get(devmap_handle);
01439
01440 if (nodep->size == size) {
01441 rc = EOK;
01442 } else if (nodep->size < size) {
01443
01444
01445
01446
01447 rc = EINVAL;
01448 } else if (ROUND_UP(nodep->size, BPC(bs)) == ROUND_UP(size, BPC(bs))) {
01449
01450
01451
01452 nodep->size = size;
01453 nodep->dirty = true;
01454 rc = EOK;
01455 } else {
01456
01457
01458
01459 if (size == 0) {
01460 rc = fat_chop_clusters(bs, nodep, FAT_CLST_RES0);
01461 if (rc != EOK)
01462 goto out;
01463 } else {
01464 fat_cluster_t lastc;
01465 rc = fat_cluster_walk(bs, devmap_handle, nodep->firstc,
01466 &lastc, NULL, (size - 1) / BPC(bs));
01467 if (rc != EOK)
01468 goto out;
01469 rc = fat_chop_clusters(bs, nodep, lastc);
01470 if (rc != EOK)
01471 goto out;
01472 }
01473 nodep->size = size;
01474 nodep->dirty = true;
01475 rc = EOK;
01476 }
01477 out:
01478 fat_node_put(fn);
01479 async_answer_0(rid, rc);
01480 return;
01481 }
01482
01483 void fat_close(ipc_callid_t rid, ipc_call_t *request)
01484 {
01485 async_answer_0(rid, EOK);
01486 }
01487
01488 void fat_destroy(ipc_callid_t rid, ipc_call_t *request)
01489 {
01490 devmap_handle_t devmap_handle = (devmap_handle_t)IPC_GET_ARG1(*request);
01491 fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
01492 fs_node_t *fn;
01493 fat_node_t *nodep;
01494 int rc;
01495
01496 rc = fat_node_get(&fn, devmap_handle, index);
01497 if (rc != EOK) {
01498 async_answer_0(rid, rc);
01499 return;
01500 }
01501 if (!fn) {
01502 async_answer_0(rid, ENOENT);
01503 return;
01504 }
01505
01506 nodep = FAT_NODE(fn);
01507
01508
01509
01510
01511 assert(nodep->refcnt == 2);
01512
01513 rc = fat_destroy_node(fn);
01514 async_answer_0(rid, rc);
01515 }
01516
01517 void fat_open_node(ipc_callid_t rid, ipc_call_t *request)
01518 {
01519 libfs_open_node(&fat_libfs_ops, fat_reg.fs_handle, rid, request);
01520 }
01521
01522 void fat_stat(ipc_callid_t rid, ipc_call_t *request)
01523 {
01524 libfs_stat(&fat_libfs_ops, fat_reg.fs_handle, rid, request);
01525 }
01526
01527 void fat_sync(ipc_callid_t rid, ipc_call_t *request)
01528 {
01529 devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
01530 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
01531
01532 fs_node_t *fn;
01533 int rc = fat_node_get(&fn, devmap_handle, index);
01534 if (rc != EOK) {
01535 async_answer_0(rid, rc);
01536 return;
01537 }
01538 if (!fn) {
01539 async_answer_0(rid, ENOENT);
01540 return;
01541 }
01542
01543 fat_node_t *nodep = FAT_NODE(fn);
01544
01545 nodep->dirty = true;
01546 rc = fat_node_sync(nodep);
01547
01548 fat_node_put(fn);
01549 async_answer_0(rid, rc);
01550 }
01551