📄 fastcopy.cpp
字号:
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 + -