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

📄 attrib.c

📁 LINUX下读写NTFS分区的工具。 已经集成了通过LIBCONV库支持中文的代码。
💻 C
📖 第 1 页 / 共 5 页
字号:
	ofs = pos - (rl->vcn << vol->cluster_size_bits);	for (; count; rl++, ofs = 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) {			if (rl->lcn != (LCN)LCN_HOLE) {				ntfs_log_perror("%s: Bad run (%lld)", 						__FUNCTION__,						(long long)rl->lcn);				goto rl_err_out;			}			/* It is a hole, just zero the matching @b range. */			to_read = min(count, (rl->length <<					vol->cluster_size_bits) - ofs);			memset(b, 0, to_read);			/* Update progress counters. */			total += to_read;			count -= to_read;			b = (u8*)b + to_read;			continue;		}		/* It is a real lcn, read it into @dst. */		to_read = min(count, (rl->length << vol->cluster_size_bits) -				ofs);retry:		ntfs_log_trace("Reading 0x%llx bytes from vcn 0x%llx, lcn 0x%llx, "				"ofs 0x%llx.\n", to_read, rl->vcn, rl->lcn, ofs);		br = ntfs_pread(vol->dev, (rl->lcn << vol->cluster_size_bits) +				ofs, to_read, b);		/* If everything ok, update progress counters and continue. */		if (br > 0) {			total += br;			count -= br;			b = (u8*)b + br;			continue;		}		/* If the syscall was interrupted, try again. */		if (br == (s64)-1 && errno == EINTR)			goto retry;		if (total)			return total;		if (!br)			errno = EIO;		ntfs_log_perror("%s: ntfs_pread failed", __FUNCTION__);		return -1;	}	/* Finally, return the number of bytes read. */	return total + total2;rl_err_out:	if (total)		return total;	errno = EIO;	return -1;}/** * ntfs_attr_pread - read from an attribute specified by an ntfs_attr structure * @na:		ntfs attribute to read from * @pos:	byte position in the attribute to begin reading from * @count:	number of bytes to read * @b:		output data buffer * * This function will read @count bytes starting at offset @pos from the ntfs * attribute @na into the data buffer @b. * * On success, return the number of successfully read bytes. If this number is * lower than @count this means that the read reached end of file or that an * error was encountered during the read so that the read is partial. 0 means * end of file or nothing was read (also return 0 when @count is 0). * * On error and nothing has been read, return -1 with errno set appropriately * to the return code of ntfs_pread(), or to EINVAL in case of invalid * arguments. */s64 ntfs_attr_pread(ntfs_attr *na, const s64 pos, s64 count, void *b){	int ret;		if (!na || !na->ni || !na->ni->vol || !b || pos < 0 || count < 0) {		errno = EINVAL;		ntfs_log_perror("%s: na=%p  b=%p  pos=%lld  count=%lld",				__FUNCTION__, na, b, (long long)pos,				(long long)count);		return -1;	}		ntfs_log_enter("Entering for inode %lld attr 0x%x pos %lld count "		       "%lld\n", (unsigned long long)na->ni->mft_no,		       na->type, (long long)pos, (long long)count);	ret = ntfs_attr_pread_i(na, pos, count, b);		ntfs_log_leave("\n");	return ret;}static int ntfs_attr_fill_zero(ntfs_attr *na, s64 pos, s64 count){	char *buf;	s64 written, size, end = pos + count;	int ret = -1;	ntfs_log_trace("pos %lld, count %lld\n", (long long)pos, 		       (long long)count);		if (!na || pos < 0 || count < 0) {		errno = EINVAL;		goto err_out;	}		buf = ntfs_calloc(NTFS_BUF_SIZE);	if (!buf)		goto err_out;		while (pos < end) {		size = min(end - pos, NTFS_BUF_SIZE);		written = ntfs_rl_pwrite(na->ni->vol, na->rl, pos, size, buf);		if (written <= 0) {			ntfs_log_perror("Failed to zero space");			goto err_free;		}		pos += written;	}		ret = 0;err_free:		free(buf);err_out:	return ret;	}static int ntfs_attr_fill_hole(ntfs_attr *na, s64 count, s64 *ofs, 			       runlist_element **rl, VCN *update_from){	s64 to_write;	ntfs_volume *vol = na->ni->vol;	int eo, ret = -1;	runlist *rlc;	LCN lcn_seek_from = -1;	VCN cur_vcn, from_vcn;	to_write = min(count, ((*rl)->length << vol->cluster_size_bits) - *ofs);		cur_vcn = (*rl)->vcn;	from_vcn = (*rl)->vcn + (*ofs >> vol->cluster_size_bits);		ntfs_log_trace("count: %lld, cur_vcn: %lld, from: %lld, to: %lld, ofs: "		       "%lld\n", count, cur_vcn, from_vcn, to_write, *ofs);	 	/* Map whole runlist to be able update mapping pairs later. */	if (ntfs_attr_map_whole_runlist(na))		goto err_out;	 	/* Restore @*rl, it probably get lost during runlist mapping. */	*rl = ntfs_attr_find_vcn(na, cur_vcn);	if (!*rl) {		ntfs_log_error("Failed to find run after mapping runlist. "			       "Please report to %s.\n", NTFS_DEV_LIST);		errno = EIO;		goto err_out;	}		/* Search backwards to find the best lcn to start seek from. */	rlc = *rl;	while (rlc->vcn) {		rlc--;		if (rlc->lcn >= 0) {			lcn_seek_from = rlc->lcn + (from_vcn - rlc->vcn);			break;		}	}	if (lcn_seek_from == -1) {		/* Backwards search failed, search forwards. */		rlc = *rl;		while (rlc->length) {			rlc++;			if (rlc->lcn >= 0) {				lcn_seek_from = rlc->lcn - (rlc->vcn - from_vcn);				if (lcn_seek_from < -1)					lcn_seek_from = -1;				break;			}		}	}		rlc = ntfs_cluster_alloc(vol, from_vcn,				((*ofs + to_write - 1) >> vol->cluster_size_bits)				 + 1 + (*rl)->vcn - from_vcn, 				 lcn_seek_from, DATA_ZONE);	if (!rlc)		goto err_out;		*rl = ntfs_runlists_merge(na->rl, rlc);	if (!*rl) {		eo = errno;		ntfs_log_perror("Failed to merge runlists");		if (ntfs_cluster_free_from_rl(vol, rlc)) {			ntfs_log_perror("Failed to free hot clusters. "					"Please run chkdsk /f");		}		errno = eo;		goto err_out;	}	na->rl = *rl;	if (*update_from == -1)		*update_from = from_vcn;	*rl = ntfs_attr_find_vcn(na, cur_vcn);	if (!*rl) {		/*		 * It's definitely a BUG, if we failed to find @cur_vcn, because		 * we missed it during instantiating of the hole.		 */		ntfs_log_error("Failed to find run after hole instantiation. "			       "Please report to %s.\n", NTFS_DEV_LIST);		errno = EIO;		goto err_out;	}	/* If leaved part of the hole go to the next run. */	if ((*rl)->lcn < 0)		(*rl)++;	/* Now LCN shoudn't be less than 0. */	if ((*rl)->lcn < 0) {		ntfs_log_error("BUG! LCN is lesser than 0. "			       "Please report to the %s.\n", NTFS_DEV_LIST);		errno = EIO;		goto err_out;	}	if (*ofs) {		/* Clear non-sparse region from @cur_vcn to @*ofs. */		if (ntfs_attr_fill_zero(na, cur_vcn << vol->cluster_size_bits,					*ofs))			goto err_out;	}	if ((*rl)->vcn < cur_vcn) {		/*		 * Clusters that replaced hole are merged with		 * previous run, so we need to update offset.		 */		*ofs += (cur_vcn - (*rl)->vcn) << vol->cluster_size_bits;	}	if ((*rl)->vcn > cur_vcn) {		/*		 * We left part of the hole, so we need to update offset		 */		*ofs -= ((*rl)->vcn - cur_vcn) << vol->cluster_size_bits;	}		ret = 0;err_out:	return ret;}/** * ntfs_attr_pwrite - positioned write to an ntfs attribute * @na:		ntfs attribute to write to * @pos:	position in the attribute to write to * @count:	number of bytes to write * @b:		data buffer to write to disk * * This function will write @count bytes from data buffer @b to ntfs attribute * @na at position @pos. * * On success, return the number of successfully written bytes. If this number * is lower than @count 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 @count is 0). * * On error and nothing has been written, return -1 with errno set * appropriately to the return code of ntfs_pwrite(), or to EINVAL in case of * invalid arguments. */s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b){	s64 written, to_write, ofs, old_initialized_size, old_data_size;	s64 total = 0;	VCN update_from = -1;	ntfs_volume *vol;	ntfs_attr_search_ctx *ctx = NULL;	runlist_element *rl;	s64 eo, hole;	struct {		unsigned int undo_initialized_size	: 1;		unsigned int undo_data_size		: 1;	} need_to = { 0, 0 };	ntfs_log_enter("Entering for inode 0x%llx, attr 0x%x, pos 0x%llx, count "			"0x%llx.\n", na->ni->mft_no, na->type, (long long)pos,			(long long)count);		if (!na || !na->ni || !na->ni->vol || !b || pos < 0 || count < 0) {		errno = EINVAL;		ntfs_log_perror("%s", __FUNCTION__);		goto errno_set;	}	vol = na->ni->vol;	/*	 * Encrypted non-resident attributes are not supported.  We return	 * access denied, which is what Windows NT4 does, too.	 */	if (NAttrEncrypted(na) && NAttrNonResident(na)) {		errno = EACCES;		goto errno_set;	}	/* If this is a compressed attribute it needs special treatment. */	if (NAttrCompressed(na)) {		// TODO: Implement writing compressed attributes! (AIA)		// return ntfs_attr_pwrite_compressed(ntfs_attr *na,		//		const s64 pos, s64 count, void *b);		errno = EOPNOTSUPP;		goto errno_set;	}		if (!count)		goto out;	/* If the write reaches beyond the end, extend the attribute. */	old_data_size = na->data_size;	if (pos + count > na->data_size) {		if (ntfs_attr_truncate(na, pos + count)) {			ntfs_log_perror("Failed to enlarge attribute");			goto errno_set;		}		need_to.undo_data_size = 1;	}	old_initialized_size = na->initialized_size;	/* If it is a resident attribute, write the data to the mft record. */	if (!NAttrNonResident(na)) {		char *val;		ctx = ntfs_attr_get_search_ctx(na->ni, NULL);		if (!ctx)			goto err_out;		if (ntfs_attr_lookup(na->type, na->name, na->name_len, 0,				0, NULL, 0, ctx)) {			ntfs_log_perror("%s: lookup failed", __FUNCTION__);			goto err_out;		}		val = (char*)ctx->attr + le16_to_cpu(ctx->attr->value_offset);		if (val < (char*)ctx->attr || val +				le32_to_cpu(ctx->attr->value_length) >				(char*)ctx->mrec + vol->mft_record_size) {			errno = EIO;			ntfs_log_perror("%s: Sanity check failed", __FUNCTION__);			goto err_out;		}		memcpy(val + pos, b, count);		if (ntfs_mft_record_write(vol, ctx->ntfs_ino->mft_no,				ctx->mrec)) {			/*			 * NOTE: We are in a bad state at this moment. We have			 * dirtied the mft record but we failed to commit it to			 * disk. Since we have read the mft record ok before,			 * it is unlikely to fail writing it, so is ok to just			 * return error here... (AIA)			 */			ntfs_log_perror("%s: failed to write mft record", __FUNCTION__);			goto err_out;		}		ntfs_attr_put_search_ctx(ctx);		total = count;		goto out;	}		/* Handle writes beyond initialized_size. */	if (pos + count > na->initialized_size) {		if (ntfs_attr_map_whole_runlist(na))			goto err_out;		/* Set initialized_size to @pos + @count. */		ctx = ntfs_attr_get_search_ctx(na->ni, NULL);		if (!ctx)			goto err_out;		if (ntfs_attr_lookup(na->type, na->name, na->name_len, 0,				0, NULL, 0, ctx))			goto err_out;				/* If write starts beyond initialized_size, zero the gap. */		if (pos > na->initialized_size)			if (ntfs_attr_fill_zero(na, na->initialized_size, 						pos - na->initialized_size))				goto err_out;					ctx->attr->initialized_size = cpu_to_sle64(pos + count);		if (ntfs_mft_record_write(vol, ctx->ntfs_ino->mft_no,				ctx->mrec)) {			/*			 * Undo the change in the in-memory copy and send it			 * back for writing.			 */			ctx->attr->initialized_size =					cpu_to_sle64(old_initialized_size);			ntfs_mft_record_write(vol, ctx->ntfs_ino->mft_no,					ctx->mrec);			goto err_out;		}		na->initialized_size = pos + count;		ntfs_attr_put_search_ctx(ctx);		ctx = NULL;		/*		 * NOTE: At this point the initialized_size in the mft record		 * has been updated BUT there is random data on disk thus if		 * we decide to abort, we MUST change the initialized_size		 * again.		 */		need_to.undo_initialized_size = 1;	}	/* Find the runlist element containing the vcn. */	rl = ntfs_attr_find_vcn(na, pos >> vol->cluster_size_bits);	if (!rl) {		/*		 * If the vcn is not present it is an out of bounds write.		 * However, we already extended the size of the attribute,		 * so getting this here must be an error of some kind.		 */		if (errno == ENOENT) {			errno = EIO;			ntfs_log_perror("%s: Failed to find VCN #1", __FUNCTION__);		}		goto err_out;

⌨️ 快捷键说明

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