Changes by: antona
Update of /cvsroot/linux-ntfs/linux-ntfs/ntfstools
In directory usw-pr-cvs1:/tmp/cvs-serv19578/ntfstools
Modified Files:
ntfsfix.c
Log Message:
More fixes and updates.
Index: ntfsfix.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/ntfstools/ntfsfix.c,v
retrieving revision 1.31
retrieving revision 1.32
diff -U2 -r1.31 -r1.32
--- ntfsfix.c 29 Apr 2002 01:53:55 -0000 1.31
+++ ntfsfix.c 2 Jun 2002 23:02:20 -0000 1.32
@@ -63,21 +63,20 @@
int main(int argc, char **argv)
{
+ __s64 l, br;
const char *EXEC_NAME = "NtfsFix";
const char *OK = "OK";
const char *FAILED = "FAILED";
- unsigned char *b1 = NULL;
- unsigned char *b2 = NULL;
- int i, ebits;
- ssize_t br;
+ unsigned char *m = NULL, *m2 = NULL;
+ ntfs_volume *vol;
+ ntfs_attr_search_ctx *ctx;
ATTR_RECORD *a;
- __s64 l;
unsigned char *lfd;
- ntfs_volume *vol = NULL;
+ unsigned long mnt_flags;
+ int i;
__u16 flags;
- ntfs_attr_search_ctx *ctx = NULL;
- MFT_REF mref;
+ BOOL done, force = FALSE;
printf("\n");
- if (argc != 2) {
+ if (argc != 2 || !argv[1]) {
printf("%s v%s - Attempt to fix an NTFS partition that "
"has been damaged by the\nLinux NTFS driver. Note that "
@@ -105,228 +104,237 @@
exit(1);
}
+ if (!ntfs_check_if_mounted(argv[1], &mnt_flags)) {
+ if ((mnt_flags & NTFS_MF_MOUNTED) &&
+ !(mnt_flags & NTFS_MF_READONLY) && !force) {
+ fprintf(stderr, "Refusing to operate on read-write "
+ "mounted device %s.\n", argv[1]);
+ exit(1);
+ }
+ } else
+ fprintf(stderr, "Failed to determine whether %s is mounted: "
+ "%s\n", argv[1], strerror(errno));
+ /* Attempt a full mount first. */
+ printf("Mounting volume... ");
vol = ntfs_mount(argv[1], 0);
+ if (vol) {
+ puts(OK);
+ printf("\nProcessing of $MFT and $MFTMirr completed "
+ "successfully.\n\n");
+ goto mount_ok;
+ }
+ puts(FAILED);
+
+ puts("Attempting to correct errors.");
+
+ vol = ntfs_startup_volume(argv[1], 0);
if (!vol) {
- perror("ntfs_mount() failed");
- exit(1);
+ puts(FAILED);
+ perror("Failed to startup volume");
+ fprintf(stderr, "Volume is corrupt. You should run chkdsk.");
+ goto error_exit;
}
-/* Lazyness caused define for offset from one Mft record to the next. (-; */
-#define mrs (vol->mft_record_size)
+ puts("Processing $MFT and $MFTMirr.");
- printf("Beginning processing of the $Mft and $MftMirr...\n");
- b1 = (__u8 *)malloc(mrs * 8);
- if (!b1) {
- perror("Error allocating internal buffers");
- goto error_exit;
- }
- b2 = b1 + (mrs * 4);
-#ifdef DEBUG
- printf("$Mft LCN = 0x%Lx\n", vol->mft_lcn);
- printf("$MftMirr LCN = 0x%Lx\n", vol->mftmirr_lcn);
-#endif
- /* Read $MFT and $MFTmirr. */
- printf("Going to read $Mft... ");
- mref = (MFT_REF)FILE_MFT;
- br = ntfs_read_mft_records(vol, mref, 4, (MFT_RECORD*)b1);
- if (br) {
- puts(FAILED);
+ /* Load data from $MFT and $MFTMirr and compare the contents. */
+ m = (__u8*)malloc(vol->mftmirr_size << vol->mft_record_size_bits);
+ m2 = (__u8*)malloc(vol->mftmirr_size << vol->mft_record_size_bits);
+ if (!m || !m2) {
+ perror("Failed to allocate memory");
goto error_exit;
}
- puts(OK);
- /* Use ntfs_mst_pread as we don't want to rely on information in $Mft
- * for locating $MftMirr as that would defeat the point of $MftMirr. */
- printf("Going to read $MftMirr... ");
- br = ntfs_mst_pread(vol->fd, vol->mftmirr_lcn << vol->cluster_size_bits,
- 4, mrs, b2);
- if (br != 4) {
- puts(FAILED);
-#define ESTR "Error reading $MftMirr"
- if (br == -1)
- perror(ESTR);
- else if (br < 4)
- fprintf(stderr, "Error: $MftMirr LCN is outside of "
- "the partition!\nIs it maybe part of "
- "a RAID array?\n");
- else
- fprintf(stderr, ESTR ": unknown error\n");
-#undef ESTR
+
+ printf("Reading $MFT... ");
+ l = ntfs_attr_mst_pread(vol->mft_na, 0, vol->mftmirr_size,
+ vol->mft_record_size, m);
+ if (l != vol->mftmirr_size) {
+ puts(FAILED);
+ if (l != -1)
+ errno = EIO;
+ perror("Failed to read $MFT");
goto error_exit;
}
puts(OK);
- /* Check first four Mft records. */
- printf("Checking first four entries in $Mft. ");
- for (i = 0; i < 4; ++i) {
- const char *ESTR[4] = { "$Mft", "$MftMirr", "$LogFile",
- "$Volume" };
-
- if (is_baad_recordp(b1 + (i * mrs))) {
- puts(FAILED);
- fprintf(stderr, "Error: Incomplete multi sector "
- "transfer detected in %s.\nCannot "
- "handle this yet. )-:\n", ESTR[i]);
- goto error_exit;
- }
- if (!is_mft_recordp(b1 + (i * mrs))) {
- puts(FAILED);
- fprintf(stderr, "Error: Invalid $Mft record for %s.\n"
- "Cannot handle this yet. )-:\n",
- ESTR[i]);
- goto error_exit;
- }
- printf("%s\b. ", i == 0? "\b": "");
+
+ printf("Reading $MFTMirr... ");
+ l = ntfs_attr_mst_pread(vol->mftmirr_na, 0, vol->mftmirr_size,
+ vol->mft_record_size, m2);
+ if (l != vol->mftmirr_size) {
+ puts(FAILED);
+ if (l != -1)
+ errno = EIO;
+ perror("Failed to read $MFTMirr");
+ goto error_exit;
}
puts(OK);
+
/*
- * FIXME: Need to actually check the $MftMirr for being real. Otherwise
+ * FIXME: Need to actually check the $MFTMirr for being real. Otherwise
* we might corrupt the partition if someone is experimenting with
- * software RAID and the $MftMirr is not actually in the position we
+ * software RAID and the $MFTMirr is not actually in the position we
* expect it to be... )-:
- * FIXME: We should emit a warning it $MftMirr is damaged and ask
- * user whether to recreate it from $Mft or whether to abort. - The
+ * FIXME: We should emit a warning it $MFTMirr is damaged and ask
+ * user whether to recreate it from $MFT or whether to abort. - The
* warning needs to include the danger of software RAID arrays.
* Maybe we should go as far as to detect whether we are running on a
* MD disk and if yes then bomb out right at the start of the program?
*/
- /* Check the four MftMirr records. */
- printf("Checking entries in $MftMirr. ");
- for (i = 0; i < 4; ++i) {
- const char *ESTR[4] = { "$Mft", "$MftMirr", "$LogFile",
- "$Volume" };
-
- if (is_baad_recordp(b2 + (i * mrs))) {
- puts(FAILED);
- fprintf(stderr, "Error: Incomplete multi sector "
- "transfer detected in %s.\nCannot "
- "handle this yet. )-:\n", ESTR[i]);
+
+ printf("Comparing $MFTMirr to $MFT... ");
+ done = FALSE;
+ for (i = 0; i < vol->mftmirr_size; ++i) {
+ const char *ESTR[12] = { "$MFT", "$MFTMirr", "$LogFile",
+ "$Volume", "$AttrDef", "root directory", "$Bitmap",
+ "$Boot", "$BadClus", "$Secure", "$UpCase", "$Extend" };
+ const char *s;
+
+ if (i < 12)
+ s = ESTR[i];
+ else if (i < 16)
+ s = "system file";
+ else
+ s = "mft record";
+
+ if (is_baad_recordp(m + i * vol->mft_record_size)) {
+ puts("FAILED");
+ fprintf(stderr, "$MFT error: Incomplete multi sector "
+ "transfer detected in %s.\nCannot "
+ "handle this yet. )-:\n", s);
goto error_exit;
}
- if (!is_mft_recordp(b2 + (i * mrs))) {
- puts(FAILED);
- fprintf(stderr, "Error: Invalid $MftMirr record for %s.\n"
- "Cannot handle this yet. )-:\n",
- ESTR[i]);
+ if (!is_mft_recordp(m + i * vol->mft_record_size)) {
+ puts("FAILED");
+ fprintf(stderr, "$MFT error: Invalid mft record for "
+ "%s.\nCannot handle this yet. )-:\n",
+ s);
goto error_exit;
}
- printf("%s\b. ", i == 0? "\b": "");
- }
- puts(OK);
- /* Compare each record in turn and set the corresponding bit in ebits
- * if a mismatch is encountered. Note that we EXPECT a bit-to-bit match
- * of the $Mft and the $MftMirr. This is CORRECT behaviour(!). Even just
- * having the USNs in $Mft and $MftMirr being different has to trigger
- * the correction procedure! */
- printf("Comparing $MftMirr to $Mft... ");
- for (i = 0, ebits = 0; i < 4; ++i) {
- if (memcmp(b1 + i * mrs, b2 + i * mrs,
- ntfs_get_mft_record_data_size((MFT_RECORD*)(b1
- + i * mrs)))) {
- ebits |= 1 << i;
-#ifdef DEBUG
- printf("in memcmp: i = %x, count = 0x%x\n", i,
- ntfs_get_mft_record_data_size(
- (MFT_RECORD*)(b1 + i * mrs)));
-#endif
+ if (is_baad_recordp(m2 + i * vol->mft_record_size)) {
+ puts("FAILED");
+ fprintf(stderr, "$MFTMirr error: Incomplete multi "
+ "sector transfer detected in %s.\n", s);
+ goto error_exit;
}
- }
- if (ebits) {
- puts(FAILED);
- printf("Assuming $Mft is valid and correcting differences "
- "in $MftMirr... ");
- /* MST protect & write the $Mft records corresponding to the
- mismatched ones to both $Mft and $MftMirr. */
- for (i = 0; i < 4; ++i) {
- /* Only fix if there was an error! */
- if ( !( ebits & (1 << i) ) )
- continue;
- /* Copy the buffer first (due to USN stuff, can't
- recycle the buffer) */
- memcpy(b2 + mrs * i, b1 + mrs * i, mrs);
- /* Do the writes now. */
- mref = (MFT_REF)i;
- br = ntfs_write_mft_record(vol, mref,
- (MFT_RECORD*)(b1 + mrs * i));
+ if (!is_mft_recordp(m2 + i * vol->mft_record_size)) {
+ puts("FAILED");
+ fprintf(stderr, "$MFTMirr error: Invalid mft record "
+ "for %s.\n", s);
+ goto error_exit;
+ }
+ if (memcmp((__u8*)m + i * vol->mft_record_size, (__u8*)m2 +
+ i * vol->mft_record_size,
+ ntfs_get_mft_record_data_size((MFT_RECORD*)(
+ (__u8*)m + i * vol->mft_record_size)))) {
+ if (!done) {
+ done = TRUE;
+ puts(FAILED);
+ printf("Correcting differences in "
+ "$MFTMirr... ");
+ }
+ /*
+ * Copy the buffer from $MFT to $MFTMirr (due to USN
+ * stuff, can't recycle the buffer).
+ */
+ memcpy(m2 + i * vol->mft_record_size,
+ m + i * vol->mft_record_size,
+ vol->mft_record_size);
+ br = ntfs_write_mft_record(vol, i, (MFT_RECORD*)(m +
+ i * vol->mft_record_size));
if (br)
goto mirr_sync_failed;
br = ntfs_mst_pwrite(vol->fd, (vol->mftmirr_lcn <<
- vol->cluster_size_bits) + i * mrs, 1,
- mrs, b2 + mrs * i);
- /* If we succeeded then do the next record. */
- if (br == 1)
- continue;
-mirr_sync_failed: /* Synchronization failed. )-: */
- puts(FAILED);
-#define ESTR "Error correcting $MftMirr"
- if (br == -1)
- perror(ESTR);
- else
- fprintf(stderr, ESTR ": unknown error\n");
-#undef ESTR
- goto error_exit;
+ vol->cluster_size_bits) +
+ i * vol->mft_record_size, 1,
+ vol->mft_record_size,
+ m2 + i * vol->mft_record_size);
+ if (br != 1) {
+mirr_sync_failed:
+ puts(FAILED);
+ if (br != -1)
+ errno = EIO;
+ perror("Error correcting $MFTMirr");
+ goto error_exit;
+ }
}
}
puts(OK);
- printf("Processing of the $Mft and $MftMirr completed successfully."
- "\n\n");
+
+ free(m);
+ free(m2);
+ m = m2 = NULL;
+
+ printf("Processing of $MFT and $MFTMirr completed successfully.\n\n");
+ if (ntfs_umount(vol, 0))
+ ntfs_umount(vol, 1);
+ vol = ntfs_mount(argv[1], 0);
+ if (!vol) {
+ perror("Remount failed");
+ goto error_exit;
+ }
+mount_ok:
+ m = NULL;
+ m2 = (__u8*)malloc(vol->mft_record_size);
+ if (!m2) {
+ perror("Failed to allocate memory");
+ goto error_exit;
+ }
+
+ if (ntfs_read_file_record(vol, FILE_Volume, (MFT_RECORD**)&m, NULL)) {
+ perror("Failed to read $Volume");
+ goto error_exit;
+ }
+
/* Check NTFS version is ok for us (in $Volume) */
- printf("NTFS volume version is %i.%i.\n", vol->major_ver,
- vol->minor_ver);
+ printf("NTFS volume version is %i.%i.\n\n", vol->major_ver,
+ vol->minor_ver);
switch (vol->major_ver) {
- case 1:
- if (vol->minor_ver == 1 || vol->minor_ver == 2)
- break;
- else
- goto version_error;
- case 2:
+ case 1:
+ if (vol->minor_ver == 1 || vol->minor_ver == 2)
+ break;
+ else
+ goto version_error;
+ case 2:
+ break;
+ case 3:
+ if (vol->minor_ver == 0 || vol->minor_ver == 1)
break;
- case 3:
- if (vol->minor_ver == 0 || vol->minor_ver == 1)
- break;
- /* Fall through on error. */
- default:
+ /* Fall through on error. */
+ default:
version_error:
- fprintf(stderr, "Error: Unknown NTFS version.\n");
- goto error_exit;
+ fprintf(stderr, "Error: Unknown NTFS version.\n");
+ goto error_exit;
}
printf("Setting required flags on partition... ");
- /* Set chkdsk flag, i.e. mark the partition dirty so chkdsk will run
- and fix it for us. */
- flags = vol->flags;
- flags |= VOLUME_IS_DIRTY;
+ /*
+ * Set chkdsk flag, i.e. mark the partition dirty so chkdsk will run
+ * and fix it for us.
+ */
+ flags = vol->flags | VOLUME_IS_DIRTY;
/* If NTFS volume version >= 2.0 then set mounted on NT4 flag. */
if (vol->major_ver >= 2)
flags |= VOLUME_MOUNTED_ON_NT4;
- if (!set_ntfs_volume_flags(vol, (MFT_RECORD*)(b1+3*mrs), flags)) {
+ if (!set_ntfs_volume_flags(vol, (MFT_RECORD*)m, flags)) {
puts(FAILED);
fprintf(stderr, "Error setting volume flags.\n");
goto error_exit;
}
- vol->flags = flags;
/* FIXME: The above makes me puke! We definitely need functions just
- taking the volume and flags and [sg]etting the volume flags! */
- puts(OK);
- /* Sync $MftMirr and $Mft buffers. */
- memcpy(b2 + 3 * mrs, b1 + 3 * mrs, mrs);
- /* Write $Volume to $Mft. */
- printf("Writing $Volume to $Mft... ");
- mref = (MFT_REF)FILE_Volume;
- br = ntfs_write_mft_record(vol, mref, (MFT_RECORD*)(b1 + 3 * mrs));
+ taking the volume and flags and setting the volume flags! */
+ /* Sync $MFTMirr and $MFT buffers. */
+ memcpy(m2, m, vol->mft_record_size);
+ br = ntfs_write_mft_record(vol, FILE_Volume, (MFT_RECORD*)m);
if (br) {
puts(FAILED);
-#define ESTR "Error writing $Volume to $Mft"
- if (br == -1)
- perror(ESTR);
- else
- fprintf(stderr, ESTR ": unknown error\n");
-#undef ESTR
+ if (br != -1)
+ errno = EIO;
+ perror("Error writing $Volume to $MFT");
goto error_exit;
}
- puts(OK);
- /* Write $Volume to $MftMirr. */
- printf("Writing $Volume to $MftMirr... ");
br = ntfs_mst_pwrite(vol->fd, (vol->mftmirr_lcn <<
- vol->cluster_size_bits) + 3 * mrs, 1, mrs,
- b2 + 3 * mrs);
+ vol->cluster_size_bits) + 3 * vol->mft_record_size, 1,
+ vol->mft_record_size, m2);
if (br != 1) {
puts(FAILED);
+ perror("Error writing $Volume to $MFTMirr");
goto error_exit;
}
@@ -340,7 +348,12 @@
* happens, since chkdsk might pickup the pieces and do it for us...)
*/
+ if (ntfs_read_file_record(vol, FILE_LogFile, (MFT_RECORD**)&m, NULL)) {
+ perror("Failed to read $LogFile");
+ goto error_exit;
+ }
+
printf("Going to empty the journal ($LogFile)... ");
/* Find the $DATA attribute. */
- ctx = ntfs_get_attr_search_ctx(NULL, (MFT_RECORD*)(b1 + (2 * mrs)));
+ ctx = ntfs_get_attr_search_ctx(NULL, (MFT_RECORD*)m);
if (!ctx) {
puts(FAILED);
@@ -379,6 +392,5 @@
decompressing the mapping pairs array correctly and hence writing
below if safe as well. */
- if (l != get_attribute_value(vol, (MFT_RECORD*)(b1 + (2 * mrs)),
- a, lfd)) {
+ if (l != get_attribute_value(vol, (MFT_RECORD*)m, a, lfd)) {
puts(FAILED);
puts("Amount of data read does not correspond to expected "
@@ -414,4 +426,7 @@
printf("\n");
+ if (ctx)
+ ntfs_put_attr_search_ctx(ctx);
+
if (vol->major_ver >= 3) {
/* FIXME: If on NTFS 3.0+, check for presence of the usn journal and
@@ -425,12 +440,12 @@
/* That's all for now! */
printf("NTFS partition %s was processed successfully.\n",
- vol->dev_name);
+ vol->dev_name);
/* Set return code to 0. */
i = 0;
final_exit:
- if (ctx)
- ntfs_put_attr_search_ctx(ctx);
- if (b1)
- free(b1);
+ if (m)
+ free(m);
+ if (m2)
+ free(m2);
if (vol && ntfs_umount(vol, 0))
ntfs_umount(vol, 1);
|