Changeset 2e37308 in mainline for uspace/srv/fs/fat/fat_ops.c


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.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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);
Note: See TracChangeset for help on using the changeset viewer.