📄 fastcopy.cpp
字号:
} data = fileStatBuf.Buf() + fileStatBuf.UsedSize(); data_size = sid.Size.LowPart + STRMID_OFFSET; fileStatBuf.AddUsedSize(data_size); if (fileStatBuf.RemainSize() <= maxStatSize && !fileStatBuf.Grow(ALIGN_SIZE(maxStatSize + data_size, MIN_ATTR_BUF))) { if (info.flags & REPORT_ACL_ERROR) ConfirmErr("Can't alloc memory(fileStat(ACL/EADATA))", MakeAddr(src, srcPrefixLen), FALSE); break; } memcpy(data, &sid, STRMID_OFFSET); if (!::BackupRead(stat->hFile, data + STRMID_OFFSET, sid.Size.LowPart, &size, FALSE, TRUE, &context) || size <= 0) { if (info.flags & REPORT_ACL_ERROR) ConfirmErr("BackupRead(ACL/EADATA)", MakeAddr(src, srcPrefixLen)); break; } sid.Size.LowPart = 0; } if ((sid.Size.LowPart || sid.Size.HighPart) && !::BackupSeek(stat->hFile, sid.Size.LowPart, sid.Size.HighPart, &lowSeek, &highSeek, &context)) { if (info.flags & (REPORT_ACL_ERROR|REPORT_STREAM_ERROR)) ConfirmErr("BackupSeek", MakeAddr(src, srcPrefixLen)); break; } } ::BackupRead(stat->hFile, 0, 0, 0, TRUE, FALSE, &context); if (ret) total.readAclStream++; else total.errAclStream++; return ret;}BOOL FastCopy::ReadMultiFilesProc(int dir_len){ for (int i=0; !isAbort && i < openFilesCnt; ) { ReadFileProc(i, &i, dir_len); } 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;}void *FastCopy::RestoreOpenFilePath(void *path, int idx, int dir_len){ FileStat *stat = openFiles[idx]; BOOL isStream = stat->dwFileAttributes ? FALSE : TRUE; if (isStream) { int i; for (i=idx-1; i >= 0; i--) { if (openFiles[i]->dwFileAttributes) { dir_len += sprintfV(MakeAddr(path, dir_len), FMT_STR_V, openFiles[i]->cFileName); break; } } if (i < 0) ConfirmErr("RestoreOpenFilePath", MakeAddr(path, srcPrefixLen), FALSE); } sprintfV(MakeAddr(path, dir_len), FMT_STR_V, stat->cFileName); return path;}BOOL FastCopy::ReadFileProc(int start_idx, int *end_idx, int dir_len){ BOOL ret = TRUE; FileStat *stat = openFiles[start_idx]; _int64 file_size = stat->FileSize(); DWORD trans_size; ReqBuf req_buf; Command command = enableAcl || enableStream ? stat->dwFileAttributes ? WRITE_BACKUP_FILE : WRITE_BACKUP_ALTSTREAM : WRITE_FILE; BOOL isStream = command == WRITE_BACKUP_ALTSTREAM; BOOL is_reparse = IsReparse(stat->dwFileAttributes) && (info.flags & FILE_REPARSE) == 0; BOOL is_send_request = FALSE; int &totalFiles = isStream ? total.readAclStream : total.readFiles; int &totalErrFiles = isStream ? total.errAclStream : total.errFiles; *end_idx = start_idx + 1;// ReadFile 偱懳張// if (!is_reparse && IsReparse(stat->dwFileAttributes)) { // reparse愭傪僐僺乕// srcSectorSize = max(srcSectorSize, OPT_SECTOR_SIZE);// sectorSize = max(srcSectorSize, dstSectorSize);// } if ((file_size == 0 && !is_reparse) || (info.flags & LISTING_ONLY)) { ret = SendRequest(command, 0, stat); is_send_request = TRUE; if (command != WRITE_BACKUP_FILE || (info.flags & LISTING_ONLY)) return ret; } if (stat->hFile == INVALID_HANDLE_VALUE) { if (command != WRITE_BACKUP_ALTSTREAM && file_size > 0) { ::SetLastError(stat->lastError); totalErrFiles++; } stat->SetFileSize(0); if (isStream && !(info.flags & REPORT_STREAM_ERROR) || ConfirmErr(isStream ? "OpenFile(Stream)" : "OpenFile", MakeAddr(RestoreOpenFilePath(src, start_idx, dir_len), srcPrefixLen)) == Confirm::CONTINUE_RESULT) { if ((info.flags & CREATE_OPENERR_FILE) && !is_send_request) { SendRequest(command, 0, stat); is_send_request = TRUE; } } if (is_send_request && command == WRITE_BACKUP_FILE) { SendRequest(WRITE_BACKUP_END, 0, 0); } return FALSE; } if (is_reparse) { BYTE rd[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; if ((stat->repSize = ReadReparsePoint(stat->hFile, rd, sizeof(rd))) <= 0 || PrepareReqBuf(offsetof(ReqHeader, stat) + stat->minSize, stat->repSize, stat->fileID, &req_buf) == FALSE) { ConfirmErr("ReadReparsePoint(File)", MakeAddr(RestoreOpenFilePath(src, start_idx, dir_len), srcPrefixLen)); totalErrFiles++; return FALSE; } memcpy(req_buf.buf, rd, stat->repSize); SendRequest(command, &req_buf, stat); is_send_request = TRUE; } else { ::SetFilePointer(stat->hFile, 0, NULL, FILE_BEGIN); for (_int64 remain_size=file_size; remain_size > 0; remain_size -= trans_size) { trans_size = 0; while (1) { if ((ret = PrepareReqBuf(offsetof(ReqHeader, stat) + (is_send_request ? 0 : stat->minSize), remain_size, stat->fileID, &req_buf)) == FALSE) break; if ((ret = ::ReadFile(stat->hFile, req_buf.buf, req_buf.bufSize, &trans_size, NULL))) break; if (::GetLastError() == ERROR_INVALID_PARAMETER || sectorSize < OPT_SECTOR_SIZE) { // reparse point 偱暿 volume 偵堏摦偟偨応崌梡 srcSectorSize = max(srcSectorSize, OPT_SECTOR_SIZE); sectorSize = max(srcSectorSize, dstSectorSize); }// 僄儔乕専弌傑偱偵帪娫偑偐偐傞偨傔丄堦扷丄儁儞僨傿儞僌// else if (::GetLastError() == ERROR_NO_SYSTEM_RESOURCES && maxTransSize > MIN_BUF) {// maxTransSize = maxTransSize / 2;// maxTransSize = ALIGN_SIZE(maxTransSize, MIN_BUF);// ConfirmErr("limit changed");// } else break; } if (!ret || trans_size != (DWORD)req_buf.bufSize && trans_size < remain_size) { ret = FALSE; totalErrFiles++; if (isStream && !(info.flags & REPORT_STREAM_ERROR) || ConfirmErr(isStream ? "ReadFile(stream)" : ret && !trans_size ? "ReadFile(truncate)" : "ReadFile", MakeAddr(RestoreOpenFilePath(src, start_idx, dir_len), srcPrefixLen)) == Confirm::CONTINUE_RESULT) { stat->SetFileSize(0); req_buf.bufSize = 0; if ((info.flags & CREATE_OPENERR_FILE) || is_send_request) { SendRequest(is_send_request ? WRITE_ABORT : command, &req_buf, is_send_request ? 0 : stat); is_send_request = TRUE; } } break; } total.readTrans += trans_size; SendRequest(is_send_request ? WRITE_FILE_CONT : command, &req_buf, is_send_request ? 0 : stat); is_send_request = TRUE; if (waitTick && remain_size > trans_size) Wait(); } } if (command == WRITE_BACKUP_FILE) { while (ret && !isAbort && (*end_idx) < openFilesCnt && openFiles[(*end_idx)]->dwFileAttributes == 0) { ret = ReadFileProc(*end_idx, end_idx, dir_len); } if (ret && stat->acl) { if ((ret = PrepareReqBuf(offsetof(ReqHeader, stat) + stat->minSize, stat->aclSize, stat->fileID, &req_buf))) { memcpy(req_buf.buf, stat->acl, stat->aclSize); ret = SendRequest(WRITE_BACKUP_ACL, &req_buf, stat); } } if (ret && stat->ead) { if ((ret = PrepareReqBuf(offsetof(ReqHeader, stat) + stat->minSize, stat->eadSize, stat->fileID, &req_buf))) { memcpy(req_buf.buf, stat->ead, stat->eadSize); ret = SendRequest(WRITE_BACKUP_EADATA, &req_buf, stat); } } if (!isAbort && is_send_request) { SendRequest(WRITE_BACKUP_END, 0, 0); } } return ret && !isAbort;}void FastCopy::DstRequest(DstReqKind kind){ cv.Lock(); dstAsyncRequest = kind; cv.Notify(); cv.UnLock();}BOOL FastCopy::WaitDstRequest(void){ cv.Lock(); while (dstAsyncRequest != DSTREQ_NONE && !isAbort) cv.Wait(5000); cv.UnLock(); return dstRequestResult;}BOOL FastCopy::CheckDstRequest(void){ if (isAbort || dstAsyncRequest == DSTREQ_NONE) return FALSE; if (!isSameDrv) cv.UnLock(); switch (dstAsyncRequest) { case DSTREQ_READSTAT: dstRequestResult = ReadDstStat(); break; case DSTREQ_DIGEST: dstRequestResult = MakeDigest(confirmDst, &dstDigestBuf, &dstDigest, dstDigestVal); break; } if (!isSameDrv) { cv.Lock(); cv.Notify(); } dstAsyncRequest = DSTREQ_NONE; return dstRequestResult;}BOOL FastCopy::ReadDstStat(void){ HANDLE fh; int num = 0, len; FileStat *dstStat, **dstStatIdx; WIN32_FIND_DATAW fdat; BOOL ret = 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) { ret = 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++; ret = FALSE; ConfirmErr("FindNextFile(stat)", MakeAddr(confirmDst, dstPrefixLen)); } ::FindClose(fh);END: if (ret) ret = MakeHashTable(); return ret;}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++) { FileStat **stat = hashTbl+(data[i]->hashVal % hashNum); while (*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); } FinishNotify(); 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 (waitTick) Wait((waitTick + 9) / 10); // 嶍彍巜掕偟偨僨傿儗僋僩儕帺懱乮儖乕僩乯偱側偔偐偮丄僼傿儖僞乕彍奜懳徾 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 (IsDir(stat.dwFileAttributes)) 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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -