]> git.sven.stormbind.net Git - sven/exfatprogs.git/blobdiff - fsck/fsck.c
releasing package exfatprogs version 1.2.3-1
[sven/exfatprogs.git] / fsck / fsck.c
index cd9ee9a193e344af59482af52256cbe98b4c5896..fe8a1220649b65057ecf0de32eb65a33411de9c3 100644 (file)
@@ -102,32 +102,22 @@ static void usage(char *name)
                                 exfat_de_iter_device_offset(iter));    \
 })
 
                                 exfat_de_iter_device_offset(iter));    \
 })
 
-static int check_clus_chain(struct exfat_de_iter *de_iter,
-                               struct exfat_inode *node)
+static int check_clus_chain(struct exfat_de_iter *de_iter, int stream_idx,
+                           struct exfat_inode *node)
 {
        struct exfat *exfat = de_iter->exfat;
        struct exfat_dentry *stream_de;
 {
        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;
        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);
 
 
        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;
                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))) {
        /* 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,45 +215,13 @@ static int check_clus_chain(struct exfat_de_iter *de_iter,
        }
 
        return 0;
        }
 
        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))
                node->first_clus = EXFAT_FREE_CLUSTER;
 
 truncate_file:
        node->size = count * exfat->clus_size;
        if (!exfat_heap_clus(exfat, prev))
                node->first_clus = EXFAT_FREE_CLUSTER;
 
-       exfat_de_iter_get_dirty(de_iter, 1, &stream_de);
-       if (count * exfat->clus_size <
+       exfat_de_iter_get_dirty(de_iter, stream_idx, &stream_de);
+       if (stream_idx == 1 && count * exfat->clus_size <
            le64_to_cpu(stream_de->stream_valid_size))
                stream_de->stream_valid_size = cpu_to_le64(
                                                           count * exfat->clus_size);
            le64_to_cpu(stream_de->stream_valid_size))
                stream_de->stream_valid_size = cpu_to_le64(
                                                           count * exfat->clus_size);
@@ -413,9 +371,10 @@ static int read_boot_region(struct exfat_blk_dev *bd, struct pbr **pbr,
 {
        struct pbr *bs;
        int ret = -EINVAL;
 {
        struct pbr *bs;
        int ret = -EINVAL;
+       unsigned long long clu_max_count;
 
        *pbr = NULL;
 
        *pbr = NULL;
-       bs = (struct pbr *)malloc(sizeof(struct pbr));
+       bs = malloc(sizeof(struct pbr));
        if (!bs) {
                exfat_err("failed to allocate memory\n");
                return -ENOMEM;
        if (!bs) {
                exfat_err("failed to allocate memory\n");
                return -ENOMEM;
@@ -476,12 +435,13 @@ static int read_boot_region(struct exfat_blk_dev *bd, struct pbr **pbr,
                goto err;
        }
 
                goto err;
        }
 
-       if (le32_to_cpu(bs->bsx.clu_count) * EXFAT_CLUSTER_SIZE(bs) >
-                       bd->size) {
+       clu_max_count = (le64_to_cpu(bs->bsx.vol_length) - le32_to_cpu(bs->bsx.clu_offset)) >>
+                               bs->bsx.sect_per_clus_bits;
+       if (le32_to_cpu(bs->bsx.clu_count) > clu_max_count) {
                if (verbose)
                if (verbose)
-                       exfat_err("too large cluster count: %u, expected: %u\n",
+                       exfat_err("too large cluster count: %u, expected: %llu\n",
                                  le32_to_cpu(bs->bsx.clu_count),
                                  le32_to_cpu(bs->bsx.clu_count),
-                                 bd->num_clusters);
+                                 MIN(clu_max_count, EXFAT_MAX_NUM_CLUSTER));
                goto err;
        }
 
                goto err;
        }
 
@@ -607,21 +567,24 @@ restore:
        return ret;
 }
 
        return ret;
 }
 
-static uint16_t file_calc_checksum(struct exfat_de_iter *iter)
+static int file_calc_checksum(struct exfat_de_iter *iter, uint16_t *checksum)
 {
 {
-       uint16_t checksum;
        struct exfat_dentry *file_de, *de;
        struct exfat_dentry *file_de, *de;
-       int i;
+       int i, ret;
 
 
-       checksum = 0;
-       exfat_de_iter_get(iter, 0, &file_de);
+       *checksum = 0;
+       ret = exfat_de_iter_get(iter, 0, &file_de);
+       if (ret)
+               return ret;
 
 
-       exfat_calc_dentry_checksum(file_de, &checksum, true);
+       exfat_calc_dentry_checksum(file_de, checksum, true);
        for (i = 1; i <= file_de->file_num_ext; i++) {
        for (i = 1; i <= file_de->file_num_ext; i++) {
-               exfat_de_iter_get(iter, i, &de);
-               exfat_calc_dentry_checksum(de, &checksum, false);
+               ret = exfat_de_iter_get(iter, i, &de);
+               if (ret)
+                       return ret;
+               exfat_calc_dentry_checksum(de, checksum, false);
        }
        }
-       return checksum;
+       return 0;
 }
 
 /*
 }
 
 /*
@@ -636,7 +599,7 @@ static int check_inode(struct exfat_de_iter *iter, struct exfat_inode *node)
        uint16_t checksum;
        bool valid = true;
 
        uint16_t checksum;
        bool valid = true;
 
-       ret = check_clus_chain(iter, node);
+       ret = check_clus_chain(iter, 1, node);
        if (ret < 0)
                return ret;
 
        if (ret < 0)
                return ret;
 
@@ -666,7 +629,9 @@ static int check_inode(struct exfat_de_iter *iter, struct exfat_inode *node)
                valid = false;
        }
 
                valid = false;
        }
 
-       checksum = file_calc_checksum(iter);
+       ret = file_calc_checksum(iter, &checksum);
+       if (ret)
+               return ret;
        exfat_de_iter_get(iter, 0, &dentry);
        if (checksum != le16_to_cpu(dentry->file_checksum)) {
                exfat_de_iter_get_dirty(iter, 0, &dentry);
        exfat_de_iter_get(iter, 0, &dentry);
        if (checksum != le16_to_cpu(dentry->file_checksum)) {
                exfat_de_iter_get_dirty(iter, 0, &dentry);
@@ -677,12 +642,42 @@ static int check_inode(struct exfat_de_iter *iter, struct exfat_inode *node)
        return valid ? ret : -EINVAL;
 }
 
        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)
 {
        struct exfat_dentry *stream_de;
        size_t name_len;
        __u16 hash;
 static int check_name_dentry_set(struct exfat_de_iter *iter,
                                 struct exfat_inode *inode)
 {
        struct exfat_dentry *stream_de;
        size_t name_len;
        __u16 hash;
+       int ret = 0;
 
        exfat_de_iter_get(iter, 1, &stream_de);
 
 
        exfat_de_iter_get(iter, 1, &stream_de);
 
@@ -692,6 +687,7 @@ static int check_name_dentry_set(struct exfat_de_iter *iter,
                                    "the name length of a file is wrong")) {
                        exfat_de_iter_get_dirty(iter, 1, &stream_de);
                        stream_de->stream_name_len = (__u8)name_len;
                                    "the name length of a file is wrong")) {
                        exfat_de_iter_get_dirty(iter, 1, &stream_de);
                        stream_de->stream_name_len = (__u8)name_len;
+                       ret = 1;
                } else {
                        return -EINVAL;
                }
                } else {
                        return -EINVAL;
                }
@@ -703,81 +699,18 @@ static int check_name_dentry_set(struct exfat_de_iter *iter,
                                    "the name hash of a file is wrong")) {
                        exfat_de_iter_get_dirty(iter, 1, &stream_de);
                        stream_de->stream_name_hash = cpu_to_le16(hash);
                                    "the name hash of a file is wrong")) {
                        exfat_de_iter_get_dirty(iter, 1, &stream_de);
                        stream_de->stream_name_hash = cpu_to_le16(hash);
+                       ret = 1;
                } else {
                        return -EINVAL;
                }
        }
                } else {
                        return -EINVAL;
                }
        }
-       return 0;
-}
 
 
-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)
-{
-       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;
-                       }
-               }
+       if (BITMAP_GET(iter->name_hash_bitmap, hash)) {
+               ret = handle_duplicated_filename(iter, inode);
+       } else
+               BITMAP_SET(iter->name_hash_bitmap, hash);
 
 
-               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;
-       }
-
-       return rename;
+       return ret;
 }
 
 const __le16 MSDOS_DOT[ENTRY_NAME_MAX] = {cpu_to_le16(46), 0, };
 }
 
 const __le16 MSDOS_DOT[ENTRY_NAME_MAX] = {cpu_to_le16(46), 0, };
@@ -788,8 +721,6 @@ static int handle_dot_dotdot_filename(struct exfat_de_iter *iter,
                                      int strm_name_len)
 {
        char *filename;
                                      int strm_name_len)
 {
        char *filename;
-       char error_msg[150];
-       int num;
 
        if (!memcmp(dentry->name_unicode, MSDOS_DOT, strm_name_len * 2))
                filename = ".";
 
        if (!memcmp(dentry->name_unicode, MSDOS_DOT, strm_name_len * 2))
                filename = ".";
@@ -799,56 +730,8 @@ static int handle_dot_dotdot_filename(struct exfat_de_iter *iter,
        else
                return 0;
 
        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,
 }
 
 static int read_file_dentry_set(struct exfat_de_iter *iter,
@@ -856,8 +739,8 @@ static int read_file_dentry_set(struct exfat_de_iter *iter,
 {
        struct exfat_dentry *file_de, *stream_de, *dentry;
        struct exfat_inode *node = NULL;
 {
        struct exfat_dentry *file_de, *stream_de, *dentry;
        struct exfat_inode *node = NULL;
-       int i, ret;
-       bool need_delete = false;
+       int i, j, ret, name_de_count;
+       bool need_delete = false, need_copy_up = false;
        uint16_t checksum;
 
        ret = exfat_de_iter_get(iter, 0, &file_de);
        uint16_t checksum;
 
        ret = exfat_de_iter_get(iter, 0, &file_de);
@@ -866,10 +749,11 @@ static int read_file_dentry_set(struct exfat_de_iter *iter,
                return -EINVAL;
        }
 
                return -EINVAL;
        }
 
-       checksum = file_calc_checksum(iter);
-       if (checksum != le16_to_cpu(file_de->file_checksum)) {
+       ret = file_calc_checksum(iter, &checksum);
+       if (ret || checksum != le16_to_cpu(file_de->file_checksum)) {
                if (repair_file_ask(iter, NULL, ER_DE_CHECKSUM,
                if (repair_file_ask(iter, NULL, ER_DE_CHECKSUM,
-                                   "the checksum of a file is wrong"))
+                                   "the checksum %#x of a file is wrong, expected: %#x",
+                                   le16_to_cpu(file_de->file_checksum), checksum))
                        need_delete = true;
                *skip_dentries = 1;
                goto skip_dset;
                        need_delete = true;
                *skip_dentries = 1;
                goto skip_dset;
@@ -898,17 +782,22 @@ static int read_file_dentry_set(struct exfat_de_iter *iter,
        if (!node)
                return -ENOMEM;
 
        if (!node)
                return -ENOMEM;
 
-       for (i = 2; i <= file_de->file_num_ext; i++) {
+       name_de_count = DIV_ROUND_UP(stream_de->stream_name_len, ENTRY_NAME_MAX);
+       for (i = 2; i <= MIN(name_de_count + 1, file_de->file_num_ext); i++) {
                ret = exfat_de_iter_get(iter, i, &dentry);
                if (ret || dentry->type != EXFAT_NAME) {
                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,
-                                                    "failed to get name dentry")) {
-                               exfat_de_iter_get_dirty(iter, 0, &file_de);
-                               file_de->file_num_ext = i - 1;
+                       if (repair_file_ask(iter, NULL, ER_DE_NAME,
+                                           "failed to get name dentry")) {
+                               if (i == 2) {
+                                       need_delete = 1;
+                                       *skip_dentries = i + 1;
+                                       goto skip_dset;
+                               }
                                break;
                                break;
+                       } else {
+                               *skip_dentries = i + 1;
+                               goto skip_dset;
                        }
                        }
-                       *skip_dentries = i + 1;
-                       goto skip_dset;
                }
 
                memcpy(node->name +
                }
 
                memcpy(node->name +
@@ -917,9 +806,14 @@ static int read_file_dentry_set(struct exfat_de_iter *iter,
        }
 
        ret = check_name_dentry_set(iter, node);
        }
 
        ret = check_name_dentry_set(iter, node);
-       if (ret) {
+       if (ret < 0) {
                *skip_dentries = file_de->file_num_ext + 1;
                goto skip_dset;
                *skip_dentries = file_de->file_num_ext + 1;
                goto skip_dset;
+       } else if (ret) {
+               exfat_de_iter_get(iter, 1, &stream_de);
+               if (DIV_ROUND_UP(stream_de->stream_name_len, ENTRY_NAME_MAX) !=
+                   name_de_count)
+                       i = DIV_ROUND_UP(stream_de->stream_name_len, ENTRY_NAME_MAX) + 2;
        }
 
        if (file_de->file_num_ext == 2 && stream_de->stream_name_len <= 2) {
        }
 
        if (file_de->file_num_ext == 2 && stream_de->stream_name_len <= 2) {
@@ -931,6 +825,69 @@ static int read_file_dentry_set(struct exfat_de_iter *iter,
                }
        }
 
                }
        }
 
+       for (j = i; i <= file_de->file_num_ext; i++) {
+               exfat_de_iter_get(iter, i, &dentry);
+               if (dentry->type == EXFAT_VENDOR_EXT ||
+                   dentry->type == EXFAT_VENDOR_ALLOC) {
+                       char zeroes[EXFAT_GUID_LEN] = {0};
+                       /*
+                        * Vendor GUID should not be zero, But Windows fsck
+                        * also does not check and fix it.
+                        */
+                       if (!memcmp(dentry->dentry.vendor_ext.guid,
+                                   zeroes, EXFAT_GUID_LEN))
+                               repair_file_ask(iter, NULL, ER_VENDOR_GUID,
+                                               "Vendor Extension has zero filled GUID");
+                       if (dentry->type == EXFAT_VENDOR_ALLOC) {
+                               struct exfat_inode *vendor_node;
+
+                               /* verify cluster chain */
+                               vendor_node = exfat_alloc_inode(0);
+                               if (!vendor_node) {
+                                       *skip_dentries = i + i;
+                                       goto skip_dset;
+                               }
+                               vendor_node->first_clus =
+                                       le32_to_cpu(dentry->dentry.vendor_alloc.start_clu);
+                               vendor_node->is_contiguous = ((dentry->dentry.vendor_alloc.flags
+                                                              & EXFAT_SF_CONTIGUOUS) != 0);
+                               vendor_node->size =
+                                       le64_to_cpu(dentry->dentry.vendor_alloc.size);
+                               if (check_clus_chain(iter, i, vendor_node) < 0) {
+                                       exfat_free_inode(vendor_node);
+                                       *skip_dentries = i + 1;
+                                       goto skip_dset;
+                               }
+                               if (vendor_node->size == 0 &&
+                                   vendor_node->is_contiguous) {
+                                       exfat_de_iter_get_dirty(iter, i, &dentry);
+                                       dentry->stream_flags &= ~EXFAT_SF_CONTIGUOUS;
+
+                               }
+                               exfat_free_inode(vendor_node);
+                       }
+
+                       if (need_copy_up) {
+                               struct exfat_dentry *src_de;
+
+                               exfat_de_iter_get_dirty(iter, j, &src_de);
+                               memcpy(src_de, dentry, sizeof(struct exfat_dentry));
+                       }
+                       j++;
+               } else {
+                       if (need_copy_up) {
+                               continue;
+                       } else if (repair_file_ask(iter, NULL, ER_DE_UNKNOWN,
+                                                 "unknown entry type %#x", dentry->type)) {
+                               j = i;
+                               need_copy_up = true;
+                       } else {
+                               *skip_dentries = i + 1;
+                               goto skip_dset;
+                       }
+               }
+       }
+
        node->first_clus = le32_to_cpu(stream_de->stream_start_clu);
        node->is_contiguous =
                ((stream_de->stream_flags & EXFAT_SF_CONTIGUOUS) != 0);
        node->first_clus = le32_to_cpu(stream_de->stream_start_clu);
        node->is_contiguous =
                ((stream_de->stream_flags & EXFAT_SF_CONTIGUOUS) != 0);
