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

📄 fastcopy.cpp

📁 FastCopy 利用缓冲技术加快文件拷贝
💻 CPP
📖 第 1 页 / 共 4 页
字号:
static char *fastcopy_id = 
	"@(#)Copyright (C) H.Shirouzu 2004-2007   fastcopy.cpp	Ver1.52";
/* ========================================================================
	Project  Name			: Fast Copy file and directory
	Create					: 2004-09-15(Wed)
	Update					: 2007-02-06(Tue)
	Copyright				: H.Shirouzu
	Reference				: 
	======================================================================== */

#include "fastcopy.h"
#include <stdarg.h>
#include <stddef.h>
#include <process.h>
#include <stdio.h>

void *NTFS_STR_V;		// "NTFS"
void *FMT_RENAME_V;		// ".%03d"
void *FMT_LIST1_V;		//
void *FMT_LIST2_V;		//

#ifdef ACL_TEST
BOOL SetPrivilege(LPTSTR pszPrivilege, BOOL bEnable)
{
    HANDLE           hToken;
    TOKEN_PRIVILEGES tp;

    if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
        return FALSE;

    if (!::LookupPrivilegeValue(NULL, pszPrivilege, &tp.Privileges[0].Luid))
        return FALSE;

    tp.PrivilegeCount = 1;

    if (bEnable)
         tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    else
         tp.Privileges[0].Attributes = 0;

    if (!::AdjustTokenPrivileges(hToken, FALSE, &tp, 0, (PTOKEN_PRIVILEGES)NULL, 0))
         return FALSE;

    if (!::CloseHandle(hToken))
         return FALSE;

    return TRUE;
}
#endif

/*=========================================================================
  僋儔僗 丗 FastCopy
  奣  梫 丗 儅儖僠僗儗僢僪側僼傽僀儖僐僺乕娗棟僋儔僗
  愢  柧 丗 
  拲  堄 丗 
=========================================================================*/
FastCopy::FastCopy()
{
	hReadThread = hWriteThread = NULL;

#ifdef ACL_TEST
	SetPrivilege(SE_BACKUP_NAME, TRUE);
	SetPrivilege(SE_RESTORE_NAME, TRUE);
#endif

	::InitializeCriticalSection(&errCs);
	::InitializeCriticalSection(&listCs);

	hRunMutex = ::CreateMutex(NULL, FALSE, FASTCOPY_MUTEX);

	if (IS_WINNT_V) {
		src = new WCHAR [MAX_PATHLEN_V + MAX_PATH];
		dst = new WCHAR [MAX_PATHLEN_V + MAX_PATH];
		confirmDst = new WCHAR [MAX_PATHLEN_V + MAX_PATH];
		NTFS_STR_V		= L"NTFS";
		FMT_INT_STR_V	= L"%d";
		FMT_RENAME_V	= L"%.*s(%d)%s";
		FMT_LIST1_V		= L"%c %s%s%s";
		FMT_LIST2_V		= L"\r\n%c %s%s%s";
	}
	else {
		src = new char [MAX_PATHLEN_V + MAX_PATH_EX];
		dst = new char [MAX_PATHLEN_V + MAX_PATH_EX];
		confirmDst = new char [MAX_PATHLEN_V + MAX_PATH_EX];
		NTFS_STR_V		= "NTFS";
		FMT_INT_STR_V	= "%d";
		FMT_RENAME_V	= "%.*s(%d)%s";
		FMT_LIST1_V		= "%c %s%s%s";
		FMT_LIST2_V		= "\r\n%c %s%s%s";
	}
	maxStatSize = (MAX_PATH * CHAR_LEN_V) * 2 + offsetof(FileStat, cFileName) + 8;
	hashVal.Init(MAX_PATH * CHAR_LEN_V);
}

FastCopy::~FastCopy()
{
	delete [] confirmDst;
	delete [] dst;
	delete [] src;

	::CloseHandle(hRunMutex);

	::DeleteCriticalSection(&listCs);
	::DeleteCriticalSection(&errCs);
}

