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

📄 fastcopy.cpp

📁 FastCopy 利用缓冲技术加快文件拷贝
💻 CPP
📖 第 1 页 / 共 4 页
字号:

	if (fh == INVALID_HANDLE_VALUE) {
		total.errFiles++;
		SetErrFileID(stat->fileID);
		ConfirmErr("CreateFile", MakeAddr(dst, dstPrefixLen));
		return	FALSE;
	}
	if (isReOpen) {
#ifdef ACL_TEST
		fh2 = CreateFileV(dst, GENERIC_WRITE|WRITE_OWNER|WRITE_DAC, FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
#else
		fh2 = CreateFileV(dst, GENERIC_WRITE                      , FILE_SHARE_WRITE, 0, OPEN_EXISTING,                          0, 0);
#endif
	}

	if (file_size > writeReq->bufSize) {
		_int64	alloc_size = isNonBuf ? ALIGN_SIZE(file_size, dstSectorSize) : file_size;
		LONG	high_size = (LONG)(alloc_size >> 32);
		::SetFilePointer(fh, (LONG)alloc_size, &high_size, FILE_BEGIN);
		::SetEndOfFile(fh);
		::SetFilePointer(fh, 0, NULL, FILE_BEGIN);
	}

	while (remain > 0) {
		if ((ret = ::WriteFile(fh, writeReq->buf, remain >= writeReq->bufSize ? writeReq->bufSize : (DWORD)(isNonBuf ? ALIGN_SIZE(remain, dstSectorSize) : remain), &trans_size, NULL)) == FALSE) {
			SetErrFileID(stat->fileID);
			ConfirmErr("WriteFile", MakeAddr(dst, dstPrefixLen), GetLastError() != ERROR_DISK_FULL);
			break;
		}
		if ((remain -= trans_size) > 0) {	// 懕偒偑偁傞
			total.writeTrans += trans_size;
			if (&sv_stat != stat)		// file stat 偺戅旔
				memcpy((stat = &sv_stat), &writeReq->stat, offsetof(FileStat, cFileName));

			if (RecvRequest() == FALSE || writeReq->command != WRITE_FILE_CONT) {
				ret = FALSE;
				remain = 0;
				break;
			}
		}
		else {
			total.writeTrans += trans_size + remain;
		}
		if (autoSlow) {
			Sleep(autoSlow);
		}
	}

	if (isReOpen) {
		::CloseHandle(fh);
		if (fh2 == INVALID_HANDLE_VALUE) {
			for (int i=0; i < 10 && !isAbort; i++) {	// 僂僀儖僗僠僃僢僋僜僼僩懳嶔
				total.openRetry++;

#ifdef ACL_TEST
				if ((fh2 = CreateFileV(dst, GENERIC_WRITE|WRITE_OWNER|WRITE_DAC, FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)) != INVALID_HANDLE_VALUE)
#else
				if ((fh2 = CreateFileV(dst, GENERIC_WRITE                      , FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)) != INVALID_HANDLE_VALUE)
#endif
					break;
				if (::GetLastError() != ERROR_SHARING_VIOLATION)
					break;
				::Sleep(i * i * 10);
			}
			if (fh2 == INVALID_HANDLE_VALUE) {
				total.errFiles++;
				ConfirmErr("CreateFile2", MakeAddr(dst, dstPrefixLen));
				return	FALSE;
			}
		}
		fh = fh2;
	}

	if (ret && remain != 0) {
		::SetFilePointer(fh, stat->nFileSizeLow, (LONG *)&stat->nFileSizeHigh, FILE_BEGIN);
		if ((ret = ::SetEndOfFile(fh)) == FALSE)
			ConfirmErr("SetEndOfFile", MakeAddr(dst, dstPrefixLen));
	}
	if (ret) {
#ifdef ACL_TEST
		if (acl_size) {
			void	*content = NULL;
			DWORD	size;
			if (::BackupWrite(fh, (BYTE *)&acl_sid, offsetof(WIN32_STREAM_ID, cStreamName), &size, FALSE, TRUE, &content)) {
				if (!::BackupWrite(fh, (BYTE *)&acl_data, acl_size, &acl_size, FALSE, TRUE, &content))
					ConfirmErr("BackupWrite", MakeAddr(dst, dstPrefixLen));
			}
			::BackupWrite(fh, NULL, NULL, NULL, TRUE, TRUE, &content);
		}
#endif
		::SetFileTime(fh, &stat->ftCreationTime, &stat->ftLastAccessTime, &stat->ftLastWriteTime);
	}

	::CloseHandle(fh);

	if (ret) {
		if (stat->dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM))
			SetFileAttributesV(dst, stat->dwFileAttributes);
		total.writeFiles++;
	}
	else {
		total.errFiles++;
		DeleteFileV(dst);
	}
	return	ret && !isAbort;
}

