Changeset 1787e527 in mainline for uspace/srv/fs/fat/fat_ops.c


Ignore:
Timestamp:
2009-11-16T21:22:54Z (14 years ago)
Author:
Lenka Trochtova <trochtova.lenka@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
5ebdf94
Parents:
fcbd1be (diff), 9c70ed6 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

merged with head (unstable)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/fs/fat/fat_ops.c

    rfcbd1be r1787e527  
    6565static LIST_INITIALIZE(ffn_head);
    6666
     67/*
     68 * Forward declarations of FAT libfs operations.
     69 */
     70static int fat_root_get(fs_node_t **, dev_handle_t);
     71static int fat_match(fs_node_t **, fs_node_t *, const char *);
     72static int fat_node_get(fs_node_t **, dev_handle_t, fs_index_t);
     73static int fat_node_put(fs_node_t *);
     74static int fat_create_node(fs_node_t **, dev_handle_t, int);
     75static int fat_destroy_node(fs_node_t *);
     76static int fat_link(fs_node_t *, fs_node_t *, const char *);
     77static int fat_unlink(fs_node_t *, fs_node_t *, const char *);
     78static int fat_has_children(bool *, fs_node_t *);
     79static fs_index_t fat_index_get(fs_node_t *);
     80static size_t fat_size_get(fs_node_t *);
     81static unsigned fat_lnkcnt_get(fs_node_t *);
     82static char fat_plb_get_char(unsigned);
     83static bool fat_is_directory(fs_node_t *);
     84static bool fat_is_file(fs_node_t *node);
     85
     86/*
     87 * Helper functions.
     88 */
    6789static void fat_node_initialize(fat_node_t *node)
    6890{
     
    78100}
    79101
    80 static void fat_node_sync(fat_node_t *node)
     102static int fat_node_sync(fat_node_t *node)
    81103{
    82104        block_t *b;
     
    85107        uint16_t bps;
    86108        unsigned dps;
     109        int rc;
    87110       
    88111        assert(node->dirty);
     
    93116       
    94117        /* Read the block that contains the dentry of interest. */
    95         b = _fat_block_get(bs, node->idx->dev_handle, node->idx->pfc,
     118        rc = _fat_block_get(&b, bs, node->idx->dev_handle, node->idx->pfc,
    96119            (node->idx->pdi * sizeof(fat_dentry_t)) / bps, BLOCK_FLAGS_NONE);
     120        if (rc != EOK)
     121                return rc;
    97122
    98123        d = ((fat_dentry_t *)b->data) + (node->idx->pdi % dps);
     
    108133       
    109134        b->dirty = true;                /* need to sync block */
    110         block_put(b);
    111 }
    112 
    113 static fat_node_t *fat_node_get_new(void)
     135        rc = block_put(b);
     136        return rc;
     137}
     138
     139static int fat_node_get_new(fat_node_t **nodepp)
    114140{
    115141        fs_node_t *fn;
    116142        fat_node_t *nodep;
     143        int rc;
    117144
    118145        fibril_mutex_lock(&ffn_mutex);
     
    130157                list_remove(&nodep->ffn_link);
    131158                fibril_mutex_unlock(&ffn_mutex);
    132                 if (nodep->dirty)
    133                         fat_node_sync(nodep);
     159                if (nodep->dirty) {
     160                        rc = fat_node_sync(nodep);
     161                        if (rc != EOK) {
     162                                idxp_tmp->nodep = NULL;
     163                                fibril_mutex_unlock(&nodep->lock);
     164                                fibril_mutex_unlock(&idxp_tmp->lock);
     165                                free(nodep->bp);
     166                                free(nodep);
     167                                return rc;
     168                        }
     169                }
    134170                idxp_tmp->nodep = NULL;
    135171                fibril_mutex_unlock(&nodep->lock);
     
    142178                fn = (fs_node_t *)malloc(sizeof(fs_node_t));
    143179                if (!fn)
    144                         return NULL;
     180                        return ENOMEM;
    145181                nodep = (fat_node_t *)malloc(sizeof(fat_node_t));
    146182                if (!nodep) {
    147183                        free(fn);
    148                         return NULL;
     184                        return ENOMEM;
    149185                }
    150186        }
     
    154190        nodep->bp = fn;
    155191       
    156         return nodep;
     192        *nodepp = nodep;
     193        return EOK;
    157194}
    158195
     
    161198 * @param idxp          Locked index structure.
    162199 */
    163 static fat_node_t *fat_node_get_core(fat_idx_t *idxp)
     200static int fat_node_get_core(fat_node_t **nodepp, fat_idx_t *idxp)
    164201{
    165202        block_t *b;
     
    170207        unsigned spc;
    171208        unsigned dps;
     209        int rc;
    172210
    173211        if (idxp->nodep) {
     
    177215                 */
    178216                fibril_mutex_lock(&idxp->nodep->lock);
    179                 if (!idxp->nodep->refcnt++)
     217                if (!idxp->nodep->refcnt++) {
     218                        fibril_mutex_lock(&ffn_mutex);
    180219                        list_remove(&idxp->nodep->ffn_link);
     220                        fibril_mutex_unlock(&ffn_mutex);
     221                }
    181222                fibril_mutex_unlock(&idxp->nodep->lock);
    182                 return idxp->nodep;
     223                *nodepp = idxp->nodep;
     224                return EOK;
    183225        }
    184226
     
    189231        assert(idxp->pfc);
    190232
    191         nodep = fat_node_get_new();
    192         if (!nodep)
    193                 return NULL;
     233        rc = fat_node_get_new(&nodep);
     234        if (rc != EOK)
     235                return rc;
    194236
    195237        bs = block_bb_get(idxp->dev_handle);
     
    199241
    200242        /* Read the block that contains the dentry of interest. */
    201         b = _fat_block_get(bs, idxp->dev_handle, idxp->pfc,
     243        rc = _fat_block_get(&b, bs, idxp->dev_handle, idxp->pfc,
    202244            (idxp->pdi * sizeof(fat_dentry_t)) / bps, BLOCK_FLAGS_NONE);
    203         assert(b);
     245        if (rc != EOK) {
     246                (void) fat_node_put(FS_NODE(nodep));
     247                return rc;
     248        }
    204249
    205250        d = ((fat_dentry_t *)b->data) + (idxp->pdi % dps);
     
    216261                 * size of the directory by walking the FAT.
    217262                 */
    218                 nodep->size = bps * spc * fat_clusters_get(bs, idxp->dev_handle,
     263                uint16_t clusters;
     264                rc = fat_clusters_get(&clusters, bs, idxp->dev_handle,
    219265                    uint16_t_le2host(d->firstc));
     266                if (rc != EOK) {
     267                        (void) fat_node_put(FS_NODE(nodep));
     268                        return rc;
     269                }
     270                nodep->size = bps * spc * clusters;
    220271        } else {
    221272                nodep->type = FAT_FILE;
     
    226277        nodep->refcnt = 1;
    227278
    228         block_put(b);
     279        rc = block_put(b);
     280        if (rc != EOK) {
     281                (void) fat_node_put(FS_NODE(nodep));
     282                return rc;
     283        }
    229284
    230285        /* Link the idx structure with the node structure. */
     
    232287        idxp->nodep = nodep;
    233288
    234         return nodep;
    235 }
    236 
    237 /*
    238  * Forward declarations of FAT libfs operations.
    239  */
    240 static fs_node_t *fat_node_get(dev_handle_t, fs_index_t);
    241 static void fat_node_put(fs_node_t *);
    242 static fs_node_t *fat_create_node(dev_handle_t, int);
    243 static int fat_destroy_node(fs_node_t *);
    244 static int fat_link(fs_node_t *, fs_node_t *, const char *);
    245 static int fat_unlink(fs_node_t *, fs_node_t *, const char *);
    246 static fs_node_t *fat_match(fs_node_t *, const char *);
    247 static fs_index_t fat_index_get(fs_node_t *);
    248 static size_t fat_size_get(fs_node_t *);
    249 static unsigned fat_lnkcnt_get(fs_node_t *);
    250 static bool fat_has_children(fs_node_t *);
    251 static fs_node_t *fat_root_get(dev_handle_t);
    252 static char fat_plb_get_char(unsigned);
    253 static bool fat_is_directory(fs_node_t *);
    254 static bool fat_is_file(fs_node_t *node);
     289        *nodepp = nodep;
     290        return EOK;
     291}
    255292
    256293/*
     
    258295 */
    259296
    260 /** Instantiate a FAT in-core node. */
    261 fs_node_t *fat_node_get(dev_handle_t dev_handle, fs_index_t index)
    262 {
    263         fat_node_t *nodep;
    264         fat_idx_t *idxp;
    265 
    266         idxp = fat_idx_get_by_index(dev_handle, index);
    267         if (!idxp)
    268                 return NULL;
    269         /* idxp->lock held */
    270         nodep = fat_node_get_core(idxp);
    271         fibril_mutex_unlock(&idxp->lock);
    272         return FS_NODE(nodep);
    273 }
    274 
    275 void fat_node_put(fs_node_t *fn)
    276 {
    277         fat_node_t *nodep = FAT_NODE(fn);
    278         bool destroy = false;
    279 
    280         fibril_mutex_lock(&nodep->lock);
    281         if (!--nodep->refcnt) {
    282                 if (nodep->idx) {
    283                         fibril_mutex_lock(&ffn_mutex);
    284                         list_append(&nodep->ffn_link, &ffn_head);
    285                         fibril_mutex_unlock(&ffn_mutex);
    286                 } else {
    287                         /*
    288                          * The node does not have any index structure associated
    289                          * with itself. This can only mean that we are releasing
    290                          * the node after a failed attempt to allocate the index
    291                          * structure for it.
    292                          */
    293                         destroy = true;
    294                 }
    295         }
    296         fibril_mutex_unlock(&nodep->lock);
    297         if (destroy) {
    298                 free(nodep->bp);
    299                 free(nodep);
    300         }
    301 }
    302 
    303 fs_node_t *fat_create_node(dev_handle_t dev_handle, int flags)
    304 {
    305         fat_idx_t *idxp;
    306         fat_node_t *nodep;
    307         fat_bs_t *bs;
    308         fat_cluster_t mcl, lcl;
    309         uint16_t bps;
    310         int rc;
    311 
    312         bs = block_bb_get(dev_handle);
    313         bps = uint16_t_le2host(bs->bps);
    314         if (flags & L_DIRECTORY) {
    315                 /* allocate a cluster */
    316                 rc = fat_alloc_clusters(bs, dev_handle, 1, &mcl, &lcl);
    317                 if (rc != EOK)
    318                         return NULL;
    319         }
    320 
    321         nodep = fat_node_get_new();
    322         if (!nodep) {
    323                 fat_free_clusters(bs, dev_handle, mcl);
    324                 return NULL;
    325         }
    326         idxp = fat_idx_get_new(dev_handle);
    327         if (!idxp) {
    328                 fat_free_clusters(bs, dev_handle, mcl);
    329                 fat_node_put(FS_NODE(nodep));
    330                 return NULL;
    331         }
    332         /* idxp->lock held */
    333         if (flags & L_DIRECTORY) {
    334                 /* Populate the new cluster with unused dentries. */
    335                 fat_zero_cluster(bs, dev_handle, mcl);
    336                 nodep->type = FAT_DIRECTORY;
    337                 nodep->firstc = mcl;
    338                 nodep->size = bps * bs->spc;
    339         } else {
    340                 nodep->type = FAT_FILE;
    341                 nodep->firstc = FAT_CLST_RES0;
    342                 nodep->size = 0;
    343         }
    344         nodep->lnkcnt = 0;      /* not linked anywhere */
    345         nodep->refcnt = 1;
    346         nodep->dirty = true;
    347 
    348         nodep->idx = idxp;
    349         idxp->nodep = nodep;
    350 
    351         fibril_mutex_unlock(&idxp->lock);
    352         return FS_NODE(nodep);
    353 }
    354 
    355 int fat_destroy_node(fs_node_t *fn)
    356 {
    357         fat_node_t *nodep = FAT_NODE(fn);
    358         fat_bs_t *bs;
    359 
    360         /*
    361          * The node is not reachable from the file system. This means that the
    362          * link count should be zero and that the index structure cannot be
    363          * found in the position hash. Obviously, we don't need to lock the node
    364          * nor its index structure.
    365          */
    366         assert(nodep->lnkcnt == 0);
    367 
    368         /*
    369          * The node may not have any children.
    370          */
    371         assert(fat_has_children(fn) == false);
    372 
    373         bs = block_bb_get(nodep->idx->dev_handle);
    374         if (nodep->firstc != FAT_CLST_RES0) {
    375                 assert(nodep->size);
    376                 /* Free all clusters allocated to the node. */
    377                 fat_free_clusters(bs, nodep->idx->dev_handle, nodep->firstc);
    378         }
    379 
    380         fat_idx_destroy(nodep->idx);
    381         free(nodep->bp);
    382         free(nodep);
    383         return EOK;
    384 }
    385 
    386 int fat_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
    387 {
    388         fat_node_t *parentp = FAT_NODE(pfn);
    389         fat_node_t *childp = FAT_NODE(cfn);
    390         fat_dentry_t *d;
    391         fat_bs_t *bs;
    392         block_t *b;
    393         unsigned i, j;
    394         uint16_t bps;
    395         unsigned dps;
    396         unsigned blocks;
    397         fat_cluster_t mcl, lcl;
    398         int rc;
    399 
    400         fibril_mutex_lock(&childp->lock);
    401         if (childp->lnkcnt == 1) {
    402                 /*
    403                  * On FAT, we don't support multiple hard links.
    404                  */
    405                 fibril_mutex_unlock(&childp->lock);
    406                 return EMLINK;
    407         }
    408         assert(childp->lnkcnt == 0);
    409         fibril_mutex_unlock(&childp->lock);
    410 
    411         if (!fat_dentry_name_verify(name)) {
    412                 /*
    413                  * Attempt to create unsupported name.
    414                  */
    415                 return ENOTSUP;
    416         }
    417 
    418         /*
    419          * Get us an unused parent node's dentry or grow the parent and allocate
    420          * a new one.
    421          */
    422        
    423         fibril_mutex_lock(&parentp->idx->lock);
    424         bs = block_bb_get(parentp->idx->dev_handle);
    425         bps = uint16_t_le2host(bs->bps);
    426         dps = bps / sizeof(fat_dentry_t);
    427 
    428         blocks = parentp->size / bps;
    429 
    430         for (i = 0; i < blocks; i++) {
    431                 b = fat_block_get(bs, parentp, i, BLOCK_FLAGS_NONE);
    432                 for (j = 0; j < dps; j++) {
    433                         d = ((fat_dentry_t *)b->data) + j;
    434                         switch (fat_classify_dentry(d)) {
    435                         case FAT_DENTRY_SKIP:
    436                         case FAT_DENTRY_VALID:
    437                                 /* skipping used and meta entries */
    438                                 continue;
    439                         case FAT_DENTRY_FREE:
    440                         case FAT_DENTRY_LAST:
    441                                 /* found an empty slot */
    442                                 goto hit;
    443                         }
    444                 }
    445                 block_put(b);
    446         }
    447         j = 0;
    448        
    449         /*
    450          * We need to grow the parent in order to create a new unused dentry.
    451          */
    452         if (parentp->firstc == FAT_CLST_ROOT) {
    453                 /* Can't grow the root directory. */
    454                 fibril_mutex_unlock(&parentp->idx->lock);
    455                 return ENOSPC;
    456         }
    457         rc = fat_alloc_clusters(bs, parentp->idx->dev_handle, 1, &mcl, &lcl);
    458         if (rc != EOK) {
    459                 fibril_mutex_unlock(&parentp->idx->lock);
    460                 return rc;
    461         }
    462         fat_zero_cluster(bs, parentp->idx->dev_handle, mcl);
    463         fat_append_clusters(bs, parentp, mcl);
    464         parentp->size += bps * bs->spc;
    465         parentp->dirty = true;          /* need to sync node */
    466         b = fat_block_get(bs, parentp, i, BLOCK_FLAGS_NONE);
    467         d = (fat_dentry_t *)b->data;
    468 
    469 hit:
    470         /*
    471          * At this point we only establish the link between the parent and the
    472          * child.  The dentry, except of the name and the extension, will remain
    473          * uninitialized until the corresponding node is synced. Thus the valid
    474          * dentry data is kept in the child node structure.
    475          */
    476         memset(d, 0, sizeof(fat_dentry_t));
    477         fat_dentry_name_set(d, name);
    478         b->dirty = true;                /* need to sync block */
    479         block_put(b);
    480         fibril_mutex_unlock(&parentp->idx->lock);
    481 
    482         fibril_mutex_lock(&childp->idx->lock);
    483        
    484         /*
    485          * If possible, create the Sub-directory Identifier Entry and the
    486          * Sub-directory Parent Pointer Entry (i.e. "." and ".."). These entries
    487          * are not mandatory according to Standard ECMA-107 and HelenOS VFS does
    488          * not use them anyway, so this is rather a sign of our good will.
    489          */
    490         b = fat_block_get(bs, childp, 0, BLOCK_FLAGS_NONE);
    491         d = (fat_dentry_t *)b->data;
    492         if (fat_classify_dentry(d) == FAT_DENTRY_LAST ||
    493             str_cmp(d->name, FAT_NAME_DOT) == 0) {
    494                 memset(d, 0, sizeof(fat_dentry_t));
    495                 str_cpy(d->name, 8, FAT_NAME_DOT);
    496                 str_cpy(d->ext, 3, FAT_EXT_PAD);
    497                 d->attr = FAT_ATTR_SUBDIR;
    498                 d->firstc = host2uint16_t_le(childp->firstc);
    499                 /* TODO: initialize also the date/time members. */
    500         }
    501         d++;
    502         if (fat_classify_dentry(d) == FAT_DENTRY_LAST ||
    503             str_cmp(d->name, FAT_NAME_DOT_DOT) == 0) {
    504                 memset(d, 0, sizeof(fat_dentry_t));
    505                 str_cpy(d->name, 8, FAT_NAME_DOT_DOT);
    506                 str_cpy(d->ext, 3, FAT_EXT_PAD);
    507                 d->attr = FAT_ATTR_SUBDIR;
    508                 d->firstc = (parentp->firstc == FAT_CLST_ROOT) ?
    509                     host2uint16_t_le(FAT_CLST_RES0) :
    510                     host2uint16_t_le(parentp->firstc);
    511                 /* TODO: initialize also the date/time members. */
    512         }
    513         b->dirty = true;                /* need to sync block */
    514         block_put(b);
    515 
    516         childp->idx->pfc = parentp->firstc;
    517         childp->idx->pdi = i * dps + j;
    518         fibril_mutex_unlock(&childp->idx->lock);
    519 
    520         fibril_mutex_lock(&childp->lock);
    521         childp->lnkcnt = 1;
    522         childp->dirty = true;           /* need to sync node */
    523         fibril_mutex_unlock(&childp->lock);
    524 
    525         /*
    526          * Hash in the index structure into the position hash.
    527          */
    528         fat_idx_hashin(childp->idx);
    529 
    530         return EOK;
    531 }
    532 
    533 int fat_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
    534 {
    535         fat_node_t *parentp = FAT_NODE(pfn);
    536         fat_node_t *childp = FAT_NODE(cfn);
    537         fat_bs_t *bs;
    538         fat_dentry_t *d;
    539         uint16_t bps;
    540         block_t *b;
    541 
    542         if (!parentp)
    543                 return EBUSY;
    544        
    545         if (fat_has_children(cfn))
    546                 return ENOTEMPTY;
    547 
    548         fibril_mutex_lock(&parentp->lock);
    549         fibril_mutex_lock(&childp->lock);
    550         assert(childp->lnkcnt == 1);
    551         fibril_mutex_lock(&childp->idx->lock);
    552         bs = block_bb_get(childp->idx->dev_handle);
    553         bps = uint16_t_le2host(bs->bps);
    554 
    555         b = _fat_block_get(bs, childp->idx->dev_handle, childp->idx->pfc,
    556             (childp->idx->pdi * sizeof(fat_dentry_t)) / bps,
    557             BLOCK_FLAGS_NONE);
    558         d = (fat_dentry_t *)b->data +
    559             (childp->idx->pdi % (bps / sizeof(fat_dentry_t)));
    560         /* mark the dentry as not-currently-used */
    561         d->name[0] = FAT_DENTRY_ERASED;
    562         b->dirty = true;                /* need to sync block */
    563         block_put(b);
    564 
    565         /* remove the index structure from the position hash */
    566         fat_idx_hashout(childp->idx);
    567         /* clear position information */
    568         childp->idx->pfc = FAT_CLST_RES0;
    569         childp->idx->pdi = 0;
    570         fibril_mutex_unlock(&childp->idx->lock);
    571         childp->lnkcnt = 0;
    572         childp->dirty = true;
    573         fibril_mutex_unlock(&childp->lock);
    574         fibril_mutex_unlock(&parentp->lock);
    575 
    576         return EOK;
    577 }
    578 
    579 fs_node_t *fat_match(fs_node_t *pfn, const char *component)
     297int fat_root_get(fs_node_t **rfn, dev_handle_t dev_handle)
     298{
     299        return fat_node_get(rfn, dev_handle, 0);
     300}
     301
     302int fat_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
    580303{
    581304        fat_bs_t *bs;
     
    588311        fat_dentry_t *d;
    589312        block_t *b;
     313        int rc;
    590314
    591315        fibril_mutex_lock(&parentp->idx->lock);
     
    595319        blocks = parentp->size / bps;
    596320        for (i = 0; i < blocks; i++) {
    597                 b = fat_block_get(bs, parentp, i, BLOCK_FLAGS_NONE);
     321                rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE);
     322                if (rc != EOK) {
     323                        fibril_mutex_unlock(&parentp->idx->lock);
     324                        return rc;
     325                }
    598326                for (j = 0; j < dps; j++) {
    599327                        d = ((fat_dentry_t *)b->data) + j;
     
    603331                                continue;
    604332                        case FAT_DENTRY_LAST:
    605                                 block_put(b);
     333                                /* miss */
     334                                rc = block_put(b);
    606335                                fibril_mutex_unlock(&parentp->idx->lock);
    607                                 return NULL;
     336                                *rfn = NULL;
     337                                return rc;
    608338                        default:
    609339                        case FAT_DENTRY_VALID:
     
    629359                                         * run out of 32-bit indices.
    630360                                         */
    631                                         block_put(b);
    632                                         return NULL;
     361                                        rc = block_put(b);
     362                                        return (rc == EOK) ? ENOMEM : rc;
    633363                                }
    634                                 nodep = fat_node_get_core(idx);
     364                                rc = fat_node_get_core(&nodep, idx);
    635365                                fibril_mutex_unlock(&idx->lock);
    636                                 block_put(b);
    637                                 return FS_NODE(nodep);
     366                                if (rc != EOK) {
     367                                        (void) block_put(b);
     368                                        return rc;
     369                                }
     370                                *rfn = FS_NODE(nodep);
     371                                rc = block_put(b);
     372                                if (rc != EOK)
     373                                        (void) fat_node_put(*rfn);
     374                                return rc;
    638375                        }
    639376                }
    640                 block_put(b);
     377                rc = block_put(b);
     378                if (rc != EOK) {
     379                        fibril_mutex_unlock(&parentp->idx->lock);
     380                        return rc;
     381                }
    641382        }
    642383
    643384        fibril_mutex_unlock(&parentp->idx->lock);
    644         return NULL;
    645 }
    646 
    647 fs_index_t fat_index_get(fs_node_t *fn)
    648 {
    649         return FAT_NODE(fn)->idx->index;
    650 }
    651 
    652 size_t fat_size_get(fs_node_t *fn)
    653 {
    654         return FAT_NODE(fn)->size;
    655 }
    656 
    657 unsigned fat_lnkcnt_get(fs_node_t *fn)
    658 {
    659         return FAT_NODE(fn)->lnkcnt;
    660 }
    661 
    662 bool fat_has_children(fs_node_t *fn)
     385        *rfn = NULL;
     386        return EOK;
     387}
     388
     389/** Instantiate a FAT in-core node. */
     390int fat_node_get(fs_node_t **rfn, dev_handle_t dev_handle, fs_index_t index)
     391{
     392        fat_node_t *nodep;
     393        fat_idx_t *idxp;
     394        int rc;
     395
     396        idxp = fat_idx_get_by_index(dev_handle, index);
     397        if (!idxp) {
     398                *rfn = NULL;
     399                return EOK;
     400        }
     401        /* idxp->lock held */
     402        rc = fat_node_get_core(&nodep, idxp);
     403        fibril_mutex_unlock(&idxp->lock);
     404        if (rc == EOK)
     405                *rfn = FS_NODE(nodep);
     406        return rc;
     407}
     408
     409int fat_node_put(fs_node_t *fn)
     410{
     411        fat_node_t *nodep = FAT_NODE(fn);
     412        bool destroy = false;
     413
     414        fibril_mutex_lock(&nodep->lock);
     415        if (!--nodep->refcnt) {
     416                if (nodep->idx) {
     417                        fibril_mutex_lock(&ffn_mutex);
     418                        list_append(&nodep->ffn_link, &ffn_head);
     419                        fibril_mutex_unlock(&ffn_mutex);
     420                } else {
     421                        /*
     422                         * The node does not have any index structure associated
     423                         * with itself. This can only mean that we are releasing
     424                         * the node after a failed attempt to allocate the index
     425                         * structure for it.
     426                         */
     427                        destroy = true;
     428                }
     429        }
     430        fibril_mutex_unlock(&nodep->lock);
     431        if (destroy) {
     432                free(nodep->bp);
     433                free(nodep);
     434        }
     435        return EOK;
     436}
     437
     438int fat_create_node(fs_node_t **rfn, dev_handle_t dev_handle, int flags)
     439{
     440        fat_idx_t *idxp;
     441        fat_node_t *nodep;
     442        fat_bs_t *bs;
     443        fat_cluster_t mcl, lcl;
     444        uint16_t bps;
     445        int rc;
     446
     447        bs = block_bb_get(dev_handle);
     448        bps = uint16_t_le2host(bs->bps);
     449        if (flags & L_DIRECTORY) {
     450                /* allocate a cluster */
     451                rc = fat_alloc_clusters(bs, dev_handle, 1, &mcl, &lcl);
     452                if (rc != EOK)
     453                        return rc;
     454                /* populate the new cluster with unused dentries */
     455                rc = fat_zero_cluster(bs, dev_handle, mcl);
     456                if (rc != EOK) {
     457                        (void) fat_free_clusters(bs, dev_handle, mcl);
     458                        return rc;
     459                }
     460        }
     461
     462        rc = fat_node_get_new(&nodep);
     463        if (rc != EOK) {
     464                (void) fat_free_clusters(bs, dev_handle, mcl);
     465                return rc;
     466        }
     467        rc = fat_idx_get_new(&idxp, dev_handle);
     468        if (rc != EOK) {
     469                (void) fat_free_clusters(bs, dev_handle, mcl); 
     470                (void) fat_node_put(FS_NODE(nodep));
     471                return rc;
     472        }
     473        /* idxp->lock held */
     474        if (flags & L_DIRECTORY) {
     475                nodep->type = FAT_DIRECTORY;
     476                nodep->firstc = mcl;
     477                nodep->size = bps * bs->spc;
     478        } else {
     479                nodep->type = FAT_FILE;
     480                nodep->firstc = FAT_CLST_RES0;
     481                nodep->size = 0;
     482        }
     483        nodep->lnkcnt = 0;      /* not linked anywhere */
     484        nodep->refcnt = 1;
     485        nodep->dirty = true;
     486
     487        nodep->idx = idxp;
     488        idxp->nodep = nodep;
     489
     490        fibril_mutex_unlock(&idxp->lock);
     491        *rfn = FS_NODE(nodep);
     492        return EOK;
     493}
     494
     495int fat_destroy_node(fs_node_t *fn)
     496{
     497        fat_node_t *nodep = FAT_NODE(fn);
     498        fat_bs_t *bs;
     499        bool has_children;
     500        int rc;
     501
     502        /*
     503         * The node is not reachable from the file system. This means that the
     504         * link count should be zero and that the index structure cannot be
     505         * found in the position hash. Obviously, we don't need to lock the node
     506         * nor its index structure.
     507         */
     508        assert(nodep->lnkcnt == 0);
     509
     510        /*
     511         * The node may not have any children.
     512         */
     513        rc = fat_has_children(&has_children, fn);
     514        if (rc != EOK)
     515                return rc;
     516        assert(!has_children);
     517
     518        bs = block_bb_get(nodep->idx->dev_handle);
     519        if (nodep->firstc != FAT_CLST_RES0) {
     520                assert(nodep->size);
     521                /* Free all clusters allocated to the node. */
     522                rc = fat_free_clusters(bs, nodep->idx->dev_handle,
     523                    nodep->firstc);
     524        }
     525
     526        fat_idx_destroy(nodep->idx);
     527        free(nodep->bp);
     528        free(nodep);
     529        return rc;
     530}
     531
     532int fat_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
     533{
     534        fat_node_t *parentp = FAT_NODE(pfn);
     535        fat_node_t *childp = FAT_NODE(cfn);
     536        fat_dentry_t *d;
     537        fat_bs_t *bs;
     538        block_t *b;
     539        unsigned i, j;
     540        uint16_t bps;
     541        unsigned dps;
     542        unsigned blocks;
     543        fat_cluster_t mcl, lcl;
     544        int rc;
     545
     546        fibril_mutex_lock(&childp->lock);
     547        if (childp->lnkcnt == 1) {
     548                /*
     549                 * On FAT, we don't support multiple hard links.
     550                 */
     551                fibril_mutex_unlock(&childp->lock);
     552                return EMLINK;
     553        }
     554        assert(childp->lnkcnt == 0);
     555        fibril_mutex_unlock(&childp->lock);
     556
     557        if (!fat_dentry_name_verify(name)) {
     558                /*
     559                 * Attempt to create unsupported name.
     560                 */
     561                return ENOTSUP;
     562        }
     563
     564        /*
     565         * Get us an unused parent node's dentry or grow the parent and allocate
     566         * a new one.
     567         */
     568       
     569        fibril_mutex_lock(&parentp->idx->lock);
     570        bs = block_bb_get(parentp->idx->dev_handle);
     571        bps = uint16_t_le2host(bs->bps);
     572        dps = bps / sizeof(fat_dentry_t);
     573
     574        blocks = parentp->size / bps;
     575
     576        for (i = 0; i < blocks; i++) {
     577                rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE);
     578                if (rc != EOK) {
     579                        fibril_mutex_unlock(&parentp->idx->lock);
     580                        return rc;
     581                }
     582                for (j = 0; j < dps; j++) {
     583                        d = ((fat_dentry_t *)b->data) + j;
     584                        switch (fat_classify_dentry(d)) {
     585                        case FAT_DENTRY_SKIP:
     586                        case FAT_DENTRY_VALID:
     587                                /* skipping used and meta entries */
     588                                continue;
     589                        case FAT_DENTRY_FREE:
     590                        case FAT_DENTRY_LAST:
     591                                /* found an empty slot */
     592                                goto hit;
     593                        }
     594                }
     595                rc = block_put(b);
     596                if (rc != EOK) {
     597                        fibril_mutex_unlock(&parentp->idx->lock);
     598                        return rc;
     599                }
     600        }
     601        j = 0;
     602       
     603        /*
     604         * We need to grow the parent in order to create a new unused dentry.
     605         */
     606        if (parentp->firstc == FAT_CLST_ROOT) {
     607                /* Can't grow the root directory. */
     608                fibril_mutex_unlock(&parentp->idx->lock);
     609                return ENOSPC;
     610        }
     611        rc = fat_alloc_clusters(bs, parentp->idx->dev_handle, 1, &mcl, &lcl);
     612        if (rc != EOK) {
     613                fibril_mutex_unlock(&parentp->idx->lock);
     614                return rc;
     615        }
     616        rc = fat_zero_cluster(bs, parentp->idx->dev_handle, mcl);
     617        if (rc != EOK) {
     618                (void) fat_free_clusters(bs, parentp->idx->dev_handle, mcl);
     619                fibril_mutex_unlock(&parentp->idx->lock);
     620                return rc;
     621        }
     622        rc = fat_append_clusters(bs, parentp, mcl);
     623        if (rc != EOK) {
     624                (void) fat_free_clusters(bs, parentp->idx->dev_handle, mcl);
     625                fibril_mutex_unlock(&parentp->idx->lock);
     626                return rc;
     627        }
     628        parentp->size += bps * bs->spc;
     629        parentp->dirty = true;          /* need to sync node */
     630        rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE);
     631        if (rc != EOK) {
     632                fibril_mutex_unlock(&parentp->idx->lock);
     633                return rc;
     634        }
     635        d = (fat_dentry_t *)b->data;
     636
     637hit:
     638        /*
     639         * At this point we only establish the link between the parent and the
     640         * child.  The dentry, except of the name and the extension, will remain
     641         * uninitialized until the corresponding node is synced. Thus the valid
     642         * dentry data is kept in the child node structure.
     643         */
     644        memset(d, 0, sizeof(fat_dentry_t));
     645        fat_dentry_name_set(d, name);
     646        b->dirty = true;                /* need to sync block */
     647        rc = block_put(b);
     648        fibril_mutex_unlock(&parentp->idx->lock);
     649        if (rc != EOK)
     650                return rc;
     651
     652        fibril_mutex_lock(&childp->idx->lock);
     653       
     654        /*
     655         * If possible, create the Sub-directory Identifier Entry and the
     656         * Sub-directory Parent Pointer Entry (i.e. "." and ".."). These entries
     657         * are not mandatory according to Standard ECMA-107 and HelenOS VFS does
     658         * not use them anyway, so this is rather a sign of our good will.
     659         */
     660        rc = fat_block_get(&b, bs, childp, 0, BLOCK_FLAGS_NONE);
     661        if (rc != EOK) {
     662                /*
     663                 * Rather than returning an error, simply skip the creation of
     664                 * these two entries.
     665                 */
     666                goto skip_dots;
     667        }
     668        d = (fat_dentry_t *)b->data;
     669        if (fat_classify_dentry(d) == FAT_DENTRY_LAST ||
     670            str_cmp(d->name, FAT_NAME_DOT) == 0) {
     671                memset(d, 0, sizeof(fat_dentry_t));
     672                str_cpy(d->name, 8, FAT_NAME_DOT);
     673                str_cpy(d->ext, 3, FAT_EXT_PAD);
     674                d->attr = FAT_ATTR_SUBDIR;
     675                d->firstc = host2uint16_t_le(childp->firstc);
     676                /* TODO: initialize also the date/time members. */
     677        }
     678        d++;
     679        if (fat_classify_dentry(d) == FAT_DENTRY_LAST ||
     680            str_cmp(d->name, FAT_NAME_DOT_DOT) == 0) {
     681                memset(d, 0, sizeof(fat_dentry_t));
     682                str_cpy(d->name, 8, FAT_NAME_DOT_DOT);
     683                str_cpy(d->ext, 3, FAT_EXT_PAD);
     684                d->attr = FAT_ATTR_SUBDIR;
     685                d->firstc = (parentp->firstc == FAT_CLST_ROOT) ?
     686                    host2uint16_t_le(FAT_CLST_RES0) :
     687                    host2uint16_t_le(parentp->firstc);
     688                /* TODO: initialize also the date/time members. */
     689        }
     690        b->dirty = true;                /* need to sync block */
     691        /*
     692         * Ignore the return value as we would have fallen through on error
     693         * anyway.
     694         */
     695        (void) block_put(b);
     696skip_dots:
     697
     698        childp->idx->pfc = parentp->firstc;
     699        childp->idx->pdi = i * dps + j;
     700        fibril_mutex_unlock(&childp->idx->lock);
     701
     702        fibril_mutex_lock(&childp->lock);
     703        childp->lnkcnt = 1;
     704        childp->dirty = true;           /* need to sync node */
     705        fibril_mutex_unlock(&childp->lock);
     706
     707        /*
     708         * Hash in the index structure into the position hash.
     709         */
     710        fat_idx_hashin(childp->idx);
     711
     712        return EOK;
     713}
     714
     715int fat_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
     716{
     717        fat_node_t *parentp = FAT_NODE(pfn);
     718        fat_node_t *childp = FAT_NODE(cfn);
     719        fat_bs_t *bs;
     720        fat_dentry_t *d;
     721        uint16_t bps;
     722        block_t *b;
     723        bool has_children;
     724        int rc;
     725
     726        if (!parentp)
     727                return EBUSY;
     728       
     729        rc = fat_has_children(&has_children, cfn);
     730        if (rc != EOK)
     731                return rc;
     732        if (has_children)
     733                return ENOTEMPTY;
     734
     735        fibril_mutex_lock(&parentp->lock);
     736        fibril_mutex_lock(&childp->lock);
     737        assert(childp->lnkcnt == 1);
     738        fibril_mutex_lock(&childp->idx->lock);
     739        bs = block_bb_get(childp->idx->dev_handle);
     740        bps = uint16_t_le2host(bs->bps);
     741
     742        rc = _fat_block_get(&b, bs, childp->idx->dev_handle, childp->idx->pfc,
     743            (childp->idx->pdi * sizeof(fat_dentry_t)) / bps,
     744            BLOCK_FLAGS_NONE);
     745        if (rc != EOK)
     746                goto error;
     747        d = (fat_dentry_t *)b->data +
     748            (childp->idx->pdi % (bps / sizeof(fat_dentry_t)));
     749        /* mark the dentry as not-currently-used */
     750        d->name[0] = FAT_DENTRY_ERASED;
     751        b->dirty = true;                /* need to sync block */
     752        rc = block_put(b);
     753        if (rc != EOK)
     754                goto error;
     755
     756        /* remove the index structure from the position hash */
     757        fat_idx_hashout(childp->idx);
     758        /* clear position information */
     759        childp->idx->pfc = FAT_CLST_RES0;
     760        childp->idx->pdi = 0;
     761        fibril_mutex_unlock(&childp->idx->lock);
     762        childp->lnkcnt = 0;
     763        childp->dirty = true;
     764        fibril_mutex_unlock(&childp->lock);
     765        fibril_mutex_unlock(&parentp->lock);
     766
     767        return EOK;
     768
     769error:
     770        fibril_mutex_unlock(&parentp->idx->lock);
     771        fibril_mutex_unlock(&childp->lock);
     772        fibril_mutex_unlock(&childp->idx->lock);
     773        return rc;
     774}
     775
     776int fat_has_children(bool *has_children, fs_node_t *fn)
    663777{
    664778        fat_bs_t *bs;
     
    669783        block_t *b;
    670784        unsigned i, j;
    671 
    672         if (nodep->type != FAT_DIRECTORY)
    673                 return false;
     785        int rc;
     786
     787        if (nodep->type != FAT_DIRECTORY) {
     788                *has_children = false;
     789                return EOK;
     790        }
    674791       
    675792        fibril_mutex_lock(&nodep->idx->lock);
     
    683800                fat_dentry_t *d;
    684801       
    685                 b = fat_block_get(bs, nodep, i, BLOCK_FLAGS_NONE);
     802                rc = fat_block_get(&b, bs, nodep, i, BLOCK_FLAGS_NONE);
     803                if (rc != EOK) {
     804                        fibril_mutex_unlock(&nodep->idx->lock);
     805                        return rc;
     806                }
    686807                for (j = 0; j < dps; j++) {
    687808                        d = ((fat_dentry_t *)b->data) + j;
     
    691812                                continue;
    692813                        case FAT_DENTRY_LAST:
    693                                 block_put(b);
     814                                rc = block_put(b);
    694815                                fibril_mutex_unlock(&nodep->idx->lock);
    695                                 return false;
     816                                *has_children = false;
     817                                return rc;
    696818                        default:
    697819                        case FAT_DENTRY_VALID:
    698                                 block_put(b);
     820                                rc = block_put(b);
    699821                                fibril_mutex_unlock(&nodep->idx->lock);
    700                                 return true;
     822                                *has_children = true;
     823                                return rc;
    701824                        }
    702                         block_put(b);
     825                }
     826                rc = block_put(b);
     827                if (rc != EOK) {
    703828                        fibril_mutex_unlock(&nodep->idx->lock);
    704                         return true;
    705                 }
    706                 block_put(b);
     829                        return rc;     
     830                }
    707831        }
    708832
    709833        fibril_mutex_unlock(&nodep->idx->lock);
    710         return false;
    711 }
    712 
    713 fs_node_t *fat_root_get(dev_handle_t dev_handle)
    714 {
    715         return fat_node_get(dev_handle, 0);
     834        *has_children = false;
     835        return EOK;
     836}
     837
     838
     839fs_index_t fat_index_get(fs_node_t *fn)
     840{
     841        return FAT_NODE(fn)->idx->index;
     842}
     843
     844size_t fat_size_get(fs_node_t *fn)
     845{
     846        return FAT_NODE(fn)->size;
     847}
     848
     849unsigned fat_lnkcnt_get(fs_node_t *fn)
     850{
     851        return FAT_NODE(fn)->lnkcnt;
    716852}
    717853
     
    733869/** libfs operations */
    734870libfs_ops_t fat_libfs_ops = {
     871        .root_get = fat_root_get,
    735872        .match = fat_match,
    736873        .node_get = fat_node_get,
     
    740877        .link = fat_link,
    741878        .unlink = fat_unlink,
     879        .has_children = fat_has_children,
    742880        .index_get = fat_index_get,
    743881        .size_get = fat_size_get,
    744882        .lnkcnt_get = fat_lnkcnt_get,
    745         .has_children = fat_has_children,
    746         .root_get = fat_root_get,
    747883        .plb_get_char = fat_plb_get_char,
    748884        .is_directory = fat_is_directory,
     
    766902        ipc_callid_t callid;
    767903        size_t size;
    768         if (!ipc_data_write_receive(&callid, &size)) {
     904        if (!async_data_write_receive(&callid, &size)) {
    769905                ipc_answer_0(callid, EINVAL);
    770906                ipc_answer_0(rid, EINVAL);
     
    777913                return;
    778914        }
    779         ipcarg_t retval = ipc_data_write_finalize(callid, opts, size);
     915        ipcarg_t retval = async_data_write_finalize(callid, opts, size);
    780916        if (retval != EOK) {
    781917                ipc_answer_0(rid, retval);
     
    799935
    800936        /* prepare the boot block */
    801         rc = block_bb_read(dev_handle, BS_BLOCK * BS_SIZE, BS_SIZE);
     937        rc = block_bb_read(dev_handle, BS_BLOCK);
    802938        if (rc != EOK) {
    803939                block_fini(dev_handle);
     
    8951031        fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
    8961032        off_t pos = (off_t)IPC_GET_ARG3(*request);
    897         fs_node_t *fn = fat_node_get(dev_handle, index);
     1033        fs_node_t *fn;
    8981034        fat_node_t *nodep;
    8991035        fat_bs_t *bs;
     
    9011037        size_t bytes;
    9021038        block_t *b;
    903 
     1039        int rc;
     1040
     1041        rc = fat_node_get(&fn, dev_handle, index);
     1042        if (rc != EOK) {
     1043                ipc_answer_0(rid, rc);
     1044                return;
     1045        }
    9041046        if (!fn) {
    9051047                ipc_answer_0(rid, ENOENT);
     
    9101052        ipc_callid_t callid;
    9111053        size_t len;
    912         if (!ipc_data_read_receive(&callid, &len)) {
     1054        if (!async_data_read_receive(&callid, &len)) {
    9131055                fat_node_put(fn);
    9141056                ipc_answer_0(callid, EINVAL);
     
    9291071                        /* reading beyond the EOF */
    9301072                        bytes = 0;
    931                         (void) ipc_data_read_finalize(callid, NULL, 0);
     1073                        (void) async_data_read_finalize(callid, NULL, 0);
    9321074                } else {
    9331075                        bytes = min(len, bps - pos % bps);
    9341076                        bytes = min(bytes, nodep->size - pos);
    935                         b = fat_block_get(bs, nodep, pos / bps,
     1077                        rc = fat_block_get(&b, bs, nodep, pos / bps,
    9361078                            BLOCK_FLAGS_NONE);
    937                         (void) ipc_data_read_finalize(callid, b->data + pos % bps,
     1079                        if (rc != EOK) {
     1080                                fat_node_put(fn);
     1081                                ipc_answer_0(callid, rc);
     1082                                ipc_answer_0(rid, rc);
     1083                                return;
     1084                        }
     1085                        (void) async_data_read_finalize(callid, b->data + pos % bps,
    9381086                            bytes);
    939                         block_put(b);
     1087                        rc = block_put(b);
     1088                        if (rc != EOK) {
     1089                                fat_node_put(fn);
     1090                                ipc_answer_0(rid, rc);
     1091                                return;
     1092                        }
    9401093                }
    9411094        } else {
     
    9591112                        off_t o;
    9601113
    961                         b = fat_block_get(bs, nodep, bnum, BLOCK_FLAGS_NONE);
     1114                        rc = fat_block_get(&b, bs, nodep, bnum,
     1115                            BLOCK_FLAGS_NONE);
     1116                        if (rc != EOK)
     1117                                goto err;
    9621118                        for (o = pos % (bps / sizeof(fat_dentry_t));
    9631119                            o < bps / sizeof(fat_dentry_t);
     
    9691125                                        continue;
    9701126                                case FAT_DENTRY_LAST:
    971                                         block_put(b);
     1127                                        rc = block_put(b);
     1128                                        if (rc != EOK)
     1129                                                goto err;
    9721130                                        goto miss;
    9731131                                default:
    9741132                                case FAT_DENTRY_VALID:
    9751133                                        fat_dentry_name_get(d, name);
    976                                         block_put(b);
     1134                                        rc = block_put(b);
     1135                                        if (rc != EOK)
     1136                                                goto err;
    9771137                                        goto hit;
    9781138                                }
    9791139                        }
    980                         block_put(b);
     1140                        rc = block_put(b);
     1141                        if (rc != EOK)
     1142                                goto err;
    9811143                        bnum++;
    9821144                }
    9831145miss:
    984                 fat_node_put(fn);
    985                 ipc_answer_0(callid, ENOENT);
    986                 ipc_answer_1(rid, ENOENT, 0);
    987                 return;
     1146                rc = fat_node_put(fn);
     1147                ipc_answer_0(callid, rc != EOK ? rc : ENOENT);
     1148                ipc_answer_1(rid, rc != EOK ? rc : ENOENT, 0);
     1149                return;
     1150
     1151err:
     1152                (void) fat_node_put(fn);
     1153                ipc_answer_0(callid, rc);
     1154                ipc_answer_0(rid, rc);
     1155                return;
     1156
    9881157hit:
    989                 (void) ipc_data_read_finalize(callid, name, str_size(name) + 1);
     1158                (void) async_data_read_finalize(callid, name, str_size(name) + 1);
    9901159                bytes = (pos - spos) + 1;
    9911160        }
    9921161
    993         fat_node_put(fn);
    994         ipc_answer_1(rid, EOK, (ipcarg_t)bytes);
     1162        rc = fat_node_put(fn);
     1163        ipc_answer_1(rid, rc, (ipcarg_t)bytes);
    9951164}
    9961165
     
    10001169        fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
    10011170        off_t pos = (off_t)IPC_GET_ARG3(*request);
    1002         fs_node_t *fn = fat_node_get(dev_handle, index);
     1171        fs_node_t *fn;
    10031172        fat_node_t *nodep;
    10041173        fat_bs_t *bs;
    1005         size_t bytes;
     1174        size_t bytes, size;
    10061175        block_t *b;
    10071176        uint16_t bps;
     
    10101179        off_t boundary;
    10111180        int flags = BLOCK_FLAGS_NONE;
    1012        
     1181        int rc;
     1182       
     1183        rc = fat_node_get(&fn, dev_handle, index);
     1184        if (rc != EOK) {
     1185                ipc_answer_0(rid, rc);
     1186                return;
     1187        }
    10131188        if (!fn) {
    10141189                ipc_answer_0(rid, ENOENT);
     
    10191194        ipc_callid_t callid;
    10201195        size_t len;
    1021         if (!ipc_data_write_receive(&callid, &len)) {
    1022                 fat_node_put(fn);
     1196        if (!async_data_write_receive(&callid, &len)) {
     1197                (void) fat_node_put(fn);
    10231198                ipc_answer_0(callid, EINVAL);
    10241199                ipc_answer_0(rid, EINVAL);
     
    10501225                 * next block size boundary.
    10511226                 */
    1052                 fat_fill_gap(bs, nodep, FAT_CLST_RES0, pos);
    1053                 b = fat_block_get(bs, nodep, pos / bps, flags);
    1054                 (void) ipc_data_write_finalize(callid, b->data + pos % bps,
     1227                rc = fat_fill_gap(bs, nodep, FAT_CLST_RES0, pos);
     1228                if (rc != EOK) {
     1229                        (void) fat_node_put(fn);
     1230                        ipc_answer_0(callid, rc);
     1231                        ipc_answer_0(rid, rc);
     1232                        return;
     1233                }
     1234                rc = fat_block_get(&b, bs, nodep, pos / bps, flags);
     1235                if (rc != EOK) {
     1236                        (void) fat_node_put(fn);
     1237                        ipc_answer_0(callid, rc);
     1238                        ipc_answer_0(rid, rc);
     1239                        return;
     1240                }
     1241                (void) async_data_write_finalize(callid, b->data + pos % bps,
    10551242                    bytes);
    10561243                b->dirty = true;                /* need to sync block */
    1057                 block_put(b);
     1244                rc = block_put(b);
     1245                if (rc != EOK) {
     1246                        (void) fat_node_put(fn);
     1247                        ipc_answer_0(rid, rc);
     1248                        return;
     1249                }
    10581250                if (pos + bytes > nodep->size) {
    10591251                        nodep->size = pos + bytes;
    10601252                        nodep->dirty = true;    /* need to sync node */
    10611253                }
    1062                 ipc_answer_2(rid, EOK, bytes, nodep->size);     
    1063                 fat_node_put(fn);
     1254                size = nodep->size;
     1255                rc = fat_node_put(fn);
     1256                ipc_answer_2(rid, rc, bytes, nodep->size);
    10641257                return;
    10651258        } else {
     
    10681261                 * clusters for the node and zero them out.
    10691262                 */
    1070                 int status;
    10711263                unsigned nclsts;
    10721264                fat_cluster_t mcl, lcl;
     
    10741266                nclsts = (ROUND_UP(pos + bytes, bpc) - boundary) / bpc;
    10751267                /* create an independent chain of nclsts clusters in all FATs */
    1076                 status = fat_alloc_clusters(bs, dev_handle, nclsts, &mcl, &lcl);
    1077                 if (status != EOK) {
     1268                rc = fat_alloc_clusters(bs, dev_handle, nclsts, &mcl, &lcl);
     1269                if (rc != EOK) {
    10781270                        /* could not allocate a chain of nclsts clusters */
    1079                         fat_node_put(fn);
    1080                         ipc_answer_0(callid, status);
    1081                         ipc_answer_0(rid, status);
     1271                        (void) fat_node_put(fn);
     1272                        ipc_answer_0(callid, rc);
     1273                        ipc_answer_0(rid, rc);
    10821274                        return;
    10831275                }
    10841276                /* zero fill any gaps */
    1085                 fat_fill_gap(bs, nodep, mcl, pos);
    1086                 b = _fat_block_get(bs, dev_handle, lcl, (pos / bps) % spc,
     1277                rc = fat_fill_gap(bs, nodep, mcl, pos);
     1278                if (rc != EOK) {
     1279                        (void) fat_free_clusters(bs, dev_handle, mcl);
     1280                        (void) fat_node_put(fn);
     1281                        ipc_answer_0(callid, rc);
     1282                        ipc_answer_0(rid, rc);
     1283                        return;
     1284                }
     1285                rc = _fat_block_get(&b, bs, dev_handle, lcl, (pos / bps) % spc,
    10871286                    flags);
    1088                 (void) ipc_data_write_finalize(callid, b->data + pos % bps,
     1287                if (rc != EOK) {
     1288                        (void) fat_free_clusters(bs, dev_handle, mcl);
     1289                        (void) fat_node_put(fn);
     1290                        ipc_answer_0(callid, rc);
     1291                        ipc_answer_0(rid, rc);
     1292                        return;
     1293                }
     1294                (void) async_data_write_finalize(callid, b->data + pos % bps,
    10891295                    bytes);
    10901296                b->dirty = true;                /* need to sync block */
    1091                 block_put(b);
     1297                rc = block_put(b);
     1298                if (rc != EOK) {
     1299                        (void) fat_free_clusters(bs, dev_handle, mcl);
     1300                        (void) fat_node_put(fn);
     1301                        ipc_answer_0(rid, rc);
     1302                        return;
     1303                }
    10921304                /*
    10931305                 * Append the cluster chain starting in mcl to the end of the
    10941306                 * node's cluster chain.
    10951307                 */
    1096                 fat_append_clusters(bs, nodep, mcl);
    1097                 nodep->size = pos + bytes;
     1308                rc = fat_append_clusters(bs, nodep, mcl);
     1309                if (rc != EOK) {
     1310                        (void) fat_free_clusters(bs, dev_handle, mcl);
     1311                        (void) fat_node_put(fn);
     1312                        ipc_answer_0(rid, rc);
     1313                        return;
     1314                }
     1315                nodep->size = size = pos + bytes;
    10981316                nodep->dirty = true;            /* need to sync node */
    1099                 ipc_answer_2(rid, EOK, bytes, nodep->size);
    1100                 fat_node_put(fn);
     1317                rc = fat_node_put(fn);
     1318                ipc_answer_2(rid, rc, bytes, size);
    11011319                return;
    11021320        }
     
    11081326        fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
    11091327        size_t size = (off_t)IPC_GET_ARG3(*request);
    1110         fs_node_t *fn = fat_node_get(dev_handle, index);
     1328        fs_node_t *fn;
    11111329        fat_node_t *nodep;
    11121330        fat_bs_t *bs;
     
    11161334        int rc;
    11171335
     1336        rc = fat_node_get(&fn, dev_handle, index);
     1337        if (rc != EOK) {
     1338                ipc_answer_0(rid, rc);
     1339                return;
     1340        }
    11181341        if (!fn) {
    11191342                ipc_answer_0(rid, ENOENT);
     
    11471370                 */
    11481371                if (size == 0) {
    1149                         fat_chop_clusters(bs, nodep, FAT_CLST_RES0);
     1372                        rc = fat_chop_clusters(bs, nodep, FAT_CLST_RES0);
     1373                        if (rc != EOK)
     1374                                goto out;
    11501375                } else {
    11511376                        fat_cluster_t lastc;
    1152                         (void) fat_cluster_walk(bs, dev_handle, nodep->firstc,
    1153                             &lastc, (size - 1) / bpc);
    1154                         fat_chop_clusters(bs, nodep, lastc);
     1377                        rc = fat_cluster_walk(bs, dev_handle, nodep->firstc,
     1378                            &lastc, NULL, (size - 1) / bpc);
     1379                        if (rc != EOK)
     1380                                goto out;
     1381                        rc = fat_chop_clusters(bs, nodep, lastc);
     1382                        if (rc != EOK)
     1383                                goto out;
    11551384                }
    11561385                nodep->size = size;
     
    11581387                rc = EOK;       
    11591388        }
     1389out:
    11601390        fat_node_put(fn);
    11611391        ipc_answer_0(rid, rc);
     
    11721402        dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
    11731403        fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
     1404        fs_node_t *fn;
    11741405        int rc;
    11751406
    1176         fs_node_t *fn = fat_node_get(dev_handle, index);
     1407        rc = fat_node_get(&fn, dev_handle, index);
     1408        if (rc != EOK) {
     1409                ipc_answer_0(rid, rc);
     1410                return;
     1411        }
    11771412        if (!fn) {
    11781413                ipc_answer_0(rid, ENOENT);
Note: See TracChangeset for help on using the changeset viewer.