Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset 4cf5ed46 in mainline


Ignore:
Timestamp:
2011-08-26T23:52:15Z (10 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master
Children:
51d0ee9
Parents:
7fadb65 (diff), 0be611b (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 from lp:~jakub/helenos/fat-from-oleg.

  • This merge effectively merges Oleg Romanenko's GSoC 2011 changes.
  • Support for FAT12, FAT32.
  • Support for LFN.
  • Initial read/write support for exFAT.
Files:
15 added
15 edited

Legend:

Unmodified
Added
Removed
  • boot/Makefile.common

    r7fadb65 r4cf5ed46  
    102102        $(USPACE_PATH)/srv/fs/tmpfs/tmpfs \
    103103        $(USPACE_PATH)/srv/fs/fat/fat \
     104        $(USPACE_PATH)/srv/fs/exfat/exfat \
    104105        $(USPACE_PATH)/srv/fs/ext2fs/ext2fs \
    105106        $(USPACE_PATH)/srv/taskmon/taskmon \
  • uspace/Makefile

    r7fadb65 r4cf5ed46  
    7979        srv/bd/part/guid_part \
    8080        srv/bd/part/mbr_part \
     81        srv/fs/exfat \
    8182        srv/fs/fat \
    8283        srv/fs/tmpfs \
  • uspace/app/mkfat/fat.h

    r7fadb65 r4cf5ed46  
    3838#define BS_BLOCK                0
    3939#define BS_SIZE                 512
     40#define DIRENT_SIZE             32
    4041
    41 #define DIRENT_SIZE             32
     42#define FAT12_CLST_MAX    4085
     43#define FAT16_CLST_MAX    65525
     44
     45#define FAT12   12
     46#define FAT16   16
     47#define FAT32   32
     48
     49#define FAT_SIZE(a) (((a) == FAT12) ? 1.5 : (((a) == FAT16) ? 2 : 4))
    4250
    4351typedef struct fat_bs {
  • uspace/app/mkfat/mkfat.c

    r7fadb65 r4cf5ed46  
    3535 * @brief       Tool for creating new FAT file systems.
    3636 *
    37  * Currently we can only create 16-bit FAT.
     37 * Currently we can create 12/16/32-bit FAT.
    3838 */
    3939
     
    5555#define div_round_up(a, b) (((a) + (b) - 1) / (b))
    5656
    57 /** Predefined file-system parameters */
     57/** Default file-system parameters */
    5858enum {
    59         sector_size             = 512,
    60         sectors_per_cluster     = 8,
    61         fat_count               = 2,
    62         reserved_clusters       = 2,
    63         media_descriptor        = 0xF8 /**< fixed disk */
     59        default_sector_size             = 512,
     60        default_sectors_per_cluster     = 4,
     61        default_fat_count               = 2,
     62        default_reserved_clusters       = 2,
     63        default_media_descriptor        = 0xF8 /**< fixed disk */
    6464};
    6565
    6666/** Configurable file-system parameters */
    6767typedef struct fat_cfg {
     68        int fat_type; /* FAT12 = 12, FAT16 = 16, FAT32 = 32 */
     69        size_t sector_size;
    6870        uint32_t total_sectors;
    6971        uint16_t root_ent_max;
    70         uint16_t addt_res_sectors;
     72        uint32_t addt_res_sectors;
     73        uint8_t sectors_per_cluster;
     74
     75        uint16_t reserved_sectors;
     76        uint32_t rootdir_sectors;
     77        uint32_t fat_sectors;
     78        uint32_t total_clusters;
     79        uint8_t fat_count;
    7180} fat_cfg_t;
    7281
    73 /** Derived file-system parameters */
    74 typedef struct fat_params {
    75         struct fat_cfg cfg;
    76         uint16_t reserved_sectors;
    77         uint16_t rootdir_sectors;
    78         uint32_t fat_sectors;
    79         uint16_t total_clusters;
    80 } fat_params_t;
    81 
    8282static void syntax_print(void);
    8383
    84 static int fat_params_compute(struct fat_cfg const *cfg,
    85     struct fat_params *par);
    86 static int fat_blocks_write(struct fat_params const *par,
    87     service_id_t service_id);
    88 static void fat_bootsec_create(struct fat_params const *par, struct fat_bs *bs);
     84static int fat_params_compute(struct fat_cfg *cfg);
     85static int fat_blocks_write(struct fat_cfg const *cfg, service_id_t service_id);
     86static void fat_bootsec_create(struct fat_cfg const *cfg, struct fat_bs *bs);
    8987
    9088int main(int argc, char **argv)
    9189{
    92         struct fat_params par;
    9390        struct fat_cfg cfg;
    9491
     
    9693        char *dev_path;
    9794        service_id_t service_id;
    98         size_t block_size;
    9995        char *endptr;
    10096        aoff64_t dev_nblocks;
    10197
     98        cfg.sector_size = default_sector_size;
     99        cfg.sectors_per_cluster = default_sectors_per_cluster;
     100        cfg.fat_count = default_fat_count;
    102101        cfg.total_sectors = 0;
    103102        cfg.addt_res_sectors = 0;
    104103        cfg.root_ent_max = 128;
     104        cfg.fat_type = FAT16;
    105105
    106106        if (argc < 2) {
     
    111111
    112112        --argc; ++argv;
    113 
    114113        if (str_cmp(*argv, "--size") == 0) {
    115114                --argc; ++argv;
     
    130129        }
    131130
     131        if (str_cmp(*argv, "--type") == 0) {
     132                --argc; ++argv;
     133                if (*argv == NULL) {
     134                        printf(NAME ": Error, argument missing.\n");
     135                        syntax_print();
     136                        return 1;
     137                }
     138
     139                cfg.fat_type = strtol(*argv, &endptr, 10);
     140                if (*endptr != '\0') {
     141                        printf(NAME ": Error, invalid argument.\n");
     142                        syntax_print();
     143                        return 1;
     144                }
     145
     146                --argc; ++argv;
     147        }
     148
    132149        if (argc != 1) {
    133150                printf(NAME ": Error, unexpected argument.\n");
     
    137154
    138155        dev_path = *argv;
     156        printf("Device: %s\n", dev_path);
    139157
    140158        rc = loc_service_get_id(dev_path, &service_id, 0);
     
    150168        }
    151169
    152         rc = block_get_bsize(service_id, &block_size);
     170        rc = block_get_bsize(service_id, &cfg.sector_size);
    153171        if (rc != EOK) {
    154172                printf(NAME ": Error determining device block size.\n");
     
    162180                printf(NAME ": Block device has %" PRIuOFF64 " blocks.\n",
    163181                    dev_nblocks);
    164                 cfg.total_sectors = dev_nblocks;
    165         }
    166 
    167         if (block_size != 512) {
    168                 printf(NAME ": Error. Device block size is not 512 bytes.\n");
    169                 return 2;
     182                if (!cfg.total_sectors || dev_nblocks < cfg.total_sectors)
     183                        cfg.total_sectors = dev_nblocks;
    170184        }
    171185
     
    175189        }
    176190
    177         printf(NAME ": Creating FAT filesystem on device %s.\n", dev_path);
    178 
    179         rc = fat_params_compute(&cfg, &par);
     191        if (cfg.fat_type != FAT12 && cfg.fat_type != FAT16 && cfg.fat_type != FAT32) {
     192                printf(NAME ": Error. Unknown FAT type.\n");
     193                return 2;
     194        }
     195
     196        printf(NAME ": Creating FAT%d filesystem on device %s.\n", cfg.fat_type, dev_path);
     197
     198        rc = fat_params_compute(&cfg);
    180199        if (rc != EOK) {
    181200                printf(NAME ": Invalid file-system parameters.\n");
     
    183202        }
    184203
    185         rc = fat_blocks_write(&par, service_id);
     204        rc = fat_blocks_write(&cfg, service_id);
    186205        if (rc != EOK) {
    187206                printf(NAME ": Error writing device.\n");
     
    197216static void syntax_print(void)
    198217{
    199         printf("syntax: mkfat [--size <num_blocks>] <device_name>\n");
     218        printf("syntax: mkfat [--size <sectors>] [--type 12|16|32] <device_name>\n");
    200219}
    201220
     
    205224 * file system params.
    206225 */
    207 static int fat_params_compute(struct fat_cfg const *cfg, struct fat_params *par)
     226static int fat_params_compute(struct fat_cfg *cfg)
    208227{
    209228        uint32_t fat_bytes;
     
    211230
    212231        /*
    213          * Make a conservative guess on the FAT size needed for the file
    214          * system. The optimum could be potentially smaller since we
    215          * do not subtract size of the FAT itself when computing the
    216          * size of the data region.
    217          */
    218 
    219         par->reserved_sectors = 1 + cfg->addt_res_sectors;
    220         par->rootdir_sectors = div_round_up(cfg->root_ent_max * DIRENT_SIZE,
    221             sector_size);
    222         non_data_sectors_lb = par->reserved_sectors + par->rootdir_sectors;
    223 
    224         par->total_clusters = div_round_up(cfg->total_sectors - non_data_sectors_lb,
    225             sectors_per_cluster);
    226 
    227         fat_bytes = (par->total_clusters + 2) * 2;
    228         par->fat_sectors = div_round_up(fat_bytes, sector_size);
    229 
    230         par->cfg = *cfg;
     232         * Make a conservative guess on the FAT size needed for the file
     233         * system. The optimum could be potentially smaller since we
     234         * do not subtract size of the FAT itself when computing the
     235         * size of the data region.
     236         */
     237
     238        cfg->reserved_sectors = 1 + cfg->addt_res_sectors;
     239        if (cfg->fat_type != FAT32) {
     240                cfg->rootdir_sectors = div_round_up(cfg->root_ent_max * DIRENT_SIZE,
     241                        cfg->sector_size);
     242        } else
     243                cfg->rootdir_sectors = 0;
     244        non_data_sectors_lb = cfg->reserved_sectors + cfg->rootdir_sectors;
     245
     246        cfg->total_clusters = div_round_up(cfg->total_sectors - non_data_sectors_lb,
     247            cfg->sectors_per_cluster);
     248
     249        if ((cfg->fat_type == FAT12 && cfg->total_clusters > FAT12_CLST_MAX) ||
     250            (cfg->fat_type == FAT16 && (cfg->total_clusters <= FAT12_CLST_MAX ||
     251            cfg->total_clusters > FAT16_CLST_MAX)) ||
     252            (cfg->fat_type == FAT32 && cfg->total_clusters <= FAT16_CLST_MAX))
     253                return ENOSPC;
     254
     255        fat_bytes = (cfg->total_clusters + 2) * FAT_SIZE(cfg->fat_type);
     256        cfg->fat_sectors = div_round_up(fat_bytes, cfg->sector_size);
    231257
    232258        return EOK;
     
    234260
    235261/** Create file system with the given parameters. */
    236 static int fat_blocks_write(struct fat_params const *par, service_id_t service_id)
     262static int fat_blocks_write(struct fat_cfg const *cfg, service_id_t service_id)
    237263{
    238264        aoff64_t addr;
     
    243269        struct fat_bs bs;
    244270
    245         fat_bootsec_create(par, &bs);
     271        fat_bootsec_create(cfg, &bs);
    246272
    247273        rc = block_write_direct(service_id, BS_BLOCK, 1, &bs);
     
    251277        addr = BS_BLOCK + 1;
    252278
    253         buffer = calloc(sector_size, 1);
     279        buffer = calloc(cfg->sector_size, 1);
    254280        if (buffer == NULL)
    255281                return ENOMEM;
     282        memset(buffer, 0, cfg->sector_size);
    256283
    257284        /* Reserved sectors */
    258         for (i = 0; i < par->reserved_sectors - 1; ++i) {
     285        for (i = 0; i < cfg->reserved_sectors - 1; ++i) {
    259286                rc = block_write_direct(service_id, addr, 1, buffer);
    260287                if (rc != EOK)
     
    265292
    266293        /* File allocation tables */
    267         for (i = 0; i < fat_count; ++i) {
     294        for (i = 0; i < cfg->fat_count; ++i) {
    268295                printf("Writing allocation table %d.\n", i + 1);
    269296
    270                 for (j = 0; j < par->fat_sectors; ++j) {
    271                         memset(buffer, 0, sector_size);
     297                for (j = 0; j < cfg->fat_sectors; ++j) {
     298                        memset(buffer, 0, cfg->sector_size);
    272299                        if (j == 0) {
    273                                 buffer[0] = media_descriptor;
     300                                buffer[0] = default_media_descriptor;
    274301                                buffer[1] = 0xFF;
    275302                                buffer[2] = 0xFF;
    276                                 buffer[3] = 0xFF;
     303                                if (cfg->fat_type == FAT16) {
     304                                        buffer[3] = 0xFF;
     305                                } else if (cfg->fat_type == FAT32) {
     306                                        buffer[3] = 0x0F;
     307                                        buffer[4] = 0xFF;
     308                                        buffer[5] = 0xFF;
     309                                        buffer[6] = 0xFF;
     310                                        buffer[7] = 0x0F;
     311                                        buffer[8] = 0xF8;
     312                                        buffer[9] = 0xFF;
     313                                        buffer[10] = 0xFF;
     314                                        buffer[11] = 0x0F;
     315                                }
    277316                        }
    278317
     
    285324        }
    286325
     326        /* Root directory */
    287327        printf("Writing root directory.\n");
    288 
    289         memset(buffer, 0, sector_size);
    290 
    291         /* Root directory */
    292         for (i = 0; i < par->rootdir_sectors; ++i) {
    293                 rc = block_write_direct(service_id, addr, 1, buffer);
    294                 if (rc != EOK)
    295                         return EIO;
    296 
    297                 ++addr;
     328        memset(buffer, 0, cfg->sector_size);
     329        if (cfg->fat_type != FAT32) {
     330                size_t idx;
     331                for (idx = 0; idx < cfg->rootdir_sectors; ++idx) {
     332                        rc = block_write_direct(service_id, addr, 1, buffer);
     333                        if (rc != EOK)
     334                                return EIO;
     335
     336                        ++addr;
     337                }
     338        } else {
     339                for (i = 0; i < cfg->sectors_per_cluster; i++) {
     340                        rc = block_write_direct(service_id, addr, 1, buffer);
     341                        if (rc != EOK)
     342                                return EIO;
     343
     344                        ++addr;
     345                }       
    298346        }
    299347
     
    304352
    305353/** Construct boot sector with the given parameters. */
    306 static void fat_bootsec_create(struct fat_params const *par, struct fat_bs *bs)
     354static void fat_bootsec_create(struct fat_cfg const *cfg, struct fat_bs *bs)
    307355{
    308356        memset(bs, 0, sizeof(*bs));
     
    315363
    316364        /* BIOS Parameter Block */
    317         bs->bps = host2uint16_t_le(sector_size);
    318         bs->spc = sectors_per_cluster;
    319         bs->rscnt = host2uint16_t_le(par->reserved_sectors);
    320         bs->fatcnt = fat_count;
    321         bs->root_ent_max = host2uint16_t_le(par->cfg.root_ent_max);
    322 
    323         if (par->cfg.total_sectors < 0x10000)
    324                 bs->totsec16 = host2uint16_t_le(par->cfg.total_sectors);
    325         else
    326                 bs->totsec16 = host2uint16_t_le(0);
    327 
    328         bs->mdesc = media_descriptor;
    329         bs->sec_per_fat = host2uint16_t_le(par->fat_sectors);
     365        bs->bps = host2uint16_t_le(cfg->sector_size);
     366        bs->spc = cfg->sectors_per_cluster;
     367        bs->rscnt = host2uint16_t_le(cfg->reserved_sectors);
     368        bs->fatcnt = cfg->fat_count;
     369        bs->root_ent_max = host2uint16_t_le(cfg->root_ent_max);
     370
     371        if (cfg->total_sectors < 0x10000) {
     372                bs->totsec16 = host2uint16_t_le(cfg->total_sectors);
     373                bs->totsec32 = 0;
     374        } else {
     375                bs->totsec16 = 0;
     376                bs->totsec32 = host2uint32_t_le(cfg->total_sectors);
     377        }
     378
     379        bs->mdesc = default_media_descriptor;
    330380        bs->sec_per_track = host2uint16_t_le(63);
     381        bs->signature = host2uint16_t_be(0x55AA);
    331382        bs->headcnt = host2uint16_t_le(6);
    332383        bs->hidden_sec = host2uint32_t_le(0);
    333384
    334         if (par->cfg.total_sectors >= 0x10000)
    335                 bs->totsec32 = host2uint32_t_le(par->cfg.total_sectors);
    336         else
    337                 bs->totsec32 = host2uint32_t_le(0);
    338 
    339         /* Extended BPB */
    340         bs->pdn = 0x80;
    341         bs->ebs = 0x29;
    342         bs->id = host2uint32_t_be(0x12345678);
    343 
    344         memcpy(bs->label, "HELENOS_NEW", 11);
    345         memcpy(bs->type, "FAT16   ", 8);
    346         bs->signature = host2uint16_t_be(0x55AA);
     385        if (cfg->fat_type == FAT32) {
     386                bs->sec_per_fat = 0;
     387                bs->fat32.sectors_per_fat = host2uint32_t_le(cfg->fat_sectors);
     388
     389                bs->fat32.pdn = 0x80;
     390                bs->fat32.ebs = 0x29;
     391                bs->fat32.id = host2uint32_t_be(0x12345678);
     392                bs->fat32.root_cluster = 2;
     393
     394                memcpy(bs->fat32.label, "HELENOS_NEW", 11);
     395                memcpy(bs->fat32.type, "FAT32   ", 8);
     396        } else {
     397                bs->sec_per_fat = host2uint16_t_le(cfg->fat_sectors);
     398                bs->pdn = 0x80;
     399                bs->ebs = 0x29;
     400                bs->id = host2uint32_t_be(0x12345678);
     401
     402                memcpy(bs->label, "HELENOS_NEW", 11);
     403                memcpy(bs->type, "FAT   ", 8);
     404        }
    347405}
    348406
  • uspace/lib/c/generic/str.c

    r7fadb65 r4cf5ed46  
    33 * Copyright (c) 2008 Jiri Svoboda
    44 * Copyright (c) 2011 Martin Sucha
     5 * Copyright (c) 2011 Oleg Romanenko
    56 * All rights reserved.
    67 *
     
    640641}
    641642
     643/** Convert UTF16 string to string.
     644 *
     645 * Convert utf16 string @a src to string. The output is written to the buffer
     646 * specified by @a dest and @a size. @a size must be non-zero and the string
     647 * written will always be well-formed. Surrogate pairs also supported.
     648 *
     649 * @param dest  Destination buffer.
     650 * @param size  Size of the destination buffer.
     651 * @param src   Source utf16 string.
     652 *
     653 * @return EOK, if success, negative otherwise.
     654 */
     655int utf16_to_str(char *dest, size_t size, const uint16_t *src)
     656{
     657        size_t idx = 0, dest_off = 0;
     658        wchar_t ch;
     659        int rc = EOK;
     660
     661        /* There must be space for a null terminator in the buffer. */
     662        assert(size > 0);
     663
     664        while (src[idx]) {
     665                if ((src[idx] & 0xfc00) == 0xd800) {
     666                        if (src[idx + 1] && (src[idx + 1] & 0xfc00) == 0xdc00) {
     667                                ch = 0x10000;
     668                                ch += (src[idx] & 0x03FF) << 10;
     669                                ch += (src[idx + 1] & 0x03FF);
     670                                idx += 2;
     671                        }
     672                        else
     673                                break;
     674                } else {
     675                        ch = src[idx];
     676                        idx++;
     677                }
     678                rc = chr_encode(ch, dest, &dest_off, size - 1);
     679                if (rc != EOK)
     680                        break;
     681        }
     682        dest[dest_off] = '\0';
     683        return rc;
     684}
     685
     686int str_to_utf16(uint16_t *dest, size_t size, const char *src)
     687{
     688        int rc = EOK;
     689        size_t offset = 0;
     690        size_t idx = 0;
     691        wchar_t c;
     692
     693        assert(size > 0);
     694       
     695        while ((c = str_decode(src, &offset, STR_NO_LIMIT)) != 0) {
     696                if (c > 0x10000) {
     697                        if (idx + 2 >= size - 1) {
     698                                rc = EOVERFLOW;
     699                                break;
     700                        }
     701                        c = (c - 0x10000);
     702                        dest[idx] = 0xD800 | (c >> 10);
     703                        dest[idx + 1] = 0xDC00 | (c & 0x3FF);
     704                        idx++;
     705                } else {
     706                         dest[idx] = c;
     707                }
     708
     709                idx++;
     710                if (idx >= size - 1) {
     711                        rc = EOVERFLOW;
     712                        break;
     713                }
     714        }
     715
     716        dest[idx] = '\0';
     717        return rc;
     718}
     719
     720
    642721/** Convert wide string to new string.
    643722 *
     
    10361115        return dest;
    10371116}
    1038 
    10391117
    10401118/** Convert initial part of string to unsigned long according to given base.
  • uspace/lib/c/include/str.h

    r7fadb65 r4cf5ed46  
    11/*
    22 * Copyright (c) 2005 Martin Decky
     3 * Copyright (c) 2011 Oleg Romanenko
    34 * All rights reserved.
    45 *
     
    8485extern void str_to_wstr(wchar_t *dest, size_t dlen, const char *src);
    8586extern wchar_t *str_to_awstr(const char *src);
     87extern int utf16_to_str(char *dest, size_t size, const uint16_t *src);
     88extern int str_to_utf16(uint16_t *dest, size_t size, const char *src);
    8689
    8790extern char *str_chr(const char *str, wchar_t ch);
  • uspace/srv/fs/fat/Makefile

    r7fadb65 r4cf5ed46  
    3939        fat_idx.c \
    4040        fat_dentry.c \
     41        fat_directory.c \
    4142        fat_fat.c
    4243
  • uspace/srv/fs/fat/fat.c

    r7fadb65 r4cf5ed46  
    22 * Copyright (c) 2006 Martin Decky
    33 * Copyright (c) 2008 Jakub Jermar
     4 * Copyright (c) 2011 Oleg Romanenko
    45 * All rights reserved.
    56 *
  • uspace/srv/fs/fat/fat.h

    r7fadb65 r4cf5ed46  
    11/*
    22 * Copyright (c) 2008 Jakub Jermar
     3 * Copyright (c) 2011 Oleg Romanenko
    34 * All rights reserved.
    45 *
     
    4647#endif
    4748
    48 #define min(a, b)               ((a) < (b) ? (a) : (b))
     49#define min(a, b)       ((a) < (b) ? (a) : (b))
    4950
    5051/*
     
    5556#define RSCNT(bs)       uint16_t_le2host((bs)->rscnt)
    5657#define FATCNT(bs)      (bs)->fatcnt
    57 #define SF(bs)          uint16_t_le2host((bs)->sec_per_fat)
     58
     59#define SF(bs)          (uint16_t_le2host((bs)->sec_per_fat) ? \
     60    uint16_t_le2host((bs)->sec_per_fat) : \
     61    uint32_t_le2host(bs->fat32.sectors_per_fat))
     62
    5863#define RDE(bs)         uint16_t_le2host((bs)->root_ent_max)
    59 #define TS(bs)          (uint16_t_le2host((bs)->totsec16) != 0 ? \
    60                         uint16_t_le2host((bs)->totsec16) : \
    61                         uint32_t_le2host(bs->totsec32))
    62 
    63 #define BS_BLOCK                0
    64 #define BS_SIZE                 512
     64
     65#define TS(bs)          (uint16_t_le2host((bs)->totsec16) ? \
     66    uint16_t_le2host((bs)->totsec16) : \
     67    uint32_t_le2host(bs->totsec32))
     68
     69#define BS_BLOCK        0
     70#define BS_SIZE         512
    6571
    6672typedef struct fat_bs {
  • uspace/srv/fs/fat/fat_dentry.c

    r7fadb65 r4cf5ed46  
    11/*
    22 * Copyright (c) 2008 Jakub Jermar
     3 * Copyright (c) 2011 Oleg Romanenko
    34 * All rights reserved.
    45 *
     
    3940#include <ctype.h>
    4041#include <str.h>
    41 
    42 static bool is_d_char(const char ch)
    43 {
    44         if (isalnum(ch) || ch == '_')
    45                 return true;
    46         else
    47                 return false;
    48 }
     42#include <errno.h>
     43#include <byteorder.h>
     44#include <assert.h>
    4945
    5046/** Compare path component with the name read from the dentry.
     
    8076}
    8177
    82 bool fat_dentry_name_verify(const char *name)
     78void fat_dentry_name_get(const fat_dentry_t *d, char *buf)
     79{
     80        unsigned int i;
     81       
     82        for (i = 0; i < FAT_NAME_LEN; i++) {
     83                if (d->name[i] == FAT_PAD)
     84                        break;
     85               
     86                if (d->name[i] == FAT_DENTRY_E5_ESC)
     87                        *buf++ = 0xe5;
     88                else {
     89                        if (d->lcase & FAT_LCASE_LOWER_NAME)
     90                                *buf++ = tolower(d->name[i]);
     91                        else
     92                                *buf++ = d->name[i];
     93                }
     94        }
     95       
     96        if (d->ext[0] != FAT_PAD)
     97                *buf++ = '.';
     98       
     99        for (i = 0; i < FAT_EXT_LEN; i++) {
     100                if (d->ext[i] == FAT_PAD) {
     101                        *buf = '\0';
     102                        return;
     103                }
     104               
     105                if (d->ext[i] == FAT_DENTRY_E5_ESC)
     106                        *buf++ = 0xe5;
     107                else {
     108                        if (d->lcase & FAT_LCASE_LOWER_EXT)
     109                                *buf++ = tolower(d->ext[i]);
     110                        else
     111                                *buf++ = d->ext[i];
     112                }
     113        }
     114       
     115        *buf = '\0';
     116}
     117
     118void fat_dentry_name_set(fat_dentry_t *d, const char *name)
     119{
     120        unsigned int i;
     121        const char fake_ext[] = "   ";
     122        bool lower_name = true;
     123        bool lower_ext = true;
     124       
     125        for (i = 0; i < FAT_NAME_LEN; i++) {
     126                switch ((uint8_t) *name) {
     127                case 0xe5:
     128                        d->name[i] = FAT_DENTRY_E5_ESC;
     129                        name++;
     130                        break;
     131                case '\0':
     132                case '.':
     133                        d->name[i] = FAT_PAD;
     134                        break;
     135                default:
     136                        if (isalpha(*name)) {
     137                                if (!islower(*name))
     138                                        lower_name = false;
     139                        }
     140                       
     141                        d->name[i] = toupper(*name++);
     142                        break;
     143                }
     144        }
     145       
     146        if (*name++ != '.')
     147                name = fake_ext;
     148       
     149        for (i = 0; i < FAT_EXT_LEN; i++) {
     150                switch ((uint8_t) *name) {
     151                case 0xe5:
     152                        d->ext[i] = FAT_DENTRY_E5_ESC;
     153                        name++;
     154                        break;
     155                case '\0':
     156                        d->ext[i] = FAT_PAD;
     157                        break;
     158                default:
     159                        if (isalpha(*name)) {
     160                                if (!islower(*name))
     161                                        lower_ext = false;
     162                        }
     163                       
     164                        d->ext[i] = toupper(*name++);
     165                        break;
     166                }
     167        }
     168       
     169        if (lower_name)
     170                d->lcase |= FAT_LCASE_LOWER_NAME;
     171        else
     172                d->lcase &= ~FAT_LCASE_LOWER_NAME;
     173       
     174        if (lower_ext)
     175                d->lcase |= FAT_LCASE_LOWER_EXT;
     176        else
     177                d->lcase &= ~FAT_LCASE_LOWER_EXT;
     178}
     179
     180fat_dentry_clsf_t fat_classify_dentry(const fat_dentry_t *d)
     181{
     182        if (d->attr == FAT_ATTR_LFN) {
     183                /* long name entry */
     184                if (FAT_LFN_ORDER(d) & FAT_LFN_ERASED)
     185                        return FAT_DENTRY_FREE;
     186                else
     187                        return FAT_DENTRY_LFN;
     188        }
     189        if (d->attr & FAT_ATTR_VOLLABEL) {
     190                /* volume label entry */
     191                return FAT_DENTRY_SKIP;
     192        }
     193        if (d->name[0] == FAT_DENTRY_ERASED) {
     194                /* not-currently-used entry */
     195                return FAT_DENTRY_FREE;
     196        }
     197        if (d->name[0] == FAT_DENTRY_UNUSED) {
     198                /* never used entry */
     199                return FAT_DENTRY_LAST;
     200        }
     201        if (d->name[0] == FAT_DENTRY_DOT) {
     202                /*
     203                 * Most likely '.' or '..'.
     204                 * It cannot occur in a regular file name.
     205                 */
     206                return FAT_DENTRY_SKIP;
     207        }
     208        return FAT_DENTRY_VALID;
     209}
     210
     211/** Compute checksum of Node name.
     212 *
     213 * Returns an unsigned byte checksum computed on an unsigned byte
     214 * array. The array must be 11 bytes long and is assumed to contain
     215 * a name stored in the format of a MS-DOS directory entry.
     216 *
     217 * @param name          Node name read from the dentry.
     218 *
     219 * @return              An 8-bit unsigned checksum of the name.
     220 */
     221uint8_t fat_dentry_chksum(uint8_t *name)
     222{
     223        uint8_t i, sum = 0;
     224
     225        for (i = 0; i < (FAT_NAME_LEN + FAT_EXT_LEN); i++)
     226                sum = ((sum & 1) ? 0x80 : 0) + (sum >> 1) + name[i];
     227
     228        return sum;
     229}
     230
     231/** Get number of bytes in a string with size limit.
     232 *
     233 * @param str  NULL-terminated (or not) string.
     234 * @param size Maximum number of bytes to consider.
     235 *
     236 * @return Number of bytes in string (without 0 and ff).
     237 *
     238 */
     239size_t fat_lfn_str_nlength(const uint16_t *str, size_t size)
     240{
     241        size_t offset = 0;
     242
     243        while (offset < size) {
     244                if (str[offset] == 0 || str[offset] == FAT_LFN_PAD)
     245                        break;
     246                offset++;
     247        }
     248        return offset;
     249}
     250
     251/** Get number of bytes in a FAT long entry occuped by characters.
     252 *
     253 * @param d FAT long entry.
     254 *
     255 * @return Number of bytes.
     256 *
     257 */
     258size_t fat_lfn_size(const fat_dentry_t *d)
     259{
     260        size_t size = 0;
     261       
     262        size += fat_lfn_str_nlength(FAT_LFN_PART1(d), FAT_LFN_PART1_SIZE);
     263        size += fat_lfn_str_nlength(FAT_LFN_PART2(d), FAT_LFN_PART2_SIZE);
     264        size += fat_lfn_str_nlength(FAT_LFN_PART3(d), FAT_LFN_PART3_SIZE);     
     265       
     266        return size;
     267}
     268
     269size_t fat_lfn_get_entry(const fat_dentry_t *d, uint16_t *dst, size_t *offset)
     270{
     271        int i;
     272        for (i = FAT_LFN_PART3_SIZE - 1; i >= 0 && *offset > 0; i--) {
     273                if (d->lfn.part3[i] == 0 || d->lfn.part3[i] == FAT_LFN_PAD)
     274                        continue;
     275                (*offset)--;
     276                dst[(*offset)] = uint16_t_le2host(d->lfn.part3[i]);
     277        }
     278        for (i = FAT_LFN_PART2_SIZE - 1; i >= 0 && *offset > 0; i--) {
     279                if (d->lfn.part2[i] == 0 || d->lfn.part2[i] == FAT_LFN_PAD)
     280                        continue;
     281                (*offset)--;
     282                dst[(*offset)] = uint16_t_le2host(d->lfn.part2[i]);
     283        }
     284        for (i = FAT_LFN_PART1_SIZE - 1; i >= 0 && *offset > 0; i--) {
     285                if (d->lfn.part1[i] == 0 || d->lfn.part1[i] == FAT_LFN_PAD)
     286                        continue;
     287                (*offset)--;
     288                dst[(*offset)] = uint16_t_le2host(d->lfn.part1[i]);
     289        }
     290        return *offset;
     291}
     292
     293size_t fat_lfn_set_entry(const uint16_t *src, size_t *offset, size_t size,
     294    fat_dentry_t *d)
     295{
     296        size_t idx;
     297        for (idx = 0; idx < FAT_LFN_PART1_SIZE; idx++) {
     298                if (*offset < size) {
     299                        d->lfn.part1[idx] = host2uint16_t_le(src[*offset]);
     300                        (*offset)++;
     301                } else
     302                        d->lfn.part1[idx] = FAT_LFN_PAD;
     303        }
     304        for (idx = 0; idx < FAT_LFN_PART2_SIZE; idx++) {
     305                if (*offset < size) {
     306                        d->lfn.part2[idx] = host2uint16_t_le(src[*offset]);
     307                        (*offset)++;
     308                } else
     309                        d->lfn.part2[idx] = FAT_LFN_PAD;
     310        }
     311        for (idx = 0; idx < FAT_LFN_PART3_SIZE; idx++) {
     312                if (*offset < size) {
     313                        d->lfn.part3[idx] = host2uint16_t_le(src[*offset]);
     314                        (*offset)++;
     315                } else
     316                        d->lfn.part3[idx] = FAT_LFN_PAD;
     317        }
     318
     319        if (src[*offset] == 0)
     320                offset++;
     321        FAT_LFN_ATTR(d) = FAT_ATTR_LFN;
     322        d->lfn.type = 0;
     323        d->lfn.firstc_lo = 0;
     324       
     325        return *offset;
     326}
     327
     328void str_to_ascii(char *dst, const char *src, size_t count, uint8_t pad)
     329{
     330        wchar_t ch;
     331        size_t off = 0;
     332        size_t i = 0;
     333       
     334        while (i < count) {
     335                if ((ch = str_decode(src, &off, STR_NO_LIMIT)) != 0) {
     336                        if (ascii_check(ch) & IS_D_CHAR(ch))
     337                                *dst = toupper(ch);
     338                        else
     339                                *dst = pad;
     340                } else
     341                        break;
     342
     343                dst++;
     344                i++;
     345        }
     346        *dst = '\0';
     347}
     348
     349bool fat_valid_name(const char *name)
     350{
     351        wchar_t ch;
     352        size_t offset=0;
     353        bool result = true;
     354       
     355        while ((ch = str_decode(name, &offset, STR_NO_LIMIT)) != 0) {
     356                if (str_chr(FAT_STOP_CHARS, ch) != NULL) {
     357                        result = false;
     358                        break;
     359                }
     360        }
     361        return result;
     362}
     363
     364bool fat_valid_short_name(const char *name)
    83365{
    84366        unsigned int i;
    85367        unsigned int dot = 0;
    86368        bool dot_found = false;
    87        
    88369
    89370        for (i = 0; name[i]; i++) {
     
    96377                        }
    97378                } else {
    98                         if (!is_d_char(name[i]))
     379                        if (!IS_D_CHAR(name[i]))
    99380                                return false;
    100381                }
     
    114395}
    115396
    116 void fat_dentry_name_get(const fat_dentry_t *d, char *buf)
    117 {
    118         unsigned int i;
    119        
    120         for (i = 0; i < FAT_NAME_LEN; i++) {
    121                 if (d->name[i] == FAT_PAD)
    122                         break;
    123                
    124                 if (d->name[i] == FAT_DENTRY_E5_ESC)
    125                         *buf++ = 0xe5;
    126                 else {
    127                         if (d->lcase & FAT_LCASE_LOWER_NAME)
    128                                 *buf++ = tolower(d->name[i]);
    129                         else
    130                                 *buf++ = d->name[i];
    131                 }
    132         }
    133        
    134         if (d->ext[0] != FAT_PAD)
    135                 *buf++ = '.';
    136        
    137         for (i = 0; i < FAT_EXT_LEN; i++) {
    138                 if (d->ext[i] == FAT_PAD) {
    139                         *buf = '\0';
    140                         return;
    141                 }
    142                
    143                 if (d->ext[i] == FAT_DENTRY_E5_ESC)
    144                         *buf++ = 0xe5;
    145                 else {
    146                         if (d->lcase & FAT_LCASE_LOWER_EXT)
    147                                 *buf++ = tolower(d->ext[i]);
    148                         else
    149                                 *buf++ = d->ext[i];
    150                 }
    151         }
    152        
    153         *buf = '\0';
    154 }
    155 
    156 void fat_dentry_name_set(fat_dentry_t *d, const char *name)
    157 {
    158         unsigned int i;
    159         const char fake_ext[] = "   ";
    160         bool lower_name = true;
    161         bool lower_ext = true;
    162        
    163         for (i = 0; i < FAT_NAME_LEN; i++) {
    164                 switch ((uint8_t) *name) {
    165                 case 0xe5:
    166                         d->name[i] = FAT_DENTRY_E5_ESC;
    167                         name++;
    168                         break;
    169                 case '\0':
    170                 case '.':
    171                         d->name[i] = FAT_PAD;
    172                         break;
    173                 default:
    174                         if (isalpha(*name)) {
    175                                 if (!islower(*name))
    176                                         lower_name = false;
    177                         }
    178                        
    179                         d->name[i] = toupper(*name++);
    180                         break;
    181                 }
    182         }
    183        
    184         if (*name++ != '.')
    185                 name = fake_ext;
    186        
    187         for (i = 0; i < FAT_EXT_LEN; i++) {
    188                 switch ((uint8_t) *name) {
    189                 case 0xe5:
    190                         d->ext[i] = FAT_DENTRY_E5_ESC;
    191                         name++;
    192                         break;
    193                 case '\0':
    194                         d->ext[i] = FAT_PAD;
    195                         break;
    196                 default:
    197                         if (isalpha(*name)) {
    198                                 if (!islower(*name))
    199                                         lower_ext = false;
    200                         }
    201                        
    202                         d->ext[i] = toupper(*name++);
    203                         break;
    204                 }
    205         }
    206        
    207         if (lower_name)
    208                 d->lcase |= FAT_LCASE_LOWER_NAME;
    209         else
    210                 d->lcase &= ~FAT_LCASE_LOWER_NAME;
    211        
    212         if (lower_ext)
    213                 d->lcase |= FAT_LCASE_LOWER_EXT;
    214         else
    215                 d->lcase &= ~FAT_LCASE_LOWER_EXT;
    216 }
    217 
    218 fat_dentry_clsf_t fat_classify_dentry(const fat_dentry_t *d)
    219 {
    220         if (d->attr & FAT_ATTR_VOLLABEL) {
    221                 /* volume label entry */
    222                 return FAT_DENTRY_SKIP;
    223         }
    224         if (d->name[0] == FAT_DENTRY_ERASED) {
    225                 /* not-currently-used entry */
    226                 return FAT_DENTRY_FREE;
    227         }
    228         if (d->name[0] == FAT_DENTRY_UNUSED) {
    229                 /* never used entry */
    230                 return FAT_DENTRY_LAST;
    231         }
    232         if (d->name[0] == FAT_DENTRY_DOT) {
    233                 /*
    234                  * Most likely '.' or '..'.
    235                  * It cannot occur in a regular file name.
    236                  */
    237                 return FAT_DENTRY_SKIP;
    238         }
    239         return FAT_DENTRY_VALID;
     397size_t utf16_length(const uint16_t *wstr)
     398{
     399        size_t len = 0;
     400       
     401        while (*wstr++ != 0)
     402                len++;
     403       
     404        return len;
    240405}
    241406
  • uspace/srv/fs/fat/fat_dentry.h

    r7fadb65 r4cf5ed46  
    11/*
    22 * Copyright (c) 2008 Jakub Jermar
     3 * Copyright (c) 2011 Oleg Romanenko
    34 * All rights reserved.
    45 *
     
    3738#include <bool.h>
    3839
     40#define IS_D_CHAR(ch) (isalnum(ch) || ch == '_')
     41#define FAT_STOP_CHARS "*?/\\\n\t|'"
     42
    3943#define FAT_NAME_LEN            8
    4044#define FAT_EXT_LEN             3
     
    4448#define FAT_EXT_PAD             "   "
    4549
    46 #define FAT_ATTR_RDONLY         (1 << 0)
    47 #define FAT_ATTR_VOLLABEL       (1 << 3)
    48 #define FAT_ATTR_SUBDIR         (1 << 4)
    49 
     50#define FAT_ATTR_RDONLY   0x01
     51#define FAT_ATTR_HIDDEN   0x02
     52#define FAT_ATTR_SYSTEM   0x04
     53#define FAT_ATTR_VOLLABEL 0x08
     54#define FAT_ATTR_SUBDIR   0x10
     55#define FAT_ATTR_ARCHIVE  0x20
     56#define FAT_ATTR_LFN \
     57    (FAT_ATTR_RDONLY | FAT_ATTR_HIDDEN | FAT_ATTR_SYSTEM | FAT_ATTR_VOLLABEL)
     58   
    5059#define FAT_LCASE_LOWER_NAME    0x08
    5160#define FAT_LCASE_LOWER_EXT     0x10
    5261
    53 #define FAT_PAD                 ' '
     62#define FAT_PAD                 ' '
     63#define FAT_LFN_PAD     0xffff
     64#define FAT_SFN_CHAR '_'
    5465
    5566#define FAT_DENTRY_UNUSED       0x00
     
    5768#define FAT_DENTRY_DOT          0x2e
    5869#define FAT_DENTRY_ERASED       0xe5
     70#define FAT_LFN_LAST            0x40
     71#define FAT_LFN_ERASED          0x80
     72
     73#define FAT_LFN_ORDER(d) ((d)->lfn.order)
     74#define FAT_IS_LFN(d) \
     75    ((FAT_LFN_ORDER((d)) & FAT_LFN_LAST) == FAT_LFN_LAST)
     76#define FAT_LFN_COUNT(d) \
     77    (FAT_LFN_ORDER((d)) ^ FAT_LFN_LAST)
     78#define FAT_LFN_PART1(d) ((d)->lfn.part1)
     79#define FAT_LFN_PART2(d) ((d)->lfn.part2)
     80#define FAT_LFN_PART3(d) ((d)->lfn.part3)
     81#define FAT_LFN_ATTR(d) ((d)->lfn.attr)
     82#define FAT_LFN_CHKSUM(d) ((d)->lfn.check_sum)
     83
     84#define FAT_LFN_NAME_SIZE   260
     85#define FAT_LFN_MAX_COUNT   20
     86#define FAT_LFN_PART1_SIZE  5
     87#define FAT_LFN_PART2_SIZE  6
     88#define FAT_LFN_PART3_SIZE  2
     89#define FAT_LFN_ENTRY_SIZE \
     90    (FAT_LFN_PART1_SIZE + FAT_LFN_PART2_SIZE + FAT_LFN_PART3_SIZE)
    5991
    6092typedef enum {
     
    6294        FAT_DENTRY_LAST,
    6395        FAT_DENTRY_FREE,
    64         FAT_DENTRY_VALID
     96        FAT_DENTRY_VALID,
     97        FAT_DENTRY_LFN
    6598} fat_dentry_clsf_t;
    6699
    67 typedef struct {
    68         uint8_t         name[8];
    69         uint8_t         ext[3];
    70         uint8_t         attr;
    71         uint8_t         lcase;
    72         uint8_t         ctime_fine;
    73         uint16_t        ctime;
    74         uint16_t        cdate;
    75         uint16_t        adate;
    76         union {
    77                 uint16_t        eaidx;          /* FAT12/FAT16 */
    78                 uint16_t        firstc_hi;      /* FAT32 */
     100typedef union {
     101        struct {
     102                uint8_t         name[8];
     103                uint8_t         ext[3];
     104                uint8_t         attr;
     105                uint8_t         lcase;
     106                uint8_t         ctime_fine;
     107                uint16_t        ctime;
     108                uint16_t        cdate;
     109                uint16_t        adate;
     110                union {
     111                        uint16_t        eaidx;          /* FAT12/FAT16 */
     112                        uint16_t        firstc_hi;      /* FAT32 */
     113                } __attribute__ ((packed));
     114                uint16_t        mtime;
     115                uint16_t        mdate;
     116                union {
     117                        uint16_t        firstc;         /* FAT12/FAT16 */
     118                        uint16_t        firstc_lo;      /* FAT32 */
     119                } __attribute__ ((packed));
     120                uint32_t        size;
    79121        } __attribute__ ((packed));
    80         uint16_t        mtime;
    81         uint16_t        mdate;
    82         union {
    83                 uint16_t        firstc;         /* FAT12/FAT16 */
    84                 uint16_t        firstc_lo;      /* FAT32 */
    85         } __attribute__ ((packed));
    86         uint32_t        size;
     122        struct {
     123                uint8_t         order;
     124                uint16_t        part1[FAT_LFN_PART1_SIZE];
     125                uint8_t         attr;
     126                uint8_t         type;
     127                uint8_t         check_sum;
     128                uint16_t        part2[FAT_LFN_PART2_SIZE];
     129                uint16_t        firstc_lo; /* MUST be 0 */
     130                uint16_t        part3[FAT_LFN_PART3_SIZE];
     131        } __attribute__ ((packed)) lfn;
    87132} __attribute__ ((packed)) fat_dentry_t;
    88133
     134
    89135extern int fat_dentry_namecmp(char *, const char *);
    90 extern bool fat_dentry_name_verify(const char *);
    91136extern void fat_dentry_name_get(const fat_dentry_t *, char *);
    92137extern void fat_dentry_name_set(fat_dentry_t *, const char *);
    93138extern fat_dentry_clsf_t fat_classify_dentry(const fat_dentry_t *);
     139extern uint8_t fat_dentry_chksum(uint8_t *);
     140
     141extern size_t fat_lfn_str_nlength(const uint16_t *, size_t);
     142extern size_t fat_lfn_size(const fat_dentry_t *);
     143extern size_t fat_lfn_get_entry(const fat_dentry_t *, uint16_t *, size_t *);
     144extern size_t fat_lfn_set_entry(const uint16_t *, size_t *, size_t,
     145    fat_dentry_t *);
     146
     147extern void str_to_ascii(char *, const char *, size_t, uint8_t);
     148extern size_t utf16_length(const uint16_t *);
     149
     150extern bool fat_valid_name(const char *);
     151extern bool fat_valid_short_name(const char *);
    94152
    95153#endif
  • uspace/srv/fs/fat/fat_fat.c

    r7fadb65 r4cf5ed46  
    11/*
    22 * Copyright (c) 2008 Jakub Jermar
     3 * Copyright (c) 2011 Oleg Romanenko
    34 * All rights reserved.
    45 *
     
    2930/** @addtogroup fs
    3031 * @{
    31  */ 
     32 */
    3233
    3334/**
     
    5051#include <mem.h>
    5152
    52 /*
    53  * Convenience macros for computing some frequently used values from the
    54  * primitive boot sector members.
    55  */
    56 #define RDS(bs)         ((sizeof(fat_dentry_t) * RDE((bs))) / BPS((bs))) + \
    57                         (((sizeof(fat_dentry_t) * RDE((bs))) % BPS((bs))) != 0)
    58 #define SSA(bs)         (RSCNT((bs)) + FATCNT((bs)) * SF((bs)) + RDS(bs))
    59 
    60 #define CLBN2PBN(bs, cl, bn) \
    61         (SSA((bs)) + ((cl) - FAT_CLST_FIRST) * SPC((bs)) + (bn) % SPC((bs)))
     53#define IS_ODD(number)  (number & 0x1)
    6254
    6355/**
     
    6557 * during allocation of clusters. The lock does not have to be held durring
    6658 * deallocation of clusters.
    67  */ 
     59 */
    6860static FIBRIL_MUTEX_INITIALIZE(fat_alloc_lock);
    6961
     
    7769 * @param numc          If non-NULL, output argument holding the number of
    7870 *                      clusters seen during the walk.
    79  * @param max_clusters  Maximum number of clusters to visit.   
     71 * @param max_clusters  Maximum number of clusters to visit.
    8072 *
    8173 * @return              EOK on success or a negative error code.
    8274 */
    83 int 
     75int
    8476fat_cluster_walk(fat_bs_t *bs, service_id_t service_id, fat_cluster_t firstc,
    85     fat_cluster_t *lastc, uint16_t *numc, uint16_t max_clusters)
    86 {
    87         block_t *b;
    88         uint16_t clusters = 0;
    89         fat_cluster_t clst = firstc;
     77    fat_cluster_t *lastc, uint32_t *numc, uint32_t max_clusters)
     78{
     79        uint32_t clusters = 0;
     80        fat_cluster_t clst = firstc, clst_last1 = FAT_CLST_LAST1(bs);
     81        fat_cluster_t clst_bad = FAT_CLST_BAD(bs);
    9082        int rc;
    9183
     
    9991        }
    10092
    101         while (clst < FAT_CLST_LAST1 && clusters < max_clusters) {
    102                 aoff64_t fsec;  /* sector offset relative to FAT1 */
    103                 unsigned fidx;  /* FAT1 entry index */
    104 
     93        while (clst < clst_last1 && clusters < max_clusters) {
    10594                assert(clst >= FAT_CLST_FIRST);
    10695                if (lastc)
    10796                        *lastc = clst;  /* remember the last cluster number */
    108                 fsec = (clst * sizeof(fat_cluster_t)) / BPS(bs);
    109                 fidx = clst % (BPS(bs) / sizeof(fat_cluster_t));
     97
    11098                /* read FAT1 */
    111                 rc = block_get(&b, service_id, RSCNT(bs) + fsec,
    112                     BLOCK_FLAGS_NONE);
    113                 if (rc != EOK)
    114                         return rc;
    115                 clst = uint16_t_le2host(((fat_cluster_t *)b->data)[fidx]);
    116                 assert(clst != FAT_CLST_BAD);
    117                 rc = block_put(b);
    118                 if (rc != EOK)
    119                         return rc;
     99                rc = fat_get_cluster(bs, service_id, FAT1, clst, &clst);
     100                if (rc != EOK)
     101                        return rc;
     102
     103                assert(clst != clst_bad);
    120104                clusters++;
    121105        }
    122106
    123         if (lastc && clst < FAT_CLST_LAST1)
     107        if (lastc && clst < clst_last1)
    124108                *lastc = clst;
    125109        if (numc)
     
    151135                return ELIMIT;
    152136
    153         if (nodep->firstc == FAT_CLST_ROOT)
     137        if (!FAT_IS_FAT32(bs) && nodep->firstc == FAT_CLST_ROOT)
    154138                goto fall_through;
    155139
     
    178162        if (rc != EOK)
    179163                return rc;
    180        
     164
    181165        /*
    182166         * Update the "current" cluster cache.
     
    198182 * @param clp           If not NULL, address where the cluster containing bn
    199183 *                      will be stored.
    200  *                      stored 
     184 *                      stored
    201185 * @param bn            Block number.
    202186 * @param flags         Flags passed to libblock.
     
    208192    fat_cluster_t fcl, fat_cluster_t *clp, aoff64_t bn, int flags)
    209193{
    210         uint16_t clusters;
    211         unsigned max_clusters;
     194        uint32_t clusters;
     195        uint32_t max_clusters;
    212196        fat_cluster_t c;
    213197        int rc;
     
    219203                return ELIMIT;
    220204
    221         if (fcl == FAT_CLST_ROOT) {
     205        if (!FAT_IS_FAT32(bs) && fcl == FAT_CLST_ROOT) {
    222206                /* root directory special case */
    223207                assert(bn < RDS(bs));
     
    253237 * @return              EOK on success or a negative error code.
    254238 */
    255 int fat_fill_gap(fat_bs_t *bs, fat_node_t *nodep, fat_cluster_t mcl, aoff64_t pos)
     239int
     240fat_fill_gap(fat_bs_t *bs, fat_node_t *nodep, fat_cluster_t mcl, aoff64_t pos)
    256241{
    257242        block_t *b;
     
    275260                        return rc;
    276261        }
    277        
     262
    278263        if (o >= pos)
    279264                return EOK;
    280        
     265
    281266        /* zero out the initial part of the new cluster chain */
    282267        for (o = boundary; o < pos; o += BPS(bs)) {
     
    304289 * @return              EOK or a negative error code.
    305290 */
     291static int
     292fat_get_cluster_fat12(fat_bs_t *bs, service_id_t service_id, unsigned fatno,
     293    fat_cluster_t clst, fat_cluster_t *value)
     294{
     295        block_t *b, *b1;
     296        uint16_t byte1, byte2;
     297        aoff64_t offset;
     298        int rc;
     299
     300        offset = (clst + clst / 2);
     301        if (offset / BPS(bs) >= SF(bs))
     302                return ERANGE;
     303
     304        rc = block_get(&b, service_id, RSCNT(bs) + SF(bs) * fatno +
     305            offset / BPS(bs), BLOCK_FLAGS_NONE);
     306        if (rc != EOK)
     307                return rc;
     308
     309        byte1 = ((uint8_t *) b->data)[offset % BPS(bs)];
     310        /* This cluster access spans a sector boundary. Check only for FAT12 */
     311        if ((offset % BPS(bs)) + 1 == BPS(bs)) {
     312                /* Is this the last sector of FAT? */
     313                if (offset / BPS(bs) < SF(bs)) {
     314                        /* No, read the next sector */
     315                        rc = block_get(&b1, service_id, 1 + RSCNT(bs) +
     316                            SF(bs) * fatno + offset / BPS(bs),
     317                            BLOCK_FLAGS_NONE);
     318                        if (rc != EOK) {
     319                                block_put(b);
     320                                return rc;
     321                        }
     322                        /*
     323                        * Combining value with last byte of current sector and
     324                        * first byte of next sector
     325                        */
     326                        byte2 = ((uint8_t*) b1->data)[0];
     327
     328                        rc = block_put(b1);
     329                        if (rc != EOK) {
     330                                block_put(b);
     331                                return rc;
     332                        }
     333                } else {
     334                        /* Yes. This is the last sector of FAT */
     335                        block_put(b);
     336                        return ERANGE;
     337                }
     338        } else
     339                byte2 = ((uint8_t *) b->data)[(offset % BPS(bs)) + 1];
     340
     341        *value = uint16_t_le2host(byte1 | (byte2 << 8));
     342        if (IS_ODD(clst))
     343                *value = (*value) >> 4;
     344        else
     345                *value = (*value) & FAT12_MASK;
     346       
     347        rc = block_put(b);
     348
     349        return rc;
     350}
     351
     352/** Get cluster from the first FAT.
     353 *
     354 * @param bs            Buffer holding the boot sector for the file system.
     355 * @param service_id    Service ID for the file system.
     356 * @param clst          Cluster which to get.
     357 * @param value         Output argument holding the value of the cluster.
     358 *
     359 * @return              EOK or a negative error code.
     360 */
     361static int
     362fat_get_cluster_fat16(fat_bs_t *bs, service_id_t service_id, unsigned fatno,
     363    fat_cluster_t clst, fat_cluster_t *value)
     364{
     365        block_t *b;
     366        aoff64_t offset;
     367        int rc;
     368
     369        offset = (clst * FAT16_CLST_SIZE);
     370
     371        rc = block_get(&b, service_id, RSCNT(bs) + SF(bs) * fatno +
     372            offset / BPS(bs), BLOCK_FLAGS_NONE);
     373        if (rc != EOK)
     374                return rc;
     375
     376        *value = uint16_t_le2host(*(uint16_t *)(b->data + offset % BPS(bs)));
     377
     378        rc = block_put(b);
     379
     380        return rc;
     381}
     382
     383/** Get cluster from the first FAT.
     384 *
     385 * @param bs            Buffer holding the boot sector for the file system.
     386 * @param service_id    Service ID for the file system.
     387 * @param clst          Cluster which to get.
     388 * @param value         Output argument holding the value of the cluster.
     389 *
     390 * @return              EOK or a negative error code.
     391 */
     392static int
     393fat_get_cluster_fat32(fat_bs_t *bs, service_id_t service_id, unsigned fatno,
     394    fat_cluster_t clst, fat_cluster_t *value)
     395{
     396        block_t *b;
     397        aoff64_t offset;
     398        int rc;
     399
     400        offset = (clst * FAT32_CLST_SIZE);
     401
     402        rc = block_get(&b, service_id, RSCNT(bs) + SF(bs) * fatno +
     403            offset / BPS(bs), BLOCK_FLAGS_NONE);
     404        if (rc != EOK)
     405                return rc;
     406
     407        *value = uint32_t_le2host(*(uint32_t *)(b->data + offset % BPS(bs))) &
     408            FAT32_MASK;
     409
     410        rc = block_put(b);
     411
     412        return rc;
     413}
     414
     415
     416/** Get cluster from the first FAT.
     417 *
     418 * @param bs            Buffer holding the boot sector for the file system.
     419 * @param service_id    Service ID for the file system.
     420 * @param clst          Cluster which to get.
     421 * @param value         Output argument holding the value of the cluster.
     422 *
     423 * @return              EOK or a negative error code.
     424 */
    306425int
    307426fat_get_cluster(fat_bs_t *bs, service_id_t service_id, unsigned fatno,
    308427    fat_cluster_t clst, fat_cluster_t *value)
    309428{
    310         block_t *b;
    311         fat_cluster_t *cp;
    312         int rc;
    313 
     429        int rc;
     430
     431        assert(fatno < FATCNT(bs));
     432
     433        if (FAT_IS_FAT12(bs))
     434                rc = fat_get_cluster_fat12(bs, service_id, fatno, clst, value);
     435        else if (FAT_IS_FAT16(bs))
     436                rc = fat_get_cluster_fat16(bs, service_id, fatno, clst, value);
     437        else
     438                rc = fat_get_cluster_fat32(bs, service_id, fatno, clst, value);
     439
     440        return rc;
     441}
     442
     443/** Set cluster in one instance of FAT.
     444 *
     445 * @param bs            Buffer holding the boot sector for the file system.
     446 * @param service_id    Service ID for the file system.
     447 * @param fatno         Number of the FAT instance where to make the change.
     448 * @param clst          Cluster which is to be set.
     449 * @param value         Value to set the cluster with.
     450 *
     451 * @return              EOK on success or a negative error code.
     452 */
     453static int
     454fat_set_cluster_fat12(fat_bs_t *bs, service_id_t service_id, unsigned fatno,
     455    fat_cluster_t clst, fat_cluster_t value)
     456{
     457        block_t *b, *b1 = NULL;
     458        aoff64_t offset;
     459        uint16_t byte1, byte2;
     460        int rc;
     461
     462        offset = (clst + clst / 2);
     463        if (offset / BPS(bs) >= SF(bs))
     464                return ERANGE;
     465       
    314466        rc = block_get(&b, service_id, RSCNT(bs) + SF(bs) * fatno +
    315             (clst * sizeof(fat_cluster_t)) / BPS(bs), BLOCK_FLAGS_NONE);
     467            offset / BPS(bs), BLOCK_FLAGS_NONE);
    316468        if (rc != EOK)
    317469                return rc;
    318         cp = (fat_cluster_t *)b->data +
    319             clst % (BPS(bs) / sizeof(fat_cluster_t));
    320         *value = uint16_t_le2host(*cp);
     470
     471        byte1 = ((uint8_t*) b->data)[offset % BPS(bs)];
     472        bool border = false;
     473        /* This cluster access spans a sector boundary. */
     474        if ((offset % BPS(bs)) + 1 == BPS(bs)) {
     475                /* Is it the last sector of FAT? */
     476                if (offset / BPS(bs) < SF(bs)) {
     477                        /* No, read the next sector */
     478                        rc = block_get(&b1, service_id, 1 + RSCNT(bs) +
     479                            SF(bs) * fatno + offset / BPS(bs),
     480                            BLOCK_FLAGS_NONE);
     481                        if (rc != EOK) {
     482                                block_put(b);
     483                                return rc;
     484                        }
     485                        /*
     486                         * Combining value with last byte of current sector and
     487                         * first byte of next sector
     488                         */
     489                        byte2 = ((uint8_t *) b1->data)[0];
     490                        border = true;
     491                } else {
     492                        /* Yes. This is the last sector of FAT */
     493                        block_put(b);
     494                        return ERANGE;
     495                }
     496        } else
     497                byte2 = ((uint8_t*) b->data)[(offset % BPS(bs)) + 1];
     498
     499        if (IS_ODD(clst)) {
     500                byte1 &= 0x0f;
     501                byte2 = 0;
     502                value = (value << 4);
     503        } else {
     504                byte1 = 0;
     505                byte2 &= 0xf0;
     506                value &= FAT12_MASK;
     507        }
     508
     509        byte1 = byte1 | (value & 0xff);
     510        byte2 = byte2 | (value >> 8);
     511
     512        ((uint8_t *) b->data)[(offset % BPS(bs))] = byte1;
     513        if (border) {
     514                ((uint8_t *) b1->data)[0] = byte2;
     515
     516                b1->dirty = true;
     517                rc = block_put(b1);
     518                if (rc != EOK) {
     519                        block_put(b);
     520                        return rc;
     521                }
     522        } else
     523                ((uint8_t *) b->data)[(offset % BPS(bs)) + 1] = byte2;
     524
     525        b->dirty = true;        /* need to sync block */
    321526        rc = block_put(b);
    322        
     527
     528        return rc;
     529}
     530
     531/** Set cluster in one instance of FAT.
     532 *
     533 * @param bs            Buffer holding the boot sector for the file system.
     534 * @param service_id    Service ID for the file system.
     535 * @param fatno         Number of the FAT instance where to make the change.
     536 * @param clst          Cluster which is to be set.
     537 * @param value         Value to set the cluster with.
     538 *
     539 * @return              EOK on success or a negative error code.
     540 */
     541static int
     542fat_set_cluster_fat16(fat_bs_t *bs, service_id_t service_id, unsigned fatno,
     543    fat_cluster_t clst, fat_cluster_t value)
     544{
     545        block_t *b;
     546        aoff64_t offset;
     547        int rc;
     548
     549        offset = (clst * FAT16_CLST_SIZE);
     550
     551        rc = block_get(&b, service_id, RSCNT(bs) + SF(bs) * fatno +
     552            offset / BPS(bs), BLOCK_FLAGS_NONE);
     553        if (rc != EOK)
     554                return rc;
     555
     556        *(uint16_t *)(b->data + offset % BPS(bs)) = host2uint16_t_le(value);
     557
     558        b->dirty = true;        /* need to sync block */
     559        rc = block_put(b);
     560
     561        return rc;
     562}
     563
     564/** Set cluster in one instance of FAT.
     565 *
     566 * @param bs            Buffer holding the boot sector for the file system.
     567 * @param service_id    Service ID for the file system.
     568 * @param fatno         Number of the FAT instance where to make the change.
     569 * @param clst          Cluster which is to be set.
     570 * @param value         Value to set the cluster with.
     571 *
     572 * @return              EOK on success or a negative error code.
     573 */
     574static int
     575fat_set_cluster_fat32(fat_bs_t *bs, service_id_t service_id, unsigned fatno,
     576    fat_cluster_t clst, fat_cluster_t value)
     577{
     578        block_t *b;
     579        aoff64_t offset;
     580        int rc;
     581        fat_cluster_t temp;
     582
     583        offset = (clst * FAT32_CLST_SIZE);
     584
     585        rc = block_get(&b, service_id, RSCNT(bs) + SF(bs) * fatno +
     586            offset / BPS(bs), BLOCK_FLAGS_NONE);
     587        if (rc != EOK)
     588                return rc;
     589
     590        temp = uint32_t_le2host(*(uint32_t *)(b->data + offset % BPS(bs)));
     591        temp &= 0xf0000000;
     592        temp |= (value & FAT32_MASK);
     593        *(uint32_t *)(b->data + offset % BPS(bs)) = host2uint32_t_le(temp);
     594
     595        b->dirty = true;        /* need to sync block */
     596        rc = block_put(b);
     597
    323598        return rc;
    324599}
     
    338613    fat_cluster_t clst, fat_cluster_t value)
    339614{
    340         block_t *b;
    341         fat_cluster_t *cp;
    342615        int rc;
    343616
    344617        assert(fatno < FATCNT(bs));
    345         rc = block_get(&b, service_id, RSCNT(bs) + SF(bs) * fatno +
    346             (clst * sizeof(fat_cluster_t)) / BPS(bs), BLOCK_FLAGS_NONE);
    347         if (rc != EOK)
    348                 return rc;
    349         cp = (fat_cluster_t *)b->data +
    350             clst % (BPS(bs) / sizeof(fat_cluster_t));
    351         *cp = host2uint16_t_le(value);
    352         b->dirty = true;                /* need to sync block */
    353         rc = block_put(b);
     618
     619        if (FAT_IS_FAT12(bs))
     620                rc = fat_set_cluster_fat12(bs, service_id, fatno, clst, value);
     621        else if (FAT_IS_FAT16(bs))
     622                rc = fat_set_cluster_fat16(bs, service_id, fatno, clst, value);
     623        else
     624                rc = fat_set_cluster_fat32(bs, service_id, fatno, clst, value);
     625
    354626        return rc;
    355627}
     
    369641        uint8_t fatno;
    370642        unsigned c;
    371         int rc;
    372 
    373         for (fatno = FAT1 + 1; fatno < bs->fatcnt; fatno++) {
     643        fat_cluster_t clst_last1 = FAT_CLST_LAST1(bs);
     644        int rc;
     645
     646        for (fatno = FAT1 + 1; fatno < FATCNT(bs); fatno++) {
    374647                for (c = 0; c < nclsts; c++) {
    375648                        rc = fat_set_cluster(bs, service_id, fatno, lifo[c],
    376                             c == 0 ? FAT_CLST_LAST1 : lifo[c - 1]);
     649                            c == 0 ? clst_last1 : lifo[c - 1]);
    377650                        if (rc != EOK)
    378651                                return rc;
     
    404677    fat_cluster_t *mcl, fat_cluster_t *lcl)
    405678{
    406         block_t *blk;
    407         fat_cluster_t *lifo;    /* stack for storing free cluster numbers */
    408         unsigned found = 0;     /* top of the free cluster number stack */
    409         unsigned b, c, cl;
    410         int rc;
     679        fat_cluster_t *lifo;    /* stack for storing free cluster numbers */
     680        unsigned found = 0;     /* top of the free cluster number stack */
     681        fat_cluster_t clst, value, clst_last1 = FAT_CLST_LAST1(bs);
     682        int rc = EOK;
    411683
    412684        lifo = (fat_cluster_t *) malloc(nclsts * sizeof(fat_cluster_t));
    413685        if (!lifo)
    414686                return ENOMEM;
    415        
    416687        /*
    417688         * Search FAT1 for unused clusters.
    418689         */
    419690        fibril_mutex_lock(&fat_alloc_lock);
    420         for (b = 0, cl = 0; b < SF(bs); b++) {
    421                 rc = block_get(&blk, service_id, RSCNT(bs) + b,
    422                     BLOCK_FLAGS_NONE);
    423                 if (rc != EOK)
    424                         goto error;
    425                 for (c = 0; c < BPS(bs) / sizeof(fat_cluster_t); c++, cl++) {
     691        for (clst = FAT_CLST_FIRST; clst < CC(bs) + 2 && found < nclsts;
     692            clst++) {
     693                rc = fat_get_cluster(bs, service_id, FAT1, clst, &value);
     694                if (rc != EOK)
     695                        break;
     696
     697                if (value == FAT_CLST_RES0) {
    426698                        /*
    427                          * Check if the entire cluster is physically there.
    428                          * This check becomes necessary when the file system is
    429                          * created with fewer total sectors than how many is
    430                          * inferred from the size of the file allocation table
    431                          * or when the last cluster ends beyond the end of the
    432                          * device.
     699                         * The cluster is free. Put it into our stack
     700                         * of found clusters and mark it as non-free.
    433701                         */
    434                         if ((cl >= FAT_CLST_FIRST) &&
    435                             CLBN2PBN(bs, cl, SPC(bs) - 1) >= TS(bs)) {
    436                                 rc = block_put(blk);
    437                                 if (rc != EOK)
    438                                         goto error;
    439                                 goto out;
    440                         }
    441 
    442                         fat_cluster_t *clst = (fat_cluster_t *)blk->data + c;
    443                         if (uint16_t_le2host(*clst) == FAT_CLST_RES0) {
    444                                 /*
    445                                  * The cluster is free. Put it into our stack
    446                                  * of found clusters and mark it as non-free.
    447                                  */
    448                                 lifo[found] = cl;
    449                                 *clst = (found == 0) ?
    450                                     host2uint16_t_le(FAT_CLST_LAST1) :
    451                                     host2uint16_t_le(lifo[found - 1]);
    452                                 blk->dirty = true;      /* need to sync block */
    453                                 if (++found == nclsts) {
    454                                         /* we are almost done */
    455                                         rc = block_put(blk);
    456                                         if (rc != EOK)
    457                                                 goto error;
    458                                         /* update the shadow copies of FAT */
    459                                         rc = fat_alloc_shadow_clusters(bs,
    460                                             service_id, lifo, nclsts);
    461                                         if (rc != EOK)
    462                                                 goto error;
    463                                         *mcl = lifo[found - 1];
    464                                         *lcl = lifo[0];
    465                                         free(lifo);
    466                                         fibril_mutex_unlock(&fat_alloc_lock);
    467                                         return EOK;
    468                                 }
    469                         }
     702                        lifo[found] = clst;
     703                        rc = fat_set_cluster(bs, service_id, FAT1, clst,
     704                            (found == 0) ?  clst_last1 : lifo[found - 1]);
     705                        if (rc != EOK)
     706                                break;
     707
     708                        found++;
    470709                }
    471                 rc = block_put(blk);
    472                 if (rc != EOK) {
    473 error:
     710        }
     711
     712        if (rc == EOK && found == nclsts) {
     713                rc = fat_alloc_shadow_clusters(bs, service_id, lifo, nclsts);
     714                if (rc == EOK) {
     715                        *mcl = lifo[found - 1];
     716                        *lcl = lifo[0];
     717                        free(lifo);
    474718                        fibril_mutex_unlock(&fat_alloc_lock);
    475                         free(lifo);
    476                         return rc;
     719                        return EOK;
    477720                }
    478721        }
    479 out:
     722
     723        /* If something wrong - free the clusters */
     724        while (found--) {
     725                (void) fat_set_cluster(bs, service_id, FAT1, lifo[found],
     726                    FAT_CLST_RES0);
     727        }
     728
     729        free(lifo);
    480730        fibril_mutex_unlock(&fat_alloc_lock);
    481731
    482         /*
    483          * We could not find enough clusters. Now we need to free the clusters
    484          * we have allocated so far.
    485          */
    486         while (found--) {
    487                 rc = fat_set_cluster(bs, service_id, FAT1, lifo[found],
    488                     FAT_CLST_RES0);
    489                 if (rc != EOK) {
    490                         free(lifo);
    491                         return rc;
    492                 }
    493         }
    494        
    495         free(lifo);
    496732        return ENOSPC;
    497733}
     
    509745{
    510746        unsigned fatno;
    511         fat_cluster_t nextc;
     747        fat_cluster_t nextc, clst_bad = FAT_CLST_BAD(bs);
    512748        int rc;
    513749
    514750        /* Mark all clusters in the chain as free in all copies of FAT. */
    515         while (firstc < FAT_CLST_LAST1) {
    516                 assert(firstc >= FAT_CLST_FIRST && firstc < FAT_CLST_BAD);
     751        while (firstc < FAT_CLST_LAST1(bs)) {
     752                assert(firstc >= FAT_CLST_FIRST && firstc < clst_bad);
     753
    517754                rc = fat_get_cluster(bs, service_id, FAT1, firstc, &nextc);
    518755                if (rc != EOK)
    519756                        return rc;
    520                 for (fatno = FAT1; fatno < bs->fatcnt; fatno++) {
     757
     758                for (fatno = FAT1; fatno < FATCNT(bs); fatno++) {
    521759                        rc = fat_set_cluster(bs, service_id, fatno, firstc,
    522760                            FAT_CLST_RES0);
     
    524762                                return rc;
    525763                }
    526 
    527764                firstc = nextc;
    528765        }
     
    540777 * @return              EOK on success or a negative error code.
    541778 */
    542 int
    543 fat_append_clusters(fat_bs_t *bs, fat_node_t *nodep, fat_cluster_t mcl,
     779int fat_append_clusters(fat_bs_t *bs, fat_node_t *nodep, fat_cluster_t mcl,
    544780    fat_cluster_t lcl)
    545781{
     
    559795                } else {
    560796                        rc = fat_cluster_walk(bs, service_id, nodep->firstc,
    561                             &lastc, NULL, (uint16_t) -1);
     797                            &lastc, NULL, (uint32_t) -1);
    562798                        if (rc != EOK)
    563799                                return rc;
    564800                }
    565801
    566                 for (fatno = FAT1; fatno < bs->fatcnt; fatno++) {
    567                         rc = fat_set_cluster(bs, nodep->idx->service_id, fatno,
    568                             lastc, mcl);
     802                for (fatno = FAT1; fatno < FATCNT(bs); fatno++) {
     803                        rc = fat_set_cluster(bs, nodep->idx->service_id,
     804                            fatno, lastc, mcl);
    569805                        if (rc != EOK)
    570806                                return rc;
     
    590826int fat_chop_clusters(fat_bs_t *bs, fat_node_t *nodep, fat_cluster_t lcl)
    591827{
     828        fat_cluster_t clst_last1 = FAT_CLST_LAST1(bs);
    592829        int rc;
    593830        service_id_t service_id = nodep->idx->service_id;
     
    616853
    617854                /* Terminate the cluster chain in all copies of FAT. */
    618                 for (fatno = FAT1; fatno < bs->fatcnt; fatno++) {
     855                for (fatno = FAT1; fatno < FATCNT(bs); fatno++) {
    619856                        rc = fat_set_cluster(bs, service_id, fatno, lcl,
    620                             FAT_CLST_LAST1);
     857                            clst_last1);
    621858                        if (rc != EOK)
    622859                                return rc;
     
    673910
    674911        /* Check number of FATs. */
    675         if (bs->fatcnt == 0)
     912        if (FATCNT(bs) == 0)
    676913                return ENOTSUP;
    677914
    678915        /* Check total number of sectors. */
    679 
    680         if (bs->totsec16 == 0 && bs->totsec32 == 0)
     916        if (TS(bs) == 0)
    681917                return ENOTSUP;
    682918
    683919        if (bs->totsec16 != 0 && bs->totsec32 != 0 &&
    684             bs->totsec16 != bs->totsec32) 
     920            bs->totsec16 != bs->totsec32)
    685921                return ENOTSUP;
    686922
     
    690926
    691927        /* Check number of sectors per FAT. */
    692         if (bs->sec_per_fat == 0)
     928        if (SF(bs) == 0)
    693929                return ENOTSUP;
    694930
     
    700936         * sanitized to support file systems with this property.
    701937         */
    702         if ((uint16_t_le2host(bs->root_ent_max) * sizeof(fat_dentry_t)) %
    703             uint16_t_le2host(bs->bps) != 0)
     938        if (!FAT_IS_FAT32(bs) &&
     939            (RDE(bs) * sizeof(fat_dentry_t)) % BPS(bs) != 0)
    704940                return ENOTSUP;
    705941
    706942        /* Check signature of each FAT. */
    707 
    708         for (fat_no = 0; fat_no < bs->fatcnt; fat_no++) {
     943        for (fat_no = 0; fat_no < FATCNT(bs); fat_no++) {
    709944                rc = fat_get_cluster(bs, service_id, fat_no, 0, &e0);
    710945                if (rc != EOK)
     
    715950                        return EIO;
    716951
    717                 /* Check that first byte of FAT contains the media descriptor. */
     952                /*
     953                 * Check that first byte of FAT contains the media descriptor.
     954                 */
    718955                if ((e0 & 0xff) != bs->mdesc)
    719956                        return ENOTSUP;
     
    723960                 * set to one.
    724961                 */
    725                 if ((e0 >> 8) != 0xff || e1 != 0xffff)
     962                if (!FAT_IS_FAT12(bs) &&
     963                    ((e0 >> 8) != (FAT_MASK(bs) >> 8) || e1 != FAT_MASK(bs)))
    726964                        return ENOTSUP;
    727965        }
     
    732970/**
    733971 * @}
    734  */ 
     972 */
  • uspace/srv/fs/fat/fat_fat.h

    r7fadb65 r4cf5ed46  
    11/*
    22 * Copyright (c) 2008 Jakub Jermar
     3 * Copyright (c) 2011 Oleg Romanenko
    34 * All rights reserved.
    45 *
     
    2930/** @addtogroup fs
    3031 * @{
    31  */ 
     32 */
    3233
    3334#ifndef FAT_FAT_FAT_H_
     
    4041#define FAT1            0
    4142
    42 #define FAT_CLST_RES0   0x0000
    43 #define FAT_CLST_RES1   0x0001
    44 #define FAT_CLST_FIRST  0x0002
    45 #define FAT_CLST_BAD    0xfff7
    46 #define FAT_CLST_LAST1  0xfff8
    47 #define FAT_CLST_LAST8  0xffff
     43#define FAT_CLST_RES0     0
     44#define FAT_CLST_RES1     1
     45#define FAT_CLST_FIRST    2
     46
     47#define FAT32_CLST_BAD    0x0ffffff7
     48#define FAT32_CLST_LAST1  0x0ffffff8
     49#define FAT32_CLST_LAST8  0x0fffffff
     50
     51#define FAT12_MASK        0x0fff
     52#define FAT16_MASK        0xffff
     53#define FAT32_MASK        0x0fffffff
     54
     55#define FAT12_CLST_MAX    4085
     56#define FAT16_CLST_MAX    65525
     57
     58/* Size in bytes for cluster value of FAT */
     59#define FAT12_CLST_SIZE   2
     60#define FAT16_CLST_SIZE   2
     61#define FAT32_CLST_SIZE   4
    4862
    4963/* internally used to mark root directory's parent */
     
    5266#define FAT_CLST_ROOT           FAT_CLST_RES1
    5367
     68/*
     69 * Convenience macros for computing some frequently used values from the
     70 * primitive boot sector members.
     71 */
     72#define RDS(bs)   ((sizeof(fat_dentry_t) * RDE((bs))) / BPS((bs))) + \
     73                   (((sizeof(fat_dentry_t) * RDE((bs))) % BPS((bs))) != 0)
     74#define SSA(bs)   (RSCNT((bs)) + FATCNT((bs)) * SF((bs)) + RDS(bs))
     75#define DS(bs)    (TS(bs) - SSA(bs))
     76#define CC(bs)    (DS(bs) / SPC(bs))
     77
     78#define CLBN2PBN(bs, cl, bn) \
     79        (SSA((bs)) + ((cl) - FAT_CLST_FIRST) * SPC((bs)) + (bn) % SPC((bs)))
     80
     81#define FAT_IS_FAT12(bs)        (CC(bs) < FAT12_CLST_MAX)
     82#define FAT_IS_FAT16(bs) \
     83    ((CC(bs) >= FAT12_CLST_MAX) && (CC(bs) < FAT16_CLST_MAX))
     84#define FAT_IS_FAT32(bs)        (CC(bs) >= FAT16_CLST_MAX)
     85
     86#define FAT_CLST_SIZE(bs) \
     87    (FAT_IS_FAT32(bs) ? FAT32_CLST_SIZE : FAT16_CLST_SIZE)
     88
     89#define FAT_MASK(bs) \
     90    (FAT_IS_FAT12(bs) ? FAT12_MASK : \
     91    (FAT_IS_FAT32(bs) ? FAT32_MASK : FAT16_MASK))
     92
     93#define FAT_CLST_LAST1(bs)      (FAT32_CLST_LAST1 & FAT_MASK((bs)))
     94#define FAT_CLST_LAST8(bs)      (FAT32_CLST_LAST8 & FAT_MASK((bs)))
     95#define FAT_CLST_BAD(bs)        (FAT32_CLST_BAD & FAT_MASK((bs)))
     96
     97#define FAT_ROOT_CLST(bs) \
     98    (FAT_IS_FAT32(bs) ? uint32_t_le2host(bs->fat32.root_cluster) : \
     99    FAT_CLST_ROOT)
     100
    54101/* forward declarations */
    55102struct block;
     
    57104struct fat_bs;
    58105
    59 typedef uint16_t fat_cluster_t;
     106typedef uint32_t fat_cluster_t;
    60107
    61 #define fat_clusters_get(numc, bs, dh, fc) \
    62     fat_cluster_walk((bs), (dh), (fc), NULL, (numc), (uint16_t) -1)
     108#define fat_clusters_get(numc, bs, sid, fc) \
     109    fat_cluster_walk((bs), (sid), (fc), NULL, (numc), (uint32_t) -1)
    63110extern int fat_cluster_walk(struct fat_bs *, service_id_t, fat_cluster_t,
    64     fat_cluster_t *, uint16_t *, uint16_t);
     111    fat_cluster_t *, uint32_t *, uint32_t);
    65112
    66113extern int fat_block_get(block_t **, struct fat_bs *, struct fat_node *,
  • uspace/srv/fs/fat/fat_idx.c

    r7fadb65 r4cf5ed46  
    116116#define UPH_BUCKETS     (1 << UPH_BUCKETS_LOG)
    117117
    118 #define UPH_DH_KEY      0
     118#define UPH_SID_KEY     0
    119119#define UPH_PFC_KEY     1
    120120#define UPH_PDI_KEY     2
     
    122122static hash_index_t pos_hash(unsigned long key[])
    123123{
    124         service_id_t service_id = (service_id_t)key[UPH_DH_KEY];
     124        service_id_t service_id = (service_id_t)key[UPH_SID_KEY];
    125125        fat_cluster_t pfc = (fat_cluster_t)key[UPH_PFC_KEY];
    126126        unsigned pdi = (unsigned)key[UPH_PDI_KEY];
     
    150150static int pos_compare(unsigned long key[], hash_count_t keys, link_t *item)
    151151{
    152         service_id_t service_id = (service_id_t)key[UPH_DH_KEY];
     152        service_id_t service_id = (service_id_t)key[UPH_SID_KEY];
    153153        fat_cluster_t pfc;
    154154        unsigned pdi;
     
    190190#define UIH_BUCKETS     (1 << UIH_BUCKETS_LOG)
    191191
    192 #define UIH_DH_KEY      0
     192#define UIH_SID_KEY     0
    193193#define UIH_INDEX_KEY   1
    194194
    195195static hash_index_t idx_hash(unsigned long key[])
    196196{
    197         service_id_t service_id = (service_id_t)key[UIH_DH_KEY];
     197        service_id_t service_id = (service_id_t)key[UIH_SID_KEY];
    198198        fs_index_t index = (fs_index_t)key[UIH_INDEX_KEY];
    199199
     
    209209static int idx_compare(unsigned long key[], hash_count_t keys, link_t *item)
    210210{
    211         service_id_t service_id = (service_id_t)key[UIH_DH_KEY];
     211        service_id_t service_id = (service_id_t)key[UIH_SID_KEY];
    212212        fs_index_t index;
    213213        fat_idx_t *fidx = list_get_instance(item, fat_idx_t, uih_link);
     
    402402               
    403403        unsigned long ikey[] = {
    404                 [UIH_DH_KEY] = service_id,
     404                [UIH_SID_KEY] = service_id,
    405405                [UIH_INDEX_KEY] = fidx->index,
    406406        };
     
    420420        link_t *l;
    421421        unsigned long pkey[] = {
    422                 [UPH_DH_KEY] = service_id,
     422                [UPH_SID_KEY] = service_id,
    423423                [UPH_PFC_KEY] = pfc,
    424424                [UPH_PDI_KEY] = pdi,
     
    439439               
    440440                unsigned long ikey[] = {
    441                         [UIH_DH_KEY] = service_id,
     441                        [UIH_SID_KEY] = service_id,
    442442                        [UIH_INDEX_KEY] = fidx->index,
    443443                };
     
    458458{
    459459        unsigned long pkey[] = {
    460                 [UPH_DH_KEY] = idx->service_id,
     460                [UPH_SID_KEY] = idx->service_id,
    461461                [UPH_PFC_KEY] = idx->pfc,
    462462                [UPH_PDI_KEY] = idx->pdi,
     
    471471{
    472472        unsigned long pkey[] = {
    473                 [UPH_DH_KEY] = idx->service_id,
     473                [UPH_SID_KEY] = idx->service_id,
    474474                [UPH_PFC_KEY] = idx->pfc,
    475475                [UPH_PDI_KEY] = idx->pdi,
     
    487487        link_t *l;
    488488        unsigned long ikey[] = {
    489                 [UIH_DH_KEY] = service_id,
     489                [UIH_SID_KEY] = service_id,
    490490                [UIH_INDEX_KEY] = index,
    491491        };
     
    509509{
    510510        unsigned long ikey[] = {
    511                 [UIH_DH_KEY] = idx->service_id,
     511                [UIH_SID_KEY] = idx->service_id,
    512512                [UIH_INDEX_KEY] = idx->index,
    513513        };
     
    571571{
    572572        unsigned long ikey[] = {
    573                 [UIH_DH_KEY] = service_id
     573                [UIH_SID_KEY] = service_id
    574574        };
    575575        unsigned long pkey[] = {
    576                 [UPH_DH_KEY] = service_id
     576                [UPH_SID_KEY] = service_id
    577577        };
    578578
  • uspace/srv/fs/fat/fat_ops.c

    r7fadb65 r4cf5ed46  
    11/*
    22 * Copyright (c) 2008 Jakub Jermar
     3 * Copyright (c) 2011 Oleg Romanenko
    34 * All rights reserved.
    45 *
     
    2930/** @addtogroup fs
    3031 * @{
    31  */ 
     32 */
    3233
    3334/**
     
    3940#include "fat_dentry.h"
    4041#include "fat_fat.h"
     42#include "fat_directory.h"
    4143#include "../../vfs/vfs.h"
    4244#include <libfs.h>
     
    5658#include <align.h>
    5759#include <malloc.h>
     60#include <str.h>
    5861
    5962#define FAT_NODE(node)  ((node) ? (fat_node_t *) (node)->data : NULL)
     
    104107        node->dirty = false;
    105108        node->lastc_cached_valid = false;
    106         node->lastc_cached_value = FAT_CLST_LAST1;
     109        node->lastc_cached_value = 0;
    107110        node->currc_cached_valid = false;
    108111        node->currc_cached_bn = 0;
    109         node->currc_cached_value = FAT_CLST_LAST1;
     112        node->currc_cached_value = 0;
    110113}
    111114
     
    116119        fat_dentry_t *d;
    117120        int rc;
    118        
     121
    119122        assert(node->dirty);
    120123
    121124        bs = block_bb_get(node->idx->service_id);
    122        
     125
    123126        /* Read the block that contains the dentry of interest. */
    124127        rc = _fat_block_get(&b, bs, node->idx->service_id, node->idx->pfc,
     
    136139                d->attr = FAT_ATTR_SUBDIR;
    137140        }
    138        
     141
    139142        /* TODO: update other fields? (e.g time fields) */
    140        
     143
    141144        b->dirty = true;                /* need to sync block */
    142145        rc = block_put(b);
     
    255258        fn->data = nodep;
    256259        nodep->bp = fn;
    257        
     260
    258261        *nodepp = nodep;
    259262        return EOK;
     
    291294         * We must instantiate the node from the file system.
    292295         */
    293        
     296
    294297        assert(idxp->pfc);
    295298
     
    309312
    310313        d = ((fat_dentry_t *)b->data) + (idxp->pdi % DPS(bs));
     314        if (FAT_IS_FAT32(bs)) {
     315                nodep->firstc = uint16_t_le2host(d->firstc_lo) |
     316                    (uint16_t_le2host(d->firstc_hi) << 16);
     317        } else
     318                nodep->firstc = uint16_t_le2host(d->firstc);
     319
    311320        if (d->attr & FAT_ATTR_SUBDIR) {
    312                 /* 
     321                /*
    313322                 * The only directory which does not have this bit set is the
    314323                 * root directory itself. The root directory node is handled
     
    316325                 */
    317326                nodep->type = FAT_DIRECTORY;
     327
    318328                /*
    319329                 * Unfortunately, the 'size' field of the FAT dentry is not
     
    321331                 * size of the directory by walking the FAT.
    322332                 */
    323                 uint16_t clusters;
     333                uint32_t clusters;
    324334                rc = fat_clusters_get(&clusters, bs, idxp->service_id,
    325                     uint16_t_le2host(d->firstc));
     335                    nodep->firstc);
    326336                if (rc != EOK) {
    327337                        (void) block_put(b);
     
    334344                nodep->size = uint32_t_le2host(d->size);
    335345        }
    336         nodep->firstc = uint16_t_le2host(d->firstc);
     346
    337347        nodep->lnkcnt = 1;
    338348        nodep->refcnt = 1;
     
    363373int fat_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
    364374{
    365         fat_bs_t *bs;
    366375        fat_node_t *parentp = FAT_NODE(pfn);
    367         char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
    368         unsigned i, j;
    369         unsigned blocks;
     376        char name[FAT_LFN_NAME_SIZE];
    370377        fat_dentry_t *d;
    371378        service_id_t service_id;
    372         block_t *b;
    373379        int rc;
    374380
     
    376382        service_id = parentp->idx->service_id;
    377383        fibril_mutex_unlock(&parentp->idx->lock);
    378 
    379         bs = block_bb_get(service_id);
    380         blocks = parentp->size / BPS(bs);
    381         for (i = 0; i < blocks; i++) {
    382                 rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE);
    383                 if (rc != EOK)
    384                         return rc;
    385                 for (j = 0; j < DPS(bs); j++) {
    386                         d = ((fat_dentry_t *)b->data) + j;
    387                         switch (fat_classify_dentry(d)) {
    388                         case FAT_DENTRY_SKIP:
    389                         case FAT_DENTRY_FREE:
    390                                 continue;
    391                         case FAT_DENTRY_LAST:
    392                                 /* miss */
    393                                 rc = block_put(b);
    394                                 *rfn = NULL;
    395                                 return rc;
    396                         default:
    397                         case FAT_DENTRY_VALID:
    398                                 fat_dentry_name_get(d, name);
    399                                 break;
     384       
     385        fat_directory_t di;
     386        rc = fat_directory_open(parentp, &di);
     387        if (rc != EOK)
     388                return rc;
     389
     390        while (fat_directory_read(&di, name, &d) == EOK) {
     391                if (fat_dentry_namecmp(name, component) == 0) {
     392                        /* hit */
     393                        fat_node_t *nodep;
     394                        aoff64_t o = di.pos %
     395                            (BPS(di.bs) / sizeof(fat_dentry_t));
     396                        fat_idx_t *idx = fat_idx_get_by_pos(service_id,
     397                            parentp->firstc, di.bnum * DPS(di.bs) + o);
     398                        if (!idx) {
     399                                /*
     400                                 * Can happen if memory is low or if we
     401                                 * run out of 32-bit indices.
     402                                 */
     403                                rc = fat_directory_close(&di);
     404                                return (rc == EOK) ? ENOMEM : rc;
    400405                        }
    401                         if (fat_dentry_namecmp(name, component) == 0) {
    402                                 /* hit */
    403                                 fat_node_t *nodep;
    404                                 fat_idx_t *idx = fat_idx_get_by_pos(service_id,
    405                                     parentp->firstc, i * DPS(bs) + j);
    406                                 if (!idx) {
    407                                         /*
    408                                          * Can happen if memory is low or if we
    409                                          * run out of 32-bit indices.
    410                                          */
    411                                         rc = block_put(b);
    412                                         return (rc == EOK) ? ENOMEM : rc;
    413                                 }
    414                                 rc = fat_node_get_core(&nodep, idx);
    415                                 fibril_mutex_unlock(&idx->lock);
    416                                 if (rc != EOK) {
    417                                         (void) block_put(b);
    418                                         return rc;
    419                                 }
    420                                 *rfn = FS_NODE(nodep);
    421                                 rc = block_put(b);
    422                                 if (rc != EOK)
    423                                         (void) fat_node_put(*rfn);
     406                        rc = fat_node_get_core(&nodep, idx);
     407                        fibril_mutex_unlock(&idx->lock);
     408                        if (rc != EOK) {
     409                                (void) fat_directory_close(&di);
    424410                                return rc;
    425411                        }
    426                 }
    427                 rc = block_put(b);
    428                 if (rc != EOK)
     412                        *rfn = FS_NODE(nodep);
     413                        rc = fat_directory_close(&di);
     414                        if (rc != EOK)
     415                                (void) fat_node_put(*rfn);
    429416                        return rc;
    430         }
    431 
     417                } else {
     418                        rc = fat_directory_next(&di);
     419                        if (rc != EOK)
     420                                break;
     421                }
     422        }
     423        (void) fat_directory_close(&di);
    432424        *rfn = NULL;
    433425        return EOK;
     
    591583        fat_bs_t *bs;
    592584        block_t *b;
    593         unsigned i, j;
    594         unsigned blocks;
    595         fat_cluster_t mcl, lcl;
     585        fat_directory_t di;
     586        fat_dentry_t de;
    596587        int rc;
    597588
     
    607598        fibril_mutex_unlock(&childp->lock);
    608599
    609         if (!fat_dentry_name_verify(name)) {
    610                 /*
    611                  * Attempt to create unsupported name.
    612                  */
     600        if (!fat_valid_name(name))
    613601                return ENOTSUP;
    614         }
    615 
    616         /*
    617          * Get us an unused parent node's dentry or grow the parent and allocate
    618          * a new one.
    619          */
    620        
     602
    621603        fibril_mutex_lock(&parentp->idx->lock);
    622604        bs = block_bb_get(parentp->idx->service_id);
    623 
    624         blocks = parentp->size / BPS(bs);
    625 
    626         for (i = 0; i < blocks; i++) {
    627                 rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE);
    628                 if (rc != EOK) {
    629                         fibril_mutex_unlock(&parentp->idx->lock);
    630                         return rc;
    631                 }
    632                 for (j = 0; j < DPS(bs); j++) {
    633                         d = ((fat_dentry_t *)b->data) + j;
    634                         switch (fat_classify_dentry(d)) {
    635                         case FAT_DENTRY_SKIP:
    636                         case FAT_DENTRY_VALID:
    637                                 /* skipping used and meta entries */
    638                                 continue;
    639                         case FAT_DENTRY_FREE:
    640                         case FAT_DENTRY_LAST:
    641                                 /* found an empty slot */
    642                                 goto hit;
    643                         }
    644                 }
    645                 rc = block_put(b);
    646                 if (rc != EOK) {
    647                         fibril_mutex_unlock(&parentp->idx->lock);
    648                         return rc;
    649                 }
    650         }
    651         j = 0;
    652        
    653         /*
    654          * We need to grow the parent in order to create a new unused dentry.
    655          */
    656         if (parentp->firstc == FAT_CLST_ROOT) {
    657                 /* Can't grow the root directory. */
    658                 fibril_mutex_unlock(&parentp->idx->lock);
    659                 return ENOSPC;
    660         }
    661         rc = fat_alloc_clusters(bs, parentp->idx->service_id, 1, &mcl, &lcl);
     605        rc = fat_directory_open(parentp, &di);
    662606        if (rc != EOK) {
    663607                fibril_mutex_unlock(&parentp->idx->lock);
    664608                return rc;
    665609        }
    666         rc = fat_zero_cluster(bs, parentp->idx->service_id, mcl);
    667         if (rc != EOK) {
    668                 (void) fat_free_clusters(bs, parentp->idx->service_id, mcl);
    669                 fibril_mutex_unlock(&parentp->idx->lock);
    670                 return rc;
    671         }
    672         rc = fat_append_clusters(bs, parentp, mcl, lcl);
    673         if (rc != EOK) {
    674                 (void) fat_free_clusters(bs, parentp->idx->service_id, mcl);
    675                 fibril_mutex_unlock(&parentp->idx->lock);
    676                 return rc;
    677         }
    678         parentp->size += BPS(bs) * SPC(bs);
    679         parentp->dirty = true;          /* need to sync node */
    680         rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE);
    681         if (rc != EOK) {
    682                 fibril_mutex_unlock(&parentp->idx->lock);
    683                 return rc;
    684         }
    685         d = (fat_dentry_t *)b->data;
    686 
    687 hit:
     610
    688611        /*
    689612         * At this point we only establish the link between the parent and the
     
    692615         * dentry data is kept in the child node structure.
    693616         */
    694         memset(d, 0, sizeof(fat_dentry_t));
    695         fat_dentry_name_set(d, name);
    696         b->dirty = true;                /* need to sync block */
    697         rc = block_put(b);
     617        memset(&de, 0, sizeof(fat_dentry_t));
     618
     619        rc = fat_directory_write(&di, name, &de);
     620        if (rc != EOK) {
     621                (void) fat_directory_close(&di);
     622                fibril_mutex_unlock(&parentp->idx->lock);
     623                return rc;
     624        }
     625        rc = fat_directory_close(&di);
     626        if (rc != EOK) {
     627                fibril_mutex_unlock(&parentp->idx->lock);
     628                return rc;
     629        }
     630
    698631        fibril_mutex_unlock(&parentp->idx->lock);
    699         if (rc != EOK)
    700                 return rc;
    701632
    702633        fibril_mutex_lock(&childp->idx->lock);
    703        
     634
    704635        if (childp->type == FAT_DIRECTORY) {
    705636                /*
     
    720651                d = (fat_dentry_t *) b->data;
    721652                if ((fat_classify_dentry(d) == FAT_DENTRY_LAST) ||
    722                     (str_cmp((char *) d->name, FAT_NAME_DOT)) == 0) {
     653                    (bcmp(d->name, FAT_NAME_DOT, FAT_NAME_LEN)) == 0) {
    723654                        memset(d, 0, sizeof(fat_dentry_t));
    724655                        memcpy(d->name, FAT_NAME_DOT, FAT_NAME_LEN);
     
    730661                d++;
    731662                if ((fat_classify_dentry(d) == FAT_DENTRY_LAST) ||
    732                     (str_cmp((char *) d->name, FAT_NAME_DOT_DOT) == 0)) {
     663                    (bcmp(d->name, FAT_NAME_DOT_DOT, FAT_NAME_LEN) == 0)) {
    733664                        memset(d, 0, sizeof(fat_dentry_t));
    734665                        memcpy(d->name, FAT_NAME_DOT_DOT, FAT_NAME_LEN);
    735666                        memcpy(d->ext, FAT_EXT_PAD, FAT_EXT_LEN);
    736667                        d->attr = FAT_ATTR_SUBDIR;
    737                         d->firstc = (parentp->firstc == FAT_CLST_ROOT) ?
    738                             host2uint16_t_le(FAT_CLST_RES0) :
     668                        d->firstc = (parentp->firstc == FAT_ROOT_CLST(bs)) ?
     669                            host2uint16_t_le(FAT_CLST_ROOTPAR) :
    739670                            host2uint16_t_le(parentp->firstc);
    740671                        /* TODO: initialize also the date/time members. */
     
    750681
    751682        childp->idx->pfc = parentp->firstc;
    752         childp->idx->pdi = i * DPS(bs) + j;
     683        childp->idx->pdi = di.pos;      /* di.pos holds absolute position of SFN entry */
    753684        fibril_mutex_unlock(&childp->idx->lock);
    754685
     
    770701        fat_node_t *parentp = FAT_NODE(pfn);
    771702        fat_node_t *childp = FAT_NODE(cfn);
    772         fat_bs_t *bs;
    773         fat_dentry_t *d;
    774         block_t *b;
    775703        bool has_children;
    776704        int rc;
     
    778706        if (!parentp)
    779707                return EBUSY;
    780        
     708
    781709        rc = fat_has_children(&has_children, cfn);
    782710        if (rc != EOK)
     
    789717        assert(childp->lnkcnt == 1);
    790718        fibril_mutex_lock(&childp->idx->lock);
    791         bs = block_bb_get(childp->idx->service_id);
    792 
    793         rc = _fat_block_get(&b, bs, childp->idx->service_id, childp->idx->pfc,
    794             NULL, (childp->idx->pdi * sizeof(fat_dentry_t)) / BPS(bs),
    795             BLOCK_FLAGS_NONE);
    796         if (rc != EOK)
     719       
     720        fat_directory_t di;
     721        rc = fat_directory_open(parentp, &di);
     722        if (rc != EOK)
    797723                goto error;
    798         d = (fat_dentry_t *)b->data +
    799             (childp->idx->pdi % (BPS(bs) / sizeof(fat_dentry_t)));
    800         /* mark the dentry as not-currently-used */
    801         d->name[0] = FAT_DENTRY_ERASED;
    802         b->dirty = true;                /* need to sync block */
    803         rc = block_put(b);
     724        rc = fat_directory_seek(&di, childp->idx->pdi);
     725        if (rc != EOK)
     726                goto error;
     727        rc = fat_directory_erase(&di);
     728        if (rc != EOK)
     729                goto error;
     730        rc = fat_directory_close(&di);
    804731        if (rc != EOK)
    805732                goto error;
     
    820747
    821748error:
    822         fibril_mutex_unlock(&parentp->idx->lock);
     749        (void) fat_directory_close(&di);
     750        fibril_mutex_unlock(&childp->idx->lock);
    823751        fibril_mutex_unlock(&childp->lock);
    824         fibril_mutex_unlock(&childp->idx->lock);
     752        fibril_mutex_unlock(&parentp->lock);
    825753        return rc;
    826754}
     
    839767                return EOK;
    840768        }
    841        
     769
    842770        fibril_mutex_lock(&nodep->idx->lock);
    843771        bs = block_bb_get(nodep->idx->service_id);
     
    847775        for (i = 0; i < blocks; i++) {
    848776                fat_dentry_t *d;
    849        
     777
    850778                rc = fat_block_get(&b, bs, nodep, i, BLOCK_FLAGS_NONE);
    851779                if (rc != EOK) {
     
    875803                if (rc != EOK) {
    876804                        fibril_mutex_unlock(&nodep->idx->lock);
    877                         return rc;     
     805                        return rc;
    878806                }
    879807        }
     
    946874        fat_bs_t *bs;
    947875        int rc;
    948        
     876
    949877        /* Check for option enabling write through. */
    950878        if (str_cmp(opts, "wtcache") == 0)
     
    1003931                return ENOMEM;
    1004932        }
     933
    1005934        fs_node_initialize(rfn);
    1006935        fat_node_t *rootp = (fat_node_t *)malloc(sizeof(fat_node_t));
     
    1027956
    1028957        rootp->type = FAT_DIRECTORY;
    1029         rootp->firstc = FAT_CLST_ROOT;
     958        rootp->firstc = FAT_ROOT_CLST(bs);
    1030959        rootp->refcnt = 1;
    1031960        rootp->lnkcnt = 0;      /* FS root is not linked */
    1032         rootp->size = RDE(bs) * sizeof(fat_dentry_t);
     961
     962        if (FAT_IS_FAT32(bs)) {
     963                uint32_t clusters;
     964                rc = fat_clusters_get(&clusters, bs, service_id, rootp->firstc);
     965                if (rc != EOK) {
     966                        free(rfn);
     967                        free(rootp);
     968                        (void) block_cache_fini(service_id);
     969                        block_fini(service_id);
     970                        fat_idx_fini_by_service_id(service_id);
     971                        return ENOTSUP;
     972                }
     973                rootp->size = BPS(bs) * SPC(bs) * clusters;
     974        } else
     975                rootp->size = RDE(bs) * sizeof(fat_dentry_t);
     976
    1033977        rootp->idx = ridxp;
    1034978        ridxp->nodep = rootp;
    1035979        rootp->bp = rfn;
    1036980        rfn->data = rootp;
    1037        
     981
    1038982        fibril_mutex_unlock(&ridxp->lock);
    1039983
     
    10641008                return EBUSY;
    10651009        }
    1066        
     1010
    10671011        /*
    10681012         * Put the root node and force it to the FAT free node list.
     
    11411085                }
    11421086        } else {
    1143                 unsigned bnum;
    11441087                aoff64_t spos = pos;
    1145                 char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
     1088                char name[FAT_LFN_NAME_SIZE];
    11461089                fat_dentry_t *d;
    11471090
     
    11501093                assert(BPS(bs) % sizeof(fat_dentry_t) == 0);
    11511094
    1152                 /*
    1153                  * Our strategy for readdir() is to use the position pointer as
    1154                  * an index into the array of all dentries. On entry, it points
    1155                  * to the first unread dentry. If we skip any dentries, we bump
    1156                  * the position pointer accordingly.
    1157                  */
    1158                 bnum = (pos * sizeof(fat_dentry_t)) / BPS(bs);
    1159                 while (bnum < nodep->size / BPS(bs)) {
    1160                         aoff64_t o;
    1161 
    1162                         rc = fat_block_get(&b, bs, nodep, bnum,
    1163                             BLOCK_FLAGS_NONE);
    1164                         if (rc != EOK)
    1165                                 goto err;
    1166                         for (o = pos % (BPS(bs) / sizeof(fat_dentry_t));
    1167                             o < BPS(bs) / sizeof(fat_dentry_t);
    1168                             o++, pos++) {
    1169                                 d = ((fat_dentry_t *)b->data) + o;
    1170                                 switch (fat_classify_dentry(d)) {
    1171                                 case FAT_DENTRY_SKIP:
    1172                                 case FAT_DENTRY_FREE:
    1173                                         continue;
    1174                                 case FAT_DENTRY_LAST:
    1175                                         rc = block_put(b);
    1176                                         if (rc != EOK)
    1177                                                 goto err;
    1178                                         goto miss;
    1179                                 default:
    1180                                 case FAT_DENTRY_VALID:
    1181                                         fat_dentry_name_get(d, name);
    1182                                         rc = block_put(b);
    1183                                         if (rc != EOK)
    1184                                                 goto err;
    1185                                         goto hit;
    1186                                 }
    1187                         }
    1188                         rc = block_put(b);
    1189                         if (rc != EOK)
    1190                                 goto err;
    1191                         bnum++;
    1192                 }
     1095                fat_directory_t di;
     1096                rc = fat_directory_open(nodep, &di);
     1097                if (rc != EOK)
     1098                        goto err;
     1099                rc = fat_directory_seek(&di, pos);
     1100                if (rc != EOK) {
     1101                        (void) fat_directory_close(&di);
     1102                        goto err;
     1103                }
     1104
     1105                rc = fat_directory_read(&di, name, &d);
     1106                if (rc == EOK)
     1107                        goto hit;
     1108                if (rc == ENOENT)
     1109                        goto miss;
     1110
     1111err:
     1112                (void) fat_node_put(fn);
     1113                async_answer_0(callid, rc);
     1114                return rc;
     1115
    11931116miss:
     1117                rc = fat_directory_close(&di);
     1118                if (rc != EOK)
     1119                        goto err;
    11941120                rc = fat_node_put(fn);
    11951121                async_answer_0(callid, rc != EOK ? rc : ENOENT);
     
    11971123                return rc != EOK ? rc : ENOENT;
    11981124
    1199 err:
    1200                 (void) fat_node_put(fn);
    1201                 async_answer_0(callid, rc);
    1202                 return rc;
    1203 
    12041125hit:
    1205                 (void) async_data_read_finalize(callid, name, str_size(name) + 1);
     1126                pos = di.pos;
     1127                rc = fat_directory_close(&di);
     1128                if (rc != EOK)
     1129                        goto err;
     1130                (void) async_data_read_finalize(callid, name,
     1131                    str_size(name) + 1);
    12061132                bytes = (pos - spos) + 1;
    12071133        }
     
    12311157                return ENOENT;
    12321158        nodep = FAT_NODE(fn);
    1233        
     1159
    12341160        ipc_callid_t callid;
    12351161        size_t len;
     
    12471173         * but this one greatly simplifies fat_write(). Note that we can afford
    12481174         * to do this because the client must be ready to handle the return
    1249          * value signalizing a smaller number of bytes written. 
    1250          */ 
     1175         * value signalizing a smaller number of bytes written.
     1176         */
    12511177        bytes = min(len, BPS(bs) - pos % BPS(bs));
    12521178        if (bytes == BPS(bs))
    12531179                flags |= BLOCK_FLAGS_NOREAD;
    1254        
     1180
    12551181        boundary = ROUND_UP(nodep->size, BPC(bs));
    12561182        if (pos < boundary) {
     
    12951221                 */
    12961222                unsigned nclsts;
    1297                 fat_cluster_t mcl, lcl; 
    1298  
     1223                fat_cluster_t mcl, lcl;
     1224
    12991225                nclsts = (ROUND_UP(pos + bytes, BPC(bs)) - boundary) / BPC(bs);
    13001226                /* create an independent chain of nclsts clusters in all FATs */
     
    13801306                nodep->size = size;
    13811307                nodep->dirty = true;            /* need to sync node */
    1382                 rc = EOK;       
     1308                rc = EOK;
    13831309        } else {
    13841310                /*
     
    14011327                nodep->size = size;
    14021328                nodep->dirty = true;            /* need to sync node */
    1403                 rc = EOK;       
     1329                rc = EOK;
    14041330        }
    14051331out:
     
    14441370        if (!fn)
    14451371                return ENOENT;
    1446        
     1372
    14471373        fat_node_t *nodep = FAT_NODE(fn);
    1448        
     1374
    14491375        nodep->dirty = true;
    14501376        rc = fat_node_sync(nodep);
    1451        
     1377
    14521378        fat_node_put(fn);
    14531379        return rc;
Note: See TracChangeset for help on using the changeset viewer.