inode.c
来自「LINUX下读写NTFS分区的工具。 已经集成了通过LIBCONV库支持中文的」· C语言 代码 · 共 1,184 行 · 第 1/3 页
C
1,184 行
/** * inode.c - Inode handling code. Originated from the Linux-NTFS project. * * Copyright (c) 2002-2005 Anton Altaparmakov * Copyright (c) 2002-2008 Szabolcs Szakacsits * Copyright (c) 2004-2007 Yura Pakhuchiy * Copyright (c) 2004-2005 Richard Russon * * 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 NTFS-3G * 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_STDLIB_H#include <stdlib.h>#endif#ifdef HAVE_STRING_H#include <string.h>#endif#ifdef HAVE_ERRNO_H#include <errno.h>#endif#include "compat.h"#include "types.h"#include "attrib.h"#include "inode.h"#include "debug.h"#include "mft.h"#include "attrlist.h"#include "runlist.h"#include "lcnalloc.h"#include "index.h"#include "dir.h"#include "ntfstime.h"#include "logging.h"#include "misc.h"ntfs_inode *ntfs_inode_base(ntfs_inode *ni){ if (ni->nr_extents == -1) return ni->base_ni; return ni;}/** * ntfs_inode_mark_dirty - set the inode (and its base inode if it exists) dirty * @ni: ntfs inode to set dirty * * Set the inode @ni dirty so it is written out later (at the latest at * ntfs_inode_close() time). If @ni is an extent inode, set the base inode * dirty, too. * * This function cannot fail. */void ntfs_inode_mark_dirty(ntfs_inode *ni){ NInoSetDirty(ni); if (ni->nr_extents == -1) NInoSetDirty(ni->base_ni);}/** * __ntfs_inode_allocate - Create and initialise an NTFS inode object * @vol: * * Description... * * Returns: */static ntfs_inode *__ntfs_inode_allocate(ntfs_volume *vol){ ntfs_inode *ni; ni = (ntfs_inode*)calloc(1, sizeof(ntfs_inode)); if (ni) ni->vol = vol; return ni;}/** * ntfs_inode_allocate - Create an NTFS inode object * @vol: * * Description... * * Returns: */ntfs_inode *ntfs_inode_allocate(ntfs_volume *vol){ return __ntfs_inode_allocate(vol);}/** * __ntfs_inode_release - Destroy an NTFS inode object * @ni: * * Description... * * Returns: */static void __ntfs_inode_release(ntfs_inode *ni){ if (NInoDirty(ni)) ntfs_log_error("Releasing dirty inode %lld!\n", (long long)ni->mft_no); if (NInoAttrList(ni) && ni->attr_list) free(ni->attr_list); free(ni->mrec); free(ni); return;}/** * ntfs_inode_open - open an inode ready for access * @vol: volume to get the inode from * @mref: inode number / mft record number to open * * Allocate an ntfs_inode structure and initialize it for the given inode * specified by @mref. @mref specifies the inode number / mft record to read, * including the sequence number, which can be 0 if no sequence number checking * is to be performed. * * Then, allocate a buffer for the mft record, read the mft record from the * volume @vol, and attach it to the ntfs_inode structure (->mrec). The * mft record is mst deprotected and sanity checked for validity and we abort * if deprotection or checks fail. * * Finally, search for an attribute list attribute in the mft record and if one * is found, load the attribute list attribute value and attach it to the * ntfs_inode structure (->attr_list). Also set the NI_AttrList bit to indicate * this. * * Return a pointer to the ntfs_inode structure on success or NULL on error, * with errno set to the error code. */ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref){ s64 l; ntfs_inode *ni = NULL; ntfs_attr_search_ctx *ctx; STANDARD_INFORMATION *std_info; ntfs_log_enter("Entering for inode %lld\n", MREF(mref)); if (!vol) { errno = EINVAL; goto out; } ni = __ntfs_inode_allocate(vol); if (!ni) goto out; if (ntfs_file_record_read(vol, mref, &ni->mrec, NULL)) goto err_out; if (!(ni->mrec->flags & MFT_RECORD_IN_USE)) { errno = ENOENT; goto err_out; } ni->mft_no = MREF(mref); ctx = ntfs_attr_get_search_ctx(ni, NULL); if (!ctx) goto err_out; /* Receive some basic information about inode. */ if (ntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED, 0, CASE_SENSITIVE, 0, NULL, 0, ctx)) { ntfs_log_trace("Failed to receive STANDARD_INFORMATION " "attribute.\n"); goto put_err_out; } std_info = (STANDARD_INFORMATION *)((u8 *)ctx->attr + le16_to_cpu(ctx->attr->value_offset)); ni->flags = std_info->file_attributes; ni->creation_time = ntfs2utc(std_info->creation_time); ni->last_data_change_time = ntfs2utc(std_info->last_data_change_time); ni->last_mft_change_time = ntfs2utc(std_info->last_mft_change_time); ni->last_access_time = ntfs2utc(std_info->last_access_time); /* Set attribute list information. */ if (ntfs_attr_lookup(AT_ATTRIBUTE_LIST, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) { if (errno != ENOENT) goto put_err_out; /* Attribute list attribute does not present. */ goto get_size; } NInoSetAttrList(ni); l = ntfs_get_attribute_value_length(ctx->attr); if (!l) goto put_err_out; if (l > 0x40000) { errno = EIO; goto put_err_out; } ni->attr_list_size = l; ni->attr_list = ntfs_malloc(ni->attr_list_size); if (!ni->attr_list) goto put_err_out; l = ntfs_get_attribute_value(vol, ctx->attr, ni->attr_list); if (!l) goto put_err_out; if (l != ni->attr_list_size) { errno = EIO; goto put_err_out; }get_size: if (ntfs_attr_lookup(AT_DATA, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) { if (errno != ENOENT) goto put_err_out; /* Directory or special file. */ ni->data_size = ni->allocated_size = 0; } else { if (ctx->attr->non_resident) { ni->data_size = sle64_to_cpu(ctx->attr->data_size); if (ctx->attr->flags & (ATTR_IS_COMPRESSED | ATTR_IS_SPARSE)) ni->allocated_size = sle64_to_cpu( ctx->attr->compressed_size); else ni->allocated_size = sle64_to_cpu( ctx->attr->allocated_size); } else { ni->data_size = le32_to_cpu(ctx->attr->value_length); ni->allocated_size = (ni->data_size + 7) & ~7; } } ntfs_attr_put_search_ctx(ctx);out: ntfs_log_leave("\n"); return ni;put_err_out: ntfs_attr_put_search_ctx(ctx);err_out: __ntfs_inode_release(ni); ni = NULL; goto out;}/** * ntfs_inode_close - close an ntfs inode and free all associated memory * @ni: ntfs inode to close * * Make sure the ntfs inode @ni is clean. * * If the ntfs inode @ni is a base inode, close all associated extent inodes, * then deallocate all memory attached to it, and finally free the ntfs inode * structure itself. * * If it is an extent inode, we disconnect it from its base inode before we * destroy it. * * Return 0 on success or -1 on error with errno set to the error code. On * error, @ni has not been freed. The user should attempt to handle the error * and call ntfs_inode_close() again. The following error codes are defined: * * EBUSY @ni and/or its attribute list runlist is/are dirty and the * attempt to write it/them to disk failed. * EINVAL @ni is invalid (probably it is an extent inode). * EIO I/O error while trying to write inode to disk. */int ntfs_inode_close(ntfs_inode *ni){ int ret = -1; if (!ni) return 0; ntfs_log_enter("Entering for inode %lld\n", (long long)ni->mft_no); /* If we have dirty metadata, write it out. */ if (NInoDirty(ni) || NInoAttrListDirty(ni)) { if (ntfs_inode_sync(ni)) { if (errno != EIO) errno = EBUSY; goto err; } } /* Is this a base inode with mapped extent inodes? */ if (ni->nr_extents > 0) { while (ni->nr_extents > 0) { if (ntfs_inode_close(ni->extent_nis[0])) { if (errno != EIO) errno = EBUSY; goto err; } } } else if (ni->nr_extents == -1) { ntfs_inode **tmp_nis; ntfs_inode *base_ni; s32 i; /* * If the inode is an extent inode, disconnect it from the * base inode before destroying it. */ base_ni = ni->base_ni; for (i = 0; i < base_ni->nr_extents; ++i) { tmp_nis = base_ni->extent_nis; if (tmp_nis[i] != ni) continue; /* Found it. Disconnect. */ memmove(tmp_nis + i, tmp_nis + i + 1, (base_ni->nr_extents - i - 1) * sizeof(ntfs_inode *)); /* Buffer should be for multiple of four extents. */ if ((--base_ni->nr_extents) & 3) { i = -1; break; } /* * ElectricFence is unhappy with realloc(x,0) as free(x) * thus we explicitly separate these two cases. */ if (base_ni->nr_extents) { /* Resize the memory buffer. */ tmp_nis = realloc(tmp_nis, base_ni->nr_extents * sizeof(ntfs_inode *)); /* Ignore errors, they don't really matter. */ if (tmp_nis) base_ni->extent_nis = tmp_nis; } else if (tmp_nis) free(tmp_nis); /* Allow for error checking. */ i = -1; break; } /* * We could successfully sync, so only log this error * and try to sync other inode extents too. */ if (i != -1) ntfs_log_error("Extent inode %lld was not found\n", (long long)ni->mft_no); } __ntfs_inode_release(ni); ret = 0;err: ntfs_log_leave("\n"); return ret;}/** * ntfs_extent_inode_open - load an extent inode and attach it to its base * @base_ni: base ntfs inode * @mref: mft reference of the extent inode to load (in little endian) * * First check if the extent inode @mref is already attached to the base ntfs * inode @base_ni, and if so, return a pointer to the attached extent inode. * * If the extent inode is not already attached to the base inode, allocate an * ntfs_inode structure and initialize it for the given inode @mref. @mref * specifies the inode number / mft record to read, including the sequence * number, which can be 0 if no sequence number checking is to be performed. * * Then, allocate a buffer for the mft record, read the mft record from the * volume @base_ni->vol, and attach it to the ntfs_inode structure (->mrec). * The mft record is mst deprotected and sanity checked for validity and we * abort if deprotection or checks fail. * * Finally attach the ntfs inode to its base inode @base_ni and return a * pointer to the ntfs_inode structure on success or NULL on error, with errno * set to the error code. * * Note, extent inodes are never closed directly. They are automatically * disposed off by the closing of the base inode. */ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, const MFT_REF mref){ u64 mft_no = MREF_LE(mref); ntfs_inode *ni = NULL; ntfs_inode **extent_nis; int i; if (!base_ni) { errno = EINVAL; ntfs_log_perror("%s", __FUNCTION__); return NULL; } ntfs_log_enter("Opening extent inode %lld (base mft record %lld).\n",
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?