⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 utils.c

📁 一个在linux下挂载ntfs文件系统的好工具
💻 C
📖 第 1 页 / 共 2 页
字号:
/** * utils.c - Part of the Linux-NTFS project. * * Copyright (c) 2002-2005 Richard Russon * Copyright (c) 2003-2006 Anton Altaparmakov * Copyright (c) 2003 Lode Leroy * * A set of shared functions for ntfs utilities * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program (in the main directory of the Linux-NTFS * distribution in the file COPYING); if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */#ifdef HAVE_CONFIG_H#include "config.h"#endif#ifdef HAVE_STDIO_H#include <stdio.h>#endif#ifdef HAVE_STDARG_H#include <stdarg.h>#endif#ifdef HAVE_ERRNO_H#include <errno.h>#endif#ifdef HAVE_SYS_TYPES_H#include <sys/types.h>#endif#ifdef HAVE_SYS_STAT_H#include <sys/stat.h>#endif#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#ifdef HAVE_STRING_H#include <string.h>#endif#ifdef HAVE_LOCALE_H#include <locale.h>#endif#ifdef HAVE_LIBINTL_H#include <libintl.h>#endif#ifdef HAVE_STDLIB_H#include <stdlib.h>#endif#ifdef HAVE_LIMITS_H#include <limits.h>#endif#ifdef HAVE_CTYPE_H#include <ctype.h>#endif#include "utils.h"#include "types.h"#include "volume.h"#include "debug.h"#include "dir.h"#include "version.h"#include "logging.h"#include "misc.h"const char *ntfs_bugs = "Developers' email address: "NTFS_DEV_LIST"\n";const char *ntfs_home = "Linux NTFS homepage: http://www.linux-ntfs.org\n";const char *ntfs_gpl = "This program is free software, released under the GNU "	"General Public License\nand you are welcome to redistribute it under "	"certain conditions.  It comes with\nABSOLUTELY NO WARRANTY; for "	"details read the GNU General Public License to be\nfound in the file "	"\"COPYING\" distributed with this program, or online at:\n"	"http://www.gnu.org/copyleft/gpl.html\n";/** * utils_set_locale */int utils_set_locale(void){	const char *locale;	locale = setlocale(LC_ALL, "");	if (!locale) {		locale = setlocale(LC_ALL, NULL);		ntfs_log_error("Couldn't set local environment, using default '%s'.\n", locale);		return 1;	} else {		return 0;	}}/** * utils_valid_device - Perform some safety checks on the device, before we start * @name:   Full pathname of the device/file to work with * @force:  Continue regardless of problems * * Check that the name refers to a device and that is isn't already mounted. * These checks can be overridden by using the force option. * * Return:  1  Success, we can continue *	    0  Error, we cannot use this device */int utils_valid_device(const char *name, int force){	unsigned long mnt_flags = 0;	struct stat st;#ifdef __CYGWIN32__	/* FIXME: This doesn't work for Cygwin, so just return success for now... */	return 1;#endif	if (!name) {		errno = EINVAL;		return 0;	}	if (stat(name, &st) == -1) {		if (errno == ENOENT) {			ntfs_log_error("The device %s doesn't exist\n", name);		} else {			ntfs_log_perror("Error getting information about %s", name);		}		return 0;	}	if (!S_ISBLK(st.st_mode) && !S_ISREG(st.st_mode)) {		ntfs_log_warning("%s is not a block device, "				 "nor regular file.\n", name);		if (!force) {			ntfs_log_error("Use the force option to work with other"				       " file types, for your own risk!\n");			return 0;		}		ntfs_log_warning("Forced to continue.\n");	}	/* Make sure the file system is not mounted. */	if (ntfs_check_if_mounted(name, &mnt_flags)) {		ntfs_log_perror("Failed to determine whether %s is mounted", name);		if (!force) {			ntfs_log_error("Use the force option to ignore this error.\n");			return 0;		}		ntfs_log_warning("Forced to continue.\n");	} else if (mnt_flags & NTFS_MF_MOUNTED) {		ntfs_log_warning("The device %s, is mounted.\n", name);		if (!force) {			ntfs_log_error("Use the force option to work a mounted filesystem.\n");			return 0;		}		ntfs_log_warning("Forced to continue.\n");	}	return 1;}/** * utils_mount_volume - Mount an NTFS volume */ntfs_volume * utils_mount_volume(const char *device, unsigned long flags, BOOL force){	ntfs_volume *vol;	if (!device) {		errno = EINVAL;		return NULL;	}	if (!utils_valid_device(device, force))		return NULL;	vol = ntfs_mount(device, flags);	if (!vol) {		ntfs_log_perror("Couldn't mount device '%s'", device);		if (errno == EPERM)			ntfs_log_error("Windows was hibernated.  Try to mount "					"volume in windows, shut down and try "					"again.\n");		if (errno == EOPNOTSUPP)			ntfs_log_error("Windows did not shut down properly.  "					"Try to mount volume in windows, "					"shut down and try again.\n");		return NULL;	}	if (vol->flags & VOLUME_IS_DIRTY) {		ntfs_log_warning("Volume is dirty.\n");		if (!force) {			ntfs_log_error("Run chkdsk and try again, or use the "					"force option.\n");			ntfs_umount(vol, FALSE);			return NULL;		}		ntfs_log_warning("Forced to continue.\n");	}	return vol;}/** * utils_parse_size - Convert a string representing a size * @value:  String to be parsed * @size:   Parsed size * @scale:  Whether or not to allow a suffix to scale the value * * Read a string and convert it to a number.  Strings may be suffixed to scale * them.  Any number without a suffix is assumed to be in bytes. * * Suffix  Description  Multiple *  [tT]    Terabytes     10^12 *  [gG]    Gigabytes     10^9 *  [mM]    Megabytes     10^6 *  [kK]    Kilobytes     10^3 * * Notes: *     Only the first character of the suffix is read. *     The multipliers are decimal thousands, not binary: 1000, not 1024. *     If parse_size fails, @size will not be changed * * Return:  1  Success *	    0  Error, the string was malformed */int utils_parse_size(const char *value, s64 *size, BOOL scale){	long long result;	char *suffix = NULL;	if (!value || !size) {		errno = EINVAL;		return 0;	}	result = strtoll(value, &suffix, 0);	if (result < 0 || errno == ERANGE) {		ntfs_log_error("Invalid size '%s'.\n", value);		return 0;	}	if (!suffix) {		ntfs_log_error("Internal error, strtoll didn't return a suffix.\n");		return 0;	}	if (scale) {		switch (suffix[0]) {			case 't': case 'T': result *= 1000;			case 'g': case 'G': result *= 1000;			case 'm': case 'M': result *= 1000;			case 'k': case 'K': result *= 1000;			case '-': case 0:				break;			default:				ntfs_log_error("Invalid size suffix '%s'.  Use T, G, M, or K.\n", suffix);				return 0;		}	} else {		if ((suffix[0] != '-') && (suffix[0] != 0)) {			ntfs_log_error("Invalid number '%.*s'.\n", (int)(suffix - value + 1), value);			return 0;		}	}	*size = result;	return 1;}/** * utils_parse_range - Convert a string representing a range of numbers * @string:  The string to be parsed * @start:   The beginning of the range will be stored here * @finish:  The end of the range will be stored here * * Read a string of the form n-m.  If the lower end is missing, zero will be * substituted.  If the upper end is missing LONG_MAX will be used.  If the * string cannot be parsed correctly, @start and @finish will not be changed. * * Return:  1  Success, a valid string was found *	    0  Error, the string was not a valid range */int utils_parse_range(const char *string, s64 *start, s64 *finish, BOOL scale){	s64 a, b;	char *middle;	if (!string || !start || !finish) {		errno = EINVAL;		return 0;	}	middle = strchr(string, '-');	if (string == middle) {		ntfs_log_debug("Range has no beginning, defaulting to 0.\n");		a = 0;	} else {		if (!utils_parse_size(string, &a, scale))			return 0;	}	if (middle) {		if (middle[1] == 0) {			b = LONG_MAX;		// XXX ULLONG_MAX			ntfs_log_debug("Range has no end, defaulting to %lld.\n", b);		} else {			if (!utils_parse_size(middle+1, &b, scale))				return 0;		}	} else {		b = a;	}	ntfs_log_debug("Range '%s' = %lld - %lld\n", string, a, b);	*start  = a;	*finish = b;	return 1;}/** * find_attribute - Find an attribute of the given type * @type:  An attribute type, e.g. AT_FILE_NAME * @ctx:   A search context, created using ntfs_get_attr_search_ctx * * Using the search context to keep track, find the first/next occurrence of a * given attribute type. * * N.B.  This will return a pointer into @mft.  As long as the search context *       has been created without an inode, it won't overflow the buffer. * * Return:  Pointer  Success, an attribute was found *	    NULL     Error, no matching attributes were found */ATTR_RECORD * find_attribute(const ATTR_TYPES type, ntfs_attr_search_ctx *ctx){	if (!ctx) {		errno = EINVAL;		return NULL;	}	if (ntfs_attr_lookup(type, NULL, 0, 0, 0, NULL, 0, ctx) != 0) {		ntfs_log_debug("find_attribute didn't find an attribute of type: 0x%02x.\n", type);		return NULL;	/* None / no more of that type */	}	ntfs_log_debug("find_attribute found an attribute of type: 0x%02x.\n", type);	return ctx->attr;}/** * find_first_attribute - Find the first attribute of a given type * @type:  An attribute type, e.g. AT_FILE_NAME * @mft:   A buffer containing a raw MFT record * * Search through a raw MFT record for an attribute of a given type. * The return value is a pointer into the MFT record that was supplied. * * N.B.  This will return a pointer into @mft.  The pointer won't stray outside *       the buffer, since we created the search context without an inode. * * Return:  Pointer  Success, an attribute was found *	    NULL     Error, no matching attributes were found */ATTR_RECORD * find_first_attribute(const ATTR_TYPES type, MFT_RECORD *mft){	ntfs_attr_search_ctx *ctx;	ATTR_RECORD *rec;	if (!mft) {		errno = EINVAL;		return NULL;	}	ctx = ntfs_attr_get_search_ctx(NULL, mft);	if (!ctx) {		ntfs_log_error("Couldn't create a search context.\n");		return NULL;	}	rec = find_attribute(type, ctx);	ntfs_attr_put_search_ctx(ctx);	if (rec)		ntfs_log_debug("find_first_attribute: found attr of type 0x%02x.\n", type);	else		ntfs_log_debug("find_first_attribute: didn't find attr of type 0x%02x.\n", type);	return rec;}/** * utils_inode_get_name * * using inode * get filename * add name to list * get parent * if parent is 5 (/) stop * get inode of parent */int utils_inode_get_name(ntfs_inode *inode, char *buffer, int bufsize){	// XXX option: names = posix/win32 or dos	// flags: path, filename, or both	const int max_path = 20;	ntfs_volume *vol;	ntfs_attr_search_ctx *ctx;	ATTR_RECORD *rec;	FILE_NAME_ATTR *attr;	int name_space;	MFT_REF parent = FILE_root;	char *names[max_path + 1];// XXX ntfs_malloc? and make max bigger?	int i, len, offset = 0;	if (!inode || !buffer) {		errno = EINVAL;		return 0;	}	vol = inode->vol;	//ntfs_log_debug("sizeof(char*) = %d, sizeof(names) = %d\n", sizeof(char*), sizeof(names));	memset(names, 0, sizeof(names));	for (i = 0; i < max_path; i++) {		ctx = ntfs_attr_get_search_ctx(inode, NULL);		if (!ctx) {			ntfs_log_error("Couldn't create a search context.\n");			return 0;		}		//ntfs_log_debug("i = %d, inode = %p (%lld)\n", i, inode, inode->mft_no);		name_space = 4;		while ((rec = find_attribute(AT_FILE_NAME, ctx))) {			/* We know this will always be resident. */			attr = (FILE_NAME_ATTR *) ((char *) rec + le16_to_cpu(rec->value_offset));			if (attr->file_name_type > name_space) { //XXX find the ...				continue;			}			name_space = attr->file_name_type;			parent     = le64_to_cpu(attr->parent_directory);			if (names[i]) {				free(names[i]);				names[i] = NULL;			}			if (ntfs_ucstombs(attr->file_name, attr->file_name_length,			    &names[i], 0) < 0) {				char *temp;				ntfs_log_error("Couldn't translate filename to current locale.\n");				temp = ntfs_malloc(30);				if (!temp)					return 0;				snprintf(temp, 30, "<MFT%llu>", (unsigned						long long)inode->mft_no);				names[i] = temp;			}			//ntfs_log_debug("names[%d] %s\n", i, names[i]);			//ntfs_log_debug("parent = %lld\n", MREF(parent));		}		ntfs_attr_put_search_ctx(ctx);		if (i > 0)			/* Don't close the original inode */			ntfs_inode_close(inode);		if (MREF(parent) == FILE_root) {	/* The root directory, stop. */			//ntfs_log_debug("inode 5\n");			break;		}		inode = ntfs_inode_open(vol, parent);		if (!inode) {			ntfs_log_error("Couldn't open inode %llu.\n",					(unsigned long long)MREF(parent));			break;		}	}	if (i >= max_path) {		/* If we get into an infinite loop, we'll end up here. */		ntfs_log_error("The directory structure is too deep (over %d) nested directories.\n", max_path);		return 0;	}	/* Assemble the names in the correct order. */	for (i = max_path; i >= 0; i--) {		if (!names[i])			continue;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -