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

📄 mft.c

📁 上一个上传的有问题,这个是好的。visopsys包括系统内核和GUI的全部SOURCE code ,还包括一些基本的docs文档。里面src子目录对应所有SOURCE code.对于想研究操作系统的朋
💻 C
📖 第 1 页 / 共 4 页
字号:
/** * mft.c - Mft record handling code. Part of the Linux-NTFS project. * * Copyright (c) 2000-2004 Anton Altaparmakov * Copyright (c)      2005 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 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_ERRNO_H#include <errno.h>#endif#ifdef HAVE_STRING_H#include <string.h>#endif#include <time.h>#include "compat.h"#include "types.h"#include "device.h"#include "debug.h"#include "bitmap.h"#include "attrib.h"#include "inode.h"#include "volume.h"#include "layout.h"#include "lcnalloc.h"#include "mft.h"#include "logging.h"/** * ntfs_mft_records_read - read records from the mft from disk * @vol:	volume to read from * @mref:	starting mft record number to read * @count:	number of mft records to read * @b:		output data buffer * * Read @count mft records starting at @mref from volume @vol into buffer * @b. Return 0 on success or -1 on error, with errno set to the error * code. * * If any of the records exceed the initialized size of the $MFT/$DATA * attribute, i.e. they cannot possibly be allocated mft records, assume this * is a bug and return error code ESPIPE. * * The read mft records are mst deprotected and are hence ready to use. The * caller should check each record with is_baad_record() in case mst * deprotection failed. * * NOTE: @b has to be at least of size @count * vol->mft_record_size. */int ntfs_mft_records_read(const ntfs_volume *vol, const MFT_REF mref,		const s64 count, MFT_RECORD *b){	s64 br;	VCN m;	ntfs_log_trace("Entering for inode 0x%llx.\n", MREF(mref));	if (!vol || !vol->mft_na || !b || count < 0) {		errno = EINVAL;		return -1;	}	m = MREF(mref);	/* Refuse to read non-allocated mft records. */	if (m + count > vol->mft_na->initialized_size >>			vol->mft_record_size_bits) {		errno = ESPIPE;		return -1;	}	br = ntfs_attr_mst_pread(vol->mft_na, m << vol->mft_record_size_bits,			count, vol->mft_record_size, b);	if (br != count) {		if (br != -1)			errno = EIO;		if (br >= 0)			ntfs_log_debug("Error: partition is smaller than it should "					"be!\n");		else			ntfs_log_perror("Error reading $Mft record(s)");		return -1;	}	return 0;}/** * ntfs_mft_records_write - write mft records to disk * @vol:	volume to write to * @mref:	starting mft record number to write * @count:	number of mft records to write * @b:		data buffer containing the mft records to write * * Write @count mft records starting at @mref from data buffer @b to volume * @vol. Return 0 on success or -1 on error, with errno set to the error code. * * If any of the records exceed the initialized size of the $MFT/$DATA * attribute, i.e. they cannot possibly be allocated mft records, assume this * is a bug and return error code ESPIPE. * * Before the mft records are written, they are mst protected. After the write, * they are deprotected again, thus resulting in an increase in the update * sequence number inside the data buffer @b. * * If any mft records are written which are also represented in the mft mirror * $MFTMirr, we make a copy of the relevant parts of the data buffer @b into a * temporary buffer before we do the actual write. Then if at least one mft * record was successfully written, we write the appropriate mft records from * the copied buffer to the mft mirror, too. */int ntfs_mft_records_write(const ntfs_volume *vol, const MFT_REF mref,		const s64 count, MFT_RECORD *b){	s64 bw;	VCN m;	void *bmirr = NULL;	int cnt = 0, res = 0;	ntfs_log_trace("Entering for inode 0x%llx.\n", MREF(mref));	if (!vol || !vol->mft_na || vol->mftmirr_size <= 0 || !b || count < 0) {		errno = EINVAL;		return -1;	}	m = MREF(mref);	/* Refuse to write non-allocated mft records. */	if (m + count > vol->mft_na->initialized_size >>			vol->mft_record_size_bits) {		errno = ESPIPE;		return -1;	}	if (m < vol->mftmirr_size) {		if (!vol->mftmirr_na) {			errno = EINVAL;			return -1;		}		cnt = vol->mftmirr_size - m;		if (cnt > count)			cnt = count;		bmirr = malloc(cnt * vol->mft_record_size);		if (!bmirr)			return -1;		memcpy(bmirr, b, cnt * vol->mft_record_size);	}	bw = ntfs_attr_mst_pwrite(vol->mft_na, m << vol->mft_record_size_bits,			count, vol->mft_record_size, b);	if (bw != count) {		if (bw != -1)			errno = EIO;		if (bw >= 0)			ntfs_log_debug("Error: partial write while writing $Mft "					"record(s)!\n");		else			ntfs_log_perror("Error writing $Mft record(s)");		res = errno;	}	if (bmirr && bw > 0) {		if (bw < cnt)			cnt = bw;		bw = ntfs_attr_mst_pwrite(vol->mftmirr_na,				m << vol->mft_record_size_bits, cnt,				vol->mft_record_size, bmirr);		if (bw != cnt) {			if (bw != -1)				errno = EIO;			ntfs_log_debug("Error: failed to sync $MFTMirr! Run "					"chkdsk.\n");			res = errno;		}	}	if (bmirr)		free(bmirr);	if (!res)		return res;	errno = res;	return -1;}/** * ntfs_file_record_read - read a FILE record from the mft from disk * @vol:	volume to read from * @mref:	mft reference specifying mft record to read * @mrec:	address of pointer in which to return the mft record * @attr:	address of pointer in which to return the first attribute * * Read a FILE record from the mft of @vol from the storage medium. @mref * specifies the mft record to read, including the sequence number, which can * be 0 if no sequence number checking is to be performed. * * The function allocates a buffer large enough to hold the mft record and * reads the record into the buffer (mst deprotecting it in the process). * *@mrec is then set to point to the buffer. * * If @attr is not NULL, *@attr is set to point to the first attribute in the * mft record, i.e. *@attr is a pointer into *@mrec. * * Return 0 on success, or -1 on error, with errno set to the error code. * * The read mft record is checked for having the magic FILE, * and for having a matching sequence number (if MSEQNO(*@mref) != 0). * If either of these fails, -1 is returned and errno is set to EIO. If you get * this, but you still want to read the mft record (e.g. in order to correct * it), use ntfs_mft_record_read() directly. * * Note: Caller has to free *@mrec when finished. * * Note: We do not check if the mft record is flagged in use. The caller can *	 check if desired. */int ntfs_file_record_read(const ntfs_volume *vol, const MFT_REF mref,		MFT_RECORD **mrec, ATTR_RECORD **attr){	MFT_RECORD *m;	ATTR_RECORD *a;	int err;	if (!vol || !mrec) {		errno = EINVAL;		return -1;	}	m = *mrec;	if (!m) {		m = (MFT_RECORD*)malloc(vol->mft_record_size);		if (!m)			return -1;	}	if (ntfs_mft_record_read(vol, mref, m)) {		err = errno;		goto read_failed;	}	if (!ntfs_is_file_record(m->magic))		goto file_corrupt;	if (MSEQNO(mref) && MSEQNO(mref) != le16_to_cpu(m->sequence_number))		goto file_corrupt;	a = (ATTR_RECORD*)((char*)m + le16_to_cpu(m->attrs_offset));	if (p2n(a) < p2n(m) || (char*)a > (char*)m + vol->mft_record_size)		goto file_corrupt;	*mrec = m;	if (attr)		*attr = a;	return 0;file_corrupt:	ntfs_log_debug("ntfs_file_record_read(): file is corrupt.\n");	err = EIO;read_failed:	if (m != *mrec)		free(m);	errno = err;	return -1;}/** * ntfs_mft_record_layout - layout an mft record into a memory buffer * @vol:	volume to which the mft record will belong * @mref:	mft reference specifying the mft record number * @mrec:	destination buffer of size >= @vol->mft_record_size bytes * * Layout an empty, unused mft record with the mft reference @mref into the * buffer @m.  The volume @vol is needed because the mft record structure was * modified in NTFS 3.1 so we need to know which volume version this mft record * will be used on. * * On success return 0 and on error return -1 with errno set to the error code. */int ntfs_mft_record_layout(const ntfs_volume *vol, const MFT_REF mref,		MFT_RECORD *mrec){	ATTR_RECORD *a;	if (!vol || !mrec) {		errno = EINVAL;		return -1;	}	/* Aligned to 2-byte boundary. */	if (vol->major_ver < 3 || (vol->major_ver == 3 && !vol->minor_ver))		mrec->usa_ofs = cpu_to_le16((sizeof(MFT_RECORD_OLD) + 1) & ~1);	else {		/* Abort if mref is > 32 bits. */		if (MREF(mref) & 0x0000ffff00000000ull) {			ntfs_log_debug("Mft reference exceeds 32 bits!\n");			errno = ERANGE;			return -1;		}		mrec->usa_ofs = cpu_to_le16((sizeof(MFT_RECORD) + 1) & ~1);		/*		 * Set the NTFS 3.1+ specific fields while we know that the		 * volume version is 3.1+.		 */		mrec->reserved = cpu_to_le16(0);		mrec->mft_record_number = cpu_to_le32(MREF(mref));	}	mrec->magic = magic_FILE;	if (vol->mft_record_size >= NTFS_BLOCK_SIZE)		mrec->usa_count = cpu_to_le16(vol->mft_record_size /				NTFS_BLOCK_SIZE + 1);	else {		mrec->usa_count = cpu_to_le16(1);		ntfs_log_error("Sector size is bigger than MFT record size.  "				"Setting usa_count to 1.  If Windows chkdsk "				"reports this as corruption, please email %s "				"stating that you saw this message and that "				"the file system created was corrupt.  "				"Thank you.\n", NTFS_DEV_LIST);	}	/* Set the update sequence number to 1. */	*(u16*)((u8*)mrec + le16_to_cpu(mrec->usa_ofs)) = cpu_to_le16(1);	mrec->lsn = cpu_to_le64(0ull);	mrec->sequence_number = cpu_to_le16(1);	mrec->link_count = cpu_to_le16(0);	/* Aligned to 8-byte boundary. */	mrec->attrs_offset = cpu_to_le16((le16_to_cpu(mrec->usa_ofs) +			(le16_to_cpu(mrec->usa_count) << 1) + 7) & ~7);	mrec->flags = cpu_to_le16(0);	/*	 * Using attrs_offset plus eight bytes (for the termination attribute),	 * aligned to 8-byte boundary.	 */	mrec->bytes_in_use = cpu_to_le32((le16_to_cpu(mrec->attrs_offset) + 8 +			7) & ~7);	mrec->bytes_allocated = cpu_to_le32(vol->mft_record_size);	mrec->base_mft_record = cpu_to_le64((MFT_REF)0);	mrec->next_attr_instance = cpu_to_le16(0);	a = (ATTR_RECORD*)((u8*)mrec + le16_to_cpu(mrec->attrs_offset));	a->type = AT_END;	a->length = cpu_to_le32(0);	/* Finally, clear the unused part of the mft record. */	memset((u8*)a + 8, 0, vol->mft_record_size - ((u8*)a + 8 - (u8*)mrec));	return 0;}/** * ntfs_mft_record_format - format an mft record on an ntfs volume * @vol:	volume on which to format the mft record * @mref:	mft reference specifying mft record to format * * Format the mft record with the mft reference @mref in $MFT/$DATA, i.e. lay * out an empty, unused mft record in memory and write it to the volume @vol. * * On success return 0 and on error return -1 with errno set to the error code. */int ntfs_mft_record_format(const ntfs_volume *vol, const MFT_REF mref){	MFT_RECORD *m;	int err;	if (!vol || !vol->mft_na) {		errno = EINVAL;		return -1;	}	m = malloc(vol->mft_record_size);	if (!m)		return -1;	if (ntfs_mft_record_layout(vol, mref, m)) {		err = errno;		free(m);		errno = err;		return -1;	}	if (ntfs_mft_record_write(vol, mref, m)) {		err = errno;		free(m);		errno = err;		return -1;	}	free(m);	return 0;}#ifndef NTFS_DISABLE_DEBUG_LOGGINGstatic const char *es = "  Leaving inconsistent metadata.  Run chkdsk.";#endif/** * ntfs_ffz - Find the first unset (zero) bit in a word * @word: * * Description... * * Returns: */static inline unsigned int ntfs_ffz(unsigned int word){	return ffs(~word) - 1;}#ifndef PAGE_SIZE#define PAGE_SIZE 4096#endif/** * ntfs_mft_bitmap_find_free_rec - find a free mft record in the mft bitmap * @vol:	volume on which to search for a free mft record * @base_ni:	open base inode if allocating an extent mft record or NULL * * Search for a free mft record in the mft bitmap attribute on the ntfs volume * @vol. * * If @base_ni is NULL start the search at the default allocator position. * * If @base_ni is not NULL start the search at the mft record after the base * mft record @base_ni. * * Return the free mft record on success and -1 on error with errno set to the * error code.  An error code of ENOSPC means that there are no free mft * records in the currently initialized mft bitmap. */static int ntfs_mft_bitmap_find_free_rec(ntfs_volume *vol, ntfs_inode *base_ni){	s64 pass_end, ll, data_pos, pass_start, ofs, bit;	ntfs_attr *mftbmp_na;	u8 *buf, *byte;	unsigned int size;	u8 pass, b;	mftbmp_na = vol->mftbmp_na;	/*	 * Set the end of the pass making sure we do not overflow the mft	 * bitmap.	 */	size = PAGE_SIZE;	pass_end = vol->mft_na->allocated_size >> vol->mft_record_size_bits;	ll = mftbmp_na->initialized_size << 3;	if (pass_end > ll)		pass_end = ll;	pass = 1;	if (!base_ni)		data_pos = vol->mft_data_pos;	else		data_pos = base_ni->mft_no + 1;	if (data_pos < 24)		data_pos = 24;	if (data_pos >= pass_end) {		data_pos = 24;		pass = 2;		/* This happens on a freshly formatted volume. */		if (data_pos >= pass_end) {			errno = ENOSPC;			return -1;		}	}	pass_start = data_pos;	buf = (u8*)malloc(PAGE_SIZE);	if (!buf)		return -1;	ntfs_log_debug("Starting bitmap search: pass %u, pass_start 0x%llx, "			"pass_end 0x%llx, data_pos 0x%llx.\n", pass,			(long long)pass_start, (long long)pass_end,			(long long)data_pos);#ifndef NTFS_DISABLE_DEBUG_LOGGING	byte = NULL;	b = 0;#endif	/* Loop until a free mft record is found. */	for (; pass <= 2; size = PAGE_SIZE) {		/* Cap size to pass_end. */		ofs = data_pos >> 3;		ll = ((pass_end + 7) >> 3) - ofs;		if (size > ll)			size = ll;		ll = ntfs_attr_pread(mftbmp_na, ofs, size, buf);		if (ll < 0) {			ntfs_log_error("Failed to read mft bitmap "					"attribute, aborting.\n");			free(buf);			return -1;		}		ntfs_log_debug("Read 0x%llx bytes.\n", (long long)ll);		/* If we read at least one byte, search @buf for a zero bit. */		if (ll) {

⌨️ 快捷键说明

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