diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index 5d597ea..f945c1a 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -19,8 +19,9 @@ jobs: - uses: actions/checkout@v4 - name: before test run: | - sudo apt-get install linux-headers-$(uname -r) - sudo apt-get install xz-utils + sudo apt-get install linux-headers-$(uname -r) xz-utils \ + gcc-mips-linux-gnu qemu-system-mips \ + qemu-user git clone https://github.com/namjaejeon/linux-exfat-oot export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH export PATH=/usr/local/lib:$PATH @@ -30,10 +31,18 @@ jobs: ./configure > /dev/null make -j$((`nproc`+1)) > /dev/null sudo make install > /dev/null + make distclean > /dev/null + ./configure --host=mips-linux-gnu CFLAGS=--static > /dev/null + make -j$((`nproc`+1)) > /dev/null - name: run fsck repair testcases run: | cd tests - sudo ./test_fsck.sh + export FSCK1="qemu-mips ../fsck/fsck.exfat" + export FSCK2="fsck.exfat" + sudo -E ./test_fsck.sh + export FSCK1="fsck.exfat" + export FSCK2="qemu-mips ../fsck/fsck.exfat" + sudo -E ./test_fsck.sh - name: create file/director test run: | cd linux-exfat-oot diff --git a/.travis.yml b/.travis.yml index 2d44bd1..0d5edc9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,8 +6,7 @@ notifications: - email: true before_script: - - sudo apt-get install linux-headers-$(uname -r) - - sudo apt-get install xz-utils + - sudo apt-get install linux-headers-$(uname -r) xz-utils - git clone --branch=exfat-next https://github.com/namjaejeon/exfat_oot - ./.travis_get_mainline_kernel - export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH 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/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 @@ static char *get_rename_from_user(struct exfat_de_iter *iter) } } - 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 @@ int exfat_repair_rename_ask(struct exfat_fsck *fsck, struct exfat_de_iter *iter, " [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/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/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/test_fsck.sh b/tests/test_fsck.sh index 66f4cfb..678b331 100755 --- a/tests/test_fsck.sh +++ b/tests/test_fsck.sh @@ -3,8 +3,8 @@ TESTCASE_DIR=$1 NEED_LOOPDEV=$2 IMAGE_FILE=exfat.img -FSCK_PROG=fsck.exfat -FSCK_PROG_2=fsck.exfat +FSCK_PROG=${FSCK1:-"fsck.exfat"} +FSCK_PROG_2=${FSCK2:-"fsck.exfat"} FSCK_OPTS="-y -s" PASS_COUNT=0 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)