BOOL FastCopy::ChangeToWriteModeCore(void)
{
	writeReqList.MoveList(&readReqList);
	cv.Notify();
	while (!writeReqList.IsEmpty() && !isAbort)
		cv.Wait();
	return	!isAbort;
}

BOOL FastCopy::ChangeToWriteMode(void)
{
	cv.Lock();
	BOOL	ret = ChangeToWriteModeCore();
	cv.UnLock();
	return	ret;
}

BOOL FastCopy::AllocReqBuf(int req_size, _int64 _data_size, ReqBuf *buf)
{
	int		max_free = mainBuf.Buf() + mainBuf.Size() - usedOffset;
	int		max_trans = autoSlow && (info.flags & AUTOSLOW_IOLIMIT) ? MIN_BUF : maxTransSize;
	int		data_size = (_data_size > max_trans) ? max_trans : (int)_data_size;
	int		align_data_size = ALIGN_SIZE(data_size, 8);
	int		sector_data_size = ALIGN_SIZE(data_size, sectorSize);
	int		require_size = align_data_size + req_size;
	BYTE	*align_offset = data_size ? (BYTE *)ALIGN_SIZE((u_int)usedOffset, sectorSize) : usedOffset;

	max_free -= align_offset - usedOffset;

	if (data_size && align_data_size + req_size < sector_data_size)
		require_size = sector_data_size;

	if (require_size > max_free) {
		if (max_free < MIN_BUF) {
			align_offset = mainBuf.Buf();
			if (isSameDrv && ChangeToWriteModeCore() == FALSE)	// Read -> Write 愗傝懼偊
				return	FALSE;
		}
		else {
			data_size = max_free - req_size;
			align_data_size = data_size = (data_size / BIGTRANS_ALIGN) * BIGTRANS_ALIGN;
			require_size = data_size + req_size;
		}
	}
	buf->buf = align_offset;
	buf->bufSize = ALIGN_SIZE(data_size, sectorSize);
	buf->req = (ReqHeader *)(buf->buf + align_data_size);
	buf->reqSize = req_size;

	while (!writeReqList.IsEmpty() && !isAbort) {	// isSameDrv == TRUE 偺応崌丄昁偢 Empty
		if (buf->buf == mainBuf.Buf()) {
			if (freeOffset < usedOffset && (freeOffset - mainBuf.Buf()) >= require_size)
				break;
		}
		else {
			if (freeOffset < usedOffset || buf->buf + require_size <= freeOffset)
				break;
		}
		cv.Wait();
	}

	usedOffset = buf->buf + require_size;
	return	!isAbort;
}

BOOL FastCopy::PrepareReqBuf(int req_size, _int64 data_size, _int64 file_id, ReqBuf *buf)
{
	BOOL ret = TRUE;

	cv.Lock();

	if (errFileID) {
		if (errFileID == file_id)
			ret = FALSE;
		errFileID = 0;
	}

	if (ret)
		ret = AllocReqBuf(req_size, data_size, buf);

	cv.UnLock();

	return	ret;
}

BOOL FastCopy::SendRequest(Command command, ReqBuf *buf, FileStat *stat)
{
	BOOL	ret = TRUE;
	ReqBuf	tmp_buf;

	cv.Lock();

	if (buf == NULL) {
		buf = &tmp_buf;
		ret = AllocReqBuf(offsetof(ReqHeader, stat) + (stat ? stat->minSize : 0), 0, buf);
	}

	if (ret && !isAbort) {
		ReqHeader	*readReq;
		readReq				= buf->req;
		readReq->reqSize	= buf->reqSize;
		readReq->command	= command;
		readReq->buf		= buf->buf;
		readReq->bufSize	= buf->bufSize;
		if (stat)
			memcpy(&readReq->stat, stat, stat->minSize);

		if (isSameDrv) {
			readReqList.AddObj(readReq);
		}
		else {
			writeReqList.AddObj(readReq);
			cv.Notify();
		}
	}

	cv.UnLock();

	return	ret && !isAbort;
}

