xref: /haiku/src/add-ons/kernel/file_systems/ntfs/libntfs/volume.c (revision 80bca3d3c8c08d3c9b31d7609a7805941529e9c3)
1*80bca3d3SAxel Dörfler /**
2*80bca3d3SAxel Dörfler  * volume.c - NTFS volume handling code. Originated from the Linux-NTFS project.
3*80bca3d3SAxel Dörfler  *
4*80bca3d3SAxel Dörfler  * Copyright (c) 2000-2006 Anton Altaparmakov
5*80bca3d3SAxel Dörfler  * Copyright (c) 2002-2006 Szabolcs Szakacsits
6*80bca3d3SAxel Dörfler  * Copyright (c) 2004-2005 Richard Russon
7*80bca3d3SAxel Dörfler  *
8*80bca3d3SAxel Dörfler  * This program/include file is free software; you can redistribute it and/or
9*80bca3d3SAxel Dörfler  * modify it under the terms of the GNU General Public License as published
10*80bca3d3SAxel Dörfler  * by the Free Software Foundation; either version 2 of the License, or
11*80bca3d3SAxel Dörfler  * (at your option) any later version.
12*80bca3d3SAxel Dörfler  *
13*80bca3d3SAxel Dörfler  * This program/include file is distributed in the hope that it will be
14*80bca3d3SAxel Dörfler  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
15*80bca3d3SAxel Dörfler  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16*80bca3d3SAxel Dörfler  * GNU General Public License for more details.
17*80bca3d3SAxel Dörfler  *
18*80bca3d3SAxel Dörfler  * You should have received a copy of the GNU General Public License
19*80bca3d3SAxel Dörfler  * along with this program (in the main directory of the NTFS-3G
20*80bca3d3SAxel Dörfler  * distribution in the file COPYING); if not, write to the Free Software
21*80bca3d3SAxel Dörfler  * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22*80bca3d3SAxel Dörfler  */
23*80bca3d3SAxel Dörfler 
24*80bca3d3SAxel Dörfler #ifdef HAVE_CONFIG_H
25*80bca3d3SAxel Dörfler #include "config.h"
26*80bca3d3SAxel Dörfler #endif
27*80bca3d3SAxel Dörfler 
28*80bca3d3SAxel Dörfler #ifdef HAVE_STDLIB_H
29*80bca3d3SAxel Dörfler #include <stdlib.h>
30*80bca3d3SAxel Dörfler #endif
31*80bca3d3SAxel Dörfler #ifdef HAVE_STDIO_H
32*80bca3d3SAxel Dörfler #include <stdio.h>
33*80bca3d3SAxel Dörfler #endif
34*80bca3d3SAxel Dörfler #ifdef HAVE_STRING_H
35*80bca3d3SAxel Dörfler #include <string.h>
36*80bca3d3SAxel Dörfler #endif
37*80bca3d3SAxel Dörfler #ifdef HAVE_FCNTL_H
38*80bca3d3SAxel Dörfler #include <fcntl.h>
39*80bca3d3SAxel Dörfler #endif
40*80bca3d3SAxel Dörfler #ifdef HAVE_UNISTD_H
41*80bca3d3SAxel Dörfler #include <unistd.h>
42*80bca3d3SAxel Dörfler #endif
43*80bca3d3SAxel Dörfler #ifdef HAVE_ERRNO_H
44*80bca3d3SAxel Dörfler #include <errno.h>
45*80bca3d3SAxel Dörfler #endif
46*80bca3d3SAxel Dörfler #ifdef HAVE_SYS_STAT_H
47*80bca3d3SAxel Dörfler #include <sys/stat.h>
48*80bca3d3SAxel Dörfler #endif
49*80bca3d3SAxel Dörfler #ifdef HAVE_LIMITS_H
50*80bca3d3SAxel Dörfler #include <limits.h>
51*80bca3d3SAxel Dörfler #endif
52*80bca3d3SAxel Dörfler 
53*80bca3d3SAxel Dörfler #include "volume.h"
54*80bca3d3SAxel Dörfler #include "attrib.h"
55*80bca3d3SAxel Dörfler #include "mft.h"
56*80bca3d3SAxel Dörfler #include "bootsect.h"
57*80bca3d3SAxel Dörfler #include "device.h"
58*80bca3d3SAxel Dörfler #include "debug.h"
59*80bca3d3SAxel Dörfler #include "inode.h"
60*80bca3d3SAxel Dörfler #include "runlist.h"
61*80bca3d3SAxel Dörfler #include "logfile.h"
62*80bca3d3SAxel Dörfler #include "dir.h"
63*80bca3d3SAxel Dörfler #include "logging.h"
64*80bca3d3SAxel Dörfler #include "misc.h"
65*80bca3d3SAxel Dörfler 
66*80bca3d3SAxel Dörfler #ifndef PATH_MAX
67*80bca3d3SAxel Dörfler #define PATH_MAX 4096
68*80bca3d3SAxel Dörfler #endif
69*80bca3d3SAxel Dörfler 
70*80bca3d3SAxel Dörfler /**
71*80bca3d3SAxel Dörfler  * ntfs_volume_alloc - Create an NTFS volume object and initialise it
72*80bca3d3SAxel Dörfler  *
73*80bca3d3SAxel Dörfler  * Description...
74*80bca3d3SAxel Dörfler  *
75*80bca3d3SAxel Dörfler  * Returns:
76*80bca3d3SAxel Dörfler  */
77*80bca3d3SAxel Dörfler ntfs_volume *ntfs_volume_alloc(void)
78*80bca3d3SAxel Dörfler {
79*80bca3d3SAxel Dörfler 	return calloc(1, sizeof(ntfs_volume));
80*80bca3d3SAxel Dörfler }
81*80bca3d3SAxel Dörfler 
82*80bca3d3SAxel Dörfler /**
83*80bca3d3SAxel Dörfler  * __ntfs_volume_release - Destroy an NTFS volume object
84*80bca3d3SAxel Dörfler  * @v:
85*80bca3d3SAxel Dörfler  *
86*80bca3d3SAxel Dörfler  * Description...
87*80bca3d3SAxel Dörfler  *
88*80bca3d3SAxel Dörfler  * Returns:
89*80bca3d3SAxel Dörfler  */
90*80bca3d3SAxel Dörfler static void __ntfs_volume_release(ntfs_volume *v)
91*80bca3d3SAxel Dörfler {
92*80bca3d3SAxel Dörfler 	if (v->lcnbmp_ni && NInoDirty(v->lcnbmp_ni))
93*80bca3d3SAxel Dörfler 		ntfs_inode_sync(v->lcnbmp_ni);
94*80bca3d3SAxel Dörfler 	if (v->vol_ni)
95*80bca3d3SAxel Dörfler 		ntfs_inode_close(v->vol_ni);
96*80bca3d3SAxel Dörfler 	if (v->lcnbmp_na)
97*80bca3d3SAxel Dörfler 		ntfs_attr_close(v->lcnbmp_na);
98*80bca3d3SAxel Dörfler 	if (v->lcnbmp_ni)
99*80bca3d3SAxel Dörfler 		ntfs_inode_close(v->lcnbmp_ni);
100*80bca3d3SAxel Dörfler 	if (v->mft_ni && NInoDirty(v->mft_ni))
101*80bca3d3SAxel Dörfler 		ntfs_inode_sync(v->mft_ni);
102*80bca3d3SAxel Dörfler 	if (v->mftbmp_na)
103*80bca3d3SAxel Dörfler 		ntfs_attr_close(v->mftbmp_na);
104*80bca3d3SAxel Dörfler 	if (v->mft_na)
105*80bca3d3SAxel Dörfler 		ntfs_attr_close(v->mft_na);
106*80bca3d3SAxel Dörfler 	if (v->mft_ni)
107*80bca3d3SAxel Dörfler 		ntfs_inode_close(v->mft_ni);
108*80bca3d3SAxel Dörfler 	if (v->mftmirr_ni && NInoDirty(v->mftmirr_ni))
109*80bca3d3SAxel Dörfler 		ntfs_inode_sync(v->mftmirr_ni);
110*80bca3d3SAxel Dörfler 	if (v->mftmirr_na)
111*80bca3d3SAxel Dörfler 		ntfs_attr_close(v->mftmirr_na);
112*80bca3d3SAxel Dörfler 	if (v->mftmirr_ni)
113*80bca3d3SAxel Dörfler 		ntfs_inode_close(v->mftmirr_ni);
114*80bca3d3SAxel Dörfler 	if (v->dev) {
115*80bca3d3SAxel Dörfler 		struct ntfs_device *dev = v->dev;
116*80bca3d3SAxel Dörfler 
117*80bca3d3SAxel Dörfler 		dev->d_ops->sync(dev);
118*80bca3d3SAxel Dörfler 		if (dev->d_ops->close(dev))
119*80bca3d3SAxel Dörfler 			ntfs_log_perror("Failed to close the device");
120*80bca3d3SAxel Dörfler 	}
121*80bca3d3SAxel Dörfler 	free(v->vol_name);
122*80bca3d3SAxel Dörfler 	free(v->upcase);
123*80bca3d3SAxel Dörfler 	free(v->attrdef);
124*80bca3d3SAxel Dörfler 	free(v);
125*80bca3d3SAxel Dörfler }
126*80bca3d3SAxel Dörfler 
127*80bca3d3SAxel Dörfler static void ntfs_attr_setup_flag(ntfs_inode *ni)
128*80bca3d3SAxel Dörfler {
129*80bca3d3SAxel Dörfler 	STANDARD_INFORMATION *si;
130*80bca3d3SAxel Dörfler 
131*80bca3d3SAxel Dörfler 	si = ntfs_attr_readall(ni, AT_STANDARD_INFORMATION, AT_UNNAMED, 0, NULL);
132*80bca3d3SAxel Dörfler 	if (si) {
133*80bca3d3SAxel Dörfler 		ni->flags = si->file_attributes;
134*80bca3d3SAxel Dörfler 		free(si);
135*80bca3d3SAxel Dörfler 	}
136*80bca3d3SAxel Dörfler }
137*80bca3d3SAxel Dörfler 
138*80bca3d3SAxel Dörfler /**
139*80bca3d3SAxel Dörfler  * ntfs_mft_load - load the $MFT and setup the ntfs volume with it
140*80bca3d3SAxel Dörfler  * @vol:	ntfs volume whose $MFT to load
141*80bca3d3SAxel Dörfler  *
142*80bca3d3SAxel Dörfler  * Load $MFT from @vol and setup @vol with it. After calling this function the
143*80bca3d3SAxel Dörfler  * volume @vol is ready for use by all read access functions provided by the
144*80bca3d3SAxel Dörfler  * ntfs library.
145*80bca3d3SAxel Dörfler  *
146*80bca3d3SAxel Dörfler  * Return 0 on success and -1 on error with errno set to the error code.
147*80bca3d3SAxel Dörfler  */
148*80bca3d3SAxel Dörfler static int ntfs_mft_load(ntfs_volume *vol)
149*80bca3d3SAxel Dörfler {
150*80bca3d3SAxel Dörfler 	VCN next_vcn, last_vcn, highest_vcn;
151*80bca3d3SAxel Dörfler 	s64 l;
152*80bca3d3SAxel Dörfler 	MFT_RECORD *mb = NULL;
153*80bca3d3SAxel Dörfler 	ntfs_attr_search_ctx *ctx = NULL;
154*80bca3d3SAxel Dörfler 	ATTR_RECORD *a;
155*80bca3d3SAxel Dörfler 	int eo;
156*80bca3d3SAxel Dörfler 
157*80bca3d3SAxel Dörfler 	/* Manually setup an ntfs_inode. */
158*80bca3d3SAxel Dörfler 	vol->mft_ni = ntfs_inode_allocate(vol);
159*80bca3d3SAxel Dörfler 	mb = ntfs_malloc(vol->mft_record_size);
160*80bca3d3SAxel Dörfler 	if (!vol->mft_ni || !mb) {
161*80bca3d3SAxel Dörfler 		ntfs_log_perror("Error allocating memory for $MFT");
162*80bca3d3SAxel Dörfler 		goto error_exit;
163*80bca3d3SAxel Dörfler 	}
164*80bca3d3SAxel Dörfler 	vol->mft_ni->mft_no = 0;
165*80bca3d3SAxel Dörfler 	vol->mft_ni->mrec = mb;
166*80bca3d3SAxel Dörfler 	/* Can't use any of the higher level functions yet! */
167*80bca3d3SAxel Dörfler 	l = ntfs_mst_pread(vol->dev, vol->mft_lcn << vol->cluster_size_bits, 1,
168*80bca3d3SAxel Dörfler 			vol->mft_record_size, mb);
169*80bca3d3SAxel Dörfler 	if (l != 1) {
170*80bca3d3SAxel Dörfler 		if (l != -1)
171*80bca3d3SAxel Dörfler 			errno = EIO;
172*80bca3d3SAxel Dörfler 		ntfs_log_perror("Error reading $MFT");
173*80bca3d3SAxel Dörfler 		goto error_exit;
174*80bca3d3SAxel Dörfler 	}
175*80bca3d3SAxel Dörfler 	if (ntfs_is_baad_record(mb->magic)) {
176*80bca3d3SAxel Dörfler 		ntfs_log_error("Incomplete multi sector transfer detected in "
177*80bca3d3SAxel Dörfler 				"$MFT.\n");
178*80bca3d3SAxel Dörfler 		goto io_error_exit;
179*80bca3d3SAxel Dörfler 	}
180*80bca3d3SAxel Dörfler 	if (!ntfs_is_mft_record(mb->magic)) {
181*80bca3d3SAxel Dörfler 		ntfs_log_error("$MFT has invalid magic.\n");
182*80bca3d3SAxel Dörfler 		goto io_error_exit;
183*80bca3d3SAxel Dörfler 	}
184*80bca3d3SAxel Dörfler 	ctx = ntfs_attr_get_search_ctx(vol->mft_ni, NULL);
185*80bca3d3SAxel Dörfler 	if (!ctx) {
186*80bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to allocate attribute search context");
187*80bca3d3SAxel Dörfler 		goto error_exit;
188*80bca3d3SAxel Dörfler 	}
189*80bca3d3SAxel Dörfler 	if (p2n(ctx->attr) < p2n(mb) ||
190*80bca3d3SAxel Dörfler 			(char*)ctx->attr > (char*)mb + vol->mft_record_size) {
191*80bca3d3SAxel Dörfler 		ntfs_log_error("$MFT is corrupt.\n");
192*80bca3d3SAxel Dörfler 		goto io_error_exit;
193*80bca3d3SAxel Dörfler 	}
194*80bca3d3SAxel Dörfler 	/* Find the $ATTRIBUTE_LIST attribute in $MFT if present. */
195*80bca3d3SAxel Dörfler 	if (ntfs_attr_lookup(AT_ATTRIBUTE_LIST, AT_UNNAMED, 0, 0, 0, NULL, 0,
196*80bca3d3SAxel Dörfler 			ctx)) {
197*80bca3d3SAxel Dörfler 		if (errno != ENOENT) {
198*80bca3d3SAxel Dörfler 			ntfs_log_error("$MFT has corrupt attribute list.\n");
199*80bca3d3SAxel Dörfler 			goto io_error_exit;
200*80bca3d3SAxel Dörfler 		}
201*80bca3d3SAxel Dörfler 		goto mft_has_no_attr_list;
202*80bca3d3SAxel Dörfler 	}
203*80bca3d3SAxel Dörfler 	NInoSetAttrList(vol->mft_ni);
204*80bca3d3SAxel Dörfler 	l = ntfs_get_attribute_value_length(ctx->attr);
205*80bca3d3SAxel Dörfler 	if (l <= 0 || l > 0x40000) {
206*80bca3d3SAxel Dörfler 		ntfs_log_error("$MFT/$ATTR_LIST invalid length (%lld).\n", l);
207*80bca3d3SAxel Dörfler 		goto io_error_exit;
208*80bca3d3SAxel Dörfler 	}
209*80bca3d3SAxel Dörfler 	vol->mft_ni->attr_list_size = l;
210*80bca3d3SAxel Dörfler 	vol->mft_ni->attr_list = ntfs_malloc(l);
211*80bca3d3SAxel Dörfler 	if (!vol->mft_ni->attr_list)
212*80bca3d3SAxel Dörfler 		goto error_exit;
213*80bca3d3SAxel Dörfler 
214*80bca3d3SAxel Dörfler 	l = ntfs_get_attribute_value(vol, ctx->attr, vol->mft_ni->attr_list);
215*80bca3d3SAxel Dörfler 	if (!l) {
216*80bca3d3SAxel Dörfler 		ntfs_log_error("Failed to get value of $MFT/$ATTR_LIST.\n");
217*80bca3d3SAxel Dörfler 		goto io_error_exit;
218*80bca3d3SAxel Dörfler 	}
219*80bca3d3SAxel Dörfler 	if (l != vol->mft_ni->attr_list_size) {
220*80bca3d3SAxel Dörfler 		ntfs_log_error("Partial read of $MFT/$ATTR_LIST (%lld != "
221*80bca3d3SAxel Dörfler 			       "%u).\n", l, vol->mft_ni->attr_list_size);
222*80bca3d3SAxel Dörfler 		goto io_error_exit;
223*80bca3d3SAxel Dörfler 	}
224*80bca3d3SAxel Dörfler 
225*80bca3d3SAxel Dörfler mft_has_no_attr_list:
226*80bca3d3SAxel Dörfler 
227*80bca3d3SAxel Dörfler 	ntfs_attr_setup_flag(vol->mft_ni);
228*80bca3d3SAxel Dörfler 
229*80bca3d3SAxel Dörfler 	/* We now have a fully setup ntfs inode for $MFT in vol->mft_ni. */
230*80bca3d3SAxel Dörfler 
231*80bca3d3SAxel Dörfler 	/* Get an ntfs attribute for $MFT/$DATA and set it up, too. */
232*80bca3d3SAxel Dörfler 	vol->mft_na = ntfs_attr_open(vol->mft_ni, AT_DATA, AT_UNNAMED, 0);
233*80bca3d3SAxel Dörfler 	if (!vol->mft_na) {
234*80bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to open ntfs attribute");
235*80bca3d3SAxel Dörfler 		goto error_exit;
236*80bca3d3SAxel Dörfler 	}
237*80bca3d3SAxel Dörfler 	/* Read all extents from the $DATA attribute in $MFT. */
238*80bca3d3SAxel Dörfler 	ntfs_attr_reinit_search_ctx(ctx);
239*80bca3d3SAxel Dörfler 	last_vcn = vol->mft_na->allocated_size >> vol->cluster_size_bits;
240*80bca3d3SAxel Dörfler 	highest_vcn = next_vcn = 0;
241*80bca3d3SAxel Dörfler 	a = NULL;
242*80bca3d3SAxel Dörfler 	while (!ntfs_attr_lookup(AT_DATA, AT_UNNAMED, 0, 0, next_vcn, NULL, 0,
243*80bca3d3SAxel Dörfler 			ctx)) {
244*80bca3d3SAxel Dörfler 		runlist_element *nrl;
245*80bca3d3SAxel Dörfler 
246*80bca3d3SAxel Dörfler 		a = ctx->attr;
247*80bca3d3SAxel Dörfler 		/* $MFT must be non-resident. */
248*80bca3d3SAxel Dörfler 		if (!a->non_resident) {
249*80bca3d3SAxel Dörfler 			ntfs_log_error("$MFT must be non-resident.\n");
250*80bca3d3SAxel Dörfler 			goto io_error_exit;
251*80bca3d3SAxel Dörfler 		}
252*80bca3d3SAxel Dörfler 		/* $MFT must be uncompressed and unencrypted. */
253*80bca3d3SAxel Dörfler 		if (a->flags & ATTR_COMPRESSION_MASK ||
254*80bca3d3SAxel Dörfler 				a->flags & ATTR_IS_ENCRYPTED) {
255*80bca3d3SAxel Dörfler 			ntfs_log_error("$MFT must be uncompressed and "
256*80bca3d3SAxel Dörfler 				       "unencrypted.\n");
257*80bca3d3SAxel Dörfler 			goto io_error_exit;
258*80bca3d3SAxel Dörfler 		}
259*80bca3d3SAxel Dörfler 		/*
260*80bca3d3SAxel Dörfler 		 * Decompress the mapping pairs array of this extent and merge
261*80bca3d3SAxel Dörfler 		 * the result into the existing runlist. No need for locking
262*80bca3d3SAxel Dörfler 		 * as we have exclusive access to the inode at this time and we
263*80bca3d3SAxel Dörfler 		 * are a mount in progress task, too.
264*80bca3d3SAxel Dörfler 		 */
265*80bca3d3SAxel Dörfler 		nrl = ntfs_mapping_pairs_decompress(vol, a, vol->mft_na->rl);
266*80bca3d3SAxel Dörfler 		if (!nrl) {
267*80bca3d3SAxel Dörfler 			ntfs_log_perror("ntfs_mapping_pairs_decompress() failed");
268*80bca3d3SAxel Dörfler 			goto error_exit;
269*80bca3d3SAxel Dörfler 		}
270*80bca3d3SAxel Dörfler 		vol->mft_na->rl = nrl;
271*80bca3d3SAxel Dörfler 
272*80bca3d3SAxel Dörfler 		/* Get the lowest vcn for the next extent. */
273*80bca3d3SAxel Dörfler 		highest_vcn = sle64_to_cpu(a->highest_vcn);
274*80bca3d3SAxel Dörfler 		next_vcn = highest_vcn + 1;
275*80bca3d3SAxel Dörfler 
276*80bca3d3SAxel Dörfler 		/* Only one extent or error, which we catch below. */
277*80bca3d3SAxel Dörfler 		if (next_vcn <= 0)
278*80bca3d3SAxel Dörfler 			break;
279*80bca3d3SAxel Dörfler 
280*80bca3d3SAxel Dörfler 		/* Avoid endless loops due to corruption. */
281*80bca3d3SAxel Dörfler 		if (next_vcn < sle64_to_cpu(a->lowest_vcn)) {
282*80bca3d3SAxel Dörfler 			ntfs_log_error("$MFT has corrupt attribute list.\n");
283*80bca3d3SAxel Dörfler 			goto io_error_exit;
284*80bca3d3SAxel Dörfler 		}
285*80bca3d3SAxel Dörfler 	}
286*80bca3d3SAxel Dörfler 	if (!a) {
287*80bca3d3SAxel Dörfler 		ntfs_log_error("$MFT/$DATA attribute not found.\n");
288*80bca3d3SAxel Dörfler 		goto io_error_exit;
289*80bca3d3SAxel Dörfler 	}
290*80bca3d3SAxel Dörfler 	if (highest_vcn && highest_vcn != last_vcn - 1) {
291*80bca3d3SAxel Dörfler 		ntfs_log_error("Failed to load runlist for $MFT/$DATA.\n");
292*80bca3d3SAxel Dörfler 		ntfs_log_error("highest_vcn = 0x%llx, last_vcn - 1 = 0x%llx\n",
293*80bca3d3SAxel Dörfler 			       (long long)highest_vcn, (long long)last_vcn - 1);
294*80bca3d3SAxel Dörfler 		goto io_error_exit;
295*80bca3d3SAxel Dörfler 	}
296*80bca3d3SAxel Dörfler 	/* Done with the $Mft mft record. */
297*80bca3d3SAxel Dörfler 	ntfs_attr_put_search_ctx(ctx);
298*80bca3d3SAxel Dörfler 	ctx = NULL;
299*80bca3d3SAxel Dörfler 	/*
300*80bca3d3SAxel Dörfler 	 * The volume is now setup so we can use all read access functions.
301*80bca3d3SAxel Dörfler 	 */
302*80bca3d3SAxel Dörfler 	vol->mftbmp_na = ntfs_attr_open(vol->mft_ni, AT_BITMAP, AT_UNNAMED, 0);
303*80bca3d3SAxel Dörfler 	if (!vol->mftbmp_na) {
304*80bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to open $MFT/$BITMAP");
305*80bca3d3SAxel Dörfler 		goto error_exit;
306*80bca3d3SAxel Dörfler 	}
307*80bca3d3SAxel Dörfler 	return 0;
308*80bca3d3SAxel Dörfler io_error_exit:
309*80bca3d3SAxel Dörfler 	errno = EIO;
310*80bca3d3SAxel Dörfler error_exit:
311*80bca3d3SAxel Dörfler 	eo = errno;
312*80bca3d3SAxel Dörfler 	if (ctx)
313*80bca3d3SAxel Dörfler 		ntfs_attr_put_search_ctx(ctx);
314*80bca3d3SAxel Dörfler 	if (vol->mft_na) {
315*80bca3d3SAxel Dörfler 		ntfs_attr_close(vol->mft_na);
316*80bca3d3SAxel Dörfler 		vol->mft_na = NULL;
317*80bca3d3SAxel Dörfler 	}
318*80bca3d3SAxel Dörfler 	if (vol->mft_ni) {
319*80bca3d3SAxel Dörfler 		ntfs_inode_close(vol->mft_ni);
320*80bca3d3SAxel Dörfler 		vol->mft_ni = NULL;
321*80bca3d3SAxel Dörfler 	}
322*80bca3d3SAxel Dörfler 	errno = eo;
323*80bca3d3SAxel Dörfler 	return -1;
324*80bca3d3SAxel Dörfler }
325*80bca3d3SAxel Dörfler 
326*80bca3d3SAxel Dörfler /**
327*80bca3d3SAxel Dörfler  * ntfs_mftmirr_load - load the $MFTMirr and setup the ntfs volume with it
328*80bca3d3SAxel Dörfler  * @vol:	ntfs volume whose $MFTMirr to load
329*80bca3d3SAxel Dörfler  *
330*80bca3d3SAxel Dörfler  * Load $MFTMirr from @vol and setup @vol with it. After calling this function
331*80bca3d3SAxel Dörfler  * the volume @vol is ready for use by all write access functions provided by
332*80bca3d3SAxel Dörfler  * the ntfs library (assuming ntfs_mft_load() has been called successfully
333*80bca3d3SAxel Dörfler  * beforehand).
334*80bca3d3SAxel Dörfler  *
335*80bca3d3SAxel Dörfler  * Return 0 on success and -1 on error with errno set to the error code.
336*80bca3d3SAxel Dörfler  */
337*80bca3d3SAxel Dörfler static int ntfs_mftmirr_load(ntfs_volume *vol)
338*80bca3d3SAxel Dörfler {
339*80bca3d3SAxel Dörfler 	int err;
340*80bca3d3SAxel Dörfler 
341*80bca3d3SAxel Dörfler 	vol->mftmirr_ni = ntfs_inode_open(vol, FILE_MFTMirr);
342*80bca3d3SAxel Dörfler 	if (!vol->mftmirr_ni) {
343*80bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to open inode $MFTMirr");
344*80bca3d3SAxel Dörfler 		return -1;
345*80bca3d3SAxel Dörfler 	}
346*80bca3d3SAxel Dörfler 
347*80bca3d3SAxel Dörfler 	vol->mftmirr_na = ntfs_attr_open(vol->mftmirr_ni, AT_DATA, AT_UNNAMED, 0);
348*80bca3d3SAxel Dörfler 	if (!vol->mftmirr_na) {
349*80bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to open $MFTMirr/$DATA");
350*80bca3d3SAxel Dörfler 		goto error_exit;
351*80bca3d3SAxel Dörfler 	}
352*80bca3d3SAxel Dörfler 
353*80bca3d3SAxel Dörfler 	if (ntfs_attr_map_runlist(vol->mftmirr_na, 0) < 0) {
354*80bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to map runlist of $MFTMirr/$DATA");
355*80bca3d3SAxel Dörfler 		goto error_exit;
356*80bca3d3SAxel Dörfler 	}
357*80bca3d3SAxel Dörfler 
358*80bca3d3SAxel Dörfler 	return 0;
359*80bca3d3SAxel Dörfler 
360*80bca3d3SAxel Dörfler error_exit:
361*80bca3d3SAxel Dörfler 	err = errno;
362*80bca3d3SAxel Dörfler 	if (vol->mftmirr_na) {
363*80bca3d3SAxel Dörfler 		ntfs_attr_close(vol->mftmirr_na);
364*80bca3d3SAxel Dörfler 		vol->mftmirr_na = NULL;
365*80bca3d3SAxel Dörfler 	}
366*80bca3d3SAxel Dörfler 	ntfs_inode_close(vol->mftmirr_ni);
367*80bca3d3SAxel Dörfler 	vol->mftmirr_ni = NULL;
368*80bca3d3SAxel Dörfler 	errno = err;
369*80bca3d3SAxel Dörfler 	return -1;
370*80bca3d3SAxel Dörfler }
371*80bca3d3SAxel Dörfler 
372*80bca3d3SAxel Dörfler /**
373*80bca3d3SAxel Dörfler  * ntfs_volume_startup - allocate and setup an ntfs volume
374*80bca3d3SAxel Dörfler  * @dev:	device to open
375*80bca3d3SAxel Dörfler  * @flags:	optional mount flags
376*80bca3d3SAxel Dörfler  *
377*80bca3d3SAxel Dörfler  * Load, verify, and parse bootsector; load and setup $MFT and $MFTMirr. After
378*80bca3d3SAxel Dörfler  * calling this function, the volume is setup sufficiently to call all read
379*80bca3d3SAxel Dörfler  * and write access functions provided by the library.
380*80bca3d3SAxel Dörfler  *
381*80bca3d3SAxel Dörfler  * Return the allocated volume structure on success and NULL on error with
382*80bca3d3SAxel Dörfler  * errno set to the error code.
383*80bca3d3SAxel Dörfler  */
384*80bca3d3SAxel Dörfler ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, unsigned long flags)
385*80bca3d3SAxel Dörfler {
386*80bca3d3SAxel Dörfler 	LCN mft_zone_size, mft_lcn;
387*80bca3d3SAxel Dörfler 	s64 br;
388*80bca3d3SAxel Dörfler 	ntfs_volume *vol;
389*80bca3d3SAxel Dörfler 	NTFS_BOOT_SECTOR *bs;
390*80bca3d3SAxel Dörfler 	int eo;
391*80bca3d3SAxel Dörfler #ifdef DEBUG
392*80bca3d3SAxel Dörfler 	const char *OK = "OK\n";
393*80bca3d3SAxel Dörfler 	const char *FAILED = "FAILED\n";
394*80bca3d3SAxel Dörfler #endif
395*80bca3d3SAxel Dörfler 
396*80bca3d3SAxel Dörfler 	if (!dev || !dev->d_ops || !dev->d_name) {
397*80bca3d3SAxel Dörfler 		errno = EINVAL;
398*80bca3d3SAxel Dörfler 		return NULL;
399*80bca3d3SAxel Dörfler 	}
400*80bca3d3SAxel Dörfler 
401*80bca3d3SAxel Dörfler 	bs = ntfs_malloc(sizeof(NTFS_BOOT_SECTOR));
402*80bca3d3SAxel Dörfler 	if (!bs)
403*80bca3d3SAxel Dörfler 		return NULL;
404*80bca3d3SAxel Dörfler 
405*80bca3d3SAxel Dörfler 	/* Allocate the volume structure. */
406*80bca3d3SAxel Dörfler 	vol = ntfs_volume_alloc();
407*80bca3d3SAxel Dörfler 	if (!vol)
408*80bca3d3SAxel Dörfler 		goto error_exit;
409*80bca3d3SAxel Dörfler 	/* Create the default upcase table. */
410*80bca3d3SAxel Dörfler 	vol->upcase_len = 65536;
411*80bca3d3SAxel Dörfler 	vol->upcase = ntfs_malloc(vol->upcase_len * sizeof(ntfschar));
412*80bca3d3SAxel Dörfler 	if (!vol->upcase)
413*80bca3d3SAxel Dörfler 		goto error_exit;
414*80bca3d3SAxel Dörfler 
415*80bca3d3SAxel Dörfler 	ntfs_upcase_table_build(vol->upcase,
416*80bca3d3SAxel Dörfler 			vol->upcase_len * sizeof(ntfschar));
417*80bca3d3SAxel Dörfler 	if (flags & MS_RDONLY)
418*80bca3d3SAxel Dörfler 		NVolSetReadOnly(vol);
419*80bca3d3SAxel Dörfler 	if (flags & MS_NOATIME)
420*80bca3d3SAxel Dörfler 		NVolSetNoATime(vol);
421*80bca3d3SAxel Dörfler 	ntfs_log_debug("Reading bootsector... ");
422*80bca3d3SAxel Dörfler 	if (dev->d_ops->open(dev, NVolReadOnly(vol) ? O_RDONLY: O_RDWR)) {
423*80bca3d3SAxel Dörfler 		ntfs_log_debug(FAILED);
424*80bca3d3SAxel Dörfler 		ntfs_log_perror("Error opening partition device");
425*80bca3d3SAxel Dörfler 		goto error_exit;
426*80bca3d3SAxel Dörfler 	}
427*80bca3d3SAxel Dörfler 	/* Attach the device to the volume. */
428*80bca3d3SAxel Dörfler 	vol->dev = dev;
429*80bca3d3SAxel Dörfler 	/* Now read the bootsector. */
430*80bca3d3SAxel Dörfler 	br = ntfs_pread(dev, 0, sizeof(NTFS_BOOT_SECTOR), bs);
431*80bca3d3SAxel Dörfler 	if (br != sizeof(NTFS_BOOT_SECTOR)) {
432*80bca3d3SAxel Dörfler 		ntfs_log_debug(FAILED);
433*80bca3d3SAxel Dörfler 		if (br != -1)
434*80bca3d3SAxel Dörfler 			errno = EINVAL;
435*80bca3d3SAxel Dörfler 		if (!br)
436*80bca3d3SAxel Dörfler 			ntfs_log_error("Partition is smaller than bootsector "
437*80bca3d3SAxel Dörfler 				       "size.\n");
438*80bca3d3SAxel Dörfler 		else
439*80bca3d3SAxel Dörfler 			ntfs_log_perror("Error reading bootsector");
440*80bca3d3SAxel Dörfler 		goto error_exit;
441*80bca3d3SAxel Dörfler 	}
442*80bca3d3SAxel Dörfler 	ntfs_log_debug(OK);
443*80bca3d3SAxel Dörfler 	if (!ntfs_boot_sector_is_ntfs(bs)) {
444*80bca3d3SAxel Dörfler 		errno = EINVAL;
445*80bca3d3SAxel Dörfler 		goto error_exit;
446*80bca3d3SAxel Dörfler 	}
447*80bca3d3SAxel Dörfler 	if (ntfs_boot_sector_parse(vol, bs) < 0)
448*80bca3d3SAxel Dörfler 		goto error_exit;
449*80bca3d3SAxel Dörfler 
450*80bca3d3SAxel Dörfler 	free(bs);
451*80bca3d3SAxel Dörfler 	bs = NULL;
452*80bca3d3SAxel Dörfler 	/* Now set the device block size to the sector size. */
453*80bca3d3SAxel Dörfler 	if (ntfs_device_block_size_set(vol->dev, vol->sector_size))
454*80bca3d3SAxel Dörfler 		ntfs_log_debug("Failed to set the device block size to the "
455*80bca3d3SAxel Dörfler 				"sector size.  This may affect performance "
456*80bca3d3SAxel Dörfler 				"but should be harmless otherwise.  Error: "
457*80bca3d3SAxel Dörfler 				"%s\n", strerror(errno));
458*80bca3d3SAxel Dörfler 	/*
459*80bca3d3SAxel Dörfler 	 * We now initialize the cluster allocator.
460*80bca3d3SAxel Dörfler 	 *
461*80bca3d3SAxel Dörfler 	 * FIXME: Move this to its own function? (AIA)
462*80bca3d3SAxel Dörfler 	 */
463*80bca3d3SAxel Dörfler 
464*80bca3d3SAxel Dörfler 	// TODO: Make this tunable at mount time. (AIA)
465*80bca3d3SAxel Dörfler 	vol->mft_zone_multiplier = 1;
466*80bca3d3SAxel Dörfler 
467*80bca3d3SAxel Dörfler 	/* Determine the size of the MFT zone. */
468*80bca3d3SAxel Dörfler 	mft_zone_size = vol->nr_clusters;
469*80bca3d3SAxel Dörfler 	switch (vol->mft_zone_multiplier) {  /* % of volume size in clusters */
470*80bca3d3SAxel Dörfler 	case 4:
471*80bca3d3SAxel Dörfler 		mft_zone_size >>= 1;			/* 50%   */
472*80bca3d3SAxel Dörfler 		break;
473*80bca3d3SAxel Dörfler 	case 3:
474*80bca3d3SAxel Dörfler 		mft_zone_size = mft_zone_size * 3 >> 3;	/* 37.5% */
475*80bca3d3SAxel Dörfler 		break;
476*80bca3d3SAxel Dörfler 	case 2:
477*80bca3d3SAxel Dörfler 		mft_zone_size >>= 2;			/* 25%   */
478*80bca3d3SAxel Dörfler 		break;
479*80bca3d3SAxel Dörfler 	/* case 1: */
480*80bca3d3SAxel Dörfler 	default:
481*80bca3d3SAxel Dörfler 		mft_zone_size >>= 3;			/* 12.5% */
482*80bca3d3SAxel Dörfler 		break;
483*80bca3d3SAxel Dörfler 	}
484*80bca3d3SAxel Dörfler 
485*80bca3d3SAxel Dörfler 	/* Setup the mft zone. */
486*80bca3d3SAxel Dörfler 	vol->mft_zone_start = vol->mft_zone_pos = vol->mft_lcn;
487*80bca3d3SAxel Dörfler 	ntfs_log_debug("mft_zone_pos = 0x%llx\n", (long long)vol->mft_zone_pos);
488*80bca3d3SAxel Dörfler 
489*80bca3d3SAxel Dörfler 	/*
490*80bca3d3SAxel Dörfler 	 * Calculate the mft_lcn for an unmodified NTFS volume (see mkntfs
491*80bca3d3SAxel Dörfler 	 * source) and if the actual mft_lcn is in the expected place or even
492*80bca3d3SAxel Dörfler 	 * further to the front of the volume, extend the mft_zone to cover the
493*80bca3d3SAxel Dörfler 	 * beginning of the volume as well. This is in order to protect the
494*80bca3d3SAxel Dörfler 	 * area reserved for the mft bitmap as well within the mft_zone itself.
495*80bca3d3SAxel Dörfler 	 * On non-standard volumes we don't protect it as the overhead would be
496*80bca3d3SAxel Dörfler 	 * higher than the speed increase we would get by doing it.
497*80bca3d3SAxel Dörfler 	 */
498*80bca3d3SAxel Dörfler 	mft_lcn = (8192 + 2 * vol->cluster_size - 1) / vol->cluster_size;
499*80bca3d3SAxel Dörfler 	if (mft_lcn * vol->cluster_size < 16 * 1024)
500*80bca3d3SAxel Dörfler 		mft_lcn = (16 * 1024 + vol->cluster_size - 1) /
501*80bca3d3SAxel Dörfler 				vol->cluster_size;
502*80bca3d3SAxel Dörfler 	if (vol->mft_zone_start <= mft_lcn)
503*80bca3d3SAxel Dörfler 		vol->mft_zone_start = 0;
504*80bca3d3SAxel Dörfler 	ntfs_log_debug("mft_zone_start = 0x%llx\n", (long long)vol->mft_zone_start);
505*80bca3d3SAxel Dörfler 
506*80bca3d3SAxel Dörfler 	/*
507*80bca3d3SAxel Dörfler 	 * Need to cap the mft zone on non-standard volumes so that it does
508*80bca3d3SAxel Dörfler 	 * not point outside the boundaries of the volume. We do this by
509*80bca3d3SAxel Dörfler 	 * halving the zone size until we are inside the volume.
510*80bca3d3SAxel Dörfler 	 */
511*80bca3d3SAxel Dörfler 	vol->mft_zone_end = vol->mft_lcn + mft_zone_size;
512*80bca3d3SAxel Dörfler 	while (vol->mft_zone_end >= vol->nr_clusters) {
513*80bca3d3SAxel Dörfler 		mft_zone_size >>= 1;
514*80bca3d3SAxel Dörfler 		vol->mft_zone_end = vol->mft_lcn + mft_zone_size;
515*80bca3d3SAxel Dörfler 	}
516*80bca3d3SAxel Dörfler 	ntfs_log_debug("mft_zone_end = 0x%llx\n", (long long)vol->mft_zone_end);
517*80bca3d3SAxel Dörfler 
518*80bca3d3SAxel Dörfler 	/*
519*80bca3d3SAxel Dörfler 	 * Set the current position within each data zone to the start of the
520*80bca3d3SAxel Dörfler 	 * respective zone.
521*80bca3d3SAxel Dörfler 	 */
522*80bca3d3SAxel Dörfler 	vol->data1_zone_pos = vol->mft_zone_end;
523*80bca3d3SAxel Dörfler 	ntfs_log_debug("data1_zone_pos = 0x%llx\n", vol->data1_zone_pos);
524*80bca3d3SAxel Dörfler 	vol->data2_zone_pos = 0;
525*80bca3d3SAxel Dörfler 	ntfs_log_debug("data2_zone_pos = 0x%llx\n", vol->data2_zone_pos);
526*80bca3d3SAxel Dörfler 
527*80bca3d3SAxel Dörfler 	/* Set the mft data allocation position to mft record 24. */
528*80bca3d3SAxel Dörfler 	vol->mft_data_pos = 24;
529*80bca3d3SAxel Dörfler 
530*80bca3d3SAxel Dörfler 	/*
531*80bca3d3SAxel Dörfler 	 * The cluster allocator is now fully operational.
532*80bca3d3SAxel Dörfler 	 */
533*80bca3d3SAxel Dörfler 
534*80bca3d3SAxel Dörfler 	/* Need to setup $MFT so we can use the library read functions. */
535*80bca3d3SAxel Dörfler 	ntfs_log_debug("Loading $MFT... ");
536*80bca3d3SAxel Dörfler 	if (ntfs_mft_load(vol) < 0) {
537*80bca3d3SAxel Dörfler 		ntfs_log_debug(FAILED);
538*80bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to load $MFT");
539*80bca3d3SAxel Dörfler 		goto error_exit;
540*80bca3d3SAxel Dörfler 	}
541*80bca3d3SAxel Dörfler 	ntfs_log_debug(OK);
542*80bca3d3SAxel Dörfler 
543*80bca3d3SAxel Dörfler 	/* Need to setup $MFTMirr so we can use the write functions, too. */
544*80bca3d3SAxel Dörfler 	ntfs_log_debug("Loading $MFTMirr... ");
545*80bca3d3SAxel Dörfler 	if (ntfs_mftmirr_load(vol) < 0) {
546*80bca3d3SAxel Dörfler 		ntfs_log_debug(FAILED);
547*80bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to load $MFTMirr");
548*80bca3d3SAxel Dörfler 		goto error_exit;
549*80bca3d3SAxel Dörfler 	}
550*80bca3d3SAxel Dörfler 	ntfs_log_debug(OK);
551*80bca3d3SAxel Dörfler 	return vol;
552*80bca3d3SAxel Dörfler error_exit:
553*80bca3d3SAxel Dörfler 	eo = errno;
554*80bca3d3SAxel Dörfler 	free(bs);
555*80bca3d3SAxel Dörfler 	if (vol)
556*80bca3d3SAxel Dörfler 		__ntfs_volume_release(vol);
557*80bca3d3SAxel Dörfler 	errno = eo;
558*80bca3d3SAxel Dörfler 	return NULL;
559*80bca3d3SAxel Dörfler }
560*80bca3d3SAxel Dörfler 
561*80bca3d3SAxel Dörfler /**
562*80bca3d3SAxel Dörfler  * ntfs_volume_check_logfile - check logfile on target volume
563*80bca3d3SAxel Dörfler  * @vol:	volume on which to check logfile
564*80bca3d3SAxel Dörfler  *
565*80bca3d3SAxel Dörfler  * Return 0 on success and -1 on error with errno set error code.
566*80bca3d3SAxel Dörfler  */
567*80bca3d3SAxel Dörfler static int ntfs_volume_check_logfile(ntfs_volume *vol)
568*80bca3d3SAxel Dörfler {
569*80bca3d3SAxel Dörfler 	ntfs_inode *ni;
570*80bca3d3SAxel Dörfler 	ntfs_attr *na = NULL;
571*80bca3d3SAxel Dörfler 	RESTART_PAGE_HEADER *rp = NULL;
572*80bca3d3SAxel Dörfler 	int err = 0;
573*80bca3d3SAxel Dörfler 
574*80bca3d3SAxel Dörfler 	if ((ni = ntfs_inode_open(vol, FILE_LogFile)) == NULL) {
575*80bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to open inode FILE_LogFile");
576*80bca3d3SAxel Dörfler 		errno = EIO;
577*80bca3d3SAxel Dörfler 		return -1;
578*80bca3d3SAxel Dörfler 	}
579*80bca3d3SAxel Dörfler 	if ((na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0)) == NULL) {
580*80bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to open $FILE_LogFile/$DATA");
581*80bca3d3SAxel Dörfler 		err = EIO;
582*80bca3d3SAxel Dörfler 		goto exit;
583*80bca3d3SAxel Dörfler 	}
584*80bca3d3SAxel Dörfler 	if (!ntfs_check_logfile(na, &rp) || !ntfs_is_logfile_clean(na, rp))
585*80bca3d3SAxel Dörfler 		err = EOPNOTSUPP;
586*80bca3d3SAxel Dörfler 	free(rp);
587*80bca3d3SAxel Dörfler exit:
588*80bca3d3SAxel Dörfler 	if (na)
589*80bca3d3SAxel Dörfler 		ntfs_attr_close(na);
590*80bca3d3SAxel Dörfler 	ntfs_inode_close(ni);
591*80bca3d3SAxel Dörfler 	if (err) {
592*80bca3d3SAxel Dörfler 		errno = err;
593*80bca3d3SAxel Dörfler 		return -1;
594*80bca3d3SAxel Dörfler 	}
595*80bca3d3SAxel Dörfler 	return 0;
596*80bca3d3SAxel Dörfler }
597*80bca3d3SAxel Dörfler 
598*80bca3d3SAxel Dörfler /**
599*80bca3d3SAxel Dörfler  * ntfs_hiberfile_open - Find and open '/hiberfil.sys'
600*80bca3d3SAxel Dörfler  * @vol:    An ntfs volume obtained from ntfs_mount
601*80bca3d3SAxel Dörfler  *
602*80bca3d3SAxel Dörfler  * Return:  inode  Success, hiberfil.sys is valid
603*80bca3d3SAxel Dörfler  *	    NULL   hiberfil.sys doesn't exist or some other error occurred
604*80bca3d3SAxel Dörfler  */
605*80bca3d3SAxel Dörfler static ntfs_inode *ntfs_hiberfile_open(ntfs_volume *vol)
606*80bca3d3SAxel Dörfler {
607*80bca3d3SAxel Dörfler 	u64 inode;
608*80bca3d3SAxel Dörfler 	ntfs_inode *ni_root;
609*80bca3d3SAxel Dörfler 	ntfs_inode *ni_hibr = NULL;
610*80bca3d3SAxel Dörfler 	ntfschar   *unicode = NULL;
611*80bca3d3SAxel Dörfler 	int unicode_len;
612*80bca3d3SAxel Dörfler 	const char *hiberfile = "hiberfil.sys";
613*80bca3d3SAxel Dörfler 
614*80bca3d3SAxel Dörfler 	if (!vol) {
615*80bca3d3SAxel Dörfler 		errno = EINVAL;
616*80bca3d3SAxel Dörfler 		return NULL;
617*80bca3d3SAxel Dörfler 	}
618*80bca3d3SAxel Dörfler 
619*80bca3d3SAxel Dörfler 	ni_root = ntfs_inode_open(vol, FILE_root);
620*80bca3d3SAxel Dörfler 	if (!ni_root) {
621*80bca3d3SAxel Dörfler 		ntfs_log_debug("Couldn't open the root directory.\n");
622*80bca3d3SAxel Dörfler 		return NULL;
623*80bca3d3SAxel Dörfler 	}
624*80bca3d3SAxel Dörfler 
625*80bca3d3SAxel Dörfler 	unicode_len = ntfs_mbstoucs(hiberfile, &unicode, 0);
626*80bca3d3SAxel Dörfler 	if (unicode_len < 0) {
627*80bca3d3SAxel Dörfler 		ntfs_log_perror("Couldn't convert 'hiberfil.sys' to Unicode");
628*80bca3d3SAxel Dörfler 		goto out;
629*80bca3d3SAxel Dörfler 	}
630*80bca3d3SAxel Dörfler 
631*80bca3d3SAxel Dörfler 	inode = ntfs_inode_lookup_by_name(ni_root, unicode, unicode_len);
632*80bca3d3SAxel Dörfler 	if (inode == (u64)-1) {
633*80bca3d3SAxel Dörfler 		ntfs_log_debug("Couldn't find file '%s'.\n", hiberfile);
634*80bca3d3SAxel Dörfler 		goto out;
635*80bca3d3SAxel Dörfler 	}
636*80bca3d3SAxel Dörfler 
637*80bca3d3SAxel Dörfler 	inode = MREF(inode);
638*80bca3d3SAxel Dörfler 	ni_hibr = ntfs_inode_open(vol, inode);
639*80bca3d3SAxel Dörfler 	if (!ni_hibr) {
640*80bca3d3SAxel Dörfler 		ntfs_log_debug("Couldn't open inode %lld.\n", (long long)inode);
641*80bca3d3SAxel Dörfler 		goto out;
642*80bca3d3SAxel Dörfler 	}
643*80bca3d3SAxel Dörfler out:
644*80bca3d3SAxel Dörfler 	ntfs_inode_close(ni_root);
645*80bca3d3SAxel Dörfler 	free(unicode);
646*80bca3d3SAxel Dörfler 	return ni_hibr;
647*80bca3d3SAxel Dörfler }
648*80bca3d3SAxel Dörfler 
649*80bca3d3SAxel Dörfler 
650*80bca3d3SAxel Dörfler #define NTFS_HIBERFILE_HEADER_SIZE	4096
651*80bca3d3SAxel Dörfler 
652*80bca3d3SAxel Dörfler /**
653*80bca3d3SAxel Dörfler  * ntfs_volume_check_hiberfile - check hiberfil.sys whether Windows is
654*80bca3d3SAxel Dörfler  *                               hibernated on the target volume
655*80bca3d3SAxel Dörfler  * @vol:    volume on which to check hiberfil.sys
656*80bca3d3SAxel Dörfler  *
657*80bca3d3SAxel Dörfler  * Return:  0 if Windows isn't hibernated for sure
658*80bca3d3SAxel Dörfler  *         -1 otherwise and errno is set to the appropriate value
659*80bca3d3SAxel Dörfler  */
660*80bca3d3SAxel Dörfler static int ntfs_volume_check_hiberfile(ntfs_volume *vol)
661*80bca3d3SAxel Dörfler {
662*80bca3d3SAxel Dörfler 	ntfs_inode *ni;
663*80bca3d3SAxel Dörfler 	ntfs_attr *na = NULL;
664*80bca3d3SAxel Dörfler 	int i, bytes_read, ret = -1;
665*80bca3d3SAxel Dörfler 	char *buf = NULL;
666*80bca3d3SAxel Dörfler 
667*80bca3d3SAxel Dörfler 	ni = ntfs_hiberfile_open(vol);
668*80bca3d3SAxel Dörfler 	if (!ni) {
669*80bca3d3SAxel Dörfler 		if (errno == ENOENT)
670*80bca3d3SAxel Dörfler 			return 0;
671*80bca3d3SAxel Dörfler 		return -1;
672*80bca3d3SAxel Dörfler 	}
673*80bca3d3SAxel Dörfler 
674*80bca3d3SAxel Dörfler 	buf = ntfs_malloc(NTFS_HIBERFILE_HEADER_SIZE);
675*80bca3d3SAxel Dörfler 	if (!buf)
676*80bca3d3SAxel Dörfler 		goto out;
677*80bca3d3SAxel Dörfler 
678*80bca3d3SAxel Dörfler 	na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
679*80bca3d3SAxel Dörfler 	if (!na) {
680*80bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to open hiberfil.sys data attribute");
681*80bca3d3SAxel Dörfler 		goto out;
682*80bca3d3SAxel Dörfler 	}
683*80bca3d3SAxel Dörfler 
684*80bca3d3SAxel Dörfler 	bytes_read = ntfs_attr_pread(na, 0, NTFS_HIBERFILE_HEADER_SIZE, buf);
685*80bca3d3SAxel Dörfler 	if (bytes_read == -1) {
686*80bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to read hiberfil.sys");
687*80bca3d3SAxel Dörfler 		goto out;
688*80bca3d3SAxel Dörfler 	}
689*80bca3d3SAxel Dörfler 	if (bytes_read < NTFS_HIBERFILE_HEADER_SIZE) {
690*80bca3d3SAxel Dörfler 		ntfs_log_error("Hibernated non-system partition, refused to "
691*80bca3d3SAxel Dörfler 			       "mount.\n");
692*80bca3d3SAxel Dörfler 		errno = EPERM;
693*80bca3d3SAxel Dörfler 		goto out;
694*80bca3d3SAxel Dörfler 	}
695*80bca3d3SAxel Dörfler 	if (memcmp(buf, "hibr", 4) == 0) {
696*80bca3d3SAxel Dörfler 		ntfs_log_error("Windows is hibernated, refused to mount.\n");
697*80bca3d3SAxel Dörfler 		errno = EPERM;
698*80bca3d3SAxel Dörfler 		goto out;
699*80bca3d3SAxel Dörfler 	}
700*80bca3d3SAxel Dörfler 	for (i = 0; i < NTFS_HIBERFILE_HEADER_SIZE; i++) {
701*80bca3d3SAxel Dörfler 		if (buf[i]) {
702*80bca3d3SAxel Dörfler 			ntfs_log_error("Windows is hibernated, won't mount.\n");
703*80bca3d3SAxel Dörfler 			errno = EPERM;
704*80bca3d3SAxel Dörfler 			goto out;
705*80bca3d3SAxel Dörfler 		}
706*80bca3d3SAxel Dörfler 	}
707*80bca3d3SAxel Dörfler         /* All right, all header bytes are zero */
708*80bca3d3SAxel Dörfler 	ret = 0;
709*80bca3d3SAxel Dörfler out:
710*80bca3d3SAxel Dörfler 	if (na)
711*80bca3d3SAxel Dörfler 		ntfs_attr_close(na);
712*80bca3d3SAxel Dörfler 	free(buf);
713*80bca3d3SAxel Dörfler 	ntfs_inode_close(ni);
714*80bca3d3SAxel Dörfler 	return ret;
715*80bca3d3SAxel Dörfler }
716*80bca3d3SAxel Dörfler 
717*80bca3d3SAxel Dörfler /**
718*80bca3d3SAxel Dörfler  * ntfs_device_mount - open ntfs volume
719*80bca3d3SAxel Dörfler  * @dev:	device to open
720*80bca3d3SAxel Dörfler  * @flags:	optional mount flags
721*80bca3d3SAxel Dörfler  *
722*80bca3d3SAxel Dörfler  * This function mounts an ntfs volume. @dev should describe the device which
723*80bca3d3SAxel Dörfler  * to mount as the ntfs volume.
724*80bca3d3SAxel Dörfler  *
725*80bca3d3SAxel Dörfler  * @flags is an optional second parameter. The same flags are used as for
726*80bca3d3SAxel Dörfler  * the mount system call (man 2 mount). Currently only the following flags
727*80bca3d3SAxel Dörfler  * are implemented:
728*80bca3d3SAxel Dörfler  *	MS_RDONLY	- mount volume read-only
729*80bca3d3SAxel Dörfler  *	MS_NOATIME	- do not update access time
730*80bca3d3SAxel Dörfler  *
731*80bca3d3SAxel Dörfler  * The function opens the device @dev and verifies that it contains a valid
732*80bca3d3SAxel Dörfler  * bootsector. Then, it allocates an ntfs_volume structure and initializes
733*80bca3d3SAxel Dörfler  * some of the values inside the structure from the information stored in the
734*80bca3d3SAxel Dörfler  * bootsector. It proceeds to load the necessary system files and completes
735*80bca3d3SAxel Dörfler  * setting up the structure.
736*80bca3d3SAxel Dörfler  *
737*80bca3d3SAxel Dörfler  * Return the allocated volume structure on success and NULL on error with
738*80bca3d3SAxel Dörfler  * errno set to the error code.
739*80bca3d3SAxel Dörfler  */
740*80bca3d3SAxel Dörfler ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags)
741*80bca3d3SAxel Dörfler {
742*80bca3d3SAxel Dörfler 	s64 l;
743*80bca3d3SAxel Dörfler #ifdef DEBUG
744*80bca3d3SAxel Dörfler 	const char *OK = "OK\n";
745*80bca3d3SAxel Dörfler 	const char *FAILED = "FAILED\n";
746*80bca3d3SAxel Dörfler #endif
747*80bca3d3SAxel Dörfler 	ntfs_volume *vol;
748*80bca3d3SAxel Dörfler 	u8 *m = NULL, *m2 = NULL;
749*80bca3d3SAxel Dörfler 	ntfs_attr_search_ctx *ctx = NULL;
750*80bca3d3SAxel Dörfler 	ntfs_inode *ni;
751*80bca3d3SAxel Dörfler 	ntfs_attr *na;
752*80bca3d3SAxel Dörfler 	ATTR_RECORD *a;
753*80bca3d3SAxel Dörfler 	VOLUME_INFORMATION *vinf;
754*80bca3d3SAxel Dörfler 	ntfschar *vname;
755*80bca3d3SAxel Dörfler 	int i, j, eo;
756*80bca3d3SAxel Dörfler 	u32 u;
757*80bca3d3SAxel Dörfler 
758*80bca3d3SAxel Dörfler 	vol = ntfs_volume_startup(dev, flags);
759*80bca3d3SAxel Dörfler 	if (!vol) {
760*80bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to startup volume");
761*80bca3d3SAxel Dörfler 		return NULL;
762*80bca3d3SAxel Dörfler 	}
763*80bca3d3SAxel Dörfler 
764*80bca3d3SAxel Dörfler 	/* Load data from $MFT and $MFTMirr and compare the contents. */
765*80bca3d3SAxel Dörfler 	m  = ntfs_malloc(vol->mftmirr_size << vol->mft_record_size_bits);
766*80bca3d3SAxel Dörfler 	m2 = ntfs_malloc(vol->mftmirr_size << vol->mft_record_size_bits);
767*80bca3d3SAxel Dörfler 	if (!m || !m2)
768*80bca3d3SAxel Dörfler 		goto error_exit;
769*80bca3d3SAxel Dörfler 
770*80bca3d3SAxel Dörfler 	l = ntfs_attr_mst_pread(vol->mft_na, 0, vol->mftmirr_size,
771*80bca3d3SAxel Dörfler 			vol->mft_record_size, m);
772*80bca3d3SAxel Dörfler 	if (l != vol->mftmirr_size) {
773*80bca3d3SAxel Dörfler 		if (l == -1)
774*80bca3d3SAxel Dörfler 			ntfs_log_perror("Failed to read $MFT");
775*80bca3d3SAxel Dörfler 		else {
776*80bca3d3SAxel Dörfler 			ntfs_log_error("Failed to read $MFT, unexpected length "
777*80bca3d3SAxel Dörfler 				       "(%lld != %d).\n", l, vol->mftmirr_size);
778*80bca3d3SAxel Dörfler 			errno = EIO;
779*80bca3d3SAxel Dörfler 		}
780*80bca3d3SAxel Dörfler 		goto error_exit;
781*80bca3d3SAxel Dörfler 	}
782*80bca3d3SAxel Dörfler 	l = ntfs_attr_mst_pread(vol->mftmirr_na, 0, vol->mftmirr_size,
783*80bca3d3SAxel Dörfler 			vol->mft_record_size, m2);
784*80bca3d3SAxel Dörfler 	if (l != vol->mftmirr_size) {
785*80bca3d3SAxel Dörfler 		if (l == 4)
786*80bca3d3SAxel Dörfler 			vol->mftmirr_size = 4;
787*80bca3d3SAxel Dörfler 		else {
788*80bca3d3SAxel Dörfler 			if (l == -1)
789*80bca3d3SAxel Dörfler 				ntfs_log_perror("Failed to read $MFTMirr");
790*80bca3d3SAxel Dörfler 			else {
791*80bca3d3SAxel Dörfler 				ntfs_log_error("Failed to read $MFTMirr "
792*80bca3d3SAxel Dörfler 					       "unexpected length (%d != %lld)."
793*80bca3d3SAxel Dörfler 					       "\n", vol->mftmirr_size, l);
794*80bca3d3SAxel Dörfler 				errno = EIO;
795*80bca3d3SAxel Dörfler 			}
796*80bca3d3SAxel Dörfler 			goto error_exit;
797*80bca3d3SAxel Dörfler 		}
798*80bca3d3SAxel Dörfler 	}
799*80bca3d3SAxel Dörfler 	ntfs_log_debug("Comparing $MFTMirr to $MFT... ");
800*80bca3d3SAxel Dörfler 	for (i = 0; i < vol->mftmirr_size; ++i) {
801*80bca3d3SAxel Dörfler 		MFT_RECORD *mrec, *mrec2;
802*80bca3d3SAxel Dörfler 		const char *ESTR[12] = { "$MFT", "$MFTMirr", "$LogFile",
803*80bca3d3SAxel Dörfler 			"$Volume", "$AttrDef", "root directory", "$Bitmap",
804*80bca3d3SAxel Dörfler 			"$Boot", "$BadClus", "$Secure", "$UpCase", "$Extend" };
805*80bca3d3SAxel Dörfler 		const char *s;
806*80bca3d3SAxel Dörfler 
807*80bca3d3SAxel Dörfler 		if (i < 12)
808*80bca3d3SAxel Dörfler 			s = ESTR[i];
809*80bca3d3SAxel Dörfler 		else if (i < 16)
810*80bca3d3SAxel Dörfler 			s = "system file";
811*80bca3d3SAxel Dörfler 		else
812*80bca3d3SAxel Dörfler 			s = "mft record";
813*80bca3d3SAxel Dörfler 
814*80bca3d3SAxel Dörfler 		mrec = (MFT_RECORD*)(m + i * vol->mft_record_size);
815*80bca3d3SAxel Dörfler 		if (mrec->flags & MFT_RECORD_IN_USE) {
816*80bca3d3SAxel Dörfler 			if (ntfs_is_baad_recordp(mrec)) {
817*80bca3d3SAxel Dörfler 				ntfs_log_debug("FAILED\n");
818*80bca3d3SAxel Dörfler 				ntfs_log_error("$MFT error: Incomplete multi "
819*80bca3d3SAxel Dörfler 					       "sector transfer detected in "
820*80bca3d3SAxel Dörfler 					       "'%s'.\n", s);
821*80bca3d3SAxel Dörfler 				goto io_error_exit;
822*80bca3d3SAxel Dörfler 			}
823*80bca3d3SAxel Dörfler 			if (!ntfs_is_mft_recordp(mrec)) {
824*80bca3d3SAxel Dörfler 				ntfs_log_debug("FAILED\n");
825*80bca3d3SAxel Dörfler 				ntfs_log_error("$MFT error: Invalid mft "
826*80bca3d3SAxel Dörfler 						"record for '%s'.\n", s);
827*80bca3d3SAxel Dörfler 				goto io_error_exit;
828*80bca3d3SAxel Dörfler 			}
829*80bca3d3SAxel Dörfler 		}
830*80bca3d3SAxel Dörfler 		mrec2 = (MFT_RECORD*)(m2 + i * vol->mft_record_size);
831*80bca3d3SAxel Dörfler 		if (mrec2->flags & MFT_RECORD_IN_USE) {
832*80bca3d3SAxel Dörfler 			if (ntfs_is_baad_recordp(mrec2)) {
833*80bca3d3SAxel Dörfler 				ntfs_log_debug("FAILED\n");
834*80bca3d3SAxel Dörfler 				ntfs_log_error("$MFTMirr error: Incomplete "
835*80bca3d3SAxel Dörfler 						"multi sector transfer "
836*80bca3d3SAxel Dörfler 						"detected in '%s'.\n", s);
837*80bca3d3SAxel Dörfler 				goto io_error_exit;
838*80bca3d3SAxel Dörfler 			}
839*80bca3d3SAxel Dörfler 			if (!ntfs_is_mft_recordp(mrec2)) {
840*80bca3d3SAxel Dörfler 				ntfs_log_debug("FAILED\n");
841*80bca3d3SAxel Dörfler 				ntfs_log_error("$MFTMirr error: Invalid mft "
842*80bca3d3SAxel Dörfler 						"record for '%s'.\n", s);
843*80bca3d3SAxel Dörfler 				goto io_error_exit;
844*80bca3d3SAxel Dörfler 			}
845*80bca3d3SAxel Dörfler 		}
846*80bca3d3SAxel Dörfler 		if (memcmp(mrec, mrec2, ntfs_mft_record_get_data_size(mrec))) {
847*80bca3d3SAxel Dörfler 			ntfs_log_debug(FAILED);
848*80bca3d3SAxel Dörfler 			ntfs_log_error("$MFTMirr does not match $MFT (record "
849*80bca3d3SAxel Dörfler 				       "%d).\n", i);
850*80bca3d3SAxel Dörfler 			goto io_error_exit;
851*80bca3d3SAxel Dörfler 		}
852*80bca3d3SAxel Dörfler 	}
853*80bca3d3SAxel Dörfler 	ntfs_log_debug(OK);
854*80bca3d3SAxel Dörfler 
855*80bca3d3SAxel Dörfler 	free(m2);
856*80bca3d3SAxel Dörfler 	free(m);
857*80bca3d3SAxel Dörfler 	m = m2 = NULL;
858*80bca3d3SAxel Dörfler 
859*80bca3d3SAxel Dörfler 	/* Now load the bitmap from $Bitmap. */
860*80bca3d3SAxel Dörfler 	ntfs_log_debug("Loading $Bitmap... ");
861*80bca3d3SAxel Dörfler 	vol->lcnbmp_ni = ntfs_inode_open(vol, FILE_Bitmap);
862*80bca3d3SAxel Dörfler 	if (!vol->lcnbmp_ni) {
863*80bca3d3SAxel Dörfler 		ntfs_log_debug(FAILED);
864*80bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to open inode");
865*80bca3d3SAxel Dörfler 		goto error_exit;
866*80bca3d3SAxel Dörfler 	}
867*80bca3d3SAxel Dörfler 	/* Get an ntfs attribute for $Bitmap/$DATA. */
868*80bca3d3SAxel Dörfler 	vol->lcnbmp_na = ntfs_attr_open(vol->lcnbmp_ni, AT_DATA, AT_UNNAMED, 0);
869*80bca3d3SAxel Dörfler 	if (!vol->lcnbmp_na) {
870*80bca3d3SAxel Dörfler 		ntfs_log_debug(FAILED);
871*80bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to open ntfs attribute");
872*80bca3d3SAxel Dörfler 		goto error_exit;
873*80bca3d3SAxel Dörfler 	}
874*80bca3d3SAxel Dörfler 	/* Done with the $Bitmap mft record. */
875*80bca3d3SAxel Dörfler 	ntfs_log_debug(OK);
876*80bca3d3SAxel Dörfler 
877*80bca3d3SAxel Dörfler 	/* Now load the upcase table from $UpCase. */
878*80bca3d3SAxel Dörfler 	ntfs_log_debug("Loading $UpCase... ");
879*80bca3d3SAxel Dörfler 	ni = ntfs_inode_open(vol, FILE_UpCase);
880*80bca3d3SAxel Dörfler 	if (!ni) {
881*80bca3d3SAxel Dörfler 		ntfs_log_debug(FAILED);
882*80bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to open inode");
883*80bca3d3SAxel Dörfler 		goto error_exit;
884*80bca3d3SAxel Dörfler 	}
885*80bca3d3SAxel Dörfler 	/* Get an ntfs attribute for $UpCase/$DATA. */
886*80bca3d3SAxel Dörfler 	na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
887*80bca3d3SAxel Dörfler 	if (!na) {
888*80bca3d3SAxel Dörfler 		ntfs_log_debug(FAILED);
889*80bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to open ntfs attribute");
890*80bca3d3SAxel Dörfler 		goto error_exit;
891*80bca3d3SAxel Dörfler 	}
892*80bca3d3SAxel Dörfler 	/*
893*80bca3d3SAxel Dörfler 	 * Note: Normally, the upcase table has a length equal to 65536
894*80bca3d3SAxel Dörfler 	 * 2-byte Unicode characters but allow for different cases, so no
895*80bca3d3SAxel Dörfler 	 * checks done. Just check we don't overflow 32-bits worth of Unicode
896*80bca3d3SAxel Dörfler 	 * characters.
897*80bca3d3SAxel Dörfler 	 */
898*80bca3d3SAxel Dörfler 	if (na->data_size & ~0x1ffffffffULL) {
899*80bca3d3SAxel Dörfler 		ntfs_log_debug(FAILED);
900*80bca3d3SAxel Dörfler 		ntfs_log_error("Error: Upcase table is too big (max 32-bit "
901*80bca3d3SAxel Dörfler 				"allowed).\n");
902*80bca3d3SAxel Dörfler 		errno = EINVAL;
903*80bca3d3SAxel Dörfler 		goto error_exit;
904*80bca3d3SAxel Dörfler 	}
905*80bca3d3SAxel Dörfler 	if (vol->upcase_len != na->data_size >> 1) {
906*80bca3d3SAxel Dörfler 		vol->upcase_len = na->data_size >> 1;
907*80bca3d3SAxel Dörfler 		/* Throw away default table. */
908*80bca3d3SAxel Dörfler 		free(vol->upcase);
909*80bca3d3SAxel Dörfler 		vol->upcase = ntfs_malloc(na->data_size);
910*80bca3d3SAxel Dörfler 		if (!vol->upcase) {
911*80bca3d3SAxel Dörfler 			ntfs_log_debug(FAILED);
912*80bca3d3SAxel Dörfler 			goto error_exit;
913*80bca3d3SAxel Dörfler 		}
914*80bca3d3SAxel Dörfler 	}
915*80bca3d3SAxel Dörfler 	/* Read in the $DATA attribute value into the buffer. */
916*80bca3d3SAxel Dörfler 	l = ntfs_attr_pread(na, 0, na->data_size, vol->upcase);
917*80bca3d3SAxel Dörfler 	if (l != na->data_size) {
918*80bca3d3SAxel Dörfler 		ntfs_log_debug(FAILED);
919*80bca3d3SAxel Dörfler 		ntfs_log_error("Failed to read $UpCase, unexpected length "
920*80bca3d3SAxel Dörfler 			       "(%lld != %lld).\n", l, na->data_size);
921*80bca3d3SAxel Dörfler 		errno = EIO;
922*80bca3d3SAxel Dörfler 		goto error_exit;
923*80bca3d3SAxel Dörfler 	}
924*80bca3d3SAxel Dörfler 	/* Done with the $UpCase mft record. */
925*80bca3d3SAxel Dörfler 	ntfs_log_debug(OK);
926*80bca3d3SAxel Dörfler 	ntfs_attr_close(na);
927*80bca3d3SAxel Dörfler 	if (ntfs_inode_close(ni))
928*80bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to close inode, leaking memory");
929*80bca3d3SAxel Dörfler 
930*80bca3d3SAxel Dörfler 	/*
931*80bca3d3SAxel Dörfler 	 * Now load $Volume and set the version information and flags in the
932*80bca3d3SAxel Dörfler 	 * vol structure accordingly.
933*80bca3d3SAxel Dörfler 	 */
934*80bca3d3SAxel Dörfler 	ntfs_log_debug("Loading $Volume... ");
935*80bca3d3SAxel Dörfler 	vol->vol_ni = ntfs_inode_open(vol, FILE_Volume);
936*80bca3d3SAxel Dörfler 	if (!vol->vol_ni) {
937*80bca3d3SAxel Dörfler 		ntfs_log_debug(FAILED);
938*80bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to open inode");
939*80bca3d3SAxel Dörfler 		goto error_exit;
940*80bca3d3SAxel Dörfler 	}
941*80bca3d3SAxel Dörfler 	/* Get a search context for the $Volume/$VOLUME_INFORMATION lookup. */
942*80bca3d3SAxel Dörfler 	ctx = ntfs_attr_get_search_ctx(vol->vol_ni, NULL);
943*80bca3d3SAxel Dörfler 	if (!ctx) {
944*80bca3d3SAxel Dörfler 		ntfs_log_debug(FAILED);
945*80bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to allocate attribute search context");
946*80bca3d3SAxel Dörfler 		goto error_exit;
947*80bca3d3SAxel Dörfler 	}
948*80bca3d3SAxel Dörfler 	/* Find the $VOLUME_INFORMATION attribute. */
949*80bca3d3SAxel Dörfler 	if (ntfs_attr_lookup(AT_VOLUME_INFORMATION, AT_UNNAMED, 0, 0, 0, NULL,
950*80bca3d3SAxel Dörfler 			0, ctx)) {
951*80bca3d3SAxel Dörfler 		ntfs_log_debug(FAILED);
952*80bca3d3SAxel Dörfler 		ntfs_log_perror("$VOLUME_INFORMATION attribute not found in "
953*80bca3d3SAxel Dörfler 				"$Volume");
954*80bca3d3SAxel Dörfler 		goto error_exit;
955*80bca3d3SAxel Dörfler 	}
956*80bca3d3SAxel Dörfler 	a = ctx->attr;
957*80bca3d3SAxel Dörfler 	/* Has to be resident. */
958*80bca3d3SAxel Dörfler 	if (a->non_resident) {
959*80bca3d3SAxel Dörfler 		ntfs_log_debug(FAILED);
960*80bca3d3SAxel Dörfler 		ntfs_log_error("Attribute $VOLUME_INFORMATION must be "
961*80bca3d3SAxel Dörfler 			       "resident but it isn't.\n");
962*80bca3d3SAxel Dörfler 		errno = EIO;
963*80bca3d3SAxel Dörfler 		goto error_exit;
964*80bca3d3SAxel Dörfler 	}
965*80bca3d3SAxel Dörfler 	/* Get a pointer to the value of the attribute. */
966*80bca3d3SAxel Dörfler 	vinf = (VOLUME_INFORMATION*)(le16_to_cpu(a->value_offset) + (char*)a);
967*80bca3d3SAxel Dörfler 	/* Sanity checks. */
968*80bca3d3SAxel Dörfler 	if ((char*)vinf + le32_to_cpu(a->value_length) > (char*)ctx->mrec +
969*80bca3d3SAxel Dörfler 			le32_to_cpu(ctx->mrec->bytes_in_use) ||
970*80bca3d3SAxel Dörfler 			le16_to_cpu(a->value_offset) + le32_to_cpu(
971*80bca3d3SAxel Dörfler 			a->value_length) > le32_to_cpu(a->length)) {
972*80bca3d3SAxel Dörfler 		ntfs_log_debug(FAILED);
973*80bca3d3SAxel Dörfler 		ntfs_log_error("$VOLUME_INFORMATION in $Volume is corrupt.\n");
974*80bca3d3SAxel Dörfler 		errno = EIO;
975*80bca3d3SAxel Dörfler 		goto error_exit;
976*80bca3d3SAxel Dörfler 	}
977*80bca3d3SAxel Dörfler 	/* Setup vol from the volume information attribute value. */
978*80bca3d3SAxel Dörfler 	vol->major_ver = vinf->major_ver;
979*80bca3d3SAxel Dörfler 	vol->minor_ver = vinf->minor_ver;
980*80bca3d3SAxel Dörfler 	/* Do not use le16_to_cpu() macro here as our VOLUME_FLAGS are
981*80bca3d3SAxel Dörfler 	   defined using cpu_to_le16() macro and hence are consistent. */
982*80bca3d3SAxel Dörfler 	vol->flags = vinf->flags;
983*80bca3d3SAxel Dörfler 	/*
984*80bca3d3SAxel Dörfler 	 * Reinitialize the search context for the $Volume/$VOLUME_NAME lookup.
985*80bca3d3SAxel Dörfler 	 */
986*80bca3d3SAxel Dörfler 	ntfs_attr_reinit_search_ctx(ctx);
987*80bca3d3SAxel Dörfler 	if (ntfs_attr_lookup(AT_VOLUME_NAME, AT_UNNAMED, 0, 0, 0, NULL, 0,
988*80bca3d3SAxel Dörfler 			ctx)) {
989*80bca3d3SAxel Dörfler 		if (errno != ENOENT) {
990*80bca3d3SAxel Dörfler 			ntfs_log_debug(FAILED);
991*80bca3d3SAxel Dörfler 			ntfs_log_perror("Failed to lookup of $VOLUME_NAME in "
992*80bca3d3SAxel Dörfler 					"$Volume failed");
993*80bca3d3SAxel Dörfler 			goto error_exit;
994*80bca3d3SAxel Dörfler 		}
995*80bca3d3SAxel Dörfler 		/*
996*80bca3d3SAxel Dörfler 		 * Attribute not present.  This has been seen in the field.
997*80bca3d3SAxel Dörfler 		 * Treat this the same way as if the attribute was present but
998*80bca3d3SAxel Dörfler 		 * had zero length.
999*80bca3d3SAxel Dörfler 		 */
1000*80bca3d3SAxel Dörfler 		vol->vol_name = ntfs_malloc(1);
1001*80bca3d3SAxel Dörfler 		if (!vol->vol_name) {
1002*80bca3d3SAxel Dörfler 			ntfs_log_debug(FAILED);
1003*80bca3d3SAxel Dörfler 			goto error_exit;
1004*80bca3d3SAxel Dörfler 		}
1005*80bca3d3SAxel Dörfler 		vol->vol_name[0] = '\0';
1006*80bca3d3SAxel Dörfler 	} else {
1007*80bca3d3SAxel Dörfler 		a = ctx->attr;
1008*80bca3d3SAxel Dörfler 		/* Has to be resident. */
1009*80bca3d3SAxel Dörfler 		if (a->non_resident) {
1010*80bca3d3SAxel Dörfler 			ntfs_log_debug(FAILED);
1011*80bca3d3SAxel Dörfler 			ntfs_log_error("$VOLUME_NAME must be resident.\n");
1012*80bca3d3SAxel Dörfler 			errno = EIO;
1013*80bca3d3SAxel Dörfler 			goto error_exit;
1014*80bca3d3SAxel Dörfler 		}
1015*80bca3d3SAxel Dörfler 		/* Get a pointer to the value of the attribute. */
1016*80bca3d3SAxel Dörfler 		vname = (ntfschar*)(le16_to_cpu(a->value_offset) + (char*)a);
1017*80bca3d3SAxel Dörfler 		u = le32_to_cpu(a->value_length) / 2;
1018*80bca3d3SAxel Dörfler 		/*
1019*80bca3d3SAxel Dörfler 		 * Convert Unicode volume name to current locale multibyte
1020*80bca3d3SAxel Dörfler 		 * format.
1021*80bca3d3SAxel Dörfler 		 */
1022*80bca3d3SAxel Dörfler 		vol->vol_name = NULL;
1023*80bca3d3SAxel Dörfler 		if (ntfs_ucstombs(vname, u, &vol->vol_name, 0) == -1) {
1024*80bca3d3SAxel Dörfler 			ntfs_log_perror("Volume name could not be converted "
1025*80bca3d3SAxel Dörfler 					"to current locale");
1026*80bca3d3SAxel Dörfler 			ntfs_log_debug("Forcing name into ASCII by replacing "
1027*80bca3d3SAxel Dörfler 				"non-ASCII characters with underscores.\n");
1028*80bca3d3SAxel Dörfler 			vol->vol_name = ntfs_malloc(u + 1);
1029*80bca3d3SAxel Dörfler 			if (!vol->vol_name) {
1030*80bca3d3SAxel Dörfler 				ntfs_log_debug(FAILED);
1031*80bca3d3SAxel Dörfler 				goto error_exit;
1032*80bca3d3SAxel Dörfler 			}
1033*80bca3d3SAxel Dörfler 			for (j = 0; j < (s32)u; j++) {
1034*80bca3d3SAxel Dörfler 				ntfschar uc = le16_to_cpu(vname[j]);
1035*80bca3d3SAxel Dörfler 				if (uc > 0xff)
1036*80bca3d3SAxel Dörfler 					uc = (ntfschar)'_';
1037*80bca3d3SAxel Dörfler 				vol->vol_name[j] = (char)uc;
1038*80bca3d3SAxel Dörfler 			}
1039*80bca3d3SAxel Dörfler 			vol->vol_name[u] = '\0';
1040*80bca3d3SAxel Dörfler 		}
1041*80bca3d3SAxel Dörfler 	}
1042*80bca3d3SAxel Dörfler 	ntfs_log_debug(OK);
1043*80bca3d3SAxel Dörfler 	ntfs_attr_put_search_ctx(ctx);
1044*80bca3d3SAxel Dörfler 	ctx = NULL;
1045*80bca3d3SAxel Dörfler 	/* Now load the attribute definitions from $AttrDef. */
1046*80bca3d3SAxel Dörfler 	ntfs_log_debug("Loading $AttrDef... ");
1047*80bca3d3SAxel Dörfler 	ni = ntfs_inode_open(vol, FILE_AttrDef);
1048*80bca3d3SAxel Dörfler 	if (!ni) {
1049*80bca3d3SAxel Dörfler 		ntfs_log_debug(FAILED);
1050*80bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to open $AttrDef");
1051*80bca3d3SAxel Dörfler 		goto error_exit;
1052*80bca3d3SAxel Dörfler 	}
1053*80bca3d3SAxel Dörfler 	/* Get an ntfs attribute for $AttrDef/$DATA. */
1054*80bca3d3SAxel Dörfler 	na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
1055*80bca3d3SAxel Dörfler 	if (!na) {
1056*80bca3d3SAxel Dörfler 		ntfs_log_debug(FAILED);
1057*80bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to open ntfs attribute");
1058*80bca3d3SAxel Dörfler 		goto error_exit;
1059*80bca3d3SAxel Dörfler 	}
1060*80bca3d3SAxel Dörfler 	/* Check we don't overflow 32-bits. */
1061*80bca3d3SAxel Dörfler 	if (na->data_size > 0xffffffffLL) {
1062*80bca3d3SAxel Dörfler 		ntfs_log_debug(FAILED);
1063*80bca3d3SAxel Dörfler 		ntfs_log_error("Attribute definition table is too big (max "
1064*80bca3d3SAxel Dörfler 			       "32-bit allowed).\n");
1065*80bca3d3SAxel Dörfler 		errno = EINVAL;
1066*80bca3d3SAxel Dörfler 		goto error_exit;
1067*80bca3d3SAxel Dörfler 	}
1068*80bca3d3SAxel Dörfler 	vol->attrdef_len = na->data_size;
1069*80bca3d3SAxel Dörfler 	vol->attrdef = ntfs_malloc(na->data_size);
1070*80bca3d3SAxel Dörfler 	if (!vol->attrdef) {
1071*80bca3d3SAxel Dörfler 		ntfs_log_debug(FAILED);
1072*80bca3d3SAxel Dörfler 		goto error_exit;
1073*80bca3d3SAxel Dörfler 	}
1074*80bca3d3SAxel Dörfler 	/* Read in the $DATA attribute value into the buffer. */
1075*80bca3d3SAxel Dörfler 	l = ntfs_attr_pread(na, 0, na->data_size, vol->attrdef);
1076*80bca3d3SAxel Dörfler 	if (l != na->data_size) {
1077*80bca3d3SAxel Dörfler 		ntfs_log_debug(FAILED);
1078*80bca3d3SAxel Dörfler 		ntfs_log_error("Failed to read $AttrDef, unexpected length "
1079*80bca3d3SAxel Dörfler 			       "(%lld != %lld).\n", l, na->data_size);
1080*80bca3d3SAxel Dörfler 		errno = EIO;
1081*80bca3d3SAxel Dörfler 		goto error_exit;
1082*80bca3d3SAxel Dörfler 	}
1083*80bca3d3SAxel Dörfler 	/* Done with the $AttrDef mft record. */
1084*80bca3d3SAxel Dörfler 	ntfs_log_debug(OK);
1085*80bca3d3SAxel Dörfler 	ntfs_attr_close(na);
1086*80bca3d3SAxel Dörfler 	if (ntfs_inode_close(ni))
1087*80bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to close inode, leaking memory");
1088*80bca3d3SAxel Dörfler 	/*
1089*80bca3d3SAxel Dörfler 	 * Check for dirty logfile and hibernated Windows.
1090*80bca3d3SAxel Dörfler 	 * We care only about read-write mounts.
1091*80bca3d3SAxel Dörfler 	 */
1092*80bca3d3SAxel Dörfler 	if (!(flags & MS_RDONLY)) {
1093*80bca3d3SAxel Dörfler 		if (ntfs_volume_check_logfile(vol) < 0)
1094*80bca3d3SAxel Dörfler 			goto error_exit;
1095*80bca3d3SAxel Dörfler 		if (ntfs_volume_check_hiberfile(vol) < 0)
1096*80bca3d3SAxel Dörfler 			goto error_exit;
1097*80bca3d3SAxel Dörfler 	}
1098*80bca3d3SAxel Dörfler 
1099*80bca3d3SAxel Dörfler 	return vol;
1100*80bca3d3SAxel Dörfler io_error_exit:
1101*80bca3d3SAxel Dörfler 	errno = EIO;
1102*80bca3d3SAxel Dörfler error_exit:
1103*80bca3d3SAxel Dörfler 	eo = errno;
1104*80bca3d3SAxel Dörfler 	if (ctx)
1105*80bca3d3SAxel Dörfler 		ntfs_attr_put_search_ctx(ctx);
1106*80bca3d3SAxel Dörfler 	free(m);
1107*80bca3d3SAxel Dörfler 	free(m2);
1108*80bca3d3SAxel Dörfler 	__ntfs_volume_release(vol);
1109*80bca3d3SAxel Dörfler 	errno = eo;
1110*80bca3d3SAxel Dörfler 	return NULL;
1111*80bca3d3SAxel Dörfler }
1112*80bca3d3SAxel Dörfler 
1113*80bca3d3SAxel Dörfler /**
1114*80bca3d3SAxel Dörfler  * ntfs_mount - open ntfs volume
1115*80bca3d3SAxel Dörfler  * @name:	name of device/file to open
1116*80bca3d3SAxel Dörfler  * @flags:	optional mount flags
1117*80bca3d3SAxel Dörfler  *
1118*80bca3d3SAxel Dörfler  * This function mounts an ntfs volume. @name should contain the name of the
1119*80bca3d3SAxel Dörfler  * device/file to mount as the ntfs volume.
1120*80bca3d3SAxel Dörfler  *
1121*80bca3d3SAxel Dörfler  * @flags is an optional second parameter. The same flags are used as for
1122*80bca3d3SAxel Dörfler  * the mount system call (man 2 mount). Currently only the following flags
1123*80bca3d3SAxel Dörfler  * are implemented:
1124*80bca3d3SAxel Dörfler  *	MS_RDONLY	- mount volume read-only
1125*80bca3d3SAxel Dörfler  *	MS_NOATIME	- do not update access time
1126*80bca3d3SAxel Dörfler  *
1127*80bca3d3SAxel Dörfler  * The function opens the device or file @name and verifies that it contains a
1128*80bca3d3SAxel Dörfler  * valid bootsector. Then, it allocates an ntfs_volume structure and initializes
1129*80bca3d3SAxel Dörfler  * some of the values inside the structure from the information stored in the
1130*80bca3d3SAxel Dörfler  * bootsector. It proceeds to load the necessary system files and completes
1131*80bca3d3SAxel Dörfler  * setting up the structure.
1132*80bca3d3SAxel Dörfler  *
1133*80bca3d3SAxel Dörfler  * Return the allocated volume structure on success and NULL on error with
1134*80bca3d3SAxel Dörfler  * errno set to the error code.
1135*80bca3d3SAxel Dörfler  *
1136*80bca3d3SAxel Dörfler  * Note, that a copy is made of @name, and hence it can be discarded as
1137*80bca3d3SAxel Dörfler  * soon as the function returns.
1138*80bca3d3SAxel Dörfler  */
1139*80bca3d3SAxel Dörfler ntfs_volume *ntfs_mount(const char *name __attribute__((unused)),
1140*80bca3d3SAxel Dörfler 		unsigned long flags __attribute__((unused)))
1141*80bca3d3SAxel Dörfler {
1142*80bca3d3SAxel Dörfler #ifndef NO_NTFS_DEVICE_DEFAULT_IO_OPS
1143*80bca3d3SAxel Dörfler 	struct ntfs_device *dev;
1144*80bca3d3SAxel Dörfler 	ntfs_volume *vol;
1145*80bca3d3SAxel Dörfler 
1146*80bca3d3SAxel Dörfler 	/* Allocate an ntfs_device structure. */
1147*80bca3d3SAxel Dörfler 	dev = ntfs_device_alloc(name, 0, &ntfs_device_default_io_ops, NULL);
1148*80bca3d3SAxel Dörfler 	if (!dev)
1149*80bca3d3SAxel Dörfler 		return NULL;
1150*80bca3d3SAxel Dörfler 	/* Call ntfs_device_mount() to do the actual mount. */
1151*80bca3d3SAxel Dörfler 	vol = ntfs_device_mount(dev, flags);
1152*80bca3d3SAxel Dörfler 	if (!vol) {
1153*80bca3d3SAxel Dörfler 		int eo = errno;
1154*80bca3d3SAxel Dörfler 		ntfs_device_free(dev);
1155*80bca3d3SAxel Dörfler 		errno = eo;
1156*80bca3d3SAxel Dörfler 	}
1157*80bca3d3SAxel Dörfler 	return vol;
1158*80bca3d3SAxel Dörfler #else
1159*80bca3d3SAxel Dörfler 	/*
1160*80bca3d3SAxel Dörfler 	 * ntfs_mount() makes no sense if NO_NTFS_DEVICE_DEFAULT_IO_OPS is
1161*80bca3d3SAxel Dörfler 	 * defined as there are no device operations available in libntfs in
1162*80bca3d3SAxel Dörfler 	 * this case.
1163*80bca3d3SAxel Dörfler 	 */
1164*80bca3d3SAxel Dörfler 	errno = EOPNOTSUPP;
1165*80bca3d3SAxel Dörfler 	return NULL;
1166*80bca3d3SAxel Dörfler #endif
1167*80bca3d3SAxel Dörfler }
1168*80bca3d3SAxel Dörfler 
1169*80bca3d3SAxel Dörfler /**
1170*80bca3d3SAxel Dörfler  * ntfs_device_umount - close ntfs volume
1171*80bca3d3SAxel Dörfler  * @vol: address of ntfs_volume structure of volume to close
1172*80bca3d3SAxel Dörfler  * @force: if true force close the volume even if it is busy
1173*80bca3d3SAxel Dörfler  *
1174*80bca3d3SAxel Dörfler  * Deallocate all structures (including @vol itself) associated with the ntfs
1175*80bca3d3SAxel Dörfler  * volume @vol.
1176*80bca3d3SAxel Dörfler  *
1177*80bca3d3SAxel Dörfler  * Note it is up to the caller to destroy the device associated with the volume
1178*80bca3d3SAxel Dörfler  * being unmounted after this function returns.
1179*80bca3d3SAxel Dörfler  *
1180*80bca3d3SAxel Dörfler  * Return 0 on success. On error return -1 with errno set appropriately
1181*80bca3d3SAxel Dörfler  * (most likely to one of EAGAIN, EBUSY or EINVAL). The EAGAIN error means that
1182*80bca3d3SAxel Dörfler  * an operation is in progress and if you try the close later the operation
1183*80bca3d3SAxel Dörfler  * might be completed and the close succeed.
1184*80bca3d3SAxel Dörfler  *
1185*80bca3d3SAxel Dörfler  * If @force is true (i.e. not zero) this function will close the volume even
1186*80bca3d3SAxel Dörfler  * if this means that data might be lost.
1187*80bca3d3SAxel Dörfler  *
1188*80bca3d3SAxel Dörfler  * @vol must have previously been returned by a call to ntfs_device_mount().
1189*80bca3d3SAxel Dörfler  *
1190*80bca3d3SAxel Dörfler  * @vol itself is deallocated and should no longer be dereferenced after this
1191*80bca3d3SAxel Dörfler  * function returns success. If it returns an error then nothing has been done
1192*80bca3d3SAxel Dörfler  * so it is safe to continue using @vol.
1193*80bca3d3SAxel Dörfler  */
1194*80bca3d3SAxel Dörfler int ntfs_device_umount(ntfs_volume *vol,
1195*80bca3d3SAxel Dörfler 		const BOOL force __attribute__((unused)))
1196*80bca3d3SAxel Dörfler {
1197*80bca3d3SAxel Dörfler 	if (!vol) {
1198*80bca3d3SAxel Dörfler 		errno = EINVAL;
1199*80bca3d3SAxel Dörfler 		return -1;
1200*80bca3d3SAxel Dörfler 	}
1201*80bca3d3SAxel Dörfler 	__ntfs_volume_release(vol);
1202*80bca3d3SAxel Dörfler 	return 0;
1203*80bca3d3SAxel Dörfler }
1204*80bca3d3SAxel Dörfler 
1205*80bca3d3SAxel Dörfler /**
1206*80bca3d3SAxel Dörfler  * ntfs_umount - close ntfs volume
1207*80bca3d3SAxel Dörfler  * @vol: address of ntfs_volume structure of volume to close
1208*80bca3d3SAxel Dörfler  * @force: if true force close the volume even if it is busy
1209*80bca3d3SAxel Dörfler  *
1210*80bca3d3SAxel Dörfler  * Deallocate all structures (including @vol itself) associated with the ntfs
1211*80bca3d3SAxel Dörfler  * volume @vol.
1212*80bca3d3SAxel Dörfler  *
1213*80bca3d3SAxel Dörfler  * Return 0 on success. On error return -1 with errno set appropriately
1214*80bca3d3SAxel Dörfler  * (most likely to one of EAGAIN, EBUSY or EINVAL). The EAGAIN error means that
1215*80bca3d3SAxel Dörfler  * an operation is in progress and if you try the close later the operation
1216*80bca3d3SAxel Dörfler  * might be completed and the close succeed.
1217*80bca3d3SAxel Dörfler  *
1218*80bca3d3SAxel Dörfler  * If @force is true (i.e. not zero) this function will close the volume even
1219*80bca3d3SAxel Dörfler  * if this means that data might be lost.
1220*80bca3d3SAxel Dörfler  *
1221*80bca3d3SAxel Dörfler  * @vol must have previously been returned by a call to ntfs_mount().
1222*80bca3d3SAxel Dörfler  *
1223*80bca3d3SAxel Dörfler  * @vol itself is deallocated and should no longer be dereferenced after this
1224*80bca3d3SAxel Dörfler  * function returns success. If it returns an error then nothing has been done
1225*80bca3d3SAxel Dörfler  * so it is safe to continue using @vol.
1226*80bca3d3SAxel Dörfler  */
1227*80bca3d3SAxel Dörfler int ntfs_umount(ntfs_volume *vol,
1228*80bca3d3SAxel Dörfler 		const BOOL force __attribute__((unused)))
1229*80bca3d3SAxel Dörfler {
1230*80bca3d3SAxel Dörfler 	struct ntfs_device *dev;
1231*80bca3d3SAxel Dörfler 
1232*80bca3d3SAxel Dörfler 	if (!vol) {
1233*80bca3d3SAxel Dörfler 		errno = EINVAL;
1234*80bca3d3SAxel Dörfler 		return -1;
1235*80bca3d3SAxel Dörfler 	}
1236*80bca3d3SAxel Dörfler 	dev = vol->dev;
1237*80bca3d3SAxel Dörfler 	__ntfs_volume_release(vol);
1238*80bca3d3SAxel Dörfler 	ntfs_device_free(dev);
1239*80bca3d3SAxel Dörfler 	return 0;
1240*80bca3d3SAxel Dörfler }
1241*80bca3d3SAxel Dörfler 
1242*80bca3d3SAxel Dörfler #ifdef HAVE_MNTENT_H
1243*80bca3d3SAxel Dörfler 
1244*80bca3d3SAxel Dörfler #ifndef HAVE_REALPATH
1245*80bca3d3SAxel Dörfler /**
1246*80bca3d3SAxel Dörfler  * realpath - If there is no realpath on the system
1247*80bca3d3SAxel Dörfler  */
1248*80bca3d3SAxel Dörfler static char *realpath(const char *path, char *resolved_path)
1249*80bca3d3SAxel Dörfler {
1250*80bca3d3SAxel Dörfler 	strncpy(resolved_path, path, PATH_MAX);
1251*80bca3d3SAxel Dörfler 	resolved_path[PATH_MAX] = '\0';
1252*80bca3d3SAxel Dörfler 	return resolved_path;
1253*80bca3d3SAxel Dörfler }
1254*80bca3d3SAxel Dörfler #endif
1255*80bca3d3SAxel Dörfler 
1256*80bca3d3SAxel Dörfler /**
1257*80bca3d3SAxel Dörfler  * ntfs_mntent_check - desc
1258*80bca3d3SAxel Dörfler  *
1259*80bca3d3SAxel Dörfler  * If you are wanting to use this, you actually wanted to use
1260*80bca3d3SAxel Dörfler  * ntfs_check_if_mounted(), you just didn't realize. (-:
1261*80bca3d3SAxel Dörfler  *
1262*80bca3d3SAxel Dörfler  * See description of ntfs_check_if_mounted(), below.
1263*80bca3d3SAxel Dörfler  */
1264*80bca3d3SAxel Dörfler static int ntfs_mntent_check(const char *file, unsigned long *mnt_flags)
1265*80bca3d3SAxel Dörfler {
1266*80bca3d3SAxel Dörfler 	struct mntent *mnt;
1267*80bca3d3SAxel Dörfler 	char *real_file = NULL, *real_fsname = NULL;
1268*80bca3d3SAxel Dörfler 	FILE *f;
1269*80bca3d3SAxel Dörfler 	int err = 0;
1270*80bca3d3SAxel Dörfler 
1271*80bca3d3SAxel Dörfler 	real_file = ntfs_malloc(PATH_MAX + 1);
1272*80bca3d3SAxel Dörfler 	if (!real_file)
1273*80bca3d3SAxel Dörfler 		return -1;
1274*80bca3d3SAxel Dörfler 	real_fsname = ntfs_malloc(PATH_MAX + 1);
1275*80bca3d3SAxel Dörfler 	if (!real_fsname) {
1276*80bca3d3SAxel Dörfler 		err = errno;
1277*80bca3d3SAxel Dörfler 		goto exit;
1278*80bca3d3SAxel Dörfler 	}
1279*80bca3d3SAxel Dörfler 	if (!realpath(file, real_file)) {
1280*80bca3d3SAxel Dörfler 		err = errno;
1281*80bca3d3SAxel Dörfler 		goto exit;
1282*80bca3d3SAxel Dörfler 	}
1283*80bca3d3SAxel Dörfler 	if (!(f = setmntent(MOUNTED, "r"))) {
1284*80bca3d3SAxel Dörfler 		err = errno;
1285*80bca3d3SAxel Dörfler 		goto exit;
1286*80bca3d3SAxel Dörfler 	}
1287*80bca3d3SAxel Dörfler 	while ((mnt = getmntent(f))) {
1288*80bca3d3SAxel Dörfler 		if (!realpath(mnt->mnt_fsname, real_fsname))
1289*80bca3d3SAxel Dörfler 			continue;
1290*80bca3d3SAxel Dörfler 		if (!strcmp(real_file, real_fsname))
1291*80bca3d3SAxel Dörfler 			break;
1292*80bca3d3SAxel Dörfler 	}
1293*80bca3d3SAxel Dörfler 	endmntent(f);
1294*80bca3d3SAxel Dörfler 	if (!mnt)
1295*80bca3d3SAxel Dörfler 		goto exit;
1296*80bca3d3SAxel Dörfler 	*mnt_flags = NTFS_MF_MOUNTED;
1297*80bca3d3SAxel Dörfler 	if (!strcmp(mnt->mnt_dir, "/"))
1298*80bca3d3SAxel Dörfler 		*mnt_flags |= NTFS_MF_ISROOT;
1299*80bca3d3SAxel Dörfler #ifdef HAVE_HASMNTOPT
1300*80bca3d3SAxel Dörfler 	if (hasmntopt(mnt, "ro") && !hasmntopt(mnt, "rw"))
1301*80bca3d3SAxel Dörfler 		*mnt_flags |= NTFS_MF_READONLY;
1302*80bca3d3SAxel Dörfler #endif
1303*80bca3d3SAxel Dörfler exit:
1304*80bca3d3SAxel Dörfler 	free(real_file);
1305*80bca3d3SAxel Dörfler 	free(real_fsname);
1306*80bca3d3SAxel Dörfler 	if (err) {
1307*80bca3d3SAxel Dörfler 		errno = err;
1308*80bca3d3SAxel Dörfler 		return -1;
1309*80bca3d3SAxel Dörfler 	}
1310*80bca3d3SAxel Dörfler 	return 0;
1311*80bca3d3SAxel Dörfler }
1312*80bca3d3SAxel Dörfler #endif /* HAVE_MNTENT_H */
1313*80bca3d3SAxel Dörfler 
1314*80bca3d3SAxel Dörfler /**
1315*80bca3d3SAxel Dörfler  * ntfs_check_if_mounted - check if an ntfs volume is currently mounted
1316*80bca3d3SAxel Dörfler  * @file:	device file to check
1317*80bca3d3SAxel Dörfler  * @mnt_flags:	pointer into which to return the ntfs mount flags (see volume.h)
1318*80bca3d3SAxel Dörfler  *
1319*80bca3d3SAxel Dörfler  * If the running system does not support the {set,get,end}mntent() calls,
1320*80bca3d3SAxel Dörfler  * just return 0 and set *@mnt_flags to zero.
1321*80bca3d3SAxel Dörfler  *
1322*80bca3d3SAxel Dörfler  * When the system does support the calls, ntfs_check_if_mounted() first tries
1323*80bca3d3SAxel Dörfler  * to find the device @file in /etc/mtab (or wherever this is kept on the
1324*80bca3d3SAxel Dörfler  * running system). If it is not found, assume the device is not mounted and
1325*80bca3d3SAxel Dörfler  * return 0 and set *@mnt_flags to zero.
1326*80bca3d3SAxel Dörfler  *
1327*80bca3d3SAxel Dörfler  * If the device @file is found, set the NTFS_MF_MOUNTED flags in *@mnt_flags.
1328*80bca3d3SAxel Dörfler  *
1329*80bca3d3SAxel Dörfler  * Further if @file is mounted as the file system root ("/"), set the flag
1330*80bca3d3SAxel Dörfler  * NTFS_MF_ISROOT in *@mnt_flags.
1331*80bca3d3SAxel Dörfler  *
1332*80bca3d3SAxel Dörfler  * Finally, check if the file system is mounted read-only, and if so set the
1333*80bca3d3SAxel Dörfler  * NTFS_MF_READONLY flag in *@mnt_flags.
1334*80bca3d3SAxel Dörfler  *
1335*80bca3d3SAxel Dörfler  * On success return 0 with *@mnt_flags set to the ntfs mount flags.
1336*80bca3d3SAxel Dörfler  *
1337*80bca3d3SAxel Dörfler  * On error return -1 with errno set to the error code.
1338*80bca3d3SAxel Dörfler  */
1339*80bca3d3SAxel Dörfler int ntfs_check_if_mounted(const char *file __attribute__((unused)),
1340*80bca3d3SAxel Dörfler 		unsigned long *mnt_flags)
1341*80bca3d3SAxel Dörfler {
1342*80bca3d3SAxel Dörfler 	*mnt_flags = 0;
1343*80bca3d3SAxel Dörfler #ifdef HAVE_MNTENT_H
1344*80bca3d3SAxel Dörfler 	return ntfs_mntent_check(file, mnt_flags);
1345*80bca3d3SAxel Dörfler #else
1346*80bca3d3SAxel Dörfler 	return 0;
1347*80bca3d3SAxel Dörfler #endif
1348*80bca3d3SAxel Dörfler }
1349*80bca3d3SAxel Dörfler 
1350*80bca3d3SAxel Dörfler /**
1351*80bca3d3SAxel Dörfler  * ntfs_version_is_supported - check if NTFS version is supported.
1352*80bca3d3SAxel Dörfler  * @vol:	ntfs volume whose version we're interested in.
1353*80bca3d3SAxel Dörfler  *
1354*80bca3d3SAxel Dörfler  * The function checks if the NTFS volume version is known or not.
1355*80bca3d3SAxel Dörfler  * Version 1.1 and 1.2 are used by Windows NT3.x and NT4.
1356*80bca3d3SAxel Dörfler  * Version 2.x is used by Windows 2000 Betas.
1357*80bca3d3SAxel Dörfler  * Version 3.0 is used by Windows 2000.
1358*80bca3d3SAxel Dörfler  * Version 3.1 is used by Windows XP, Windows Server 2003 and Longhorn.
1359*80bca3d3SAxel Dörfler  *
1360*80bca3d3SAxel Dörfler  * Return 0 if NTFS version is supported otherwise -1 with errno set.
1361*80bca3d3SAxel Dörfler  *
1362*80bca3d3SAxel Dörfler  * The following error codes are defined:
1363*80bca3d3SAxel Dörfler  *	EOPNOTSUPP - Unknown NTFS version
1364*80bca3d3SAxel Dörfler  *	EINVAL	   - Invalid argument
1365*80bca3d3SAxel Dörfler  */
1366*80bca3d3SAxel Dörfler int ntfs_version_is_supported(ntfs_volume *vol)
1367*80bca3d3SAxel Dörfler {
1368*80bca3d3SAxel Dörfler 	u8 major, minor;
1369*80bca3d3SAxel Dörfler 
1370*80bca3d3SAxel Dörfler 	if (!vol) {
1371*80bca3d3SAxel Dörfler 		errno = EINVAL;
1372*80bca3d3SAxel Dörfler 		return -1;
1373*80bca3d3SAxel Dörfler 	}
1374*80bca3d3SAxel Dörfler 
1375*80bca3d3SAxel Dörfler 	major = vol->major_ver;
1376*80bca3d3SAxel Dörfler 	minor = vol->minor_ver;
1377*80bca3d3SAxel Dörfler 
1378*80bca3d3SAxel Dörfler 	if (NTFS_V1_1(major, minor) || NTFS_V1_2(major, minor))
1379*80bca3d3SAxel Dörfler 		return 0;
1380*80bca3d3SAxel Dörfler 
1381*80bca3d3SAxel Dörfler 	if (NTFS_V2_X(major, minor))
1382*80bca3d3SAxel Dörfler 		return 0;
1383*80bca3d3SAxel Dörfler 
1384*80bca3d3SAxel Dörfler 	if (NTFS_V3_0(major, minor) || NTFS_V3_1(major, minor))
1385*80bca3d3SAxel Dörfler 		return 0;
1386*80bca3d3SAxel Dörfler 
1387*80bca3d3SAxel Dörfler 	errno = EOPNOTSUPP;
1388*80bca3d3SAxel Dörfler 	return -1;
1389*80bca3d3SAxel Dörfler }
1390*80bca3d3SAxel Dörfler 
1391*80bca3d3SAxel Dörfler /**
1392*80bca3d3SAxel Dörfler  * ntfs_logfile_reset - "empty" $LogFile data attribute value
1393*80bca3d3SAxel Dörfler  * @vol:	ntfs volume whose $LogFile we intend to reset.
1394*80bca3d3SAxel Dörfler  *
1395*80bca3d3SAxel Dörfler  * Fill the value of the $LogFile data attribute, i.e. the contents of
1396*80bca3d3SAxel Dörfler  * the file, with 0xff's, thus marking the journal as empty.
1397*80bca3d3SAxel Dörfler  *
1398*80bca3d3SAxel Dörfler  * FIXME(?): We might need to zero the LSN field of every single mft
1399*80bca3d3SAxel Dörfler  * record as well. (But, first try without doing that and see what
1400*80bca3d3SAxel Dörfler  * happens, since chkdsk might pickup the pieces and do it for us...)
1401*80bca3d3SAxel Dörfler  *
1402*80bca3d3SAxel Dörfler  * On success return 0.
1403*80bca3d3SAxel Dörfler  *
1404*80bca3d3SAxel Dörfler  * On error return -1 with errno set to the error code.
1405*80bca3d3SAxel Dörfler  */
1406*80bca3d3SAxel Dörfler int ntfs_logfile_reset(ntfs_volume *vol)
1407*80bca3d3SAxel Dörfler {
1408*80bca3d3SAxel Dörfler 	ntfs_inode *ni;
1409*80bca3d3SAxel Dörfler 	ntfs_attr *na;
1410*80bca3d3SAxel Dörfler 	int eo;
1411*80bca3d3SAxel Dörfler 
1412*80bca3d3SAxel Dörfler 	if (!vol) {
1413*80bca3d3SAxel Dörfler 		errno = EINVAL;
1414*80bca3d3SAxel Dörfler 		return -1;
1415*80bca3d3SAxel Dörfler 	}
1416*80bca3d3SAxel Dörfler 
1417*80bca3d3SAxel Dörfler 	if ((ni = ntfs_inode_open(vol, FILE_LogFile)) == NULL) {
1418*80bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to open inode FILE_LogFile.");
1419*80bca3d3SAxel Dörfler 		return -1;
1420*80bca3d3SAxel Dörfler 	}
1421*80bca3d3SAxel Dörfler 
1422*80bca3d3SAxel Dörfler 	if ((na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0)) == NULL) {
1423*80bca3d3SAxel Dörfler 		eo = errno;
1424*80bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to open $FILE_LogFile/$DATA");
1425*80bca3d3SAxel Dörfler 		goto error_exit;
1426*80bca3d3SAxel Dörfler 	}
1427*80bca3d3SAxel Dörfler 
1428*80bca3d3SAxel Dörfler 	if (ntfs_empty_logfile(na)) {
1429*80bca3d3SAxel Dörfler 		eo = errno;
1430*80bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to empty $FILE_LogFile/$DATA");
1431*80bca3d3SAxel Dörfler 		ntfs_attr_close(na);
1432*80bca3d3SAxel Dörfler 		goto error_exit;
1433*80bca3d3SAxel Dörfler 	}
1434*80bca3d3SAxel Dörfler 	ntfs_attr_close(na);
1435*80bca3d3SAxel Dörfler 	return ntfs_inode_close(ni);
1436*80bca3d3SAxel Dörfler 
1437*80bca3d3SAxel Dörfler error_exit:
1438*80bca3d3SAxel Dörfler 	ntfs_inode_close(ni);
1439*80bca3d3SAxel Dörfler 	errno = eo;
1440*80bca3d3SAxel Dörfler 	return -1;
1441*80bca3d3SAxel Dörfler }
1442*80bca3d3SAxel Dörfler 
1443*80bca3d3SAxel Dörfler /**
1444*80bca3d3SAxel Dörfler  * ntfs_volume_write_flags - set the flags of an ntfs volume
1445*80bca3d3SAxel Dörfler  * @vol:	ntfs volume where we set the volume flags
1446*80bca3d3SAxel Dörfler  * @flags:	new flags
1447*80bca3d3SAxel Dörfler  *
1448*80bca3d3SAxel Dörfler  * Set the on-disk volume flags in the mft record of $Volume and
1449*80bca3d3SAxel Dörfler  * on volume @vol to @flags.
1450*80bca3d3SAxel Dörfler  *
1451*80bca3d3SAxel Dörfler  * Return 0 if successful and -1 if not with errno set to the error code.
1452*80bca3d3SAxel Dörfler  */
1453*80bca3d3SAxel Dörfler int ntfs_volume_write_flags(ntfs_volume *vol, const u16 flags)
1454*80bca3d3SAxel Dörfler {
1455*80bca3d3SAxel Dörfler 	ATTR_RECORD *a;
1456*80bca3d3SAxel Dörfler 	VOLUME_INFORMATION *c;
1457*80bca3d3SAxel Dörfler 	ntfs_attr_search_ctx *ctx;
1458*80bca3d3SAxel Dörfler 	int ret = -1;	/* failure */
1459*80bca3d3SAxel Dörfler 
1460*80bca3d3SAxel Dörfler 	if (!vol || !vol->vol_ni) {
1461*80bca3d3SAxel Dörfler 		errno = EINVAL;
1462*80bca3d3SAxel Dörfler 		return -1;
1463*80bca3d3SAxel Dörfler 	}
1464*80bca3d3SAxel Dörfler 	/* Get a pointer to the volume information attribute. */
1465*80bca3d3SAxel Dörfler 	ctx = ntfs_attr_get_search_ctx(vol->vol_ni, NULL);
1466*80bca3d3SAxel Dörfler 	if (!ctx) {
1467*80bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to allocate attribute search context");
1468*80bca3d3SAxel Dörfler 		return -1;
1469*80bca3d3SAxel Dörfler 	}
1470*80bca3d3SAxel Dörfler 	if (ntfs_attr_lookup(AT_VOLUME_INFORMATION, AT_UNNAMED, 0, 0, 0, NULL,
1471*80bca3d3SAxel Dörfler 			0, ctx)) {
1472*80bca3d3SAxel Dörfler 		ntfs_log_error("Attribute $VOLUME_INFORMATION was not found "
1473*80bca3d3SAxel Dörfler 			       "in $Volume!\n");
1474*80bca3d3SAxel Dörfler 		goto err_out;
1475*80bca3d3SAxel Dörfler 	}
1476*80bca3d3SAxel Dörfler 	a = ctx->attr;
1477*80bca3d3SAxel Dörfler 	/* Sanity check. */
1478*80bca3d3SAxel Dörfler 	if (a->non_resident) {
1479*80bca3d3SAxel Dörfler 		ntfs_log_error("Attribute $VOLUME_INFORMATION must be resident "
1480*80bca3d3SAxel Dörfler 			       "but it isn't.\n");
1481*80bca3d3SAxel Dörfler 		errno = EIO;
1482*80bca3d3SAxel Dörfler 		goto err_out;
1483*80bca3d3SAxel Dörfler 	}
1484*80bca3d3SAxel Dörfler 	/* Get a pointer to the value of the attribute. */
1485*80bca3d3SAxel Dörfler 	c = (VOLUME_INFORMATION*)(le16_to_cpu(a->value_offset) + (char*)a);
1486*80bca3d3SAxel Dörfler 	/* Sanity checks. */
1487*80bca3d3SAxel Dörfler 	if ((char*)c + le32_to_cpu(a->value_length) > (char*)ctx->mrec +
1488*80bca3d3SAxel Dörfler 			le32_to_cpu(ctx->mrec->bytes_in_use) ||
1489*80bca3d3SAxel Dörfler 			le16_to_cpu(a->value_offset) +
1490*80bca3d3SAxel Dörfler 			le32_to_cpu(a->value_length) > le32_to_cpu(a->length)) {
1491*80bca3d3SAxel Dörfler 		ntfs_log_error("Attribute $VOLUME_INFORMATION in $Volume is "
1492*80bca3d3SAxel Dörfler 			       "corrupt!\n");
1493*80bca3d3SAxel Dörfler 		errno = EIO;
1494*80bca3d3SAxel Dörfler 		goto err_out;
1495*80bca3d3SAxel Dörfler 	}
1496*80bca3d3SAxel Dörfler 	/* Set the volume flags. */
1497*80bca3d3SAxel Dörfler 	vol->flags = c->flags = flags & VOLUME_FLAGS_MASK;
1498*80bca3d3SAxel Dörfler 	/* Write them to disk. */
1499*80bca3d3SAxel Dörfler 	ntfs_inode_mark_dirty(vol->vol_ni);
1500*80bca3d3SAxel Dörfler 	if (ntfs_inode_sync(vol->vol_ni)) {
1501*80bca3d3SAxel Dörfler 		ntfs_log_perror("Error writing $Volume");
1502*80bca3d3SAxel Dörfler 		goto err_out;
1503*80bca3d3SAxel Dörfler 	}
1504*80bca3d3SAxel Dörfler 	ret = 0; /* success */
1505*80bca3d3SAxel Dörfler err_out:
1506*80bca3d3SAxel Dörfler 	ntfs_attr_put_search_ctx(ctx);
1507*80bca3d3SAxel Dörfler 	return ret;
1508*80bca3d3SAxel Dörfler }
1509*80bca3d3SAxel Dörfler 
1510