X-Git-Url: https://git.sven.stormbind.net/?p=sven%2Fexfatprogs.git;a=blobdiff_plain;f=fsck%2Ffsck.c;fp=fsck%2Ffsck.c;h=77272aa0bd991c0e1f9ae1b537e22a89eb4d7fa3;hp=cd9ee9a193e344af59482af52256cbe98b4c5896;hb=fa2bd7b968e130b5833bb0bebffda6c14c34de31;hpb=18d68918e6789c8e26d7a44751192f58787e3cd6 diff --git a/fsck/fsck.c b/fsck/fsck.c index cd9ee9a..77272aa 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -103,31 +103,21 @@ static void usage(char *name) }) static int check_clus_chain(struct exfat_de_iter *de_iter, - struct exfat_inode *node) + struct exfat_inode *node) { struct exfat *exfat = de_iter->exfat; struct exfat_dentry *stream_de; - clus_t clus, prev, next, new_clus; + clus_t clus, prev, next; uint64_t count, max_count; - int err; clus = node->first_clus; prev = EXFAT_EOF_CLUSTER; count = 0; max_count = DIV_ROUND_UP(node->size, exfat->clus_size); - if (node->size == 0 && node->first_clus == EXFAT_FREE_CLUSTER) { - /* locate a cluster for the empty dir if the dir starts with EXFAT_FREE_CLUSTER */ - if (node->attr & ATTR_SUBDIR) { - if (repair_file_ask(de_iter, node, - ER_DE_FIRST_CLUS, - "size %#" PRIx64 ", but the first cluster %#x", - node->size, node->first_clus)) - goto allocate_cluster; - return -EINVAL; - } + if (node->size == 0 && node->first_clus == EXFAT_FREE_CLUSTER) return 0; - } + /* the first cluster is wrong */ if ((node->size == 0 && node->first_clus != EXFAT_FREE_CLUSTER) || (node->size > 0 && !exfat_heap_clus(exfat, node->first_clus))) { @@ -225,38 +215,6 @@ static int check_clus_chain(struct exfat_de_iter *de_iter, } return 0; -allocate_cluster: - exfat_de_iter_get_dirty(de_iter, 1, &stream_de); - err = exfat_find_free_cluster(exfat, exfat->start_clu, &new_clus); - if (err) { - exfat->start_clu = EXFAT_FIRST_CLUSTER; - exfat_err("failed to find a free cluster\n"); - return -ENOSPC; - } - exfat->start_clu = new_clus; - - if (exfat_set_fat(exfat, new_clus, EXFAT_EOF_CLUSTER)) - return -EIO; - - /* zero out the new cluster */ - if (exfat_write(exfat->blk_dev->dev_fd, exfat->zero_cluster, - exfat->clus_size, exfat_c2o(exfat, new_clus)) != - (ssize_t)exfat->clus_size) { - exfat_err("failed to fill new cluster with zeroes\n"); - return -EIO; - } - - /* modify the number of cluster form 0 to 1 */ - count = 1; - stream_de->stream_start_clu = cpu_to_le32(new_clus); - stream_de->stream_size = cpu_to_le64(count * exfat->clus_size); - stream_de->stream_valid_size = cpu_to_le64(count * exfat->clus_size); - stream_de->dentry.stream.flags |= EXFAT_SF_CONTIGUOUS; - node->first_clus = new_clus; - node->size = count * exfat->clus_size; - node->is_contiguous = true; - exfat_bitmap_set(exfat->alloc_bitmap, new_clus); - return 1; truncate_file: node->size = count * exfat->clus_size; if (!exfat_heap_clus(exfat, prev)) @@ -677,6 +635,35 @@ static int check_inode(struct exfat_de_iter *iter, struct exfat_inode *node) return valid ? ret : -EINVAL; } +static int handle_duplicated_filename(struct exfat_de_iter *iter, + struct exfat_inode *inode) +{ + 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); + if (ret) + return ret; + + free(filter.out.dentry_set); + + /* Hash is same, but filename is not same */ + 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, + ER_DE_DUPLICATED_NAME, "filename is duplicated"); +} + static int check_name_dentry_set(struct exfat_de_iter *iter, struct exfat_inode *inode) { @@ -707,77 +694,16 @@ static int check_name_dentry_set(struct exfat_de_iter *iter, return -EINVAL; } } - return 0; -} -static int check_bad_char(char w) -{ - return (w < 0x0020) || (w == '*') || (w == '?') || (w == '<') || - (w == '>') || (w == '|') || (w == '"') || (w == ':') || - (w == '/') || (w == '\\'); -} + if (BITMAP_GET(iter->name_hash_bitmap, hash)) { + int ret = handle_duplicated_filename(iter, inode); -static char *get_rename_from_user(struct exfat_de_iter *iter) -{ - char *rename = malloc(ENTRY_NAME_MAX + 2); - - if (!rename) - return NULL; - -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; - 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; - } - } - - exfat_de_iter_flush(iter); - err = exfat_lookup_file(iter->exfat, iter->parent, rename, &filter); - if (!err) { - printf("file(%s) already exists, retry to insert name\n", rename); - goto retry; - } - } - - return rename; -} - -static char *generate_rename(struct exfat_de_iter *iter) -{ - char *rename; - - if (iter->dot_name_num > DOT_NAME_NUM_MAX) - return NULL; - - rename = malloc(ENTRY_NAME_MAX + 1); - if (!rename) - return NULL; - - while (1) { - struct exfat_lookup_filter filter; - int err; - - snprintf(rename, ENTRY_NAME_MAX + 1, "FILE%07d.CHK", - iter->dot_name_num++); - err = exfat_lookup_file(iter->exfat, iter->parent, rename, - &filter); - if (!err) - continue; - break; - } + if (ret) + return ret; + } else + BITMAP_SET(iter->name_hash_bitmap, hash); - return rename; + return 0; } const __le16 MSDOS_DOT[ENTRY_NAME_MAX] = {cpu_to_le16(46), 0, }; @@ -788,8 +714,6 @@ static int handle_dot_dotdot_filename(struct exfat_de_iter *iter, int strm_name_len) { char *filename; - char error_msg[150]; - int num; if (!memcmp(dentry->name_unicode, MSDOS_DOT, strm_name_len * 2)) filename = "."; @@ -799,56 +723,8 @@ static int handle_dot_dotdot_filename(struct exfat_de_iter *iter, else return 0; - sprintf(error_msg, "ERROR: '%s' filename is not allowed.\n" - " [1] Insert the name you want to rename.\n" - " [2] Automatically renames filename.\n" - " [3] Bypass this check(No repair)\n", filename); -ask_again: - num = exfat_repair_ask(&exfat_fsck, ER_DE_DOT_NAME, - error_msg); - if (num) { - __le16 utf16_name[ENTRY_NAME_MAX]; - char *rename = NULL; - __u16 hash; - struct exfat_dentry *stream_de; - int name_len, ret; - - switch (num) { - case 1: - rename = get_rename_from_user(iter); - break; - case 2: - rename = generate_rename(iter); - break; - case 3: - break; - default: - exfat_info("select 1 or 2 number instead of %d\n", num); - goto ask_again; - } - - if (!rename) - return -EINVAL; - - exfat_info("%s filename is renamed to %s\n", filename, 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; - - memcpy(dentry->name_unicode, utf16_name, ENTRY_NAME_MAX * 2); - name_len = exfat_utf16_len(utf16_name, ENTRY_NAME_MAX * 2); - hash = exfat_calc_name_hash(iter->exfat, utf16_name, (int)name_len); - exfat_de_iter_get_dirty(iter, 1, &stream_de); - stream_de->stream_name_len = (__u8)name_len; - stream_de->stream_name_hash = cpu_to_le16(hash); - } - - return 0; + return exfat_repair_rename_ask(&exfat_fsck, iter, filename, + ER_DE_DOT_NAME, "filename is not allowed"); } static int read_file_dentry_set(struct exfat_de_iter *iter, @@ -898,7 +774,7 @@ static int read_file_dentry_set(struct exfat_de_iter *iter, if (!node) return -ENOMEM; - for (i = 2; i <= file_de->file_num_ext; i++) { + for (i = 2; i <= MIN(file_de->file_num_ext, 1 + MAX_NAME_DENTRIES); i++) { ret = exfat_de_iter_get(iter, i, &dentry); if (ret || dentry->type != EXFAT_NAME) { if (i > 2 && repair_file_ask(iter, NULL, ER_DE_NAME, @@ -1004,6 +880,7 @@ static int read_bitmap(struct exfat *exfat) { struct exfat_lookup_filter filter = { .in.type = EXFAT_BITMAP, + .in.dentry_count = 0, .in.filter = NULL, .in.param = NULL, }; @@ -1078,6 +955,7 @@ static int read_upcase_table(struct exfat *exfat) { struct exfat_lookup_filter filter = { .in.type = EXFAT_UPCASE, + .in.dentry_count = 0, .in.filter = NULL, .in.param = NULL, }; @@ -1171,6 +1049,10 @@ static int read_children(struct exfat_fsck *fsck, struct exfat_inode *dir) else if (ret) return ret; + de_iter->name_hash_bitmap = fsck->name_hash_bitmap; + memset(fsck->name_hash_bitmap, 0, + EXFAT_BITMAP_SIZE(EXFAT_MAX_HASH_COUNT)); + while (1) { ret = exfat_de_iter_get(de_iter, 0, &dentry); if (ret == EOF) { @@ -1211,6 +1093,7 @@ static int read_children(struct exfat_fsck *fsck, struct exfat_inode *dir) case EXFAT_VOLUME: case EXFAT_BITMAP: case EXFAT_UPCASE: + case EXFAT_GUID: if (dir == exfat->root) break; /* fallthrough */ @@ -1300,6 +1183,12 @@ static int exfat_filesystem_check(struct exfat_fsck *fsck) return -ENOENT; } + fsck->name_hash_bitmap = malloc(EXFAT_BITMAP_SIZE(EXFAT_MAX_HASH_COUNT)); + if (!fsck->name_hash_bitmap) { + exfat_err("failed to allocate name hash bitmap\n"); + return -ENOMEM; + } + list_add(&exfat->root->list, &exfat->dir_list); while (!list_empty(&exfat->dir_list)) { @@ -1328,6 +1217,7 @@ static int exfat_filesystem_check(struct exfat_fsck *fsck) } out: exfat_free_dir_list(exfat); + free(fsck->name_hash_bitmap); return ret; } @@ -1427,9 +1317,40 @@ static int rescue_orphan_clusters(struct exfat_fsck *fsck) struct exfat_dentry_loc loc; struct exfat_lookup_filter lf = { .in.type = EXFAT_INVAL, + .in.dentry_count = 0, .in.filter = NULL, }; + clu_count = le32_to_cpu(exfat->bs->bsx.clu_count); + + /* find clusters which are not marked as free, but not allocated to + * any files. + */ + disk_b = (bitmap_t *)exfat->disk_bitmap; + alloc_b = (bitmap_t *)exfat->alloc_bitmap; + ohead_b = (bitmap_t *)exfat->ohead_bitmap; + for (i = 0; i < EXFAT_BITMAP_SIZE(clu_count) / sizeof(bitmap_t); i++) + ohead_b[i] = disk_b[i] & ~alloc_b[i]; + + /* no orphan clusters */ + if (exfat_bitmap_find_one(exfat, exfat->ohead_bitmap, + EXFAT_FIRST_CLUSTER, &s_clu)) + return 0; + + err = exfat_create_file(exfat_fsck.exfat, + exfat_fsck.exfat->root, + "LOST+FOUND", + ATTR_SUBDIR); + if (err) { + exfat_err("failed to create LOST+FOUND directory\n"); + return err; + } + + if (fsync(exfat_fsck.exfat->blk_dev->dev_fd) != 0) { + exfat_err("failed to sync()\n"); + return -EIO; + } + err = read_lostfound(exfat, &lostfound); if (err) { exfat_err("failed to find LOST+FOUND\n"); @@ -1455,17 +1376,6 @@ static int rescue_orphan_clusters(struct exfat_fsck *fsck) } dset[1].dentry.stream.flags |= EXFAT_SF_CONTIGUOUS; - clu_count = le32_to_cpu(exfat->bs->bsx.clu_count); - - /* find clusters which are not marked as free, but not allocated to - * any files. - */ - disk_b = (bitmap_t *)exfat->disk_bitmap; - alloc_b = (bitmap_t *)exfat->alloc_bitmap; - ohead_b = (bitmap_t *)exfat->ohead_bitmap; - for (i = 0; i < EXFAT_BITMAP_SIZE(clu_count) / sizeof(bitmap_t); i++) - ohead_b[i] = disk_b[i] & ~alloc_b[i]; - /* create temporary files and allocate contiguous orphan clusters * to each file. */ @@ -1657,23 +1567,6 @@ int main(int argc, char * const argv[]) goto out; } - if (exfat_fsck.options & FSCK_OPTS_RESCUE_CLUS) { - ret = exfat_create_file(exfat_fsck.exfat, - exfat_fsck.exfat->root, - "LOST+FOUND", - ATTR_SUBDIR); - if (ret) { - exfat_err("failed to create lost+found directory\n"); - goto out; - } - - if (fsync(exfat_fsck.exfat->blk_dev->dev_fd) != 0) { - ret = -EIO; - exfat_err("failed to sync()\n"); - goto out; - } - } - exfat_debug("verifying directory entries...\n"); ret = exfat_filesystem_check(&exfat_fsck); if (ret)