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

📄 attrib.c

📁 LINUX下读写NTFS分区的工具。 已经集成了通过LIBCONV库支持中文的代码。
💻 C
📖 第 1 页 / 共 5 页
字号:
		 * Otherwise, match any attribute.		 */		if (name == AT_UNNAMED) {			/* The search failed if the found attribute is named. */			if (a->name_length) {				errno = ENOENT;				return -1;			}		} else if (name && !ntfs_names_are_equal(name, name_len,			    (ntfschar*)((char*)a + le16_to_cpu(a->name_offset)),			    a->name_length, ic, upcase, upcase_len)) {			register int rc;			rc = ntfs_names_collate(name, name_len,					(ntfschar*)((char*)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) {				errno = ENOENT;				return -1;			}			/* If the strings are not equal, continue search. */			if (rc)				continue;			rc = ntfs_names_collate(name, name_len,					(ntfschar*)((char*)a +					le16_to_cpu(a->name_offset)),					a->name_length, 1, CASE_SENSITIVE,					upcase, upcase_len);			if (rc == -1) {				errno = ENOENT;				return -1;			}			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, (char*)a +le16_to_cpu(a->value_offset),					min(val_len,					le32_to_cpu(a->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->value_length);				if (val_len == avl)					return 0;				if (val_len < avl) {					errno = ENOENT;					return -1;				}			} else if (rc < 0) {				errno = ENOENT;				return -1;			}		}	}	ntfs_log_debug("ntfs_attr_find(): File is corrupt. Run chkdsk.\n");	errno = EIO;	return -1;}void ntfs_attr_name_free(char **name){	if (*name) {		free(*name);		*name = NULL;	}}char *ntfs_attr_name_get(const ntfschar *uname, const int uname_len){	char *name = NULL;	int name_len;	name_len = ntfs_ucstombs(uname, uname_len, &name, 0);	if (name_len < 0) {		ntfs_log_perror("ntfs_ucstombs");		return NULL;	} else if (name_len > 0)		return name;	ntfs_attr_name_free(&name);	return NULL;}/** * 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 shouldn't 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 for read * if the attribute is in a different mft record/inode, find the attribute in * there and return it. * * If @type is AT_UNUSED, return the first found attribute, i.e. one can * enumerate all attributes by setting @type to AT_UNUSED and then calling * ntfs_external_attr_find() repeatedly until it returns -1 with errno set to * ENOENT to indicate that there are no more entries. During the enumeration, * each successful call of ntfs_external_attr_find() will return the next * attribute described by the attribute list of the base mft record described * by the search context @ctx. * * If @type is AT_END, seek to the end of the base mft record ignoring the * attribute list completely and return -1 with errno set to ENOENT.  AT_END is * not a valid attribute, its length is zero for example, thus it is safer to * return error instead of success in this case. * * If @name is AT_UNNAMED search for an unnamed attribute. If @name is present * but not AT_UNNAMED search for a named attribute matching @name. Otherwise, * match both named and unnamed attributes. * * On first search @ctx->ntfs_ino must be the inode of 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 extent inodes, etc). * * Return 0 if the search was successful and -1 if not, with errno set to the * error code. * * On success, @ctx->attr is the found attribute, it is in mft record * @ctx->mrec, and @ctx->al_entry is the attribute list entry for this * attribute with @ctx->base_* being the base mft record to which @ctx->attr * belongs. * * On error ENOENT, i.e. attribute not found, @ctx->attr is set to the * attribute which collates just after the attribute being searched for in the * base ntfs inode, i.e. if one wants to add the attribute to the mft record * this is the correct place to insert it into, and if there is not enough * space, the attribute should be placed in an extent mft record. * @ctx->al_entry points to the position within @ctx->base_ntfs_ino->attr_list * at which the new attribute's attribute list entry should be inserted.  The * other @ctx fields, base_ntfs_ino, base_mrec, and base_attr are set to NULL. * The only exception to this is when @type is AT_END, in which case * @ctx->al_entry is set to NULL also (see above). * * The following error codes are defined: *	ENOENT	Attribute not found, not an error as such. *	EINVAL	Invalid arguments. *	EIO	I/O error or corrupt data structures found. *	ENOMEM	Not enough memory to allocate necessary buffers. */static int ntfs_external_attr_find(ATTR_TYPES 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;	BOOL is_first_search = FALSE;	ni = ctx->ntfs_ino;	base_ni = ctx->base_ntfs_ino;	ntfs_log_trace("Entering for inode %lld, attribute type 0x%x.\n",			(unsigned long long)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;		is_first_search = TRUE;	}	/*	 * 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;		/*		 * If an enumeration and the first attribute is higher than		 * the attribute list itself, need to return the attribute list		 * attribute.		 */		if ((type == AT_UNUSED) && is_first_search &&				le32_to_cpu(al_entry->type) >				le32_to_cpu(AT_ATTRIBUTE_LIST))			goto find_attr_list_attr;	} else {		al_entry = (ATTR_LIST_ENTRY*)((char*)ctx->al_entry +				le16_to_cpu(ctx->al_entry->length));		/*		 * If this is an enumeration and the attribute list attribute		 * is the next one in the enumeration sequence, just return the		 * attribute list attribute from the base mft record as it is		 * not listed in the attribute list itself.		 */		if ((type == AT_UNUSED) && le32_to_cpu(ctx->al_entry->type) <				le32_to_cpu(AT_ATTRIBUTE_LIST) &&				le32_to_cpu(al_entry->type) >				le32_to_cpu(AT_ATTRIBUTE_LIST)) {			int rc;find_attr_list_attr:			/* Check for bogus calls. */			if (name || name_len || val || val_len || lowest_vcn) {				errno = EINVAL;				return -1;			}			/* We want the base record. */			ctx->ntfs_ino = base_ni;			ctx->mrec = ctx->base_mrec;			ctx->is_first = TRUE;			/* Sanity checks are performed elsewhere. */			ctx->attr = (ATTR_RECORD*)((u8*)ctx->mrec +					le16_to_cpu(ctx->mrec->attrs_offset));			/* Find the attribute list attribute. */			rc = ntfs_attr_find(AT_ATTRIBUTE_LIST, NULL, 0,					IGNORE_CASE, NULL, 0, ctx);			/*			 * Setup the search context so the correct			 * attribute is returned next time round.			 */			ctx->al_entry = al_entry;			ctx->is_first = TRUE;			/* Got it. Done. */			if (!rc)				return 0;			/* Error! If other than not found return it. */			if (errno != ENOENT)				return rc;			/* Not found?!? Absurd! Must be a bug... )-: */			ntfs_log_error("Extant attribute list wasn't found\n");			errno = EINVAL;			return -1;		}	}	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 (type != AT_UNUSED) {			if (le32_to_cpu(al_entry->type) > le32_to_cpu(type))				goto not_found;			if (type != al_entry->type)				continue;		}		al_name_len = al_entry->name_length;		al_name = (ntfschar*)((u8*)al_entry + al_entry->name_offset);		/*		 * If !@type we want the attribute represented by this		 * attribute list entry.		 */		if (type == AT_UNUSED)			goto is_enumeration;		/*		 * If @name is AT_UNNAMED we want an unnamed attribute.		 * If @name is present, compare the two names.		 * Otherwise, match any attribute.		 */		if (name == AT_UNNAMED) {			if (al_name_len)				goto not_found;		} else if (name && !ntfs_names_are_equal(al_name, al_name_len,				name, name_len, ic, vol->upcase,				vol->upcase_len)) {			register int rc;			rc = ntfs_names_collate(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_names_collate(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_names_are_equal((ntfschar*)((char*)					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;is_enumeration:		if (MREF_LE(al_entry->mft_reference) == ni->mft_no) {			if (MSEQNO_LE(al_entry->mft_reference) !=					le16_to_cpu(					ni->mrec->sequence_number)) {				ntfs_log_debug("Found stale mft reference in "						"attribute list!\n");				break;			}		} else { /* Mft references do not match. */			/* 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. */				ni = ntfs_extent_inode_open(base_ni,						al_entry->mft_reference);				if (!ni) {					ntfs_log_perror("Failed to map extent inode");					break;				}				ctx->ntfs_ino = ni;				ctx->mrec = ni->mrec;			}		}		a = ctx->attr = (ATTR_RECORD*)((char*)ctx->mrec +				le16_to_cpu(ctx->mrec->attrs_offset));		/*		 * ctx->ntfs_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.		 *		 * Use a manual loop so we can still use break and continue		 * with the same meanings as above.		 */do_next_attr_loop:		if ((char*)a < (char*)ctx->mrec || (char*)a > (char*)ctx->mrec +				le32_to_cpu(ctx->mrec->bytes_allocated))			break;		if (a->type == AT_END)			continue;		if (!a->length)			break;		if (al_entry->instance != a->instance)			goto do_next_attr;		/*		 * If the type and/or the name are/is mismatched b

⌨️ 快捷键说明

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