inode.c

来自「LINUX下读写NTFS分区的工具。 已经集成了通过LIBCONV库支持中文的」· C语言 代码 · 共 1,184 行 · 第 1/3 页

C
1,184
字号
			(unsigned long long)mft_no,			(unsigned long long)base_ni->mft_no);		/* Is the extent inode already open and attached to the base inode? */	if (base_ni->nr_extents > 0) {		extent_nis = base_ni->extent_nis;		for (i = 0; i < base_ni->nr_extents; i++) {			u16 seq_no;			ni = extent_nis[i];			if (mft_no != ni->mft_no)				continue;			/* Verify the sequence number if given. */			seq_no = MSEQNO_LE(mref);			if (seq_no && seq_no != le16_to_cpu(					ni->mrec->sequence_number)) {				errno = EIO;				ntfs_log_perror("Found stale extent mft "					"reference mft=%lld",					(long long)ni->mft_no);				goto out;			}			goto out;		}	}	/* Wasn't there, we need to load the extent inode. */	ni = __ntfs_inode_allocate(base_ni->vol);	if (!ni)		goto out;	if (ntfs_file_record_read(base_ni->vol, le64_to_cpu(mref), &ni->mrec,			NULL)) {		ntfs_log_perror("ntfs_file_record_read failed #2");		goto err_out;	}	ni->mft_no = mft_no;	ni->nr_extents = -1;	ni->base_ni = base_ni;	/* Attach extent inode to base inode, reallocating memory if needed. */	if (!(base_ni->nr_extents & 3)) {		i = (base_ni->nr_extents + 4) * sizeof(ntfs_inode *);		extent_nis = ntfs_malloc(i);		if (!extent_nis)			goto err_out;		if (base_ni->nr_extents) {			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;out:	ntfs_log_leave("\n");	return ni;err_out:	__ntfs_inode_release(ni);	ni = NULL;	goto out;}/** * ntfs_inode_attach_all_extents - attach all extents for target inode * @ni:		opened ntfs inode for which perform attach * * Return 0 on success and -1 on error with errno set to the error code. */int ntfs_inode_attach_all_extents(ntfs_inode *ni){	ATTR_LIST_ENTRY *ale;	u64 prev_attached = 0;	if (!ni) {		ntfs_log_trace("Invalid arguments.\n");		errno = EINVAL;		return -1;	}	if (ni->nr_extents == -1)		ni = ni->base_ni;	ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no);	/* Inode haven't got attribute list, thus nothing to attach. */	if (!NInoAttrList(ni))		return 0;	if (!ni->attr_list) {		ntfs_log_trace("Corrupt in-memory struct.\n");		errno = EINVAL;		return -1;	}	/* Walk through attribute list and attach all extents. */	errno = 0;	ale = (ATTR_LIST_ENTRY *)ni->attr_list;	while ((u8*)ale < ni->attr_list + ni->attr_list_size) {		if (ni->mft_no != MREF_LE(ale->mft_reference) &&				prev_attached != MREF_LE(ale->mft_reference)) {			if (!ntfs_extent_inode_open(ni, ale->mft_reference)) {				ntfs_log_trace("Couldn't attach extent inode.\n");				return -1;			}			prev_attached = MREF_LE(ale->mft_reference);		}		ale = (ATTR_LIST_ENTRY *)((u8*)ale + le16_to_cpu(ale->length));	}	return 0;}/** * ntfs_inode_sync_standard_information - update standard information attribute * @ni:		ntfs inode to update standard information * * Return 0 on success or -1 on error with errno set to the error code. */static int ntfs_inode_sync_standard_information(ntfs_inode *ni){	ntfs_attr_search_ctx *ctx;	STANDARD_INFORMATION *std_info;	int err;	ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no);	ctx = ntfs_attr_get_search_ctx(ni, NULL);	if (!ctx)		return -1;	if (ntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED,				0, CASE_SENSITIVE, 0, NULL, 0, ctx)) {		err = errno;		ntfs_log_trace("Failed to receive STANDARD_INFORMATION "				"attribute.\n");		ntfs_attr_put_search_ctx(ctx);		errno = err;		return -1;	}	std_info = (STANDARD_INFORMATION *)((u8 *)ctx->attr +			le16_to_cpu(ctx->attr->value_offset));	std_info->file_attributes = ni->flags;	std_info->creation_time = utc2ntfs(ni->creation_time);	std_info->last_data_change_time = utc2ntfs(ni->last_data_change_time);	std_info->last_mft_change_time = utc2ntfs(ni->last_mft_change_time);	std_info->last_access_time = utc2ntfs(ni->last_access_time);	ntfs_inode_mark_dirty(ctx->ntfs_ino);	ntfs_attr_put_search_ctx(ctx);	return 0;}/** * ntfs_inode_sync_file_name - update FILE_NAME attributes * @ni:		ntfs inode to update FILE_NAME attributes * * Update all FILE_NAME attributes for inode @ni in the index. * * Return 0 on success or -1 on error with errno set to the error code. */static int ntfs_inode_sync_file_name(ntfs_inode *ni){	ntfs_attr_search_ctx *ctx = NULL;	ntfs_index_context *ictx;	ntfs_inode *index_ni;	FILE_NAME_ATTR *fn;	int err = 0;	ntfs_log_trace("Entering for inode %lld\n", (long long)ni->mft_no);	ctx = ntfs_attr_get_search_ctx(ni, NULL);	if (!ctx) {		err = errno;		goto err_out;	}	/* Walk through all FILE_NAME attributes and update them. */	while (!ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, 0, 0, NULL, 0, ctx)) {		fn = (FILE_NAME_ATTR *)((u8 *)ctx->attr +				le16_to_cpu(ctx->attr->value_offset));		if (MREF_LE(fn->parent_directory) == ni->mft_no) {			/*			 * WARNING: We cheat here and obtain 2 attribute			 * search contexts for one inode (first we obtained			 * above, second will be obtained inside			 * ntfs_index_lookup), it's acceptable for library,			 * but will deadlock in the kernel.			 */			index_ni = ni;		} else			index_ni = ntfs_inode_open(ni->vol, 					le64_to_cpu(fn->parent_directory));		if (!index_ni) {			if (!err)				err = errno;			ntfs_log_perror("Failed to open inode %lld with index",				(long long)le64_to_cpu(fn->parent_directory));			continue;		}		ictx = ntfs_index_ctx_get(index_ni, NTFS_INDEX_I30, 4);		if (!ictx) {			if (!err)				err = errno;			ntfs_log_perror("Failed to get index ctx, inode %lld",					(long long)index_ni->mft_no);			if (ni != index_ni && ntfs_inode_close(index_ni) && !err)				err = errno;			continue;		}		if (ntfs_index_lookup(fn, sizeof(FILE_NAME_ATTR), ictx)) {			if (!err) {				if (errno == ENOENT)					err = EIO;				else					err = errno;			}			ntfs_log_perror("Index lookup failed, inode %lld",					(long long)index_ni->mft_no);			ntfs_index_ctx_put(ictx);			if (ni != index_ni && ntfs_inode_close(index_ni) && !err)				err = errno;			continue;		}		/* Update flags and file size. */		fn = (FILE_NAME_ATTR *)ictx->data;		fn->file_attributes =				(fn->file_attributes & ~FILE_ATTR_VALID_FLAGS) |				(ni->flags & FILE_ATTR_VALID_FLAGS);		fn->allocated_size = cpu_to_sle64(ni->allocated_size);		fn->data_size = cpu_to_sle64(ni->data_size);		fn->creation_time = utc2ntfs(ni->creation_time);		fn->last_data_change_time = utc2ntfs(ni->last_data_change_time);		fn->last_mft_change_time = utc2ntfs(ni->last_mft_change_time);		fn->last_access_time = utc2ntfs(ni->last_access_time);		ntfs_index_entry_mark_dirty(ictx);		ntfs_index_ctx_put(ictx);		if ((ni != index_ni) && ntfs_inode_close(index_ni) && !err)			err = errno;	}	/* Check for real error occurred. */	if (errno != ENOENT) {		err = errno;		ntfs_log_perror("Attribute lookup failed, inode %lld",				(long long)ni->mft_no);		goto err_out;	}	ntfs_attr_put_search_ctx(ctx);	if (err) {		errno = err;		return -1;	}	return 0;err_out:	if (ctx)		ntfs_attr_put_search_ctx(ctx);	errno = err;	return -1;}/** * ntfs_inode_sync - write the inode (and its dirty extents) to disk * @ni:		ntfs inode to write * * Write the inode @ni to disk as well as its dirty extent inodes if such * exist and @ni is a base inode. If @ni is an extent inode, only @ni is * written completely disregarding its base inode and any other extent inodes. * * For a base inode with dirty extent inodes if any writes fail for whatever * reason, the failing inode is skipped and the sync process is continued. At * the end the error condition that brought about the failure is returned. Thus * the smallest amount of data loss possible occurs. * * Return 0 on success or -1 on error with errno set to the error code. * The following error codes are defined: *	EINVAL	- Invalid arguments were passed to the function. *	EBUSY	- Inode and/or one of its extents is busy, try again later. *	EIO	- I/O error while writing the inode (or one of its extents). */int ntfs_inode_sync(ntfs_inode *ni){	int ret = 0;	int err = 0;	if (!ni) {		errno = EINVAL;		ntfs_log_error("Failed to sync NULL inode\n");		return -1;	}	ntfs_log_enter("Entering for inode %lld\n", (long long)ni->mft_no);	/* Update STANDARD_INFORMATION. */	if ((ni->mrec->flags & MFT_RECORD_IN_USE) && ni->nr_extents != -1 &&			ntfs_inode_sync_standard_information(ni)) {		if (!err || errno == EIO) {			err = errno;			if (err != EIO)				err = EBUSY;		}		ntfs_log_perror("Failed to sync standard info (inode %lld)",				(long long)ni->mft_no);	}	/* Update FILE_NAME's in the index. */	if ((ni->mrec->flags & MFT_RECORD_IN_USE) && ni->nr_extents != -1 &&			NInoFileNameTestAndClearDirty(ni) &&			ntfs_inode_sync_file_name(ni)) {		if (!err || errno == EIO) {			err = errno;			if (err != EIO)				err = EBUSY;		}		ntfs_log_perror("Failed to sync FILE_NAME (inode %lld)",				(long long)ni->mft_no);		NInoFileNameSetDirty(ni);	}	/* Write out attribute list from cache to disk. */	if ((ni->mrec->flags & MFT_RECORD_IN_USE) && ni->nr_extents != -1 &&			NInoAttrList(ni) && NInoAttrListTestAndClearDirty(ni)) {		ntfs_attr *na;		na = ntfs_attr_open(ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0);		if (!na) {			if (!err || errno == EIO) {				err = errno;				if (err != EIO)					err = EBUSY;				ntfs_log_perror("Attribute list sync failed "						"(open, inode %lld)",						(long long)ni->mft_no);			}			NInoAttrListSetDirty(ni);			goto sync_inode;		} 				if (na->data_size == ni->attr_list_size) {			if (ntfs_attr_pwrite(na, 0, ni->attr_list_size,				        ni->attr_list) != ni->attr_list_size) {				if (!err || errno == EIO) {					err = errno;					if (err != EIO)						err = EBUSY;					ntfs_log_perror("Attribute list sync "						"failed (write, inode %lld)",						(long long)ni->mft_no);				}				NInoAttrListSetDirty(ni);			}		} else {			err = EIO;			ntfs_log_error("Attribute list sync failed (bad size, "				       "inode %lld)\n", (long long)ni->mft_no);			NInoAttrListSetDirty(ni);		}		ntfs_attr_close(na);	}	sync_inode:	/* Write this inode out to the $MFT (and $MFTMirr if applicable). */	if (NInoTestAndClearDirty(ni)) {		if (ntfs_mft_record_write(ni->vol, ni->mft_no, ni->mrec)) {			if (!err || errno == EIO) {				err = errno;				if (err != EIO)					err = EBUSY;			}			NInoSetDirty(ni);			ntfs_log_perror("MFT record sync failed, inode %lld",					(long long)ni->mft_no);		}	}	/* If this is a base inode with extents write all dirty extents, too. */	if (ni->nr_extents > 0) {		s32 i;		for (i = 0; i < ni->nr_extents; ++i) {			ntfs_inode *eni;			eni = ni->extent_nis[i];			if (!NInoTestAndClearDirty(eni))				continue;						if (ntfs_mft_record_write(eni->vol, eni->mft_no, 						  eni->mrec)) {				if (!err || errno == EIO) {					err = errno;					if (err != EIO)						err = EBUSY;				}				NInoSetDirty(eni);				ntfs_log_perror("Extent MFT record sync failed,"						" inode %lld/%lld",						(long long)ni->mft_no,						(long long)eni->mft_no);			}		}	}

⌨️ 快捷键说明

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