summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-08-26 10:36:08 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-08-26 10:36:08 +0000
commitf1b69cec3c86b1a52a8cc8980d139105c08518a9 (patch)
tree375566cab235df08966d399e21d0238a0ddc9bd1
parentAdding upstream version 1.2.4. (diff)
downloadexfatprogs-f1b69cec3c86b1a52a8cc8980d139105c08518a9.tar.xz
exfatprogs-f1b69cec3c86b1a52a8cc8980d139105c08518a9.zip
Adding upstream version 1.2.5.upstream/1.2.5upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
-rw-r--r--Makefile.am1
-rw-r--r--Makefile.in1
-rw-r--r--NEWS21
-rwxr-xr-xconfigure20
-rw-r--r--dump/dump.c5
-rw-r--r--exfat2img/exfat2img.c2
-rw-r--r--fsck/fsck.c54
-rw-r--r--fsck/repair.c79
-rw-r--r--fsck/repair.h3
-rw-r--r--include/exfat_ondisk.h18
-rw-r--r--include/libexfat.h3
-rw-r--r--include/version.h2
-rw-r--r--label/label.c5
-rw-r--r--lib/exfat_dir.c3
-rw-r--r--lib/exfat_fs.c6
-rw-r--r--lib/libexfat.c38
-rw-r--r--mkfs/mkfs.c3
-rw-r--r--tests/2tb_disk/exfat.img.tar.xzbin0 -> 13368 bytes
-rw-r--r--tests/bad_bitmap/exfat.img.tar.xzbin0 -> 4056 bytes
-rw-r--r--tests/bad_dentries/exfat.img.tar.xzbin0 -> 9628 bytes
-rw-r--r--tests/bad_dentries2/exfat.img.tar.xzbin0 -> 9724 bytes
-rw-r--r--tests/bad_file_size/exfat.img.tar.xzbin0 -> 4052 bytes
-rw-r--r--tests/bad_first_clu/exfat.img.tar.xzbin0 -> 3232 bytes
-rw-r--r--tests/bad_num_chain/config1
-rw-r--r--tests/bad_num_chain/exfat.img.tar.xzbin0 -> 4064 bytes
-rw-r--r--tests/bad_root/exfat.img.tar.xzbin0 -> 4528 bytes
-rw-r--r--tests/bs_bad_csum/exfat.img.tar.xzbin0 -> 3036 bytes
-rw-r--r--tests/de_bad_csum/exfat.img.tar.xzbin0 -> 3196 bytes
-rw-r--r--tests/duplicate_clu/exfat.img.tar.xzbin0 -> 4048 bytes
-rw-r--r--tests/duplicated_name/exfat.img.tar.xzbin0 -> 3940 bytes
-rw-r--r--tests/file_invalid_clus/exfat.img.tar.xzbin0 -> 3392 bytes
-rw-r--r--tests/invalid_name/exfat.img.tar.xzbin0 -> 4444 bytes
-rw-r--r--tests/large_file_invalid_clus/exfat.img.tar.xzbin0 -> 17280 bytes
-rw-r--r--tests/loop_chain/config1
-rw-r--r--tests/loop_chain/exfat.img.tar.xzbin0 -> 4052 bytes
-rw-r--r--tests/rename_dot_entry/exfat.img.tar.xzbin0 -> 7336 bytes
-rwxr-xr-xtests/test_fsck.sh88
-rw-r--r--tune/tune.c5
38 files changed, 256 insertions, 103 deletions
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 <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\\"
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 <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))
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
--- /dev/null
+++ b/tests/2tb_disk/exfat.img.tar.xz
Binary files 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
--- /dev/null
+++ b/tests/bad_bitmap/exfat.img.tar.xz
Binary files 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
--- /dev/null
+++ b/tests/bad_dentries/exfat.img.tar.xz
Binary files 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
--- /dev/null
+++ b/tests/bad_dentries2/exfat.img.tar.xz
Binary files 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
--- /dev/null
+++ b/tests/bad_file_size/exfat.img.tar.xz
Binary files 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
--- /dev/null
+++ b/tests/bad_first_clu/exfat.img.tar.xz
Binary files 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
--- /dev/null
+++ b/tests/bad_num_chain/exfat.img.tar.xz
Binary files 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
--- /dev/null
+++ b/tests/bad_root/exfat.img.tar.xz
Binary files 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
--- /dev/null
+++ b/tests/bs_bad_csum/exfat.img.tar.xz
Binary files 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
--- /dev/null
+++ b/tests/de_bad_csum/exfat.img.tar.xz
Binary files 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
--- /dev/null
+++ b/tests/duplicate_clu/exfat.img.tar.xz
Binary files 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
--- /dev/null
+++ b/tests/duplicated_name/exfat.img.tar.xz
Binary files 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
--- /dev/null
+++ b/tests/file_invalid_clus/exfat.img.tar.xz
Binary files 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
--- /dev/null
+++ b/tests/invalid_name/exfat.img.tar.xz
Binary files 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
--- /dev/null
+++ b/tests/large_file_invalid_clus/exfat.img.tar.xz
Binary files 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
--- /dev/null
+++ b/tests/loop_chain/exfat.img.tar.xz
Binary files 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
--- /dev/null
+++ b/tests/rename_dot_entry/exfat.img.tar.xz
Binary files 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)