Changeset 04803bf in mainline for uspace/srv/fs/fat/fat_fat.c


Ignore:
Timestamp:
2011-03-21T22:00:17Z (13 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
143932e
Parents:
b50b5af2 (diff), 7308e84 (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 mainline changes (needs fixes).

File:
1 edited

Legend:

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

    rb50b5af2 r04803bf  
    4646#include <align.h>
    4747#include <assert.h>
    48 #include <fibril_sync.h>
     48#include <fibril_synch.h>
    4949#include <mem.h>
     50
     51/*
     52 * Convenience macros for computing some frequently used values from the
     53 * primitive boot sector members.
     54 */
     55#define RDS(bs)         ((sizeof(fat_dentry_t) * RDE((bs))) / BPS((bs))) + \
     56                        (((sizeof(fat_dentry_t) * RDE((bs))) % BPS((bs))) != 0)
     57#define SSA(bs)         (RSCNT((bs)) + FATCNT((bs)) * SF((bs)) + RDS(bs))
     58
     59#define CLBN2PBN(bs, cl, bn) \
     60        (SSA((bs)) + ((cl) - FAT_CLST_FIRST) * SPC((bs)) + (bn) % SPC((bs)))
    5061
    5162/**
     
    5970 *
    6071 * @param bs            Buffer holding the boot sector for the file.
    61  * @param dev_handle    Device handle of the device with the file.
     72 * @param devmap_handle Device handle of the device with the file.
    6273 * @param firstc        First cluster to start the walk with.
    63  * @param lastc         If non-NULL, output argument hodling the last cluster number visited.
     74 * @param lastc         If non-NULL, output argument hodling the last cluster
     75 *                      number visited.
     76 * @param numc          If non-NULL, output argument holding the number of
     77 *                      clusters seen during the walk.
    6478 * @param max_clusters  Maximum number of clusters to visit.   
    6579 *
    66  * @return              Number of clusters seen during the walk.
    67  */
    68 uint16_t
    69 fat_cluster_walk(fat_bs_t *bs, dev_handle_t dev_handle, fat_cluster_t firstc,
    70     fat_cluster_t *lastc, uint16_t max_clusters)
     80 * @return              EOK on success or a negative error code.
     81 */
     82int
     83fat_cluster_walk(fat_bs_t *bs, devmap_handle_t devmap_handle, fat_cluster_t firstc,
     84    fat_cluster_t *lastc, uint16_t *numc, uint16_t max_clusters)
    7185{
    7286        block_t *b;
    73         unsigned bps;
    74         unsigned rscnt;         /* block address of the first FAT */
    7587        uint16_t clusters = 0;
    7688        fat_cluster_t clst = firstc;
    77 
    78         bps = uint16_t_le2host(bs->bps);
    79         rscnt = uint16_t_le2host(bs->rscnt);
     89        int rc;
    8090
    8191        if (firstc == FAT_CLST_RES0) {
     
    8393                if (lastc)
    8494                        *lastc = firstc;
    85                 return 0;
     95                if (numc)
     96                        *numc = 0;
     97                return EOK;
    8698        }
    8799
    88100        while (clst < FAT_CLST_LAST1 && clusters < max_clusters) {
    89                 bn_t fsec;      /* sector offset relative to FAT1 */
     101                aoff64_t fsec;  /* sector offset relative to FAT1 */
    90102                unsigned fidx;  /* FAT1 entry index */
    91103
     
    93105                if (lastc)
    94106                        *lastc = clst;  /* remember the last cluster number */
    95                 fsec = (clst * sizeof(fat_cluster_t)) / bps;
    96                 fidx = clst % (bps / sizeof(fat_cluster_t));
     107                fsec = (clst * sizeof(fat_cluster_t)) / BPS(bs);
     108                fidx = clst % (BPS(bs) / sizeof(fat_cluster_t));
    97109                /* read FAT1 */
    98                 b = block_get(dev_handle, rscnt + fsec, BLOCK_FLAGS_NONE);
     110                rc = block_get(&b, devmap_handle, RSCNT(bs) + fsec,
     111                    BLOCK_FLAGS_NONE);
     112                if (rc != EOK)
     113                        return rc;
    99114                clst = uint16_t_le2host(((fat_cluster_t *)b->data)[fidx]);
    100115                assert(clst != FAT_CLST_BAD);
    101                 block_put(b);
     116                rc = block_put(b);
     117                if (rc != EOK)
     118                        return rc;
    102119                clusters++;
    103120        }
     
    105122        if (lastc && clst < FAT_CLST_LAST1)
    106123                *lastc = clst;
    107 
    108         return clusters;
     124        if (numc)
     125                *numc = clusters;
     126
     127        return EOK;
    109128}
    110129
    111130/** Read block from file located on a FAT file system.
    112131 *
     132 * @param block         Pointer to a block pointer for storing result.
    113133 * @param bs            Buffer holding the boot sector of the file system.
    114  * @param dev_handle    Device handle of the file system.
    115  * @param firstc        First cluster used by the file. Can be zero if the file
    116  *                      is empty.
     134 * @param nodep         FAT node.
    117135 * @param bn            Block number.
    118136 * @param flags         Flags passed to libblock.
    119137 *
    120  * @return              Block structure holding the requested block.
    121  */
    122 block_t *
    123 _fat_block_get(fat_bs_t *bs, dev_handle_t dev_handle, fat_cluster_t firstc,
    124     bn_t bn, int flags)
    125 {
    126         block_t *b;
    127         unsigned bps;
    128         unsigned rscnt;         /* block address of the first FAT */
    129         unsigned rde;
    130         unsigned rds;           /* root directory size */
    131         unsigned sf;
    132         unsigned ssa;           /* size of the system area */
    133         unsigned clusters, max_clusters;
    134         fat_cluster_t lastc;
    135 
    136         bps = uint16_t_le2host(bs->bps);
    137         rscnt = uint16_t_le2host(bs->rscnt);
    138         rde = uint16_t_le2host(bs->root_ent_max);
    139         sf = uint16_t_le2host(bs->sec_per_fat);
    140 
    141         rds = (sizeof(fat_dentry_t) * rde) / bps;
    142         rds += ((sizeof(fat_dentry_t) * rde) % bps != 0);
    143         ssa = rscnt + bs->fatcnt * sf + rds;
    144 
    145         if (firstc == FAT_CLST_ROOT) {
     138 * @return              EOK on success or a negative error code.
     139 */
     140int
     141fat_block_get(block_t **block, struct fat_bs *bs, fat_node_t *nodep,
     142    aoff64_t bn, int flags)
     143{
     144        fat_cluster_t firstc = nodep->firstc;
     145        fat_cluster_t currc;
     146        aoff64_t relbn = bn;
     147        int rc;
     148
     149        if (!nodep->size)
     150                return ELIMIT;
     151
     152        if (nodep->firstc == FAT_CLST_ROOT)
     153                goto fall_through;
     154
     155        if (((((nodep->size - 1) / BPS(bs)) / SPC(bs)) == bn / SPC(bs)) &&
     156            nodep->lastc_cached_valid) {
     157                /*
     158                 * This is a request to read a block within the last cluster
     159                 * when fortunately we have the last cluster number cached.
     160                 */
     161                return block_get(block, nodep->idx->devmap_handle,
     162                    CLBN2PBN(bs, nodep->lastc_cached_value, bn), flags);
     163        }
     164
     165        if (nodep->currc_cached_valid && bn >= nodep->currc_cached_bn) {
     166                /*
     167                 * We can start with the cluster cached by the previous call to
     168                 * fat_block_get().
     169                 */
     170                firstc = nodep->currc_cached_value;
     171                relbn -= (nodep->currc_cached_bn / SPC(bs)) * SPC(bs);
     172        }
     173
     174fall_through:
     175        rc = _fat_block_get(block, bs, nodep->idx->devmap_handle, firstc,
     176            &currc, relbn, flags);
     177        if (rc != EOK)
     178                return rc;
     179       
     180        /*
     181         * Update the "current" cluster cache.
     182         */
     183        nodep->currc_cached_valid = true;
     184        nodep->currc_cached_bn = bn;
     185        nodep->currc_cached_value = currc;
     186
     187        return rc;
     188}
     189
     190/** Read block from file located on a FAT file system.
     191 *
     192 * @param block         Pointer to a block pointer for storing result.
     193 * @param bs            Buffer holding the boot sector of the file system.
     194 * @param devmap_handle Device handle of the file system.
     195 * @param fcl           First cluster used by the file. Can be zero if the file
     196 *                      is empty.
     197 * @param clp           If not NULL, address where the cluster containing bn
     198 *                      will be stored.
     199 *                      stored
     200 * @param bn            Block number.
     201 * @param flags         Flags passed to libblock.
     202 *
     203 * @return              EOK on success or a negative error code.
     204 */
     205int
     206_fat_block_get(block_t **block, fat_bs_t *bs, devmap_handle_t devmap_handle,
     207    fat_cluster_t fcl, fat_cluster_t *clp, aoff64_t bn, int flags)
     208{
     209        uint16_t clusters;
     210        unsigned max_clusters;
     211        fat_cluster_t c;
     212        int rc;
     213
     214        /*
     215         * This function can only operate on non-zero length files.
     216         */
     217        if (fcl == FAT_CLST_RES0)
     218                return ELIMIT;
     219
     220        if (fcl == FAT_CLST_ROOT) {
    146221                /* root directory special case */
    147                 assert(bn < rds);
    148                 b = block_get(dev_handle, rscnt + bs->fatcnt * sf + bn, flags);
    149                 return b;
    150         }
    151 
    152         max_clusters = bn / bs->spc;
    153         clusters = fat_cluster_walk(bs, dev_handle, firstc, &lastc,
    154             max_clusters);
     222                assert(bn < RDS(bs));
     223                rc = block_get(block, devmap_handle,
     224                    RSCNT(bs) + FATCNT(bs) * SF(bs) + bn, flags);
     225                return rc;
     226        }
     227
     228        max_clusters = bn / SPC(bs);
     229        rc = fat_cluster_walk(bs, devmap_handle, fcl, &c, &clusters, max_clusters);
     230        if (rc != EOK)
     231                return rc;
    155232        assert(clusters == max_clusters);
    156233
    157         b = block_get(dev_handle, ssa + (lastc - FAT_CLST_FIRST) * bs->spc +
    158             bn % bs->spc, flags);
    159 
    160         return b;
     234        rc = block_get(block, devmap_handle, CLBN2PBN(bs, c, bn), flags);
     235
     236        if (clp)
     237                *clp = c;
     238
     239        return rc;
    161240}
    162241
     
    170249 *                      this argument is ignored.
    171250 * @param pos           Position in the last node block.
    172  */
    173 void fat_fill_gap(fat_bs_t *bs, fat_node_t *nodep, fat_cluster_t mcl, off_t pos)
    174 {
    175         uint16_t bps;
    176         unsigned spc;
     251 *
     252 * @return              EOK on success or a negative error code.
     253 */
     254int fat_fill_gap(fat_bs_t *bs, fat_node_t *nodep, fat_cluster_t mcl, aoff64_t pos)
     255{
    177256        block_t *b;
    178         off_t o, boundary;
    179 
    180         bps = uint16_t_le2host(bs->bps);
    181         spc = bs->spc;
    182        
    183         boundary = ROUND_UP(nodep->size, bps * spc);
     257        aoff64_t o, boundary;
     258        int rc;
     259
     260        boundary = ROUND_UP(nodep->size, BPS(bs) * SPC(bs));
    184261
    185262        /* zero out already allocated space */
    186263        for (o = nodep->size; o < pos && o < boundary;
    187             o = ALIGN_DOWN(o + bps, bps)) {
    188                 int flags = (o % bps == 0) ?
     264            o = ALIGN_DOWN(o + BPS(bs), BPS(bs))) {
     265                int flags = (o % BPS(bs) == 0) ?
    189266                    BLOCK_FLAGS_NOREAD : BLOCK_FLAGS_NONE;
    190                 b = fat_block_get(bs, nodep, o / bps, flags);
    191                 memset(b->data + o % bps, 0, bps - o % bps);
     267                rc = fat_block_get(&b, bs, nodep, o / BPS(bs), flags);
     268                if (rc != EOK)
     269                        return rc;
     270                memset(b->data + o % BPS(bs), 0, BPS(bs) - o % BPS(bs));
    192271                b->dirty = true;                /* need to sync node */
    193                 block_put(b);
     272                rc = block_put(b);
     273                if (rc != EOK)
     274                        return rc;
    194275        }
    195276       
    196277        if (o >= pos)
    197                 return;
     278                return EOK;
    198279       
    199280        /* zero out the initial part of the new cluster chain */
    200         for (o = boundary; o < pos; o += bps) {
    201                 b = _fat_block_get(bs, nodep->idx->dev_handle, mcl,
    202                     (o - boundary) / bps, BLOCK_FLAGS_NOREAD);
    203                 memset(b->data, 0, min(bps, pos - o));
     281        for (o = boundary; o < pos; o += BPS(bs)) {
     282                rc = _fat_block_get(&b, bs, nodep->idx->devmap_handle, mcl,
     283                    NULL, (o - boundary) / BPS(bs), BLOCK_FLAGS_NOREAD);
     284                if (rc != EOK)
     285                        return rc;
     286                memset(b->data, 0, min(BPS(bs), pos - o));
    204287                b->dirty = true;                /* need to sync node */
    205                 block_put(b);
    206         }
     288                rc = block_put(b);
     289                if (rc != EOK)
     290                        return rc;
     291        }
     292
     293        return EOK;
    207294}
    208295
     
    210297 *
    211298 * @param bs            Buffer holding the boot sector for the file system.
    212  * @param dev_handle    Device handle for the file system.
     299 * @param devmap_handle Device handle for the file system.
    213300 * @param clst          Cluster which to get.
    214  *
    215  * @return              Value found in the cluster.
    216  */
    217 fat_cluster_t
    218 fat_get_cluster(fat_bs_t *bs, dev_handle_t dev_handle, fat_cluster_t clst)
     301 * @param value         Output argument holding the value of the cluster.
     302 *
     303 * @return              EOK or a negative error code.
     304 */
     305int
     306fat_get_cluster(fat_bs_t *bs, devmap_handle_t devmap_handle, unsigned fatno,
     307    fat_cluster_t clst, fat_cluster_t *value)
    219308{
    220309        block_t *b;
    221         uint16_t bps;
    222         uint16_t rscnt;
    223         fat_cluster_t *cp, value;
    224 
    225         bps = uint16_t_le2host(bs->bps);
    226         rscnt = uint16_t_le2host(bs->rscnt);
    227 
    228         b = block_get(dev_handle, rscnt + (clst * sizeof(fat_cluster_t)) / bps,
    229             BLOCK_FLAGS_NONE);
    230         cp = (fat_cluster_t *)b->data + clst % (bps / sizeof(fat_cluster_t));
    231         value = uint16_t_le2host(*cp);
    232         block_put(b);
     310        fat_cluster_t *cp;
     311        int rc;
     312
     313        rc = block_get(&b, devmap_handle, RSCNT(bs) + SF(bs) * fatno +
     314            (clst * sizeof(fat_cluster_t)) / BPS(bs), BLOCK_FLAGS_NONE);
     315        if (rc != EOK)
     316                return rc;
     317        cp = (fat_cluster_t *)b->data +
     318            clst % (BPS(bs) / sizeof(fat_cluster_t));
     319        *value = uint16_t_le2host(*cp);
     320        rc = block_put(b);
    233321       
    234         return value;
     322        return rc;
    235323}
    236324
     
    238326 *
    239327 * @param bs            Buffer holding the boot sector for the file system.
    240  * @param dev_handle    Device handle for the file system.
     328 * @param devmap_handle Device handle for the file system.
    241329 * @param fatno         Number of the FAT instance where to make the change.
    242330 * @param clst          Cluster which is to be set.
    243331 * @param value         Value to set the cluster with.
    244  */
    245 void
    246 fat_set_cluster(fat_bs_t *bs, dev_handle_t dev_handle, unsigned fatno,
     332 *
     333 * @return              EOK on success or a negative error code.
     334 */
     335int
     336fat_set_cluster(fat_bs_t *bs, devmap_handle_t devmap_handle, unsigned fatno,
    247337    fat_cluster_t clst, fat_cluster_t value)
    248338{
    249339        block_t *b;
    250         uint16_t bps;
    251         uint16_t rscnt;
    252         uint16_t sf;
    253340        fat_cluster_t *cp;
    254 
    255         bps = uint16_t_le2host(bs->bps);
    256         rscnt = uint16_t_le2host(bs->rscnt);
    257         sf = uint16_t_le2host(bs->sec_per_fat);
    258 
    259         assert(fatno < bs->fatcnt);
    260         b = block_get(dev_handle, rscnt + sf * fatno +
    261             (clst * sizeof(fat_cluster_t)) / bps, BLOCK_FLAGS_NONE);
    262         cp = (fat_cluster_t *)b->data + clst % (bps / sizeof(fat_cluster_t));
     341        int rc;
     342
     343        assert(fatno < FATCNT(bs));
     344        rc = block_get(&b, devmap_handle, RSCNT(bs) + SF(bs) * fatno +
     345            (clst * sizeof(fat_cluster_t)) / BPS(bs), BLOCK_FLAGS_NONE);
     346        if (rc != EOK)
     347                return rc;
     348        cp = (fat_cluster_t *)b->data +
     349            clst % (BPS(bs) / sizeof(fat_cluster_t));
    263350        *cp = host2uint16_t_le(value);
    264351        b->dirty = true;                /* need to sync block */
    265         block_put(b);
     352        rc = block_put(b);
     353        return rc;
    266354}
    267355
     
    269357 *
    270358 * @param bs            Buffer holding the boot sector of the file system.
    271  * @param dev_handle    Device handle of the file system.
     359 * @param devmap_handle Device handle of the file system.
    272360 * @param lifo          Chain of allocated clusters.
    273361 * @param nclsts        Number of clusters in the lifo chain.
    274  */
    275 void fat_alloc_shadow_clusters(fat_bs_t *bs, dev_handle_t dev_handle,
     362 *
     363 * @return              EOK on success or a negative error code.
     364 */
     365int fat_alloc_shadow_clusters(fat_bs_t *bs, devmap_handle_t devmap_handle,
    276366    fat_cluster_t *lifo, unsigned nclsts)
    277367{
    278368        uint8_t fatno;
    279369        unsigned c;
     370        int rc;
    280371
    281372        for (fatno = FAT1 + 1; fatno < bs->fatcnt; fatno++) {
    282373                for (c = 0; c < nclsts; c++) {
    283                         fat_set_cluster(bs, dev_handle, fatno, lifo[c],
     374                        rc = fat_set_cluster(bs, devmap_handle, fatno, lifo[c],
    284375                            c == 0 ? FAT_CLST_LAST1 : lifo[c - 1]);
     376                        if (rc != EOK)
     377                                return rc;
    285378                }
    286379        }
     380
     381        return EOK;
    287382}
    288383
     
    295390 *
    296391 * @param bs            Buffer holding the boot sector of the file system.
    297  * @param dev_handle    Device handle of the file system.
     392 * @param devmap_handle Device handle of the file system.
    298393 * @param nclsts        Number of clusters to allocate.
    299394 * @param mcl           Output parameter where the first cluster in the chain
     
    305400 */
    306401int
    307 fat_alloc_clusters(fat_bs_t *bs, dev_handle_t dev_handle, unsigned nclsts,
     402fat_alloc_clusters(fat_bs_t *bs, devmap_handle_t devmap_handle, unsigned nclsts,
    308403    fat_cluster_t *mcl, fat_cluster_t *lcl)
    309404{
    310         uint16_t bps;
    311         uint16_t rscnt;
    312         uint16_t sf;
    313405        block_t *blk;
    314406        fat_cluster_t *lifo;    /* stack for storing free cluster numbers */
    315407        unsigned found = 0;     /* top of the free cluster number stack */
    316408        unsigned b, c, cl;
     409        int rc;
    317410
    318411        lifo = (fat_cluster_t *) malloc(nclsts * sizeof(fat_cluster_t));
    319412        if (!lifo)
    320413                return ENOMEM;
    321        
    322         bps = uint16_t_le2host(bs->bps);
    323         rscnt = uint16_t_le2host(bs->rscnt);
    324         sf = uint16_t_le2host(bs->sec_per_fat);
    325414       
    326415        /*
     
    328417         */
    329418        fibril_mutex_lock(&fat_alloc_lock);
    330         for (b = 0, cl = 0; b < sf; b++) {
    331                 blk = block_get(dev_handle, rscnt + b, BLOCK_FLAGS_NONE);
    332                 for (c = 0; c < bps / sizeof(fat_cluster_t); c++, cl++) {
     419        for (b = 0, cl = 0; b < SF(bs); b++) {
     420                rc = block_get(&blk, devmap_handle, RSCNT(bs) + b,
     421                    BLOCK_FLAGS_NONE);
     422                if (rc != EOK)
     423                        goto error;
     424                for (c = 0; c < BPS(bs) / sizeof(fat_cluster_t); c++, cl++) {
     425                        /*
     426                         * Check if the entire cluster is physically there.
     427                         * This check becomes necessary when the file system is
     428                         * created with fewer total sectors than how many is
     429                         * inferred from the size of the file allocation table
     430                         * or when the last cluster ends beyond the end of the
     431                         * device.
     432                         */
     433                        if ((cl >= FAT_CLST_FIRST) &&
     434                            CLBN2PBN(bs, cl, SPC(bs) - 1) >= TS(bs)) {
     435                                rc = block_put(blk);
     436                                if (rc != EOK)
     437                                        goto error;
     438                                goto out;
     439                        }
     440
    333441                        fat_cluster_t *clst = (fat_cluster_t *)blk->data + c;
    334442                        if (uint16_t_le2host(*clst) == FAT_CLST_RES0) {
     
    344452                                if (++found == nclsts) {
    345453                                        /* we are almost done */
    346                                         block_put(blk);
     454                                        rc = block_put(blk);
     455                                        if (rc != EOK)
     456                                                goto error;
    347457                                        /* update the shadow copies of FAT */
    348                                         fat_alloc_shadow_clusters(bs,
    349                                             dev_handle, lifo, nclsts);
     458                                        rc = fat_alloc_shadow_clusters(bs,
     459                                            devmap_handle, lifo, nclsts);
     460                                        if (rc != EOK)
     461                                                goto error;
    350462                                        *mcl = lifo[found - 1];
    351463                                        *lcl = lifo[0];
     
    356468                        }
    357469                }
    358                 block_put(blk);
    359         }
     470                rc = block_put(blk);
     471                if (rc != EOK) {
     472error:
     473                        fibril_mutex_unlock(&fat_alloc_lock);
     474                        free(lifo);
     475                        return rc;
     476                }
     477        }
     478out:
    360479        fibril_mutex_unlock(&fat_alloc_lock);
    361480
     
    365484         */
    366485        while (found--) {
    367                 fat_set_cluster(bs, dev_handle, FAT1, lifo[found],
     486                rc = fat_set_cluster(bs, devmap_handle, FAT1, lifo[found],
    368487                    FAT_CLST_RES0);
     488                if (rc != EOK) {
     489                        free(lifo);
     490                        return rc;
     491                }
    369492        }
    370493       
     
    376499 *
    377500 * @param bs            Buffer hodling the boot sector of the file system.
    378  * @param dev_handle    Device handle of the file system.
     501 * @param devmap_handle Device handle of the file system.
    379502 * @param firstc        First cluster in the chain which is to be freed.
    380  */
    381 void
    382 fat_free_clusters(fat_bs_t *bs, dev_handle_t dev_handle, fat_cluster_t firstc)
     503 *
     504 * @return              EOK on success or a negative return code.
     505 */
     506int
     507fat_free_clusters(fat_bs_t *bs, devmap_handle_t devmap_handle, fat_cluster_t firstc)
    383508{
    384509        unsigned fatno;
    385510        fat_cluster_t nextc;
     511        int rc;
    386512
    387513        /* Mark all clusters in the chain as free in all copies of FAT. */
    388514        while (firstc < FAT_CLST_LAST1) {
    389515                assert(firstc >= FAT_CLST_FIRST && firstc < FAT_CLST_BAD);
    390                 nextc = fat_get_cluster(bs, dev_handle, firstc);
    391                 for (fatno = FAT1; fatno < bs->fatcnt; fatno++)
    392                         fat_set_cluster(bs, dev_handle, fatno, firstc,
     516                rc = fat_get_cluster(bs, devmap_handle, FAT1, firstc, &nextc);
     517                if (rc != EOK)
     518                        return rc;
     519                for (fatno = FAT1; fatno < bs->fatcnt; fatno++) {
     520                        rc = fat_set_cluster(bs, devmap_handle, fatno, firstc,
    393521                            FAT_CLST_RES0);
     522                        if (rc != EOK)
     523                                return rc;
     524                }
     525
    394526                firstc = nextc;
    395527        }
     528
     529        return EOK;
    396530}
    397531
     
    401535 * @param nodep         Node representing the file.
    402536 * @param mcl           First cluster of the cluster chain to append.
    403  */
    404 void fat_append_clusters(fat_bs_t *bs, fat_node_t *nodep, fat_cluster_t mcl)
    405 {
    406         dev_handle_t dev_handle = nodep->idx->dev_handle;
    407         fat_cluster_t lcl;
     537 * @param lcl           Last cluster of the cluster chain to append.
     538 *
     539 * @return              EOK on success or a negative error code.
     540 */
     541int
     542fat_append_clusters(fat_bs_t *bs, fat_node_t *nodep, fat_cluster_t mcl,
     543    fat_cluster_t lcl)
     544{
     545        devmap_handle_t devmap_handle = nodep->idx->devmap_handle;
     546        fat_cluster_t lastc;
    408547        uint8_t fatno;
    409 
    410         if (fat_cluster_walk(bs, dev_handle, nodep->firstc, &lcl,
    411             (uint16_t) -1) == 0) {
     548        int rc;
     549
     550        if (nodep->firstc == FAT_CLST_RES0) {
    412551                /* No clusters allocated to the node yet. */
    413552                nodep->firstc = mcl;
    414                 nodep->dirty = true;            /* need to sync node */
    415                 return;
    416         }
    417 
    418         for (fatno = FAT1; fatno < bs->fatcnt; fatno++)
    419                 fat_set_cluster(bs, nodep->idx->dev_handle, fatno, lcl, mcl);
     553                nodep->dirty = true;    /* need to sync node */
     554        } else {
     555                if (nodep->lastc_cached_valid) {
     556                        lastc = nodep->lastc_cached_value;
     557                        nodep->lastc_cached_valid = false;
     558                } else {
     559                        rc = fat_cluster_walk(bs, devmap_handle, nodep->firstc,
     560                            &lastc, NULL, (uint16_t) -1);
     561                        if (rc != EOK)
     562                                return rc;
     563                }
     564
     565                for (fatno = FAT1; fatno < bs->fatcnt; fatno++) {
     566                        rc = fat_set_cluster(bs, nodep->idx->devmap_handle, fatno,
     567                            lastc, mcl);
     568                        if (rc != EOK)
     569                                return rc;
     570                }
     571        }
     572
     573        nodep->lastc_cached_valid = true;
     574        nodep->lastc_cached_value = lcl;
     575
     576        return EOK;
    420577}
    421578
     
    424581 * @param bs            Buffer holding the boot sector of the file system.
    425582 * @param nodep         FAT node where the chopping will take place.
    426  * @param lastc         Last cluster which will remain in the node. If this
     583 * @param lcl           Last cluster which will remain in the node. If this
    427584 *                      argument is FAT_CLST_RES0, then all clusters will
    428585 *                      be chopped off.
    429  */
    430 void fat_chop_clusters(fat_bs_t *bs, fat_node_t *nodep, fat_cluster_t lastc)
    431 {
    432         dev_handle_t dev_handle = nodep->idx->dev_handle;
    433         if (lastc == FAT_CLST_RES0) {
     586 *
     587 * @return              EOK on success or a negative return code.
     588 */
     589int fat_chop_clusters(fat_bs_t *bs, fat_node_t *nodep, fat_cluster_t lcl)
     590{
     591        int rc;
     592        devmap_handle_t devmap_handle = nodep->idx->devmap_handle;
     593
     594        /*
     595         * Invalidate cached cluster numbers.
     596         */
     597        nodep->lastc_cached_valid = false;
     598        if (nodep->currc_cached_value != lcl)
     599                nodep->currc_cached_valid = false;
     600
     601        if (lcl == FAT_CLST_RES0) {
    434602                /* The node will have zero size and no clusters allocated. */
    435                 fat_free_clusters(bs, dev_handle, nodep->firstc);
     603                rc = fat_free_clusters(bs, devmap_handle, nodep->firstc);
     604                if (rc != EOK)
     605                        return rc;
    436606                nodep->firstc = FAT_CLST_RES0;
    437607                nodep->dirty = true;            /* need to sync node */
     
    440610                unsigned fatno;
    441611
    442                 nextc = fat_get_cluster(bs, dev_handle, lastc);
     612                rc = fat_get_cluster(bs, devmap_handle, FAT1, lcl, &nextc);
     613                if (rc != EOK)
     614                        return rc;
    443615
    444616                /* Terminate the cluster chain in all copies of FAT. */
    445                 for (fatno = FAT1; fatno < bs->fatcnt; fatno++)
    446                         fat_set_cluster(bs, dev_handle, fatno, lastc, FAT_CLST_LAST1);
     617                for (fatno = FAT1; fatno < bs->fatcnt; fatno++) {
     618                        rc = fat_set_cluster(bs, devmap_handle, fatno, lcl,
     619                            FAT_CLST_LAST1);
     620                        if (rc != EOK)
     621                                return rc;
     622                }
    447623
    448624                /* Free all following clusters. */
    449                 fat_free_clusters(bs, dev_handle, nextc);
    450         }
    451 }
    452 
    453 void
    454 fat_zero_cluster(struct fat_bs *bs, dev_handle_t dev_handle, fat_cluster_t c)
     625                rc = fat_free_clusters(bs, devmap_handle, nextc);
     626                if (rc != EOK)
     627                        return rc;
     628        }
     629
     630        /*
     631         * Update and re-enable the last cluster cache.
     632         */
     633        nodep->lastc_cached_valid = true;
     634        nodep->lastc_cached_value = lcl;
     635
     636        return EOK;
     637}
     638
     639int
     640fat_zero_cluster(struct fat_bs *bs, devmap_handle_t devmap_handle, fat_cluster_t c)
    455641{
    456642        int i;
    457643        block_t *b;
    458         unsigned bps;
    459 
    460         bps = uint16_t_le2host(bs->bps);
    461        
    462         for (i = 0; i < bs->spc; i++) {
    463                 b = _fat_block_get(bs, dev_handle, c, i, BLOCK_FLAGS_NOREAD);
    464                 memset(b->data, 0, bps);
     644        int rc;
     645
     646        for (i = 0; i < SPC(bs); i++) {
     647                rc = _fat_block_get(&b, bs, devmap_handle, c, NULL, i,
     648                    BLOCK_FLAGS_NOREAD);
     649                if (rc != EOK)
     650                        return rc;
     651                memset(b->data, 0, BPS(bs));
    465652                b->dirty = true;
    466                 block_put(b);
    467         }
     653                rc = block_put(b);
     654                if (rc != EOK)
     655                        return rc;
     656        }
     657
     658        return EOK;
     659}
     660
     661/** Perform basic sanity checks on the file system.
     662 *
     663 * Verify if values of boot sector fields are sane. Also verify media
     664 * descriptor. This is used to rule out cases when a device obviously
     665 * does not contain a fat file system.
     666 */
     667int fat_sanity_check(fat_bs_t *bs, devmap_handle_t devmap_handle)
     668{
     669        fat_cluster_t e0, e1;
     670        unsigned fat_no;
     671        int rc;
     672
     673        /* Check number of FATs. */
     674        if (bs->fatcnt == 0)
     675                return ENOTSUP;
     676
     677        /* Check total number of sectors. */
     678
     679        if (bs->totsec16 == 0 && bs->totsec32 == 0)
     680                return ENOTSUP;
     681
     682        if (bs->totsec16 != 0 && bs->totsec32 != 0 &&
     683            bs->totsec16 != bs->totsec32)
     684                return ENOTSUP;
     685
     686        /* Check media descriptor. Must be between 0xf0 and 0xff. */
     687        if ((bs->mdesc & 0xf0) != 0xf0)
     688                return ENOTSUP;
     689
     690        /* Check number of sectors per FAT. */
     691        if (bs->sec_per_fat == 0)
     692                return ENOTSUP;
     693
     694        /*
     695         * Check that the root directory entries take up whole blocks.
     696         * This check is rather strict, but it allows us to treat the root
     697         * directory and non-root directories uniformly in some places.
     698         * It can be removed provided that functions such as fat_read() are
     699         * sanitized to support file systems with this property.
     700         */
     701        if ((uint16_t_le2host(bs->root_ent_max) * sizeof(fat_dentry_t)) %
     702            uint16_t_le2host(bs->bps) != 0)
     703                return ENOTSUP;
     704
     705        /* Check signature of each FAT. */
     706
     707        for (fat_no = 0; fat_no < bs->fatcnt; fat_no++) {
     708                rc = fat_get_cluster(bs, devmap_handle, fat_no, 0, &e0);
     709                if (rc != EOK)
     710                        return EIO;
     711
     712                rc = fat_get_cluster(bs, devmap_handle, fat_no, 1, &e1);
     713                if (rc != EOK)
     714                        return EIO;
     715
     716                /* Check that first byte of FAT contains the media descriptor. */
     717                if ((e0 & 0xff) != bs->mdesc)
     718                        return ENOTSUP;
     719
     720                /*
     721                 * Check that remaining bits of the first two entries are
     722                 * set to one.
     723                 */
     724                if ((e0 >> 8) != 0xff || e1 != 0xffff)
     725                        return ENOTSUP;
     726        }
     727
     728        return EOK;
    468729}
    469730
Note: See TracChangeset for help on using the changeset viewer.