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

📄 attrib.c

📁 LINUX下读写NTFS分区的工具。 已经集成了通过LIBCONV库支持中文的代码。
💻 C
📖 第 1 页 / 共 5 页
字号:
	}	/*	 * Scatter the data from the linear data buffer to the volume. Note, a	 * partial final vcn is taken care of by the @count capping of write	 * length.	 */	ofs = pos - (rl->vcn << vol->cluster_size_bits);	for (hole = 0; count; rl++, ofs = 0, hole = 0) {		if (rl->lcn == LCN_RL_NOT_MAPPED) {			rl = ntfs_attr_find_vcn(na, rl->vcn);			if (!rl) {				if (errno == ENOENT) {					errno = EIO;					ntfs_log_perror("%s: Failed to find VCN"							" #2", __FUNCTION__);				}				goto rl_err_out;			}			/* Needed for case when runs merged. */			ofs = pos + total - (rl->vcn << vol->cluster_size_bits);		}		if (!rl->length) {			errno = EIO;			ntfs_log_perror("%s: Zero run length", __FUNCTION__);			goto rl_err_out;		}		if (rl->lcn < (LCN)0) {						hole = rl->vcn + rl->length;			if (rl->lcn != (LCN)LCN_HOLE) {				errno = EIO;				ntfs_log_perror("%s: Unexpected LCN (%lld)", 						__FUNCTION__,						(long long)rl->lcn);				goto rl_err_out;			}						if (ntfs_attr_fill_hole(na, count, &ofs, &rl, &update_from))				goto err_out;		}		/* It is a real lcn, write it to the volume. */		to_write = min(count, (rl->length << vol->cluster_size_bits) - ofs);retry:		ntfs_log_trace("Writing %lld bytes to vcn %lld, lcn %lld, ofs "			       "%lld.\n", to_write, rl->vcn, rl->lcn, ofs);		if (!NVolReadOnly(vol)) {						s64 wpos = (rl->lcn << vol->cluster_size_bits) + ofs;			s64 wend = (rl->vcn << vol->cluster_size_bits) + ofs + to_write;			u32 bsize = vol->cluster_size;			s64 rounded = ((wend + bsize - 1) & ~(s64)(bsize - 1)) - wend;			/*			 * Zero fill to cluster boundary if we're writing to an			 * ex-sparse cluster or we're at the end of the attribute.			 * This will cause the kernel not to seek and read disk 			 * blocks during write(2) to fill the end of the buffer 			 * which increases write speed by 2-10 fold typically.			 */			if ((rounded && (wend < (hole << vol->cluster_size_bits))) || 			    (((to_write % bsize) && 			      (ofs + to_write == na->initialized_size)))) {								char *cb;								rounded += to_write;								cb = ntfs_malloc(rounded);				if (!cb)					goto err_out;								memcpy(cb, b, to_write);				memset(cb + to_write, 0, rounded - to_write);								written = ntfs_pwrite(vol->dev, wpos, rounded, cb); 				if (written == rounded)					written = to_write;								free(cb);			} else				written = ntfs_pwrite(vol->dev, wpos, to_write, b);		} else			written = to_write;		/* If everything ok, update progress counters and continue. */		if (written > 0) {			total += written;			count -= written;			b = (const u8*)b + written;			continue;		}		/* If the syscall was interrupted, try again. */		if (written == (s64)-1 && errno == EINTR)			goto retry;		if (!written)			errno = EIO;		goto rl_err_out;	}done:	if (ctx)		ntfs_attr_put_search_ctx(ctx);	/* Update mapping pairs if needed. */	if (update_from != -1)		if (ntfs_attr_update_mapping_pairs(na, 0 /*update_from*/)) {			/*			 * FIXME: trying to recover by goto rl_err_out; 			 * could cause driver hang by infinite looping.			 */			total = -1;			goto out;		}out:		ntfs_log_leave("\n");	return total;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;		ntfs_log_perror("%s", __FUNCTION__);		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. */			ntfs_log_perror("%s #1", __FUNCTION__);			if (!i)				return err;			bk_cnt = i;			break;		}	}	/* Write the prepared data. */	written = ntfs_attr_pwrite(na, pos, bk_cnt * bk_size, src);	if (written <= 0) {		ntfs_log_perror("%s: written=%lld", __FUNCTION__,				(long long)written);	}	/* 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.

⌨️ 快捷键说明

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