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

Changeset 375ab5e in mainline


Ignore:
Timestamp:
2011-08-24T20:10:43Z (10 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master
Children:
eb660787
Parents:
7fadb65 (diff), 842a2d2 (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:~romanenko-oleg/helenos/fat.

Files:
23 added
14 edited

Legend:

Unmodified
Added
Removed
  • boot/Makefile.common

    r7fadb65 r375ab5e  
    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 \
     
    148149        $(USPACE_PATH)/app/dload/dload \
    149150        $(USPACE_PATH)/app/edit/edit \
     151        $(USPACE_PATH)/app/filecrc/filecrc \
     152        $(USPACE_PATH)/app/filegen/filegen \
    150153        $(USPACE_PATH)/app/ext2info/ext2info \
    151154        $(USPACE_PATH)/app/kill/kill \
  • uspace/Makefile

    r7fadb65 r375ab5e  
    3939        app/devctl \
    4040        app/edit \
     41        app/filecrc \
     42        app/filegen \
    4143        app/ext2info \
    4244        app/getterm \
     
    7981        srv/bd/part/guid_part \
    8082        srv/bd/part/mbr_part \
     83        srv/fs/exfat \
    8184        srv/fs/fat \
    8285        srv/fs/tmpfs \
  • uspace/app/mkfat/fat.h

    r7fadb65 r375ab5e  
    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 r375ab5e  
    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");
     
    165183        }
    166184
    167         if (block_size != 512) {
    168                 printf(NAME ": Error. Device block size is not 512 bytes.\n");
     185        if (cfg.fat_type == FAT12 && cfg.sector_size != 512) {
     186                printf(NAME ": Error. Device block size is not 512 bytes for FAT12 file system.\n");
    169187                return 2;
    170188        }
     
    175193        }
    176194
    177         printf(NAME ": Creating FAT filesystem on device %s.\n", dev_path);
    178 
    179         rc = fat_params_compute(&cfg, &par);
     195        printf(NAME ": Creating FAT%d filesystem on device %s.\n", cfg.fat_type, dev_path);
     196
     197        rc = fat_params_compute(&cfg);
    180198        if (rc != EOK) {
    181199                printf(NAME ": Invalid file-system parameters.\n");
     
    183201        }
    184202
    185         rc = fat_blocks_write(&par, service_id);
     203        rc = fat_blocks_write(&cfg, service_id);
    186204        if (rc != EOK) {
    187205                printf(NAME ": Error writing device.\n");
     
    197215static void syntax_print(void)
    198216{
    199         printf("syntax: mkfat [--size <num_blocks>] <device_name>\n");
     217        printf("syntax: mkfat32 [--size <sectors>] [--type 12|16|32] <device_name>\n");
    200218}
    201219
     
    205223 * file system params.
    206224 */
    207 static int fat_params_compute(struct fat_cfg const *cfg, struct fat_params *par)
     225static int fat_params_compute(struct fat_cfg *cfg)
    208226{
    209227        uint32_t fat_bytes;
     
    211229
    212230        /*
    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;
     231     * Make a conservative guess on the FAT size needed for the file
     232     * system. The optimum could be potentially smaller since we
     233     * do not subtract size of the FAT itself when computing the
     234     * size of the data region.
     235     */
     236
     237        if (cfg->fat_type == FAT12)
     238                cfg->sectors_per_cluster = 1;
     239
     240        cfg->reserved_sectors = 1 + cfg->addt_res_sectors;
     241        if (cfg->fat_type != FAT32) {
     242                cfg->rootdir_sectors = div_round_up(cfg->root_ent_max * DIRENT_SIZE,
     243                        cfg->sector_size);
     244        }
     245        else
     246                cfg->rootdir_sectors = 0;
     247        non_data_sectors_lb = cfg->reserved_sectors + cfg->rootdir_sectors;
     248
     249        cfg->total_clusters = div_round_up(cfg->total_sectors - non_data_sectors_lb,
     250            cfg->sectors_per_cluster);
     251
     252        if ((cfg->fat_type == FAT12 && cfg->total_clusters > FAT12_CLST_MAX) ||
     253                (cfg->fat_type == FAT16 && (cfg->total_clusters <= FAT12_CLST_MAX ||
     254                cfg->total_clusters > FAT16_CLST_MAX)) ||
     255            (cfg->fat_type == FAT32 && cfg->total_clusters <= FAT16_CLST_MAX))
     256                return ENOSPC;
     257
     258        fat_bytes = (cfg->total_clusters + 2) * FAT_SIZE(cfg->fat_type);
     259        cfg->fat_sectors = div_round_up(fat_bytes, cfg->sector_size);
    231260
    232261        return EOK;
     
    234263
    235264/** Create file system with the given parameters. */
    236 static int fat_blocks_write(struct fat_params const *par, service_id_t service_id)
     265static int fat_blocks_write(struct fat_cfg const *cfg, service_id_t service_id)
    237266{
    238267        aoff64_t addr;
     
    243272        struct fat_bs bs;
    244273
    245         fat_bootsec_create(par, &bs);
     274        fat_bootsec_create(cfg, &bs);
    246275
    247276        rc = block_write_direct(service_id, BS_BLOCK, 1, &bs);
     
    251280        addr = BS_BLOCK + 1;
    252281
    253         buffer = calloc(sector_size, 1);
     282        buffer = calloc(cfg->sector_size, 1);
    254283        if (buffer == NULL)
    255284                return ENOMEM;
     285        memset(buffer, 0, cfg->sector_size);
    256286
    257287        /* Reserved sectors */
    258         for (i = 0; i < par->reserved_sectors - 1; ++i) {
     288        for (i = 0; i < cfg->reserved_sectors - 1; ++i) {
    259289                rc = block_write_direct(service_id, addr, 1, buffer);
    260290                if (rc != EOK)
     
    265295
    266296        /* File allocation tables */
    267         for (i = 0; i < fat_count; ++i) {
     297        for (i = 0; i < cfg->fat_count; ++i) {
    268298                printf("Writing allocation table %d.\n", i + 1);
    269299
    270                 for (j = 0; j < par->fat_sectors; ++j) {
    271                         memset(buffer, 0, sector_size);
     300                for (j = 0; j < cfg->fat_sectors; ++j) {
     301                        memset(buffer, 0, cfg->sector_size);
    272302                        if (j == 0) {
    273                                 buffer[0] = media_descriptor;
     303                                buffer[0] = default_media_descriptor;
    274304                                buffer[1] = 0xFF;
    275305                                buffer[2] = 0xFF;
    276                                 buffer[3] = 0xFF;
     306                                if (cfg->fat_type == FAT16) {
     307                                        buffer[3] = 0xFF;
     308                                } else if (cfg->fat_type == FAT32) {
     309                                        buffer[3] = 0x0F;
     310                                        buffer[4] = 0xFF;
     311                                        buffer[5] = 0xFF;
     312                                        buffer[6] = 0xFF;
     313                                        buffer[7] = 0x0F;
     314                                        buffer[8] = 0xF8;
     315                                        buffer[9] = 0xFF;
     316                                        buffer[10] = 0xFF;
     317                                        buffer[11] = 0x0F;
     318                                }
    277319                        }
    278320
     
    285327        }
    286328
     329        /* Root directory */
    287330        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;
     331        memset(buffer, 0, cfg->sector_size);
     332        if (cfg->fat_type != FAT32) {
     333                size_t idx;
     334                for (idx = 0; idx < cfg->rootdir_sectors; ++idx) {
     335                        rc = block_write_direct(service_id, addr, 1, buffer);
     336                        if (rc != EOK)
     337                                return EIO;
     338
     339                        ++addr;
     340                }
     341        } else {
     342                for (i=0; i<cfg->sectors_per_cluster; i++) {
     343                        rc = block_write_direct(service_id, addr, 1, buffer);
     344                        if (rc != EOK)
     345                                return EIO;
     346
     347                        ++addr;
     348                }       
    298349        }
    299350
     
    304355
    305356/** Construct boot sector with the given parameters. */
    306 static void fat_bootsec_create(struct fat_params const *par, struct fat_bs *bs)
     357static void fat_bootsec_create(struct fat_cfg const *cfg, struct fat_bs *bs)
    307358{
    308359        memset(bs, 0, sizeof(*bs));
     
    315366
    316367        /* 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);
     368        bs->bps = host2uint16_t_le(cfg->sector_size);
     369        bs->spc = cfg->sectors_per_cluster;
     370        bs->rscnt = host2uint16_t_le(cfg->reserved_sectors);
     371        bs->fatcnt = cfg->fat_count;
     372        bs->root_ent_max = host2uint16_t_le(cfg->root_ent_max);
     373
     374        if (cfg->total_sectors < 0x10000) {
     375                bs->totsec16 = host2uint16_t_le(cfg->total_sectors);
     376                bs->totsec32 = 0;
     377        } else {
     378                bs->totsec16 = 0;
     379                bs->totsec32 = host2uint32_t_le(cfg->total_sectors);
     380        }
     381
     382        bs->mdesc = default_media_descriptor;
    330383        bs->sec_per_track = host2uint16_t_le(63);
     384        bs->signature = host2uint16_t_be(0x55AA);
    331385        bs->headcnt = host2uint16_t_le(6);
    332386        bs->hidden_sec = host2uint32_t_le(0);
    333387
    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);
     388        if (cfg->fat_type == FAT32) {
     389                bs->sec_per_fat = 0;
     390                bs->fat32.sectors_per_fat = host2uint32_t_le(cfg->fat_sectors);
     391
     392                bs->fat32.pdn = 0x80;
     393                bs->fat32.ebs = 0x29;
     394                bs->fat32.id = host2uint32_t_be(0x12345678);
     395                bs->fat32.root_cluster = 2;
     396
     397                memcpy(bs->fat32.label, "HELENOS_NEW", 11);
     398                memcpy(bs->fat32.type, "FAT32   ", 8);
     399        } else {
     400                bs->sec_per_fat = host2uint16_t_le(cfg->fat_sectors);
     401                bs->pdn = 0x80;
     402                bs->ebs = 0x29;
     403                bs->id = host2uint32_t_be(0x12345678);
     404
     405                memcpy(bs->label, "HELENOS_NEW", 11);
     406                memcpy(bs->type, "FAT   ", 8);
     407        }
    347408}
    348409
  • uspace/lib/c/generic/str.c

    r7fadb65 r375ab5e  
    33 * Copyright (c) 2008 Jiri Svoboda
    44 * Copyright (c) 2011 Martin Sucha
     5 * Copyright (c) 2011 Oleg Romanenko
    56 * All rights reserved.
    67 *
     
    367368}
    368369
     370/** Check whether wide string is plain ASCII.
     371 *
     372 * @return True if wide string is plain ASCII.
     373 *
     374 */
     375bool wstr_is_ascii(const wchar_t *wstr)
     376{
     377        while (*wstr && ascii_check(*wstr))
     378                wstr++;
     379        return *wstr == 0;
     380}
     381
    369382/** Check whether character is valid
    370383 *
     
    619632 * @param size  Size of the destination buffer.
    620633 * @param src   Source wide string.
    621  */
    622 void wstr_to_str(char *dest, size_t size, const wchar_t *src)
    623 {
     634 *
     635 * @return EOK, if success, negative otherwise.
     636 */
     637int wstr_to_str(char *dest, size_t size, const wchar_t *src)
     638{
     639        int rc;
    624640        wchar_t ch;
    625641        size_t src_idx;
     
    633649
    634650        while ((ch = src[src_idx++]) != 0) {
    635                 if (chr_encode(ch, dest, &dest_off, size - 1) != EOK)
     651                rc = chr_encode(ch, dest, &dest_off, size - 1);
     652                if (rc != EOK)
    636653                        break;
    637654        }
    638655
    639656        dest[dest_off] = '\0';
    640 }
     657        return rc;
     658}
     659
     660/** Convert UTF16 string to string.
     661 *
     662 * Convert utf16 string @a src to string. The output is written to the buffer
     663 * specified by @a dest and @a size. @a size must be non-zero and the string
     664 * written will always be well-formed. Surrogate pairs also supported.
     665 *
     666 * @param dest  Destination buffer.
     667 * @param size  Size of the destination buffer.
     668 * @param src   Source utf16 string.
     669 *
     670 * @return EOK, if success, negative otherwise.
     671 */
     672int utf16_to_str(char *dest, size_t size, const uint16_t *src)
     673{
     674        size_t idx=0, dest_off=0;
     675        wchar_t ch;
     676        int rc = EOK;
     677
     678        /* There must be space for a null terminator in the buffer. */
     679        assert(size > 0);
     680
     681        while (src[idx]) {
     682                if ((src[idx] & 0xfc00) == 0xd800) {
     683                        if (src[idx+1] && (src[idx+1] & 0xfc00) == 0xdc00) {
     684                                ch = 0x10000;
     685                                ch += (src[idx] & 0x03FF) << 10;
     686                                ch += (src[idx+1] & 0x03FF);
     687                                idx += 2;
     688                        }
     689                        else
     690                                break;
     691                } else {
     692                        ch = src[idx];
     693                        idx++;
     694                }
     695                rc = chr_encode(ch, dest, &dest_off, size-1);
     696                if (rc != EOK)
     697                        break;
     698        }
     699        dest[dest_off] = '\0';
     700        return rc;
     701}
     702
     703int str_to_utf16(uint16_t *dest, size_t size, const char *src)
     704{
     705        int rc=EOK;
     706        size_t offset=0;
     707        size_t idx=0;
     708        wchar_t c;
     709
     710        assert(size > 0);
     711       
     712        while ((c = str_decode(src, &offset, STR_NO_LIMIT)) != 0) {
     713                if (c > 0x10000) {
     714                        if (idx+2 >= size-1) {
     715                                rc=EOVERFLOW;
     716                                break;
     717                        }
     718                        c = (c - 0x10000);
     719                        dest[idx] = 0xD800 | (c >> 10);
     720                        dest[idx+1] = 0xDC00 | (c & 0x3FF);
     721                        idx++;
     722                } else {
     723                         dest[idx] = c;
     724                }
     725
     726                idx++;
     727                if (idx >= size-1) {
     728                        rc=EOVERFLOW;
     729                        break;
     730                }
     731        }
     732
     733        dest[idx] = '\0';
     734        return rc;
     735}
     736
    641737
    642738/** Convert wide string to new string.
     
    698794 * @param dlen  Length of destination buffer (number of wchars).
    699795 * @param src   Source string.
    700  */
    701 void str_to_wstr(wchar_t *dest, size_t dlen, const char *src)
    702 {
     796 *
     797 * @return EOK, if success, negative otherwise.
     798 */
     799int str_to_wstr(wchar_t *dest, size_t dlen, const char *src)
     800{
     801        int rc=EOK;
    703802        size_t offset;
    704803        size_t di;
     
    711810
    712811        do {
    713                 if (di >= dlen - 1)
     812                if (di >= dlen - 1) {
     813                        rc = EOVERFLOW;
    714814                        break;
     815                }
    715816
    716817                c = str_decode(src, &offset, STR_NO_LIMIT);
     
    719820
    720821        dest[dlen - 1] = '\0';
     822        return rc;
    721823}
    722824
     
    783885       
    784886        return (char *) res;
     887}
     888
     889/** Find first occurence of character in wide string.
     890 *
     891 * @param wstr String to search.
     892 * @param ch  Character to look for.
     893 *
     894 * @return Pointer to character in @a wstr or NULL if not found.
     895 */
     896wchar_t *wstr_chr(const wchar_t *wstr, wchar_t ch)
     897{
     898        while (*wstr && *wstr != ch)
     899                wstr++;
     900        if (*wstr)
     901                return (wchar_t *) wstr;
     902        else
     903                return NULL;
     904}
     905
     906/** Find last occurence of character in wide string.
     907 *
     908 * @param wstr String to search.
     909 * @param ch  Character to look for.
     910 *
     911 * @return Pointer to character in @a wstr or NULL if not found.
     912 */
     913wchar_t *wstr_rchr(const wchar_t *wstr, wchar_t ch)
     914{
     915        const wchar_t *res = NULL;
     916        while (*wstr) {
     917                if (*wstr == ch)
     918                        res = wstr;
     919                wstr++;
     920        }
     921        return (wchar_t *) res;
    785922}
    786923
     
    10371174}
    10381175
     1176void str_reverse(char* begin, char* end)
     1177{
     1178    char aux;
     1179    while(end>begin)
     1180        aux=*end, *end--=*begin, *begin++=aux;
     1181}
     1182
     1183int size_t_str(size_t value, int base, char* str, size_t size)
     1184{
     1185    static char num[] = "0123456789abcdefghijklmnopqrstuvwxyz";
     1186    char* wstr=str;
     1187       
     1188        if (size == 0)
     1189                return EINVAL;
     1190    if (base<2 || base>35) {
     1191        *str='\0';
     1192        return EINVAL;
     1193    }
     1194
     1195    do {
     1196        *wstr++ = num[value % base];
     1197                if (--size == 0)
     1198                        return EOVERFLOW;
     1199    } while(value /= base);
     1200    *wstr='\0';
     1201
     1202    // Reverse string
     1203    str_reverse(str,wstr-1);
     1204        return EOK;
     1205}
    10391206
    10401207/** Convert initial part of string to unsigned long according to given base.
  • uspace/lib/c/include/str.h

    r7fadb65 r375ab5e  
    11/*
    22 * Copyright (c) 2005 Martin Decky
     3 * Copyright (c) 2011 Oleg Romanenko
    34 * All rights reserved.
    45 *
     
    7172extern bool ascii_check(wchar_t ch);
    7273extern bool chr_check(wchar_t ch);
     74extern bool wstr_is_ascii(const wchar_t *wstr);
    7375
    7476extern int str_cmp(const char *s1, const char *s2);
     
    7981extern void str_append(char *dest, size_t size, const char *src);
    8082
     83extern int wstr_to_str(char *dest, size_t size, const wchar_t *src);
    8184extern int spascii_to_str(char *dest, size_t size, const uint8_t *src, size_t n);
    82 extern void wstr_to_str(char *dest, size_t size, const wchar_t *src);
    8385extern char *wstr_to_astr(const wchar_t *src);
    84 extern void str_to_wstr(wchar_t *dest, size_t dlen, const char *src);
    8586extern wchar_t *str_to_awstr(const char *src);
     87extern int str_to_wstr(wchar_t *dest, size_t dlen, const char *src);
     88extern int utf16_to_str(char *dest, size_t size, const uint16_t *src);
     89extern int str_to_utf16(uint16_t *dest, size_t size, const char *src);
    8690
    8791extern char *str_chr(const char *str, wchar_t ch);
    8892extern char *str_rchr(const char *str, wchar_t ch);
     93extern wchar_t *wstr_chr(const wchar_t *wstr, wchar_t ch);
     94extern wchar_t *wstr_rchr(const wchar_t *wstr, wchar_t ch);
    8995
    9096extern bool wstr_linsert(wchar_t *str, wchar_t ch, size_t pos, size_t max_pos);
     
    9399extern char *str_dup(const char *);
    94100extern char *str_ndup(const char *, size_t max_size);
     101
     102extern void str_reverse(char* begin, char* end);
     103extern int size_t_str(size_t value, int base, char* str, size_t size);
    95104
    96105extern int str_uint64(const char *, char **, unsigned int, bool, uint64_t *);
  • uspace/srv/fs/fat/Makefile

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

    r7fadb65 r375ab5e  
    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 r375ab5e  
    11/*
    22 * Copyright (c) 2008 Jakub Jermar
     3 * Copyright (c) 2011 Oleg Romanenko
    34 * All rights reserved.
    45 *
     
    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#define SF(bs)          (uint16_t_le2host((bs)->sec_per_fat) !=0 ? \
     59    uint16_t_le2host((bs)->sec_per_fat) : \
     60    uint32_t_le2host(bs->fat32.sectors_per_fat))
    5861#define RDE(bs)         uint16_t_le2host((bs)->root_ent_max)
    5962#define TS(bs)          (uint16_t_le2host((bs)->totsec16) != 0 ? \
  • uspace/srv/fs/fat/fat_dentry.c

    r7fadb65 r375ab5e  
    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        for (i=0; i<(FAT_NAME_LEN+FAT_EXT_LEN); i++) {
     225                sum = ((sum & 1) ? 0x80 : 0) + (sum >> 1) + name[i];
     226        }
     227        return sum;
     228}
     229
     230/** Get number of bytes in a string with size limit.
     231 *
     232 * @param str  NULL-terminated (or not) string.
     233 * @param size Maximum number of bytes to consider.
     234 *
     235 * @return Number of bytes in string (without 0 and ff).
     236 *
     237 */
     238size_t fat_lfn_str_nlength(const uint16_t *str, size_t size)
     239{
     240        size_t offset = 0;
     241
     242        while (offset < size) {
     243                if (str[offset] == 0 || str[offset] == FAT_LFN_PAD)
     244                        break;
     245                offset++;
     246        }
     247        return offset;
     248}
     249
     250/** Get number of bytes in a FAT long entry occuped by characters.
     251 *
     252 * @param d FAT long entry.
     253 *
     254 * @return Number of bytes.
     255 *
     256 */
     257size_t fat_lfn_size(const fat_dentry_t *d)
     258{
     259        size_t size = 0;
     260       
     261        size += fat_lfn_str_nlength(FAT_LFN_PART1(d), FAT_LFN_PART1_SIZE);
     262        size += fat_lfn_str_nlength(FAT_LFN_PART2(d), FAT_LFN_PART2_SIZE);
     263        size += fat_lfn_str_nlength(FAT_LFN_PART3(d), FAT_LFN_PART3_SIZE);     
     264       
     265        return size;
     266}
     267
     268size_t fat_lfn_get_entry(const fat_dentry_t *d, uint16_t *dst, size_t *offset)
     269{
     270        int i;
     271        for (i=FAT_LFN_PART3_SIZE-1; i>=0 && *offset>0; i--) {
     272                if (d->lfn.part3[i] == 0 || d->lfn.part3[i] == FAT_LFN_PAD)
     273                        continue;
     274                (*offset)--;
     275                dst[(*offset)] = uint16_t_le2host(d->lfn.part3[i]);
     276        }
     277        for (i=FAT_LFN_PART2_SIZE-1; i>=0 && *offset>0; i--) {
     278                if (d->lfn.part2[i] == 0 || d->lfn.part2[i] == FAT_LFN_PAD)
     279                        continue;
     280                (*offset)--;
     281                dst[(*offset)] = uint16_t_le2host(d->lfn.part2[i]);
     282        }
     283        for (i=FAT_LFN_PART1_SIZE-1; i>=0 && *offset>0; i--) {
     284                if (d->lfn.part1[i] == 0 || d->lfn.part1[i] == FAT_LFN_PAD)
     285                        continue;
     286                (*offset)--;
     287                dst[(*offset)] = uint16_t_le2host(d->lfn.part1[i]);
     288        }
     289        return *offset;
     290}
     291
     292size_t fat_lfn_set_entry(const uint16_t *src, size_t *offset, size_t size, fat_dentry_t *d)
     293{
     294        size_t idx;
     295        for (idx=0; idx < FAT_LFN_PART1_SIZE; idx++) {
     296                if (*offset < size) {
     297                        d->lfn.part1[idx] = host2uint16_t_le(src[*offset]);
     298                        (*offset)++;
     299                }
     300                else
     301                        d->lfn.part1[idx] = FAT_LFN_PAD;
     302        }
     303        for (idx=0; idx < FAT_LFN_PART2_SIZE; idx++) {
     304                if (*offset < size) {
     305                        d->lfn.part2[idx] = host2uint16_t_le(src[*offset]);
     306                        (*offset)++;
     307                }
     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                }
     316                else
     317                        d->lfn.part3[idx] = FAT_LFN_PAD;
     318        }
     319
     320        if (src[*offset] == 0)
     321                offset++;
     322        FAT_LFN_ATTR(d) = FAT_ATTR_LFN;
     323        d->lfn.type = 0;
     324        d->lfn.firstc_lo = 0;
     325       
     326        return *offset;
     327}
     328
     329void str_to_ascii(char *dst, const char *src, size_t count, uint8_t pad)
     330{
     331        wchar_t ch;
     332        size_t off = 0;
     333        size_t i = 0;
     334       
     335        while (i < count) {
     336                if ((ch = str_decode(src, &off, STR_NO_LIMIT)) != 0) {
     337                        if (ascii_check(ch) & IS_D_CHAR(ch))
     338                                *dst = toupper(ch);
     339                        else
     340                                *dst = pad;
     341                }
     342                else
     343                        break;
     344
     345                dst++;
     346                i++;
     347        }
     348        *dst = '\0';
     349}
     350
     351bool fat_valid_name(const char *name)
     352{
     353        wchar_t ch;
     354        size_t offset=0;
     355        bool result = true;
     356       
     357        while ((ch = str_decode(name, &offset, STR_NO_LIMIT)) != 0) {
     358                if (wstr_chr(FAT_STOP_CHARS, ch) != NULL) {
     359                        result = false;
     360                        break;
     361                }
     362        }
     363        return result;
     364}
     365
     366bool fat_valid_short_name(const char *name)
    83367{
    84368        unsigned int i;
    85369        unsigned int dot = 0;
    86370        bool dot_found = false;
    87        
    88371
    89372        for (i = 0; name[i]; i++) {
     
    96379                        }
    97380                } else {
    98                         if (!is_d_char(name[i]))
     381                        if (!IS_D_CHAR(name[i]))
    99382                                return false;
    100383                }
     
    114397}
    115398
    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;
     399size_t utf16_length(const uint16_t *wstr)
     400{
     401        size_t len = 0;
     402       
     403        while (*wstr++ != 0)
     404                len++;
     405       
     406        return len;
    240407}
    241408
  • uspace/srv/fs/fat/fat_dentry.h

    r7fadb65 r375ab5e  
    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 L"*?/\\\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
    67100typedef 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;
    76101        union {
    77                 uint16_t        eaidx;          /* FAT12/FAT16 */
    78                 uint16_t        firstc_hi;      /* FAT32 */
    79         } __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;
     102                struct {
     103                        uint8_t         name[8];
     104                        uint8_t         ext[3];
     105                        uint8_t         attr;
     106                        uint8_t         lcase;
     107                        uint8_t         ctime_fine;
     108                        uint16_t        ctime;
     109                        uint16_t        cdate;
     110                        uint16_t        adate;
     111                        union {
     112                                uint16_t        eaidx;          /* FAT12/FAT16 */
     113                                uint16_t        firstc_hi;      /* FAT32 */
     114                        } __attribute__ ((packed));
     115                        uint16_t        mtime;
     116                        uint16_t        mdate;
     117                        union {
     118                                uint16_t        firstc;         /* FAT12/FAT16 */
     119                                uint16_t        firstc_lo;      /* FAT32 */
     120                        } __attribute__ ((packed));
     121                        uint32_t        size;
     122                } __attribute__ ((packed));
     123                struct {
     124                        uint8_t         order;
     125                        uint16_t        part1[FAT_LFN_PART1_SIZE];
     126                        uint8_t         attr;
     127                        uint8_t         type;
     128                        uint8_t         check_sum;
     129                        uint16_t        part2[FAT_LFN_PART2_SIZE];
     130                        uint16_t        firstc_lo; /* MUST be 0 */
     131                        uint16_t        part3[FAT_LFN_PART3_SIZE];
     132                } __attribute__ ((packed)) lfn;
     133        };
    87134} __attribute__ ((packed)) fat_dentry_t;
    88135
     136
    89137extern int fat_dentry_namecmp(char *, const char *);
    90 extern bool fat_dentry_name_verify(const char *);
    91138extern void fat_dentry_name_get(const fat_dentry_t *, char *);
    92139extern void fat_dentry_name_set(fat_dentry_t *, const char *);
    93140extern fat_dentry_clsf_t fat_classify_dentry(const fat_dentry_t *);
     141extern uint8_t fat_dentry_chksum(uint8_t *);
     142
     143extern size_t fat_lfn_str_nlength(const uint16_t *, size_t);
     144extern size_t fat_lfn_size(const fat_dentry_t *);
     145extern size_t fat_lfn_get_entry(const fat_dentry_t *, uint16_t *, size_t *);
     146extern size_t fat_lfn_set_entry(const uint16_t *, size_t *, size_t, fat_dentry_t *);
     147
     148extern void str_to_ascii(char *dst, const char *src, size_t count, uint8_t pad);
     149extern size_t utf16_length(const uint16_t *wstr);
     150
     151extern bool fat_valid_name(const char *name);
     152extern bool fat_valid_short_name(const char *name);
     153
    94154
    95155#endif
  • uspace/srv/fs/fat/fat_fat.c

    r7fadb65 r375ab5e  
    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/**
     
    5455 * primitive boot sector members.
    5556 */
    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 
    6057#define CLBN2PBN(bs, cl, bn) \
    6158        (SSA((bs)) + ((cl) - FAT_CLST_FIRST) * SPC((bs)) + (bn) % SPC((bs)))
     59
     60#define IS_ODD(number)  (number & 0x1)
    6261
    6362/**
     
    6564 * during allocation of clusters. The lock does not have to be held durring
    6665 * deallocation of clusters.
    67  */ 
     66 */
    6867static FIBRIL_MUTEX_INITIALIZE(fat_alloc_lock);
    6968
     
    7776 * @param numc          If non-NULL, output argument holding the number of
    7877 *                      clusters seen during the walk.
    79  * @param max_clusters  Maximum number of clusters to visit.   
     78 * @param max_clusters  Maximum number of clusters to visit.
    8079 *
    8180 * @return              EOK on success or a negative error code.
    8281 */
    83 int 
     82int
    8483fat_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;
     84    fat_cluster_t *lastc, uint32_t *numc, uint32_t max_clusters)
     85{
     86        uint32_t clusters = 0;
     87        fat_cluster_t clst = firstc, clst_last1 = FAT_CLST_LAST1(bs);
     88        fat_cluster_t clst_bad = FAT_CLST_BAD(bs);
    9089        int rc;
    9190
     
    9998        }
    10099
    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 
     100        while (clst < clst_last1 && clusters < max_clusters) {
    105101                assert(clst >= FAT_CLST_FIRST);
    106102                if (lastc)
    107103                        *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));
     104
    110105                /* 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;
     106                rc = fat_get_cluster(bs, service_id, FAT1, clst, &clst);
     107                if (rc != EOK)
     108                        return rc;
     109
     110                assert(clst != clst_bad);
    120111                clusters++;
    121112        }
    122113
    123         if (lastc && clst < FAT_CLST_LAST1)
     114        if (lastc && clst < clst_last1)
    124115                *lastc = clst;
    125116        if (numc)
     
    151142                return ELIMIT;
    152143
    153         if (nodep->firstc == FAT_CLST_ROOT)
     144        if (!FAT_IS_FAT32(bs) && nodep->firstc == FAT_CLST_ROOT)
    154145                goto fall_through;
    155146
     
    178169        if (rc != EOK)
    179170                return rc;
    180        
     171
    181172        /*
    182173         * Update the "current" cluster cache.
     
    198189 * @param clp           If not NULL, address where the cluster containing bn
    199190 *                      will be stored.
    200  *                      stored 
     191 *                      stored
    201192 * @param bn            Block number.
    202193 * @param flags         Flags passed to libblock.
     
    208199    fat_cluster_t fcl, fat_cluster_t *clp, aoff64_t bn, int flags)
    209200{
    210         uint16_t clusters;
    211         unsigned max_clusters;
     201        uint32_t clusters;
     202        uint32_t max_clusters;
    212203        fat_cluster_t c;
    213204        int rc;
     
    219210                return ELIMIT;
    220211
    221         if (fcl == FAT_CLST_ROOT) {
     212        if (!FAT_IS_FAT32(bs) && fcl == FAT_CLST_ROOT) {
    222213                /* root directory special case */
    223214                assert(bn < RDS(bs));
     
    275266                        return rc;
    276267        }
    277        
     268
    278269        if (o >= pos)
    279270                return EOK;
    280        
     271
    281272        /* zero out the initial part of the new cluster chain */
    282273        for (o = boundary; o < pos; o += BPS(bs)) {
     
    295286}
    296287
    297 /** Get cluster from the first FAT.
     288/** Get cluster from the first FAT. FAT12 version
    298289 *
    299290 * @param bs            Buffer holding the boot sector for the file system.
     
    305296 */
    306297int
     298fat_get_cluster_fat12(fat_bs_t *bs, service_id_t service_id, unsigned fatno,
     299    fat_cluster_t clst, fat_cluster_t *value)
     300{
     301        block_t *b, *b1;
     302        uint16_t byte1, byte2;
     303        aoff64_t offset;
     304        int rc;
     305
     306        offset = (clst + clst/2);
     307        if (offset / BPS(bs) >= SF(bs))
     308                return ERANGE;
     309
     310        rc = block_get(&b, service_id, RSCNT(bs) + SF(bs) * fatno +
     311            offset / BPS(bs), BLOCK_FLAGS_NONE);
     312        if (rc != EOK)
     313                return rc;
     314
     315        byte1 = ((uint8_t*) b->data)[offset % BPS(bs)];
     316        /* This cluster access spans a sector boundary. Check only for FAT12 */
     317        if ((offset % BPS(bs)) + 1 == BPS(bs)) {
     318                /* Is it last sector of FAT? */
     319                if (offset / BPS(bs) < SF(bs)) {
     320                        /* No. Reading next sector */
     321                        rc = block_get(&b1, service_id, 1 + RSCNT(bs) +
     322                                SF(bs)*fatno + offset / BPS(bs), BLOCK_FLAGS_NONE);
     323                        if (rc != EOK) {
     324                                block_put(b);
     325                                return rc;
     326                        }
     327                        /*
     328                        * Combining value with last byte of current sector and
     329                        * first byte of next sector
     330                        */
     331                        byte2 = ((uint8_t*) b1->data)[0];
     332
     333                        rc = block_put(b1);
     334                        if (rc != EOK) {
     335                                block_put(b);
     336                                return rc;
     337                        }
     338                }
     339                else {
     340                        /* Yes. It is last sector of FAT */
     341                        block_put(b);
     342                        return ERANGE;
     343                }
     344        }
     345        else
     346                byte2 = ((uint8_t*) b->data)[(offset % BPS(bs))+1];
     347
     348        *value = uint16_t_le2host(byte1 | (byte2 << 8));
     349        if (IS_ODD(clst))
     350                *value = (*value) >> 4;
     351        else
     352                *value = (*value) & FAT12_MASK;
     353       
     354        rc = block_put(b);
     355        return rc;
     356}
     357
     358/** Get cluster from the first FAT. FAT16 version
     359 *
     360 * @param bs            Buffer holding the boot sector for the file system.
     361 * @param service_id    Service ID for the file system.
     362 * @param clst          Cluster which to get.
     363 * @param value         Output argument holding the value of the cluster.
     364 *
     365 * @return              EOK or a negative error code.
     366 */
     367int
     368fat_get_cluster_fat16(fat_bs_t *bs, service_id_t service_id, unsigned fatno,
     369    fat_cluster_t clst, fat_cluster_t *value)
     370{
     371        block_t *b;
     372        aoff64_t offset;
     373        int rc;
     374
     375        offset = (clst * FAT16_CLST_SIZE);
     376
     377        rc = block_get(&b, service_id, RSCNT(bs) + SF(bs) * fatno +
     378            offset / BPS(bs), BLOCK_FLAGS_NONE);
     379        if (rc != EOK)
     380                return rc;
     381
     382        *value = uint16_t_le2host(*(uint16_t *)(b->data + offset % BPS(bs)));
     383
     384        rc = block_put(b);
     385
     386        return rc;
     387}
     388
     389/** Get cluster from the first FAT. FAT32 version
     390 *
     391 * @param bs            Buffer holding the boot sector for the file system.
     392 * @param service_id    Service ID for the file system.
     393 * @param clst          Cluster which to get.
     394 * @param value         Output argument holding the value of the cluster.
     395 *
     396 * @return              EOK or a negative error code.
     397 */
     398int
     399fat_get_cluster_fat32(fat_bs_t *bs, service_id_t service_id, unsigned fatno,
     400    fat_cluster_t clst, fat_cluster_t *value)
     401{
     402        block_t *b;
     403        aoff64_t offset;
     404        int rc;
     405
     406        offset = (clst * FAT32_CLST_SIZE);
     407
     408        rc = block_get(&b, service_id, RSCNT(bs) + SF(bs) * fatno +
     409            offset / BPS(bs), BLOCK_FLAGS_NONE);
     410        if (rc != EOK)
     411                return rc;
     412
     413        *value = uint32_t_le2host(*(uint32_t *)(b->data + offset % BPS(bs))) & FAT32_MASK;
     414
     415        rc = block_put(b);
     416
     417        return rc;
     418}
     419
     420
     421/** Get cluster from the first FAT.
     422 *
     423 * @param bs            Buffer holding the boot sector for the file system.
     424 * @param service_id    Service ID for the file system.
     425 * @param clst          Cluster which to get.
     426 * @param value         Output argument holding the value of the cluster.
     427 *
     428 * @return              EOK or a negative error code.
     429 */
     430int
    307431fat_get_cluster(fat_bs_t *bs, service_id_t service_id, unsigned fatno,
    308432    fat_cluster_t clst, fat_cluster_t *value)
    309433{
    310         block_t *b;
    311         fat_cluster_t *cp;
    312         int rc;
    313 
     434        int rc;
     435
     436        assert(fatno < FATCNT(bs));
     437
     438        if (FAT_IS_FAT12(bs)) {
     439                rc = fat_get_cluster_fat12(bs, service_id, fatno, clst, value);
     440        }
     441        else {
     442                if (FAT_IS_FAT32(bs))
     443                        rc = fat_get_cluster_fat32(bs, service_id, fatno, clst, value);
     444                else
     445                        rc = fat_get_cluster_fat16(bs, service_id, fatno, clst, value);
     446        }
     447
     448        return rc;
     449}
     450
     451/** Set cluster in one instance of FAT. FAT12 version.
     452 *
     453 * @param bs            Buffer holding the boot sector for the file system.
     454 * @param service_id    Service ID for the file system.
     455 * @param fatno         Number of the FAT instance where to make the change.
     456 * @param clst          Cluster which is to be set.
     457 * @param value         Value to set the cluster with.
     458 *
     459 * @return              EOK on success or a negative error code.
     460 */
     461int
     462fat_set_cluster_fat12(fat_bs_t *bs, service_id_t service_id, unsigned fatno,
     463    fat_cluster_t clst, fat_cluster_t value)
     464{
     465        block_t *b, *b1=NULL;
     466        aoff64_t offset;
     467        uint16_t byte1, byte2;
     468        int rc;
     469
     470        offset = (clst + clst/2);
     471        if (offset / BPS(bs) >= SF(bs))
     472                return ERANGE;
     473       
    314474        rc = block_get(&b, service_id, RSCNT(bs) + SF(bs) * fatno +
    315             (clst * sizeof(fat_cluster_t)) / BPS(bs), BLOCK_FLAGS_NONE);
     475            offset / BPS(bs), BLOCK_FLAGS_NONE);
    316476        if (rc != EOK)
    317477                return rc;
    318         cp = (fat_cluster_t *)b->data +
    319             clst % (BPS(bs) / sizeof(fat_cluster_t));
    320         *value = uint16_t_le2host(*cp);
     478
     479        byte1 = ((uint8_t*) b->data)[offset % BPS(bs)];
     480        bool border = false;
     481        /* This cluster access spans a sector boundary. Check only for FAT12 */
     482        if ((offset % BPS(bs))+1 == BPS(bs)) {
     483                /* Is it last sector of FAT? */
     484                if (offset / BPS(bs) < SF(bs)) {
     485                        /* No. Reading next sector */
     486                        rc = block_get(&b1, service_id, 1 + RSCNT(bs) +
     487                                SF(bs)*fatno + offset / BPS(bs), BLOCK_FLAGS_NONE);
     488                        if (rc != EOK) {
     489                                block_put(b);
     490                                return rc;
     491                        }
     492                        /*
     493                         * Combining value with last byte of current sector and
     494                         * first byte of next sector
     495                         */
     496                        byte2 = ((uint8_t*) b1->data)[0];
     497                        border = true;
     498                }
     499                else {
     500                        /* Yes. It is last sector of fat */
     501                        block_put(b);
     502                        return ERANGE;
     503                }
     504        }
     505        else
     506                byte2 = ((uint8_t*) b->data)[(offset % BPS(bs))+1];
     507
     508        if (IS_ODD(clst)) {
     509                byte1 &= 0x0f;
     510                byte2 = 0;
     511                value = (value << 4);
     512        } else {
     513                byte1 = 0;
     514                byte2 &= 0xf0;
     515                value &= FAT12_MASK;
     516        }
     517
     518        byte1 = byte1 | (value & 0xff);
     519        byte2 = byte2 | (value >> 8);
     520
     521        ((uint8_t*) b->data)[(offset % BPS(bs))] = byte1;
     522        if (border) {
     523                ((uint8_t*) b1->data)[0] = byte2;
     524
     525                b1->dirty = true;
     526                rc = block_put(b1);
     527                if (rc != EOK) {
     528                        block_put(b);
     529                        return rc;
     530                }
     531        } else
     532                ((uint8_t*) b->data)[(offset % BPS(bs))+1] = byte2;
     533
     534        b->dirty = true;        /* need to sync block */
    321535        rc = block_put(b);
    322        
     536        return rc;
     537}
     538
     539/** Set cluster in one instance of FAT. FAT16 version.
     540 *
     541 * @param bs            Buffer holding the boot sector for the file system.
     542 * @param service_id    Service ID for the file system.
     543 * @param fatno         Number of the FAT instance where to make the change.
     544 * @param clst          Cluster which is to be set.
     545 * @param value         Value to set the cluster with.
     546 *
     547 * @return              EOK on success or a negative error code.
     548 */
     549int
     550fat_set_cluster_fat16(fat_bs_t *bs, service_id_t service_id, unsigned fatno,
     551    fat_cluster_t clst, fat_cluster_t value)
     552{
     553        block_t *b;
     554        aoff64_t offset;
     555        int rc;
     556
     557        offset = (clst * FAT16_CLST_SIZE);
     558
     559        rc = block_get(&b, service_id, RSCNT(bs) + SF(bs) * fatno +
     560            offset / BPS(bs), BLOCK_FLAGS_NONE);
     561        if (rc != EOK)
     562                return rc;
     563
     564        *(uint16_t *)(b->data + offset % BPS(bs)) = host2uint16_t_le(value);
     565
     566        b->dirty = true;        /* need to sync block */
     567        rc = block_put(b);
     568        return rc;
     569}
     570
     571/** Set cluster in one instance of FAT. FAT32 version.
     572 *
     573 * @param bs            Buffer holding the boot sector for the file system.
     574 * @param service_id    Service ID for the file system.
     575 * @param fatno         Number of the FAT instance where to make the change.
     576 * @param clst          Cluster which is to be set.
     577 * @param value         Value to set the cluster with.
     578 *
     579 * @return              EOK on success or a negative error code.
     580 */
     581int
     582fat_set_cluster_fat32(fat_bs_t *bs, service_id_t service_id, unsigned fatno,
     583    fat_cluster_t clst, fat_cluster_t value)
     584{
     585        block_t *b;
     586        aoff64_t offset;
     587        int rc;
     588        fat_cluster_t temp;
     589
     590        offset = (clst * FAT32_CLST_SIZE);
     591
     592        rc = block_get(&b, service_id, RSCNT(bs) + SF(bs) * fatno +
     593            offset / BPS(bs), BLOCK_FLAGS_NONE);
     594        if (rc != EOK)
     595                return rc;
     596
     597        temp = uint32_t_le2host(*(uint32_t *)(b->data + offset % BPS(bs)));
     598        temp &= 0xf0000000;
     599        temp |= (value & FAT32_MASK);
     600        *(uint32_t *)(b->data + offset % BPS(bs)) = host2uint32_t_le(temp);
     601
     602        b->dirty = true;        /* need to sync block */
     603        rc = block_put(b);
    323604        return rc;
    324605}
     
    338619    fat_cluster_t clst, fat_cluster_t value)
    339620{
    340         block_t *b;
    341         fat_cluster_t *cp;
    342621        int rc;
    343622
    344623        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);
     624
     625        if (FAT_IS_FAT12(bs))
     626                rc = fat_set_cluster_fat12(bs, service_id, fatno, clst, value);
     627        else if (FAT_IS_FAT32(bs))
     628                rc = fat_set_cluster_fat32(bs, service_id, fatno, clst, value);
     629        else
     630                rc = fat_set_cluster_fat16(bs, service_id, fatno, clst, value);
     631
    354632        return rc;
    355633}
     
    369647        uint8_t fatno;
    370648        unsigned c;
    371         int rc;
    372 
    373         for (fatno = FAT1 + 1; fatno < bs->fatcnt; fatno++) {
     649        fat_cluster_t clst_last1 = FAT_CLST_LAST1(bs);
     650        int rc;
     651
     652        for (fatno = FAT1 + 1; fatno < FATCNT(bs); fatno++) {
    374653                for (c = 0; c < nclsts; c++) {
    375654                        rc = fat_set_cluster(bs, service_id, fatno, lifo[c],
    376                             c == 0 ? FAT_CLST_LAST1 : lifo[c - 1]);
     655                            c == 0 ? clst_last1 : lifo[c - 1]);
    377656                        if (rc != EOK)
    378657                                return rc;
     
    404683    fat_cluster_t *mcl, fat_cluster_t *lcl)
    405684{
    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;
     685        fat_cluster_t *lifo;    /* stack for storing free cluster numbers */
     686        unsigned found = 0;     /* top of the free cluster number stack */
     687        fat_cluster_t clst, value, clst_last1 = FAT_CLST_LAST1(bs);
     688        int rc = EOK;
    411689
    412690        lifo = (fat_cluster_t *) malloc(nclsts * sizeof(fat_cluster_t));
    413691        if (!lifo)
    414692                return ENOMEM;
    415        
    416693        /*
    417694         * Search FAT1 for unused clusters.
    418695         */
    419696        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++) {
    426                         /*
    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.
    433                          */
    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                         }
    470                 }
    471                 rc = block_put(blk);
    472                 if (rc != EOK) {
    473 error:
     697        for (clst=FAT_CLST_FIRST; clst < CC(bs)+2 && found < nclsts; clst++) {
     698                rc = fat_get_cluster(bs, service_id, FAT1, clst, &value);
     699                if (rc != EOK)
     700                break;
     701
     702                if (value == FAT_CLST_RES0) {
     703                /*
     704                 * The cluster is free. Put it into our stack
     705                 * of found clusters and mark it as non-free.
     706                 */
     707                lifo[found] = clst;
     708                rc = fat_set_cluster(bs, service_id, FAT1, clst,
     709                    (found == 0) ?  clst_last1 : lifo[found - 1]);
     710                if (rc != EOK)
     711                        break;
     712
     713                found++;
     714                }
     715        }
     716
     717        if (rc == EOK && found == nclsts) {
     718                rc = fat_alloc_shadow_clusters(bs, service_id, lifo, nclsts);
     719                if (rc == EOK) {
     720                        *mcl = lifo[found - 1];
     721                        *lcl = lifo[0];
     722                        free(lifo);
    474723                        fibril_mutex_unlock(&fat_alloc_lock);
    475                         free(lifo);
    476                         return rc;
    477                 }
    478         }
    479 out:
    480         fibril_mutex_unlock(&fat_alloc_lock);
    481 
    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--) {
     724                        return EOK;
     725                }
     726        }
     727
     728        /* If something wrong - free the clusters */
     729        if (found > 0) {
     730                while (found--) {
    487731                rc = fat_set_cluster(bs, service_id, FAT1, lifo[found],
    488732                    FAT_CLST_RES0);
    489                 if (rc != EOK) {
    490                         free(lifo);
    491                         return rc;
    492                 }
    493         }
    494        
     733                }
     734        }
     735
    495736        free(lifo);
     737        fibril_mutex_unlock(&fat_alloc_lock);
    496738        return ENOSPC;
    497739}
     
    509751{
    510752        unsigned fatno;
    511         fat_cluster_t nextc;
     753        fat_cluster_t nextc, clst_bad = FAT_CLST_BAD(bs);
    512754        int rc;
    513755
    514756        /* 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);
     757        while (firstc < FAT_CLST_LAST1(bs)) {
     758                assert(firstc >= FAT_CLST_FIRST && firstc < clst_bad);
    517759                rc = fat_get_cluster(bs, service_id, FAT1, firstc, &nextc);
    518760                if (rc != EOK)
    519761                        return rc;
    520                 for (fatno = FAT1; fatno < bs->fatcnt; fatno++) {
     762                for (fatno = FAT1; fatno < FATCNT(bs); fatno++) {
    521763                        rc = fat_set_cluster(bs, service_id, fatno, firstc,
    522764                            FAT_CLST_RES0);
     
    564806                }
    565807
    566                 for (fatno = FAT1; fatno < bs->fatcnt; fatno++) {
    567                         rc = fat_set_cluster(bs, nodep->idx->service_id, fatno,
    568                             lastc, mcl);
     808                for (fatno = FAT1; fatno < FATCNT(bs); fatno++) {
     809                        rc = fat_set_cluster(bs, nodep->idx->service_id,
     810                            fatno, lastc, mcl);
    569811                        if (rc != EOK)
    570812                                return rc;
     
    590832int fat_chop_clusters(fat_bs_t *bs, fat_node_t *nodep, fat_cluster_t lcl)
    591833{
     834        fat_cluster_t clst_last1 = FAT_CLST_LAST1(bs);
    592835        int rc;
    593836        service_id_t service_id = nodep->idx->service_id;
     
    616859
    617860                /* Terminate the cluster chain in all copies of FAT. */
    618                 for (fatno = FAT1; fatno < bs->fatcnt; fatno++) {
     861                for (fatno = FAT1; fatno < FATCNT(bs); fatno++) {
    619862                        rc = fat_set_cluster(bs, service_id, fatno, lcl,
    620                             FAT_CLST_LAST1);
     863                            clst_last1);
    621864                        if (rc != EOK)
    622865                                return rc;
     
    673916
    674917        /* Check number of FATs. */
    675         if (bs->fatcnt == 0)
     918        if (FATCNT(bs) == 0)
    676919                return ENOTSUP;
    677920
    678921        /* Check total number of sectors. */
    679 
    680         if (bs->totsec16 == 0 && bs->totsec32 == 0)
     922        if (TS(bs) == 0)
    681923                return ENOTSUP;
    682924
    683925        if (bs->totsec16 != 0 && bs->totsec32 != 0 &&
    684             bs->totsec16 != bs->totsec32) 
     926            bs->totsec16 != bs->totsec32)
    685927                return ENOTSUP;
    686928
     
    690932
    691933        /* Check number of sectors per FAT. */
    692         if (bs->sec_per_fat == 0)
     934        if (SF(bs) == 0)
    693935                return ENOTSUP;
    694936
     
    700942         * sanitized to support file systems with this property.
    701943         */
    702         if ((uint16_t_le2host(bs->root_ent_max) * sizeof(fat_dentry_t)) %
    703             uint16_t_le2host(bs->bps) != 0)
     944        if (!FAT_IS_FAT32(bs) && (RDE(bs) * sizeof(fat_dentry_t)) % BPS(bs) != 0)
    704945                return ENOTSUP;
    705946
    706947        /* Check signature of each FAT. */
    707 
    708         for (fat_no = 0; fat_no < bs->fatcnt; fat_no++) {
     948        for (fat_no = 0; fat_no < FATCNT(bs); fat_no++) {
    709949                rc = fat_get_cluster(bs, service_id, fat_no, 0, &e0);
    710950                if (rc != EOK)
     
    723963                 * set to one.
    724964                 */
    725                 if ((e0 >> 8) != 0xff || e1 != 0xffff)
     965                if (!FAT_IS_FAT12(bs) &&
     966                        ((e0 >> 8) != (FAT_MASK(bs) >> 8) || e1 != FAT_MASK(bs)))
    726967                        return ENOTSUP;
    727968        }
     
    732973/**
    733974 * @}
    734  */ 
     975 */
  • uspace/srv/fs/fat/fat_fat.h

    r7fadb65 r375ab5e  
    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 FAT_IS_FAT12(bs)        (CC(bs) < FAT12_CLST_MAX)
     79#define FAT_IS_FAT16(bs) \
     80    ((CC(bs) >= FAT12_CLST_MAX) && (CC(bs) < FAT16_CLST_MAX))
     81#define FAT_IS_FAT32(bs)        (CC(bs) >= FAT16_CLST_MAX)
     82
     83#define FAT_CLST_SIZE(bs) \
     84    (FAT_IS_FAT32(bs) ? FAT32_CLST_SIZE : FAT16_CLST_SIZE)
     85
     86#define FAT_MASK(bs) \
     87    (FAT_IS_FAT12(bs) ? FAT12_MASK : \
     88    (FAT_IS_FAT32(bs) ? FAT32_MASK : FAT16_MASK))
     89
     90#define FAT_CLST_LAST1(bs)      (FAT32_CLST_LAST1 & FAT_MASK((bs)))
     91#define FAT_CLST_LAST8(bs)      (FAT32_CLST_LAST8 & FAT_MASK((bs)))
     92#define FAT_CLST_BAD(bs)        (FAT32_CLST_BAD & FAT_MASK((bs)))
     93
     94#define FAT_ROOT_CLST(bs) \
     95    (FAT_IS_FAT32(bs) ? uint32_t_le2host(bs->fat32.root_cluster) : \
     96    FAT_CLST_ROOT)
     97
    5498/* forward declarations */
    5599struct block;
     
    57101struct fat_bs;
    58102
    59 typedef uint16_t fat_cluster_t;
     103typedef uint32_t fat_cluster_t;
    60104
    61 #define fat_clusters_get(numc, bs, dh, fc) \
    62     fat_cluster_walk((bs), (dh), (fc), NULL, (numc), (uint16_t) -1)
     105#define fat_clusters_get(numc, bs, sid, fc) \
     106    fat_cluster_walk((bs), (sid), (fc), NULL, (numc), (uint32_t) -1)
    63107extern int fat_cluster_walk(struct fat_bs *, service_id_t, fat_cluster_t,
    64     fat_cluster_t *, uint16_t *, uint16_t);
     108    fat_cluster_t *, uint32_t *, uint32_t);
    65109
    66110extern int fat_block_get(block_t **, struct fat_bs *, struct fat_node *,
     
    78122extern int fat_alloc_shadow_clusters(struct fat_bs *, service_id_t,
    79123    fat_cluster_t *, unsigned);
     124extern int fat_get_cluster_fat12(struct fat_bs *, service_id_t, unsigned,
     125    fat_cluster_t, fat_cluster_t *);
     126extern int fat_get_cluster_fat16(struct fat_bs *, service_id_t, unsigned,
     127    fat_cluster_t, fat_cluster_t *);
     128extern int fat_get_cluster_fat32(struct fat_bs *, service_id_t, unsigned,
     129    fat_cluster_t, fat_cluster_t *);
    80130extern int fat_get_cluster(struct fat_bs *, service_id_t, unsigned,
    81131    fat_cluster_t, fat_cluster_t *);
     132extern int fat_set_cluster_fat12(struct fat_bs *, service_id_t, unsigned,
     133    fat_cluster_t, fat_cluster_t);
     134extern int fat_set_cluster_fat16(struct fat_bs *, service_id_t, unsigned,
     135    fat_cluster_t, fat_cluster_t);
     136extern int fat_set_cluster_fat32(struct fat_bs *, service_id_t, unsigned,
     137    fat_cluster_t, fat_cluster_t);
    82138extern int fat_set_cluster(struct fat_bs *, service_id_t, unsigned,
    83139    fat_cluster_t, fat_cluster_t);
  • uspace/srv/fs/fat/fat_ops.c

    r7fadb65 r375ab5e  
    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        }
     318        else
     319                nodep->firstc = uint16_t_le2host(d->firstc);
     320
    311321        if (d->attr & FAT_ATTR_SUBDIR) {
    312                 /* 
     322                /*
    313323                 * The only directory which does not have this bit set is the
    314324                 * root directory itself. The root directory node is handled
     
    316326                 */
    317327                nodep->type = FAT_DIRECTORY;
     328
    318329                /*
    319330                 * Unfortunately, the 'size' field of the FAT dentry is not
     
    321332                 * size of the directory by walking the FAT.
    322333                 */
    323                 uint16_t clusters;
    324                 rc = fat_clusters_get(&clusters, bs, idxp->service_id,
    325                     uint16_t_le2host(d->firstc));
     334                uint32_t clusters;
     335                rc = fat_clusters_get(&clusters, bs, idxp->service_id, 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 % (BPS(di.bs) / sizeof(fat_dentry_t));
     395                        fat_idx_t *idx = fat_idx_get_by_pos(service_id,
     396                                parentp->firstc, di.bnum * DPS(di.bs) + o);
     397                        if (!idx) {
     398                                /*
     399                                 * Can happen if memory is low or if we
     400                                 * run out of 32-bit indices.
     401                                 */
     402                                rc = fat_directory_close(&di);
     403                                return (rc == EOK) ? ENOMEM : rc;
    400404                        }
    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);
     405                        rc = fat_node_get_core(&nodep, idx);
     406                        fibril_mutex_unlock(&idx->lock);
     407                        if (rc != EOK) {
     408                                (void) fat_directory_close(&di);
    424409                                return rc;
    425410                        }
    426                 }
    427                 rc = block_put(b);
    428                 if (rc != EOK)
     411                        *rfn = FS_NODE(nodep);
     412                        rc = fat_directory_close(&di);
     413                        if (rc != EOK)
     414                                (void) fat_node_put(*rfn);
    429415                        return rc;
    430         }
    431 
     416                } else {
     417                        rc = fat_directory_next(&di);
     418                        if (rc != EOK)
     419                                break;
     420                }
     421        }
     422        (void) fat_directory_close(&di);
    432423        *rfn = NULL;
    433424        return EOK;
     
    591582        fat_bs_t *bs;
    592583        block_t *b;
    593         unsigned i, j;
    594         unsigned blocks;
    595         fat_cluster_t mcl, lcl;
     584        fat_directory_t di;
     585        fat_dentry_t de;
    596586        int rc;
    597587
     
    607597        fibril_mutex_unlock(&childp->lock);
    608598
    609         if (!fat_dentry_name_verify(name)) {
    610                 /*
    611                  * Attempt to create unsupported name.
    612                  */
     599        if (!fat_valid_name(name))
    613600                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        
     601
    621602        fibril_mutex_lock(&parentp->idx->lock);
    622603        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);
    662         if (rc != EOK) {
    663                 fibril_mutex_unlock(&parentp->idx->lock);
    664                 return rc;
    665         }
    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:
     604        rc = fat_directory_open(parentp, &di);
     605        if (rc != EOK)
     606                return rc;
     607
    688608        /*
    689609         * At this point we only establish the link between the parent and the
     
    692612         * dentry data is kept in the child node structure.
    693613         */
    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);
     614        memset(&de, 0, sizeof(fat_dentry_t));
     615
     616        rc = fat_directory_write(&di, name, &de);
     617        if (rc!=EOK)
     618                return rc;
     619        rc = fat_directory_close(&di);
     620        if (rc!=EOK)
     621                return rc;
     622
    698623        fibril_mutex_unlock(&parentp->idx->lock);
    699         if (rc != EOK) 
     624        if (rc != EOK)
    700625                return rc;
    701626
    702627        fibril_mutex_lock(&childp->idx->lock);
    703        
     628
    704629        if (childp->type == FAT_DIRECTORY) {
    705630                /*
     
    720645                d = (fat_dentry_t *) b->data;
    721646                if ((fat_classify_dentry(d) == FAT_DENTRY_LAST) ||
    722                     (str_cmp((char *) d->name, FAT_NAME_DOT)) == 0) {
     647                    (bcmp(d->name, FAT_NAME_DOT, FAT_NAME_LEN)) == 0) {
    723648                        memset(d, 0, sizeof(fat_dentry_t));
    724649                        memcpy(d->name, FAT_NAME_DOT, FAT_NAME_LEN);
     
    730655                d++;
    731656                if ((fat_classify_dentry(d) == FAT_DENTRY_LAST) ||
    732                     (str_cmp((char *) d->name, FAT_NAME_DOT_DOT) == 0)) {
     657                    (bcmp(d->name, FAT_NAME_DOT_DOT, FAT_NAME_LEN) == 0)) {
    733658                        memset(d, 0, sizeof(fat_dentry_t));
    734659                        memcpy(d->name, FAT_NAME_DOT_DOT, FAT_NAME_LEN);
    735660                        memcpy(d->ext, FAT_EXT_PAD, FAT_EXT_LEN);
    736661                        d->attr = FAT_ATTR_SUBDIR;
    737                         d->firstc = (parentp->firstc == FAT_CLST_ROOT) ?
    738                             host2uint16_t_le(FAT_CLST_RES0) :
     662                        d->firstc = (parentp->firstc == FAT_ROOT_CLST(bs)) ?
     663                            host2uint16_t_le(FAT_CLST_ROOTPAR) :
    739664                            host2uint16_t_le(parentp->firstc);
    740665                        /* TODO: initialize also the date/time members. */
     
    750675
    751676        childp->idx->pfc = parentp->firstc;
    752         childp->idx->pdi = i * DPS(bs) + j;
     677        childp->idx->pdi = di.pos;      /* di.pos holds absolute position of SFN entry */
    753678        fibril_mutex_unlock(&childp->idx->lock);
    754679
     
    770695        fat_node_t *parentp = FAT_NODE(pfn);
    771696        fat_node_t *childp = FAT_NODE(cfn);
    772         fat_bs_t *bs;
    773         fat_dentry_t *d;
    774         block_t *b;
    775697        bool has_children;
    776698        int rc;
     
    778700        if (!parentp)
    779701                return EBUSY;
    780        
     702
    781703        rc = fat_has_children(&has_children, cfn);
    782704        if (rc != EOK)
     
    789711        assert(childp->lnkcnt == 1);
    790712        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)
     713       
     714        fat_directory_t di;
     715        rc = fat_directory_open(parentp,&di);
     716        if (rc != EOK)
    797717                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);
     718        rc = fat_directory_seek(&di, childp->idx->pdi);
     719        if (rc != EOK)
     720                goto error;
     721        rc = fat_directory_erase(&di);
     722        if (rc != EOK)
     723                goto error;
     724        rc = fat_directory_close(&di);
    804725        if (rc != EOK)
    805726                goto error;
     
    820741
    821742error:
    822         fibril_mutex_unlock(&parentp->idx->lock);
     743        (void) fat_directory_close(&di);
     744        fibril_mutex_unlock(&childp->idx->lock);
    823745        fibril_mutex_unlock(&childp->lock);
    824         fibril_mutex_unlock(&childp->idx->lock);
     746        fibril_mutex_unlock(&parentp->lock);
    825747        return rc;
    826748}
     
    839761                return EOK;
    840762        }
    841        
     763
    842764        fibril_mutex_lock(&nodep->idx->lock);
    843765        bs = block_bb_get(nodep->idx->service_id);
     
    847769        for (i = 0; i < blocks; i++) {
    848770                fat_dentry_t *d;
    849        
     771
    850772                rc = fat_block_get(&b, bs, nodep, i, BLOCK_FLAGS_NONE);
    851773                if (rc != EOK) {
     
    875797                if (rc != EOK) {
    876798                        fibril_mutex_unlock(&nodep->idx->lock);
    877                         return rc;     
     799                        return rc;
    878800                }
    879801        }
     
    946868        fat_bs_t *bs;
    947869        int rc;
    948        
     870
    949871        /* Check for option enabling write through. */
    950872        if (str_cmp(opts, "wtcache") == 0)
     
    1003925                return ENOMEM;
    1004926        }
     927
    1005928        fs_node_initialize(rfn);
    1006929        fat_node_t *rootp = (fat_node_t *)malloc(sizeof(fat_node_t));
     
    1027950
    1028951        rootp->type = FAT_DIRECTORY;
    1029         rootp->firstc = FAT_CLST_ROOT;
     952        rootp->firstc = FAT_ROOT_CLST(bs);
    1030953        rootp->refcnt = 1;
    1031954        rootp->lnkcnt = 0;      /* FS root is not linked */
    1032         rootp->size = RDE(bs) * sizeof(fat_dentry_t);
     955
     956        if (FAT_IS_FAT32(bs)) {
     957                uint32_t clusters;
     958                rc = fat_clusters_get(&clusters, bs, service_id, rootp->firstc);
     959                if (rc != EOK) {
     960                        free(rfn);
     961                        free(rootp);
     962                        (void) block_cache_fini(service_id);
     963                        block_fini(service_id);
     964                        fat_idx_fini_by_service_id(service_id);
     965                        return ENOTSUP;
     966                }
     967                rootp->size = BPS(bs) * SPC(bs) * clusters;
     968        } else
     969                rootp->size = RDE(bs) * sizeof(fat_dentry_t);
     970
    1033971        rootp->idx = ridxp;
    1034972        ridxp->nodep = rootp;
    1035973        rootp->bp = rfn;
    1036974        rfn->data = rootp;
    1037        
     975
    1038976        fibril_mutex_unlock(&ridxp->lock);
    1039977
     
    10641002                return EBUSY;
    10651003        }
    1066        
     1004
    10671005        /*
    10681006         * Put the root node and force it to the FAT free node list.
     
    11411079                }
    11421080        } else {
    1143                 unsigned bnum;
    11441081                aoff64_t spos = pos;
    1145                 char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
     1082                char name[FAT_LFN_NAME_SIZE];
    11461083                fat_dentry_t *d;
    11471084
     
    11501087                assert(BPS(bs) % sizeof(fat_dentry_t) == 0);
    11511088
    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                 }
     1089                fat_directory_t di;
     1090                rc = fat_directory_open(nodep, &di);
     1091                if (rc != EOK) goto err;
     1092                rc = fat_directory_seek(&di, pos);
     1093                if (rc != EOK) {
     1094                        (void) fat_directory_close(&di);
     1095                        goto err;
     1096                }
     1097
     1098                rc = fat_directory_read(&di, name, &d);
     1099                if (rc == EOK) goto hit;
     1100                if (rc == ENOENT) goto miss;
     1101
     1102err:
     1103                (void) fat_node_put(fn);
     1104                async_answer_0(callid, rc);
     1105                return rc;
     1106
    11931107miss:
     1108                rc = fat_directory_close(&di);
     1109                if (rc!=EOK)
     1110                        goto err;
    11941111                rc = fat_node_put(fn);
    11951112                async_answer_0(callid, rc != EOK ? rc : ENOENT);
     
    11971114                return rc != EOK ? rc : ENOENT;
    11981115
    1199 err:
    1200                 (void) fat_node_put(fn);
    1201                 async_answer_0(callid, rc);
    1202                 return rc;
    1203 
    12041116hit:
     1117                pos = di.pos;
     1118                rc = fat_directory_close(&di);
     1119                if (rc!=EOK)
     1120                        goto err;
    12051121                (void) async_data_read_finalize(callid, name, str_size(name) + 1);
    1206                 bytes = (pos - spos) + 1;
     1122                bytes = (pos - spos)+1;
    12071123        }
    12081124
     
    12311147                return ENOENT;
    12321148        nodep = FAT_NODE(fn);
    1233        
     1149
    12341150        ipc_callid_t callid;
    12351151        size_t len;
     
    12471163         * but this one greatly simplifies fat_write(). Note that we can afford
    12481164         * to do this because the client must be ready to handle the return
    1249          * value signalizing a smaller number of bytes written. 
    1250          */ 
     1165         * value signalizing a smaller number of bytes written.
     1166         */
    12511167        bytes = min(len, BPS(bs) - pos % BPS(bs));
    12521168        if (bytes == BPS(bs))
    12531169                flags |= BLOCK_FLAGS_NOREAD;
    1254        
     1170
    12551171        boundary = ROUND_UP(nodep->size, BPC(bs));
    12561172        if (pos < boundary) {
     
    12951211                 */
    12961212                unsigned nclsts;
    1297                 fat_cluster_t mcl, lcl; 
    1298  
     1213                fat_cluster_t mcl, lcl;
     1214
    12991215                nclsts = (ROUND_UP(pos + bytes, BPC(bs)) - boundary) / BPC(bs);
    13001216                /* create an independent chain of nclsts clusters in all FATs */
     
    13801296                nodep->size = size;
    13811297                nodep->dirty = true;            /* need to sync node */
    1382                 rc = EOK;       
     1298                rc = EOK;
    13831299        } else {
    13841300                /*
     
    14011317                nodep->size = size;
    14021318                nodep->dirty = true;            /* need to sync node */
    1403                 rc = EOK;       
     1319                rc = EOK;
    14041320        }
    14051321out:
     
    14441360        if (!fn)
    14451361                return ENOENT;
    1446        
     1362
    14471363        fat_node_t *nodep = FAT_NODE(fn);
    1448        
     1364
    14491365        nodep->dirty = true;
    14501366        rc = fat_node_sync(nodep);
    1451        
     1367
    14521368        fat_node_put(fn);
    14531369        return rc;
Note: See TracChangeset for help on using the changeset viewer.