blob: 2518eedc144e574583b3e88c8896fb428e2ec90a
1 | /** |
2 | * ntfsfix - Part of the Linux-NTFS project. |
3 | * |
4 | * Copyright (c) 2000-2006 Anton Altaparmakov |
5 | * Copyright (c) 2002-2006 Szabolcs Szakacsits |
6 | * Copyright (c) 2007 Yura Pakhuchiy |
7 | * Copyright (c) 2011-2012 Jean-Pierre Andre |
8 | * |
9 | * This utility fixes some common NTFS problems, resets the NTFS journal file |
10 | * and schedules an NTFS consistency check for the first boot into Windows. |
11 | * |
12 | * Anton Altaparmakov <aia21@cantab.net> |
13 | * |
14 | * This program is free software; you can redistribute it and/or modify |
15 | * it under the terms of the GNU General Public License as published by |
16 | * the Free Software Foundation; either version 2 of the License, or |
17 | * (at your option) any later version. |
18 | * |
19 | * This program is distributed in the hope that it will be useful, |
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
22 | * GNU General Public License for more details. |
23 | * |
24 | * You should have received a copy of the GNU General Public License |
25 | * along with this program (in the main directory of the Linux-NTFS source |
26 | * in the file COPYING); if not, write to the Free Software Foundation, |
27 | * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
28 | */ |
29 | |
30 | /* |
31 | * WARNING: This program might not work on architectures which do not allow |
32 | * unaligned access. For those, the program would need to start using |
33 | * get/put_unaligned macros (#include <asm/unaligned.h>), but not doing it yet, |
34 | * since NTFS really mostly applies to ia32 only, which does allow unaligned |
35 | * accesses. We might not actually have a problem though, since the structs are |
36 | * defined as being packed so that might be enough for gcc to insert the |
37 | * correct code. |
38 | * |
39 | * If anyone using a non-little endian and/or an aligned access only CPU tries |
40 | * this program please let me know whether it works or not! |
41 | * |
42 | * Anton Altaparmakov <aia21@cantab.net> |
43 | */ |
44 | |
45 | #include "config.h" |
46 | |
47 | #ifdef HAVE_UNISTD_H |
48 | #include <unistd.h> |
49 | #endif |
50 | #ifdef HAVE_STDLIB_H |
51 | #include <stdlib.h> |
52 | #endif |
53 | #ifdef HAVE_STDIO_H |
54 | #include <stdio.h> |
55 | #endif |
56 | #ifdef HAVE_FCNTL_H |
57 | #include <fcntl.h> |
58 | #endif |
59 | #ifdef HAVE_ERRNO_H |
60 | #include <errno.h> |
61 | #endif |
62 | #ifdef HAVE_STRING_H |
63 | #include <string.h> |
64 | #endif |
65 | #ifdef HAVE_GETOPT_H |
66 | #include <getopt.h> |
67 | #endif |
68 | |
69 | #include "types.h" |
70 | #include "attrib.h" |
71 | #include "volume.h" |
72 | #include "bootsect.h" |
73 | #include "mft.h" |
74 | #include "device.h" |
75 | #include "logfile.h" |
76 | #include "runlist.h" |
77 | #include "mst.h" |
78 | #include "utils.h" |
79 | /* #include "version.h" */ |
80 | #include "logging.h" |
81 | #include "misc.h" |
82 | |
83 | #ifdef NO_NTFS_DEVICE_DEFAULT_IO_OPS |
84 | # error "No default device io operations! Cannot build ntfsfix. \ |
85 | You need to run ./configure without the --disable-default-device-io-ops \ |
86 | switch if you want to be able to build the NTFS utilities." |
87 | #endif |
88 | |
89 | #ifdef ANDROID |
90 | #define LOG_TAG "Ntfsfix" |
91 | #endif |
92 | |
93 | static const char *EXEC_NAME = "ntfsfix"; |
94 | static const char OK[] = "OK\n"; |
95 | static const char FAILED[] = "FAILED\n"; |
96 | static const char FOUND[] = "FOUND\n"; |
97 | |
98 | #define DEFAULT_SECTOR_SIZE 512 |
99 | |
100 | static struct { |
101 | char *volume; |
102 | BOOL no_action; |
103 | BOOL clear_bad_sectors; |
104 | BOOL clear_dirty; |
105 | } opt; |
106 | |
107 | /* |
108 | * Definitions for fixing the self-located MFT bug |
109 | */ |
110 | |
111 | #define SELFLOC_LIMIT 16 |
112 | |
113 | struct MFT_SELF_LOCATED { |
114 | ntfs_volume *vol; |
115 | MFT_RECORD *mft0; |
116 | MFT_RECORD *mft1; |
117 | MFT_RECORD *mft2; |
118 | ATTR_LIST_ENTRY *attrlist; |
119 | ATTR_LIST_ENTRY *attrlist_to_ref1; |
120 | MFT_REF mft_ref0; |
121 | MFT_REF mft_ref1; |
122 | LCN attrlist_lcn; |
123 | BOOL attrlist_resident; |
124 | } ; |
125 | |
126 | /** |
127 | * usage |
128 | */ |
129 | __attribute__((noreturn)) |
130 | static void usage(void) |
131 | { |
132 | ntfs_log_info("%s v%s (libntfs-3g)\n" |
133 | "\n" |
134 | "Usage: %s [options] device\n" |
135 | " Attempt to fix an NTFS partition.\n" |
136 | "\n" |
137 | " -b, --clear-bad-sectors Clear the bad sector list\n" |
138 | " -d, --clear-dirty Clear the volume dirty flag\n" |
139 | " -h, --help Display this help\n" |
140 | " -n, --no-action Do not write anything\n" |
141 | " -V, --version Display version information\n" |
142 | "\n" |
143 | "For example: %s /dev/hda6\n\n", |
144 | EXEC_NAME, VERSION, EXEC_NAME, |
145 | EXEC_NAME); |
146 | ntfs_log_info("%s%s", ntfs_bugs, ntfs_home); |
147 | exit(1); |
148 | } |
149 | |
150 | /** |
151 | * version |
152 | */ |
153 | __attribute__((noreturn)) |
154 | static void version(void) |
155 | { |
156 | ntfs_log_info("%s v%s\n\n" |
157 | "Attempt to fix an NTFS partition.\n\n" |
158 | "Copyright (c) 2000-2006 Anton Altaparmakov\n" |
159 | "Copyright (c) 2002-2006 Szabolcs Szakacsits\n" |
160 | "Copyright (c) 2007 Yura Pakhuchiy\n\n" |
161 | "Copyright (c) 2011 Jean-Pierre Andre\n\n", |
162 | EXEC_NAME, VERSION); |
163 | ntfs_log_info("%s\n%s%s", ntfs_gpl, ntfs_bugs, ntfs_home); |
164 | exit(1); |
165 | } |
166 | |
167 | /** |
168 | * parse_options |
169 | */ |
170 | static void parse_options(int argc, char **argv) |
171 | { |
172 | int c; |
173 | static const char *sopt = "-bdhnV"; |
174 | static const struct option lopt[] = { |
175 | { "help", no_argument, NULL, 'h' }, |
176 | { "no-action", no_argument, NULL, 'n' }, |
177 | { "clear-bad-sectors", no_argument, NULL, 'b' }, |
178 | { "clear-dirty", no_argument, NULL, 'd' }, |
179 | { "version", no_argument, NULL, 'V' }, |
180 | { NULL, 0, NULL, 0 } |
181 | }; |
182 | |
183 | memset(&opt, 0, sizeof(opt)); |
184 | |
185 | while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) { |
186 | switch (c) { |
187 | case 1: /* A non-option argument */ |
188 | if (!opt.volume) |
189 | opt.volume = argv[optind - 1]; |
190 | else { |
191 | ntfs_log_info("ERROR: Too many arguments.\n"); |
192 | usage(); |
193 | } |
194 | break; |
195 | case 'b': |
196 | opt.clear_bad_sectors = TRUE; |
197 | break; |
198 | case 'd': |
199 | opt.clear_dirty = TRUE; |
200 | break; |
201 | case 'n': |
202 | opt.no_action = TRUE; |
203 | break; |
204 | case 'h': |
205 | case '?': |
206 | usage(); |
207 | /* fall through */ |
208 | case 'V': |
209 | version(); |
210 | default: |
211 | ntfs_log_info("ERROR: Unknown option '%s'.\n", argv[optind - 1]); |
212 | usage(); |
213 | } |
214 | } |
215 | |
216 | if (opt.volume == NULL) { |
217 | ntfs_log_info("ERROR: You must specify a device.\n"); |
218 | usage(); |
219 | } |
220 | } |
221 | |
222 | /** |
223 | * OLD_ntfs_volume_set_flags |
224 | */ |
225 | static int OLD_ntfs_volume_set_flags(ntfs_volume *vol, const le16 flags) |
226 | { |
227 | MFT_RECORD *m = NULL; |
228 | ATTR_RECORD *a; |
229 | VOLUME_INFORMATION *c; |
230 | ntfs_attr_search_ctx *ctx; |
231 | int ret = -1; /* failure */ |
232 | |
233 | if (!vol) { |
234 | errno = EINVAL; |
235 | return -1; |
236 | } |
237 | if (ntfs_file_record_read(vol, FILE_Volume, &m, NULL)) { |
238 | ntfs_log_perror("Failed to read $Volume"); |
239 | return -1; |
240 | } |
241 | /* Sanity check */ |
242 | if (!(m->flags & MFT_RECORD_IN_USE)) { |
243 | ntfs_log_error("$Volume has been deleted. Cannot handle this " |
244 | "yet. Run chkdsk to fix this.\n"); |
245 | errno = EIO; |
246 | goto err_exit; |
247 | } |
248 | /* Get a pointer to the volume information attribute. */ |
249 | ctx = ntfs_attr_get_search_ctx(NULL, m); |
250 | if (!ctx) { |
251 | ntfs_log_debug("Failed to allocate attribute search " |
252 | "context.\n"); |
253 | goto err_exit; |
254 | } |
255 | if (ntfs_attr_lookup(AT_VOLUME_INFORMATION, AT_UNNAMED, 0, |
256 | CASE_SENSITIVE, 0, NULL, 0, ctx)) { |
257 | ntfs_log_error("Attribute $VOLUME_INFORMATION was not found in " |
258 | "$Volume!\n"); |
259 | goto err_out; |
260 | } |
261 | a = ctx->attr; |
262 | /* Sanity check. */ |
263 | if (a->non_resident) { |
264 | ntfs_log_error("Attribute $VOLUME_INFORMATION must be resident " |
265 | "(and it isn't)!\n"); |
266 | errno = EIO; |
267 | goto err_out; |
268 | } |
269 | /* Get a pointer to the value of the attribute. */ |
270 | c = (VOLUME_INFORMATION*)(le16_to_cpu(a->value_offset) + (char*)a); |
271 | /* Sanity checks. */ |
272 | if ((char*)c + le32_to_cpu(a->value_length) > |
273 | (char*)m + le32_to_cpu(m->bytes_in_use) || |
274 | le16_to_cpu(a->value_offset) + |
275 | le32_to_cpu(a->value_length) > le32_to_cpu(a->length)) { |
276 | ntfs_log_error("Attribute $VOLUME_INFORMATION in $Volume is " |
277 | "corrupt!\n"); |
278 | errno = EIO; |
279 | goto err_out; |
280 | } |
281 | /* Set the volume flags. */ |
282 | vol->flags = c->flags = flags; |
283 | if (ntfs_mft_record_write(vol, FILE_Volume, m)) { |
284 | ntfs_log_perror("Error writing $Volume"); |
285 | goto err_out; |
286 | } |
287 | ret = 0; /* success */ |
288 | err_out: |
289 | ntfs_attr_put_search_ctx(ctx); |
290 | err_exit: |
291 | free(m); |
292 | return ret; |
293 | } |
294 | |
295 | /** |
296 | * set_dirty_flag |
297 | */ |
298 | static int set_dirty_flag(ntfs_volume *vol) |
299 | { |
300 | le16 flags; |
301 | |
302 | /* Porting note: We test for the current state of VOLUME_IS_DIRTY. This |
303 | * should actually be more appropriate than testing for NVolWasDirty. */ |
304 | if (vol->flags & VOLUME_IS_DIRTY) |
305 | return 0; |
306 | ntfs_log_info("Setting required flags on partition... "); |
307 | /* |
308 | * Set chkdsk flag, i.e. mark the partition dirty so chkdsk will run |
309 | * and fix it for us. |
310 | */ |
311 | flags = vol->flags | VOLUME_IS_DIRTY; |
312 | if (!opt.no_action && OLD_ntfs_volume_set_flags(vol, flags)) { |
313 | ntfs_log_info(FAILED); |
314 | ntfs_log_error("Error setting volume flags.\n"); |
315 | return -1; |
316 | } |
317 | vol->flags = flags; |
318 | |
319 | /* Porting note: libntfs-3g does not have the 'WasDirty' flag/property, |
320 | * and never touches the 'dirty' bit except when explicitly told to do |
321 | * so. Since we just wrote the VOLUME_IS_DIRTY bit to disk, and |
322 | * vol->flags is up-to-date, we can just ignore the NVolSetWasDirty |
323 | * statement. */ |
324 | /* NVolSetWasDirty(vol); */ |
325 | |
326 | ntfs_log_info(OK); |
327 | return 0; |
328 | } |
329 | |
330 | /** |
331 | * empty_journal |
332 | */ |
333 | static int empty_journal(ntfs_volume *vol) |
334 | { |
335 | if (NVolLogFileEmpty(vol)) |
336 | return 0; |
337 | ntfs_log_info("Going to empty the journal ($LogFile)... "); |
338 | if (ntfs_logfile_reset(vol)) { |
339 | ntfs_log_info(FAILED); |
340 | ntfs_log_perror("Failed to reset $LogFile"); |
341 | return -1; |
342 | } |
343 | ntfs_log_info(OK); |
344 | return 0; |
345 | } |
346 | |
347 | /** |
348 | * Clear the bad cluster marks (option) |
349 | */ |
350 | static int clear_badclus(ntfs_volume *vol) |
351 | { |
352 | static ntfschar badstream[] = { |
353 | const_cpu_to_le16('$'), const_cpu_to_le16('B'), |
354 | const_cpu_to_le16('a'), const_cpu_to_le16('d') |
355 | } ; |
356 | ntfs_inode *ni; |
357 | ntfs_attr *na; |
358 | BOOL ok; |
359 | |
360 | ok = FALSE; |
361 | ntfs_log_info("Going to un-mark the bad clusters ($BadClus)... "); |
362 | ni = ntfs_inode_open(vol, FILE_BadClus); |
363 | if (ni) { |
364 | na = ntfs_attr_open(ni, AT_DATA, badstream, 4); |
365 | /* |
366 | * chkdsk does not adjust the data size when |
367 | * moving clusters to $BadClus, so we have to |
368 | * check the runlist. |
369 | */ |
370 | if (na && !ntfs_attr_map_whole_runlist(na)) { |
371 | if (na->rl |
372 | && na->rl[0].length && na->rl[1].length) { |
373 | /* |
374 | * Truncate the stream to free all its clusters, |
375 | * (which requires setting the data size according |
376 | * to allocation), then reallocate a sparse stream |
377 | * to full size of volume and reset the data size. |
378 | */ |
379 | na->data_size = na->allocated_size; |
380 | na->initialized_size = na->allocated_size; |
381 | if (!ntfs_attr_truncate(na,0) |
382 | && !ntfs_attr_truncate(na,vol->nr_clusters |
383 | << vol->cluster_size_bits)) { |
384 | na->data_size = 0; |
385 | na->initialized_size = 0; |
386 | ni->flags |= FILE_ATTR_SPARSE_FILE; |
387 | NInoFileNameSetDirty(ni); |
388 | ok = TRUE; |
389 | } else { |
390 | ntfs_log_perror("Failed to un-mark the bad clusters"); |
391 | } |
392 | } else { |
393 | ntfs_log_info("No bad clusters..."); |
394 | ok = TRUE; |
395 | } |
396 | ntfs_attr_close(na); |
397 | } else { |
398 | ntfs_log_perror("Failed to open $BadClus::$Bad"); |
399 | } |
400 | ntfs_inode_close(ni); |
401 | } else { |
402 | ntfs_log_perror("Failed to open inode FILE_BadClus"); |
403 | } |
404 | if (ok) |
405 | ntfs_log_info(OK); |
406 | return (ok ? 0 : -1); |
407 | } |
408 | |
409 | /** |
410 | * fix_mftmirr |
411 | */ |
412 | static int fix_mftmirr(ntfs_volume *vol) |
413 | { |
414 | s64 l, br; |
415 | unsigned char *m, *m2; |
416 | int i, ret = -1; /* failure */ |
417 | BOOL done; |
418 | |
419 | ntfs_log_info("\nProcessing $MFT and $MFTMirr...\n"); |
420 | |
421 | /* Load data from $MFT and $MFTMirr and compare the contents. */ |
422 | m = (u8*)malloc(vol->mftmirr_size << vol->mft_record_size_bits); |
423 | if (!m) { |
424 | ntfs_log_perror("Failed to allocate memory"); |
425 | return -1; |
426 | } |
427 | m2 = (u8*)malloc(vol->mftmirr_size << vol->mft_record_size_bits); |
428 | if (!m2) { |
429 | ntfs_log_perror("Failed to allocate memory"); |
430 | free(m); |
431 | return -1; |
432 | } |
433 | |
434 | ntfs_log_info("Reading $MFT... "); |
435 | l = ntfs_attr_mst_pread(vol->mft_na, 0, vol->mftmirr_size, |
436 | vol->mft_record_size, m); |
437 | if (l != vol->mftmirr_size) { |
438 | ntfs_log_info(FAILED); |
439 | if (l != -1) |
440 | errno = EIO; |
441 | ntfs_log_perror("Failed to read $MFT"); |
442 | goto error_exit; |
443 | } |
444 | ntfs_log_info(OK); |
445 | |
446 | ntfs_log_info("Reading $MFTMirr... "); |
447 | l = ntfs_attr_mst_pread(vol->mftmirr_na, 0, vol->mftmirr_size, |
448 | vol->mft_record_size, m2); |
449 | if (l != vol->mftmirr_size) { |
450 | ntfs_log_info(FAILED); |
451 | if (l != -1) |
452 | errno = EIO; |
453 | ntfs_log_perror("Failed to read $MFTMirr"); |
454 | goto error_exit; |
455 | } |
456 | ntfs_log_info(OK); |
457 | |
458 | /* |
459 | * FIXME: Need to actually check the $MFTMirr for being real. Otherwise |
460 | * we might corrupt the partition if someone is experimenting with |
461 | * software RAID and the $MFTMirr is not actually in the position we |
462 | * expect it to be... )-: |
463 | * FIXME: We should emit a warning it $MFTMirr is damaged and ask |
464 | * user whether to recreate it from $MFT or whether to abort. - The |
465 | * warning needs to include the danger of software RAID arrays. |
466 | * Maybe we should go as far as to detect whether we are running on a |
467 | * MD disk and if yes then bomb out right at the start of the program? |
468 | */ |
469 | |
470 | ntfs_log_info("Comparing $MFTMirr to $MFT... "); |
471 | done = FALSE; |
472 | for (i = 0; i < vol->mftmirr_size; ++i) { |
473 | MFT_RECORD *mrec, *mrec2; |
474 | const char *ESTR[12] = { "$MFT", "$MFTMirr", "$LogFile", |
475 | "$Volume", "$AttrDef", "root directory", "$Bitmap", |
476 | "$Boot", "$BadClus", "$Secure", "$UpCase", "$Extend" }; |
477 | const char *s; |
478 | BOOL use_mirr; |
479 | |
480 | if (i < 12) |
481 | s = ESTR[i]; |
482 | else if (i < 16) |
483 | s = "system file"; |
484 | else |
485 | s = "mft record"; |
486 | |
487 | use_mirr = FALSE; |
488 | mrec = (MFT_RECORD*)(m + i * vol->mft_record_size); |
489 | if (mrec->flags & MFT_RECORD_IN_USE) { |
490 | if (ntfs_is_baad_record(mrec->magic)) { |
491 | ntfs_log_info(FAILED); |
492 | ntfs_log_error("$MFT error: Incomplete multi " |
493 | "sector transfer detected in " |
494 | "%s.\nCannot handle this yet. " |
495 | ")-:\n", s); |
496 | goto error_exit; |
497 | } |
498 | if (!ntfs_is_mft_record(mrec->magic)) { |
499 | ntfs_log_info(FAILED); |
500 | ntfs_log_error("$MFT error: Invalid mft " |
501 | "record for %s.\nCannot " |
502 | "handle this yet. )-:\n", s); |
503 | goto error_exit; |
504 | } |
505 | } |
506 | mrec2 = (MFT_RECORD*)(m2 + i * vol->mft_record_size); |
507 | if (mrec2->flags & MFT_RECORD_IN_USE) { |
508 | if (ntfs_is_baad_record(mrec2->magic)) { |
509 | ntfs_log_info(FAILED); |
510 | ntfs_log_error("$MFTMirr error: Incomplete " |
511 | "multi sector transfer " |
512 | "detected in %s.\n", s); |
513 | goto error_exit; |
514 | } |
515 | if (!ntfs_is_mft_record(mrec2->magic)) { |
516 | ntfs_log_info(FAILED); |
517 | ntfs_log_error("$MFTMirr error: Invalid mft " |
518 | "record for %s.\n", s); |
519 | goto error_exit; |
520 | } |
521 | /* $MFT is corrupt but $MFTMirr is ok, use $MFTMirr. */ |
522 | if (!(mrec->flags & MFT_RECORD_IN_USE) && |
523 | !ntfs_is_mft_record(mrec->magic)) |
524 | use_mirr = TRUE; |
525 | } |
526 | if (memcmp(mrec, mrec2, ntfs_mft_record_get_data_size(mrec))) { |
527 | if (!done) { |
528 | done = TRUE; |
529 | ntfs_log_info(FAILED); |
530 | } |
531 | ntfs_log_info("Correcting differences in $MFT%s " |
532 | "record %d...", use_mirr ? "" : "Mirr", |
533 | i); |
534 | br = ntfs_mft_record_write(vol, i, |
535 | use_mirr ? mrec2 : mrec); |
536 | if (br) { |
537 | ntfs_log_info(FAILED); |
538 | ntfs_log_perror("Error correcting $MFT%s", |
539 | use_mirr ? "" : "Mirr"); |
540 | goto error_exit; |
541 | } |
542 | ntfs_log_info(OK); |
543 | } |
544 | } |
545 | if (!done) |
546 | ntfs_log_info(OK); |
547 | ntfs_log_info("Processing of $MFT and $MFTMirr completed " |
548 | "successfully.\n"); |
549 | ret = 0; |
550 | error_exit: |
551 | free(m); |
552 | free(m2); |
553 | return ret; |
554 | } |
555 | |
556 | /* |
557 | * Rewrite the $UpCase file as default |
558 | * |
559 | * Returns 0 if could be written |
560 | */ |
561 | |
562 | static int rewrite_upcase(ntfs_volume *vol, ntfs_attr *na) |
563 | { |
564 | s64 l; |
565 | int res; |
566 | |
567 | /* writing the $UpCase may require bitmap updates */ |
568 | res = -1; |
569 | vol->lcnbmp_ni = ntfs_inode_open(vol, FILE_Bitmap); |
570 | if (!vol->lcnbmp_ni) { |
571 | ntfs_log_perror("Failed to open bitmap inode"); |
572 | } else { |
573 | vol->lcnbmp_na = ntfs_attr_open(vol->lcnbmp_ni, AT_DATA, |
574 | AT_UNNAMED, 0); |
575 | if (!vol->lcnbmp_na) { |
576 | ntfs_log_perror("Failed to open bitmap data attribute"); |
577 | } else { |
578 | /* minimal consistency check on the bitmap */ |
579 | if (((vol->lcnbmp_na->data_size << 3) |
580 | < vol->nr_clusters) |
581 | || ((vol->lcnbmp_na->data_size << 3) |
582 | >= (vol->nr_clusters << 1)) |
583 | || (vol->lcnbmp_na->data_size |
584 | > vol->lcnbmp_na->allocated_size)) { |
585 | ntfs_log_error("Corrupt cluster map size %lld" |
586 | " (allocated %lld minimum %lld)\n", |
587 | (long long)vol->lcnbmp_na->data_size, |
588 | (long long)vol->lcnbmp_na->allocated_size, |
589 | (long long)(vol->nr_clusters + 7) >> 3); |
590 | } else { |
591 | ntfs_log_info("Rewriting $UpCase file\n"); |
592 | l = ntfs_attr_pwrite(na, 0, vol->upcase_len*2, |
593 | vol->upcase); |
594 | if (l != vol->upcase_len*2) { |
595 | ntfs_log_error("Failed to rewrite $UpCase\n"); |
596 | } else { |
597 | ntfs_log_info("$UpCase has been set to default\n"); |
598 | res = 0; |
599 | } |
600 | } |
601 | ntfs_attr_close(vol->lcnbmp_na); |
602 | vol->lcnbmp_na = (ntfs_attr*)NULL; |
603 | } |
604 | ntfs_inode_close(vol->lcnbmp_ni); |
605 | vol->lcnbmp_ni = (ntfs_inode*)NULL; |
606 | } |
607 | return (res); |
608 | } |
609 | |
610 | /* |
611 | * Fix the $UpCase file |
612 | * |
613 | * Returns 0 if the table is valid or has been fixed |
614 | */ |
615 | |
616 | static int fix_upcase(ntfs_volume *vol) |
617 | { |
618 | ntfs_inode *ni; |
619 | ntfs_attr *na; |
620 | ntfschar *upcase; |
621 | s64 l; |
622 | u32 upcase_len; |
623 | u32 k; |
624 | int res; |
625 | |
626 | res = -1; |
627 | ni = (ntfs_inode*)NULL; |
628 | na = (ntfs_attr*)NULL; |
629 | /* Now load the upcase table from $UpCase. */ |
630 | ntfs_log_debug("Loading $UpCase...\n"); |
631 | ni = ntfs_inode_open(vol, FILE_UpCase); |
632 | if (!ni) { |
633 | ntfs_log_perror("Failed to open inode FILE_UpCase"); |
634 | goto error_exit; |
635 | } |
636 | /* Get an ntfs attribute for $UpCase/$DATA. */ |
637 | na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); |
638 | if (!na) { |
639 | ntfs_log_perror("Failed to open ntfs attribute"); |
640 | goto error_exit; |
641 | } |
642 | /* |
643 | * Note: Normally, the upcase table has a length equal to 65536 |
644 | * 2-byte Unicode characters but allow for different cases, so no |
645 | * checks done. Just check we don't overflow 32-bits worth of Unicode |
646 | * characters. |
647 | */ |
648 | if (na->data_size & ~0x1ffffffffULL) { |
649 | ntfs_log_error("Error: Upcase table is too big (max 32-bit " |
650 | "allowed).\n"); |
651 | errno = EINVAL; |
652 | goto error_exit; |
653 | } |
654 | upcase_len = na->data_size >> 1; |
655 | upcase = (ntfschar*)ntfs_malloc(na->data_size); |
656 | if (!upcase) |
657 | goto error_exit; |
658 | /* Read in the $DATA attribute value into the buffer. */ |
659 | l = ntfs_attr_pread(na, 0, na->data_size, upcase); |
660 | if (l != na->data_size) { |
661 | ntfs_log_error("Failed to read $UpCase, unexpected length " |
662 | "(%lld != %lld).\n", (long long)l, |
663 | (long long)na->data_size); |
664 | errno = EIO; |
665 | goto error_exit; |
666 | } |
667 | /* Consistency check of $UpCase, restricted to plain ASCII chars */ |
668 | k = 0x20; |
669 | while ((k < upcase_len) |
670 | && (k < 0x7f) |
671 | && (le16_to_cpu(upcase[k]) |
672 | == ((k < 'a') || (k > 'z') ? k : k + 'A' - 'a'))) |
673 | k++; |
674 | if (k < 0x7f) { |
675 | ntfs_log_error("Corrupted file $UpCase\n"); |
676 | if (!opt.no_action) { |
677 | /* rewrite the $UpCase file from default */ |
678 | res = rewrite_upcase(vol, na); |
679 | /* free the bad upcase record */ |
680 | if (!res) |
681 | free(upcase); |
682 | } else { |
683 | /* keep the default upcase but return an error */ |
684 | free(upcase); |
685 | } |
686 | } else { |
687 | /* accept the upcase table read from $UpCase */ |
688 | free(vol->upcase); |
689 | vol->upcase = upcase; |
690 | vol->upcase_len = upcase_len; |
691 | res = 0; |
692 | } |
693 | error_exit : |
694 | /* Done with the $UpCase mft record. */ |
695 | if (na) |
696 | ntfs_attr_close(na); |
697 | if (ni && ntfs_inode_close(ni)) { |
698 | ntfs_log_perror("Failed to close $UpCase"); |
699 | } |
700 | return (res); |
701 | } |
702 | |
703 | /* |
704 | * Rewrite the boot sector |
705 | * |
706 | * Returns 0 if successful |
707 | */ |
708 | |
709 | static int rewrite_boot(struct ntfs_device *dev, char *full_bs, |
710 | s32 sector_size) |
711 | { |
712 | s64 bw; |
713 | int res; |
714 | |
715 | res = -1; |
716 | ntfs_log_info("Rewriting the bootsector\n"); |
717 | bw = ntfs_pwrite(dev, 0, sector_size, full_bs); |
718 | if (bw == sector_size) |
719 | res = 0; |
720 | else { |
721 | if (bw != -1) |
722 | errno = EINVAL; |
723 | if (!bw) |
724 | ntfs_log_error("Failed to rewrite the bootsector (size=0)\n"); |
725 | else |
726 | ntfs_log_perror("Error rewriting the bootsector"); |
727 | } |
728 | return (res); |
729 | } |
730 | |
731 | /* |
732 | * Locate an unnamed attribute in an MFT record |
733 | * |
734 | * Returns NULL if not found (with no error message) |
735 | */ |
736 | |
737 | static ATTR_RECORD *find_unnamed_attr(MFT_RECORD *mrec, ATTR_TYPES type) |
738 | { |
739 | ATTR_RECORD *a; |
740 | u32 offset; |
741 | |
742 | /* fetch the requested attribute */ |
743 | offset = le16_to_cpu(mrec->attrs_offset); |
744 | a = (ATTR_RECORD*)((char*)mrec + offset); |
745 | while ((a->type != AT_END) |
746 | && ((a->type != type) || a->name_length) |
747 | && (offset < le32_to_cpu(mrec->bytes_in_use))) { |
748 | offset += le32_to_cpu(a->length); |
749 | a = (ATTR_RECORD*)((char*)mrec + offset); |
750 | } |
751 | if ((a->type != type) |
752 | || a->name_length) |
753 | a = (ATTR_RECORD*)NULL; |
754 | return (a); |
755 | } |
756 | |
757 | /* |
758 | * First condition for having a self-located MFT : |
759 | * only 16 MFT records are defined in MFT record 0 |
760 | * |
761 | * Only low-level library functions can be used. |
762 | * |
763 | * Returns TRUE if the condition is met. |
764 | */ |
765 | |
766 | static BOOL short_mft_selfloc_condition(struct MFT_SELF_LOCATED *selfloc) |
767 | { |
768 | BOOL ok; |
769 | ntfs_volume *vol; |
770 | MFT_RECORD *mft0; |
771 | ATTR_RECORD *a; |
772 | runlist_element *rl; |
773 | u16 seqn; |
774 | |
775 | ok = FALSE; |
776 | vol = selfloc->vol; |
777 | mft0 = selfloc->mft0; |
778 | if ((ntfs_pread(vol->dev, |
779 | vol->mft_lcn << vol->cluster_size_bits, |
780 | vol->mft_record_size, mft0) |
781 | == vol->mft_record_size) |
782 | && !ntfs_mst_post_read_fixup((NTFS_RECORD*)mft0, |
783 | vol->mft_record_size)) { |
784 | a = find_unnamed_attr(mft0,AT_DATA); |
785 | if (a |
786 | && a->non_resident |
787 | && (((le64_to_cpu(a->highest_vcn) + 1) |
788 | << vol->cluster_size_bits) |
789 | == (SELFLOC_LIMIT*vol->mft_record_size))) { |
790 | rl = ntfs_mapping_pairs_decompress(vol, a, NULL); |
791 | if (rl) { |
792 | /* |
793 | * The first error condition is having only |
794 | * 16 entries mapped in the first MFT record. |
795 | */ |
796 | if ((rl[0].lcn >= 0) |
797 | && ((rl[0].length << vol->cluster_size_bits) |
798 | == SELFLOC_LIMIT*vol->mft_record_size) |
799 | && (rl[1].vcn == rl[0].length) |
800 | && (rl[1].lcn == LCN_RL_NOT_MAPPED)) { |
801 | ok = TRUE; |
802 | seqn = le16_to_cpu( |
803 | mft0->sequence_number); |
804 | selfloc->mft_ref0 |
805 | = ((MFT_REF)seqn) << 48; |
806 | } |
807 | free(rl); |
808 | } |
809 | } |
810 | } |
811 | return (ok); |
812 | } |
813 | |
814 | /* |
815 | * Second condition for having a self-located MFT : |
816 | * The 16th MFT record is defined in MFT record >= 16 |
817 | * |
818 | * Only low-level library functions can be used. |
819 | * |
820 | * Returns TRUE if the condition is met. |
821 | */ |
822 | |
823 | static BOOL attrlist_selfloc_condition(struct MFT_SELF_LOCATED *selfloc) |
824 | { |
825 | ntfs_volume *vol; |
826 | ATTR_RECORD *a; |
827 | ATTR_LIST_ENTRY *attrlist; |
828 | ATTR_LIST_ENTRY *al; |
829 | runlist_element *rl; |
830 | VCN vcn; |
831 | leVCN levcn; |
832 | u32 length; |
833 | int ok; |
834 | |
835 | ok = FALSE; |
836 | length = 0; |
837 | vol = selfloc->vol; |
838 | a = find_unnamed_attr(selfloc->mft0,AT_ATTRIBUTE_LIST); |
839 | if (a) { |
840 | selfloc->attrlist_resident = !a->non_resident; |
841 | selfloc->attrlist_lcn = 0; |
842 | if (a->non_resident) { |
843 | attrlist = selfloc->attrlist; |
844 | rl = ntfs_mapping_pairs_decompress(vol, a, NULL); |
845 | if (rl |
846 | && (rl->lcn >= 0) |
847 | && (le64_to_cpu(a->data_size) < vol->cluster_size) |
848 | && (ntfs_pread(vol->dev, |
849 | rl->lcn << vol->cluster_size_bits, |
850 | vol->cluster_size, attrlist) == vol->cluster_size)) { |
851 | selfloc->attrlist_lcn = rl->lcn; |
852 | al = attrlist; |
853 | length = le64_to_cpu(a->data_size); |
854 | } |
855 | } else { |
856 | al = (ATTR_LIST_ENTRY*) |
857 | ((char*)a + le16_to_cpu(a->value_offset)); |
858 | length = le32_to_cpu(a->value_length); |
859 | } |
860 | if (length) { |
861 | /* search for a data attribute defining entry 16 */ |
862 | vcn = (SELFLOC_LIMIT*vol->mft_record_size) |
863 | >> vol->cluster_size_bits; |
864 | levcn = cpu_to_le64(vcn); |
865 | while ((length > 0) |
866 | && al->length |
867 | && ((al->type != AT_DATA) |
868 | || ((leVCN)al->lowest_vcn != levcn))) { |
869 | length -= le16_to_cpu(al->length); |
870 | al = (ATTR_LIST_ENTRY*) |
871 | ((char*)al + le16_to_cpu(al->length)); |
872 | } |
873 | if ((length > 0) |
874 | && al->length |
875 | && (al->type == AT_DATA) |
876 | && !al->name_length |
877 | && ((leVCN)al->lowest_vcn == levcn) |
878 | && (MREF_LE(al->mft_reference) >= SELFLOC_LIMIT)) { |
879 | selfloc->mft_ref1 |
880 | = le64_to_cpu(al->mft_reference); |
881 | selfloc->attrlist_to_ref1 = al; |
882 | ok = TRUE; |
883 | } |
884 | } |
885 | } |
886 | return (ok); |
887 | } |
888 | |
889 | /* |
890 | * Third condition for having a self-located MFT : |
891 | * The location of the second part of the MFT is defined in itself |
892 | * |
893 | * To locate the second part, we have to assume the first and the |
894 | * second part of the MFT data are contiguous. |
895 | * |
896 | * Only low-level library functions can be used. |
897 | * |
898 | * Returns TRUE if the condition is met. |
899 | */ |
900 | |
901 | static BOOL self_mapped_selfloc_condition(struct MFT_SELF_LOCATED *selfloc) |
902 | { |
903 | BOOL ok; |
904 | s64 inum; |
905 | u64 offs; |
906 | VCN lowest_vcn; |
907 | MFT_RECORD *mft1; |
908 | ATTR_RECORD *a; |
909 | ntfs_volume *vol; |
910 | runlist_element *rl; |
911 | |
912 | ok = FALSE; |
913 | vol = selfloc->vol; |
914 | mft1 = selfloc->mft1; |
915 | inum = MREF(selfloc->mft_ref1); |
916 | offs = (vol->mft_lcn << vol->cluster_size_bits) |
917 | + (inum << vol->mft_record_size_bits); |
918 | if ((ntfs_pread(vol->dev, offs, vol->mft_record_size, |
919 | mft1) == vol->mft_record_size) |
920 | && !ntfs_mst_post_read_fixup((NTFS_RECORD*)mft1, |
921 | vol->mft_record_size)) { |
922 | lowest_vcn = (SELFLOC_LIMIT*vol->mft_record_size) |
923 | >> vol->cluster_size_bits; |
924 | a = find_unnamed_attr(mft1,AT_DATA); |
925 | if (a |
926 | && (mft1->flags & MFT_RECORD_IN_USE) |
927 | && ((VCN)le64_to_cpu(a->lowest_vcn) == lowest_vcn) |
928 | && (le64_to_cpu(mft1->base_mft_record) |
929 | == selfloc->mft_ref0) |
930 | && ((u16)MSEQNO(selfloc->mft_ref1) |
931 | == le16_to_cpu(mft1->sequence_number))) { |
932 | rl = ntfs_mapping_pairs_decompress(vol, a, NULL); |
933 | if ((rl[0].lcn == LCN_RL_NOT_MAPPED) |
934 | && !rl[0].vcn |
935 | && (rl[0].length == lowest_vcn) |
936 | && (rl[1].vcn == lowest_vcn) |
937 | && ((u64)(rl[1].lcn << vol->cluster_size_bits) |
938 | <= offs) |
939 | && ((u64)((rl[1].lcn + rl[1].length) |
940 | << vol->cluster_size_bits) > offs)) { |
941 | ok = TRUE; |
942 | } |
943 | } |
944 | } |
945 | return (ok); |
946 | } |
947 | |
948 | /* |
949 | * Fourth condition, to be able to fix a self-located MFT : |
950 | * The MFT record 15 must be available. |
951 | * |
952 | * The MFT record 15 is expected to be marked in use, we assume |
953 | * it is available if it has no parent, no name and no attr list. |
954 | * |
955 | * Only low-level library functions can be used. |
956 | * |
957 | * Returns TRUE if the condition is met. |
958 | */ |
959 | |
960 | static BOOL spare_record_selfloc_condition(struct MFT_SELF_LOCATED *selfloc) |
961 | { |
962 | BOOL ok; |
963 | s64 inum; |
964 | u64 offs; |
965 | MFT_RECORD *mft2; |
966 | ntfs_volume *vol; |
967 | |
968 | ok = FALSE; |
969 | vol = selfloc->vol; |
970 | mft2 = selfloc->mft2; |
971 | inum = SELFLOC_LIMIT - 1; |
972 | offs = (vol->mft_lcn << vol->cluster_size_bits) |
973 | + (inum << vol->mft_record_size_bits); |
974 | if ((ntfs_pread(vol->dev, offs, vol->mft_record_size, |
975 | mft2) == vol->mft_record_size) |
976 | && !ntfs_mst_post_read_fixup((NTFS_RECORD*)mft2, |
977 | vol->mft_record_size)) { |
978 | if (!mft2->base_mft_record |
979 | && (mft2->flags & MFT_RECORD_IN_USE) |
980 | && !find_unnamed_attr(mft2,AT_ATTRIBUTE_LIST) |
981 | && !find_unnamed_attr(mft2,AT_FILE_NAME)) { |
982 | ok = TRUE; |
983 | } |
984 | } |
985 | return (ok); |
986 | } |
987 | |
988 | /* |
989 | * Fix a self-located MFT by swapping two MFT records |
990 | * |
991 | * Only low-level library functions can be used. |
992 | * |
993 | * Returns 0 if the MFT corruption could be fixed. |
994 | */ |
995 | static int fix_selfloc_conditions(struct MFT_SELF_LOCATED *selfloc) |
996 | { |
997 | MFT_RECORD *mft1; |
998 | MFT_RECORD *mft2; |
999 | ATTR_RECORD *a; |
1000 | ATTR_LIST_ENTRY *al; |
1001 | ntfs_volume *vol; |
1002 | s64 offs; |
1003 | s64 offsm; |
1004 | s64 offs1; |
1005 | s64 offs2; |
1006 | s64 inum; |
1007 | u16 usa_ofs; |
1008 | int res; |
1009 | |
1010 | res = 0; |
1011 | /* |
1012 | * In MFT1, we must fix : |
1013 | * - the self-reference, if present, |
1014 | * - its own sequence number, must be 15 |
1015 | * - the sizes of the data attribute. |
1016 | */ |
1017 | vol = selfloc->vol; |
1018 | mft1 = selfloc->mft1; |
1019 | mft2 = selfloc->mft2; |
1020 | usa_ofs = le16_to_cpu(mft1->usa_ofs); |
1021 | if (usa_ofs >= 48) |
1022 | mft1->mft_record_number = const_cpu_to_le32(SELFLOC_LIMIT - 1); |
1023 | mft1->sequence_number = const_cpu_to_le16(SELFLOC_LIMIT - 1); |
1024 | a = find_unnamed_attr(mft1,AT_DATA); |
1025 | if (a) { |
1026 | a->allocated_size = const_cpu_to_le64(0); |
1027 | a->data_size = const_cpu_to_le64(0); |
1028 | a->initialized_size = const_cpu_to_le64(0); |
1029 | } else |
1030 | res = -1; /* bug : it has been found earlier */ |
1031 | |
1032 | /* |
1033 | * In MFT2, we must fix : |
1034 | * - the self-reference, if present |
1035 | */ |
1036 | usa_ofs = le16_to_cpu(mft2->usa_ofs); |
1037 | if (usa_ofs >= 48) |
1038 | mft2->mft_record_number = cpu_to_le32(MREF(selfloc->mft_ref1)); |
1039 | |
1040 | /* |
1041 | * In the attribute list, we must fix : |
1042 | * - the reference to MFT1 |
1043 | */ |
1044 | al = selfloc->attrlist_to_ref1; |
1045 | al->mft_reference = MK_LE_MREF(SELFLOC_LIMIT - 1, SELFLOC_LIMIT - 1); |
1046 | |
1047 | /* |
1048 | * All fixes done, we can write all if allowed |
1049 | */ |
1050 | if (!res && !opt.no_action) { |
1051 | inum = SELFLOC_LIMIT - 1; |
1052 | offs2 = (vol->mft_lcn << vol->cluster_size_bits) |
1053 | + (inum << vol->mft_record_size_bits); |
1054 | inum = MREF(selfloc->mft_ref1); |
1055 | offs1 = (vol->mft_lcn << vol->cluster_size_bits) |
1056 | + (inum << vol->mft_record_size_bits); |
1057 | |
1058 | /* rewrite the attribute list */ |
1059 | if (selfloc->attrlist_resident) { |
1060 | /* write mft0 and mftmirr if it is resident */ |
1061 | offs = vol->mft_lcn << vol->cluster_size_bits; |
1062 | offsm = vol->mftmirr_lcn << vol->cluster_size_bits; |
1063 | if (ntfs_mst_pre_write_fixup( |
1064 | (NTFS_RECORD*)selfloc->mft0, |
1065 | vol->mft_record_size) |
1066 | || (ntfs_pwrite(vol->dev, offs, vol->mft_record_size, |
1067 | selfloc->mft0) != vol->mft_record_size) |
1068 | || (ntfs_pwrite(vol->dev, offsm, vol->mft_record_size, |
1069 | selfloc->mft0) != vol->mft_record_size)) |
1070 | res = -1; |
1071 | } else { |
1072 | /* write a full cluster if non resident */ |
1073 | offs = selfloc->attrlist_lcn << vol->cluster_size_bits; |
1074 | if (ntfs_pwrite(vol->dev, offs, vol->cluster_size, |
1075 | selfloc->attrlist) != vol->cluster_size) |
1076 | res = -1; |
1077 | } |
1078 | /* replace MFT2 by MFT1 and replace MFT1 by MFT2 */ |
1079 | if (!res |
1080 | && (ntfs_mst_pre_write_fixup((NTFS_RECORD*)selfloc->mft1, |
1081 | vol->mft_record_size) |
1082 | || ntfs_mst_pre_write_fixup((NTFS_RECORD*)selfloc->mft2, |
1083 | vol->mft_record_size) |
1084 | || (ntfs_pwrite(vol->dev, offs2, vol->mft_record_size, |
1085 | mft1) != vol->mft_record_size) |
1086 | || (ntfs_pwrite(vol->dev, offs1, vol->mft_record_size, |
1087 | mft2) != vol->mft_record_size))) |
1088 | res = -1; |
1089 | } |
1090 | return (res); |
1091 | } |
1092 | |
1093 | /* |
1094 | * Detect and fix a Windows XP bug, leading to a corrupt MFT |
1095 | * |
1096 | * Windows cannot boot anymore, so chkdsk cannot be started, which |
1097 | * is a good point, because chkdsk would have deleted all the files. |
1098 | * Older ntfs-3g fell into an endless recursion (recent versions |
1099 | * refuse to mount). |
1100 | * |
1101 | * This situation is very rare, but it was fun to fix it. |
1102 | * |
1103 | * The corrupted condition is : |
1104 | * - MFT entry 0 has only the runlist for MFT entries 0-15 |
1105 | * - The attribute list for MFT shows the second part |
1106 | * in an MFT record beyond 15 |
1107 | * Of course, this record has to be read in order to know where it is. |
1108 | * |
1109 | * Sample case, met in 2011 (Windows XP) : |
1110 | * MFT record 0 has : stdinfo, nonres attrlist, the first |
1111 | * part of MFT data (entries 0-15), and bitmap |
1112 | * MFT record 16 has the name |
1113 | * MFT record 17 has the third part of MFT data (16-117731) |
1114 | * MFT record 18 has the second part of MFT data (117732-170908) |
1115 | * |
1116 | * Assuming the second part of the MFT is contiguous to the first |
1117 | * part, we can find it, and fix the condition by relocating it |
1118 | * and swapping it with MFT record 15. |
1119 | * This record number 15 appears to be hardcoded into Windows NTFS. |
1120 | * |
1121 | * Only low-level library functions can be used. |
1122 | * |
1123 | * Returns 0 if the conditions for the error were not met or |
1124 | * the error could be fixed, |
1125 | * -1 if some error was encountered |
1126 | */ |
1127 | |
1128 | static int fix_self_located_mft(ntfs_volume *vol) |
1129 | { |
1130 | struct MFT_SELF_LOCATED selfloc; |
1131 | BOOL res; |
1132 | |
1133 | ntfs_log_info("Checking for self-located MFT segment... "); |
1134 | res = -1; |
1135 | selfloc.vol = vol; |
1136 | selfloc.mft0 = (MFT_RECORD*)malloc(vol->mft_record_size); |
1137 | selfloc.mft1 = (MFT_RECORD*)malloc(vol->mft_record_size); |
1138 | selfloc.mft2 = (MFT_RECORD*)malloc(vol->mft_record_size); |
1139 | selfloc.attrlist = (ATTR_LIST_ENTRY*)malloc(vol->cluster_size); |
1140 | if (selfloc.mft0 && selfloc.mft1 && selfloc.mft2 |
1141 | && selfloc.attrlist) { |
1142 | if (short_mft_selfloc_condition(&selfloc) |
1143 | && attrlist_selfloc_condition(&selfloc) |
1144 | && self_mapped_selfloc_condition(&selfloc) |
1145 | && spare_record_selfloc_condition(&selfloc)) { |
1146 | ntfs_log_info(FOUND); |
1147 | ntfs_log_info("Fixing the self-located MFT segment... "); |
1148 | res = fix_selfloc_conditions(&selfloc); |
1149 | ntfs_log_info(res ? FAILED : OK); |
1150 | } else { |
1151 | ntfs_log_info(OK); |
1152 | res = 0; |
1153 | } |
1154 | free(selfloc.mft0); |
1155 | free(selfloc.mft1); |
1156 | free(selfloc.mft2); |
1157 | free(selfloc.attrlist); |
1158 | } |
1159 | return (res); |
1160 | } |
1161 | |
1162 | /* |
1163 | * Try an alternate boot sector and fix the real one |
1164 | * |
1165 | * Only after successful checks is the boot sector rewritten. |
1166 | * |
1167 | * The alternate boot sector is not rewritten, either because it |
1168 | * was found correct, or because we truncated the file system |
1169 | * and the last actual sector might be part of some file. |
1170 | * |
1171 | * Returns 0 if successful |
1172 | */ |
1173 | |
1174 | static int try_fix_boot(ntfs_volume *vol, char *full_bs, |
1175 | s64 read_sector, s64 fix_sectors, s32 sector_size) |
1176 | { |
1177 | s64 br; |
1178 | int res; |
1179 | s64 got_sectors; |
1180 | le16 sector_size_le; |
1181 | NTFS_BOOT_SECTOR *bs; |
1182 | |
1183 | res = -1; |
1184 | br = ntfs_pread(vol->dev, read_sector*sector_size, |
1185 | sector_size, full_bs); |
1186 | if (br != sector_size) { |
1187 | if (br != -1) |
1188 | errno = EINVAL; |
1189 | if (!br) |
1190 | ntfs_log_error("Failed to read alternate bootsector (size=0)\n"); |
1191 | else |
1192 | ntfs_log_perror("Error reading alternate bootsector"); |
1193 | } else { |
1194 | bs = (NTFS_BOOT_SECTOR*)full_bs; |
1195 | got_sectors = le64_to_cpu(bs->number_of_sectors); |
1196 | bs->number_of_sectors = cpu_to_le64(fix_sectors); |
1197 | /* alignment problem on Sparc, even doing memcpy() */ |
1198 | sector_size_le = cpu_to_le16(sector_size); |
1199 | if (!memcmp(§or_size_le, &bs->bpb.bytes_per_sector,2) |
1200 | && ntfs_boot_sector_is_ntfs(bs) |
1201 | && !ntfs_boot_sector_parse(vol, bs)) { |
1202 | ntfs_log_info("The alternate bootsector is usable\n"); |
1203 | if (fix_sectors != got_sectors) |
1204 | ntfs_log_info("Set sector count to %lld instead of %lld\n", |
1205 | (long long)fix_sectors, |
1206 | (long long)got_sectors); |
1207 | /* fix the normal boot sector */ |
1208 | if (!opt.no_action) { |
1209 | res = rewrite_boot(vol->dev, full_bs, |
1210 | sector_size); |
1211 | } else |
1212 | res = 0; |
1213 | } |
1214 | if (!res && !opt.no_action) |
1215 | ntfs_log_info("The boot sector has been rewritten\n"); |
1216 | } |
1217 | return (res); |
1218 | } |
1219 | |
1220 | /* |
1221 | * Try the alternate boot sector if the normal one is bad |
1222 | * |
1223 | * Actually : |
1224 | * - first try the last sector of the partition (expected location) |
1225 | * - then try the last sector as shown in the main boot sector, |
1226 | * (could be meaningful for an undersized partition) |
1227 | * - finally try truncating the file system actual size of partition |
1228 | * (could be meaningful for an oversized partition) |
1229 | * |
1230 | * if successful, rewrite the normal boot sector accordingly |
1231 | * |
1232 | * Returns 0 if successful |
1233 | */ |
1234 | |
1235 | static int try_alternate_boot(ntfs_volume *vol, char *full_bs, |
1236 | s32 sector_size, s64 shown_sectors) |
1237 | { |
1238 | s64 actual_sectors; |
1239 | int res; |
1240 | |
1241 | res = -1; |
1242 | ntfs_log_info("Trying the alternate boot sector\n"); |
1243 | |
1244 | /* |
1245 | * We do not rely on the sector size defined in the |
1246 | * boot sector, supposed to be corrupt, so we try to get |
1247 | * the actual sector size and defaulting to 512 if failed |
1248 | * to get. This value is only used to guess the alternate |
1249 | * boot sector location and it is checked against the |
1250 | * value found in the sector itself. It should not damage |
1251 | * anything if wrong. |
1252 | * |
1253 | * Note : the real last sector is not accounted for here. |
1254 | */ |
1255 | actual_sectors = ntfs_device_size_get(vol->dev,sector_size) - 1; |
1256 | |
1257 | /* first try the actual last sector */ |
1258 | if ((actual_sectors > 0) |
1259 | && !try_fix_boot(vol, full_bs, actual_sectors, |
1260 | actual_sectors, sector_size)) |
1261 | res = 0; |
1262 | |
1263 | /* then try the shown last sector, if less than actual */ |
1264 | if (res |
1265 | && (shown_sectors > 0) |
1266 | && (shown_sectors < actual_sectors) |
1267 | && !try_fix_boot(vol, full_bs, shown_sectors, |
1268 | shown_sectors, sector_size)) |
1269 | res = 0; |
1270 | |
1271 | /* then try reducing the number of sectors to actual value */ |
1272 | if (res |
1273 | && (shown_sectors > actual_sectors) |
1274 | && !try_fix_boot(vol, full_bs, 0, actual_sectors, sector_size)) |
1275 | res = 0; |
1276 | |
1277 | return (res); |
1278 | } |
1279 | |
1280 | /* |
1281 | * Check and fix the alternate boot sector |
1282 | * |
1283 | * The alternate boot sector is usually in the last sector of a |
1284 | * partition, which should not be used by the file system |
1285 | * (the sector count in the boot sector should be less than |
1286 | * the total sector count in the partition). |
1287 | * |
1288 | * chkdsk never changes the count in the boot sector. |
1289 | * - If this is less than the total count, chkdsk place the |
1290 | * alternate boot sector into the sector, |
1291 | * - if the count is the same as the total count, chkdsk place |
1292 | * the alternate boot sector into the middle sector (half |
1293 | * the total count rounded upwards) |
1294 | * - if the count is greater than the total count, chkdsk |
1295 | * declares the file system as raw, and refuses to fix anything. |
1296 | * |
1297 | * Here, we check and fix the alternate boot sector, only in the |
1298 | * first situation where the file system does not overflow on the |
1299 | * last sector. |
1300 | * |
1301 | * Note : when shrinking a partition, ntfsresize cannot determine |
1302 | * the future size of the partition. As a consequence the number of |
1303 | * sectors in the boot sectors may be less than the possible size. |
1304 | * |
1305 | * Returns 0 if successful |
1306 | */ |
1307 | |
1308 | static int check_alternate_boot(ntfs_volume *vol) |
1309 | { |
1310 | #if 0 |
1311 | s64 got_sectors; |
1312 | s64 actual_sectors; |
1313 | s64 last_sector_off; |
1314 | char *full_bs; |
1315 | char *alt_bs; |
1316 | NTFS_BOOT_SECTOR *bs; |
1317 | s64 br; |
1318 | s64 bw; |
1319 | int res; |
1320 | |
1321 | res = -1; |
1322 | full_bs = (char*)malloc(vol->sector_size); |
1323 | alt_bs = (char*)malloc(vol->sector_size); |
1324 | if (!full_bs || !alt_bs) { |
1325 | ntfs_log_info("Error : failed to allocate memory\n"); |
1326 | goto error_exit; |
1327 | } |
1328 | /* Now read both bootsectors. */ |
1329 | br = ntfs_pread(vol->dev, 0, vol->sector_size, full_bs); |
1330 | if (br == vol->sector_size) { |
1331 | bs = (NTFS_BOOT_SECTOR*)full_bs; |
1332 | got_sectors = le64_to_cpu(bs->number_of_sectors); |
1333 | actual_sectors = ntfs_device_size_get(vol->dev, |
1334 | vol->sector_size); |
1335 | if (actual_sectors > got_sectors) { |
1336 | last_sector_off = (actual_sectors - 1) |
1337 | << vol->sector_size_bits; |
1338 | ntfs_log_info("Checking the alternate boot sector... "); |
1339 | br = ntfs_pread(vol->dev, last_sector_off, |
1340 | vol->sector_size, alt_bs); |
1341 | } else { |
1342 | ntfs_log_info("Checking file system overflow... "); |
1343 | br = -1; |
1344 | } |
1345 | /* accept getting no byte, needed for short image files */ |
1346 | if (br >= 0) { |
1347 | if ((br != vol->sector_size) |
1348 | || memcmp(full_bs, alt_bs, vol->sector_size)) { |
1349 | if (opt.no_action) { |
1350 | ntfs_log_info("BAD\n"); |
1351 | } else { |
1352 | bw = ntfs_pwrite(vol->dev, |
1353 | last_sector_off, |
1354 | vol->sector_size, full_bs); |
1355 | if (bw == vol->sector_size) { |
1356 | ntfs_log_info("FIXED\n"); |
1357 | res = 0; |
1358 | } else { |
1359 | ntfs_log_info(FAILED); |
1360 | } |
1361 | } |
1362 | } else { |
1363 | ntfs_log_info(OK); |
1364 | res = 0; |
1365 | } |
1366 | } else { |
1367 | ntfs_log_info(FAILED); |
1368 | } |
1369 | } else { |
1370 | ntfs_log_info("Error : could not read the boot sector again\n"); |
1371 | } |
1372 | free(full_bs); |
1373 | free(alt_bs); |
1374 | |
1375 | error_exit : |
1376 | return (res); |
1377 | #endif |
1378 | return (0); |
1379 | } |
1380 | |
1381 | /* |
1382 | * Try to fix problems which may arise in the start up sequence |
1383 | * |
1384 | * This is a replay of the normal start up sequence with fixes when |
1385 | * some problem arise. |
1386 | */ |
1387 | |
1388 | static int fix_startup(struct ntfs_device *dev, unsigned long flags) |
1389 | { |
1390 | s64 br; |
1391 | ntfs_volume *vol; |
1392 | BOOL dev_open; |
1393 | s64 shown_sectors; |
1394 | char *full_bs; |
1395 | NTFS_BOOT_SECTOR *bs; |
1396 | s32 sector_size; |
1397 | int res; |
1398 | int eo; |
1399 | |
1400 | errno = 0; |
1401 | res = -1; |
1402 | dev_open = FALSE; |
1403 | full_bs = (char*)NULL; |
1404 | if (!dev || !dev->d_ops || !dev->d_name) { |
1405 | errno = EINVAL; |
1406 | ntfs_log_perror("%s: dev = %p", __FUNCTION__, dev); |
1407 | vol = (ntfs_volume*)NULL; |
1408 | goto error_exit; |
1409 | } |
1410 | |
1411 | /* Allocate the volume structure. */ |
1412 | vol = ntfs_volume_alloc(); |
1413 | if (!vol) |
1414 | goto error_exit; |
1415 | |
1416 | /* Create the default upcase table. */ |
1417 | vol->upcase_len = ntfs_upcase_build_default(&vol->upcase); |
1418 | if (!vol->upcase_len || !vol->upcase) |
1419 | goto error_exit; |
1420 | |
1421 | /* Default with no locase table and case sensitive file names */ |
1422 | vol->locase = (ntfschar*)NULL; |
1423 | NVolSetCaseSensitive(vol); |
1424 | |
1425 | /* by default, all files are shown and not marked hidden */ |
1426 | NVolSetShowSysFiles(vol); |
1427 | NVolSetShowHidFiles(vol); |
1428 | NVolClearHideDotFiles(vol); |
1429 | if (flags & NTFS_MNT_RDONLY) |
1430 | NVolSetReadOnly(vol); |
1431 | |
1432 | /* ...->open needs bracketing to compile with glibc 2.7 */ |
1433 | if ((dev->d_ops->open)(dev, NVolReadOnly(vol) ? O_RDONLY: O_RDWR)) { |
1434 | ntfs_log_perror("Error opening '%s'", dev->d_name); |
1435 | goto error_exit; |
1436 | } |
1437 | dev_open = TRUE; |
1438 | /* Attach the device to the volume. */ |
1439 | vol->dev = dev; |
1440 | |
1441 | sector_size = ntfs_device_sector_size_get(dev); |
1442 | if (sector_size <= 0) |
1443 | sector_size = DEFAULT_SECTOR_SIZE; |
1444 | full_bs = (char*)malloc(sector_size); |
1445 | if (!full_bs) |
1446 | goto error_exit; |
1447 | /* Now read the bootsector. */ |
1448 | br = ntfs_pread(dev, 0, sector_size, full_bs); |
1449 | if (br != sector_size) { |
1450 | if (br != -1) |
1451 | errno = EINVAL; |
1452 | if (!br) |
1453 | ntfs_log_error("Failed to read bootsector (size=0)\n"); |
1454 | else |
1455 | ntfs_log_perror("Error reading bootsector"); |
1456 | goto error_exit; |
1457 | } |
1458 | bs = (NTFS_BOOT_SECTOR*)full_bs; |
1459 | if (!ntfs_boot_sector_is_ntfs(bs) |
1460 | /* get the bootsector data, only fails when inconsistent */ |
1461 | || (ntfs_boot_sector_parse(vol, bs) < 0)) { |
1462 | shown_sectors = le64_to_cpu(bs->number_of_sectors); |
1463 | /* boot sector is wrong, try the alternate boot sector */ |
1464 | if (try_alternate_boot(vol, full_bs, sector_size, |
1465 | shown_sectors)) { |
1466 | errno = EINVAL; |
1467 | goto error_exit; |
1468 | } |
1469 | res = 0; |
1470 | } else { |
1471 | res = fix_self_located_mft(vol); |
1472 | } |
1473 | error_exit: |
1474 | if (res) { |
1475 | switch (errno) { |
1476 | case ENOMEM : |
1477 | ntfs_log_error("Failed to allocate memory\n"); |
1478 | break; |
1479 | case EINVAL : |
1480 | ntfs_log_error("Unrecoverable error\n"); |
1481 | break; |
1482 | default : |
1483 | break; |
1484 | } |
1485 | } |
1486 | eo = errno; |
1487 | free(full_bs); |
1488 | if (vol) { |
1489 | free(vol->upcase); |
1490 | free(vol); |
1491 | } |
1492 | if (dev_open) { |
1493 | (dev->d_ops->close)(dev); |
1494 | } |
1495 | errno = eo; |
1496 | return (res); |
1497 | } |
1498 | |
1499 | /** |
1500 | * fix_mount |
1501 | */ |
1502 | static int fix_mount(void) |
1503 | { |
1504 | int ret = 0; /* default success */ |
1505 | ntfs_volume *vol; |
1506 | struct ntfs_device *dev; |
1507 | unsigned long flags; |
1508 | |
1509 | ntfs_log_info("Attempting to correct errors... "); |
1510 | |
1511 | dev = ntfs_device_alloc(opt.volume, 0, &ntfs_device_default_io_ops, |
1512 | NULL); |
1513 | if (!dev) { |
1514 | ntfs_log_info(FAILED); |
1515 | ntfs_log_perror("Failed to allocate device"); |
1516 | return -1; |
1517 | } |
1518 | flags = (opt.no_action ? NTFS_MNT_RDONLY : 0); |
1519 | vol = ntfs_volume_startup(dev, flags); |
1520 | if (!vol) { |
1521 | ntfs_log_info(FAILED); |
1522 | ntfs_log_perror("Failed to startup volume"); |
1523 | |
1524 | /* Try fixing the bootsector and MFT, then redo the startup */ |
1525 | if (!fix_startup(dev, flags)) { |
1526 | if (opt.no_action) |
1527 | ntfs_log_info("The startup data can be fixed, " |
1528 | "but no change was requested\n"); |
1529 | else |
1530 | vol = ntfs_volume_startup(dev, flags); |
1531 | } |
1532 | if (!vol) { |
1533 | ntfs_log_error("Volume is corrupt. You should run chkdsk.\n"); |
1534 | ntfs_device_free(dev); |
1535 | return -1; |
1536 | } |
1537 | if (opt.no_action) |
1538 | ret = -1; /* error present and not fixed */ |
1539 | } |
1540 | /* if option -n proceed despite errors, to display them all */ |
1541 | if ((!ret || opt.no_action) && (fix_mftmirr(vol) < 0)) |
1542 | ret = -1; |
1543 | if ((!ret || opt.no_action) && (fix_upcase(vol) < 0)) |
1544 | ret = -1; |
1545 | if ((!ret || opt.no_action) && (set_dirty_flag(vol) < 0)) |
1546 | ret = -1; |
1547 | if ((!ret || opt.no_action) && (empty_journal(vol) < 0)) |
1548 | ret = -1; |
1549 | /* |
1550 | * ntfs_umount() will invoke ntfs_device_free() for us. |
1551 | * Ignore the returned error resulting from partial mounting. |
1552 | */ |
1553 | ntfs_umount(vol, 1); |
1554 | return ret; |
1555 | } |
1556 | |
1557 | /** |
1558 | * main |
1559 | */ |
1560 | int main(int argc, char **argv) |
1561 | { |
1562 | ntfs_volume *vol; |
1563 | unsigned long mnt_flags; |
1564 | unsigned long flags; |
1565 | int ret = 1; /* failure */ |
1566 | BOOL force = FALSE; |
1567 | |
1568 | ntfs_log_set_handler(ntfs_log_handler_outerr); |
1569 | |
1570 | parse_options(argc, argv); |
1571 | |
1572 | if (!ntfs_check_if_mounted(opt.volume, &mnt_flags)) { |
1573 | if ((mnt_flags & NTFS_MF_MOUNTED) && |
1574 | !(mnt_flags & NTFS_MF_READONLY) && !force) { |
1575 | ntfs_log_error("Refusing to operate on read-write " |
1576 | "mounted device %s.\n", opt.volume); |
1577 | exit(1); |
1578 | } |
1579 | } else |
1580 | ntfs_log_perror("Failed to determine whether %s is mounted", |
1581 | opt.volume); |
1582 | /* Attempt a full mount first. */ |
1583 | flags = (opt.no_action ? NTFS_MNT_RDONLY : 0); |
1584 | ntfs_log_info("Mounting volume... "); |
1585 | vol = ntfs_mount(opt.volume, flags); |
1586 | if (vol) { |
1587 | ntfs_log_info(OK); |
1588 | ntfs_log_info("Processing of $MFT and $MFTMirr completed " |
1589 | "successfully.\n"); |
1590 | } else { |
1591 | ntfs_log_info(FAILED); |
1592 | if (fix_mount() < 0) { |
1593 | if (opt.no_action) |
1594 | ntfs_log_info("No change made\n"); |
1595 | exit(1); |
1596 | } |
1597 | vol = ntfs_mount(opt.volume, 0); |
1598 | if (!vol) { |
1599 | ntfs_log_perror("Remount failed"); |
1600 | exit(1); |
1601 | } |
1602 | } |
1603 | if (check_alternate_boot(vol)) { |
1604 | ntfs_log_error("Error: Failed to fix the alternate boot sector\n"); |
1605 | exit(1); |
1606 | } |
1607 | /* So the unmount does not clear it again. */ |
1608 | |
1609 | /* Porting note: The WasDirty flag was set here to prevent ntfs_unmount |
1610 | * from clearing the dirty bit (which might have been set in |
1611 | * fix_mount()). So the intention is to leave the dirty bit set. |
1612 | * |
1613 | * libntfs-3g does not automatically set or clear dirty flags on |
1614 | * mount/unmount, this means that the assumption that the dirty flag is |
1615 | * now set does not hold. So we need to set it if not already set. |
1616 | * |
1617 | * However clear the flag if requested to do so, at this stage |
1618 | * mounting was successful. |
1619 | */ |
1620 | if (opt.clear_dirty) |
1621 | vol->flags &= ~VOLUME_IS_DIRTY; |
1622 | else |
1623 | vol->flags |= VOLUME_IS_DIRTY; |
1624 | if (!opt.no_action && ntfs_volume_write_flags(vol, vol->flags)) { |
1625 | ntfs_log_error("Error: Failed to set volume dirty flag (%d " |
1626 | "(%s))!\n", errno, strerror(errno)); |
1627 | } |
1628 | |
1629 | /* Check NTFS version is ok for us (in $Volume) */ |
1630 | ntfs_log_info("NTFS volume version is %i.%i.\n", vol->major_ver, |
1631 | vol->minor_ver); |
1632 | if (ntfs_version_is_supported(vol)) { |
1633 | ntfs_log_error("Error: Unknown NTFS version.\n"); |
1634 | goto error_exit; |
1635 | } |
1636 | if (opt.clear_bad_sectors && !opt.no_action) { |
1637 | if (clear_badclus(vol)) { |
1638 | ntfs_log_error("Error: Failed to un-mark bad sectors.\n"); |
1639 | goto error_exit; |
1640 | } |
1641 | } |
1642 | if (vol->major_ver >= 3) { |
1643 | /* |
1644 | * FIXME: If on NTFS 3.0+, check for presence of the usn |
1645 | * journal and stamp it if present. |
1646 | */ |
1647 | } |
1648 | /* FIXME: We should be marking the quota out of date, too. */ |
1649 | /* That's all for now! */ |
1650 | ntfs_log_info("NTFS partition %s was processed successfully.\n", |
1651 | vol->dev->d_name); |
1652 | /* Set return code to 0. */ |
1653 | ret = 0; |
1654 | error_exit: |
1655 | if (ntfs_umount(vol, 0)) |
1656 | ntfs_umount(vol, 1); |
1657 | if (ret) |
1658 | exit(ret); |
1659 | return ret; |
1660 | } |
1661 | |
1662 |