attrib.c

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

C
1,911
字号
 * 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;	ntfschar *upcase;	u32 upcase_len;	if (ic == IGNORE_CASE) {		vol = ctx->ntfs_ino->vol;		upcase = vol->upcase;		upcase_len = vol->upcase_len;	} else {		vol = NULL;		upcase = NULL;		upcase_len = 0;	}	/*	 * 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(NULL, "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;	/* Read all clusters specified by the runlist one run at a time. */	while (rl->length) {		lcn = ntfs_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) {			ntfs_error(sb, "ntfs_vcn_to_lcn() failed. Cannot read "					"attribute list.");			goto err_out;		}		block = lcn << vol->cluster_size_bits >> block_size_bits;		/* Read the run from device in chunks of block_size bytes. */		max_block = block + (rl->length << vol->cluster_size_bits >>				block_size_bits);		ntfs_debug("max_block = 0x%lx.", max_block);		do {			ntfs_debug("Reading block = 0x%lx.", block);			bh = sb_bread(sb, block);			if (!bh) {				ntfs_error(sb, "sb_bread() failed. Cannot "						"read attribute list.");				goto err_out;			}			if (al + block_size >= al_end)				goto do_final;			memcpy(al, bh->b_data, block_size);			brelse(bh);			al += block_size;		} while (++block < max_block);		rl++;	}	if (initialized_size < size) {initialize:		memset(al_start + initialized_size, 0, size - initialized_size);	}done:	up_read(&runlist->lock);	return err;do_final:	if (al < al_end) {		/*		 * Partial block.		 *		 * Note: The attribute list can be smaller than its allocation		 * by multiple clusters.  This has been encountered by at least		 * two people running Windows XP, thus we cannot do any		 * truncation sanity checking here. (AIA)		 */		memcpy(al, bh->b_data, al_end - al);		brelse(bh);		if (initialized_size < size)			goto initialize;		goto done;	}	brelse(bh);	/* Real overflow! */	ntfs_error(sb, "Attribute list buffer overflow. Read attribute list "			"is truncated.");err_out:	err = -EIO;	goto done;}/** * ntfs_external_attr_find - find an attribute in the attribute list of an inode * @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) * @lowest_vcn:	lowest vcn to find (optional, non-resident attributes only) * @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. * * Find an attribute by searching the attribute list for the corresponding * attribute list entry.  Having found the entry, map the mft record if the * attribute is in a different mft record/inode, ntfs_attr_find() the attribute * in there and return it. * * On first search @ctx->ntfs_ino must be the base mft record and @ctx must * have been obtained from a call to ntfs_attr_get_search_ctx().  On subsequent * calls @ctx->ntfs_ino can be any extent inode, too (@ctx->base_ntfs_ino is * then the base inode). * * After finishing with the attribute/mft record you need to call * ntfs_attr_put_search_ctx() to cleanup the search context (unmapping any * mapped inodes, etc). * * If the attribute is found, ntfs_external_attr_find() returns 0 and * @ctx->attr will point to the found attribute.  @ctx->mrec will point to the * mft record in which @ctx->attr is located and @ctx->al_entry will point to * the attribute list entry for the attribute. * * If the attribute is not found, ntfs_external_attr_find() returns -ENOENT and * @ctx->attr will point to the attribute in the base mft record before which * the attribute being searched for would need to be inserted if such an action * were to be desired.  @ctx->mrec will point to the mft record in which * @ctx->attr is located and @ctx->al_entry will point to the attribute list * entry of the attribute before which the attribute being searched for would * need to be inserted if such an action were to be desired. * * Thus to insert the not found attribute, one wants to add the attribute to * @ctx->mrec (the base mft record) and if there is not enough space, the * attribute should be placed in a newly allocated extent mft record.  The * attribute list entry for the inserted attribute should be inserted in the * attribute list attribute at @ctx->al_entry. * * On actual error, ntfs_external_attr_find() returns -EIO.  In this case * @ctx->attr is undefined and in particular do not rely on it not changing. */static int ntfs_external_attr_find(const ATTR_TYPE type,		const ntfschar *name, const u32 name_len,		const IGNORE_CASE_BOOL ic, const VCN lowest_vcn,		const u8 *val, const u32 val_len, ntfs_attr_search_ctx *ctx){	ntfs_inode *base_ni, *ni;	ntfs_volume *vol;	ATTR_LIST_ENTRY *al_entry, *next_al_entry;	u8 *al_start, *al_end;	ATTR_RECORD *a;	ntfschar *al_name;	u32 al_name_len;	int err = 0;	static const char *es = " Unmount and run chkdsk.";	ni = ctx->ntfs_ino;	base_ni = ctx->base_ntfs_ino;	ntfs_debug("Entering for inode 0x%lx, type 0x%x.", ni->mft_no, type);	if (!base_ni) {		/* First call happens with the base mft record. */		base_ni = ctx->base_ntfs_ino = ctx->ntfs_ino;		ctx->base_mrec = ctx->mrec;	}	if (ni == base_ni)		ctx->base_attr = ctx->attr;	if (type == AT_END)		goto not_found;	vol = base_ni->vol;	al_start = base_ni->attr_list;	al_end = al_start + base_ni->attr_list_size;	if (!ctx->al_entry)		ctx->al_entry = (ATTR_LIST_ENTRY*)al_start;	/*	 * Iterate over entries in attribute list starting at @ctx->al_entry,	 * or the entry following that, if @ctx->is_first is TRUE.	 */	if (ctx->is_first) {		al_entry = ctx->al_entry;		ctx->is_first = FALSE;	} else		al_entry = (ATTR_LIST_ENTRY*)((u8*)ctx->al_entry +				le16_to_cpu(ctx->al_entry->length));	for (;; al_entry = next_al_entry) {		/* Out of bounds check. */		if ((u8*)al_entry < base_ni->attr_list ||				(u8*)al_entry > al_end)			break;	/* Inode is corrupt. */		ctx->al_entry = al_entry;		/* Catch the end of the attribute list. */		if ((u8*)al_entry == al_end)			goto not_found;		if (!al_entry->length)			break;		if ((u8*)al_entry + 6 > al_end || (u8*)al_entry +				le16_to_cpu(al_entry->length) > al_end)

⌨️ 快捷键说明

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