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
70const char *ntfs_home =
71"Ntfs-3g news, support and information:  http://ntfs-3g.org\n";
72
73static 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
78static 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
87static 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
96static 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
100static 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
105static 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
111static 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 */
123ntfs_volume *ntfs_volume_alloc(void)
124{
125	return ntfs_calloc(sizeof(ntfs_volume));
126}
127
128static void ntfs_attr_free(ntfs_attr **na)
129{
130	if (na && *na) {
131		ntfs_attr_close(*na);
132		*na = NULL;
133	}
134}
135
136static 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
148static 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 */
162static 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
209static 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 */
230static 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
298mft_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;
381io_error_exit:
382	errno = EIO;
383error_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 */
410static 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
433error_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 */
457ntfs_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;
591error_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 */
606static 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);
631out:
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 */
648static 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	}
686out:
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 */
706int 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;
750out:
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 */
783ntfs_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;
1114io_error_exit:
1115	errno = EIO;
1116error_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 */
1152ntfs_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 */
1204int 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 */
1225static 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 */
1241static 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
1280exit:
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 */
1316int 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 */
1343int 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 */
1383int 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
1416error_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 */
1432int 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 */
1482err_out:
1483	ntfs_attr_put_search_ctx(ctx);
1484	return ret;
1485}
1486
1487int 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
1524void 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
1551int ntfs_set_locale(void)
1552{
1553	const char *locale;
1554
1555	//locale = setlocale(LC_ALL, "");
1556	locale = NULL;
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	return 0;
1564}
1565
1566