attrib.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,911 行 · 第 1/5 页

C
1,911
字号
		 * not-mapped and terminator elements. ntfs_malloc_nofs()		 * operates on whole pages only.		 */		if (((rlpos + 3) * sizeof(*old_rl)) > rlsize) {			runlist_element *rl2;			rl2 = ntfs_malloc_nofs(rlsize + (int)PAGE_SIZE);			if (unlikely(!rl2)) {				ntfs_free(rl);				return ERR_PTR(-ENOMEM);			}			memcpy(rl2, rl, rlsize);			ntfs_free(rl);			rl = rl2;			rlsize += PAGE_SIZE;		}		/* Enter the current vcn into the current runlist element. */		rl[rlpos].vcn = vcn;		/*		 * Get the change in vcn, i.e. the run length in clusters.		 * Doing it this way ensures that we signextend negative values.		 * A negative run length doesn't make any sense, but hey, I		 * didn't make up the NTFS specs and Windows NT4 treats the run		 * length as a signed value so that's how it is...		 */		b = *buf & 0xf;		if (b) {			if (unlikely(buf + b > attr_end))				goto io_error;			for (deltaxcn = (s8)buf[b--]; b; b--)				deltaxcn = (deltaxcn << 8) + buf[b];		} else { /* The length entry is compulsory. */			ntfs_error(vol->sb, "Missing length entry in mapping "					"pairs array.");			deltaxcn = (s64)-1;		}		/*		 * Assume a negative length to indicate data corruption and		 * hence clean-up and return NULL.		 */		if (unlikely(deltaxcn < 0)) {			ntfs_error(vol->sb, "Invalid length in mapping pairs "					"array.");			goto err_out;		}		/*		 * Enter the current run length into the current runlist		 * element.		 */		rl[rlpos].length = deltaxcn;		/* Increment the current vcn by the current run length. */		vcn += deltaxcn;		/*		 * There might be no lcn change at all, as is the case for		 * sparse clusters on NTFS 3.0+, in which case we set the lcn		 * to LCN_HOLE.		 */		if (!(*buf & 0xf0))			rl[rlpos].lcn = (LCN)LCN_HOLE;		else {			/* Get the lcn change which really can be negative. */			u8 b2 = *buf & 0xf;			b = b2 + ((*buf >> 4) & 0xf);			if (buf + b > attr_end)				goto io_error;			for (deltaxcn = (s8)buf[b--]; b > b2; b--)				deltaxcn = (deltaxcn << 8) + buf[b];			/* Change the current lcn to its new value. */			lcn += deltaxcn;#ifdef DEBUG			/*			 * On NTFS 1.2-, apparently can have lcn == -1 to			 * indicate a hole. But we haven't verified ourselves			 * whether it is really the lcn or the deltaxcn that is			 * -1. So if either is found give us a message so we			 * can investigate it further!			 */			if (vol->major_ver < 3) {				if (unlikely(deltaxcn == (LCN)-1))					ntfs_error(vol->sb, "lcn delta == -1");				if (unlikely(lcn == (LCN)-1))					ntfs_error(vol->sb, "lcn == -1");			}#endif			/* Check lcn is not below -1. */			if (unlikely(lcn < (LCN)-1)) {				ntfs_error(vol->sb, "Invalid LCN < -1 in "						"mapping pairs array.");				goto err_out;			}			/* Enter the current lcn into the runlist element. */			rl[rlpos].lcn = lcn;		}		/* Get to the next runlist element. */		rlpos++;		/* Increment the buffer position to the next mapping pair. */		buf += (*buf & 0xf) + ((*buf >> 4) & 0xf) + 1;	}	if (unlikely(buf >= attr_end))		goto io_error;	/*	 * If there is a highest_vcn specified, it must be equal to the final	 * vcn in the runlist - 1, or something has gone badly wrong.	 */	deltaxcn = sle64_to_cpu(attr->data.non_resident.highest_vcn);	if (unlikely(deltaxcn && vcn - 1 != deltaxcn)) {mpa_err:		ntfs_error(vol->sb, "Corrupt mapping pairs array in "				"non-resident attribute.");		goto err_out;	}	/* Setup not mapped runlist element if this is the base extent. */	if (!attr->data.non_resident.lowest_vcn) {		VCN max_cluster;		max_cluster = (sle64_to_cpu(				attr->data.non_resident.allocated_size) +				vol->cluster_size - 1) >>				vol->cluster_size_bits;		/*		 * If there is a difference between the highest_vcn and the		 * highest cluster, the runlist is either corrupt or, more		 * likely, there are more extents following this one.		 */		if (deltaxcn < --max_cluster) {			ntfs_debug("More extents to follow; deltaxcn = 0x%llx, "					"max_cluster = 0x%llx",					(unsigned long long)deltaxcn,					(unsigned long long)max_cluster);			rl[rlpos].vcn = vcn;			vcn += rl[rlpos].length = max_cluster - deltaxcn;			rl[rlpos].lcn = (LCN)LCN_RL_NOT_MAPPED;			rlpos++;		} else if (unlikely(deltaxcn > max_cluster)) {			ntfs_error(vol->sb, "Corrupt attribute. deltaxcn = "					"0x%llx, max_cluster = 0x%llx",					(unsigned long long)deltaxcn,					(unsigned long long)max_cluster);			goto mpa_err;		}		rl[rlpos].lcn = (LCN)LCN_ENOENT;	} else /* Not the base extent. There may be more extents to follow. */		rl[rlpos].lcn = (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_merge_runlists(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_map_runlist - map (a part of) a runlist of an ntfs inode * @ni:		ntfs inode 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 the ntfs inode @ni. * * Return 0 on success and -errno on error. * * Locking: - The runlist must be unlocked on entry and is unlocked on return. *	    - This function takes the lock for writing and modifies the runlist. */int ntfs_map_runlist(ntfs_inode *ni, VCN vcn){	ntfs_inode *base_ni;	ntfs_attr_search_ctx *ctx;	MFT_RECORD *mrec;	int err = 0;	ntfs_debug("Mapping runlist part containing vcn 0x%llx.",			(unsigned long long)vcn);	if (!NInoAttr(ni))		base_ni = ni;	else		base_ni = ni->ext.base_ntfs_ino;	mrec = map_mft_record(base_ni);	if (IS_ERR(mrec))		return PTR_ERR(mrec);	ctx = ntfs_attr_get_search_ctx(base_ni, mrec);	if (unlikely(!ctx)) {		err = -ENOMEM;		goto err_out;	}	err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len,			CASE_SENSITIVE, vcn, NULL, 0, ctx);	if (unlikely(err))		goto put_err_out;	down_write(&ni->runlist.lock);	/* Make sure someone else didn't do the work while we were sleeping. */	if (likely(ntfs_vcn_to_lcn(ni->runlist.rl, vcn) <= LCN_RL_NOT_MAPPED)) {		runlist_element *rl;		rl = decompress_mapping_pairs(ni->vol, ctx->attr,				ni->runlist.rl);		if (IS_ERR(rl))			err = PTR_ERR(rl);		else			ni->runlist.rl = rl;	}	up_write(&ni->runlist.lock);put_err_out:	ntfs_attr_put_search_ctx(ctx);err_out:	unmap_mft_record(base_ni);	return err;}/** * ntfs_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 values with special meaning: * * Return value			Meaning / Description * ================================================== *  -1 = LCN_HOLE		Hole / not allocated on disk. *  -2 = LCN_RL_NOT_MAPPED	This is part of the runlist which has not been *				inserted into the runlist yet. *  -3 = 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. */LCN ntfs_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)LCN_RL_NOT_MAPPED;	/* Catch out of lower bounds vcn. */	if (unlikely(vcn < rl[0].vcn))		return (LCN)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)LCN_ENOENT;}/** * ntfs_find_vcn - find a vcn in the runlist described by an ntfs inode * @ni:		ntfs inode describing the runlist to search * @vcn:	vcn to find * @need_write:	if false, lock for reading and if true, lock for writing * * Find the virtual cluster number @vcn in the runlist described by the ntfs * inode @ni and return the address of the runlist element containing the @vcn. * The runlist is left locked and the caller has to unlock it.  If @need_write * is true, the runlist is locked for writing and if @need_write is false, the * runlist is locked for reading.  In the error case, the runlist is not left * locked. * * 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. * * Return the runlist element containing the @vcn on success and * ERR_PTR(-errno) on error.  You need to test the return value with IS_ERR() * to decide if the return is success or failure and PTR_ERR() to get to the * error code if IS_ERR() is true. * * The possible error return codes are: *	-ENOENT - No such vcn in the runlist, i.e. @vcn is out of bounds. *	-ENOMEM - Not enough memory to map runlist. *	-EIO	- Critical error (runlist/file is corrupt, i/o error, etc). * * Locking: - The runlist must be unlocked on entry. *	    - On failing return, the runlist is unlocked. *	    - On successful return, the runlist is locked.  If @need_write us *	      true, it is locked for writing.  Otherwise is is locked for *	      reading. */runlist_element *ntfs_find_vcn(ntfs_inode *ni, const VCN vcn,		const BOOL need_write){	runlist_element *rl;	int err = 0;	BOOL is_retry = FALSE;	ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, lock for %sing.",			ni->mft_no, (unsigned long long)vcn,			!need_write ? "read" : "writ");	BUG_ON(!ni);	BUG_ON(!NInoNonResident(ni));	BUG_ON(vcn < 0);lock_retry_remap:	if (!need_write)		down_read(&ni->runlist.lock);	else		down_write(&ni->runlist.lock);	rl = ni->runlist.rl;	if (likely(rl && vcn >= rl[0].vcn)) {		while (likely(rl->length)) {			if (likely(vcn < rl[1].vcn)) {				if (likely(rl->lcn >= (LCN)LCN_HOLE)) {					ntfs_debug("Done.");					return rl;				}				break;			}			rl++;		}		if (likely(rl->lcn != (LCN)LCN_RL_NOT_MAPPED)) {			if (likely(rl->lcn == (LCN)LCN_ENOENT))				err = -ENOENT;			else				err = -EIO;		}	}	if (!need_write)		up_read(&ni->runlist.lock);	else		up_write(&ni->runlist.lock);	if (!err && !is_retry) {		/*		 * The @vcn is in an unmapped region, map the runlist and		 * retry.		 */		err = ntfs_map_runlist(ni, vcn);		if (likely(!err)) {			is_retry = TRUE;			goto lock_retry_remap;		}		/*		 * -EINVAL and -ENOENT coming from a failed mapping attempt are		 * equivalent to i/o errors for us as they should not happen in		 * our code paths.		 */		if (err == -EINVAL || err == -ENOENT)			err = -EIO;	} else if (!err)		err = -EIO;	ntfs_error(ni->vol->sb, "Failed with error code %i.", err);	return ERR_PTR(err);}/**

⌨️ 快捷键说明

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