xref: /haiku/src/add-ons/kernel/file_systems/ntfs/libntfs/volume.c (revision 30bc84e97110496a267b765a5a9090fc06ed7557)
180bca3d3SAxel Dörfler /**
280bca3d3SAxel Dörfler  * volume.c - NTFS volume handling code. Originated from the Linux-NTFS project.
380bca3d3SAxel Dörfler  *
480bca3d3SAxel Dörfler  * Copyright (c) 2000-2006 Anton Altaparmakov
5*30bc84e9SGerasim Troeglazov  * Copyright (c) 2002-2009 Szabolcs Szakacsits
680bca3d3SAxel Dörfler  * Copyright (c) 2004-2005 Richard Russon
780bca3d3SAxel Dörfler  *
880bca3d3SAxel Dörfler  * This program/include file is free software; you can redistribute it and/or
980bca3d3SAxel Dörfler  * modify it under the terms of the GNU General Public License as published
1080bca3d3SAxel Dörfler  * by the Free Software Foundation; either version 2 of the License, or
1180bca3d3SAxel Dörfler  * (at your option) any later version.
1280bca3d3SAxel Dörfler  *
1380bca3d3SAxel Dörfler  * This program/include file is distributed in the hope that it will be
1480bca3d3SAxel Dörfler  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
1580bca3d3SAxel Dörfler  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1680bca3d3SAxel Dörfler  * GNU General Public License for more details.
1780bca3d3SAxel Dörfler  *
1880bca3d3SAxel Dörfler  * You should have received a copy of the GNU General Public License
1980bca3d3SAxel Dörfler  * along with this program (in the main directory of the NTFS-3G
2080bca3d3SAxel Dörfler  * distribution in the file COPYING); if not, write to the Free Software
2180bca3d3SAxel Dörfler  * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
2280bca3d3SAxel Dörfler  */
2380bca3d3SAxel Dörfler 
2480bca3d3SAxel Dörfler #ifdef HAVE_CONFIG_H
2580bca3d3SAxel Dörfler #include "config.h"
2680bca3d3SAxel Dörfler #endif
2780bca3d3SAxel Dörfler 
2880bca3d3SAxel Dörfler #ifdef HAVE_STDLIB_H
2980bca3d3SAxel Dörfler #include <stdlib.h>
3080bca3d3SAxel Dörfler #endif
3180bca3d3SAxel Dörfler #ifdef HAVE_STDIO_H
3280bca3d3SAxel Dörfler #include <stdio.h>
3380bca3d3SAxel Dörfler #endif
3480bca3d3SAxel Dörfler #ifdef HAVE_STRING_H
3580bca3d3SAxel Dörfler #include <string.h>
3680bca3d3SAxel Dörfler #endif
3780bca3d3SAxel Dörfler #ifdef HAVE_FCNTL_H
3880bca3d3SAxel Dörfler #include <fcntl.h>
3980bca3d3SAxel Dörfler #endif
4080bca3d3SAxel Dörfler #ifdef HAVE_UNISTD_H
4180bca3d3SAxel Dörfler #include <unistd.h>
4280bca3d3SAxel Dörfler #endif
4380bca3d3SAxel Dörfler #ifdef HAVE_ERRNO_H
4480bca3d3SAxel Dörfler #include <errno.h>
4580bca3d3SAxel Dörfler #endif
4680bca3d3SAxel Dörfler #ifdef HAVE_SYS_STAT_H
4780bca3d3SAxel Dörfler #include <sys/stat.h>
4880bca3d3SAxel Dörfler #endif
4980bca3d3SAxel Dörfler #ifdef HAVE_LIMITS_H
5080bca3d3SAxel Dörfler #include <limits.h>
5180bca3d3SAxel Dörfler #endif
52*30bc84e9SGerasim Troeglazov #ifdef HAVE_LOCALE_H
53*30bc84e9SGerasim Troeglazov #include <locale.h>
54*30bc84e9SGerasim Troeglazov #endif
5580bca3d3SAxel Dörfler 
56*30bc84e9SGerasim Troeglazov #include "compat.h"
5780bca3d3SAxel Dörfler #include "volume.h"
5880bca3d3SAxel Dörfler #include "attrib.h"
5980bca3d3SAxel Dörfler #include "mft.h"
6080bca3d3SAxel Dörfler #include "bootsect.h"
6180bca3d3SAxel Dörfler #include "device.h"
6280bca3d3SAxel Dörfler #include "debug.h"
6380bca3d3SAxel Dörfler #include "inode.h"
6480bca3d3SAxel Dörfler #include "runlist.h"
6580bca3d3SAxel Dörfler #include "logfile.h"
6680bca3d3SAxel Dörfler #include "dir.h"
6780bca3d3SAxel Dörfler #include "logging.h"
6880bca3d3SAxel Dörfler #include "misc.h"
6980bca3d3SAxel Dörfler 
70*30bc84e9SGerasim Troeglazov const char *ntfs_home =
71*30bc84e9SGerasim Troeglazov "Ntfs-3g news, support and information:  http://ntfs-3g.org\n";
72*30bc84e9SGerasim Troeglazov 
73*30bc84e9SGerasim Troeglazov static const char *invalid_ntfs_msg =
74*30bc84e9SGerasim Troeglazov "The device '%s' doesn't seem to have a valid NTFS.\n"
75*30bc84e9SGerasim Troeglazov "Maybe the wrong device is used? Or the whole disk instead of a\n"
76*30bc84e9SGerasim Troeglazov "partition (e.g. /dev/sda, not /dev/sda1)? Or the other way around?\n";
77*30bc84e9SGerasim Troeglazov 
78*30bc84e9SGerasim Troeglazov static const char *corrupt_volume_msg =
79*30bc84e9SGerasim Troeglazov "NTFS is either inconsistent, or there is a hardware fault, or it's a\n"
80*30bc84e9SGerasim Troeglazov "SoftRAID/FakeRAID hardware. In the first case run chkdsk /f on Windows\n"
81*30bc84e9SGerasim Troeglazov "then reboot into Windows twice. The usage of the /f parameter is very\n"
82*30bc84e9SGerasim Troeglazov "important! If the device is a SoftRAID/FakeRAID then first activate\n"
83*30bc84e9SGerasim Troeglazov "it and mount a different device under the /dev/mapper/ directory, (e.g.\n"
84*30bc84e9SGerasim Troeglazov "/dev/mapper/nvidia_eahaabcc1). Please see the 'dmraid' documentation\n"
85*30bc84e9SGerasim Troeglazov "for more details.\n";
86*30bc84e9SGerasim Troeglazov 
87*30bc84e9SGerasim Troeglazov static const char *hibernated_volume_msg =
88*30bc84e9SGerasim Troeglazov "The NTFS partition is hibernated. Please resume and shutdown Windows\n"
89*30bc84e9SGerasim Troeglazov "properly, or mount the volume read-only with the 'ro' mount option, or\n"
90*30bc84e9SGerasim Troeglazov "mount the volume read-write with the 'remove_hiberfile' mount option.\n"
91*30bc84e9SGerasim Troeglazov "For example type on the command line:\n"
92*30bc84e9SGerasim Troeglazov "\n"
93*30bc84e9SGerasim Troeglazov "            mount -t ntfs-3g -o remove_hiberfile %s %s\n"
94*30bc84e9SGerasim Troeglazov "\n";
95*30bc84e9SGerasim Troeglazov 
96*30bc84e9SGerasim Troeglazov static const char *unclean_journal_msg =
97*30bc84e9SGerasim Troeglazov "Write access is denied because the disk wasn't safely powered\n"
98*30bc84e9SGerasim Troeglazov "off and the 'norecover' mount option was specified.\n";
99*30bc84e9SGerasim Troeglazov 
100*30bc84e9SGerasim Troeglazov static const char *opened_volume_msg =
101*30bc84e9SGerasim Troeglazov "Mount is denied because the NTFS volume is already exclusively opened.\n"
102*30bc84e9SGerasim Troeglazov "The volume may be already mounted, or another software may use it which\n"
103*30bc84e9SGerasim Troeglazov "could be identified for example by the help of the 'fuser' command.\n";
104*30bc84e9SGerasim Troeglazov 
105*30bc84e9SGerasim Troeglazov static const char *fakeraid_msg =
106*30bc84e9SGerasim Troeglazov "Either the device is missing or it's powered down, or you have\n"
107*30bc84e9SGerasim Troeglazov "SoftRAID hardware and must use an activated, different device under\n"
108*30bc84e9SGerasim Troeglazov "/dev/mapper/, (e.g. /dev/mapper/nvidia_eahaabcc1) to mount NTFS.\n"
109*30bc84e9SGerasim Troeglazov "Please see the 'dmraid' documentation for help.\n";
110*30bc84e9SGerasim Troeglazov 
111*30bc84e9SGerasim Troeglazov static const char *access_denied_msg =
112*30bc84e9SGerasim Troeglazov "Please check '%s' and the ntfs-3g binary permissions,\n"
113*30bc84e9SGerasim Troeglazov "and the mounting user ID. More explanation is provided at\n"
114*30bc84e9SGerasim Troeglazov "http://ntfs-3g.org/support.html#unprivileged\n";
11580bca3d3SAxel Dörfler 
11680bca3d3SAxel Dörfler /**
11780bca3d3SAxel Dörfler  * ntfs_volume_alloc - Create an NTFS volume object and initialise it
11880bca3d3SAxel Dörfler  *
11980bca3d3SAxel Dörfler  * Description...
12080bca3d3SAxel Dörfler  *
12180bca3d3SAxel Dörfler  * Returns:
12280bca3d3SAxel Dörfler  */
12380bca3d3SAxel Dörfler ntfs_volume *ntfs_volume_alloc(void)
12480bca3d3SAxel Dörfler {
125*30bc84e9SGerasim Troeglazov 	return ntfs_calloc(sizeof(ntfs_volume));
12680bca3d3SAxel Dörfler }
12780bca3d3SAxel Dörfler 
12862cee9f9SGerasim Troeglazov static void ntfs_attr_free(ntfs_attr **na)
12962cee9f9SGerasim Troeglazov {
13062cee9f9SGerasim Troeglazov 	if (na && *na) {
13162cee9f9SGerasim Troeglazov 		ntfs_attr_close(*na);
13262cee9f9SGerasim Troeglazov 		*na = NULL;
133*30bc84e9SGerasim Troeglazov 	}
13462cee9f9SGerasim Troeglazov }
13562cee9f9SGerasim Troeglazov 
13662cee9f9SGerasim Troeglazov static int ntfs_inode_free(ntfs_inode **ni)
13762cee9f9SGerasim Troeglazov {
13862cee9f9SGerasim Troeglazov 	int ret = -1;
13962cee9f9SGerasim Troeglazov 
14062cee9f9SGerasim Troeglazov 	if (ni && *ni) {
14162cee9f9SGerasim Troeglazov 		ret = ntfs_inode_close(*ni);
14262cee9f9SGerasim Troeglazov 		*ni = NULL;
143*30bc84e9SGerasim Troeglazov 	}
14462cee9f9SGerasim Troeglazov 
14562cee9f9SGerasim Troeglazov 	return ret;
14662cee9f9SGerasim Troeglazov }
14762cee9f9SGerasim Troeglazov 
14862cee9f9SGerasim Troeglazov static void ntfs_error_set(int *err)
14962cee9f9SGerasim Troeglazov {
15062cee9f9SGerasim Troeglazov 	if (!*err)
15162cee9f9SGerasim Troeglazov 		*err = errno;
15262cee9f9SGerasim Troeglazov }
15362cee9f9SGerasim Troeglazov 
15480bca3d3SAxel Dörfler /**
15580bca3d3SAxel Dörfler  * __ntfs_volume_release - Destroy an NTFS volume object
15680bca3d3SAxel Dörfler  * @v:
15780bca3d3SAxel Dörfler  *
15880bca3d3SAxel Dörfler  * Description...
15980bca3d3SAxel Dörfler  *
16080bca3d3SAxel Dörfler  * Returns:
16180bca3d3SAxel Dörfler  */
16262cee9f9SGerasim Troeglazov static int __ntfs_volume_release(ntfs_volume *v)
16380bca3d3SAxel Dörfler {
16462cee9f9SGerasim Troeglazov 	int err = 0;
16562cee9f9SGerasim Troeglazov 
16662cee9f9SGerasim Troeglazov 	if (ntfs_inode_free(&v->vol_ni))
16762cee9f9SGerasim Troeglazov 		ntfs_error_set(&err);
16862cee9f9SGerasim Troeglazov 	/*
16962cee9f9SGerasim Troeglazov 	 * FIXME: Inodes must be synced before closing
17062cee9f9SGerasim Troeglazov 	 * attributes, otherwise unmount could fail.
17162cee9f9SGerasim Troeglazov 	 */
17280bca3d3SAxel Dörfler 	if (v->lcnbmp_ni && NInoDirty(v->lcnbmp_ni))
17380bca3d3SAxel Dörfler 		ntfs_inode_sync(v->lcnbmp_ni);
17462cee9f9SGerasim Troeglazov 	ntfs_attr_free(&v->lcnbmp_na);
17562cee9f9SGerasim Troeglazov 	if (ntfs_inode_free(&v->lcnbmp_ni))
17662cee9f9SGerasim Troeglazov 		ntfs_error_set(&err);
17762cee9f9SGerasim Troeglazov 
17880bca3d3SAxel Dörfler 	if (v->mft_ni && NInoDirty(v->mft_ni))
17980bca3d3SAxel Dörfler 		ntfs_inode_sync(v->mft_ni);
18062cee9f9SGerasim Troeglazov 	ntfs_attr_free(&v->mftbmp_na);
18162cee9f9SGerasim Troeglazov 	ntfs_attr_free(&v->mft_na);
18262cee9f9SGerasim Troeglazov 	if (ntfs_inode_free(&v->mft_ni))
18362cee9f9SGerasim Troeglazov 		ntfs_error_set(&err);
18462cee9f9SGerasim Troeglazov 
18580bca3d3SAxel Dörfler 	if (v->mftmirr_ni && NInoDirty(v->mftmirr_ni))
18680bca3d3SAxel Dörfler 		ntfs_inode_sync(v->mftmirr_ni);
18762cee9f9SGerasim Troeglazov 	ntfs_attr_free(&v->mftmirr_na);
18862cee9f9SGerasim Troeglazov 	if (ntfs_inode_free(&v->mftmirr_ni))
18962cee9f9SGerasim Troeglazov 		ntfs_error_set(&err);
19062cee9f9SGerasim Troeglazov 
19180bca3d3SAxel Dörfler 	if (v->dev) {
19280bca3d3SAxel Dörfler 		struct ntfs_device *dev = v->dev;
19380bca3d3SAxel Dörfler 
19462cee9f9SGerasim Troeglazov 		if (dev->d_ops->sync(dev))
19562cee9f9SGerasim Troeglazov 			ntfs_error_set(&err);
19680bca3d3SAxel Dörfler 		if (dev->d_ops->close(dev))
19762cee9f9SGerasim Troeglazov 			ntfs_error_set(&err);
19880bca3d3SAxel Dörfler 	}
19962cee9f9SGerasim Troeglazov 
20080bca3d3SAxel Dörfler 	free(v->vol_name);
20180bca3d3SAxel Dörfler 	free(v->upcase);
20280bca3d3SAxel Dörfler 	free(v->attrdef);
20380bca3d3SAxel Dörfler 	free(v);
20462cee9f9SGerasim Troeglazov 
20562cee9f9SGerasim Troeglazov 	errno = err;
20662cee9f9SGerasim Troeglazov 	return errno ? -1 : 0;
20780bca3d3SAxel Dörfler }
20880bca3d3SAxel Dörfler 
20980bca3d3SAxel Dörfler static void ntfs_attr_setup_flag(ntfs_inode *ni)
21080bca3d3SAxel Dörfler {
21180bca3d3SAxel Dörfler 	STANDARD_INFORMATION *si;
21280bca3d3SAxel Dörfler 
21380bca3d3SAxel Dörfler 	si = ntfs_attr_readall(ni, AT_STANDARD_INFORMATION, AT_UNNAMED, 0, NULL);
21480bca3d3SAxel Dörfler 	if (si) {
21580bca3d3SAxel Dörfler 		ni->flags = si->file_attributes;
21680bca3d3SAxel Dörfler 		free(si);
21780bca3d3SAxel Dörfler 	}
21880bca3d3SAxel Dörfler }
21980bca3d3SAxel Dörfler 
22080bca3d3SAxel Dörfler /**
22180bca3d3SAxel Dörfler  * ntfs_mft_load - load the $MFT and setup the ntfs volume with it
22280bca3d3SAxel Dörfler  * @vol:	ntfs volume whose $MFT to load
22380bca3d3SAxel Dörfler  *
22480bca3d3SAxel Dörfler  * Load $MFT from @vol and setup @vol with it. After calling this function the
22580bca3d3SAxel Dörfler  * volume @vol is ready for use by all read access functions provided by the
22680bca3d3SAxel Dörfler  * ntfs library.
22780bca3d3SAxel Dörfler  *
22880bca3d3SAxel Dörfler  * Return 0 on success and -1 on error with errno set to the error code.
22980bca3d3SAxel Dörfler  */
23080bca3d3SAxel Dörfler static int ntfs_mft_load(ntfs_volume *vol)
23180bca3d3SAxel Dörfler {
23280bca3d3SAxel Dörfler 	VCN next_vcn, last_vcn, highest_vcn;
23380bca3d3SAxel Dörfler 	s64 l;
23480bca3d3SAxel Dörfler 	MFT_RECORD *mb = NULL;
23580bca3d3SAxel Dörfler 	ntfs_attr_search_ctx *ctx = NULL;
23680bca3d3SAxel Dörfler 	ATTR_RECORD *a;
23780bca3d3SAxel Dörfler 	int eo;
23880bca3d3SAxel Dörfler 
23980bca3d3SAxel Dörfler 	/* Manually setup an ntfs_inode. */
24080bca3d3SAxel Dörfler 	vol->mft_ni = ntfs_inode_allocate(vol);
24180bca3d3SAxel Dörfler 	mb = ntfs_malloc(vol->mft_record_size);
24280bca3d3SAxel Dörfler 	if (!vol->mft_ni || !mb) {
24380bca3d3SAxel Dörfler 		ntfs_log_perror("Error allocating memory for $MFT");
24480bca3d3SAxel Dörfler 		goto error_exit;
24580bca3d3SAxel Dörfler 	}
24680bca3d3SAxel Dörfler 	vol->mft_ni->mft_no = 0;
24780bca3d3SAxel Dörfler 	vol->mft_ni->mrec = mb;
24880bca3d3SAxel Dörfler 	/* Can't use any of the higher level functions yet! */
24980bca3d3SAxel Dörfler 	l = ntfs_mst_pread(vol->dev, vol->mft_lcn << vol->cluster_size_bits, 1,
25080bca3d3SAxel Dörfler 			vol->mft_record_size, mb);
25180bca3d3SAxel Dörfler 	if (l != 1) {
25280bca3d3SAxel Dörfler 		if (l != -1)
25380bca3d3SAxel Dörfler 			errno = EIO;
25480bca3d3SAxel Dörfler 		ntfs_log_perror("Error reading $MFT");
25580bca3d3SAxel Dörfler 		goto error_exit;
25680bca3d3SAxel Dörfler 	}
257*30bc84e9SGerasim Troeglazov 
258*30bc84e9SGerasim Troeglazov 	if (ntfs_mft_record_check(vol, 0, mb))
25980bca3d3SAxel Dörfler 		goto error_exit;
260*30bc84e9SGerasim Troeglazov 
261*30bc84e9SGerasim Troeglazov 	ctx = ntfs_attr_get_search_ctx(vol->mft_ni, NULL);
262*30bc84e9SGerasim Troeglazov 	if (!ctx)
263*30bc84e9SGerasim Troeglazov 		goto error_exit;
264*30bc84e9SGerasim Troeglazov 
26580bca3d3SAxel Dörfler 	/* Find the $ATTRIBUTE_LIST attribute in $MFT if present. */
26680bca3d3SAxel Dörfler 	if (ntfs_attr_lookup(AT_ATTRIBUTE_LIST, AT_UNNAMED, 0, 0, 0, NULL, 0,
26780bca3d3SAxel Dörfler 			ctx)) {
26880bca3d3SAxel Dörfler 		if (errno != ENOENT) {
26980bca3d3SAxel Dörfler 			ntfs_log_error("$MFT has corrupt attribute list.\n");
27080bca3d3SAxel Dörfler 			goto io_error_exit;
27180bca3d3SAxel Dörfler 		}
27280bca3d3SAxel Dörfler 		goto mft_has_no_attr_list;
27380bca3d3SAxel Dörfler 	}
27480bca3d3SAxel Dörfler 	NInoSetAttrList(vol->mft_ni);
27580bca3d3SAxel Dörfler 	l = ntfs_get_attribute_value_length(ctx->attr);
27680bca3d3SAxel Dörfler 	if (l <= 0 || l > 0x40000) {
2776b3592caSGerasim Troeglazov 		ntfs_log_error("$MFT/$ATTR_LIST invalid length (%lld).\n",
2786b3592caSGerasim Troeglazov 			       (long long)l);
27980bca3d3SAxel Dörfler 		goto io_error_exit;
28080bca3d3SAxel Dörfler 	}
28180bca3d3SAxel Dörfler 	vol->mft_ni->attr_list_size = l;
28280bca3d3SAxel Dörfler 	vol->mft_ni->attr_list = ntfs_malloc(l);
28380bca3d3SAxel Dörfler 	if (!vol->mft_ni->attr_list)
28480bca3d3SAxel Dörfler 		goto error_exit;
28580bca3d3SAxel Dörfler 
28680bca3d3SAxel Dörfler 	l = ntfs_get_attribute_value(vol, ctx->attr, vol->mft_ni->attr_list);
28780bca3d3SAxel Dörfler 	if (!l) {
28880bca3d3SAxel Dörfler 		ntfs_log_error("Failed to get value of $MFT/$ATTR_LIST.\n");
28980bca3d3SAxel Dörfler 		goto io_error_exit;
29080bca3d3SAxel Dörfler 	}
29180bca3d3SAxel Dörfler 	if (l != vol->mft_ni->attr_list_size) {
29280bca3d3SAxel Dörfler 		ntfs_log_error("Partial read of $MFT/$ATTR_LIST (%lld != "
2936b3592caSGerasim Troeglazov 			       "%u).\n", (long long)l,
2946b3592caSGerasim Troeglazov 			       vol->mft_ni->attr_list_size);
29580bca3d3SAxel Dörfler 		goto io_error_exit;
29680bca3d3SAxel Dörfler 	}
29780bca3d3SAxel Dörfler 
29880bca3d3SAxel Dörfler mft_has_no_attr_list:
29980bca3d3SAxel Dörfler 
30080bca3d3SAxel Dörfler 	ntfs_attr_setup_flag(vol->mft_ni);
30180bca3d3SAxel Dörfler 
30280bca3d3SAxel Dörfler 	/* We now have a fully setup ntfs inode for $MFT in vol->mft_ni. */
30380bca3d3SAxel Dörfler 
30480bca3d3SAxel Dörfler 	/* Get an ntfs attribute for $MFT/$DATA and set it up, too. */
30580bca3d3SAxel Dörfler 	vol->mft_na = ntfs_attr_open(vol->mft_ni, AT_DATA, AT_UNNAMED, 0);
30680bca3d3SAxel Dörfler 	if (!vol->mft_na) {
30780bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to open ntfs attribute");
30880bca3d3SAxel Dörfler 		goto error_exit;
30980bca3d3SAxel Dörfler 	}
31080bca3d3SAxel Dörfler 	/* Read all extents from the $DATA attribute in $MFT. */
31180bca3d3SAxel Dörfler 	ntfs_attr_reinit_search_ctx(ctx);
31280bca3d3SAxel Dörfler 	last_vcn = vol->mft_na->allocated_size >> vol->cluster_size_bits;
31380bca3d3SAxel Dörfler 	highest_vcn = next_vcn = 0;
31480bca3d3SAxel Dörfler 	a = NULL;
31580bca3d3SAxel Dörfler 	while (!ntfs_attr_lookup(AT_DATA, AT_UNNAMED, 0, 0, next_vcn, NULL, 0,
31680bca3d3SAxel Dörfler 			ctx)) {
31780bca3d3SAxel Dörfler 		runlist_element *nrl;
31880bca3d3SAxel Dörfler 
31980bca3d3SAxel Dörfler 		a = ctx->attr;
32080bca3d3SAxel Dörfler 		/* $MFT must be non-resident. */
32180bca3d3SAxel Dörfler 		if (!a->non_resident) {
32280bca3d3SAxel Dörfler 			ntfs_log_error("$MFT must be non-resident.\n");
32380bca3d3SAxel Dörfler 			goto io_error_exit;
32480bca3d3SAxel Dörfler 		}
32580bca3d3SAxel Dörfler 		/* $MFT must be uncompressed and unencrypted. */
32680bca3d3SAxel Dörfler 		if (a->flags & ATTR_COMPRESSION_MASK ||
32780bca3d3SAxel Dörfler 				a->flags & ATTR_IS_ENCRYPTED) {
32880bca3d3SAxel Dörfler 			ntfs_log_error("$MFT must be uncompressed and "
32980bca3d3SAxel Dörfler 				       "unencrypted.\n");
33080bca3d3SAxel Dörfler 			goto io_error_exit;
33180bca3d3SAxel Dörfler 		}
33280bca3d3SAxel Dörfler 		/*
33380bca3d3SAxel Dörfler 		 * Decompress the mapping pairs array of this extent and merge
33480bca3d3SAxel Dörfler 		 * the result into the existing runlist. No need for locking
33580bca3d3SAxel Dörfler 		 * as we have exclusive access to the inode at this time and we
33680bca3d3SAxel Dörfler 		 * are a mount in progress task, too.
33780bca3d3SAxel Dörfler 		 */
33880bca3d3SAxel Dörfler 		nrl = ntfs_mapping_pairs_decompress(vol, a, vol->mft_na->rl);
33980bca3d3SAxel Dörfler 		if (!nrl) {
34080bca3d3SAxel Dörfler 			ntfs_log_perror("ntfs_mapping_pairs_decompress() failed");
34180bca3d3SAxel Dörfler 			goto error_exit;
34280bca3d3SAxel Dörfler 		}
34380bca3d3SAxel Dörfler 		vol->mft_na->rl = nrl;
34480bca3d3SAxel Dörfler 
34580bca3d3SAxel Dörfler 		/* Get the lowest vcn for the next extent. */
34680bca3d3SAxel Dörfler 		highest_vcn = sle64_to_cpu(a->highest_vcn);
34780bca3d3SAxel Dörfler 		next_vcn = highest_vcn + 1;
34880bca3d3SAxel Dörfler 
34980bca3d3SAxel Dörfler 		/* Only one extent or error, which we catch below. */
35080bca3d3SAxel Dörfler 		if (next_vcn <= 0)
35180bca3d3SAxel Dörfler 			break;
35280bca3d3SAxel Dörfler 
35380bca3d3SAxel Dörfler 		/* Avoid endless loops due to corruption. */
35480bca3d3SAxel Dörfler 		if (next_vcn < sle64_to_cpu(a->lowest_vcn)) {
35580bca3d3SAxel Dörfler 			ntfs_log_error("$MFT has corrupt attribute list.\n");
35680bca3d3SAxel Dörfler 			goto io_error_exit;
35780bca3d3SAxel Dörfler 		}
35880bca3d3SAxel Dörfler 	}
35980bca3d3SAxel Dörfler 	if (!a) {
36080bca3d3SAxel Dörfler 		ntfs_log_error("$MFT/$DATA attribute not found.\n");
36180bca3d3SAxel Dörfler 		goto io_error_exit;
36280bca3d3SAxel Dörfler 	}
36380bca3d3SAxel Dörfler 	if (highest_vcn && highest_vcn != last_vcn - 1) {
36480bca3d3SAxel Dörfler 		ntfs_log_error("Failed to load runlist for $MFT/$DATA.\n");
36580bca3d3SAxel Dörfler 		ntfs_log_error("highest_vcn = 0x%llx, last_vcn - 1 = 0x%llx\n",
36680bca3d3SAxel Dörfler 			       (long long)highest_vcn, (long long)last_vcn - 1);
36780bca3d3SAxel Dörfler 		goto io_error_exit;
36880bca3d3SAxel Dörfler 	}
36980bca3d3SAxel Dörfler 	/* Done with the $Mft mft record. */
37080bca3d3SAxel Dörfler 	ntfs_attr_put_search_ctx(ctx);
37180bca3d3SAxel Dörfler 	ctx = NULL;
37280bca3d3SAxel Dörfler 	/*
37380bca3d3SAxel Dörfler 	 * The volume is now setup so we can use all read access functions.
37480bca3d3SAxel Dörfler 	 */
37580bca3d3SAxel Dörfler 	vol->mftbmp_na = ntfs_attr_open(vol->mft_ni, AT_BITMAP, AT_UNNAMED, 0);
37680bca3d3SAxel Dörfler 	if (!vol->mftbmp_na) {
37780bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to open $MFT/$BITMAP");
37880bca3d3SAxel Dörfler 		goto error_exit;
37980bca3d3SAxel Dörfler 	}
38080bca3d3SAxel Dörfler 	return 0;
38180bca3d3SAxel Dörfler io_error_exit:
38280bca3d3SAxel Dörfler 	errno = EIO;
38380bca3d3SAxel Dörfler error_exit:
38480bca3d3SAxel Dörfler 	eo = errno;
38580bca3d3SAxel Dörfler 	if (ctx)
38680bca3d3SAxel Dörfler 		ntfs_attr_put_search_ctx(ctx);
38780bca3d3SAxel Dörfler 	if (vol->mft_na) {
38880bca3d3SAxel Dörfler 		ntfs_attr_close(vol->mft_na);
38980bca3d3SAxel Dörfler 		vol->mft_na = NULL;
39080bca3d3SAxel Dörfler 	}
39180bca3d3SAxel Dörfler 	if (vol->mft_ni) {
39280bca3d3SAxel Dörfler 		ntfs_inode_close(vol->mft_ni);
39380bca3d3SAxel Dörfler 		vol->mft_ni = NULL;
39480bca3d3SAxel Dörfler 	}
39580bca3d3SAxel Dörfler 	errno = eo;
39680bca3d3SAxel Dörfler 	return -1;
39780bca3d3SAxel Dörfler }
39880bca3d3SAxel Dörfler 
39980bca3d3SAxel Dörfler /**
40080bca3d3SAxel Dörfler  * ntfs_mftmirr_load - load the $MFTMirr and setup the ntfs volume with it
40180bca3d3SAxel Dörfler  * @vol:	ntfs volume whose $MFTMirr to load
40280bca3d3SAxel Dörfler  *
40380bca3d3SAxel Dörfler  * Load $MFTMirr from @vol and setup @vol with it. After calling this function
40480bca3d3SAxel Dörfler  * the volume @vol is ready for use by all write access functions provided by
40580bca3d3SAxel Dörfler  * the ntfs library (assuming ntfs_mft_load() has been called successfully
40680bca3d3SAxel Dörfler  * beforehand).
40780bca3d3SAxel Dörfler  *
40880bca3d3SAxel Dörfler  * Return 0 on success and -1 on error with errno set to the error code.
40980bca3d3SAxel Dörfler  */
41080bca3d3SAxel Dörfler static int ntfs_mftmirr_load(ntfs_volume *vol)
41180bca3d3SAxel Dörfler {
41280bca3d3SAxel Dörfler 	int err;
41380bca3d3SAxel Dörfler 
41480bca3d3SAxel Dörfler 	vol->mftmirr_ni = ntfs_inode_open(vol, FILE_MFTMirr);
41580bca3d3SAxel Dörfler 	if (!vol->mftmirr_ni) {
41680bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to open inode $MFTMirr");
41780bca3d3SAxel Dörfler 		return -1;
41880bca3d3SAxel Dörfler 	}
41980bca3d3SAxel Dörfler 
42080bca3d3SAxel Dörfler 	vol->mftmirr_na = ntfs_attr_open(vol->mftmirr_ni, AT_DATA, AT_UNNAMED, 0);
42180bca3d3SAxel Dörfler 	if (!vol->mftmirr_na) {
42280bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to open $MFTMirr/$DATA");
42380bca3d3SAxel Dörfler 		goto error_exit;
42480bca3d3SAxel Dörfler 	}
42580bca3d3SAxel Dörfler 
42680bca3d3SAxel Dörfler 	if (ntfs_attr_map_runlist(vol->mftmirr_na, 0) < 0) {
42780bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to map runlist of $MFTMirr/$DATA");
42880bca3d3SAxel Dörfler 		goto error_exit;
42980bca3d3SAxel Dörfler 	}
43080bca3d3SAxel Dörfler 
43180bca3d3SAxel Dörfler 	return 0;
43280bca3d3SAxel Dörfler 
43380bca3d3SAxel Dörfler error_exit:
43480bca3d3SAxel Dörfler 	err = errno;
43580bca3d3SAxel Dörfler 	if (vol->mftmirr_na) {
43680bca3d3SAxel Dörfler 		ntfs_attr_close(vol->mftmirr_na);
43780bca3d3SAxel Dörfler 		vol->mftmirr_na = NULL;
43880bca3d3SAxel Dörfler 	}
43980bca3d3SAxel Dörfler 	ntfs_inode_close(vol->mftmirr_ni);
44080bca3d3SAxel Dörfler 	vol->mftmirr_ni = NULL;
44180bca3d3SAxel Dörfler 	errno = err;
44280bca3d3SAxel Dörfler 	return -1;
44380bca3d3SAxel Dörfler }
44480bca3d3SAxel Dörfler 
44580bca3d3SAxel Dörfler /**
44680bca3d3SAxel Dörfler  * ntfs_volume_startup - allocate and setup an ntfs volume
44780bca3d3SAxel Dörfler  * @dev:	device to open
44880bca3d3SAxel Dörfler  * @flags:	optional mount flags
44980bca3d3SAxel Dörfler  *
45080bca3d3SAxel Dörfler  * Load, verify, and parse bootsector; load and setup $MFT and $MFTMirr. After
45180bca3d3SAxel Dörfler  * calling this function, the volume is setup sufficiently to call all read
45280bca3d3SAxel Dörfler  * and write access functions provided by the library.
45380bca3d3SAxel Dörfler  *
45480bca3d3SAxel Dörfler  * Return the allocated volume structure on success and NULL on error with
45580bca3d3SAxel Dörfler  * errno set to the error code.
45680bca3d3SAxel Dörfler  */
45780bca3d3SAxel Dörfler ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, unsigned long flags)
45880bca3d3SAxel Dörfler {
45980bca3d3SAxel Dörfler 	LCN mft_zone_size, mft_lcn;
46080bca3d3SAxel Dörfler 	s64 br;
46180bca3d3SAxel Dörfler 	ntfs_volume *vol;
46280bca3d3SAxel Dörfler 	NTFS_BOOT_SECTOR *bs;
46380bca3d3SAxel Dörfler 	int eo;
46480bca3d3SAxel Dörfler 
46580bca3d3SAxel Dörfler 	if (!dev || !dev->d_ops || !dev->d_name) {
46680bca3d3SAxel Dörfler 		errno = EINVAL;
467*30bc84e9SGerasim Troeglazov 		ntfs_log_perror("%s: dev = %p", __FUNCTION__, dev);
46880bca3d3SAxel Dörfler 		return NULL;
46980bca3d3SAxel Dörfler 	}
47080bca3d3SAxel Dörfler 
47180bca3d3SAxel Dörfler 	bs = ntfs_malloc(sizeof(NTFS_BOOT_SECTOR));
47280bca3d3SAxel Dörfler 	if (!bs)
47380bca3d3SAxel Dörfler 		return NULL;
47480bca3d3SAxel Dörfler 
47580bca3d3SAxel Dörfler 	/* Allocate the volume structure. */
47680bca3d3SAxel Dörfler 	vol = ntfs_volume_alloc();
47780bca3d3SAxel Dörfler 	if (!vol)
47880bca3d3SAxel Dörfler 		goto error_exit;
479*30bc84e9SGerasim Troeglazov 
48080bca3d3SAxel Dörfler 	/* Create the default upcase table. */
48180bca3d3SAxel Dörfler 	vol->upcase_len = 65536;
48280bca3d3SAxel Dörfler 	vol->upcase = ntfs_malloc(vol->upcase_len * sizeof(ntfschar));
48380bca3d3SAxel Dörfler 	if (!vol->upcase)
48480bca3d3SAxel Dörfler 		goto error_exit;
48580bca3d3SAxel Dörfler 
48680bca3d3SAxel Dörfler 	ntfs_upcase_table_build(vol->upcase,
48780bca3d3SAxel Dörfler 			vol->upcase_len * sizeof(ntfschar));
488*30bc84e9SGerasim Troeglazov 
48980bca3d3SAxel Dörfler 	if (flags & MS_RDONLY)
49080bca3d3SAxel Dörfler 		NVolSetReadOnly(vol);
491*30bc84e9SGerasim Troeglazov 
492*30bc84e9SGerasim Troeglazov 	/* ...->open needs bracketing to compile with glibc 2.7 */
493*30bc84e9SGerasim Troeglazov 	if ((dev->d_ops->open)(dev, NVolReadOnly(vol) ? O_RDONLY: O_RDWR)) {
494*30bc84e9SGerasim Troeglazov 		ntfs_log_perror("Error opening '%s'", dev->d_name);
49580bca3d3SAxel Dörfler 		goto error_exit;
49680bca3d3SAxel Dörfler 	}
49780bca3d3SAxel Dörfler 	/* Attach the device to the volume. */
49880bca3d3SAxel Dörfler 	vol->dev = dev;
499*30bc84e9SGerasim Troeglazov 
50080bca3d3SAxel Dörfler 	/* Now read the bootsector. */
50180bca3d3SAxel Dörfler 	br = ntfs_pread(dev, 0, sizeof(NTFS_BOOT_SECTOR), bs);
50280bca3d3SAxel Dörfler 	if (br != sizeof(NTFS_BOOT_SECTOR)) {
50380bca3d3SAxel Dörfler 		if (br != -1)
50480bca3d3SAxel Dörfler 			errno = EINVAL;
50580bca3d3SAxel Dörfler 		if (!br)
506*30bc84e9SGerasim Troeglazov 			ntfs_log_error("Failed to read bootsector (size=0)\n");
50780bca3d3SAxel Dörfler 		else
50880bca3d3SAxel Dörfler 			ntfs_log_perror("Error reading bootsector");
50980bca3d3SAxel Dörfler 		goto error_exit;
51080bca3d3SAxel Dörfler 	}
51180bca3d3SAxel Dörfler 	if (!ntfs_boot_sector_is_ntfs(bs)) {
51280bca3d3SAxel Dörfler 		errno = EINVAL;
51380bca3d3SAxel Dörfler 		goto error_exit;
51480bca3d3SAxel Dörfler 	}
51580bca3d3SAxel Dörfler 	if (ntfs_boot_sector_parse(vol, bs) < 0)
51680bca3d3SAxel Dörfler 		goto error_exit;
51780bca3d3SAxel Dörfler 
51880bca3d3SAxel Dörfler 	free(bs);
51980bca3d3SAxel Dörfler 	bs = NULL;
52080bca3d3SAxel Dörfler 	/* Now set the device block size to the sector size. */
52180bca3d3SAxel Dörfler 	if (ntfs_device_block_size_set(vol->dev, vol->sector_size))
52280bca3d3SAxel Dörfler 		ntfs_log_debug("Failed to set the device block size to the "
52380bca3d3SAxel Dörfler 				"sector size.  This may affect performance "
52480bca3d3SAxel Dörfler 				"but should be harmless otherwise.  Error: "
52580bca3d3SAxel Dörfler 				"%s\n", strerror(errno));
52680bca3d3SAxel Dörfler 
52762cee9f9SGerasim Troeglazov 	/* We now initialize the cluster allocator. */
528*30bc84e9SGerasim Troeglazov 	mft_zone_size = vol->nr_clusters >> 3;      /* 12.5% */
52980bca3d3SAxel Dörfler 
53080bca3d3SAxel Dörfler 	/* Setup the mft zone. */
53180bca3d3SAxel Dörfler 	vol->mft_zone_start = vol->mft_zone_pos = vol->mft_lcn;
53280bca3d3SAxel Dörfler 	ntfs_log_debug("mft_zone_pos = 0x%llx\n", (long long)vol->mft_zone_pos);
53380bca3d3SAxel Dörfler 
53480bca3d3SAxel Dörfler 	/*
53580bca3d3SAxel Dörfler 	 * Calculate the mft_lcn for an unmodified NTFS volume (see mkntfs
53680bca3d3SAxel Dörfler 	 * source) and if the actual mft_lcn is in the expected place or even
53780bca3d3SAxel Dörfler 	 * further to the front of the volume, extend the mft_zone to cover the
53880bca3d3SAxel Dörfler 	 * beginning of the volume as well. This is in order to protect the
53980bca3d3SAxel Dörfler 	 * area reserved for the mft bitmap as well within the mft_zone itself.
54080bca3d3SAxel Dörfler 	 * On non-standard volumes we don't protect it as the overhead would be
54180bca3d3SAxel Dörfler 	 * higher than the speed increase we would get by doing it.
54280bca3d3SAxel Dörfler 	 */
54380bca3d3SAxel Dörfler 	mft_lcn = (8192 + 2 * vol->cluster_size - 1) / vol->cluster_size;
54480bca3d3SAxel Dörfler 	if (mft_lcn * vol->cluster_size < 16 * 1024)
54580bca3d3SAxel Dörfler 		mft_lcn = (16 * 1024 + vol->cluster_size - 1) /
54680bca3d3SAxel Dörfler 				vol->cluster_size;
54780bca3d3SAxel Dörfler 	if (vol->mft_zone_start <= mft_lcn)
54880bca3d3SAxel Dörfler 		vol->mft_zone_start = 0;
54980bca3d3SAxel Dörfler 	ntfs_log_debug("mft_zone_start = 0x%llx\n", (long long)vol->mft_zone_start);
55080bca3d3SAxel Dörfler 
55180bca3d3SAxel Dörfler 	/*
55280bca3d3SAxel Dörfler 	 * Need to cap the mft zone on non-standard volumes so that it does
55380bca3d3SAxel Dörfler 	 * not point outside the boundaries of the volume. We do this by
55480bca3d3SAxel Dörfler 	 * halving the zone size until we are inside the volume.
55580bca3d3SAxel Dörfler 	 */
55680bca3d3SAxel Dörfler 	vol->mft_zone_end = vol->mft_lcn + mft_zone_size;
55780bca3d3SAxel Dörfler 	while (vol->mft_zone_end >= vol->nr_clusters) {
55880bca3d3SAxel Dörfler 		mft_zone_size >>= 1;
55980bca3d3SAxel Dörfler 		vol->mft_zone_end = vol->mft_lcn + mft_zone_size;
56080bca3d3SAxel Dörfler 	}
56180bca3d3SAxel Dörfler 	ntfs_log_debug("mft_zone_end = 0x%llx\n", (long long)vol->mft_zone_end);
56280bca3d3SAxel Dörfler 
56380bca3d3SAxel Dörfler 	/*
56480bca3d3SAxel Dörfler 	 * Set the current position within each data zone to the start of the
56580bca3d3SAxel Dörfler 	 * respective zone.
56680bca3d3SAxel Dörfler 	 */
56780bca3d3SAxel Dörfler 	vol->data1_zone_pos = vol->mft_zone_end;
568*30bc84e9SGerasim Troeglazov 	ntfs_log_debug("data1_zone_pos = %lld\n", (long long)vol->data1_zone_pos);
56980bca3d3SAxel Dörfler 	vol->data2_zone_pos = 0;
570*30bc84e9SGerasim Troeglazov 	ntfs_log_debug("data2_zone_pos = %lld\n", (long long)vol->data2_zone_pos);
57180bca3d3SAxel Dörfler 
57280bca3d3SAxel Dörfler 	/* Set the mft data allocation position to mft record 24. */
57380bca3d3SAxel Dörfler 	vol->mft_data_pos = 24;
57480bca3d3SAxel Dörfler 
57580bca3d3SAxel Dörfler 	/*
57680bca3d3SAxel Dörfler 	 * The cluster allocator is now fully operational.
57780bca3d3SAxel Dörfler 	 */
57880bca3d3SAxel Dörfler 
57980bca3d3SAxel Dörfler 	/* Need to setup $MFT so we can use the library read functions. */
58080bca3d3SAxel Dörfler 	if (ntfs_mft_load(vol) < 0) {
58180bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to load $MFT");
58280bca3d3SAxel Dörfler 		goto error_exit;
58380bca3d3SAxel Dörfler 	}
58480bca3d3SAxel Dörfler 
58580bca3d3SAxel Dörfler 	/* Need to setup $MFTMirr so we can use the write functions, too. */
58680bca3d3SAxel Dörfler 	if (ntfs_mftmirr_load(vol) < 0) {
58780bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to load $MFTMirr");
58880bca3d3SAxel Dörfler 		goto error_exit;
58980bca3d3SAxel Dörfler 	}
59080bca3d3SAxel Dörfler 	return vol;
59180bca3d3SAxel Dörfler error_exit:
59280bca3d3SAxel Dörfler 	eo = errno;
59380bca3d3SAxel Dörfler 	free(bs);
59480bca3d3SAxel Dörfler 	if (vol)
59580bca3d3SAxel Dörfler 		__ntfs_volume_release(vol);
59680bca3d3SAxel Dörfler 	errno = eo;
59780bca3d3SAxel Dörfler 	return NULL;
59880bca3d3SAxel Dörfler }
59980bca3d3SAxel Dörfler 
60080bca3d3SAxel Dörfler /**
60180bca3d3SAxel Dörfler  * ntfs_volume_check_logfile - check logfile on target volume
60280bca3d3SAxel Dörfler  * @vol:	volume on which to check logfile
60380bca3d3SAxel Dörfler  *
60480bca3d3SAxel Dörfler  * Return 0 on success and -1 on error with errno set error code.
60580bca3d3SAxel Dörfler  */
60680bca3d3SAxel Dörfler static int ntfs_volume_check_logfile(ntfs_volume *vol)
60780bca3d3SAxel Dörfler {
60880bca3d3SAxel Dörfler 	ntfs_inode *ni;
60980bca3d3SAxel Dörfler 	ntfs_attr *na = NULL;
61080bca3d3SAxel Dörfler 	RESTART_PAGE_HEADER *rp = NULL;
61180bca3d3SAxel Dörfler 	int err = 0;
61280bca3d3SAxel Dörfler 
61362cee9f9SGerasim Troeglazov 	ni = ntfs_inode_open(vol, FILE_LogFile);
61462cee9f9SGerasim Troeglazov 	if (!ni) {
61580bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to open inode FILE_LogFile");
61680bca3d3SAxel Dörfler 		errno = EIO;
61780bca3d3SAxel Dörfler 		return -1;
61880bca3d3SAxel Dörfler 	}
61962cee9f9SGerasim Troeglazov 
62062cee9f9SGerasim Troeglazov 	na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
62162cee9f9SGerasim Troeglazov 	if (!na) {
62280bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to open $FILE_LogFile/$DATA");
62380bca3d3SAxel Dörfler 		err = EIO;
62462cee9f9SGerasim Troeglazov 		goto out;
62580bca3d3SAxel Dörfler 	}
62662cee9f9SGerasim Troeglazov 
62780bca3d3SAxel Dörfler 	if (!ntfs_check_logfile(na, &rp) || !ntfs_is_logfile_clean(na, rp))
62880bca3d3SAxel Dörfler 		err = EOPNOTSUPP;
62980bca3d3SAxel Dörfler 	free(rp);
63080bca3d3SAxel Dörfler 	ntfs_attr_close(na);
63162cee9f9SGerasim Troeglazov out:
63262cee9f9SGerasim Troeglazov 	if (ntfs_inode_close(ni))
63362cee9f9SGerasim Troeglazov 		ntfs_error_set(&err);
63480bca3d3SAxel Dörfler 	if (err) {
63580bca3d3SAxel Dörfler 		errno = err;
63680bca3d3SAxel Dörfler 		return -1;
63780bca3d3SAxel Dörfler 	}
63880bca3d3SAxel Dörfler 	return 0;
63980bca3d3SAxel Dörfler }
64080bca3d3SAxel Dörfler 
64180bca3d3SAxel Dörfler /**
64280bca3d3SAxel Dörfler  * ntfs_hiberfile_open - Find and open '/hiberfil.sys'
64380bca3d3SAxel Dörfler  * @vol:    An ntfs volume obtained from ntfs_mount
64480bca3d3SAxel Dörfler  *
64580bca3d3SAxel Dörfler  * Return:  inode  Success, hiberfil.sys is valid
64680bca3d3SAxel Dörfler  *	    NULL   hiberfil.sys doesn't exist or some other error occurred
64780bca3d3SAxel Dörfler  */
64880bca3d3SAxel Dörfler static ntfs_inode *ntfs_hiberfile_open(ntfs_volume *vol)
64980bca3d3SAxel Dörfler {
65080bca3d3SAxel Dörfler 	u64 inode;
65180bca3d3SAxel Dörfler 	ntfs_inode *ni_root;
65280bca3d3SAxel Dörfler 	ntfs_inode *ni_hibr = NULL;
65380bca3d3SAxel Dörfler 	ntfschar   *unicode = NULL;
65480bca3d3SAxel Dörfler 	int unicode_len;
65580bca3d3SAxel Dörfler 	const char *hiberfile = "hiberfil.sys";
65680bca3d3SAxel Dörfler 
65780bca3d3SAxel Dörfler 	if (!vol) {
65880bca3d3SAxel Dörfler 		errno = EINVAL;
65980bca3d3SAxel Dörfler 		return NULL;
66080bca3d3SAxel Dörfler 	}
66180bca3d3SAxel Dörfler 
66280bca3d3SAxel Dörfler 	ni_root = ntfs_inode_open(vol, FILE_root);
66380bca3d3SAxel Dörfler 	if (!ni_root) {
66480bca3d3SAxel Dörfler 		ntfs_log_debug("Couldn't open the root directory.\n");
66580bca3d3SAxel Dörfler 		return NULL;
66680bca3d3SAxel Dörfler 	}
66780bca3d3SAxel Dörfler 
668*30bc84e9SGerasim Troeglazov 	unicode_len = ntfs_mbstoucs(hiberfile, &unicode);
66980bca3d3SAxel Dörfler 	if (unicode_len < 0) {
67080bca3d3SAxel Dörfler 		ntfs_log_perror("Couldn't convert 'hiberfil.sys' to Unicode");
67180bca3d3SAxel Dörfler 		goto out;
67280bca3d3SAxel Dörfler 	}
67380bca3d3SAxel Dörfler 
67480bca3d3SAxel Dörfler 	inode = ntfs_inode_lookup_by_name(ni_root, unicode, unicode_len);
67580bca3d3SAxel Dörfler 	if (inode == (u64)-1) {
67680bca3d3SAxel Dörfler 		ntfs_log_debug("Couldn't find file '%s'.\n", hiberfile);
67780bca3d3SAxel Dörfler 		goto out;
67880bca3d3SAxel Dörfler 	}
67980bca3d3SAxel Dörfler 
68080bca3d3SAxel Dörfler 	inode = MREF(inode);
68180bca3d3SAxel Dörfler 	ni_hibr = ntfs_inode_open(vol, inode);
68280bca3d3SAxel Dörfler 	if (!ni_hibr) {
68380bca3d3SAxel Dörfler 		ntfs_log_debug("Couldn't open inode %lld.\n", (long long)inode);
68480bca3d3SAxel Dörfler 		goto out;
68580bca3d3SAxel Dörfler 	}
68680bca3d3SAxel Dörfler out:
68762cee9f9SGerasim Troeglazov 	if (ntfs_inode_close(ni_root)) {
68862cee9f9SGerasim Troeglazov 		ntfs_inode_close(ni_hibr);
68962cee9f9SGerasim Troeglazov 		ni_hibr = NULL;
69062cee9f9SGerasim Troeglazov 	}
69180bca3d3SAxel Dörfler 	free(unicode);
69280bca3d3SAxel Dörfler 	return ni_hibr;
69380bca3d3SAxel Dörfler }
69480bca3d3SAxel Dörfler 
69580bca3d3SAxel Dörfler 
69680bca3d3SAxel Dörfler #define NTFS_HIBERFILE_HEADER_SIZE	4096
69780bca3d3SAxel Dörfler 
69880bca3d3SAxel Dörfler /**
69980bca3d3SAxel Dörfler  * ntfs_volume_check_hiberfile - check hiberfil.sys whether Windows is
70080bca3d3SAxel Dörfler  *                               hibernated on the target volume
70180bca3d3SAxel Dörfler  * @vol:    volume on which to check hiberfil.sys
70280bca3d3SAxel Dörfler  *
70380bca3d3SAxel Dörfler  * Return:  0 if Windows isn't hibernated for sure
70480bca3d3SAxel Dörfler  *         -1 otherwise and errno is set to the appropriate value
70580bca3d3SAxel Dörfler  */
706*30bc84e9SGerasim Troeglazov int ntfs_volume_check_hiberfile(ntfs_volume *vol, int verbose)
70780bca3d3SAxel Dörfler {
70880bca3d3SAxel Dörfler 	ntfs_inode *ni;
70980bca3d3SAxel Dörfler 	ntfs_attr *na = NULL;
710*30bc84e9SGerasim Troeglazov 	int bytes_read, err;
71180bca3d3SAxel Dörfler 	char *buf = NULL;
71280bca3d3SAxel Dörfler 
71380bca3d3SAxel Dörfler 	ni = ntfs_hiberfile_open(vol);
71480bca3d3SAxel Dörfler 	if (!ni) {
71580bca3d3SAxel Dörfler 		if (errno == ENOENT)
71680bca3d3SAxel Dörfler 			return 0;
71780bca3d3SAxel Dörfler 		return -1;
71880bca3d3SAxel Dörfler 	}
71980bca3d3SAxel Dörfler 
72080bca3d3SAxel Dörfler 	buf = ntfs_malloc(NTFS_HIBERFILE_HEADER_SIZE);
72180bca3d3SAxel Dörfler 	if (!buf)
72280bca3d3SAxel Dörfler 		goto out;
72380bca3d3SAxel Dörfler 
72480bca3d3SAxel Dörfler 	na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
72580bca3d3SAxel Dörfler 	if (!na) {
72680bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to open hiberfil.sys data attribute");
72780bca3d3SAxel Dörfler 		goto out;
72880bca3d3SAxel Dörfler 	}
72980bca3d3SAxel Dörfler 
73080bca3d3SAxel Dörfler 	bytes_read = ntfs_attr_pread(na, 0, NTFS_HIBERFILE_HEADER_SIZE, buf);
73180bca3d3SAxel Dörfler 	if (bytes_read == -1) {
73280bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to read hiberfil.sys");
73380bca3d3SAxel Dörfler 		goto out;
73480bca3d3SAxel Dörfler 	}
73580bca3d3SAxel Dörfler 	if (bytes_read < NTFS_HIBERFILE_HEADER_SIZE) {
736*30bc84e9SGerasim Troeglazov 		if (verbose)
737*30bc84e9SGerasim Troeglazov 			ntfs_log_error("Hibernated non-system partition, "
738*30bc84e9SGerasim Troeglazov 				       "refused to mount.\n");
73980bca3d3SAxel Dörfler 		errno = EPERM;
74080bca3d3SAxel Dörfler 		goto out;
74180bca3d3SAxel Dörfler 	}
74280bca3d3SAxel Dörfler 	if (memcmp(buf, "hibr", 4) == 0) {
743*30bc84e9SGerasim Troeglazov 		if (verbose)
74480bca3d3SAxel Dörfler 			ntfs_log_error("Windows is hibernated, refused to mount.\n");
74580bca3d3SAxel Dörfler 		errno = EPERM;
74680bca3d3SAxel Dörfler 		goto out;
74780bca3d3SAxel Dörfler 	}
74880bca3d3SAxel Dörfler         /* All right, all header bytes are zero */
74962cee9f9SGerasim Troeglazov 	errno = 0;
75080bca3d3SAxel Dörfler out:
75180bca3d3SAxel Dörfler 	if (na)
75280bca3d3SAxel Dörfler 		ntfs_attr_close(na);
75380bca3d3SAxel Dörfler 	free(buf);
75462cee9f9SGerasim Troeglazov 	err = errno;
75562cee9f9SGerasim Troeglazov 	if (ntfs_inode_close(ni))
75662cee9f9SGerasim Troeglazov 		ntfs_error_set(&err);
75762cee9f9SGerasim Troeglazov 	errno = err;
75862cee9f9SGerasim Troeglazov 	return errno ? -1 : 0;
75980bca3d3SAxel Dörfler }
76080bca3d3SAxel Dörfler 
76180bca3d3SAxel Dörfler /**
76280bca3d3SAxel Dörfler  * ntfs_device_mount - open ntfs volume
76380bca3d3SAxel Dörfler  * @dev:	device to open
76480bca3d3SAxel Dörfler  * @flags:	optional mount flags
76580bca3d3SAxel Dörfler  *
76680bca3d3SAxel Dörfler  * This function mounts an ntfs volume. @dev should describe the device which
76780bca3d3SAxel Dörfler  * to mount as the ntfs volume.
76880bca3d3SAxel Dörfler  *
76980bca3d3SAxel Dörfler  * @flags is an optional second parameter. The same flags are used as for
770*30bc84e9SGerasim Troeglazov  * the mount system call (man 2 mount). Currently only the following flag
771*30bc84e9SGerasim Troeglazov  * is implemented:
77280bca3d3SAxel Dörfler  *	MS_RDONLY	- mount volume read-only
77380bca3d3SAxel Dörfler  *
77480bca3d3SAxel Dörfler  * The function opens the device @dev and verifies that it contains a valid
77580bca3d3SAxel Dörfler  * bootsector. Then, it allocates an ntfs_volume structure and initializes
77680bca3d3SAxel Dörfler  * some of the values inside the structure from the information stored in the
77780bca3d3SAxel Dörfler  * bootsector. It proceeds to load the necessary system files and completes
77880bca3d3SAxel Dörfler  * setting up the structure.
77980bca3d3SAxel Dörfler  *
78080bca3d3SAxel Dörfler  * Return the allocated volume structure on success and NULL on error with
78180bca3d3SAxel Dörfler  * errno set to the error code.
78280bca3d3SAxel Dörfler  */
78380bca3d3SAxel Dörfler ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags)
78480bca3d3SAxel Dörfler {
78580bca3d3SAxel Dörfler 	s64 l;
78680bca3d3SAxel Dörfler 	ntfs_volume *vol;
78780bca3d3SAxel Dörfler 	u8 *m = NULL, *m2 = NULL;
78880bca3d3SAxel Dörfler 	ntfs_attr_search_ctx *ctx = NULL;
78980bca3d3SAxel Dörfler 	ntfs_inode *ni;
79080bca3d3SAxel Dörfler 	ntfs_attr *na;
79180bca3d3SAxel Dörfler 	ATTR_RECORD *a;
79280bca3d3SAxel Dörfler 	VOLUME_INFORMATION *vinf;
79380bca3d3SAxel Dörfler 	ntfschar *vname;
79480bca3d3SAxel Dörfler 	int i, j, eo;
79580bca3d3SAxel Dörfler 	u32 u;
79680bca3d3SAxel Dörfler 
79780bca3d3SAxel Dörfler 	vol = ntfs_volume_startup(dev, flags);
798*30bc84e9SGerasim Troeglazov 	if (!vol)
79980bca3d3SAxel Dörfler 		return NULL;
80080bca3d3SAxel Dörfler 
80180bca3d3SAxel Dörfler 	/* Load data from $MFT and $MFTMirr and compare the contents. */
80280bca3d3SAxel Dörfler 	m  = ntfs_malloc(vol->mftmirr_size << vol->mft_record_size_bits);
80380bca3d3SAxel Dörfler 	m2 = ntfs_malloc(vol->mftmirr_size << vol->mft_record_size_bits);
80480bca3d3SAxel Dörfler 	if (!m || !m2)
80580bca3d3SAxel Dörfler 		goto error_exit;
80680bca3d3SAxel Dörfler 
80780bca3d3SAxel Dörfler 	l = ntfs_attr_mst_pread(vol->mft_na, 0, vol->mftmirr_size,
80880bca3d3SAxel Dörfler 			vol->mft_record_size, m);
80980bca3d3SAxel Dörfler 	if (l != vol->mftmirr_size) {
81080bca3d3SAxel Dörfler 		if (l == -1)
81180bca3d3SAxel Dörfler 			ntfs_log_perror("Failed to read $MFT");
81280bca3d3SAxel Dörfler 		else {
81380bca3d3SAxel Dörfler 			ntfs_log_error("Failed to read $MFT, unexpected length "
8146b3592caSGerasim Troeglazov 				       "(%lld != %d).\n", (long long)l,
8156b3592caSGerasim Troeglazov 				       vol->mftmirr_size);
81680bca3d3SAxel Dörfler 			errno = EIO;
81780bca3d3SAxel Dörfler 		}
81880bca3d3SAxel Dörfler 		goto error_exit;
81980bca3d3SAxel Dörfler 	}
82080bca3d3SAxel Dörfler 	l = ntfs_attr_mst_pread(vol->mftmirr_na, 0, vol->mftmirr_size,
82180bca3d3SAxel Dörfler 			vol->mft_record_size, m2);
82280bca3d3SAxel Dörfler 	if (l != vol->mftmirr_size) {
82362cee9f9SGerasim Troeglazov 		if (l == -1) {
82480bca3d3SAxel Dörfler 			ntfs_log_perror("Failed to read $MFTMirr");
82580bca3d3SAxel Dörfler 			goto error_exit;
82680bca3d3SAxel Dörfler 		}
82762cee9f9SGerasim Troeglazov 		vol->mftmirr_size = l;
82880bca3d3SAxel Dörfler 	}
829*30bc84e9SGerasim Troeglazov 	ntfs_log_debug("Comparing $MFTMirr to $MFT...\n");
83080bca3d3SAxel Dörfler 	for (i = 0; i < vol->mftmirr_size; ++i) {
83180bca3d3SAxel Dörfler 		MFT_RECORD *mrec, *mrec2;
83280bca3d3SAxel Dörfler 		const char *ESTR[12] = { "$MFT", "$MFTMirr", "$LogFile",
83380bca3d3SAxel Dörfler 			"$Volume", "$AttrDef", "root directory", "$Bitmap",
83480bca3d3SAxel Dörfler 			"$Boot", "$BadClus", "$Secure", "$UpCase", "$Extend" };
83580bca3d3SAxel Dörfler 		const char *s;
83680bca3d3SAxel Dörfler 
83780bca3d3SAxel Dörfler 		if (i < 12)
83880bca3d3SAxel Dörfler 			s = ESTR[i];
83980bca3d3SAxel Dörfler 		else if (i < 16)
84080bca3d3SAxel Dörfler 			s = "system file";
84180bca3d3SAxel Dörfler 		else
84280bca3d3SAxel Dörfler 			s = "mft record";
84380bca3d3SAxel Dörfler 
84480bca3d3SAxel Dörfler 		mrec = (MFT_RECORD*)(m + i * vol->mft_record_size);
84580bca3d3SAxel Dörfler 		if (mrec->flags & MFT_RECORD_IN_USE) {
84680bca3d3SAxel Dörfler 			if (ntfs_is_baad_recordp(mrec)) {
84780bca3d3SAxel Dörfler 				ntfs_log_error("$MFT error: Incomplete multi "
84880bca3d3SAxel Dörfler 					       "sector transfer detected in "
84980bca3d3SAxel Dörfler 					       "'%s'.\n", s);
85080bca3d3SAxel Dörfler 				goto io_error_exit;
85180bca3d3SAxel Dörfler 			}
85280bca3d3SAxel Dörfler 			if (!ntfs_is_mft_recordp(mrec)) {
85380bca3d3SAxel Dörfler 				ntfs_log_error("$MFT error: Invalid mft "
85480bca3d3SAxel Dörfler 						"record for '%s'.\n", s);
85580bca3d3SAxel Dörfler 				goto io_error_exit;
85680bca3d3SAxel Dörfler 			}
85780bca3d3SAxel Dörfler 		}
85880bca3d3SAxel Dörfler 		mrec2 = (MFT_RECORD*)(m2 + i * vol->mft_record_size);
85980bca3d3SAxel Dörfler 		if (mrec2->flags & MFT_RECORD_IN_USE) {
86080bca3d3SAxel Dörfler 			if (ntfs_is_baad_recordp(mrec2)) {
86180bca3d3SAxel Dörfler 				ntfs_log_error("$MFTMirr error: Incomplete "
86280bca3d3SAxel Dörfler 						"multi sector transfer "
86380bca3d3SAxel Dörfler 						"detected in '%s'.\n", s);
86480bca3d3SAxel Dörfler 				goto io_error_exit;
86580bca3d3SAxel Dörfler 			}
86680bca3d3SAxel Dörfler 			if (!ntfs_is_mft_recordp(mrec2)) {
86780bca3d3SAxel Dörfler 				ntfs_log_error("$MFTMirr error: Invalid mft "
86880bca3d3SAxel Dörfler 						"record for '%s'.\n", s);
86980bca3d3SAxel Dörfler 				goto io_error_exit;
87080bca3d3SAxel Dörfler 			}
87180bca3d3SAxel Dörfler 		}
87280bca3d3SAxel Dörfler 		if (memcmp(mrec, mrec2, ntfs_mft_record_get_data_size(mrec))) {
87380bca3d3SAxel Dörfler 			ntfs_log_error("$MFTMirr does not match $MFT (record "
87480bca3d3SAxel Dörfler 				       "%d).\n", i);
87580bca3d3SAxel Dörfler 			goto io_error_exit;
87680bca3d3SAxel Dörfler 		}
87780bca3d3SAxel Dörfler 	}
87880bca3d3SAxel Dörfler 
87980bca3d3SAxel Dörfler 	free(m2);
88080bca3d3SAxel Dörfler 	free(m);
88180bca3d3SAxel Dörfler 	m = m2 = NULL;
88280bca3d3SAxel Dörfler 
88380bca3d3SAxel Dörfler 	/* Now load the bitmap from $Bitmap. */
884*30bc84e9SGerasim Troeglazov 	ntfs_log_debug("Loading $Bitmap...\n");
88580bca3d3SAxel Dörfler 	vol->lcnbmp_ni = ntfs_inode_open(vol, FILE_Bitmap);
88680bca3d3SAxel Dörfler 	if (!vol->lcnbmp_ni) {
887*30bc84e9SGerasim Troeglazov 		ntfs_log_perror("Failed to open inode FILE_Bitmap");
88880bca3d3SAxel Dörfler 		goto error_exit;
88980bca3d3SAxel Dörfler 	}
890*30bc84e9SGerasim Troeglazov 
89180bca3d3SAxel Dörfler 	vol->lcnbmp_na = ntfs_attr_open(vol->lcnbmp_ni, AT_DATA, AT_UNNAMED, 0);
89280bca3d3SAxel Dörfler 	if (!vol->lcnbmp_na) {
89380bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to open ntfs attribute");
89480bca3d3SAxel Dörfler 		goto error_exit;
89580bca3d3SAxel Dörfler 	}
896*30bc84e9SGerasim Troeglazov 
897*30bc84e9SGerasim Troeglazov 	if (vol->lcnbmp_na->data_size > vol->lcnbmp_na->allocated_size) {
898*30bc84e9SGerasim Troeglazov 		ntfs_log_error("Corrupt cluster map size (%lld > %lld)\n",
899*30bc84e9SGerasim Troeglazov 				(long long)vol->lcnbmp_na->data_size,
900*30bc84e9SGerasim Troeglazov 				(long long)vol->lcnbmp_na->allocated_size);
901*30bc84e9SGerasim Troeglazov 		goto io_error_exit;
902*30bc84e9SGerasim Troeglazov 	}
90380bca3d3SAxel Dörfler 
90480bca3d3SAxel Dörfler 	/* Now load the upcase table from $UpCase. */
905*30bc84e9SGerasim Troeglazov 	ntfs_log_debug("Loading $UpCase...\n");
90680bca3d3SAxel Dörfler 	ni = ntfs_inode_open(vol, FILE_UpCase);
90780bca3d3SAxel Dörfler 	if (!ni) {
908*30bc84e9SGerasim Troeglazov 		ntfs_log_perror("Failed to open inode FILE_UpCase");
90980bca3d3SAxel Dörfler 		goto error_exit;
91080bca3d3SAxel Dörfler 	}
91180bca3d3SAxel Dörfler 	/* Get an ntfs attribute for $UpCase/$DATA. */
91280bca3d3SAxel Dörfler 	na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
91380bca3d3SAxel Dörfler 	if (!na) {
91480bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to open ntfs attribute");
91580bca3d3SAxel Dörfler 		goto error_exit;
91680bca3d3SAxel Dörfler 	}
91780bca3d3SAxel Dörfler 	/*
91880bca3d3SAxel Dörfler 	 * Note: Normally, the upcase table has a length equal to 65536
91980bca3d3SAxel Dörfler 	 * 2-byte Unicode characters but allow for different cases, so no
92080bca3d3SAxel Dörfler 	 * checks done. Just check we don't overflow 32-bits worth of Unicode
92180bca3d3SAxel Dörfler 	 * characters.
92280bca3d3SAxel Dörfler 	 */
92380bca3d3SAxel Dörfler 	if (na->data_size & ~0x1ffffffffULL) {
92480bca3d3SAxel Dörfler 		ntfs_log_error("Error: Upcase table is too big (max 32-bit "
92580bca3d3SAxel Dörfler 				"allowed).\n");
92680bca3d3SAxel Dörfler 		errno = EINVAL;
92780bca3d3SAxel Dörfler 		goto error_exit;
92880bca3d3SAxel Dörfler 	}
92980bca3d3SAxel Dörfler 	if (vol->upcase_len != na->data_size >> 1) {
93080bca3d3SAxel Dörfler 		vol->upcase_len = na->data_size >> 1;
93180bca3d3SAxel Dörfler 		/* Throw away default table. */
93280bca3d3SAxel Dörfler 		free(vol->upcase);
93380bca3d3SAxel Dörfler 		vol->upcase = ntfs_malloc(na->data_size);
934*30bc84e9SGerasim Troeglazov 		if (!vol->upcase)
93580bca3d3SAxel Dörfler 			goto error_exit;
93680bca3d3SAxel Dörfler 	}
93780bca3d3SAxel Dörfler 	/* Read in the $DATA attribute value into the buffer. */
93880bca3d3SAxel Dörfler 	l = ntfs_attr_pread(na, 0, na->data_size, vol->upcase);
93980bca3d3SAxel Dörfler 	if (l != na->data_size) {
94080bca3d3SAxel Dörfler 		ntfs_log_error("Failed to read $UpCase, unexpected length "
9416b3592caSGerasim Troeglazov 			       "(%lld != %lld).\n", (long long)l,
9426b3592caSGerasim Troeglazov 			       (long long)na->data_size);
94380bca3d3SAxel Dörfler 		errno = EIO;
94480bca3d3SAxel Dörfler 		goto error_exit;
94580bca3d3SAxel Dörfler 	}
94680bca3d3SAxel Dörfler 	/* Done with the $UpCase mft record. */
94780bca3d3SAxel Dörfler 	ntfs_attr_close(na);
94862cee9f9SGerasim Troeglazov 	if (ntfs_inode_close(ni)) {
94962cee9f9SGerasim Troeglazov 		ntfs_log_perror("Failed to close $UpCase");
95062cee9f9SGerasim Troeglazov 		goto error_exit;
95162cee9f9SGerasim Troeglazov 	}
95280bca3d3SAxel Dörfler 
95380bca3d3SAxel Dörfler 	/*
95480bca3d3SAxel Dörfler 	 * Now load $Volume and set the version information and flags in the
95580bca3d3SAxel Dörfler 	 * vol structure accordingly.
95680bca3d3SAxel Dörfler 	 */
957*30bc84e9SGerasim Troeglazov 	ntfs_log_debug("Loading $Volume...\n");
95880bca3d3SAxel Dörfler 	vol->vol_ni = ntfs_inode_open(vol, FILE_Volume);
95980bca3d3SAxel Dörfler 	if (!vol->vol_ni) {
960*30bc84e9SGerasim Troeglazov 		ntfs_log_perror("Failed to open inode FILE_Volume");
96180bca3d3SAxel Dörfler 		goto error_exit;
96280bca3d3SAxel Dörfler 	}
96380bca3d3SAxel Dörfler 	/* Get a search context for the $Volume/$VOLUME_INFORMATION lookup. */
96480bca3d3SAxel Dörfler 	ctx = ntfs_attr_get_search_ctx(vol->vol_ni, NULL);
965*30bc84e9SGerasim Troeglazov 	if (!ctx)
96680bca3d3SAxel Dörfler 		goto error_exit;
967*30bc84e9SGerasim Troeglazov 
96880bca3d3SAxel Dörfler 	/* Find the $VOLUME_INFORMATION attribute. */
96980bca3d3SAxel Dörfler 	if (ntfs_attr_lookup(AT_VOLUME_INFORMATION, AT_UNNAMED, 0, 0, 0, NULL,
97080bca3d3SAxel Dörfler 			0, ctx)) {
97180bca3d3SAxel Dörfler 		ntfs_log_perror("$VOLUME_INFORMATION attribute not found in "
97280bca3d3SAxel Dörfler 				"$Volume");
97380bca3d3SAxel Dörfler 		goto error_exit;
97480bca3d3SAxel Dörfler 	}
97580bca3d3SAxel Dörfler 	a = ctx->attr;
97680bca3d3SAxel Dörfler 	/* Has to be resident. */
97780bca3d3SAxel Dörfler 	if (a->non_resident) {
97880bca3d3SAxel Dörfler 		ntfs_log_error("Attribute $VOLUME_INFORMATION must be "
97980bca3d3SAxel Dörfler 			       "resident but it isn't.\n");
98080bca3d3SAxel Dörfler 		errno = EIO;
98180bca3d3SAxel Dörfler 		goto error_exit;
98280bca3d3SAxel Dörfler 	}
98380bca3d3SAxel Dörfler 	/* Get a pointer to the value of the attribute. */
98480bca3d3SAxel Dörfler 	vinf = (VOLUME_INFORMATION*)(le16_to_cpu(a->value_offset) + (char*)a);
98580bca3d3SAxel Dörfler 	/* Sanity checks. */
98680bca3d3SAxel Dörfler 	if ((char*)vinf + le32_to_cpu(a->value_length) > (char*)ctx->mrec +
98780bca3d3SAxel Dörfler 			le32_to_cpu(ctx->mrec->bytes_in_use) ||
98880bca3d3SAxel Dörfler 			le16_to_cpu(a->value_offset) + le32_to_cpu(
98980bca3d3SAxel Dörfler 			a->value_length) > le32_to_cpu(a->length)) {
99080bca3d3SAxel Dörfler 		ntfs_log_error("$VOLUME_INFORMATION in $Volume is corrupt.\n");
99180bca3d3SAxel Dörfler 		errno = EIO;
99280bca3d3SAxel Dörfler 		goto error_exit;
99380bca3d3SAxel Dörfler 	}
99480bca3d3SAxel Dörfler 	/* Setup vol from the volume information attribute value. */
99580bca3d3SAxel Dörfler 	vol->major_ver = vinf->major_ver;
99680bca3d3SAxel Dörfler 	vol->minor_ver = vinf->minor_ver;
99780bca3d3SAxel Dörfler 	/* Do not use le16_to_cpu() macro here as our VOLUME_FLAGS are
99880bca3d3SAxel Dörfler 	   defined using cpu_to_le16() macro and hence are consistent. */
99980bca3d3SAxel Dörfler 	vol->flags = vinf->flags;
100080bca3d3SAxel Dörfler 	/*
100180bca3d3SAxel Dörfler 	 * Reinitialize the search context for the $Volume/$VOLUME_NAME lookup.
100280bca3d3SAxel Dörfler 	 */
100380bca3d3SAxel Dörfler 	ntfs_attr_reinit_search_ctx(ctx);
100480bca3d3SAxel Dörfler 	if (ntfs_attr_lookup(AT_VOLUME_NAME, AT_UNNAMED, 0, 0, 0, NULL, 0,
100580bca3d3SAxel Dörfler 			ctx)) {
100680bca3d3SAxel Dörfler 		if (errno != ENOENT) {
100780bca3d3SAxel Dörfler 			ntfs_log_perror("Failed to lookup of $VOLUME_NAME in "
100880bca3d3SAxel Dörfler 					"$Volume failed");
100980bca3d3SAxel Dörfler 			goto error_exit;
101080bca3d3SAxel Dörfler 		}
101180bca3d3SAxel Dörfler 		/*
101280bca3d3SAxel Dörfler 		 * Attribute not present.  This has been seen in the field.
101380bca3d3SAxel Dörfler 		 * Treat this the same way as if the attribute was present but
101480bca3d3SAxel Dörfler 		 * had zero length.
101580bca3d3SAxel Dörfler 		 */
101680bca3d3SAxel Dörfler 		vol->vol_name = ntfs_malloc(1);
1017*30bc84e9SGerasim Troeglazov 		if (!vol->vol_name)
101880bca3d3SAxel Dörfler 			goto error_exit;
101980bca3d3SAxel Dörfler 		vol->vol_name[0] = '\0';
102080bca3d3SAxel Dörfler 	} else {
102180bca3d3SAxel Dörfler 		a = ctx->attr;
102280bca3d3SAxel Dörfler 		/* Has to be resident. */
102380bca3d3SAxel Dörfler 		if (a->non_resident) {
102480bca3d3SAxel Dörfler 			ntfs_log_error("$VOLUME_NAME must be resident.\n");
102580bca3d3SAxel Dörfler 			errno = EIO;
102680bca3d3SAxel Dörfler 			goto error_exit;
102780bca3d3SAxel Dörfler 		}
102880bca3d3SAxel Dörfler 		/* Get a pointer to the value of the attribute. */
102980bca3d3SAxel Dörfler 		vname = (ntfschar*)(le16_to_cpu(a->value_offset) + (char*)a);
103080bca3d3SAxel Dörfler 		u = le32_to_cpu(a->value_length) / 2;
103180bca3d3SAxel Dörfler 		/*
103280bca3d3SAxel Dörfler 		 * Convert Unicode volume name to current locale multibyte
103380bca3d3SAxel Dörfler 		 * format.
103480bca3d3SAxel Dörfler 		 */
103580bca3d3SAxel Dörfler 		vol->vol_name = NULL;
103680bca3d3SAxel Dörfler 		if (ntfs_ucstombs(vname, u, &vol->vol_name, 0) == -1) {
103780bca3d3SAxel Dörfler 			ntfs_log_perror("Volume name could not be converted "
103880bca3d3SAxel Dörfler 					"to current locale");
103980bca3d3SAxel Dörfler 			ntfs_log_debug("Forcing name into ASCII by replacing "
104080bca3d3SAxel Dörfler 				"non-ASCII characters with underscores.\n");
104180bca3d3SAxel Dörfler 			vol->vol_name = ntfs_malloc(u + 1);
1042*30bc84e9SGerasim Troeglazov 			if (!vol->vol_name)
104380bca3d3SAxel Dörfler 				goto error_exit;
1044*30bc84e9SGerasim Troeglazov 
104580bca3d3SAxel Dörfler 			for (j = 0; j < (s32)u; j++) {
104680bca3d3SAxel Dörfler 				ntfschar uc = le16_to_cpu(vname[j]);
104780bca3d3SAxel Dörfler 				if (uc > 0xff)
104880bca3d3SAxel Dörfler 					uc = (ntfschar)'_';
104980bca3d3SAxel Dörfler 				vol->vol_name[j] = (char)uc;
105080bca3d3SAxel Dörfler 			}
105180bca3d3SAxel Dörfler 			vol->vol_name[u] = '\0';
105280bca3d3SAxel Dörfler 		}
105380bca3d3SAxel Dörfler 	}
105480bca3d3SAxel Dörfler 	ntfs_attr_put_search_ctx(ctx);
105580bca3d3SAxel Dörfler 	ctx = NULL;
105680bca3d3SAxel Dörfler 	/* Now load the attribute definitions from $AttrDef. */
1057*30bc84e9SGerasim Troeglazov 	ntfs_log_debug("Loading $AttrDef...\n");
105880bca3d3SAxel Dörfler 	ni = ntfs_inode_open(vol, FILE_AttrDef);
105980bca3d3SAxel Dörfler 	if (!ni) {
106080bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to open $AttrDef");
106180bca3d3SAxel Dörfler 		goto error_exit;
106280bca3d3SAxel Dörfler 	}
106380bca3d3SAxel Dörfler 	/* Get an ntfs attribute for $AttrDef/$DATA. */
106480bca3d3SAxel Dörfler 	na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
106580bca3d3SAxel Dörfler 	if (!na) {
106680bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to open ntfs attribute");
106780bca3d3SAxel Dörfler 		goto error_exit;
106880bca3d3SAxel Dörfler 	}
106980bca3d3SAxel Dörfler 	/* Check we don't overflow 32-bits. */
107080bca3d3SAxel Dörfler 	if (na->data_size > 0xffffffffLL) {
107180bca3d3SAxel Dörfler 		ntfs_log_error("Attribute definition table is too big (max "
107280bca3d3SAxel Dörfler 			       "32-bit allowed).\n");
107380bca3d3SAxel Dörfler 		errno = EINVAL;
107480bca3d3SAxel Dörfler 		goto error_exit;
107580bca3d3SAxel Dörfler 	}
107680bca3d3SAxel Dörfler 	vol->attrdef_len = na->data_size;
107780bca3d3SAxel Dörfler 	vol->attrdef = ntfs_malloc(na->data_size);
1078*30bc84e9SGerasim Troeglazov 	if (!vol->attrdef)
107980bca3d3SAxel Dörfler 		goto error_exit;
108080bca3d3SAxel Dörfler 	/* Read in the $DATA attribute value into the buffer. */
108180bca3d3SAxel Dörfler 	l = ntfs_attr_pread(na, 0, na->data_size, vol->attrdef);
108280bca3d3SAxel Dörfler 	if (l != na->data_size) {
108380bca3d3SAxel Dörfler 		ntfs_log_error("Failed to read $AttrDef, unexpected length "
10846b3592caSGerasim Troeglazov 			       "(%lld != %lld).\n", (long long)l,
10856b3592caSGerasim Troeglazov 			       (long long)na->data_size);
108680bca3d3SAxel Dörfler 		errno = EIO;
108780bca3d3SAxel Dörfler 		goto error_exit;
108880bca3d3SAxel Dörfler 	}
108980bca3d3SAxel Dörfler 	/* Done with the $AttrDef mft record. */
109080bca3d3SAxel Dörfler 	ntfs_attr_close(na);
109162cee9f9SGerasim Troeglazov 	if (ntfs_inode_close(ni)) {
109262cee9f9SGerasim Troeglazov 		ntfs_log_perror("Failed to close $AttrDef");
109362cee9f9SGerasim Troeglazov 		goto error_exit;
109462cee9f9SGerasim Troeglazov 	}
109580bca3d3SAxel Dörfler 	/*
109680bca3d3SAxel Dörfler 	 * Check for dirty logfile and hibernated Windows.
109780bca3d3SAxel Dörfler 	 * We care only about read-write mounts.
109880bca3d3SAxel Dörfler 	 */
109980bca3d3SAxel Dörfler 	if (!(flags & MS_RDONLY)) {
1100*30bc84e9SGerasim Troeglazov 		if (!(flags & MS_IGNORE_HIBERFILE) &&
1101*30bc84e9SGerasim Troeglazov 		    ntfs_volume_check_hiberfile(vol, 1) < 0)
110280bca3d3SAxel Dörfler 			goto error_exit;
110362cee9f9SGerasim Troeglazov 		if (ntfs_volume_check_logfile(vol) < 0) {
1104*30bc84e9SGerasim Troeglazov 			if (!(flags & MS_RECOVER))
110562cee9f9SGerasim Troeglazov 				goto error_exit;
1106*30bc84e9SGerasim Troeglazov 			ntfs_log_info("The file system wasn't safely "
1107*30bc84e9SGerasim Troeglazov 				      "closed on Windows. Fixing.\n");
110862cee9f9SGerasim Troeglazov 			if (ntfs_logfile_reset(vol))
110962cee9f9SGerasim Troeglazov 				goto error_exit;
111062cee9f9SGerasim Troeglazov 		}
111180bca3d3SAxel Dörfler 	}
111280bca3d3SAxel Dörfler 
111380bca3d3SAxel Dörfler 	return vol;
111480bca3d3SAxel Dörfler io_error_exit:
111580bca3d3SAxel Dörfler 	errno = EIO;
111680bca3d3SAxel Dörfler error_exit:
111780bca3d3SAxel Dörfler 	eo = errno;
111880bca3d3SAxel Dörfler 	if (ctx)
111980bca3d3SAxel Dörfler 		ntfs_attr_put_search_ctx(ctx);
112080bca3d3SAxel Dörfler 	free(m);
112180bca3d3SAxel Dörfler 	free(m2);
112280bca3d3SAxel Dörfler 	__ntfs_volume_release(vol);
112380bca3d3SAxel Dörfler 	errno = eo;
112480bca3d3SAxel Dörfler 	return NULL;
112580bca3d3SAxel Dörfler }
112680bca3d3SAxel Dörfler 
112780bca3d3SAxel Dörfler /**
112880bca3d3SAxel Dörfler  * ntfs_mount - open ntfs volume
112980bca3d3SAxel Dörfler  * @name:	name of device/file to open
113080bca3d3SAxel Dörfler  * @flags:	optional mount flags
113180bca3d3SAxel Dörfler  *
113280bca3d3SAxel Dörfler  * This function mounts an ntfs volume. @name should contain the name of the
113380bca3d3SAxel Dörfler  * device/file to mount as the ntfs volume.
113480bca3d3SAxel Dörfler  *
113580bca3d3SAxel Dörfler  * @flags is an optional second parameter. The same flags are used as for
113680bca3d3SAxel Dörfler  * the mount system call (man 2 mount). Currently only the following flags
1137*30bc84e9SGerasim Troeglazov  * is implemented:
113880bca3d3SAxel Dörfler  *	MS_RDONLY	- mount volume read-only
113980bca3d3SAxel Dörfler  *
114080bca3d3SAxel Dörfler  * The function opens the device or file @name and verifies that it contains a
114180bca3d3SAxel Dörfler  * valid bootsector. Then, it allocates an ntfs_volume structure and initializes
114280bca3d3SAxel Dörfler  * some of the values inside the structure from the information stored in the
114380bca3d3SAxel Dörfler  * bootsector. It proceeds to load the necessary system files and completes
114480bca3d3SAxel Dörfler  * setting up the structure.
114580bca3d3SAxel Dörfler  *
114680bca3d3SAxel Dörfler  * Return the allocated volume structure on success and NULL on error with
114780bca3d3SAxel Dörfler  * errno set to the error code.
114880bca3d3SAxel Dörfler  *
114980bca3d3SAxel Dörfler  * Note, that a copy is made of @name, and hence it can be discarded as
115080bca3d3SAxel Dörfler  * soon as the function returns.
115180bca3d3SAxel Dörfler  */
115280bca3d3SAxel Dörfler ntfs_volume *ntfs_mount(const char *name __attribute__((unused)),
115380bca3d3SAxel Dörfler 		unsigned long flags __attribute__((unused)))
115480bca3d3SAxel Dörfler {
115580bca3d3SAxel Dörfler #ifndef NO_NTFS_DEVICE_DEFAULT_IO_OPS
115680bca3d3SAxel Dörfler 	struct ntfs_device *dev;
115780bca3d3SAxel Dörfler 	ntfs_volume *vol;
115880bca3d3SAxel Dörfler 
115980bca3d3SAxel Dörfler 	/* Allocate an ntfs_device structure. */
116080bca3d3SAxel Dörfler 	dev = ntfs_device_alloc(name, 0, &ntfs_device_default_io_ops, NULL);
116180bca3d3SAxel Dörfler 	if (!dev)
116280bca3d3SAxel Dörfler 		return NULL;
116380bca3d3SAxel Dörfler 	/* Call ntfs_device_mount() to do the actual mount. */
116480bca3d3SAxel Dörfler 	vol = ntfs_device_mount(dev, flags);
116580bca3d3SAxel Dörfler 	if (!vol) {
116680bca3d3SAxel Dörfler 		int eo = errno;
116780bca3d3SAxel Dörfler 		ntfs_device_free(dev);
116880bca3d3SAxel Dörfler 		errno = eo;
116980bca3d3SAxel Dörfler 	}
117080bca3d3SAxel Dörfler 	return vol;
117180bca3d3SAxel Dörfler #else
117280bca3d3SAxel Dörfler 	/*
117380bca3d3SAxel Dörfler 	 * ntfs_mount() makes no sense if NO_NTFS_DEVICE_DEFAULT_IO_OPS is
117480bca3d3SAxel Dörfler 	 * defined as there are no device operations available in libntfs in
117580bca3d3SAxel Dörfler 	 * this case.
117680bca3d3SAxel Dörfler 	 */
117780bca3d3SAxel Dörfler 	errno = EOPNOTSUPP;
117880bca3d3SAxel Dörfler 	return NULL;
117980bca3d3SAxel Dörfler #endif
118080bca3d3SAxel Dörfler }
118180bca3d3SAxel Dörfler 
118280bca3d3SAxel Dörfler /**
118380bca3d3SAxel Dörfler  * ntfs_umount - close ntfs volume
118480bca3d3SAxel Dörfler  * @vol: address of ntfs_volume structure of volume to close
118580bca3d3SAxel Dörfler  * @force: if true force close the volume even if it is busy
118680bca3d3SAxel Dörfler  *
118780bca3d3SAxel Dörfler  * Deallocate all structures (including @vol itself) associated with the ntfs
118880bca3d3SAxel Dörfler  * volume @vol.
118980bca3d3SAxel Dörfler  *
119080bca3d3SAxel Dörfler  * Return 0 on success. On error return -1 with errno set appropriately
119180bca3d3SAxel Dörfler  * (most likely to one of EAGAIN, EBUSY or EINVAL). The EAGAIN error means that
119280bca3d3SAxel Dörfler  * an operation is in progress and if you try the close later the operation
119380bca3d3SAxel Dörfler  * might be completed and the close succeed.
119480bca3d3SAxel Dörfler  *
119580bca3d3SAxel Dörfler  * If @force is true (i.e. not zero) this function will close the volume even
119680bca3d3SAxel Dörfler  * if this means that data might be lost.
119780bca3d3SAxel Dörfler  *
119880bca3d3SAxel Dörfler  * @vol must have previously been returned by a call to ntfs_mount().
119980bca3d3SAxel Dörfler  *
120080bca3d3SAxel Dörfler  * @vol itself is deallocated and should no longer be dereferenced after this
120180bca3d3SAxel Dörfler  * function returns success. If it returns an error then nothing has been done
120280bca3d3SAxel Dörfler  * so it is safe to continue using @vol.
120380bca3d3SAxel Dörfler  */
120462cee9f9SGerasim Troeglazov int ntfs_umount(ntfs_volume *vol, const BOOL force __attribute__((unused)))
120580bca3d3SAxel Dörfler {
120680bca3d3SAxel Dörfler 	struct ntfs_device *dev;
120762cee9f9SGerasim Troeglazov 	int ret;
120880bca3d3SAxel Dörfler 
120980bca3d3SAxel Dörfler 	if (!vol) {
121080bca3d3SAxel Dörfler 		errno = EINVAL;
121180bca3d3SAxel Dörfler 		return -1;
121280bca3d3SAxel Dörfler 	}
121380bca3d3SAxel Dörfler 	dev = vol->dev;
121462cee9f9SGerasim Troeglazov 	ret = __ntfs_volume_release(vol);
121580bca3d3SAxel Dörfler 	ntfs_device_free(dev);
121662cee9f9SGerasim Troeglazov 	return ret;
121780bca3d3SAxel Dörfler }
121880bca3d3SAxel Dörfler 
121980bca3d3SAxel Dörfler #ifdef HAVE_MNTENT_H
122080bca3d3SAxel Dörfler 
122180bca3d3SAxel Dörfler #ifndef HAVE_REALPATH
122280bca3d3SAxel Dörfler /**
122380bca3d3SAxel Dörfler  * realpath - If there is no realpath on the system
122480bca3d3SAxel Dörfler  */
122580bca3d3SAxel Dörfler static char *realpath(const char *path, char *resolved_path)
122680bca3d3SAxel Dörfler {
122780bca3d3SAxel Dörfler 	strncpy(resolved_path, path, PATH_MAX);
122880bca3d3SAxel Dörfler 	resolved_path[PATH_MAX] = '\0';
122980bca3d3SAxel Dörfler 	return resolved_path;
123080bca3d3SAxel Dörfler }
123180bca3d3SAxel Dörfler #endif
123280bca3d3SAxel Dörfler 
123380bca3d3SAxel Dörfler /**
123480bca3d3SAxel Dörfler  * ntfs_mntent_check - desc
123580bca3d3SAxel Dörfler  *
123680bca3d3SAxel Dörfler  * If you are wanting to use this, you actually wanted to use
123780bca3d3SAxel Dörfler  * ntfs_check_if_mounted(), you just didn't realize. (-:
123880bca3d3SAxel Dörfler  *
123980bca3d3SAxel Dörfler  * See description of ntfs_check_if_mounted(), below.
124080bca3d3SAxel Dörfler  */
124180bca3d3SAxel Dörfler static int ntfs_mntent_check(const char *file, unsigned long *mnt_flags)
124280bca3d3SAxel Dörfler {
124380bca3d3SAxel Dörfler 	struct mntent *mnt;
124480bca3d3SAxel Dörfler 	char *real_file = NULL, *real_fsname = NULL;
124580bca3d3SAxel Dörfler 	FILE *f;
124680bca3d3SAxel Dörfler 	int err = 0;
124780bca3d3SAxel Dörfler 
124880bca3d3SAxel Dörfler 	real_file = ntfs_malloc(PATH_MAX + 1);
124980bca3d3SAxel Dörfler 	if (!real_file)
125080bca3d3SAxel Dörfler 		return -1;
125180bca3d3SAxel Dörfler 	real_fsname = ntfs_malloc(PATH_MAX + 1);
125280bca3d3SAxel Dörfler 	if (!real_fsname) {
125380bca3d3SAxel Dörfler 		err = errno;
125480bca3d3SAxel Dörfler 		goto exit;
125580bca3d3SAxel Dörfler 	}
125680bca3d3SAxel Dörfler 	if (!realpath(file, real_file)) {
125780bca3d3SAxel Dörfler 		err = errno;
125880bca3d3SAxel Dörfler 		goto exit;
125980bca3d3SAxel Dörfler 	}
126080bca3d3SAxel Dörfler 	if (!(f = setmntent(MOUNTED, "r"))) {
126180bca3d3SAxel Dörfler 		err = errno;
126280bca3d3SAxel Dörfler 		goto exit;
126380bca3d3SAxel Dörfler 	}
126480bca3d3SAxel Dörfler 	while ((mnt = getmntent(f))) {
126580bca3d3SAxel Dörfler 		if (!realpath(mnt->mnt_fsname, real_fsname))
126680bca3d3SAxel Dörfler 			continue;
126780bca3d3SAxel Dörfler 		if (!strcmp(real_file, real_fsname))
126880bca3d3SAxel Dörfler 			break;
126980bca3d3SAxel Dörfler 	}
127080bca3d3SAxel Dörfler 	endmntent(f);
127180bca3d3SAxel Dörfler 	if (!mnt)
127280bca3d3SAxel Dörfler 		goto exit;
127380bca3d3SAxel Dörfler 	*mnt_flags = NTFS_MF_MOUNTED;
127480bca3d3SAxel Dörfler 	if (!strcmp(mnt->mnt_dir, "/"))
127580bca3d3SAxel Dörfler 		*mnt_flags |= NTFS_MF_ISROOT;
127680bca3d3SAxel Dörfler #ifdef HAVE_HASMNTOPT
127780bca3d3SAxel Dörfler 	if (hasmntopt(mnt, "ro") && !hasmntopt(mnt, "rw"))
127880bca3d3SAxel Dörfler 		*mnt_flags |= NTFS_MF_READONLY;
127980bca3d3SAxel Dörfler #endif
128080bca3d3SAxel Dörfler exit:
128180bca3d3SAxel Dörfler 	free(real_file);
128280bca3d3SAxel Dörfler 	free(real_fsname);
128380bca3d3SAxel Dörfler 	if (err) {
128480bca3d3SAxel Dörfler 		errno = err;
128580bca3d3SAxel Dörfler 		return -1;
128680bca3d3SAxel Dörfler 	}
128780bca3d3SAxel Dörfler 	return 0;
128880bca3d3SAxel Dörfler }
128980bca3d3SAxel Dörfler #endif /* HAVE_MNTENT_H */
129080bca3d3SAxel Dörfler 
129180bca3d3SAxel Dörfler /**
129280bca3d3SAxel Dörfler  * ntfs_check_if_mounted - check if an ntfs volume is currently mounted
129380bca3d3SAxel Dörfler  * @file:	device file to check
129480bca3d3SAxel Dörfler  * @mnt_flags:	pointer into which to return the ntfs mount flags (see volume.h)
129580bca3d3SAxel Dörfler  *
129680bca3d3SAxel Dörfler  * If the running system does not support the {set,get,end}mntent() calls,
129780bca3d3SAxel Dörfler  * just return 0 and set *@mnt_flags to zero.
129880bca3d3SAxel Dörfler  *
129980bca3d3SAxel Dörfler  * When the system does support the calls, ntfs_check_if_mounted() first tries
130080bca3d3SAxel Dörfler  * to find the device @file in /etc/mtab (or wherever this is kept on the
130180bca3d3SAxel Dörfler  * running system). If it is not found, assume the device is not mounted and
130280bca3d3SAxel Dörfler  * return 0 and set *@mnt_flags to zero.
130380bca3d3SAxel Dörfler  *
130480bca3d3SAxel Dörfler  * If the device @file is found, set the NTFS_MF_MOUNTED flags in *@mnt_flags.
130580bca3d3SAxel Dörfler  *
130680bca3d3SAxel Dörfler  * Further if @file is mounted as the file system root ("/"), set the flag
130780bca3d3SAxel Dörfler  * NTFS_MF_ISROOT in *@mnt_flags.
130880bca3d3SAxel Dörfler  *
130980bca3d3SAxel Dörfler  * Finally, check if the file system is mounted read-only, and if so set the
131080bca3d3SAxel Dörfler  * NTFS_MF_READONLY flag in *@mnt_flags.
131180bca3d3SAxel Dörfler  *
131280bca3d3SAxel Dörfler  * On success return 0 with *@mnt_flags set to the ntfs mount flags.
131380bca3d3SAxel Dörfler  *
131480bca3d3SAxel Dörfler  * On error return -1 with errno set to the error code.
131580bca3d3SAxel Dörfler  */
131680bca3d3SAxel Dörfler int ntfs_check_if_mounted(const char *file __attribute__((unused)),
131780bca3d3SAxel Dörfler 		unsigned long *mnt_flags)
131880bca3d3SAxel Dörfler {
131980bca3d3SAxel Dörfler 	*mnt_flags = 0;
132080bca3d3SAxel Dörfler #ifdef HAVE_MNTENT_H
132180bca3d3SAxel Dörfler 	return ntfs_mntent_check(file, mnt_flags);
132280bca3d3SAxel Dörfler #else
132380bca3d3SAxel Dörfler 	return 0;
132480bca3d3SAxel Dörfler #endif
132580bca3d3SAxel Dörfler }
132680bca3d3SAxel Dörfler 
132780bca3d3SAxel Dörfler /**
132880bca3d3SAxel Dörfler  * ntfs_version_is_supported - check if NTFS version is supported.
132980bca3d3SAxel Dörfler  * @vol:	ntfs volume whose version we're interested in.
133080bca3d3SAxel Dörfler  *
133180bca3d3SAxel Dörfler  * The function checks if the NTFS volume version is known or not.
133280bca3d3SAxel Dörfler  * Version 1.1 and 1.2 are used by Windows NT3.x and NT4.
133380bca3d3SAxel Dörfler  * Version 2.x is used by Windows 2000 Betas.
133480bca3d3SAxel Dörfler  * Version 3.0 is used by Windows 2000.
133580bca3d3SAxel Dörfler  * Version 3.1 is used by Windows XP, Windows Server 2003 and Longhorn.
133680bca3d3SAxel Dörfler  *
133780bca3d3SAxel Dörfler  * Return 0 if NTFS version is supported otherwise -1 with errno set.
133880bca3d3SAxel Dörfler  *
133980bca3d3SAxel Dörfler  * The following error codes are defined:
134080bca3d3SAxel Dörfler  *	EOPNOTSUPP - Unknown NTFS version
134180bca3d3SAxel Dörfler  *	EINVAL	   - Invalid argument
134280bca3d3SAxel Dörfler  */
134380bca3d3SAxel Dörfler int ntfs_version_is_supported(ntfs_volume *vol)
134480bca3d3SAxel Dörfler {
134580bca3d3SAxel Dörfler 	u8 major, minor;
134680bca3d3SAxel Dörfler 
134780bca3d3SAxel Dörfler 	if (!vol) {
134880bca3d3SAxel Dörfler 		errno = EINVAL;
134980bca3d3SAxel Dörfler 		return -1;
135080bca3d3SAxel Dörfler 	}
135180bca3d3SAxel Dörfler 
135280bca3d3SAxel Dörfler 	major = vol->major_ver;
135380bca3d3SAxel Dörfler 	minor = vol->minor_ver;
135480bca3d3SAxel Dörfler 
135580bca3d3SAxel Dörfler 	if (NTFS_V1_1(major, minor) || NTFS_V1_2(major, minor))
135680bca3d3SAxel Dörfler 		return 0;
135780bca3d3SAxel Dörfler 
135880bca3d3SAxel Dörfler 	if (NTFS_V2_X(major, minor))
135980bca3d3SAxel Dörfler 		return 0;
136080bca3d3SAxel Dörfler 
136180bca3d3SAxel Dörfler 	if (NTFS_V3_0(major, minor) || NTFS_V3_1(major, minor))
136280bca3d3SAxel Dörfler 		return 0;
136380bca3d3SAxel Dörfler 
136480bca3d3SAxel Dörfler 	errno = EOPNOTSUPP;
136580bca3d3SAxel Dörfler 	return -1;
136680bca3d3SAxel Dörfler }
136780bca3d3SAxel Dörfler 
136880bca3d3SAxel Dörfler /**
136980bca3d3SAxel Dörfler  * ntfs_logfile_reset - "empty" $LogFile data attribute value
137080bca3d3SAxel Dörfler  * @vol:	ntfs volume whose $LogFile we intend to reset.
137180bca3d3SAxel Dörfler  *
137280bca3d3SAxel Dörfler  * Fill the value of the $LogFile data attribute, i.e. the contents of
137380bca3d3SAxel Dörfler  * the file, with 0xff's, thus marking the journal as empty.
137480bca3d3SAxel Dörfler  *
137580bca3d3SAxel Dörfler  * FIXME(?): We might need to zero the LSN field of every single mft
137680bca3d3SAxel Dörfler  * record as well. (But, first try without doing that and see what
137780bca3d3SAxel Dörfler  * happens, since chkdsk might pickup the pieces and do it for us...)
137880bca3d3SAxel Dörfler  *
137980bca3d3SAxel Dörfler  * On success return 0.
138080bca3d3SAxel Dörfler  *
138180bca3d3SAxel Dörfler  * On error return -1 with errno set to the error code.
138280bca3d3SAxel Dörfler  */
138380bca3d3SAxel Dörfler int ntfs_logfile_reset(ntfs_volume *vol)
138480bca3d3SAxel Dörfler {
138580bca3d3SAxel Dörfler 	ntfs_inode *ni;
138680bca3d3SAxel Dörfler 	ntfs_attr *na;
138780bca3d3SAxel Dörfler 	int eo;
138880bca3d3SAxel Dörfler 
138980bca3d3SAxel Dörfler 	if (!vol) {
139080bca3d3SAxel Dörfler 		errno = EINVAL;
139180bca3d3SAxel Dörfler 		return -1;
139280bca3d3SAxel Dörfler 	}
139380bca3d3SAxel Dörfler 
139462cee9f9SGerasim Troeglazov 	ni = ntfs_inode_open(vol, FILE_LogFile);
139562cee9f9SGerasim Troeglazov 	if (!ni) {
139662cee9f9SGerasim Troeglazov 		ntfs_log_perror("Failed to open inode FILE_LogFile");
139780bca3d3SAxel Dörfler 		return -1;
139880bca3d3SAxel Dörfler 	}
139980bca3d3SAxel Dörfler 
140062cee9f9SGerasim Troeglazov 	na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
140162cee9f9SGerasim Troeglazov 	if (!na) {
140280bca3d3SAxel Dörfler 		eo = errno;
140380bca3d3SAxel Dörfler 		ntfs_log_perror("Failed to open $FILE_LogFile/$DATA");
140480bca3d3SAxel Dörfler 		goto error_exit;
140580bca3d3SAxel Dörfler 	}
140680bca3d3SAxel Dörfler 
140780bca3d3SAxel Dörfler 	if (ntfs_empty_logfile(na)) {
140880bca3d3SAxel Dörfler 		eo = errno;
140980bca3d3SAxel Dörfler 		ntfs_attr_close(na);
141080bca3d3SAxel Dörfler 		goto error_exit;
141180bca3d3SAxel Dörfler 	}
141262cee9f9SGerasim Troeglazov 
141380bca3d3SAxel Dörfler 	ntfs_attr_close(na);
141480bca3d3SAxel Dörfler 	return ntfs_inode_close(ni);
141580bca3d3SAxel Dörfler 
141680bca3d3SAxel Dörfler error_exit:
141780bca3d3SAxel Dörfler 	ntfs_inode_close(ni);
141880bca3d3SAxel Dörfler 	errno = eo;
141980bca3d3SAxel Dörfler 	return -1;
142080bca3d3SAxel Dörfler }
142180bca3d3SAxel Dörfler 
142280bca3d3SAxel Dörfler /**
142380bca3d3SAxel Dörfler  * ntfs_volume_write_flags - set the flags of an ntfs volume
142480bca3d3SAxel Dörfler  * @vol:	ntfs volume where we set the volume flags
142580bca3d3SAxel Dörfler  * @flags:	new flags
142680bca3d3SAxel Dörfler  *
142780bca3d3SAxel Dörfler  * Set the on-disk volume flags in the mft record of $Volume and
142880bca3d3SAxel Dörfler  * on volume @vol to @flags.
142980bca3d3SAxel Dörfler  *
143080bca3d3SAxel Dörfler  * Return 0 if successful and -1 if not with errno set to the error code.
143180bca3d3SAxel Dörfler  */
143280bca3d3SAxel Dörfler int ntfs_volume_write_flags(ntfs_volume *vol, const u16 flags)
143380bca3d3SAxel Dörfler {
143480bca3d3SAxel Dörfler 	ATTR_RECORD *a;
143580bca3d3SAxel Dörfler 	VOLUME_INFORMATION *c;
143680bca3d3SAxel Dörfler 	ntfs_attr_search_ctx *ctx;
143780bca3d3SAxel Dörfler 	int ret = -1;	/* failure */
143880bca3d3SAxel Dörfler 
143980bca3d3SAxel Dörfler 	if (!vol || !vol->vol_ni) {
144080bca3d3SAxel Dörfler 		errno = EINVAL;
144180bca3d3SAxel Dörfler 		return -1;
144280bca3d3SAxel Dörfler 	}
144380bca3d3SAxel Dörfler 	/* Get a pointer to the volume information attribute. */
144480bca3d3SAxel Dörfler 	ctx = ntfs_attr_get_search_ctx(vol->vol_ni, NULL);
1445*30bc84e9SGerasim Troeglazov 	if (!ctx)
144680bca3d3SAxel Dörfler 		return -1;
1447*30bc84e9SGerasim Troeglazov 
144880bca3d3SAxel Dörfler 	if (ntfs_attr_lookup(AT_VOLUME_INFORMATION, AT_UNNAMED, 0, 0, 0, NULL,
144980bca3d3SAxel Dörfler 			0, ctx)) {
145080bca3d3SAxel Dörfler 		ntfs_log_error("Attribute $VOLUME_INFORMATION was not found "
145180bca3d3SAxel Dörfler 			       "in $Volume!\n");
145280bca3d3SAxel Dörfler 		goto err_out;
145380bca3d3SAxel Dörfler 	}
145480bca3d3SAxel Dörfler 	a = ctx->attr;
145580bca3d3SAxel Dörfler 	/* Sanity check. */
145680bca3d3SAxel Dörfler 	if (a->non_resident) {
145780bca3d3SAxel Dörfler 		ntfs_log_error("Attribute $VOLUME_INFORMATION must be resident "
145880bca3d3SAxel Dörfler 			       "but it isn't.\n");
145980bca3d3SAxel Dörfler 		errno = EIO;
146080bca3d3SAxel Dörfler 		goto err_out;
146180bca3d3SAxel Dörfler 	}
146280bca3d3SAxel Dörfler 	/* Get a pointer to the value of the attribute. */
146380bca3d3SAxel Dörfler 	c = (VOLUME_INFORMATION*)(le16_to_cpu(a->value_offset) + (char*)a);
146480bca3d3SAxel Dörfler 	/* Sanity checks. */
146580bca3d3SAxel Dörfler 	if ((char*)c + le32_to_cpu(a->value_length) > (char*)ctx->mrec +
146680bca3d3SAxel Dörfler 			le32_to_cpu(ctx->mrec->bytes_in_use) ||
146780bca3d3SAxel Dörfler 			le16_to_cpu(a->value_offset) +
146880bca3d3SAxel Dörfler 			le32_to_cpu(a->value_length) > le32_to_cpu(a->length)) {
146980bca3d3SAxel Dörfler 		ntfs_log_error("Attribute $VOLUME_INFORMATION in $Volume is "
147080bca3d3SAxel Dörfler 			       "corrupt!\n");
147180bca3d3SAxel Dörfler 		errno = EIO;
147280bca3d3SAxel Dörfler 		goto err_out;
147380bca3d3SAxel Dörfler 	}
147480bca3d3SAxel Dörfler 	/* Set the volume flags. */
147580bca3d3SAxel Dörfler 	vol->flags = c->flags = flags & VOLUME_FLAGS_MASK;
147680bca3d3SAxel Dörfler 	/* Write them to disk. */
147780bca3d3SAxel Dörfler 	ntfs_inode_mark_dirty(vol->vol_ni);
1478*30bc84e9SGerasim Troeglazov 	if (ntfs_inode_sync(vol->vol_ni))
147980bca3d3SAxel Dörfler 		goto err_out;
1480*30bc84e9SGerasim Troeglazov 
148180bca3d3SAxel Dörfler 	ret = 0; /* success */
148280bca3d3SAxel Dörfler err_out:
148380bca3d3SAxel Dörfler 	ntfs_attr_put_search_ctx(ctx);
148480bca3d3SAxel Dörfler 	return ret;
148580bca3d3SAxel Dörfler }
148680bca3d3SAxel Dörfler 
1487*30bc84e9SGerasim Troeglazov int ntfs_volume_error(int err)
1488*30bc84e9SGerasim Troeglazov {
1489*30bc84e9SGerasim Troeglazov 	int ret;
1490*30bc84e9SGerasim Troeglazov 
1491*30bc84e9SGerasim Troeglazov 	switch (err) {
1492*30bc84e9SGerasim Troeglazov 		case 0:
1493*30bc84e9SGerasim Troeglazov 			ret = NTFS_VOLUME_OK;
1494*30bc84e9SGerasim Troeglazov 			break;
1495*30bc84e9SGerasim Troeglazov 		case EINVAL:
1496*30bc84e9SGerasim Troeglazov 			ret = NTFS_VOLUME_NOT_NTFS;
1497*30bc84e9SGerasim Troeglazov 			break;
1498*30bc84e9SGerasim Troeglazov 		case EIO:
1499*30bc84e9SGerasim Troeglazov 			ret = NTFS_VOLUME_CORRUPT;
1500*30bc84e9SGerasim Troeglazov 			break;
1501*30bc84e9SGerasim Troeglazov 		case EPERM:
1502*30bc84e9SGerasim Troeglazov 			ret = NTFS_VOLUME_HIBERNATED;
1503*30bc84e9SGerasim Troeglazov 			break;
1504*30bc84e9SGerasim Troeglazov 		case EOPNOTSUPP:
1505*30bc84e9SGerasim Troeglazov 			ret = NTFS_VOLUME_UNCLEAN_UNMOUNT;
1506*30bc84e9SGerasim Troeglazov 			break;
1507*30bc84e9SGerasim Troeglazov 		case EBUSY:
1508*30bc84e9SGerasim Troeglazov 			ret = NTFS_VOLUME_LOCKED;
1509*30bc84e9SGerasim Troeglazov 			break;
1510*30bc84e9SGerasim Troeglazov 		case ENXIO:
1511*30bc84e9SGerasim Troeglazov 			ret = NTFS_VOLUME_RAID;
1512*30bc84e9SGerasim Troeglazov 			break;
1513*30bc84e9SGerasim Troeglazov 		case EACCES:
1514*30bc84e9SGerasim Troeglazov 			ret = NTFS_VOLUME_NO_PRIVILEGE;
1515*30bc84e9SGerasim Troeglazov 			break;
1516*30bc84e9SGerasim Troeglazov 		default:
1517*30bc84e9SGerasim Troeglazov 			ret = NTFS_VOLUME_UNKNOWN_REASON;
1518*30bc84e9SGerasim Troeglazov 			break;
1519*30bc84e9SGerasim Troeglazov 	}
1520*30bc84e9SGerasim Troeglazov 	return ret;
1521*30bc84e9SGerasim Troeglazov }
1522*30bc84e9SGerasim Troeglazov 
1523*30bc84e9SGerasim Troeglazov 
1524*30bc84e9SGerasim Troeglazov void ntfs_mount_error(const char *volume, const char *mntpoint, int err)
1525*30bc84e9SGerasim Troeglazov {
1526*30bc84e9SGerasim Troeglazov 	switch (err) {
1527*30bc84e9SGerasim Troeglazov 		case NTFS_VOLUME_NOT_NTFS:
1528*30bc84e9SGerasim Troeglazov 			ntfs_log_error(invalid_ntfs_msg, volume);
1529*30bc84e9SGerasim Troeglazov 			break;
1530*30bc84e9SGerasim Troeglazov 		case NTFS_VOLUME_CORRUPT:
1531*30bc84e9SGerasim Troeglazov 			ntfs_log_error("%s", corrupt_volume_msg);
1532*30bc84e9SGerasim Troeglazov 			break;
1533*30bc84e9SGerasim Troeglazov 		case NTFS_VOLUME_HIBERNATED:
1534*30bc84e9SGerasim Troeglazov 			ntfs_log_error(hibernated_volume_msg, volume, mntpoint);
1535*30bc84e9SGerasim Troeglazov 			break;
1536*30bc84e9SGerasim Troeglazov 		case NTFS_VOLUME_UNCLEAN_UNMOUNT:
1537*30bc84e9SGerasim Troeglazov 			ntfs_log_error("%s", unclean_journal_msg);
1538*30bc84e9SGerasim Troeglazov 			break;
1539*30bc84e9SGerasim Troeglazov 		case NTFS_VOLUME_LOCKED:
1540*30bc84e9SGerasim Troeglazov 			ntfs_log_error("%s", opened_volume_msg);
1541*30bc84e9SGerasim Troeglazov 			break;
1542*30bc84e9SGerasim Troeglazov 		case NTFS_VOLUME_RAID:
1543*30bc84e9SGerasim Troeglazov 			ntfs_log_error("%s", fakeraid_msg);
1544*30bc84e9SGerasim Troeglazov 			break;
1545*30bc84e9SGerasim Troeglazov 		case NTFS_VOLUME_NO_PRIVILEGE:
1546*30bc84e9SGerasim Troeglazov 			ntfs_log_error(access_denied_msg, volume);
1547*30bc84e9SGerasim Troeglazov 			break;
1548*30bc84e9SGerasim Troeglazov 	}
1549*30bc84e9SGerasim Troeglazov }
1550*30bc84e9SGerasim Troeglazov 
1551*30bc84e9SGerasim Troeglazov int ntfs_set_locale(void)
1552*30bc84e9SGerasim Troeglazov {
1553*30bc84e9SGerasim Troeglazov #ifndef __HAIKU__
1554*30bc84e9SGerasim Troeglazov 	const char *locale;
1555*30bc84e9SGerasim Troeglazov 
1556*30bc84e9SGerasim Troeglazov 	locale = setlocale(LC_ALL, "");
1557*30bc84e9SGerasim Troeglazov 	if (!locale) {
1558*30bc84e9SGerasim Troeglazov 		locale = setlocale(LC_ALL, NULL);
1559*30bc84e9SGerasim Troeglazov 		ntfs_log_error("Couldn't set local environment, using default "
1560*30bc84e9SGerasim Troeglazov 			       "'%s'.\n", locale);
1561*30bc84e9SGerasim Troeglazov 		return 1;
1562*30bc84e9SGerasim Troeglazov 	}
1563*30bc84e9SGerasim Troeglazov #endif
1564*30bc84e9SGerasim Troeglazov 	return 0;
1565*30bc84e9SGerasim Troeglazov }
1566*30bc84e9SGerasim Troeglazov 
1567