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

📄 fastcopy.cpp

📁 FastCopy 利用缓冲技术加快文件拷贝
💻 CPP
📖 第 1 页 / 共 4 页
字号:
		subStat->lastError = ::GetLastError();
		return	FALSE;
	}
	::BackupRead(stat->hFile, 0, 0, 0, TRUE, FALSE, &context);
#endif

	return	TRUE;
}

BOOL FastCopy::ReadMultiFilesProc(void)
{
	for (int i=0; i < openFilesCnt; i++) {
		if (ReadFileProc(openFiles[i]), isAbort)
			break;
	}
	return	!isAbort;
}

BOOL FastCopy::CloseMultiFilesProc(void)
{
	if ((info.flags & LISTING_ONLY) == 0) {
		for (int i=0; i < openFilesCnt; i++) {
			if (openFiles[i]->hFile != INVALID_HANDLE_VALUE)
				::CloseHandle(openFiles[i]->hFile);
		}
	}
	openFilesCnt = 0;

	return	!isAbort;
}

BOOL FastCopy::ReadFileProc(FileStat *stat)
{
	BOOL	ret = TRUE;
	_int64	file_size = stat->FileSize();
	DWORD	trans_size;
	ReqBuf	req_buf;

	if (file_size == 0 || (info.flags & LISTING_ONLY))
		return	SendRequest(WRITE_FILE, 0, stat);

	if (stat->hFile == INVALID_HANDLE_VALUE) {
		total.errFiles++;
		::SetLastError(stat->lastError);
		if (ConfirmErr("OpenFile", MakeAddr(src, srcPrefixLen)) == Confirm::CONTINUE_RESULT) {
			stat->SetFileSize(0);
			if (info.flags & CREATE_OPENERR_FILE)
				SendRequest(WRITE_FILE, 0, stat);
		}
		return	FALSE;
	}

	for (_int64 remain_size=file_size; remain_size > 0; remain_size -= trans_size) {
		BOOL	isFirst = remain_size == file_size;
		if ((ret = PrepareReqBuf(offsetof(ReqHeader, stat) + (isFirst ? stat->minSize : 0), remain_size, stat->fileID, &req_buf)) == FALSE)
			break;
		if ((ret = ::ReadFile(stat->hFile, req_buf.buf, req_buf.bufSize, &trans_size, NULL)) == FALSE || trans_size == 0) {
			total.errFiles++;
			if (ConfirmErr(ret && !trans_size ? "ReadFile(truncate)" : "ReadFile", MakeAddr(src, srcPrefixLen)) == Confirm::CONTINUE_RESULT || remain_size != file_size) {
				stat->SetFileSize(0);
				req_buf.bufSize = 0;
				SendRequest(isFirst ? WRITE_FILE : WRITE_ABORT, &req_buf, isFirst ? stat : 0);
			}
			break;
		}
		else
			total.readTrans += trans_size;
		SendRequest(isFirst ? WRITE_FILE : WRITE_FILE_CONT, &req_buf, isFirst ? stat : 0);

		if (autoSlow) {
			::Sleep(autoSlow);
		}
	}

	return	ret && !isAbort;
}

void FastCopy::ReadDestStatRequest(void)
{
	cv.Lock();
	readDestStatQueue = TRUE;
	cv.Notify();
	cv.UnLock();
}

BOOL FastCopy::WaitReadDestStat(void)
{
	cv.Lock();
	while (readDestStatQueue && !isAbort)
		cv.Wait();
	cv.UnLock();
	return	readDestStatResult;
}

