📄 fastcopy.cpp
字号:
if (fh == INVALID_HANDLE_VALUE) {
total.errFiles++;
SetErrFileID(stat->fileID);
ConfirmErr("CreateFile", MakeAddr(dst, dstPrefixLen));
return FALSE;
}
if (isReOpen) {
#ifdef ACL_TEST
fh2 = CreateFileV(dst, GENERIC_WRITE|WRITE_OWNER|WRITE_DAC, FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
#else
fh2 = CreateFileV(dst, GENERIC_WRITE , FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
#endif
}
if (file_size > writeReq->bufSize) {
_int64 alloc_size = isNonBuf ? ALIGN_SIZE(file_size, dstSectorSize) : file_size;
LONG high_size = (LONG)(alloc_size >> 32);
::SetFilePointer(fh, (LONG)alloc_size, &high_size, FILE_BEGIN);
::SetEndOfFile(fh);
::SetFilePointer(fh, 0, NULL, FILE_BEGIN);
}
while (remain > 0) {
if ((ret = ::WriteFile(fh, writeReq->buf, remain >= writeReq->bufSize ? writeReq->bufSize : (DWORD)(isNonBuf ? ALIGN_SIZE(remain, dstSectorSize) : remain), &trans_size, NULL)) == FALSE) {
SetErrFileID(stat->fileID);
ConfirmErr("WriteFile", MakeAddr(dst, dstPrefixLen), GetLastError() != ERROR_DISK_FULL);
break;
}
if ((remain -= trans_size) > 0) { // 懕偒偑偁傞
total.writeTrans += trans_size;
if (&sv_stat != stat) // file stat 偺戅旔
memcpy((stat = &sv_stat), &writeReq->stat, offsetof(FileStat, cFileName));
if (RecvRequest() == FALSE || writeReq->command != WRITE_FILE_CONT) {
ret = FALSE;
remain = 0;
break;
}
}
else {
total.writeTrans += trans_size + remain;
}
if (autoSlow) {
Sleep(autoSlow);
}
}
if (isReOpen) {
::CloseHandle(fh);
if (fh2 == INVALID_HANDLE_VALUE) {
for (int i=0; i < 10 && !isAbort; i++) { // 僂僀儖僗僠僃僢僋僜僼僩懳嶔
total.openRetry++;
#ifdef ACL_TEST
if ((fh2 = CreateFileV(dst, GENERIC_WRITE|WRITE_OWNER|WRITE_DAC, FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)) != INVALID_HANDLE_VALUE)
#else
if ((fh2 = CreateFileV(dst, GENERIC_WRITE , FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)) != INVALID_HANDLE_VALUE)
#endif
break;
if (::GetLastError() != ERROR_SHARING_VIOLATION)
break;
::Sleep(i * i * 10);
}
if (fh2 == INVALID_HANDLE_VALUE) {
total.errFiles++;
ConfirmErr("CreateFile2", MakeAddr(dst, dstPrefixLen));
return FALSE;
}
}
fh = fh2;
}
if (ret && remain != 0) {
::SetFilePointer(fh, stat->nFileSizeLow, (LONG *)&stat->nFileSizeHigh, FILE_BEGIN);
if ((ret = ::SetEndOfFile(fh)) == FALSE)
ConfirmErr("SetEndOfFile", MakeAddr(dst, dstPrefixLen));
}
if (ret) {
#ifdef ACL_TEST
if (acl_size) {
void *content = NULL;
DWORD size;
if (::BackupWrite(fh, (BYTE *)&acl_sid, offsetof(WIN32_STREAM_ID, cStreamName), &size, FALSE, TRUE, &content)) {
if (!::BackupWrite(fh, (BYTE *)&acl_data, acl_size, &acl_size, FALSE, TRUE, &content))
ConfirmErr("BackupWrite", MakeAddr(dst, dstPrefixLen));
}
::BackupWrite(fh, NULL, NULL, NULL, TRUE, TRUE, &content);
}
#endif
::SetFileTime(fh, &stat->ftCreationTime, &stat->ftLastAccessTime, &stat->ftLastWriteTime);
}
::CloseHandle(fh);
if (ret) {
if (stat->dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM))
SetFileAttributesV(dst, stat->dwFileAttributes);
total.writeFiles++;
}
else {
total.errFiles++;
DeleteFileV(dst);
}
return ret && !isAbort;
}
BOOL FastCopy::ChangeToWriteModeCore(void)
{
writeReqList.MoveList(&readReqList);
cv.Notify();
while (!writeReqList.IsEmpty() && !isAbort)
cv.Wait();
return !isAbort;
}
BOOL FastCopy::ChangeToWriteMode(void)
{
cv.Lock();
BOOL ret = ChangeToWriteModeCore();
cv.UnLock();
return ret;
}
BOOL FastCopy::AllocReqBuf(int req_size, _int64 _data_size, ReqBuf *buf)
{
int max_free = mainBuf.Buf() + mainBuf.Size() - usedOffset;
int max_trans = autoSlow && (info.flags & AUTOSLOW_IOLIMIT) ? MIN_BUF : maxTransSize;
int data_size = (_data_size > max_trans) ? max_trans : (int)_data_size;
int align_data_size = ALIGN_SIZE(data_size, 8);
int sector_data_size = ALIGN_SIZE(data_size, sectorSize);
int require_size = align_data_size + req_size;
BYTE *align_offset = data_size ? (BYTE *)ALIGN_SIZE((u_int)usedOffset, sectorSize) : usedOffset;
max_free -= align_offset - usedOffset;
if (data_size && align_data_size + req_size < sector_data_size)
require_size = sector_data_size;
if (require_size > max_free) {
if (max_free < MIN_BUF) {
align_offset = mainBuf.Buf();
if (isSameDrv && ChangeToWriteModeCore() == FALSE) // Read -> Write 愗傝懼偊
return FALSE;
}
else {
data_size = max_free - req_size;
align_data_size = data_size = (data_size / BIGTRANS_ALIGN) * BIGTRANS_ALIGN;
require_size = data_size + req_size;
}
}
buf->buf = align_offset;
buf->bufSize = ALIGN_SIZE(data_size, sectorSize);
buf->req = (ReqHeader *)(buf->buf + align_data_size);
buf->reqSize = req_size;
while (!writeReqList.IsEmpty() && !isAbort) { // isSameDrv == TRUE 偺応崌丄昁偢 Empty
if (buf->buf == mainBuf.Buf()) {
if (freeOffset < usedOffset && (freeOffset - mainBuf.Buf()) >= require_size)
break;
}
else {
if (freeOffset < usedOffset || buf->buf + require_size <= freeOffset)
break;
}
cv.Wait();
}
usedOffset = buf->buf + require_size;
return !isAbort;
}
BOOL FastCopy::PrepareReqBuf(int req_size, _int64 data_size, _int64 file_id, ReqBuf *buf)
{
BOOL ret = TRUE;
cv.Lock();
if (errFileID) {
if (errFileID == file_id)
ret = FALSE;
errFileID = 0;
}
if (ret)
ret = AllocReqBuf(req_size, data_size, buf);
cv.UnLock();
return ret;
}
BOOL FastCopy::SendRequest(Command command, ReqBuf *buf, FileStat *stat)
{
BOOL ret = TRUE;
ReqBuf tmp_buf;
cv.Lock();
if (buf == NULL) {
buf = &tmp_buf;
ret = AllocReqBuf(offsetof(ReqHeader, stat) + (stat ? stat->minSize : 0), 0, buf);
}
if (ret && !isAbort) {
ReqHeader *readReq;
readReq = buf->req;
readReq->reqSize = buf->reqSize;
readReq->command = command;
readReq->buf = buf->buf;
readReq->bufSize = buf->bufSize;
if (stat)
memcpy(&readReq->stat, stat, stat->minSize);
if (isSameDrv) {
readReqList.AddObj(readReq);
}
else {
writeReqList.AddObj(readReq);
cv.Notify();
}
}
cv.UnLock();
return ret && !isAbort;
}
BOOL FastCopy::RecvRequest(void)
{
cv.Lock();
if (writeReq)
WriteReqDone();
if (readDestStatQueue)
ReadDestStat();
while (writeReqList.IsEmpty() && !isAbort) {
cv.Wait();
if (readDestStatQueue)
ReadDestStat();
}
writeReq = writeReqList.TopObj();
if (writeReq && writeReq->command == REQ_EOF)
WriteReqDone();
cv.UnLock();
return writeReq && !isAbort;
}
void FastCopy::WriteReqDone(void)
{
writeReqList.DelObj(writeReq);
freeOffset = (BYTE *)writeReq + writeReq->reqSize;
if (!isSameDrv || writeReqList.IsEmpty())
cv.Notify();
}
void FastCopy::SetErrFileID(_int64 file_id)
{
cv.Lock();
errFileID = file_id;
cv.UnLock();
}
BOOL FastCopy::End(void)
{
isAbort = TRUE;
while (hWriteThread || hReadThread) { // WaitForMultipleObject() 傊偺曄峏偼屻擔
cv.Lock();
cv.Notify();
cv.UnLock();
if (hReadThread && ::WaitForSingleObject(hReadThread, 100) != WAIT_TIMEOUT) {
::CloseHandle(hReadThread);
hReadThread = NULL;
}
if (hWriteThread && ::WaitForSingleObject(hWriteThread, 100) != WAIT_TIMEOUT) {
::CloseHandle(hWriteThread);
hWriteThread = NULL;
}
}
::ReleaseMutex(hRunMutex);
if (info.flags & LISTING_ONLY)
listBuf.FreeBuf();
errBuf.FreeBuf();
if (info.mode != DELETE_MODE) {
delete [] openFiles;
openFiles = NULL;
if (info.flags & SKIP_EMPTYDIR)
mkdirQueueBuf.FreeBuf();
fileStatBuf.FreeBuf();
dirStatBuf.FreeBuf();
dstStatBuf.FreeBuf();
dstStatIdxBuf.FreeBuf();
mainBuf.FreeBuf();
}
return TRUE;
}
BOOL FastCopy::Suspend(void)
{
if (!hReadThread && !hWriteThread || isSuspend)
return FALSE;
if (hReadThread)
::SuspendThread(hReadThread);
if (hWriteThread)
::SuspendThread(hWriteThread);
isSuspend = TRUE;
suspendTick = ::GetTickCount();
return TRUE;
}
BOOL FastCopy::Resume(void)
{
if (!hReadThread && !hWriteThread || !isSuspend)
return FALSE;
isSuspend = FALSE;
startTick += (::GetTickCount() - suspendTick);
if (hReadThread)
::ResumeThread(hReadThread);
if (hWriteThread)
::ResumeThread(hWriteThread);
return TRUE;
}
BOOL FastCopy::GetTransInfo(TransInfo *ti, BOOL fullInfo)
{
ti->total = total;
ti->listBuf = &listBuf;
ti->listCs = &listCs;
ti->errBuf = &errBuf;
ti->errCs = &errCs;
ti->isSameDrv = isSameDrv;
ti->ignoreErr = info.ignoreErr;
ti->autoSlow = autoSlow;
ti->tickCount = (isSuspend ? suspendTick : ::GetTickCount()) - startTick;
if (fullInfo) {
if (IS_WINNT_V)
ConvertExternalPath(MakeAddr(dst, dstPrefixLen), ti->curPath, sizeof(ti->curPath)/sizeof(WCHAR));
else
sprintfV(ti->curPath, "%.250s", dst);
}
return TRUE;
}
int FastCopy::FdatToFileStat(WIN32_FIND_DATAW *fdat, FileStat *stat, BOOL is_usehash)
{
stat->fileID = 0;
stat->ftCreationTime = fdat->ftCreationTime;
stat->ftLastAccessTime = fdat->ftLastAccessTime;
stat->ftLastWriteTime = fdat->ftLastWriteTime;
stat->nFileSizeLow = fdat->nFileSizeLow;
stat->nFileSizeHigh = fdat->nFileSizeHigh;
stat->dwFileAttributes = fdat->dwFileAttributes;
stat->hFile = INVALID_HANDLE_VALUE;
stat->lastError = 0;
stat->isExists = FALSE;
stat->renameCount = 0;
stat->next = NULL;
int len = (sprintfV(stat->cFileName, FMT_STR_V, fdat->cFileName) + 1) * CHAR_LEN_V;
stat->size = len + offsetof(FileStat, cFileName);
stat->minSize = ALIGN_SIZE(stat->size, 8);
if (is_usehash) {
stat->upperName = stat->cFileName + len;
memcpy(stat->upperName, stat->cFileName, len);
CharUpperV(stat->upperName);
stat->hashVal = hashVal.MakeHash(stat->upperName, len);
stat->size += len;
}
stat->size = ALIGN_SIZE(stat->size, 8);
return stat->size;
}
BOOL FastCopy::ConvertExternalPath(const void *path, void *buf, int max_buf, BOOL to_ansi)
{
if (GetChar(path, 0) == '\\' && GetChar(path, 1) != '\\') { // UNC
if (to_ansi) {
*(char *)buf = '\\';
buf = (char *)buf + 1;
}
else {
SetChar(buf, 0, '\\');
buf = MakeAddr(buf, 1);
}
max_buf--;
}
if (to_ansi)
::WideCharToMultiByte(CP_ACP, 0, (WCHAR *)path, -1, (char *)buf, max_buf, 0, 0);
else
sprintfV(buf, L"%.*s", max_buf, path);
return TRUE;
}
FastCopy::Confirm::Result FastCopy::ConfirmErr(const char *message, const void *path, BOOL allow_continue)
{
if (isAbort)
return Confirm::CANCEL_RESULT;
char path_buf[MAX_PATH_EX], msg_buf[MAX_PATH_EX + 100];
DWORD err_code = ::GetLastError();
if (path && IS_WINNT_V) {
ConvertExternalPath(path, path_buf, sizeof(path_buf), TRUE);
path = path_buf;
}
int len = sprintf(msg_buf, "%s(", message);
len += FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err_code, info.lcid > 0 ? LANGIDFROMLCID(info.lcid) : MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), msg_buf + len, MAX_PATH_EX, NULL);
if (msg_buf[len-1] == '\n')
len -= 2;
len += sprintf(msg_buf + len, "%u) : %s", err_code, path ? path : "");
WriteErrLog(msg_buf, len);
if (allow_continue == FALSE)
isAbort = TRUE;
else if (info.ignoreErr)
return Confirm::CONTINUE_RESULT;
isSuspend = TRUE;
suspendTick = ::GetTickCount();
Confirm confirm = { msg_buf, allow_continue, path, Confirm::CONTINUE_RESULT };
info.notifyWnd->SendMessage(info.uNotifyMsg, CONFIRM_NOTIFY, (LPARAM)&confirm);
isSuspend = FALSE;
startTick += (::GetTickCount() - suspendTick);
switch (confirm.result) {
case Confirm::IGNORE_RESULT:
info.ignoreErr = TRUE;
confirm.result = Confirm::CONTINUE_RESULT;
break;
case Confirm::CANCEL_RESULT:
isAbort = TRUE;
break;
}
return confirm.result;
}
BOOL FastCopy::WriteErrLog(char *message, int len)
{
#define ERRMSG_SIZE 30
::EnterCriticalSection(&errCs);
BOOL ret = TRUE;
char *msg_buf = (char *)errBuf.Buf() + errBuf.UsedSize();
if (len == -1)
len = strlen(message);
len += ERRMSG_SIZE;
if (errBuf.UsedSize() + len <= errBuf.MaxSize()) {
if (errBuf.RemainSize() > len || errBuf.Grow(ALIGN_SIZE(len, PAGE_SIZE))) {
len = sprintf(msg_buf, "%s%s", errBuf.UsedSize() ? "\r\n" : "", message);
errBuf.AddUsedSize(len);
}
}
else {
if (errBuf.RemainSize()) {
sprintf(msg_buf, "%s", "\r\n Too Many Errors...");
errBuf.SetUsedSize(errBuf.MaxSize());
}
ret = FALSE;
}
::LeaveCriticalSection(&errCs);
return ret;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -