2 * NtfsFix - Part of the Linux-NTFS project.
4 * Copyright (c) 2000-2003 Anton Altaparmakov.
6 * This utility will attempt to fix a partition that has been damaged by the
7 * current Linux-NTFS driver. It should be run after dismounting a NTFS
8 * partition that has been mounted read-write under Linux and before rebooting
9 * into Windows NT/2000. NtfsFix can be run even after Windows has had mounted
10 * the partition, but it might be too late and irreversible damage to the data
11 * might have been done already.
13 * Anton Altaparmakov <aia21@cantab.net>
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program (in the main directory of the Linux-NTFS source
27 * in the file COPYING); if not, write to the Free Software Foundation,
28 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 * WARNING: This program might not work on architectures which do not allow
33 * unaligned access. For those, the program would need to start using
34 * get/put_unaligned macros (#include <asm/unaligned.h>), but not doing it yet,
35 * since NTFS really mostly applies to ia32 only, which does allow unaligned
36 * accesses. We might not actually have a problem though, since the structs are
37 * defined as being packed so that might be enough for gcc to insert the
40 * If anyone using a non-little endian and/or an aligned access only CPU tries
41 * this program please let me know whether it works or not!
43 * Anton Altaparmakov <aia21@cantab.net>
65 int main(int argc, char **argv)
68 const char *EXEC_NAME = "NtfsFix";
69 const char *OK = "OK";
70 const char *FAILED = "FAILED";
71 unsigned char *m = NULL, *m2 = NULL;
73 struct ntfs_device *dev;
74 unsigned long mnt_flags;
77 BOOL done, force = FALSE;
80 if (argc != 2 || !argv[1]) {
81 printf("%s v%s - Attempt to fix an NTFS partition that "
82 "has been damaged by the\nLinux NTFS driver. Note that "
83 "you should run it every time after you have used\nthe "
84 "Linux NTFS driver to write to an NTFS partition to "
85 "prevent massive data\ncorruption from happening when "
86 "Windows mounts the partition.\nIMPORTANT: Run this "
87 "only *after* unmounting the partition in Linux but "
88 "*before*\nrebooting into Windows NT/2000/XP or you "
89 "*will* suffer! - You have been warned!\n\n"
90 /* Generic copyright / disclaimer. */
91 "Copyright (c) 2000-2003 Anton Altaparmakov.\n\n"
92 "%s is free software, released under the GNU "
93 "General Public License and you\nare welcome to "
94 "redistribute it under certain conditions.\n"
95 "%s comes with ABSOLUTELY NO WARRANTY; for details "
96 "read the file GNU\nGeneral Public License to be found "
97 "in the file COPYING in the main Linux-NTFS\n"
98 "distribution directory.\n\n"
99 /* Generic part ends here. */
100 "Syntax: ntfsfix partition_or_file_name\n"
101 " e.g. ntfsfix /dev/hda6\n\n", EXEC_NAME,
102 VERSION, EXEC_NAME, EXEC_NAME);
103 fprintf(stderr, "Error: incorrect syntax\n");
106 if (!ntfs_check_if_mounted(argv[1], &mnt_flags)) {
107 if ((mnt_flags & NTFS_MF_MOUNTED) &&
108 !(mnt_flags & NTFS_MF_READONLY) && !force) {
109 fprintf(stderr, "Refusing to operate on read-write "
110 "mounted device %s.\n", argv[1]);
114 fprintf(stderr, "Failed to determine whether %s is mounted: "
115 "%s\n", argv[1], strerror(errno));
116 /* Attempt a full mount first. */
117 printf("Mounting volume... ");
118 vol = ntfs_mount(argv[1], 0);
121 printf("\nProcessing of $MFT and $MFTMirr completed "
122 "successfully.\n\n");
127 printf("Attempting to correct errors... ");
129 dev = ntfs_device_alloc(argv[1], 0, &ntfs_device_disk_io_ops, NULL);
132 perror("Failed to allocate device");
136 vol = ntfs_volume_startup(dev, 0);
139 perror("Failed to startup volume");
140 fprintf(stderr, "Volume is corrupt. You should run chkdsk.");
141 ntfs_device_free(dev);
145 puts("Processing $MFT and $MFTMirr.");
147 /* Load data from $MFT and $MFTMirr and compare the contents. */
148 m = (u8*)malloc(vol->mftmirr_size << vol->mft_record_size_bits);
149 m2 = (u8*)malloc(vol->mftmirr_size << vol->mft_record_size_bits);
151 perror("Failed to allocate memory");
155 printf("Reading $MFT... ");
156 l = ntfs_attr_mst_pread(vol->mft_na, 0, vol->mftmirr_size,
157 vol->mft_record_size, m);
158 if (l != vol->mftmirr_size) {
162 perror("Failed to read $MFT");
167 printf("Reading $MFTMirr... ");
168 l = ntfs_attr_mst_pread(vol->mftmirr_na, 0, vol->mftmirr_size,
169 vol->mft_record_size, m2);
170 if (l != vol->mftmirr_size) {
174 perror("Failed to read $MFTMirr");
180 * FIXME: Need to actually check the $MFTMirr for being real. Otherwise
181 * we might corrupt the partition if someone is experimenting with
182 * software RAID and the $MFTMirr is not actually in the position we
183 * expect it to be... )-:
184 * FIXME: We should emit a warning it $MFTMirr is damaged and ask
185 * user whether to recreate it from $MFT or whether to abort. - The
186 * warning needs to include the danger of software RAID arrays.
187 * Maybe we should go as far as to detect whether we are running on a
188 * MD disk and if yes then bomb out right at the start of the program?
191 printf("Comparing $MFTMirr to $MFT... ");
193 for (i = 0; i < vol->mftmirr_size; ++i) {
194 const char *ESTR[12] = { "$MFT", "$MFTMirr", "$LogFile",
195 "$Volume", "$AttrDef", "root directory", "$Bitmap",
196 "$Boot", "$BadClus", "$Secure", "$UpCase", "$Extend" };
206 if (ntfs_is_baad_recordp(m + i * vol->mft_record_size)) {
208 fprintf(stderr, "$MFT error: Incomplete multi sector "
209 "transfer detected in %s.\nCannot "
210 "handle this yet. )-:\n", s);
213 if (!ntfs_is_mft_recordp(m + i * vol->mft_record_size)) {
215 fprintf(stderr, "$MFT error: Invalid mft record for "
216 "%s.\nCannot handle this yet. )-:\n",
220 if (ntfs_is_baad_recordp(m2 + i * vol->mft_record_size)) {
222 fprintf(stderr, "$MFTMirr error: Incomplete multi "
223 "sector transfer detected in %s.\n", s);
226 if (!ntfs_is_mft_recordp(m2 + i * vol->mft_record_size)) {
228 fprintf(stderr, "$MFTMirr error: Invalid mft record "
232 if (memcmp((u8*)m + i * vol->mft_record_size, (u8*)m2 +
233 i * vol->mft_record_size,
234 ntfs_mft_record_get_data_size((MFT_RECORD*)(
235 (u8*)m + i * vol->mft_record_size)))) {
239 printf("Correcting differences in "
242 br = ntfs_mft_record_write(vol, i, (MFT_RECORD*)(m +
243 i * vol->mft_record_size));
246 perror("Error correcting $MFTMirr");
257 printf("Processing of $MFT and $MFTMirr completed successfully.\n\n");
258 /* ntfs_umount() will invoke ntfs_device_free() for us. */
259 if (ntfs_umount(vol, 0))
261 vol = ntfs_mount(argv[1], 0);
263 perror("Remount failed");
269 /* Check NTFS version is ok for us (in $Volume) */
270 printf("NTFS volume version is %i.%i.\n\n", vol->major_ver,
272 if (ntfs_version_is_supported(vol)) {
273 fprintf(stderr, "Error: Unknown NTFS version.\n");
277 printf("Setting required flags on partition... ");
279 * Set chkdsk flag, i.e. mark the partition dirty so chkdsk will run
282 flags = vol->flags | VOLUME_IS_DIRTY;
283 /* If NTFS volume version >= 2.0 then set mounted on NT4 flag. */
284 if (vol->major_ver >= 2)
285 flags |= VOLUME_MOUNTED_ON_NT4;
286 if (ntfs_volume_set_flags(vol, flags)) {
288 fprintf(stderr, "Error setting volume flags.\n");
294 printf("Going to empty the journal ($LogFile)... ");
295 if (ntfs_logfile_reset(vol)) {
297 perror("Failed to reset $LogFile");
303 if (vol->major_ver >= 3) {
304 /* FIXME: If on NTFS 3.0+, check for presence of the usn journal and
305 disable it (if present) as Win2k might be unhappy otherwise and Bad
306 Things(TM) could happen depending on what applications are actually
310 /* FIXME: Should we be marking the quota out of date, too? */
312 /* That's all for now! */
313 printf("NTFS partition %s was processed successfully.\n",
315 /* Set return code to 0. */
322 if (vol && ntfs_umount(vol, 0))