BOOL FastCopy::ReadDestStat(void)
{
	HANDLE		fh;
	int			num = 0, len;
	FileStat	*dstStat, **dstStatIdx;
	WIN32_FIND_DATAW	fdat;

	if (!isSameDrv)
		cv.UnLock();
	readDestStatResult = TRUE;
	dstStat = (FileStat *)dstStatBuf.Buf();
	dstStatIdx = (FileStat **)dstStatIdxBuf.Buf();
	dstStatBuf.SetUsedSize(0);
	dstStatIdxBuf.SetUsedSize(0);

	if ((fh = FindFirstFileV(confirmDst, &fdat)) == INVALID_HANDLE_VALUE) {
		if (::GetLastError() != ERROR_FILE_NOT_FOUND && strcmpV(MakeAddr(confirmDst, dstBaseLen), ASTERISK_V) == 0) {
			readDestStatResult = FALSE;
			total.errDirs++;
			ConfirmErr("FindFirstFile(stat)", MakeAddr(confirmDst, dstPrefixLen));
		}	// 僼傽僀儖柤傪巜掕偟偰偺僐僺乕偱丄僐僺乕愭偑尒偮偐傜側偄応崌偼丄
			// 僄儞僩儕側偟偱偺惉岟偲傒側偡
		goto END;
	}
	do {
		if (IsParentOrSelfDirs(fdat.cFileName))
			continue;
		dstStatIdx[num++] = dstStat;
		len = FdatToFileStat(&fdat, dstStat, TRUE);
		dstStatBuf.AddUsedSize(len);

		// 師偺 stat 梡 buffer 偺僙僢僩
		dstStat = (FileStat *)(dstStatBuf.Buf() + dstStatBuf.UsedSize());
		dstStatIdxBuf.AddUsedSize(sizeof(FileStat *));

		if (dstStatBuf.RemainSize() <= maxStatSize && dstStatBuf.Grow(MIN_ATTR_BUF) == FALSE) {
			ConfirmErr("Can't alloc memory(dstStatBuf)", NULL, FALSE);
			break;
		}
		if (dstStatIdxBuf.RemainSize() <= sizeof(FileStat *) && dstStatIdxBuf.Grow(MIN_ATTRIDX_BUF) == FALSE) {
			ConfirmErr("Can't alloc memory(dstStatIdxBuf)", NULL, FALSE);
			break;
		}
	}
	while (!isAbort && FindNextFileV(fh, &fdat));

	if (!isAbort && ::GetLastError() != ERROR_NO_MORE_FILES) {
		total.errFiles++;
		readDestStatResult = FALSE;
		ConfirmErr("FindNextFile(stat)", MakeAddr(confirmDst, dstPrefixLen));
	}
	::FindClose(fh);

END:
	if (readDestStatResult)
		readDestStatResult = MakeHashTable();

	if (!isSameDrv) {
		cv.Lock();
		cv.Notify();
	}
	readDestStatQueue = FALSE;
	return	readDestStatResult;
}

BOOL FastCopy::MakeHashTable(void)
{
	int		num = dstStatIdxBuf.UsedSize() / sizeof(FileStat *);
	int		require_size = hash.RequireSize(num), grow_size;

	if ((grow_size = require_size - dstStatIdxBuf.RemainSize()) > 0 && dstStatIdxBuf.Grow(ALIGN_SIZE(grow_size, MIN_ATTRIDX_BUF)) == FALSE) {
		ConfirmErr("Can't alloc memory(dstStatIdxBuf2)", NULL, FALSE);
		return	FALSE;
	}

	return	hash.Init((FileStat **)dstStatIdxBuf.Buf(), num, dstStatIdxBuf.Buf() + dstStatIdxBuf.UsedSize());
}

int StatHash::HashNum(int data_num)
{
	return	data_num | 1;
}

BOOL StatHash::Init(FileStat **data, int data_num, void *tbl_buf)
{
	hashNum = HashNum(data_num);
	hashTbl = (FileStat **)tbl_buf;
	memset(hashTbl, 0, hashNum * sizeof(FileStat *));

	for (int i=0; i < data_num; i++) {
		for (FileStat **stat = hashTbl+(data[i]->hashVal % hashNum); *stat; stat = &(*stat)->next)
			;
		*stat = data[i];
	}
	return	TRUE;
}

FileStat *StatHash::Search(void *upperName, DWORD hash_val)
{
	for (FileStat *target = hashTbl[hash_val % hashNum]; target; target = target->next) {
		if (target->hashVal == hash_val && strcmpV(target->upperName, upperName) == 0)
			return	target;
	}

	return	NULL;
}

/*=========================================================================
  娭  悢 丗 DeleteThread
  奣  梫 丗 DELETE_MODE 張棟
  愢  柧 丗 
  拲  堄 丗 
=========================================================================*/
unsigned WINAPI FastCopy::DeleteThread(void *fastCopyObj)
{
	return	((FastCopy *)fastCopyObj)->DeleteThreadCore();
}