BOOL FastCopy::GetRootDir(const void *path, void *root_dir)
{
	if (GetChar(path, 0) == '\\') {	// "\\server\volname\" 4偮栚偺 \ 傪尒偮偗傞
		DWORD	ch;
		int		backslash_cnt = 0, offset;

		for (offset=0; (ch = GetChar(path, offset)) != 0 && backslash_cnt < 4; offset++) {
			if (ch == '\\')
				backslash_cnt++;
		}
		memcpy(root_dir, path, offset * CHAR_LEN_V);
		if (backslash_cnt < 4)					// 4偮偺 \ 偑側偄応崌偼丄枛旜偵 \ 傪晅梌
			SetChar(root_dir, offset++, '\\');	// 乮\\server\volume 側偳乯
		SetChar(root_dir, offset, 0);	// NULL terminate
	}
	else {	// "C:\" 摍
		memcpy(root_dir, path, 3 * CHAR_LEN_V);
		SetChar(root_dir, 3, 0);	// NULL terminate
	}
	return	TRUE;
}

FastCopy::FsType FastCopy::GetFsType(const void *root_dir)
{
	if (GetDriveTypeV(root_dir) == DRIVE_REMOTE)
		return	FSTYPE_NETWORK;

	DWORD	serial, max_fname, fs_flags;
	WCHAR	vol[MAX_PATH], fs[MAX_PATH];

	if (GetVolumeInformationV(root_dir, vol, sizeof(vol) / CHAR_LEN_V, &serial, &max_fname, &fs_flags, fs, sizeof(fs) / CHAR_LEN_V) == FALSE)
		return	ConfirmErr("GetVolumeInformation", root_dir, FALSE), FSTYPE_NONE;

	return	lstrcmpiV(fs, NTFS_STR_V) == 0 ? FSTYPE_NTFS : FSTYPE_FAT;
}

int FastCopy::GetSectorSize(const void *root_dir)
{
	DWORD	spc, bps, fc, cl;

	if (GetDiskFreeSpaceV(root_dir, &spc, &bps, &fc, &cl) == FALSE) {
//		if (IS_WINNT_V)
//			ConfirmErr("GetDiskFreeSpace", root_dir, FALSE);
		return	OPT_SECTOR_SIZE;
	}
	return	bps;
}

BOOL FastCopy::IsSameDrive(const void *root1, const void *root2)
{
	if (GetChar(root1, 1) == ':' && GetChar(root2, 1) == ':')
		return	driveMng.IsSameDrive(GetChar(root1, 0), GetChar(root2, 0));

	if (GetChar(root1, 1) != GetChar(root2, 1) || GetDriveTypeV(root1) != GetDriveTypeV(root2))
		return	FALSE;

	return	lstrcmpiV(root1, root2) == 0 ? TRUE : FALSE;
}

int FastCopy::MakeUnlimitedPath(WCHAR *buf)
{
	int		prefix_len;
	WCHAR	*prefix;
	BOOL	isUNC = (*buf == '\\') ? TRUE : FALSE;

	prefix		= isUNC ? PATH_UNC_PREFIX : PATH_LOCAL_PREFIX;
	prefix_len	= isUNC ? PATH_UNC_PREFIX_LEN : PATH_LOCAL_PREFIX_LEN;

	// (isUNC ? 1 : 0) ... PATH_UNC_PREFIX 偺応崌丄\\server -> \\?\UNC\server 
	//  偵偡傞偨傔丄\\server 偺摢偺 \ 傪堦偮捵偡丅
	memmove(buf + prefix_len - (isUNC ? 1 : 0), buf, (strlenV(buf) + 1) * CHAR_LEN_V);
	memcpy(buf, prefix, prefix_len * CHAR_LEN_V);
	return	prefix_len;
}

