diff --git a/ChangeLog b/ChangeLog index 57519a4f..030e0b51 100644 --- a/ChangeLog +++ b/ChangeLog @@ -22,6 +22,11 @@ xx/xx/2006 - 1.13.1-WIP numbers in hex (and octal if anyone is crazy enough to use that) in addition to decimal numbers on the command line options to most if not all utilities. (Anton) + - Fix comparison of $MFT and $MFTMirr to not bail out when there are + unused, invalid mft records which are the same in both $MFT and + $MFTMirr. Ported from kernel driver 2.1.27 release and aplied both + to libntfs/volume.c mount related code and to ntfsprogs/ntfsfix.c's + fixup code. (Anton) 27/02/2006 - 1.13.0 - Lots and lots and lots of fixes and enhancements. diff --git a/libntfs/volume.c b/libntfs/volume.c index 9e08c24c..9477a9cd 100644 --- a/libntfs/volume.c +++ b/libntfs/volume.c @@ -816,6 +816,7 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags) } ntfs_log_debug("Comparing $MFTMirr to $MFT... "); for (i = 0; i < vol->mftmirr_size; ++i) { + MFT_RECORD *mrec, *mrec2; const char *ESTR[12] = { "$MFT", "$MFTMirr", "$LogFile", "$Volume", "$AttrDef", "root directory", "$Bitmap", "$Boot", "$BadClus", "$Secure", "$UpCase", "$Extend" }; @@ -828,33 +829,39 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags) else s = "mft record"; - if (ntfs_is_baad_recordp(m + i * vol->mft_record_size)) { - ntfs_log_debug("FAILED\n"); - ntfs_log_debug("$MFT error: Incomplete multi sector transfer " - "detected in %s.\n", s); - goto io_error_exit; + mrec = (MFT_RECORD*)(m + i * vol->mft_record_size); + if (mrec->flags & MFT_RECORD_IN_USE) { + if (ntfs_is_baad_recordp(mrec)) { + ntfs_log_debug("FAILED\n"); + ntfs_log_debug("$MFT error: Incomplete multi " + "sector transfer detected in " + "%s.\n", s); + goto io_error_exit; + } + if (!ntfs_is_mft_recordp(mrec)) { + ntfs_log_debug("FAILED\n"); + ntfs_log_debug("$MFT error: Invalid mft " + "record for %s.\n", s); + goto io_error_exit; + } } - if (!ntfs_is_mft_recordp(m + i * vol->mft_record_size)) { - ntfs_log_debug("FAILED\n"); - ntfs_log_debug("$MFT error: Invalid mft record for %s.\n", s); - goto io_error_exit; + mrec2 = (MFT_RECORD*)(m2 + i * vol->mft_record_size); + if (mrec2->flags & MFT_RECORD_IN_USE) { + if (ntfs_is_baad_recordp(mrec2)) { + ntfs_log_debug("FAILED\n"); + ntfs_log_debug("$MFTMirr error: Incomplete " + "multi sector transfer " + "detected in %s.\n", s); + goto io_error_exit; + } + if (!ntfs_is_mft_recordp(mrec2)) { + ntfs_log_debug("FAILED\n"); + ntfs_log_debug("$MFTMirr error: Invalid mft " + "record for %s.\n", s); + goto io_error_exit; + } } - if (ntfs_is_baad_recordp(m2 + i * vol->mft_record_size)) { - ntfs_log_debug("FAILED\n"); - ntfs_log_debug("$MFTMirr error: Incomplete multi sector " - "transfer detected in %s.\n", s); - goto io_error_exit; - } - if (!ntfs_is_mft_recordp(m2 + i * vol->mft_record_size)) { - ntfs_log_debug("FAILED\n"); - ntfs_log_debug("$MFTMirr error: Invalid mft record for " - "%s.\n", s); - goto io_error_exit; - } - if (memcmp((u8*)m + i * vol->mft_record_size, (u8*)m2 + - i * vol->mft_record_size, - ntfs_mft_record_get_data_size((MFT_RECORD*)( - (u8*)m + i * vol->mft_record_size)))) { + if (memcmp(mrec, mrec2, ntfs_mft_record_get_data_size(mrec))) { ntfs_log_debug(FAILED); ntfs_log_debug("$MFTMirr does not match $MFT. Run " "chkdsk.\n"); diff --git a/ntfsprogs/ntfsfix.c b/ntfsprogs/ntfsfix.c index e9f0d45f..a6c0c83e 100644 --- a/ntfsprogs/ntfsfix.c +++ b/ntfsprogs/ntfsfix.c @@ -380,10 +380,12 @@ static int fix_mftmirr(ntfs_volume *vol) ntfs_log_info("Comparing $MFTMirr to $MFT... "); done = FALSE; for (i = 0; i < vol->mftmirr_size; ++i) { + MFT_RECORD *mrec, *mrec2; const char *ESTR[12] = { "$MFT", "$MFTMirr", "$LogFile", "$Volume", "$AttrDef", "root directory", "$Bitmap", "$Boot", "$BadClus", "$Secure", "$UpCase", "$Extend" }; const char *s; + BOOL use_mirr; if (i < 12) s = ESTR[i]; @@ -392,46 +394,68 @@ static int fix_mftmirr(ntfs_volume *vol) else s = "mft record"; - if (ntfs_is_baad_recordp(m + i * vol->mft_record_size)) { - ntfs_log_info("FAILED"); - ntfs_log_error("$MFT error: Incomplete multi sector " - "transfer detected in %s.\nCannot " - "handle this yet. )-:\n", s); - goto error_exit; - } - if (!ntfs_is_mft_recordp(m + i * vol->mft_record_size)) { - ntfs_log_info("FAILED"); - ntfs_log_error("$MFT error: Invalid mft record for " - "%s.\nCannot handle this yet. )-:\n", - s); - goto error_exit; - } - if (ntfs_is_baad_recordp(m2 + i * vol->mft_record_size)) { - ntfs_log_info("FAILED"); - ntfs_log_error("$MFTMirr error: Incomplete multi " - "sector transfer detected in %s.\n", s); - goto error_exit; - } - if (memcmp((u8*)m + i * vol->mft_record_size, (u8*)m2 + - i * vol->mft_record_size, - ntfs_mft_record_get_data_size((MFT_RECORD*)( - (u8*)m + i * vol->mft_record_size)))) { - if (!done) { - done = TRUE; + use_mirr = FALSE; + mrec = (MFT_RECORD*)(m + i * vol->mft_record_size); + if (mrec->flags & MFT_RECORD_IN_USE) { + if (ntfs_is_baad_recordp(mrec)) { ntfs_log_info(FAILED); - ntfs_log_info("Correcting differences in $MFTMirr..."); + ntfs_log_error("$MFT error: Incomplete multi " + "sector transfer detected in " + "%s.\nCannot handle this yet. " + ")-:\n", s); + goto error_exit; } - br = ntfs_mft_record_write(vol, i, (MFT_RECORD*)(m + - i * vol->mft_record_size)); - if (br) { + if (!ntfs_is_mft_recordp(mrec)) { ntfs_log_info(FAILED); - ntfs_log_perror("Error correcting $MFTMirr"); + ntfs_log_error("$MFT error: Invalid mft " + "record for %s.\nCannot " + "handle this yet. )-:\n", s); goto error_exit; } } + mrec2 = (MFT_RECORD*)(m2 + i * vol->mft_record_size); + if (mrec2->flags & MFT_RECORD_IN_USE) { + if (ntfs_is_baad_recordp(mrec2)) { + ntfs_log_info(FAILED); + ntfs_log_error("$MFTMirr error: Incomplete " + "multi sector transfer " + "detected in %s.\n", s); + goto error_exit; + } + if (!ntfs_is_mft_recordp(mrec2)) { + ntfs_log_info(FAILED); + ntfs_log_error("$MFTMirr error: Invalid mft " + "record for %s.\n", s); + goto error_exit; + } + /* $MFT is corrupt but $MFTMirr is ok, use $MFTMirr. */ + if (!(mrec->flags & MFT_RECORD_IN_USE) && + !ntfs_is_mft_recordp(mrec)) + use_mirr = TRUE; + } + if (memcmp(mrec, mrec2, ntfs_mft_record_get_data_size(mrec))) { + if (!done) { + done = TRUE; + ntfs_log_info(FAILED); + } + ntfs_log_info("Correcting differences in $MFT%s " + "record %d...", use_mirr ? "" : "Mirr", + i); + br = ntfs_mft_record_write(vol, i, + use_mirr ? mrec2 : mrec); + if (br) { + ntfs_log_info(FAILED); + ntfs_log_perror("Error correcting $MFT%s", + use_mirr ? "" : "Mirr"); + goto error_exit; + } + ntfs_log_info(OK); + } } - ntfs_log_info(OK); - ntfs_log_info("Processing of $MFT and $MFTMirr completed successfully.\n"); + if (!done) + ntfs_log_info(OK); + ntfs_log_info("Processing of $MFT and $MFTMirr completed " + "successfully.\n"); ret = 0; error_exit: free(m);