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

📄 volume.c

📁 上一个上传的有问题,这个是好的。visopsys包括系统内核和GUI的全部SOURCE code ,还包括一些基本的docs文档。里面src子目录对应所有SOURCE code.对于想研究操作系统的朋
💻 C
📖 第 1 页 / 共 4 页
字号:
/** * volume.c - NTFS volume handling code. Part of the Linux-NTFS project. * * Copyright (c) 2000-2006 Anton Altaparmakov * Copyright (c) 2002-2005 Szabolcs Szakacsits * 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 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_STDLIB_H#include <stdlib.h>#endif#ifdef HAVE_STDIO_H#include <stdio.h>#endif#ifdef HAVE_STRING_H#include <string.h>#endif#ifdef HAVE_FCNTL_H#include <fcntl.h>#endif#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#ifdef HAVE_ERRNO_H#include <errno.h>#endif#ifdef HAVE_SYS_STAT_H#include <sys/stat.h>#endif#ifdef HAVE_LIMITS_H#include <limits.h>#endif#include "volume.h"#include "attrib.h"#include "mft.h"#include "bootsect.h"#include "device.h"#include "debug.h"#include "inode.h"#include "runlist.h"#include "logfile.h"#include "dir.h"#include "logging.h"#ifndef PATH_MAX#define PATH_MAX 4096#endif/** * ntfs_volume_alloc - Create an NTFS volume object and initialise it * * Description... * * Returns: */ntfs_volume *ntfs_volume_alloc(void){	return calloc(1, sizeof(ntfs_volume));}/** * __ntfs_volume_release - Destroy an NTFS volume object * @v: * * Description... * * Returns: */static void __ntfs_volume_release(ntfs_volume *v){	if (v->lcnbmp_ni && NInoDirty(v->lcnbmp_ni))		ntfs_inode_sync(v->lcnbmp_ni);	if (v->vol_ni)		ntfs_inode_close(v->vol_ni);	if (v->lcnbmp_na)		ntfs_attr_close(v->lcnbmp_na);	if (v->lcnbmp_ni)		ntfs_inode_close(v->lcnbmp_ni);	if (v->mft_ni && NInoDirty(v->mft_ni))		ntfs_inode_sync(v->mft_ni);	if (v->mftbmp_na)		ntfs_attr_close(v->mftbmp_na);	if (v->mft_na)		ntfs_attr_close(v->mft_na);	if (v->mft_ni)		ntfs_inode_close(v->mft_ni);	if (v->mftmirr_ni && NInoDirty(v->mftmirr_ni))		ntfs_inode_sync(v->mftmirr_ni);	if (v->mftmirr_na)		ntfs_attr_close(v->mftmirr_na);	if (v->mftmirr_ni)		ntfs_inode_close(v->mftmirr_ni);	if (v->dev) {		struct ntfs_device *dev = v->dev;		if (NDevDirty(dev))			dev->d_ops->sync(dev);		if (dev->d_ops->close(dev))			ntfs_log_perror("Eeek! Failed to close the device.  Error: ");	}	if (v->vol_name)		free(v->vol_name);	if (v->upcase)		free(v->upcase);	if (v->attrdef)		free(v->attrdef);	free(v);}/** * ntfs_mft_load - load the $MFT and setup the ntfs volume with it * @vol:	ntfs volume whose $MFT to load * * Load $MFT from @vol and setup @vol with it. After calling this function the * volume @vol is ready for use by all read access functions provided by the * ntfs library. * * Return 0 on success and -1 on error with errno set to the error code. */static int ntfs_mft_load(ntfs_volume *vol){	VCN next_vcn, last_vcn, highest_vcn;	s64 l;	MFT_RECORD *mb = NULL;	ntfs_attr_search_ctx *ctx = NULL;	ATTR_RECORD *a;	int eo;	/* Manually setup an ntfs_inode. */	vol->mft_ni = ntfs_inode_allocate(vol);	mb = (MFT_RECORD*)malloc(vol->mft_record_size);	if (!vol->mft_ni || !mb) {		ntfs_log_perror("Error allocating memory for $MFT");		goto error_exit;	}	vol->mft_ni->mft_no = 0;	vol->mft_ni->mrec = mb;	/* Can't use any of the higher level functions yet! */	l = ntfs_mst_pread(vol->dev, vol->mft_lcn << vol->cluster_size_bits, 1,			vol->mft_record_size, mb);	if (l != 1) {		if (l != -1)			errno = EIO;		ntfs_log_perror("Error reading $MFT");		goto error_exit;	}	if (ntfs_is_baad_record(mb->magic)) {		ntfs_log_debug("Error: Incomplete multi sector transfer detected in "				"$MFT.\n");		goto io_error_exit;	}	if (!ntfs_is_mft_record(mb->magic)) {		ntfs_log_debug("Error: $MFT has invalid magic.\n");		goto io_error_exit;	}	ctx = ntfs_attr_get_search_ctx(vol->mft_ni, NULL);	if (!ctx) {		ntfs_log_perror("Failed to allocate attribute search context");		goto error_exit;	}	if (p2n(ctx->attr) < p2n(mb) ||			(char*)ctx->attr > (char*)mb + vol->mft_record_size) {		ntfs_log_debug("Error: $MFT is corrupt.\n");		goto io_error_exit;	}	/* Find the $ATTRIBUTE_LIST attribute in $MFT if present. */	if (ntfs_attr_lookup(AT_ATTRIBUTE_LIST, AT_UNNAMED, 0, 0, 0, NULL, 0,			ctx)) {		if (errno != ENOENT) {			ntfs_log_debug("Error: $MFT has corrupt attribute list.\n");			goto io_error_exit;		}		goto mft_has_no_attr_list;	}	NInoSetAttrList(vol->mft_ni);	l = ntfs_get_attribute_value_length(ctx->attr);	if (l <= 0 || l > 0x40000) {		ntfs_log_debug("Error: $MFT/$ATTRIBUTE_LIST has invalid length.\n");		goto io_error_exit;	}	vol->mft_ni->attr_list_size = l;	vol->mft_ni->attr_list = malloc(l);	if (!vol->mft_ni->attr_list) {		ntfs_log_debug("Error: failed to allocate buffer for attribute "				"list.\n");		goto error_exit;	}	l = ntfs_get_attribute_value(vol, ctx->attr, vol->mft_ni->attr_list);	if (!l) {		ntfs_log_debug("Error: failed to get value of "				"$MFT/$ATTRIBUTE_LIST.\n");		goto io_error_exit;	}	if (l != vol->mft_ni->attr_list_size) {		ntfs_log_debug("Error: got unexpected amount of data when reading "				"$MFT/$ATTRIBUTE_LIST.\n");		goto io_error_exit;	}mft_has_no_attr_list:	/* We now have a fully setup ntfs inode for $MFT in vol->mft_ni. */	/* Get an ntfs attribute for $MFT/$DATA and set it up, too. */	vol->mft_na = ntfs_attr_open(vol->mft_ni, AT_DATA, AT_UNNAMED, 0);	if (!vol->mft_na) {		ntfs_log_perror("Failed to open ntfs attribute");		goto error_exit;	}	/* Read all extents from the $DATA attribute in $MFT. */	ntfs_attr_reinit_search_ctx(ctx);	last_vcn = vol->mft_na->allocated_size >> vol->cluster_size_bits;	highest_vcn = next_vcn = 0;	a = NULL;	while (!ntfs_attr_lookup(AT_DATA, AT_UNNAMED, 0, 0, next_vcn, NULL, 0,			ctx)) {		runlist_element *nrl;		a = ctx->attr;		/* $MFT must be non-resident. */		if (!a->non_resident) {			ntfs_log_debug("$MFT must be non-resident but a resident "					"extent was found. $MFT is corrupt. Run "					"chkdsk.\n");			goto io_error_exit;		}		/* $MFT must be uncompressed and unencrypted. */		if (a->flags & ATTR_COMPRESSION_MASK ||				a->flags & ATTR_IS_ENCRYPTED) {			ntfs_log_debug("$MFT must be uncompressed and unencrypted "					"but a compressed/encrypted extent was "					"found. $MFT is corrupt. Run chkdsk.\n");			goto io_error_exit;		}		/*		 * Decompress the mapping pairs array of this extent and merge		 * the result into the existing runlist. No need for locking		 * as we have exclusive access to the inode at this time and we		 * are a mount in progress task, too.		 */		nrl = ntfs_mapping_pairs_decompress(vol, a, vol->mft_na->rl);		if (!nrl) {			ntfs_log_perror("ntfs_mapping_pairs_decompress() failed");			goto error_exit;		}		vol->mft_na->rl = nrl;		/* Get the lowest vcn for the next extent. */		highest_vcn = sle64_to_cpu(a->highest_vcn);		next_vcn = highest_vcn + 1;		/* Only one extent or error, which we catch below. */		if (next_vcn <= 0)			break;		/* Avoid endless loops due to corruption. */		if (next_vcn < sle64_to_cpu(a->lowest_vcn)) {			ntfs_log_debug("$MFT has corrupt attribute list attribute. "					"Run chkdsk.\n");			goto io_error_exit;		}	}	if (!a) {		ntfs_log_debug("$MFT/$DATA attribute not found. $MFT is corrupt. Run "				"chkdsk.\n");		goto io_error_exit;	}	if (highest_vcn && highest_vcn != last_vcn - 1) {		ntfs_log_debug("Failed to load the complete runlist for $MFT/$DATA. "				"Bug or corrupt $MFT. Run chkdsk.\n");		ntfs_log_debug("highest_vcn = 0x%llx, last_vcn - 1 = 0x%llx\n",				(long long)highest_vcn, (long long)last_vcn - 1);		goto io_error_exit;	}	/* Done with the $Mft mft record. */	ntfs_attr_put_search_ctx(ctx);	ctx = NULL;	/*	 * The volume is now setup so we can use all read access functions.	 */	vol->mftbmp_na = ntfs_attr_open(vol->mft_ni, AT_BITMAP, AT_UNNAMED, 0);	if (!vol->mftbmp_na) {		ntfs_log_perror("Failed to open $MFT/$BITMAP");		goto error_exit;	}	return 0;io_error_exit:	errno = EIO;error_exit:	eo = errno;	if (ctx)		ntfs_attr_put_search_ctx(ctx);	if (vol->mft_na) {		ntfs_attr_close(vol->mft_na);		vol->mft_na = NULL;	}	if (vol->mft_ni) {		ntfs_inode_close(vol->mft_ni);		vol->mft_ni = NULL;	}	errno = eo;	return -1;}/** * ntfs_mftmirr_load - load the $MFTMirr and setup the ntfs volume with it * @vol:	ntfs volume whose $MFTMirr to load * * Load $MFTMirr from @vol and setup @vol with it. After calling this function * the volume @vol is ready for use by all write access functions provided by * the ntfs library (assuming ntfs_mft_load() has been called successfully * beforehand). * * Return 0 on success and -1 on error with errno set to the error code. */static int ntfs_mftmirr_load(ntfs_volume *vol){	int i;	runlist_element rl[2];	vol->mftmirr_ni = ntfs_inode_open(vol, FILE_MFTMirr);	if (!vol->mftmirr_ni) {		ntfs_log_perror("Failed to open inode $MFTMirr");		return -1;	}	/* Get an ntfs attribute for $MFTMirr/$DATA, too. */	vol->mftmirr_na = ntfs_attr_open(vol->mftmirr_ni, AT_DATA, AT_UNNAMED, 0);	if (!vol->mftmirr_na) {		ntfs_log_perror("Failed to open $MFTMirr/$DATA");		goto error_exit;	}	if (ntfs_attr_map_runlist(vol->mftmirr_na, 0) < 0) {		ntfs_log_perror("Failed to map runlist of $MFTMirr/$DATA");		goto error_exit;	}	/* Construct the mft mirror runlist. */	rl[0].vcn = 0;	rl[0].lcn = vol->mftmirr_lcn;	rl[0].length = (vol->mftmirr_size * vol->mft_record_size +			vol->cluster_size - 1) / vol->cluster_size;	rl[1].vcn = rl[0].length;	rl[1].lcn = LCN_ENOENT;	rl[1].length = 0;	/* Compare the two runlists. They must be identical. */	i = 0;	do {		if (rl[i].vcn != vol->mftmirr_na->rl[i].vcn ||				rl[i].lcn != vol->mftmirr_na->rl[i].lcn ||				rl[i].length != vol->mftmirr_na->rl[i].length) {			ntfs_log_debug("Error: $MFTMirr location mismatch! Run "					"chkdsk.\n");			errno = EIO;			goto error_exit;		}	} while (rl[i++].length);	return 0;error_exit:	i = errno;	if (vol->mftmirr_na) {		ntfs_attr_close(vol->mftmirr_na);		vol->mftmirr_na = NULL;	}	ntfs_inode_close(vol->mftmirr_ni);	vol->mftmirr_ni = NULL;	errno = i;	return -1;}/** * ntfs_volume_startup - allocate and setup an ntfs volume * @dev:	device to open * @flags:	optional mount flags * * Load, verify, and parse bootsector; load and setup $MFT and $MFTMirr. After * calling this function, the volume is setup sufficiently to call all read * and write access functions provided by the library. * * Return the allocated volume structure on success and NULL on error with * errno set to the error code. */ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, unsigned long flags){	LCN mft_zone_size, mft_lcn;	s64 br;	ntfs_volume *vol;	NTFS_BOOT_SECTOR *bs;	int eo;#ifndef NTFS_DISABLE_DEBUG_LOGGING	const char *OK = "OK\n";	const char *FAILED = "FAILED\n";	BOOL debug = 1;#else	BOOL debug = 0;#endif	if (!dev || !dev->d_ops || !dev->d_name) {		errno = EINVAL;		return NULL;	}	/* Allocate the boot sector structure. */	if (!(bs = (NTFS_BOOT_SECTOR *)malloc(sizeof(NTFS_BOOT_SECTOR))))		return NULL;	/* Allocate the volume structure. */	vol = ntfs_volume_alloc();	if (!vol)		goto error_exit;	/* Create the default upcase table. */	vol->upcase_len = 65536;	vol->upcase = (ntfschar*)malloc(vol->upcase_len * sizeof(ntfschar));	if (!vol->upcase) {		ntfs_log_perror("Error allocating memory for upcase table.");		goto error_exit;	}	ntfs_upcase_table_build(vol->upcase,			vol->upcase_len * sizeof(ntfschar));	if (flags & MS_RDONLY)		NVolSetReadOnly(vol);	if (flags & MS_NOATIME)		NVolSetNoATime(vol);	ntfs_log_debug("Reading bootsector... ");	if (dev->d_ops->open(dev, NVolReadOnly(vol) ? O_RDONLY: O_RDWR)) {		ntfs_log_debug(FAILED);		ntfs_log_perror("Error opening partition device");		goto error_exit;	}	/* Attach the device to the volume. */	vol->dev = dev;	/* Now read the bootsector. */	br = ntfs_pread(dev, 0, sizeof(NTFS_BOOT_SECTOR), bs);	if (br != sizeof(NTFS_BOOT_SECTOR)) {		ntfs_log_debug(FAILED);		if (br != -1)			errno = EINVAL;		if (!br)			ntfs_log_debug("Error: partition is smaller than bootsector "					"size. Weird!\n");		else			ntfs_log_perror("Error reading bootsector");		goto error_exit;	}	ntfs_log_debug(OK);	if (!ntfs_boot_sector_is_ntfs(bs, !debug)) {		ntfs_log_debug("Error: %s is not a valid NTFS partition!\n",				dev->d_name);		errno = EINVAL;		goto error_exit;	}	if (ntfs_boot_sector_parse(vol, bs) < 0) {		ntfs_log_perror("Failed to parse ntfs bootsector");		goto error_exit;	}	free(bs);	bs = NULL;	/* Now set the device block size to the sector size. */	if (ntfs_device_block_size_set(vol->dev, vol->sector_size))		ntfs_log_debug("Failed to set the device block size to the "				"sector size.  This may affect performance "				"but should be harmless otherwise.  Error: "

⌨️ 快捷键说明

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