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
530bc84e9SGerasim Troeglazov * Copyright (c) 2002-2009 Szabolcs Szakacsits
680bca3d3SAxel Dörfler * Copyright (c) 2004-2005 Richard Russon
70d2c294fSGerasim Troeglazov * Copyright (c) 2010 Jean-Pierre Andre
880bca3d3SAxel Dörfler *
980bca3d3SAxel Dörfler * This program/include file is free software; you can redistribute it and/or
1080bca3d3SAxel Dörfler * modify it under the terms of the GNU General Public License as published
1180bca3d3SAxel Dörfler * by the Free Software Foundation; either version 2 of the License, or
1280bca3d3SAxel Dörfler * (at your option) any later version.
1380bca3d3SAxel Dörfler *
1480bca3d3SAxel Dörfler * This program/include file is distributed in the hope that it will be
1580bca3d3SAxel Dörfler * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
1680bca3d3SAxel Dörfler * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1780bca3d3SAxel Dörfler * GNU General Public License for more details.
1880bca3d3SAxel Dörfler *
1980bca3d3SAxel Dörfler * You should have received a copy of the GNU General Public License
2080bca3d3SAxel Dörfler * along with this program (in the main directory of the NTFS-3G
2180bca3d3SAxel Dörfler * distribution in the file COPYING); if not, write to the Free Software
2280bca3d3SAxel Dörfler * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2380bca3d3SAxel Dörfler */
2480bca3d3SAxel Dörfler
2580bca3d3SAxel Dörfler #ifdef HAVE_CONFIG_H
2680bca3d3SAxel Dörfler #include "config.h"
2780bca3d3SAxel Dörfler #endif
2880bca3d3SAxel Dörfler
2980bca3d3SAxel Dörfler #ifdef HAVE_STDLIB_H
3080bca3d3SAxel Dörfler #include <stdlib.h>
3180bca3d3SAxel Dörfler #endif
3280bca3d3SAxel Dörfler #ifdef HAVE_STDIO_H
3380bca3d3SAxel Dörfler #include <stdio.h>
3480bca3d3SAxel Dörfler #endif
3580bca3d3SAxel Dörfler #ifdef HAVE_STRING_H
3680bca3d3SAxel Dörfler #include <string.h>
3780bca3d3SAxel Dörfler #endif
3880bca3d3SAxel Dörfler #ifdef HAVE_FCNTL_H
3980bca3d3SAxel Dörfler #include <fcntl.h>
4080bca3d3SAxel Dörfler #endif
4180bca3d3SAxel Dörfler #ifdef HAVE_UNISTD_H
4280bca3d3SAxel Dörfler #include <unistd.h>
4380bca3d3SAxel Dörfler #endif
4480bca3d3SAxel Dörfler #ifdef HAVE_ERRNO_H
4580bca3d3SAxel Dörfler #include <errno.h>
4680bca3d3SAxel Dörfler #endif
4780bca3d3SAxel Dörfler #ifdef HAVE_SYS_STAT_H
4880bca3d3SAxel Dörfler #include <sys/stat.h>
4980bca3d3SAxel Dörfler #endif
5080bca3d3SAxel Dörfler #ifdef HAVE_LIMITS_H
5180bca3d3SAxel Dörfler #include <limits.h>
5280bca3d3SAxel Dörfler #endif
5330bc84e9SGerasim Troeglazov #ifdef HAVE_LOCALE_H
5430bc84e9SGerasim Troeglazov #include <locale.h>
5530bc84e9SGerasim Troeglazov #endif
5680bca3d3SAxel Dörfler
57da0906f2SGerasim Troeglazov #if defined(__sun) && defined (__SVR4)
58da0906f2SGerasim Troeglazov #include <sys/mnttab.h>
59da0906f2SGerasim Troeglazov #endif
60da0906f2SGerasim Troeglazov
61a814d850Sthreedeyes #include "param.h"
6230bc84e9SGerasim Troeglazov #include "compat.h"
6380bca3d3SAxel Dörfler #include "volume.h"
6480bca3d3SAxel Dörfler #include "attrib.h"
6580bca3d3SAxel Dörfler #include "mft.h"
6680bca3d3SAxel Dörfler #include "bootsect.h"
6780bca3d3SAxel Dörfler #include "device.h"
6880bca3d3SAxel Dörfler #include "debug.h"
6980bca3d3SAxel Dörfler #include "inode.h"
7080bca3d3SAxel Dörfler #include "runlist.h"
7180bca3d3SAxel Dörfler #include "logfile.h"
7280bca3d3SAxel Dörfler #include "dir.h"
7380bca3d3SAxel Dörfler #include "logging.h"
740d2c294fSGerasim Troeglazov #include "cache.h"
75a814d850Sthreedeyes #include "realpath.h"
7680bca3d3SAxel Dörfler #include "misc.h"
770490778eSAugustin Cavalier #include "security.h"
7880bca3d3SAxel Dörfler
7930bc84e9SGerasim Troeglazov const char *ntfs_home =
80*4cb94084SAugustin Cavalier "News, support and information: https://github.com/tuxera/ntfs-3g/\n";
8130bc84e9SGerasim Troeglazov
8230bc84e9SGerasim Troeglazov static const char *invalid_ntfs_msg =
8330bc84e9SGerasim Troeglazov "The device '%s' doesn't seem to have a valid NTFS.\n"
8430bc84e9SGerasim Troeglazov "Maybe the wrong device is used? Or the whole disk instead of a\n"
8530bc84e9SGerasim Troeglazov "partition (e.g. /dev/sda, not /dev/sda1)? Or the other way around?\n";
8630bc84e9SGerasim Troeglazov
8730bc84e9SGerasim Troeglazov static const char *corrupt_volume_msg =
8830bc84e9SGerasim Troeglazov "NTFS is either inconsistent, or there is a hardware fault, or it's a\n"
8930bc84e9SGerasim Troeglazov "SoftRAID/FakeRAID hardware. In the first case run chkdsk /f on Windows\n"
9030bc84e9SGerasim Troeglazov "then reboot into Windows twice. The usage of the /f parameter is very\n"
9130bc84e9SGerasim Troeglazov "important! If the device is a SoftRAID/FakeRAID then first activate\n"
9230bc84e9SGerasim Troeglazov "it and mount a different device under the /dev/mapper/ directory, (e.g.\n"
9330bc84e9SGerasim Troeglazov "/dev/mapper/nvidia_eahaabcc1). Please see the 'dmraid' documentation\n"
9430bc84e9SGerasim Troeglazov "for more details.\n";
9530bc84e9SGerasim Troeglazov
9630bc84e9SGerasim Troeglazov static const char *hibernated_volume_msg =
97da0906f2SGerasim Troeglazov "The NTFS partition is in an unsafe state. Please resume and shutdown\n"
98da0906f2SGerasim Troeglazov "Windows fully (no hibernation or fast restarting), or mount the volume\n"
99da0906f2SGerasim Troeglazov "read-only with the 'ro' mount option.\n";
10030bc84e9SGerasim Troeglazov
1010490778eSAugustin Cavalier static const char *fallback_readonly_msg =
1020490778eSAugustin Cavalier "Falling back to read-only mount because the NTFS partition is in an\n"
1030490778eSAugustin Cavalier "unsafe state. Please resume and shutdown Windows fully (no hibernation\n"
1040490778eSAugustin Cavalier "or fast restarting.)\n";
1050490778eSAugustin Cavalier
10630bc84e9SGerasim Troeglazov static const char *unclean_journal_msg =
10730bc84e9SGerasim Troeglazov "Write access is denied because the disk wasn't safely powered\n"
10830bc84e9SGerasim Troeglazov "off and the 'norecover' mount option was specified.\n";
10930bc84e9SGerasim Troeglazov
11030bc84e9SGerasim Troeglazov static const char *opened_volume_msg =
11130bc84e9SGerasim Troeglazov "Mount is denied because the NTFS volume is already exclusively opened.\n"
11230bc84e9SGerasim Troeglazov "The volume may be already mounted, or another software may use it which\n"
11330bc84e9SGerasim Troeglazov "could be identified for example by the help of the 'fuser' command.\n";
11430bc84e9SGerasim Troeglazov
11530bc84e9SGerasim Troeglazov static const char *fakeraid_msg =
11630bc84e9SGerasim Troeglazov "Either the device is missing or it's powered down, or you have\n"
11730bc84e9SGerasim Troeglazov "SoftRAID hardware and must use an activated, different device under\n"
11830bc84e9SGerasim Troeglazov "/dev/mapper/, (e.g. /dev/mapper/nvidia_eahaabcc1) to mount NTFS.\n"
11930bc84e9SGerasim Troeglazov "Please see the 'dmraid' documentation for help.\n";
12030bc84e9SGerasim Troeglazov
12130bc84e9SGerasim Troeglazov static const char *access_denied_msg =
12230bc84e9SGerasim Troeglazov "Please check '%s' and the ntfs-3g binary permissions,\n"
12330bc84e9SGerasim Troeglazov "and the mounting user ID. More explanation is provided at\n"
124*4cb94084SAugustin Cavalier "https://github.com/tuxera/ntfs-3g/wiki/NTFS-3G-FAQ\n";
12580bca3d3SAxel Dörfler
12680bca3d3SAxel Dörfler /**
12780bca3d3SAxel Dörfler * ntfs_volume_alloc - Create an NTFS volume object and initialise it
12880bca3d3SAxel Dörfler *
12980bca3d3SAxel Dörfler * Description...
13080bca3d3SAxel Dörfler *
13180bca3d3SAxel Dörfler * Returns:
13280bca3d3SAxel Dörfler */
ntfs_volume_alloc(void)13380bca3d3SAxel Dörfler ntfs_volume *ntfs_volume_alloc(void)
13480bca3d3SAxel Dörfler {
13530bc84e9SGerasim Troeglazov return ntfs_calloc(sizeof(ntfs_volume));
13680bca3d3SAxel Dörfler }
13780bca3d3SAxel Dörfler
ntfs_attr_free(ntfs_attr ** na)13862cee9f9SGerasim Troeglazov static void ntfs_attr_free(ntfs_attr **na)
13962cee9f9SGerasim Troeglazov {
14062cee9f9SGerasim Troeglazov if (na && *na) {
14162cee9f9SGerasim Troeglazov ntfs_attr_close(*na);
14262cee9f9SGerasim Troeglazov *na = NULL;
14330bc84e9SGerasim Troeglazov }
14462cee9f9SGerasim Troeglazov }
14562cee9f9SGerasim Troeglazov
ntfs_inode_free(ntfs_inode ** ni)14662cee9f9SGerasim Troeglazov static int ntfs_inode_free(ntfs_inode **ni)
14762cee9f9SGerasim Troeglazov {
14862cee9f9SGerasim Troeglazov int ret = -1;
14962cee9f9SGerasim Troeglazov
15062cee9f9SGerasim Troeglazov if (ni && *ni) {
15162cee9f9SGerasim Troeglazov ret = ntfs_inode_close(*ni);
15262cee9f9SGerasim Troeglazov *ni = NULL;
15330bc84e9SGerasim Troeglazov }
15462cee9f9SGerasim Troeglazov
15562cee9f9SGerasim Troeglazov return ret;
15662cee9f9SGerasim Troeglazov }
15762cee9f9SGerasim Troeglazov
ntfs_error_set(int * err)15862cee9f9SGerasim Troeglazov static void ntfs_error_set(int *err)
15962cee9f9SGerasim Troeglazov {
16062cee9f9SGerasim Troeglazov if (!*err)
16162cee9f9SGerasim Troeglazov *err = errno;
16262cee9f9SGerasim Troeglazov }
16362cee9f9SGerasim Troeglazov
16480bca3d3SAxel Dörfler /**
16580bca3d3SAxel Dörfler * __ntfs_volume_release - Destroy an NTFS volume object
16680bca3d3SAxel Dörfler * @v:
16780bca3d3SAxel Dörfler *
16880bca3d3SAxel Dörfler * Description...
16980bca3d3SAxel Dörfler *
17080bca3d3SAxel Dörfler * Returns:
17180bca3d3SAxel Dörfler */
__ntfs_volume_release(ntfs_volume * v)17262cee9f9SGerasim Troeglazov static int __ntfs_volume_release(ntfs_volume *v)
17380bca3d3SAxel Dörfler {
17462cee9f9SGerasim Troeglazov int err = 0;
17562cee9f9SGerasim Troeglazov
1760490778eSAugustin Cavalier if (ntfs_close_secure(v))
1770490778eSAugustin Cavalier ntfs_error_set(&err);
1780490778eSAugustin Cavalier
17962cee9f9SGerasim Troeglazov if (ntfs_inode_free(&v->vol_ni))
18062cee9f9SGerasim Troeglazov ntfs_error_set(&err);
18162cee9f9SGerasim Troeglazov /*
18262cee9f9SGerasim Troeglazov * FIXME: Inodes must be synced before closing
18362cee9f9SGerasim Troeglazov * attributes, otherwise unmount could fail.
18462cee9f9SGerasim Troeglazov */
18580bca3d3SAxel Dörfler if (v->lcnbmp_ni && NInoDirty(v->lcnbmp_ni))
18680bca3d3SAxel Dörfler ntfs_inode_sync(v->lcnbmp_ni);
18762cee9f9SGerasim Troeglazov ntfs_attr_free(&v->lcnbmp_na);
18862cee9f9SGerasim Troeglazov if (ntfs_inode_free(&v->lcnbmp_ni))
18962cee9f9SGerasim Troeglazov ntfs_error_set(&err);
19062cee9f9SGerasim Troeglazov
19180bca3d3SAxel Dörfler if (v->mft_ni && NInoDirty(v->mft_ni))
19280bca3d3SAxel Dörfler ntfs_inode_sync(v->mft_ni);
19362cee9f9SGerasim Troeglazov ntfs_attr_free(&v->mftbmp_na);
19462cee9f9SGerasim Troeglazov ntfs_attr_free(&v->mft_na);
19562cee9f9SGerasim Troeglazov if (ntfs_inode_free(&v->mft_ni))
19662cee9f9SGerasim Troeglazov ntfs_error_set(&err);
19762cee9f9SGerasim Troeglazov
19880bca3d3SAxel Dörfler if (v->mftmirr_ni && NInoDirty(v->mftmirr_ni))
19980bca3d3SAxel Dörfler ntfs_inode_sync(v->mftmirr_ni);
20062cee9f9SGerasim Troeglazov ntfs_attr_free(&v->mftmirr_na);
20162cee9f9SGerasim Troeglazov if (ntfs_inode_free(&v->mftmirr_ni))
20262cee9f9SGerasim Troeglazov ntfs_error_set(&err);
20362cee9f9SGerasim Troeglazov
20480bca3d3SAxel Dörfler if (v->dev) {
20580bca3d3SAxel Dörfler struct ntfs_device *dev = v->dev;
20680bca3d3SAxel Dörfler
20762cee9f9SGerasim Troeglazov if (dev->d_ops->sync(dev))
20862cee9f9SGerasim Troeglazov ntfs_error_set(&err);
20980bca3d3SAxel Dörfler if (dev->d_ops->close(dev))
21062cee9f9SGerasim Troeglazov ntfs_error_set(&err);
21180bca3d3SAxel Dörfler }
21262cee9f9SGerasim Troeglazov
2130d2c294fSGerasim Troeglazov ntfs_free_lru_caches(v);
21480bca3d3SAxel Dörfler free(v->vol_name);
21580bca3d3SAxel Dörfler free(v->upcase);
2160d2c294fSGerasim Troeglazov if (v->locase) free(v->locase);
21780bca3d3SAxel Dörfler free(v->attrdef);
21880bca3d3SAxel Dörfler free(v);
21962cee9f9SGerasim Troeglazov
22062cee9f9SGerasim Troeglazov errno = err;
22162cee9f9SGerasim Troeglazov return errno ? -1 : 0;
22280bca3d3SAxel Dörfler }
22380bca3d3SAxel Dörfler
ntfs_attr_setup_flag(ntfs_inode * ni)2249102cad6SAugustin Cavalier static int ntfs_attr_setup_flag(ntfs_inode *ni)
22580bca3d3SAxel Dörfler {
22680bca3d3SAxel Dörfler STANDARD_INFORMATION *si;
2279102cad6SAugustin Cavalier s64 lth;
2289102cad6SAugustin Cavalier int r;
22980bca3d3SAxel Dörfler
2309102cad6SAugustin Cavalier si = (STANDARD_INFORMATION*)ntfs_attr_readall(ni,
2319102cad6SAugustin Cavalier AT_STANDARD_INFORMATION, AT_UNNAMED, 0, <h);
23280bca3d3SAxel Dörfler if (si) {
2339102cad6SAugustin Cavalier if ((u64)lth >= offsetof(STANDARD_INFORMATION, owner_id))
23480bca3d3SAxel Dörfler ni->flags = si->file_attributes;
23580bca3d3SAxel Dörfler free(si);
2369102cad6SAugustin Cavalier r = 0;
2379102cad6SAugustin Cavalier } else {
2389102cad6SAugustin Cavalier ntfs_log_error("Failed to get standard information of $MFT\n");
2399102cad6SAugustin Cavalier r = -1;
24080bca3d3SAxel Dörfler }
2419102cad6SAugustin Cavalier return (r);
24280bca3d3SAxel Dörfler }
24380bca3d3SAxel Dörfler
24480bca3d3SAxel Dörfler /**
24580bca3d3SAxel Dörfler * ntfs_mft_load - load the $MFT and setup the ntfs volume with it
24680bca3d3SAxel Dörfler * @vol: ntfs volume whose $MFT to load
24780bca3d3SAxel Dörfler *
24880bca3d3SAxel Dörfler * Load $MFT from @vol and setup @vol with it. After calling this function the
24980bca3d3SAxel Dörfler * volume @vol is ready for use by all read access functions provided by the
25080bca3d3SAxel Dörfler * ntfs library.
25180bca3d3SAxel Dörfler *
25280bca3d3SAxel Dörfler * Return 0 on success and -1 on error with errno set to the error code.
25380bca3d3SAxel Dörfler */
ntfs_mft_load(ntfs_volume * vol)25480bca3d3SAxel Dörfler static int ntfs_mft_load(ntfs_volume *vol)
25580bca3d3SAxel Dörfler {
25680bca3d3SAxel Dörfler VCN next_vcn, last_vcn, highest_vcn;
25780bca3d3SAxel Dörfler s64 l;
25880bca3d3SAxel Dörfler MFT_RECORD *mb = NULL;
25980bca3d3SAxel Dörfler ntfs_attr_search_ctx *ctx = NULL;
26080bca3d3SAxel Dörfler ATTR_RECORD *a;
26180bca3d3SAxel Dörfler int eo;
26280bca3d3SAxel Dörfler
26380bca3d3SAxel Dörfler /* Manually setup an ntfs_inode. */
26480bca3d3SAxel Dörfler vol->mft_ni = ntfs_inode_allocate(vol);
26580bca3d3SAxel Dörfler mb = ntfs_malloc(vol->mft_record_size);
26680bca3d3SAxel Dörfler if (!vol->mft_ni || !mb) {
26780bca3d3SAxel Dörfler ntfs_log_perror("Error allocating memory for $MFT");
26880bca3d3SAxel Dörfler goto error_exit;
26980bca3d3SAxel Dörfler }
27080bca3d3SAxel Dörfler vol->mft_ni->mft_no = 0;
27180bca3d3SAxel Dörfler vol->mft_ni->mrec = mb;
27280bca3d3SAxel Dörfler /* Can't use any of the higher level functions yet! */
27380bca3d3SAxel Dörfler l = ntfs_mst_pread(vol->dev, vol->mft_lcn << vol->cluster_size_bits, 1,
27480bca3d3SAxel Dörfler vol->mft_record_size, mb);
27580bca3d3SAxel Dörfler if (l != 1) {
27680bca3d3SAxel Dörfler if (l != -1)
27780bca3d3SAxel Dörfler errno = EIO;
27880bca3d3SAxel Dörfler ntfs_log_perror("Error reading $MFT");
27980bca3d3SAxel Dörfler goto error_exit;
28080bca3d3SAxel Dörfler }
28130bc84e9SGerasim Troeglazov
28230bc84e9SGerasim Troeglazov if (ntfs_mft_record_check(vol, 0, mb))
28380bca3d3SAxel Dörfler goto error_exit;
28430bc84e9SGerasim Troeglazov
28530bc84e9SGerasim Troeglazov ctx = ntfs_attr_get_search_ctx(vol->mft_ni, NULL);
28630bc84e9SGerasim Troeglazov if (!ctx)
28730bc84e9SGerasim Troeglazov goto error_exit;
28830bc84e9SGerasim Troeglazov
28980bca3d3SAxel Dörfler /* Find the $ATTRIBUTE_LIST attribute in $MFT if present. */
29080bca3d3SAxel Dörfler if (ntfs_attr_lookup(AT_ATTRIBUTE_LIST, AT_UNNAMED, 0, 0, 0, NULL, 0,
29180bca3d3SAxel Dörfler ctx)) {
29280bca3d3SAxel Dörfler if (errno != ENOENT) {
29380bca3d3SAxel Dörfler ntfs_log_error("$MFT has corrupt attribute list.\n");
29480bca3d3SAxel Dörfler goto io_error_exit;
29580bca3d3SAxel Dörfler }
29680bca3d3SAxel Dörfler goto mft_has_no_attr_list;
29780bca3d3SAxel Dörfler }
29880bca3d3SAxel Dörfler NInoSetAttrList(vol->mft_ni);
29980bca3d3SAxel Dörfler l = ntfs_get_attribute_value_length(ctx->attr);
30080bca3d3SAxel Dörfler if (l <= 0 || l > 0x40000) {
3016b3592caSGerasim Troeglazov ntfs_log_error("$MFT/$ATTR_LIST invalid length (%lld).\n",
3026b3592caSGerasim Troeglazov (long long)l);
30380bca3d3SAxel Dörfler goto io_error_exit;
30480bca3d3SAxel Dörfler }
30580bca3d3SAxel Dörfler vol->mft_ni->attr_list_size = l;
30680bca3d3SAxel Dörfler vol->mft_ni->attr_list = ntfs_malloc(l);
30780bca3d3SAxel Dörfler if (!vol->mft_ni->attr_list)
30880bca3d3SAxel Dörfler goto error_exit;
30980bca3d3SAxel Dörfler
31080bca3d3SAxel Dörfler l = ntfs_get_attribute_value(vol, ctx->attr, vol->mft_ni->attr_list);
31180bca3d3SAxel Dörfler if (!l) {
31280bca3d3SAxel Dörfler ntfs_log_error("Failed to get value of $MFT/$ATTR_LIST.\n");
31380bca3d3SAxel Dörfler goto io_error_exit;
31480bca3d3SAxel Dörfler }
3159102cad6SAugustin Cavalier if ((l != vol->mft_ni->attr_list_size)
3169102cad6SAugustin Cavalier || (l < (s64)offsetof(ATTR_LIST_ENTRY, name))) {
31780bca3d3SAxel Dörfler ntfs_log_error("Partial read of $MFT/$ATTR_LIST (%lld != "
3189102cad6SAugustin Cavalier "%u or < %d).\n", (long long)l,
3199102cad6SAugustin Cavalier vol->mft_ni->attr_list_size,
3209102cad6SAugustin Cavalier (int)offsetof(ATTR_LIST_ENTRY, name));
32180bca3d3SAxel Dörfler goto io_error_exit;
32280bca3d3SAxel Dörfler }
32380bca3d3SAxel Dörfler
32480bca3d3SAxel Dörfler mft_has_no_attr_list:
32580bca3d3SAxel Dörfler
3269102cad6SAugustin Cavalier if (ntfs_attr_setup_flag(vol->mft_ni))
3279102cad6SAugustin Cavalier goto error_exit;
32880bca3d3SAxel Dörfler
32980bca3d3SAxel Dörfler /* We now have a fully setup ntfs inode for $MFT in vol->mft_ni. */
33080bca3d3SAxel Dörfler
33180bca3d3SAxel Dörfler /* Get an ntfs attribute for $MFT/$DATA and set it up, too. */
33280bca3d3SAxel Dörfler vol->mft_na = ntfs_attr_open(vol->mft_ni, AT_DATA, AT_UNNAMED, 0);
33380bca3d3SAxel Dörfler if (!vol->mft_na) {
33480bca3d3SAxel Dörfler ntfs_log_perror("Failed to open ntfs attribute");
33580bca3d3SAxel Dörfler goto error_exit;
33680bca3d3SAxel Dörfler }
33780bca3d3SAxel Dörfler /* Read all extents from the $DATA attribute in $MFT. */
33880bca3d3SAxel Dörfler ntfs_attr_reinit_search_ctx(ctx);
33980bca3d3SAxel Dörfler last_vcn = vol->mft_na->allocated_size >> vol->cluster_size_bits;
34080bca3d3SAxel Dörfler highest_vcn = next_vcn = 0;
34180bca3d3SAxel Dörfler a = NULL;
34280bca3d3SAxel Dörfler while (!ntfs_attr_lookup(AT_DATA, AT_UNNAMED, 0, 0, next_vcn, NULL, 0,
34380bca3d3SAxel Dörfler ctx)) {
34480bca3d3SAxel Dörfler runlist_element *nrl;
34580bca3d3SAxel Dörfler
34680bca3d3SAxel Dörfler a = ctx->attr;
34780bca3d3SAxel Dörfler /* $MFT must be non-resident. */
34880bca3d3SAxel Dörfler if (!a->non_resident) {
34980bca3d3SAxel Dörfler ntfs_log_error("$MFT must be non-resident.\n");
35080bca3d3SAxel Dörfler goto io_error_exit;
35180bca3d3SAxel Dörfler }
35280bca3d3SAxel Dörfler /* $MFT must be uncompressed and unencrypted. */
35380bca3d3SAxel Dörfler if (a->flags & ATTR_COMPRESSION_MASK ||
35480bca3d3SAxel Dörfler a->flags & ATTR_IS_ENCRYPTED) {
35580bca3d3SAxel Dörfler ntfs_log_error("$MFT must be uncompressed and "
35680bca3d3SAxel Dörfler "unencrypted.\n");
35780bca3d3SAxel Dörfler goto io_error_exit;
35880bca3d3SAxel Dörfler }
35980bca3d3SAxel Dörfler /*
36080bca3d3SAxel Dörfler * Decompress the mapping pairs array of this extent and merge
36180bca3d3SAxel Dörfler * the result into the existing runlist. No need for locking
36280bca3d3SAxel Dörfler * as we have exclusive access to the inode at this time and we
36380bca3d3SAxel Dörfler * are a mount in progress task, too.
36480bca3d3SAxel Dörfler */
36580bca3d3SAxel Dörfler nrl = ntfs_mapping_pairs_decompress(vol, a, vol->mft_na->rl);
36680bca3d3SAxel Dörfler if (!nrl) {
36780bca3d3SAxel Dörfler ntfs_log_perror("ntfs_mapping_pairs_decompress() failed");
36880bca3d3SAxel Dörfler goto error_exit;
36980bca3d3SAxel Dörfler }
3709102cad6SAugustin Cavalier /* Make sure $DATA is the MFT itself */
3719102cad6SAugustin Cavalier if (nrl->lcn != vol->mft_lcn) {
3729102cad6SAugustin Cavalier ntfs_log_perror("The MFT is not self-contained");
3739102cad6SAugustin Cavalier goto error_exit;
3749102cad6SAugustin Cavalier }
37580bca3d3SAxel Dörfler vol->mft_na->rl = nrl;
37680bca3d3SAxel Dörfler
37780bca3d3SAxel Dörfler /* Get the lowest vcn for the next extent. */
37880bca3d3SAxel Dörfler highest_vcn = sle64_to_cpu(a->highest_vcn);
37980bca3d3SAxel Dörfler next_vcn = highest_vcn + 1;
38080bca3d3SAxel Dörfler
38180bca3d3SAxel Dörfler /* Only one extent or error, which we catch below. */
38280bca3d3SAxel Dörfler if (next_vcn <= 0)
38380bca3d3SAxel Dörfler break;
38480bca3d3SAxel Dörfler
38580bca3d3SAxel Dörfler /* Avoid endless loops due to corruption. */
38680bca3d3SAxel Dörfler if (next_vcn < sle64_to_cpu(a->lowest_vcn)) {
38780bca3d3SAxel Dörfler ntfs_log_error("$MFT has corrupt attribute list.\n");
38880bca3d3SAxel Dörfler goto io_error_exit;
38980bca3d3SAxel Dörfler }
39080bca3d3SAxel Dörfler }
39180bca3d3SAxel Dörfler if (!a) {
39280bca3d3SAxel Dörfler ntfs_log_error("$MFT/$DATA attribute not found.\n");
39380bca3d3SAxel Dörfler goto io_error_exit;
39480bca3d3SAxel Dörfler }
39580bca3d3SAxel Dörfler if (highest_vcn && highest_vcn != last_vcn - 1) {
39680bca3d3SAxel Dörfler ntfs_log_error("Failed to load runlist for $MFT/$DATA.\n");
39780bca3d3SAxel Dörfler ntfs_log_error("highest_vcn = 0x%llx, last_vcn - 1 = 0x%llx\n",
39880bca3d3SAxel Dörfler (long long)highest_vcn, (long long)last_vcn - 1);
39980bca3d3SAxel Dörfler goto io_error_exit;
40080bca3d3SAxel Dörfler }
40180bca3d3SAxel Dörfler /* Done with the $Mft mft record. */
40280bca3d3SAxel Dörfler ntfs_attr_put_search_ctx(ctx);
40380bca3d3SAxel Dörfler ctx = NULL;
404a814d850Sthreedeyes
405a814d850Sthreedeyes /* Update the size fields in the inode. */
406a814d850Sthreedeyes vol->mft_ni->data_size = vol->mft_na->data_size;
407a814d850Sthreedeyes vol->mft_ni->allocated_size = vol->mft_na->allocated_size;
408a814d850Sthreedeyes set_nino_flag(vol->mft_ni, KnownSize);
409a814d850Sthreedeyes
41080bca3d3SAxel Dörfler /*
41180bca3d3SAxel Dörfler * The volume is now setup so we can use all read access functions.
41280bca3d3SAxel Dörfler */
41380bca3d3SAxel Dörfler vol->mftbmp_na = ntfs_attr_open(vol->mft_ni, AT_BITMAP, AT_UNNAMED, 0);
41480bca3d3SAxel Dörfler if (!vol->mftbmp_na) {
41580bca3d3SAxel Dörfler ntfs_log_perror("Failed to open $MFT/$BITMAP");
41680bca3d3SAxel Dörfler goto error_exit;
41780bca3d3SAxel Dörfler }
41880bca3d3SAxel Dörfler return 0;
41980bca3d3SAxel Dörfler io_error_exit:
42080bca3d3SAxel Dörfler errno = EIO;
42180bca3d3SAxel Dörfler error_exit:
42280bca3d3SAxel Dörfler eo = errno;
42380bca3d3SAxel Dörfler if (ctx)
42480bca3d3SAxel Dörfler ntfs_attr_put_search_ctx(ctx);
42580bca3d3SAxel Dörfler if (vol->mft_na) {
42680bca3d3SAxel Dörfler ntfs_attr_close(vol->mft_na);
42780bca3d3SAxel Dörfler vol->mft_na = NULL;
42880bca3d3SAxel Dörfler }
42980bca3d3SAxel Dörfler if (vol->mft_ni) {
43080bca3d3SAxel Dörfler ntfs_inode_close(vol->mft_ni);
43180bca3d3SAxel Dörfler vol->mft_ni = NULL;
43280bca3d3SAxel Dörfler }
43380bca3d3SAxel Dörfler errno = eo;
43480bca3d3SAxel Dörfler return -1;
43580bca3d3SAxel Dörfler }
43680bca3d3SAxel Dörfler
43780bca3d3SAxel Dörfler /**
43880bca3d3SAxel Dörfler * ntfs_mftmirr_load - load the $MFTMirr and setup the ntfs volume with it
43980bca3d3SAxel Dörfler * @vol: ntfs volume whose $MFTMirr to load
44080bca3d3SAxel Dörfler *
44180bca3d3SAxel Dörfler * Load $MFTMirr from @vol and setup @vol with it. After calling this function
44280bca3d3SAxel Dörfler * the volume @vol is ready for use by all write access functions provided by
44380bca3d3SAxel Dörfler * the ntfs library (assuming ntfs_mft_load() has been called successfully
44480bca3d3SAxel Dörfler * beforehand).
44580bca3d3SAxel Dörfler *
44680bca3d3SAxel Dörfler * Return 0 on success and -1 on error with errno set to the error code.
44780bca3d3SAxel Dörfler */
ntfs_mftmirr_load(ntfs_volume * vol)44880bca3d3SAxel Dörfler static int ntfs_mftmirr_load(ntfs_volume *vol)
44980bca3d3SAxel Dörfler {
45080bca3d3SAxel Dörfler int err;
45180bca3d3SAxel Dörfler
45280bca3d3SAxel Dörfler vol->mftmirr_ni = ntfs_inode_open(vol, FILE_MFTMirr);
45380bca3d3SAxel Dörfler if (!vol->mftmirr_ni) {
45480bca3d3SAxel Dörfler ntfs_log_perror("Failed to open inode $MFTMirr");
45580bca3d3SAxel Dörfler return -1;
45680bca3d3SAxel Dörfler }
45780bca3d3SAxel Dörfler
45880bca3d3SAxel Dörfler vol->mftmirr_na = ntfs_attr_open(vol->mftmirr_ni, AT_DATA, AT_UNNAMED, 0);
45980bca3d3SAxel Dörfler if (!vol->mftmirr_na) {
46080bca3d3SAxel Dörfler ntfs_log_perror("Failed to open $MFTMirr/$DATA");
46180bca3d3SAxel Dörfler goto error_exit;
46280bca3d3SAxel Dörfler }
46380bca3d3SAxel Dörfler
46480bca3d3SAxel Dörfler if (ntfs_attr_map_runlist(vol->mftmirr_na, 0) < 0) {
46580bca3d3SAxel Dörfler ntfs_log_perror("Failed to map runlist of $MFTMirr/$DATA");
46680bca3d3SAxel Dörfler goto error_exit;
46780bca3d3SAxel Dörfler }
4689102cad6SAugustin Cavalier if (vol->mftmirr_na->rl->lcn != vol->mftmirr_lcn) {
4699102cad6SAugustin Cavalier ntfs_log_error("Bad $MFTMirr lcn 0x%llx, want 0x%llx\n",
4709102cad6SAugustin Cavalier (long long)vol->mftmirr_na->rl->lcn,
4719102cad6SAugustin Cavalier (long long)vol->mftmirr_lcn);
4729102cad6SAugustin Cavalier goto error_exit;
4739102cad6SAugustin Cavalier }
47480bca3d3SAxel Dörfler
47580bca3d3SAxel Dörfler return 0;
47680bca3d3SAxel Dörfler
47780bca3d3SAxel Dörfler error_exit:
47880bca3d3SAxel Dörfler err = errno;
47980bca3d3SAxel Dörfler if (vol->mftmirr_na) {
48080bca3d3SAxel Dörfler ntfs_attr_close(vol->mftmirr_na);
48180bca3d3SAxel Dörfler vol->mftmirr_na = NULL;
48280bca3d3SAxel Dörfler }
48380bca3d3SAxel Dörfler ntfs_inode_close(vol->mftmirr_ni);
48480bca3d3SAxel Dörfler vol->mftmirr_ni = NULL;
48580bca3d3SAxel Dörfler errno = err;
48680bca3d3SAxel Dörfler return -1;
48780bca3d3SAxel Dörfler }
48880bca3d3SAxel Dörfler
48980bca3d3SAxel Dörfler /**
49080bca3d3SAxel Dörfler * ntfs_volume_startup - allocate and setup an ntfs volume
49180bca3d3SAxel Dörfler * @dev: device to open
49280bca3d3SAxel Dörfler * @flags: optional mount flags
49380bca3d3SAxel Dörfler *
49480bca3d3SAxel Dörfler * Load, verify, and parse bootsector; load and setup $MFT and $MFTMirr. After
49580bca3d3SAxel Dörfler * calling this function, the volume is setup sufficiently to call all read
49680bca3d3SAxel Dörfler * and write access functions provided by the library.
49780bca3d3SAxel Dörfler *
49880bca3d3SAxel Dörfler * Return the allocated volume structure on success and NULL on error with
49980bca3d3SAxel Dörfler * errno set to the error code.
50080bca3d3SAxel Dörfler */
ntfs_volume_startup(struct ntfs_device * dev,ntfs_mount_flags flags)501da0906f2SGerasim Troeglazov ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev,
502da0906f2SGerasim Troeglazov ntfs_mount_flags flags)
50380bca3d3SAxel Dörfler {
50480bca3d3SAxel Dörfler LCN mft_zone_size, mft_lcn;
50580bca3d3SAxel Dörfler s64 br;
50680bca3d3SAxel Dörfler ntfs_volume *vol;
50780bca3d3SAxel Dörfler NTFS_BOOT_SECTOR *bs;
50880bca3d3SAxel Dörfler int eo;
50980bca3d3SAxel Dörfler
51080bca3d3SAxel Dörfler if (!dev || !dev->d_ops || !dev->d_name) {
51180bca3d3SAxel Dörfler errno = EINVAL;
51230bc84e9SGerasim Troeglazov ntfs_log_perror("%s: dev = %p", __FUNCTION__, dev);
51380bca3d3SAxel Dörfler return NULL;
51480bca3d3SAxel Dörfler }
51580bca3d3SAxel Dörfler
51680bca3d3SAxel Dörfler bs = ntfs_malloc(sizeof(NTFS_BOOT_SECTOR));
51780bca3d3SAxel Dörfler if (!bs)
51880bca3d3SAxel Dörfler return NULL;
51980bca3d3SAxel Dörfler
52080bca3d3SAxel Dörfler /* Allocate the volume structure. */
52180bca3d3SAxel Dörfler vol = ntfs_volume_alloc();
52280bca3d3SAxel Dörfler if (!vol)
52380bca3d3SAxel Dörfler goto error_exit;
52430bc84e9SGerasim Troeglazov
52580bca3d3SAxel Dörfler /* Create the default upcase table. */
526a814d850Sthreedeyes vol->upcase_len = ntfs_upcase_build_default(&vol->upcase);
527a814d850Sthreedeyes if (!vol->upcase_len || !vol->upcase)
52880bca3d3SAxel Dörfler goto error_exit;
52980bca3d3SAxel Dörfler
5300d2c294fSGerasim Troeglazov /* Default with no locase table and case sensitive file names */
5310d2c294fSGerasim Troeglazov vol->locase = (ntfschar*)NULL;
5320d2c294fSGerasim Troeglazov NVolSetCaseSensitive(vol);
53330bc84e9SGerasim Troeglazov
5340d2c294fSGerasim Troeglazov /* by default, all files are shown and not marked hidden */
5350d2c294fSGerasim Troeglazov NVolSetShowSysFiles(vol);
5360d2c294fSGerasim Troeglazov NVolSetShowHidFiles(vol);
5370d2c294fSGerasim Troeglazov NVolClearHideDotFiles(vol);
538a814d850Sthreedeyes /* set default compression */
539a814d850Sthreedeyes #if DEFAULT_COMPRESSION
540a814d850Sthreedeyes NVolSetCompression(vol);
541a814d850Sthreedeyes #else
542a814d850Sthreedeyes NVolClearCompression(vol);
543a814d850Sthreedeyes #endif
544da0906f2SGerasim Troeglazov if (flags & NTFS_MNT_RDONLY)
54580bca3d3SAxel Dörfler NVolSetReadOnly(vol);
54630bc84e9SGerasim Troeglazov
54730bc84e9SGerasim Troeglazov /* ...->open needs bracketing to compile with glibc 2.7 */
54830bc84e9SGerasim Troeglazov if ((dev->d_ops->open)(dev, NVolReadOnly(vol) ? O_RDONLY: O_RDWR)) {
549da0906f2SGerasim Troeglazov if (!NVolReadOnly(vol) && (errno == EROFS)) {
550da0906f2SGerasim Troeglazov if ((dev->d_ops->open)(dev, O_RDONLY)) {
551da0906f2SGerasim Troeglazov ntfs_log_perror("Error opening read-only '%s'",
552da0906f2SGerasim Troeglazov dev->d_name);
553da0906f2SGerasim Troeglazov goto error_exit;
554da0906f2SGerasim Troeglazov } else {
5559102cad6SAugustin Cavalier ntfs_log_info("Error opening '%s' read-write\n",
556da0906f2SGerasim Troeglazov dev->d_name);
557da0906f2SGerasim Troeglazov NVolSetReadOnly(vol);
558da0906f2SGerasim Troeglazov }
559da0906f2SGerasim Troeglazov } else {
56030bc84e9SGerasim Troeglazov ntfs_log_perror("Error opening '%s'", dev->d_name);
56180bca3d3SAxel Dörfler goto error_exit;
56280bca3d3SAxel Dörfler }
563da0906f2SGerasim Troeglazov }
56480bca3d3SAxel Dörfler /* Attach the device to the volume. */
56580bca3d3SAxel Dörfler vol->dev = dev;
56630bc84e9SGerasim Troeglazov
56780bca3d3SAxel Dörfler /* Now read the bootsector. */
56880bca3d3SAxel Dörfler br = ntfs_pread(dev, 0, sizeof(NTFS_BOOT_SECTOR), bs);
56980bca3d3SAxel Dörfler if (br != sizeof(NTFS_BOOT_SECTOR)) {
57080bca3d3SAxel Dörfler if (br != -1)
57180bca3d3SAxel Dörfler errno = EINVAL;
57280bca3d3SAxel Dörfler if (!br)
57330bc84e9SGerasim Troeglazov ntfs_log_error("Failed to read bootsector (size=0)\n");
57480bca3d3SAxel Dörfler else
57580bca3d3SAxel Dörfler ntfs_log_perror("Error reading bootsector");
57680bca3d3SAxel Dörfler goto error_exit;
57780bca3d3SAxel Dörfler }
57880bca3d3SAxel Dörfler if (!ntfs_boot_sector_is_ntfs(bs)) {
57980bca3d3SAxel Dörfler errno = EINVAL;
58080bca3d3SAxel Dörfler goto error_exit;
58180bca3d3SAxel Dörfler }
58280bca3d3SAxel Dörfler if (ntfs_boot_sector_parse(vol, bs) < 0)
58380bca3d3SAxel Dörfler goto error_exit;
58480bca3d3SAxel Dörfler
58580bca3d3SAxel Dörfler free(bs);
58680bca3d3SAxel Dörfler bs = NULL;
58780bca3d3SAxel Dörfler /* Now set the device block size to the sector size. */
58880bca3d3SAxel Dörfler if (ntfs_device_block_size_set(vol->dev, vol->sector_size))
58980bca3d3SAxel Dörfler ntfs_log_debug("Failed to set the device block size to the "
59080bca3d3SAxel Dörfler "sector size. This may affect performance "
59180bca3d3SAxel Dörfler "but should be harmless otherwise. Error: "
59280bca3d3SAxel Dörfler "%s\n", strerror(errno));
59380bca3d3SAxel Dörfler
59462cee9f9SGerasim Troeglazov /* We now initialize the cluster allocator. */
5950d2c294fSGerasim Troeglazov vol->full_zones = 0;
59630bc84e9SGerasim Troeglazov mft_zone_size = vol->nr_clusters >> 3; /* 12.5% */
59780bca3d3SAxel Dörfler
59880bca3d3SAxel Dörfler /* Setup the mft zone. */
59980bca3d3SAxel Dörfler vol->mft_zone_start = vol->mft_zone_pos = vol->mft_lcn;
60080bca3d3SAxel Dörfler ntfs_log_debug("mft_zone_pos = 0x%llx\n", (long long)vol->mft_zone_pos);
60180bca3d3SAxel Dörfler
60280bca3d3SAxel Dörfler /*
60380bca3d3SAxel Dörfler * Calculate the mft_lcn for an unmodified NTFS volume (see mkntfs
60480bca3d3SAxel Dörfler * source) and if the actual mft_lcn is in the expected place or even
60580bca3d3SAxel Dörfler * further to the front of the volume, extend the mft_zone to cover the
60680bca3d3SAxel Dörfler * beginning of the volume as well. This is in order to protect the
60780bca3d3SAxel Dörfler * area reserved for the mft bitmap as well within the mft_zone itself.
60880bca3d3SAxel Dörfler * On non-standard volumes we don't protect it as the overhead would be
60980bca3d3SAxel Dörfler * higher than the speed increase we would get by doing it.
61080bca3d3SAxel Dörfler */
61180bca3d3SAxel Dörfler mft_lcn = (8192 + 2 * vol->cluster_size - 1) / vol->cluster_size;
61280bca3d3SAxel Dörfler if (mft_lcn * vol->cluster_size < 16 * 1024)
61380bca3d3SAxel Dörfler mft_lcn = (16 * 1024 + vol->cluster_size - 1) /
61480bca3d3SAxel Dörfler vol->cluster_size;
61580bca3d3SAxel Dörfler if (vol->mft_zone_start <= mft_lcn)
61680bca3d3SAxel Dörfler vol->mft_zone_start = 0;
61780bca3d3SAxel Dörfler ntfs_log_debug("mft_zone_start = 0x%llx\n", (long long)vol->mft_zone_start);
61880bca3d3SAxel Dörfler
61980bca3d3SAxel Dörfler /*
62080bca3d3SAxel Dörfler * Need to cap the mft zone on non-standard volumes so that it does
62180bca3d3SAxel Dörfler * not point outside the boundaries of the volume. We do this by
62280bca3d3SAxel Dörfler * halving the zone size until we are inside the volume.
62380bca3d3SAxel Dörfler */
62480bca3d3SAxel Dörfler vol->mft_zone_end = vol->mft_lcn + mft_zone_size;
62580bca3d3SAxel Dörfler while (vol->mft_zone_end >= vol->nr_clusters) {
62680bca3d3SAxel Dörfler mft_zone_size >>= 1;
6279102cad6SAugustin Cavalier if (!mft_zone_size) {
6289102cad6SAugustin Cavalier errno = EINVAL;
6299102cad6SAugustin Cavalier goto error_exit;
6309102cad6SAugustin Cavalier }
63180bca3d3SAxel Dörfler vol->mft_zone_end = vol->mft_lcn + mft_zone_size;
63280bca3d3SAxel Dörfler }
63380bca3d3SAxel Dörfler ntfs_log_debug("mft_zone_end = 0x%llx\n", (long long)vol->mft_zone_end);
63480bca3d3SAxel Dörfler
63580bca3d3SAxel Dörfler /*
63680bca3d3SAxel Dörfler * Set the current position within each data zone to the start of the
63780bca3d3SAxel Dörfler * respective zone.
63880bca3d3SAxel Dörfler */
63980bca3d3SAxel Dörfler vol->data1_zone_pos = vol->mft_zone_end;
64030bc84e9SGerasim Troeglazov ntfs_log_debug("data1_zone_pos = %lld\n", (long long)vol->data1_zone_pos);
64180bca3d3SAxel Dörfler vol->data2_zone_pos = 0;
64230bc84e9SGerasim Troeglazov ntfs_log_debug("data2_zone_pos = %lld\n", (long long)vol->data2_zone_pos);
64380bca3d3SAxel Dörfler
64480bca3d3SAxel Dörfler /* Set the mft data allocation position to mft record 24. */
64580bca3d3SAxel Dörfler vol->mft_data_pos = 24;
64680bca3d3SAxel Dörfler
64780bca3d3SAxel Dörfler /*
64880bca3d3SAxel Dörfler * The cluster allocator is now fully operational.
64980bca3d3SAxel Dörfler */
65080bca3d3SAxel Dörfler
65180bca3d3SAxel Dörfler /* Need to setup $MFT so we can use the library read functions. */
65280bca3d3SAxel Dörfler if (ntfs_mft_load(vol) < 0) {
65380bca3d3SAxel Dörfler ntfs_log_perror("Failed to load $MFT");
65480bca3d3SAxel Dörfler goto error_exit;
65580bca3d3SAxel Dörfler }
65680bca3d3SAxel Dörfler
65780bca3d3SAxel Dörfler /* Need to setup $MFTMirr so we can use the write functions, too. */
65880bca3d3SAxel Dörfler if (ntfs_mftmirr_load(vol) < 0) {
65980bca3d3SAxel Dörfler ntfs_log_perror("Failed to load $MFTMirr");
66080bca3d3SAxel Dörfler goto error_exit;
66180bca3d3SAxel Dörfler }
66280bca3d3SAxel Dörfler return vol;
66380bca3d3SAxel Dörfler error_exit:
66480bca3d3SAxel Dörfler eo = errno;
66580bca3d3SAxel Dörfler free(bs);
66680bca3d3SAxel Dörfler if (vol)
66780bca3d3SAxel Dörfler __ntfs_volume_release(vol);
66880bca3d3SAxel Dörfler errno = eo;
66980bca3d3SAxel Dörfler return NULL;
67080bca3d3SAxel Dörfler }
67180bca3d3SAxel Dörfler
67280bca3d3SAxel Dörfler /**
67380bca3d3SAxel Dörfler * ntfs_volume_check_logfile - check logfile on target volume
67480bca3d3SAxel Dörfler * @vol: volume on which to check logfile
67580bca3d3SAxel Dörfler *
67680bca3d3SAxel Dörfler * Return 0 on success and -1 on error with errno set error code.
67780bca3d3SAxel Dörfler */
ntfs_volume_check_logfile(ntfs_volume * vol)67880bca3d3SAxel Dörfler static int ntfs_volume_check_logfile(ntfs_volume *vol)
67980bca3d3SAxel Dörfler {
68080bca3d3SAxel Dörfler ntfs_inode *ni;
68180bca3d3SAxel Dörfler ntfs_attr *na = NULL;
68280bca3d3SAxel Dörfler RESTART_PAGE_HEADER *rp = NULL;
68380bca3d3SAxel Dörfler int err = 0;
68480bca3d3SAxel Dörfler
68562cee9f9SGerasim Troeglazov ni = ntfs_inode_open(vol, FILE_LogFile);
68662cee9f9SGerasim Troeglazov if (!ni) {
68780bca3d3SAxel Dörfler ntfs_log_perror("Failed to open inode FILE_LogFile");
68880bca3d3SAxel Dörfler errno = EIO;
68980bca3d3SAxel Dörfler return -1;
69080bca3d3SAxel Dörfler }
69162cee9f9SGerasim Troeglazov
69262cee9f9SGerasim Troeglazov na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
69362cee9f9SGerasim Troeglazov if (!na) {
69480bca3d3SAxel Dörfler ntfs_log_perror("Failed to open $FILE_LogFile/$DATA");
69580bca3d3SAxel Dörfler err = EIO;
69662cee9f9SGerasim Troeglazov goto out;
69780bca3d3SAxel Dörfler }
69862cee9f9SGerasim Troeglazov
69980bca3d3SAxel Dörfler if (!ntfs_check_logfile(na, &rp) || !ntfs_is_logfile_clean(na, rp))
70080bca3d3SAxel Dörfler err = EOPNOTSUPP;
701da0906f2SGerasim Troeglazov /*
702da0906f2SGerasim Troeglazov * If the latest restart page was identified as version
703da0906f2SGerasim Troeglazov * 2.0, then Windows may have kept a cached copy of
704da0906f2SGerasim Troeglazov * metadata for fast restarting, and we should not mount.
705da0906f2SGerasim Troeglazov * Hibernation will be seen the same way on a non
706da0906f2SGerasim Troeglazov * Windows-system partition, so we have to use the same
707da0906f2SGerasim Troeglazov * error code (EPERM).
708da0906f2SGerasim Troeglazov * The restart page may also be identified as version 2.0
709da0906f2SGerasim Troeglazov * when access to the file system is terminated abruptly
710da0906f2SGerasim Troeglazov * by unplugging or power cut, so mounting is also rejected
711da0906f2SGerasim Troeglazov * after such an event.
712da0906f2SGerasim Troeglazov */
713da0906f2SGerasim Troeglazov if (rp
714da0906f2SGerasim Troeglazov && (rp->major_ver == const_cpu_to_le16(2))
715da0906f2SGerasim Troeglazov && (rp->minor_ver == const_cpu_to_le16(0))) {
716da0906f2SGerasim Troeglazov ntfs_log_error("Metadata kept in Windows cache, refused to mount.\n");
717da0906f2SGerasim Troeglazov err = EPERM;
718da0906f2SGerasim Troeglazov }
71980bca3d3SAxel Dörfler free(rp);
72080bca3d3SAxel Dörfler ntfs_attr_close(na);
72162cee9f9SGerasim Troeglazov out:
72262cee9f9SGerasim Troeglazov if (ntfs_inode_close(ni))
72362cee9f9SGerasim Troeglazov ntfs_error_set(&err);
72480bca3d3SAxel Dörfler if (err) {
72580bca3d3SAxel Dörfler errno = err;
72680bca3d3SAxel Dörfler return -1;
72780bca3d3SAxel Dörfler }
72880bca3d3SAxel Dörfler return 0;
72980bca3d3SAxel Dörfler }
73080bca3d3SAxel Dörfler
73180bca3d3SAxel Dörfler /**
73280bca3d3SAxel Dörfler * ntfs_hiberfile_open - Find and open '/hiberfil.sys'
73380bca3d3SAxel Dörfler * @vol: An ntfs volume obtained from ntfs_mount
73480bca3d3SAxel Dörfler *
73580bca3d3SAxel Dörfler * Return: inode Success, hiberfil.sys is valid
73680bca3d3SAxel Dörfler * NULL hiberfil.sys doesn't exist or some other error occurred
73780bca3d3SAxel Dörfler */
ntfs_hiberfile_open(ntfs_volume * vol)73880bca3d3SAxel Dörfler static ntfs_inode *ntfs_hiberfile_open(ntfs_volume *vol)
73980bca3d3SAxel Dörfler {
74080bca3d3SAxel Dörfler u64 inode;
74180bca3d3SAxel Dörfler ntfs_inode *ni_root;
74280bca3d3SAxel Dörfler ntfs_inode *ni_hibr = NULL;
74380bca3d3SAxel Dörfler ntfschar *unicode = NULL;
74480bca3d3SAxel Dörfler int unicode_len;
74580bca3d3SAxel Dörfler const char *hiberfile = "hiberfil.sys";
74680bca3d3SAxel Dörfler
74780bca3d3SAxel Dörfler if (!vol) {
74880bca3d3SAxel Dörfler errno = EINVAL;
74980bca3d3SAxel Dörfler return NULL;
75080bca3d3SAxel Dörfler }
75180bca3d3SAxel Dörfler
75280bca3d3SAxel Dörfler ni_root = ntfs_inode_open(vol, FILE_root);
75380bca3d3SAxel Dörfler if (!ni_root) {
75480bca3d3SAxel Dörfler ntfs_log_debug("Couldn't open the root directory.\n");
75580bca3d3SAxel Dörfler return NULL;
75680bca3d3SAxel Dörfler }
75780bca3d3SAxel Dörfler
75830bc84e9SGerasim Troeglazov unicode_len = ntfs_mbstoucs(hiberfile, &unicode);
75980bca3d3SAxel Dörfler if (unicode_len < 0) {
76080bca3d3SAxel Dörfler ntfs_log_perror("Couldn't convert 'hiberfil.sys' to Unicode");
76180bca3d3SAxel Dörfler goto out;
76280bca3d3SAxel Dörfler }
76380bca3d3SAxel Dörfler
76480bca3d3SAxel Dörfler inode = ntfs_inode_lookup_by_name(ni_root, unicode, unicode_len);
76580bca3d3SAxel Dörfler if (inode == (u64)-1) {
76680bca3d3SAxel Dörfler ntfs_log_debug("Couldn't find file '%s'.\n", hiberfile);
76780bca3d3SAxel Dörfler goto out;
76880bca3d3SAxel Dörfler }
76980bca3d3SAxel Dörfler
77080bca3d3SAxel Dörfler inode = MREF(inode);
77180bca3d3SAxel Dörfler ni_hibr = ntfs_inode_open(vol, inode);
77280bca3d3SAxel Dörfler if (!ni_hibr) {
77380bca3d3SAxel Dörfler ntfs_log_debug("Couldn't open inode %lld.\n", (long long)inode);
77480bca3d3SAxel Dörfler goto out;
77580bca3d3SAxel Dörfler }
77680bca3d3SAxel Dörfler out:
77762cee9f9SGerasim Troeglazov if (ntfs_inode_close(ni_root)) {
77862cee9f9SGerasim Troeglazov ntfs_inode_close(ni_hibr);
77962cee9f9SGerasim Troeglazov ni_hibr = NULL;
78062cee9f9SGerasim Troeglazov }
78180bca3d3SAxel Dörfler free(unicode);
78280bca3d3SAxel Dörfler return ni_hibr;
78380bca3d3SAxel Dörfler }
78480bca3d3SAxel Dörfler
78580bca3d3SAxel Dörfler
78680bca3d3SAxel Dörfler #define NTFS_HIBERFILE_HEADER_SIZE 4096
78780bca3d3SAxel Dörfler
78880bca3d3SAxel Dörfler /**
78980bca3d3SAxel Dörfler * ntfs_volume_check_hiberfile - check hiberfil.sys whether Windows is
79080bca3d3SAxel Dörfler * hibernated on the target volume
79180bca3d3SAxel Dörfler * @vol: volume on which to check hiberfil.sys
79280bca3d3SAxel Dörfler *
79380bca3d3SAxel Dörfler * Return: 0 if Windows isn't hibernated for sure
79480bca3d3SAxel Dörfler * -1 otherwise and errno is set to the appropriate value
79580bca3d3SAxel Dörfler */
ntfs_volume_check_hiberfile(ntfs_volume * vol,int verbose)79630bc84e9SGerasim Troeglazov int ntfs_volume_check_hiberfile(ntfs_volume *vol, int verbose)
79780bca3d3SAxel Dörfler {
79880bca3d3SAxel Dörfler ntfs_inode *ni;
79980bca3d3SAxel Dörfler ntfs_attr *na = NULL;
80030bc84e9SGerasim Troeglazov int bytes_read, err;
80180bca3d3SAxel Dörfler char *buf = NULL;
80280bca3d3SAxel Dörfler
80380bca3d3SAxel Dörfler ni = ntfs_hiberfile_open(vol);
80480bca3d3SAxel Dörfler if (!ni) {
80580bca3d3SAxel Dörfler if (errno == ENOENT)
80680bca3d3SAxel Dörfler return 0;
80780bca3d3SAxel Dörfler return -1;
80880bca3d3SAxel Dörfler }
80980bca3d3SAxel Dörfler
81080bca3d3SAxel Dörfler buf = ntfs_malloc(NTFS_HIBERFILE_HEADER_SIZE);
81180bca3d3SAxel Dörfler if (!buf)
81280bca3d3SAxel Dörfler goto out;
81380bca3d3SAxel Dörfler
81480bca3d3SAxel Dörfler na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
81580bca3d3SAxel Dörfler if (!na) {
81680bca3d3SAxel Dörfler ntfs_log_perror("Failed to open hiberfil.sys data attribute");
81780bca3d3SAxel Dörfler goto out;
81880bca3d3SAxel Dörfler }
81980bca3d3SAxel Dörfler
82080bca3d3SAxel Dörfler bytes_read = ntfs_attr_pread(na, 0, NTFS_HIBERFILE_HEADER_SIZE, buf);
82180bca3d3SAxel Dörfler if (bytes_read == -1) {
82280bca3d3SAxel Dörfler ntfs_log_perror("Failed to read hiberfil.sys");
82380bca3d3SAxel Dörfler goto out;
82480bca3d3SAxel Dörfler }
82580bca3d3SAxel Dörfler if (bytes_read < NTFS_HIBERFILE_HEADER_SIZE) {
82630bc84e9SGerasim Troeglazov if (verbose)
82730bc84e9SGerasim Troeglazov ntfs_log_error("Hibernated non-system partition, "
82830bc84e9SGerasim Troeglazov "refused to mount.\n");
82980bca3d3SAxel Dörfler errno = EPERM;
83080bca3d3SAxel Dörfler goto out;
83180bca3d3SAxel Dörfler }
832da0906f2SGerasim Troeglazov if ((memcmp(buf, "hibr", 4) == 0)
833da0906f2SGerasim Troeglazov || (memcmp(buf, "HIBR", 4) == 0)) {
83430bc84e9SGerasim Troeglazov if (verbose)
83580bca3d3SAxel Dörfler ntfs_log_error("Windows is hibernated, refused to mount.\n");
83680bca3d3SAxel Dörfler errno = EPERM;
83780bca3d3SAxel Dörfler goto out;
83880bca3d3SAxel Dörfler }
83980bca3d3SAxel Dörfler /* All right, all header bytes are zero */
84062cee9f9SGerasim Troeglazov errno = 0;
84180bca3d3SAxel Dörfler out:
84280bca3d3SAxel Dörfler if (na)
84380bca3d3SAxel Dörfler ntfs_attr_close(na);
84480bca3d3SAxel Dörfler free(buf);
84562cee9f9SGerasim Troeglazov err = errno;
84662cee9f9SGerasim Troeglazov if (ntfs_inode_close(ni))
84762cee9f9SGerasim Troeglazov ntfs_error_set(&err);
84862cee9f9SGerasim Troeglazov errno = err;
84962cee9f9SGerasim Troeglazov return errno ? -1 : 0;
85080bca3d3SAxel Dörfler }
85180bca3d3SAxel Dörfler
8520d2c294fSGerasim Troeglazov /*
8530d2c294fSGerasim Troeglazov * Make sure a LOGGED_UTILITY_STREAM attribute named "$TXF_DATA"
8540d2c294fSGerasim Troeglazov * on the root directory is resident.
8550d2c294fSGerasim Troeglazov * When it is non-resident, the partition cannot be mounted on Vista
8560d2c294fSGerasim Troeglazov * (see http://support.microsoft.com/kb/974729)
8570d2c294fSGerasim Troeglazov *
8580d2c294fSGerasim Troeglazov * We take care to avoid this situation, however this can be a
8590d2c294fSGerasim Troeglazov * consequence of having used an older version (including older
8600d2c294fSGerasim Troeglazov * Windows version), so we had better fix it.
8610d2c294fSGerasim Troeglazov *
8620d2c294fSGerasim Troeglazov * Returns 0 if unneeded or successful
8630d2c294fSGerasim Troeglazov * -1 if there was an error, explained by errno
8640d2c294fSGerasim Troeglazov */
8650d2c294fSGerasim Troeglazov
fix_txf_data(ntfs_volume * vol)8660d2c294fSGerasim Troeglazov static int fix_txf_data(ntfs_volume *vol)
8670d2c294fSGerasim Troeglazov {
8680d2c294fSGerasim Troeglazov void *txf_data;
8690d2c294fSGerasim Troeglazov s64 txf_data_size;
8700d2c294fSGerasim Troeglazov ntfs_inode *ni;
8710d2c294fSGerasim Troeglazov ntfs_attr *na;
8720d2c294fSGerasim Troeglazov int res;
8730d2c294fSGerasim Troeglazov
8740d2c294fSGerasim Troeglazov res = 0;
8750d2c294fSGerasim Troeglazov ntfs_log_debug("Loading root directory\n");
8760d2c294fSGerasim Troeglazov ni = ntfs_inode_open(vol, FILE_root);
8770d2c294fSGerasim Troeglazov if (!ni) {
8780d2c294fSGerasim Troeglazov ntfs_log_perror("Failed to open root directory");
8790d2c294fSGerasim Troeglazov res = -1;
8800d2c294fSGerasim Troeglazov } else {
8810d2c294fSGerasim Troeglazov /* Get the $TXF_DATA attribute */
8820d2c294fSGerasim Troeglazov na = ntfs_attr_open(ni, AT_LOGGED_UTILITY_STREAM, TXF_DATA, 9);
8830d2c294fSGerasim Troeglazov if (na) {
8840d2c294fSGerasim Troeglazov if (NAttrNonResident(na)) {
8850d2c294fSGerasim Troeglazov /*
8860d2c294fSGerasim Troeglazov * Fix the attribute by truncating, then
8870d2c294fSGerasim Troeglazov * rewriting it.
8880d2c294fSGerasim Troeglazov */
8890d2c294fSGerasim Troeglazov ntfs_log_debug("Making $TXF_DATA resident\n");
8900d2c294fSGerasim Troeglazov txf_data = ntfs_attr_readall(ni,
8910d2c294fSGerasim Troeglazov AT_LOGGED_UTILITY_STREAM,
8920d2c294fSGerasim Troeglazov TXF_DATA, 9, &txf_data_size);
8930d2c294fSGerasim Troeglazov if (txf_data) {
8940d2c294fSGerasim Troeglazov if (ntfs_attr_truncate(na, 0)
8950d2c294fSGerasim Troeglazov || (ntfs_attr_pwrite(na, 0,
8960d2c294fSGerasim Troeglazov txf_data_size, txf_data)
8970d2c294fSGerasim Troeglazov != txf_data_size))
8980d2c294fSGerasim Troeglazov res = -1;
8990d2c294fSGerasim Troeglazov free(txf_data);
9000d2c294fSGerasim Troeglazov }
9010d2c294fSGerasim Troeglazov if (res)
9020d2c294fSGerasim Troeglazov ntfs_log_error("Failed to make $TXF_DATA resident\n");
9030d2c294fSGerasim Troeglazov else
9040d2c294fSGerasim Troeglazov ntfs_log_error("$TXF_DATA made resident\n");
9050d2c294fSGerasim Troeglazov }
9060d2c294fSGerasim Troeglazov ntfs_attr_close(na);
9070d2c294fSGerasim Troeglazov }
9080d2c294fSGerasim Troeglazov if (ntfs_inode_close(ni)) {
9090d2c294fSGerasim Troeglazov ntfs_log_perror("Failed to close root");
9100d2c294fSGerasim Troeglazov res = -1;
9110d2c294fSGerasim Troeglazov }
9120d2c294fSGerasim Troeglazov }
9130d2c294fSGerasim Troeglazov return (res);
9140d2c294fSGerasim Troeglazov }
9150d2c294fSGerasim Troeglazov
91680bca3d3SAxel Dörfler /**
91780bca3d3SAxel Dörfler * ntfs_device_mount - open ntfs volume
91880bca3d3SAxel Dörfler * @dev: device to open
91980bca3d3SAxel Dörfler * @flags: optional mount flags
92080bca3d3SAxel Dörfler *
92180bca3d3SAxel Dörfler * This function mounts an ntfs volume. @dev should describe the device which
92280bca3d3SAxel Dörfler * to mount as the ntfs volume.
92380bca3d3SAxel Dörfler *
92480bca3d3SAxel Dörfler * @flags is an optional second parameter. The same flags are used as for
92530bc84e9SGerasim Troeglazov * the mount system call (man 2 mount). Currently only the following flag
92630bc84e9SGerasim Troeglazov * is implemented:
927da0906f2SGerasim Troeglazov * NTFS_MNT_RDONLY - mount volume read-only
92880bca3d3SAxel Dörfler *
92980bca3d3SAxel Dörfler * The function opens the device @dev and verifies that it contains a valid
93080bca3d3SAxel Dörfler * bootsector. Then, it allocates an ntfs_volume structure and initializes
93180bca3d3SAxel Dörfler * some of the values inside the structure from the information stored in the
93280bca3d3SAxel Dörfler * bootsector. It proceeds to load the necessary system files and completes
93380bca3d3SAxel Dörfler * setting up the structure.
93480bca3d3SAxel Dörfler *
93580bca3d3SAxel Dörfler * Return the allocated volume structure on success and NULL on error with
93680bca3d3SAxel Dörfler * errno set to the error code.
93780bca3d3SAxel Dörfler */
ntfs_device_mount(struct ntfs_device * dev,ntfs_mount_flags flags)938da0906f2SGerasim Troeglazov ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags)
93980bca3d3SAxel Dörfler {
94080bca3d3SAxel Dörfler s64 l;
94180bca3d3SAxel Dörfler ntfs_volume *vol;
94280bca3d3SAxel Dörfler u8 *m = NULL, *m2 = NULL;
94380bca3d3SAxel Dörfler ntfs_attr_search_ctx *ctx = NULL;
94480bca3d3SAxel Dörfler ntfs_inode *ni;
94580bca3d3SAxel Dörfler ntfs_attr *na;
94680bca3d3SAxel Dörfler ATTR_RECORD *a;
94780bca3d3SAxel Dörfler VOLUME_INFORMATION *vinf;
94880bca3d3SAxel Dörfler ntfschar *vname;
9490490778eSAugustin Cavalier u32 record_size;
95080bca3d3SAxel Dörfler int i, j, eo;
951a814d850Sthreedeyes unsigned int k;
95280bca3d3SAxel Dörfler u32 u;
9530490778eSAugustin Cavalier BOOL need_fallback_ro;
95480bca3d3SAxel Dörfler
9550490778eSAugustin Cavalier need_fallback_ro = FALSE;
95680bca3d3SAxel Dörfler vol = ntfs_volume_startup(dev, flags);
95730bc84e9SGerasim Troeglazov if (!vol)
95880bca3d3SAxel Dörfler return NULL;
95980bca3d3SAxel Dörfler
96080bca3d3SAxel Dörfler /* Load data from $MFT and $MFTMirr and compare the contents. */
96180bca3d3SAxel Dörfler m = ntfs_malloc(vol->mftmirr_size << vol->mft_record_size_bits);
96280bca3d3SAxel Dörfler m2 = ntfs_malloc(vol->mftmirr_size << vol->mft_record_size_bits);
96380bca3d3SAxel Dörfler if (!m || !m2)
96480bca3d3SAxel Dörfler goto error_exit;
96580bca3d3SAxel Dörfler
96680bca3d3SAxel Dörfler l = ntfs_attr_mst_pread(vol->mft_na, 0, vol->mftmirr_size,
96780bca3d3SAxel Dörfler vol->mft_record_size, m);
96880bca3d3SAxel Dörfler if (l != vol->mftmirr_size) {
96980bca3d3SAxel Dörfler if (l == -1)
97080bca3d3SAxel Dörfler ntfs_log_perror("Failed to read $MFT");
97180bca3d3SAxel Dörfler else {
97280bca3d3SAxel Dörfler ntfs_log_error("Failed to read $MFT, unexpected length "
9736b3592caSGerasim Troeglazov "(%lld != %d).\n", (long long)l,
9746b3592caSGerasim Troeglazov vol->mftmirr_size);
97580bca3d3SAxel Dörfler errno = EIO;
97680bca3d3SAxel Dörfler }
97780bca3d3SAxel Dörfler goto error_exit;
97880bca3d3SAxel Dörfler }
9799102cad6SAugustin Cavalier for (i = 0; (i < l) && (i < FILE_first_user); ++i)
9809102cad6SAugustin Cavalier if (ntfs_mft_record_check(vol, FILE_MFT + i,
9819102cad6SAugustin Cavalier (MFT_RECORD*)(m + i*vol->mft_record_size)))
9829102cad6SAugustin Cavalier goto error_exit;
98380bca3d3SAxel Dörfler l = ntfs_attr_mst_pread(vol->mftmirr_na, 0, vol->mftmirr_size,
98480bca3d3SAxel Dörfler vol->mft_record_size, m2);
98580bca3d3SAxel Dörfler if (l != vol->mftmirr_size) {
98662cee9f9SGerasim Troeglazov if (l == -1) {
98780bca3d3SAxel Dörfler ntfs_log_perror("Failed to read $MFTMirr");
98880bca3d3SAxel Dörfler goto error_exit;
98980bca3d3SAxel Dörfler }
99062cee9f9SGerasim Troeglazov vol->mftmirr_size = l;
99180bca3d3SAxel Dörfler }
9929102cad6SAugustin Cavalier for (i = 0; (i < l) && (i < FILE_first_user); ++i)
9939102cad6SAugustin Cavalier if (ntfs_mft_record_check(vol, FILE_MFT + i,
9949102cad6SAugustin Cavalier (MFT_RECORD*)(m2 + i*vol->mft_record_size)))
9959102cad6SAugustin Cavalier goto error_exit;
99630bc84e9SGerasim Troeglazov ntfs_log_debug("Comparing $MFTMirr to $MFT...\n");
9979102cad6SAugustin Cavalier /* Windows 10 does not update the full $MFTMirr any more */
9989102cad6SAugustin Cavalier for (i = 0; (i < vol->mftmirr_size) && (i < FILE_first_user); ++i) {
99980bca3d3SAxel Dörfler MFT_RECORD *mrec, *mrec2;
100080bca3d3SAxel Dörfler const char *ESTR[12] = { "$MFT", "$MFTMirr", "$LogFile",
100180bca3d3SAxel Dörfler "$Volume", "$AttrDef", "root directory", "$Bitmap",
100280bca3d3SAxel Dörfler "$Boot", "$BadClus", "$Secure", "$UpCase", "$Extend" };
100380bca3d3SAxel Dörfler const char *s;
100480bca3d3SAxel Dörfler
100580bca3d3SAxel Dörfler if (i < 12)
100680bca3d3SAxel Dörfler s = ESTR[i];
100780bca3d3SAxel Dörfler else if (i < 16)
100880bca3d3SAxel Dörfler s = "system file";
100980bca3d3SAxel Dörfler else
101080bca3d3SAxel Dörfler s = "mft record";
101180bca3d3SAxel Dörfler
101280bca3d3SAxel Dörfler mrec = (MFT_RECORD*)(m + i * vol->mft_record_size);
101380bca3d3SAxel Dörfler if (mrec->flags & MFT_RECORD_IN_USE) {
10140490778eSAugustin Cavalier if (ntfs_is_baad_record(mrec->magic)) {
101580bca3d3SAxel Dörfler ntfs_log_error("$MFT error: Incomplete multi "
101680bca3d3SAxel Dörfler "sector transfer detected in "
101780bca3d3SAxel Dörfler "'%s'.\n", s);
101880bca3d3SAxel Dörfler goto io_error_exit;
101980bca3d3SAxel Dörfler }
10200490778eSAugustin Cavalier if (!ntfs_is_mft_record(mrec->magic)) {
102180bca3d3SAxel Dörfler ntfs_log_error("$MFT error: Invalid mft "
102280bca3d3SAxel Dörfler "record for '%s'.\n", s);
102380bca3d3SAxel Dörfler goto io_error_exit;
102480bca3d3SAxel Dörfler }
102580bca3d3SAxel Dörfler }
102680bca3d3SAxel Dörfler mrec2 = (MFT_RECORD*)(m2 + i * vol->mft_record_size);
102780bca3d3SAxel Dörfler if (mrec2->flags & MFT_RECORD_IN_USE) {
10280490778eSAugustin Cavalier if (ntfs_is_baad_record(mrec2->magic)) {
102980bca3d3SAxel Dörfler ntfs_log_error("$MFTMirr error: Incomplete "
103080bca3d3SAxel Dörfler "multi sector transfer "
103180bca3d3SAxel Dörfler "detected in '%s'.\n", s);
103280bca3d3SAxel Dörfler goto io_error_exit;
103380bca3d3SAxel Dörfler }
10340490778eSAugustin Cavalier if (!ntfs_is_mft_record(mrec2->magic)) {
103580bca3d3SAxel Dörfler ntfs_log_error("$MFTMirr error: Invalid mft "
103680bca3d3SAxel Dörfler "record for '%s'.\n", s);
103780bca3d3SAxel Dörfler goto io_error_exit;
103880bca3d3SAxel Dörfler }
103980bca3d3SAxel Dörfler }
10400490778eSAugustin Cavalier record_size = ntfs_mft_record_get_data_size(mrec);
10410490778eSAugustin Cavalier if ((record_size <= sizeof(MFT_RECORD))
10420490778eSAugustin Cavalier || (record_size > vol->mft_record_size)
10430490778eSAugustin Cavalier || memcmp(mrec, mrec2, record_size)) {
104480bca3d3SAxel Dörfler ntfs_log_error("$MFTMirr does not match $MFT (record "
104580bca3d3SAxel Dörfler "%d).\n", i);
104680bca3d3SAxel Dörfler goto io_error_exit;
104780bca3d3SAxel Dörfler }
104880bca3d3SAxel Dörfler }
104980bca3d3SAxel Dörfler
105080bca3d3SAxel Dörfler free(m2);
105180bca3d3SAxel Dörfler free(m);
105280bca3d3SAxel Dörfler m = m2 = NULL;
105380bca3d3SAxel Dörfler
105480bca3d3SAxel Dörfler /* Now load the bitmap from $Bitmap. */
105530bc84e9SGerasim Troeglazov ntfs_log_debug("Loading $Bitmap...\n");
105680bca3d3SAxel Dörfler vol->lcnbmp_ni = ntfs_inode_open(vol, FILE_Bitmap);
105780bca3d3SAxel Dörfler if (!vol->lcnbmp_ni) {
105830bc84e9SGerasim Troeglazov ntfs_log_perror("Failed to open inode FILE_Bitmap");
105980bca3d3SAxel Dörfler goto error_exit;
106080bca3d3SAxel Dörfler }
106130bc84e9SGerasim Troeglazov
106280bca3d3SAxel Dörfler vol->lcnbmp_na = ntfs_attr_open(vol->lcnbmp_ni, AT_DATA, AT_UNNAMED, 0);
106380bca3d3SAxel Dörfler if (!vol->lcnbmp_na) {
106480bca3d3SAxel Dörfler ntfs_log_perror("Failed to open ntfs attribute");
106580bca3d3SAxel Dörfler goto error_exit;
106680bca3d3SAxel Dörfler }
106730bc84e9SGerasim Troeglazov
106830bc84e9SGerasim Troeglazov if (vol->lcnbmp_na->data_size > vol->lcnbmp_na->allocated_size) {
106930bc84e9SGerasim Troeglazov ntfs_log_error("Corrupt cluster map size (%lld > %lld)\n",
107030bc84e9SGerasim Troeglazov (long long)vol->lcnbmp_na->data_size,
107130bc84e9SGerasim Troeglazov (long long)vol->lcnbmp_na->allocated_size);
107230bc84e9SGerasim Troeglazov goto io_error_exit;
107330bc84e9SGerasim Troeglazov }
107480bca3d3SAxel Dörfler
107580bca3d3SAxel Dörfler /* Now load the upcase table from $UpCase. */
107630bc84e9SGerasim Troeglazov ntfs_log_debug("Loading $UpCase...\n");
107780bca3d3SAxel Dörfler ni = ntfs_inode_open(vol, FILE_UpCase);
107880bca3d3SAxel Dörfler if (!ni) {
107930bc84e9SGerasim Troeglazov ntfs_log_perror("Failed to open inode FILE_UpCase");
108080bca3d3SAxel Dörfler goto error_exit;
108180bca3d3SAxel Dörfler }
108280bca3d3SAxel Dörfler /* Get an ntfs attribute for $UpCase/$DATA. */
108380bca3d3SAxel Dörfler na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
108480bca3d3SAxel Dörfler if (!na) {
108580bca3d3SAxel Dörfler ntfs_log_perror("Failed to open ntfs attribute");
10869102cad6SAugustin Cavalier ntfs_inode_close(ni);
108780bca3d3SAxel Dörfler goto error_exit;
108880bca3d3SAxel Dörfler }
108980bca3d3SAxel Dörfler /*
109080bca3d3SAxel Dörfler * Note: Normally, the upcase table has a length equal to 65536
10919102cad6SAugustin Cavalier * 2-byte Unicode characters. Anyway we currently can only process
10929102cad6SAugustin Cavalier * such characters.
109380bca3d3SAxel Dörfler */
10949102cad6SAugustin Cavalier if ((na->data_size - 2) & ~0x1fffeULL) {
10959102cad6SAugustin Cavalier ntfs_log_error("Error: Upcase table is invalid (want size even "
10969102cad6SAugustin Cavalier "<= 131072).\n");
109780bca3d3SAxel Dörfler errno = EINVAL;
10989102cad6SAugustin Cavalier goto bad_upcase;
109980bca3d3SAxel Dörfler }
110080bca3d3SAxel Dörfler if (vol->upcase_len != na->data_size >> 1) {
110180bca3d3SAxel Dörfler vol->upcase_len = na->data_size >> 1;
110280bca3d3SAxel Dörfler /* Throw away default table. */
110380bca3d3SAxel Dörfler free(vol->upcase);
110480bca3d3SAxel Dörfler vol->upcase = ntfs_malloc(na->data_size);
110530bc84e9SGerasim Troeglazov if (!vol->upcase)
11069102cad6SAugustin Cavalier goto bad_upcase;
110780bca3d3SAxel Dörfler }
110880bca3d3SAxel Dörfler /* Read in the $DATA attribute value into the buffer. */
110980bca3d3SAxel Dörfler l = ntfs_attr_pread(na, 0, na->data_size, vol->upcase);
111080bca3d3SAxel Dörfler if (l != na->data_size) {
111180bca3d3SAxel Dörfler ntfs_log_error("Failed to read $UpCase, unexpected length "
11126b3592caSGerasim Troeglazov "(%lld != %lld).\n", (long long)l,
11136b3592caSGerasim Troeglazov (long long)na->data_size);
111480bca3d3SAxel Dörfler errno = EIO;
11159102cad6SAugustin Cavalier goto bad_upcase;
111680bca3d3SAxel Dörfler }
111780bca3d3SAxel Dörfler /* Done with the $UpCase mft record. */
111880bca3d3SAxel Dörfler ntfs_attr_close(na);
111962cee9f9SGerasim Troeglazov if (ntfs_inode_close(ni)) {
112062cee9f9SGerasim Troeglazov ntfs_log_perror("Failed to close $UpCase");
112162cee9f9SGerasim Troeglazov goto error_exit;
112262cee9f9SGerasim Troeglazov }
1123a814d850Sthreedeyes /* Consistency check of $UpCase, restricted to plain ASCII chars */
1124a814d850Sthreedeyes k = 0x20;
1125a814d850Sthreedeyes while ((k < vol->upcase_len)
1126a814d850Sthreedeyes && (k < 0x7f)
1127a814d850Sthreedeyes && (le16_to_cpu(vol->upcase[k])
1128a814d850Sthreedeyes == ((k < 'a') || (k > 'z') ? k : k + 'A' - 'a')))
1129a814d850Sthreedeyes k++;
1130a814d850Sthreedeyes if (k < 0x7f) {
1131a814d850Sthreedeyes ntfs_log_error("Corrupted file $UpCase\n");
1132a814d850Sthreedeyes goto io_error_exit;
1133a814d850Sthreedeyes }
113480bca3d3SAxel Dörfler
113580bca3d3SAxel Dörfler /*
113680bca3d3SAxel Dörfler * Now load $Volume and set the version information and flags in the
113780bca3d3SAxel Dörfler * vol structure accordingly.
113880bca3d3SAxel Dörfler */
113930bc84e9SGerasim Troeglazov ntfs_log_debug("Loading $Volume...\n");
114080bca3d3SAxel Dörfler vol->vol_ni = ntfs_inode_open(vol, FILE_Volume);
114180bca3d3SAxel Dörfler if (!vol->vol_ni) {
114230bc84e9SGerasim Troeglazov ntfs_log_perror("Failed to open inode FILE_Volume");
114380bca3d3SAxel Dörfler goto error_exit;
114480bca3d3SAxel Dörfler }
114580bca3d3SAxel Dörfler /* Get a search context for the $Volume/$VOLUME_INFORMATION lookup. */
114680bca3d3SAxel Dörfler ctx = ntfs_attr_get_search_ctx(vol->vol_ni, NULL);
114730bc84e9SGerasim Troeglazov if (!ctx)
114880bca3d3SAxel Dörfler goto error_exit;
114930bc84e9SGerasim Troeglazov
115080bca3d3SAxel Dörfler /* Find the $VOLUME_INFORMATION attribute. */
115180bca3d3SAxel Dörfler if (ntfs_attr_lookup(AT_VOLUME_INFORMATION, AT_UNNAMED, 0, 0, 0, NULL,
115280bca3d3SAxel Dörfler 0, ctx)) {
115380bca3d3SAxel Dörfler ntfs_log_perror("$VOLUME_INFORMATION attribute not found in "
115480bca3d3SAxel Dörfler "$Volume");
115580bca3d3SAxel Dörfler goto error_exit;
115680bca3d3SAxel Dörfler }
115780bca3d3SAxel Dörfler a = ctx->attr;
115880bca3d3SAxel Dörfler /* Has to be resident. */
115980bca3d3SAxel Dörfler if (a->non_resident) {
116080bca3d3SAxel Dörfler ntfs_log_error("Attribute $VOLUME_INFORMATION must be "
116180bca3d3SAxel Dörfler "resident but it isn't.\n");
116280bca3d3SAxel Dörfler errno = EIO;
116380bca3d3SAxel Dörfler goto error_exit;
116480bca3d3SAxel Dörfler }
116580bca3d3SAxel Dörfler /* Get a pointer to the value of the attribute. */
116680bca3d3SAxel Dörfler vinf = (VOLUME_INFORMATION*)(le16_to_cpu(a->value_offset) + (char*)a);
116780bca3d3SAxel Dörfler /* Sanity checks. */
116880bca3d3SAxel Dörfler if ((char*)vinf + le32_to_cpu(a->value_length) > (char*)ctx->mrec +
116980bca3d3SAxel Dörfler le32_to_cpu(ctx->mrec->bytes_in_use) ||
117080bca3d3SAxel Dörfler le16_to_cpu(a->value_offset) + le32_to_cpu(
117180bca3d3SAxel Dörfler a->value_length) > le32_to_cpu(a->length)) {
117280bca3d3SAxel Dörfler ntfs_log_error("$VOLUME_INFORMATION in $Volume is corrupt.\n");
117380bca3d3SAxel Dörfler errno = EIO;
117480bca3d3SAxel Dörfler goto error_exit;
117580bca3d3SAxel Dörfler }
117680bca3d3SAxel Dörfler /* Setup vol from the volume information attribute value. */
117780bca3d3SAxel Dörfler vol->major_ver = vinf->major_ver;
117880bca3d3SAxel Dörfler vol->minor_ver = vinf->minor_ver;
117980bca3d3SAxel Dörfler /* Do not use le16_to_cpu() macro here as our VOLUME_FLAGS are
118080bca3d3SAxel Dörfler defined using cpu_to_le16() macro and hence are consistent. */
118180bca3d3SAxel Dörfler vol->flags = vinf->flags;
118280bca3d3SAxel Dörfler /*
118380bca3d3SAxel Dörfler * Reinitialize the search context for the $Volume/$VOLUME_NAME lookup.
118480bca3d3SAxel Dörfler */
118580bca3d3SAxel Dörfler ntfs_attr_reinit_search_ctx(ctx);
118680bca3d3SAxel Dörfler if (ntfs_attr_lookup(AT_VOLUME_NAME, AT_UNNAMED, 0, 0, 0, NULL, 0,
118780bca3d3SAxel Dörfler ctx)) {
118880bca3d3SAxel Dörfler if (errno != ENOENT) {
118980bca3d3SAxel Dörfler ntfs_log_perror("Failed to lookup of $VOLUME_NAME in "
119080bca3d3SAxel Dörfler "$Volume failed");
119180bca3d3SAxel Dörfler goto error_exit;
119280bca3d3SAxel Dörfler }
119380bca3d3SAxel Dörfler /*
119480bca3d3SAxel Dörfler * Attribute not present. This has been seen in the field.
119580bca3d3SAxel Dörfler * Treat this the same way as if the attribute was present but
119680bca3d3SAxel Dörfler * had zero length.
119780bca3d3SAxel Dörfler */
119880bca3d3SAxel Dörfler vol->vol_name = ntfs_malloc(1);
119930bc84e9SGerasim Troeglazov if (!vol->vol_name)
120080bca3d3SAxel Dörfler goto error_exit;
120180bca3d3SAxel Dörfler vol->vol_name[0] = '\0';
120280bca3d3SAxel Dörfler } else {
120380bca3d3SAxel Dörfler a = ctx->attr;
120480bca3d3SAxel Dörfler /* Has to be resident. */
120580bca3d3SAxel Dörfler if (a->non_resident) {
120680bca3d3SAxel Dörfler ntfs_log_error("$VOLUME_NAME must be resident.\n");
120780bca3d3SAxel Dörfler errno = EIO;
120880bca3d3SAxel Dörfler goto error_exit;
120980bca3d3SAxel Dörfler }
121080bca3d3SAxel Dörfler /* Get a pointer to the value of the attribute. */
121180bca3d3SAxel Dörfler vname = (ntfschar*)(le16_to_cpu(a->value_offset) + (char*)a);
121280bca3d3SAxel Dörfler u = le32_to_cpu(a->value_length) / 2;
121380bca3d3SAxel Dörfler /*
121480bca3d3SAxel Dörfler * Convert Unicode volume name to current locale multibyte
121580bca3d3SAxel Dörfler * format.
121680bca3d3SAxel Dörfler */
121780bca3d3SAxel Dörfler vol->vol_name = NULL;
121880bca3d3SAxel Dörfler if (ntfs_ucstombs(vname, u, &vol->vol_name, 0) == -1) {
121980bca3d3SAxel Dörfler ntfs_log_perror("Volume name could not be converted "
122080bca3d3SAxel Dörfler "to current locale");
122180bca3d3SAxel Dörfler ntfs_log_debug("Forcing name into ASCII by replacing "
122280bca3d3SAxel Dörfler "non-ASCII characters with underscores.\n");
122380bca3d3SAxel Dörfler vol->vol_name = ntfs_malloc(u + 1);
122430bc84e9SGerasim Troeglazov if (!vol->vol_name)
122580bca3d3SAxel Dörfler goto error_exit;
122630bc84e9SGerasim Troeglazov
122780bca3d3SAxel Dörfler for (j = 0; j < (s32)u; j++) {
12280d2c294fSGerasim Troeglazov u16 uc = le16_to_cpu(vname[j]);
122980bca3d3SAxel Dörfler if (uc > 0xff)
12300d2c294fSGerasim Troeglazov uc = (u16)'_';
123180bca3d3SAxel Dörfler vol->vol_name[j] = (char)uc;
123280bca3d3SAxel Dörfler }
123380bca3d3SAxel Dörfler vol->vol_name[u] = '\0';
123480bca3d3SAxel Dörfler }
123580bca3d3SAxel Dörfler }
123680bca3d3SAxel Dörfler ntfs_attr_put_search_ctx(ctx);
123780bca3d3SAxel Dörfler ctx = NULL;
123880bca3d3SAxel Dörfler /* Now load the attribute definitions from $AttrDef. */
123930bc84e9SGerasim Troeglazov ntfs_log_debug("Loading $AttrDef...\n");
124080bca3d3SAxel Dörfler ni = ntfs_inode_open(vol, FILE_AttrDef);
124180bca3d3SAxel Dörfler if (!ni) {
124280bca3d3SAxel Dörfler ntfs_log_perror("Failed to open $AttrDef");
124380bca3d3SAxel Dörfler goto error_exit;
124480bca3d3SAxel Dörfler }
124580bca3d3SAxel Dörfler /* Get an ntfs attribute for $AttrDef/$DATA. */
124680bca3d3SAxel Dörfler na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
124780bca3d3SAxel Dörfler if (!na) {
124880bca3d3SAxel Dörfler ntfs_log_perror("Failed to open ntfs attribute");
124980bca3d3SAxel Dörfler goto error_exit;
125080bca3d3SAxel Dörfler }
12519102cad6SAugustin Cavalier /* Check we don't overflow 24-bits. */
12529102cad6SAugustin Cavalier if ((u64)na->data_size > 0xffffffLL) {
125380bca3d3SAxel Dörfler ntfs_log_error("Attribute definition table is too big (max "
12549102cad6SAugustin Cavalier "24-bit allowed).\n");
125580bca3d3SAxel Dörfler errno = EINVAL;
125680bca3d3SAxel Dörfler goto error_exit;
125780bca3d3SAxel Dörfler }
125880bca3d3SAxel Dörfler vol->attrdef_len = na->data_size;
125980bca3d3SAxel Dörfler vol->attrdef = ntfs_malloc(na->data_size);
126030bc84e9SGerasim Troeglazov if (!vol->attrdef)
126180bca3d3SAxel Dörfler goto error_exit;
126280bca3d3SAxel Dörfler /* Read in the $DATA attribute value into the buffer. */
126380bca3d3SAxel Dörfler l = ntfs_attr_pread(na, 0, na->data_size, vol->attrdef);
126480bca3d3SAxel Dörfler if (l != na->data_size) {
126580bca3d3SAxel Dörfler ntfs_log_error("Failed to read $AttrDef, unexpected length "
12666b3592caSGerasim Troeglazov "(%lld != %lld).\n", (long long)l,
12676b3592caSGerasim Troeglazov (long long)na->data_size);
126880bca3d3SAxel Dörfler errno = EIO;
126980bca3d3SAxel Dörfler goto error_exit;
127080bca3d3SAxel Dörfler }
127180bca3d3SAxel Dörfler /* Done with the $AttrDef mft record. */
127280bca3d3SAxel Dörfler ntfs_attr_close(na);
127362cee9f9SGerasim Troeglazov if (ntfs_inode_close(ni)) {
127462cee9f9SGerasim Troeglazov ntfs_log_perror("Failed to close $AttrDef");
127562cee9f9SGerasim Troeglazov goto error_exit;
127662cee9f9SGerasim Troeglazov }
12770490778eSAugustin Cavalier
12780490778eSAugustin Cavalier /* Open $Secure. */
12790490778eSAugustin Cavalier if (ntfs_open_secure(vol))
12800490778eSAugustin Cavalier goto error_exit;
12810490778eSAugustin Cavalier
128280bca3d3SAxel Dörfler /*
128380bca3d3SAxel Dörfler * Check for dirty logfile and hibernated Windows.
128480bca3d3SAxel Dörfler * We care only about read-write mounts.
128580bca3d3SAxel Dörfler */
1286da0906f2SGerasim Troeglazov if (!(flags & (NTFS_MNT_RDONLY | NTFS_MNT_FORENSIC))) {
1287da0906f2SGerasim Troeglazov if (!(flags & NTFS_MNT_IGNORE_HIBERFILE) &&
12880490778eSAugustin Cavalier ntfs_volume_check_hiberfile(vol, 1) < 0) {
12890490778eSAugustin Cavalier if (flags & NTFS_MNT_MAY_RDONLY)
12900490778eSAugustin Cavalier need_fallback_ro = TRUE;
12910490778eSAugustin Cavalier else
129280bca3d3SAxel Dörfler goto error_exit;
12930490778eSAugustin Cavalier }
129462cee9f9SGerasim Troeglazov if (ntfs_volume_check_logfile(vol) < 0) {
1295da0906f2SGerasim Troeglazov /* Always reject cached metadata for now */
12960490778eSAugustin Cavalier if (!(flags & NTFS_MNT_RECOVER) || (errno == EPERM)) {
12970490778eSAugustin Cavalier if (flags & NTFS_MNT_MAY_RDONLY)
12980490778eSAugustin Cavalier need_fallback_ro = TRUE;
12990490778eSAugustin Cavalier else
130062cee9f9SGerasim Troeglazov goto error_exit;
13010490778eSAugustin Cavalier } else {
130230bc84e9SGerasim Troeglazov ntfs_log_info("The file system wasn't safely "
130330bc84e9SGerasim Troeglazov "closed on Windows. Fixing.\n");
130462cee9f9SGerasim Troeglazov if (ntfs_logfile_reset(vol))
130562cee9f9SGerasim Troeglazov goto error_exit;
130662cee9f9SGerasim Troeglazov }
13070490778eSAugustin Cavalier }
13080d2c294fSGerasim Troeglazov /* make $TXF_DATA resident if present on the root directory */
13090490778eSAugustin Cavalier if (!(flags & NTFS_MNT_RDONLY) && !need_fallback_ro) {
1310a814d850Sthreedeyes if (fix_txf_data(vol))
13110d2c294fSGerasim Troeglazov goto error_exit;
1312a814d850Sthreedeyes }
13130490778eSAugustin Cavalier }
13140490778eSAugustin Cavalier if (need_fallback_ro) {
13150490778eSAugustin Cavalier NVolSetReadOnly(vol);
13160490778eSAugustin Cavalier ntfs_log_error("%s", fallback_readonly_msg);
13170490778eSAugustin Cavalier }
131880bca3d3SAxel Dörfler
131980bca3d3SAxel Dörfler return vol;
13209102cad6SAugustin Cavalier bad_upcase :
13219102cad6SAugustin Cavalier ntfs_attr_close(na);
13229102cad6SAugustin Cavalier ntfs_inode_close(ni);
13239102cad6SAugustin Cavalier goto error_exit;
132480bca3d3SAxel Dörfler io_error_exit:
132580bca3d3SAxel Dörfler errno = EIO;
132680bca3d3SAxel Dörfler error_exit:
132780bca3d3SAxel Dörfler eo = errno;
132880bca3d3SAxel Dörfler if (ctx)
132980bca3d3SAxel Dörfler ntfs_attr_put_search_ctx(ctx);
133080bca3d3SAxel Dörfler free(m);
133180bca3d3SAxel Dörfler free(m2);
133280bca3d3SAxel Dörfler __ntfs_volume_release(vol);
133380bca3d3SAxel Dörfler errno = eo;
133480bca3d3SAxel Dörfler return NULL;
133580bca3d3SAxel Dörfler }
133680bca3d3SAxel Dörfler
13370d2c294fSGerasim Troeglazov /*
13380d2c294fSGerasim Troeglazov * Set appropriate flags for showing NTFS metafiles
13390d2c294fSGerasim Troeglazov * or files marked as hidden.
13400d2c294fSGerasim Troeglazov * Not set in ntfs_mount() to avoid breaking existing tools.
13410d2c294fSGerasim Troeglazov */
13420d2c294fSGerasim Troeglazov
ntfs_set_shown_files(ntfs_volume * vol,BOOL show_sys_files,BOOL show_hid_files,BOOL hide_dot_files)13430d2c294fSGerasim Troeglazov int ntfs_set_shown_files(ntfs_volume *vol,
13440d2c294fSGerasim Troeglazov BOOL show_sys_files, BOOL show_hid_files,
13450d2c294fSGerasim Troeglazov BOOL hide_dot_files)
13460d2c294fSGerasim Troeglazov {
13470d2c294fSGerasim Troeglazov int res;
13480d2c294fSGerasim Troeglazov
13490d2c294fSGerasim Troeglazov res = -1;
13500d2c294fSGerasim Troeglazov if (vol) {
13510d2c294fSGerasim Troeglazov NVolClearShowSysFiles(vol);
13520d2c294fSGerasim Troeglazov NVolClearShowHidFiles(vol);
13530d2c294fSGerasim Troeglazov NVolClearHideDotFiles(vol);
13540d2c294fSGerasim Troeglazov if (show_sys_files)
13550d2c294fSGerasim Troeglazov NVolSetShowSysFiles(vol);
13560d2c294fSGerasim Troeglazov if (show_hid_files)
13570d2c294fSGerasim Troeglazov NVolSetShowHidFiles(vol);
13580d2c294fSGerasim Troeglazov if (hide_dot_files)
13590d2c294fSGerasim Troeglazov NVolSetHideDotFiles(vol);
13600d2c294fSGerasim Troeglazov res = 0;
13610d2c294fSGerasim Troeglazov }
13620d2c294fSGerasim Troeglazov if (res)
13630d2c294fSGerasim Troeglazov ntfs_log_error("Failed to set file visibility\n");
13640d2c294fSGerasim Troeglazov return (res);
13650d2c294fSGerasim Troeglazov }
13660d2c294fSGerasim Troeglazov
13670d2c294fSGerasim Troeglazov /*
13680d2c294fSGerasim Troeglazov * Set ignore case mode
13690d2c294fSGerasim Troeglazov */
13700d2c294fSGerasim Troeglazov
ntfs_set_ignore_case(ntfs_volume * vol)13710d2c294fSGerasim Troeglazov int ntfs_set_ignore_case(ntfs_volume *vol)
13720d2c294fSGerasim Troeglazov {
13730d2c294fSGerasim Troeglazov int res;
13740d2c294fSGerasim Troeglazov
13750d2c294fSGerasim Troeglazov res = -1;
13760d2c294fSGerasim Troeglazov if (vol && vol->upcase) {
13770d2c294fSGerasim Troeglazov vol->locase = ntfs_locase_table_build(vol->upcase,
13780d2c294fSGerasim Troeglazov vol->upcase_len);
13790d2c294fSGerasim Troeglazov if (vol->locase) {
13800d2c294fSGerasim Troeglazov NVolClearCaseSensitive(vol);
13810d2c294fSGerasim Troeglazov res = 0;
13820d2c294fSGerasim Troeglazov }
13830d2c294fSGerasim Troeglazov }
13840d2c294fSGerasim Troeglazov if (res)
13850d2c294fSGerasim Troeglazov ntfs_log_error("Failed to set ignore_case mode\n");
13860d2c294fSGerasim Troeglazov return (res);
13870d2c294fSGerasim Troeglazov }
13880d2c294fSGerasim Troeglazov
138980bca3d3SAxel Dörfler /**
139080bca3d3SAxel Dörfler * ntfs_mount - open ntfs volume
139180bca3d3SAxel Dörfler * @name: name of device/file to open
139280bca3d3SAxel Dörfler * @flags: optional mount flags
139380bca3d3SAxel Dörfler *
139480bca3d3SAxel Dörfler * This function mounts an ntfs volume. @name should contain the name of the
139580bca3d3SAxel Dörfler * device/file to mount as the ntfs volume.
139680bca3d3SAxel Dörfler *
139780bca3d3SAxel Dörfler * @flags is an optional second parameter. The same flags are used as for
139880bca3d3SAxel Dörfler * the mount system call (man 2 mount). Currently only the following flags
139930bc84e9SGerasim Troeglazov * is implemented:
1400da0906f2SGerasim Troeglazov * NTFS_MNT_RDONLY - mount volume read-only
140180bca3d3SAxel Dörfler *
140280bca3d3SAxel Dörfler * The function opens the device or file @name and verifies that it contains a
140380bca3d3SAxel Dörfler * valid bootsector. Then, it allocates an ntfs_volume structure and initializes
140480bca3d3SAxel Dörfler * some of the values inside the structure from the information stored in the
140580bca3d3SAxel Dörfler * bootsector. It proceeds to load the necessary system files and completes
140680bca3d3SAxel Dörfler * setting up the structure.
140780bca3d3SAxel Dörfler *
140880bca3d3SAxel Dörfler * Return the allocated volume structure on success and NULL on error with
140980bca3d3SAxel Dörfler * errno set to the error code.
141080bca3d3SAxel Dörfler *
141180bca3d3SAxel Dörfler * Note, that a copy is made of @name, and hence it can be discarded as
141280bca3d3SAxel Dörfler * soon as the function returns.
141380bca3d3SAxel Dörfler */
ntfs_mount(const char * name,ntfs_mount_flags flags)141480bca3d3SAxel Dörfler ntfs_volume *ntfs_mount(const char *name __attribute__((unused)),
1415da0906f2SGerasim Troeglazov ntfs_mount_flags flags __attribute__((unused)))
141680bca3d3SAxel Dörfler {
141780bca3d3SAxel Dörfler #ifndef NO_NTFS_DEVICE_DEFAULT_IO_OPS
141880bca3d3SAxel Dörfler struct ntfs_device *dev;
141980bca3d3SAxel Dörfler ntfs_volume *vol;
142080bca3d3SAxel Dörfler
142180bca3d3SAxel Dörfler /* Allocate an ntfs_device structure. */
142280bca3d3SAxel Dörfler dev = ntfs_device_alloc(name, 0, &ntfs_device_default_io_ops, NULL);
142380bca3d3SAxel Dörfler if (!dev)
142480bca3d3SAxel Dörfler return NULL;
142580bca3d3SAxel Dörfler /* Call ntfs_device_mount() to do the actual mount. */
142680bca3d3SAxel Dörfler vol = ntfs_device_mount(dev, flags);
142780bca3d3SAxel Dörfler if (!vol) {
142880bca3d3SAxel Dörfler int eo = errno;
142980bca3d3SAxel Dörfler ntfs_device_free(dev);
143080bca3d3SAxel Dörfler errno = eo;
14310d2c294fSGerasim Troeglazov } else
14320d2c294fSGerasim Troeglazov ntfs_create_lru_caches(vol);
143380bca3d3SAxel Dörfler return vol;
143480bca3d3SAxel Dörfler #else
143580bca3d3SAxel Dörfler /*
143680bca3d3SAxel Dörfler * ntfs_mount() makes no sense if NO_NTFS_DEVICE_DEFAULT_IO_OPS is
143780bca3d3SAxel Dörfler * defined as there are no device operations available in libntfs in
143880bca3d3SAxel Dörfler * this case.
143980bca3d3SAxel Dörfler */
144080bca3d3SAxel Dörfler errno = EOPNOTSUPP;
144180bca3d3SAxel Dörfler return NULL;
144280bca3d3SAxel Dörfler #endif
144380bca3d3SAxel Dörfler }
144480bca3d3SAxel Dörfler
144580bca3d3SAxel Dörfler /**
144680bca3d3SAxel Dörfler * ntfs_umount - close ntfs volume
144780bca3d3SAxel Dörfler * @vol: address of ntfs_volume structure of volume to close
144880bca3d3SAxel Dörfler * @force: if true force close the volume even if it is busy
144980bca3d3SAxel Dörfler *
145080bca3d3SAxel Dörfler * Deallocate all structures (including @vol itself) associated with the ntfs
145180bca3d3SAxel Dörfler * volume @vol.
145280bca3d3SAxel Dörfler *
145380bca3d3SAxel Dörfler * Return 0 on success. On error return -1 with errno set appropriately
145480bca3d3SAxel Dörfler * (most likely to one of EAGAIN, EBUSY or EINVAL). The EAGAIN error means that
145580bca3d3SAxel Dörfler * an operation is in progress and if you try the close later the operation
145680bca3d3SAxel Dörfler * might be completed and the close succeed.
145780bca3d3SAxel Dörfler *
145880bca3d3SAxel Dörfler * If @force is true (i.e. not zero) this function will close the volume even
145980bca3d3SAxel Dörfler * if this means that data might be lost.
146080bca3d3SAxel Dörfler *
146180bca3d3SAxel Dörfler * @vol must have previously been returned by a call to ntfs_mount().
146280bca3d3SAxel Dörfler *
146380bca3d3SAxel Dörfler * @vol itself is deallocated and should no longer be dereferenced after this
146480bca3d3SAxel Dörfler * function returns success. If it returns an error then nothing has been done
146580bca3d3SAxel Dörfler * so it is safe to continue using @vol.
146680bca3d3SAxel Dörfler */
ntfs_umount(ntfs_volume * vol,const BOOL force)146762cee9f9SGerasim Troeglazov int ntfs_umount(ntfs_volume *vol, const BOOL force __attribute__((unused)))
146880bca3d3SAxel Dörfler {
146980bca3d3SAxel Dörfler struct ntfs_device *dev;
147062cee9f9SGerasim Troeglazov int ret;
147180bca3d3SAxel Dörfler
147280bca3d3SAxel Dörfler if (!vol) {
147380bca3d3SAxel Dörfler errno = EINVAL;
147480bca3d3SAxel Dörfler return -1;
147580bca3d3SAxel Dörfler }
147680bca3d3SAxel Dörfler dev = vol->dev;
147762cee9f9SGerasim Troeglazov ret = __ntfs_volume_release(vol);
147880bca3d3SAxel Dörfler ntfs_device_free(dev);
147962cee9f9SGerasim Troeglazov return ret;
148080bca3d3SAxel Dörfler }
148180bca3d3SAxel Dörfler
148280bca3d3SAxel Dörfler #ifdef HAVE_MNTENT_H
148380bca3d3SAxel Dörfler
148480bca3d3SAxel Dörfler /**
148580bca3d3SAxel Dörfler * ntfs_mntent_check - desc
148680bca3d3SAxel Dörfler *
148780bca3d3SAxel Dörfler * If you are wanting to use this, you actually wanted to use
148880bca3d3SAxel Dörfler * ntfs_check_if_mounted(), you just didn't realize. (-:
148980bca3d3SAxel Dörfler *
149080bca3d3SAxel Dörfler * See description of ntfs_check_if_mounted(), below.
149180bca3d3SAxel Dörfler */
ntfs_mntent_check(const char * file,unsigned long * mnt_flags)149280bca3d3SAxel Dörfler static int ntfs_mntent_check(const char *file, unsigned long *mnt_flags)
149380bca3d3SAxel Dörfler {
149480bca3d3SAxel Dörfler struct mntent *mnt;
149580bca3d3SAxel Dörfler char *real_file = NULL, *real_fsname = NULL;
149680bca3d3SAxel Dörfler FILE *f;
149780bca3d3SAxel Dörfler int err = 0;
149880bca3d3SAxel Dörfler
149980bca3d3SAxel Dörfler real_file = ntfs_malloc(PATH_MAX + 1);
150080bca3d3SAxel Dörfler if (!real_file)
150180bca3d3SAxel Dörfler return -1;
150280bca3d3SAxel Dörfler real_fsname = ntfs_malloc(PATH_MAX + 1);
150380bca3d3SAxel Dörfler if (!real_fsname) {
150480bca3d3SAxel Dörfler err = errno;
150580bca3d3SAxel Dörfler goto exit;
150680bca3d3SAxel Dörfler }
1507a814d850Sthreedeyes if (!ntfs_realpath_canonicalize(file, real_file)) {
150880bca3d3SAxel Dörfler err = errno;
150980bca3d3SAxel Dörfler goto exit;
151080bca3d3SAxel Dörfler }
1511d68289f7SGerasim Troeglazov f = setmntent("/proc/mounts", "r");
1512d68289f7SGerasim Troeglazov if (!f && !(f = setmntent(MOUNTED, "r"))) {
151380bca3d3SAxel Dörfler err = errno;
151480bca3d3SAxel Dörfler goto exit;
151580bca3d3SAxel Dörfler }
151680bca3d3SAxel Dörfler while ((mnt = getmntent(f))) {
1517a814d850Sthreedeyes if (!ntfs_realpath_canonicalize(mnt->mnt_fsname, real_fsname))
151880bca3d3SAxel Dörfler continue;
151980bca3d3SAxel Dörfler if (!strcmp(real_file, real_fsname))
152080bca3d3SAxel Dörfler break;
152180bca3d3SAxel Dörfler }
152280bca3d3SAxel Dörfler endmntent(f);
152380bca3d3SAxel Dörfler if (!mnt)
152480bca3d3SAxel Dörfler goto exit;
152580bca3d3SAxel Dörfler *mnt_flags = NTFS_MF_MOUNTED;
152680bca3d3SAxel Dörfler if (!strcmp(mnt->mnt_dir, "/"))
152780bca3d3SAxel Dörfler *mnt_flags |= NTFS_MF_ISROOT;
152880bca3d3SAxel Dörfler #ifdef HAVE_HASMNTOPT
152980bca3d3SAxel Dörfler if (hasmntopt(mnt, "ro") && !hasmntopt(mnt, "rw"))
153080bca3d3SAxel Dörfler *mnt_flags |= NTFS_MF_READONLY;
153180bca3d3SAxel Dörfler #endif
153280bca3d3SAxel Dörfler exit:
153380bca3d3SAxel Dörfler free(real_file);
153480bca3d3SAxel Dörfler free(real_fsname);
153580bca3d3SAxel Dörfler if (err) {
153680bca3d3SAxel Dörfler errno = err;
153780bca3d3SAxel Dörfler return -1;
153880bca3d3SAxel Dörfler }
153980bca3d3SAxel Dörfler return 0;
154080bca3d3SAxel Dörfler }
1541da0906f2SGerasim Troeglazov
1542da0906f2SGerasim Troeglazov #else /* HAVE_MNTENT_H */
1543da0906f2SGerasim Troeglazov
1544da0906f2SGerasim Troeglazov #if defined(__sun) && defined (__SVR4)
1545da0906f2SGerasim Troeglazov
ntfs_mntent_check(const char * file,unsigned long * mnt_flags)1546da0906f2SGerasim Troeglazov static int ntfs_mntent_check(const char *file, unsigned long *mnt_flags)
1547da0906f2SGerasim Troeglazov {
1548da0906f2SGerasim Troeglazov struct mnttab *mnt = NULL;
1549da0906f2SGerasim Troeglazov char *real_file = NULL, *real_fsname = NULL;
1550da0906f2SGerasim Troeglazov FILE *f;
1551da0906f2SGerasim Troeglazov int err = 0;
1552da0906f2SGerasim Troeglazov
1553da0906f2SGerasim Troeglazov real_file = (char*)ntfs_malloc(PATH_MAX + 1);
1554da0906f2SGerasim Troeglazov if (!real_file)
1555da0906f2SGerasim Troeglazov return -1;
1556da0906f2SGerasim Troeglazov real_fsname = (char*)ntfs_malloc(PATH_MAX + 1);
1557da0906f2SGerasim Troeglazov mnt = (struct mnttab*)ntfs_malloc(MNT_LINE_MAX + 1);
1558da0906f2SGerasim Troeglazov if (!real_fsname || !mnt) {
1559da0906f2SGerasim Troeglazov err = errno;
1560da0906f2SGerasim Troeglazov goto exit;
1561da0906f2SGerasim Troeglazov }
1562da0906f2SGerasim Troeglazov if (!ntfs_realpath_canonicalize(file, real_file)) {
1563da0906f2SGerasim Troeglazov err = errno;
1564da0906f2SGerasim Troeglazov goto exit;
1565da0906f2SGerasim Troeglazov }
1566da0906f2SGerasim Troeglazov if (!(f = fopen(MNTTAB, "r"))) {
1567da0906f2SGerasim Troeglazov err = errno;
1568da0906f2SGerasim Troeglazov goto exit;
1569da0906f2SGerasim Troeglazov }
1570da0906f2SGerasim Troeglazov while (!getmntent(f, mnt)) {
1571da0906f2SGerasim Troeglazov if (!ntfs_realpath_canonicalize(mnt->mnt_special, real_fsname))
1572da0906f2SGerasim Troeglazov continue;
1573da0906f2SGerasim Troeglazov if (!strcmp(real_file, real_fsname)) {
1574da0906f2SGerasim Troeglazov *mnt_flags = NTFS_MF_MOUNTED;
1575da0906f2SGerasim Troeglazov if (!strcmp(mnt->mnt_mountp, "/"))
1576da0906f2SGerasim Troeglazov *mnt_flags |= NTFS_MF_ISROOT;
1577da0906f2SGerasim Troeglazov if (hasmntopt(mnt, "ro") && !hasmntopt(mnt, "rw"))
1578da0906f2SGerasim Troeglazov *mnt_flags |= NTFS_MF_READONLY;
1579da0906f2SGerasim Troeglazov break;
1580da0906f2SGerasim Troeglazov }
1581da0906f2SGerasim Troeglazov }
1582da0906f2SGerasim Troeglazov fclose(f);
1583da0906f2SGerasim Troeglazov exit:
1584da0906f2SGerasim Troeglazov free(mnt);
1585da0906f2SGerasim Troeglazov free(real_file);
1586da0906f2SGerasim Troeglazov free(real_fsname);
1587da0906f2SGerasim Troeglazov if (err) {
1588da0906f2SGerasim Troeglazov errno = err;
1589da0906f2SGerasim Troeglazov return -1;
1590da0906f2SGerasim Troeglazov }
1591da0906f2SGerasim Troeglazov return 0;
1592da0906f2SGerasim Troeglazov }
1593da0906f2SGerasim Troeglazov
1594da0906f2SGerasim Troeglazov #endif /* defined(__sun) && defined (__SVR4) */
159580bca3d3SAxel Dörfler #endif /* HAVE_MNTENT_H */
159680bca3d3SAxel Dörfler
159780bca3d3SAxel Dörfler /**
159880bca3d3SAxel Dörfler * ntfs_check_if_mounted - check if an ntfs volume is currently mounted
159980bca3d3SAxel Dörfler * @file: device file to check
160080bca3d3SAxel Dörfler * @mnt_flags: pointer into which to return the ntfs mount flags (see volume.h)
160180bca3d3SAxel Dörfler *
160280bca3d3SAxel Dörfler * If the running system does not support the {set,get,end}mntent() calls,
160380bca3d3SAxel Dörfler * just return 0 and set *@mnt_flags to zero.
160480bca3d3SAxel Dörfler *
160580bca3d3SAxel Dörfler * When the system does support the calls, ntfs_check_if_mounted() first tries
160680bca3d3SAxel Dörfler * to find the device @file in /etc/mtab (or wherever this is kept on the
160780bca3d3SAxel Dörfler * running system). If it is not found, assume the device is not mounted and
160880bca3d3SAxel Dörfler * return 0 and set *@mnt_flags to zero.
160980bca3d3SAxel Dörfler *
161080bca3d3SAxel Dörfler * If the device @file is found, set the NTFS_MF_MOUNTED flags in *@mnt_flags.
161180bca3d3SAxel Dörfler *
161280bca3d3SAxel Dörfler * Further if @file is mounted as the file system root ("/"), set the flag
161380bca3d3SAxel Dörfler * NTFS_MF_ISROOT in *@mnt_flags.
161480bca3d3SAxel Dörfler *
161580bca3d3SAxel Dörfler * Finally, check if the file system is mounted read-only, and if so set the
161680bca3d3SAxel Dörfler * NTFS_MF_READONLY flag in *@mnt_flags.
161780bca3d3SAxel Dörfler *
161880bca3d3SAxel Dörfler * On success return 0 with *@mnt_flags set to the ntfs mount flags.
161980bca3d3SAxel Dörfler *
162080bca3d3SAxel Dörfler * On error return -1 with errno set to the error code.
162180bca3d3SAxel Dörfler */
ntfs_check_if_mounted(const char * file,unsigned long * mnt_flags)162280bca3d3SAxel Dörfler int ntfs_check_if_mounted(const char *file __attribute__((unused)),
162380bca3d3SAxel Dörfler unsigned long *mnt_flags)
162480bca3d3SAxel Dörfler {
162580bca3d3SAxel Dörfler *mnt_flags = 0;
1626da0906f2SGerasim Troeglazov #if defined(HAVE_MNTENT_H) || (defined(__sun) && defined (__SVR4))
162780bca3d3SAxel Dörfler return ntfs_mntent_check(file, mnt_flags);
162880bca3d3SAxel Dörfler #else
162980bca3d3SAxel Dörfler return 0;
163080bca3d3SAxel Dörfler #endif
163180bca3d3SAxel Dörfler }
163280bca3d3SAxel Dörfler
163380bca3d3SAxel Dörfler /**
163480bca3d3SAxel Dörfler * ntfs_version_is_supported - check if NTFS version is supported.
163580bca3d3SAxel Dörfler * @vol: ntfs volume whose version we're interested in.
163680bca3d3SAxel Dörfler *
163780bca3d3SAxel Dörfler * The function checks if the NTFS volume version is known or not.
163880bca3d3SAxel Dörfler * Version 1.1 and 1.2 are used by Windows NT3.x and NT4.
163980bca3d3SAxel Dörfler * Version 2.x is used by Windows 2000 Betas.
164080bca3d3SAxel Dörfler * Version 3.0 is used by Windows 2000.
164180bca3d3SAxel Dörfler * Version 3.1 is used by Windows XP, Windows Server 2003 and Longhorn.
164280bca3d3SAxel Dörfler *
164380bca3d3SAxel Dörfler * Return 0 if NTFS version is supported otherwise -1 with errno set.
164480bca3d3SAxel Dörfler *
164580bca3d3SAxel Dörfler * The following error codes are defined:
164680bca3d3SAxel Dörfler * EOPNOTSUPP - Unknown NTFS version
164780bca3d3SAxel Dörfler * EINVAL - Invalid argument
164880bca3d3SAxel Dörfler */
ntfs_version_is_supported(ntfs_volume * vol)164980bca3d3SAxel Dörfler int ntfs_version_is_supported(ntfs_volume *vol)
165080bca3d3SAxel Dörfler {
165180bca3d3SAxel Dörfler u8 major, minor;
165280bca3d3SAxel Dörfler
165380bca3d3SAxel Dörfler if (!vol) {
165480bca3d3SAxel Dörfler errno = EINVAL;
165580bca3d3SAxel Dörfler return -1;
165680bca3d3SAxel Dörfler }
165780bca3d3SAxel Dörfler
165880bca3d3SAxel Dörfler major = vol->major_ver;
165980bca3d3SAxel Dörfler minor = vol->minor_ver;
166080bca3d3SAxel Dörfler
166180bca3d3SAxel Dörfler if (NTFS_V1_1(major, minor) || NTFS_V1_2(major, minor))
166280bca3d3SAxel Dörfler return 0;
166380bca3d3SAxel Dörfler
166480bca3d3SAxel Dörfler if (NTFS_V2_X(major, minor))
166580bca3d3SAxel Dörfler return 0;
166680bca3d3SAxel Dörfler
166780bca3d3SAxel Dörfler if (NTFS_V3_0(major, minor) || NTFS_V3_1(major, minor))
166880bca3d3SAxel Dörfler return 0;
166980bca3d3SAxel Dörfler
167080bca3d3SAxel Dörfler errno = EOPNOTSUPP;
167180bca3d3SAxel Dörfler return -1;
167280bca3d3SAxel Dörfler }
167380bca3d3SAxel Dörfler
167480bca3d3SAxel Dörfler /**
167580bca3d3SAxel Dörfler * ntfs_logfile_reset - "empty" $LogFile data attribute value
167680bca3d3SAxel Dörfler * @vol: ntfs volume whose $LogFile we intend to reset.
167780bca3d3SAxel Dörfler *
167880bca3d3SAxel Dörfler * Fill the value of the $LogFile data attribute, i.e. the contents of
167980bca3d3SAxel Dörfler * the file, with 0xff's, thus marking the journal as empty.
168080bca3d3SAxel Dörfler *
168180bca3d3SAxel Dörfler * FIXME(?): We might need to zero the LSN field of every single mft
168280bca3d3SAxel Dörfler * record as well. (But, first try without doing that and see what
168380bca3d3SAxel Dörfler * happens, since chkdsk might pickup the pieces and do it for us...)
168480bca3d3SAxel Dörfler *
168580bca3d3SAxel Dörfler * On success return 0.
168680bca3d3SAxel Dörfler *
168780bca3d3SAxel Dörfler * On error return -1 with errno set to the error code.
168880bca3d3SAxel Dörfler */
ntfs_logfile_reset(ntfs_volume * vol)168980bca3d3SAxel Dörfler int ntfs_logfile_reset(ntfs_volume *vol)
169080bca3d3SAxel Dörfler {
169180bca3d3SAxel Dörfler ntfs_inode *ni;
169280bca3d3SAxel Dörfler ntfs_attr *na;
169380bca3d3SAxel Dörfler int eo;
169480bca3d3SAxel Dörfler
169580bca3d3SAxel Dörfler if (!vol) {
169680bca3d3SAxel Dörfler errno = EINVAL;
169780bca3d3SAxel Dörfler return -1;
169880bca3d3SAxel Dörfler }
169980bca3d3SAxel Dörfler
170062cee9f9SGerasim Troeglazov ni = ntfs_inode_open(vol, FILE_LogFile);
170162cee9f9SGerasim Troeglazov if (!ni) {
170262cee9f9SGerasim Troeglazov ntfs_log_perror("Failed to open inode FILE_LogFile");
170380bca3d3SAxel Dörfler return -1;
170480bca3d3SAxel Dörfler }
170580bca3d3SAxel Dörfler
170662cee9f9SGerasim Troeglazov na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
170762cee9f9SGerasim Troeglazov if (!na) {
170880bca3d3SAxel Dörfler eo = errno;
170980bca3d3SAxel Dörfler ntfs_log_perror("Failed to open $FILE_LogFile/$DATA");
171080bca3d3SAxel Dörfler goto error_exit;
171180bca3d3SAxel Dörfler }
171280bca3d3SAxel Dörfler
171380bca3d3SAxel Dörfler if (ntfs_empty_logfile(na)) {
171480bca3d3SAxel Dörfler eo = errno;
171580bca3d3SAxel Dörfler ntfs_attr_close(na);
171680bca3d3SAxel Dörfler goto error_exit;
171780bca3d3SAxel Dörfler }
171862cee9f9SGerasim Troeglazov
171980bca3d3SAxel Dörfler ntfs_attr_close(na);
172080bca3d3SAxel Dörfler return ntfs_inode_close(ni);
172180bca3d3SAxel Dörfler
172280bca3d3SAxel Dörfler error_exit:
172380bca3d3SAxel Dörfler ntfs_inode_close(ni);
172480bca3d3SAxel Dörfler errno = eo;
172580bca3d3SAxel Dörfler return -1;
172680bca3d3SAxel Dörfler }
172780bca3d3SAxel Dörfler
172880bca3d3SAxel Dörfler /**
172980bca3d3SAxel Dörfler * ntfs_volume_write_flags - set the flags of an ntfs volume
173080bca3d3SAxel Dörfler * @vol: ntfs volume where we set the volume flags
173180bca3d3SAxel Dörfler * @flags: new flags
173280bca3d3SAxel Dörfler *
173380bca3d3SAxel Dörfler * Set the on-disk volume flags in the mft record of $Volume and
173480bca3d3SAxel Dörfler * on volume @vol to @flags.
173580bca3d3SAxel Dörfler *
173680bca3d3SAxel Dörfler * Return 0 if successful and -1 if not with errno set to the error code.
173780bca3d3SAxel Dörfler */
ntfs_volume_write_flags(ntfs_volume * vol,const le16 flags)17380d2c294fSGerasim Troeglazov int ntfs_volume_write_flags(ntfs_volume *vol, const le16 flags)
173980bca3d3SAxel Dörfler {
174080bca3d3SAxel Dörfler ATTR_RECORD *a;
174180bca3d3SAxel Dörfler VOLUME_INFORMATION *c;
174280bca3d3SAxel Dörfler ntfs_attr_search_ctx *ctx;
174380bca3d3SAxel Dörfler int ret = -1; /* failure */
174480bca3d3SAxel Dörfler
174580bca3d3SAxel Dörfler if (!vol || !vol->vol_ni) {
174680bca3d3SAxel Dörfler errno = EINVAL;
174780bca3d3SAxel Dörfler return -1;
174880bca3d3SAxel Dörfler }
174980bca3d3SAxel Dörfler /* Get a pointer to the volume information attribute. */
175080bca3d3SAxel Dörfler ctx = ntfs_attr_get_search_ctx(vol->vol_ni, NULL);
175130bc84e9SGerasim Troeglazov if (!ctx)
175280bca3d3SAxel Dörfler return -1;
175330bc84e9SGerasim Troeglazov
175480bca3d3SAxel Dörfler if (ntfs_attr_lookup(AT_VOLUME_INFORMATION, AT_UNNAMED, 0, 0, 0, NULL,
175580bca3d3SAxel Dörfler 0, ctx)) {
175680bca3d3SAxel Dörfler ntfs_log_error("Attribute $VOLUME_INFORMATION was not found "
175780bca3d3SAxel Dörfler "in $Volume!\n");
175880bca3d3SAxel Dörfler goto err_out;
175980bca3d3SAxel Dörfler }
176080bca3d3SAxel Dörfler a = ctx->attr;
176180bca3d3SAxel Dörfler /* Sanity check. */
176280bca3d3SAxel Dörfler if (a->non_resident) {
176380bca3d3SAxel Dörfler ntfs_log_error("Attribute $VOLUME_INFORMATION must be resident "
176480bca3d3SAxel Dörfler "but it isn't.\n");
176580bca3d3SAxel Dörfler errno = EIO;
176680bca3d3SAxel Dörfler goto err_out;
176780bca3d3SAxel Dörfler }
176880bca3d3SAxel Dörfler /* Get a pointer to the value of the attribute. */
176980bca3d3SAxel Dörfler c = (VOLUME_INFORMATION*)(le16_to_cpu(a->value_offset) + (char*)a);
177080bca3d3SAxel Dörfler /* Sanity checks. */
177180bca3d3SAxel Dörfler if ((char*)c + le32_to_cpu(a->value_length) > (char*)ctx->mrec +
177280bca3d3SAxel Dörfler le32_to_cpu(ctx->mrec->bytes_in_use) ||
177380bca3d3SAxel Dörfler le16_to_cpu(a->value_offset) +
177480bca3d3SAxel Dörfler le32_to_cpu(a->value_length) > le32_to_cpu(a->length)) {
177580bca3d3SAxel Dörfler ntfs_log_error("Attribute $VOLUME_INFORMATION in $Volume is "
177680bca3d3SAxel Dörfler "corrupt!\n");
177780bca3d3SAxel Dörfler errno = EIO;
177880bca3d3SAxel Dörfler goto err_out;
177980bca3d3SAxel Dörfler }
178080bca3d3SAxel Dörfler /* Set the volume flags. */
178180bca3d3SAxel Dörfler vol->flags = c->flags = flags & VOLUME_FLAGS_MASK;
178280bca3d3SAxel Dörfler /* Write them to disk. */
178380bca3d3SAxel Dörfler ntfs_inode_mark_dirty(vol->vol_ni);
178430bc84e9SGerasim Troeglazov if (ntfs_inode_sync(vol->vol_ni))
178580bca3d3SAxel Dörfler goto err_out;
178630bc84e9SGerasim Troeglazov
178780bca3d3SAxel Dörfler ret = 0; /* success */
178880bca3d3SAxel Dörfler err_out:
178980bca3d3SAxel Dörfler ntfs_attr_put_search_ctx(ctx);
179080bca3d3SAxel Dörfler return ret;
179180bca3d3SAxel Dörfler }
179280bca3d3SAxel Dörfler
ntfs_volume_error(int err)179330bc84e9SGerasim Troeglazov int ntfs_volume_error(int err)
179430bc84e9SGerasim Troeglazov {
179530bc84e9SGerasim Troeglazov int ret;
179630bc84e9SGerasim Troeglazov
179730bc84e9SGerasim Troeglazov switch (err) {
179830bc84e9SGerasim Troeglazov case 0:
179930bc84e9SGerasim Troeglazov ret = NTFS_VOLUME_OK;
180030bc84e9SGerasim Troeglazov break;
180130bc84e9SGerasim Troeglazov case EINVAL:
180230bc84e9SGerasim Troeglazov ret = NTFS_VOLUME_NOT_NTFS;
180330bc84e9SGerasim Troeglazov break;
180430bc84e9SGerasim Troeglazov case EIO:
180530bc84e9SGerasim Troeglazov ret = NTFS_VOLUME_CORRUPT;
180630bc84e9SGerasim Troeglazov break;
180730bc84e9SGerasim Troeglazov case EPERM:
1808da0906f2SGerasim Troeglazov /*
1809da0906f2SGerasim Troeglazov * Hibernation and fast restarting are seen the
1810da0906f2SGerasim Troeglazov * same way on a non Windows-system partition.
1811da0906f2SGerasim Troeglazov */
181230bc84e9SGerasim Troeglazov ret = NTFS_VOLUME_HIBERNATED;
181330bc84e9SGerasim Troeglazov break;
181430bc84e9SGerasim Troeglazov case EOPNOTSUPP:
181530bc84e9SGerasim Troeglazov ret = NTFS_VOLUME_UNCLEAN_UNMOUNT;
181630bc84e9SGerasim Troeglazov break;
181730bc84e9SGerasim Troeglazov case EBUSY:
181830bc84e9SGerasim Troeglazov ret = NTFS_VOLUME_LOCKED;
181930bc84e9SGerasim Troeglazov break;
182030bc84e9SGerasim Troeglazov case ENXIO:
182130bc84e9SGerasim Troeglazov ret = NTFS_VOLUME_RAID;
182230bc84e9SGerasim Troeglazov break;
182330bc84e9SGerasim Troeglazov case EACCES:
182430bc84e9SGerasim Troeglazov ret = NTFS_VOLUME_NO_PRIVILEGE;
182530bc84e9SGerasim Troeglazov break;
182630bc84e9SGerasim Troeglazov default:
182730bc84e9SGerasim Troeglazov ret = NTFS_VOLUME_UNKNOWN_REASON;
182830bc84e9SGerasim Troeglazov break;
182930bc84e9SGerasim Troeglazov }
183030bc84e9SGerasim Troeglazov return ret;
183130bc84e9SGerasim Troeglazov }
183230bc84e9SGerasim Troeglazov
183330bc84e9SGerasim Troeglazov
ntfs_mount_error(const char * volume,const char * mntpoint,int err)183430bc84e9SGerasim Troeglazov void ntfs_mount_error(const char *volume, const char *mntpoint, int err)
183530bc84e9SGerasim Troeglazov {
183630bc84e9SGerasim Troeglazov switch (err) {
183730bc84e9SGerasim Troeglazov case NTFS_VOLUME_NOT_NTFS:
183830bc84e9SGerasim Troeglazov ntfs_log_error(invalid_ntfs_msg, volume);
183930bc84e9SGerasim Troeglazov break;
184030bc84e9SGerasim Troeglazov case NTFS_VOLUME_CORRUPT:
184130bc84e9SGerasim Troeglazov ntfs_log_error("%s", corrupt_volume_msg);
184230bc84e9SGerasim Troeglazov break;
184330bc84e9SGerasim Troeglazov case NTFS_VOLUME_HIBERNATED:
184430bc84e9SGerasim Troeglazov ntfs_log_error(hibernated_volume_msg, volume, mntpoint);
184530bc84e9SGerasim Troeglazov break;
184630bc84e9SGerasim Troeglazov case NTFS_VOLUME_UNCLEAN_UNMOUNT:
184730bc84e9SGerasim Troeglazov ntfs_log_error("%s", unclean_journal_msg);
184830bc84e9SGerasim Troeglazov break;
184930bc84e9SGerasim Troeglazov case NTFS_VOLUME_LOCKED:
185030bc84e9SGerasim Troeglazov ntfs_log_error("%s", opened_volume_msg);
185130bc84e9SGerasim Troeglazov break;
185230bc84e9SGerasim Troeglazov case NTFS_VOLUME_RAID:
185330bc84e9SGerasim Troeglazov ntfs_log_error("%s", fakeraid_msg);
185430bc84e9SGerasim Troeglazov break;
185530bc84e9SGerasim Troeglazov case NTFS_VOLUME_NO_PRIVILEGE:
185630bc84e9SGerasim Troeglazov ntfs_log_error(access_denied_msg, volume);
185730bc84e9SGerasim Troeglazov break;
185830bc84e9SGerasim Troeglazov }
185930bc84e9SGerasim Troeglazov }
186030bc84e9SGerasim Troeglazov
ntfs_set_locale(void)186130bc84e9SGerasim Troeglazov int ntfs_set_locale(void)
186230bc84e9SGerasim Troeglazov {
186330bc84e9SGerasim Troeglazov #ifndef __HAIKU__
186430bc84e9SGerasim Troeglazov const char *locale;
186530bc84e9SGerasim Troeglazov
186630bc84e9SGerasim Troeglazov locale = setlocale(LC_ALL, "");
186730bc84e9SGerasim Troeglazov if (!locale) {
186830bc84e9SGerasim Troeglazov locale = setlocale(LC_ALL, NULL);
186930bc84e9SGerasim Troeglazov ntfs_log_error("Couldn't set local environment, using default "
187030bc84e9SGerasim Troeglazov "'%s'.\n", locale);
187130bc84e9SGerasim Troeglazov return 1;
187230bc84e9SGerasim Troeglazov }
187330bc84e9SGerasim Troeglazov #endif
187430bc84e9SGerasim Troeglazov return 0;
187530bc84e9SGerasim Troeglazov }
187630bc84e9SGerasim Troeglazov
18770d2c294fSGerasim Troeglazov /*
18780d2c294fSGerasim Troeglazov * Feed the counts of free clusters and free mft records
18790d2c294fSGerasim Troeglazov */
18800d2c294fSGerasim Troeglazov
ntfs_volume_get_free_space(ntfs_volume * vol)18810d2c294fSGerasim Troeglazov int ntfs_volume_get_free_space(ntfs_volume *vol)
18820d2c294fSGerasim Troeglazov {
18830d2c294fSGerasim Troeglazov ntfs_attr *na;
18840d2c294fSGerasim Troeglazov int ret;
18850d2c294fSGerasim Troeglazov
18860d2c294fSGerasim Troeglazov ret = -1; /* default return */
18870d2c294fSGerasim Troeglazov vol->free_clusters = ntfs_attr_get_free_bits(vol->lcnbmp_na);
18880d2c294fSGerasim Troeglazov if (vol->free_clusters < 0) {
18890d2c294fSGerasim Troeglazov ntfs_log_perror("Failed to read NTFS $Bitmap");
18900d2c294fSGerasim Troeglazov } else {
18910d2c294fSGerasim Troeglazov na = vol->mftbmp_na;
18920d2c294fSGerasim Troeglazov vol->free_mft_records = ntfs_attr_get_free_bits(na);
18930d2c294fSGerasim Troeglazov
18940d2c294fSGerasim Troeglazov if (vol->free_mft_records >= 0)
18950d2c294fSGerasim Troeglazov vol->free_mft_records += (na->allocated_size - na->data_size) << 3;
18960d2c294fSGerasim Troeglazov
18970d2c294fSGerasim Troeglazov if (vol->free_mft_records < 0)
18980d2c294fSGerasim Troeglazov ntfs_log_perror("Failed to calculate free MFT records");
18999102cad6SAugustin Cavalier else {
19009102cad6SAugustin Cavalier NVolSetFreeSpaceKnown(vol);
19010d2c294fSGerasim Troeglazov ret = 0;
19020d2c294fSGerasim Troeglazov }
19039102cad6SAugustin Cavalier }
19040d2c294fSGerasim Troeglazov return (ret);
19050d2c294fSGerasim Troeglazov }
1906a814d850Sthreedeyes
1907a814d850Sthreedeyes /**
1908a814d850Sthreedeyes * ntfs_volume_rename - change the current label on a volume
1909a814d850Sthreedeyes * @vol: volume to change the label on
1910a814d850Sthreedeyes * @label: the new label
1911a814d850Sthreedeyes * @label_len: the length of @label in ntfschars including the terminating NULL
1912a814d850Sthreedeyes * character, which is mandatory (the value can not exceed 128)
1913a814d850Sthreedeyes *
1914a814d850Sthreedeyes * Change the label on the volume @vol to @label.
1915a814d850Sthreedeyes */
ntfs_volume_rename(ntfs_volume * vol,const ntfschar * label,int label_len)1916da0906f2SGerasim Troeglazov int ntfs_volume_rename(ntfs_volume *vol, const ntfschar *label, int label_len)
1917a814d850Sthreedeyes {
1918a814d850Sthreedeyes ntfs_attr *na;
1919a814d850Sthreedeyes char *old_vol_name;
1920a814d850Sthreedeyes char *new_vol_name = NULL;
1921a814d850Sthreedeyes int new_vol_name_len;
1922a814d850Sthreedeyes int err;
1923a814d850Sthreedeyes
1924a814d850Sthreedeyes if (NVolReadOnly(vol)) {
1925a814d850Sthreedeyes ntfs_log_error("Refusing to change label on read-only mounted "
1926a814d850Sthreedeyes "volume.\n");
1927a814d850Sthreedeyes errno = EROFS;
1928a814d850Sthreedeyes return -1;
1929a814d850Sthreedeyes }
1930a814d850Sthreedeyes
1931a814d850Sthreedeyes label_len *= sizeof(ntfschar);
1932a814d850Sthreedeyes if (label_len > 0x100) {
1933a814d850Sthreedeyes ntfs_log_error("New label is too long. Maximum %u characters "
1934a814d850Sthreedeyes "allowed.\n",
1935a814d850Sthreedeyes (unsigned)(0x100 / sizeof(ntfschar)));
1936a814d850Sthreedeyes errno = ERANGE;
1937a814d850Sthreedeyes return -1;
1938a814d850Sthreedeyes }
1939a814d850Sthreedeyes
1940a814d850Sthreedeyes na = ntfs_attr_open(vol->vol_ni, AT_VOLUME_NAME, AT_UNNAMED, 0);
1941a814d850Sthreedeyes if (!na) {
1942a814d850Sthreedeyes if (errno != ENOENT) {
1943a814d850Sthreedeyes err = errno;
1944a814d850Sthreedeyes ntfs_log_perror("Lookup of $VOLUME_NAME attribute "
1945a814d850Sthreedeyes "failed");
1946a814d850Sthreedeyes goto err_out;
1947a814d850Sthreedeyes }
1948a814d850Sthreedeyes
1949a814d850Sthreedeyes /* The volume name attribute does not exist. Need to add it. */
1950a814d850Sthreedeyes if (ntfs_attr_add(vol->vol_ni, AT_VOLUME_NAME, AT_UNNAMED, 0,
1951da0906f2SGerasim Troeglazov (const u8*) label, label_len))
1952a814d850Sthreedeyes {
1953a814d850Sthreedeyes err = errno;
1954a814d850Sthreedeyes ntfs_log_perror("Encountered error while adding "
1955a814d850Sthreedeyes "$VOLUME_NAME attribute");
1956a814d850Sthreedeyes goto err_out;
1957a814d850Sthreedeyes }
1958a814d850Sthreedeyes }
1959a814d850Sthreedeyes else {
1960a814d850Sthreedeyes s64 written;
1961a814d850Sthreedeyes
1962a814d850Sthreedeyes if (NAttrNonResident(na)) {
1963a814d850Sthreedeyes err = errno;
1964a814d850Sthreedeyes ntfs_log_error("Error: Attribute $VOLUME_NAME must be "
1965a814d850Sthreedeyes "resident.\n");
1966a814d850Sthreedeyes goto err_out;
1967a814d850Sthreedeyes }
1968a814d850Sthreedeyes
1969a814d850Sthreedeyes if (na->data_size != label_len) {
1970a814d850Sthreedeyes if (ntfs_attr_truncate(na, label_len)) {
1971a814d850Sthreedeyes err = errno;
1972a814d850Sthreedeyes ntfs_log_perror("Error resizing resident "
1973a814d850Sthreedeyes "attribute");
1974a814d850Sthreedeyes goto err_out;
1975a814d850Sthreedeyes }
1976a814d850Sthreedeyes }
1977a814d850Sthreedeyes
1978a814d850Sthreedeyes if (label_len) {
1979a814d850Sthreedeyes written = ntfs_attr_pwrite(na, 0, label_len, label);
1980a814d850Sthreedeyes if (written == -1) {
1981a814d850Sthreedeyes err = errno;
1982a814d850Sthreedeyes ntfs_log_perror("Error when writing "
1983a814d850Sthreedeyes "$VOLUME_NAME data");
1984a814d850Sthreedeyes goto err_out;
1985a814d850Sthreedeyes }
1986a814d850Sthreedeyes else if (written != label_len) {
1987a814d850Sthreedeyes err = EIO;
1988a814d850Sthreedeyes ntfs_log_error("Partial write when writing "
1989a814d850Sthreedeyes "$VOLUME_NAME data.");
1990a814d850Sthreedeyes goto err_out;
1991a814d850Sthreedeyes
1992a814d850Sthreedeyes }
1993a814d850Sthreedeyes }
1994a814d850Sthreedeyes }
1995a814d850Sthreedeyes
1996a814d850Sthreedeyes new_vol_name_len =
1997a814d850Sthreedeyes ntfs_ucstombs(label, label_len, &new_vol_name, 0);
1998a814d850Sthreedeyes if (new_vol_name_len == -1) {
1999a814d850Sthreedeyes err = errno;
2000a814d850Sthreedeyes ntfs_log_perror("Error while decoding new volume name");
2001a814d850Sthreedeyes goto err_out;
2002a814d850Sthreedeyes }
2003a814d850Sthreedeyes
2004a814d850Sthreedeyes old_vol_name = vol->vol_name;
2005a814d850Sthreedeyes vol->vol_name = new_vol_name;
2006a814d850Sthreedeyes free(old_vol_name);
2007a814d850Sthreedeyes
2008a814d850Sthreedeyes err = 0;
2009a814d850Sthreedeyes err_out:
2010a814d850Sthreedeyes if (na)
2011a814d850Sthreedeyes ntfs_attr_close(na);
2012a814d850Sthreedeyes if (err)
2013a814d850Sthreedeyes errno = err;
2014a814d850Sthreedeyes return err ? -1 : 0;
2015a814d850Sthreedeyes }
2016