X-Git-Url: https://git.sven.stormbind.net/?p=sven%2Fexfatprogs.git;a=blobdiff_plain;f=fsck%2Ffsck.c;fp=fsck%2Ffsck.c;h=cd9ee9a193e344af59482af52256cbe98b4c5896;hp=219d7237e1b3ece0b13cb487d4fd2ca38549a3d5;hb=0a7a8b470671035ad0c2d8dc0d7714d06921273d;hpb=03290761e3849db9b13d2d3b176b36ab31c395bb diff --git a/fsck/fsck.c b/fsck/fsck.c index 219d723..cd9ee9a 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -103,21 +103,31 @@ 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; + clus_t clus, prev, next, new_clus; 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) + 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; + } 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))) { @@ -215,6 +225,38 @@ 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))