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

📄 attrib.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
			up_read(&ni->runlist.lock);			down_write(&ni->runlist.lock);			if (unlikely(ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn) !=					LCN_RL_NOT_MAPPED)) {				up_write(&ni->runlist.lock);				down_read(&ni->runlist.lock);				goto retry_remap;			}		}		err = ntfs_map_runlist_nolock(ni, vcn, NULL);		if (!write_locked) {			up_write(&ni->runlist.lock);			down_read(&ni->runlist.lock);		}		if (likely(!err)) {			is_retry = true;			goto retry_remap;		}		if (err == -ENOENT)			lcn = LCN_ENOENT;		else if (err == -ENOMEM)			lcn = LCN_ENOMEM;		else			lcn = LCN_EIO;	}	if (lcn != LCN_ENOENT)		ntfs_error(ni->vol->sb, "Failed with error code %lli.",				(long long)lcn);	return lcn;}/** * ntfs_attr_find_vcn_nolock - find a vcn in the runlist of an ntfs inode * @ni:		ntfs inode describing the runlist to search * @vcn:	vcn to find * @ctx:	active attribute search context if present or NULL if not * * 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. * * If the @vcn is not mapped yet, the attempt is made to map the attribute * extent containing the @vcn and the vcn to lcn conversion is retried. * * If @ctx is specified, it is an active search context of @ni and its base mft * record.  This is needed when ntfs_attr_find_vcn_nolock() encounters unmapped * runlist fragments and allows their mapping.  If you do not have the mft * record mapped, you can specify @ctx as NULL and ntfs_attr_find_vcn_nolock() * will perform the necessary mapping and unmapping. * * Note, ntfs_attr_find_vcn_nolock() saves the state of @ctx on entry and * restores it before returning.  Thus, @ctx will be left pointing to the same * attribute on return as on entry.  However, the actual pointers in @ctx may * point to different memory locations on return, so you must remember to reset * any cached pointers from the @ctx, i.e. after the call to * ntfs_attr_find_vcn_nolock(), you will probably want to do: *	m = ctx->mrec; *	a = ctx->attr; * Assuming you cache ctx->attr in a variable @a of type ATTR_RECORD * and that * you cache ctx->mrec in a variable @m of type MFT_RECORD *. * 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). * * WARNING: If @ctx is supplied, regardless of whether success or failure is *	    returned, you need to check IS_ERR(@ctx->mrec) and if 'true' the @ctx *	    is no longer valid, i.e. you need to either call *	    ntfs_attr_reinit_search_ctx() or ntfs_attr_put_search_ctx() on it. *	    In that case PTR_ERR(@ctx->mrec) will give you the error code for *	    why the mapping of the old inode failed. * * Locking: - The runlist described by @ni must be locked for writing on entry *	      and is locked on return.  Note the runlist may be modified when *	      needed runlist fragments need to be mapped. *	    - If @ctx is NULL, the base mft record of @ni must not be mapped on *	      entry and it will be left unmapped on return. *	    - If @ctx is not NULL, the base mft record must be mapped on entry *	      and it will be left mapped on return. */runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni, const VCN vcn,		ntfs_attr_search_ctx *ctx){	unsigned long flags;	runlist_element *rl;	int err = 0;	bool is_retry = false;	ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, with%s ctx.",			ni->mft_no, (unsigned long long)vcn, ctx ? "" : "out");	BUG_ON(!ni);	BUG_ON(!NInoNonResident(ni));	BUG_ON(vcn < 0);	if (!ni->runlist.rl) {		read_lock_irqsave(&ni->size_lock, flags);		if (!ni->allocated_size) {			read_unlock_irqrestore(&ni->size_lock, flags);			return ERR_PTR(-ENOENT);		}		read_unlock_irqrestore(&ni->size_lock, flags);	}retry_remap:	rl = ni->runlist.rl;	if (likely(rl && vcn >= rl[0].vcn)) {		while (likely(rl->length)) {			if (unlikely(vcn < rl[1].vcn)) {				if (likely(rl->lcn >= LCN_HOLE)) {					ntfs_debug("Done.");					return rl;				}				break;			}			rl++;		}		if (likely(rl->lcn != LCN_RL_NOT_MAPPED)) {			if (likely(rl->lcn == LCN_ENOENT))				err = -ENOENT;			else				err = -EIO;		}	}	if (!err && !is_retry) {		/*		 * If the search context is invalid we cannot map the unmapped		 * region.		 */		if (IS_ERR(ctx->mrec))			err = PTR_ERR(ctx->mrec);		else {			/*			 * The @vcn is in an unmapped region, map the runlist			 * and retry.			 */			err = ntfs_map_runlist_nolock(ni, vcn, ctx);			if (likely(!err)) {				is_retry = true;				goto retry_remap;			}		}		if (err == -EINVAL)			err = -EIO;	} else if (!err)		err = -EIO;	if (err != -ENOENT)		ntfs_error(ni->vol->sb, "Failed with error code %i.", err);	return ERR_PTR(err);}/** * ntfs_attr_find - find (next) attribute in mft record * @type:	attribute type to find * @name:	attribute name to find (optional, i.e. NULL means don't care) * @name_len:	attribute name length (only needed if @name present) * @ic:		IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present) * @val:	attribute value to find (optional, resident attributes only) * @val_len:	attribute value length * @ctx:	search context with mft record and attribute to search from * * You should not need to call this function directly.  Use ntfs_attr_lookup() * instead. * * ntfs_attr_find() takes a search context @ctx as parameter and searches the * mft record specified by @ctx->mrec, beginning at @ctx->attr, for an * attribute of @type, optionally @name and @val. * * If the attribute is found, ntfs_attr_find() returns 0 and @ctx->attr will * point to the found attribute. * * If the attribute is not found, ntfs_attr_find() returns -ENOENT and * @ctx->attr will point to the attribute before which the attribute being * searched for would need to be inserted if such an action were to be desired. * * On actual error, ntfs_attr_find() returns -EIO.  In this case @ctx->attr is * undefined and in particular do not rely on it not changing. * * If @ctx->is_first is 'true', the search begins with @ctx->attr itself.  If it * is 'false', the search begins after @ctx->attr. * * If @ic is IGNORE_CASE, the @name comparisson is not case sensitive and * @ctx->ntfs_ino must be set to the ntfs inode to which the mft record * @ctx->mrec belongs.  This is so we can get at the ntfs volume and hence at * the upcase table.  If @ic is CASE_SENSITIVE, the comparison is case * sensitive.  When @name is present, @name_len is the @name length in Unicode * characters. * * If @name is not present (NULL), we assume that the unnamed attribute is * being searched for. * * Finally, the resident attribute value @val is looked for, if present.  If * @val is not present (NULL), @val_len is ignored. * * ntfs_attr_find() only searches the specified mft record and it ignores the * presence of an attribute list attribute (unless it is the one being searched * for, obviously).  If you need to take attribute lists into consideration, * use ntfs_attr_lookup() instead (see below).  This also means that you cannot * use ntfs_attr_find() to search for extent records of non-resident * attributes, as extents with lowest_vcn != 0 are usually described by the * attribute list attribute only. - Note that it is possible that the first * extent is only in the attribute list while the last extent is in the base * mft record, so do not rely on being able to find the first extent in the * base mft record. * * Warning: Never use @val when looking for attribute types which can be *	    non-resident as this most likely will result in a crash! */static int ntfs_attr_find(const ATTR_TYPE type, const ntfschar *name,		const u32 name_len, const IGNORE_CASE_BOOL ic,		const u8 *val, const u32 val_len, ntfs_attr_search_ctx *ctx){	ATTR_RECORD *a;	ntfs_volume *vol = ctx->ntfs_ino->vol;	ntfschar *upcase = vol->upcase;	u32 upcase_len = vol->upcase_len;	/*	 * Iterate over attributes in mft record starting at @ctx->attr, or the	 * attribute following that, if @ctx->is_first is 'true'.	 */	if (ctx->is_first) {		a = ctx->attr;		ctx->is_first = false;	} else		a = (ATTR_RECORD*)((u8*)ctx->attr +				le32_to_cpu(ctx->attr->length));	for (;;	a = (ATTR_RECORD*)((u8*)a + le32_to_cpu(a->length))) {		if ((u8*)a < (u8*)ctx->mrec || (u8*)a > (u8*)ctx->mrec +				le32_to_cpu(ctx->mrec->bytes_allocated))			break;		ctx->attr = a;		if (unlikely(le32_to_cpu(a->type) > le32_to_cpu(type) ||				a->type == AT_END))			return -ENOENT;		if (unlikely(!a->length))			break;		if (a->type != type)			continue;		/*		 * If @name is present, compare the two names.  If @name is		 * missing, assume we want an unnamed attribute.		 */		if (!name) {			/* The search failed if the found attribute is named. */			if (a->name_length)				return -ENOENT;		} else if (!ntfs_are_names_equal(name, name_len,			    (ntfschar*)((u8*)a + le16_to_cpu(a->name_offset)),			    a->name_length, ic, upcase, upcase_len)) {			register int rc;			rc = ntfs_collate_names(name, name_len,					(ntfschar*)((u8*)a +					le16_to_cpu(a->name_offset)),					a->name_length, 1, IGNORE_CASE,					upcase, upcase_len);			/*			 * If @name collates before a->name, there is no			 * matching attribute.			 */			if (rc == -1)				return -ENOENT;			/* If the strings are not equal, continue search. */			if (rc)				continue;			rc = ntfs_collate_names(name, name_len,					(ntfschar*)((u8*)a +					le16_to_cpu(a->name_offset)),					a->name_length, 1, CASE_SENSITIVE,					upcase, upcase_len);			if (rc == -1)				return -ENOENT;			if (rc)				continue;		}		/*		 * The names match or @name not present and attribute is		 * unnamed.  If no @val specified, we have found the attribute		 * and are done.		 */		if (!val)			return 0;		/* @val is present; compare values. */		else {			register int rc;			rc = memcmp(val, (u8*)a + le16_to_cpu(					a->data.resident.value_offset),					min_t(u32, val_len, le32_to_cpu(					a->data.resident.value_length)));			/*			 * If @val collates before the current attribute's			 * value, there is no matching attribute.			 */			if (!rc) {				register u32 avl;				avl = le32_to_cpu(						a->data.resident.value_length);				if (val_len == avl)					return 0;				if (val_len < avl)					return -ENOENT;			} else if (rc < 0)				return -ENOENT;		}	}	ntfs_error(vol->sb, "Inode is corrupt.  Run chkdsk.");	NVolSetErrors(vol);	return -EIO;}/** * load_attribute_list - load an attribute list into memory * @vol:		ntfs volume from which to read * @runlist:		runlist of the attribute list * @al_start:		destination buffer * @size:		size of the destination buffer in bytes * @initialized_size:	initialized size of the attribute list * * Walk the runlist @runlist and load all clusters from it copying them into * the linear buffer @al. The maximum number of bytes copied to @al is @size * bytes. Note, @size does not need to be a multiple of the cluster size. If * @initialized_size is less than @size, the region in @al between * @initialized_size and @size will be zeroed and not read from disk. * * Return 0 on success or -errno on error. */int load_attribute_list(ntfs_volume *vol, runlist *runlist, u8 *al_start,		const s64 size, const s64 initialized_size){	LCN lcn;	u8 *al = al_start;	u8 *al_end = al + initialized_size;	runlist_element *rl;	struct buffer_head *bh;	struct super_block *sb;	unsigned long block_size;	unsigned long block, max_block;	int err = 0;	unsigned char block_size_bits;	ntfs_debug("Entering.");	if (!vol || !runlist || !al || size <= 0 || initialized_size < 0 ||			initialized_size > size)		return -EINVAL;	if (!initialized_size) {		memset(al, 0, size);		return 0;	}	sb = vol->sb;	block_size = sb->s_blocksize;	block_size_bits = sb->s_blocksize_bits;	down_read(&runlist->lock);	rl = runlist->rl;	if (!rl) {		ntfs_error(sb, "Cannot read attribute list since runlist is "				"missing.");		goto err_out;		}	/* Read all clusters specified by the runlist one run at a time. */	while (rl->length) {		lcn = ntfs_rl_vcn_to_lcn(rl, rl->vcn);		ntfs_debug("Reading vcn = 0x%llx, lcn = 0x%llx.",				(unsigned long long)rl->vcn,				(unsigned long long)lcn);		/* The attribute list cannot be sparse. */		if (lcn < 0) {

⌨️ 快捷键说明

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