+#define repair_file_ask(iter, inode, code, fmt, ...) \
+({ \
+ resolve_path_parent(&path_resolve_ctx, \
+ (iter)->parent, inode); \
+ exfat_repair_ask((iter)->exfat, code, \
+ "ERROR: %s: " fmt, \
+ path_resolve_ctx.local_path, \
+ ##__VA_ARGS__); \
+})
+
+static inline bool heap_clus(struct exfat *exfat, clus_t clus)
+{
+ return clus >= EXFAT_FIRST_CLUSTER &&
+ (clus - EXFAT_FIRST_CLUSTER) < exfat->clus_count;
+}
+
+int get_next_clus(struct exfat *exfat, struct exfat_inode *node,
+ clus_t clus, clus_t *next)
+{
+ off_t offset;
+
+ *next = EXFAT_EOF_CLUSTER;
+
+ if (!heap_clus(exfat, clus))
+ return -EINVAL;
+
+ if (node->is_contiguous) {
+ *next = clus + 1;
+ return 0;
+ }
+
+ offset = (off_t)le32_to_cpu(exfat->bs->bsx.fat_offset) <<
+ exfat->bs->bsx.sect_size_bits;
+ offset += sizeof(clus_t) * clus;
+
+ if (exfat_read(exfat->blk_dev->dev_fd, next, sizeof(*next), offset)
+ != sizeof(*next))
+ return -EIO;
+ *next = le32_to_cpu(*next);
+ return 0;
+}
+
+static int set_fat(struct exfat *exfat, clus_t clus, clus_t next_clus)
+{
+ off_t offset;
+
+ offset = le32_to_cpu(exfat->bs->bsx.fat_offset) <<
+ exfat->bs->bsx.sect_size_bits;
+ offset += sizeof(clus_t) * clus;
+
+ if (exfat_write(exfat->blk_dev->dev_fd, &next_clus, sizeof(next_clus),
+ offset) != sizeof(next_clus))
+ return -EIO;
+ return 0;
+}
+
+static int check_clus_chain(struct exfat *exfat, struct exfat_inode *node)
+{
+ struct exfat_dentry *stream_de;
+ clus_t clus, prev, next;
+ uint64_t count, max_count;
+
+ 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)
+ return 0;
+
+ /* the first cluster is wrong */
+ if ((node->size == 0 && node->first_clus != EXFAT_FREE_CLUSTER) ||
+ (node->size > 0 && !heap_clus(exfat, node->first_clus))) {
+ if (repair_file_ask(&exfat->de_iter, node,
+ ER_FILE_FIRST_CLUS, "first cluster is wrong"))
+ goto truncate_file;
+ else
+ return -EINVAL;
+ }
+
+ while (clus != EXFAT_EOF_CLUSTER) {
+ if (count >= max_count) {
+ if (node->is_contiguous)
+ break;
+ if (repair_file_ask(&exfat->de_iter, node,
+ ER_FILE_SMALLER_SIZE,
+ "more clusters are allocated. "
+ "truncate to %" PRIu64 " bytes",
+ count * exfat->clus_size))
+ goto truncate_file;
+ else
+ return -EINVAL;
+ }
+
+ /*
+ * This cluster is already allocated. it may be shared with
+ * the other file, or there is a loop in cluster chain.
+ */
+ if (EXFAT_BITMAP_GET(exfat->alloc_bitmap,
+ clus - EXFAT_FIRST_CLUSTER)) {
+ if (repair_file_ask(&exfat->de_iter, node,
+ ER_FILE_DUPLICATED_CLUS,
+ "cluster is already allocated for "
+ "the other file. truncated to %"
+ PRIu64 " bytes",
+ count * exfat->clus_size))
+ goto truncate_file;
+ else
+ return -EINVAL;
+ }
+
+ if (!EXFAT_BITMAP_GET(exfat->disk_bitmap,
+ clus - EXFAT_FIRST_CLUSTER)) {
+ if (repair_file_ask(&exfat->de_iter, node,
+ ER_FILE_INVALID_CLUS,
+ "cluster is marked as free. truncate to %" PRIu64 " bytes",
+ count * exfat->clus_size))
+ goto truncate_file;
+
+ else
+ return -EINVAL;
+ }
+
+ /* This cluster is allocated or not */
+ if (get_next_clus(exfat, node, clus, &next))
+ goto truncate_file;
+ if (!node->is_contiguous) {
+ if (!heap_clus(exfat, next) &&
+ next != EXFAT_EOF_CLUSTER) {
+ if (repair_file_ask(&exfat->de_iter, node,
+ ER_FILE_INVALID_CLUS,
+ "broken cluster chain. "
+ "truncate to %"
+ PRIu64 " bytes",
+ count * exfat->clus_size))
+ goto truncate_file;
+
+ else
+ return -EINVAL;
+ }
+ }
+
+ count++;
+ EXFAT_BITMAP_SET(exfat->alloc_bitmap,
+ clus - EXFAT_FIRST_CLUSTER);
+ prev = clus;
+ clus = next;
+ }
+
+ if (count < max_count) {
+ if (repair_file_ask(&exfat->de_iter, node,
+ ER_FILE_LARGER_SIZE, "less clusters are allocated. "
+ "truncates to %" PRIu64 " bytes",
+ count * exfat->clus_size))
+ goto truncate_file;
+ else
+ return -EINVAL;
+ }
+
+ return 0;
+truncate_file:
+ node->size = count * exfat->clus_size;
+ if (!heap_clus(exfat, prev))
+ node->first_clus = EXFAT_FREE_CLUSTER;
+
+ exfat_de_iter_get_dirty(&exfat->de_iter, 1, &stream_de);
+ if (count * exfat->clus_size <
+ le64_to_cpu(stream_de->stream_valid_size))
+ stream_de->stream_valid_size = cpu_to_le64(
+ count * exfat->clus_size);
+ if (!heap_clus(exfat, prev))
+ stream_de->stream_start_clu = EXFAT_FREE_CLUSTER;
+ stream_de->stream_size = cpu_to_le64(
+ count * exfat->clus_size);
+
+ /* remaining clusters will be freed while FAT is compared with
+ * alloc_bitmap.
+ */
+ if (!node->is_contiguous && heap_clus(exfat, prev))
+ return set_fat(exfat, prev, EXFAT_EOF_CLUSTER);
+ return 1;
+}
+
+static bool root_get_clus_count(struct exfat *exfat, struct exfat_inode *node,
+ clus_t *clus_count)
+{
+ clus_t clus;
+
+ clus = node->first_clus;
+ *clus_count = 0;
+
+ do {
+ if (!heap_clus(exfat, clus)) {
+ exfat_err("/: bad cluster. 0x%x\n", clus);
+ return false;
+ }
+
+ if (EXFAT_BITMAP_GET(exfat->alloc_bitmap,
+ clus - EXFAT_FIRST_CLUSTER)) {
+ exfat_err("/: cluster is already allocated, or "
+ "there is a loop in cluster chain\n");
+ return false;
+ }
+
+ EXFAT_BITMAP_SET(exfat->alloc_bitmap,
+ clus - EXFAT_FIRST_CLUSTER);
+
+ if (get_next_clus(exfat, node, clus, &clus) != 0) {
+ exfat_err("/: broken cluster chain\n");
+ return false;