1987da915Sopenharmony_ci/**
2987da915Sopenharmony_ci * ntfsfix - Part of the Linux-NTFS project.
3987da915Sopenharmony_ci *
4987da915Sopenharmony_ci * Copyright (c) 2000-2006 Anton Altaparmakov
5987da915Sopenharmony_ci * Copyright (c) 2002-2006 Szabolcs Szakacsits
6987da915Sopenharmony_ci * Copyright (c) 2007      Yura Pakhuchiy
7987da915Sopenharmony_ci * Copyright (c) 2011-2015 Jean-Pierre Andre
8987da915Sopenharmony_ci *
9987da915Sopenharmony_ci * This utility fixes some common NTFS problems, resets the NTFS journal file
10987da915Sopenharmony_ci * and schedules an NTFS consistency check for the first boot into Windows.
11987da915Sopenharmony_ci *
12987da915Sopenharmony_ci *	Anton Altaparmakov <aia21@cantab.net>
13987da915Sopenharmony_ci *
14987da915Sopenharmony_ci * This program is free software; you can redistribute it and/or modify
15987da915Sopenharmony_ci * it under the terms of the GNU General Public License as published by
16987da915Sopenharmony_ci * the Free Software Foundation; either version 2 of the License, or
17987da915Sopenharmony_ci * (at your option) any later version.
18987da915Sopenharmony_ci *
19987da915Sopenharmony_ci * This program is distributed in the hope that it will be useful,
20987da915Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
21987da915Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22987da915Sopenharmony_ci * GNU General Public License for more details.
23987da915Sopenharmony_ci *
24987da915Sopenharmony_ci * You should have received a copy of the GNU General Public License
25987da915Sopenharmony_ci * along with this program (in the main directory of the Linux-NTFS source
26987da915Sopenharmony_ci * in the file COPYING); if not, write to the Free Software Foundation,
27987da915Sopenharmony_ci * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28987da915Sopenharmony_ci */
29987da915Sopenharmony_ci
30987da915Sopenharmony_ci/*
31987da915Sopenharmony_ci * WARNING: This program might not work on architectures which do not allow
32987da915Sopenharmony_ci * unaligned access. For those, the program would need to start using
33987da915Sopenharmony_ci * get/put_unaligned macros (#include <asm/unaligned.h>), but not doing it yet,
34987da915Sopenharmony_ci * since NTFS really mostly applies to ia32 only, which does allow unaligned
35987da915Sopenharmony_ci * accesses. We might not actually have a problem though, since the structs are
36987da915Sopenharmony_ci * defined as being packed so that might be enough for gcc to insert the
37987da915Sopenharmony_ci * correct code.
38987da915Sopenharmony_ci *
39987da915Sopenharmony_ci * If anyone using a non-little endian and/or an aligned access only CPU tries
40987da915Sopenharmony_ci * this program please let me know whether it works or not!
41987da915Sopenharmony_ci *
42987da915Sopenharmony_ci *	Anton Altaparmakov <aia21@cantab.net>
43987da915Sopenharmony_ci */
44987da915Sopenharmony_ci
45987da915Sopenharmony_ci#include "config.h"
46987da915Sopenharmony_ci
47987da915Sopenharmony_ci#ifdef HAVE_UNISTD_H
48987da915Sopenharmony_ci#include <unistd.h>
49987da915Sopenharmony_ci#endif
50987da915Sopenharmony_ci#ifdef HAVE_STDLIB_H
51987da915Sopenharmony_ci#include <stdlib.h>
52987da915Sopenharmony_ci#endif
53987da915Sopenharmony_ci#ifdef HAVE_STDIO_H
54987da915Sopenharmony_ci#include <stdio.h>
55987da915Sopenharmony_ci#endif
56987da915Sopenharmony_ci#ifdef HAVE_FCNTL_H
57987da915Sopenharmony_ci#include <fcntl.h>
58987da915Sopenharmony_ci#endif
59987da915Sopenharmony_ci#ifdef HAVE_ERRNO_H
60987da915Sopenharmony_ci#include <errno.h>
61987da915Sopenharmony_ci#endif
62987da915Sopenharmony_ci#ifdef HAVE_STRING_H
63987da915Sopenharmony_ci#include <string.h>
64987da915Sopenharmony_ci#endif
65987da915Sopenharmony_ci#ifdef HAVE_GETOPT_H
66987da915Sopenharmony_ci#include <getopt.h>
67987da915Sopenharmony_ci#endif
68987da915Sopenharmony_ci
69987da915Sopenharmony_ci#include "types.h"
70987da915Sopenharmony_ci#include "attrib.h"
71987da915Sopenharmony_ci#include "volume.h"
72987da915Sopenharmony_ci#include "bootsect.h"
73987da915Sopenharmony_ci#include "mft.h"
74987da915Sopenharmony_ci#include "device.h"
75987da915Sopenharmony_ci#include "logfile.h"
76987da915Sopenharmony_ci#include "runlist.h"
77987da915Sopenharmony_ci#include "mst.h"
78987da915Sopenharmony_ci#include "utils.h"
79987da915Sopenharmony_ci/* #include "version.h" */
80987da915Sopenharmony_ci#include "logging.h"
81987da915Sopenharmony_ci#include "misc.h"
82987da915Sopenharmony_ci
83987da915Sopenharmony_ci#ifdef NO_NTFS_DEVICE_DEFAULT_IO_OPS
84987da915Sopenharmony_ci#	error "No default device io operations!  Cannot build ntfsfix.  \
85987da915Sopenharmony_ciYou need to run ./configure without the --disable-default-device-io-ops \
86987da915Sopenharmony_ciswitch if you want to be able to build the NTFS utilities."
87987da915Sopenharmony_ci#endif
88987da915Sopenharmony_ci
89987da915Sopenharmony_cistatic const char *EXEC_NAME = "ntfsfix";
90987da915Sopenharmony_cistatic const char OK[]       = "OK\n";
91987da915Sopenharmony_cistatic const char FAILED[]   = "FAILED\n";
92987da915Sopenharmony_cistatic const char FOUND[]    = "FOUND\n";
93987da915Sopenharmony_ci
94987da915Sopenharmony_ci#define DEFAULT_SECTOR_SIZE 512
95987da915Sopenharmony_ci
96987da915Sopenharmony_cistatic struct {
97987da915Sopenharmony_ci	char *volume;
98987da915Sopenharmony_ci	BOOL no_action;
99987da915Sopenharmony_ci	BOOL clear_bad_sectors;
100987da915Sopenharmony_ci	BOOL clear_dirty;
101987da915Sopenharmony_ci} opt;
102987da915Sopenharmony_ci
103987da915Sopenharmony_ci/*
104987da915Sopenharmony_ci *		Definitions for fixing the self-located MFT bug
105987da915Sopenharmony_ci */
106987da915Sopenharmony_ci
107987da915Sopenharmony_ci#define SELFLOC_LIMIT 16
108987da915Sopenharmony_ci
109987da915Sopenharmony_cistruct MFT_SELF_LOCATED {
110987da915Sopenharmony_ci	ntfs_volume *vol;
111987da915Sopenharmony_ci	MFT_RECORD *mft0;
112987da915Sopenharmony_ci	MFT_RECORD *mft1;
113987da915Sopenharmony_ci	MFT_RECORD *mft2;
114987da915Sopenharmony_ci	ATTR_LIST_ENTRY *attrlist;
115987da915Sopenharmony_ci	ATTR_LIST_ENTRY *attrlist_to_ref1;
116987da915Sopenharmony_ci	MFT_REF mft_ref0;
117987da915Sopenharmony_ci	MFT_REF mft_ref1;
118987da915Sopenharmony_ci	LCN attrlist_lcn;
119987da915Sopenharmony_ci	BOOL attrlist_resident;
120987da915Sopenharmony_ci} ;
121987da915Sopenharmony_ci
122987da915Sopenharmony_ci/**
123987da915Sopenharmony_ci * usage
124987da915Sopenharmony_ci */
125987da915Sopenharmony_ci__attribute__((noreturn))
126987da915Sopenharmony_cistatic void usage(int ret)
127987da915Sopenharmony_ci{
128987da915Sopenharmony_ci	ntfs_log_info("%s v%s (libntfs-3g)\n"
129987da915Sopenharmony_ci		   "\n"
130987da915Sopenharmony_ci		   "Usage: %s [options] device\n"
131987da915Sopenharmony_ci		   "    Attempt to fix an NTFS partition.\n"
132987da915Sopenharmony_ci		   "\n"
133987da915Sopenharmony_ci		   "    -b, --clear-bad-sectors Clear the bad sector list\n"
134987da915Sopenharmony_ci		   "    -d, --clear-dirty       Clear the volume dirty flag\n"
135987da915Sopenharmony_ci		   "    -h, --help              Display this help\n"
136987da915Sopenharmony_ci		   "    -n, --no-action         Do not write anything\n"
137987da915Sopenharmony_ci		   "    -V, --version           Display version information\n"
138987da915Sopenharmony_ci		   "\n"
139987da915Sopenharmony_ci		   "For example: %s /dev/hda6\n\n",
140987da915Sopenharmony_ci		   EXEC_NAME, VERSION, EXEC_NAME,
141987da915Sopenharmony_ci		   EXEC_NAME);
142987da915Sopenharmony_ci	ntfs_log_info("%s%s", ntfs_bugs, ntfs_home);
143987da915Sopenharmony_ci	exit(ret);
144987da915Sopenharmony_ci}
145987da915Sopenharmony_ci
146987da915Sopenharmony_ci/**
147987da915Sopenharmony_ci * version
148987da915Sopenharmony_ci */
149987da915Sopenharmony_ci__attribute__((noreturn))
150987da915Sopenharmony_cistatic void version(void)
151987da915Sopenharmony_ci{
152987da915Sopenharmony_ci	ntfs_log_info("%s v%s\n\n"
153987da915Sopenharmony_ci		   "Attempt to fix an NTFS partition.\n\n"
154987da915Sopenharmony_ci		   "Copyright (c) 2000-2006 Anton Altaparmakov\n"
155987da915Sopenharmony_ci		   "Copyright (c) 2002-2006 Szabolcs Szakacsits\n"
156987da915Sopenharmony_ci		   "Copyright (c) 2007      Yura Pakhuchiy\n"
157987da915Sopenharmony_ci		   "Copyright (c) 2011-2015 Jean-Pierre Andre\n\n",
158987da915Sopenharmony_ci		   EXEC_NAME, VERSION);
159987da915Sopenharmony_ci	ntfs_log_info("%s\n%s%s", ntfs_gpl, ntfs_bugs, ntfs_home);
160987da915Sopenharmony_ci	exit(0);
161987da915Sopenharmony_ci}
162987da915Sopenharmony_ci
163987da915Sopenharmony_ci/**
164987da915Sopenharmony_ci * parse_options
165987da915Sopenharmony_ci */
166987da915Sopenharmony_cistatic void parse_options(int argc, char **argv)
167987da915Sopenharmony_ci{
168987da915Sopenharmony_ci	int c;
169987da915Sopenharmony_ci	static const char *sopt = "-bdhnV";
170987da915Sopenharmony_ci	static const struct option lopt[] = {
171987da915Sopenharmony_ci		{ "help",		no_argument,	NULL, 'h' },
172987da915Sopenharmony_ci		{ "no-action",		no_argument,	NULL, 'n' },
173987da915Sopenharmony_ci		{ "clear-bad-sectors",	no_argument,	NULL, 'b' },
174987da915Sopenharmony_ci		{ "clear-dirty",	no_argument,	NULL, 'd' },
175987da915Sopenharmony_ci		{ "version",		no_argument,	NULL, 'V' },
176987da915Sopenharmony_ci		{ NULL, 		0, NULL, 0 }
177987da915Sopenharmony_ci	};
178987da915Sopenharmony_ci
179987da915Sopenharmony_ci	memset(&opt, 0, sizeof(opt));
180987da915Sopenharmony_ci
181987da915Sopenharmony_ci	while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) {
182987da915Sopenharmony_ci		switch (c) {
183987da915Sopenharmony_ci		case 1:	/* A non-option argument */
184987da915Sopenharmony_ci			if (!opt.volume)
185987da915Sopenharmony_ci				opt.volume = argv[optind - 1];
186987da915Sopenharmony_ci			else {
187987da915Sopenharmony_ci				ntfs_log_info("ERROR: Too many arguments.\n");
188987da915Sopenharmony_ci				usage(1);
189987da915Sopenharmony_ci			}
190987da915Sopenharmony_ci			break;
191987da915Sopenharmony_ci		case 'b':
192987da915Sopenharmony_ci			opt.clear_bad_sectors = TRUE;
193987da915Sopenharmony_ci			break;
194987da915Sopenharmony_ci		case 'd':
195987da915Sopenharmony_ci			opt.clear_dirty = TRUE;
196987da915Sopenharmony_ci			break;
197987da915Sopenharmony_ci		case 'n':
198987da915Sopenharmony_ci			opt.no_action = TRUE;
199987da915Sopenharmony_ci			break;
200987da915Sopenharmony_ci		case 'h':
201987da915Sopenharmony_ci			usage(0);
202987da915Sopenharmony_ci		case '?':
203987da915Sopenharmony_ci			usage(1);
204987da915Sopenharmony_ci			/* fall through */
205987da915Sopenharmony_ci		case 'V':
206987da915Sopenharmony_ci			version();
207987da915Sopenharmony_ci		default:
208987da915Sopenharmony_ci			ntfs_log_info("ERROR: Unknown option '%s'.\n", argv[optind - 1]);
209987da915Sopenharmony_ci			usage(1);
210987da915Sopenharmony_ci		}
211987da915Sopenharmony_ci	}
212987da915Sopenharmony_ci
213987da915Sopenharmony_ci	if (opt.volume == NULL) {
214987da915Sopenharmony_ci		ntfs_log_info("ERROR: You must specify a device.\n");
215987da915Sopenharmony_ci		usage(1);
216987da915Sopenharmony_ci	}
217987da915Sopenharmony_ci}
218987da915Sopenharmony_ci
219987da915Sopenharmony_ci/**
220987da915Sopenharmony_ci * OLD_ntfs_volume_set_flags
221987da915Sopenharmony_ci */
222987da915Sopenharmony_cistatic int OLD_ntfs_volume_set_flags(ntfs_volume *vol, const le16 flags)
223987da915Sopenharmony_ci{
224987da915Sopenharmony_ci	MFT_RECORD *m = NULL;
225987da915Sopenharmony_ci	ATTR_RECORD *a;
226987da915Sopenharmony_ci	VOLUME_INFORMATION *c;
227987da915Sopenharmony_ci	ntfs_attr_search_ctx *ctx;
228987da915Sopenharmony_ci	int ret = -1;   /* failure */
229987da915Sopenharmony_ci
230987da915Sopenharmony_ci	if (!vol) {
231987da915Sopenharmony_ci		errno = EINVAL;
232987da915Sopenharmony_ci		return -1;
233987da915Sopenharmony_ci	}
234987da915Sopenharmony_ci	if (ntfs_file_record_read(vol, FILE_Volume, &m, NULL)) {
235987da915Sopenharmony_ci		ntfs_log_perror("Failed to read $Volume");
236987da915Sopenharmony_ci		return -1;
237987da915Sopenharmony_ci	}
238987da915Sopenharmony_ci	/* Sanity check */
239987da915Sopenharmony_ci	if (!(m->flags & MFT_RECORD_IN_USE)) {
240987da915Sopenharmony_ci		ntfs_log_error("$Volume has been deleted. Cannot handle this "
241987da915Sopenharmony_ci				"yet. Run chkdsk to fix this.\n");
242987da915Sopenharmony_ci		errno = EIO;
243987da915Sopenharmony_ci		goto err_exit;
244987da915Sopenharmony_ci	}
245987da915Sopenharmony_ci	/* Get a pointer to the volume information attribute. */
246987da915Sopenharmony_ci	ctx = ntfs_attr_get_search_ctx(NULL, m);
247987da915Sopenharmony_ci	if (!ctx) {
248987da915Sopenharmony_ci		ntfs_log_debug("Failed to allocate attribute search "
249987da915Sopenharmony_ci				"context.\n");
250987da915Sopenharmony_ci		goto err_exit;
251987da915Sopenharmony_ci	}
252987da915Sopenharmony_ci	if (ntfs_attr_lookup(AT_VOLUME_INFORMATION, AT_UNNAMED, 0,
253987da915Sopenharmony_ci			CASE_SENSITIVE, 0, NULL, 0, ctx)) {
254987da915Sopenharmony_ci		ntfs_log_error("Attribute $VOLUME_INFORMATION was not found in "
255987da915Sopenharmony_ci				"$Volume!\n");
256987da915Sopenharmony_ci		goto err_out;
257987da915Sopenharmony_ci	}
258987da915Sopenharmony_ci	a = ctx->attr;
259987da915Sopenharmony_ci	/* Sanity check. */
260987da915Sopenharmony_ci	if (a->non_resident) {
261987da915Sopenharmony_ci		ntfs_log_error("Attribute $VOLUME_INFORMATION must be resident "
262987da915Sopenharmony_ci				"(and it isn't)!\n");
263987da915Sopenharmony_ci		errno = EIO;
264987da915Sopenharmony_ci		goto err_out;
265987da915Sopenharmony_ci	}
266987da915Sopenharmony_ci	/* Get a pointer to the value of the attribute. */
267987da915Sopenharmony_ci	c = (VOLUME_INFORMATION*)(le16_to_cpu(a->value_offset) + (char*)a);
268987da915Sopenharmony_ci	/* Sanity checks. */
269987da915Sopenharmony_ci	if ((char*)c + le32_to_cpu(a->value_length) >
270987da915Sopenharmony_ci			(char*)m + le32_to_cpu(m->bytes_in_use) ||
271987da915Sopenharmony_ci			le16_to_cpu(a->value_offset) +
272987da915Sopenharmony_ci			le32_to_cpu(a->value_length) > le32_to_cpu(a->length)) {
273987da915Sopenharmony_ci		ntfs_log_error("Attribute $VOLUME_INFORMATION in $Volume is "
274987da915Sopenharmony_ci				"corrupt!\n");
275987da915Sopenharmony_ci		errno = EIO;
276987da915Sopenharmony_ci		goto err_out;
277987da915Sopenharmony_ci	}
278987da915Sopenharmony_ci	/* Set the volume flags. */
279987da915Sopenharmony_ci	vol->flags = c->flags = flags;
280987da915Sopenharmony_ci	if (ntfs_mft_record_write(vol, FILE_Volume, m)) {
281987da915Sopenharmony_ci		ntfs_log_perror("Error writing $Volume");
282987da915Sopenharmony_ci		goto err_out;
283987da915Sopenharmony_ci	}
284987da915Sopenharmony_ci	ret = 0; /* success */
285987da915Sopenharmony_cierr_out:
286987da915Sopenharmony_ci	ntfs_attr_put_search_ctx(ctx);
287987da915Sopenharmony_cierr_exit:
288987da915Sopenharmony_ci	free(m);
289987da915Sopenharmony_ci	return ret;
290987da915Sopenharmony_ci}
291987da915Sopenharmony_ci
292987da915Sopenharmony_ci/**
293987da915Sopenharmony_ci * set_dirty_flag
294987da915Sopenharmony_ci */
295987da915Sopenharmony_cistatic int set_dirty_flag(ntfs_volume *vol)
296987da915Sopenharmony_ci{
297987da915Sopenharmony_ci	le16 flags;
298987da915Sopenharmony_ci
299987da915Sopenharmony_ci	/* Porting note: We test for the current state of VOLUME_IS_DIRTY. This
300987da915Sopenharmony_ci	 * should actually be more appropriate than testing for NVolWasDirty. */
301987da915Sopenharmony_ci	if (vol->flags & VOLUME_IS_DIRTY)
302987da915Sopenharmony_ci		return 0;
303987da915Sopenharmony_ci	ntfs_log_info("Setting required flags on partition... ");
304987da915Sopenharmony_ci	/*
305987da915Sopenharmony_ci	 * Set chkdsk flag, i.e. mark the partition dirty so chkdsk will run
306987da915Sopenharmony_ci	 * and fix it for us.
307987da915Sopenharmony_ci	 */
308987da915Sopenharmony_ci	flags = vol->flags | VOLUME_IS_DIRTY;
309987da915Sopenharmony_ci	if (!opt.no_action && OLD_ntfs_volume_set_flags(vol, flags)) {
310987da915Sopenharmony_ci		ntfs_log_info(FAILED);
311987da915Sopenharmony_ci		ntfs_log_error("Error setting volume flags.\n");
312987da915Sopenharmony_ci		return -1;
313987da915Sopenharmony_ci	}
314987da915Sopenharmony_ci	vol->flags = flags;
315987da915Sopenharmony_ci
316987da915Sopenharmony_ci	/* Porting note: libntfs-3g does not have the 'WasDirty' flag/property,
317987da915Sopenharmony_ci	 * and never touches the 'dirty' bit except when explicitly told to do
318987da915Sopenharmony_ci	 * so. Since we just wrote the VOLUME_IS_DIRTY bit to disk, and
319987da915Sopenharmony_ci	 * vol->flags is up-to-date, we can just ignore the NVolSetWasDirty
320987da915Sopenharmony_ci	 * statement. */
321987da915Sopenharmony_ci	/* NVolSetWasDirty(vol); */
322987da915Sopenharmony_ci
323987da915Sopenharmony_ci	ntfs_log_info(OK);
324987da915Sopenharmony_ci	return 0;
325987da915Sopenharmony_ci}
326987da915Sopenharmony_ci
327987da915Sopenharmony_ci/**
328987da915Sopenharmony_ci * empty_journal
329987da915Sopenharmony_ci */
330987da915Sopenharmony_cistatic int empty_journal(ntfs_volume *vol)
331987da915Sopenharmony_ci{
332987da915Sopenharmony_ci	if (NVolLogFileEmpty(vol))
333987da915Sopenharmony_ci		return 0;
334987da915Sopenharmony_ci	ntfs_log_info("Going to empty the journal ($LogFile)... ");
335987da915Sopenharmony_ci	if (ntfs_logfile_reset(vol)) {
336987da915Sopenharmony_ci		ntfs_log_info(FAILED);
337987da915Sopenharmony_ci		ntfs_log_perror("Failed to reset $LogFile");
338987da915Sopenharmony_ci		return -1;
339987da915Sopenharmony_ci	}
340987da915Sopenharmony_ci	ntfs_log_info(OK);
341987da915Sopenharmony_ci	return 0;
342987da915Sopenharmony_ci}
343987da915Sopenharmony_ci
344987da915Sopenharmony_ci/*
345987da915Sopenharmony_ci *		Clear the sparse flag of an attribute
346987da915Sopenharmony_ci */
347987da915Sopenharmony_ci
348987da915Sopenharmony_cistatic int clear_sparse(ntfs_attr *na, const char *name)
349987da915Sopenharmony_ci{
350987da915Sopenharmony_ci	ntfs_attr_search_ctx *ctx;
351987da915Sopenharmony_ci	int res;
352987da915Sopenharmony_ci
353987da915Sopenharmony_ci	res = -1;
354987da915Sopenharmony_ci	ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
355987da915Sopenharmony_ci	if (ctx) {
356987da915Sopenharmony_ci		if (!ntfs_attr_lookup(na->type, na->name, na->name_len,
357987da915Sopenharmony_ci				CASE_SENSITIVE,	0, NULL, 0, ctx)) {
358987da915Sopenharmony_ci			na->data_flags &= ~ATTR_IS_SPARSE;
359987da915Sopenharmony_ci			ctx->attr->data_size = cpu_to_sle64(na->data_size);
360987da915Sopenharmony_ci			ctx->attr->initialized_size
361987da915Sopenharmony_ci					= cpu_to_sle64(na->initialized_size);
362987da915Sopenharmony_ci			ctx->attr->flags = na->data_flags;
363987da915Sopenharmony_ci			ctx->attr->compression_unit = 0;
364987da915Sopenharmony_ci			ntfs_inode_mark_dirty(ctx->ntfs_ino);
365987da915Sopenharmony_ci			NInoFileNameSetDirty(na->ni);
366987da915Sopenharmony_ci			res = 0;
367987da915Sopenharmony_ci		} else
368987da915Sopenharmony_ci			ntfs_log_perror("Could not locate attribute for %s",
369987da915Sopenharmony_ci						name);
370987da915Sopenharmony_ci		ntfs_attr_put_search_ctx(ctx);
371987da915Sopenharmony_ci	} else
372987da915Sopenharmony_ci		ntfs_log_perror("Could not get a search context for %s",
373987da915Sopenharmony_ci					name);
374987da915Sopenharmony_ci	return (res);
375987da915Sopenharmony_ci}
376987da915Sopenharmony_ci
377987da915Sopenharmony_ci/**
378987da915Sopenharmony_ci *		Clear the bad cluster marks (option)
379987da915Sopenharmony_ci */
380987da915Sopenharmony_cistatic int clear_badclus(ntfs_volume *vol)
381987da915Sopenharmony_ci{
382987da915Sopenharmony_ci	static ntfschar badstream[] = {
383987da915Sopenharmony_ci				const_cpu_to_le16('$'), const_cpu_to_le16('B'),
384987da915Sopenharmony_ci				const_cpu_to_le16('a'), const_cpu_to_le16('d')
385987da915Sopenharmony_ci	} ;
386987da915Sopenharmony_ci	ntfs_inode *ni;
387987da915Sopenharmony_ci	ntfs_attr *na;
388987da915Sopenharmony_ci	BOOL ok;
389987da915Sopenharmony_ci
390987da915Sopenharmony_ci	ok = FALSE;
391987da915Sopenharmony_ci	ntfs_log_info("Going to un-mark the bad clusters ($BadClus)... ");
392987da915Sopenharmony_ci	ni = ntfs_inode_open(vol, FILE_BadClus);
393987da915Sopenharmony_ci	if (ni) {
394987da915Sopenharmony_ci		na = ntfs_attr_open(ni, AT_DATA, badstream, 4);
395987da915Sopenharmony_ci			/*
396987da915Sopenharmony_ci			 * chkdsk does not adjust the data size when
397987da915Sopenharmony_ci			 * moving clusters to $BadClus, so we have to
398987da915Sopenharmony_ci			 * check the runlist.
399987da915Sopenharmony_ci			 */
400987da915Sopenharmony_ci		if (na && !ntfs_attr_map_whole_runlist(na)) {
401987da915Sopenharmony_ci			if (na->rl
402987da915Sopenharmony_ci			    && na->rl[0].length && na->rl[1].length) {
403987da915Sopenharmony_ci			/*
404987da915Sopenharmony_ci			 * Truncate the stream to free all its clusters,
405987da915Sopenharmony_ci			 * (which requires setting the data size according
406987da915Sopenharmony_ci			 * to allocation), then reallocate a sparse stream
407987da915Sopenharmony_ci			 * to full size of volume and reset the data size.
408987da915Sopenharmony_ci			 * Note : the sparse flags should not be set.
409987da915Sopenharmony_ci			 */
410987da915Sopenharmony_ci				na->data_size = na->allocated_size;
411987da915Sopenharmony_ci				na->initialized_size = na->allocated_size;
412987da915Sopenharmony_ci				if (!ntfs_attr_truncate(na,0)
413987da915Sopenharmony_ci				    && !ntfs_attr_truncate(na,vol->nr_clusters
414987da915Sopenharmony_ci						<< vol->cluster_size_bits)) {
415987da915Sopenharmony_ci					na->initialized_size = 0;
416987da915Sopenharmony_ci					NInoFileNameSetDirty(ni);
417987da915Sopenharmony_ci					ok = TRUE;
418987da915Sopenharmony_ci				} else {
419987da915Sopenharmony_ci					ntfs_log_perror("Failed to un-mark the bad clusters");
420987da915Sopenharmony_ci				}
421987da915Sopenharmony_ci			} else {
422987da915Sopenharmony_ci				ntfs_log_info("No bad clusters...");
423987da915Sopenharmony_ci				ok = TRUE;
424987da915Sopenharmony_ci			}
425987da915Sopenharmony_ci			/*
426987da915Sopenharmony_ci			 * The sparse flags are not set after an initial
427987da915Sopenharmony_ci			 * formatting, so do the same.
428987da915Sopenharmony_ci			 */
429987da915Sopenharmony_ci			if (ok) {
430987da915Sopenharmony_ci				ni->flags &= ~FILE_ATTR_SPARSE_FILE;
431987da915Sopenharmony_ci				ok = !clear_sparse(na, "$BadClus::$Bad");
432987da915Sopenharmony_ci			}
433987da915Sopenharmony_ci			ntfs_attr_close(na);
434987da915Sopenharmony_ci		} else {
435987da915Sopenharmony_ci			ntfs_log_perror("Failed to open $BadClus::$Bad");
436987da915Sopenharmony_ci		}
437987da915Sopenharmony_ci		ntfs_inode_close(ni);
438987da915Sopenharmony_ci	} else {
439987da915Sopenharmony_ci		ntfs_log_perror("Failed to open inode FILE_BadClus");
440987da915Sopenharmony_ci	}
441987da915Sopenharmony_ci	if (ok)
442987da915Sopenharmony_ci		ntfs_log_info(OK);
443987da915Sopenharmony_ci	return (ok ? 0 : -1);
444987da915Sopenharmony_ci}
445987da915Sopenharmony_ci
446987da915Sopenharmony_ci/**
447987da915Sopenharmony_ci * fix_mftmirr
448987da915Sopenharmony_ci */
449987da915Sopenharmony_cistatic int fix_mftmirr(ntfs_volume *vol)
450987da915Sopenharmony_ci{
451987da915Sopenharmony_ci	s64 l, br;
452987da915Sopenharmony_ci	unsigned char *m, *m2;
453987da915Sopenharmony_ci	int i, ret = -1; /* failure */
454987da915Sopenharmony_ci	BOOL done;
455987da915Sopenharmony_ci
456987da915Sopenharmony_ci	ntfs_log_info("\nProcessing $MFT and $MFTMirr...\n");
457987da915Sopenharmony_ci
458987da915Sopenharmony_ci	/* Load data from $MFT and $MFTMirr and compare the contents. */
459987da915Sopenharmony_ci	m = (u8*)malloc(vol->mftmirr_size << vol->mft_record_size_bits);
460987da915Sopenharmony_ci	if (!m) {
461987da915Sopenharmony_ci		ntfs_log_perror("Failed to allocate memory");
462987da915Sopenharmony_ci		return -1;
463987da915Sopenharmony_ci	}
464987da915Sopenharmony_ci	m2 = (u8*)malloc(vol->mftmirr_size << vol->mft_record_size_bits);
465987da915Sopenharmony_ci	if (!m2) {
466987da915Sopenharmony_ci		ntfs_log_perror("Failed to allocate memory");
467987da915Sopenharmony_ci		free(m);
468987da915Sopenharmony_ci		return -1;
469987da915Sopenharmony_ci	}
470987da915Sopenharmony_ci
471987da915Sopenharmony_ci	ntfs_log_info("Reading $MFT... ");
472987da915Sopenharmony_ci	l = ntfs_attr_mst_pread(vol->mft_na, 0, vol->mftmirr_size,
473987da915Sopenharmony_ci			vol->mft_record_size, m);
474987da915Sopenharmony_ci	if (l != vol->mftmirr_size) {
475987da915Sopenharmony_ci		ntfs_log_info(FAILED);
476987da915Sopenharmony_ci		if (l != -1)
477987da915Sopenharmony_ci			errno = EIO;
478987da915Sopenharmony_ci		ntfs_log_perror("Failed to read $MFT");
479987da915Sopenharmony_ci		goto error_exit;
480987da915Sopenharmony_ci	}
481987da915Sopenharmony_ci	ntfs_log_info(OK);
482987da915Sopenharmony_ci
483987da915Sopenharmony_ci	ntfs_log_info("Reading $MFTMirr... ");
484987da915Sopenharmony_ci	l = ntfs_attr_mst_pread(vol->mftmirr_na, 0, vol->mftmirr_size,
485987da915Sopenharmony_ci			vol->mft_record_size, m2);
486987da915Sopenharmony_ci	if (l != vol->mftmirr_size) {
487987da915Sopenharmony_ci		ntfs_log_info(FAILED);
488987da915Sopenharmony_ci		if (l != -1)
489987da915Sopenharmony_ci			errno = EIO;
490987da915Sopenharmony_ci		ntfs_log_perror("Failed to read $MFTMirr");
491987da915Sopenharmony_ci		goto error_exit;
492987da915Sopenharmony_ci	}
493987da915Sopenharmony_ci	ntfs_log_info(OK);
494987da915Sopenharmony_ci
495987da915Sopenharmony_ci	/*
496987da915Sopenharmony_ci	 * FIXME: Need to actually check the $MFTMirr for being real. Otherwise
497987da915Sopenharmony_ci	 * we might corrupt the partition if someone is experimenting with
498987da915Sopenharmony_ci	 * software RAID and the $MFTMirr is not actually in the position we
499987da915Sopenharmony_ci	 * expect it to be... )-:
500987da915Sopenharmony_ci	 * FIXME: We should emit a warning it $MFTMirr is damaged and ask
501987da915Sopenharmony_ci	 * user whether to recreate it from $MFT or whether to abort. - The
502987da915Sopenharmony_ci	 * warning needs to include the danger of software RAID arrays.
503987da915Sopenharmony_ci	 * Maybe we should go as far as to detect whether we are running on a
504987da915Sopenharmony_ci	 * MD disk and if yes then bomb out right at the start of the program?
505987da915Sopenharmony_ci	 */
506987da915Sopenharmony_ci
507987da915Sopenharmony_ci	ntfs_log_info("Comparing $MFTMirr to $MFT... ");
508987da915Sopenharmony_ci	done = FALSE;
509987da915Sopenharmony_ci	/*
510987da915Sopenharmony_ci	 * Since 2017, Windows 10 does not mirror to full $MFTMirr when
511987da915Sopenharmony_ci	 * using big clusters, and some records may be found different.
512987da915Sopenharmony_ci	 * Nevertheless chkdsk.exe mirrors it fully, so we do similarly.
513987da915Sopenharmony_ci	 */
514987da915Sopenharmony_ci	for (i = 0; i < vol->mftmirr_size; ++i) {
515987da915Sopenharmony_ci		MFT_RECORD *mrec, *mrec2;
516987da915Sopenharmony_ci		const char *ESTR[12] = { "$MFT", "$MFTMirr", "$LogFile",
517987da915Sopenharmony_ci			"$Volume", "$AttrDef", "root directory", "$Bitmap",
518987da915Sopenharmony_ci			"$Boot", "$BadClus", "$Secure", "$UpCase", "$Extend" };
519987da915Sopenharmony_ci		const char *s;
520987da915Sopenharmony_ci		BOOL use_mirr;
521987da915Sopenharmony_ci
522987da915Sopenharmony_ci		if (i < 12)
523987da915Sopenharmony_ci			s = ESTR[i];
524987da915Sopenharmony_ci		else if (i < 16)
525987da915Sopenharmony_ci			s = "system file";
526987da915Sopenharmony_ci		else
527987da915Sopenharmony_ci			s = "mft record";
528987da915Sopenharmony_ci
529987da915Sopenharmony_ci		use_mirr = FALSE;
530987da915Sopenharmony_ci		mrec = (MFT_RECORD*)(m + i * vol->mft_record_size);
531987da915Sopenharmony_ci		if (mrec->flags & MFT_RECORD_IN_USE) {
532987da915Sopenharmony_ci			if (ntfs_is_baad_record(mrec->magic)) {
533987da915Sopenharmony_ci				ntfs_log_info(FAILED);
534987da915Sopenharmony_ci				ntfs_log_error("$MFT error: Incomplete multi "
535987da915Sopenharmony_ci						"sector transfer detected in "
536987da915Sopenharmony_ci						"%s.\nCannot handle this yet. "
537987da915Sopenharmony_ci						")-:\n", s);
538987da915Sopenharmony_ci				goto error_exit;
539987da915Sopenharmony_ci			}
540987da915Sopenharmony_ci			if (!ntfs_is_mft_record(mrec->magic)) {
541987da915Sopenharmony_ci				ntfs_log_info(FAILED);
542987da915Sopenharmony_ci				ntfs_log_error("$MFT error: Invalid mft "
543987da915Sopenharmony_ci						"record for %s.\nCannot "
544987da915Sopenharmony_ci						"handle this yet. )-:\n", s);
545987da915Sopenharmony_ci				goto error_exit;
546987da915Sopenharmony_ci			}
547987da915Sopenharmony_ci		}
548987da915Sopenharmony_ci		mrec2 = (MFT_RECORD*)(m2 + i * vol->mft_record_size);
549987da915Sopenharmony_ci		if (mrec2->flags & MFT_RECORD_IN_USE) {
550987da915Sopenharmony_ci			if (ntfs_is_baad_record(mrec2->magic)) {
551987da915Sopenharmony_ci				ntfs_log_info(FAILED);
552987da915Sopenharmony_ci				ntfs_log_error("$MFTMirr error: Incomplete "
553987da915Sopenharmony_ci						"multi sector transfer "
554987da915Sopenharmony_ci						"detected in %s.\n", s);
555987da915Sopenharmony_ci				goto error_exit;
556987da915Sopenharmony_ci			}
557987da915Sopenharmony_ci			if (!ntfs_is_mft_record(mrec2->magic)) {
558987da915Sopenharmony_ci				ntfs_log_info(FAILED);
559987da915Sopenharmony_ci				ntfs_log_error("$MFTMirr error: Invalid mft "
560987da915Sopenharmony_ci						"record for %s.\n", s);
561987da915Sopenharmony_ci				goto error_exit;
562987da915Sopenharmony_ci			}
563987da915Sopenharmony_ci			/* $MFT is corrupt but $MFTMirr is ok, use $MFTMirr. */
564987da915Sopenharmony_ci			if (!(mrec->flags & MFT_RECORD_IN_USE) &&
565987da915Sopenharmony_ci					!ntfs_is_mft_record(mrec->magic))
566987da915Sopenharmony_ci				use_mirr = TRUE;
567987da915Sopenharmony_ci		}
568987da915Sopenharmony_ci		if (memcmp(mrec, mrec2, ntfs_mft_record_get_data_size(mrec))) {
569987da915Sopenharmony_ci			if (!done) {
570987da915Sopenharmony_ci				done = TRUE;
571987da915Sopenharmony_ci				ntfs_log_info(FAILED);
572987da915Sopenharmony_ci			}
573987da915Sopenharmony_ci			ntfs_log_info("Correcting differences in $MFT%s "
574987da915Sopenharmony_ci					"record %d...", use_mirr ? "" : "Mirr",
575987da915Sopenharmony_ci					i);
576987da915Sopenharmony_ci			br = ntfs_mft_record_write(vol, i,
577987da915Sopenharmony_ci					use_mirr ? mrec2 : mrec);
578987da915Sopenharmony_ci			if (br) {
579987da915Sopenharmony_ci				ntfs_log_info(FAILED);
580987da915Sopenharmony_ci				ntfs_log_perror("Error correcting $MFT%s",
581987da915Sopenharmony_ci						use_mirr ? "" : "Mirr");
582987da915Sopenharmony_ci				goto error_exit;
583987da915Sopenharmony_ci			}
584987da915Sopenharmony_ci			ntfs_log_info(OK);
585987da915Sopenharmony_ci		}
586987da915Sopenharmony_ci	}
587987da915Sopenharmony_ci	if (!done)
588987da915Sopenharmony_ci		ntfs_log_info(OK);
589987da915Sopenharmony_ci	ntfs_log_info("Processing of $MFT and $MFTMirr completed "
590987da915Sopenharmony_ci			"successfully.\n");
591987da915Sopenharmony_ci	ret = 0;
592987da915Sopenharmony_cierror_exit:
593987da915Sopenharmony_ci	free(m);
594987da915Sopenharmony_ci	free(m2);
595987da915Sopenharmony_ci	return ret;
596987da915Sopenharmony_ci}
597987da915Sopenharmony_ci
598987da915Sopenharmony_ci/*
599987da915Sopenharmony_ci *		Rewrite the $UpCase file as default
600987da915Sopenharmony_ci *
601987da915Sopenharmony_ci *	Returns 0 if could be written
602987da915Sopenharmony_ci */
603987da915Sopenharmony_ci
604987da915Sopenharmony_cistatic int rewrite_upcase(ntfs_volume *vol, ntfs_attr *na)
605987da915Sopenharmony_ci{
606987da915Sopenharmony_ci	s64 l;
607987da915Sopenharmony_ci	int res;
608987da915Sopenharmony_ci
609987da915Sopenharmony_ci		/* writing the $UpCase may require bitmap updates */
610987da915Sopenharmony_ci	res = -1;
611987da915Sopenharmony_ci	vol->lcnbmp_ni = ntfs_inode_open(vol, FILE_Bitmap);
612987da915Sopenharmony_ci	if (!vol->lcnbmp_ni) {
613987da915Sopenharmony_ci		ntfs_log_perror("Failed to open bitmap inode");
614987da915Sopenharmony_ci	} else {
615987da915Sopenharmony_ci		vol->lcnbmp_na = ntfs_attr_open(vol->lcnbmp_ni, AT_DATA,
616987da915Sopenharmony_ci					AT_UNNAMED, 0);
617987da915Sopenharmony_ci		if (!vol->lcnbmp_na) {
618987da915Sopenharmony_ci			ntfs_log_perror("Failed to open bitmap data attribute");
619987da915Sopenharmony_ci		} else {
620987da915Sopenharmony_ci			/* minimal consistency check on the bitmap */
621987da915Sopenharmony_ci			if (((vol->lcnbmp_na->data_size << 3)
622987da915Sopenharmony_ci				< vol->nr_clusters)
623987da915Sopenharmony_ci			    || ((vol->lcnbmp_na->data_size << 3)
624987da915Sopenharmony_ci				>= (vol->nr_clusters << 1))
625987da915Sopenharmony_ci			    || (vol->lcnbmp_na->data_size
626987da915Sopenharmony_ci					> vol->lcnbmp_na->allocated_size)) {
627987da915Sopenharmony_ci				ntfs_log_error("Corrupt cluster map size %lld"
628987da915Sopenharmony_ci					" (allocated %lld minimum %lld)\n",
629987da915Sopenharmony_ci					(long long)vol->lcnbmp_na->data_size,
630987da915Sopenharmony_ci					(long long)vol->lcnbmp_na->allocated_size,
631987da915Sopenharmony_ci					(long long)(vol->nr_clusters + 7) >> 3);
632987da915Sopenharmony_ci			} else {
633987da915Sopenharmony_ci				ntfs_log_info("Rewriting $UpCase file\n");
634987da915Sopenharmony_ci				l = ntfs_attr_pwrite(na, 0, vol->upcase_len*2,
635987da915Sopenharmony_ci							vol->upcase);
636987da915Sopenharmony_ci				if (l != vol->upcase_len*2) {
637987da915Sopenharmony_ci					ntfs_log_error("Failed to rewrite $UpCase\n");
638987da915Sopenharmony_ci				} else {
639987da915Sopenharmony_ci					ntfs_log_info("$UpCase has been set to default\n");
640987da915Sopenharmony_ci					res = 0;
641987da915Sopenharmony_ci				}
642987da915Sopenharmony_ci			}
643987da915Sopenharmony_ci			ntfs_attr_close(vol->lcnbmp_na);
644987da915Sopenharmony_ci			vol->lcnbmp_na = (ntfs_attr*)NULL;
645987da915Sopenharmony_ci		}
646987da915Sopenharmony_ci		ntfs_inode_close(vol->lcnbmp_ni);
647987da915Sopenharmony_ci		vol->lcnbmp_ni = (ntfs_inode*)NULL;
648987da915Sopenharmony_ci	}
649987da915Sopenharmony_ci	return (res);
650987da915Sopenharmony_ci}
651987da915Sopenharmony_ci
652987da915Sopenharmony_ci/*
653987da915Sopenharmony_ci *		Fix the $UpCase file
654987da915Sopenharmony_ci *
655987da915Sopenharmony_ci *	Returns 0 if the table is valid or has been fixed
656987da915Sopenharmony_ci */
657987da915Sopenharmony_ci
658987da915Sopenharmony_cistatic int fix_upcase(ntfs_volume *vol)
659987da915Sopenharmony_ci{
660987da915Sopenharmony_ci	ntfs_inode *ni;
661987da915Sopenharmony_ci	ntfs_attr *na;
662987da915Sopenharmony_ci	ntfschar *upcase;
663987da915Sopenharmony_ci	s64 l;
664987da915Sopenharmony_ci	u32 upcase_len;
665987da915Sopenharmony_ci	u32 k;
666987da915Sopenharmony_ci	int res;
667987da915Sopenharmony_ci
668987da915Sopenharmony_ci	res = -1;
669987da915Sopenharmony_ci	ni = (ntfs_inode*)NULL;
670987da915Sopenharmony_ci	na = (ntfs_attr*)NULL;
671987da915Sopenharmony_ci	/* Now load the upcase table from $UpCase. */
672987da915Sopenharmony_ci	ntfs_log_debug("Loading $UpCase...\n");
673987da915Sopenharmony_ci	ni = ntfs_inode_open(vol, FILE_UpCase);
674987da915Sopenharmony_ci	if (!ni) {
675987da915Sopenharmony_ci		ntfs_log_perror("Failed to open inode FILE_UpCase");
676987da915Sopenharmony_ci		goto error_exit;
677987da915Sopenharmony_ci	}
678987da915Sopenharmony_ci	/* Get an ntfs attribute for $UpCase/$DATA. */
679987da915Sopenharmony_ci	na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
680987da915Sopenharmony_ci	if (!na) {
681987da915Sopenharmony_ci		ntfs_log_perror("Failed to open ntfs attribute");
682987da915Sopenharmony_ci		goto error_exit;
683987da915Sopenharmony_ci	}
684987da915Sopenharmony_ci	/*
685987da915Sopenharmony_ci	 * Note: Normally, the upcase table has a length equal to 65536
686987da915Sopenharmony_ci	 * 2-byte Unicode characters but allow for different cases, so no
687987da915Sopenharmony_ci	 * checks done. Just check we don't overflow 32-bits worth of Unicode
688987da915Sopenharmony_ci	 * characters.
689987da915Sopenharmony_ci	 */
690987da915Sopenharmony_ci	if (na->data_size & ~0x1ffffffffULL) {
691987da915Sopenharmony_ci		ntfs_log_error("Error: Upcase table is too big (max 32-bit "
692987da915Sopenharmony_ci				"allowed).\n");
693987da915Sopenharmony_ci		errno = EINVAL;
694987da915Sopenharmony_ci		goto error_exit;
695987da915Sopenharmony_ci	}
696987da915Sopenharmony_ci	upcase_len = na->data_size >> 1;
697987da915Sopenharmony_ci	upcase = (ntfschar*)ntfs_malloc(na->data_size);
698987da915Sopenharmony_ci	if (!upcase)
699987da915Sopenharmony_ci		goto error_exit;
700987da915Sopenharmony_ci	/* Read in the $DATA attribute value into the buffer. */
701987da915Sopenharmony_ci	l = ntfs_attr_pread(na, 0, na->data_size, upcase);
702987da915Sopenharmony_ci	if (l != na->data_size) {
703987da915Sopenharmony_ci		ntfs_log_error("Failed to read $UpCase, unexpected length "
704987da915Sopenharmony_ci			       "(%lld != %lld).\n", (long long)l,
705987da915Sopenharmony_ci			       (long long)na->data_size);
706987da915Sopenharmony_ci		errno = EIO;
707987da915Sopenharmony_ci		goto error_exit;
708987da915Sopenharmony_ci	}
709987da915Sopenharmony_ci	/* Consistency check of $UpCase, restricted to plain ASCII chars */
710987da915Sopenharmony_ci	k = 0x20;
711987da915Sopenharmony_ci	while ((k < upcase_len)
712987da915Sopenharmony_ci	    && (k < 0x7f)
713987da915Sopenharmony_ci	    && (le16_to_cpu(upcase[k])
714987da915Sopenharmony_ci			== ((k < 'a') || (k > 'z') ? k : k + 'A' - 'a')))
715987da915Sopenharmony_ci		k++;
716987da915Sopenharmony_ci	if (k < 0x7f) {
717987da915Sopenharmony_ci		ntfs_log_error("Corrupted file $UpCase\n");
718987da915Sopenharmony_ci		if (!opt.no_action) {
719987da915Sopenharmony_ci			/* rewrite the $UpCase file from default */
720987da915Sopenharmony_ci			res = rewrite_upcase(vol, na);
721987da915Sopenharmony_ci			/* free the bad upcase record */
722987da915Sopenharmony_ci			if (!res)
723987da915Sopenharmony_ci				free(upcase);
724987da915Sopenharmony_ci		} else {
725987da915Sopenharmony_ci			/* keep the default upcase but return an error */
726987da915Sopenharmony_ci			free(upcase);
727987da915Sopenharmony_ci		}
728987da915Sopenharmony_ci	} else {
729987da915Sopenharmony_ci			/* accept the upcase table read from $UpCase */
730987da915Sopenharmony_ci		free(vol->upcase);
731987da915Sopenharmony_ci		vol->upcase = upcase;
732987da915Sopenharmony_ci		vol->upcase_len = upcase_len;
733987da915Sopenharmony_ci		res = 0;
734987da915Sopenharmony_ci	}
735987da915Sopenharmony_cierror_exit :
736987da915Sopenharmony_ci	/* Done with the $UpCase mft record. */
737987da915Sopenharmony_ci	if (na)
738987da915Sopenharmony_ci		ntfs_attr_close(na);
739987da915Sopenharmony_ci	if (ni && ntfs_inode_close(ni)) {
740987da915Sopenharmony_ci		ntfs_log_perror("Failed to close $UpCase");
741987da915Sopenharmony_ci	}
742987da915Sopenharmony_ci	return (res);
743987da915Sopenharmony_ci}
744987da915Sopenharmony_ci
745987da915Sopenharmony_ci/*
746987da915Sopenharmony_ci *		Rewrite the boot sector
747987da915Sopenharmony_ci *
748987da915Sopenharmony_ci *	Returns 0 if successful
749987da915Sopenharmony_ci */
750987da915Sopenharmony_ci
751987da915Sopenharmony_cistatic int rewrite_boot(struct ntfs_device *dev, char *full_bs,
752987da915Sopenharmony_ci				s32 sector_size)
753987da915Sopenharmony_ci{
754987da915Sopenharmony_ci	s64 bw;
755987da915Sopenharmony_ci	int res;
756987da915Sopenharmony_ci
757987da915Sopenharmony_ci	res = -1;
758987da915Sopenharmony_ci	ntfs_log_info("Rewriting the bootsector\n");
759987da915Sopenharmony_ci	bw = ntfs_pwrite(dev, 0, sector_size, full_bs);
760987da915Sopenharmony_ci	if (bw == sector_size)
761987da915Sopenharmony_ci		res = 0;
762987da915Sopenharmony_ci	else {
763987da915Sopenharmony_ci		if (bw != -1)
764987da915Sopenharmony_ci			errno = EINVAL;
765987da915Sopenharmony_ci		if (!bw)
766987da915Sopenharmony_ci			ntfs_log_error("Failed to rewrite the bootsector (size=0)\n");
767987da915Sopenharmony_ci		else
768987da915Sopenharmony_ci			ntfs_log_perror("Error rewriting the bootsector");
769987da915Sopenharmony_ci	}
770987da915Sopenharmony_ci	return (res);
771987da915Sopenharmony_ci}
772987da915Sopenharmony_ci
773987da915Sopenharmony_ci/*
774987da915Sopenharmony_ci *		Locate an unnamed attribute in an MFT record
775987da915Sopenharmony_ci *
776987da915Sopenharmony_ci *	Returns NULL if not found (with no error message)
777987da915Sopenharmony_ci */
778987da915Sopenharmony_ci
779987da915Sopenharmony_cistatic ATTR_RECORD *find_unnamed_attr(MFT_RECORD *mrec, ATTR_TYPES type)
780987da915Sopenharmony_ci{
781987da915Sopenharmony_ci	ATTR_RECORD *a;
782987da915Sopenharmony_ci	u32 offset;
783987da915Sopenharmony_ci	s32 space;
784987da915Sopenharmony_ci
785987da915Sopenharmony_ci			/* fetch the requested attribute */
786987da915Sopenharmony_ci	offset = le16_to_cpu(mrec->attrs_offset);
787987da915Sopenharmony_ci	space = le32_to_cpu(mrec->bytes_in_use) - offset;
788987da915Sopenharmony_ci	a = (ATTR_RECORD*)((char*)mrec + offset);
789987da915Sopenharmony_ci	while ((space >= (s32)offsetof(ATTR_RECORD, resident_end))
790987da915Sopenharmony_ci	    && (a->type != AT_END)
791987da915Sopenharmony_ci	    && (le32_to_cpu(a->length) <= (u32)space)
792987da915Sopenharmony_ci	    && !(le32_to_cpu(a->length) & 7)
793987da915Sopenharmony_ci	    && ((a->type != type) || a->name_length)) {
794987da915Sopenharmony_ci		offset += le32_to_cpu(a->length);
795987da915Sopenharmony_ci		space -= le32_to_cpu(a->length);
796987da915Sopenharmony_ci		a = (ATTR_RECORD*)((char*)mrec + offset);
797987da915Sopenharmony_ci	}
798987da915Sopenharmony_ci	if ((offset >= le32_to_cpu(mrec->bytes_in_use))
799987da915Sopenharmony_ci	    || (a->type != type)
800987da915Sopenharmony_ci	    || a->name_length)
801987da915Sopenharmony_ci		a = (ATTR_RECORD*)NULL;
802987da915Sopenharmony_ci	return (a);
803987da915Sopenharmony_ci}
804987da915Sopenharmony_ci
805987da915Sopenharmony_ci/*
806987da915Sopenharmony_ci *		First condition for having a self-located MFT :
807987da915Sopenharmony_ci *		only 16 MFT records are defined in MFT record 0
808987da915Sopenharmony_ci *
809987da915Sopenharmony_ci *	Only low-level library functions can be used.
810987da915Sopenharmony_ci *
811987da915Sopenharmony_ci *	Returns TRUE if the condition is met.
812987da915Sopenharmony_ci */
813987da915Sopenharmony_ci
814987da915Sopenharmony_cistatic BOOL short_mft_selfloc_condition(struct MFT_SELF_LOCATED *selfloc)
815987da915Sopenharmony_ci{
816987da915Sopenharmony_ci	BOOL ok;
817987da915Sopenharmony_ci	ntfs_volume *vol;
818987da915Sopenharmony_ci	MFT_RECORD *mft0;
819987da915Sopenharmony_ci	ATTR_RECORD *a;
820987da915Sopenharmony_ci	runlist_element *rl;
821987da915Sopenharmony_ci	u16 seqn;
822987da915Sopenharmony_ci
823987da915Sopenharmony_ci	ok = FALSE;
824987da915Sopenharmony_ci	vol = selfloc->vol;
825987da915Sopenharmony_ci	mft0 = selfloc->mft0;
826987da915Sopenharmony_ci	if ((ntfs_pread(vol->dev,
827987da915Sopenharmony_ci			vol->mft_lcn << vol->cluster_size_bits,
828987da915Sopenharmony_ci			vol->mft_record_size, mft0)
829987da915Sopenharmony_ci				== vol->mft_record_size)
830987da915Sopenharmony_ci	    && !ntfs_mst_post_read_fixup((NTFS_RECORD*)mft0,
831987da915Sopenharmony_ci			vol->mft_record_size)
832987da915Sopenharmony_ci	    && !ntfs_mft_record_check(vol, 0, mft0)) {
833987da915Sopenharmony_ci		a = find_unnamed_attr(mft0,AT_DATA);
834987da915Sopenharmony_ci		if (a
835987da915Sopenharmony_ci		    && a->non_resident
836987da915Sopenharmony_ci		    && (((sle64_to_cpu(a->highest_vcn) + 1)
837987da915Sopenharmony_ci					<< vol->cluster_size_bits)
838987da915Sopenharmony_ci				== (SELFLOC_LIMIT*vol->mft_record_size))) {
839987da915Sopenharmony_ci			rl = ntfs_mapping_pairs_decompress(vol, a, NULL);
840987da915Sopenharmony_ci			if (rl) {
841987da915Sopenharmony_ci				/*
842987da915Sopenharmony_ci				 * The first error condition is having only
843987da915Sopenharmony_ci				 * 16 entries mapped in the first MFT record.
844987da915Sopenharmony_ci				 */
845987da915Sopenharmony_ci				if ((rl[0].lcn >= 0)
846987da915Sopenharmony_ci				  && ((rl[0].length << vol->cluster_size_bits)
847987da915Sopenharmony_ci					== SELFLOC_LIMIT*vol->mft_record_size)
848987da915Sopenharmony_ci				  && (rl[1].vcn == rl[0].length)
849987da915Sopenharmony_ci				  && (rl[1].lcn == LCN_RL_NOT_MAPPED)) {
850987da915Sopenharmony_ci					ok = TRUE;
851987da915Sopenharmony_ci					seqn = le16_to_cpu(
852987da915Sopenharmony_ci						mft0->sequence_number);
853987da915Sopenharmony_ci					selfloc->mft_ref0
854987da915Sopenharmony_ci						= ((MFT_REF)seqn) << 48;
855987da915Sopenharmony_ci				}
856987da915Sopenharmony_ci				free(rl);
857987da915Sopenharmony_ci			}
858987da915Sopenharmony_ci		}
859987da915Sopenharmony_ci	}
860987da915Sopenharmony_ci	return (ok);
861987da915Sopenharmony_ci}
862987da915Sopenharmony_ci
863987da915Sopenharmony_ci/*
864987da915Sopenharmony_ci *		Second condition for having a self-located MFT :
865987da915Sopenharmony_ci *		The 16th MFT record is defined in MFT record >= 16
866987da915Sopenharmony_ci *
867987da915Sopenharmony_ci *	Only low-level library functions can be used.
868987da915Sopenharmony_ci *
869987da915Sopenharmony_ci *	Returns TRUE if the condition is met.
870987da915Sopenharmony_ci */
871987da915Sopenharmony_ci
872987da915Sopenharmony_cistatic BOOL attrlist_selfloc_condition(struct MFT_SELF_LOCATED *selfloc)
873987da915Sopenharmony_ci{
874987da915Sopenharmony_ci	ntfs_volume *vol;
875987da915Sopenharmony_ci	ATTR_RECORD *a;
876987da915Sopenharmony_ci	ATTR_LIST_ENTRY *attrlist;
877987da915Sopenharmony_ci	ATTR_LIST_ENTRY *al;
878987da915Sopenharmony_ci	runlist_element *rl;
879987da915Sopenharmony_ci	VCN vcn;
880987da915Sopenharmony_ci	leVCN levcn;
881987da915Sopenharmony_ci	u32 length;
882987da915Sopenharmony_ci	int ok;
883987da915Sopenharmony_ci
884987da915Sopenharmony_ci	ok = FALSE;
885987da915Sopenharmony_ci	length = 0;
886987da915Sopenharmony_ci	vol = selfloc->vol;
887987da915Sopenharmony_ci	a = find_unnamed_attr(selfloc->mft0,AT_ATTRIBUTE_LIST);
888987da915Sopenharmony_ci	if (a) {
889987da915Sopenharmony_ci		selfloc->attrlist_resident = !a->non_resident;
890987da915Sopenharmony_ci		selfloc->attrlist_lcn = 0;
891987da915Sopenharmony_ci		if (a->non_resident) {
892987da915Sopenharmony_ci			attrlist = selfloc->attrlist;
893987da915Sopenharmony_ci			rl = ntfs_mapping_pairs_decompress(vol, a, NULL);
894987da915Sopenharmony_ci			if (rl
895987da915Sopenharmony_ci			    && (rl->lcn >= 0)
896987da915Sopenharmony_ci			    && (sle64_to_cpu(a->data_size) < vol->cluster_size)
897987da915Sopenharmony_ci			    && (ntfs_pread(vol->dev,
898987da915Sopenharmony_ci					rl->lcn << vol->cluster_size_bits,
899987da915Sopenharmony_ci					vol->cluster_size, attrlist) == vol->cluster_size)) {
900987da915Sopenharmony_ci				selfloc->attrlist_lcn = rl->lcn;
901987da915Sopenharmony_ci				al = attrlist;
902987da915Sopenharmony_ci				length = sle64_to_cpu(a->data_size);
903987da915Sopenharmony_ci			}
904987da915Sopenharmony_ci		} else {
905987da915Sopenharmony_ci			al = (ATTR_LIST_ENTRY*)
906987da915Sopenharmony_ci				((char*)a + le16_to_cpu(a->value_offset));
907987da915Sopenharmony_ci			length = le32_to_cpu(a->value_length);
908987da915Sopenharmony_ci		}
909987da915Sopenharmony_ci		if (length) {
910987da915Sopenharmony_ci			/* search for a data attribute defining entry 16 */
911987da915Sopenharmony_ci			vcn = (SELFLOC_LIMIT*vol->mft_record_size)
912987da915Sopenharmony_ci					>> vol->cluster_size_bits;
913987da915Sopenharmony_ci			levcn = cpu_to_sle64(vcn);
914987da915Sopenharmony_ci			while ((length > 0)
915987da915Sopenharmony_ci			    && al->length
916987da915Sopenharmony_ci			    && ((al->type != AT_DATA)
917987da915Sopenharmony_ci				|| ((leVCN)al->lowest_vcn != levcn))) {
918987da915Sopenharmony_ci				length -= le16_to_cpu(al->length);
919987da915Sopenharmony_ci				al = (ATTR_LIST_ENTRY*)
920987da915Sopenharmony_ci					((char*)al + le16_to_cpu(al->length));
921987da915Sopenharmony_ci			}
922987da915Sopenharmony_ci			if ((length > 0)
923987da915Sopenharmony_ci			    && al->length
924987da915Sopenharmony_ci			    && (al->type == AT_DATA)
925987da915Sopenharmony_ci			    && !al->name_length
926987da915Sopenharmony_ci			    && ((leVCN)al->lowest_vcn == levcn)
927987da915Sopenharmony_ci			    && (MREF_LE(al->mft_reference) >= SELFLOC_LIMIT)) {
928987da915Sopenharmony_ci				selfloc->mft_ref1
929987da915Sopenharmony_ci					= le64_to_cpu(al->mft_reference);
930987da915Sopenharmony_ci				selfloc->attrlist_to_ref1 = al;
931987da915Sopenharmony_ci				ok = TRUE;
932987da915Sopenharmony_ci			}
933987da915Sopenharmony_ci		}
934987da915Sopenharmony_ci	}
935987da915Sopenharmony_ci	return (ok);
936987da915Sopenharmony_ci}
937987da915Sopenharmony_ci
938987da915Sopenharmony_ci/*
939987da915Sopenharmony_ci *		Third condition for having a self-located MFT :
940987da915Sopenharmony_ci *		The location of the second part of the MFT is defined in itself
941987da915Sopenharmony_ci *
942987da915Sopenharmony_ci *	To locate the second part, we have to assume the first and the
943987da915Sopenharmony_ci *	second part of the MFT data are contiguous.
944987da915Sopenharmony_ci *
945987da915Sopenharmony_ci *	Only low-level library functions can be used.
946987da915Sopenharmony_ci *
947987da915Sopenharmony_ci *	Returns TRUE if the condition is met.
948987da915Sopenharmony_ci */
949987da915Sopenharmony_ci
950987da915Sopenharmony_cistatic BOOL self_mapped_selfloc_condition(struct MFT_SELF_LOCATED *selfloc)
951987da915Sopenharmony_ci{
952987da915Sopenharmony_ci	BOOL ok;
953987da915Sopenharmony_ci	s64 inum;
954987da915Sopenharmony_ci	u64 offs;
955987da915Sopenharmony_ci	VCN lowest_vcn;
956987da915Sopenharmony_ci	MFT_RECORD *mft1;
957987da915Sopenharmony_ci	ATTR_RECORD *a;
958987da915Sopenharmony_ci	ntfs_volume *vol;
959987da915Sopenharmony_ci	runlist_element *rl;
960987da915Sopenharmony_ci
961987da915Sopenharmony_ci	ok = FALSE;
962987da915Sopenharmony_ci	vol = selfloc->vol;
963987da915Sopenharmony_ci	mft1 = selfloc->mft1;
964987da915Sopenharmony_ci	inum = MREF(selfloc->mft_ref1);
965987da915Sopenharmony_ci	offs = 	(vol->mft_lcn << vol->cluster_size_bits)
966987da915Sopenharmony_ci			+ (inum << vol->mft_record_size_bits);
967987da915Sopenharmony_ci	if ((ntfs_pread(vol->dev, offs, vol->mft_record_size,
968987da915Sopenharmony_ci			mft1) == vol->mft_record_size)
969987da915Sopenharmony_ci	    && !ntfs_mst_post_read_fixup((NTFS_RECORD*)mft1,
970987da915Sopenharmony_ci			vol->mft_record_size)
971987da915Sopenharmony_ci	    && !ntfs_mft_record_check(vol, inum, mft1)) {
972987da915Sopenharmony_ci
973987da915Sopenharmony_ci		lowest_vcn = (SELFLOC_LIMIT*vol->mft_record_size)
974987da915Sopenharmony_ci				>> vol->cluster_size_bits;
975987da915Sopenharmony_ci		a = find_unnamed_attr(mft1,AT_DATA);
976987da915Sopenharmony_ci		if (a
977987da915Sopenharmony_ci		    && (mft1->flags & MFT_RECORD_IN_USE)
978987da915Sopenharmony_ci		    && ((VCN)sle64_to_cpu(a->lowest_vcn) == lowest_vcn)
979987da915Sopenharmony_ci		    && (le64_to_cpu(mft1->base_mft_record)
980987da915Sopenharmony_ci				== selfloc->mft_ref0)
981987da915Sopenharmony_ci		    && ((u16)MSEQNO(selfloc->mft_ref1)
982987da915Sopenharmony_ci				== le16_to_cpu(mft1->sequence_number))) {
983987da915Sopenharmony_ci			rl = ntfs_mapping_pairs_decompress(vol, a, NULL);
984987da915Sopenharmony_ci			if ((rl[0].lcn == LCN_RL_NOT_MAPPED)
985987da915Sopenharmony_ci			   && !rl[0].vcn
986987da915Sopenharmony_ci			   && (rl[0].length == lowest_vcn)
987987da915Sopenharmony_ci			   && (rl[1].vcn == lowest_vcn)
988987da915Sopenharmony_ci			   && ((u64)(rl[1].lcn << vol->cluster_size_bits)
989987da915Sopenharmony_ci					<= offs)
990987da915Sopenharmony_ci			   && ((u64)((rl[1].lcn + rl[1].length)
991987da915Sopenharmony_ci					<< vol->cluster_size_bits) > offs)) {
992987da915Sopenharmony_ci				ok = TRUE;
993987da915Sopenharmony_ci			}
994987da915Sopenharmony_ci		}
995987da915Sopenharmony_ci	}
996987da915Sopenharmony_ci	return (ok);
997987da915Sopenharmony_ci}
998987da915Sopenharmony_ci
999987da915Sopenharmony_ci/*
1000987da915Sopenharmony_ci *		Fourth condition, to be able to fix a self-located MFT :
1001987da915Sopenharmony_ci *		The MFT record 15 must be available.
1002987da915Sopenharmony_ci *
1003987da915Sopenharmony_ci *	The MFT record 15 is expected to be marked in use, we assume
1004987da915Sopenharmony_ci *	it is available if it has no parent, no name and no attr list.
1005987da915Sopenharmony_ci *
1006987da915Sopenharmony_ci *	Only low-level library functions can be used.
1007987da915Sopenharmony_ci *
1008987da915Sopenharmony_ci *	Returns TRUE if the condition is met.
1009987da915Sopenharmony_ci */
1010987da915Sopenharmony_ci
1011987da915Sopenharmony_cistatic BOOL spare_record_selfloc_condition(struct MFT_SELF_LOCATED *selfloc)
1012987da915Sopenharmony_ci{
1013987da915Sopenharmony_ci	BOOL ok;
1014987da915Sopenharmony_ci	s64 inum;
1015987da915Sopenharmony_ci	u64 offs;
1016987da915Sopenharmony_ci	MFT_RECORD *mft2;
1017987da915Sopenharmony_ci	ntfs_volume *vol;
1018987da915Sopenharmony_ci
1019987da915Sopenharmony_ci	ok = FALSE;
1020987da915Sopenharmony_ci	vol = selfloc->vol;
1021987da915Sopenharmony_ci	mft2 = selfloc->mft2;
1022987da915Sopenharmony_ci	inum = SELFLOC_LIMIT - 1;
1023987da915Sopenharmony_ci	offs = 	(vol->mft_lcn << vol->cluster_size_bits)
1024987da915Sopenharmony_ci			+ (inum << vol->mft_record_size_bits);
1025987da915Sopenharmony_ci	if ((ntfs_pread(vol->dev, offs, vol->mft_record_size,
1026987da915Sopenharmony_ci			mft2) == vol->mft_record_size)
1027987da915Sopenharmony_ci	    && !ntfs_mst_post_read_fixup((NTFS_RECORD*)mft2,
1028987da915Sopenharmony_ci			vol->mft_record_size)
1029987da915Sopenharmony_ci	    && !ntfs_mft_record_check(vol, inum, mft2)) {
1030987da915Sopenharmony_ci		if (!mft2->base_mft_record
1031987da915Sopenharmony_ci		    && (mft2->flags & MFT_RECORD_IN_USE)
1032987da915Sopenharmony_ci		    && !find_unnamed_attr(mft2,AT_ATTRIBUTE_LIST)
1033987da915Sopenharmony_ci		    && !find_unnamed_attr(mft2,AT_FILE_NAME)) {
1034987da915Sopenharmony_ci			ok = TRUE;
1035987da915Sopenharmony_ci		}
1036987da915Sopenharmony_ci	}
1037987da915Sopenharmony_ci	return (ok);
1038987da915Sopenharmony_ci}
1039987da915Sopenharmony_ci
1040987da915Sopenharmony_ci/*
1041987da915Sopenharmony_ci *		Fix a self-located MFT by swapping two MFT records
1042987da915Sopenharmony_ci *
1043987da915Sopenharmony_ci *	Only low-level library functions can be used.
1044987da915Sopenharmony_ci *
1045987da915Sopenharmony_ci *	Returns 0 if the MFT corruption could be fixed.
1046987da915Sopenharmony_ci */
1047987da915Sopenharmony_cistatic int fix_selfloc_conditions(struct MFT_SELF_LOCATED *selfloc)
1048987da915Sopenharmony_ci{
1049987da915Sopenharmony_ci	MFT_RECORD *mft1;
1050987da915Sopenharmony_ci	MFT_RECORD *mft2;
1051987da915Sopenharmony_ci	ATTR_RECORD *a;
1052987da915Sopenharmony_ci	ATTR_LIST_ENTRY *al;
1053987da915Sopenharmony_ci	ntfs_volume *vol;
1054987da915Sopenharmony_ci	s64 offs;
1055987da915Sopenharmony_ci	s64 offsm;
1056987da915Sopenharmony_ci	s64 offs1;
1057987da915Sopenharmony_ci	s64 offs2;
1058987da915Sopenharmony_ci	s64 inum;
1059987da915Sopenharmony_ci	u16 usa_ofs;
1060987da915Sopenharmony_ci	int res;
1061987da915Sopenharmony_ci
1062987da915Sopenharmony_ci	res = 0;
1063987da915Sopenharmony_ci			/*
1064987da915Sopenharmony_ci			 * In MFT1, we must fix :
1065987da915Sopenharmony_ci			 * - the self-reference, if present,
1066987da915Sopenharmony_ci			 * - its own sequence number, must be 15
1067987da915Sopenharmony_ci			 * - the sizes of the data attribute.
1068987da915Sopenharmony_ci			 */
1069987da915Sopenharmony_ci	vol = selfloc->vol;
1070987da915Sopenharmony_ci	mft1 = selfloc->mft1;
1071987da915Sopenharmony_ci	mft2 = selfloc->mft2;
1072987da915Sopenharmony_ci	usa_ofs = le16_to_cpu(mft1->usa_ofs);
1073987da915Sopenharmony_ci	if (usa_ofs >= 48)
1074987da915Sopenharmony_ci		mft1->mft_record_number = const_cpu_to_le32(SELFLOC_LIMIT - 1);
1075987da915Sopenharmony_ci	mft1->sequence_number = const_cpu_to_le16(SELFLOC_LIMIT - 1);
1076987da915Sopenharmony_ci	a = find_unnamed_attr(mft1,AT_DATA);
1077987da915Sopenharmony_ci	if (a) {
1078987da915Sopenharmony_ci		a->allocated_size = const_cpu_to_sle64(0);
1079987da915Sopenharmony_ci		a->data_size = const_cpu_to_sle64(0);
1080987da915Sopenharmony_ci		a->initialized_size = const_cpu_to_sle64(0);
1081987da915Sopenharmony_ci	} else
1082987da915Sopenharmony_ci		res = -1; /* bug : it has been found earlier */
1083987da915Sopenharmony_ci
1084987da915Sopenharmony_ci			/*
1085987da915Sopenharmony_ci			 * In MFT2, we must fix :
1086987da915Sopenharmony_ci			 * - the self-reference, if present
1087987da915Sopenharmony_ci			 */
1088987da915Sopenharmony_ci	usa_ofs = le16_to_cpu(mft2->usa_ofs);
1089987da915Sopenharmony_ci	if (usa_ofs >= 48)
1090987da915Sopenharmony_ci		mft2->mft_record_number = cpu_to_le32(MREF(selfloc->mft_ref1));
1091987da915Sopenharmony_ci
1092987da915Sopenharmony_ci			/*
1093987da915Sopenharmony_ci			 * In the attribute list, we must fix :
1094987da915Sopenharmony_ci			 * - the reference to MFT1
1095987da915Sopenharmony_ci			 */
1096987da915Sopenharmony_ci	al = selfloc->attrlist_to_ref1;
1097987da915Sopenharmony_ci	al->mft_reference = MK_LE_MREF(SELFLOC_LIMIT - 1, SELFLOC_LIMIT - 1);
1098987da915Sopenharmony_ci
1099987da915Sopenharmony_ci			/*
1100987da915Sopenharmony_ci			 * All fixes done, we can write all if allowed
1101987da915Sopenharmony_ci			 */
1102987da915Sopenharmony_ci	if (!res && !opt.no_action) {
1103987da915Sopenharmony_ci		inum = SELFLOC_LIMIT - 1;
1104987da915Sopenharmony_ci		offs2 = (vol->mft_lcn << vol->cluster_size_bits)
1105987da915Sopenharmony_ci			+ (inum << vol->mft_record_size_bits);
1106987da915Sopenharmony_ci		inum = MREF(selfloc->mft_ref1);
1107987da915Sopenharmony_ci		offs1 = (vol->mft_lcn << vol->cluster_size_bits)
1108987da915Sopenharmony_ci			+ (inum << vol->mft_record_size_bits);
1109987da915Sopenharmony_ci
1110987da915Sopenharmony_ci			/* rewrite the attribute list */
1111987da915Sopenharmony_ci		if (selfloc->attrlist_resident) {
1112987da915Sopenharmony_ci				/* write mft0 and mftmirr if it is resident */
1113987da915Sopenharmony_ci			offs = vol->mft_lcn << vol->cluster_size_bits;
1114987da915Sopenharmony_ci			offsm = vol->mftmirr_lcn << vol->cluster_size_bits;
1115987da915Sopenharmony_ci			if (ntfs_mst_pre_write_fixup(
1116987da915Sopenharmony_ci					(NTFS_RECORD*)selfloc->mft0,
1117987da915Sopenharmony_ci					vol->mft_record_size)
1118987da915Sopenharmony_ci			    || (ntfs_pwrite(vol->dev, offs, vol->mft_record_size,
1119987da915Sopenharmony_ci					selfloc->mft0) != vol->mft_record_size)
1120987da915Sopenharmony_ci			    || (ntfs_pwrite(vol->dev, offsm, vol->mft_record_size,
1121987da915Sopenharmony_ci					selfloc->mft0) != vol->mft_record_size))
1122987da915Sopenharmony_ci				res = -1;
1123987da915Sopenharmony_ci		} else {
1124987da915Sopenharmony_ci				/* write a full cluster if non resident */
1125987da915Sopenharmony_ci			offs = selfloc->attrlist_lcn << vol->cluster_size_bits;
1126987da915Sopenharmony_ci			if (ntfs_pwrite(vol->dev, offs, vol->cluster_size,
1127987da915Sopenharmony_ci					selfloc->attrlist) != vol->cluster_size)
1128987da915Sopenharmony_ci				res = -1;
1129987da915Sopenharmony_ci		}
1130987da915Sopenharmony_ci			/* replace MFT2 by MFT1 and replace MFT1 by MFT2 */
1131987da915Sopenharmony_ci		if (!res
1132987da915Sopenharmony_ci		    && (ntfs_mst_pre_write_fixup((NTFS_RECORD*)selfloc->mft1,
1133987da915Sopenharmony_ci					vol->mft_record_size)
1134987da915Sopenharmony_ci			|| ntfs_mst_pre_write_fixup((NTFS_RECORD*)selfloc->mft2,
1135987da915Sopenharmony_ci					vol->mft_record_size)
1136987da915Sopenharmony_ci			|| (ntfs_pwrite(vol->dev, offs2, vol->mft_record_size,
1137987da915Sopenharmony_ci					mft1) != vol->mft_record_size)
1138987da915Sopenharmony_ci			|| (ntfs_pwrite(vol->dev, offs1, vol->mft_record_size,
1139987da915Sopenharmony_ci					mft2) != vol->mft_record_size)))
1140987da915Sopenharmony_ci				res = -1;
1141987da915Sopenharmony_ci	}
1142987da915Sopenharmony_ci	return (res);
1143987da915Sopenharmony_ci}
1144987da915Sopenharmony_ci
1145987da915Sopenharmony_ci/*
1146987da915Sopenharmony_ci *		Detect and fix a Windows XP bug, leading to a corrupt MFT
1147987da915Sopenharmony_ci *
1148987da915Sopenharmony_ci *	Windows cannot boot anymore, so chkdsk cannot be started, which
1149987da915Sopenharmony_ci *	is a good point, because chkdsk would have deleted all the files.
1150987da915Sopenharmony_ci *	Older ntfs-3g fell into an endless recursion (recent versions
1151987da915Sopenharmony_ci *	refuse to mount).
1152987da915Sopenharmony_ci *
1153987da915Sopenharmony_ci *	This situation is very rare, but it was fun to fix it.
1154987da915Sopenharmony_ci *
1155987da915Sopenharmony_ci *	The corrupted condition is :
1156987da915Sopenharmony_ci *		- MFT entry 0 has only the runlist for MFT entries 0-15
1157987da915Sopenharmony_ci *		- The attribute list for MFT shows the second part
1158987da915Sopenharmony_ci *			in an MFT record beyond 15
1159987da915Sopenharmony_ci *	Of course, this record has to be read in order to know where it is.
1160987da915Sopenharmony_ci *
1161987da915Sopenharmony_ci *	Sample case, met in 2011 (Windows XP) :
1162987da915Sopenharmony_ci *		MFT record 0 has : stdinfo, nonres attrlist, the first
1163987da915Sopenharmony_ci *				part of MFT data (entries 0-15), and bitmap
1164987da915Sopenharmony_ci *		MFT record 16 has the name
1165987da915Sopenharmony_ci *		MFT record 17 has the third part of MFT data (16-117731)
1166987da915Sopenharmony_ci *		MFT record 18 has the second part of MFT data (117732-170908)
1167987da915Sopenharmony_ci *
1168987da915Sopenharmony_ci *	Assuming the second part of the MFT is contiguous to the first
1169987da915Sopenharmony_ci *	part, we can find it, and fix the condition by relocating it
1170987da915Sopenharmony_ci *	and swapping it with MFT record 15.
1171987da915Sopenharmony_ci *	This record number 15 appears to be hardcoded into Windows NTFS.
1172987da915Sopenharmony_ci *
1173987da915Sopenharmony_ci *	Only low-level library functions can be used.
1174987da915Sopenharmony_ci *
1175987da915Sopenharmony_ci *	Returns 0 if the conditions for the error was met and
1176987da915Sopenharmony_ci *			this error could be fixed,
1177987da915Sopenharmony_ci *		-1 if the condition was not met or some error
1178987da915Sopenharmony_ci *			which could not be fixed was encountered.
1179987da915Sopenharmony_ci */
1180987da915Sopenharmony_ci
1181987da915Sopenharmony_cistatic int fix_self_located_mft(ntfs_volume *vol)
1182987da915Sopenharmony_ci{
1183987da915Sopenharmony_ci	struct MFT_SELF_LOCATED selfloc;
1184987da915Sopenharmony_ci	BOOL res;
1185987da915Sopenharmony_ci
1186987da915Sopenharmony_ci	ntfs_log_info("Checking for self-located MFT segment... ");
1187987da915Sopenharmony_ci	res = -1;
1188987da915Sopenharmony_ci	selfloc.vol = vol;
1189987da915Sopenharmony_ci	selfloc.mft0 = (MFT_RECORD*)malloc(vol->mft_record_size);
1190987da915Sopenharmony_ci	selfloc.mft1 = (MFT_RECORD*)malloc(vol->mft_record_size);
1191987da915Sopenharmony_ci	selfloc.mft2 = (MFT_RECORD*)malloc(vol->mft_record_size);
1192987da915Sopenharmony_ci	selfloc.attrlist = (ATTR_LIST_ENTRY*)malloc(vol->cluster_size);
1193987da915Sopenharmony_ci	if (selfloc.mft0 && selfloc.mft1 && selfloc.mft2
1194987da915Sopenharmony_ci	    && selfloc.attrlist) {
1195987da915Sopenharmony_ci		if (short_mft_selfloc_condition(&selfloc)
1196987da915Sopenharmony_ci		    && attrlist_selfloc_condition(&selfloc)
1197987da915Sopenharmony_ci		    && self_mapped_selfloc_condition(&selfloc)
1198987da915Sopenharmony_ci		    && spare_record_selfloc_condition(&selfloc)) {
1199987da915Sopenharmony_ci			ntfs_log_info(FOUND);
1200987da915Sopenharmony_ci			ntfs_log_info("Fixing the self-located MFT segment... ");
1201987da915Sopenharmony_ci			res = fix_selfloc_conditions(&selfloc);
1202987da915Sopenharmony_ci			ntfs_log_info(res ? FAILED : OK);
1203987da915Sopenharmony_ci		} else {
1204987da915Sopenharmony_ci			ntfs_log_info(OK);
1205987da915Sopenharmony_ci			res = -1;
1206987da915Sopenharmony_ci		}
1207987da915Sopenharmony_ci		free(selfloc.mft0);
1208987da915Sopenharmony_ci		free(selfloc.mft1);
1209987da915Sopenharmony_ci		free(selfloc.mft2);
1210987da915Sopenharmony_ci		free(selfloc.attrlist);
1211987da915Sopenharmony_ci	}
1212987da915Sopenharmony_ci	return (res);
1213987da915Sopenharmony_ci}
1214987da915Sopenharmony_ci
1215987da915Sopenharmony_ci/*
1216987da915Sopenharmony_ci *		Try an alternate boot sector and fix the real one
1217987da915Sopenharmony_ci *
1218987da915Sopenharmony_ci *	Only after successful checks is the boot sector rewritten.
1219987da915Sopenharmony_ci *
1220987da915Sopenharmony_ci *	The alternate boot sector is not rewritten, either because it
1221987da915Sopenharmony_ci *	was found correct, or because we truncated the file system
1222987da915Sopenharmony_ci *	and the last actual sector might be part of some file.
1223987da915Sopenharmony_ci *
1224987da915Sopenharmony_ci *	Returns 0 if successful
1225987da915Sopenharmony_ci */
1226987da915Sopenharmony_ci
1227987da915Sopenharmony_cistatic int try_fix_boot(ntfs_volume *vol, char *full_bs,
1228987da915Sopenharmony_ci			s64 read_sector, s64 fix_sectors, s32 sector_size)
1229987da915Sopenharmony_ci{
1230987da915Sopenharmony_ci	s64 br;
1231987da915Sopenharmony_ci	int res;
1232987da915Sopenharmony_ci	s64 got_sectors;
1233987da915Sopenharmony_ci	le16 sector_size_le;
1234987da915Sopenharmony_ci	NTFS_BOOT_SECTOR *bs;
1235987da915Sopenharmony_ci
1236987da915Sopenharmony_ci	res = -1;
1237987da915Sopenharmony_ci	br = ntfs_pread(vol->dev, read_sector*sector_size,
1238987da915Sopenharmony_ci					sector_size, full_bs);
1239987da915Sopenharmony_ci	if (br != sector_size) {
1240987da915Sopenharmony_ci		if (br != -1)
1241987da915Sopenharmony_ci			errno = EINVAL;
1242987da915Sopenharmony_ci		if (!br)
1243987da915Sopenharmony_ci			ntfs_log_error("Failed to read alternate bootsector (size=0)\n");
1244987da915Sopenharmony_ci		else
1245987da915Sopenharmony_ci			ntfs_log_perror("Error reading alternate bootsector");
1246987da915Sopenharmony_ci	} else {
1247987da915Sopenharmony_ci		bs = (NTFS_BOOT_SECTOR*)full_bs;
1248987da915Sopenharmony_ci		got_sectors = sle64_to_cpu(bs->number_of_sectors);
1249987da915Sopenharmony_ci		bs->number_of_sectors = cpu_to_sle64(fix_sectors);
1250987da915Sopenharmony_ci		/* alignment problem on Sparc, even doing memcpy() */
1251987da915Sopenharmony_ci		sector_size_le = cpu_to_le16(sector_size);
1252987da915Sopenharmony_ci		if (!memcmp(&sector_size_le, &bs->bpb.bytes_per_sector,2)
1253987da915Sopenharmony_ci		    && ntfs_boot_sector_is_ntfs(bs)
1254987da915Sopenharmony_ci		    && !ntfs_boot_sector_parse(vol, bs)) {
1255987da915Sopenharmony_ci			ntfs_log_info("The alternate bootsector is usable\n");
1256987da915Sopenharmony_ci			if (fix_sectors != got_sectors)
1257987da915Sopenharmony_ci				ntfs_log_info("Set sector count to %lld instead of %lld\n",
1258987da915Sopenharmony_ci						(long long)fix_sectors,
1259987da915Sopenharmony_ci						(long long)got_sectors);
1260987da915Sopenharmony_ci			/* fix the normal boot sector */
1261987da915Sopenharmony_ci			if (!opt.no_action) {
1262987da915Sopenharmony_ci				res = rewrite_boot(vol->dev, full_bs,
1263987da915Sopenharmony_ci							sector_size);
1264987da915Sopenharmony_ci			} else
1265987da915Sopenharmony_ci				res = 0;
1266987da915Sopenharmony_ci		}
1267987da915Sopenharmony_ci		if (!res && !opt.no_action)
1268987da915Sopenharmony_ci			ntfs_log_info("The boot sector has been rewritten\n");
1269987da915Sopenharmony_ci	}
1270987da915Sopenharmony_ci	return (res);
1271987da915Sopenharmony_ci}
1272987da915Sopenharmony_ci
1273987da915Sopenharmony_ci/*
1274987da915Sopenharmony_ci *		Try the alternate boot sector if the normal one is bad
1275987da915Sopenharmony_ci *
1276987da915Sopenharmony_ci *	Actually :
1277987da915Sopenharmony_ci *	- first try the last sector of the partition (expected location)
1278987da915Sopenharmony_ci *	- then try the last sector as shown in the main boot sector,
1279987da915Sopenharmony_ci *		(could be meaningful for an undersized partition)
1280987da915Sopenharmony_ci *	- finally try truncating the file system actual size of partition
1281987da915Sopenharmony_ci *		(could be meaningful for an oversized partition)
1282987da915Sopenharmony_ci *
1283987da915Sopenharmony_ci *	if successful, rewrite the normal boot sector accordingly
1284987da915Sopenharmony_ci *
1285987da915Sopenharmony_ci *	Returns 0 if successful
1286987da915Sopenharmony_ci */
1287987da915Sopenharmony_ci
1288987da915Sopenharmony_cistatic int try_alternate_boot(ntfs_volume *vol, char *full_bs,
1289987da915Sopenharmony_ci			s32 sector_size, s64 shown_sectors)
1290987da915Sopenharmony_ci{
1291987da915Sopenharmony_ci	s64 actual_sectors;
1292987da915Sopenharmony_ci	int res;
1293987da915Sopenharmony_ci
1294987da915Sopenharmony_ci	res = -1;
1295987da915Sopenharmony_ci	ntfs_log_info("Trying the alternate boot sector\n");
1296987da915Sopenharmony_ci
1297987da915Sopenharmony_ci		/*
1298987da915Sopenharmony_ci		 * We do not rely on the sector size defined in the
1299987da915Sopenharmony_ci		 * boot sector, supposed to be corrupt, so we try to get
1300987da915Sopenharmony_ci		 * the actual sector size and defaulting to 512 if failed
1301987da915Sopenharmony_ci		 * to get. This value is only used to guess the alternate
1302987da915Sopenharmony_ci		 * boot sector location and it is checked against the
1303987da915Sopenharmony_ci		 * value found in the sector itself. It should not damage
1304987da915Sopenharmony_ci		 * anything if wrong.
1305987da915Sopenharmony_ci		 *
1306987da915Sopenharmony_ci		 * Note : the real last sector is not accounted for here.
1307987da915Sopenharmony_ci		 */
1308987da915Sopenharmony_ci	actual_sectors = ntfs_device_size_get(vol->dev,sector_size) - 1;
1309987da915Sopenharmony_ci
1310987da915Sopenharmony_ci		/* first try the actual last sector */
1311987da915Sopenharmony_ci	if ((actual_sectors > 0)
1312987da915Sopenharmony_ci	    && !try_fix_boot(vol, full_bs, actual_sectors,
1313987da915Sopenharmony_ci				actual_sectors, sector_size))
1314987da915Sopenharmony_ci		res = 0;
1315987da915Sopenharmony_ci
1316987da915Sopenharmony_ci		/* then try the shown last sector, if less than actual */
1317987da915Sopenharmony_ci	if (res
1318987da915Sopenharmony_ci	    && (shown_sectors > 0)
1319987da915Sopenharmony_ci	    && (shown_sectors < actual_sectors)
1320987da915Sopenharmony_ci	    && !try_fix_boot(vol, full_bs, shown_sectors,
1321987da915Sopenharmony_ci				shown_sectors, sector_size))
1322987da915Sopenharmony_ci		res = 0;
1323987da915Sopenharmony_ci
1324987da915Sopenharmony_ci		/* then try reducing the number of sectors to actual value */
1325987da915Sopenharmony_ci	if (res
1326987da915Sopenharmony_ci	    && (shown_sectors > actual_sectors)
1327987da915Sopenharmony_ci	    && !try_fix_boot(vol, full_bs, 0, actual_sectors, sector_size))
1328987da915Sopenharmony_ci		res = 0;
1329987da915Sopenharmony_ci
1330987da915Sopenharmony_ci	return (res);
1331987da915Sopenharmony_ci}
1332987da915Sopenharmony_ci
1333987da915Sopenharmony_ci/*
1334987da915Sopenharmony_ci *		Check and fix the alternate boot sector
1335987da915Sopenharmony_ci *
1336987da915Sopenharmony_ci *	The alternate boot sector is usually in the last sector of a
1337987da915Sopenharmony_ci *	partition, which should not be used by the file system
1338987da915Sopenharmony_ci *	(the sector count in the boot sector should be less than
1339987da915Sopenharmony_ci *	the total sector count in the partition).
1340987da915Sopenharmony_ci *
1341987da915Sopenharmony_ci *	chkdsk never changes the count in the boot sector.
1342987da915Sopenharmony_ci *	- If this is less than the total count, chkdsk place the
1343987da915Sopenharmony_ci *	  alternate boot sector into the sector,
1344987da915Sopenharmony_ci *	- if the count is the same as the total count, chkdsk place
1345987da915Sopenharmony_ci *	  the alternate boot sector into the middle sector (half
1346987da915Sopenharmony_ci *	  the total count rounded upwards)
1347987da915Sopenharmony_ci *	- if the count is greater than the total count, chkdsk
1348987da915Sopenharmony_ci *	  declares the file system as raw, and refuses to fix anything.
1349987da915Sopenharmony_ci *
1350987da915Sopenharmony_ci *	Here, we check and fix the alternate boot sector, only in the
1351987da915Sopenharmony_ci *	first situation where the file system does not overflow on the
1352987da915Sopenharmony_ci *	last sector.
1353987da915Sopenharmony_ci *
1354987da915Sopenharmony_ci *	Note : when shrinking a partition, ntfsresize cannot determine
1355987da915Sopenharmony_ci *	the future size of the partition. As a consequence the number of
1356987da915Sopenharmony_ci *	sectors in the boot sectors may be less than the possible size.
1357987da915Sopenharmony_ci *
1358987da915Sopenharmony_ci *	Returns 0 if successful
1359987da915Sopenharmony_ci */
1360987da915Sopenharmony_ci
1361987da915Sopenharmony_cistatic int check_alternate_boot(ntfs_volume *vol)
1362987da915Sopenharmony_ci{
1363987da915Sopenharmony_ci	s64 got_sectors;
1364987da915Sopenharmony_ci	s64 actual_sectors;
1365987da915Sopenharmony_ci	s64 last_sector_off;
1366987da915Sopenharmony_ci	char *full_bs;
1367987da915Sopenharmony_ci	char *alt_bs;
1368987da915Sopenharmony_ci	NTFS_BOOT_SECTOR *bs;
1369987da915Sopenharmony_ci	s64 br;
1370987da915Sopenharmony_ci	s64 bw;
1371987da915Sopenharmony_ci	int res;
1372987da915Sopenharmony_ci
1373987da915Sopenharmony_ci	res = -1;
1374987da915Sopenharmony_ci	full_bs = (char*)malloc(vol->sector_size);
1375987da915Sopenharmony_ci	alt_bs = (char*)malloc(vol->sector_size);
1376987da915Sopenharmony_ci	if (!full_bs || !alt_bs) {
1377987da915Sopenharmony_ci		ntfs_log_info("Error : failed to allocate memory\n");
1378987da915Sopenharmony_ci		goto error_exit;
1379987da915Sopenharmony_ci	}
1380987da915Sopenharmony_ci	/* Now read both bootsectors. */
1381987da915Sopenharmony_ci	br = ntfs_pread(vol->dev, 0, vol->sector_size, full_bs);
1382987da915Sopenharmony_ci	if (br == vol->sector_size) {
1383987da915Sopenharmony_ci		bs = (NTFS_BOOT_SECTOR*)full_bs;
1384987da915Sopenharmony_ci		got_sectors = sle64_to_cpu(bs->number_of_sectors);
1385987da915Sopenharmony_ci		actual_sectors = ntfs_device_size_get(vol->dev,
1386987da915Sopenharmony_ci						vol->sector_size);
1387987da915Sopenharmony_ci		if (actual_sectors > got_sectors) {
1388987da915Sopenharmony_ci			last_sector_off = (actual_sectors - 1)
1389987da915Sopenharmony_ci						<< vol->sector_size_bits;
1390987da915Sopenharmony_ci			ntfs_log_info("Checking the alternate boot sector... ");
1391987da915Sopenharmony_ci			br = ntfs_pread(vol->dev, last_sector_off,
1392987da915Sopenharmony_ci						vol->sector_size, alt_bs);
1393987da915Sopenharmony_ci		} else {
1394987da915Sopenharmony_ci			ntfs_log_info("Checking file system overflow... ");
1395987da915Sopenharmony_ci			br = -1;
1396987da915Sopenharmony_ci		}
1397987da915Sopenharmony_ci		/* accept getting no byte, needed for short image files */
1398987da915Sopenharmony_ci		if (br >= 0) {
1399987da915Sopenharmony_ci			if ((br != vol->sector_size)
1400987da915Sopenharmony_ci			    || memcmp(full_bs, alt_bs, vol->sector_size)) {
1401987da915Sopenharmony_ci				if (opt.no_action) {
1402987da915Sopenharmony_ci					ntfs_log_info("BAD\n");
1403987da915Sopenharmony_ci				} else {
1404987da915Sopenharmony_ci					bw = ntfs_pwrite(vol->dev,
1405987da915Sopenharmony_ci						last_sector_off,
1406987da915Sopenharmony_ci						vol->sector_size, full_bs);
1407987da915Sopenharmony_ci					if (bw == vol->sector_size) {
1408987da915Sopenharmony_ci						ntfs_log_info("FIXED\n");
1409987da915Sopenharmony_ci						res = 0;
1410987da915Sopenharmony_ci					} else {
1411987da915Sopenharmony_ci						ntfs_log_info(FAILED);
1412987da915Sopenharmony_ci					}
1413987da915Sopenharmony_ci				}
1414987da915Sopenharmony_ci			} else {
1415987da915Sopenharmony_ci				ntfs_log_info(OK);
1416987da915Sopenharmony_ci				res = 0;
1417987da915Sopenharmony_ci			}
1418987da915Sopenharmony_ci		} else {
1419987da915Sopenharmony_ci			ntfs_log_info(FAILED);
1420987da915Sopenharmony_ci		}
1421987da915Sopenharmony_ci	} else {
1422987da915Sopenharmony_ci		ntfs_log_info("Error : could not read the boot sector again\n");
1423987da915Sopenharmony_ci	}
1424987da915Sopenharmony_ci	free(full_bs);
1425987da915Sopenharmony_ci	free(alt_bs);
1426987da915Sopenharmony_ci
1427987da915Sopenharmony_cierror_exit :
1428987da915Sopenharmony_ci	return (res);
1429987da915Sopenharmony_ci}
1430987da915Sopenharmony_ci
1431987da915Sopenharmony_ci/*
1432987da915Sopenharmony_ci *		Try to fix problems which may arise in the start up sequence
1433987da915Sopenharmony_ci *
1434987da915Sopenharmony_ci *	This is a replay of the normal start up sequence with fixes when
1435987da915Sopenharmony_ci *	some problem arise.
1436987da915Sopenharmony_ci *
1437987da915Sopenharmony_ci *	Returns 0 if there was an error and a fix is available
1438987da915Sopenharmony_ci */
1439987da915Sopenharmony_ci
1440987da915Sopenharmony_cistatic int fix_startup(struct ntfs_device *dev, unsigned long flags)
1441987da915Sopenharmony_ci{
1442987da915Sopenharmony_ci	s64 br;
1443987da915Sopenharmony_ci	ntfs_volume *vol;
1444987da915Sopenharmony_ci	BOOL dev_open;
1445987da915Sopenharmony_ci	s64 shown_sectors;
1446987da915Sopenharmony_ci	char *full_bs;
1447987da915Sopenharmony_ci	NTFS_BOOT_SECTOR *bs;
1448987da915Sopenharmony_ci	s32 sector_size;
1449987da915Sopenharmony_ci	int res;
1450987da915Sopenharmony_ci	int eo;
1451987da915Sopenharmony_ci
1452987da915Sopenharmony_ci	errno = 0;
1453987da915Sopenharmony_ci	res = -1;
1454987da915Sopenharmony_ci	dev_open = FALSE;
1455987da915Sopenharmony_ci	full_bs = (char*)NULL;
1456987da915Sopenharmony_ci	if (!dev || !dev->d_ops || !dev->d_name) {
1457987da915Sopenharmony_ci		errno = EINVAL;
1458987da915Sopenharmony_ci		ntfs_log_perror("%s: dev = %p", __FUNCTION__, dev);
1459987da915Sopenharmony_ci		vol = (ntfs_volume*)NULL;
1460987da915Sopenharmony_ci		goto error_exit;
1461987da915Sopenharmony_ci	}
1462987da915Sopenharmony_ci
1463987da915Sopenharmony_ci	/* Allocate the volume structure. */
1464987da915Sopenharmony_ci	vol = ntfs_volume_alloc();
1465987da915Sopenharmony_ci	if (!vol)
1466987da915Sopenharmony_ci		goto error_exit;
1467987da915Sopenharmony_ci
1468987da915Sopenharmony_ci	/* Create the default upcase table. */
1469987da915Sopenharmony_ci	vol->upcase_len = ntfs_upcase_build_default(&vol->upcase);
1470987da915Sopenharmony_ci	if (!vol->upcase_len || !vol->upcase)
1471987da915Sopenharmony_ci		goto error_exit;
1472987da915Sopenharmony_ci
1473987da915Sopenharmony_ci	/* Default with no locase table and case sensitive file names */
1474987da915Sopenharmony_ci	vol->locase = (ntfschar*)NULL;
1475987da915Sopenharmony_ci	NVolSetCaseSensitive(vol);
1476987da915Sopenharmony_ci
1477987da915Sopenharmony_ci		/* by default, all files are shown and not marked hidden */
1478987da915Sopenharmony_ci	NVolSetShowSysFiles(vol);
1479987da915Sopenharmony_ci	NVolSetShowHidFiles(vol);
1480987da915Sopenharmony_ci	NVolClearHideDotFiles(vol);
1481987da915Sopenharmony_ci	if (flags & NTFS_MNT_RDONLY)
1482987da915Sopenharmony_ci		NVolSetReadOnly(vol);
1483987da915Sopenharmony_ci
1484987da915Sopenharmony_ci	/* ...->open needs bracketing to compile with glibc 2.7 */
1485987da915Sopenharmony_ci	if ((dev->d_ops->open)(dev, NVolReadOnly(vol) ? O_RDONLY: O_RDWR)) {
1486987da915Sopenharmony_ci		ntfs_log_perror("Error opening '%s'", dev->d_name);
1487987da915Sopenharmony_ci		goto error_exit;
1488987da915Sopenharmony_ci	}
1489987da915Sopenharmony_ci	dev_open = TRUE;
1490987da915Sopenharmony_ci	/* Attach the device to the volume. */
1491987da915Sopenharmony_ci	vol->dev = dev;
1492987da915Sopenharmony_ci
1493987da915Sopenharmony_ci	sector_size = ntfs_device_sector_size_get(dev);
1494987da915Sopenharmony_ci	if (sector_size <= 0)
1495987da915Sopenharmony_ci		sector_size = DEFAULT_SECTOR_SIZE;
1496987da915Sopenharmony_ci	full_bs = (char*)malloc(sector_size);
1497987da915Sopenharmony_ci	if (!full_bs)
1498987da915Sopenharmony_ci		goto error_exit;
1499987da915Sopenharmony_ci	/* Now read the bootsector. */
1500987da915Sopenharmony_ci	br = ntfs_pread(dev, 0, sector_size, full_bs);
1501987da915Sopenharmony_ci	if (br != sector_size) {
1502987da915Sopenharmony_ci		if (br != -1)
1503987da915Sopenharmony_ci			errno = EINVAL;
1504987da915Sopenharmony_ci		if (!br)
1505987da915Sopenharmony_ci			ntfs_log_error("Failed to read bootsector (size=0)\n");
1506987da915Sopenharmony_ci		else
1507987da915Sopenharmony_ci			ntfs_log_perror("Error reading bootsector");
1508987da915Sopenharmony_ci		goto error_exit;
1509987da915Sopenharmony_ci	}
1510987da915Sopenharmony_ci	bs = (NTFS_BOOT_SECTOR*)full_bs;
1511987da915Sopenharmony_ci	if (!ntfs_boot_sector_is_ntfs(bs)
1512987da915Sopenharmony_ci		/* get the bootsector data, only fails when inconsistent */
1513987da915Sopenharmony_ci	    || (ntfs_boot_sector_parse(vol, bs) < 0)) {
1514987da915Sopenharmony_ci		shown_sectors = sle64_to_cpu(bs->number_of_sectors);
1515987da915Sopenharmony_ci		/* boot sector is wrong, try the alternate boot sector */
1516987da915Sopenharmony_ci		if (try_alternate_boot(vol, full_bs, sector_size,
1517987da915Sopenharmony_ci						shown_sectors)) {
1518987da915Sopenharmony_ci			errno = EINVAL;
1519987da915Sopenharmony_ci			goto error_exit;
1520987da915Sopenharmony_ci		}
1521987da915Sopenharmony_ci		res = 0;
1522987da915Sopenharmony_ci	} else {
1523987da915Sopenharmony_ci		res = fix_self_located_mft(vol);
1524987da915Sopenharmony_ci	}
1525987da915Sopenharmony_cierror_exit:
1526987da915Sopenharmony_ci	if (res) {
1527987da915Sopenharmony_ci		switch (errno) {
1528987da915Sopenharmony_ci		case ENOMEM :
1529987da915Sopenharmony_ci			ntfs_log_error("Failed to allocate memory\n");
1530987da915Sopenharmony_ci			break;
1531987da915Sopenharmony_ci		case EINVAL :
1532987da915Sopenharmony_ci			ntfs_log_error("Unrecoverable error\n");
1533987da915Sopenharmony_ci			break;
1534987da915Sopenharmony_ci		default :
1535987da915Sopenharmony_ci			break;
1536987da915Sopenharmony_ci		}
1537987da915Sopenharmony_ci	}
1538987da915Sopenharmony_ci	eo = errno;
1539987da915Sopenharmony_ci	free(full_bs);
1540987da915Sopenharmony_ci	if (vol) {
1541987da915Sopenharmony_ci		free(vol->upcase);
1542987da915Sopenharmony_ci		free(vol);
1543987da915Sopenharmony_ci	}
1544987da915Sopenharmony_ci	if (dev_open) {
1545987da915Sopenharmony_ci		(dev->d_ops->close)(dev);
1546987da915Sopenharmony_ci	}
1547987da915Sopenharmony_ci	errno = eo;
1548987da915Sopenharmony_ci	return (res);
1549987da915Sopenharmony_ci}
1550987da915Sopenharmony_ci
1551987da915Sopenharmony_ci/**
1552987da915Sopenharmony_ci * fix_mount
1553987da915Sopenharmony_ci */
1554987da915Sopenharmony_cistatic int fix_mount(void)
1555987da915Sopenharmony_ci{
1556987da915Sopenharmony_ci	int ret = 0; /* default success */
1557987da915Sopenharmony_ci	ntfs_volume *vol;
1558987da915Sopenharmony_ci	struct ntfs_device *dev;
1559987da915Sopenharmony_ci	unsigned long flags;
1560987da915Sopenharmony_ci
1561987da915Sopenharmony_ci	ntfs_log_info("Attempting to correct errors... ");
1562987da915Sopenharmony_ci
1563987da915Sopenharmony_ci	dev = ntfs_device_alloc(opt.volume, 0, &ntfs_device_default_io_ops,
1564987da915Sopenharmony_ci			NULL);
1565987da915Sopenharmony_ci	if (!dev) {
1566987da915Sopenharmony_ci		ntfs_log_info(FAILED);
1567987da915Sopenharmony_ci		ntfs_log_perror("Failed to allocate device");
1568987da915Sopenharmony_ci		return -1;
1569987da915Sopenharmony_ci	}
1570987da915Sopenharmony_ci	flags = (opt.no_action ? NTFS_MNT_RDONLY : 0);
1571987da915Sopenharmony_ci	vol = ntfs_volume_startup(dev, flags);
1572987da915Sopenharmony_ci	if (!vol) {
1573987da915Sopenharmony_ci		ntfs_log_info(FAILED);
1574987da915Sopenharmony_ci		ntfs_log_perror("Failed to startup volume");
1575987da915Sopenharmony_ci
1576987da915Sopenharmony_ci		/* Try fixing the bootsector and MFT, then redo the startup */
1577987da915Sopenharmony_ci		if (!fix_startup(dev, flags)) {
1578987da915Sopenharmony_ci			if (opt.no_action)
1579987da915Sopenharmony_ci				ntfs_log_info("The startup data can be fixed, "
1580987da915Sopenharmony_ci						"but no change was requested\n");
1581987da915Sopenharmony_ci			else
1582987da915Sopenharmony_ci				vol = ntfs_volume_startup(dev, flags);
1583987da915Sopenharmony_ci		}
1584987da915Sopenharmony_ci		if (!vol) {
1585987da915Sopenharmony_ci			ntfs_log_error("Volume is corrupt. You should run chkdsk.\n");
1586987da915Sopenharmony_ci			ntfs_device_free(dev);
1587987da915Sopenharmony_ci			return -1;
1588987da915Sopenharmony_ci		}
1589987da915Sopenharmony_ci		if (opt.no_action)
1590987da915Sopenharmony_ci			ret = -1; /* error present and not fixed */
1591987da915Sopenharmony_ci	}
1592987da915Sopenharmony_ci		/* if option -n proceed despite errors, to display them all */
1593987da915Sopenharmony_ci	if ((!ret || opt.no_action) && (fix_mftmirr(vol) < 0))
1594987da915Sopenharmony_ci		ret = -1;
1595987da915Sopenharmony_ci	if ((!ret || opt.no_action) && (fix_upcase(vol) < 0))
1596987da915Sopenharmony_ci		ret = -1;
1597987da915Sopenharmony_ci	if ((!ret || opt.no_action) && (set_dirty_flag(vol) < 0))
1598987da915Sopenharmony_ci		ret = -1;
1599987da915Sopenharmony_ci	if ((!ret || opt.no_action) && (empty_journal(vol) < 0))
1600987da915Sopenharmony_ci		ret = -1;
1601987da915Sopenharmony_ci	/*
1602987da915Sopenharmony_ci	 * ntfs_umount() will invoke ntfs_device_free() for us.
1603987da915Sopenharmony_ci	 * Ignore the returned error resulting from partial mounting.
1604987da915Sopenharmony_ci	 */
1605987da915Sopenharmony_ci	ntfs_umount(vol, 1);
1606987da915Sopenharmony_ci	return ret;
1607987da915Sopenharmony_ci}
1608987da915Sopenharmony_ci
1609987da915Sopenharmony_ci/**
1610987da915Sopenharmony_ci * main
1611987da915Sopenharmony_ci */
1612987da915Sopenharmony_ciint main(int argc, char **argv)
1613987da915Sopenharmony_ci{
1614987da915Sopenharmony_ci	ntfs_volume *vol;
1615987da915Sopenharmony_ci	unsigned long mnt_flags;
1616987da915Sopenharmony_ci	unsigned long flags;
1617987da915Sopenharmony_ci	int ret = 1; /* failure */
1618987da915Sopenharmony_ci	BOOL force = FALSE;
1619987da915Sopenharmony_ci
1620987da915Sopenharmony_ci	ntfs_log_set_handler(ntfs_log_handler_outerr);
1621987da915Sopenharmony_ci
1622987da915Sopenharmony_ci	parse_options(argc, argv);
1623987da915Sopenharmony_ci
1624987da915Sopenharmony_ci	if (!ntfs_check_if_mounted(opt.volume, &mnt_flags)) {
1625987da915Sopenharmony_ci		if ((mnt_flags & NTFS_MF_MOUNTED) &&
1626987da915Sopenharmony_ci				!(mnt_flags & NTFS_MF_READONLY) && !force) {
1627987da915Sopenharmony_ci			ntfs_log_error("Refusing to operate on read-write "
1628987da915Sopenharmony_ci					"mounted device %s.\n", opt.volume);
1629987da915Sopenharmony_ci			exit(1);
1630987da915Sopenharmony_ci		}
1631987da915Sopenharmony_ci	} else
1632987da915Sopenharmony_ci		ntfs_log_perror("Failed to determine whether %s is mounted",
1633987da915Sopenharmony_ci				opt.volume);
1634987da915Sopenharmony_ci	/* Attempt a full mount first. */
1635987da915Sopenharmony_ci	flags = (opt.no_action ? NTFS_MNT_RDONLY : 0);
1636987da915Sopenharmony_ci	ntfs_log_info("Mounting volume... ");
1637987da915Sopenharmony_ci	vol = ntfs_mount(opt.volume, flags);
1638987da915Sopenharmony_ci	if (vol) {
1639987da915Sopenharmony_ci		ntfs_log_info(OK);
1640987da915Sopenharmony_ci		ntfs_log_info("Processing of $MFT and $MFTMirr completed "
1641987da915Sopenharmony_ci				"successfully.\n");
1642987da915Sopenharmony_ci	} else {
1643987da915Sopenharmony_ci		ntfs_log_info(FAILED);
1644987da915Sopenharmony_ci		if (fix_mount() < 0) {
1645987da915Sopenharmony_ci			if (opt.no_action)
1646987da915Sopenharmony_ci				ntfs_log_info("No change made\n");
1647987da915Sopenharmony_ci			exit(1);
1648987da915Sopenharmony_ci		}
1649987da915Sopenharmony_ci		vol = ntfs_mount(opt.volume, 0);
1650987da915Sopenharmony_ci		if (!vol) {
1651987da915Sopenharmony_ci			ntfs_log_perror("Remount failed");
1652987da915Sopenharmony_ci			exit(1);
1653987da915Sopenharmony_ci		}
1654987da915Sopenharmony_ci	}
1655987da915Sopenharmony_ci	if (check_alternate_boot(vol)) {
1656987da915Sopenharmony_ci		ntfs_log_error("Error: Failed to fix the alternate boot sector\n");
1657987da915Sopenharmony_ci		exit(1);
1658987da915Sopenharmony_ci	}
1659987da915Sopenharmony_ci	/* So the unmount does not clear it again. */
1660987da915Sopenharmony_ci
1661987da915Sopenharmony_ci	/* Porting note: The WasDirty flag was set here to prevent ntfs_unmount
1662987da915Sopenharmony_ci	 * from clearing the dirty bit (which might have been set in
1663987da915Sopenharmony_ci	 * fix_mount()). So the intention is to leave the dirty bit set.
1664987da915Sopenharmony_ci	 *
1665987da915Sopenharmony_ci	 * libntfs-3g does not automatically set or clear dirty flags on
1666987da915Sopenharmony_ci	 * mount/unmount, this means that the assumption that the dirty flag is
1667987da915Sopenharmony_ci	 * now set does not hold. So we need to set it if not already set.
1668987da915Sopenharmony_ci	 *
1669987da915Sopenharmony_ci	 * However clear the flag if requested to do so, at this stage
1670987da915Sopenharmony_ci	 * mounting was successful.
1671987da915Sopenharmony_ci	 */
1672987da915Sopenharmony_ci	if (opt.clear_dirty)
1673987da915Sopenharmony_ci		vol->flags &= ~VOLUME_IS_DIRTY;
1674987da915Sopenharmony_ci	else
1675987da915Sopenharmony_ci		vol->flags |= VOLUME_IS_DIRTY;
1676987da915Sopenharmony_ci	if (!opt.no_action && ntfs_volume_write_flags(vol, vol->flags)) {
1677987da915Sopenharmony_ci		ntfs_log_error("Error: Failed to set volume dirty flag (%d "
1678987da915Sopenharmony_ci			"(%s))!\n", errno, strerror(errno));
1679987da915Sopenharmony_ci	}
1680987da915Sopenharmony_ci
1681987da915Sopenharmony_ci	/* Check NTFS version is ok for us (in $Volume) */
1682987da915Sopenharmony_ci	ntfs_log_info("NTFS volume version is %i.%i.\n", vol->major_ver,
1683987da915Sopenharmony_ci			vol->minor_ver);
1684987da915Sopenharmony_ci	if (ntfs_version_is_supported(vol)) {
1685987da915Sopenharmony_ci		ntfs_log_error("Error: Unknown NTFS version.\n");
1686987da915Sopenharmony_ci		goto error_exit;
1687987da915Sopenharmony_ci	}
1688987da915Sopenharmony_ci	if (opt.clear_bad_sectors && !opt.no_action) {
1689987da915Sopenharmony_ci		if (clear_badclus(vol)) {
1690987da915Sopenharmony_ci			ntfs_log_error("Error: Failed to un-mark bad sectors.\n");
1691987da915Sopenharmony_ci			goto error_exit;
1692987da915Sopenharmony_ci		}
1693987da915Sopenharmony_ci	}
1694987da915Sopenharmony_ci	if (vol->major_ver >= 3) {
1695987da915Sopenharmony_ci		/*
1696987da915Sopenharmony_ci		 * FIXME: If on NTFS 3.0+, check for presence of the usn
1697987da915Sopenharmony_ci		 * journal and stamp it if present.
1698987da915Sopenharmony_ci		 */
1699987da915Sopenharmony_ci	}
1700987da915Sopenharmony_ci	/* FIXME: We should be marking the quota out of date, too. */
1701987da915Sopenharmony_ci	/* That's all for now! */
1702987da915Sopenharmony_ci	ntfs_log_info("NTFS partition %s was processed successfully.\n",
1703987da915Sopenharmony_ci			vol->dev->d_name);
1704987da915Sopenharmony_ci	/* Set return code to 0. */
1705987da915Sopenharmony_ci	ret = 0;
1706987da915Sopenharmony_cierror_exit:
1707987da915Sopenharmony_ci	if (ntfs_umount(vol, 1)) {
1708987da915Sopenharmony_ci		ntfs_log_info("Failed to unmount partition\n");
1709987da915Sopenharmony_ci		ret = 1;
1710987da915Sopenharmony_ci	}
1711987da915Sopenharmony_ci	if (ret)
1712987da915Sopenharmony_ci		exit(ret);
1713987da915Sopenharmony_ci	return ret;
1714987da915Sopenharmony_ci}
1715987da915Sopenharmony_ci
1716