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

📄 attrib.c

📁 一个在linux下挂载ntfs文件系统的好工具
💻 C
📖 第 1 页 / 共 5 页
字号:
				if (errno == ENOENT)					errno = EIO;				goto rl_err_out;			}			/* Needed for case when runs merged. */			ofs = pos + total - (rl->vcn << vol->cluster_size_bits);		}		if (!rl->length)			goto rl_err_out;		if (rl->lcn < (LCN)0) {			if (rl->lcn != (LCN)LCN_HOLE)				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;		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_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, total, old_initialized_size, old_data_size;	VCN update_from = -1;	ntfs_volume *vol;	ntfs_attr_search_ctx *ctx = NULL;	runlist_element *rl;	int eo;	struct {		unsigned int undo_initialized_size	: 1;		unsigned int undo_data_size		: 1;		unsigned int update_mapping_pairs	: 1;	} need_to = { 0, 0, 0 };	ntfs_log_trace("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;		return -1;	}	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;		return -1;	}	/* 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;		return -1;	}	/* Update access and change times if needed. */	if (na->type == AT_DATA || na->type == AT_INDEX_ROOT ||			na->type == AT_INDEX_ALLOCATION)		ntfs_inode_update_time(na->ni);	if (!count)		return 0;	/* 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)) {			eo = errno;			ntfs_log_trace("Attribute extend failed.\n");			errno = eo;			return -1;		}		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))			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;			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)			 */			goto err_out;		}		ntfs_attr_put_search_ctx(ctx);		return count;	}	total = 0;	/* 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) {			char *buf;			buf = ntfs_malloc(NTFS_BUF_SIZE);			if (!buf)				goto err_out;						memset(buf, 0, NTFS_BUF_SIZE);			ofs = na->initialized_size;			while (ofs < pos) {				to_write = min(pos - ofs, NTFS_BUF_SIZE);				written = ntfs_rl_pwrite(vol, na->rl, ofs,							to_write, buf);				if (written <= 0) {					ntfs_log_trace("Failed to zero space between "							"initialized size and @pos.\n");					free(buf);					goto err_out;				}				ofs += written;			}			free(buf);		}		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;		goto err_out;	}	/*	 * 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 (; 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;				goto rl_err_out;			}			/* Needed for case when runs merged. */			ofs = pos + total - (rl->vcn << vol->cluster_size_bits);		}		if (!rl->length) {			errno = EIO;			goto rl_err_out;		}		if (rl->lcn < (LCN)0) {			LCN lcn_seek_from = -1;			runlist *rlc;			VCN cur_vcn, from_vcn;			if (rl->lcn != (LCN)LCN_HOLE) {				errno = EIO;				goto rl_err_out;			}						to_write = min(count, (rl->length <<					vol->cluster_size_bits) - ofs);						/* Instantiate the hole. */			cur_vcn = rl->vcn;			from_vcn = rl->vcn + (ofs >> vol->cluster_size_bits);			ntfs_log_trace("Instantiate the hole with vcn 0x%llx.\n",					cur_vcn);			/*			 * 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("BUG! Failed to find run after "						"mapping whole runlist. Please "						"report to the %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);						break;					}				}			}			/* Allocate clusters to instantiate the hole. */			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) {				eo = errno;				ntfs_log_trace("Failed to allocate clusters for hole "						"instantiating.\n");				errno = eo;				goto err_out;			}			/* Merge runlists. */			rl = ntfs_runlists_merge(na->rl, rlc);			if (!rl) {				eo = errno;				ntfs_log_trace("Failed to merge runlists.\n");				if (ntfs_cluster_free_from_rl(vol, rlc)) {					ntfs_log_trace("Failed to free just "						"allocated clusters. Leaving "						"inconstant metadata. Run chkdsk\n");				}				errno = eo;				goto err_out;			}			na->rl = rl;			need_to.update_mapping_pairs = 1;			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("BUG! Failed to find run after "						"instantiating. Please report "						"to the %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) {				/*				 * Need to clear region between start of				 * @cur_vcn cluster and @ofs.				 */				char *buf;				buf = ntfs_malloc(ofs);				if (!buf)					goto err_out;								memset(buf, 0, ofs);				if (ntfs_rl_pwrite(vol, na->rl, cur_vcn <<							vol->cluster_size_bits,							ofs, buf) < 0) {					eo = errno;					ntfs_log_trace("Failed to zero area.\n");					free(buf);					errno = eo;					goto err_out;				}				free(buf);			}			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 update we need				 * to update offset				 */				ofs -= (rl->vcn - cur_vcn) <<					vol->cluster_size_bits;			}		}		/* 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 0x%llx bytes to vcn 0x%llx, lcn 0x%llx,"				" ofs 0x%llx.\n", to_write, rl->vcn, rl->lcn,				ofs);		if (!NVolReadOnly(vol))			written = ntfs_pwrite(vol->dev, (rl->lcn <<					vol->cluster_size_bits) + ofs,					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;

⌨️ 快捷键说明

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