@@ -951,6 +908,18 @@ static int read_file_dentry_set(struct exfat_de_iter *iter,
                }
        }
 
                }
        }
 
+       if (file_de->file_num_ext != j - 1) {
+               if (repair_file_ask(iter, node, ER_DE_SECONDARY_COUNT,
+                                   "SecondaryCount %d is different with %d",
+                                   file_de->file_num_ext, j - 1)) {
+                       exfat_de_iter_get_dirty(iter, 0, &file_de);
+                       file_de->file_num_ext = j - 1;
+               } else {
+                       *skip_dentries = file_de->file_num_ext + 1;
+                       goto skip_dset;
+               }
+       }
+
        *skip_dentries = (file_de->file_num_ext + 1);
        *new_node = node;
        return 0;
        *skip_dentries = (file_de->file_num_ext + 1);
        *new_node = node;
        return 0;
@@ -1004,6 +973,7 @@ static int read_bitmap(struct exfat *exfat)
 {
        struct exfat_lookup_filter filter = {
                .in.type        = EXFAT_BITMAP,
 {
        struct exfat_lookup_filter filter = {
                .in.type        = EXFAT_BITMAP,
+               .in.dentry_count = 0,
                .in.filter      = NULL,
                .in.param       = NULL,
        };
                .in.filter      = NULL,
                .in.param       = NULL,
        };
@@ -1078,6 +1048,7 @@ static int read_upcase_table(struct exfat *exfat)
 {
        struct exfat_lookup_filter filter = {
                .in.type        = EXFAT_UPCASE,
 {
        struct exfat_lookup_filter filter = {
                .in.type        = EXFAT_UPCASE,
+               .in.dentry_count = 0,
                .in.filter      = NULL,
                .in.param       = NULL,
        };
                .in.filter      = NULL,
                .in.param       = NULL,
        };
@@ -1109,7 +1080,7 @@ static int read_upcase_table(struct exfat *exfat)
                goto out;
        }
 
                goto out;
        }
 
-       upcase = (__le16 *)malloc(size);
+       upcase = malloc(size);
        if (!upcase) {
                exfat_err("failed to allocate upcase table\n");
                retval = -ENOMEM;
        if (!upcase) {
                exfat_err("failed to allocate upcase table\n");
                retval = -ENOMEM;
@@ -1138,8 +1109,7 @@ static int read_upcase_table(struct exfat *exfat)
                               DIV_ROUND_UP(le64_to_cpu(dentry->upcase_size),
                                            exfat->clus_size));
 
                               DIV_ROUND_UP(le64_to_cpu(dentry->upcase_size),
                                            exfat->clus_size));
 
-       exfat->upcase_table = calloc(1,
-                                    sizeof(uint16_t) * EXFAT_UPCASE_TABLE_CHARS);
+       exfat->upcase_table = calloc(EXFAT_UPCASE_TABLE_CHARS, sizeof(uint16_t));
        if (!exfat->upcase_table) {
                retval = -EIO;
                goto out;
        if (!exfat->upcase_table) {
                retval = -EIO;
                goto out;
@@ -1171,6 +1141,10 @@ static int read_children(struct exfat_fsck *fsck, struct exfat_inode *dir)
        else if (ret)
                return ret;
 
        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) {
        while (1) {
                ret = exfat_de_iter_get(de_iter, 0, &dentry);
                if (ret == EOF) {
@@ -1211,6 +1185,7 @@ static int read_children(struct exfat_fsck *fsck, struct exfat_inode *dir)
                case EXFAT_VOLUME:
                case EXFAT_BITMAP:
                case EXFAT_UPCASE:
                case EXFAT_VOLUME:
                case EXFAT_BITMAP:
                case EXFAT_UPCASE:
+               case EXFAT_GUID:
                        if (dir == exfat->root)
                                break;
                        /* fallthrough */
                        if (dir == exfat->root)
                                break;
                        /* fallthrough */
@@ -1218,9 +1193,7 @@ static int read_children(struct exfat_fsck *fsck, struct exfat_inode *dir)
                        if (IS_EXFAT_DELETED(dentry->type))
                                break;
                        if (repair_file_ask(de_iter, NULL, ER_DE_UNKNOWN,
                        if (IS_EXFAT_DELETED(dentry->type))
                                break;
                        if (repair_file_ask(de_iter, NULL, ER_DE_UNKNOWN,
-                                           "unknown entry type %#x at %07" PRIx64,
-                                           dentry->type,
-                                           exfat_de_iter_file_offset(de_iter))) {
+                                           "unknown entry type %#x", dentry->type)) {
                                struct exfat_dentry *dentry;
 
                                exfat_de_iter_get_dirty(de_iter, 0, &dentry);
                                struct exfat_dentry *dentry;
 
                                exfat_de_iter_get_dirty(de_iter, 0, &dentry);
@@ -1300,6 +1273,12 @@ static int exfat_filesystem_check(struct exfat_fsck *fsck)
                return -ENOENT;
        }
 
                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)) {
        list_add(&exfat->root->list, &exfat->dir_list);
 
        while (!list_empty(&exfat->dir_list)) {
@@ -1328,6 +1307,7 @@ static int exfat_filesystem_check(struct exfat_fsck *fsck)
        }
 out:
        exfat_free_dir_list(exfat);
        }
 out:
        exfat_free_dir_list(exfat);
+       free(fsck->name_hash_bitmap);
        return ret;
 }
 
        return ret;
 }
 
@@ -1358,7 +1338,6 @@ static int exfat_root_dir_check(struct exfat *exfat)
        err = exfat_read_volume_label(exfat);
        if (err && err != EOF)
                exfat_err("failed to read volume label\n");
        err = exfat_read_volume_label(exfat);
        if (err && err != EOF)
                exfat_err("failed to read volume label\n");
-       err = 0;
 
        err = read_bitmap(exfat);
        if (err) {
 
        err = read_bitmap(exfat);
        if (err) {
@@ -1427,9 +1406,40 @@ static int rescue_orphan_clusters(struct exfat_fsck *fsck)
        struct exfat_dentry_loc loc;
        struct exfat_lookup_filter lf = {
                .in.type = EXFAT_INVAL,
        struct exfat_dentry_loc loc;
        struct exfat_lookup_filter lf = {
                .in.type = EXFAT_INVAL,
+               .in.dentry_count = 0,
                .in.filter = NULL,
        };
 
                .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");
        err = read_lostfound(exfat, &lostfound);
        if (err) {
                exfat_err("failed to find LOST+FOUND\n");
@@ -1455,17 +1465,6 @@ static int rescue_orphan_clusters(struct exfat_fsck *fsck)
        }
        dset[1].dentry.stream.flags |= EXFAT_SF_CONTIGUOUS;
 
        }
        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.
         */
        /* create temporary files and allocate contiguous orphan clusters
         * to each file.
         */
@@ -1636,9 +1635,7 @@ int main(int argc, char * const argv[])
                goto err;
        }
 
                goto err;
        }
 
-       exfat_fsck.buffer_desc = exfat_alloc_buffer(2,
-                                                   exfat_fsck.exfat->clus_size,
-                                                   exfat_fsck.exfat->sect_size);
+       exfat_fsck.buffer_desc = exfat_alloc_buffer(exfat_fsck.exfat);
        if (!exfat_fsck.buffer_desc) {
                ret = -ENOMEM;
                goto err;
        if (!exfat_fsck.buffer_desc) {
                ret = -ENOMEM;
                goto err;
@@ -1657,23 +1654,6 @@ int main(int argc, char * const argv[])
                goto out;
        }
 
                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)
        exfat_debug("verifying directory entries...\n");
        ret = exfat_filesystem_check(&exfat_fsck);
        if (ret)
@@ -1715,7 +1695,7 @@ err:
                exit_code = FSCK_EXIT_NO_ERRORS;
 
        if (exfat_fsck.buffer_desc)
                exit_code = FSCK_EXIT_NO_ERRORS;
 
        if (exfat_fsck.buffer_desc)
-               exfat_free_buffer(exfat_fsck.buffer_desc, 2);
+               exfat_free_buffer(exfat_fsck.exfat, exfat_fsck.buffer_desc);
        if (exfat_fsck.exfat)
                exfat_free_exfat(exfat_fsck.exfat);
        close(bd.dev_fd);
        if (exfat_fsck.exfat)
                exfat_free_exfat(exfat_fsck.exfat);
        close(bd.dev_fd);