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

📄 mft.c

📁 一个在linux下挂载ntfs文件系统的好工具
💻 C
📖 第 1 页 / 共 4 页
字号:
	s64 ll, bit, old_data_initialized, old_data_size;	ntfs_attr *mft_na, *mftbmp_na;	ntfs_attr_search_ctx *ctx;	MFT_RECORD *m;	ATTR_RECORD *a;	ntfs_inode *ni;	int err;	u16 seq_no, usn;	if (base_ni)		ntfs_log_trace("Entering (allocating an extent mft record for "				"base mft record 0x%llx).\n",				(long long)base_ni->mft_no);	else		ntfs_log_trace("Entering (allocating a base mft record).\n");	if (!vol || !vol->mft_na || !vol->mftbmp_na) {		errno = EINVAL;		return NULL;	}	mft_na = vol->mft_na;	mftbmp_na = vol->mftbmp_na;	bit = ntfs_mft_bitmap_find_free_rec(vol, base_ni);	if (bit >= 0) {		ntfs_log_debug("Found free record (#1), bit 0x%llx.\n",				(long long)bit);		goto found_free_rec;	}	if (errno != ENOSPC)		return NULL;	/*	 * No free mft records left.  If the mft bitmap already covers more	 * than the currently used mft records, the next records are all free,	 * so we can simply allocate the first unused mft record.	 * Note: We also have to make sure that the mft bitmap at least covers	 * the first 24 mft records as they are special and whilst they may not	 * be in use, we do not allocate from them.	 */	ll = mft_na->initialized_size >> vol->mft_record_size_bits;	if (mftbmp_na->initialized_size << 3 > ll &&			mftbmp_na->initialized_size > 3) {		bit = ll;		if (bit < 24)			bit = 24;		ntfs_log_debug("Found free record (#2), bit 0x%llx.\n",				(long long)bit);		goto found_free_rec;	}	/*	 * The mft bitmap needs to be expanded until it covers the first unused	 * mft record that we can allocate.	 * Note: The smallest mft record we allocate is mft record 24.	 */	ntfs_log_debug("Status of mftbmp before extension: 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);	if (mftbmp_na->initialized_size + 8 > mftbmp_na->allocated_size) {		/* Need to extend bitmap by one more cluster. */		ntfs_log_debug("mftbmp: initialized_size + 8 > allocated_size.\n");		if (ntfs_mft_bitmap_extend_allocation(vol))			goto err_out;		ntfs_log_debug("Status of mftbmp after allocation extension: "				"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);	}	/*	 * We now have sufficient allocated space, extend the initialized_size	 * as well as the data_size if necessary and fill the new space with	 * zeroes.	 */	bit = mftbmp_na->initialized_size << 3;	if (ntfs_mft_bitmap_extend_initialized(vol))		goto err_out;	ntfs_log_debug("Status of mftbmp after initialized extension: "			"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);	ntfs_log_debug("Found free record (#3), bit 0x%llx.\n", (long long)bit);found_free_rec:	/* @bit is the found free mft record, allocate it in the mft bitmap. */	ntfs_log_debug("At found_free_rec.\n");	if (ntfs_bitmap_set_bit(mftbmp_na, bit)) {		ntfs_log_error("Failed to allocate bit in mft bitmap.\n");		goto err_out;	}	ntfs_log_debug("Set bit 0x%llx in mft bitmap.\n", (long long)bit);	/* The mft bitmap is now uptodate.  Deal with mft data attribute now. */	ll = (bit + 1) << vol->mft_record_size_bits;	if (ll <= mft_na->initialized_size) {		ntfs_log_debug("Allocated mft record already initialized.\n");		goto mft_rec_already_initialized;	}	ntfs_log_debug("Initializing allocated mft record.\n");	/*	 * 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 (ll > mft_na->allocated_size) {		if (ntfs_mft_data_extend_allocation(vol))			goto undo_mftbmp_alloc;		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 (ll > 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);		err = ntfs_mft_record_format(vol, ll2);		if (err) {			ntfs_log_error("Failed to format mft record.\n");			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) {		ntfs_log_error("Failed to get search context.\n");		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;	}	a = ctx->attr;	a->initialized_size = cpu_to_sle64(mft_na->initialized_size);	a->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);	/* Sync MFT to minimize data loss if there won't be clean unmount. */	if (ntfs_inode_sync(mft_na->ni)) {		ntfs_log_error("Failed to sync $MFT.");		goto undo_data_init;	}mft_rec_already_initialized:	/*	 * We now have allocated and initialized the mft record.  Need to read	 * it from disk and re-format it, preserving the sequence number if it	 * is not zero as well as the update sequence number if it is not zero	 * or -1 (0xffff).	 */	m = ntfs_malloc(vol->mft_record_size);	if (!m)		goto undo_mftbmp_alloc;		if (ntfs_mft_record_read(vol, bit, m)) {		err = errno;		ntfs_log_error("Failed to read mft record.\n");		free(m);		errno = err;		goto undo_mftbmp_alloc;	}	/* Sanity check that the mft record is really not in use. */	if (ntfs_is_file_record(m->magic) && (m->flags & MFT_RECORD_IN_USE)) {		ntfs_log_error("Mft record 0x%llx was marked unused in "				"mft bitmap but is marked used itself.  "				"Corrupt filesystem or library bug!  "				"Run chkdsk immediately!\n", (long long)bit);		free(m);		errno = EIO;		goto undo_mftbmp_alloc;	}	seq_no = m->sequence_number;	usn = *(u16*)((u8*)m + le16_to_cpu(m->usa_ofs));	if (ntfs_mft_record_layout(vol, bit, m)) {		err = errno;		ntfs_log_error("Failed to re-format mft record.\n");		free(m);		errno = err;		goto undo_mftbmp_alloc;	}	if (le16_to_cpu(seq_no))		m->sequence_number = seq_no;	seq_no = le16_to_cpu(usn);	if (seq_no && seq_no != 0xffff)		*(u16*)((u8*)m + le16_to_cpu(m->usa_ofs)) = usn;	/* Set the mft record itself in use. */	m->flags |= MFT_RECORD_IN_USE;	/* Now need to open an ntfs inode for the mft record. */	ni = ntfs_inode_allocate(vol);	if (!ni) {		err = errno;		ntfs_log_error("Failed to allocate buffer for inode.\n");		free(m);		errno = err;		goto undo_mftbmp_alloc;	}	ni->mft_no = bit;	ni->mrec = m;	/*	 * If we are allocating an extent mft record, make the opened inode an	 * extent inode and attach it to the base inode.  Also, set the base	 * mft record reference in the extent inode.	 */	if (base_ni) {		ni->nr_extents = -1;		ni->base_ni = base_ni;		m->base_mft_record = MK_LE_MREF(base_ni->mft_no,				le16_to_cpu(base_ni->mrec->sequence_number));		/*		 * Attach the extent inode to the base inode, reallocating		 * memory if needed.		 */		if (!(base_ni->nr_extents & 3)) {			ntfs_inode **extent_nis;			int i;			i = (base_ni->nr_extents + 4) * sizeof(ntfs_inode *);			extent_nis = ntfs_malloc(i);			if (!extent_nis) {				free(m);				free(ni);				goto undo_mftbmp_alloc;			}			if (base_ni->extent_nis) {				memcpy(extent_nis, base_ni->extent_nis,						i - 4 * sizeof(ntfs_inode *));				free(base_ni->extent_nis);			}			base_ni->extent_nis = extent_nis;		}		base_ni->extent_nis[base_ni->nr_extents++] = ni;	}	/* Make sure the allocated inode is written out to disk later. */	ntfs_inode_mark_dirty(ni);	/* Initialize time, allocated and data size in ntfs_inode struct. */	ni->data_size = ni->allocated_size = 0;	ni->flags = 0;	ni->creation_time = ni->last_data_change_time =			ni->last_mft_change_time =			ni->last_access_time = time(NULL);	/* Update the default mft allocation position if it was used. */	if (!base_ni)		vol->mft_data_pos = bit + 1;	/* Return the opened, allocated inode of the allocated mft record. */	ntfs_log_debug("Returning opened, allocated %sinode 0x%llx.\n",			base_ni ? "extent " : "", (long long)bit);	return ni;undo_data_init:	mft_na->initialized_size = old_data_initialized;	mft_na->data_size = old_data_size;undo_mftbmp_alloc:	err = errno;	if (ntfs_bitmap_clear_bit(mftbmp_na, bit))		ntfs_log_error("Failed to clear bit in mft bitmap.%s\n", es);	errno = err;err_out:	if (!errno)		errno = EIO;	return NULL;}/** * ntfs_mft_record_free - free an mft record on an ntfs volume * @vol:	volume on which to free the mft record * @ni:		open ntfs inode of the mft record to free * * Free the mft record of the open inode @ni on the mounted ntfs volume @vol. * Note that this function calls ntfs_inode_close() internally and hence you * cannot use the pointer @ni any more after this function returns success. * * On success return 0 and on error return -1 with errno set to the error code. */int ntfs_mft_record_free(ntfs_volume *vol, ntfs_inode *ni){	u64 mft_no;	int err;	u16 seq_no, old_seq_no;	ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no);	if (!vol || !vol->mftbmp_na || !ni) {		errno = EINVAL;		return -1;	}	/* Cache the mft reference for later. */	mft_no = ni->mft_no;	/* Mark the mft record as not in use. */	ni->mrec->flags &= ~MFT_RECORD_IN_USE;	/* Increment the sequence number, skipping zero, if it is not zero. */	old_seq_no = ni->mrec->sequence_number;	seq_no = le16_to_cpu(old_seq_no);	if (seq_no == 0xffff)		seq_no = 1;	else if (seq_no)		seq_no++;	ni->mrec->sequence_number = cpu_to_le16(seq_no);	/* Set the inode dirty and write it out. */	ntfs_inode_mark_dirty(ni);	if (ntfs_inode_sync(ni)) {		err = errno;		goto sync_rollback;	}	/* Clear the bit in the $MFT/$BITMAP corresponding to this record. */	if (ntfs_bitmap_clear_bit(vol->mftbmp_na, mft_no)) {		err = errno;		// FIXME: If ntfs_bitmap_clear_run() guarantees rollback on		//	  error, this could be changed to goto sync_rollback;		goto bitmap_rollback;	}	/* Throw away the now freed inode. */	if (!ntfs_inode_close(ni))		return 0;	err = errno;	/* Rollback what we did... */bitmap_rollback:	if (ntfs_bitmap_set_bit(vol->mftbmp_na, mft_no))		ntfs_log_debug("Eeek! Rollback failed in ntfs_mft_record_free().  "				"Leaving inconsistent metadata!\n");sync_rollback:	ni->mrec->flags |= MFT_RECORD_IN_USE;	ni->mrec->sequence_number = old_seq_no;	ntfs_inode_mark_dirty(ni);	errno = err;	return -1;}/** * ntfs_mft_usn_dec - Decrement USN by one * @mrec:	pointer to an mft record * * On success return 0 and on error return -1 with errno set. */int ntfs_mft_usn_dec(MFT_RECORD *mrec){	u16 usn, *usnp;	if (!mrec) {		errno = EINVAL;		return -1;	}	usnp = (u16 *)((char *)mrec + le16_to_cpu(mrec->usa_ofs));	usn = le16_to_cpup(usnp);	if (usn-- <= 1)		usn = 0xfffe;	*usnp = cpu_to_le16(usn);	return 0;}

⌨️ 快捷键说明

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