]> git.sven.stormbind.net Git - sven/exfatprogs.git/commitdiff
New upstream version 1.2.5 upstream/1.2.5
authorSven Hoexter <sven@stormbind.net>
Tue, 13 Aug 2024 09:41:23 +0000 (11:41 +0200)
committerSven Hoexter <sven@stormbind.net>
Tue, 13 Aug 2024 09:41:23 +0000 (11:41 +0200)
38 files changed:
Makefile.am
Makefile.in
NEWS
configure
dump/dump.c
exfat2img/exfat2img.c
fsck/fsck.c
fsck/repair.c
fsck/repair.h
include/exfat_ondisk.h
include/libexfat.h
include/version.h
label/label.c
lib/exfat_dir.c
lib/exfat_fs.c
lib/libexfat.c
mkfs/mkfs.c
tests/2tb_disk/exfat.img.tar.xz [new file with mode: 0644]
tests/bad_bitmap/exfat.img.tar.xz [new file with mode: 0644]
tests/bad_dentries/exfat.img.tar.xz [new file with mode: 0644]
tests/bad_dentries2/exfat.img.tar.xz [new file with mode: 0644]
tests/bad_file_size/exfat.img.tar.xz [new file with mode: 0644]
tests/bad_first_clu/exfat.img.tar.xz [new file with mode: 0644]
tests/bad_num_chain/config [new file with mode: 0644]
tests/bad_num_chain/exfat.img.tar.xz [new file with mode: 0644]
tests/bad_root/exfat.img.tar.xz [new file with mode: 0644]
tests/bs_bad_csum/exfat.img.tar.xz [new file with mode: 0644]
tests/de_bad_csum/exfat.img.tar.xz [new file with mode: 0644]
tests/duplicate_clu/exfat.img.tar.xz [new file with mode: 0644]
tests/duplicated_name/exfat.img.tar.xz [new file with mode: 0644]
tests/file_invalid_clus/exfat.img.tar.xz [new file with mode: 0644]
tests/invalid_name/exfat.img.tar.xz [new file with mode: 0644]
tests/large_file_invalid_clus/exfat.img.tar.xz [new file with mode: 0644]
tests/loop_chain/config [new file with mode: 0644]
tests/loop_chain/exfat.img.tar.xz [new file with mode: 0644]
tests/rename_dot_entry/exfat.img.tar.xz [new file with mode: 0644]
tests/test_fsck.sh [new file with mode: 0755]
tune/tune.c

index 3e36f55a096b1fc348ea9dd86060a184666eda4d..51c2c34dd28a378ce58a4f181f6d918b09f0abb7 100644 (file)
@@ -16,6 +16,7 @@ dist_man8_MANS =              \
 # other stuff
 EXTRA_DIST =                   \
        include                 \
+       tests                   \
        Android.bp              \
        lib/Android.bp          \
        mkfs/Android.bp         \
index 914c23f45edfda10f1b5070936f2bb61e7944fe4..3186b63cf6060b7285a79dbea68ce94876043bfb 100644 (file)
@@ -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 072344e10c7fbf67d4e37af3e2fa0761528f4ae5..ffbbdc14a238112139c45873515c1e61768c96d9 100644 (file)
--- 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
 ======================================
 
index f1e6d79700a610d23bdf740493f5d2f658b5eb7d..8e6d08bb69ee5d890b59d689f150b8c4aa1cb934 100755 (executable)
--- 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 <linkinjeon@kernel.org>.
 #
@@ -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\\"
 
index 73a231ab2c9e367837ae49b87833f098819c44f9..e15e195da8ef555e4141be2e5ebd6193751874f9 100644 (file)
@@ -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)
index bd9db444ca82bdea9561d8e2e67bbf1a8d31798b..e75b42f3ec986e562dd28001c6a74a2b1a16d14c 100644 (file)
@@ -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
index fe8a1220649b65057ecf0de32eb65a33411de9c3..48e64cdfa51ec3080229cb54e8ba41d282f21c29 100644 (file)
@@ -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);
index 6179b65e32157c7c61f646dec058be499226e5e8..420b1fb87eda65af54f59ad532b19351e9c186f3 100644 (file)
@@ -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);
index f1cde24dd5684d95ab793c1ebeba0542ec694705..2d46b8ea53b0257a3b1032d6bcbdc140d1f867fc 100644 (file)
@@ -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
index 21372266a3382f5da409dc7e09d076481a6a29a1..636f5ea59307f920d5a87bcc22da8921d06ebd64 100644 (file)
@@ -7,23 +7,29 @@
 #define _EXFAT_H
 
 #include <stdint.h>
+#include <byteswap.h>
 #include <linux/fs.h>
 
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #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))
index 2ed9aa719bbdb384586019cb8cbbfa1a2d9e9172..bcab23a24bf40a25e1bd8d36d8eee686e28159d0 100644 (file)
@@ -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
index 31f150eebe25d228278ff09cc7e0d95ba66fc4d9..e3243634980b85a145fcc01813a69c267a1d3491 100644 (file)
@@ -5,6 +5,6 @@
 
 #ifndef _VERSION_H
 
-#define EXFAT_PROGS_VERSION "1.2.4"
+#define EXFAT_PROGS_VERSION "1.2.5"
 
 #endif /* !_VERSION_H */
index 278014334aa3ce1021e4580b3bc854ec04c871c7..12d027be27f8b7f08bb73cf16de6dc1577f3d8a6 100644 (file)
@@ -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)
index 7b99af114c48cc5b6cbba2618b29085b836491f5..f6e0d0129cc57fe85b05ea82cf822676c5b302f0 100644 (file)
@@ -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;
index b24f5321b9b9d88dcfb85d5d815d64e6d73c7449..ee87bb1f7efe15572df39efdafaf3b77be2a370a 100644 (file)
@@ -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);
index 9cc184fbdd327ca37d2ecea6897330291e12cada..6d4535846599dbe283c7103c268dee521e96a5bc 100644 (file)
@@ -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;
+}
index f9286c1d159e92fe7f8bc3682cf1241abeaf4764..71f2b1045d21deb4b44eaa5779449d3cff7b6a0c 100644 (file)
@@ -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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
index 0000000..f62cec1
--- /dev/null
@@ -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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
index 0000000..f62cec1
--- /dev/null
@@ -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 (file)
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 (file)
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 (executable)
index 0000000..678b331
--- /dev/null
@@ -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
index 4966e0a1783a1815e8d0aef61ab0613f584e2155..8a4b934fc6370cd74e796aedcd07161da3374b57 100644 (file)
@@ -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)