From: Sven Hoexter Date: Tue, 13 Aug 2024 09:41:23 +0000 (+0200) Subject: New upstream version 1.2.5 X-Git-Tag: upstream/1.2.5 X-Git-Url: https://git.sven.stormbind.net/?a=commitdiff_plain;h=190baccf7fdd5e22e7d1251d12073d4e241a0363;p=sven%2Fexfatprogs.git New upstream version 1.2.5 --- diff --git a/Makefile.am b/Makefile.am index 3e36f55..51c2c34 100644 --- a/Makefile.am +++ b/Makefile.am @@ -16,6 +16,7 @@ dist_man8_MANS = \ # other stuff EXTRA_DIST = \ include \ + tests \ Android.bp \ lib/Android.bp \ mkfs/Android.bp \ diff --git a/Makefile.in b/Makefile.in index 914c23f..3186b63 100644 --- a/Makefile.in +++ b/Makefile.in @@ -374,6 +374,7 @@ dist_man8_MANS = \ # other stuff EXTRA_DIST = \ include \ + tests \ Android.bp \ lib/Android.bp \ mkfs/Android.bp \ diff --git a/NEWS b/NEWS index 072344e..ffbbdc1 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,24 @@ +exfatprogs 1.2.5 - released 2024-08-06 +====================================== + +CHANGES : + * exfatprogs: remove the limitation that the device + path length cannot exceed 254 bytes. + * exfatprogs: include the test images in the release + package. + +NEW FEATURES : + * fsck.exfat: check and repair the filename which has + invalid characters. + +BUG FIXES : + * tune.exfat: check whether the volume has invalid + characters correctly. + * fsck.exfat: check whether the filename and volume + has invalid characters correctly. + * fsck.exfat: fix endianess issues which happen + in the big-endian system. + exfatprogs 1.2.4 - released 2024-06-17 ====================================== diff --git a/configure b/configure index f1e6d79..8e6d08b 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for exfatprogs 1.2.4. +# Generated by GNU Autoconf 2.69 for exfatprogs 1.2.5. # # Report bugs to . # @@ -590,8 +590,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='exfatprogs' PACKAGE_TARNAME='exfatprogs' -PACKAGE_VERSION='1.2.4' -PACKAGE_STRING='exfatprogs 1.2.4' +PACKAGE_VERSION='1.2.5' +PACKAGE_STRING='exfatprogs 1.2.5' PACKAGE_BUGREPORT='linkinjeon@kernel.org' PACKAGE_URL='https://github.com/exfatprogs/exfatprogs' @@ -1325,7 +1325,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures exfatprogs 1.2.4 to adapt to many kinds of systems. +\`configure' configures exfatprogs 1.2.5 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1396,7 +1396,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of exfatprogs 1.2.4:";; + short | recursive ) echo "Configuration of exfatprogs 1.2.5:";; esac cat <<\_ACEOF @@ -1508,7 +1508,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -exfatprogs configure 1.2.4 +exfatprogs configure 1.2.5 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1786,7 +1786,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by exfatprogs $as_me 1.2.4, which was +It was created by exfatprogs $as_me 1.2.5, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2654,7 +2654,7 @@ fi # Define the identity of the package. PACKAGE='exfatprogs' - VERSION='1.2.4' + VERSION='1.2.5' cat >>confdefs.h <<_ACEOF @@ -13253,7 +13253,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by exfatprogs $as_me 1.2.4, which was +This file was extended by exfatprogs $as_me 1.2.5, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -13320,7 +13320,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -exfatprogs config.status 1.2.4 +exfatprogs config.status 1.2.5 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/dump/dump.c b/dump/dump.c index 73a231a..e15e195 100644 --- a/dump/dump.c +++ b/dump/dump.c @@ -244,11 +244,10 @@ int main(int argc, char *argv[]) if (version_only) exit(EXIT_FAILURE); - if (argc < 2) + if (argc - optind != 1) usage(); - memset(ui.dev_name, 0, sizeof(ui.dev_name)); - snprintf(ui.dev_name, sizeof(ui.dev_name), "%s", argv[1]); + ui.dev_name = argv[1]; ret = exfat_get_blk_dev_info(&ui, &bd); if (ret < 0) diff --git a/exfat2img/exfat2img.c b/exfat2img/exfat2img.c index bd9db44..e75b42f 100644 --- a/exfat2img/exfat2img.c +++ b/exfat2img/exfat2img.c @@ -926,7 +926,7 @@ int main(int argc, char * const argv[]) } memset(&ui, 0, sizeof(ui)); - snprintf(ui.dev_name, sizeof(ui.dev_name), "%s", blkdev_path); + ui.dev_name = blkdev_path; if (restore) ui.writeable = true; else diff --git a/fsck/fsck.c b/fsck/fsck.c index fe8a122..48e64cd 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -647,7 +647,6 @@ static int handle_duplicated_filename(struct exfat_de_iter *iter, { int ret; struct exfat_lookup_filter filter; - char filename[PATH_MAX + 1] = {0}; ret = exfat_lookup_file_by_utf16name(iter->exfat, iter->parent, inode->name, &filter); @@ -660,14 +659,7 @@ static int handle_duplicated_filename(struct exfat_de_iter *iter, if (exfat_de_iter_device_offset(iter) == filter.out.dev_offset) return 0; - ret = exfat_utf16_dec(inode->name, NAME_BUFFER_SIZE, filename, - PATH_MAX); - if (ret < 0) { - exfat_err("failed to decode filename\n"); - return ret; - } - - return exfat_repair_rename_ask(&exfat_fsck, iter, filename, + return exfat_repair_rename_ask(&exfat_fsck, iter, inode->name, ER_DE_DUPLICATED_NAME, "filename is duplicated"); } @@ -682,7 +674,7 @@ static int check_name_dentry_set(struct exfat_de_iter *iter, exfat_de_iter_get(iter, 1, &stream_de); name_len = exfat_utf16_len(inode->name, NAME_BUFFER_SIZE); - if (stream_de->stream_name_len != name_len) { + if (name_len && stream_de->stream_name_len != name_len) { if (repair_file_ask(iter, NULL, ER_DE_NAME_LEN, "the name length of a file is wrong")) { exfat_de_iter_get_dirty(iter, 1, &stream_de); @@ -693,6 +685,18 @@ static int check_name_dentry_set(struct exfat_de_iter *iter, } } + ret = exfat_check_name(inode->name, stream_de->stream_name_len); + if (ret != stream_de->stream_name_len) { + char err_msg[36]; + + snprintf(err_msg, sizeof(err_msg), + "filename has invalid character '%c'", + le16_to_cpu(inode->name[ret])); + + return exfat_repair_rename_ask(&exfat_fsck, iter, inode->name, + ER_DE_INVALID_NAME, err_msg); + } + hash = exfat_calc_name_hash(iter->exfat, inode->name, (int)name_len); if (cpu_to_le16(hash) != stream_de->stream_name_hash) { if (repair_file_ask(iter, NULL, ER_DE_NAME_HASH, @@ -713,21 +717,18 @@ static int check_name_dentry_set(struct exfat_de_iter *iter, return ret; } -const __le16 MSDOS_DOT[ENTRY_NAME_MAX] = {cpu_to_le16(46), 0, }; -const __le16 MSDOS_DOTDOT[ENTRY_NAME_MAX] = {cpu_to_le16(46), cpu_to_le16(46), 0, }; - static int handle_dot_dotdot_filename(struct exfat_de_iter *iter, - struct exfat_dentry *dentry, + __le16 *filename, int strm_name_len) { - char *filename; + int i; - if (!memcmp(dentry->name_unicode, MSDOS_DOT, strm_name_len * 2)) - filename = "."; - else if (!memcmp(dentry->name_unicode, MSDOS_DOTDOT, - strm_name_len * 2)) - filename = ".."; - else + for (i = 0; i < strm_name_len; i++) { + if (filename[i] != UTF16_DOT) + return 0; + } + + if (filename[i]) return 0; return exfat_repair_rename_ask(&exfat_fsck, iter, filename, @@ -817,7 +818,7 @@ static int read_file_dentry_set(struct exfat_de_iter *iter, } if (file_de->file_num_ext == 2 && stream_de->stream_name_len <= 2) { - ret = handle_dot_dotdot_filename(iter, dentry, + ret = handle_dot_dotdot_filename(iter, node->name, stream_de->stream_name_len); if (ret < 0) { *skip_dentries = file_de->file_num_ext + 1; @@ -1005,7 +1006,7 @@ static int read_bitmap(struct exfat *exfat) exfat->disk_bitmap_size = DIV_ROUND_UP(exfat->clus_count, 8); exfat_bitmap_set_range(exfat, exfat->alloc_bitmap, - le64_to_cpu(dentry->bitmap_start_clu), + le32_to_cpu(dentry->bitmap_start_clu), DIV_ROUND_UP(exfat->disk_bitmap_size, exfat->clus_size)); free(filter.out.dentry_set); @@ -1034,9 +1035,8 @@ static int decompress_upcase_table(const __le16 *in_table, size_t in_len, ch = le16_to_cpu(in_table[i]); if (ch == 0xFFFF && i + 1 < in_len) { - uint16_t len = le16_to_cpu(in_table[++i]); - - k += len; + ++i; + k += le16_to_cpu(in_table[i]); } else { out_table[k++] = ch; } @@ -1616,7 +1616,7 @@ int main(int argc, char * const argv[]) exfat_fsck.options = ui.options; - snprintf(ui.ei.dev_name, sizeof(ui.ei.dev_name), "%s", argv[optind]); + ui.ei.dev_name = argv[optind]; ret = exfat_get_blk_dev_info(&ui.ei, &bd); if (ret < 0) { exfat_err("failed to open %s. %d\n", ui.ei.dev_name, ret); diff --git a/fsck/repair.c b/fsck/repair.c index 6179b65..420b1fb 100644 --- a/fsck/repair.c +++ b/fsck/repair.c @@ -55,6 +55,7 @@ static struct exfat_repair_problem problems[] = { {ER_DE_NAME_LEN, ERF_PREEN_YES, ERP_FIX, 0, 0, 0}, {ER_DE_DOT_NAME, ERF_PREEN_YES, ERP_RENAME, 2, 3, 4}, {ER_DE_DUPLICATED_NAME, ERF_PREEN_YES, ERP_RENAME, 2, 3, 4}, + {ER_DE_INVALID_NAME, ERF_PREEN_YES, ERP_RENAME, 2, 3, 4}, {ER_FILE_VALID_SIZE, ERF_PREEN_YES, ERP_FIX, 0, 0, 0}, {ER_FILE_INVALID_CLUS, ERF_PREEN_YES, ERP_TRUNCATE, 0, 0, 0}, {ER_FILE_FIRST_CLUS, ERF_PREEN_YES, ERP_TRUNCATE, 0, 0, 0}, @@ -160,36 +161,37 @@ int exfat_repair_ask(struct exfat_fsck *fsck, er_problem_code_t prcode, return repair; } -static int check_bad_char(char w) -{ - return (w < 0x0020) || (w == '*') || (w == '?') || (w == '<') || - (w == '>') || (w == '|') || (w == '"') || (w == ':') || - (w == '/') || (w == '\\'); -} - -static char *get_rename_from_user(struct exfat_de_iter *iter) +static int get_rename_from_user(struct exfat_de_iter *iter, + __le16 *utf16_name, int name_size) { + int len = 0; char *rename = malloc(ENTRY_NAME_MAX + 2); if (!rename) - return NULL; + return -ENOMEM; retry: /* +2 means LF(Line Feed) and NULL terminator */ memset(rename, 0x1, ENTRY_NAME_MAX + 2); printf("New name: "); if (fgets(rename, ENTRY_NAME_MAX + 2, stdin)) { - int i, len, err; + int err; struct exfat_lookup_filter filter; len = strlen(rename); /* Remove LF in filename */ rename[len - 1] = '\0'; - for (i = 0; i < len - 1; i++) { - if (check_bad_char(rename[i])) { - printf("filename contain invalid character(%c)\n", rename[i]); - goto retry; - } + + memset(utf16_name, 0, name_size); + len = exfat_utf16_enc(rename, utf16_name, name_size); + if (len < 0) + goto out; + + err = exfat_check_name(utf16_name, len >> 1); + if (err != len >> 1) { + printf("filename contain invalid character(%c)\n", + le16_to_cpu(utf16_name[err])); + goto retry; } exfat_de_iter_flush(iter); @@ -200,23 +202,27 @@ retry: } } - return rename; +out: + free(rename); + + return len; } -static char *generate_rename(struct exfat_de_iter *iter) +static int generate_rename(struct exfat_de_iter *iter, __le16 *utf16_name, + int name_size) { + int err; char *rename; if (iter->invalid_name_num > INVALID_NAME_NUM_MAX) - return NULL; + return -ERANGE; rename = malloc(ENTRY_NAME_MAX + 1); if (!rename) - return NULL; + return -ENOMEM; while (1) { struct exfat_lookup_filter filter; - int err; snprintf(rename, ENTRY_NAME_MAX + 1, "FILE%07d.CHK", iter->invalid_name_num++); @@ -227,13 +233,23 @@ static char *generate_rename(struct exfat_de_iter *iter) break; } - return rename; + memset(utf16_name, 0, name_size); + err = exfat_utf16_enc(rename, utf16_name, name_size); + free(rename); + + return err; } int exfat_repair_rename_ask(struct exfat_fsck *fsck, struct exfat_de_iter *iter, - char *old_name, er_problem_code_t prcode, char *error_msg) + __le16 *uname, er_problem_code_t prcode, char *error_msg) { int num; + char old_name[PATH_MAX + 1] = {0}; + + if (exfat_utf16_dec(uname, NAME_BUFFER_SIZE, old_name, PATH_MAX) <= 0) { + exfat_err("failed to decode filename\n"); + return -EINVAL; + } ask_again: num = exfat_repair_ask(fsck, prcode, "ERROR: '%s' %s.\n%s", @@ -243,38 +259,31 @@ ask_again: " [3] Bypass this check(No repair)\n"); if (num) { __le16 utf16_name[ENTRY_NAME_MAX]; - char *rename = NULL; __u16 hash; struct exfat_dentry *dentry; int ret; switch (num) { case 1: - rename = get_rename_from_user(iter); + ret = get_rename_from_user(iter, utf16_name, + sizeof(utf16_name)); break; case 2: - rename = generate_rename(iter); + ret = generate_rename(iter, utf16_name, + sizeof(utf16_name)); break; case 3: - break; + return -EINVAL; default: exfat_info("select 1 or 2 number instead of %d\n", num); goto ask_again; } - if (!rename) + if (ret < 0) return -EINVAL; - exfat_info("%s filename is renamed to %s\n", old_name, rename); - exfat_de_iter_get_dirty(iter, 2, &dentry); - memset(utf16_name, 0, sizeof(utf16_name)); - ret = exfat_utf16_enc(rename, utf16_name, sizeof(utf16_name)); - free(rename); - if (ret < 0) - return ret; - ret >>= 1; memcpy(dentry->name_unicode, utf16_name, ENTRY_NAME_MAX * 2); hash = exfat_calc_name_hash(iter->exfat, utf16_name, ret); diff --git a/fsck/repair.h b/fsck/repair.h index f1cde24..2d46b8e 100644 --- a/fsck/repair.h +++ b/fsck/repair.h @@ -19,6 +19,7 @@ #define ER_DE_NAME_LEN 0x00001032 #define ER_DE_DOT_NAME 0x00001033 #define ER_DE_DUPLICATED_NAME 0x00001034 +#define ER_DE_INVALID_NAME 0x00001035 #define ER_FILE_VALID_SIZE 0x00002001 #define ER_FILE_INVALID_CLUS 0x00002002 #define ER_FILE_FIRST_CLUS 0x00002003 @@ -35,5 +36,5 @@ int exfat_repair_ask(struct exfat_fsck *fsck, er_problem_code_t prcode, const char *fmt, ...); int exfat_repair_rename_ask(struct exfat_fsck *fsck, struct exfat_de_iter *iter, - char *old_name, er_problem_code_t prcode, char *error_msg); + __le16 *uname, er_problem_code_t prcode, char *error_msg); #endif diff --git a/include/exfat_ondisk.h b/include/exfat_ondisk.h index 2137226..636f5ea 100644 --- a/include/exfat_ondisk.h +++ b/include/exfat_ondisk.h @@ -7,23 +7,29 @@ #define _EXFAT_H #include +#include #include #ifdef HAVE_CONFIG_H #include #endif +#define UTF16_NULL 0x0000 + #ifdef WORDS_BIGENDIAN -#define cpu_to_le16(x) ((((x) >> 8) & 0xffu) | (((x) & 0xffu) << 8)) -#define cpu_to_le32(x) \ - ((((x) & 0xff000000u) >> 24) | (((x) & 0x00ff0000u) >> 8) | \ - (((x) & 0x0000ff00u) << 8) | (((x) & 0x000000ffu) << 24)) -#define cpu_to_le64(x) (cpu_to_le32((uint64_t)(x)) << 32 | \ - cpu_to_le32((uint64_t)(x) >> 32)) +#define cpu_to_le16(x) bswap_16(x) +#define cpu_to_le32(x) bswap_32(x) +#define cpu_to_le64(x) bswap_64(x) + +#define UTF16_DOT 0x2E00 /* . */ +#define UTF16_SLASH 0x2F00 /* / */ #else #define cpu_to_le16(x) (x) #define cpu_to_le32(x) (x) #define cpu_to_le64(x) (x) + +#define UTF16_DOT 0x002E /* . */ +#define UTF16_SLASH 0x002F /* / */ #endif #define le64_to_cpu(x) ((uint64_t)cpu_to_le64(x)) diff --git a/include/libexfat.h b/include/libexfat.h index 2ed9aa7..bcab23a 100644 --- a/include/libexfat.h +++ b/include/libexfat.h @@ -78,7 +78,7 @@ struct exfat_blk_dev { }; struct exfat_user_input { - char dev_name[255]; + const char *dev_name; bool writeable; unsigned int sector_size; unsigned int cluster_size; @@ -190,6 +190,7 @@ bool exfat_heap_clus(struct exfat *exfat, clus_t clus); int exfat_root_clus_count(struct exfat *exfat); int read_boot_sect(struct exfat_blk_dev *bdev, struct pbr **bs); int exfat_parse_ulong(const char *s, unsigned long *out); +int exfat_check_name(__le16 *utf16_name, int len); /* * Exfat Print diff --git a/include/version.h b/include/version.h index 31f150e..e324363 100644 --- a/include/version.h +++ b/include/version.h @@ -5,6 +5,6 @@ #ifndef _VERSION_H -#define EXFAT_PROGS_VERSION "1.2.4" +#define EXFAT_PROGS_VERSION "1.2.5" #endif /* !_VERSION_H */ diff --git a/label/label.c b/label/label.c index 2780143..12d027b 100644 --- a/label/label.c +++ b/label/label.c @@ -78,11 +78,10 @@ int main(int argc, char *argv[]) if (version_only) exit(EXIT_FAILURE); - if (argc < 2) + if (argc - optind != 1) usage(); - memset(ui.dev_name, 0, sizeof(ui.dev_name)); - snprintf(ui.dev_name, sizeof(ui.dev_name), "%s", argv[serial_mode + 1]); + ui.dev_name = argv[serial_mode + 1]; ret = exfat_get_blk_dev_info(&ui, &bd); if (ret < 0) diff --git a/lib/exfat_dir.c b/lib/exfat_dir.c index 7b99af1..f6e0d01 100644 --- a/lib/exfat_dir.c +++ b/lib/exfat_dir.c @@ -577,7 +577,6 @@ uint16_t exfat_calc_name_hash(struct exfat *exfat, for (i = 0; i < len; i++) { ch = exfat->upcase_table[le16_to_cpu(name[i])]; - ch = cpu_to_le16(ch); /* use += to avoid promotion to int; UBSan complaints about signed overflow */ chksum = (chksum << 15) | (chksum >> 1); @@ -692,7 +691,7 @@ int exfat_update_file_dentry_set(struct exfat *exfat, dset[1].dentry.stream.name_len = (__u8)name_len; dset[1].dentry.stream.name_hash = - exfat_calc_name_hash(exfat, utf16_name, name_len); + cpu_to_le16(exfat_calc_name_hash(exfat, utf16_name, name_len)); for (i = 2; i < dcount; i++) { dset[i].type = EXFAT_NAME; diff --git a/lib/exfat_fs.c b/lib/exfat_fs.c index b24f532..ee87bb1 100644 --- a/lib/exfat_fs.c +++ b/lib/exfat_fs.c @@ -249,8 +249,6 @@ int exfat_resolve_path(struct path_resolve_ctx *ctx, struct exfat_inode *child) int depth, i; int name_len; __le16 *utf16_path; - static const __le16 utf16_slash = cpu_to_le16(0x002F); - static const __le16 utf16_null = cpu_to_le16(0x0000); size_t in_size; ctx->local_path[0] = '\0'; @@ -268,13 +266,13 @@ int exfat_resolve_path(struct path_resolve_ctx *ctx, struct exfat_inode *child) memcpy((char *)utf16_path, (char *)ctx->ancestors[i]->name, name_len * 2); utf16_path += name_len; - memcpy((char *)utf16_path, &utf16_slash, sizeof(utf16_slash)); + *utf16_path = UTF16_SLASH; utf16_path++; } if (depth > 1) utf16_path--; - memcpy((char *)utf16_path, &utf16_null, sizeof(utf16_null)); + *utf16_path = UTF16_NULL; utf16_path++; in_size = (utf16_path - ctx->utf16_path) * sizeof(__le16); diff --git a/lib/libexfat.c b/lib/libexfat.c index 9cc184f..6d45358 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -496,12 +496,20 @@ int exfat_set_volume_label(struct exfat *exfat, char *label_input) volume_label, sizeof(volume_label)); if (volume_label_len < 0) { exfat_err("failed to encode volume label\n"); - free(pvol); - return -1; + err = -1; + goto out; } - memcpy(pvol->vol_label, volume_label, volume_label_len); pvol->vol_char_cnt = volume_label_len/2; + err = exfat_check_name(volume_label, pvol->vol_char_cnt); + if (err != pvol->vol_char_cnt) { + exfat_err("volume label contain invalid character(%c)\n", + le16_to_cpu(label_input[err])); + err = -1; + goto out; + } + + memcpy(pvol->vol_label, volume_label, volume_label_len); loc.parent = exfat->root; loc.file_offset = filter.out.file_offset; @@ -509,6 +517,7 @@ int exfat_set_volume_label(struct exfat *exfat, char *label_input) err = exfat_add_dentry_set(exfat, &loc, pvol, dcount, false); exfat_info("new label: %s\n", label_input); +out: free(pvol); return err; @@ -759,7 +768,7 @@ int exfat_show_volume_serial(int fd) goto free_ppbr; } - exfat_info("volume serial : 0x%x\n", ppbr->bsx.vol_serial); + exfat_info("volume serial : 0x%x\n", le32_to_cpu(ppbr->bsx.vol_serial)); free_ppbr: free(ppbr); @@ -919,6 +928,8 @@ int exfat_set_fat(struct exfat *exfat, clus_t clus, clus_t next_clus) exfat->bs->bsx.sect_size_bits; offset += sizeof(clus_t) * clus; + next_clus = cpu_to_le32(next_clus); + if (exfat_write(exfat->blk_dev->dev_fd, &next_clus, sizeof(next_clus), offset) != sizeof(next_clus)) return -EIO; @@ -1058,3 +1069,22 @@ int exfat_parse_ulong(const char *s, unsigned long *out) return 0; } + +static inline int check_bad_utf16_char(unsigned short w) +{ + return (w < 0x0020) || (w == '*') || (w == '?') || (w == '<') || + (w == '>') || (w == '|') || (w == '"') || (w == ':') || + (w == '/') || (w == '\\'); +} + +int exfat_check_name(__le16 *utf16_name, int len) +{ + int i; + + for (i = 0; i < len; i++) { + if (check_bad_utf16_char(le16_to_cpu(utf16_name[i]))) + break; + } + + return i; +} diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index f9286c1..71f2b10 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -737,8 +737,7 @@ int main(int argc, char *argv[]) goto out; } - memset(ui.dev_name, 0, sizeof(ui.dev_name)); - snprintf(ui.dev_name, sizeof(ui.dev_name), "%s", argv[optind]); + ui.dev_name = argv[optind]; ret = exfat_get_blk_dev_info(&ui, &bd); if (ret < 0) diff --git a/tests/2tb_disk/exfat.img.tar.xz b/tests/2tb_disk/exfat.img.tar.xz new file mode 100644 index 0000000..f979bde Binary files /dev/null and b/tests/2tb_disk/exfat.img.tar.xz differ diff --git a/tests/bad_bitmap/exfat.img.tar.xz b/tests/bad_bitmap/exfat.img.tar.xz new file mode 100644 index 0000000..df09d10 Binary files /dev/null and b/tests/bad_bitmap/exfat.img.tar.xz differ diff --git a/tests/bad_dentries/exfat.img.tar.xz b/tests/bad_dentries/exfat.img.tar.xz new file mode 100644 index 0000000..32643ca Binary files /dev/null and b/tests/bad_dentries/exfat.img.tar.xz differ diff --git a/tests/bad_dentries2/exfat.img.tar.xz b/tests/bad_dentries2/exfat.img.tar.xz new file mode 100644 index 0000000..f266741 Binary files /dev/null and b/tests/bad_dentries2/exfat.img.tar.xz differ diff --git a/tests/bad_file_size/exfat.img.tar.xz b/tests/bad_file_size/exfat.img.tar.xz new file mode 100644 index 0000000..df7ff14 Binary files /dev/null and b/tests/bad_file_size/exfat.img.tar.xz differ diff --git a/tests/bad_first_clu/exfat.img.tar.xz b/tests/bad_first_clu/exfat.img.tar.xz new file mode 100644 index 0000000..3dc29ec Binary files /dev/null and b/tests/bad_first_clu/exfat.img.tar.xz differ diff --git a/tests/bad_num_chain/config b/tests/bad_num_chain/config new file mode 100644 index 0000000..f62cec1 --- /dev/null +++ b/tests/bad_num_chain/config @@ -0,0 +1 @@ +#OPTS: -s diff --git a/tests/bad_num_chain/exfat.img.tar.xz b/tests/bad_num_chain/exfat.img.tar.xz new file mode 100644 index 0000000..68b8605 Binary files /dev/null and b/tests/bad_num_chain/exfat.img.tar.xz differ diff --git a/tests/bad_root/exfat.img.tar.xz b/tests/bad_root/exfat.img.tar.xz new file mode 100644 index 0000000..de0066f Binary files /dev/null and b/tests/bad_root/exfat.img.tar.xz differ diff --git a/tests/bs_bad_csum/exfat.img.tar.xz b/tests/bs_bad_csum/exfat.img.tar.xz new file mode 100644 index 0000000..cbcc5c0 Binary files /dev/null and b/tests/bs_bad_csum/exfat.img.tar.xz differ diff --git a/tests/de_bad_csum/exfat.img.tar.xz b/tests/de_bad_csum/exfat.img.tar.xz new file mode 100644 index 0000000..f753e82 Binary files /dev/null and b/tests/de_bad_csum/exfat.img.tar.xz differ diff --git a/tests/duplicate_clu/exfat.img.tar.xz b/tests/duplicate_clu/exfat.img.tar.xz new file mode 100644 index 0000000..bf3fdd8 Binary files /dev/null and b/tests/duplicate_clu/exfat.img.tar.xz differ diff --git a/tests/duplicated_name/exfat.img.tar.xz b/tests/duplicated_name/exfat.img.tar.xz new file mode 100644 index 0000000..ceb046f Binary files /dev/null and b/tests/duplicated_name/exfat.img.tar.xz differ diff --git a/tests/file_invalid_clus/exfat.img.tar.xz b/tests/file_invalid_clus/exfat.img.tar.xz new file mode 100644 index 0000000..830edf2 Binary files /dev/null and b/tests/file_invalid_clus/exfat.img.tar.xz differ diff --git a/tests/invalid_name/exfat.img.tar.xz b/tests/invalid_name/exfat.img.tar.xz new file mode 100644 index 0000000..d274028 Binary files /dev/null and b/tests/invalid_name/exfat.img.tar.xz differ diff --git a/tests/large_file_invalid_clus/exfat.img.tar.xz b/tests/large_file_invalid_clus/exfat.img.tar.xz new file mode 100644 index 0000000..5e3dbef Binary files /dev/null and b/tests/large_file_invalid_clus/exfat.img.tar.xz differ diff --git a/tests/loop_chain/config b/tests/loop_chain/config new file mode 100644 index 0000000..f62cec1 --- /dev/null +++ b/tests/loop_chain/config @@ -0,0 +1 @@ +#OPTS: -s diff --git a/tests/loop_chain/exfat.img.tar.xz b/tests/loop_chain/exfat.img.tar.xz new file mode 100644 index 0000000..c863cdd Binary files /dev/null and b/tests/loop_chain/exfat.img.tar.xz differ diff --git a/tests/rename_dot_entry/exfat.img.tar.xz b/tests/rename_dot_entry/exfat.img.tar.xz new file mode 100644 index 0000000..6e50a72 Binary files /dev/null and b/tests/rename_dot_entry/exfat.img.tar.xz differ diff --git a/tests/test_fsck.sh b/tests/test_fsck.sh new file mode 100755 index 0000000..678b331 --- /dev/null +++ b/tests/test_fsck.sh @@ -0,0 +1,88 @@ +#!/usr/bin/env bash + +TESTCASE_DIR=$1 +NEED_LOOPDEV=$2 +IMAGE_FILE=exfat.img +FSCK_PROG=${FSCK1:-"fsck.exfat"} +FSCK_PROG_2=${FSCK2:-"fsck.exfat"} +FSCK_OPTS="-y -s" +PASS_COUNT=0 + +cleanup() { + echo "" + echo "Passed ${PASS_COUNT} of ${TEST_COUNT}" + if [ ${PASS_COUNT} -ne ${TEST_COUNT} ]; then + exit 1 + else + exit 0 + fi +} + +if [ $# -eq 0 ]; then + TESTCASE_DIRS=$(find . -mindepth 1 -maxdepth 1 -type d) + TEST_COUNT=$(find . -mindepth 1 -maxdepth 1 -type d | wc -l) +else + TESTCASE_DIRS=$@ + TEST_COUNT=$# +fi + +for TESTCASE_DIR in $TESTCASE_DIRS; do + if [ ! -e "${TESTCASE_DIR}/${IMAGE_FILE}.tar.xz" ]; then + TEST_COUNT=$((TEST_COUNT - 1)) + continue + fi + + echo "Running ${TESTCASE_DIR}" + echo "-----------------------------------" + + # Set up image file as loop device + tar -C . -xf "${TESTCASE_DIR}/${IMAGE_FILE}.tar.xz" + if [ $NEED_LOOPDEV ]; then + DEV_FILE=$(losetup -f "${IMAGE_FILE}" --show) + else + DEV_FILE=$IMAGE_FILE + fi + + # Run fsck to detect corruptions + $FSCK_PROG "$DEV_FILE" | grep -q "ERROR:\|corrupted" + if [ $? -ne 0 ]; then + echo "" + echo "Failed to detect corruption for ${TESTCASE_DIR}" + if [ $NEED_LOOPDEV ]; then + losetup -d "${DEV_FILE}" + fi + cleanup + fi + + # Run fsck for repair + $FSCK_PROG $FSCK_OPTS "$DEV_FILE" + if [ $? -ne 1 ] && [ $? -ne 0 ]; then + echo "" + echo "Failed to repair ${TESTCASE_DIR}" + if [ $NEED_LOOPDEV ]; then + losetup -d "${DEV_FILE}" + fi + cleanup + fi + + echo "" + # Run fsck again + $FSCK_PROG_2 "$DEV_FILE" + if [ $? -ne 0 ]; then + echo "" + echo "Failed, corrupted ${TESTCASE_DIR}" + if [ $NEED_LOOPDEV ]; then + losetup -d "${DEV_FILE}" + fi + cleanup + fi + + echo "" + echo "Passed ${TESTCASE_DIR}" + PASS_COUNT=$((PASS_COUNT + 1)) + + if [ $NEED_LOOPDEV ]; then + losetup -d "${DEV_FILE}" + fi +done +cleanup diff --git a/tune/tune.c b/tune/tune.c index 4966e0a..8a4b934 100644 --- a/tune/tune.c +++ b/tune/tune.c @@ -115,11 +115,10 @@ int main(int argc, char *argv[]) if (version_only) exit(EXIT_FAILURE); - if (argc < 3) + if (argc < 3 || argc - optind != 1) usage(); - memset(ui.dev_name, 0, sizeof(ui.dev_name)); - snprintf(ui.dev_name, sizeof(ui.dev_name), "%s", argv[argc - 1]); + ui.dev_name = argv[argc - 1]; ret = exfat_get_blk_dev_info(&ui, &bd); if (ret < 0)