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