BOOL FastCopy::RecvRequest(void)
{
	cv.Lock();

	if (writeReq)
		WriteReqDone();

	if (readDestStatQueue)
		ReadDestStat();

	while (writeReqList.IsEmpty() && !isAbort) {
		cv.Wait();
		if (readDestStatQueue)
			ReadDestStat();
	}
	writeReq = writeReqList.TopObj();

	if (writeReq && writeReq->command == REQ_EOF)
		WriteReqDone();

	cv.UnLock();

	return	writeReq && !isAbort;
}

void FastCopy::WriteReqDone(void)
{
	writeReqList.DelObj(writeReq);
	freeOffset = (BYTE *)writeReq + writeReq->reqSize;
	if (!isSameDrv || writeReqList.IsEmpty())
		cv.Notify();
}

void FastCopy::SetErrFileID(_int64 file_id)
{
	cv.Lock();
	errFileID = file_id;
	cv.UnLock();
}

BOOL FastCopy::End(void)
{
	isAbort = TRUE;

	while (hWriteThread || hReadThread) { // WaitForMultipleObject() 傊偺曄峏偼屻擔
		cv.Lock();
		cv.Notify();
		cv.UnLock();

		if (hReadThread && ::WaitForSingleObject(hReadThread, 100) != WAIT_TIMEOUT) {
			::CloseHandle(hReadThread);
			hReadThread = NULL;
		}
		if (hWriteThread && ::WaitForSingleObject(hWriteThread, 100) != WAIT_TIMEOUT) {
			::CloseHandle(hWriteThread);
			hWriteThread = NULL;
		}
	}

	::ReleaseMutex(hRunMutex);

	if (info.flags & LISTING_ONLY)
		listBuf.FreeBuf();

	errBuf.FreeBuf();

	if (info.mode != DELETE_MODE) {
		delete [] openFiles;
		openFiles = NULL;
		if (info.flags & SKIP_EMPTYDIR)
			mkdirQueueBuf.FreeBuf();
		fileStatBuf.FreeBuf();
		dirStatBuf.FreeBuf();
		dstStatBuf.FreeBuf();
		dstStatIdxBuf.FreeBuf();
		mainBuf.FreeBuf();
	}

	return	TRUE;
}

BOOL FastCopy::Suspend(void)
{
	if (!hReadThread && !hWriteThread || isSuspend)
		return	FALSE;

	if (hReadThread)
		::SuspendThread(hReadThread);

	if (hWriteThread)
		::SuspendThread(hWriteThread);

	isSuspend = TRUE;
	suspendTick = ::GetTickCount();

	return	TRUE;
}

BOOL FastCopy::Resume(void)
{
	if (!hReadThread && !hWriteThread || !isSuspend)
		return	FALSE;

	isSuspend = FALSE;
	startTick += (::GetTickCount() - suspendTick);

	if (hReadThread)
		::ResumeThread(hReadThread);

	if (hWriteThread)
		::ResumeThread(hWriteThread);

	return	TRUE;
}

BOOL FastCopy::GetTransInfo(TransInfo *ti, BOOL fullInfo)
{
	ti->total = total;
	ti->listBuf = &listBuf;
	ti->listCs = &listCs;
	ti->errBuf = &errBuf;
	ti->errCs = &errCs;
	ti->isSameDrv = isSameDrv;
	ti->ignoreErr = info.ignoreErr;
	ti->autoSlow = autoSlow;
	ti->tickCount = (isSuspend ? suspendTick : ::GetTickCount()) - startTick;
	if (fullInfo) {
		if (IS_WINNT_V)
			ConvertExternalPath(MakeAddr(dst, dstPrefixLen), ti->curPath, sizeof(ti->curPath)/sizeof(WCHAR));
		else
			sprintfV(ti->curPath, "%.250s", dst);
	}
	return	TRUE;
}