BOOL FastCopy::DeleteThreadCore(void)
{
	if ((info.flags & PRE_SEARCH) && info.mode == DELETE_MODE)
		PreSearch();

	for (int i=0; i < srcArray.Num() && !isAbort; i++) {
		if (InitDeletePath(i))
			DeleteProc(dst, dstBaseLen);
	}
	::PostMessage(info.notifyWnd->hWnd, info.uNotifyMsg, END_NOTIFY, 0);
	return	TRUE;
}

/*
	嶍彍張棟
*/
BOOL FastCopy::DeleteProc(void *path, int dir_len)
{
	HANDLE		hDir;
	BOOL		ret = TRUE;
	FileStat	stat;
	WIN32_FIND_DATAW fdat;

	if ((hDir = FindFirstFileV(path, &fdat)) == INVALID_HANDLE_VALUE) {
		total.errDirs++;
		return	ConfirmErr("FindFirstFile(del)", MakeAddr(path, dstPrefixLen)), FALSE;
	}

	do {
		if (IsParentOrSelfDirs(fdat.cFileName))
			continue;

		// 嶍彍巜掕偟偨僨傿儗僋僩儕帺懱乮儖乕僩乯偱側偔偐偮丄僼傿儖僞乕彍奜懳徾
		if (isFilter && (dstBaseLen != dir_len || isMetaSrc) && !FilterCheck(path, fdat.cFileName, fdat.dwFileAttributes)) {
			total.filterSkips++;
			continue;
		}

		stat.nFileSizeLow		= fdat.nFileSizeLow;
		stat.nFileSizeHigh		= fdat.nFileSizeHigh;
		stat.dwFileAttributes	= fdat.dwFileAttributes;

		if (stat.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
			ret = DeleteDirProc(path, dir_len, fdat.cFileName, &stat);
		else
			ret = DeleteFileProc(path, dir_len, fdat.cFileName, &stat);
	}
	while (!isAbort && FindNextFileV(hDir, &fdat));

	if (!isAbort && ret && ::GetLastError() != ERROR_NO_MORE_FILES) {
		ret = FALSE;
		ConfirmErr("FindNextFile(del)", MakeAddr(path, dstPrefixLen));
	}

	::FindClose(hDir);

	return	ret && !isAbort;
}

BOOL FastCopy::DeleteDirProc(void *path, int dir_len, void *fname, FileStat *stat)
{
	int		new_dir_len = dir_len + sprintfV(MakeAddr(path, dir_len), FMT_CAT_ASTER_V, fname) -1;
	BOOL	ret;
	int		cur_skips = total.filterSkips;

	if ((ret = DeleteProc(path, new_dir_len)), isAbort)
		return	ret;

	if (isFilter && (cur_skips != total.filterSkips || regExp[INC_EXP][FILE_EXP].IsRegistered()))
		return	ret;

	SetChar(path, new_dir_len - 1, 0);

	if (info.flags & LISTING_ONLY) {
		PutList(MakeAddr(path, dstPrefixLen), PL_DIRECTORY|PL_DELETE);
	}
	else {
		if (stat->dwFileAttributes & FILE_ATTRIBUTE_READONLY)
			SetFileAttributesV(path, stat->dwFileAttributes & ~FILE_ATTRIBUTE_READONLY);

		if ((ret = RemoveDirectoryV(path)) == FALSE) {
			total.errDirs++;
			return	ConfirmErr("RemoveDirectory", MakeAddr(path, dstPrefixLen)), FALSE;
		}
	}

	total.deleteDirs++;
	return	ret;
}

BOOL FastCopy::DeleteFileProc(void *path, int dir_len, void *fname, FileStat *stat)
{
	strcpyV(MakeAddr(path, dir_len), fname);

	if (info.flags & LISTING_ONLY) {
		PutList(MakeAddr(path, dstPrefixLen), PL_DELETE);
	}
	else {
		if (stat->dwFileAttributes & FILE_ATTRIBUTE_READONLY)
			SetFileAttributesV(path, FILE_ATTRIBUTE_NORMAL);

		if (DeleteFileV(path) == FALSE) {
			total.errFiles++;
			return	ConfirmErr("DeleteFile", MakeAddr(path, dstPrefixLen)), FALSE;
		}
	}

	total.deleteFiles++;
	total.deleteTrans += stat->FileSize();
	return	TRUE;
}


/*=========================================================================
  娭  悢 丗 WriteThread
  奣  梫 丗 Write 張棟
  愢  柧 丗 
  拲  堄 丗 
=========================================================================*/
unsigned WINAPI FastCopy::WriteThread(void *fastCopyObj)
{
	return	((FastCopy *)fastCopyObj)->WriteThreadCore();
}

BOOL FastCopy::WriteThreadCore(void)
{
	BOOL	ret = WriteProc(dstBaseLen);

	if (info.mode == MOVE_MODE && !isAbort && errBuf.UsedSize() == 0 && total.errFiles == 0 && total.errDirs == 0)
		DeleteThreadCore();	// 僄儔乕偑側偄側傜丄僜乕僗偺嶍彍
	else
		::PostMessage(info.notifyWnd->hWnd, info.uNotifyMsg, END_NOTIFY, 0);

	return	ret;
}

BOOL FastCopy::WriteProc(int dir_len)
{
	BOOL		ret = TRUE;
	int			new_dir_len;
	HANDLE		fh;
	FileStat	sv_stat;
	DWORD		stream_base_len;

	while (!isAbort) {
		if ((ret = RecvRequest()) == FALSE || writeReq->command == REQ_EOF) {
			break;
		}
		if (writeReq->command == WRITE_FILE) {
#ifdef ACL_TEST
			if (writeReq->stat.dwFileAttributes == 0) {
				strcpyV(MakeAddr(dst, stream_base_len), writeReq->stat.cFileName);
				ConfirmErr("Stream", writeReq->stat.cFileName);
			}
			else
#endif
			{
				if (writeReq->stat.renameCount == 0)
					strcpyV(MakeAddr(dst, dir_len), writeReq->stat.cFileName);
				else
					MakeRenameName(MakeAddr(dst, dir_len), writeReq->stat.renameCount, writeReq->stat.cFileName);
				stream_base_len = strlenV(MakeAddr(dst, dir_len)) + dir_len;
			}

			if (mkdirQueueBuf.UsedSize())
				ExecDirQueue();

			if (info.flags & LISTING_ONLY) {
				PutList(MakeAddr(dst, dstPrefixLen), PL_NORMAL);
				total.writeFiles++;
				total.writeTrans += writeReq->stat.FileSize();
			}
			else if ((ret = WriteFileProc()), isAbort)
				break;
		}
		else if (writeReq->command == MKDIR || writeReq->command == INTODIR) {
			memcpy(&sv_stat, &writeReq->stat, offsetof(FileStat, cFileName));

			if (writeReq->stat.renameCount == 0)
				new_dir_len = dir_len + sprintfV(MakeAddr(dst, dir_len), FMT_STR_V, writeReq->stat.cFileName);
			else
				new_dir_len = dir_len + MakeRenameName(MakeAddr(dst, dir_len), writeReq->stat.renameCount, writeReq->stat.cFileName);

			if (writeReq->command == MKDIR) {
				if (info.flags & SKIP_EMPTYDIR) {
					if (mkdirQueueBuf.RemainSize() < sizeof(int) && mkdirQueueBuf.Grow(MIN_MKDIRQUEUE_BUF) == FALSE) {
						ConfirmErr("Can't alloc memory(mkdirQueueBuf)", NULL, FALSE);
						break;
					}
					*(int *)(mkdirQueueBuf.Buf() + mkdirQueueBuf.UsedSize()) = new_dir_len;
					mkdirQueueBuf.AddUsedSize(sizeof(int));
				}
				else {
					if (info.flags & LISTING_ONLY)
						PutList(MakeAddr(dst, dstPrefixLen), PL_DIRECTORY);
					else
						CreateDirectoryV(dst, NULL);
					total.writeDirs++;
				}
			}
			strcpyV(MakeAddr(dst, new_dir_len++), BACK_SLASH_V);

			if ((ret = WriteProc(new_dir_len)), isAbort)	// 嵞婣
				break;

			if (mkdirQueueBuf.UsedSize()) {
				mkdirQueueBuf.AddUsedSize(-(int)sizeof(int));
			}
			else {
				// 僞僀儉僗僞儞僾/懏惈偺僙僢僩
				SetChar(dst, --new_dir_len, 0);	// 枛旜偺 '\\' 傪庢傞
				if ((info.flags & LISTING_ONLY) == 0) {
					if (sv_stat.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM))
						SetFileAttributesV(dst, sv_stat.dwFileAttributes);
					if (IS_WINNT_V && (fh = CreateFileV(dst, GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)) != INVALID_HANDLE_VALUE)
					{
						::SetFileTime(fh, &sv_stat.ftCreationTime, &sv_stat.ftLastAccessTime, &sv_stat.ftLastWriteTime);
						::CloseHandle(fh);
					}
				}
			}
		}
		else if (writeReq->command == DELETE_FILES) {
			if (writeReq->stat.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
				ret = DeleteDirProc(dst, dir_len, writeReq->stat.cFileName, &writeReq->stat);
			else
				ret = DeleteFileProc(dst, dir_len, writeReq->stat.cFileName, &writeReq->stat);
		}
		else if (writeReq->command == RETURN_PARENT) {
			break;
		}
		else if (writeReq->command < WRITE_FILE && writeReq->command > REQ_EOF) {
			ret = FALSE;
			ConfirmErr("Illegal Request (internal error)", NULL, FALSE);
			break;
		}
	}
	return	ret && !isAbort;
}

BOOL FastCopy::ExecDirQueue(void)
{
	for (int offset=0; offset < mkdirQueueBuf.UsedSize(); offset += sizeof(int)) {
		int dir_len = *(int *)(mkdirQueueBuf.Buf() + offset);
		SetChar(dst, dir_len, 0);
		if (info.flags & LISTING_ONLY)
			PutList(MakeAddr(dst, dstPrefixLen), PL_DIRECTORY);
		else
			CreateDirectoryV(dst, NULL);
		SetChar(dst, dir_len, '\\');
		total.writeDirs++;
	}
	mkdirQueueBuf.SetUsedSize(0);
	return	TRUE;
}


BOOL FastCopy::WriteFileProc(void)
{
	HANDLE		fh, fh2;
	BOOL		ret = TRUE;
	_int64		file_size = writeReq->stat.FileSize();
	_int64		remain = file_size;
	DWORD		trans_size;
	FileStat	*stat = &writeReq->stat, sv_stat;
	BOOL		isNonBuf = dstFsType != FSTYPE_NETWORK && (file_size >= nbMinSize || (file_size % dstSectorSize) == 0) && (info.flags & USE_OSCACHE_WRITE) == 0 ? TRUE : FALSE;
	BOOL		isReOpen = isNonBuf && (file_size % dstSectorSize) ? TRUE : FALSE;

	if (autoSlow) {
		Sleep(autoSlow);
	}

#ifdef ACL_TEST
	if ((fh = CreateFileV(dst, GENERIC_WRITE|WRITE_OWNER|WRITE_DAC, FILE_SHARE_WRITE, 0, CREATE_ALWAYS, (isNonBuf ? FILE_FLAG_NO_BUFFERING : 0)|FILE_FLAG_BACKUP_SEMANTICS, 0)) == INVALID_HANDLE_VALUE) {
		SetFileAttributesV(dst, FILE_ATTRIBUTE_NORMAL);
		fh = CreateFileV(dst, GENERIC_WRITE|WRITE_OWNER|WRITE_DAC, FILE_SHARE_WRITE, 0, CREATE_ALWAYS, (isNonBuf ? FILE_FLAG_NO_BUFFERING : 0)|FILE_FLAG_BACKUP_SEMANTICS, 0);
	}
#else
	if ((fh = CreateFileV(dst, GENERIC_WRITE                     , FILE_SHARE_WRITE, 0, CREATE_ALWAYS, (isNonBuf ? FILE_FLAG_NO_BUFFERING : 0)                            , 0)) == INVALID_HANDLE_VALUE) {
		SetFileAttributesV(dst, FILE_ATTRIBUTE_NORMAL);
		fh = CreateFileV(dst, GENERIC_WRITE                      , FILE_SHARE_WRITE, 0, CREATE_ALWAYS, (isNonBuf ? FILE_FLAG_NO_BUFFERING : 0)                           , 0);
	}
#endif

⌨️ 快捷键说明

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