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