int FastCopy::FdatToFileStat(WIN32_FIND_DATAW *fdat, FileStat *stat, BOOL is_usehash)
{
	stat->fileID			= 0;
	stat->ftCreationTime	= fdat->ftCreationTime;
	stat->ftLastAccessTime	= fdat->ftLastAccessTime;
	stat->ftLastWriteTime	= fdat->ftLastWriteTime;
	stat->nFileSizeLow		= fdat->nFileSizeLow;
	stat->nFileSizeHigh		= fdat->nFileSizeHigh;
	stat->dwFileAttributes	= fdat->dwFileAttributes;
	stat->hFile				= INVALID_HANDLE_VALUE;
	stat->lastError			= 0;
	stat->isExists			= FALSE;
	stat->renameCount		= 0;
	stat->next				= NULL;

	int	len = (sprintfV(stat->cFileName, FMT_STR_V, fdat->cFileName) + 1) * CHAR_LEN_V;
	stat->size = len + offsetof(FileStat, cFileName);
	stat->minSize = ALIGN_SIZE(stat->size, 8);

	if (is_usehash) {
		stat->upperName = stat->cFileName + len;
		memcpy(stat->upperName, stat->cFileName, len);
		CharUpperV(stat->upperName);
		stat->hashVal = hashVal.MakeHash(stat->upperName, len);
		stat->size += len;
	}
	stat->size = ALIGN_SIZE(stat->size, 8);

	return	stat->size;
}

BOOL FastCopy::ConvertExternalPath(const void *path, void *buf, int max_buf, BOOL to_ansi)
{
	if (GetChar(path, 0) == '\\' && GetChar(path, 1) != '\\') {	// UNC
		if (to_ansi) {
			*(char *)buf = '\\';
			buf = (char *)buf + 1;
		}
		else {
			SetChar(buf, 0, '\\');
			buf = MakeAddr(buf, 1);
		}
		max_buf--;
	}
	if (to_ansi)
		::WideCharToMultiByte(CP_ACP, 0, (WCHAR *)path, -1, (char *)buf, max_buf, 0, 0);
	else
		sprintfV(buf, L"%.*s", max_buf, path);
	return	TRUE;
}

FastCopy::Confirm::Result FastCopy::ConfirmErr(const char *message, const void *path, BOOL allow_continue)
{
	if (isAbort)
		return	Confirm::CANCEL_RESULT;

	char	path_buf[MAX_PATH_EX], msg_buf[MAX_PATH_EX + 100];
	DWORD	err_code = ::GetLastError();

	if (path && IS_WINNT_V) {
		ConvertExternalPath(path, path_buf, sizeof(path_buf), TRUE);
		path = path_buf;
	}

	int	len = sprintf(msg_buf, "%s(", message);

	len += FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err_code, info.lcid > 0 ? LANGIDFROMLCID(info.lcid) : MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), msg_buf + len, MAX_PATH_EX, NULL);
	if (msg_buf[len-1] == '\n')
		len -= 2;

	len += sprintf(msg_buf + len, "%u) : %s", err_code, path ? path : "");

	WriteErrLog(msg_buf, len);

	if (allow_continue == FALSE)
		isAbort = TRUE;
	else if (info.ignoreErr)
		return	Confirm::CONTINUE_RESULT;

	isSuspend = TRUE;
	suspendTick = ::GetTickCount();

	Confirm	 confirm = { msg_buf, allow_continue, path, Confirm::CONTINUE_RESULT };
	info.notifyWnd->SendMessage(info.uNotifyMsg, CONFIRM_NOTIFY, (LPARAM)&confirm);

	isSuspend = FALSE;
	startTick += (::GetTickCount() - suspendTick);

	switch (confirm.result) {
	case Confirm::IGNORE_RESULT:
		info.ignoreErr = TRUE;
		confirm.result = Confirm::CONTINUE_RESULT;
		break;

	case Confirm::CANCEL_RESULT:
		isAbort = TRUE;
		break;
	}
	return	confirm.result;
}

BOOL FastCopy::WriteErrLog(char *message, int len)
{
#define ERRMSG_SIZE		30
	::EnterCriticalSection(&errCs);

	BOOL	ret = TRUE;
	char	*msg_buf = (char *)errBuf.Buf() + errBuf.UsedSize();

	if (len == -1)
		len = strlen(message);
	len += ERRMSG_SIZE;

	if (errBuf.UsedSize() + len <= errBuf.MaxSize()) {
		if (errBuf.RemainSize() > len || errBuf.Grow(ALIGN_SIZE(len, PAGE_SIZE))) {
			len = sprintf(msg_buf, "%s%s", errBuf.UsedSize() ? "\r\n" : "", message);
			errBuf.AddUsedSize(len);
		}
	}
	else {
		if (errBuf.RemainSize()) {
			sprintf(msg_buf, "%s", "\r\n Too Many Errors...");
			errBuf.SetUsedSize(errBuf.MaxSize());
		}
		ret = FALSE;
	}
	::LeaveCriticalSection(&errCs);
	return	ret;
}

⌨️ 快捷键说明

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