Allowed cloning a file system despite allocation errors

Allow the "--ignore-fs-check" option to be used when cloning a file system
which has allocation errors. This is useful when there is a fear that
repairing the file system might create further damage, or when the repair
has to be made on another computer.
edge.strict_endians
Jean-Pierre André 2013-02-09 11:41:39 +01:00
parent c820cb6d76
commit 81eb7baf88
1 changed files with 63 additions and 13 deletions

View File

@ -154,6 +154,7 @@ typedef struct {
ntfs_inode *ni; /* inode being processed */
ntfs_attr_search_ctx *ctx; /* inode attribute being processed */
s64 inuse; /* number of clusters in use */
int more_use; /* possibly allocated clusters */
LCN current_lcn;
} ntfs_walk_clusters_ctx;
@ -222,6 +223,8 @@ static struct image_hdr {
le32 offset_to_image_data; /* From start of image_hdr. */
} __attribute__((__packed__)) image_hdr;
static int compare_bitmaps(struct bitmap *a, BOOL copy);
#define NTFSCLONE_IMG_HEADER_SIZE_OLD \
(offsetof(struct image_hdr, offset_to_image_data))
@ -456,9 +459,9 @@ static void parse_options(int argc, char **argv)
if (opt.metadata && !opt.metadata_image && opt.std_out)
err_exit("Cloning only metadata to stdout isn't supported!\n");
if (opt.ignore_fs_check && !opt.metadata)
if (opt.ignore_fs_check && !opt.metadata && !opt.rescue)
err_exit("Filesystem check can be ignored only for metadata "
"cloning!\n");
"cloning or rescue situations!\n");
if (opt.save_image && opt.restore_image)
err_exit("Saving and restoring an image at the same time "
@ -843,7 +846,7 @@ static void write_image_hdr(void)
}
}
static void clone_ntfs(u64 nr_clusters)
static void clone_ntfs(u64 nr_clusters, int more_use)
{
u64 cl, last_cl; /* current and last used cluster */
void *buf;
@ -876,6 +879,10 @@ static void clone_ntfs(u64 nr_clusters)
perr_exit("write_all");
}
/* save suspicious clusters if required */
if (more_use && opt.ignore_fs_check) {
compare_bitmaps(&lcn_bitmap, TRUE);
}
/* Examine up to the alternate boot sector */
for (last_cl = cl = 0; cl <= (u64)vol->nr_clusters; cl++) {
@ -1261,10 +1268,13 @@ static void clone_logfile_parts(ntfs_walk_clusters_ctx *image, runlist *rl)
lseek_to_cluster(lcn);
if (opt.metadata_image && wipe)
gap_to_cluster(lcn - image->current_lcn);
if ((lcn + 1) != image->current_lcn) {
/* do not duplicate a cluster */
if (opt.metadata_image && wipe)
gap_to_cluster(lcn - image->current_lcn);
copy_cluster(opt.rescue, lcn, lcn);
copy_cluster(opt.rescue, lcn, lcn);
}
image->current_lcn = lcn + 1;
if (opt.metadata_image && !wipe)
image->inuse++;
@ -1703,17 +1713,26 @@ static void walk_attributes(struct ntfs_walk_cluster *walk)
ntfs_attr_put_search_ctx(ctx);
}
/*
* Compare the actual bitmap to the list of clusters
* allocated to identified files.
*
* Clusters found in use, though not marked in the bitmap are copied
* if the option --ignore-fs-checks is set.
*/
static void compare_bitmaps(struct bitmap *a)
static int compare_bitmaps(struct bitmap *a, BOOL copy)
{
s64 i, pos, count;
int mismatch = 0;
int more_use = 0;
s64 new_cl;
u8 bm[NTFS_BUF_SIZE];
Printf("Accounting clusters ...\n");
pos = 0;
new_cl = 0;
while (1) {
count = ntfs_attr_pread(vol->lcnbmp_na, pos, NTFS_BUF_SIZE, bm);
if (count == -1)
@ -1744,8 +1763,16 @@ static void compare_bitmaps(struct bitmap *a)
if (bit == ntfs_bit_get(bm, i * 8 + cl % 8))
continue;
if (opt.ignore_fs_check) {
if (!bit)
more_use++;
if (opt.ignore_fs_check && !bit && copy) {
lseek_to_cluster(cl);
if (opt.save_image
|| (opt.metadata
&& opt.metadata_image)) {
gap_to_cluster(cl - new_cl);
new_cl = cl + 1;
}
copy_cluster(opt.rescue, cl, cl);
}
@ -1765,12 +1792,16 @@ done:
if (opt.ignore_fs_check) {
Printf("WARNING: The NTFS inconsistency was overruled "
"by the --ignore-fs-check option.\n");
return;
if (new_cl) {
gap_to_cluster(-new_cl);
}
return (more_use);
}
err_exit("Filesystem check failed! Windows wasn't shutdown "
"properly or inconsistent\nfilesystem. Please run "
"chkdsk /f on Windows then reboot it TWICE.\n");
}
return (more_use);
}
@ -1888,6 +1919,11 @@ out:
(long long)inode);
}
if (opt.metadata) {
if (opt.metadata_image && wipe && opt.ignore_fs_check) {
gap_to_cluster(-walk->image->current_lcn);
compare_bitmaps(&lcn_bitmap, TRUE);
walk->image->current_lcn = 0;
}
/* also get the backup bootsector */
nr_clusters = vol->nr_clusters;
lseek_to_cluster(nr_clusters);
@ -2020,7 +2056,20 @@ static void mount_volume(unsigned long new_mntflag)
"disk instead of a partition (e.g. /dev/hda, "
"not /dev/hda1)?\n", opt.volume);
}
exit(1);
/*
* Retry with recovering the log file enabled.
* Normally avoided in order to get the original log file
* data, but needed when remounting the metadata of a
* volume improperly unmounted from Windows.
*/
if (!(new_mntflag & (NTFS_MNT_RDONLY | NTFS_MNT_RECOVER))) {
Printf("Trying to recover...\n");
vol = ntfs_mount(opt.volume,
new_mntflag | NTFS_MNT_RECOVER);
Printf("... %s\n",(vol ? "Successful" : "Failed"));
}
if (!vol)
exit(1);
}
if (vol->flags & VOLUME_IS_DIRTY)
@ -2483,7 +2532,8 @@ int main(int argc, char **argv)
backup_clusters.image = &image;
walk_clusters(vol, &backup_clusters);
compare_bitmaps(&lcn_bitmap);
image.more_use = compare_bitmaps(&lcn_bitmap,
opt.metadata && !opt.metadata_image);
print_disk_usage("", vol->cluster_size, vol->nr_clusters, image.inuse);
check_dest_free_space(vol->cluster_size * image.inuse);
@ -2499,7 +2549,7 @@ int main(int argc, char **argv)
nr_clusters_to_save = vol->nr_clusters;
nr_clusters_to_save++; /* account for the backup boot sector */
clone_ntfs(nr_clusters_to_save);
clone_ntfs(nr_clusters_to_save, image.more_use);
fsync_clone(fd_out);
if (opt.save_image)
fclose(stream_out);