Ignore:
File:
1 edited

Legend:

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

    red903174 r92bee46  
    4545#include <ipc/services.h>
    4646#include <ipc/devmap.h>
    47 #include <macros.h>
    4847#include <async.h>
    4948#include <errno.h>
     
    8079static int fat_has_children(bool *, fs_node_t *);
    8180static fs_index_t fat_index_get(fs_node_t *);
    82 static aoff64_t fat_size_get(fs_node_t *);
     81static size_t fat_size_get(fs_node_t *);
    8382static unsigned fat_lnkcnt_get(fs_node_t *);
    8483static char fat_plb_get_char(unsigned);
     
    138137        rc = block_put(b);
    139138        return rc;
    140 }
    141 
    142 static int fat_node_fini_by_dev_handle(dev_handle_t dev_handle)
    143 {
    144         link_t *lnk;
    145         fat_node_t *nodep;
    146         int rc;
    147 
    148         /*
    149          * We are called from fat_unmounted() and assume that there are already
    150          * no nodes belonging to this instance with non-zero refcount. Therefore
    151          * it is sufficient to clean up only the FAT free node list.
    152          */
    153 
    154 restart:
    155         fibril_mutex_lock(&ffn_mutex);
    156         for (lnk = ffn_head.next; lnk != &ffn_head; lnk = lnk->next) {
    157                 nodep = list_get_instance(lnk, fat_node_t, ffn_link);
    158                 if (!fibril_mutex_trylock(&nodep->lock)) {
    159                         fibril_mutex_unlock(&ffn_mutex);
    160                         goto restart;
    161                 }
    162                 if (!fibril_mutex_trylock(&nodep->idx->lock)) {
    163                         fibril_mutex_unlock(&nodep->lock);
    164                         fibril_mutex_unlock(&ffn_mutex);
    165                         goto restart;
    166                 }
    167                 if (nodep->idx->dev_handle != dev_handle) {
    168                         fibril_mutex_unlock(&nodep->idx->lock);
    169                         fibril_mutex_unlock(&nodep->lock);
    170                         continue;
    171                 }
    172 
    173                 list_remove(&nodep->ffn_link);
    174                 fibril_mutex_unlock(&ffn_mutex);
    175 
    176                 /*
    177                  * We can unlock the node and its index structure because we are
    178                  * the last player on this playground and VFS is preventing new
    179                  * players from entering.
    180                  */
    181                 fibril_mutex_unlock(&nodep->idx->lock);
    182                 fibril_mutex_unlock(&nodep->lock);
    183 
    184                 if (nodep->dirty) {
    185                         rc = fat_node_sync(nodep);
    186                         if (rc != EOK)
    187                                 return rc;
    188                 }
    189                 nodep->idx->nodep = NULL;
    190                 free(nodep->bp);
    191                 free(nodep);
    192 
    193                 /* Need to restart because we changed the ffn_head list. */
    194                 goto restart;
    195         }
    196         fibril_mutex_unlock(&ffn_mutex);
    197 
    198         return EOK;
    199139}
    200140
     
    350290
    351291        *nodepp = nodep;
     292        return EOK;
     293}
     294
     295/** Perform basic sanity checks on the file system.
     296 *
     297 * Verify if values of boot sector fields are sane. Also verify media
     298 * descriptor. This is used to rule out cases when a device obviously
     299 * does not contain a fat file system.
     300 */
     301static int fat_sanity_check(fat_bs_t *bs, dev_handle_t dev_handle)
     302{
     303        fat_cluster_t e0, e1;
     304        unsigned fat_no;
     305        int rc;
     306
     307        /* Check number of FATs. */
     308        if (bs->fatcnt == 0)
     309                return ENOTSUP;
     310
     311        /* Check total number of sectors. */
     312
     313        if (bs->totsec16 == 0 && bs->totsec32 == 0)
     314                return ENOTSUP;
     315
     316        if (bs->totsec16 != 0 && bs->totsec32 != 0 &&
     317            bs->totsec16 != bs->totsec32)
     318                return ENOTSUP;
     319
     320        /* Check media descriptor. Must be between 0xf0 and 0xff. */
     321        if ((bs->mdesc & 0xf0) != 0xf0)
     322                return ENOTSUP;
     323
     324        /* Check number of sectors per FAT. */
     325        if (bs->sec_per_fat == 0)
     326                return ENOTSUP;
     327
     328        /*
     329         * Check that the root directory entries take up whole blocks.
     330         * This check is rather strict, but it allows us to treat the root
     331         * directory and non-root directories uniformly in some places.
     332         * It can be removed provided that functions such as fat_read() are
     333         * sanitized to support file systems with this property.
     334         */
     335        if ((uint16_t_le2host(bs->root_ent_max) * sizeof(fat_dentry_t)) %
     336            uint16_t_le2host(bs->bps) != 0)
     337                return ENOTSUP;
     338
     339        /* Check signature of each FAT. */
     340
     341        for (fat_no = 0; fat_no < bs->fatcnt; fat_no++) {
     342                rc = fat_get_cluster(bs, dev_handle, fat_no, 0, &e0);
     343                if (rc != EOK)
     344                        return EIO;
     345
     346                rc = fat_get_cluster(bs, dev_handle, fat_no, 1, &e1);
     347                if (rc != EOK)
     348                        return EIO;
     349
     350                /* Check that first byte of FAT contains the media descriptor. */
     351                if ((e0 & 0xff) != bs->mdesc)
     352                        return ENOTSUP;
     353
     354                /*
     355                 * Check that remaining bits of the first two entries are
     356                 * set to one.
     357                 */
     358                if ((e0 >> 8) != 0xff || e1 != 0xffff)
     359                        return ENOTSUP;
     360        }
     361
    352362        return EOK;
    353363}
     
    723733        fibril_mutex_lock(&childp->idx->lock);
    724734       
    725         if (childp->type == FAT_DIRECTORY) {
     735        /*
     736         * If possible, create the Sub-directory Identifier Entry and the
     737         * Sub-directory Parent Pointer Entry (i.e. "." and ".."). These entries
     738         * are not mandatory according to Standard ECMA-107 and HelenOS VFS does
     739         * not use them anyway, so this is rather a sign of our good will.
     740         */
     741        rc = fat_block_get(&b, bs, childp, 0, BLOCK_FLAGS_NONE);
     742        if (rc != EOK) {
    726743                /*
    727                  * If possible, create the Sub-directory Identifier Entry and
    728                  * the Sub-directory Parent Pointer Entry (i.e. "." and "..").
    729                  * These entries are not mandatory according to Standard
    730                  * ECMA-107 and HelenOS VFS does not use them anyway, so this is
    731                  * rather a sign of our good will.
     744                 * Rather than returning an error, simply skip the creation of
     745                 * these two entries.
    732746                 */
    733                 rc = fat_block_get(&b, bs, childp, 0, BLOCK_FLAGS_NONE);
    734                 if (rc != EOK) {
    735                         /*
    736                          * Rather than returning an error, simply skip the
    737                          * creation of these two entries.
    738                          */
    739                         goto skip_dots;
    740                 }
    741                 d = (fat_dentry_t *) b->data;
    742                 if ((fat_classify_dentry(d) == FAT_DENTRY_LAST) ||
    743                     (str_cmp((char *) d->name, FAT_NAME_DOT)) == 0) {
    744                         memset(d, 0, sizeof(fat_dentry_t));
    745                         str_cpy((char *) d->name, 8, FAT_NAME_DOT);
    746                         str_cpy((char *) d->ext, 3, FAT_EXT_PAD);
    747                         d->attr = FAT_ATTR_SUBDIR;
    748                         d->firstc = host2uint16_t_le(childp->firstc);
    749                         /* TODO: initialize also the date/time members. */
    750                 }
    751                 d++;
    752                 if ((fat_classify_dentry(d) == FAT_DENTRY_LAST) ||
    753                     (str_cmp((char *) d->name, FAT_NAME_DOT_DOT) == 0)) {
    754                         memset(d, 0, sizeof(fat_dentry_t));
    755                         str_cpy((char *) d->name, 8, FAT_NAME_DOT_DOT);
    756                         str_cpy((char *) d->ext, 3, FAT_EXT_PAD);
    757                         d->attr = FAT_ATTR_SUBDIR;
    758                         d->firstc = (parentp->firstc == FAT_CLST_ROOT) ?
    759                             host2uint16_t_le(FAT_CLST_RES0) :
    760                             host2uint16_t_le(parentp->firstc);
    761                         /* TODO: initialize also the date/time members. */
    762                 }
    763                 b->dirty = true;                /* need to sync block */
    764                 /*
    765                  * Ignore the return value as we would have fallen through on error
    766                  * anyway.
    767                  */
    768                 (void) block_put(b);
    769         }
     747                goto skip_dots;
     748        }
     749        d = (fat_dentry_t *)b->data;
     750        if (fat_classify_dentry(d) == FAT_DENTRY_LAST ||
     751            str_cmp(d->name, FAT_NAME_DOT) == 0) {
     752                memset(d, 0, sizeof(fat_dentry_t));
     753                str_cpy(d->name, 8, FAT_NAME_DOT);
     754                str_cpy(d->ext, 3, FAT_EXT_PAD);
     755                d->attr = FAT_ATTR_SUBDIR;
     756                d->firstc = host2uint16_t_le(childp->firstc);
     757                /* TODO: initialize also the date/time members. */
     758        }
     759        d++;
     760        if (fat_classify_dentry(d) == FAT_DENTRY_LAST ||
     761            str_cmp(d->name, FAT_NAME_DOT_DOT) == 0) {
     762                memset(d, 0, sizeof(fat_dentry_t));
     763                str_cpy(d->name, 8, FAT_NAME_DOT_DOT);
     764                str_cpy(d->ext, 3, FAT_EXT_PAD);
     765                d->attr = FAT_ATTR_SUBDIR;
     766                d->firstc = (parentp->firstc == FAT_CLST_ROOT) ?
     767                    host2uint16_t_le(FAT_CLST_RES0) :
     768                    host2uint16_t_le(parentp->firstc);
     769                /* TODO: initialize also the date/time members. */
     770        }
     771        b->dirty = true;                /* need to sync block */
     772        /*
     773         * Ignore the return value as we would have fallen through on error
     774         * anyway.
     775         */
     776        (void) block_put(b);
    770777skip_dots:
    771778
     
    916923}
    917924
    918 aoff64_t fat_size_get(fs_node_t *fn)
     925size_t fat_size_get(fs_node_t *fn)
    919926{
    920927        return FAT_NODE(fn)->size;
     
    978985        uint16_t bps;
    979986        uint16_t rde;
    980        
    981         /* Accept the mount options */
    982         char *opts;
    983         int rc = async_data_write_accept((void **) &opts, true, 0, 0, 0, NULL);
    984        
    985         if (rc != EOK) {
    986                 ipc_answer_0(rid, rc);
    987                 return;
    988         }
     987        int rc;
     988
     989        /* accept the mount options */
     990        ipc_callid_t callid;
     991        size_t size;
     992        if (!async_data_write_receive(&callid, &size)) {
     993                ipc_answer_0(callid, EINVAL);
     994                ipc_answer_0(rid, EINVAL);
     995                return;
     996        }
     997        char *opts = malloc(size + 1);
     998        if (!opts) {
     999                ipc_answer_0(callid, ENOMEM);
     1000                ipc_answer_0(rid, ENOMEM);
     1001                return;
     1002        }
     1003        ipcarg_t retval = async_data_write_finalize(callid, opts, size);
     1004        if (retval != EOK) {
     1005                ipc_answer_0(rid, retval);
     1006                free(opts);
     1007                return;
     1008        }
     1009        opts[size] = '\0';
    9891010
    9901011        /* Check for option enabling write through. */
     
    9941015                cmode = CACHE_MODE_WB;
    9951016
    996         free(opts);
    997 
    9981017        /* initialize libblock */
    9991018        rc = block_init(dev_handle, BS_SIZE);
     
    10351054        rc = fat_sanity_check(bs, dev_handle);
    10361055        if (rc != EOK) {
    1037                 (void) block_cache_fini(dev_handle);
    10381056                block_fini(dev_handle);
    10391057                ipc_answer_0(rid, rc);
     
    10431061        rc = fat_idx_init_by_dev_handle(dev_handle);
    10441062        if (rc != EOK) {
    1045                 (void) block_cache_fini(dev_handle);
    10461063                block_fini(dev_handle);
    10471064                ipc_answer_0(rid, rc);
     
    10521069        fs_node_t *rfn = (fs_node_t *)malloc(sizeof(fs_node_t));
    10531070        if (!rfn) {
    1054                 (void) block_cache_fini(dev_handle);
    10551071                block_fini(dev_handle);
    10561072                fat_idx_fini_by_dev_handle(dev_handle);
     
    10621078        if (!rootp) {
    10631079                free(rfn);
    1064                 (void) block_cache_fini(dev_handle);
    10651080                block_fini(dev_handle);
    10661081                fat_idx_fini_by_dev_handle(dev_handle);
     
    10741089                free(rfn);
    10751090                free(rootp);
    1076                 (void) block_cache_fini(dev_handle);
    10771091                block_fini(dev_handle);
    10781092                fat_idx_fini_by_dev_handle(dev_handle);
     
    11031117}
    11041118
    1105 void fat_unmounted(ipc_callid_t rid, ipc_call_t *request)
    1106 {
    1107         dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request);
    1108         fs_node_t *fn;
    1109         fat_node_t *nodep;
    1110         int rc;
    1111 
    1112         rc = fat_root_get(&fn, dev_handle);
    1113         if (rc != EOK) {
    1114                 ipc_answer_0(rid, rc);
    1115                 return;
    1116         }
    1117         nodep = FAT_NODE(fn);
    1118 
    1119         /*
    1120          * We expect exactly two references on the root node. One for the
    1121          * fat_root_get() above and one created in fat_mounted().
    1122          */
    1123         if (nodep->refcnt != 2) {
    1124                 (void) fat_node_put(fn);
    1125                 ipc_answer_0(rid, EBUSY);
    1126                 return;
    1127         }
    1128        
    1129         /*
    1130          * Put the root node and force it to the FAT free node list.
    1131          */
    1132         (void) fat_node_put(fn);
    1133         (void) fat_node_put(fn);
    1134 
    1135         /*
    1136          * Perform cleanup of the node structures, index structures and
    1137          * associated data. Write back this file system's dirty blocks and
    1138          * stop using libblock for this instance.
    1139          */
    1140         (void) fat_node_fini_by_dev_handle(dev_handle);
    1141         fat_idx_fini_by_dev_handle(dev_handle);
    1142         (void) block_cache_fini(dev_handle);
    1143         block_fini(dev_handle);
    1144 
    1145         ipc_answer_0(rid, EOK);
    1146 }
    1147 
    1148 void fat_unmount(ipc_callid_t rid, ipc_call_t *request)
    1149 {
    1150         libfs_unmount(&fat_libfs_ops, rid, request);
    1151 }
    1152 
    11531119void fat_lookup(ipc_callid_t rid, ipc_call_t *request)
    11541120{
     
    11581124void fat_read(ipc_callid_t rid, ipc_call_t *request)
    11591125{
    1160         dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request);
    1161         fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
    1162         aoff64_t pos =
    1163             (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
     1126        dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
     1127        fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
     1128        off_t pos = (off_t)IPC_GET_ARG3(*request);
    11641129        fs_node_t *fn;
    11651130        fat_node_t *nodep;
     
    12251190        } else {
    12261191                unsigned bnum;
    1227                 aoff64_t spos = pos;
     1192                off_t spos = pos;
    12281193                char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
    12291194                fat_dentry_t *d;
     
    12411206                bnum = (pos * sizeof(fat_dentry_t)) / bps;
    12421207                while (bnum < nodep->size / bps) {
    1243                         aoff64_t o;
     1208                        off_t o;
    12441209
    12451210                        rc = fat_block_get(&b, bs, nodep, bnum,
     
    12971262void fat_write(ipc_callid_t rid, ipc_call_t *request)
    12981263{
    1299         dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request);
    1300         fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
    1301         aoff64_t pos =
    1302             (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
     1264        dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
     1265        fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
     1266        off_t pos = (off_t)IPC_GET_ARG3(*request);
    13031267        fs_node_t *fn;
    13041268        fat_node_t *nodep;
     
    13091273        unsigned spc;
    13101274        unsigned bpc;           /* bytes per cluster */
    1311         aoff64_t boundary;
     1275        off_t boundary;
    13121276        int flags = BLOCK_FLAGS_NONE;
    13131277        int rc;
     
    14551419void fat_truncate(ipc_callid_t rid, ipc_call_t *request)
    14561420{
    1457         dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request);
    1458         fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
    1459         aoff64_t size =
    1460             (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
     1421        dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
     1422        fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
     1423        size_t size = (off_t)IPC_GET_ARG3(*request);
    14611424        fs_node_t *fn;
    14621425        fat_node_t *nodep;
Note: See TracChangeset for help on using the changeset viewer.