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

📄 mft.c

📁 LINUX下读写NTFS分区的工具。 已经集成了通过LIBCONV库支持中文的代码。
💻 C
📖 第 1 页 / 共 4 页
字号:
 */static int ntfs_mft_bitmap_extend_initialized(ntfs_volume *vol){	s64 old_data_size, old_initialized_size, ll;	ntfs_attr *mftbmp_na;	ntfs_attr_search_ctx *ctx;	ATTR_RECORD *a;	int err;	int ret = -1;	ntfs_log_enter("Entering\n");		mftbmp_na = vol->mftbmp_na;	ctx = ntfs_attr_get_search_ctx(mftbmp_na->ni, NULL);	if (!ctx)		goto out;	if (ntfs_attr_lookup(mftbmp_na->type, mftbmp_na->name,			mftbmp_na->name_len, 0, 0, NULL, 0, ctx)) {		ntfs_log_error("Failed to find first attribute extent of "				"mft bitmap attribute.\n");		err = errno;		goto put_err_out;	}	a = ctx->attr;	old_data_size = mftbmp_na->data_size;	old_initialized_size = mftbmp_na->initialized_size;	mftbmp_na->initialized_size += 8;	a->initialized_size = cpu_to_sle64(mftbmp_na->initialized_size);	if (mftbmp_na->initialized_size > mftbmp_na->data_size) {		mftbmp_na->data_size = mftbmp_na->initialized_size;		a->data_size = cpu_to_sle64(mftbmp_na->data_size);	}	/* Ensure the changes make it to disk. */	ntfs_inode_mark_dirty(ctx->ntfs_ino);	ntfs_attr_put_search_ctx(ctx);	/* Initialize the mft bitmap attribute value with zeroes. */	ll = 0;	ll = ntfs_attr_pwrite(mftbmp_na, old_initialized_size, 8, &ll);	if (ll == 8) {		ntfs_log_debug("Wrote eight initialized bytes to mft bitmap.\n");		vol->free_mft_records += (8 * 8); 		ret = 0;		goto out;	}	ntfs_log_error("Failed to write to mft bitmap.\n");	err = errno;	if (ll >= 0)		err = EIO;	/* Try to recover from the error. */	ctx = ntfs_attr_get_search_ctx(mftbmp_na->ni, NULL);	if (!ctx)		goto err_out;	if (ntfs_attr_lookup(mftbmp_na->type, mftbmp_na->name,			mftbmp_na->name_len, 0, 0, NULL, 0, ctx)) {		ntfs_log_error("Failed to find first attribute extent of "				"mft bitmap attribute.%s\n", es);put_err_out:		ntfs_attr_put_search_ctx(ctx);		goto err_out;	}	a = ctx->attr;	mftbmp_na->initialized_size = old_initialized_size;	a->initialized_size = cpu_to_sle64(old_initialized_size);	if (mftbmp_na->data_size != old_data_size) {		mftbmp_na->data_size = old_data_size;		a->data_size = cpu_to_sle64(old_data_size);	}	ntfs_inode_mark_dirty(ctx->ntfs_ino);	ntfs_attr_put_search_ctx(ctx);	ntfs_log_debug("Restored status of mftbmp: allocated_size 0x%llx, "			"data_size 0x%llx, initialized_size 0x%llx.\n",			(long long)mftbmp_na->allocated_size,			(long long)mftbmp_na->data_size,			(long long)mftbmp_na->initialized_size);err_out:	errno = err;out:	ntfs_log_leave("\n");	return ret;}/** * ntfs_mft_data_extend_allocation - extend mft data attribute * @vol:	volume on which to extend the mft data attribute * * Extend the mft data attribute on the ntfs volume @vol by 16 mft records * worth of clusters or if not enough space for this by one mft record worth * of clusters. * * Note:  Only changes allocated_size, i.e. does not touch initialized_size or * data_size. * * Return 0 on success and -1 on error with errno set to the error code. */static int ntfs_mft_data_extend_allocation(ntfs_volume *vol){	LCN lcn;	VCN old_last_vcn;	s64 min_nr, nr, ll = 0; /* silence compiler warning */	ntfs_attr *mft_na;	runlist_element *rl, *rl2;	ntfs_attr_search_ctx *ctx;	MFT_RECORD *m = NULL; /* silence compiler warning */	ATTR_RECORD *a = NULL; /* silence compiler warning */	int err, mp_size;	int ret = -1;	u32 old_alen = 0; /* silence compiler warning */	BOOL mp_rebuilt = FALSE;	ntfs_log_enter("Extending mft data allocation.\n");		mft_na = vol->mft_na;	/*	 * Determine the preferred allocation location, i.e. the last lcn of	 * the mft data attribute.  The allocated size of the mft data	 * attribute cannot be zero so we are ok to do this.	 */	rl = ntfs_attr_find_vcn(mft_na,			(mft_na->allocated_size - 1) >> vol->cluster_size_bits);		if (!rl || !rl->length || rl->lcn < 0) {		ntfs_log_error("Failed to determine last allocated "				"cluster of mft data attribute.\n");		if (rl)			errno = EIO;		goto out;	}		lcn = rl->lcn + rl->length;	ntfs_log_debug("Last lcn of mft data attribute is 0x%llx.\n", (long long)lcn);	/* Minimum allocation is one mft record worth of clusters. */	min_nr = vol->mft_record_size >> vol->cluster_size_bits;	if (!min_nr)		min_nr = 1;	/* Want to allocate 16 mft records worth of clusters. */	nr = vol->mft_record_size << 4 >> vol->cluster_size_bits;	if (!nr)		nr = min_nr;		old_last_vcn = rl[1].vcn;	do {		rl2 = ntfs_cluster_alloc(vol, old_last_vcn, nr, lcn, MFT_ZONE);		if (rl2)			break;		if (errno != ENOSPC || nr == min_nr) {			ntfs_log_perror("Failed to allocate (%lld) clusters "					"for $MFT", (long long)nr);			goto out;		}		/*		 * There is not enough space to do the allocation, but there		 * might be enough space to do a minimal allocation so try that		 * before failing.		 */		nr = min_nr;		ntfs_log_debug("Retrying mft data allocation with minimal cluster "				"count %lli.\n", (long long)nr);	} while (1);		ntfs_log_debug("Allocated %lli clusters.\n", nr);		rl = ntfs_runlists_merge(mft_na->rl, rl2);	if (!rl) {		err = errno;		ntfs_log_error("Failed to merge runlists for mft data "				"attribute.\n");		if (ntfs_cluster_free_from_rl(vol, rl2))			ntfs_log_error("Failed to deallocate clusters "					"from the mft data attribute.%s\n", es);		free(rl2);		errno = err;		goto out;	}	mft_na->rl = rl;		/* Find the last run in the new runlist. */	for (; rl[1].length; rl++)		;	/* Update the attribute record as well. */	ctx = ntfs_attr_get_search_ctx(mft_na->ni, NULL);	if (!ctx)		goto undo_alloc;	if (ntfs_attr_lookup(mft_na->type, mft_na->name, mft_na->name_len, 0,			rl[1].vcn, NULL, 0, ctx)) {		ntfs_log_error("Failed to find last attribute extent of "				"mft data attribute.\n");		goto undo_alloc;	}	m = ctx->mrec;	a = ctx->attr;	ll = sle64_to_cpu(a->lowest_vcn);	rl2 = ntfs_attr_find_vcn(mft_na, ll);	if (!rl2 || !rl2->length) {		ntfs_log_error("Failed to determine previous last "				"allocated cluster of mft data attribute.\n");		if (rl2)			errno = EIO;		goto undo_alloc;	}	/* Get the size for the new mapping pairs array for this extent. */	mp_size = ntfs_get_size_for_mapping_pairs(vol, rl2, ll);	if (mp_size <= 0) {		ntfs_log_error("Get size for mapping pairs failed for "				"mft data attribute extent.\n");		goto undo_alloc;	}	/* Expand the attribute record if necessary. */	old_alen = le32_to_cpu(a->length);	if (ntfs_attr_record_resize(m, a,			mp_size + le16_to_cpu(a->mapping_pairs_offset))) {		// TODO: Deal with this by moving this extent to a new mft		// record or by starting a new extent in a new mft record.		// Note: Use the special reserved mft records and ensure that		// this extent is not required to find the mft record in		// question.		errno = EOPNOTSUPP;		ntfs_log_perror("Not enough space to extended mft data");		goto undo_alloc;	}	mp_rebuilt = TRUE;	/*	 * Generate the mapping pairs array directly into the attribute record.	 */	if (ntfs_mapping_pairs_build(vol,			(u8*)a + le16_to_cpu(a->mapping_pairs_offset), mp_size,			rl2, ll, NULL)) {		ntfs_log_error("Failed to build mapping pairs array of "				"mft data attribute.\n");		errno = EIO;		goto undo_alloc;	}	/* Update the highest_vcn. */	a->highest_vcn = cpu_to_sle64(rl[1].vcn - 1);	/*	 * We now have extended the mft data allocated_size by nr clusters.	 * Reflect this in the ntfs_attr structure and the attribute record.	 * @rl is the last (non-terminator) runlist element of mft data	 * attribute.	 */	if (a->lowest_vcn) {		/*		 * We are not in the first attribute extent, switch to it, but		 * first ensure the changes will make it to disk later.		 */		ntfs_inode_mark_dirty(ctx->ntfs_ino);		ntfs_attr_reinit_search_ctx(ctx);		if (ntfs_attr_lookup(mft_na->type, mft_na->name,				mft_na->name_len, 0, 0, NULL, 0, ctx)) {			ntfs_log_error("Failed to find first attribute "					"extent of mft data attribute.\n");			goto restore_undo_alloc;		}		a = ctx->attr;	}	mft_na->allocated_size += nr << vol->cluster_size_bits;	a->allocated_size = cpu_to_sle64(mft_na->allocated_size);	/* Ensure the changes make it to disk. */	ntfs_inode_mark_dirty(ctx->ntfs_ino);	ntfs_attr_put_search_ctx(ctx);	ret = 0;out:	ntfs_log_leave("\n");	return ret;restore_undo_alloc:	err = errno;	ntfs_attr_reinit_search_ctx(ctx);	if (ntfs_attr_lookup(mft_na->type, mft_na->name, mft_na->name_len, 0,			rl[1].vcn, NULL, 0, ctx)) {		ntfs_log_error("Failed to find last attribute extent of "				"mft data attribute.%s\n", es);		ntfs_attr_put_search_ctx(ctx);		mft_na->allocated_size += nr << vol->cluster_size_bits;		/*		 * The only thing that is now wrong is ->allocated_size of the		 * base attribute extent which chkdsk should be able to fix.		 */		errno = err;		goto out;	}	m = ctx->mrec;	a = ctx->attr;	a->highest_vcn = cpu_to_sle64(old_last_vcn - 1);	errno = err;undo_alloc:	err = errno;	if (ntfs_cluster_free(vol, mft_na, old_last_vcn, -1) < 0)		ntfs_log_error("Failed to free clusters from mft data "				"attribute.%s\n", es);	if (ntfs_rl_truncate(&mft_na->rl, old_last_vcn))		ntfs_log_error("Failed to truncate mft data attribute "				"runlist.%s\n", es);	if (mp_rebuilt) {		if (ntfs_mapping_pairs_build(vol, (u8*)a +				le16_to_cpu(a->mapping_pairs_offset),				old_alen - le16_to_cpu(a->mapping_pairs_offset),				rl2, ll, NULL))			ntfs_log_error("Failed to restore mapping pairs "					"array.%s\n", es);		if (ntfs_attr_record_resize(m, a, old_alen))			ntfs_log_error("Failed to restore attribute "					"record.%s\n", es);		ntfs_inode_mark_dirty(ctx->ntfs_ino);	}	if (ctx)		ntfs_attr_put_search_ctx(ctx);	errno = err;	goto out;}static int ntfs_mft_record_init(ntfs_volume *vol, s64 size){	int ret = -1;	ntfs_attr *mft_na, *mftbmp_na;	s64 old_data_initialized, old_data_size;	ntfs_attr_search_ctx *ctx;		ntfs_log_enter("Entering\n");		/* NOTE: Caller must sanity check vol, vol->mft_na and vol->mftbmp_na */		mft_na = vol->mft_na;	mftbmp_na = vol->mftbmp_na;		/*	 * The mft record is outside the initialized data. Extend the mft data	 * attribute until it covers the allocated record. The loop is only	 * actually traversed more than once when a freshly formatted volume	 * is first written to so it optimizes away nicely in the common case.	 */	ntfs_log_debug("Status of mft data before extension: "			"allocated_size 0x%llx, data_size 0x%llx, "			"initialized_size 0x%llx.\n",			(long long)mft_na->allocated_size,			(long long)mft_na->data_size,			(long long)mft_na->initialized_size);	while (size > mft_na->allocated_size) {		if (ntfs_mft_data_extend_allocation(vol))			goto out;		ntfs_log_debug("Status of mft data after allocation extension: "				"allocated_size 0x%llx, data_size 0x%llx, "				"initialized_size 0x%llx.\n",				(long long)mft_na->allocated_size,				(long long)mft_na->data_size,				(long long)mft_na->initialized_size);	}		old_data_initialized = mft_na->initialized_size;	old_data_size = mft_na->data_size;		/*	 * Extend mft data initialized size (and data size of course) to reach	 * the allocated mft record, formatting the mft records along the way.	 * Note: We only modify the ntfs_attr structure as that is all that is	 * needed by ntfs_mft_record_format().  We will update the attribute	 * record itself in one fell swoop later on.	 */	while (size > mft_na->initialized_size) {		s64 ll2 = mft_na->initialized_size >> vol->mft_record_size_bits;		mft_na->initialized_size += vol->mft_record_size;		if (mft_na->initialized_size > mft_na->data_size)			mft_na->data_size = mft_na->initialized_size;		ntfs_log_debug("Initializing mft record 0x%llx.\n", (long long)ll2);		if (ntfs_mft_record_format(vol, ll2) < 0) {			ntfs_log_perror("Failed to format mft record");			goto undo_data_init;		}	}		/* Update the mft data attribute record to reflect the new sizes. */	ctx = ntfs_attr_get_search_ctx(mft_na->ni, NULL);	if (!ctx)		goto undo_data_init;	if (ntfs_attr_lookup(mft_na->type, mft_na->name, mft_na->name_len, 0,			0, NULL, 0, ctx)) {		ntfs_log_error("Failed to find first attribute extent of "				"mft data attribute.\n");		ntfs_attr_put_search_ctx(ctx);		goto undo_data_init;	}	ctx->attr->initialized_size = cpu_to_sle64(mft_na->initialized_size);	ctx->attr->data_size = cpu_to_sle64(mft_na->data_size);		/* Ensure the changes make it to disk. */	ntfs_inode_mark_dirty(ctx->ntfs_ino);	ntfs_attr_put_search_ctx(ctx);	ntfs_log_debug("Status of mft data after mft record initialization: "			"allocated_size 0x%llx, data_size 0x%llx, "			"initialized_size 0x%llx.\n",			(long long)mft_na->allocated_size,			(long long)mft_na->data_size,			(long long)mft_na->initialized_size);		/* Sanity checks. */	if (mft_na->data_size > mft_na->allocated_size ||	    mft_na->initialized_size > mft_na->data_size)		NTFS_BUG("mft_na sanity checks failed");	// BUG_ON(mft_na->initialized_size > mft_na->data_size);	// BUG_ON(mft_na->data_size > mft_na->allocated_size);	

⌨️ 快捷键说明

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