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