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

📄 fastcopy.cpp

📁 FastCopy 利用缓冲技术加快文件拷贝
💻 CPP
📖 第 1 页 / 共 4 页
字号:
	if (!(hReadThread = (HANDLE)_beginthreadex(0, 0, FastCopy::ReadThread, this, 0, &id))
	|| !(hWriteThread = (HANDLE)_beginthreadex(0, 0, FastCopy::WriteThread, this, 0, &id)))
		goto ERR;
	return	TRUE;

ERR:
	End();
	return	FALSE;
}

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

BOOL FastCopy::ReadThreadCore(void)
{
	BOOL	isSameDrvOld;
	int		done_cnt = 0;

	if (info.flags & PRE_SEARCH)
		PreSearch();

	for (int i=0; i < srcArray.Num(); i++) {
		if (InitSrcPath(i)) {
			if (done_cnt >= 1 && isSameDrvOld != isSameDrv)
				ChangeToWriteMode();
			ReadProc(srcBaseLen, info.overWrite == BY_ALWAYS ? FALSE : TRUE);
			isSameDrvOld = isSameDrv;
			done_cnt++;
		}
		if (isAbort)
			break;
	}
	SendRequest(REQ_EOF);
	ChangeToWriteMode();
	return	TRUE;
}

BOOL FastCopy::PreSearch(void)
{
	BOOL	is_delete = info.mode == DELETE_MODE;
	BOOL	(FastCopy::*InitPath)(int) = is_delete ? InitDeletePath : InitSrcPath;
	void	*&path = is_delete ? dst : src;
	int		&prefix_len = is_delete ? dstPrefixLen : srcPrefixLen;
	int		&base_len = is_delete ? dstBaseLen : srcBaseLen;
	BOOL	ret = TRUE;

	for (int i=0; i < srcArray.Num(); i++) {
		if ((this->*InitPath)(i)) {
			if (!PreSearchProc(path, prefix_len, base_len))
				ret = FALSE;
		}
		if (isAbort)
			break;
	}
	total.isPreSearch = FALSE;
	startTick = ::GetTickCount();

	return	ret && !isAbort;
}

BOOL FastCopy::FilterCheck(const void *path, const void *fname, DWORD attr)
{
	int	targ = (attr & FILE_ATTRIBUTE_DIRECTORY) ? DIR_EXP : FILE_EXP;

	if (regExp[EXC_EXP][targ].IsMatch(fname))
		return	FALSE;

	if (!regExp[INC_EXP][targ].IsRegistered())
		return	TRUE;

	if (regExp[INC_EXP][targ].IsMatch(fname))
		return	TRUE;

	return	FALSE;
}

BOOL FastCopy::PreSearchProc(void *path, int prefix_len, int dir_len)
{
	HANDLE		hDir;
	BOOL		ret = TRUE;
	WIN32_FIND_DATAW fdat;

	if ((hDir = FindFirstFileV(path, &fdat)) == INVALID_HANDLE_VALUE) {
		return	ConfirmErr("FindFirstFile(pre)", MakeAddr(path, prefix_len)), FALSE;
	}

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

		// src 僨傿儗僋僩儕帺懱偵懳偟偰偼丄僼傿儖僞懳徾偵偟側偄
		if (isFilter && (dir_len != srcBaseLen || isMetaSrc) && !FilterCheck(path, fdat.cFileName, fdat.dwFileAttributes))
			continue;

		if (fdat.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
			total.preDirs++;
			int len = sprintfV(MakeAddr(path, dir_len), FMT_CAT_ASTER_V, fdat.cFileName) -1;
			ret = PreSearchProc(path, prefix_len, dir_len + len);
		}
		else {
			total.preFiles++;
			total.preTrans += (((_int64)fdat.nFileSizeHigh << 32) + fdat.nFileSizeLow);
		}
	}
	while (!isAbort && FindNextFileV(hDir, &fdat));

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

	::FindClose(hDir);

	return	ret && !isAbort;
}

BOOL FastCopy::PutList(void *path, DWORD opt)
{
	BOOL	add_backslash = GetChar(path, 0) == '\\' && GetChar(path, 1) != '\\';

	::EnterCriticalSection(&listCs);

	if (listBuf.RemainSize() >= MAX_PATHLEN_V || listBuf.Grow(MIN_PUTLIST_BUF)) {
		int len = sprintfV(listBuf.Buf() + listBuf.UsedSize(), listBuf.UsedSize() ? FMT_LIST2_V : FMT_LIST1_V, (opt & PL_DELETE) ? '-' : '+', add_backslash ? BACK_SLASH_V : EMPTY_STR_V, path, (opt & PL_DIRECTORY) ? L"\\" : L"");

		listBuf.AddUsedSize(len * CHAR_LEN_V);
	}

	::LeaveCriticalSection(&listCs);
	return	TRUE;
}

BOOL FastCopy::ReadProc(int dir_len, BOOL confirm_dir)
{
	BOOL		ret = TRUE;
	FileStat	*srcStat, *statEnd;
	FileStat	*dstStat = NULL;
	int			new_dir_len, curDirStatSize, confirm_len;
	BOOL		is_rename_local = isRename;
	BOOL		confirm_dir_local = confirm_dir || is_rename_local;

	isRename = FALSE;	// top level 偺傒岠壥傪弌偡

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

	// 僇儗儞僩偺僒僀僘傪曐懚
	curDirStatSize = dirStatBuf.UsedSize();

	if (confirm_dir_local && !isSameDrv)
		ReadDestStatRequest();

	// 僨傿儗僋僩儕僄儞僩儕傪愭偵偡傋偰撉傒庢傞
	ret = ReadDirEntry(dir_len, confirm_dir_local);

	if (confirm_dir_local && (isSameDrv ? ReadDestStat() : WaitReadDestStat()) == FALSE || isAbort || !ret)
		return	FALSE;

	// 僼傽僀儖傪愭偵張棟
	statEnd = (FileStat *)(fileStatBuf.Buf() + fileStatBuf.UsedSize());
	for (srcStat = (FileStat *)fileStatBuf.Buf(); srcStat < statEnd; srcStat = (FileStat *)((BYTE *)srcStat + srcStat->size)) {
		if (confirm_dir_local)
			dstStat = hash.Search(srcStat->upperName, srcStat->hashVal);

		if (dstStat) {
			if (is_rename_local) {
				SetRenameCount(srcStat);
			}
			else {
				dstStat->isExists = TRUE;
				if (IsOverWriteFile(srcStat, dstStat) == FALSE) {
					total.skipFiles++;
					total.skipTrans += dstStat->FileSize();
					continue;
				}
			}
		}
		total.readFiles++;

		if (OpenFileProc(srcStat, dir_len) == FALSE || srcFsType == FSTYPE_NETWORK || openFilesCnt >= info.maxOpenFiles) {
			ReadMultiFilesProc();
			CloseMultiFilesProc();
		}
		if (isAbort)
			goto END;
	}

	ReadMultiFilesProc();
	CloseMultiFilesProc();
	if (isAbort)
		goto END;

	statEnd = (FileStat *)(dirStatBuf.Buf() + dirStatBuf.UsedSize());

	// 僨傿儗僋僩儕偺懚嵼妋擣
	if (confirm_dir_local) {
		confirm_len = dir_len + (dstBaseLen - srcBaseLen);

		for (srcStat = (FileStat *)(dirStatBuf.Buf() + curDirStatSize); srcStat < statEnd; srcStat = (FileStat *)((BYTE *)srcStat + srcStat->size)) {
			if ((dstStat = hash.Search(srcStat->upperName, srcStat->hashVal)) != NULL) {
				if (is_rename_local)
					SetRenameCount(srcStat);
				else
					srcStat->isExists = dstStat->isExists = TRUE;
			}
			else
				srcStat->isExists = FALSE;
		}
	}

	// SYNC儌乕僪偺応崌丄僐僺乕尦偵柍偄僼傽僀儖傪嶍彍
	if (confirm_dir_local && info.mode == SYNCCP_MODE) {
		int		max = dstStatIdxBuf.UsedSize() / sizeof(FileStat *);
		for (int i=0; i < max; i++) {
			if ((dstStat = ((FileStat **)dstStatIdxBuf.Buf())[i])->isExists)
				continue;

			if (isFilter && !FilterCheck(confirmDst, dstStat->cFileName, dstStat->dwFileAttributes))
				continue;

			if (isSameDrv) {
				if (dstStat->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
					ret = DeleteDirProc(confirmDst, confirm_len, dstStat->cFileName, dstStat);
				else
					ret = DeleteFileProc(confirmDst, confirm_len, dstStat->cFileName, dstStat);
			}
			else {
				SendRequest(DELETE_FILES, 0, dstStat);
			}
			if (isAbort)
				goto END;
		}
	}

	// 僨傿儗僋僩儕張棟
	for (srcStat = (FileStat *)(dirStatBuf.Buf() + curDirStatSize); srcStat < statEnd; srcStat = (FileStat *)((BYTE *)srcStat + srcStat->size)) {
		total.readDirs++;
		new_dir_len = dir_len + sprintfV(MakeAddr(src, dir_len), FMT_CAT_ASTER_V, srcStat->cFileName) -1;
		if (confirm_dir && srcStat->isExists)
			sprintfV(MakeAddr(confirmDst, confirm_len), FMT_CAT_ASTER_V, srcStat->cFileName);
		if (SendRequest(confirm_dir && srcStat->isExists ? INTODIR : MKDIR, 0, srcStat), isAbort)
			goto END;
		if (ReadProc(new_dir_len, confirm_dir && srcStat->isExists), isAbort)
			goto END;
		if (SendRequest(RETURN_PARENT), isAbort)
			goto END;
	}

END:
	// 僇儗儞僩偺 dir梡Buf 僒僀僘傪暅尦
	dirStatBuf.SetUsedSize(curDirStatSize);
	return	ret && !isAbort;
}

int FastCopy::MakeRenameName(void *buf, int count, void *fname)
{
	void	*ext = strrchrV(fname, '.');
	int		body_limit = ext ? DiffLen(ext, fname) : MAX_PATH;

	return	sprintfV(buf, FMT_RENAME_V, body_limit, fname, count, ext ? ext : EMPTY_STR_V);
}

BOOL FastCopy::SetRenameCount(FileStat *stat)
{
	while (1) {
		WCHAR	new_name[MAX_PATH];
		int		len = MakeRenameName(new_name, ++stat->renameCount, stat->upperName);
		DWORD	hash_val = hashVal.MakeHash(new_name, len * CHAR_LEN_V);
		if (hash.Search(new_name, hash_val) == NULL)
			break;
	}
	return	TRUE;
}

/*
	忋彂偒敾掕
*/
BOOL FastCopy::IsOverWriteFile(FileStat *srcStat, FileStat *dstStat)
{
	if (info.overWrite == BY_NAME)
		return	FALSE;

// time stamp monitor
#if 0
	_int64	st = *(_int64 *)&srcStat->ftLastWriteTime;
	_int64	dt = *(_int64 *)&dstStat->ftLastWriteTime;
	if (st != dt && (info.flags & LISTING_ONLY)) {
		::EnterCriticalSection(&listCs);

		int len = sprintfV(listBuf.Buf() + listBuf.UsedSize(), L" src/dst: %I64d / %I64d", st, dt);
		listBuf.AddUsedSize(len * CHAR_LEN_V);

		::LeaveCriticalSection(&listCs);
	}
#endif

	if (info.overWrite == BY_ATTR) {
		// 僒僀僘偑摍偟偔丄偐偮...
		if (dstStat->FileSize() == srcStat->FileSize()) {
			if (*(_int64 *)&dstStat->ftLastWriteTime == *(_int64 *)&srcStat->ftLastWriteTime) {	// 峏怴擔晅偑姰慡偵摍偟偄
				return	FALSE;
			}
			if (srcFsType != FSTYPE_NTFS || dstFsType != FSTYPE_NTFS) {	// 偳偪傜偐偑 NTFS 偱側偄応崌乮僱僢僩儚乕僋僪儔僀僽傪娷傓乯
				// 曅曽偑 NTFS 偱側偄応崌丄1msec 枹枮偺岆嵎偼嫋梕偟偨忋偱丄斾妑乮UDF 懳嶔乯
				if (*(_int64 *)&dstStat->ftLastWriteTime + 10000 >= *(_int64 *)&srcStat->ftLastWriteTime &&
					*(_int64 *)&dstStat->ftLastWriteTime - 10000 <= *(_int64 *)&srcStat->ftLastWriteTime) {
					return	FALSE;
				}
				// src 偐 dst 偺僞僀儉僗僞儞僾偺嵟彫扨埵偑 1 昩埲忋乮FAT or SAMBA 摍偺壜擻惈乯偱偐偮...
				if ((*(_int64 *)&srcStat->ftLastWriteTime % 10000000) == 0 || (*(_int64 *)&dstStat->ftLastWriteTime % 10000000) == 0) {
					// 僞僀儉僗僞儞僾偺嵎偑 2 昩埲撪側傜丄摨堦僞僀儉僗僞儞僾偲傒側偟偰丄忋彂偒偟側偄
					if (*(_int64 *)&dstStat->ftLastWriteTime + 20000000 >= *(_int64 *)&srcStat->ftLastWriteTime &&
						*(_int64 *)&dstStat->ftLastWriteTime - 20000000 <= *(_int64 *)&srcStat->ftLastWriteTime)
						return	FALSE;
				}
			}
		}
		return	TRUE;
	}

	if (info.overWrite == BY_LASTEST) {
		// 峏怴擔晅偑 dst 偲摨偠偐屆偄応崌偼峏怴偟側偄
		if (*(_int64 *)&dstStat->ftLastWriteTime >= *(_int64 *)&srcStat->ftLastWriteTime) {
			return	FALSE;
		}
		if (srcFsType != FSTYPE_NTFS || dstFsType != FSTYPE_NTFS) {	// 偳偪傜偐偑 NTFS 偱側偄応崌乮僱僢僩儚乕僋僪儔僀僽傪娷傓乯
			// 曅曽偑 NTFS 偱側偄応崌丄1msec 枹枮偺岆嵎偼嫋梕偟偨忋偱丄斾妑乮UDF 懳嶔乯
			if (*(_int64 *)&dstStat->ftLastWriteTime + 10000 >= *(_int64 *)&srcStat->ftLastWriteTime) {
				return	FALSE;
			}
			// src 偐 dst 偺僞僀儉僗僞儞僾偺嵟彫扨埵偑 1 昩埲忋乮FAT or SAMBA 摍偺壜擻惈乯偱偐偮...
			if ((*(_int64 *)&srcStat->ftLastWriteTime % 10000000) == 0 || (*(_int64 *)&dstStat->ftLastWriteTime % 10000000) == 0) {
				// 僞僀儉僗僞儞僾偺嵎偵 2 昩偺儅乕僕儞傪晅偗偨忋偱丄 峏怴擔晅偑 dst 偲摨偠偐屆偄応崌偼丄忋彂偒偟側偄
				if (*(_int64 *)&dstStat->ftLastWriteTime + 20000000 >= *(_int64 *)&srcStat->ftLastWriteTime)
					return	FALSE;
			}
		}
		return	TRUE;
	}

	if (info.overWrite == BY_ALWAYS)
		return	TRUE;

	return	ConfirmErr("Illegal overwrite mode", 0, FALSE), FALSE;
}

BOOL FastCopy::ReadDirEntry(int dir_len, BOOL confirm_dir)
{
	HANDLE	fh;
	BOOL	ret = TRUE;
	int		len;
	WIN32_FIND_DATAW fdat;

	fileStatBuf.SetUsedSize(0);

	if ((fh = FindFirstFileV(src, &fdat)) == INVALID_HANDLE_VALUE) {
		total.errDirs++;
		return	ConfirmErr("FindFirstFile", MakeAddr(src, srcPrefixLen)), FALSE;
	}
	do {
		if (IsParentOrSelfDirs(fdat.cFileName))
			continue;

		// src 僨傿儗僋僩儕帺懱偵懳偟偰偼丄僼傿儖僞懳徾偵偟側偄
		if (isFilter && (dir_len != srcBaseLen || isMetaSrc) && !FilterCheck(src, fdat.cFileName, fdat.dwFileAttributes))
			continue;

		// 僨傿儗僋僩儕仌僼傽僀儖忣曬偺拁愊
		if (fdat.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
			len = FdatToFileStat(&fdat, (FileStat *)(dirStatBuf.Buf() + dirStatBuf.UsedSize()), confirm_dir);
			dirStatBuf.AddUsedSize(len);
			if (dirStatBuf.RemainSize() <= maxStatSize && dirStatBuf.Grow(MIN_ATTR_BUF) == FALSE) {
				ConfirmErr("Can't alloc memory(dirStatBuf)", NULL, FALSE);
				break;
			}
		}
		else {
			len = FdatToFileStat(&fdat, (FileStat *)(fileStatBuf.Buf() + fileStatBuf.UsedSize()), confirm_dir);
			fileStatBuf.AddUsedSize(len);
			if (fileStatBuf.RemainSize() <= maxStatSize && fileStatBuf.Grow(MIN_ATTR_BUF) == FALSE) {
				ConfirmErr("Can't alloc memory(fileStatBuf)", NULL, FALSE);
				break;
			}
		}
	}
	while (!isAbort && FindNextFileV(fh, &fdat));

	if (!isAbort && ::GetLastError() != ERROR_NO_MORE_FILES) {
		total.errFiles++;
		ret = FALSE;
		ConfirmErr("FindNextFile", MakeAddr(src, srcPrefixLen));
	}
	::FindClose(fh);

	return	ret && !isAbort;
}

#ifdef ACL_TEST
WIN32_STREAM_ID acl_sid;
BYTE	acl_data[1000];
DWORD	acl_size;
#endif

BOOL FastCopy::OpenFileProc(FileStat *stat, int dir_len)
{
//	memcpy(MakeAddr(src, dir_len), stat->cFileName, stat->minSize - offsetof(FileStat, cFileName));
	DWORD	name_len = strlenV(stat->cFileName);
	memcpy(MakeAddr(src, dir_len), stat->cFileName, ((name_len + 1) * CHAR_LEN_V));

	stat->fileID = nextFileID++;
	openFiles[openFilesCnt++] = stat;

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

	if (stat->FileSize() == 0 || (info.flags & LISTING_ONLY))
		return	TRUE;

#ifdef ACL_TEST
	if ((stat->hFile = CreateFileV(src, GENERIC_READ|READ_CONTROL, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, ((info.flags & USE_OSCACHE_READ) ? 0 : FILE_FLAG_NO_BUFFERING)|FILE_FLAG_BACKUP_SEMANTICS, 0)) == INVALID_HANDLE_VALUE) {
#else
	if ((stat->hFile = CreateFileV(src, GENERIC_READ             , FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, ((info.flags & USE_OSCACHE_READ) ? 0 : FILE_FLAG_NO_BUFFERING)|FILE_FLAG_BACKUP_SEMANTICS, 0)) == INVALID_HANDLE_VALUE) {
#endif
		stat->lastError = ::GetLastError();
		return	FALSE;
	}

#ifdef ACL_TEST
	WIN32_STREAM_ID	sid;
	BOOL	ret;
	DWORD	size = 0, i = 0;
	DWORD	lowSeek, highSeek;
	void	*context = NULL;

	while (++i < MAX_SUBSTREAM) {
		SetLastError(0);
		ret = ::BackupRead(stat->hFile, (LPBYTE) &sid, offsetof(WIN32_STREAM_ID, cStreamName), &size, FALSE, TRUE, &context);
		if (!ret || size != offsetof(WIN32_STREAM_ID, cStreamName))	{
			ConfirmErr("BackupRead", src);
			break;
		}

		if (sid.dwStreamId == BACKUP_ALTERNATE_DATA) {
			FileStat *subStat = (FileStat *)(fileStatBuf.Buf() + fileStatBuf.UsedSize());

			memcpy(subStat, stat, offsetof(FileStat, nFileSizeLow));
			subStat->nFileSizeLow = sid.Size.LowPart;
			subStat->nFileSizeHigh = sid.Size.HighPart;
			subStat->dwFileAttributes = 0;
			subStat->renameCount = 0;
			subStat->size = sid.dwStreamNameSize + offsetof(FileStat, cFileName);
			subStat->minSize = ALIGN_SIZE(subStat->size, 8);

			fileStatBuf.AddUsedSize(subStat->minSize);
			if (fileStatBuf.RemainSize() <= maxStatSize && fileStatBuf.Grow(MIN_ATTR_BUF) == FALSE) {
				ConfirmErr("Can't alloc memory(fileStatBuf2)", NULL, FALSE);
				break;
			}

			if (!::BackupRead(stat->hFile, (LPBYTE)subStat->cFileName, sid.dwStreamNameSize, &size, FALSE, TRUE, &context))
				break;

			lSetCharV((LPBYTE)subStat->cFileName + sid.dwStreamNameSize, 0, 0);	// NULL terminate 偝傟側偄偨傔
			memcpy(MakeAddr(src, dir_len + name_len), subStat->cFileName, sid.dwStreamNameSize + CHAR_LEN_V);

			if ((subStat->hFile = CreateFileV(src, GENERIC_READ|READ_CONTROL, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, (info.flags & USE_OSCACHE_READ) ? 0 : FILE_FLAG_NO_BUFFERING, 0)) == INVALID_HANDLE_VALUE) {
				ConfirmErr("OpenFile(Stream)", src);
				subStat->lastError = ::GetLastError();
				::BackupRead(stat->hFile, 0, 0, 0, TRUE, FALSE, &context);
				return	FALSE;
			}

			openFiles[openFilesCnt++] = subStat;
			subStat->fileID = nextFileID++;
		}
		if (sid.dwStreamId == BACKUP_SECURITY_DATA && acl_size == 0) {
			acl_sid = sid;
			::BackupRead(stat->hFile, acl_data, sid.Size.LowPart, &acl_size, FALSE, TRUE, &context);
			sid.Size.LowPart = sid.Size.HighPart = 0;
		}
		if (sid.Size.LowPart && !::BackupSeek(stat->hFile, sid.Size.LowPart, sid.Size.HighPart, &lowSeek, &highSeek, &context))
			break;
	}
	if (i >= MAX_SUBSTREAM) {
		ConfirmErr("Too Many SubStream", src);

⌨️ 快捷键说明

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