Ignore:
File:
1 edited

Legend:

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

    r12bdc942 r46c0498  
    250250 * Forward declarations of FAT libfs operations.
    251251 */
    252 static int fat_root_get(fs_node_t **, dev_handle_t);
    253 static int fat_match(fs_node_t **, fs_node_t *, const char *);
    254 static int fat_node_get(fs_node_t **, dev_handle_t, fs_index_t);
    255 static int fat_node_put(fs_node_t *);
    256 static int fat_create_node(fs_node_t **, dev_handle_t, int);
     252static fs_node_t *fat_node_get(dev_handle_t, fs_index_t);
     253static void fat_node_put(fs_node_t *);
     254static fs_node_t *fat_create_node(dev_handle_t, int);
    257255static int fat_destroy_node(fs_node_t *);
    258256static int fat_link(fs_node_t *, fs_node_t *, const char *);
    259257static int fat_unlink(fs_node_t *, fs_node_t *, const char *);
    260 static int fat_has_children(bool *, fs_node_t *);
     258static fs_node_t *fat_match(fs_node_t *, const char *);
    261259static fs_index_t fat_index_get(fs_node_t *);
    262260static size_t fat_size_get(fs_node_t *);
    263261static unsigned fat_lnkcnt_get(fs_node_t *);
     262static bool fat_has_children(fs_node_t *);
     263static 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 int fat_root_get(fs_node_t **rfn, dev_handle_t dev_handle)
    273 {
    274         return fat_node_get(rfn, dev_handle, 0);
    275 }
    276 
    277 int fat_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
     272/** Instantiate a FAT in-core node. */
     273fs_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
     287void 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
     315fs_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
     368int 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
     401int 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
     504hit:
     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);
     563skip_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
     582int 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
     632error:
     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
     639fs_node_t *fat_match(fs_node_t *pfn, const char *component)
    278640{
    279641        fat_bs_t *bs;
     
    295657        for (i = 0; i < blocks; i++) {
    296658                rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE);
    297                 if (rc != EOK) {
    298                         fibril_mutex_unlock(&parentp->idx->lock);
    299                         return rc;
    300                 }
     659                assert(rc == EOK);
    301660                for (j = 0; j < dps; j++) {
    302661                        d = ((fat_dentry_t *)b->data) + j;
     
    307666                        case FAT_DENTRY_LAST:
    308667                                rc = block_put(b);
    309                                 /* expect EOK as b was not dirty */
    310                                 assert(rc == EOK);     
     668                                assert(rc == EOK);
    311669                                fibril_mutex_unlock(&parentp->idx->lock);
    312                                 *rfn = NULL;
    313                                 return EOK;
     670                                return NULL;
    314671                        default:
    315672                        case FAT_DENTRY_VALID:
     
    336693                                         */
    337694                                        rc = block_put(b);
    338                                         /* expect EOK as b was not dirty */
    339                                         assert(rc == EOK);     
    340                                         return ENOMEM;
     695                                        assert(rc == EOK);
     696                                        return NULL;
    341697                                }
    342698                                nodep = fat_node_get_core(idx);
    343699                                fibril_mutex_unlock(&idx->lock);
    344700                                rc = block_put(b);
    345                                 /* expect EOK as b was not dirty */
    346701                                assert(rc == EOK);
    347                                 *rfn = FS_NODE(nodep);
    348                                 return EOK;
     702                                return FS_NODE(nodep);
    349703                        }
    350704                }
    351705                rc = block_put(b);
    352                 assert(rc == EOK);      /* expect EOK as b was not dirty */
     706                assert(rc == EOK);
    353707        }
    354708
    355709        fibril_mutex_unlock(&parentp->idx->lock);
    356         *rfn = NULL;
    357         return EOK;
    358 }
    359 
    360 /** Instantiate a FAT in-core node. */
    361 int 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 
    378 int 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 
    407 int 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 
    464 int 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 
    501 int 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 
    606 hit:
    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);
    665 skip_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 
    684 int 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 
    738 error:
    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 
    745 int fat_has_children(bool *has_children, fs_node_t *fn)
     710        return NULL;
     711}
     712
     713fs_index_t fat_index_get(fs_node_t *fn)
     714{
     715        return FAT_NODE(fn)->idx->index;
     716}
     717
     718size_t fat_size_get(fs_node_t *fn)
     719{
     720        return FAT_NODE(fn)->size;
     721}
     722
     723unsigned fat_lnkcnt_get(fs_node_t *fn)
     724{
     725        return FAT_NODE(fn)->lnkcnt;
     726}
     727
     728bool fat_has_children(fs_node_t *fn)
    746729{
    747730        fat_bs_t *bs;
     
    754737        int rc;
    755738
    756         if (nodep->type != FAT_DIRECTORY) {
    757                 *has_children = false;
    758                 return EOK;
    759         }
     739        if (nodep->type != FAT_DIRECTORY)
     740                return false;
    760741       
    761742        fibril_mutex_lock(&nodep->idx->lock);
     
    770751       
    771752                rc = fat_block_get(&b, bs, nodep, i, BLOCK_FLAGS_NONE);
    772                 if (rc != EOK) {
    773                         fibril_mutex_unlock(&nodep->idx->lock);
    774                         return rc;
    775                 }
     753                assert(rc == EOK);
    776754                for (j = 0; j < dps; j++) {
    777755                        d = ((fat_dentry_t *)b->data) + j;
     
    782760                        case FAT_DENTRY_LAST:
    783761                                rc = block_put(b);
    784                                 /* expect EOK as b was not dirty */
    785762                                assert(rc == EOK);
    786763                                fibril_mutex_unlock(&nodep->idx->lock);
    787                                 *has_children = false;
    788                                 return EOK;
     764                                return false;
    789765                        default:
    790766                        case FAT_DENTRY_VALID:
    791767                                rc = block_put(b);
    792                                 /* expect EOK as b was not dirty */
    793768                                assert(rc == EOK);
    794769                                fibril_mutex_unlock(&nodep->idx->lock);
    795                                 *has_children = true;
    796                                 return EOK;
     770                                return true;
    797771                        }
     772                        rc = block_put(b);
     773                        assert(rc == EOK);
     774                        fibril_mutex_unlock(&nodep->idx->lock);
     775                        return true;
    798776                }
    799777                rc = block_put(b);
    800                 assert(rc == EOK);      /* expect EOK as b was not dirty */
     778                assert(rc == EOK);
    801779        }
    802780
    803781        fibril_mutex_unlock(&nodep->idx->lock);
    804         *has_children = false;
    805         return EOK;
    806 }
    807 
    808 
    809 fs_index_t fat_index_get(fs_node_t *fn)
    810 {
    811         return FAT_NODE(fn)->idx->index;
    812 }
    813 
    814 size_t fat_size_get(fs_node_t *fn)
    815 {
    816         return FAT_NODE(fn)->size;
    817 }
    818 
    819 unsigned fat_lnkcnt_get(fs_node_t *fn)
    820 {
    821         return FAT_NODE(fn)->lnkcnt;
     782        return false;
     783}
     784
     785fs_node_t *fat_root_get(dev_handle_t dev_handle)
     786{
     787        return fat_node_get(dev_handle, 0);
    822788}
    823789
     
    839805/** libfs operations */
    840806libfs_ops_t fat_libfs_ops = {
    841         .root_get = fat_root_get,
    842807        .match = fat_match,
    843808        .node_get = fat_node_get,
     
    847812        .link = fat_link,
    848813        .unlink = fat_unlink,
    849         .has_children = fat_has_children,
    850814        .index_get = fat_index_get,
    851815        .size_get = fat_size_get,
    852816        .lnkcnt_get = fat_lnkcnt_get,
     817        .has_children = fat_has_children,
     818        .root_get = fat_root_get,
    853819        .plb_get_char = fat_plb_get_char,
    854820        .is_directory = fat_is_directory,
     
    1001967        fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
    1002968        off_t pos = (off_t)IPC_GET_ARG3(*request);
    1003         fs_node_t *fn;
     969        fs_node_t *fn = fat_node_get(dev_handle, index);
    1004970        fat_node_t *nodep;
    1005971        fat_bs_t *bs;
     
    1009975        int rc;
    1010976
    1011         rc = fat_node_get(&fn, dev_handle, index);
    1012         if (rc != EOK) {
    1013                 ipc_answer_0(rid, rc);
    1014                 return;
    1015         }
    1016977        if (!fn) {
    1017978                ipc_answer_0(rid, ENOENT);
     
    10911052                                case FAT_DENTRY_VALID:
    10921053                                        fat_dentry_name_get(d, name);
    1093                                         rc = block_put(b);
     1054                                        rc == block_put(b);
    10941055                                        assert(rc == EOK);
    10951056                                        goto hit;
     
    11191080        fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
    11201081        off_t pos = (off_t)IPC_GET_ARG3(*request);
    1121         fs_node_t *fn;
     1082        fs_node_t *fn = fat_node_get(dev_handle, index);
    11221083        fat_node_t *nodep;
    11231084        fat_bs_t *bs;
     
    11311092        int rc;
    11321093       
    1133         rc = fat_node_get(&fn, dev_handle, index);
    1134         if (rc != EOK) {
    1135                 ipc_answer_0(rid, rc);
    1136                 return;
    1137         }
    11381094        if (!fn) {
    11391095                ipc_answer_0(rid, ENOENT);
     
    12401196        fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
    12411197        size_t size = (off_t)IPC_GET_ARG3(*request);
    1242         fs_node_t *fn;
     1198        fs_node_t *fn = fat_node_get(dev_handle, index);
    12431199        fat_node_t *nodep;
    12441200        fat_bs_t *bs;
     
    12481204        int rc;
    12491205
    1250         rc = fat_node_get(&fn, dev_handle, index);
    1251         if (rc != EOK) {
    1252                 ipc_answer_0(rid, rc);
    1253                 return;
    1254         }
    12551206        if (!fn) {
    12561207                ipc_answer_0(rid, ENOENT);
     
    13161267        dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
    13171268        fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
    1318         fs_node_t *fn;
    13191269        int rc;
    13201270
    1321         rc = fat_node_get(&fn, dev_handle, index);
    1322         if (rc != EOK) {
    1323                 ipc_answer_0(rid, rc);
    1324                 return;
    1325         }
     1271        fs_node_t *fn = fat_node_get(dev_handle, index);
    13261272        if (!fn) {
    13271273                ipc_answer_0(rid, ENOENT);
Note: See TracChangeset for help on using the changeset viewer.