inode.c

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

C
1,184
字号
	if (err) {		errno = err;		ret = -1;	}		ntfs_log_leave("\n");	return ret;}/** * ntfs_inode_add_attrlist - add attribute list to inode and fill it * @ni: opened ntfs inode to which add attribute list * * 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. *	EEXIST	- Attribute list already exist. *	EIO	- Input/Ouput error occurred. *	ENOMEM	- Not enough memory to perform add. */int ntfs_inode_add_attrlist(ntfs_inode *ni){	int err;	ntfs_attr_search_ctx *ctx;	u8 *al = NULL, *aln;	int al_len = 0;	ATTR_LIST_ENTRY *ale = NULL;	ntfs_attr *na;	if (!ni) {		errno = EINVAL;		ntfs_log_perror("%s", __FUNCTION__);		return -1;	}	ntfs_log_trace("inode %llu\n", (unsigned long long) ni->mft_no);	if (NInoAttrList(ni) || ni->nr_extents) {		errno = EEXIST;		ntfs_log_perror("Inode already has attribute list");		return -1;	}	/* Form attribute list. */	ctx = ntfs_attr_get_search_ctx(ni, NULL);	if (!ctx) {		err = errno;		goto err_out;	}	/* Walk through all attributes. */	while (!ntfs_attr_lookup(AT_UNUSED, NULL, 0, 0, 0, NULL, 0, ctx)) {				int ale_size;				if (ctx->attr->type == AT_ATTRIBUTE_LIST) {			err = EIO;			ntfs_log_perror("Attribute list already present");			goto put_err_out;		}				ale_size = (sizeof(ATTR_LIST_ENTRY) + sizeof(ntfschar) *					ctx->attr->name_length + 7) & ~7;		al_len += ale_size;				aln = realloc(al, al_len);		if (!aln) {			err = errno;			ntfs_log_perror("Failed to realloc %d bytes", al_len);			goto put_err_out;		}		ale = (ATTR_LIST_ENTRY *)(aln + ((u8 *)ale - al));		al = aln;				memset(ale, 0, ale_size);				/* Add attribute to attribute list. */		ale->type = ctx->attr->type;		ale->length = cpu_to_le16((sizeof(ATTR_LIST_ENTRY) +			sizeof(ntfschar) * ctx->attr->name_length + 7) & ~7);		ale->name_length = ctx->attr->name_length;		ale->name_offset = (u8 *)ale->name - (u8 *)ale;		if (ctx->attr->non_resident)			ale->lowest_vcn = ctx->attr->lowest_vcn;		else			ale->lowest_vcn = 0;		ale->mft_reference = MK_LE_MREF(ni->mft_no,			le16_to_cpu(ni->mrec->sequence_number));		ale->instance = ctx->attr->instance;		memcpy(ale->name, (u8 *)ctx->attr +				le16_to_cpu(ctx->attr->name_offset),				ctx->attr->name_length * sizeof(ntfschar));		ale = (ATTR_LIST_ENTRY *)(al + al_len);	}	/* Check for real error occurred. */	if (errno != ENOENT) {		err = errno;		ntfs_log_perror("%s: Attribute lookup failed, inode %lld",				__FUNCTION__, (long long)ni->mft_no);		goto put_err_out;	}	/* Set in-memory attribute list. */	ni->attr_list = al;	ni->attr_list_size = al_len;	NInoSetAttrList(ni);	NInoAttrListSetDirty(ni);	/* Free space if there is not enough it for $ATTRIBUTE_LIST. */	if (le32_to_cpu(ni->mrec->bytes_allocated) -			le32_to_cpu(ni->mrec->bytes_in_use) <			offsetof(ATTR_RECORD, resident_end)) {		if (ntfs_inode_free_space(ni,				offsetof(ATTR_RECORD, resident_end))) {			/* Failed to free space. */			err = errno;			ntfs_log_perror("Failed to free space for attrlist");			goto rollback;		}	}	/* Add $ATTRIBUTE_LIST to mft record. */	if (ntfs_resident_attr_record_add(ni,				AT_ATTRIBUTE_LIST, NULL, 0, NULL, 0, 0) < 0) {		err = errno;		ntfs_log_perror("Couldn't add $ATTRIBUTE_LIST to MFT");		goto rollback;	}	/* Resize it. */	na = ntfs_attr_open(ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0);	if (!na) {		err = errno;		ntfs_log_perror("Failed to open just added $ATTRIBUTE_LIST");		goto remove_attrlist_record;	}	if (ntfs_attr_truncate(na, al_len)) {		err = errno;		ntfs_log_perror("Failed to resize just added $ATTRIBUTE_LIST");		ntfs_attr_close(na);		goto remove_attrlist_record;;	}		ntfs_attr_put_search_ctx(ctx);	ntfs_attr_close(na);	return 0;remove_attrlist_record:	/* Prevent ntfs_attr_recorm_rm from freeing attribute list. */	ni->attr_list = NULL;	NInoClearAttrList(ni);	/* Remove $ATTRIBUTE_LIST record. */	ntfs_attr_reinit_search_ctx(ctx);	if (!ntfs_attr_lookup(AT_ATTRIBUTE_LIST, NULL, 0,				CASE_SENSITIVE, 0, NULL, 0, ctx)) {		if (ntfs_attr_record_rm(ctx))			ntfs_log_perror("Rollback failed to remove attrlist");	} else		ntfs_log_perror("Rollback failed to find attrlist");	/* Setup back in-memory runlist. */	ni->attr_list = al;	ni->attr_list_size = al_len;	NInoSetAttrList(ni);rollback:	/*	 * Scan attribute list for attributes that placed not in the base MFT	 * record and move them to it.	 */	ntfs_attr_reinit_search_ctx(ctx);	ale = (ATTR_LIST_ENTRY*)al;	while ((u8*)ale < al + al_len) {		if (MREF_LE(ale->mft_reference) != ni->mft_no) {			if (!ntfs_attr_lookup(ale->type, ale->name,						ale->name_length,						CASE_SENSITIVE,						sle64_to_cpu(ale->lowest_vcn),						NULL, 0, ctx)) {				if (ntfs_attr_record_move_to(ctx, ni))					ntfs_log_perror("Rollback failed to "							"move attribute");			} else				ntfs_log_perror("Rollback failed to find attr");			ntfs_attr_reinit_search_ctx(ctx);		}		ale = (ATTR_LIST_ENTRY*)((u8*)ale + le16_to_cpu(ale->length));	}	/* Remove in-memory attribute list. */	ni->attr_list = NULL;	ni->attr_list_size = 0;	NInoClearAttrList(ni);	NInoAttrListClearDirty(ni);put_err_out:	ntfs_attr_put_search_ctx(ctx);err_out:	free(al);	errno = err;	return -1;}/** * ntfs_inode_free_space - free space in the MFT record of inode * @ni:		ntfs inode in which MFT record free space * @size:	amount of space needed to free * * Return 0 on success or -1 on error with errno set to the error code. */int ntfs_inode_free_space(ntfs_inode *ni, int size){	ntfs_attr_search_ctx *ctx;	int freed, err;	if (!ni || size < 0) {		errno = EINVAL;		ntfs_log_perror("%s: ni=%p size=%d", __FUNCTION__, ni, size);		return -1;	}	ntfs_log_trace("Entering for inode %lld, size %d\n",		       (unsigned long long)ni->mft_no, size);	freed = (le32_to_cpu(ni->mrec->bytes_allocated) -				le32_to_cpu(ni->mrec->bytes_in_use));	if (size <= freed)		return 0;	ctx = ntfs_attr_get_search_ctx(ni, NULL);	if (!ctx)		return -1;	/*	 * Chkdsk complain if $STANDARD_INFORMATION is not in the base MFT	 * record. FIXME: I'm not sure in this, need to recheck. For now simply	 * do not move $STANDARD_INFORMATION at all.	 *	 * Also we can't move $ATTRIBUTE_LIST from base MFT_RECORD, so position	 * search context on first attribute after $STANDARD_INFORMATION and	 * $ATTRIBUTE_LIST.	 *	 * Why we reposition instead of simply skip this attributes during	 * enumeration? Because in case we have got only in-memory attribute	 * list ntfs_attr_lookup will fail when it will try to find	 * $ATTRIBUTE_LIST.	 */	if (ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, CASE_SENSITIVE, 0, NULL,				0, ctx)) {		if (errno != ENOENT) {			err = errno;			ntfs_log_perror("%s: attr lookup failed #2", __FUNCTION__);			goto put_err_out;		}		if (ctx->attr->type == AT_END) {			err = ENOSPC;			goto put_err_out;		}	}	while (1) {		int record_size;		/*		 * Check whether attribute is from different MFT record. If so,		 * find next, because we don't need such.		 */		while (ctx->ntfs_ino->mft_no != ni->mft_no) {			if (ntfs_attr_lookup(AT_UNUSED, NULL, 0, CASE_SENSITIVE,						0, NULL, 0, ctx)) {				err = errno;				if (errno != ENOENT) {					ntfs_log_perror("Attr lookup failed #2");				} else					err = ENOSPC;				goto put_err_out;			}		}		record_size = le32_to_cpu(ctx->attr->length);		/* Move away attribute. */		if (ntfs_attr_record_move_away(ctx, 0)) {			err = errno;			ntfs_log_perror("Failed to move out attribute #2");			break;		}		freed += record_size;		/* Check whether we done. */		if (size <= freed) {			ntfs_attr_put_search_ctx(ctx);			return 0;		}		/*		 * Reposition to first attribute after $STANDARD_INFORMATION and		 * $ATTRIBUTE_LIST (see comments upwards).		 */		ntfs_attr_reinit_search_ctx(ctx);		if (ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, CASE_SENSITIVE, 0,				NULL, 0, ctx)) {			if (errno != ENOENT) {				err = errno;				ntfs_log_perror("Attr lookup #2 failed");				break;			}			if (ctx->attr->type == AT_END) {				err = ENOSPC;				break;			}		}	}put_err_out:	ntfs_attr_put_search_ctx(ctx);	if (err == ENOSPC)		ntfs_log_trace("No attributes left that can be moved out.\n");	errno = err;	return -1;}/** * ntfs_inode_update_times - update selected time fields for ntfs inode * @ni:		ntfs inode for which update time fields * @mask:	select which time fields should be updated * * This function updates time fields to current time. Fields to update are * selected using @mask (see enum @ntfs_time_update_flags for posssible values). */void ntfs_inode_update_times(ntfs_inode *ni, ntfs_time_update_flags mask){	time_t now;	if (!ni) {		ntfs_log_error("%s(): Invalid arguments.\n", __FUNCTION__);		return;	}	if ((ni->mft_no < FILE_first_user && ni->mft_no != FILE_root) ||			NVolReadOnly(ni->vol) || !mask)		return;	now = time(NULL);	if (mask & NTFS_UPDATE_ATIME)		ni->last_access_time = now;	if (mask & NTFS_UPDATE_MTIME)		ni->last_data_change_time = now;	if (mask & NTFS_UPDATE_CTIME)		ni->last_mft_change_time = now;		NInoFileNameSetDirty(ni);	NInoSetDirty(ni);}/** * ntfs_inode_badclus_bad - check for $Badclus:$Bad data attribute * @mft_no:		mft record number where @attr is present * @attr:		attribute record used to check for the $Bad attribute * * Check if the mft record given by @mft_no and @attr contains the bad sector * list. Please note that mft record numbers describing $Badclus extent inodes * will not match the current $Badclus:$Bad check. *  * On success return 1 if the file is $Badclus:$Bad, otherwise return 0. * On error return -1 with errno set to the error code. */int ntfs_inode_badclus_bad(u64 mft_no, ATTR_RECORD *attr){	int len, ret = 0;	ntfschar *ustr;	if (!attr) {		ntfs_log_error("Invalid argument.\n");		errno = EINVAL;		return -1;	}		if (mft_no != FILE_BadClus)	       	return 0;	if (attr->type != AT_DATA)	       	return 0;	if ((ustr = ntfs_str2ucs("$Bad", &len)) == NULL) {		ntfs_log_perror("Couldn't convert '$Bad' to Unicode");		return -1;	}	if (ustr && ntfs_names_are_equal(ustr, len,			(ntfschar *)((u8 *)attr + le16_to_cpu(attr->name_offset)),			attr->name_length, 0, NULL, 0))		ret = 1;	ntfs_ucsfree(ustr);	return ret;}

⌨️ 快捷键说明

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