diff options
Diffstat (limited to '')
-rw-r--r-- | fsck/fsck.c | 54 | ||||
-rw-r--r-- | fsck/repair.c | 79 | ||||
-rw-r--r-- | fsck/repair.h | 3 |
3 files changed, 73 insertions, 63 deletions
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 |