📄 attrib.c
字号:
/** * attrib.c - Attribute handling code. Part of the Linux-NTFS project. * * Copyright (c) 2000-2005 Anton Altaparmakov * Copyright (c) 2002-2005 Richard Russon * Copyright (c) 2004-2006 Yura Pakhuchiy * * This program/include file 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/include file 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 * * Modified 01/2007 by Andy McLaughlin for Visopsys port. */#ifdef HAVE_CONFIG_H#include "config.h"#endif#ifdef HAVE_STDIO_H#include <stdio.h>#endif#ifdef HAVE_STRING_H#include <string.h>#endif#ifdef HAVE_STDLIB_H#include <stdlib.h>#endif#ifdef HAVE_ERRNO_H#include <errno.h>#endif#include "compat.h"#include "attrib.h"#include "attrlist.h"#include "device.h"#include "mft.h"#include "debug.h"#include "mst.h"#include "volume.h"#include "types.h"#include "layout.h"#include "inode.h"#include "runlist.h"#include "lcnalloc.h"#include "dir.h"#include "compress.h"#include "bitmap.h"#include "logging.h"ntfschar AT_UNNAMED[] = { const_cpu_to_le16('\0') };/** * ntfs_get_attribute_value_length - Find the length of an attribute * @a: * * Description... * * Returns: */s64 ntfs_get_attribute_value_length(const ATTR_RECORD *a){ if (!a) { errno = EINVAL; return 0; } errno = 0; if (a->non_resident) return sle64_to_cpu(a->data_size); else return (s64)le32_to_cpu(a->value_length); errno = EINVAL; return 0;}/** * ntfs_get_attribute_value - Get a copy of an attribute * @vol: * @a: * @b: * * Description... * * Returns: */s64 ntfs_get_attribute_value(const ntfs_volume *vol, const ATTR_RECORD *a, u8 *b){ runlist *rl; s64 total, r; int i; /* Sanity checks. */ if (!vol || !a || !b) { errno = EINVAL; return 0; } /* Complex attribute? */ /* * Ignore the flags in case they are not zero for an attribute list * attribute. Windows does not complain about invalid flags and chkdsk * does not detect or fix them so we need to cope with it, too. */ if (a->type != AT_ATTRIBUTE_LIST && a->flags) { ntfs_log_error("Non-zero (%04x) attribute flags. Cannot handle " "this yet.\n", le16_to_cpu(a->flags)); errno = EOPNOTSUPP; return 0; } if (!a->non_resident) { /* Attribute is resident. */ /* Sanity check. */ if (le32_to_cpu(a->value_length) + le16_to_cpu(a->value_offset) > le32_to_cpu(a->length)) { return 0; } memcpy(b, (const char*)a + le16_to_cpu(a->value_offset), le32_to_cpu(a->value_length)); errno = 0; return (s64)le32_to_cpu(a->value_length); } /* Attribute is not resident. */ /* If no data, return 0. */ if (!(a->data_size)) { errno = 0; return 0; } /* * FIXME: What about attribute lists?!? (AIA) */ /* Decompress the mapping pairs array into a runlist. */ rl = ntfs_mapping_pairs_decompress(vol, a, NULL); if (!rl) { errno = EINVAL; return 0; } /* * FIXED: We were overflowing here in a nasty fashion when we * reach the last cluster in the runlist as the buffer will * only be big enough to hold data_size bytes while we are * reading in allocated_size bytes which is usually larger * than data_size, since the actual data is unlikely to have a * size equal to a multiple of the cluster size! * FIXED2: We were also overflowing here in the same fashion * when the data_size was more than one run smaller than the * allocated size which happens with Windows XP sometimes. */ /* Now load all clusters in the runlist into b. */ for (i = 0, total = 0; rl[i].length; i++) { if (total + (rl[i].length << vol->cluster_size_bits) >= sle64_to_cpu(a->data_size)) { unsigned char *intbuf = NULL; /* * We have reached the last run so we were going to * overflow when executing the ntfs_pread() which is * BAAAAAAAD! * Temporary fix: * Allocate a new buffer with size: * rl[i].length << vol->cluster_size_bits, do the * read into our buffer, then memcpy the correct * amount of data into the caller supplied buffer, * free our buffer, and continue. * We have reached the end of data size so we were * going to overflow in the same fashion. * Temporary fix: same as above. */ intbuf = malloc(rl[i].length << vol->cluster_size_bits); if (!intbuf) { int eo = errno; ntfs_log_perror("Couldn't allocate memory for " "internal buffer."); free(rl); errno = eo; return 0; } /* * FIXME: If compressed file: Only read if lcn != -1. * Otherwise, we are dealing with a sparse run and we * just memset the user buffer to 0 for the length of * the run, which should be 16 (= compression unit * size). * FIXME: Really only when file is compressed, or can * we have sparse runs in uncompressed files as well? * - Yes we can, in sparse files! But not necessarily * size of 16, just run length. */ r = ntfs_pread(vol->dev, rl[i].lcn << vol->cluster_size_bits, rl[i].length << vol->cluster_size_bits, intbuf); if (r != rl[i].length << vol->cluster_size_bits) {#define ESTR "Error reading attribute value" if (r == -1) { int eo = errno; ntfs_log_perror(ESTR); errno = eo; } else if (r < rl[i].length << vol->cluster_size_bits) { ntfs_log_debug(ESTR ": Ran out of input data.\n"); errno = EIO; } else { ntfs_log_debug(ESTR ": unknown error\n"); errno = EIO; }#undef ESTR free(rl); free(intbuf); return 0; } memcpy(b + total, intbuf, sle64_to_cpu(a->data_size) - total); free(intbuf); total = sle64_to_cpu(a->data_size); break; } /* * FIXME: If compressed file: Only read if lcn != -1. * Otherwise, we are dealing with a sparse run and we just * memset the user buffer to 0 for the length of the run, which * should be 16 (= compression unit size). * FIXME: Really only when file is compressed, or can * we have sparse runs in uncompressed files as well? * - Yes we can, in sparse files! But not necessarily size of * 16, just run length. */ r = ntfs_pread(vol->dev, rl[i].lcn << vol->cluster_size_bits, rl[i].length << vol->cluster_size_bits, b + total); if (r != rl[i].length << vol->cluster_size_bits) {#define ESTR "Error reading attribute value" if (r == -1) { int eo = errno; ntfs_log_perror(ESTR); errno = eo; } else if (r < rl[i].length << vol->cluster_size_bits) { ntfs_log_debug(ESTR ": Ran out of input data.\n"); errno = EIO; } else { ntfs_log_debug(ESTR ": unknown error\n"); errno = EIO; }#undef ESTR return 0; } total += r; } free(rl); return total;}/* Already cleaned up code below, but still look for FIXME:... *//** * __ntfs_attr_init - primary initialization of an ntfs attribute structure * @na: ntfs attribute to initialize * @ni: ntfs inode with which to initialize the ntfs attribute * @type: attribute type * @name: attribute name in little endian Unicode or NULL * @name_len: length of attribute @name in Unicode characters (if @name given) * * Initialize the ntfs attribute @na with @ni, @type, @name, and @name_len. */static __inline__ void __ntfs_attr_init(ntfs_attr *na, ntfs_inode *ni, const ATTR_TYPES type, ntfschar *name, const u32 name_len){ na->rl = NULL; na->ni = ni; na->type = type; na->name = name; if (name) na->name_len = name_len; else na->name_len = 0;}/** * ntfs_attr_init - initialize an ntfs_attr with data sizes and status * @na: * @non_resident: * @compressed: * @encrypted: * @sparse: * @allocated_size: * @data_size: * @initialized_size: * @compressed_size: * @compression_unit: * * Final initialization for an ntfs attribute. */void ntfs_attr_init(ntfs_attr *na, const BOOL non_resident, const BOOL compressed, const BOOL encrypted, const BOOL sparse, const s64 allocated_size, const s64 data_size, const s64 initialized_size, const s64 compressed_size, const u8 compression_unit){ if (!NAttrInitialized(na)) { if (non_resident) NAttrSetNonResident(na); if (compressed) NAttrSetCompressed(na); if (encrypted) NAttrSetEncrypted(na); if (sparse) NAttrSetSparse(na); na->allocated_size = allocated_size; na->data_size = data_size; na->initialized_size = initialized_size; if (compressed || sparse) { ntfs_volume *vol = na->ni->vol; na->compressed_size = compressed_size; na->compression_block_clusters = 1 << compression_unit; na->compression_block_size = 1 << (compression_unit + vol->cluster_size_bits); na->compression_block_size_bits = ffs( na->compression_block_size) - 1; } NAttrSetInitialized(na); }}/** * ntfs_attr_open - open an ntfs attribute for access * @ni: open ntfs inode in which the ntfs attribute resides * @type: attribute type * @name: attribute name in little endian Unicode or AT_UNNAMED or NULL * @name_len: length of attribute @name in Unicode characters (if @name given) * * Allocate a new ntfs attribute structure, initialize it with @ni, @type, * @name, and @name_len, then return it. Return NULL on error with * errno set to the error code. * * If @name is AT_UNNAMED look specifically for an unnamed attribute. If you * do not care whether the attribute is named or not set @name to NULL. In * both those cases @name_len is not used at all. */ntfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES type, ntfschar *name, u32 name_len){ ntfs_attr_search_ctx *ctx; ntfs_attr *na; ATTR_RECORD *a; int err; BOOL cs; ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n", (unsigned long long)ni->mft_no, type); if (!ni || !ni->vol || !ni->mrec) { errno = EINVAL; return NULL; } na = calloc(sizeof(ntfs_attr), 1); if (!na) return NULL; if (name && name != AT_UNNAMED && name != NTFS_INDEX_I30) { name = ntfs_ucsndup(name, name_len); if (!name) { err = errno; free(na); errno = err; return NULL; } } ctx = ntfs_attr_get_search_ctx(ni, NULL); if (!ctx) { err = errno; goto err_out; } if (ntfs_attr_lookup(type, name, name_len, 0, 0, NULL, 0, ctx)) { err = errno; goto put_err_out; } a = ctx->attr; /* * Wipe the flags in case they are not zero for an attribute list * attribute. Windows does not complain about invalid flags and chkdsk * does not detect or fix them so we need to cope with it, too. */ if (type == AT_ATTRIBUTE_LIST) a->flags = 0; cs = a->flags & (ATTR_IS_COMPRESSED | ATTR_IS_SPARSE); if (!name) { if (a->name_length) { name = ntfs_ucsndup((ntfschar*)((u8*)a + le16_to_cpu( a->name_offset)), a->name_length); if (!name) { err = errno; goto put_err_out; } name_len = a->name_length; } else { name = AT_UNNAMED; name_len = 0; } } __ntfs_attr_init(na, ni, type, name, name_len); if (a->non_resident) { ntfs_attr_init(na, TRUE, a->flags & ATTR_IS_COMPRESSED, a->flags & ATTR_IS_ENCRYPTED, a->flags & ATTR_IS_SPARSE, sle64_to_cpu(a->allocated_size), sle64_to_cpu(a->data_size), sle64_to_cpu(a->initialized_size), cs ? sle64_to_cpu(a->compressed_size) : 0, cs ? a->compression_unit : 0); } else { s64 l = le32_to_cpu(a->value_length); ntfs_attr_init(na, FALSE, a->flags & ATTR_IS_COMPRESSED, a->flags & ATTR_IS_ENCRYPTED, a->flags & ATTR_IS_SPARSE, (l + 7) & ~7, l, l, cs ? (l + 7) & ~7 : 0, 0); } ntfs_attr_put_search_ctx(ctx); return na;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -