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