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

📄 attrib.c

📁 LINUX下读写NTFS分区的工具。 已经集成了通过LIBCONV库支持中文的代码。
💻 C
📖 第 1 页 / 共 5 页
字号:
	     (!(a->flags & ATTR_IS_SPARSE)     != !NAttrSparse(na)) ||	     (!(a->flags & ATTR_IS_ENCRYPTED)  != !NAttrEncrypted(na)))) {		errno = EIO;		ntfs_log_perror("Inode %lld has corrupt attribute flags "				"(0x%x <> 0x%x)",(unsigned long long)ni->mft_no,				a->flags, na->ni->flags);		goto put_err_out;	}	if (a->non_resident) {		if ((a->flags & ATTR_IS_COMPRESSED) && !a->compression_unit) {			errno = EIO;			ntfs_log_perror("Compressed inode %lld attr 0x%x has "					"no compression unit",					(unsigned long long)ni->mft_no, type);			goto put_err_out;		}		ntfs_attr_init(na, TRUE, a->flags & ATTR_IS_COMPRESSED,				a->flags & ATTR_IS_ENCRYPTED,				a->flags & ATTR_IS_SPARSE,				sle64_to_cpu(a->allocated_size),				sle64_to_cpu(a->data_size),				sle64_to_cpu(a->initialized_size),				cs ? sle64_to_cpu(a->compressed_size) : 0,				cs ? a->compression_unit : 0);	} else {		s64 l = le32_to_cpu(a->value_length);		ntfs_attr_init(na, FALSE, a->flags & ATTR_IS_COMPRESSED,				a->flags & ATTR_IS_ENCRYPTED,				a->flags & ATTR_IS_SPARSE, (l + 7) & ~7, l, l,				cs ? (l + 7) & ~7 : 0, 0);	}	ntfs_attr_put_search_ctx(ctx);out:	ntfs_log_leave("\n");		return na;put_err_out:	ntfs_attr_put_search_ctx(ctx);err_out:	free(na);	na = NULL;	goto out;}/** * ntfs_attr_close - free an ntfs attribute structure * @na:		ntfs attribute structure to free * * Release all memory associated with the ntfs attribute @na and then release * @na itself. */void ntfs_attr_close(ntfs_attr *na){	if (!na)		return;	if (NAttrNonResident(na) && na->rl)		free(na->rl);	/* Don't release if using an internal constant. */	if (na->name != AT_UNNAMED && na->name != NTFS_INDEX_I30)		free(na->name);	free(na);}/** * ntfs_attr_map_runlist - map (a part of) a runlist of an ntfs attribute * @na:		ntfs attribute for which to map (part of) a runlist * @vcn:	map runlist part containing this vcn * * Map the part of a runlist containing the @vcn of an the ntfs attribute @na. * * Return 0 on success and -1 on error with errno set to the error code. */int ntfs_attr_map_runlist(ntfs_attr *na, VCN vcn){	LCN lcn;	ntfs_attr_search_ctx *ctx;	ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, vcn 0x%llx.\n",		(unsigned long long)na->ni->mft_no, na->type, (long long)vcn);	lcn = ntfs_rl_vcn_to_lcn(na->rl, vcn);	if (lcn >= 0 || lcn == LCN_HOLE || lcn == LCN_ENOENT)		return 0;	ctx = ntfs_attr_get_search_ctx(na->ni, NULL);	if (!ctx)		return -1;	/* Find the attribute in the mft record. */	if (!ntfs_attr_lookup(na->type, na->name, na->name_len, CASE_SENSITIVE,			vcn, NULL, 0, ctx)) {		runlist_element *rl;		/* Decode the runlist. */		rl = ntfs_mapping_pairs_decompress(na->ni->vol, ctx->attr,				na->rl);		if (rl) {			na->rl = rl;			ntfs_attr_put_search_ctx(ctx);			return 0;		}	}		ntfs_attr_put_search_ctx(ctx);	return -1;}/** * ntfs_attr_map_whole_runlist - map the whole runlist of an ntfs attribute * @na:		ntfs attribute for which to map the runlist * * Map the whole runlist of an the ntfs attribute @na.  For an attribute made * up of only one attribute extent this is the same as calling * ntfs_attr_map_runlist(na, 0) but for an attribute with multiple extents this * will map the runlist fragments from each of the extents thus giving access * to the entirety of the disk allocation of an attribute. * * Return 0 on success and -1 on error with errno set to the error code. */int ntfs_attr_map_whole_runlist(ntfs_attr *na){	VCN next_vcn, last_vcn, highest_vcn;	ntfs_attr_search_ctx *ctx;	ntfs_volume *vol = na->ni->vol;	ATTR_RECORD *a;	int err;	ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n",			(unsigned long long)na->ni->mft_no, na->type);	ctx = ntfs_attr_get_search_ctx(na->ni, NULL);	if (!ctx)		return -1;	/* Map all attribute extents one by one. */	next_vcn = last_vcn = highest_vcn = 0;	a = NULL;	while (1) {		runlist_element *rl;		int not_mapped = 0;		if (ntfs_rl_vcn_to_lcn(na->rl, next_vcn) == LCN_RL_NOT_MAPPED)			not_mapped = 1;		if (ntfs_attr_lookup(na->type, na->name, na->name_len,				CASE_SENSITIVE, next_vcn, NULL, 0, ctx))			break;		a = ctx->attr;		if (not_mapped) {			/* Decode the runlist. */			rl = ntfs_mapping_pairs_decompress(na->ni->vol,								a, na->rl);			if (!rl)				goto err_out;			na->rl = rl;		}		/* Are we in the first extent? */		if (!next_vcn) {			 if (a->lowest_vcn) {				 errno = EIO;				 ntfs_log_perror("First extent of inode %llu "					"attribute has non-zero lowest_vcn",					(unsigned long long)na->ni->mft_no);				 goto err_out;			}			/* Get the last vcn in the attribute. */			last_vcn = sle64_to_cpu(a->allocated_size) >>					vol->cluster_size_bits;		}		/* Get the lowest vcn for the next extent. */		highest_vcn = sle64_to_cpu(a->highest_vcn);		next_vcn = highest_vcn + 1;		/* Only one extent or error, which we catch below. */		if (next_vcn <= 0) {			errno = ENOENT;			break;		}		/* Avoid endless loops due to corruption. */		if (next_vcn < sle64_to_cpu(a->lowest_vcn)) {			errno = EIO;			ntfs_log_perror("Inode %llu has corrupt attribute list",					(unsigned long long)na->ni->mft_no);			goto err_out;		}	}	if (!a) {		ntfs_log_perror("Couldn't find attribute for runlist mapping");		goto err_out;	}	if (highest_vcn && highest_vcn != last_vcn - 1) {		errno = EIO;		ntfs_log_perror("Failed to load full runlist: inode: %llu "				"highest_vcn: 0x%llx last_vcn: 0x%llx",				(unsigned long long)na->ni->mft_no, 				(long long)highest_vcn, (long long)last_vcn);		goto err_out;	}	err = errno;	ntfs_attr_put_search_ctx(ctx);	if (err == ENOENT)		return 0;out_now:	errno = err;	return -1;err_out:	err = errno;	ntfs_attr_put_search_ctx(ctx);	goto out_now;}/** * ntfs_attr_vcn_to_lcn - convert a vcn into a lcn given an ntfs attribute * @na:		ntfs attribute whose runlist to use for conversion * @vcn:	vcn to convert * * Convert the virtual cluster number @vcn of an attribute into a logical * cluster number (lcn) of a device using the runlist @na->rl to map vcns to * their corresponding lcns. * * If the @vcn is not mapped yet, attempt to map the attribute extent * containing the @vcn and retry the vcn to lcn conversion. * * Since lcns must be >= 0, we use negative return values with special meaning: * * Return value		Meaning / Description * ========================================== *  -1 = LCN_HOLE	Hole / not allocated on disk. *  -3 = LCN_ENOENT	There is no such vcn in the attribute. *  -4 = LCN_EINVAL	Input parameter error. *  -5 = LCN_EIO	Corrupt fs, disk i/o error, or not enough memory. */LCN ntfs_attr_vcn_to_lcn(ntfs_attr *na, const VCN vcn){	LCN lcn;	BOOL is_retry = FALSE;	if (!na || !NAttrNonResident(na) || vcn < 0)		return (LCN)LCN_EINVAL;	ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n", (unsigned long			long)na->ni->mft_no, na->type);retry:	/* Convert vcn to lcn. If that fails map the runlist and retry once. */	lcn = ntfs_rl_vcn_to_lcn(na->rl, vcn);	if (lcn >= 0)		return lcn;	if (!is_retry && !ntfs_attr_map_runlist(na, vcn)) {		is_retry = TRUE;		goto retry;	}	/*	 * If the attempt to map the runlist failed, or we are getting	 * LCN_RL_NOT_MAPPED despite having mapped the attribute extent	 * successfully, something is really badly wrong...	 */	if (!is_retry || lcn == (LCN)LCN_RL_NOT_MAPPED)		return (LCN)LCN_EIO;	/* lcn contains the appropriate error code. */	return lcn;}/** * ntfs_attr_find_vcn - find a vcn in the runlist of an ntfs attribute * @na:		ntfs attribute whose runlist to search * @vcn:	vcn to find * * Find the virtual cluster number @vcn in the runlist of the ntfs attribute * @na and return the the address of the runlist element containing the @vcn. * * Note you need to distinguish between the lcn of the returned runlist * element being >= 0 and LCN_HOLE. In the later case you have to return zeroes * on read and allocate clusters on write. You need to update the runlist, the * attribute itself as well as write the modified mft record to disk. * * If there is an error return NULL with errno set to the error code. The * following error codes are defined: *	EINVAL		Input parameter error. *	ENOENT		There is no such vcn in the runlist. *	ENOMEM		Not enough memory. *	EIO		I/O error or corrupt metadata. */runlist_element *ntfs_attr_find_vcn(ntfs_attr *na, const VCN vcn){	runlist_element *rl;	BOOL is_retry = FALSE;	if (!na || !NAttrNonResident(na) || vcn < 0) {		errno = EINVAL;		return NULL;	}	ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, vcn %llx\n",		       (unsigned long long)na->ni->mft_no, na->type,		       (long long)vcn);retry:	rl = na->rl;	if (!rl)		goto map_rl;	if (vcn < rl[0].vcn)		goto map_rl;	while (rl->length) {		if (vcn < rl[1].vcn) {			if (rl->lcn >= (LCN)LCN_HOLE)				return rl;			break;		}		rl++;	}	switch (rl->lcn) {	case (LCN)LCN_RL_NOT_MAPPED:		goto map_rl;	case (LCN)LCN_ENOENT:		errno = ENOENT;		break;	case (LCN)LCN_EINVAL:		errno = EINVAL;		break;	default:		errno = EIO;		break;	}	return NULL;map_rl:	/* The @vcn is in an unmapped region, map the runlist and retry. */	if (!is_retry && !ntfs_attr_map_runlist(na, vcn)) {		is_retry = TRUE;		goto retry;	}	/*	 * If we already retried or the mapping attempt failed something has	 * gone badly wrong. EINVAL and ENOENT coming from a failed mapping	 * attempt are equivalent to errors for us as they should not happen	 * in our code paths.	 */	if (is_retry || errno == EINVAL || errno == ENOENT)		errno = EIO;	return NULL;}/** * ntfs_attr_pread_i - see description at ntfs_attr_pread() */ static s64 ntfs_attr_pread_i(ntfs_attr *na, const s64 pos, s64 count, void *b){	s64 br, to_read, ofs, total, total2;	ntfs_volume *vol;	runlist_element *rl;	/* Sanity checking arguments is done in ntfs_attr_pread(). */		if (NAttrCompressed(na) && NAttrNonResident(na))		return ntfs_compressed_attr_pread(na, pos, count, b);	/*	 * Encrypted non-resident attributes are not supported.  We return	 * access denied, which is what Windows NT4 does, too.	 */	if (NAttrEncrypted(na) && NAttrNonResident(na)) {		errno = EACCES;		return -1;	}	vol = na->ni->vol;		if (!count)		return 0;	/* Truncate reads beyond end of attribute. */	if (pos + count > na->data_size) {		if (pos >= na->data_size)			return 0;		count = na->data_size - pos;	}	/* If it is a resident attribute, get the value from the mft record. */	if (!NAttrNonResident(na)) {		ntfs_attr_search_ctx *ctx;		char *val;		ctx = ntfs_attr_get_search_ctx(na->ni, NULL);		if (!ctx)			return -1;		if (ntfs_attr_lookup(na->type, na->name, na->name_len, 0,				0, NULL, 0, ctx)) {res_err_out:			ntfs_attr_put_search_ctx(ctx);			return -1;		}		val = (char*)ctx->attr + le16_to_cpu(ctx->attr->value_offset);		if (val < (char*)ctx->attr || val +				le32_to_cpu(ctx->attr->value_length) >				(char*)ctx->mrec + vol->mft_record_size) {			errno = EIO;			ntfs_log_perror("%s: Sanity check failed", __FUNCTION__);			goto res_err_out;		}		memcpy(b, val + pos, count);		ntfs_attr_put_search_ctx(ctx);		return count;	}	total = total2 = 0;	/* Zero out reads beyond initialized size. */	if (pos + count > na->initialized_size) {		if (pos >= na->initialized_size) {			memset(b, 0, count);			return count;		}		total2 = pos + count - na->initialized_size;		count -= total2;		memset((u8*)b + count, 0, total2);	}	/* Find the runlist element containing the vcn. */	rl = ntfs_attr_find_vcn(na, pos >> vol->cluster_size_bits);	if (!rl) {		/*		 * If the vcn is not present it is an out of bounds read.		 * However, we already truncated the read to the data_size,		 * so getting this here is an error.		 */		if (errno == ENOENT) {			errno = EIO;			ntfs_log_perror("%s: Failed to find VCN #1", __FUNCTION__);		}		return -1;	}	/*	 * Gather the requested data into the linear destination buffer. Note,	 * a partial final vcn is taken care of by the @count capping of read	 * length.	 */

⌨️ 快捷键说明

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