19663SMark.Logan@Sun.COM /**
29663SMark.Logan@Sun.COM * utils.c - Part of the Linux-NTFS project.
39663SMark.Logan@Sun.COM *
49663SMark.Logan@Sun.COM * Copyright (c) 2002-2005 Richard Russon
59663SMark.Logan@Sun.COM * Copyright (c) 2003-2006 Anton Altaparmakov
69663SMark.Logan@Sun.COM * Copyright (c) 2003 Lode Leroy
79663SMark.Logan@Sun.COM * Copyright (c) 2005-2007 Yura Pakhuchiy
89663SMark.Logan@Sun.COM *
99663SMark.Logan@Sun.COM * A set of shared functions for ntfs utilities
109663SMark.Logan@Sun.COM *
119663SMark.Logan@Sun.COM * This program is free software; you can redistribute it and/or modify
129663SMark.Logan@Sun.COM * it under the terms of the GNU General Public License as published by
139663SMark.Logan@Sun.COM * the Free Software Foundation; either version 2 of the License, or
149663SMark.Logan@Sun.COM * (at your option) any later version.
159663SMark.Logan@Sun.COM *
169663SMark.Logan@Sun.COM * This program is distributed in the hope that it will be useful,
179663SMark.Logan@Sun.COM * but WITHOUT ANY WARRANTY; without even the implied warranty of
189663SMark.Logan@Sun.COM * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
199663SMark.Logan@Sun.COM * GNU General Public License for more details.
209663SMark.Logan@Sun.COM *
219663SMark.Logan@Sun.COM * You should have received a copy of the GNU General Public License
229663SMark.Logan@Sun.COM * along with this program (in the main directory of the Linux-NTFS
239663SMark.Logan@Sun.COM * distribution in the file COPYING); if not, write to the Free Software
249663SMark.Logan@Sun.COM * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
259663SMark.Logan@Sun.COM */
269663SMark.Logan@Sun.COM
279663SMark.Logan@Sun.COM #ifdef HAVE_CONFIG_H
289663SMark.Logan@Sun.COM #include "config.h"
299663SMark.Logan@Sun.COM #endif
309663SMark.Logan@Sun.COM
319663SMark.Logan@Sun.COM #ifdef HAVE_STDIO_H
329663SMark.Logan@Sun.COM #include <stdio.h>
339663SMark.Logan@Sun.COM #endif
349663SMark.Logan@Sun.COM #ifdef HAVE_STDARG_H
359663SMark.Logan@Sun.COM #include <stdarg.h>
369663SMark.Logan@Sun.COM #endif
379663SMark.Logan@Sun.COM #ifdef HAVE_ERRNO_H
389663SMark.Logan@Sun.COM #include <errno.h>
399663SMark.Logan@Sun.COM #endif
409663SMark.Logan@Sun.COM #ifdef HAVE_SYS_TYPES_H
419663SMark.Logan@Sun.COM #include <sys/types.h>
429663SMark.Logan@Sun.COM #endif
439663SMark.Logan@Sun.COM #ifdef HAVE_SYS_STAT_H
449663SMark.Logan@Sun.COM #include <sys/stat.h>
459663SMark.Logan@Sun.COM #endif
469663SMark.Logan@Sun.COM #ifdef HAVE_UNISTD_H
479663SMark.Logan@Sun.COM #include <unistd.h>
489663SMark.Logan@Sun.COM #endif
499663SMark.Logan@Sun.COM #ifdef HAVE_STRING_H
509663SMark.Logan@Sun.COM #include <string.h>
519663SMark.Logan@Sun.COM #endif
529663SMark.Logan@Sun.COM #ifdef HAVE_LOCALE_H
539663SMark.Logan@Sun.COM #include <locale.h>
549663SMark.Logan@Sun.COM #endif
559663SMark.Logan@Sun.COM #ifdef HAVE_LIBINTL_H
569663SMark.Logan@Sun.COM #include <libintl.h>
579663SMark.Logan@Sun.COM #endif
589663SMark.Logan@Sun.COM #ifdef HAVE_STDLIB_H
599663SMark.Logan@Sun.COM #include <stdlib.h>
609663SMark.Logan@Sun.COM #endif
619663SMark.Logan@Sun.COM #ifdef HAVE_LIMITS_H
629663SMark.Logan@Sun.COM #include <limits.h>
639663SMark.Logan@Sun.COM #endif
649663SMark.Logan@Sun.COM #ifdef HAVE_CTYPE_H
659663SMark.Logan@Sun.COM #include <ctype.h>
669663SMark.Logan@Sun.COM #endif
679663SMark.Logan@Sun.COM
68*10465SMark.Logan@Sun.COM #include "compat.h"
699663SMark.Logan@Sun.COM #include "utils.h"
709663SMark.Logan@Sun.COM #include "types.h"
719663SMark.Logan@Sun.COM #include "volume.h"
729663SMark.Logan@Sun.COM #include "debug.h"
739663SMark.Logan@Sun.COM #include "dir.h"
749663SMark.Logan@Sun.COM #include "version.h"
759663SMark.Logan@Sun.COM #include "logging.h"
769663SMark.Logan@Sun.COM
779663SMark.Logan@Sun.COM const char *ntfs_bugs = "Developers' email address: "NTFS_DEV_LIST"\n";
789663SMark.Logan@Sun.COM const char *ntfs_home = "Linux NTFS homepage: http://www.linux-ntfs.org\n";
799663SMark.Logan@Sun.COM const char *ntfs_gpl = "This program is free software, released under the GNU "
809663SMark.Logan@Sun.COM "General Public License\nand you are welcome to redistribute it under "
819663SMark.Logan@Sun.COM "certain conditions. It comes with\nABSOLUTELY NO WARRANTY; for "
829663SMark.Logan@Sun.COM "details read the GNU General Public License to be\nfound in the file "
839663SMark.Logan@Sun.COM "\"COPYING\" distributed with this program, or online at:\n"
849663SMark.Logan@Sun.COM "http://www.gnu.org/copyleft/gpl.html\n";
859663SMark.Logan@Sun.COM
869663SMark.Logan@Sun.COM static const char *invalid_ntfs_msg =
879663SMark.Logan@Sun.COM "The device '%s' doesn't have a valid NTFS.\n"
889663SMark.Logan@Sun.COM "Maybe you selected the wrong device? Or the whole disk instead of a\n"
899663SMark.Logan@Sun.COM "partition (e.g. /dev/hda, not /dev/hda1)? Or the other way around?\n";
909663SMark.Logan@Sun.COM
919663SMark.Logan@Sun.COM static const char *corrupt_volume_msg =
929663SMark.Logan@Sun.COM "NTFS is inconsistent. Run chkdsk /f on Windows then reboot it TWICE!\n"
939663SMark.Logan@Sun.COM "The usage of the /f parameter is very IMPORTANT! No modification was\n"
949663SMark.Logan@Sun.COM "made to NTFS by this software.\n";
959663SMark.Logan@Sun.COM
969663SMark.Logan@Sun.COM static const char *hibernated_volume_msg =
979663SMark.Logan@Sun.COM "The NTFS partition is hibernated. Please resume Windows and turned it \n"
989663SMark.Logan@Sun.COM "off properly, so mounting could be done safely.\n";
999663SMark.Logan@Sun.COM
1009663SMark.Logan@Sun.COM static const char *unclean_journal_msg =
1019663SMark.Logan@Sun.COM "Access is denied because the NTFS journal file is unclean. Choices are:\n"
1029663SMark.Logan@Sun.COM " A) Shutdown Windows properly.\n"
1039663SMark.Logan@Sun.COM " B) Click the 'Safely Remove Hardware' icon in the Windows taskbar\n"
1049663SMark.Logan@Sun.COM " notification area before disconnecting the device.\n"
1059663SMark.Logan@Sun.COM " C) Use 'Eject' from Windows Explorer to safely remove the device.\n"
1069663SMark.Logan@Sun.COM " D) If you ran chkdsk previously then boot Windows again which will\n"
1079663SMark.Logan@Sun.COM " automatically initialize the journal.\n"
1089663SMark.Logan@Sun.COM " E) Submit 'force' option (WARNING: This solution it not recommended).\n"
1099663SMark.Logan@Sun.COM " F) ntfsmount: Mount the volume read-only by using the 'ro' mount option.\n";
1109663SMark.Logan@Sun.COM
1119663SMark.Logan@Sun.COM static const char *opened_volume_msg =
1129663SMark.Logan@Sun.COM "Access is denied because the NTFS volume is already exclusively opened.\n"
1139663SMark.Logan@Sun.COM "The volume may be already mounted, or another software may use it which\n"
1149663SMark.Logan@Sun.COM "could be identified for example by the help of the 'fuser' command.\n";
1159663SMark.Logan@Sun.COM
1169663SMark.Logan@Sun.COM static const char *dirty_volume_msg =
1179663SMark.Logan@Sun.COM "Volume is scheduled for check.\n"
1189663SMark.Logan@Sun.COM "Please boot into Windows TWICE, or use the 'force' option.\n"
1199663SMark.Logan@Sun.COM "NOTE: If you had not scheduled check and last time accessed this volume\n"
1209663SMark.Logan@Sun.COM "using ntfsmount and shutdown system properly, then init scripts in your\n"
1219663SMark.Logan@Sun.COM "distribution are broken. Please report to your distribution developers\n"
1229663SMark.Logan@Sun.COM "(NOT to us!) that init scripts kill ntfsmount or mount.ntfs-fuse during\n"
1239663SMark.Logan@Sun.COM "shutdown instead of proper umount.\n";
1249663SMark.Logan@Sun.COM
1259663SMark.Logan@Sun.COM static const char *fakeraid_msg =
1269663SMark.Logan@Sun.COM "You seem to have a SoftRAID/FakeRAID hardware and must use an activated,\n"
1279663SMark.Logan@Sun.COM "different device under /dev/mapper, (e.g. /dev/mapper/nvidia_eahaabcc1)\n"
1289663SMark.Logan@Sun.COM "to mount NTFS. Please see the 'dmraid' documentation for help.\n";
1299663SMark.Logan@Sun.COM
1309663SMark.Logan@Sun.COM /**
1319663SMark.Logan@Sun.COM * utils_set_locale
1329663SMark.Logan@Sun.COM */
utils_set_locale(void)1339663SMark.Logan@Sun.COM int utils_set_locale(void)
1349663SMark.Logan@Sun.COM {
1359663SMark.Logan@Sun.COM const char *locale;
1369663SMark.Logan@Sun.COM
1379663SMark.Logan@Sun.COM locale = setlocale(LC_ALL, "");
1389663SMark.Logan@Sun.COM if (!locale) {
1399663SMark.Logan@Sun.COM locale = setlocale(LC_ALL, NULL);
1409663SMark.Logan@Sun.COM ntfs_log_error("Failed to set locale, using default '%s'.\n",
1419663SMark.Logan@Sun.COM locale);
1429663SMark.Logan@Sun.COM return 1;
1439663SMark.Logan@Sun.COM } else {
1449663SMark.Logan@Sun.COM return 0;
1459663SMark.Logan@Sun.COM }
1469663SMark.Logan@Sun.COM }
1479663SMark.Logan@Sun.COM
1489663SMark.Logan@Sun.COM /**
1499663SMark.Logan@Sun.COM * utils_valid_device - Perform some safety checks on the device, before start
1509663SMark.Logan@Sun.COM * @name: Full pathname of the device/file to work with
1519663SMark.Logan@Sun.COM * @force: Continue regardless of problems
1529663SMark.Logan@Sun.COM *
1539663SMark.Logan@Sun.COM * Check that the name refers to a device and that is isn't already mounted.
1549663SMark.Logan@Sun.COM * These checks can be overridden by using the force option.
1559663SMark.Logan@Sun.COM *
1569663SMark.Logan@Sun.COM * Return: 1 Success, we can continue
1579663SMark.Logan@Sun.COM * 0 Error, we cannot use this device
1589663SMark.Logan@Sun.COM */
utils_valid_device(const char * name,int force)1599663SMark.Logan@Sun.COM int utils_valid_device(const char *name, int force)
1609663SMark.Logan@Sun.COM {
1619663SMark.Logan@Sun.COM unsigned long mnt_flags = 0;
1629663SMark.Logan@Sun.COM struct stat st;
1639663SMark.Logan@Sun.COM
1649663SMark.Logan@Sun.COM #ifdef __CYGWIN32__
1659663SMark.Logan@Sun.COM /* FIXME: This doesn't work for Cygwin, so just return success. */
1669663SMark.Logan@Sun.COM return 1;
1679663SMark.Logan@Sun.COM #endif
1689663SMark.Logan@Sun.COM if (!name) {
1699663SMark.Logan@Sun.COM errno = EINVAL;
1709663SMark.Logan@Sun.COM return 0;
1719663SMark.Logan@Sun.COM }
1729663SMark.Logan@Sun.COM
1739663SMark.Logan@Sun.COM if (stat(name, &st) == -1) {
1749663SMark.Logan@Sun.COM if (errno == ENOENT)
1759663SMark.Logan@Sun.COM ntfs_log_error("The device %s doesn't exist\n", name);
1769663SMark.Logan@Sun.COM else
1779663SMark.Logan@Sun.COM ntfs_log_perror("Error getting information about %s",
1789663SMark.Logan@Sun.COM name);
1799663SMark.Logan@Sun.COM return 0;
1809663SMark.Logan@Sun.COM }
1819663SMark.Logan@Sun.COM
1829663SMark.Logan@Sun.COM /* Make sure the file system is not mounted. */
1839663SMark.Logan@Sun.COM if (ntfs_check_if_mounted(name, &mnt_flags)) {
1849663SMark.Logan@Sun.COM ntfs_log_perror("Failed to determine whether %s is mounted",
1859663SMark.Logan@Sun.COM name);
1869663SMark.Logan@Sun.COM if (!force) {
1879663SMark.Logan@Sun.COM ntfs_log_error("Use the force option to ignore this "
1889663SMark.Logan@Sun.COM "error.\n");
1899663SMark.Logan@Sun.COM return 0;
1909663SMark.Logan@Sun.COM }
1919663SMark.Logan@Sun.COM ntfs_log_warning("Forced to continue.\n");
1929663SMark.Logan@Sun.COM } else if (mnt_flags & NTFS_MF_MOUNTED) {
1939663SMark.Logan@Sun.COM if (!force) {
1949663SMark.Logan@Sun.COM ntfs_log_error("%s", opened_volume_msg);
1959663SMark.Logan@Sun.COM ntfs_log_error("You can use force option to avoid this "
1969663SMark.Logan@Sun.COM "check, but this is not recommended\n"
1979663SMark.Logan@Sun.COM "and may lead to data corruption.\n");
1989663SMark.Logan@Sun.COM return 0;
1999663SMark.Logan@Sun.COM }
2009663SMark.Logan@Sun.COM ntfs_log_warning("Forced to continue.\n");
2019663SMark.Logan@Sun.COM }
2029663SMark.Logan@Sun.COM
2039663SMark.Logan@Sun.COM return 1;
2049663SMark.Logan@Sun.COM }
2059663SMark.Logan@Sun.COM
2069663SMark.Logan@Sun.COM /**
2079663SMark.Logan@Sun.COM * utils_mount_volume - Mount an NTFS volume
2089663SMark.Logan@Sun.COM */
utils_mount_volume(const char * device,ntfs_mount_flags flags)2099663SMark.Logan@Sun.COM ntfs_volume * utils_mount_volume(const char *device, ntfs_mount_flags flags)
2109663SMark.Logan@Sun.COM {
2119663SMark.Logan@Sun.COM ntfs_volume *vol;
2129663SMark.Logan@Sun.COM
2139663SMark.Logan@Sun.COM if (!device) {
2149663SMark.Logan@Sun.COM errno = EINVAL;
2159663SMark.Logan@Sun.COM return NULL;
2169663SMark.Logan@Sun.COM }
2179663SMark.Logan@Sun.COM
2189663SMark.Logan@Sun.COM if (!utils_valid_device(device, flags & NTFS_MNT_FORCE))
2199663SMark.Logan@Sun.COM return NULL;
2209663SMark.Logan@Sun.COM
2219663SMark.Logan@Sun.COM vol = ntfs_mount(device, flags);
2229663SMark.Logan@Sun.COM if (!vol) {
2239663SMark.Logan@Sun.COM ntfs_log_perror("Failed to mount '%s'", device);
2249663SMark.Logan@Sun.COM if (errno == EINVAL)
2259663SMark.Logan@Sun.COM ntfs_log_error(invalid_ntfs_msg, device);
2269663SMark.Logan@Sun.COM else if (errno == EIO)
2279663SMark.Logan@Sun.COM ntfs_log_error("%s", corrupt_volume_msg);
2289663SMark.Logan@Sun.COM else if (errno == EPERM)
2299663SMark.Logan@Sun.COM ntfs_log_error("%s", hibernated_volume_msg);
2309663SMark.Logan@Sun.COM else if (errno == EOPNOTSUPP)
2319663SMark.Logan@Sun.COM ntfs_log_error("%s", unclean_journal_msg);
2329663SMark.Logan@Sun.COM else if (errno == EBUSY)
2339663SMark.Logan@Sun.COM ntfs_log_error("%s", opened_volume_msg);
2349663SMark.Logan@Sun.COM else if (errno == ENXIO)
2359663SMark.Logan@Sun.COM ntfs_log_error("%s", fakeraid_msg);
2369663SMark.Logan@Sun.COM return NULL;
2379663SMark.Logan@Sun.COM }
2389663SMark.Logan@Sun.COM
2399663SMark.Logan@Sun.COM if (NVolWasDirty(vol)) {
2409663SMark.Logan@Sun.COM if (!(flags & NTFS_MNT_FORCE)) {
2419663SMark.Logan@Sun.COM ntfs_log_error("%s", dirty_volume_msg);
2429663SMark.Logan@Sun.COM ntfs_umount(vol, FALSE);
2439663SMark.Logan@Sun.COM return NULL;
2449663SMark.Logan@Sun.COM }
2459663SMark.Logan@Sun.COM ntfs_log_error("WARNING: Dirty volume mount was forced by the "
2469663SMark.Logan@Sun.COM "'force' mount option.\n");
2479663SMark.Logan@Sun.COM }
2489663SMark.Logan@Sun.COM return vol;
2499663SMark.Logan@Sun.COM }
2509663SMark.Logan@Sun.COM
2519663SMark.Logan@Sun.COM /**
2529663SMark.Logan@Sun.COM * utils_parse_size - Convert a string representing a size
2539663SMark.Logan@Sun.COM * @value: String to be parsed
2549663SMark.Logan@Sun.COM * @size: Parsed size
2559663SMark.Logan@Sun.COM * @scale: Whether or not to allow a suffix to scale the value
2569663SMark.Logan@Sun.COM *
2579663SMark.Logan@Sun.COM * Read a string and convert it to a number. Strings may be suffixed to scale
2589663SMark.Logan@Sun.COM * them. Any number without a suffix is assumed to be in bytes.
2599663SMark.Logan@Sun.COM *
2609663SMark.Logan@Sun.COM * Suffix Description Multiple
2619663SMark.Logan@Sun.COM * [tT] Terabytes 10^12
2629663SMark.Logan@Sun.COM * [gG] Gigabytes 10^9
2639663SMark.Logan@Sun.COM * [mM] Megabytes 10^6
2649663SMark.Logan@Sun.COM * [kK] Kilobytes 10^3
2659663SMark.Logan@Sun.COM *
2669663SMark.Logan@Sun.COM * Notes:
2679663SMark.Logan@Sun.COM * Only the first character of the suffix is read.
2689663SMark.Logan@Sun.COM * The multipliers are decimal thousands, not binary: 1000, not 1024.
2699663SMark.Logan@Sun.COM * If parse_size fails, @size will not be changed
2709663SMark.Logan@Sun.COM *
2719663SMark.Logan@Sun.COM * Return: 1 Success
2729663SMark.Logan@Sun.COM * 0 Error, the string was malformed
2739663SMark.Logan@Sun.COM */
utils_parse_size(const char * value,s64 * size,BOOL scale)2749663SMark.Logan@Sun.COM int utils_parse_size(const char *value, s64 *size, BOOL scale)
2759663SMark.Logan@Sun.COM {
2769663SMark.Logan@Sun.COM long long result;
2779663SMark.Logan@Sun.COM char *suffix = NULL;
2789663SMark.Logan@Sun.COM
2799663SMark.Logan@Sun.COM if (!value || !size) {
2809663SMark.Logan@Sun.COM errno = EINVAL;
2819663SMark.Logan@Sun.COM return 0;
2829663SMark.Logan@Sun.COM }
2839663SMark.Logan@Sun.COM
2849663SMark.Logan@Sun.COM ntfs_log_debug("Parsing size '%s'.\n", value);
2859663SMark.Logan@Sun.COM
2869663SMark.Logan@Sun.COM result = strtoll(value, &suffix, 0);
2879663SMark.Logan@Sun.COM if (result < 0 || errno == ERANGE) {
2889663SMark.Logan@Sun.COM ntfs_log_error("Invalid size '%s'.\n", value);
2899663SMark.Logan@Sun.COM return 0;
2909663SMark.Logan@Sun.COM }
2919663SMark.Logan@Sun.COM
2929663SMark.Logan@Sun.COM if (!suffix) {
2939663SMark.Logan@Sun.COM ntfs_log_error("Internal error, strtoll didn't return a suffix.\n");
2949663SMark.Logan@Sun.COM return 0;
2959663SMark.Logan@Sun.COM }
2969663SMark.Logan@Sun.COM
2979663SMark.Logan@Sun.COM if (scale) {
2989663SMark.Logan@Sun.COM switch (suffix[0]) {
2999663SMark.Logan@Sun.COM case 't': case 'T': result *= 1000;
3009663SMark.Logan@Sun.COM case 'g': case 'G': result *= 1000;
3019663SMark.Logan@Sun.COM case 'm': case 'M': result *= 1000;
3029663SMark.Logan@Sun.COM case 'k': case 'K': result *= 1000;
3039663SMark.Logan@Sun.COM case '-': case 0:
3049663SMark.Logan@Sun.COM break;
3059663SMark.Logan@Sun.COM default:
3069663SMark.Logan@Sun.COM ntfs_log_error("Invalid size suffix '%s'. Use T, G, M, or K.\n", suffix);
3079663SMark.Logan@Sun.COM return 0;
3089663SMark.Logan@Sun.COM }
3099663SMark.Logan@Sun.COM } else {
3109663SMark.Logan@Sun.COM if ((suffix[0] != '-') && (suffix[0] != 0)) {
3119663SMark.Logan@Sun.COM ntfs_log_error("Invalid number '%.*s'.\n", (int)(suffix - value + 1), value);
3129663SMark.Logan@Sun.COM return 0;
3139663SMark.Logan@Sun.COM }
3149663SMark.Logan@Sun.COM }
3159663SMark.Logan@Sun.COM
3169663SMark.Logan@Sun.COM ntfs_log_debug("Parsed size = %lld.\n", result);
3179663SMark.Logan@Sun.COM *size = result;
3189663SMark.Logan@Sun.COM return 1;
3199663SMark.Logan@Sun.COM }
3209663SMark.Logan@Sun.COM
3219663SMark.Logan@Sun.COM /**
3229663SMark.Logan@Sun.COM * utils_parse_range - Convert a string representing a range of numbers
3239663SMark.Logan@Sun.COM * @string: The string to be parsed
3249663SMark.Logan@Sun.COM * @start: The beginning of the range will be stored here
3259663SMark.Logan@Sun.COM * @finish: The end of the range will be stored here
3269663SMark.Logan@Sun.COM *
3279663SMark.Logan@Sun.COM * Read a string of the form n-m. If the lower end is missing, zero will be
3289663SMark.Logan@Sun.COM * substituted. If the upper end is missing LONG_MAX will be used. If the
3299663SMark.Logan@Sun.COM * string cannot be parsed correctly, @start and @finish will not be changed.
3309663SMark.Logan@Sun.COM *
3319663SMark.Logan@Sun.COM * Return: 1 Success, a valid string was found
3329663SMark.Logan@Sun.COM * 0 Error, the string was not a valid range
3339663SMark.Logan@Sun.COM */
utils_parse_range(const char * string,s64 * start,s64 * finish,BOOL scale)3349663SMark.Logan@Sun.COM int utils_parse_range(const char *string, s64 *start, s64 *finish, BOOL scale)
3359663SMark.Logan@Sun.COM {
3369663SMark.Logan@Sun.COM s64 a, b;
3379663SMark.Logan@Sun.COM char *middle;
3389663SMark.Logan@Sun.COM
3399663SMark.Logan@Sun.COM if (!string || !start || !finish) {
3409663SMark.Logan@Sun.COM errno = EINVAL;
3419663SMark.Logan@Sun.COM return 0;
3429663SMark.Logan@Sun.COM }
3439663SMark.Logan@Sun.COM
3449663SMark.Logan@Sun.COM middle = strchr(string, '-');
3459663SMark.Logan@Sun.COM if (string == middle) {
3469663SMark.Logan@Sun.COM ntfs_log_debug("Range has no beginning, defaulting to 0.\n");
3479663SMark.Logan@Sun.COM a = 0;
3489663SMark.Logan@Sun.COM } else {
3499663SMark.Logan@Sun.COM if (!utils_parse_size(string, &a, scale))
3509663SMark.Logan@Sun.COM return 0;
3519663SMark.Logan@Sun.COM }
3529663SMark.Logan@Sun.COM
3539663SMark.Logan@Sun.COM if (middle) {
3549663SMark.Logan@Sun.COM if (middle[1] == 0) {
3559663SMark.Logan@Sun.COM b = LONG_MAX; // XXX ULLONG_MAX
3569663SMark.Logan@Sun.COM ntfs_log_debug("Range has no end, defaulting to %lld.\n", b);
3579663SMark.Logan@Sun.COM } else {
3589663SMark.Logan@Sun.COM if (!utils_parse_size(middle+1, &b, scale))
3599663SMark.Logan@Sun.COM return 0;
3609663SMark.Logan@Sun.COM }
3619663SMark.Logan@Sun.COM } else {
3629663SMark.Logan@Sun.COM b = a;
3639663SMark.Logan@Sun.COM }
3649663SMark.Logan@Sun.COM
3659663SMark.Logan@Sun.COM ntfs_log_debug("Range '%s' = %lld - %lld\n", string, a, b);
3669663SMark.Logan@Sun.COM
3679663SMark.Logan@Sun.COM *start = a;
3689663SMark.Logan@Sun.COM *finish = b;
3699663SMark.Logan@Sun.COM return 1;
3709663SMark.Logan@Sun.COM }
3719663SMark.Logan@Sun.COM
3729663SMark.Logan@Sun.COM /**
3739663SMark.Logan@Sun.COM * find_attribute - Find an attribute of the given type
3749663SMark.Logan@Sun.COM * @type: An attribute type, e.g. AT_FILE_NAME
3759663SMark.Logan@Sun.COM * @ctx: A search context, created using ntfs_get_attr_search_ctx
3769663SMark.Logan@Sun.COM *
3779663SMark.Logan@Sun.COM * Using the search context to keep track, find the first/next occurrence of a
3789663SMark.Logan@Sun.COM * given attribute type.
3799663SMark.Logan@Sun.COM *
3809663SMark.Logan@Sun.COM * N.B. This will return a pointer into @mft. As long as the search context
3819663SMark.Logan@Sun.COM * has been created without an inode, it won't overflow the buffer.
3829663SMark.Logan@Sun.COM *
3839663SMark.Logan@Sun.COM * Return: Pointer Success, an attribute was found
3849663SMark.Logan@Sun.COM * NULL Error, no matching attributes were found
3859663SMark.Logan@Sun.COM */
find_attribute(const ATTR_TYPES type,ntfs_attr_search_ctx * ctx)3869663SMark.Logan@Sun.COM ATTR_RECORD * find_attribute(const ATTR_TYPES type, ntfs_attr_search_ctx *ctx)
3879663SMark.Logan@Sun.COM {
3889663SMark.Logan@Sun.COM if (!ctx) {
3899663SMark.Logan@Sun.COM errno = EINVAL;
3909663SMark.Logan@Sun.COM return NULL;
3919663SMark.Logan@Sun.COM }
3929663SMark.Logan@Sun.COM
3939663SMark.Logan@Sun.COM if (ntfs_attr_lookup(type, NULL, 0, 0, 0, NULL, 0, ctx) != 0) {
3949663SMark.Logan@Sun.COM ntfs_log_debug("find_attribute didn't find an attribute of type: 0x%02x.\n", type);
3959663SMark.Logan@Sun.COM return NULL; /* None / no more of that type */
3969663SMark.Logan@Sun.COM }
3979663SMark.Logan@Sun.COM
3989663SMark.Logan@Sun.COM ntfs_log_debug("find_attribute found an attribute of type: 0x%02x.\n", type);
3999663SMark.Logan@Sun.COM return ctx->attr;
4009663SMark.Logan@Sun.COM }
4019663SMark.Logan@Sun.COM
4029663SMark.Logan@Sun.COM /**
4039663SMark.Logan@Sun.COM * find_first_attribute - Find the first attribute of a given type
4049663SMark.Logan@Sun.COM * @type: An attribute type, e.g. AT_FILE_NAME
4059663SMark.Logan@Sun.COM * @mft: A buffer containing a raw MFT record
4069663SMark.Logan@Sun.COM *
4079663SMark.Logan@Sun.COM * Search through a raw MFT record for an attribute of a given type.
4089663SMark.Logan@Sun.COM * The return value is a pointer into the MFT record that was supplied.
4099663SMark.Logan@Sun.COM *
4109663SMark.Logan@Sun.COM * N.B. This will return a pointer into @mft. The pointer won't stray outside
4119663SMark.Logan@Sun.COM * the buffer, since we created the search context without an inode.
4129663SMark.Logan@Sun.COM *
4139663SMark.Logan@Sun.COM * Return: Pointer Success, an attribute was found
4149663SMark.Logan@Sun.COM * NULL Error, no matching attributes were found
4159663SMark.Logan@Sun.COM */
find_first_attribute(const ATTR_TYPES type,MFT_RECORD * mft)4169663SMark.Logan@Sun.COM ATTR_RECORD * find_first_attribute(const ATTR_TYPES type, MFT_RECORD *mft)
4179663SMark.Logan@Sun.COM {
4189663SMark.Logan@Sun.COM ntfs_attr_search_ctx *ctx;
4199663SMark.Logan@Sun.COM ATTR_RECORD *rec;
4209663SMark.Logan@Sun.COM
4219663SMark.Logan@Sun.COM if (!mft) {
4229663SMark.Logan@Sun.COM errno = EINVAL;
4239663SMark.Logan@Sun.COM return NULL;
4249663SMark.Logan@Sun.COM }
4259663SMark.Logan@Sun.COM
4269663SMark.Logan@Sun.COM ctx = ntfs_attr_get_search_ctx(NULL, mft);
4279663SMark.Logan@Sun.COM if (!ctx) {
4289663SMark.Logan@Sun.COM ntfs_log_error("Couldn't create a search context.\n");
4299663SMark.Logan@Sun.COM return NULL;
4309663SMark.Logan@Sun.COM }
4319663SMark.Logan@Sun.COM
4329663SMark.Logan@Sun.COM rec = find_attribute(type, ctx);
4339663SMark.Logan@Sun.COM ntfs_attr_put_search_ctx(ctx);
4349663SMark.Logan@Sun.COM if (rec)
4359663SMark.Logan@Sun.COM ntfs_log_debug("find_first_attribute: found attr of type 0x%02x.\n", type);
4369663SMark.Logan@Sun.COM else
4379663SMark.Logan@Sun.COM ntfs_log_debug("find_first_attribute: didn't find attr of type 0x%02x.\n", type);
4389663SMark.Logan@Sun.COM return rec;
4399663SMark.Logan@Sun.COM }
4409663SMark.Logan@Sun.COM
4419663SMark.Logan@Sun.COM /**
4429663SMark.Logan@Sun.COM * utils_inode_get_name
4439663SMark.Logan@Sun.COM *
4449663SMark.Logan@Sun.COM * using inode
4459663SMark.Logan@Sun.COM * get filename
4469663SMark.Logan@Sun.COM * add name to list
4479663SMark.Logan@Sun.COM * get parent
4489663SMark.Logan@Sun.COM * if parent is 5 (/) stop
4499663SMark.Logan@Sun.COM * get inode of parent
4509663SMark.Logan@Sun.COM */
4519663SMark.Logan@Sun.COM #define max_path 20
utils_inode_get_name(ntfs_inode * inode,char * buffer,int bufsize)4529663SMark.Logan@Sun.COM int utils_inode_get_name(ntfs_inode *inode, char *buffer, int bufsize)
4539663SMark.Logan@Sun.COM {
4549663SMark.Logan@Sun.COM // XXX option: names = posix/win32 or dos
4559663SMark.Logan@Sun.COM // flags: path, filename, or both
4569663SMark.Logan@Sun.COM
4579663SMark.Logan@Sun.COM
4589663SMark.Logan@Sun.COM ntfs_volume *vol;
4599663SMark.Logan@Sun.COM ntfs_attr_search_ctx *ctx;
4609663SMark.Logan@Sun.COM ATTR_RECORD *rec;
4619663SMark.Logan@Sun.COM FILE_NAME_ATTR *attr;
4629663SMark.Logan@Sun.COM int name_space;
4639663SMark.Logan@Sun.COM MFT_REF parent = FILE_root;
4649663SMark.Logan@Sun.COM char *names[max_path + 1];// XXX ntfs_malloc? and make max bigger?
4659663SMark.Logan@Sun.COM int i, len, offset = 0;
4669663SMark.Logan@Sun.COM
4679663SMark.Logan@Sun.COM if (!inode || !buffer) {
4689663SMark.Logan@Sun.COM errno = EINVAL;
4699663SMark.Logan@Sun.COM return 0;
4709663SMark.Logan@Sun.COM }
4719663SMark.Logan@Sun.COM
4729663SMark.Logan@Sun.COM vol = inode->vol;
4739663SMark.Logan@Sun.COM
4749663SMark.Logan@Sun.COM //ntfs_log_debug("sizeof(char*) = %d, sizeof(names) = %d\n", sizeof(char*), sizeof(names));
4759663SMark.Logan@Sun.COM memset(names, 0, sizeof(names));
4769663SMark.Logan@Sun.COM
4779663SMark.Logan@Sun.COM for (i = 0; i < max_path; i++) {
4789663SMark.Logan@Sun.COM
4799663SMark.Logan@Sun.COM ctx = ntfs_attr_get_search_ctx(inode, NULL);
4809663SMark.Logan@Sun.COM if (!ctx) {
4819663SMark.Logan@Sun.COM ntfs_log_error("Couldn't create a search context.\n");
4829663SMark.Logan@Sun.COM return 0;
4839663SMark.Logan@Sun.COM }
4849663SMark.Logan@Sun.COM
4859663SMark.Logan@Sun.COM //ntfs_log_debug("i = %d, inode = %p (%lld)\n", i, inode, inode->mft_no);
4869663SMark.Logan@Sun.COM
4879663SMark.Logan@Sun.COM name_space = 4;
4889663SMark.Logan@Sun.COM while ((rec = find_attribute(AT_FILE_NAME, ctx))) {
4899663SMark.Logan@Sun.COM /* We know this will always be resident. */
4909663SMark.Logan@Sun.COM attr = (FILE_NAME_ATTR *) ((char *) rec + le16_to_cpu(rec->u.res.value_offset));
4919663SMark.Logan@Sun.COM
4929663SMark.Logan@Sun.COM if (attr->file_name_type > name_space) { //XXX find the ...
4939663SMark.Logan@Sun.COM continue;
4949663SMark.Logan@Sun.COM }
4959663SMark.Logan@Sun.COM
4969663SMark.Logan@Sun.COM name_space = attr->file_name_type;
4979663SMark.Logan@Sun.COM parent = le64_to_cpu(attr->parent_directory);
4989663SMark.Logan@Sun.COM
4999663SMark.Logan@Sun.COM if (names[i]) {
5009663SMark.Logan@Sun.COM free(names[i]);
5019663SMark.Logan@Sun.COM names[i] = NULL;
5029663SMark.Logan@Sun.COM }
5039663SMark.Logan@Sun.COM
5049663SMark.Logan@Sun.COM if (ntfs_ucstombs(attr->file_name, attr->file_name_length,
5059663SMark.Logan@Sun.COM &names[i], 0) < 0) {
5069663SMark.Logan@Sun.COM char *temp;
5079663SMark.Logan@Sun.COM ntfs_log_error("Couldn't translate filename to current locale.\n");
5089663SMark.Logan@Sun.COM temp = ntfs_malloc(30);
5099663SMark.Logan@Sun.COM if (!temp)
5109663SMark.Logan@Sun.COM return 0;
5119663SMark.Logan@Sun.COM snprintf(temp, 30, "<MFT%llu>", (unsigned
5129663SMark.Logan@Sun.COM long long)inode->mft_no);
5139663SMark.Logan@Sun.COM names[i] = temp;
5149663SMark.Logan@Sun.COM }
5159663SMark.Logan@Sun.COM
5169663SMark.Logan@Sun.COM //ntfs_log_debug("names[%d] %s\n", i, names[i]);
5179663SMark.Logan@Sun.COM //ntfs_log_debug("parent = %lld\n", MREF(parent));
5189663SMark.Logan@Sun.COM }
5199663SMark.Logan@Sun.COM
5209663SMark.Logan@Sun.COM ntfs_attr_put_search_ctx(ctx);
5219663SMark.Logan@Sun.COM
5229663SMark.Logan@Sun.COM if (i > 0) /* Don't close the original inode */
5239663SMark.Logan@Sun.COM ntfs_inode_close(inode);
5249663SMark.Logan@Sun.COM
5259663SMark.Logan@Sun.COM if (MREF(parent) == FILE_root) { /* The root directory, stop. */
5269663SMark.Logan@Sun.COM //ntfs_log_debug("inode 5\n");
5279663SMark.Logan@Sun.COM break;
5289663SMark.Logan@Sun.COM }
5299663SMark.Logan@Sun.COM
5309663SMark.Logan@Sun.COM inode = ntfs_inode_open(vol, parent);
5319663SMark.Logan@Sun.COM if (!inode) {
5329663SMark.Logan@Sun.COM ntfs_log_error("Couldn't open inode %llu.\n",
5339663SMark.Logan@Sun.COM (unsigned long long)MREF(parent));
5349663SMark.Logan@Sun.COM break;
5359663SMark.Logan@Sun.COM }
5369663SMark.Logan@Sun.COM }
5379663SMark.Logan@Sun.COM
5389663SMark.Logan@Sun.COM if (i >= max_path) {
5399663SMark.Logan@Sun.COM /* If we get into an infinite loop, we'll end up here. */
5409663SMark.Logan@Sun.COM ntfs_log_error("The directory structure is too deep (over %d) nested directories.\n", max_path);
5419663SMark.Logan@Sun.COM return 0;
5429663SMark.Logan@Sun.COM }
5439663SMark.Logan@Sun.COM
5449663SMark.Logan@Sun.COM /* Assemble the names in the correct order. */
5459663SMark.Logan@Sun.COM for (i = max_path; i >= 0; i--) {
5469663SMark.Logan@Sun.COM if (!names[i])
5479663SMark.Logan@Sun.COM continue;
5489663SMark.Logan@Sun.COM
5499663SMark.Logan@Sun.COM len = snprintf(buffer + offset, bufsize - offset, "%c%s", PATH_SEP, names[i]);
5509663SMark.Logan@Sun.COM if (len >= (bufsize - offset)) {
5519663SMark.Logan@Sun.COM ntfs_log_error("Pathname was truncated.\n");
5529663SMark.Logan@Sun.COM break;
5539663SMark.Logan@Sun.COM }
5549663SMark.Logan@Sun.COM
5559663SMark.Logan@Sun.COM offset += len;
5569663SMark.Logan@Sun.COM }
5579663SMark.Logan@Sun.COM
5589663SMark.Logan@Sun.COM /* Free all the allocated memory */
5599663SMark.Logan@Sun.COM for (i = 0; i < max_path; i++)
5609663SMark.Logan@Sun.COM free(names[i]);
5619663SMark.Logan@Sun.COM
5629663SMark.Logan@Sun.COM ntfs_log_debug("Pathname: %s\n", buffer);
5639663SMark.Logan@Sun.COM
5649663SMark.Logan@Sun.COM return 1;
5659663SMark.Logan@Sun.COM }
5669663SMark.Logan@Sun.COM #undef max_path
5679663SMark.Logan@Sun.COM
5689663SMark.Logan@Sun.COM /**
5699663SMark.Logan@Sun.COM * utils_attr_get_name
5709663SMark.Logan@Sun.COM */
utils_attr_get_name(ntfs_volume * vol,ATTR_RECORD * attr,char * buffer,int bufsize)5719663SMark.Logan@Sun.COM int utils_attr_get_name(ntfs_volume *vol, ATTR_RECORD *attr, char *buffer, int bufsize)
5729663SMark.Logan@Sun.COM {
5739663SMark.Logan@Sun.COM int len, namelen;
5749663SMark.Logan@Sun.COM char *name;
5759663SMark.Logan@Sun.COM ATTR_DEF *attrdef;
5769663SMark.Logan@Sun.COM
5779663SMark.Logan@Sun.COM // flags: attr, name, or both
5789663SMark.Logan@Sun.COM if (!attr || !buffer) {
5799663SMark.Logan@Sun.COM errno = EINVAL;
5809663SMark.Logan@Sun.COM return 0;
5819663SMark.Logan@Sun.COM }
5829663SMark.Logan@Sun.COM
5839663SMark.Logan@Sun.COM attrdef = ntfs_attr_find_in_attrdef(vol, attr->type);
5849663SMark.Logan@Sun.COM if (attrdef) {
5859663SMark.Logan@Sun.COM name = NULL;
5869663SMark.Logan@Sun.COM namelen = ntfs_ucsnlen(attrdef->name, sizeof(attrdef->name));
5879663SMark.Logan@Sun.COM if (ntfs_ucstombs(attrdef->name, namelen, &name, 0) < 0) {
5889663SMark.Logan@Sun.COM ntfs_log_error("Couldn't translate attribute type to "
5899663SMark.Logan@Sun.COM "current locale.\n");
5909663SMark.Logan@Sun.COM // <UNKNOWN>?
5919663SMark.Logan@Sun.COM return 0;
5929663SMark.Logan@Sun.COM }
5939663SMark.Logan@Sun.COM len = snprintf(buffer, bufsize, "%s", name);
5949663SMark.Logan@Sun.COM } else {
5959663SMark.Logan@Sun.COM ntfs_log_error("Unknown attribute type 0x%02x\n", attr->type);
5969663SMark.Logan@Sun.COM len = snprintf(buffer, bufsize, "<UNKNOWN>");
5979663SMark.Logan@Sun.COM }
5989663SMark.Logan@Sun.COM
5999663SMark.Logan@Sun.COM if (len >= bufsize) {
6009663SMark.Logan@Sun.COM ntfs_log_error("Attribute type was truncated.\n");
6019663SMark.Logan@Sun.COM return 0;
6029663SMark.Logan@Sun.COM }
6039663SMark.Logan@Sun.COM
6049663SMark.Logan@Sun.COM if (!attr->name_length) {
6059663SMark.Logan@Sun.COM return 0;
6069663SMark.Logan@Sun.COM }
6079663SMark.Logan@Sun.COM
6089663SMark.Logan@Sun.COM buffer += len;
6099663SMark.Logan@Sun.COM bufsize -= len;
6109663SMark.Logan@Sun.COM
6119663SMark.Logan@Sun.COM name = NULL;
6129663SMark.Logan@Sun.COM namelen = attr->name_length;
6139663SMark.Logan@Sun.COM if (ntfs_ucstombs((ntfschar *)((char *)attr + le16_to_cpu(
6149663SMark.Logan@Sun.COM attr->name_offset)), namelen, &name, 0) < 0) {
6159663SMark.Logan@Sun.COM ntfs_log_error("Couldn't translate attribute name to current "
6169663SMark.Logan@Sun.COM "locale.\n");
6179663SMark.Logan@Sun.COM // <UNKNOWN>?
6189663SMark.Logan@Sun.COM len = snprintf(buffer, bufsize, "<UNKNOWN>");
6199663SMark.Logan@Sun.COM return 0;
6209663SMark.Logan@Sun.COM }
6219663SMark.Logan@Sun.COM
6229663SMark.Logan@Sun.COM len = snprintf(buffer, bufsize, "(%s)", name);
6239663SMark.Logan@Sun.COM free(name);
6249663SMark.Logan@Sun.COM
6259663SMark.Logan@Sun.COM if (len >= bufsize) {
6269663SMark.Logan@Sun.COM ntfs_log_error("Attribute name was truncated.\n");
6279663SMark.Logan@Sun.COM return 0;
6289663SMark.Logan@Sun.COM }
6299663SMark.Logan@Sun.COM
6309663SMark.Logan@Sun.COM return 0;
6319663SMark.Logan@Sun.COM }
6329663SMark.Logan@Sun.COM
6339663SMark.Logan@Sun.COM /**
6349663SMark.Logan@Sun.COM * utils_cluster_in_use - Determine if a cluster is in use
6359663SMark.Logan@Sun.COM * @vol: An ntfs volume obtained from ntfs_mount
6369663SMark.Logan@Sun.COM * @lcn: The Logical Cluster Number to test
6379663SMark.Logan@Sun.COM *
6389663SMark.Logan@Sun.COM * The metadata file $Bitmap has one binary bit representing each cluster on
6399663SMark.Logan@Sun.COM * disk. The bit will be set for each cluster that is in use. The function
6409663SMark.Logan@Sun.COM * reads the relevant part of $Bitmap into a buffer and tests the bit.
6419663SMark.Logan@Sun.COM *
6429663SMark.Logan@Sun.COM * This function has a static buffer in which it caches a section of $Bitmap.
6439663SMark.Logan@Sun.COM * If the lcn, being tested, lies outside the range, the buffer will be
6449663SMark.Logan@Sun.COM * refreshed. @bmplcn stores offset to the first bit (in bits) stored in the
6459663SMark.Logan@Sun.COM * buffer.
6469663SMark.Logan@Sun.COM *
6479663SMark.Logan@Sun.COM * NOTE: Be very carefull with shifts by 3 everywhere in this function.
6489663SMark.Logan@Sun.COM *
6499663SMark.Logan@Sun.COM * Return: 1 Cluster is in use
6509663SMark.Logan@Sun.COM * 0 Cluster is free space
6519663SMark.Logan@Sun.COM * -1 Error occurred
6529663SMark.Logan@Sun.COM */
utils_cluster_in_use(ntfs_volume * vol,long long lcn)6539663SMark.Logan@Sun.COM int utils_cluster_in_use(ntfs_volume *vol, long long lcn)
6549663SMark.Logan@Sun.COM {
6559663SMark.Logan@Sun.COM static unsigned char buffer[512];
6569663SMark.Logan@Sun.COM static long long bmplcn = -(sizeof(buffer) << 3);
6579663SMark.Logan@Sun.COM int byte, bit;
6589663SMark.Logan@Sun.COM ntfs_attr *attr;
6599663SMark.Logan@Sun.COM
6609663SMark.Logan@Sun.COM if (!vol) {
6619663SMark.Logan@Sun.COM errno = EINVAL;
6629663SMark.Logan@Sun.COM return -1;
6639663SMark.Logan@Sun.COM }
6649663SMark.Logan@Sun.COM
6659663SMark.Logan@Sun.COM /* Does lcn lie in the section of $Bitmap we already have cached? */
6669663SMark.Logan@Sun.COM if ((lcn < bmplcn) || (lcn >= (bmplcn + (sizeof(buffer) << 3)))) {
6679663SMark.Logan@Sun.COM ntfs_log_debug("Bit lies outside cache.\n");
6689663SMark.Logan@Sun.COM attr = ntfs_attr_open(vol->lcnbmp_ni, AT_DATA, AT_UNNAMED, 0);
6699663SMark.Logan@Sun.COM if (!attr) {
6709663SMark.Logan@Sun.COM ntfs_log_perror("Couldn't open $Bitmap");
6719663SMark.Logan@Sun.COM return -1;
6729663SMark.Logan@Sun.COM }
6739663SMark.Logan@Sun.COM
6749663SMark.Logan@Sun.COM /* Mark the buffer as in use, in case the read is shorter. */
6759663SMark.Logan@Sun.COM memset(buffer, 0xFF, sizeof(buffer));
6769663SMark.Logan@Sun.COM bmplcn = lcn & (~((sizeof(buffer) << 3) - 1));
6779663SMark.Logan@Sun.COM
6789663SMark.Logan@Sun.COM if (ntfs_attr_pread(attr, (bmplcn >> 3), sizeof(buffer),
6799663SMark.Logan@Sun.COM buffer) < 0) {
6809663SMark.Logan@Sun.COM ntfs_log_perror("Couldn't read $Bitmap");
6819663SMark.Logan@Sun.COM ntfs_attr_close(attr);
6829663SMark.Logan@Sun.COM return -1;
6839663SMark.Logan@Sun.COM }
6849663SMark.Logan@Sun.COM
6859663SMark.Logan@Sun.COM ntfs_log_debug("Reloaded bitmap buffer.\n");
6869663SMark.Logan@Sun.COM ntfs_attr_close(attr);
6879663SMark.Logan@Sun.COM }
6889663SMark.Logan@Sun.COM
6899663SMark.Logan@Sun.COM bit = 1 << (lcn & 7);
6909663SMark.Logan@Sun.COM byte = (lcn >> 3) & (sizeof(buffer) - 1);
6919663SMark.Logan@Sun.COM ntfs_log_debug("cluster = %lld, bmplcn = %lld, byte = %d, bit = %d, "
6929663SMark.Logan@Sun.COM "in use %d\n", lcn, bmplcn, byte, bit, buffer[byte] &
6939663SMark.Logan@Sun.COM bit);
6949663SMark.Logan@Sun.COM
6959663SMark.Logan@Sun.COM return (buffer[byte] & bit);
6969663SMark.Logan@Sun.COM }
6979663SMark.Logan@Sun.COM
6989663SMark.Logan@Sun.COM /**
6999663SMark.Logan@Sun.COM * utils_mftrec_in_use - Determine if a MFT Record is in use
7009663SMark.Logan@Sun.COM * @vol: An ntfs volume obtained from ntfs_mount
7019663SMark.Logan@Sun.COM * @mref: MFT Reference (inode number)
7029663SMark.Logan@Sun.COM *
7039663SMark.Logan@Sun.COM * The metadata file $BITMAP has one binary bit representing each record in the
7049663SMark.Logan@Sun.COM * MFT. The bit will be set for each record that is in use. The function
7059663SMark.Logan@Sun.COM * reads the relevant part of $BITMAP into a buffer and tests the bit.
7069663SMark.Logan@Sun.COM *
7079663SMark.Logan@Sun.COM * This function has a static buffer in which it caches a section of $BITMAP.
7089663SMark.Logan@Sun.COM * If the mref, being tested, lies outside the range, the buffer will be
7099663SMark.Logan@Sun.COM * refreshed.
7109663SMark.Logan@Sun.COM *
7119663SMark.Logan@Sun.COM * Return: 1 MFT Record is in use
7129663SMark.Logan@Sun.COM * 0 MFT Record is unused
7139663SMark.Logan@Sun.COM * -1 Error occurred
7149663SMark.Logan@Sun.COM */
utils_mftrec_in_use(ntfs_volume * vol,MFT_REF mref)7159663SMark.Logan@Sun.COM int utils_mftrec_in_use(ntfs_volume *vol, MFT_REF mref)
7169663SMark.Logan@Sun.COM {
7179663SMark.Logan@Sun.COM static u8 buffer[512];
7189663SMark.Logan@Sun.COM static s64 bmpmref = -sizeof(buffer) - 1; /* Which bit of $BITMAP is in the buffer */
7199663SMark.Logan@Sun.COM int byte, bit;
7209663SMark.Logan@Sun.COM
7219663SMark.Logan@Sun.COM ntfs_log_trace("Entering.\n");
7229663SMark.Logan@Sun.COM
7239663SMark.Logan@Sun.COM if (!vol) {
7249663SMark.Logan@Sun.COM errno = EINVAL;
7259663SMark.Logan@Sun.COM return -1;
7269663SMark.Logan@Sun.COM }
7279663SMark.Logan@Sun.COM
7289663SMark.Logan@Sun.COM /* Does mref lie in the section of $Bitmap we already have cached? */
7299663SMark.Logan@Sun.COM if (((s64)MREF(mref) < bmpmref) || ((s64)MREF(mref) >= (bmpmref +
7309663SMark.Logan@Sun.COM (sizeof(buffer) << 3)))) {
7319663SMark.Logan@Sun.COM ntfs_log_debug("Bit lies outside cache.\n");
7329663SMark.Logan@Sun.COM
7339663SMark.Logan@Sun.COM /* Mark the buffer as not in use, in case the read is shorter. */
7349663SMark.Logan@Sun.COM memset(buffer, 0, sizeof(buffer));
7359663SMark.Logan@Sun.COM bmpmref = mref & (~((sizeof(buffer) << 3) - 1));
7369663SMark.Logan@Sun.COM
7379663SMark.Logan@Sun.COM if (ntfs_attr_pread(vol->mftbmp_na, (bmpmref>>3), sizeof(buffer), buffer) < 0) {
7389663SMark.Logan@Sun.COM ntfs_log_perror("Couldn't read $MFT/$BITMAP");
7399663SMark.Logan@Sun.COM return -1;
7409663SMark.Logan@Sun.COM }
7419663SMark.Logan@Sun.COM
7429663SMark.Logan@Sun.COM ntfs_log_debug("Reloaded bitmap buffer.\n");
7439663SMark.Logan@Sun.COM }
7449663SMark.Logan@Sun.COM
7459663SMark.Logan@Sun.COM bit = 1 << (mref & 7);
7469663SMark.Logan@Sun.COM byte = (mref >> 3) & (sizeof(buffer) - 1);
7479663SMark.Logan@Sun.COM ntfs_log_debug("cluster = %lld, bmpmref = %lld, byte = %d, bit = %d, in use %d\n", mref, bmpmref, byte, bit, buffer[byte] & bit);
7489663SMark.Logan@Sun.COM
7499663SMark.Logan@Sun.COM return (buffer[byte] & bit);
7509663SMark.Logan@Sun.COM }
7519663SMark.Logan@Sun.COM
7529663SMark.Logan@Sun.COM /**
7539663SMark.Logan@Sun.COM * __metadata
7549663SMark.Logan@Sun.COM */
__metadata(ntfs_volume * vol,u64 num)7559663SMark.Logan@Sun.COM static int __metadata(ntfs_volume *vol, u64 num)
7569663SMark.Logan@Sun.COM {
7579663SMark.Logan@Sun.COM if (num <= FILE_UpCase)
7589663SMark.Logan@Sun.COM return 1;
7599663SMark.Logan@Sun.COM if (!vol)
7609663SMark.Logan@Sun.COM return -1;
7619663SMark.Logan@Sun.COM if ((vol->major_ver == 3) && (num == FILE_Extend))
7629663SMark.Logan@Sun.COM return 1;
7639663SMark.Logan@Sun.COM
7649663SMark.Logan@Sun.COM return 0;
7659663SMark.Logan@Sun.COM }
7669663SMark.Logan@Sun.COM
7679663SMark.Logan@Sun.COM /**
7689663SMark.Logan@Sun.COM * utils_is_metadata - Determine if an inode represents a metadata file
7699663SMark.Logan@Sun.COM * @inode: An ntfs inode to be tested
7709663SMark.Logan@Sun.COM *
7719663SMark.Logan@Sun.COM * A handful of files in the volume contain filesystem data - metadata.
7729663SMark.Logan@Sun.COM * They can be identified by their inode number (offset in MFT/$DATA) or by
7739663SMark.Logan@Sun.COM * their parent.
7749663SMark.Logan@Sun.COM *
7759663SMark.Logan@Sun.COM * Return: 1 inode is a metadata file
7769663SMark.Logan@Sun.COM * 0 inode is not a metadata file
7779663SMark.Logan@Sun.COM * -1 Error occurred
7789663SMark.Logan@Sun.COM */
utils_is_metadata(ntfs_inode * inode)7799663SMark.Logan@Sun.COM int utils_is_metadata(ntfs_inode *inode)
7809663SMark.Logan@Sun.COM {
7819663SMark.Logan@Sun.COM ntfs_volume *vol;
7829663SMark.Logan@Sun.COM ATTR_RECORD *rec;
7839663SMark.Logan@Sun.COM FILE_NAME_ATTR *attr;
7849663SMark.Logan@Sun.COM MFT_RECORD *file;
7859663SMark.Logan@Sun.COM u64 num;
7869663SMark.Logan@Sun.COM
7879663SMark.Logan@Sun.COM if (!inode) {
7889663SMark.Logan@Sun.COM errno = EINVAL;
7899663SMark.Logan@Sun.COM return -1;
7909663SMark.Logan@Sun.COM }
7919663SMark.Logan@Sun.COM
7929663SMark.Logan@Sun.COM vol = inode->vol;
7939663SMark.Logan@Sun.COM if (!vol)
7949663SMark.Logan@Sun.COM return -1;
7959663SMark.Logan@Sun.COM
7969663SMark.Logan@Sun.COM num = inode->mft_no;
7979663SMark.Logan@Sun.COM if (__metadata(vol, num) == 1)
7989663SMark.Logan@Sun.COM return 1;
7999663SMark.Logan@Sun.COM
8009663SMark.Logan@Sun.COM file = inode->mrec;
8019663SMark.Logan@Sun.COM if (file && (file->base_mft_record != 0)) {
8029663SMark.Logan@Sun.COM num = MREF_LE(file->base_mft_record);
8039663SMark.Logan@Sun.COM if (__metadata(vol, num) == 1)
8049663SMark.Logan@Sun.COM return 1;
8059663SMark.Logan@Sun.COM }
8069663SMark.Logan@Sun.COM file = inode->mrec;
8079663SMark.Logan@Sun.COM
8089663SMark.Logan@Sun.COM rec = find_first_attribute(AT_FILE_NAME, inode->mrec);
8099663SMark.Logan@Sun.COM if (!rec)
8109663SMark.Logan@Sun.COM return -1;
8119663SMark.Logan@Sun.COM
8129663SMark.Logan@Sun.COM /* We know this will always be resident. */
8139663SMark.Logan@Sun.COM attr = (FILE_NAME_ATTR *)((char *)rec + le16_to_cpu(rec->u.res.value_offset));
8149663SMark.Logan@Sun.COM
8159663SMark.Logan@Sun.COM num = MREF_LE(attr->parent_directory);
8169663SMark.Logan@Sun.COM if ((num != FILE_root) && (__metadata(vol, num) == 1))
8179663SMark.Logan@Sun.COM return 1;
8189663SMark.Logan@Sun.COM
8199663SMark.Logan@Sun.COM return 0;
8209663SMark.Logan@Sun.COM }
8219663SMark.Logan@Sun.COM
8229663SMark.Logan@Sun.COM /**
8239663SMark.Logan@Sun.COM * utils_dump_mem - Display a block of memory in hex and ascii
8249663SMark.Logan@Sun.COM * @buf: Buffer to be displayed
8259663SMark.Logan@Sun.COM * @start: Offset into @buf to start from
8269663SMark.Logan@Sun.COM * @length: Number of bytes to display
8279663SMark.Logan@Sun.COM * @flags: Options to change the style of the output
8289663SMark.Logan@Sun.COM *
8299663SMark.Logan@Sun.COM * Display a block of memory in a tradition hex-dump manner.
8309663SMark.Logan@Sun.COM * Optionally the ascii part can be turned off.
8319663SMark.Logan@Sun.COM *
8329663SMark.Logan@Sun.COM * The flags, described fully in utils.h, default to 0 (DM_DEFAULTS).
8339663SMark.Logan@Sun.COM * Examples are: DM_INDENT (indent the output by one tab); DM_RED (colour the
8349663SMark.Logan@Sun.COM * output); DM_NO_ASCII (only print the hex values).
8359663SMark.Logan@Sun.COM */
utils_dump_mem(void * buf,int start,int length,int flags)8369663SMark.Logan@Sun.COM void utils_dump_mem(void *buf, int start, int length, int flags)
8379663SMark.Logan@Sun.COM {
8389663SMark.Logan@Sun.COM int off, i, s, e, col;
8399663SMark.Logan@Sun.COM u8 *mem = buf;
8409663SMark.Logan@Sun.COM
8419663SMark.Logan@Sun.COM s = start & ~15; // round down
8429663SMark.Logan@Sun.COM e = (start + length + 15) & ~15; // round up
8439663SMark.Logan@Sun.COM
8449663SMark.Logan@Sun.COM for (off = s; off < e; off += 16) {
8459663SMark.Logan@Sun.COM col = 30;
8469663SMark.Logan@Sun.COM if (flags & DM_RED)
8479663SMark.Logan@Sun.COM col += 1;
8489663SMark.Logan@Sun.COM if (flags & DM_GREEN)
8499663SMark.Logan@Sun.COM col += 2;
8509663SMark.Logan@Sun.COM if (flags & DM_BLUE)
8519663SMark.Logan@Sun.COM col += 4;
8529663SMark.Logan@Sun.COM if (flags & DM_INDENT)
8539663SMark.Logan@Sun.COM ntfs_log_debug("\t");
8549663SMark.Logan@Sun.COM if (flags & DM_BOLD)
8559663SMark.Logan@Sun.COM ntfs_log_debug("\e[01m");
8569663SMark.Logan@Sun.COM if (flags & (DM_RED | DM_BLUE | DM_GREEN | DM_BOLD))
8579663SMark.Logan@Sun.COM ntfs_log_debug("\e[%dm", col);
8589663SMark.Logan@Sun.COM if (off == s)
8599663SMark.Logan@Sun.COM ntfs_log_debug("%6.6x ", start);
8609663SMark.Logan@Sun.COM else
8619663SMark.Logan@Sun.COM ntfs_log_debug("%6.6x ", off);
8629663SMark.Logan@Sun.COM
8639663SMark.Logan@Sun.COM for (i = 0; i < 16; i++) {
8649663SMark.Logan@Sun.COM if ((i == 8) && (!(flags & DM_NO_DIVIDER)))
8659663SMark.Logan@Sun.COM ntfs_log_debug(" -");
8669663SMark.Logan@Sun.COM if (((off+i) >= start) && ((off+i) < (start+length)))
8679663SMark.Logan@Sun.COM ntfs_log_debug(" %02X", mem[off+i]);
8689663SMark.Logan@Sun.COM else
8699663SMark.Logan@Sun.COM ntfs_log_debug(" ");
8709663SMark.Logan@Sun.COM }
8719663SMark.Logan@Sun.COM if (!(flags & DM_NO_ASCII)) {
8729663SMark.Logan@Sun.COM ntfs_log_debug(" ");
8739663SMark.Logan@Sun.COM for (i = 0; i < 16; i++) {
8749663SMark.Logan@Sun.COM if (((off+i) < start) || ((off+i) >= (start+length)))
8759663SMark.Logan@Sun.COM ntfs_log_debug(" ");
8769663SMark.Logan@Sun.COM else if (isprint(mem[off + i]))
8779663SMark.Logan@Sun.COM ntfs_log_debug("%c", mem[off + i]);
8789663SMark.Logan@Sun.COM else
8799663SMark.Logan@Sun.COM ntfs_log_debug(".");
8809663SMark.Logan@Sun.COM }
8819663SMark.Logan@Sun.COM }
8829663SMark.Logan@Sun.COM if (flags & (DM_RED | DM_BLUE | DM_GREEN | DM_BOLD))
8839663SMark.Logan@Sun.COM ntfs_log_debug("\e[0m");
8849663SMark.Logan@Sun.COM ntfs_log_debug("\n");
8859663SMark.Logan@Sun.COM }
8869663SMark.Logan@Sun.COM }
8879663SMark.Logan@Sun.COM
8889663SMark.Logan@Sun.COM
8899663SMark.Logan@Sun.COM /**
8909663SMark.Logan@Sun.COM * mft_get_search_ctx
8919663SMark.Logan@Sun.COM */
mft_get_search_ctx(ntfs_volume * vol)8929663SMark.Logan@Sun.COM struct mft_search_ctx * mft_get_search_ctx(ntfs_volume *vol)
8939663SMark.Logan@Sun.COM {
8949663SMark.Logan@Sun.COM struct mft_search_ctx *ctx;
8959663SMark.Logan@Sun.COM
8969663SMark.Logan@Sun.COM if (!vol) {
8979663SMark.Logan@Sun.COM errno = EINVAL;
8989663SMark.Logan@Sun.COM return NULL;
8999663SMark.Logan@Sun.COM }
9009663SMark.Logan@Sun.COM
9019663SMark.Logan@Sun.COM ctx = calloc(1, sizeof *ctx);
9029663SMark.Logan@Sun.COM
9039663SMark.Logan@Sun.COM ctx->mft_num = -1;
9049663SMark.Logan@Sun.COM ctx->vol = vol;
9059663SMark.Logan@Sun.COM
9069663SMark.Logan@Sun.COM return ctx;
9079663SMark.Logan@Sun.COM }
9089663SMark.Logan@Sun.COM
9099663SMark.Logan@Sun.COM /**
9109663SMark.Logan@Sun.COM * mft_put_search_ctx
9119663SMark.Logan@Sun.COM */
mft_put_search_ctx(struct mft_search_ctx * ctx)9129663SMark.Logan@Sun.COM void mft_put_search_ctx(struct mft_search_ctx *ctx)
9139663SMark.Logan@Sun.COM {
9149663SMark.Logan@Sun.COM if (!ctx)
9159663SMark.Logan@Sun.COM return;
9169663SMark.Logan@Sun.COM if (ctx->inode)
9179663SMark.Logan@Sun.COM ntfs_inode_close(ctx->inode);
9189663SMark.Logan@Sun.COM free(ctx);
9199663SMark.Logan@Sun.COM }
9209663SMark.Logan@Sun.COM
9219663SMark.Logan@Sun.COM /**
9229663SMark.Logan@Sun.COM * mft_next_record
9239663SMark.Logan@Sun.COM */
mft_next_record(struct mft_search_ctx * ctx)9249663SMark.Logan@Sun.COM int mft_next_record(struct mft_search_ctx *ctx)
9259663SMark.Logan@Sun.COM {
9269663SMark.Logan@Sun.COM s64 nr_mft_records;
9279663SMark.Logan@Sun.COM ATTR_RECORD *attr10 = NULL;
9289663SMark.Logan@Sun.COM ATTR_RECORD *attr20 = NULL;
9299663SMark.Logan@Sun.COM ATTR_RECORD *attr80 = NULL;
9309663SMark.Logan@Sun.COM ntfs_attr_search_ctx *attr_ctx;
9319663SMark.Logan@Sun.COM
9329663SMark.Logan@Sun.COM if (!ctx) {
9339663SMark.Logan@Sun.COM errno = EINVAL;
9349663SMark.Logan@Sun.COM return -1;
9359663SMark.Logan@Sun.COM }
9369663SMark.Logan@Sun.COM
9379663SMark.Logan@Sun.COM if (ctx->inode) {
9389663SMark.Logan@Sun.COM ntfs_inode_close(ctx->inode);
9399663SMark.Logan@Sun.COM ctx->inode = NULL;
9409663SMark.Logan@Sun.COM }
9419663SMark.Logan@Sun.COM
9429663SMark.Logan@Sun.COM nr_mft_records = ctx->vol->mft_na->initialized_size >>
9439663SMark.Logan@Sun.COM ctx->vol->mft_record_size_bits;
9449663SMark.Logan@Sun.COM
9459663SMark.Logan@Sun.COM for (ctx->mft_num++; (s64)ctx->mft_num < nr_mft_records; ctx->mft_num++) {
9469663SMark.Logan@Sun.COM int in_use;
9479663SMark.Logan@Sun.COM
9489663SMark.Logan@Sun.COM ctx->flags_match = 0;
9499663SMark.Logan@Sun.COM in_use = utils_mftrec_in_use(ctx->vol, (MFT_REF) ctx->mft_num);
9509663SMark.Logan@Sun.COM if (in_use == -1) {
9519663SMark.Logan@Sun.COM ntfs_log_error("Error reading inode %llu. Aborting.\n",
9529663SMark.Logan@Sun.COM (unsigned long long)ctx->mft_num);
9539663SMark.Logan@Sun.COM return -1;
9549663SMark.Logan@Sun.COM }
9559663SMark.Logan@Sun.COM
9569663SMark.Logan@Sun.COM if (in_use) {
9579663SMark.Logan@Sun.COM ctx->flags_match |= FEMR_IN_USE;
9589663SMark.Logan@Sun.COM
9599663SMark.Logan@Sun.COM ctx->inode = ntfs_inode_open(ctx->vol, (MFT_REF) ctx->mft_num);
9609663SMark.Logan@Sun.COM if (ctx->inode == NULL) {
9619663SMark.Logan@Sun.COM ntfs_log_error("Error reading inode %llu.\n", (unsigned
9629663SMark.Logan@Sun.COM long long) ctx->mft_num);
9639663SMark.Logan@Sun.COM continue;
9649663SMark.Logan@Sun.COM }
9659663SMark.Logan@Sun.COM
9669663SMark.Logan@Sun.COM attr10 = find_first_attribute(AT_STANDARD_INFORMATION, ctx->inode->mrec);
9679663SMark.Logan@Sun.COM attr20 = find_first_attribute(AT_ATTRIBUTE_LIST, ctx->inode->mrec);
9689663SMark.Logan@Sun.COM attr80 = find_first_attribute(AT_DATA, ctx->inode->mrec);
9699663SMark.Logan@Sun.COM
9709663SMark.Logan@Sun.COM if (attr10)
9719663SMark.Logan@Sun.COM ctx->flags_match |= FEMR_BASE_RECORD;
9729663SMark.Logan@Sun.COM else
9739663SMark.Logan@Sun.COM ctx->flags_match |= FEMR_NOT_BASE_RECORD;
9749663SMark.Logan@Sun.COM
9759663SMark.Logan@Sun.COM if (attr20)
9769663SMark.Logan@Sun.COM ctx->flags_match |= FEMR_BASE_RECORD;
9779663SMark.Logan@Sun.COM
9789663SMark.Logan@Sun.COM if (attr80)
9799663SMark.Logan@Sun.COM ctx->flags_match |= FEMR_FILE;
9809663SMark.Logan@Sun.COM
9819663SMark.Logan@Sun.COM if (ctx->flags_search & FEMR_DIR) {
9829663SMark.Logan@Sun.COM attr_ctx = ntfs_attr_get_search_ctx(ctx->inode, NULL);
9839663SMark.Logan@Sun.COM if (attr_ctx) {
9849663SMark.Logan@Sun.COM if (ntfs_attr_lookup(AT_INDEX_ROOT, NTFS_INDEX_I30, 4, 0, 0, NULL, 0, attr_ctx) == 0)
9859663SMark.Logan@Sun.COM ctx->flags_match |= FEMR_DIR;
9869663SMark.Logan@Sun.COM
9879663SMark.Logan@Sun.COM ntfs_attr_put_search_ctx(attr_ctx);
9889663SMark.Logan@Sun.COM } else {
9899663SMark.Logan@Sun.COM ntfs_log_error("Couldn't create a search context.\n");
9909663SMark.Logan@Sun.COM return -1;
9919663SMark.Logan@Sun.COM }
9929663SMark.Logan@Sun.COM }
9939663SMark.Logan@Sun.COM
9949663SMark.Logan@Sun.COM switch (utils_is_metadata(ctx->inode)) {
9959663SMark.Logan@Sun.COM case 1: ctx->flags_match |= FEMR_METADATA; break;
9969663SMark.Logan@Sun.COM case 0: ctx->flags_match |= FEMR_NOT_METADATA; break;
9979663SMark.Logan@Sun.COM default:
9989663SMark.Logan@Sun.COM ctx->flags_match |= FEMR_NOT_METADATA; break;
9999663SMark.Logan@Sun.COM //ntfs_log_error("Error reading inode %lld.\n", ctx->mft_num);
10009663SMark.Logan@Sun.COM //return -1;
10019663SMark.Logan@Sun.COM }
10029663SMark.Logan@Sun.COM
10039663SMark.Logan@Sun.COM } else { // !in_use
10049663SMark.Logan@Sun.COM ntfs_attr *mft;
10059663SMark.Logan@Sun.COM
10069663SMark.Logan@Sun.COM ctx->flags_match |= FEMR_NOT_IN_USE;
10079663SMark.Logan@Sun.COM
10089663SMark.Logan@Sun.COM ctx->inode = calloc(1, sizeof(*ctx->inode));
10099663SMark.Logan@Sun.COM if (!ctx->inode) {
10109663SMark.Logan@Sun.COM ntfs_log_error("Out of memory. Aborting.\n");
10119663SMark.Logan@Sun.COM return -1;
10129663SMark.Logan@Sun.COM }
10139663SMark.Logan@Sun.COM
10149663SMark.Logan@Sun.COM ctx->inode->mft_no = ctx->mft_num;
10159663SMark.Logan@Sun.COM ctx->inode->vol = ctx->vol;
10169663SMark.Logan@Sun.COM ctx->inode->mrec = ntfs_malloc(ctx->vol->mft_record_size);
10179663SMark.Logan@Sun.COM if (!ctx->inode->mrec) {
10189663SMark.Logan@Sun.COM free(ctx->inode); // == ntfs_inode_close
10199663SMark.Logan@Sun.COM return -1;
10209663SMark.Logan@Sun.COM }
10219663SMark.Logan@Sun.COM
10229663SMark.Logan@Sun.COM mft = ntfs_attr_open(ctx->vol->mft_ni, AT_DATA,
10239663SMark.Logan@Sun.COM AT_UNNAMED, 0);
10249663SMark.Logan@Sun.COM if (!mft) {
10259663SMark.Logan@Sun.COM ntfs_log_perror("Couldn't open $MFT/$DATA");
10269663SMark.Logan@Sun.COM // free / close
10279663SMark.Logan@Sun.COM return -1;
10289663SMark.Logan@Sun.COM }
10299663SMark.Logan@Sun.COM
10309663SMark.Logan@Sun.COM if (ntfs_attr_pread(mft, ctx->vol->mft_record_size * ctx->mft_num, ctx->vol->mft_record_size, ctx->inode->mrec) < ctx->vol->mft_record_size) {
10319663SMark.Logan@Sun.COM ntfs_log_perror("Couldn't read MFT Record %llu",
10329663SMark.Logan@Sun.COM (unsigned long long) ctx->mft_num);
10339663SMark.Logan@Sun.COM // free / close
10349663SMark.Logan@Sun.COM ntfs_attr_close(mft);
10359663SMark.Logan@Sun.COM return -1;
10369663SMark.Logan@Sun.COM }
10379663SMark.Logan@Sun.COM
10389663SMark.Logan@Sun.COM ntfs_attr_close(mft);
10399663SMark.Logan@Sun.COM }
10409663SMark.Logan@Sun.COM
10419663SMark.Logan@Sun.COM if (ctx->flags_match & ctx->flags_search) {
10429663SMark.Logan@Sun.COM break;
10439663SMark.Logan@Sun.COM }
10449663SMark.Logan@Sun.COM
10459663SMark.Logan@Sun.COM if (ntfs_inode_close(ctx->inode)) {
10469663SMark.Logan@Sun.COM ntfs_log_error("Error closing inode %llu.\n",
10479663SMark.Logan@Sun.COM (unsigned long long)ctx->mft_num);
10489663SMark.Logan@Sun.COM return -errno;
10499663SMark.Logan@Sun.COM }
10509663SMark.Logan@Sun.COM
10519663SMark.Logan@Sun.COM ctx->inode = NULL;
10529663SMark.Logan@Sun.COM }
10539663SMark.Logan@Sun.COM
10549663SMark.Logan@Sun.COM return (ctx->inode == NULL);
10559663SMark.Logan@Sun.COM }
10569663SMark.Logan@Sun.COM
10579663SMark.Logan@Sun.COM
1058