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