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

📄 attrib.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
			ntfs_error(sb, "ntfs_rl_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)			break;		next_al_entry = (ATTR_LIST_ENTRY*)((u8*)al_entry +				le16_to_cpu(al_entry->length));		if (le32_to_cpu(al_entry->type) > le32_to_cpu(type))			goto not_found;		if (type != al_entry->type)			continue;		/*		 * If @name is present, compare the two names.  If @name is		 * missing, assume we want an unnamed attribute.		 */		al_name_len = al_entry->name_length;		al_name = (ntfschar*)((u8*)al_entry + al_entry->name_offset);		if (!name) {			if (al_name_len)				goto not_found;		} else if (!ntfs_are_names_equal(al_name, al_name_len, name,				name_len, ic, vol->upcase, vol->upcase_len)) {			register int rc;			rc = ntfs_collate_names(name, name_len, al_name,					al_name_len, 1, IGNORE_CASE,					vol->upcase, vol->upcase_len);			/*			 * If @name collates before al_name, there is no			 * matching attribute.			 */			if (rc == -1)				goto not_found;			/* If the strings are not equal, continue search. */			if (rc)				continue;			/*			 * FIXME: Reverse engineering showed 0, IGNORE_CASE but			 * that is inconsistent with ntfs_attr_find().  The			 * subsequent rc checks were also different.  Perhaps I			 * made a mistake in one of the two.  Need to recheck			 * which is correct or at least see what is going on...			 * (AIA)			 */			rc = ntfs_collate_names(name, name_len, al_name,					al_name_len, 1, CASE_SENSITIVE,					vol->upcase, vol->upcase_len);			if (rc == -1)				goto not_found;			if (rc)				continue;		}		/*		 * The names match or @name not present and attribute is		 * unnamed.  Now check @lowest_vcn.  Continue search if the		 * next attribute list entry still fits @lowest_vcn.  Otherwise		 * we have reached the right one or the search has failed.		 */		if (lowest_vcn && (u8*)next_al_entry >= al_start	    &&				(u8*)next_al_entry + 6 < al_end		    &&				(u8*)next_al_entry + le16_to_cpu(					next_al_entry->length) <= al_end    &&				sle64_to_cpu(next_al_entry->lowest_vcn) <=					lowest_vcn			    &&				next_al_entry->type == al_entry->type	    &&				next_al_entry->name_length == al_name_len   &&				ntfs_are_names_equal((ntfschar*)((u8*)					next_al_entry +					next_al_entry->name_offset),					next_al_entry->name_length,					al_name, al_name_len, CASE_SENSITIVE,					vol->upcase, vol->upcase_len))			continue;		if (MREF_LE(al_entry->mft_reference) == ni->mft_no) {			if (MSEQNO_LE(al_entry->mft_reference) != ni->seq_no) {				ntfs_error(vol->sb, "Found stale mft "						"reference in attribute list "						"of base inode 0x%lx.%s",						base_ni->mft_no, es);				err = -EIO;				break;			}		} else { /* Mft references do not match. */			/* If there is a mapped record unmap it first. */			if (ni != base_ni)				unmap_extent_mft_record(ni);			/* Do we want the base record back? */			if (MREF_LE(al_entry->mft_reference) ==					base_ni->mft_no) {				ni = ctx->ntfs_ino = base_ni;				ctx->mrec = ctx->base_mrec;			} else {				/* We want an extent record. */				ctx->mrec = map_extent_mft_record(base_ni,						le64_to_cpu(						al_entry->mft_reference), &ni);				if (IS_ERR(ctx->mrec)) {					ntfs_error(vol->sb, "Failed to map "							"extent mft record "							"0x%lx of base inode "							"0x%lx.%s",							MREF_LE(al_entry->							mft_reference),							base_ni->mft_no, es);					err = PTR_ERR(ctx->mrec);					if (err == -ENOENT)						err = -EIO;					/* Cause @ctx to be sanitized below. */					ni = NULL;					break;				}				ctx->ntfs_ino = ni;			}			ctx->attr = (ATTR_RECORD*)((u8*)ctx->mrec +					le16_to_cpu(ctx->mrec->attrs_offset));		}		/*		 * ctx->vfs_ino, ctx->mrec, and ctx->attr now point to the		 * mft record containing the attribute represented by the		 * current al_entry.		 */		/*		 * We could call into ntfs_attr_find() to find the right		 * attribute in this mft record but this would be less		 * efficient and not quite accurate as ntfs_attr_find() ignores		 * the attribute instance numbers for example which become		 * important when one plays with attribute lists.  Also,		 * because a proper match has been found in the attribute list		 * entry above, the comparison can now be optimized.  So it is		 * worth re-implementing a simplified ntfs_attr_find() here.		 */		a = ctx->attr;		/*		 * Use a manual loop so we can still use break and continue		 * with the same meanings as above.		 */do_next_attr_loop:		if ((u8*)a < (u8*)ctx->mrec || (u8*)a > (u8*)ctx->mrec +				le32_to_cpu(ctx->mrec->bytes_allocated))			break;		if (a->type == AT_END)			break;		if (!a->length)			break;		if (al_entry->instance != a->instance)			goto do_next_attr;		/*		 * If the type and/or the name are mismatched between the		 * attribute list entry and the attribute record, there is		 * corruption so we break and return error EIO.		 */		if (al_entry->type != a->type)			break;		if (!ntfs_are_names_equal((ntfschar*)((u8*)a +				le16_to_cpu(a->name_offset)), a->name_length,				al_name, al_name_len, CASE_SENSITIVE,				vol->upcase, vol->upcase_len))			break;		ctx->attr = a;		/*		 * If no @val specified or @val specified and it matches, we		 * have found it!		 */		if (!val || (!a->non_resident && le32_to_cpu(				a->data.resident.value_length) == val_len &&				!memcmp((u8*)a +				le16_to_cpu(a->data.resident.value_offset),				val, val_len))) {			ntfs_debug("Done, found.");			return 0;		}do_next_attr:		/* Proceed to the next attribute in the current mft record. */		a = (ATTR_RECORD*)((u8*)a + le32_to_cpu(a->length));		goto do_next_attr_loop;	}	if (!err) {		ntfs_error(vol->sb, "Base inode 0x%lx contains corrupt "				"attribute list attribute.%s", base_ni->mft_no,				es);		err = -EIO;	}	if (ni != base_ni) {		if (ni)			unmap_extent_mft_record(ni);		ctx->ntfs_ino = base_ni;		ctx->mrec = ctx->base_mrec;		ctx->attr = ctx->base_attr;	}	if (err != -ENOMEM)		NVolSetErrors(vol);	return err;not_found:	/*	 * If we were looking for AT_END, we reset the search context @ctx and	 * use ntfs_attr_find() to seek to the end of the base mft record.	 */	if (type == AT_END) {		ntfs_attr_reinit_search_ctx(ctx);		return ntfs_attr_find(AT_END, name, name_len, ic, val, val_len,				ctx);	}	/*	 * The attribute was not found.  Before we return, we want to ensure	 * @ctx->mrec and @ctx->attr indicate the position at which the	 * attribute should be inserted in the base mft record.  Since we also	 * want to preserve @ctx->al_entry we cannot reinitialize the search	 * context using ntfs_attr_reinit_search_ctx() as this would set	 * @ctx->al_entry to NULL.  Thus we do the necessary bits manually (see	 * ntfs_attr_init_search_ctx() below).  Note, we _only_ preserve	 * @ctx->al_entry as the remaining fields (base_*) are identical to	 * their non base_ counterparts and we cannot set @ctx->base_attr	 * correctly yet as we do not know what @ctx->attr will be set to by	 * the call to ntfs_attr_find() below.	 */	if (ni != base_ni)

⌨️ 快捷键说明

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