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