📄 utils.c
字号:
/** * 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 + -