BOOL FastCopy::InitDstPath(void)
{
	DWORD	attr;
	WCHAR	wbuf[MAX_PATH_EX];
	void	*buf = wbuf, *fname = NULL;
	const void	*org_path = dstArray.Path(0), *dst_root;

	// dst 偺妋擣/壛岺
	if (GetChar(org_path, 1) == ':' && GetChar(org_path, 2) != '\\')
		return	ConfirmErr(GetLoadStr(IDS_BACKSLASHERR), org_path, FALSE), FALSE;

	if (GetFullPathNameV(org_path, MAX_PATHLEN_V, dst, &fname) == 0)
		return	ConfirmErr("GetFullPathName", org_path, FALSE), FALSE;

	GetRootDir(dst, buf);
	dstArray.RegisterPath(buf);
	dst_root = dstArray.Path(dstArray.Num() -1);

	attr = GetFileAttributesV(dst);

	if ((attr = GetFileAttributesV(dst)) == 0xffffffff) {
		if (info.flags & LISTING_ONLY)
			info.overWrite = BY_ALWAYS;	// dest 偑懚嵼偟側偄偨傔丄挷嵏偺昁梫偑側偄
		else {
			CreateDirectoryV(dst, NULL);
			if ((attr = GetFileAttributesV(dst)) == 0xffffffff)
				return	ConfirmErr("CreateDirectory", dst, FALSE), FALSE;
		}
	}
	if ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0)
		return	ConfirmErr("Not a directory", dst, FALSE), FALSE;

	strcpyV(buf, dst);
	MakePathV(dst, buf, EMPTY_STR_V);
	// src帺懱傪僐僺乕偡傞偐乮dst枛旜偵 \ 偑偮偄偰偄傞 or 暋悢巜掕乯
	isExtendDir = strcmpV(buf, dst) == 0 || srcArray.Num() > 1 ? TRUE : FALSE;
	dstPrefixLen = IS_WINNT_V ? MakeUnlimitedPath((WCHAR *)dst) : 0;
	dstBaseLen = strlenV(dst);

	// dst 僼傽僀儖僔僗僥儉忣曬庢摼
	dstSectorSize = GetSectorSize(dst_root);
	dstFsType = GetFsType(dst_root);
	nbMinSize = dstFsType == FSTYPE_NTFS ? info.nbMinSizeNtfs : info.nbMinSizeFat;

	// 嵟戝揮憲僒僀僘
	maxTransSize = isSameDrv ? info.bufSize : info.bufSize / 2;
	maxTransSize = min(info.maxTransSize, maxTransSize);

	// 嵎暘僐僺乕梡dst愭僼傽僀儖妋擣
	strcpyV(confirmDst, dst);

	return	TRUE;
}

BOOL FastCopy::InitSrcPath(int idx)
{
	DWORD		attr;
	BYTE		src_root_cur[MAX_PATH];
	WCHAR		wbuf[MAX_PATH_EX];
	void		*buf = wbuf, *fname = NULL;
	const void	*dst_root = dstArray.Path(dstArray.Num() -1);
	const void	*org_path = srcArray.Path(idx);

	// src 偺妋擣/壛岺
	if (GetChar(org_path, 1) == ':' && GetChar(org_path, 2) != '\\')
		return	ConfirmErr(GetLoadStr(IDS_BACKSLASHERR), org_path), FALSE;

	if (GetFullPathNameV(org_path, MAX_PATHLEN_V, src, &fname) == 0)
		return	ConfirmErr("GetFullPathName", org_path), FALSE;
	GetRootDir(src, src_root_cur);

	if ((attr = GetFileAttributesV(src)) == 0xffffffff) {
		isMetaSrc = TRUE;
	}
	else if (attr & FILE_ATTRIBUTE_DIRECTORY) {
		isMetaSrc = FALSE;
		// 恊僨傿儗僋僩儕帺懱傪僐僺乕偟側偄応崌丄\* 傪晅梌
		strcpyV(buf, src);
		MakePathV(src, buf, ASTERISK_V);
		if (strcmpV(buf, src_root_cur) == 0 || !isExtendDir)
			isMetaSrc = TRUE;
		else
			SetChar(src, strlenV(src) - 2, 0);	// 枛旜偵 \* 傪晅偗側偄
	}
	srcPrefixLen = IS_WINNT_V ? MakeUnlimitedPath((WCHAR *)src) : 0;

	if (GetFullPathNameV(src, MAX_PATH_EX, buf, &fname) == 0 || fname == NULL)
		return	ConfirmErr("GetFullPathName2", MakeAddr(src, srcPrefixLen)), FALSE;

	// 妋擣梡dst惗惉
	strcpyV(MakeAddr(confirmDst, dstBaseLen), fname);

	// 摨堦僷僗偱側偄偙偲偺妋擣
	if (lstrcmpiV(buf, confirmDst) == 0) {
		if (info.mode != DIFFCP_MODE || (info.flags & SAMEDIR_RENAME) == 0)
			return	ConfirmErr(GetLoadStr(IDS_SAMEPATHERR), MakeAddr(confirmDst, dstBaseLen), FALSE), FALSE;
		strcpyV(MakeAddr(confirmDst, dstBaseLen), ASTERISK_V);
		isRename = TRUE;
	}
	else
		isRename = FALSE;

	if (info.mode == MOVE_MODE && (attr & FILE_ATTRIBUTE_DIRECTORY)) {	// 恊偐傜巕傊偺堏摦偼擣傔側偄
		int	end_offset = 0;
		if (GetChar(fname, 0) == '*' || attr == 0xffffffff) {
			SetChar(fname, 0, 0);
			end_offset = 1;
		}
		int		len = IS_WINNT_V ? strlenV(buf) : ::lstrlenA((char *)buf);
		if (srcBaseLen <= dstBaseLen && strnicmpV(buf, confirmDst, len) == 0) {
			DWORD ch = GetChar(confirmDst, len - end_offset);
			if (ch == 0 || ch == '\\') {
				return	ConfirmErr(GetLoadStr(IDS_PARENTPATHERR), MakeAddr(buf, srcPrefixLen), FALSE), FALSE;
			}
		}
	}

	SetChar(fname, 0, 0);
	srcBaseLen = strlenV(buf);

	// src 僼傽僀儖僔僗僥儉忣曬庢摼
	if (lstrcmpiV(src_root_cur, src_root)) {
		srcSectorSize = GetSectorSize(src_root_cur);
		srcFsType = GetFsType(src_root_cur);

		sectorSize = max(srcSectorSize, dstSectorSize);		// 戝偒偄傎偆偵崌傢偣傞
		sectorSize = max(sectorSize, MIN_SECTOR_SIZE);

		// 摨堦暔棟僪儔僀僽偐偳偆偐偺挷嵏
		if (info.flags & FIX_SAMEDISK)
			isSameDrv = TRUE;
		else if (info.flags & FIX_DIFFDISK)
			isSameDrv = FALSE;
		else
			isSameDrv = IsSameDrive(src_root_cur, dst_root);
		if (info.mode == MOVE_MODE)
			isSameVol = strcmpV(src_root_cur, dst_root);
	}

	strcpyV(src_root, src_root_cur);

	return	TRUE;
}

