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

📄 attrib.c

📁 添加linux下对NTFS格式文件系统访问支持的源代码ntfs-3g
💻 C
📖 第 1 页 / 共 5 页
字号:
rl_err_out:	eo = errno;	if (total) {		if (need_to.undo_initialized_size) {			if (pos + total > na->initialized_size)				goto done;			/*			 * TODO: Need to try to change initialized_size. If it			 * succeeds goto done, otherwise goto err_out. (AIA)			 */			errno = EOPNOTSUPP;			goto err_out;		}		goto done;	}	errno = eo;err_out:	eo = errno;	if (need_to.undo_initialized_size) {		int err;		err = 0;		if (!ctx) {			ctx = ntfs_attr_get_search_ctx(na->ni, NULL);			if (!ctx)				err = 1;		} else			ntfs_attr_reinit_search_ctx(ctx);		if (!err) {			err = ntfs_attr_lookup(na->type, na->name,					na->name_len, 0, 0, NULL, 0, ctx);			if (!err) {				na->initialized_size = old_initialized_size;				ctx->attr->initialized_size = cpu_to_sle64(						old_initialized_size);				err = ntfs_mft_record_write(vol,						ctx->ntfs_ino->mft_no,						ctx->mrec);			}		}		if (err) {			/*			 * FIXME: At this stage could try to recover by filling			 * old_initialized_size -> new_initialized_size with			 * data or at least zeroes. (AIA)			 */			ntfs_log_error("Eeek! Failed to recover from error. "					"Leaving metadata in inconsistent "					"state! Run chkdsk!\n");		}	}	if (ctx)		ntfs_attr_put_search_ctx(ctx);	/* Update mapping pairs if needed. */	if (update_from != -1)		ntfs_attr_update_mapping_pairs(na, 0 /*update_from*/);	/* Restore original data_size if needed. */	if (need_to.undo_data_size && ntfs_attr_truncate(na, old_data_size))		ntfs_log_perror("Failed to restore data_size");	errno = eo;errno_set:	total = -1;	goto out;}/** * ntfs_attr_mst_pread - multi sector transfer protected ntfs attribute read * @na:		multi sector transfer protected ntfs attribute to read from * @pos:	byte position in the attribute to begin reading from * @bk_cnt:	number of mst protected blocks to read * @bk_size:	size of each mst protected block in bytes * @dst:	output data buffer * * This function will read @bk_cnt blocks of size @bk_size bytes each starting * at offset @pos from the ntfs attribute @na into the data buffer @b. * * On success, the multi sector transfer fixups are applied and the number of * read blocks is returned. If this number is lower than @bk_cnt this means * that the read has either reached end of attribute or that an error was * encountered during the read so that the read is partial. 0 means end of * attribute or nothing to read (also return 0 when @bk_cnt or @bk_size are 0). * * On error and nothing has been read, return -1 with errno set appropriately * to the return code of ntfs_attr_pread() or to EINVAL in case of invalid * arguments. * * NOTE: If an incomplete multi sector transfer is detected the magic is * changed to BAAD but no error is returned, i.e. it is possible that any of * the returned blocks have multi sector transfer errors. This should be * detected by the caller by checking each block with is_baad_recordp(&block). * The reasoning is that we want to fixup as many blocks as possible and we * want to return even bad ones to the caller so, e.g. in case of ntfsck, the * errors can be repaired. */s64 ntfs_attr_mst_pread(ntfs_attr *na, const s64 pos, const s64 bk_cnt,		const u32 bk_size, void *dst){	s64 br;	u8 *end;	ntfs_log_trace("Entering for inode 0x%llx, attr type 0x%x, pos 0x%llx.\n",			(unsigned long long)na->ni->mft_no, na->type,			(long long)pos);	if (bk_cnt < 0 || bk_size % NTFS_BLOCK_SIZE) {		errno = EINVAL;		return -1;	}	br = ntfs_attr_pread(na, pos, bk_cnt * bk_size, dst);	if (br <= 0)		return br;	br /= bk_size;	for (end = (u8*)dst + br * bk_size; (u8*)dst < end; dst = (u8*)dst +			bk_size)		ntfs_mst_post_read_fixup((NTFS_RECORD*)dst, bk_size);	/* Finally, return the number of blocks read. */	return br;}/** * ntfs_attr_mst_pwrite - multi sector transfer protected ntfs attribute write * @na:		multi sector transfer protected ntfs attribute to write to * @pos:	position in the attribute to write to * @bk_cnt:	number of mst protected blocks to write * @bk_size:	size of each mst protected block in bytes * @src:	data buffer to write to disk * * This function will write @bk_cnt blocks of size @bk_size bytes each from * data buffer @b to multi sector transfer (mst) protected ntfs attribute @na * at position @pos. * * On success, return the number of successfully written blocks. If this number * is lower than @bk_cnt this means that an error was encountered during the * write so that the write is partial. 0 means nothing was written (also * return 0 when @bk_cnt or @bk_size are 0). * * On error and nothing has been written, return -1 with errno set * appropriately to the return code of ntfs_attr_pwrite(), or to EINVAL in case * of invalid arguments. * * NOTE: We mst protect the data, write it, then mst deprotect it using a quick * deprotect algorithm (no checking). This saves us from making a copy before * the write and at the same time causes the usn to be incremented in the * buffer. This conceptually fits in better with the idea that cached data is * always deprotected and protection is performed when the data is actually * going to hit the disk and the cache is immediately deprotected again * simulating an mst read on the written data. This way cache coherency is * achieved. */s64 ntfs_attr_mst_pwrite(ntfs_attr *na, const s64 pos, s64 bk_cnt,		const u32 bk_size, void *src){	s64 written, i;	ntfs_log_trace("Entering for inode 0x%llx, attr type 0x%x, pos 0x%llx.\n",			(unsigned long long)na->ni->mft_no, na->type,			(long long)pos);	if (bk_cnt < 0 || bk_size % NTFS_BLOCK_SIZE) {		errno = EINVAL;		return -1;	}	if (!bk_cnt)		return 0;	/* Prepare data for writing. */	for (i = 0; i < bk_cnt; ++i) {		int err;		err = ntfs_mst_pre_write_fixup((NTFS_RECORD*)				((u8*)src + i * bk_size), bk_size);		if (err < 0) {			/* Abort write at this position. */			if (!i)				return err;			bk_cnt = i;			break;		}	}	/* Write the prepared data. */	written = ntfs_attr_pwrite(na, pos, bk_cnt * bk_size, src);	/* Quickly deprotect the data again. */	for (i = 0; i < bk_cnt; ++i)		ntfs_mst_post_write_fixup((NTFS_RECORD*)((u8*)src + i *				bk_size));	if (written <= 0)		return written;	/* Finally, return the number of complete blocks written. */	return written / bk_size;}/** * 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 shouldn't need to call this function directly. Use lookup_attr() 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 found, ntfs_attr_find() * returns 0 and @ctx->attr will point to the found attribute. * * If not found, ntfs_attr_find() returns -1, with errno set to 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 -1 with errno set to the error * code but not to ENOENT.  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 @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_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_attr_find() will return the next attribute in the * mft record @ctx->mrec. * * If @type is AT_END, seek to the end 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. This also allows us * to interoperate cleanly with ntfs_external_attr_find(). * * 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. * * If @ic is IGNORE_CASE, the @name comparison 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 don't * 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_TYPES 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;	ntfs_log_trace("attribute type 0x%x.\n", type);	if (ctx->ntfs_ino) {		vol = ctx->ntfs_ino->vol;		upcase = vol->upcase;		upcase_len = vol->upcase_len;	} else {		if (name && name != AT_UNNAMED) {			errno = EINVAL;			return -1;		}		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*)((char*)ctx->attr +				le32_to_cpu(ctx->attr->length));	for (;;	a = (ATTR_RECORD*)((char*)a + le32_to_cpu(a->length))) {		if (p2n(a) < p2n(ctx->mrec) || (char*)a > (char*)ctx->mrec +				le32_to_cpu(ctx->mrec->bytes_allocated))			break;		ctx->attr = a;		if (((type != AT_UNUSED) && (le32_to_cpu(a->type) >				le32_to_cpu(type))) ||				(a->type == AT_END)) {			errno = ENOENT;			return -1;		}		if (!a->length)			break;		/* If this is an enumeration return this attribute. */		if (type == AT_UNUSED)			return 0;		if (a->type != type)			continue;		/*		 * 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) {			/* 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

⌨️ 快捷键说明

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