Ignore:
File:
1 edited

Legend:

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

    rcca29e3c r1313ee9  
    5252#include <adt/list.h>
    5353#include <assert.h>
    54 #include <fibril_sync.h>
     54#include <fibril_synch.h>
    5555#include <sys/mman.h>
    5656#include <align.h>
     
    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_open(fs_node_t *);
     74static int fat_node_put(fs_node_t *);
     75static int fat_create_node(fs_node_t **, dev_handle_t, int);
     76static int fat_destroy_node(fs_node_t *);
     77static int fat_link(fs_node_t *, fs_node_t *, const char *);
     78static int fat_unlink(fs_node_t *, fs_node_t *, const char *);
     79static int fat_has_children(bool *, fs_node_t *);
     80static fs_index_t fat_index_get(fs_node_t *);
     81static size_t fat_size_get(fs_node_t *);
     82static unsigned fat_lnkcnt_get(fs_node_t *);
     83static char fat_plb_get_char(unsigned);
     84static bool fat_is_directory(fs_node_t *);
     85static bool fat_is_file(fs_node_t *node);
     86static dev_handle_t fat_device_get(fs_node_t *node);
     87
     88/*
     89 * Helper functions.
     90 */
    6791static void fat_node_initialize(fat_node_t *node)
    6892{
     
    78102}
    79103
    80 static void fat_node_sync(fat_node_t *node)
     104static int fat_node_sync(fat_node_t *node)
    81105{
    82106        block_t *b;
     
    96120        rc = _fat_block_get(&b, bs, node->idx->dev_handle, node->idx->pfc,
    97121            (node->idx->pdi * sizeof(fat_dentry_t)) / bps, BLOCK_FLAGS_NONE);
    98         assert(rc == EOK);
     122        if (rc != EOK)
     123                return rc;
    99124
    100125        d = ((fat_dentry_t *)b->data) + (node->idx->pdi % dps);
     
    111136        b->dirty = true;                /* need to sync block */
    112137        rc = block_put(b);
    113         assert(rc == EOK);
    114 }
    115 
    116 static fat_node_t *fat_node_get_new(void)
     138        return rc;
     139}
     140
     141static int fat_node_get_new(fat_node_t **nodepp)
    117142{
    118143        fs_node_t *fn;
    119144        fat_node_t *nodep;
     145        int rc;
    120146
    121147        fibril_mutex_lock(&ffn_mutex);
     
    133159                list_remove(&nodep->ffn_link);
    134160                fibril_mutex_unlock(&ffn_mutex);
    135                 if (nodep->dirty)
    136                         fat_node_sync(nodep);
     161                if (nodep->dirty) {
     162                        rc = fat_node_sync(nodep);
     163                        if (rc != EOK) {
     164                                idxp_tmp->nodep = NULL;
     165                                fibril_mutex_unlock(&nodep->lock);
     166                                fibril_mutex_unlock(&idxp_tmp->lock);
     167                                free(nodep->bp);
     168                                free(nodep);
     169                                return rc;
     170                        }
     171                }
    137172                idxp_tmp->nodep = NULL;
    138173                fibril_mutex_unlock(&nodep->lock);
     
    145180                fn = (fs_node_t *)malloc(sizeof(fs_node_t));
    146181                if (!fn)
    147                         return NULL;
     182                        return ENOMEM;
    148183                nodep = (fat_node_t *)malloc(sizeof(fat_node_t));
    149184                if (!nodep) {
    150185                        free(fn);
    151                         return NULL;
     186                        return ENOMEM;
    152187                }
    153188        }
     
    157192        nodep->bp = fn;
    158193       
    159         return nodep;
     194        *nodepp = nodep;
     195        return EOK;
    160196}
    161197
     
    164200 * @param idxp          Locked index structure.
    165201 */
    166 static fat_node_t *fat_node_get_core(fat_idx_t *idxp)
     202static int fat_node_get_core(fat_node_t **nodepp, fat_idx_t *idxp)
    167203{
    168204        block_t *b;
     
    181217                 */
    182218                fibril_mutex_lock(&idxp->nodep->lock);
    183                 if (!idxp->nodep->refcnt++)
     219                if (!idxp->nodep->refcnt++) {
     220                        fibril_mutex_lock(&ffn_mutex);
    184221                        list_remove(&idxp->nodep->ffn_link);
     222                        fibril_mutex_unlock(&ffn_mutex);
     223                }
    185224                fibril_mutex_unlock(&idxp->nodep->lock);
    186                 return idxp->nodep;
     225                *nodepp = idxp->nodep;
     226                return EOK;
    187227        }
    188228
     
    193233        assert(idxp->pfc);
    194234
    195         nodep = fat_node_get_new();
    196         if (!nodep)
    197                 return NULL;
     235        rc = fat_node_get_new(&nodep);
     236        if (rc != EOK)
     237                return rc;
    198238
    199239        bs = block_bb_get(idxp->dev_handle);
     
    205245        rc = _fat_block_get(&b, bs, idxp->dev_handle, idxp->pfc,
    206246            (idxp->pdi * sizeof(fat_dentry_t)) / bps, BLOCK_FLAGS_NONE);
    207         assert(rc == EOK);
     247        if (rc != EOK) {
     248                (void) fat_node_put(FS_NODE(nodep));
     249                return rc;
     250        }
    208251
    209252        d = ((fat_dentry_t *)b->data) + (idxp->pdi % dps);
     
    223266                rc = fat_clusters_get(&clusters, bs, idxp->dev_handle,
    224267                    uint16_t_le2host(d->firstc));
    225                 assert(rc == EOK);
     268                if (rc != EOK) {
     269                        (void) fat_node_put(FS_NODE(nodep));
     270                        return rc;
     271                }
    226272                nodep->size = bps * spc * clusters;
    227273        } else {
     
    234280
    235281        rc = block_put(b);
    236         assert(rc == EOK);
     282        if (rc != EOK) {
     283                (void) fat_node_put(FS_NODE(nodep));
     284                return rc;
     285        }
    237286
    238287        /* Link the idx structure with the node structure. */
     
    240289        idxp->nodep = nodep;
    241290
    242         return nodep;
    243 }
    244 
    245 /*
    246  * Forward declarations of FAT libfs operations.
    247  */
    248 static fs_node_t *fat_node_get(dev_handle_t, fs_index_t);
    249 static void fat_node_put(fs_node_t *);
    250 static fs_node_t *fat_create_node(dev_handle_t, int);
    251 static int fat_destroy_node(fs_node_t *);
    252 static int fat_link(fs_node_t *, fs_node_t *, const char *);
    253 static int fat_unlink(fs_node_t *, fs_node_t *, const char *);
    254 static fs_node_t *fat_match(fs_node_t *, const char *);
    255 static fs_index_t fat_index_get(fs_node_t *);
    256 static size_t fat_size_get(fs_node_t *);
    257 static unsigned fat_lnkcnt_get(fs_node_t *);
    258 static bool fat_has_children(fs_node_t *);
    259 static fs_node_t *fat_root_get(dev_handle_t);
    260 static char fat_plb_get_char(unsigned);
    261 static bool fat_is_directory(fs_node_t *);
    262 static bool fat_is_file(fs_node_t *node);
     291        *nodepp = nodep;
     292        return EOK;
     293}
    263294
    264295/*
     
    266297 */
    267298
    268 /** Instantiate a FAT in-core node. */
    269 fs_node_t *fat_node_get(dev_handle_t dev_handle, fs_index_t index)
    270 {
    271         fat_node_t *nodep;
    272         fat_idx_t *idxp;
    273 
    274         idxp = fat_idx_get_by_index(dev_handle, index);
    275         if (!idxp)
    276                 return NULL;
    277         /* idxp->lock held */
    278         nodep = fat_node_get_core(idxp);
    279         fibril_mutex_unlock(&idxp->lock);
    280         return FS_NODE(nodep);
    281 }
    282 
    283 void fat_node_put(fs_node_t *fn)
    284 {
    285         fat_node_t *nodep = FAT_NODE(fn);
    286         bool destroy = false;
    287 
    288         fibril_mutex_lock(&nodep->lock);
    289         if (!--nodep->refcnt) {
    290                 if (nodep->idx) {
    291                         fibril_mutex_lock(&ffn_mutex);
    292                         list_append(&nodep->ffn_link, &ffn_head);
    293                         fibril_mutex_unlock(&ffn_mutex);
    294                 } else {
    295                         /*
    296                          * The node does not have any index structure associated
    297                          * with itself. This can only mean that we are releasing
    298                          * the node after a failed attempt to allocate the index
    299                          * structure for it.
    300                          */
    301                         destroy = true;
    302                 }
    303         }
    304         fibril_mutex_unlock(&nodep->lock);
    305         if (destroy) {
    306                 free(nodep->bp);
    307                 free(nodep);
    308         }
    309 }
    310 
    311 fs_node_t *fat_create_node(dev_handle_t dev_handle, int flags)
    312 {
    313         fat_idx_t *idxp;
    314         fat_node_t *nodep;
    315         fat_bs_t *bs;
    316         fat_cluster_t mcl, lcl;
    317         uint16_t bps;
    318         int rc;
    319 
    320         bs = block_bb_get(dev_handle);
    321         bps = uint16_t_le2host(bs->bps);
    322         if (flags & L_DIRECTORY) {
    323                 /* allocate a cluster */
    324                 rc = fat_alloc_clusters(bs, dev_handle, 1, &mcl, &lcl);
    325                 if (rc != EOK)
    326                         return NULL;
    327         }
    328 
    329         nodep = fat_node_get_new();
    330         if (!nodep) {
    331                 (void) fat_free_clusters(bs, dev_handle, mcl);
    332                 return NULL;
    333         }
    334         idxp = fat_idx_get_new(dev_handle);
    335         if (!idxp) {
    336                 (void) fat_free_clusters(bs, dev_handle, mcl); 
    337                 fat_node_put(FS_NODE(nodep));
    338                 return NULL;
    339         }
    340         /* idxp->lock held */
    341         if (flags & L_DIRECTORY) {
    342                 /* Populate the new cluster with unused dentries. */
    343                 rc = fat_zero_cluster(bs, dev_handle, mcl);
    344                 assert(rc == EOK);
    345                 nodep->type = FAT_DIRECTORY;
    346                 nodep->firstc = mcl;
    347                 nodep->size = bps * bs->spc;
    348         } else {
    349                 nodep->type = FAT_FILE;
    350                 nodep->firstc = FAT_CLST_RES0;
    351                 nodep->size = 0;
    352         }
    353         nodep->lnkcnt = 0;      /* not linked anywhere */
    354         nodep->refcnt = 1;
    355         nodep->dirty = true;
    356 
    357         nodep->idx = idxp;
    358         idxp->nodep = nodep;
    359 
    360         fibril_mutex_unlock(&idxp->lock);
    361         return FS_NODE(nodep);
    362 }
    363 
    364 int fat_destroy_node(fs_node_t *fn)
    365 {
    366         fat_node_t *nodep = FAT_NODE(fn);
    367         fat_bs_t *bs;
    368         int rc = EOK;
    369 
    370         /*
    371          * The node is not reachable from the file system. This means that the
    372          * link count should be zero and that the index structure cannot be
    373          * found in the position hash. Obviously, we don't need to lock the node
    374          * nor its index structure.
    375          */
    376         assert(nodep->lnkcnt == 0);
    377 
    378         /*
    379          * The node may not have any children.
    380          */
    381         assert(fat_has_children(fn) == false);
    382 
    383         bs = block_bb_get(nodep->idx->dev_handle);
    384         if (nodep->firstc != FAT_CLST_RES0) {
    385                 assert(nodep->size);
    386                 /* Free all clusters allocated to the node. */
    387                 rc = fat_free_clusters(bs, nodep->idx->dev_handle,
    388                     nodep->firstc);
    389         }
    390 
    391         fat_idx_destroy(nodep->idx);
    392         free(nodep->bp);
    393         free(nodep);
    394         return rc;
    395 }
    396 
    397 int fat_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
    398 {
    399         fat_node_t *parentp = FAT_NODE(pfn);
    400         fat_node_t *childp = FAT_NODE(cfn);
    401         fat_dentry_t *d;
    402         fat_bs_t *bs;
    403         block_t *b;
    404         unsigned i, j;
    405         uint16_t bps;
    406         unsigned dps;
    407         unsigned blocks;
    408         fat_cluster_t mcl, lcl;
    409         int rc;
    410 
    411         fibril_mutex_lock(&childp->lock);
    412         if (childp->lnkcnt == 1) {
    413                 /*
    414                  * On FAT, we don't support multiple hard links.
    415                  */
    416                 fibril_mutex_unlock(&childp->lock);
    417                 return EMLINK;
    418         }
    419         assert(childp->lnkcnt == 0);
    420         fibril_mutex_unlock(&childp->lock);
    421 
    422         if (!fat_dentry_name_verify(name)) {
    423                 /*
    424                  * Attempt to create unsupported name.
    425                  */
    426                 return ENOTSUP;
    427         }
    428 
    429         /*
    430          * Get us an unused parent node's dentry or grow the parent and allocate
    431          * a new one.
    432          */
    433        
    434         fibril_mutex_lock(&parentp->idx->lock);
    435         bs = block_bb_get(parentp->idx->dev_handle);
    436         bps = uint16_t_le2host(bs->bps);
    437         dps = bps / sizeof(fat_dentry_t);
    438 
    439         blocks = parentp->size / bps;
    440 
    441         for (i = 0; i < blocks; i++) {
    442                 rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE);
    443                 assert(rc == EOK);
    444                 for (j = 0; j < dps; j++) {
    445                         d = ((fat_dentry_t *)b->data) + j;
    446                         switch (fat_classify_dentry(d)) {
    447                         case FAT_DENTRY_SKIP:
    448                         case FAT_DENTRY_VALID:
    449                                 /* skipping used and meta entries */
    450                                 continue;
    451                         case FAT_DENTRY_FREE:
    452                         case FAT_DENTRY_LAST:
    453                                 /* found an empty slot */
    454                                 goto hit;
    455                         }
    456                 }
    457                 rc = block_put(b);
    458                 assert(rc == EOK);
    459         }
    460         j = 0;
    461        
    462         /*
    463          * We need to grow the parent in order to create a new unused dentry.
    464          */
    465         if (parentp->firstc == FAT_CLST_ROOT) {
    466                 /* Can't grow the root directory. */
    467                 fibril_mutex_unlock(&parentp->idx->lock);
    468                 return ENOSPC;
    469         }
    470         rc = fat_alloc_clusters(bs, parentp->idx->dev_handle, 1, &mcl, &lcl);
    471         if (rc != EOK) {
    472                 fibril_mutex_unlock(&parentp->idx->lock);
    473                 return rc;
    474         }
    475         rc = fat_zero_cluster(bs, parentp->idx->dev_handle, mcl);
    476         assert(rc == EOK);
    477         rc = fat_append_clusters(bs, parentp, mcl);
    478         assert(rc == EOK);
    479         parentp->size += bps * bs->spc;
    480         parentp->dirty = true;          /* need to sync node */
    481         rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE);
    482         assert(rc == EOK);
    483         d = (fat_dentry_t *)b->data;
    484 
    485 hit:
    486         /*
    487          * At this point we only establish the link between the parent and the
    488          * child.  The dentry, except of the name and the extension, will remain
    489          * uninitialized until the corresponding node is synced. Thus the valid
    490          * dentry data is kept in the child node structure.
    491          */
    492         memset(d, 0, sizeof(fat_dentry_t));
    493         fat_dentry_name_set(d, name);
    494         b->dirty = true;                /* need to sync block */
    495         rc = block_put(b);
    496         assert(rc == EOK);
    497         fibril_mutex_unlock(&parentp->idx->lock);
    498 
    499         fibril_mutex_lock(&childp->idx->lock);
    500        
    501         /*
    502          * If possible, create the Sub-directory Identifier Entry and the
    503          * Sub-directory Parent Pointer Entry (i.e. "." and ".."). These entries
    504          * are not mandatory according to Standard ECMA-107 and HelenOS VFS does
    505          * not use them anyway, so this is rather a sign of our good will.
    506          */
    507         rc = fat_block_get(&b, bs, childp, 0, BLOCK_FLAGS_NONE);
    508         assert(rc == EOK);
    509         d = (fat_dentry_t *)b->data;
    510         if (fat_classify_dentry(d) == FAT_DENTRY_LAST ||
    511             str_cmp(d->name, FAT_NAME_DOT) == 0) {
    512                 memset(d, 0, sizeof(fat_dentry_t));
    513                 str_cpy(d->name, 8, FAT_NAME_DOT);
    514                 str_cpy(d->ext, 3, FAT_EXT_PAD);
    515                 d->attr = FAT_ATTR_SUBDIR;
    516                 d->firstc = host2uint16_t_le(childp->firstc);
    517                 /* TODO: initialize also the date/time members. */
    518         }
    519         d++;
    520         if (fat_classify_dentry(d) == FAT_DENTRY_LAST ||
    521             str_cmp(d->name, FAT_NAME_DOT_DOT) == 0) {
    522                 memset(d, 0, sizeof(fat_dentry_t));
    523                 str_cpy(d->name, 8, FAT_NAME_DOT_DOT);
    524                 str_cpy(d->ext, 3, FAT_EXT_PAD);
    525                 d->attr = FAT_ATTR_SUBDIR;
    526                 d->firstc = (parentp->firstc == FAT_CLST_ROOT) ?
    527                     host2uint16_t_le(FAT_CLST_RES0) :
    528                     host2uint16_t_le(parentp->firstc);
    529                 /* TODO: initialize also the date/time members. */
    530         }
    531         b->dirty = true;                /* need to sync block */
    532         rc = block_put(b);
    533         assert(rc == EOK);
    534 
    535         childp->idx->pfc = parentp->firstc;
    536         childp->idx->pdi = i * dps + j;
    537         fibril_mutex_unlock(&childp->idx->lock);
    538 
    539         fibril_mutex_lock(&childp->lock);
    540         childp->lnkcnt = 1;
    541         childp->dirty = true;           /* need to sync node */
    542         fibril_mutex_unlock(&childp->lock);
    543 
    544         /*
    545          * Hash in the index structure into the position hash.
    546          */
    547         fat_idx_hashin(childp->idx);
    548 
    549         return EOK;
    550 }
    551 
    552 int fat_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
    553 {
    554         fat_node_t *parentp = FAT_NODE(pfn);
    555         fat_node_t *childp = FAT_NODE(cfn);
    556         fat_bs_t *bs;
    557         fat_dentry_t *d;
    558         uint16_t bps;
    559         block_t *b;
    560         int rc;
    561 
    562         if (!parentp)
    563                 return EBUSY;
    564        
    565         if (fat_has_children(cfn))
    566                 return ENOTEMPTY;
    567 
    568         fibril_mutex_lock(&parentp->lock);
    569         fibril_mutex_lock(&childp->lock);
    570         assert(childp->lnkcnt == 1);
    571         fibril_mutex_lock(&childp->idx->lock);
    572         bs = block_bb_get(childp->idx->dev_handle);
    573         bps = uint16_t_le2host(bs->bps);
    574 
    575         rc = _fat_block_get(&b, bs, childp->idx->dev_handle, childp->idx->pfc,
    576             (childp->idx->pdi * sizeof(fat_dentry_t)) / bps,
    577             BLOCK_FLAGS_NONE);
    578         assert(rc == EOK);
    579         d = (fat_dentry_t *)b->data +
    580             (childp->idx->pdi % (bps / sizeof(fat_dentry_t)));
    581         /* mark the dentry as not-currently-used */
    582         d->name[0] = FAT_DENTRY_ERASED;
    583         b->dirty = true;                /* need to sync block */
    584         rc = block_put(b);
    585         assert(rc == EOK);
    586 
    587         /* remove the index structure from the position hash */
    588         fat_idx_hashout(childp->idx);
    589         /* clear position information */
    590         childp->idx->pfc = FAT_CLST_RES0;
    591         childp->idx->pdi = 0;
    592         fibril_mutex_unlock(&childp->idx->lock);
    593         childp->lnkcnt = 0;
    594         childp->dirty = true;
    595         fibril_mutex_unlock(&childp->lock);
    596         fibril_mutex_unlock(&parentp->lock);
    597 
    598         return EOK;
    599 }
    600 
    601 fs_node_t *fat_match(fs_node_t *pfn, const char *component)
     299int fat_root_get(fs_node_t **rfn, dev_handle_t dev_handle)
     300{
     301        return fat_node_get(rfn, dev_handle, 0);
     302}
     303
     304int fat_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
    602305{
    603306        fat_bs_t *bs;
     
    619322        for (i = 0; i < blocks; i++) {
    620323                rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE);
    621                 assert(rc == EOK);
     324                if (rc != EOK) {
     325                        fibril_mutex_unlock(&parentp->idx->lock);
     326                        return rc;
     327                }
    622328                for (j = 0; j < dps; j++) {
    623329                        d = ((fat_dentry_t *)b->data) + j;
     
    627333                                continue;
    628334                        case FAT_DENTRY_LAST:
     335                                /* miss */
    629336                                rc = block_put(b);
    630                                 assert(rc == EOK);
    631337                                fibril_mutex_unlock(&parentp->idx->lock);
    632                                 return NULL;
     338                                *rfn = NULL;
     339                                return rc;
    633340                        default:
    634341                        case FAT_DENTRY_VALID:
     
    655362                                         */
    656363                                        rc = block_put(b);
    657                                         assert(rc == EOK);
    658                                         return NULL;
     364                                        return (rc == EOK) ? ENOMEM : rc;
    659365                                }
    660                                 nodep = fat_node_get_core(idx);
     366                                rc = fat_node_get_core(&nodep, idx);
    661367                                fibril_mutex_unlock(&idx->lock);
     368                                if (rc != EOK) {
     369                                        (void) block_put(b);
     370                                        return rc;
     371                                }
     372                                *rfn = FS_NODE(nodep);
    662373                                rc = block_put(b);
    663                                 assert(rc == EOK);
    664                                 return FS_NODE(nodep);
     374                                if (rc != EOK)
     375                                        (void) fat_node_put(*rfn);
     376                                return rc;
    665377                        }
    666378                }
    667379                rc = block_put(b);
    668                 assert(rc == EOK);
     380                if (rc != EOK) {
     381                        fibril_mutex_unlock(&parentp->idx->lock);
     382                        return rc;
     383                }
    669384        }
    670385
    671386        fibril_mutex_unlock(&parentp->idx->lock);
    672         return NULL;
    673 }
    674 
    675 fs_index_t fat_index_get(fs_node_t *fn)
    676 {
    677         return FAT_NODE(fn)->idx->index;
    678 }
    679 
    680 size_t fat_size_get(fs_node_t *fn)
    681 {
    682         return FAT_NODE(fn)->size;
    683 }
    684 
    685 unsigned fat_lnkcnt_get(fs_node_t *fn)
    686 {
    687         return FAT_NODE(fn)->lnkcnt;
    688 }
    689 
    690 bool fat_has_children(fs_node_t *fn)
     387        *rfn = NULL;
     388        return EOK;
     389}
     390
     391/** Instantiate a FAT in-core node. */
     392int fat_node_get(fs_node_t **rfn, dev_handle_t dev_handle, fs_index_t index)
     393{
     394        fat_node_t *nodep;
     395        fat_idx_t *idxp;
     396        int rc;
     397
     398        idxp = fat_idx_get_by_index(dev_handle, index);
     399        if (!idxp) {
     400                *rfn = NULL;
     401                return EOK;
     402        }
     403        /* idxp->lock held */
     404        rc = fat_node_get_core(&nodep, idxp);
     405        fibril_mutex_unlock(&idxp->lock);
     406        if (rc == EOK)
     407                *rfn = FS_NODE(nodep);
     408        return rc;
     409}
     410
     411int fat_node_open(fs_node_t *fn)
     412{
     413        /*
     414         * Opening a file is stateless, nothing
     415         * to be done here.
     416         */
     417        return EOK;
     418}
     419
     420int fat_node_put(fs_node_t *fn)
     421{
     422        fat_node_t *nodep = FAT_NODE(fn);
     423        bool destroy = false;
     424
     425        fibril_mutex_lock(&nodep->lock);
     426        if (!--nodep->refcnt) {
     427                if (nodep->idx) {
     428                        fibril_mutex_lock(&ffn_mutex);
     429                        list_append(&nodep->ffn_link, &ffn_head);
     430                        fibril_mutex_unlock(&ffn_mutex);
     431                } else {
     432                        /*
     433                         * The node does not have any index structure associated
     434                         * with itself. This can only mean that we are releasing
     435                         * the node after a failed attempt to allocate the index
     436                         * structure for it.
     437                         */
     438                        destroy = true;
     439                }
     440        }
     441        fibril_mutex_unlock(&nodep->lock);
     442        if (destroy) {
     443                free(nodep->bp);
     444                free(nodep);
     445        }
     446        return EOK;
     447}
     448
     449int fat_create_node(fs_node_t **rfn, dev_handle_t dev_handle, int flags)
     450{
     451        fat_idx_t *idxp;
     452        fat_node_t *nodep;
     453        fat_bs_t *bs;
     454        fat_cluster_t mcl, lcl;
     455        uint16_t bps;
     456        int rc;
     457
     458        bs = block_bb_get(dev_handle);
     459        bps = uint16_t_le2host(bs->bps);
     460        if (flags & L_DIRECTORY) {
     461                /* allocate a cluster */
     462                rc = fat_alloc_clusters(bs, dev_handle, 1, &mcl, &lcl);
     463                if (rc != EOK)
     464                        return rc;
     465                /* populate the new cluster with unused dentries */
     466                rc = fat_zero_cluster(bs, dev_handle, mcl);
     467                if (rc != EOK) {
     468                        (void) fat_free_clusters(bs, dev_handle, mcl);
     469                        return rc;
     470                }
     471        }
     472
     473        rc = fat_node_get_new(&nodep);
     474        if (rc != EOK) {
     475                (void) fat_free_clusters(bs, dev_handle, mcl);
     476                return rc;
     477        }
     478        rc = fat_idx_get_new(&idxp, dev_handle);
     479        if (rc != EOK) {
     480                (void) fat_free_clusters(bs, dev_handle, mcl); 
     481                (void) fat_node_put(FS_NODE(nodep));
     482                return rc;
     483        }
     484        /* idxp->lock held */
     485        if (flags & L_DIRECTORY) {
     486                nodep->type = FAT_DIRECTORY;
     487                nodep->firstc = mcl;
     488                nodep->size = bps * bs->spc;
     489        } else {
     490                nodep->type = FAT_FILE;
     491                nodep->firstc = FAT_CLST_RES0;
     492                nodep->size = 0;
     493        }
     494        nodep->lnkcnt = 0;      /* not linked anywhere */
     495        nodep->refcnt = 1;
     496        nodep->dirty = true;
     497
     498        nodep->idx = idxp;
     499        idxp->nodep = nodep;
     500
     501        fibril_mutex_unlock(&idxp->lock);
     502        *rfn = FS_NODE(nodep);
     503        return EOK;
     504}
     505
     506int fat_destroy_node(fs_node_t *fn)
     507{
     508        fat_node_t *nodep = FAT_NODE(fn);
     509        fat_bs_t *bs;
     510        bool has_children;
     511        int rc;
     512
     513        /*
     514         * The node is not reachable from the file system. This means that the
     515         * link count should be zero and that the index structure cannot be
     516         * found in the position hash. Obviously, we don't need to lock the node
     517         * nor its index structure.
     518         */
     519        assert(nodep->lnkcnt == 0);
     520
     521        /*
     522         * The node may not have any children.
     523         */
     524        rc = fat_has_children(&has_children, fn);
     525        if (rc != EOK)
     526                return rc;
     527        assert(!has_children);
     528
     529        bs = block_bb_get(nodep->idx->dev_handle);
     530        if (nodep->firstc != FAT_CLST_RES0) {
     531                assert(nodep->size);
     532                /* Free all clusters allocated to the node. */
     533                rc = fat_free_clusters(bs, nodep->idx->dev_handle,
     534                    nodep->firstc);
     535        }
     536
     537        fat_idx_destroy(nodep->idx);
     538        free(nodep->bp);
     539        free(nodep);
     540        return rc;
     541}
     542
     543int fat_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
     544{
     545        fat_node_t *parentp = FAT_NODE(pfn);
     546        fat_node_t *childp = FAT_NODE(cfn);
     547        fat_dentry_t *d;
     548        fat_bs_t *bs;
     549        block_t *b;
     550        unsigned i, j;
     551        uint16_t bps;
     552        unsigned dps;
     553        unsigned blocks;
     554        fat_cluster_t mcl, lcl;
     555        int rc;
     556
     557        fibril_mutex_lock(&childp->lock);
     558        if (childp->lnkcnt == 1) {
     559                /*
     560                 * On FAT, we don't support multiple hard links.
     561                 */
     562                fibril_mutex_unlock(&childp->lock);
     563                return EMLINK;
     564        }
     565        assert(childp->lnkcnt == 0);
     566        fibril_mutex_unlock(&childp->lock);
     567
     568        if (!fat_dentry_name_verify(name)) {
     569                /*
     570                 * Attempt to create unsupported name.
     571                 */
     572                return ENOTSUP;
     573        }
     574
     575        /*
     576         * Get us an unused parent node's dentry or grow the parent and allocate
     577         * a new one.
     578         */
     579       
     580        fibril_mutex_lock(&parentp->idx->lock);
     581        bs = block_bb_get(parentp->idx->dev_handle);
     582        bps = uint16_t_le2host(bs->bps);
     583        dps = bps / sizeof(fat_dentry_t);
     584
     585        blocks = parentp->size / bps;
     586
     587        for (i = 0; i < blocks; i++) {
     588                rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE);
     589                if (rc != EOK) {
     590                        fibril_mutex_unlock(&parentp->idx->lock);
     591                        return rc;
     592                }
     593                for (j = 0; j < dps; j++) {
     594                        d = ((fat_dentry_t *)b->data) + j;
     595                        switch (fat_classify_dentry(d)) {
     596                        case FAT_DENTRY_SKIP:
     597                        case FAT_DENTRY_VALID:
     598                                /* skipping used and meta entries */
     599                                continue;
     600                        case FAT_DENTRY_FREE:
     601                        case FAT_DENTRY_LAST:
     602                                /* found an empty slot */
     603                                goto hit;
     604                        }
     605                }
     606                rc = block_put(b);
     607                if (rc != EOK) {
     608                        fibril_mutex_unlock(&parentp->idx->lock);
     609                        return rc;
     610                }
     611        }
     612        j = 0;
     613       
     614        /*
     615         * We need to grow the parent in order to create a new unused dentry.
     616         */
     617        if (parentp->firstc == FAT_CLST_ROOT) {
     618                /* Can't grow the root directory. */
     619                fibril_mutex_unlock(&parentp->idx->lock);
     620                return ENOSPC;
     621        }
     622        rc = fat_alloc_clusters(bs, parentp->idx->dev_handle, 1, &mcl, &lcl);
     623        if (rc != EOK) {
     624                fibril_mutex_unlock(&parentp->idx->lock);
     625                return rc;
     626        }
     627        rc = fat_zero_cluster(bs, parentp->idx->dev_handle, mcl);
     628        if (rc != EOK) {
     629                (void) fat_free_clusters(bs, parentp->idx->dev_handle, mcl);
     630                fibril_mutex_unlock(&parentp->idx->lock);
     631                return rc;
     632        }
     633        rc = fat_append_clusters(bs, parentp, mcl);
     634        if (rc != EOK) {
     635                (void) fat_free_clusters(bs, parentp->idx->dev_handle, mcl);
     636                fibril_mutex_unlock(&parentp->idx->lock);
     637                return rc;
     638        }
     639        parentp->size += bps * bs->spc;
     640        parentp->dirty = true;          /* need to sync node */
     641        rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE);
     642        if (rc != EOK) {
     643                fibril_mutex_unlock(&parentp->idx->lock);
     644                return rc;
     645        }
     646        d = (fat_dentry_t *)b->data;
     647
     648hit:
     649        /*
     650         * At this point we only establish the link between the parent and the
     651         * child.  The dentry, except of the name and the extension, will remain
     652         * uninitialized until the corresponding node is synced. Thus the valid
     653         * dentry data is kept in the child node structure.
     654         */
     655        memset(d, 0, sizeof(fat_dentry_t));
     656        fat_dentry_name_set(d, name);
     657        b->dirty = true;                /* need to sync block */
     658        rc = block_put(b);
     659        fibril_mutex_unlock(&parentp->idx->lock);
     660        if (rc != EOK)
     661                return rc;
     662
     663        fibril_mutex_lock(&childp->idx->lock);
     664       
     665        /*
     666         * If possible, create the Sub-directory Identifier Entry and the
     667         * Sub-directory Parent Pointer Entry (i.e. "." and ".."). These entries
     668         * are not mandatory according to Standard ECMA-107 and HelenOS VFS does
     669         * not use them anyway, so this is rather a sign of our good will.
     670         */
     671        rc = fat_block_get(&b, bs, childp, 0, BLOCK_FLAGS_NONE);
     672        if (rc != EOK) {
     673                /*
     674                 * Rather than returning an error, simply skip the creation of
     675                 * these two entries.
     676                 */
     677                goto skip_dots;
     678        }
     679        d = (fat_dentry_t *)b->data;
     680        if (fat_classify_dentry(d) == FAT_DENTRY_LAST ||
     681            str_cmp(d->name, FAT_NAME_DOT) == 0) {
     682                memset(d, 0, sizeof(fat_dentry_t));
     683                str_cpy(d->name, 8, FAT_NAME_DOT);
     684                str_cpy(d->ext, 3, FAT_EXT_PAD);
     685                d->attr = FAT_ATTR_SUBDIR;
     686                d->firstc = host2uint16_t_le(childp->firstc);
     687                /* TODO: initialize also the date/time members. */
     688        }
     689        d++;
     690        if (fat_classify_dentry(d) == FAT_DENTRY_LAST ||
     691            str_cmp(d->name, FAT_NAME_DOT_DOT) == 0) {
     692                memset(d, 0, sizeof(fat_dentry_t));
     693                str_cpy(d->name, 8, FAT_NAME_DOT_DOT);
     694                str_cpy(d->ext, 3, FAT_EXT_PAD);
     695                d->attr = FAT_ATTR_SUBDIR;
     696                d->firstc = (parentp->firstc == FAT_CLST_ROOT) ?
     697                    host2uint16_t_le(FAT_CLST_RES0) :
     698                    host2uint16_t_le(parentp->firstc);
     699                /* TODO: initialize also the date/time members. */
     700        }
     701        b->dirty = true;                /* need to sync block */
     702        /*
     703         * Ignore the return value as we would have fallen through on error
     704         * anyway.
     705         */
     706        (void) block_put(b);
     707skip_dots:
     708
     709        childp->idx->pfc = parentp->firstc;
     710        childp->idx->pdi = i * dps + j;
     711        fibril_mutex_unlock(&childp->idx->lock);
     712
     713        fibril_mutex_lock(&childp->lock);
     714        childp->lnkcnt = 1;
     715        childp->dirty = true;           /* need to sync node */
     716        fibril_mutex_unlock(&childp->lock);
     717
     718        /*
     719         * Hash in the index structure into the position hash.
     720         */
     721        fat_idx_hashin(childp->idx);
     722
     723        return EOK;
     724}
     725
     726int fat_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
     727{
     728        fat_node_t *parentp = FAT_NODE(pfn);
     729        fat_node_t *childp = FAT_NODE(cfn);
     730        fat_bs_t *bs;
     731        fat_dentry_t *d;
     732        uint16_t bps;
     733        block_t *b;
     734        bool has_children;
     735        int rc;
     736
     737        if (!parentp)
     738                return EBUSY;
     739       
     740        rc = fat_has_children(&has_children, cfn);
     741        if (rc != EOK)
     742                return rc;
     743        if (has_children)
     744                return ENOTEMPTY;
     745
     746        fibril_mutex_lock(&parentp->lock);
     747        fibril_mutex_lock(&childp->lock);
     748        assert(childp->lnkcnt == 1);
     749        fibril_mutex_lock(&childp->idx->lock);
     750        bs = block_bb_get(childp->idx->dev_handle);
     751        bps = uint16_t_le2host(bs->bps);
     752
     753        rc = _fat_block_get(&b, bs, childp->idx->dev_handle, childp->idx->pfc,
     754            (childp->idx->pdi * sizeof(fat_dentry_t)) / bps,
     755            BLOCK_FLAGS_NONE);
     756        if (rc != EOK)
     757                goto error;
     758        d = (fat_dentry_t *)b->data +
     759            (childp->idx->pdi % (bps / sizeof(fat_dentry_t)));
     760        /* mark the dentry as not-currently-used */
     761        d->name[0] = FAT_DENTRY_ERASED;
     762        b->dirty = true;                /* need to sync block */
     763        rc = block_put(b);
     764        if (rc != EOK)
     765                goto error;
     766
     767        /* remove the index structure from the position hash */
     768        fat_idx_hashout(childp->idx);
     769        /* clear position information */
     770        childp->idx->pfc = FAT_CLST_RES0;
     771        childp->idx->pdi = 0;
     772        fibril_mutex_unlock(&childp->idx->lock);
     773        childp->lnkcnt = 0;
     774        childp->dirty = true;
     775        fibril_mutex_unlock(&childp->lock);
     776        fibril_mutex_unlock(&parentp->lock);
     777
     778        return EOK;
     779
     780error:
     781        fibril_mutex_unlock(&parentp->idx->lock);
     782        fibril_mutex_unlock(&childp->lock);
     783        fibril_mutex_unlock(&childp->idx->lock);
     784        return rc;
     785}
     786
     787int fat_has_children(bool *has_children, fs_node_t *fn)
    691788{
    692789        fat_bs_t *bs;
     
    699796        int rc;
    700797
    701         if (nodep->type != FAT_DIRECTORY)
    702                 return false;
     798        if (nodep->type != FAT_DIRECTORY) {
     799                *has_children = false;
     800                return EOK;
     801        }
    703802       
    704803        fibril_mutex_lock(&nodep->idx->lock);
     
    713812       
    714813                rc = fat_block_get(&b, bs, nodep, i, BLOCK_FLAGS_NONE);
    715                 assert(rc == EOK);
     814                if (rc != EOK) {
     815                        fibril_mutex_unlock(&nodep->idx->lock);
     816                        return rc;
     817                }
    716818                for (j = 0; j < dps; j++) {
    717819                        d = ((fat_dentry_t *)b->data) + j;
     
    722824                        case FAT_DENTRY_LAST:
    723825                                rc = block_put(b);
    724                                 assert(rc == EOK);
    725826                                fibril_mutex_unlock(&nodep->idx->lock);
    726                                 return false;
     827                                *has_children = false;
     828                                return rc;
    727829                        default:
    728830                        case FAT_DENTRY_VALID:
    729831                                rc = block_put(b);
    730                                 assert(rc == EOK);
    731832                                fibril_mutex_unlock(&nodep->idx->lock);
    732                                 return true;
     833                                *has_children = true;
     834                                return rc;
    733835                        }
    734                         rc = block_put(b);
    735                         assert(rc == EOK);
     836                }
     837                rc = block_put(b);
     838                if (rc != EOK) {
    736839                        fibril_mutex_unlock(&nodep->idx->lock);
    737                         return true;
    738                 }
    739                 rc = block_put(b);
    740                 assert(rc == EOK);
     840                        return rc;     
     841                }
    741842        }
    742843
    743844        fibril_mutex_unlock(&nodep->idx->lock);
    744         return false;
    745 }
    746 
    747 fs_node_t *fat_root_get(dev_handle_t dev_handle)
    748 {
    749         return fat_node_get(dev_handle, 0);
     845        *has_children = false;
     846        return EOK;
     847}
     848
     849
     850fs_index_t fat_index_get(fs_node_t *fn)
     851{
     852        return FAT_NODE(fn)->idx->index;
     853}
     854
     855size_t fat_size_get(fs_node_t *fn)
     856{
     857        return FAT_NODE(fn)->size;
     858}
     859
     860unsigned fat_lnkcnt_get(fs_node_t *fn)
     861{
     862        return FAT_NODE(fn)->lnkcnt;
    750863}
    751864
     
    763876{
    764877        return FAT_NODE(fn)->type == FAT_FILE;
     878}
     879
     880dev_handle_t fat_device_get(fs_node_t *node)
     881{
     882        return 0;
    765883}
    766884
    767885/** libfs operations */
    768886libfs_ops_t fat_libfs_ops = {
     887        .root_get = fat_root_get,
    769888        .match = fat_match,
    770889        .node_get = fat_node_get,
     890        .node_open = fat_node_open,
    771891        .node_put = fat_node_put,
    772892        .create = fat_create_node,
     
    774894        .link = fat_link,
    775895        .unlink = fat_unlink,
     896        .has_children = fat_has_children,
    776897        .index_get = fat_index_get,
    777898        .size_get = fat_size_get,
    778899        .lnkcnt_get = fat_lnkcnt_get,
    779         .has_children = fat_has_children,
    780         .root_get = fat_root_get,
    781         .plb_get_char = fat_plb_get_char,
     900        .plb_get_char = fat_plb_get_char,
    782901        .is_directory = fat_is_directory,
    783         .is_file = fat_is_file
     902        .is_file = fat_is_file,
     903        .device_get = fat_device_get
    784904};
    785905
     
    800920        ipc_callid_t callid;
    801921        size_t size;
    802         if (!ipc_data_write_receive(&callid, &size)) {
     922        if (!async_data_write_receive(&callid, &size)) {
    803923                ipc_answer_0(callid, EINVAL);
    804924                ipc_answer_0(rid, EINVAL);
     
    811931                return;
    812932        }
    813         ipcarg_t retval = ipc_data_write_finalize(callid, opts, size);
     933        ipcarg_t retval = async_data_write_finalize(callid, opts, size);
    814934        if (retval != EOK) {
    815935                ipc_answer_0(rid, retval);
     
    833953
    834954        /* prepare the boot block */
    835         rc = block_bb_read(dev_handle, BS_BLOCK * BS_SIZE, BS_SIZE);
     955        rc = block_bb_read(dev_handle, BS_BLOCK);
    836956        if (rc != EOK) {
    837957                block_fini(dev_handle);
     
    9291049        fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
    9301050        off_t pos = (off_t)IPC_GET_ARG3(*request);
    931         fs_node_t *fn = fat_node_get(dev_handle, index);
     1051        fs_node_t *fn;
    9321052        fat_node_t *nodep;
    9331053        fat_bs_t *bs;
     
    9371057        int rc;
    9381058
     1059        rc = fat_node_get(&fn, dev_handle, index);
     1060        if (rc != EOK) {
     1061                ipc_answer_0(rid, rc);
     1062                return;
     1063        }
    9391064        if (!fn) {
    9401065                ipc_answer_0(rid, ENOENT);
     
    9451070        ipc_callid_t callid;
    9461071        size_t len;
    947         if (!ipc_data_read_receive(&callid, &len)) {
     1072        if (!async_data_read_receive(&callid, &len)) {
    9481073                fat_node_put(fn);
    9491074                ipc_answer_0(callid, EINVAL);
     
    9641089                        /* reading beyond the EOF */
    9651090                        bytes = 0;
    966                         (void) ipc_data_read_finalize(callid, NULL, 0);
     1091                        (void) async_data_read_finalize(callid, NULL, 0);
    9671092                } else {
    9681093                        bytes = min(len, bps - pos % bps);
     
    9701095                        rc = fat_block_get(&b, bs, nodep, pos / bps,
    9711096                            BLOCK_FLAGS_NONE);
    972                         assert(rc == EOK);
    973                         (void) ipc_data_read_finalize(callid, b->data + pos % bps,
     1097                        if (rc != EOK) {
     1098                                fat_node_put(fn);
     1099                                ipc_answer_0(callid, rc);
     1100                                ipc_answer_0(rid, rc);
     1101                                return;
     1102                        }
     1103                        (void) async_data_read_finalize(callid, b->data + pos % bps,
    9741104                            bytes);
    9751105                        rc = block_put(b);
    976                         assert(rc == EOK);
     1106                        if (rc != EOK) {
     1107                                fat_node_put(fn);
     1108                                ipc_answer_0(rid, rc);
     1109                                return;
     1110                        }
    9771111                }
    9781112        } else {
     
    9981132                        rc = fat_block_get(&b, bs, nodep, bnum,
    9991133                            BLOCK_FLAGS_NONE);
    1000                         assert(rc == EOK);
     1134                        if (rc != EOK)
     1135                                goto err;
    10011136                        for (o = pos % (bps / sizeof(fat_dentry_t));
    10021137                            o < bps / sizeof(fat_dentry_t);
     
    10091144                                case FAT_DENTRY_LAST:
    10101145                                        rc = block_put(b);
    1011                                         assert(rc == EOK);
     1146                                        if (rc != EOK)
     1147                                                goto err;
    10121148                                        goto miss;
    10131149                                default:
    10141150                                case FAT_DENTRY_VALID:
    10151151                                        fat_dentry_name_get(d, name);
    1016                                         rc == block_put(b);
    1017                                         assert(rc == EOK);
     1152                                        rc = block_put(b);
     1153                                        if (rc != EOK)
     1154                                                goto err;
    10181155                                        goto hit;
    10191156                                }
    10201157                        }
    10211158                        rc = block_put(b);
    1022                         assert(rc == EOK);
     1159                        if (rc != EOK)
     1160                                goto err;
    10231161                        bnum++;
    10241162                }
    10251163miss:
    1026                 fat_node_put(fn);
    1027                 ipc_answer_0(callid, ENOENT);
    1028                 ipc_answer_1(rid, ENOENT, 0);
    1029                 return;
     1164                rc = fat_node_put(fn);
     1165                ipc_answer_0(callid, rc != EOK ? rc : ENOENT);
     1166                ipc_answer_1(rid, rc != EOK ? rc : ENOENT, 0);
     1167                return;
     1168
     1169err:
     1170                (void) fat_node_put(fn);
     1171                ipc_answer_0(callid, rc);
     1172                ipc_answer_0(rid, rc);
     1173                return;
     1174
    10301175hit:
    1031                 (void) ipc_data_read_finalize(callid, name, str_size(name) + 1);
     1176                (void) async_data_read_finalize(callid, name, str_size(name) + 1);
    10321177                bytes = (pos - spos) + 1;
    10331178        }
    10341179
    1035         fat_node_put(fn);
    1036         ipc_answer_1(rid, EOK, (ipcarg_t)bytes);
     1180        rc = fat_node_put(fn);
     1181        ipc_answer_1(rid, rc, (ipcarg_t)bytes);
    10371182}
    10381183
     
    10421187        fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
    10431188        off_t pos = (off_t)IPC_GET_ARG3(*request);
    1044         fs_node_t *fn = fat_node_get(dev_handle, index);
     1189        fs_node_t *fn;
    10451190        fat_node_t *nodep;
    10461191        fat_bs_t *bs;
    1047         size_t bytes;
     1192        size_t bytes, size;
    10481193        block_t *b;
    10491194        uint16_t bps;
     
    10541199        int rc;
    10551200       
     1201        rc = fat_node_get(&fn, dev_handle, index);
     1202        if (rc != EOK) {
     1203                ipc_answer_0(rid, rc);
     1204                return;
     1205        }
    10561206        if (!fn) {
    10571207                ipc_answer_0(rid, ENOENT);
     
    10621212        ipc_callid_t callid;
    10631213        size_t len;
    1064         if (!ipc_data_write_receive(&callid, &len)) {
    1065                 fat_node_put(fn);
     1214        if (!async_data_write_receive(&callid, &len)) {
     1215                (void) fat_node_put(fn);
    10661216                ipc_answer_0(callid, EINVAL);
    10671217                ipc_answer_0(rid, EINVAL);
     
    10941244                 */
    10951245                rc = fat_fill_gap(bs, nodep, FAT_CLST_RES0, pos);
    1096                 assert(rc == EOK);
     1246                if (rc != EOK) {
     1247                        (void) fat_node_put(fn);
     1248                        ipc_answer_0(callid, rc);
     1249                        ipc_answer_0(rid, rc);
     1250                        return;
     1251                }
    10971252                rc = fat_block_get(&b, bs, nodep, pos / bps, flags);
    1098                 assert(rc == EOK);
    1099                 (void) ipc_data_write_finalize(callid, b->data + pos % bps,
     1253                if (rc != EOK) {
     1254                        (void) fat_node_put(fn);
     1255                        ipc_answer_0(callid, rc);
     1256                        ipc_answer_0(rid, rc);
     1257                        return;
     1258                }
     1259                (void) async_data_write_finalize(callid, b->data + pos % bps,
    11001260                    bytes);
    11011261                b->dirty = true;                /* need to sync block */
    11021262                rc = block_put(b);
    1103                 assert(rc == EOK);
     1263                if (rc != EOK) {
     1264                        (void) fat_node_put(fn);
     1265                        ipc_answer_0(rid, rc);
     1266                        return;
     1267                }
    11041268                if (pos + bytes > nodep->size) {
    11051269                        nodep->size = pos + bytes;
    11061270                        nodep->dirty = true;    /* need to sync node */
    11071271                }
    1108                 ipc_answer_2(rid, EOK, bytes, nodep->size);     
    1109                 fat_node_put(fn);
     1272                size = nodep->size;
     1273                rc = fat_node_put(fn);
     1274                ipc_answer_2(rid, rc, bytes, nodep->size);
    11101275                return;
    11111276        } else {
     
    11141279                 * clusters for the node and zero them out.
    11151280                 */
    1116                 int status;
    11171281                unsigned nclsts;
    11181282                fat_cluster_t mcl, lcl;
     
    11201284                nclsts = (ROUND_UP(pos + bytes, bpc) - boundary) / bpc;
    11211285                /* create an independent chain of nclsts clusters in all FATs */
    1122                 status = fat_alloc_clusters(bs, dev_handle, nclsts, &mcl, &lcl);
    1123                 if (status != EOK) {
     1286                rc = fat_alloc_clusters(bs, dev_handle, nclsts, &mcl, &lcl);
     1287                if (rc != EOK) {
    11241288                        /* could not allocate a chain of nclsts clusters */
    1125                         fat_node_put(fn);
    1126                         ipc_answer_0(callid, status);
    1127                         ipc_answer_0(rid, status);
     1289                        (void) fat_node_put(fn);
     1290                        ipc_answer_0(callid, rc);
     1291                        ipc_answer_0(rid, rc);
    11281292                        return;
    11291293                }
    11301294                /* zero fill any gaps */
    11311295                rc = fat_fill_gap(bs, nodep, mcl, pos);
    1132                 assert(rc == EOK);
     1296                if (rc != EOK) {
     1297                        (void) fat_free_clusters(bs, dev_handle, mcl);
     1298                        (void) fat_node_put(fn);
     1299                        ipc_answer_0(callid, rc);
     1300                        ipc_answer_0(rid, rc);
     1301                        return;
     1302                }
    11331303                rc = _fat_block_get(&b, bs, dev_handle, lcl, (pos / bps) % spc,
    11341304                    flags);
    1135                 assert(rc == EOK);
    1136                 (void) ipc_data_write_finalize(callid, b->data + pos % bps,
     1305                if (rc != EOK) {
     1306                        (void) fat_free_clusters(bs, dev_handle, mcl);
     1307                        (void) fat_node_put(fn);
     1308                        ipc_answer_0(callid, rc);
     1309                        ipc_answer_0(rid, rc);
     1310                        return;
     1311                }
     1312                (void) async_data_write_finalize(callid, b->data + pos % bps,
    11371313                    bytes);
    11381314                b->dirty = true;                /* need to sync block */
    11391315                rc = block_put(b);
    1140                 assert(rc == EOK);
     1316                if (rc != EOK) {
     1317                        (void) fat_free_clusters(bs, dev_handle, mcl);
     1318                        (void) fat_node_put(fn);
     1319                        ipc_answer_0(rid, rc);
     1320                        return;
     1321                }
    11411322                /*
    11421323                 * Append the cluster chain starting in mcl to the end of the
     
    11441325                 */
    11451326                rc = fat_append_clusters(bs, nodep, mcl);
    1146                 assert(rc == EOK);
    1147                 nodep->size = pos + bytes;
     1327                if (rc != EOK) {
     1328                        (void) fat_free_clusters(bs, dev_handle, mcl);
     1329                        (void) fat_node_put(fn);
     1330                        ipc_answer_0(rid, rc);
     1331                        return;
     1332                }
     1333                nodep->size = size = pos + bytes;
    11481334                nodep->dirty = true;            /* need to sync node */
    1149                 ipc_answer_2(rid, EOK, bytes, nodep->size);
    1150                 fat_node_put(fn);
     1335                rc = fat_node_put(fn);
     1336                ipc_answer_2(rid, rc, bytes, size);
    11511337                return;
    11521338        }
     
    11581344        fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
    11591345        size_t size = (off_t)IPC_GET_ARG3(*request);
    1160         fs_node_t *fn = fat_node_get(dev_handle, index);
     1346        fs_node_t *fn;
    11611347        fat_node_t *nodep;
    11621348        fat_bs_t *bs;
     
    11661352        int rc;
    11671353
     1354        rc = fat_node_get(&fn, dev_handle, index);
     1355        if (rc != EOK) {
     1356                ipc_answer_0(rid, rc);
     1357                return;
     1358        }
    11681359        if (!fn) {
    11691360                ipc_answer_0(rid, ENOENT);
     
    12291420        dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
    12301421        fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
     1422        fs_node_t *fn;
    12311423        int rc;
    12321424
    1233         fs_node_t *fn = fat_node_get(dev_handle, index);
     1425        rc = fat_node_get(&fn, dev_handle, index);
     1426        if (rc != EOK) {
     1427                ipc_answer_0(rid, rc);
     1428                return;
     1429        }
    12341430        if (!fn) {
    12351431                ipc_answer_0(rid, ENOENT);
Note: See TracChangeset for help on using the changeset viewer.