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

📄 runlist.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		rl[rlpos].lcn = LCN_RL_NOT_MAPPED;	/* Setup terminating runlist element. */	rl[rlpos].vcn = vcn;	rl[rlpos].length = (s64)0;	/* If no existing runlist was specified, we are done. */	if (!old_rl) {		ntfs_debug("Mapping pairs array successfully decompressed:");		ntfs_debug_dump_runlist(rl);		return rl;	}	/* Now combine the new and old runlists checking for overlaps. */	old_rl = ntfs_runlists_merge(old_rl, rl);	if (likely(!IS_ERR(old_rl)))		return old_rl;	ntfs_free(rl);	ntfs_error(vol->sb, "Failed to merge runlists.");	return old_rl;io_error:	ntfs_error(vol->sb, "Corrupt attribute.");err_out:	ntfs_free(rl);	return ERR_PTR(-EIO);}/** * ntfs_rl_vcn_to_lcn - convert a vcn into a lcn given a runlist * @rl:		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 @rl to map vcns to their * corresponding lcns. * * It is up to the caller to serialize access to the runlist @rl. * * Since lcns must be >= 0, we use negative return codes with special meaning: * * Return code		Meaning / Description * ================================================== *  LCN_HOLE		Hole / not allocated on disk. *  LCN_RL_NOT_MAPPED	This is part of the runlist which has not been *			inserted into the runlist yet. *  LCN_ENOENT		There is no such vcn in the attribute. * * Locking: - The caller must have locked the runlist (for reading or writing). *	    - This function does not touch the lock, nor does it modify the *	      runlist. */LCN ntfs_rl_vcn_to_lcn(const runlist_element *rl, const VCN vcn){	int i;	BUG_ON(vcn < 0);	/*	 * If rl is NULL, assume that we have found an unmapped runlist. The	 * caller can then attempt to map it and fail appropriately if	 * necessary.	 */	if (unlikely(!rl))		return LCN_RL_NOT_MAPPED;	/* Catch out of lower bounds vcn. */	if (unlikely(vcn < rl[0].vcn))		return LCN_ENOENT;	for (i = 0; likely(rl[i].length); i++) {		if (unlikely(vcn < rl[i+1].vcn)) {			if (likely(rl[i].lcn >= (LCN)0))				return rl[i].lcn + (vcn - rl[i].vcn);			return rl[i].lcn;		}	}	/*	 * The terminator element is setup to the correct value, i.e. one of	 * LCN_HOLE, LCN_RL_NOT_MAPPED, or LCN_ENOENT.	 */	if (likely(rl[i].lcn < (LCN)0))		return rl[i].lcn;	/* Just in case... We could replace this with BUG() some day. */	return LCN_ENOENT;}#ifdef NTFS_RW/** * ntfs_rl_find_vcn_nolock - find a vcn in a runlist * @rl:		runlist to search * @vcn:	vcn to find * * Find the virtual cluster number @vcn in the runlist @rl and return the * address of the runlist element containing the @vcn on success. * * Return NULL if @rl is NULL or @vcn is in an unmapped part/out of bounds of * the runlist. * * Locking: The runlist must be locked on entry. */runlist_element *ntfs_rl_find_vcn_nolock(runlist_element *rl, const VCN vcn){	BUG_ON(vcn < 0);	if (unlikely(!rl || vcn < rl[0].vcn))		return NULL;	while (likely(rl->length)) {		if (unlikely(vcn < rl[1].vcn)) {			if (likely(rl->lcn >= LCN_HOLE))				return rl;			return NULL;		}		rl++;	}	if (likely(rl->lcn == LCN_ENOENT))		return rl;	return NULL;}/** * ntfs_get_nr_significant_bytes - get number of bytes needed to store a number * @n:		number for which to get the number of bytes for * * Return the number of bytes required to store @n unambiguously as * a signed number. * * This is used in the context of the mapping pairs array to determine how * many bytes will be needed in the array to store a given logical cluster * number (lcn) or a specific run length. * * Return the number of bytes written.  This function cannot fail. */static inline int ntfs_get_nr_significant_bytes(const s64 n){	s64 l = n;	int i;	s8 j;	i = 0;	do {		l >>= 8;		i++;	} while (l != 0 && l != -1);	j = (n >> 8 * (i - 1)) & 0xff;	/* If the sign bit is wrong, we need an extra byte. */	if ((n < 0 && j >= 0) || (n > 0 && j < 0))		i++;	return i;}/** * ntfs_get_size_for_mapping_pairs - get bytes needed for mapping pairs array * @vol:	ntfs volume (needed for the ntfs version) * @rl:		locked runlist to determine the size of the mapping pairs of * @first_vcn:	first vcn which to include in the mapping pairs array * @last_vcn:	last vcn which to include in the mapping pairs array * * Walk the locked runlist @rl and calculate the size in bytes of the mapping * pairs array corresponding to the runlist @rl, starting at vcn @first_vcn and * finishing with vcn @last_vcn. * * A @last_vcn of -1 means end of runlist and in that case the size of the * mapping pairs array corresponding to the runlist starting at vcn @first_vcn * and finishing at the end of the runlist is determined. * * This for example allows us to allocate a buffer of the right size when * building the mapping pairs array. * * If @rl is NULL, just return 1 (for the single terminator byte). * * Return the calculated size in bytes on success.  On error, return -errno. * The following error codes are defined: *	-EINVAL	- Run list contains unmapped elements.  Make sure to only pass *		  fully mapped runlists to this function. *	-EIO	- The runlist is corrupt. * * Locking: @rl must be locked on entry (either for reading or writing), it *	    remains locked throughout, and is left locked upon return. */int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol,		const runlist_element *rl, const VCN first_vcn,		const VCN last_vcn){	LCN prev_lcn;	int rls;	bool the_end = false;	BUG_ON(first_vcn < 0);	BUG_ON(last_vcn < -1);	BUG_ON(last_vcn >= 0 && first_vcn > last_vcn);	if (!rl) {		BUG_ON(first_vcn);		BUG_ON(last_vcn > 0);		return 1;	}	/* Skip to runlist element containing @first_vcn. */	while (rl->length && first_vcn >= rl[1].vcn)		rl++;	if (unlikely((!rl->length && first_vcn > rl->vcn) ||			first_vcn < rl->vcn))		return -EINVAL;	prev_lcn = 0;	/* Always need the termining zero byte. */	rls = 1;	/* Do the first partial run if present. */	if (first_vcn > rl->vcn) {		s64 delta, length = rl->length;		/* We know rl->length != 0 already. */		if (unlikely(length < 0 || rl->lcn < LCN_HOLE))			goto err_out;		/*		 * If @stop_vcn is given and finishes inside this run, cap the		 * run length.		 */		if (unlikely(last_vcn >= 0 && rl[1].vcn > last_vcn)) {			s64 s1 = last_vcn + 1;			if (unlikely(rl[1].vcn > s1))				length = s1 - rl->vcn;			the_end = true;		}		delta = first_vcn - rl->vcn;		/* Header byte + length. */		rls += 1 + ntfs_get_nr_significant_bytes(length - delta);		/*		 * If the logical cluster number (lcn) denotes a hole and we		 * are on NTFS 3.0+, we don't store it at all, i.e. we need		 * zero space.  On earlier NTFS versions we just store the lcn.		 * Note: this assumes that on NTFS 1.2-, holes are stored with		 * an lcn of -1 and not a delta_lcn of -1 (unless both are -1).		 */		if (likely(rl->lcn >= 0 || vol->major_ver < 3)) {			prev_lcn = rl->lcn;			if (likely(rl->lcn >= 0))				prev_lcn += delta;			/* Change in lcn. */			rls += ntfs_get_nr_significant_bytes(prev_lcn);		}		/* Go to next runlist element. */		rl++;	}	/* Do the full runs. */	for (; rl->length && !the_end; rl++) {		s64 length = rl->length;		if (unlikely(length < 0 || rl->lcn < LCN_HOLE))			goto err_out;		/*		 * If @stop_vcn is given and finishes inside this run, cap the		 * run length.		 */		if (unlikely(last_vcn >= 0 && rl[1].vcn > last_vcn)) {			s64 s1 = last_vcn + 1;			if (unlikely(rl[1].vcn > s1))				length = s1 - rl->vcn;			the_end = true;		}		/* Header byte + length. */		rls += 1 + ntfs_get_nr_significant_bytes(length);		/*		 * If the logical cluster number (lcn) denotes a hole and we		 * are on NTFS 3.0+, we don't store it at all, i.e. we need		 * zero space.  On earlier NTFS versions we just store the lcn.		 * Note: this assumes that on NTFS 1.2-, holes are stored with		 * an lcn of -1 and not a delta_lcn of -1 (unless both are -1).		 */		if (likely(rl->lcn >= 0 || vol->major_ver < 3)) {			/* Change in lcn. */			rls += ntfs_get_nr_significant_bytes(rl->lcn -					prev_lcn);			prev_lcn = rl->lcn;		}	}	return rls;err_out:	if (rl->lcn == LCN_RL_NOT_MAPPED)		rls = -EINVAL;	else		rls = -EIO;	return rls;}/** * ntfs_write_significant_bytes - write the significant bytes of a number * @dst:	destination buffer to write to * @dst_max:	pointer to last byte of destination buffer for bounds checking * @n:		number whose significant bytes to write * * Store in @dst, the minimum bytes of the number @n which are required to * identify @n unambiguously as a signed number, taking care not to exceed * @dest_max, the maximum position within @dst to which we are allowed to * write. * * This is used when building the mapping pairs array of a runlist to compress * a given logical cluster number (lcn) or a specific run length to the minumum * size possible. * * Return the number of bytes written on success.  On error, i.e. the * destination buffer @dst is too small, return -ENOSPC. */static inline int ntfs_write_significant_bytes(s8 *dst, const s8 *dst_max,		const s64 n){	s64 l = n;	int i;	s8 j;	i = 0;	do {		if (unlikely(dst > dst_max))			goto err_out;		*dst++ = l & 0xffll;		l >>= 8;		i++;	} while (l != 0 && l != -1);	j = (n >> 8 * (i - 1)) & 0xff;	/* If the sign bit is wrong, we need an extra byte. */	if (n < 0 && j >= 0) {		if (unlikely(dst > dst_max))			goto err_out;		i++;		*dst = (s8)-1;	} else if (n > 0 && j < 0) {		if (unlikely(dst > dst_max))			goto err_out;		i++;		*dst = (s8)0;	}	return i;err_out:	return -ENOSPC;}/** * ntfs_mapping_pairs_build - build the mapping pairs array from a runlist * @vol:	ntfs volume (needed for the ntfs version) * @dst:	destination buffer to which to write the mapping pairs array * @dst_len:	size of destination buffer @dst in bytes * @rl:		locked runlist for which to build the mapping pairs array * @first_vcn:	first vcn which to include in the mapping pairs array * @last_vcn:	last vcn which to include in the mapping pairs array * @stop_vcn:	first vcn outside destination buffer on success or -ENOSPC * * Create the mapping pairs array from the locked runlist @rl, starting at vcn * @first_vcn and finishing with vcn @last_vcn and save the array in @dst. * @dst_len is the size of @dst in bytes and it should be at least equal to the * value obtained by calling ntfs_get_size_for_mapping_pairs(). * * A @last_vcn of -1 means end of runlist and in that case the mapping pairs * array corresponding to the runlist starting at vcn @first_vcn and finishing * at the end of the runlist is created. * * If @rl is NULL, just write a single terminator byte to @dst. * * On success or -ENOSPC error, if @stop_vcn is not NULL, *@stop_vcn is set to * the first vcn outside the destination buffer.  Note that on error, @dst has * been filled with all the mapping pairs that will fit, thus it can be treated * as partial success, in that a new attribute extent needs to be created or * the next extent has to be used and the mapping pairs build has to be * continued with @first_vcn set to *@stop_vcn. * * Return 0 on success and -errno on error.  The following error codes are * defined: *	-EINVAL	- Run list contains unmapped elements.  Make sure to only pass *		  fully mapped runlists to this function. *	-EIO	- The runlist is corrupt. *	-ENOSPC	- The destination buffer is too small. * * Locking: @rl must be locked on entry (either for reading or writing), it *	    remains locked throughout, and is left locked upon return. */int ntfs_mapping_pairs_build(const ntfs_volume *vol, s8 *dst,		const int dst_len, const runlist_element *rl,		const VCN first_vcn, const VCN last_vcn, VCN *const stop_vcn){	LCN prev_lcn;	s8 *dst_max, *dst_next;	int err = -ENOSPC;	bool the_end = false;	s8 len_len, lcn_len;	BUG_ON(first_vcn < 0);	BUG_ON(last_vcn < -1);	BUG_ON(last_vcn >= 0 && first_vcn > last_vcn);	BUG_ON(dst_len < 1);	if (!rl) {		BUG_ON(first_vcn);		BUG_ON(last_vcn > 0);		if (stop_vcn)			*stop_vcn = 0;		/* Terminator byte. */		*dst = 0;		return 0;	}	/* Skip to runlist element containing @first_vcn. */	while (rl->length && first_vcn >= rl[1].vcn)		rl++;	if (unlikely((!rl->length && first_vcn > rl->vcn) ||			first_vcn < rl->vcn))		return -EINVAL;	/*	 * @dst_max is used for bounds checking in	 * ntfs_write_significant_bytes().	 */	dst_max = dst + dst_len - 1;	prev_lcn = 0;	/* Do the first partial run if present. */	if (first_vcn > rl->vcn) {		s64 delta, length = rl->length;		/* We know rl->length != 0 already. */		if (unlikely(length < 0 || rl->lcn < LCN_HOLE))			goto err_out;		/*		 * If @stop_vcn is given and finishes inside this run, cap the		 * run length.		 */		if (unlikely(last_vcn >= 0 && rl[1].vcn > last_vcn)) {			s64 s1 = last_vcn + 1;			if (unlikely(rl[1].vcn > s1))				length = s1 - rl->vcn;			the_end = true;		}		delta = first_vcn - rl->vcn;		/* Write length. */		len_len = ntfs_write_significant_bytes(dst + 1, dst_max,				length - delta);		if (unlikely(len_len < 0))			goto size_err;		/*		 * If the logical cluster number (lcn) denotes a hole and we		 * are on NTFS 3.0+, we don't store it at all, i.e. we need		 * zero space.  On earlier NTFS versions we just write the lcn		 * change.  FIXME: Do we need to write the lcn change or just		 * the lcn in that case?  Not sure as I have never seen this		 * case on NT4. - We assume that we just need to write the lcn		 * change until someone tells us otherwise... (AIA)		 */		if (likely(rl->lcn >= 0 || vol->major_ver < 3)) {			prev_lcn = rl->lcn;			if (likely(rl->lcn >= 0))				prev_lcn += delta;			/* Write change in lcn. */			lcn_len = ntfs_write_significant_bytes(dst + 1 +					len_len, dst_max, prev_lcn);			if (unlikely(lcn_len < 0))				goto size_err;		} else			lcn_len = 0;		dst_next = dst + len_len + lcn_len + 1;		if (unlikely(dst_next > dst_max))			goto size_err;		/* Update header byte. */		*dst = lcn_len << 4 | len_len;		/* Position at next mapping pairs array element. */		dst = dst_next;		/* Go to next runlist element. */		rl++;	}	/* Do the full runs. */	for (; rl->length && !the_end; rl++) {		s64 length = rl->length;		if (unlikely(length < 0 || rl->lcn < LCN_HOLE))			goto err_out;		/*		 * If @stop_vcn is given and finishes inside this run, cap the		 * run length.		 */		if (unlikely(last_vcn >= 0 && rl[1].vcn > last_vcn)) {			s64 s1 = last_vcn + 1;			if (unlikely(rl[1].vcn > s1))				length = s1 - rl->vcn;			the_end = true;		}		/* Write length. */		len_len = ntfs_write_significant_bytes(dst + 1, dst_max,				length);		if (unlikely(len_len < 0))			goto size_err;

⌨️ 快捷键说明

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