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

📄 attrib.c

📁 添加linux下对NTFS格式文件系统访问支持的源代码ntfs-3g
💻 C
📖 第 1 页 / 共 5 页
字号:
/** * 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("Attribute first extent has "						 "non-zero lowest_vcn");				 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 has corrupt attribute list");			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("Couldn't load full runlist: "				"highest_vcn = 0x%llx, last_vcn = 0x%llx",				(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 - read from an attribute specified by an ntfs_attr structure * @na:		ntfs attribute to read from * @pos:	byte position in the attribute to begin reading from * @count:	number of bytes to read * @b:		output data buffer * * This function will read @count bytes starting at offset @pos from the ntfs * attribute @na into the data buffer @b. * * On success, return the number of successfully read bytes. If this number is * lower than @count this means that the read reached end of file or that an * error was encountered during the read so that the read is partial. 0 means * end of file or nothing was read (also return 0 when @count is 0). * * On error and nothing has been read, return -1 with errno set appropriately * to the return code of ntfs_pread(), or to EINVAL in case of invalid * arguments. */s64 ntfs_attr_pread(ntfs_attr *na, const s64 pos, s64 count, void *b){	s64 br, to_read, ofs, total, total2;	ntfs_volume *vol;	runlist_element *rl;	ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, pos 0x%llx, count "			"0x%llx.\n", (unsigned long long)na->ni->mft_no,			na->type, (long long)pos, (long long)count);	if (!na || !na->ni || !na->ni->vol || !b || pos < 0 || count < 0) {		errno = EINVAL;		return -1;	}	/*	 * If this is a compressed attribute it needs special treatment, but	 * only if it is non-resident.	 */	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;	/* Update access time if needed. */	if (na->type == AT_DATA || na->type == AT_INDEX_ROOT ||			na->type == AT_INDEX_ALLOCATION)		ntfs_inode_update_atime(na->ni);	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;			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;		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.	 */	ofs = pos - (rl->vcn << vol->cluster_size_bits);	for (; count; rl++, ofs = 0) {		if (rl->lcn == LCN_RL_NOT_MAPPED) {			rl = ntfs_attr_find_vcn(na, rl->vcn);			if (!rl) {				if (errno == ENOENT)					errno = EIO;				goto rl_err_out;			}			/* Needed for case when runs merged. */			ofs = pos + total - (rl->vcn << vol->cluster_size_bits);		}		if (!rl->length)			goto rl_err_out;		if (rl->lcn < (LCN)0) {

⌨️ 快捷键说明

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