BOOL FastCopy::InitDeletePath(int idx)
{
	DWORD		attr;
	WCHAR		wbuf[MAX_PATH_EX];
	void		*buf = wbuf, *fname = NULL;
	const void	*org_path = srcArray.Path(idx);
	BYTE		dst_root[MAX_PATH];

	// delete 梡 path 偺妋擣/壛岺
	if (GetChar(org_path, 1) == ':' && GetChar(org_path, 2) != '\\')
		return	ConfirmErr(GetLoadStr(IDS_BACKSLASHERR), org_path), FALSE;

	if (GetFullPathNameV(org_path, MAX_PATHLEN_V, dst, &fname) == 0)
		return	ConfirmErr("GetFullPathName", org_path), FALSE;

	if ((attr = GetFileAttributesV(dst)) == 0xffffffff) {
		isMetaSrc = TRUE;
	}
	else if (attr & FILE_ATTRIBUTE_DIRECTORY) {
		isMetaSrc = FALSE;
		GetRootDir(dst, dst_root);
		strcpyV(buf, dst);
		// root_dir 偼枛旜偵 "\*" 傪晅梌丄偦傟埲奜偼枛旜偺 "\"傪嶍彍
		MakePathV(dst, buf, ASTERISK_V);
		if (lstrcmpiV(buf, dst_root) == 0)
			isMetaSrc = TRUE;
		else
			SetChar(dst, strlenV(dst) - 2, 0);
	}
	dstPrefixLen = IS_WINNT_V ? MakeUnlimitedPath((WCHAR *)dst) : 0;

	if (GetFullPathNameV(dst, MAX_PATH_EX, buf, &fname) == 0 || fname == NULL)
		return	ConfirmErr("GetFullPathName2", MakeAddr(dst, dstPrefixLen)), FALSE;
	SetChar(fname, 0, 0);
	dstBaseLen = strlenV(buf);

	return	TRUE;
}

