Changeset 2e37308 in mainline


Ignore:
Timestamp:
2009-09-25T11:50:12Z (15 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
6d4c549
Parents:
d27ed12 (diff), 12bdc942 (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:

Merge libfs error handling improvements.

Location:
uspace
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/libfs/libfs.c

    rd27ed12 r2e37308  
    4646#include <sys/stat.h>
    4747
     48#define on_error(rc, action) \
     49        do { \
     50                if ((rc) != EOK) \
     51                        action; \
     52        } while (0)
     53
     54#define combine_rc(rc1, rc2) \
     55        ((rc1) == EOK ? (rc2) : (rc1))
     56
     57#define answer_and_return(rid, rc) \
     58        do { \
     59                ipc_answer_0((rid), (rc)); \
     60                return; \
     61        } while (0)
     62
    4863/** Register file system server.
    4964 *
     
    162177        }
    163178
    164         fs_node_t *fn = ops->node_get(mp_dev_handle, mp_fs_index);
    165         if (!fn) {
     179        fs_node_t *fn;
     180        res = ops->node_get(&fn, mp_dev_handle, mp_fs_index);
     181        if (res != EOK || !fn) {
    166182                ipc_hangup(mountee_phone);
    167                 ipc_answer_0(callid, ENOENT);
    168                 ipc_answer_0(rid, ENOENT);
     183                ipc_answer_0(callid, combine_rc(res, ENOENT));
     184                ipc_answer_0(rid, combine_rc(res, ENOENT));
    169185                return;
    170186        }
     
    172188        if (fn->mp_data.mp_active) {
    173189                ipc_hangup(mountee_phone);
    174                 ops->node_put(fn);
     190                (void) ops->node_put(fn);
    175191                ipc_answer_0(callid, EBUSY);
    176192                ipc_answer_0(rid, EBUSY);
     
    179195
    180196        rc = async_req_0_0(mountee_phone, IPC_M_CONNECT_ME);
    181         if (rc != 0) {
     197        if (rc != EOK) {
    182198                ipc_hangup(mountee_phone);
    183                 ops->node_put(fn);
     199                (void) ops->node_put(fn);
    184200                ipc_answer_0(callid, rc);
    185201                ipc_answer_0(rid, rc);
     
    230246        char component[NAME_MAX + 1];
    231247        int len;
     248        int rc;
    232249
    233250        if (last < next)
     
    235252
    236253        fs_node_t *par = NULL;
    237         fs_node_t *cur = ops->root_get(dev_handle);
     254        fs_node_t *cur = NULL;
    238255        fs_node_t *tmp = NULL;
     256
     257        rc = ops->root_get(&cur, dev_handle);
     258        on_error(rc, goto out_with_answer);
    239259
    240260        if (cur->mp_data.mp_active) {
     
    242262                    next, last, cur->mp_data.dev_handle, lflag, index,
    243263                    IPC_FF_ROUTE_FROM_ME);
    244                 ops->node_put(cur);
     264                (void) ops->node_put(cur);
    245265                return;
    246266        }
     
    249269                next++;         /* eat slash */
    250270       
    251         while (next <= last && ops->has_children(cur)) {
     271        while (next <= last) {
     272                bool has_children;
     273
     274                rc = ops->has_children(&has_children, cur);
     275                on_error(rc, goto out_with_answer);
     276                if (!has_children)
     277                        break;
     278
    252279                /* collect the component */
    253280                len = 0;
     
    267294
    268295                /* match the component */
    269                 tmp = ops->match(cur, component);
     296                rc = ops->match(&tmp, cur, component);
     297                on_error(rc, goto out_with_answer);
     298
    270299                if (tmp && tmp->mp_data.mp_active) {
    271300                        if (next > last)
     
    277306                            VFS_OUT_LOOKUP, next, last, tmp->mp_data.dev_handle,
    278307                            lflag, index, IPC_FF_ROUTE_FROM_ME);
    279                         ops->node_put(cur);
    280                         ops->node_put(tmp);
     308                        (void) ops->node_put(cur);
     309                        (void) ops->node_put(tmp);
    281310                        if (par)
    282                                 ops->node_put(par);
     311                                (void) ops->node_put(par);
    283312                        return;
    284313                }
     
    300329                                fs_node_t *fn;
    301330                                if (lflag & L_CREATE)
    302                                         fn = ops->create(dev_handle, lflag);
     331                                        rc = ops->create(&fn, dev_handle,
     332                                            lflag);
    303333                                else
    304                                         fn = ops->node_get(dev_handle,
     334                                        rc = ops->node_get(&fn, dev_handle,
    305335                                            index);
     336                                on_error(rc, goto out_with_answer);
    306337                                if (fn) {
    307                                         int rc;
    308 
    309338                                        rc = ops->link(cur, fn, component);
    310339                                        if (rc != EOK) {
    311                                                 if (lflag & L_CREATE) {
    312                                                         (void)ops->destroy(fn);
    313                                                 }
     340                                                if (lflag & L_CREATE)
     341                                                        (void) ops->destroy(fn);
    314342                                                ipc_answer_0(rid, rc);
    315343                                        } else {
     
    319347                                                    ops->size_get(fn),
    320348                                                    ops->lnkcnt_get(fn));
    321                                                 ops->node_put(fn);
     349                                                (void) ops->node_put(fn);
    322350                                        }
    323351                                } else {
     
    330358                }
    331359
    332                 if (par)
    333                         ops->node_put(par);
     360                if (par) {
     361                        rc = ops->node_put(par);
     362                        on_error(rc, goto out_with_answer);
     363                }
    334364
    335365                /* descend one level */
     
    340370
    341371        /* handle miss: excessive components */
    342         if (next <= last && !ops->has_children(cur)) {
     372        if (next <= last) {
     373                bool has_children;
     374
     375                rc = ops->has_children(&has_children, cur);
     376                on_error(rc, goto out_with_answer);
     377                if (has_children)
     378                        goto skip_miss;
     379
    343380                if (lflag & (L_CREATE | L_LINK)) {
    344381                        if (!ops->is_directory(cur)) {
     
    368405                        fs_node_t *fn;
    369406                        if (lflag & L_CREATE)
    370                                 fn = ops->create(dev_handle, lflag);
     407                                rc = ops->create(&fn, dev_handle, lflag);
    371408                        else
    372                                 fn = ops->node_get(dev_handle, index);
     409                                rc = ops->node_get(&fn, dev_handle, index);
     410                        on_error(rc, goto out_with_answer);
    373411                        if (fn) {
    374                                 int rc;
    375 
    376412                                rc = ops->link(cur, fn, component);
    377413                                if (rc != EOK) {
    378414                                        if (lflag & L_CREATE)
    379                                                 (void)ops->destroy(fn);
     415                                                (void) ops->destroy(fn);
    380416                                        ipc_answer_0(rid, rc);
    381417                                } else {
     
    385421                                            ops->size_get(fn),
    386422                                            ops->lnkcnt_get(fn));
    387                                         ops->node_put(fn);
     423                                        (void) ops->node_put(fn);
    388424                                }
    389425                        } else {
     
    395431                goto out;
    396432        }
     433skip_miss:
    397434
    398435        /* handle hit */
    399436        if (lflag & L_UNLINK) {
    400437                unsigned old_lnkcnt = ops->lnkcnt_get(cur);
    401                 int res = ops->unlink(par, cur, component);
    402                 ipc_answer_5(rid, (ipcarg_t)res, fs_handle, dev_handle,
     438                rc = ops->unlink(par, cur, component);
     439                ipc_answer_5(rid, (ipcarg_t)rc, fs_handle, dev_handle,
    403440                    ops->index_get(cur), ops->size_get(cur), old_lnkcnt);
    404441                goto out;
     
    418455        }
    419456
    420         ipc_answer_5(rid, EOK, fs_handle, dev_handle, ops->index_get(cur),
    421             ops->size_get(cur), ops->lnkcnt_get(cur));
     457out_with_answer:
     458        if (rc == EOK) {
     459                ipc_answer_5(rid, EOK, fs_handle, dev_handle,
     460                    ops->index_get(cur), ops->size_get(cur),
     461                    ops->lnkcnt_get(cur));
     462        } else {
     463                ipc_answer_0(rid, rc);
     464        }
    422465
    423466out:
    424467        if (par)
    425                 ops->node_put(par);
     468                (void) ops->node_put(par);
    426469        if (cur)
    427                 ops->node_put(cur);
     470                (void) ops->node_put(cur);
    428471        if (tmp)
    429                 ops->node_put(tmp);
     472                (void) ops->node_put(tmp);
    430473}
    431474
     
    435478        dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request);
    436479        fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
    437         fs_node_t *fn = ops->node_get(dev_handle, index);
     480        fs_node_t *fn;
     481        int rc;
     482
     483        rc = ops->node_get(&fn, dev_handle, index);
     484        on_error(rc, answer_and_return(rid, rc));
    438485
    439486        ipc_callid_t callid;
     
    473520        dev_handle_t dev_handle = IPC_GET_ARG1(*request);
    474521        fs_index_t index = IPC_GET_ARG2(*request);
    475        
    476         fs_node_t *node = ops->node_get(dev_handle, index);
    477        
    478         if (node == NULL) {
     522        fs_node_t *fn;
     523        int rc;
     524       
     525        rc = ops->node_get(&fn, dev_handle, index);
     526        on_error(rc, answer_and_return(rid, rc));
     527       
     528        if (fn == NULL) {
    479529                ipc_answer_0(rid, ENOENT);
    480530                return;
    481531        }
    482532       
    483         ipc_answer_5(rid, EOK, fs_handle, dev_handle, index,
    484             ops->size_get(node), ops->lnkcnt_get(node));
    485        
    486         ops->node_put(node);
     533        ipc_answer_5(rid, EOK, fs_handle, dev_handle, index, ops->size_get(fn),
     534            ops->lnkcnt_get(fn));
     535       
     536        (void) ops->node_put(fn);
    487537}
    488538
  • uspace/lib/libfs/libfs.h

    rd27ed12 r2e37308  
    5656
    5757typedef struct {
    58         fs_node_t * (* match)(fs_node_t *, const char *);
    59         fs_node_t * (* node_get)(dev_handle_t, fs_index_t);
    60         void (* node_put)(fs_node_t *);
    61         fs_node_t * (* create)(dev_handle_t, int);
     58        /*
     59         * The first set of methods are functions that return an integer error
     60         * code. If some additional return value is to be returned, the first
     61         * argument holds the output argument.
     62         */
     63        int (* root_get)(fs_node_t **, dev_handle_t);
     64        int (* match)(fs_node_t **, fs_node_t *, const char *);
     65        int (* node_get)(fs_node_t **, dev_handle_t, fs_index_t);
     66        int (* node_put)(fs_node_t *);
     67        int (* create)(fs_node_t **, dev_handle_t, int);
    6268        int (* destroy)(fs_node_t *);
    6369        int (* link)(fs_node_t *, fs_node_t *, const char *);
    6470        int (* unlink)(fs_node_t *, fs_node_t *, const char *);
     71        int (* has_children)(bool *, fs_node_t *);
     72        /*
     73         * The second set of methods are usually mere getters that do not return
     74         * an integer error code.
     75         */
    6576        fs_index_t (* index_get)(fs_node_t *);
    6677        size_t (* size_get)(fs_node_t *);
    6778        unsigned (* lnkcnt_get)(fs_node_t *);
    68         bool (* has_children)(fs_node_t *);
    69         fs_node_t *(* root_get)(dev_handle_t);
    7079        char (* plb_get_char)(unsigned pos);
    7180        bool (* is_directory)(fs_node_t *);
  • uspace/srv/fs/fat/fat_ops.c

    rd27ed12 r2e37308  
    250250 * Forward declarations of FAT libfs operations.
    251251 */
    252 static fs_node_t *fat_node_get(dev_handle_t, fs_index_t);
    253 static void fat_node_put(fs_node_t *);
    254 static fs_node_t *fat_create_node(dev_handle_t, int);
     252static int fat_root_get(fs_node_t **, dev_handle_t);
     253static int fat_match(fs_node_t **, fs_node_t *, const char *);
     254static int fat_node_get(fs_node_t **, dev_handle_t, fs_index_t);
     255static int fat_node_put(fs_node_t *);
     256static int fat_create_node(fs_node_t **, dev_handle_t, int);
    255257static int fat_destroy_node(fs_node_t *);
    256258static int fat_link(fs_node_t *, fs_node_t *, const char *);
    257259static int fat_unlink(fs_node_t *, fs_node_t *, const char *);
    258 static fs_node_t *fat_match(fs_node_t *, const char *);
     260static int fat_has_children(bool *, fs_node_t *);
    259261static fs_index_t fat_index_get(fs_node_t *);
    260262static size_t fat_size_get(fs_node_t *);
    261263static unsigned fat_lnkcnt_get(fs_node_t *);
    262 static bool fat_has_children(fs_node_t *);
    263 static fs_node_t *fat_root_get(dev_handle_t);
    264264static char fat_plb_get_char(unsigned);
    265265static bool fat_is_directory(fs_node_t *);
     
    270270 */
    271271
    272 /** Instantiate a FAT in-core node. */
    273 fs_node_t *fat_node_get(dev_handle_t dev_handle, fs_index_t index)
    274 {
    275         fat_node_t *nodep;
    276         fat_idx_t *idxp;
    277 
    278         idxp = fat_idx_get_by_index(dev_handle, index);
    279         if (!idxp)
    280                 return NULL;
    281         /* idxp->lock held */
    282         nodep = fat_node_get_core(idxp);
    283         fibril_mutex_unlock(&idxp->lock);
    284         return FS_NODE(nodep);
    285 }
    286 
    287 void fat_node_put(fs_node_t *fn)
    288 {
    289         fat_node_t *nodep = FAT_NODE(fn);
    290         bool destroy = false;
    291 
    292         fibril_mutex_lock(&nodep->lock);
    293         if (!--nodep->refcnt) {
    294                 if (nodep->idx) {
    295                         fibril_mutex_lock(&ffn_mutex);
    296                         list_append(&nodep->ffn_link, &ffn_head);
    297                         fibril_mutex_unlock(&ffn_mutex);
    298                 } else {
    299                         /*
    300                          * The node does not have any index structure associated
    301                          * with itself. This can only mean that we are releasing
    302                          * the node after a failed attempt to allocate the index
    303                          * structure for it.
    304                          */
    305                         destroy = true;
    306                 }
    307         }
    308         fibril_mutex_unlock(&nodep->lock);
    309         if (destroy) {
    310                 free(nodep->bp);
    311                 free(nodep);
    312         }
    313 }
    314 
    315 fs_node_t *fat_create_node(dev_handle_t dev_handle, int flags)
    316 {
    317         fat_idx_t *idxp;
    318         fat_node_t *nodep;
    319         fat_bs_t *bs;
    320         fat_cluster_t mcl, lcl;
    321         uint16_t bps;
    322         int rc;
    323 
    324         bs = block_bb_get(dev_handle);
    325         bps = uint16_t_le2host(bs->bps);
    326         if (flags & L_DIRECTORY) {
    327                 /* allocate a cluster */
    328                 rc = fat_alloc_clusters(bs, dev_handle, 1, &mcl, &lcl);
    329                 if (rc != EOK)
    330                         return NULL;
    331         }
    332 
    333         nodep = fat_node_get_new();
    334         if (!nodep) {
    335                 (void) fat_free_clusters(bs, dev_handle, mcl);
    336                 return NULL;
    337         }
    338         idxp = fat_idx_get_new(dev_handle);
    339         if (!idxp) {
    340                 (void) fat_free_clusters(bs, dev_handle, mcl); 
    341                 fat_node_put(FS_NODE(nodep));
    342                 return NULL;
    343         }
    344         /* idxp->lock held */
    345         if (flags & L_DIRECTORY) {
    346                 /* Populate the new cluster with unused dentries. */
    347                 rc = fat_zero_cluster(bs, dev_handle, mcl);
    348                 assert(rc == EOK);
    349                 nodep->type = FAT_DIRECTORY;
    350                 nodep->firstc = mcl;
    351                 nodep->size = bps * bs->spc;
    352         } else {
    353                 nodep->type = FAT_FILE;
    354                 nodep->firstc = FAT_CLST_RES0;
    355                 nodep->size = 0;
    356         }
    357         nodep->lnkcnt = 0;      /* not linked anywhere */
    358         nodep->refcnt = 1;
    359         nodep->dirty = true;
    360 
    361         nodep->idx = idxp;
    362         idxp->nodep = nodep;
    363 
    364         fibril_mutex_unlock(&idxp->lock);
    365         return FS_NODE(nodep);
    366 }
    367 
    368 int fat_destroy_node(fs_node_t *fn)
    369 {
    370         fat_node_t *nodep = FAT_NODE(fn);
    371         fat_bs_t *bs;
    372         int rc = EOK;
    373 
    374         /*
    375          * The node is not reachable from the file system. This means that the
    376          * link count should be zero and that the index structure cannot be
    377          * found in the position hash. Obviously, we don't need to lock the node
    378          * nor its index structure.
    379          */
    380         assert(nodep->lnkcnt == 0);
    381 
    382         /*
    383          * The node may not have any children.
    384          */
    385         assert(fat_has_children(fn) == false);
    386 
    387         bs = block_bb_get(nodep->idx->dev_handle);
    388         if (nodep->firstc != FAT_CLST_RES0) {
    389                 assert(nodep->size);
    390                 /* Free all clusters allocated to the node. */
    391                 rc = fat_free_clusters(bs, nodep->idx->dev_handle,
    392                     nodep->firstc);
    393         }
    394 
    395         fat_idx_destroy(nodep->idx);
    396         free(nodep->bp);
    397         free(nodep);
    398         return rc;
    399 }
    400 
    401 int fat_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
    402 {
    403         fat_node_t *parentp = FAT_NODE(pfn);
    404         fat_node_t *childp = FAT_NODE(cfn);
    405         fat_dentry_t *d;
    406         fat_bs_t *bs;
    407         block_t *b;
    408         unsigned i, j;
    409         uint16_t bps;
    410         unsigned dps;
    411         unsigned blocks;
    412         fat_cluster_t mcl, lcl;
    413         int rc;
    414 
    415         fibril_mutex_lock(&childp->lock);
    416         if (childp->lnkcnt == 1) {
    417                 /*
    418                  * On FAT, we don't support multiple hard links.
    419                  */
    420                 fibril_mutex_unlock(&childp->lock);
    421                 return EMLINK;
    422         }
    423         assert(childp->lnkcnt == 0);
    424         fibril_mutex_unlock(&childp->lock);
    425 
    426         if (!fat_dentry_name_verify(name)) {
    427                 /*
    428                  * Attempt to create unsupported name.
    429                  */
    430                 return ENOTSUP;
    431         }
    432 
    433         /*
    434          * Get us an unused parent node's dentry or grow the parent and allocate
    435          * a new one.
    436          */
    437        
    438         fibril_mutex_lock(&parentp->idx->lock);
    439         bs = block_bb_get(parentp->idx->dev_handle);
    440         bps = uint16_t_le2host(bs->bps);
    441         dps = bps / sizeof(fat_dentry_t);
    442 
    443         blocks = parentp->size / bps;
    444 
    445         for (i = 0; i < blocks; i++) {
    446                 rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE);
    447                 if (rc != EOK) {
    448                         fibril_mutex_unlock(&parentp->idx->lock);
    449                         return rc;
    450                 }
    451                 for (j = 0; j < dps; j++) {
    452                         d = ((fat_dentry_t *)b->data) + j;
    453                         switch (fat_classify_dentry(d)) {
    454                         case FAT_DENTRY_SKIP:
    455                         case FAT_DENTRY_VALID:
    456                                 /* skipping used and meta entries */
    457                                 continue;
    458                         case FAT_DENTRY_FREE:
    459                         case FAT_DENTRY_LAST:
    460                                 /* found an empty slot */
    461                                 goto hit;
    462                         }
    463                 }
    464                 rc = block_put(b);
    465                 if (rc != EOK) {
    466                         fibril_mutex_unlock(&parentp->idx->lock);
    467                         return rc;
    468                 }
    469         }
    470         j = 0;
    471        
    472         /*
    473          * We need to grow the parent in order to create a new unused dentry.
    474          */
    475         if (parentp->firstc == FAT_CLST_ROOT) {
    476                 /* Can't grow the root directory. */
    477                 fibril_mutex_unlock(&parentp->idx->lock);
    478                 return ENOSPC;
    479         }
    480         rc = fat_alloc_clusters(bs, parentp->idx->dev_handle, 1, &mcl, &lcl);
    481         if (rc != EOK) {
    482                 fibril_mutex_unlock(&parentp->idx->lock);
    483                 return rc;
    484         }
    485         rc = fat_zero_cluster(bs, parentp->idx->dev_handle, mcl);
    486         if (rc != EOK) {
    487                 fibril_mutex_unlock(&parentp->idx->lock);
    488                 return rc;
    489         }
    490         rc = fat_append_clusters(bs, parentp, mcl);
    491         if (rc != EOK) {
    492                 fibril_mutex_unlock(&parentp->idx->lock);
    493                 return rc;
    494         }
    495         parentp->size += bps * bs->spc;
    496         parentp->dirty = true;          /* need to sync node */
    497         rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE);
    498         if (rc != EOK) {
    499                 fibril_mutex_unlock(&parentp->idx->lock);
    500                 return rc;
    501         }
    502         d = (fat_dentry_t *)b->data;
    503 
    504 hit:
    505         /*
    506          * At this point we only establish the link between the parent and the
    507          * child.  The dentry, except of the name and the extension, will remain
    508          * uninitialized until the corresponding node is synced. Thus the valid
    509          * dentry data is kept in the child node structure.
    510          */
    511         memset(d, 0, sizeof(fat_dentry_t));
    512         fat_dentry_name_set(d, name);
    513         b->dirty = true;                /* need to sync block */
    514         rc = block_put(b);
    515         fibril_mutex_unlock(&parentp->idx->lock);
    516         if (rc != EOK)
    517                 return rc;
    518 
    519         fibril_mutex_lock(&childp->idx->lock);
    520        
    521         /*
    522          * If possible, create the Sub-directory Identifier Entry and the
    523          * Sub-directory Parent Pointer Entry (i.e. "." and ".."). These entries
    524          * are not mandatory according to Standard ECMA-107 and HelenOS VFS does
    525          * not use them anyway, so this is rather a sign of our good will.
    526          */
    527         rc = fat_block_get(&b, bs, childp, 0, BLOCK_FLAGS_NONE);
    528         if (rc != EOK) {
    529                 /*
    530                  * Rather than returning an error, simply skip the creation of
    531                  * these two entries.
    532                  */
    533                 goto skip_dots;
    534         }
    535         d = (fat_dentry_t *)b->data;
    536         if (fat_classify_dentry(d) == FAT_DENTRY_LAST ||
    537             str_cmp(d->name, FAT_NAME_DOT) == 0) {
    538                 memset(d, 0, sizeof(fat_dentry_t));
    539                 str_cpy(d->name, 8, FAT_NAME_DOT);
    540                 str_cpy(d->ext, 3, FAT_EXT_PAD);
    541                 d->attr = FAT_ATTR_SUBDIR;
    542                 d->firstc = host2uint16_t_le(childp->firstc);
    543                 /* TODO: initialize also the date/time members. */
    544         }
    545         d++;
    546         if (fat_classify_dentry(d) == FAT_DENTRY_LAST ||
    547             str_cmp(d->name, FAT_NAME_DOT_DOT) == 0) {
    548                 memset(d, 0, sizeof(fat_dentry_t));
    549                 str_cpy(d->name, 8, FAT_NAME_DOT_DOT);
    550                 str_cpy(d->ext, 3, FAT_EXT_PAD);
    551                 d->attr = FAT_ATTR_SUBDIR;
    552                 d->firstc = (parentp->firstc == FAT_CLST_ROOT) ?
    553                     host2uint16_t_le(FAT_CLST_RES0) :
    554                     host2uint16_t_le(parentp->firstc);
    555                 /* TODO: initialize also the date/time members. */
    556         }
    557         b->dirty = true;                /* need to sync block */
    558         /*
    559          * Ignore the return value as we would have fallen through on error
    560          * anyway.
    561          */
    562         (void) block_put(b);
    563 skip_dots:
    564 
    565         childp->idx->pfc = parentp->firstc;
    566         childp->idx->pdi = i * dps + j;
    567         fibril_mutex_unlock(&childp->idx->lock);
    568 
    569         fibril_mutex_lock(&childp->lock);
    570         childp->lnkcnt = 1;
    571         childp->dirty = true;           /* need to sync node */
    572         fibril_mutex_unlock(&childp->lock);
    573 
    574         /*
    575          * Hash in the index structure into the position hash.
    576          */
    577         fat_idx_hashin(childp->idx);
    578 
    579         return EOK;
    580 }
    581 
    582 int fat_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
    583 {
    584         fat_node_t *parentp = FAT_NODE(pfn);
    585         fat_node_t *childp = FAT_NODE(cfn);
    586         fat_bs_t *bs;
    587         fat_dentry_t *d;
    588         uint16_t bps;
    589         block_t *b;
    590         int rc;
    591 
    592         if (!parentp)
    593                 return EBUSY;
    594        
    595         if (fat_has_children(cfn))
    596                 return ENOTEMPTY;
    597 
    598         fibril_mutex_lock(&parentp->lock);
    599         fibril_mutex_lock(&childp->lock);
    600         assert(childp->lnkcnt == 1);
    601         fibril_mutex_lock(&childp->idx->lock);
    602         bs = block_bb_get(childp->idx->dev_handle);
    603         bps = uint16_t_le2host(bs->bps);
    604 
    605         rc = _fat_block_get(&b, bs, childp->idx->dev_handle, childp->idx->pfc,
    606             (childp->idx->pdi * sizeof(fat_dentry_t)) / bps,
    607             BLOCK_FLAGS_NONE);
    608         if (rc != EOK)
    609                 goto error;
    610         d = (fat_dentry_t *)b->data +
    611             (childp->idx->pdi % (bps / sizeof(fat_dentry_t)));
    612         /* mark the dentry as not-currently-used */
    613         d->name[0] = FAT_DENTRY_ERASED;
    614         b->dirty = true;                /* need to sync block */
    615         rc = block_put(b);
    616         if (rc != EOK)
    617                 goto error;
    618 
    619         /* remove the index structure from the position hash */
    620         fat_idx_hashout(childp->idx);
    621         /* clear position information */
    622         childp->idx->pfc = FAT_CLST_RES0;
    623         childp->idx->pdi = 0;
    624         fibril_mutex_unlock(&childp->idx->lock);
    625         childp->lnkcnt = 0;
    626         childp->dirty = true;
    627         fibril_mutex_unlock(&childp->lock);
    628         fibril_mutex_unlock(&parentp->lock);
    629 
    630         return EOK;
    631 
    632 error:
    633         fibril_mutex_unlock(&parentp->idx->lock);
    634         fibril_mutex_unlock(&childp->lock);
    635         fibril_mutex_unlock(&childp->idx->lock);
    636         return rc;
    637 }
    638 
    639 fs_node_t *fat_match(fs_node_t *pfn, const char *component)
     272int fat_root_get(fs_node_t **rfn, dev_handle_t dev_handle)
     273{
     274        return fat_node_get(rfn, dev_handle, 0);
     275}
     276
     277int fat_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
    640278{
    641279        fat_bs_t *bs;
     
    657295        for (i = 0; i < blocks; i++) {
    658296                rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE);
    659                 assert(rc == EOK);
     297                if (rc != EOK) {
     298                        fibril_mutex_unlock(&parentp->idx->lock);
     299                        return rc;
     300                }
    660301                for (j = 0; j < dps; j++) {
    661302                        d = ((fat_dentry_t *)b->data) + j;
     
    666307                        case FAT_DENTRY_LAST:
    667308                                rc = block_put(b);
    668                                 assert(rc == EOK);
     309                                /* expect EOK as b was not dirty */
     310                                assert(rc == EOK);     
    669311                                fibril_mutex_unlock(&parentp->idx->lock);
    670                                 return NULL;
     312                                *rfn = NULL;
     313                                return EOK;
    671314                        default:
    672315                        case FAT_DENTRY_VALID:
     
    693336                                         */
    694337                                        rc = block_put(b);
    695                                         assert(rc == EOK);
    696                                         return NULL;
     338                                        /* expect EOK as b was not dirty */
     339                                        assert(rc == EOK);     
     340                                        return ENOMEM;
    697341                                }
    698342                                nodep = fat_node_get_core(idx);
    699343                                fibril_mutex_unlock(&idx->lock);
    700344                                rc = block_put(b);
     345                                /* expect EOK as b was not dirty */
    701346                                assert(rc == EOK);
    702                                 return FS_NODE(nodep);
     347                                *rfn = FS_NODE(nodep);
     348                                return EOK;
    703349                        }
    704350                }
    705351                rc = block_put(b);
    706                 assert(rc == EOK);
     352                assert(rc == EOK);      /* expect EOK as b was not dirty */
    707353        }
    708354
    709355        fibril_mutex_unlock(&parentp->idx->lock);
    710         return NULL;
    711 }
    712 
    713 fs_index_t fat_index_get(fs_node_t *fn)
    714 {
    715         return FAT_NODE(fn)->idx->index;
    716 }
    717 
    718 size_t fat_size_get(fs_node_t *fn)
    719 {
    720         return FAT_NODE(fn)->size;
    721 }
    722 
    723 unsigned fat_lnkcnt_get(fs_node_t *fn)
    724 {
    725         return FAT_NODE(fn)->lnkcnt;
    726 }
    727 
    728 bool fat_has_children(fs_node_t *fn)
     356        *rfn = NULL;
     357        return EOK;
     358}
     359
     360/** Instantiate a FAT in-core node. */
     361int fat_node_get(fs_node_t **rfn, dev_handle_t dev_handle, fs_index_t index)
     362{
     363        fat_node_t *nodep;
     364        fat_idx_t *idxp;
     365
     366        idxp = fat_idx_get_by_index(dev_handle, index);
     367        if (!idxp) {
     368                *rfn = NULL;
     369                return EOK;
     370        }
     371        /* idxp->lock held */
     372        nodep = fat_node_get_core(idxp);
     373        fibril_mutex_unlock(&idxp->lock);
     374        *rfn = FS_NODE(nodep);
     375        return EOK;
     376}
     377
     378int fat_node_put(fs_node_t *fn)
     379{
     380        fat_node_t *nodep = FAT_NODE(fn);
     381        bool destroy = false;
     382
     383        fibril_mutex_lock(&nodep->lock);
     384        if (!--nodep->refcnt) {
     385                if (nodep->idx) {
     386                        fibril_mutex_lock(&ffn_mutex);
     387                        list_append(&nodep->ffn_link, &ffn_head);
     388                        fibril_mutex_unlock(&ffn_mutex);
     389                } else {
     390                        /*
     391                         * The node does not have any index structure associated
     392                         * with itself. This can only mean that we are releasing
     393                         * the node after a failed attempt to allocate the index
     394                         * structure for it.
     395                         */
     396                        destroy = true;
     397                }
     398        }
     399        fibril_mutex_unlock(&nodep->lock);
     400        if (destroy) {
     401                free(nodep->bp);
     402                free(nodep);
     403        }
     404        return EOK;
     405}
     406
     407int fat_create_node(fs_node_t **rfn, dev_handle_t dev_handle, int flags)
     408{
     409        fat_idx_t *idxp;
     410        fat_node_t *nodep;
     411        fat_bs_t *bs;
     412        fat_cluster_t mcl, lcl;
     413        uint16_t bps;
     414        int rc;
     415
     416        bs = block_bb_get(dev_handle);
     417        bps = uint16_t_le2host(bs->bps);
     418        if (flags & L_DIRECTORY) {
     419                /* allocate a cluster */
     420                rc = fat_alloc_clusters(bs, dev_handle, 1, &mcl, &lcl);
     421                if (rc != EOK)
     422                        return rc;
     423                /* populate the new cluster with unused dentries */
     424                rc = fat_zero_cluster(bs, dev_handle, mcl);
     425                if (rc != EOK) {
     426                        (void) fat_free_clusters(bs, dev_handle, mcl);
     427                        return rc;
     428                }
     429        }
     430
     431        nodep = fat_node_get_new();
     432        if (!nodep) {
     433                (void) fat_free_clusters(bs, dev_handle, mcl);
     434                return ENOMEM;  /* FIXME: determine the true error code */
     435        }
     436        idxp = fat_idx_get_new(dev_handle);
     437        if (!idxp) {
     438                (void) fat_free_clusters(bs, dev_handle, mcl); 
     439                (void) fat_node_put(FS_NODE(nodep));
     440                return ENOMEM;  /* FIXME: determine the true error code */
     441        }
     442        /* idxp->lock held */
     443        if (flags & L_DIRECTORY) {
     444                nodep->type = FAT_DIRECTORY;
     445                nodep->firstc = mcl;
     446                nodep->size = bps * bs->spc;
     447        } else {
     448                nodep->type = FAT_FILE;
     449                nodep->firstc = FAT_CLST_RES0;
     450                nodep->size = 0;
     451        }
     452        nodep->lnkcnt = 0;      /* not linked anywhere */
     453        nodep->refcnt = 1;
     454        nodep->dirty = true;
     455
     456        nodep->idx = idxp;
     457        idxp->nodep = nodep;
     458
     459        fibril_mutex_unlock(&idxp->lock);
     460        *rfn = FS_NODE(nodep);
     461        return EOK;
     462}
     463
     464int fat_destroy_node(fs_node_t *fn)
     465{
     466        fat_node_t *nodep = FAT_NODE(fn);
     467        fat_bs_t *bs;
     468        bool has_children;
     469        int rc;
     470
     471        /*
     472         * The node is not reachable from the file system. This means that the
     473         * link count should be zero and that the index structure cannot be
     474         * found in the position hash. Obviously, we don't need to lock the node
     475         * nor its index structure.
     476         */
     477        assert(nodep->lnkcnt == 0);
     478
     479        /*
     480         * The node may not have any children.
     481         */
     482        rc = fat_has_children(&has_children, fn);
     483        if (rc != EOK)
     484                return rc;
     485        assert(!has_children);
     486
     487        bs = block_bb_get(nodep->idx->dev_handle);
     488        if (nodep->firstc != FAT_CLST_RES0) {
     489                assert(nodep->size);
     490                /* Free all clusters allocated to the node. */
     491                rc = fat_free_clusters(bs, nodep->idx->dev_handle,
     492                    nodep->firstc);
     493        }
     494
     495        fat_idx_destroy(nodep->idx);
     496        free(nodep->bp);
     497        free(nodep);
     498        return rc;
     499}
     500
     501int fat_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
     502{
     503        fat_node_t *parentp = FAT_NODE(pfn);
     504        fat_node_t *childp = FAT_NODE(cfn);
     505        fat_dentry_t *d;
     506        fat_bs_t *bs;
     507        block_t *b;
     508        unsigned i, j;
     509        uint16_t bps;
     510        unsigned dps;
     511        unsigned blocks;
     512        fat_cluster_t mcl, lcl;
     513        int rc;
     514
     515        fibril_mutex_lock(&childp->lock);
     516        if (childp->lnkcnt == 1) {
     517                /*
     518                 * On FAT, we don't support multiple hard links.
     519                 */
     520                fibril_mutex_unlock(&childp->lock);
     521                return EMLINK;
     522        }
     523        assert(childp->lnkcnt == 0);
     524        fibril_mutex_unlock(&childp->lock);
     525
     526        if (!fat_dentry_name_verify(name)) {
     527                /*
     528                 * Attempt to create unsupported name.
     529                 */
     530                return ENOTSUP;
     531        }
     532
     533        /*
     534         * Get us an unused parent node's dentry or grow the parent and allocate
     535         * a new one.
     536         */
     537       
     538        fibril_mutex_lock(&parentp->idx->lock);
     539        bs = block_bb_get(parentp->idx->dev_handle);
     540        bps = uint16_t_le2host(bs->bps);
     541        dps = bps / sizeof(fat_dentry_t);
     542
     543        blocks = parentp->size / bps;
     544
     545        for (i = 0; i < blocks; i++) {
     546                rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE);
     547                if (rc != EOK) {
     548                        fibril_mutex_unlock(&parentp->idx->lock);
     549                        return rc;
     550                }
     551                for (j = 0; j < dps; j++) {
     552                        d = ((fat_dentry_t *)b->data) + j;
     553                        switch (fat_classify_dentry(d)) {
     554                        case FAT_DENTRY_SKIP:
     555                        case FAT_DENTRY_VALID:
     556                                /* skipping used and meta entries */
     557                                continue;
     558                        case FAT_DENTRY_FREE:
     559                        case FAT_DENTRY_LAST:
     560                                /* found an empty slot */
     561                                goto hit;
     562                        }
     563                }
     564                rc = block_put(b);
     565                if (rc != EOK) {
     566                        fibril_mutex_unlock(&parentp->idx->lock);
     567                        return rc;
     568                }
     569        }
     570        j = 0;
     571       
     572        /*
     573         * We need to grow the parent in order to create a new unused dentry.
     574         */
     575        if (parentp->firstc == FAT_CLST_ROOT) {
     576                /* Can't grow the root directory. */
     577                fibril_mutex_unlock(&parentp->idx->lock);
     578                return ENOSPC;
     579        }
     580        rc = fat_alloc_clusters(bs, parentp->idx->dev_handle, 1, &mcl, &lcl);
     581        if (rc != EOK) {
     582                fibril_mutex_unlock(&parentp->idx->lock);
     583                return rc;
     584        }
     585        rc = fat_zero_cluster(bs, parentp->idx->dev_handle, mcl);
     586        if (rc != EOK) {
     587                (void) fat_free_clusters(bs, parentp->idx->dev_handle, mcl);
     588                fibril_mutex_unlock(&parentp->idx->lock);
     589                return rc;
     590        }
     591        rc = fat_append_clusters(bs, parentp, mcl);
     592        if (rc != EOK) {
     593                (void) fat_free_clusters(bs, parentp->idx->dev_handle, mcl);
     594                fibril_mutex_unlock(&parentp->idx->lock);
     595                return rc;
     596        }
     597        parentp->size += bps * bs->spc;
     598        parentp->dirty = true;          /* need to sync node */
     599        rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE);
     600        if (rc != EOK) {
     601                fibril_mutex_unlock(&parentp->idx->lock);
     602                return rc;
     603        }
     604        d = (fat_dentry_t *)b->data;
     605
     606hit:
     607        /*
     608         * At this point we only establish the link between the parent and the
     609         * child.  The dentry, except of the name and the extension, will remain
     610         * uninitialized until the corresponding node is synced. Thus the valid
     611         * dentry data is kept in the child node structure.
     612         */
     613        memset(d, 0, sizeof(fat_dentry_t));
     614        fat_dentry_name_set(d, name);
     615        b->dirty = true;                /* need to sync block */
     616        rc = block_put(b);
     617        fibril_mutex_unlock(&parentp->idx->lock);
     618        if (rc != EOK)
     619                return rc;
     620
     621        fibril_mutex_lock(&childp->idx->lock);
     622       
     623        /*
     624         * If possible, create the Sub-directory Identifier Entry and the
     625         * Sub-directory Parent Pointer Entry (i.e. "." and ".."). These entries
     626         * are not mandatory according to Standard ECMA-107 and HelenOS VFS does
     627         * not use them anyway, so this is rather a sign of our good will.
     628         */
     629        rc = fat_block_get(&b, bs, childp, 0, BLOCK_FLAGS_NONE);
     630        if (rc != EOK) {
     631                /*
     632                 * Rather than returning an error, simply skip the creation of
     633                 * these two entries.
     634                 */
     635                goto skip_dots;
     636        }
     637        d = (fat_dentry_t *)b->data;
     638        if (fat_classify_dentry(d) == FAT_DENTRY_LAST ||
     639            str_cmp(d->name, FAT_NAME_DOT) == 0) {
     640                memset(d, 0, sizeof(fat_dentry_t));
     641                str_cpy(d->name, 8, FAT_NAME_DOT);
     642                str_cpy(d->ext, 3, FAT_EXT_PAD);
     643                d->attr = FAT_ATTR_SUBDIR;
     644                d->firstc = host2uint16_t_le(childp->firstc);
     645                /* TODO: initialize also the date/time members. */
     646        }
     647        d++;
     648        if (fat_classify_dentry(d) == FAT_DENTRY_LAST ||
     649            str_cmp(d->name, FAT_NAME_DOT_DOT) == 0) {
     650                memset(d, 0, sizeof(fat_dentry_t));
     651                str_cpy(d->name, 8, FAT_NAME_DOT_DOT);
     652                str_cpy(d->ext, 3, FAT_EXT_PAD);
     653                d->attr = FAT_ATTR_SUBDIR;
     654                d->firstc = (parentp->firstc == FAT_CLST_ROOT) ?
     655                    host2uint16_t_le(FAT_CLST_RES0) :
     656                    host2uint16_t_le(parentp->firstc);
     657                /* TODO: initialize also the date/time members. */
     658        }
     659        b->dirty = true;                /* need to sync block */
     660        /*
     661         * Ignore the return value as we would have fallen through on error
     662         * anyway.
     663         */
     664        (void) block_put(b);
     665skip_dots:
     666
     667        childp->idx->pfc = parentp->firstc;
     668        childp->idx->pdi = i * dps + j;
     669        fibril_mutex_unlock(&childp->idx->lock);
     670
     671        fibril_mutex_lock(&childp->lock);
     672        childp->lnkcnt = 1;
     673        childp->dirty = true;           /* need to sync node */
     674        fibril_mutex_unlock(&childp->lock);
     675
     676        /*
     677         * Hash in the index structure into the position hash.
     678         */
     679        fat_idx_hashin(childp->idx);
     680
     681        return EOK;
     682}
     683
     684int fat_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
     685{
     686        fat_node_t *parentp = FAT_NODE(pfn);
     687        fat_node_t *childp = FAT_NODE(cfn);
     688        fat_bs_t *bs;
     689        fat_dentry_t *d;
     690        uint16_t bps;
     691        block_t *b;
     692        bool has_children;
     693        int rc;
     694
     695        if (!parentp)
     696                return EBUSY;
     697       
     698        rc = fat_has_children(&has_children, cfn);
     699        if (rc != EOK)
     700                return rc;
     701        if (has_children)
     702                return ENOTEMPTY;
     703
     704        fibril_mutex_lock(&parentp->lock);
     705        fibril_mutex_lock(&childp->lock);
     706        assert(childp->lnkcnt == 1);
     707        fibril_mutex_lock(&childp->idx->lock);
     708        bs = block_bb_get(childp->idx->dev_handle);
     709        bps = uint16_t_le2host(bs->bps);
     710
     711        rc = _fat_block_get(&b, bs, childp->idx->dev_handle, childp->idx->pfc,
     712            (childp->idx->pdi * sizeof(fat_dentry_t)) / bps,
     713            BLOCK_FLAGS_NONE);
     714        if (rc != EOK)
     715                goto error;
     716        d = (fat_dentry_t *)b->data +
     717            (childp->idx->pdi % (bps / sizeof(fat_dentry_t)));
     718        /* mark the dentry as not-currently-used */
     719        d->name[0] = FAT_DENTRY_ERASED;
     720        b->dirty = true;                /* need to sync block */
     721        rc = block_put(b);
     722        if (rc != EOK)
     723                goto error;
     724
     725        /* remove the index structure from the position hash */
     726        fat_idx_hashout(childp->idx);
     727        /* clear position information */
     728        childp->idx->pfc = FAT_CLST_RES0;
     729        childp->idx->pdi = 0;
     730        fibril_mutex_unlock(&childp->idx->lock);
     731        childp->lnkcnt = 0;
     732        childp->dirty = true;
     733        fibril_mutex_unlock(&childp->lock);
     734        fibril_mutex_unlock(&parentp->lock);
     735
     736        return EOK;
     737
     738error:
     739        fibril_mutex_unlock(&parentp->idx->lock);
     740        fibril_mutex_unlock(&childp->lock);
     741        fibril_mutex_unlock(&childp->idx->lock);
     742        return rc;
     743}
     744
     745int fat_has_children(bool *has_children, fs_node_t *fn)
    729746{
    730747        fat_bs_t *bs;
     
    737754        int rc;
    738755
    739         if (nodep->type != FAT_DIRECTORY)
    740                 return false;
     756        if (nodep->type != FAT_DIRECTORY) {
     757                *has_children = false;
     758                return EOK;
     759        }
    741760       
    742761        fibril_mutex_lock(&nodep->idx->lock);
     
    751770       
    752771                rc = fat_block_get(&b, bs, nodep, i, BLOCK_FLAGS_NONE);
    753                 assert(rc == EOK);
     772                if (rc != EOK) {
     773                        fibril_mutex_unlock(&nodep->idx->lock);
     774                        return rc;
     775                }
    754776                for (j = 0; j < dps; j++) {
    755777                        d = ((fat_dentry_t *)b->data) + j;
     
    760782                        case FAT_DENTRY_LAST:
    761783                                rc = block_put(b);
     784                                /* expect EOK as b was not dirty */
    762785                                assert(rc == EOK);
    763786                                fibril_mutex_unlock(&nodep->idx->lock);
    764                                 return false;
     787                                *has_children = false;
     788                                return EOK;
    765789                        default:
    766790                        case FAT_DENTRY_VALID:
    767791                                rc = block_put(b);
     792                                /* expect EOK as b was not dirty */
    768793                                assert(rc == EOK);
    769794                                fibril_mutex_unlock(&nodep->idx->lock);
    770                                 return true;
     795                                *has_children = true;
     796                                return EOK;
    771797                        }
    772                         rc = block_put(b);
    773                         assert(rc == EOK);
    774                         fibril_mutex_unlock(&nodep->idx->lock);
    775                         return true;
    776798                }
    777799                rc = block_put(b);
    778                 assert(rc == EOK);
     800                assert(rc == EOK);      /* expect EOK as b was not dirty */
    779801        }
    780802
    781803        fibril_mutex_unlock(&nodep->idx->lock);
    782         return false;
    783 }
    784 
    785 fs_node_t *fat_root_get(dev_handle_t dev_handle)
    786 {
    787         return fat_node_get(dev_handle, 0);
     804        *has_children = false;
     805        return EOK;
     806}
     807
     808
     809fs_index_t fat_index_get(fs_node_t *fn)
     810{
     811        return FAT_NODE(fn)->idx->index;
     812}
     813
     814size_t fat_size_get(fs_node_t *fn)
     815{
     816        return FAT_NODE(fn)->size;
     817}
     818
     819unsigned fat_lnkcnt_get(fs_node_t *fn)
     820{
     821        return FAT_NODE(fn)->lnkcnt;
    788822}
    789823
     
    805839/** libfs operations */
    806840libfs_ops_t fat_libfs_ops = {
     841        .root_get = fat_root_get,
    807842        .match = fat_match,
    808843        .node_get = fat_node_get,
     
    812847        .link = fat_link,
    813848        .unlink = fat_unlink,
     849        .has_children = fat_has_children,
    814850        .index_get = fat_index_get,
    815851        .size_get = fat_size_get,
    816852        .lnkcnt_get = fat_lnkcnt_get,
    817         .has_children = fat_has_children,
    818         .root_get = fat_root_get,
    819853        .plb_get_char = fat_plb_get_char,
    820854        .is_directory = fat_is_directory,
     
    9671001        fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
    9681002        off_t pos = (off_t)IPC_GET_ARG3(*request);
    969         fs_node_t *fn = fat_node_get(dev_handle, index);
     1003        fs_node_t *fn;
    9701004        fat_node_t *nodep;
    9711005        fat_bs_t *bs;
     
    9751009        int rc;
    9761010
     1011        rc = fat_node_get(&fn, dev_handle, index);
     1012        if (rc != EOK) {
     1013                ipc_answer_0(rid, rc);
     1014                return;
     1015        }
    9771016        if (!fn) {
    9781017                ipc_answer_0(rid, ENOENT);
     
    10521091                                case FAT_DENTRY_VALID:
    10531092                                        fat_dentry_name_get(d, name);
    1054                                         rc == block_put(b);
     1093                                        rc = block_put(b);
    10551094                                        assert(rc == EOK);
    10561095                                        goto hit;
     
    10801119        fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
    10811120        off_t pos = (off_t)IPC_GET_ARG3(*request);
    1082         fs_node_t *fn = fat_node_get(dev_handle, index);
     1121        fs_node_t *fn;
    10831122        fat_node_t *nodep;
    10841123        fat_bs_t *bs;
     
    10921131        int rc;
    10931132       
     1133        rc = fat_node_get(&fn, dev_handle, index);
     1134        if (rc != EOK) {
     1135                ipc_answer_0(rid, rc);
     1136                return;
     1137        }
    10941138        if (!fn) {
    10951139                ipc_answer_0(rid, ENOENT);
     
    11961240        fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
    11971241        size_t size = (off_t)IPC_GET_ARG3(*request);
    1198         fs_node_t *fn = fat_node_get(dev_handle, index);
     1242        fs_node_t *fn;
    11991243        fat_node_t *nodep;
    12001244        fat_bs_t *bs;
     
    12041248        int rc;
    12051249
     1250        rc = fat_node_get(&fn, dev_handle, index);
     1251        if (rc != EOK) {
     1252                ipc_answer_0(rid, rc);
     1253                return;
     1254        }
    12061255        if (!fn) {
    12071256                ipc_answer_0(rid, ENOENT);
     
    12671316        dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
    12681317        fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
     1318        fs_node_t *fn;
    12691319        int rc;
    12701320
    1271         fs_node_t *fn = fat_node_get(dev_handle, index);
     1321        rc = fat_node_get(&fn, dev_handle, index);
     1322        if (rc != EOK) {
     1323                ipc_answer_0(rid, rc);
     1324                return;
     1325        }
    12721326        if (!fn) {
    12731327                ipc_answer_0(rid, ENOENT);
  • uspace/srv/fs/tmpfs/tmpfs_dump.c

    rd27ed12 r2e37308  
    8282                                return false;
    8383                       
    84                         fn = ops->create(dev, L_FILE);
    85                         if (fn == NULL) {
     84                        rc = ops->create(&fn, dev, L_FILE);
     85                        if (rc != EOK || fn == NULL) {
    8686                                free(fname);
    8787                                return false;
     
    9090                        if (block_seqread(dev, bufpos, buflen, pos, fname,
    9191                            entry.len) != EOK) {
    92                                 ops->destroy(fn);
     92                                (void) ops->destroy(fn);
    9393                                free(fname);
    9494                                return false;
     
    9898                        rc = ops->link(pfn, fn, fname);
    9999                        if (rc != EOK) {
    100                                 ops->destroy(fn);
     100                                (void) ops->destroy(fn);
    101101                                free(fname);
    102102                                return false;
     
    126126                                return false;
    127127                       
    128                         fn = ops->create(dev, L_DIRECTORY);
    129                         if (fn == NULL) {
     128                        rc = ops->create(&fn, dev, L_DIRECTORY);
     129                        if (rc != EOK || fn == NULL) {
    130130                                free(fname);
    131131                                return false;
     
    134134                        if (block_seqread(dev, bufpos, buflen, pos, fname,
    135135                            entry.len) != EOK) {
    136                                 ops->destroy(fn);
     136                                (void) ops->destroy(fn);
    137137                                free(fname);
    138138                                return false;
     
    142142                        rc = ops->link(pfn, fn, fname);
    143143                        if (rc != EOK) {
    144                                 ops->destroy(fn);
     144                                (void) ops->destroy(fn);
    145145                                free(fname);
    146146                                return false;
     
    164164{
    165165        libfs_ops_t *ops = &tmpfs_libfs_ops;
     166        fs_node_t *fn;
    166167        int rc;
    167168
     
    182183                goto error;
    183184       
    184         if (!tmpfs_restore_recursion(dev, &bufpos, &buflen, &pos,
    185             ops->root_get(dev)))
     185        rc = ops->root_get(&fn, dev);
     186        if (rc != EOK)
     187                goto error;
     188
     189        if (!tmpfs_restore_recursion(dev, &bufpos, &buflen, &pos, fn))
    186190                goto error;
    187191               
  • uspace/srv/fs/tmpfs/tmpfs_ops.c

    rd27ed12 r2e37308  
    6767
    6868/* Forward declarations of static functions. */
    69 static fs_node_t *tmpfs_match(fs_node_t *, const char *);
    70 static fs_node_t *tmpfs_node_get(dev_handle_t, fs_index_t);
    71 static void tmpfs_node_put(fs_node_t *);
    72 static fs_node_t *tmpfs_create_node(dev_handle_t, int);
     69static int tmpfs_match(fs_node_t **, fs_node_t *, const char *);
     70static int tmpfs_node_get(fs_node_t **, dev_handle_t, fs_index_t);
     71static int tmpfs_node_put(fs_node_t *);
     72static int tmpfs_create_node(fs_node_t **, dev_handle_t, int);
     73static int tmpfs_destroy_node(fs_node_t *);
    7374static int tmpfs_link_node(fs_node_t *, fs_node_t *, const char *);
    7475static int tmpfs_unlink_node(fs_node_t *, fs_node_t *, const char *);
    75 static int tmpfs_destroy_node(fs_node_t *);
    7676
    7777/* Implementation of helper functions. */
     78static int tmpfs_root_get(fs_node_t **rfn, dev_handle_t dev_handle)
     79{
     80        return tmpfs_node_get(rfn, dev_handle, TMPFS_SOME_ROOT);
     81}
     82
     83static int tmpfs_has_children(bool *has_children, fs_node_t *fn)
     84{
     85        *has_children = !list_empty(&TMPFS_NODE(fn)->cs_head);
     86        return EOK;
     87}
     88
    7889static fs_index_t tmpfs_index_get(fs_node_t *fn)
    7990{
     
    89100{
    90101        return TMPFS_NODE(fn)->lnkcnt;
    91 }
    92 
    93 static bool tmpfs_has_children(fs_node_t *fn)
    94 {
    95         return !list_empty(&TMPFS_NODE(fn)->cs_head);
    96 }
    97 
    98 static fs_node_t *tmpfs_root_get(dev_handle_t dev_handle)
    99 {
    100         return tmpfs_node_get(dev_handle, TMPFS_SOME_ROOT);
    101102}
    102103
     
    118119/** libfs operations */
    119120libfs_ops_t tmpfs_libfs_ops = {
     121        .root_get = tmpfs_root_get,
    120122        .match = tmpfs_match,
    121123        .node_get = tmpfs_node_get,
     
    125127        .link = tmpfs_link_node,
    126128        .unlink = tmpfs_unlink_node,
     129        .has_children = tmpfs_has_children,
    127130        .index_get = tmpfs_index_get,
    128131        .size_get = tmpfs_size_get,
    129132        .lnkcnt_get = tmpfs_lnkcnt_get,
    130         .has_children = tmpfs_has_children,
    131         .root_get = tmpfs_root_get,
    132133        .plb_get_char = tmpfs_plb_get_char,
    133134        .is_directory = tmpfs_is_directory,
     
    197198{
    198199        fs_node_t *rfn;
     200        int rc;
    199201       
    200         rfn = tmpfs_create_node(dev_handle, L_DIRECTORY);
    201         if (!rfn)
     202        rc = tmpfs_create_node(&rfn, dev_handle, L_DIRECTORY);
     203        if (rc != EOK || !rfn)
    202204                return false;
    203205        TMPFS_NODE(rfn)->lnkcnt = 0;    /* FS root is not linked */
     
    205207}
    206208
    207 fs_node_t *tmpfs_match(fs_node_t *pfn, const char *component)
     209int tmpfs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
    208210{
    209211        tmpfs_node_t *parentp = TMPFS_NODE(pfn);
     
    212214        for (lnk = parentp->cs_head.next; lnk != &parentp->cs_head;
    213215            lnk = lnk->next) {
    214                 tmpfs_dentry_t *dentryp = list_get_instance(lnk, tmpfs_dentry_t,
    215                     link);
    216                 if (!str_cmp(dentryp->name, component))
    217                         return FS_NODE(dentryp->node);
    218         }
    219 
    220         return NULL;
    221 }
    222 
    223 fs_node_t *tmpfs_node_get(dev_handle_t dev_handle, fs_index_t index)
     216                tmpfs_dentry_t *dentryp;
     217                dentryp = list_get_instance(lnk, tmpfs_dentry_t, link);
     218                if (!str_cmp(dentryp->name, component)) {
     219                        *rfn = FS_NODE(dentryp->node);
     220                        return EOK;
     221                }
     222        }
     223
     224        *rfn = NULL;
     225        return EOK;
     226}
     227
     228int tmpfs_node_get(fs_node_t **rfn, dev_handle_t dev_handle, fs_index_t index)
    224229{
    225230        unsigned long key[] = {
     
    228233        };
    229234        link_t *lnk = hash_table_find(&nodes, key);
    230         if (!lnk)
    231                 return NULL;
    232         return FS_NODE(hash_table_get_instance(lnk, tmpfs_node_t, nh_link));
    233 }
    234 
    235 void tmpfs_node_put(fs_node_t *fn)
     235        if (lnk) {
     236                tmpfs_node_t *nodep;
     237                nodep = hash_table_get_instance(lnk, tmpfs_node_t, nh_link);
     238                *rfn = FS_NODE(nodep);
     239        } else {
     240                *rfn = NULL;
     241        }
     242        return EOK;     
     243}
     244
     245int tmpfs_node_put(fs_node_t *fn)
    236246{
    237247        /* nothing to do */
    238 }
    239 
    240 fs_node_t *tmpfs_create_node(dev_handle_t dev_handle, int lflag)
    241 {
     248        return EOK;
     249}
     250
     251int tmpfs_create_node(fs_node_t **rfn, dev_handle_t dev_handle, int lflag)
     252{
     253        fs_node_t *rootfn;
     254        int rc;
     255
    242256        assert((lflag & L_FILE) ^ (lflag & L_DIRECTORY));
    243257
    244258        tmpfs_node_t *nodep = malloc(sizeof(tmpfs_node_t));
    245259        if (!nodep)
    246                 return NULL;
     260                return ENOMEM;
    247261        tmpfs_node_initialize(nodep);
    248262        nodep->bp = malloc(sizeof(fs_node_t));
    249263        if (!nodep->bp) {
    250264                free(nodep);
    251                 return NULL;
     265                return ENOMEM;
    252266        }
    253267        fs_node_initialize(nodep->bp);
    254268        nodep->bp->data = nodep;        /* link the FS and TMPFS nodes */
    255         if (!tmpfs_root_get(dev_handle))
     269
     270        rc = tmpfs_root_get(&rootfn, dev_handle);
     271        assert(rc == EOK);
     272        if (!rootfn)
    256273                nodep->index = TMPFS_SOME_ROOT;
    257274        else
     
    269286        };
    270287        hash_table_insert(&nodes, key, &nodep->nh_link);
    271         return FS_NODE(nodep);
     288        *rfn = FS_NODE(nodep);
     289        return EOK;
     290}
     291
     292int tmpfs_destroy_node(fs_node_t *fn)
     293{
     294        tmpfs_node_t *nodep = TMPFS_NODE(fn);
     295       
     296        assert(!nodep->lnkcnt);
     297        assert(list_empty(&nodep->cs_head));
     298
     299        unsigned long key[] = {
     300                [NODES_KEY_INDEX] = nodep->index,
     301                [NODES_KEY_DEV] = nodep->dev_handle
     302        };
     303        hash_table_remove(&nodes, key, 2);
     304
     305        if (nodep->type == TMPFS_FILE)
     306                free(nodep->data);
     307        free(nodep->bp);
     308        free(nodep);
     309        return EOK;
    272310}
    273311
     
    343381}
    344382
    345 int tmpfs_destroy_node(fs_node_t *fn)
    346 {
    347         tmpfs_node_t *nodep = TMPFS_NODE(fn);
    348        
    349         assert(!nodep->lnkcnt);
    350         assert(list_empty(&nodep->cs_head));
    351 
    352         unsigned long key[] = {
    353                 [NODES_KEY_INDEX] = nodep->index,
    354                 [NODES_KEY_DEV] = nodep->dev_handle
    355         };
    356         hash_table_remove(&nodes, key, 2);
    357 
    358         if (nodep->type == TMPFS_FILE)
    359                 free(nodep->data);
    360         free(nodep->bp);
    361         free(nodep);
    362         return EOK;
    363 }
    364 
    365383void tmpfs_mounted(ipc_callid_t rid, ipc_call_t *request)
    366384{
    367385        dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request);
     386        int rc;
    368387
    369388        /* accept the mount options */
     
    395414        }
    396415
    397         tmpfs_node_t *rootp = TMPFS_NODE(tmpfs_root_get(dev_handle));
     416        fs_node_t *rootfn;
     417        rc = tmpfs_root_get(&rootfn, dev_handle);
     418        assert(rc == EOK);
     419        tmpfs_node_t *rootp = TMPFS_NODE(rootfn);
    398420        if (str_cmp(opts, "restore") == 0) {
    399421                if (tmpfs_restore(dev_handle))
Note: See TracChangeset for help on using the changeset viewer.