BOOL FastCopy::RegisterInfo(const PathArray *_srcArray, const PathArray *_dstArray, Info *_info, const PathArray *_includeArray, const PathArray *_excludeArray)
{
	isAbort = FALSE;
	isRename = FALSE;
	isFilter = FALSE;

	info = *_info;
	SetChar(src_root, 0, 0);

	if (info.flags & LISTING_ONLY)
		info.flags &= ~PRE_SEARCH;

	// filter
	PathArray	pathArray[] = { *_includeArray, *_excludeArray };
	void		*path = NULL;

	for (int kind=0; kind < MAX_KIND_EXP; kind++) {
		for (int ftype=0; ftype < MAX_FTYPE_EXP; ftype++)
			regExp[kind][ftype].Init();

		for (int idx=0; idx < pathArray[kind].Num(); idx++) {
			int		len = lstrlenV(path = pathArray[kind].Path(idx)), targ = FILE_EXP;

			if (lGetCharV(path, len -1) == '\\') {
				lSetCharV(path, len -1, 0);
				targ = DIR_EXP;
			}
			if (!regExp[kind][targ].RegisterWildCard(path, RegExp::CASE_INSENSE))
				return	ConfirmErr("Bad or Too long windcard string", path, FALSE), FALSE;
		}
	}
	if (path)
		isFilter = TRUE;

	// command
	if (info.mode == DELETE_MODE) {
		srcArray = *_srcArray;
		if (InitDeletePath(0) == FALSE)
			return	FALSE;
	}
	else {
		srcArray = *_srcArray;
		dstArray = *_dstArray;

		if ((info.flags & LISTING_ONLY) == 0 && (info.bufSize > MAX_BUF || info.bufSize < MIN_BUF * 2))
			return	ConfirmErr("Too large or small Main Buffer.", NULL, FALSE), FALSE;
		if (InitDstPath() == FALSE)
			return	FALSE;
		if (InitSrcPath(0) == FALSE)
			return	FALSE;
	}
	_info->isRenameMode = isRename;

	return	!isAbort;
}

BOOL FastCopy::TakeExclusivePriv(void)
{
	return	::WaitForSingleObject(hRunMutex, 0) == WAIT_OBJECT_0 ? TRUE : FALSE;
}


BOOL FastCopy::Start(void)
{
	u_int	id;
	int		allocSize = (info.flags & LISTING_ONLY) ? MAX_LIST_BUF : info.bufSize+PAGE_SIZE;
	memset(&total, 0, sizeof(total));
	if (info.flags & PRE_SEARCH)
		total.isPreSearch = TRUE;

	isAbort = FALSE;
	writeReq = NULL;
	isSuspend = FALSE;
	readDestStatQueue = FALSE;
	nextFileID = 1;
	errFileID = 0;
	openFiles = NULL;
	autoSlow = 0;

	cv.Initialize(2);
	readReqList.Init();
	writeReqList.Init();

	errBuf.AllocBuf(MIN_ERR_BUF, MAX_ERR_BUF);

	if (info.flags & LISTING_ONLY)
		listBuf.AllocBuf(MIN_PUTLIST_BUF, MAX_PUTLIST_BUF);

	if (info.mode == DELETE_MODE) {
		startTick = ::GetTickCount();
		if (!(hReadThread = (HANDLE)_beginthreadex(0, 0, FastCopy::DeleteThread, this, 0, &id)))
			goto ERR;
		return	TRUE;
	}

#ifdef ACL_TEST
#define	MAX_SUBSTREAM	1000
	openFiles = new FileStat *[info.maxOpenFiles + MAX_SUBSTREAM]; /* for Sub Stream */
#else
	openFiles = new FileStat *[info.maxOpenFiles];
#endif
	openFilesCnt = 0;

	// src/dst dir-entry/attr 梡僶僢僼傽妋曐
	fileStatBuf.AllocBuf(MIN_ATTR_BUF, info.maxAttrSize);
	dirStatBuf.AllocBuf(MIN_ATTR_BUF, info.maxDirSize);
	dstStatBuf.AllocBuf(MIN_ATTR_BUF, info.maxAttrSize);
	dstStatIdxBuf.AllocBuf(MIN_ATTRIDX_BUF, MAX_ATTRIDX_BUF(info.maxAttrSize));
	if (info.flags & SKIP_EMPTYDIR)
		mkdirQueueBuf.AllocBuf(MIN_MKDIRQUEUE_BUF, MAX_MKDIRQUEUE_BUF);

	// 儊僀儞儕儞僌僶僢僼傽妋曐
	if (mainBuf.AllocBuf(allocSize) == FALSE && (info.flags & LISTING_ONLY) == 0) {
		ConfirmErr("Can't alloc memory(mainBuf)", NULL, FALSE);
		goto ERR;
	}

	// 儕儞僌僶僢僼傽梡僆僼僙僢僩弶婜壔
	usedOffset = freeOffset = mainBuf.Buf();

	if (IS_WINNT_V && info.isPhysLock) {
		::SetProcessWorkingSetSize(::GetCurrentProcess(), mainBuf.Size() + APP_MEMSIZE, mainBuf.Size() + APP_MEMSIZE);
		mainBuf.LockBuf();
		fileStatBuf.LockBuf();
		dirStatBuf.LockBuf();
		dstStatBuf.LockBuf();
		dstStatIdxBuf.LockBuf();
	}

	startTick = ::GetTickCount();

⌨️ 快捷键说明

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