diff options
Diffstat (limited to 'plugins/CopyEngine/Ultracopier-Spec/async/TransferThreadAsync.cpp')
-rwxr-xr-x | plugins/CopyEngine/Ultracopier-Spec/async/TransferThreadAsync.cpp | 1442 |
1 files changed, 1442 insertions, 0 deletions
diff --git a/plugins/CopyEngine/Ultracopier-Spec/async/TransferThreadAsync.cpp b/plugins/CopyEngine/Ultracopier-Spec/async/TransferThreadAsync.cpp new file mode 100755 index 0000000..b5af928 --- /dev/null +++ b/plugins/CopyEngine/Ultracopier-Spec/async/TransferThreadAsync.cpp @@ -0,0 +1,1442 @@ +//presume bug linked as multple paralelle inode to resume after "overwrite" +//then do overwrite node function to not re-set the file name + +#include "TransferThreadAsync.h" +#include <string> +#include <dirent.h> + +#ifdef Q_OS_WIN32 +#include <accctrl.h> +#include <aclapi.h> +#include <winbase.h> + +#define REPARSE_MOUNTPOINT_HEADER_SIZE 8 + +typedef struct _REPARSE_DATA_BUFFER { + ULONG ReparseTag; + USHORT ReparseDataLength; + USHORT Reserved; + union { + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + ULONG Flags; + WCHAR PathBuffer[1]; + } SymbolicLinkReparseBuffer; + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + WCHAR PathBuffer[1]; + } MountPointReparseBuffer; + struct { + UCHAR DataBuffer[1]; + } GenericReparseBuffer; + } DUMMYUNIONNAME; +} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; + +/*memo> HANDLE hToken = NULL; +TOKEN_PRIVILEGES tp; +try { + if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) throw ::GetLastError(); + if (!::LookupPrivilegeValue(NULL, SE_RESTORE_NAME, &tp.Privileges[0].Luid)) throw ::GetLastError(); + tp.PrivilegeCount = 1; + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + if (!::AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) throw ::GetLastError(); +} +catch (DWORD) { + ok=false; +} +if (hToken) + ::CloseHandle(hToken);*/ +#endif + +#include "../../../../cpp11addition.h" + +#ifndef Q_OS_WIN32 +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#endif + +TransferThreadAsync::TransferThreadAsync() : + transferProgression(0) +{ + haveStartTime=false; + #ifndef Q_OS_UNIX + PSecurityD=NULL; + dacl=NULL; + #endif + //ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+QStringLiteral("] start: ")+QString::number((qint64)QThread::currentThreadId()))); + //the error push + readThread.setWriteThread(&writeThread); + + TransferThread::run(); + if(!connect(this,&TransferThreadAsync::internalStartPostOperation, this, &TransferThreadAsync::doFilePostOperation, Qt::QueuedConnection)) + abort(); + + //the thread change operation + if(!connect(this,&TransferThread::internalStartPreOperation, this, &TransferThreadAsync::preOperation, Qt::QueuedConnection)) + abort(); + if(!connect(this,&TransferThread::internalStartPostOperation, this, &TransferThreadAsync::postOperation, Qt::QueuedConnection)) + abort(); + if(!connect(this,&TransferThread::internalTryStartTheTransfer, this, &TransferThreadAsync::internalStartTheTransfer, Qt::QueuedConnection)) + abort(); + + //the error push + if(!connect(&readThread,&ReadThread::error, this, &TransferThreadAsync::read_error, Qt::QueuedConnection)) + abort(); + if(!connect(&writeThread,&WriteThread::error, this, &TransferThreadAsync::write_error, Qt::QueuedConnection)) + abort(); + //the state change operation + if(!connect(&readThread,&ReadThread::readIsStopped, this, &TransferThreadAsync::read_readIsStopped, Qt::QueuedConnection)) + abort(); + if(!connect(&readThread,&ReadThread::readIsStopped, &writeThread, &WriteThread::endIsDetected, Qt::QueuedConnection)) + abort(); + if(!connect(&readThread,&ReadThread::closed, this, &TransferThreadAsync::read_closed, Qt::QueuedConnection)) + abort(); + if(!connect(&writeThread,&WriteThread::closed, this, &TransferThreadAsync::write_closed, Qt::QueuedConnection)) + abort(); + + if(!connect(this, &TransferThreadAsync::openRead,&readThread,&ReadThread::openRead, Qt::QueuedConnection)) + abort(); + if(!connect(this, &TransferThreadAsync::openWrite,&writeThread,&WriteThread::openWrite, Qt::QueuedConnection)) + abort(); + + //when both is ready, startRead() + if(!connect(&readThread,&ReadThread::opened, this, &TransferThreadAsync::read_opened, Qt::QueuedConnection)) + abort(); + if(!connect(&writeThread,&WriteThread::opened, this, &TransferThreadAsync::write_opened, Qt::QueuedConnection)) + abort(); + + //error management +/* if(!connect(&readThread,&ReadThread::isSeekToZeroAndWait, this, &TransferThreadAsync::readThreadIsSeekToZeroAndWait, Qt::QueuedConnection)) + abort(); + if(!connect(&readThread,&ReadThread::resumeAfterErrorByRestartAtTheLastPosition,this, &TransferThreadAsync::readThreadResumeAfterError, Qt::QueuedConnection)) + abort(); + if(!connect(&readThread,&ReadThread::resumeAfterErrorByRestartAll,&writeThread, &WriteThread::flushAndSeekToZero, Qt::QueuedConnection)) + abort(); + if(!connect(&writeThread,&WriteThread::flushedAndSeekedToZero, this, &TransferThread::readThreadResumeAfterError, Qt::QueuedConnection)) + abort();*/ + + #ifdef ULTRACOPIER_PLUGIN_DEBUG + if(!connect(&readThread,&ReadThread::debugInformation, this, &TransferThreadAsync::debugInformation, Qt::QueuedConnection)) + abort(); + if(!connect(&writeThread,&WriteThread::debugInformation, this, &TransferThreadAsync::debugInformation, Qt::QueuedConnection)) + abort(); + if(!connect(&driveManagement,&DriveManagement::debugInformation,this, &TransferThreadAsync::debugInformation, Qt::QueuedConnection)) + abort(); + #endif + + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] start: "+std::to_string((int64_t)QThread::currentThreadId())); + start(); + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] stop: "+std::to_string((int64_t)QThread::currentThreadId())); +} + +TransferThreadAsync::~TransferThreadAsync() +{ + #ifdef Q_OS_WIN32 + stopItWin=1; + #endif + stopIt=true; + readThread.stop(); + readThread.exit(); + readThread.wait(); + writeThread.stop(); + writeThread.exit(); + writeThread.wait(); + exit(0); + wait(); + //else cash without this disconnect + //disconnect(&readThread); + //disconnect(&writeThread); + #ifndef Q_OS_UNIX + if(PSecurityD!=NULL) + { + //free(PSecurityD); + PSecurityD=NULL; + } + if(dacl!=NULL) + { + //free(dacl); + dacl=NULL; + } + #endif +} + +void TransferThreadAsync::run() +{ + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] start: "+std::to_string((int64_t)QThread::currentThreadId())); + moveToThread(this); + exec(); + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] stop: "+std::to_string((int64_t)QThread::currentThreadId())); +} + +void TransferThreadAsync::startTheTransfer() +{ + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+("] start")); + if(transferId==0) + { + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Critical,"["+std::to_string(id)+("] can't start transfert if transferId==0")); + return; + } + startTransferTime.restart(); + haveTransferTime=true; + emit internalTryStartTheTransfer(); +} + +void TransferThreadAsync::internalStartTheTransfer() +{ + #ifdef ULTRACOPIER_PLUGIN_DEBUG + if(QThread::currentThread()!=this) + abort(); + #endif + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+("] start")); + if(transfer_stat==TransferStat_Idle) + { + if(mode!=Ultracopier::Move) + { + /// \bug can pass here because in case of direct move on same media, it return to idle stat directly + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Critical,"["+std::to_string(id)+("] can't start transfert at idle")); + } + return; + } + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+("] start")); + if(transfer_stat==TransferStat_PostOperation) + { + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Critical,"["+std::to_string(id)+("] can't start transfert at PostOperation")); + return; + } + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+("] start")); + if(transfer_stat==TransferStat_Transfer) + { + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Critical,"["+std::to_string(id)+("] can't start transfert at Transfer")); + return; + } + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+("] start")); + if(canStartTransfer) + { + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+("] canStartTransfer is already set to true")); + // call for second time, first time was not ready, if blocked in preop why? + //ifCanStartTransfer(); + return; + } + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+("] check how start the transfer")); + canStartTransfer=true; + + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+("] start directly the transfer")); + ifCanStartTransfer(); +} + +bool TransferThreadAsync::setFiles(const INTERNALTYPEPATH& source, const int64_t &size, const INTERNALTYPEPATH& destination, const Ultracopier::CopyMode &mode) +{ + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] start, source: "+TransferThread::internalStringTostring(source)+ + ", destination: "+TransferThread::internalStringTostring(destination)); + if(transfer_stat!=TransferStat_Idle) + { + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Critical,"["+std::to_string(id)+("] already used, source: ")+TransferThread::internalStringTostring(source)+ + ", destination: "+TransferThread::internalStringTostring(destination)); + return false; + } + if(!isRunning()) + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Critical,"["+std::to_string(id)+"] The current thread is not running"); + if(!TransferThread::setFiles(source,size,destination,mode)) + return false; + transferProgression=0; + //transferSize=0;//set by ListThread at currentTransferThread->transferSize=currentActionToDoTransfer.size; very important to do parallel small file + sended_state_readStopped=false; + readIsClosedVariable=false; + writeIsClosedVariable=false; + readIsOpenVariable=false; + writeIsOpenVariable=false; + realMove=false; + return true; +} + +void TransferThreadAsync::resetExtraVariable() +{ + transferProgression=0; + readIsOpenVariable=false; + writeIsOpenVariable=false; + TransferThread::resetExtraVariable(); +} + +bool TransferThreadAsync::remainFileOpen() const +{ + return remainSourceOpen() || remainDestinationOpen(); +} + +bool TransferThreadAsync::remainSourceOpen() const +{ + return !readIsClosedVariable; +} + +bool TransferThreadAsync::remainDestinationOpen() const +{ + return !writeIsClosedVariable; +} + +void TransferThreadAsync::preOperation() +{ + if(transfer_stat!=TransferStat_PreOperation) + { + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Critical,"["+std::to_string(id)+("] already used, source: ")+ + TransferThread::internalStringTostring(source)+", destination: "+TransferThread::internalStringTostring(destination) + +" transfer_stat: "+std::to_string(transfer_stat)); + return; + } + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] start: source: "+ + TransferThread::internalStringTostring(source)+", destination: "+TransferThread::internalStringTostring(destination)); + haveStartTime=true; + needRemove=false; + if(isSame()) + { + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] is same "+ + TransferThread::internalStringTostring(source)+" than "+TransferThread::internalStringTostring(destination)); + return; + } + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] after is same"); + /*Why this code? + if(readError) + { + readError=false; + return; + }*/ + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] before destination exists"); + if(destinationExists()) + { + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] destination exists: "+TransferThread::internalStringTostring(destination)); + return; + } + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] after destination exists"); + /*Why this code? + if(readError) + { + readError=false; + return; + }*/ + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] before keep date"); + #ifdef Q_OS_WIN32 + doTheDateTransfer=!is_symlink(source); + #else + doTheDateTransfer=true; + #endif + if(doTheDateTransfer) + { + doTheDateTransfer=readSourceFileDateTime(source); + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] after keep date"); + #ifdef Q_OS_MAC + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] read the source time: "+std::to_string(butime.modtime)); + #endif + if(!doTheDateTransfer) + { + //will have the real error at source open + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] unable to read the source time: "+TransferThread::internalStringTostring(source)); + if(keepDate) + { + emit errorOnFile(source,tr("Wrong modification date or unable to get it, you can disable time transfer to do it").toStdString()); + return; + } + } + } + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] before perm"); + if(doRightTransfer) + havePermission=readSourceFilePermissions(source); + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] after perm"); + transfer_stat=TransferStat_WaitForTheTransfer; + ifCanStartTransfer(); + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] emit preOperationStopped()"); + emit preOperationStopped(); +} + +void TransferThreadAsync::postOperation() +{ + doFilePostOperation(); +} + +#ifdef Q_OS_WIN32 +DWORD CALLBACK progressRoutine( + LARGE_INTEGER TotalFileSize, + LARGE_INTEGER TotalBytesTransferred, + LARGE_INTEGER StreamSize, + LARGE_INTEGER StreamBytesTransferred, + DWORD dwStreamNumber, + DWORD dwCallbackReason, + HANDLE hSourceFile, + HANDLE hDestinationFile, + LPVOID lpData +) +{ + (void)TotalFileSize; + (void)TotalBytesTransferred; + (void)StreamSize; + (void)StreamBytesTransferred; + (void)dwStreamNumber; + (void)dwCallbackReason; + (void)hSourceFile; + (void)hDestinationFile; + (void)lpData; + + static_cast<TransferThreadAsync *>(lpData)->setProgression(TotalBytesTransferred.QuadPart,TotalFileSize.QuadPart); + return PROGRESS_CONTINUE; +} + +void TransferThreadAsync::setProgression(const uint64_t &pos, const uint64_t &size) +{ + if(transfer_stat==TransferStat_Transfer) + { + if(pos==size) + emit readStopped(); + transferProgression=pos; + } +} +#endif + +/// \brief set buffer +void TransferThreadAsync::setBuffer(const bool buffer) +{ + writeThread.buffer=buffer; +} + +void TransferThreadAsync::ifCanStartTransfer() +{ + realMove=false; + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] start "+internalStringTostring(source)+"->"+internalStringTostring(destination)); + if(transfer_stat!=TransferStat_WaitForTheTransfer /*wait preoperation*/ || !canStartTransfer/*wait start call*/) + { + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Information,"["+std::to_string(id)+ + "] transfer_stat:"+std::to_string(transfer_stat)+ + ", canStartTransfer: "+std::to_string(canStartTransfer)); + //preOperationStopped();//tiger to seam maybe is can be started, maybe this generate a bug + return; + } + transfer_stat=TransferStat_Transfer; + + #ifdef WIDESTRING + const size_t destinationIndex=destination.rfind(L'/'); + if(destinationIndex!=std::string::npos && destinationIndex<destination.size()) + { + const std::wstring &path=destination.substr(0,destinationIndex); + if(!is_dir(path)) + if(!TransferThread::mkpath(path)) + { + #ifdef Q_OS_WIN32 + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Warning,"["+std::to_string(id)+"] Unable to create the destination folder: "+internalStringTostring(path)+" "+TransferThread::GetLastErrorStdStr()); + emit errorOnFile(destination,tr("Unable to create the destination folder: ").toStdString()+TransferThread::GetLastErrorStdStr()); + #else + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Warning,"["+std::to_string(id)+"] Unable to create the destination folder: "+internalStringTostring(path)+" "+std::to_string(errno)); + emit errorOnFile(destination,tr("Unable to create the destination folder, errno: %1").arg(QString::number(errno)).toStdString()); + #endif + return; + } + } + #else + const size_t destinationIndex=destination.rfind('/'); + if(destinationIndex!=std::string::npos && destinationIndex<destination.size()) + { + const std::string &path=destination.substr(0,destinationIndex); + if(!is_dir(path)) + if(!TransferThread::mkpath(path)) + { + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Warning,"["+std::to_string(id)+"] Unable to create the destination folder: "+path); + #ifdef Q_OS_WIN32 + emit errorOnFile(destination,tr("Unable to create the destination folder: ")+TransferThread::GetLastErrorStdStr()); + #else + emit errorOnFile(destination,tr("Unable to create the destination folder, errno: %1").arg(QString::number(errno)).toStdString()); + #endif + return; + } + } + #endif + + /* http://www.flexhex.com/docs/articles/hard-links.phtml + * Do here the smblink logic + * Under windows: BOOLEAN CreateSymbolicLinkA( + LPCSTR lpSymlinkFileName, + LPCSTR lpTargetFileName, + DWORD dwFlags + unix: int symlink(const char *target, const char *linkpath); +); + + */ + + emit pushStat(transfer_stat,transferId); + realMove=(mode==Ultracopier::Move && driveManagement.isSameDrive( + internalStringTostring(source), + internalStringTostring(destination) + )); + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] start copy"); + needRemove=true; + bool successFull=false; + readError=false; + writeError=false; + if(realMove) + { + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] start real move"); + successFull=TransferThread::rename(source,destination); + #ifdef Q_OS_UNIX + if(!successFull && errno==18) + { + //try full move + realMove=false; + openRead(source,mode); + openWrite(destination,0); + return; + } + #endif + } + else + { + #ifdef Q_OS_WIN32 + bool isJunction=false; + bool isSymlink=false; + WIN32_FILE_ATTRIBUTE_DATA fileInfo; + BOOL r = GetFileAttributesExW(TransferThread::toFinalPath(source).c_str(), GetFileExInfoStandard, &fileInfo); + if(r != FALSE) + { + /*isJunction = fileInfo.dwFileAttributes != INVALID_FILE_ATTRIBUTES && + (fileInfo.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT);*/ + isSymlink = fileInfo.dwFileAttributes != INVALID_FILE_ATTRIBUTES && + (fileInfo.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT); + } + if(isSymlink) + { + BYTE buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + REPARSE_DATA_BUFFER& ReparseBuffer = (REPARSE_DATA_BUFFER&)buf; + DWORD dwRet=0; + HANDLE hDir = ::CreateFile(TransferThread::toFinalPath(source).c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL); + if (hDir != INVALID_HANDLE_VALUE) + { + BOOL ioc = ::DeviceIoControl(hDir, FSCTL_GET_REPARSE_POINT, NULL, 0, &ReparseBuffer, + MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &dwRet, NULL); + ::CloseHandle(hDir); + if(ioc!=FALSE) + { + if(ReparseBuffer.ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) + { + //printf("%S\n",ReparseBuffer.MountPointReparseBuffer.PathBuffer); + isJunction=true; + } + else + { + //printf("%S\n",ReparseBuffer.SymbolicLinkReparseBuffer.PathBuffer); + } + } + else + { + const std::string &strError=TransferThread::GetLastErrorStdStr(); + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Warning,"["+std::to_string(id)+"] stop copy in error: "+ + GetLastErrorStdStr()+" "+TransferThread::internalStringTostring(source)+"->"+TransferThread::internalStringTostring(destination)+ + " "+strError + ); + readError=true; + writeError=false; + emit errorOnFile(source,strError); + return; + } + } + else + { + const std::string &strError=TransferThread::GetLastErrorStdStr(); + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Warning,"["+std::to_string(id)+"] stop copy in error: "+ + GetLastErrorStdStr()+" "+TransferThread::internalStringTostring(source)+"->"+TransferThread::internalStringTostring(destination)+ + " "+strError + ); + readError=true; + writeError=false; + emit errorOnFile(source,strError); + return; + } + if(isJunction)//junction + { + std::wstring cleanPath(ReparseBuffer.MountPointReparseBuffer.PathBuffer); + if(cleanPath.substr(0,4)==L"\\??\\") + cleanPath=cleanPath.substr(4); + successFull=TransferThreadAsync::mkJunction( + TransferThread::toFinalPath(destination).c_str(), + cleanPath.c_str() + ); + if(successFull==FALSE) + { + const std::string &strError=TransferThread::GetLastErrorStdStr(); + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Warning,"["+std::to_string(id)+"] stop copy in error: "+ + GetLastErrorStdStr()+" "+TransferThread::internalStringTostring(source)+"->"+TransferThread::internalStringTostring(destination)+ + " "+strError + ); + readError=true; + writeError=true; + emit errorOnFile(destination,strError); + } + } + else//symlink or symlinkD + { + successFull=CopyFileExW(TransferThread::toFinalPath(source).c_str(),TransferThread::toFinalPath(destination).c_str(), + (LPPROGRESS_ROUTINE)progressRoutine,this,&stopItWin,COPY_FILE_ALLOW_DECRYPTED_DESTINATION | 0x00000800);//0x00000800 is COPY_FILE_COPY_SYMLINK + if(successFull==FALSE) + { + const std::string &strError=TransferThread::GetLastErrorStdStr(); + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Warning,"["+std::to_string(id)+"] stop copy in error: "+ + GetLastErrorStdStr()+" "+TransferThread::internalStringTostring(source)+"->"+TransferThread::internalStringTostring(destination)+ + " "+strError + ); + readError=true; + writeError=true; + emit errorOnFile(destination,strError); + } + } + } + else + #else + if(TransferThread::is_symlink(source)) + { + realMove=true; + bool isFileOrSymlink=false; + { + struct stat p_statbuf; + if (lstat(TransferThread::internalStringTostring(destination).c_str(), &p_statbuf) < 0) + {} + else if (S_ISLNK(p_statbuf.st_mode)) + isFileOrSymlink=true; + else if (S_ISREG(p_statbuf.st_mode)) + isFileOrSymlink=true; + } + if(isFileOrSymlink) + if(!unlink(destination)) + { + const int terr=errno; + if(terr!=2) + { + const std::string &strError=strerror(terr); + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Warning,"["+std::to_string(id)+"] stop copy in error "+ + TransferThread::internalStringTostring(source)+"->"+TransferThread::internalStringTostring(destination)+ + " "+strError+"("+std::to_string(terr)+")" + ); + readError=false; + writeError=true; + emit errorOnFile(destination,strError); + return; + } + } + char buf[PATH_MAX]; + const ssize_t s=readlink(TransferThread::internalStringTostring(source).c_str(),buf,sizeof(buf)); + buf[s]=0x00; + if(s<0) + { + const int terr=errno; + const std::string &strError=strerror(terr); + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Warning,"["+std::to_string(id)+"] stop copy in error "+ + TransferThread::internalStringTostring(source)+"->"+TransferThread::internalStringTostring(destination)+ + " "+strError+"("+std::to_string(terr)+")" + ); + readError=true; + writeError=false; + emit errorOnFile(source,strError); + return; + } + else + { + if(symlink(buf,TransferThread::internalStringTostring(destination).c_str())!=0) + { + const int terr=errno; + const std::string &strError=strerror(terr); + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Warning,"["+std::to_string(id)+"] stop copy in error "+ + buf+"->"+TransferThread::internalStringTostring(destination)+ + " "+strError+"("+std::to_string(terr)+")" + ); + readError=true; + writeError=false; + emit errorOnFile(destination,strError); + return; + } + } + successFull=true; + } + else + #endif + { + #ifdef Q_OS_WIN32 + if(native_copy) + { + successFull=CopyFileExW(TransferThread::toFinalPath(source).c_str(),TransferThread::toFinalPath(destination).c_str(), + (LPPROGRESS_ROUTINE)progressRoutine,this,&stopItWin,COPY_FILE_ALLOW_DECRYPTED_DESTINATION | 0x00000800);//0x00000800 is COPY_FILE_COPY_SYMLINK + if(successFull==FALSE) + { + const std::string &strError=TransferThread::GetLastErrorStdStr(); + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Warning,"["+std::to_string(id)+"] stop copy in error: "+ + GetLastErrorStdStr()+" "+TransferThread::internalStringTostring(source)+"->"+TransferThread::internalStringTostring(destination)+ + " "+strError + ); + readError=true; + writeError=true; + emit errorOnFile(destination,strError); + } + } + else + #endif + { + openRead(source,mode); + openWrite(destination,0); + return; + } + } + } + if(!successFull) + { + #ifdef Q_OS_WIN32 + const std::string &strError=TransferThread::GetLastErrorStdStr(); + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Warning,"["+std::to_string(id)+"] stop copy in error: "+ + GetLastErrorStdStr()+" "+TransferThread::internalStringTostring(source)+"->"+TransferThread::internalStringTostring(destination)+ + " "+strError + ); + #else + const int terr=errno; + const std::string &strError=strerror(terr); + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Warning,"["+std::to_string(id)+"] stop copy in error "+ + TransferThread::internalStringTostring(source)+"->"+TransferThread::internalStringTostring(destination)+ + " "+strError+"("+std::to_string(terr)+")" + ); + #endif + if(stopIt) + { + if(!source.empty()) + if(exists(source) && source!=destination) + unlink(destination); + resetExtraVariable(); + return;//and reset? + } + #ifdef Q_OS_WIN32 + readError=true; + writeError=true; + emit errorOnFile(destination,strError); + #else + if(readError) + emit errorOnFile(source,strError); + else + emit errorOnFile(destination,strError); + #endif + return; + } + readIsClosedVariable=true; + writeIsClosedVariable=true; + checkIfAllIsClosedAndDoOperations(); +} + +void TransferThreadAsync::checkIfAllIsClosedAndDoOperations() +{ + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] stop copy"); + if((readError || writeError) && !needSkip && !stopIt) + { + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] resolve error before progress"); + return; + } + if(remainFileOpen()) + { + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] remainFileOpen()"); + return; + } + if(!source.empty() && needRemove && (stopIt || needSkip)) + if(is_file(source) && source!=destination) + unlink(destination); + transfer_stat=TransferStat_Idle; + + transferSize=readThread.getLastGoodPosition(); + + if(mode==Ultracopier::Move && !realMove) + if(exists(destination)) + if(!unlink(source)) + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Warning,"["+std::to_string(id)+"] move and unable to remove: "+ + TransferThread::internalStringTostring(source)+ + #ifdef Q_OS_WIN32 + GetLastErrorStdStr() + #else + strerror(errno) + #endif + ); + transfer_stat=TransferStat_PostTransfer; + emit pushStat(transfer_stat,transferId); + transfer_stat=TransferStat_PostOperation; + emit pushStat(transfer_stat,transferId); + doFilePostOperation(); + + source.clear(); + destination.clear(); + resetExtraVariable(); + //don't need remove because have correctly finish (it's not in: have started) + needRemove=false; + needSkip=false; + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] emit postOperationStopped() transfer_stat=TransferStat_Idle"); + transfer_stat=TransferStat_Idle; + emit postOperationStopped(); +} + +//stop the current copy +void TransferThreadAsync::stop() +{ + #ifdef Q_OS_WIN32 + stopItWin=1; + #endif + stopIt=true; + haveStartTime=false; + if(transfer_stat==TransferStat_Idle) + { + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Warning,"["+std::to_string(id)+"] transfer_stat==TransferStat_Idle"); + return; + } + if(transfer_stat==TransferStat_PreOperation) + { + transfer_stat=TransferStat_Idle; + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Warning,"["+std::to_string(id)+"] transfer_stat==TransferStat_PreOperation"); + return; + } + if(realMove) + { + if(readError || writeError) + transfer_stat=TransferStat_Idle; + return; + } + readThread.stop(); + writeThread.stop(); +} + +//retry after error +void TransferThreadAsync::retryAfterError() +{ + /// \warning skip the resetExtraVariable(); to be more exact and resolv some bug + if(transfer_stat==TransferStat_Idle) + { + if(transferId==0) + { + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Critical,"["+std::to_string(id)+ + ("] seam have bug, source: ")+TransferThread::internalStringTostring(source)+", destination: "+TransferThread::internalStringTostring(destination)); + return; + } + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+ + "] restart all, source: "+TransferThread::internalStringTostring(source)+", destination: "+TransferThread::internalStringTostring(destination)); + readError=false; + //writeError=false; + emit internalStartPreOperation(); + return; + } + //opening error + if(transfer_stat==TransferStat_PreOperation) + { + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+ + "] is not idle, source: "+TransferThread::internalStringTostring(source)+", destination: "+TransferThread::internalStringTostring(destination)+ + ", stat: "+std::to_string(transfer_stat)); + readError=false; + //writeError=false; + emit internalStartPreOperation(); + //tryOpen();-> recheck all, because can be an error into isSame(), rename(), ... + return; + } + //data streaming error + if(transfer_stat!=TransferStat_PostOperation && transfer_stat!=TransferStat_Transfer && transfer_stat!=TransferStat_PostTransfer) + { + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Critical,"["+std::to_string(id)+("] is not in right stat, source: ")+ + TransferThread::internalStringTostring(source)+", destination: "+TransferThread::internalStringTostring(destination)+", stat: "+std::to_string(transfer_stat)); + return; + } + if(transfer_stat==TransferStat_PostOperation) + { + emit internalStartPostOperation(); + return; + } + emit internalTryStartTheTransfer(); +} + +//skip the copy +void TransferThreadAsync::skip() +{ + #ifdef Q_OS_WIN32 + stopItWin=1; + #endif + stopIt=true; + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] start with stat: "+std::to_string(transfer_stat)); + switch(static_cast<TransferStat>(transfer_stat)) + { + case TransferStat_WaitForTheTransfer: + //needRemove=true;never put that's here, can product destruction of the file + case TransferStat_PreOperation: + if(needSkip) + { + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] skip already in progress"); + return; + } + needSkip=true; + //check if all is source and destination is closed + if(remainFileOpen()) + { + if(remainSourceOpen()) + readThread.stop(); + if(remainDestinationOpen()) + writeThread.stop(); + } + else // wait nothing, just quit + { + transfer_stat=TransferStat_PostOperation; + emit internalStartPostOperation(); + } + resetExtraVariable(); + break; + case TransferStat_Transfer: + if(needSkip) + { + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] skip already in progress"); + return; + } + //needRemove=true;never put that's here, can product destruction of the file + needSkip=true; + if(realMove) + { + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+ + "] Do the direct FS fake close, realMove: "+std::to_string(realMove)); + /*readThread.fakeReadIsStarted(); + writeThread.fakeWriteIsStarted(); + readThread.fakeReadIsStopped(); + writeThread.fakeWriteIsStopped();*/ + emit readStopped(); + emit postOperationStopped(); + transfer_stat=TransferStat_Idle; + emit pushStat(transfer_stat,transferId); + return; + } + writeThread.flushBuffer(); + if(remainFileOpen()) + { + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] remainFileOpen"); + if(remainSourceOpen()) + readThread.stop(); + if(remainDestinationOpen()) + writeThread.stop(); + } + else // wait nothing, just quit + { + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] wait nothing, just quit"); + transfer_stat=TransferStat_PostOperation; + emit internalStartPostOperation(); + } + if(!source.empty() && needRemove) + if(exists(source) && source!=destination) + unlink(destination); + break; + case TransferStat_PostTransfer: + if(needSkip) + { + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] skip already in progress"); + return; + } + //needRemove=true;never put that's here, can product destruction of the file + needSkip=true; + if(realMove) + { + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] Do the direct FS fake close, realMove: "+std::to_string(realMove)); + readThread.fakeReadIsStarted(); + writeThread.fakeWriteIsStarted(); + readThread.fakeReadIsStopped(); + writeThread.fakeWriteIsStopped(); + return; + } + writeThread.flushBuffer(); + if(remainFileOpen()) + { + if(remainSourceOpen()) + readThread.stop(); + if(remainDestinationOpen()) + writeThread.stop(); + } + else // wait nothing, just quit + { + transfer_stat=TransferStat_PostOperation; + emit internalStartPostOperation(); + } + break; + case TransferStat_PostOperation: + break; + default: + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Warning,"["+std::to_string(id)+"] can skip in this state: "+std::to_string(transfer_stat)); + return; + } + //can be reset + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] transfer_stat=TransferStat_Idle"); + transfer_stat=TransferStat_Idle; + //emit to manager with List Thread + emit postOperationStopped(); +} + +//return info about the copied size +int64_t TransferThreadAsync::copiedSize() +{ + switch(static_cast<TransferStat>(transfer_stat)) + { + case TransferStat_Transfer: + case TransferStat_PostOperation: + case TransferStat_PostTransfer: + return (readThread.getLastGoodPosition()+writeThread.getLastGoodPosition())/2; + default: + return 0; + } +} + +//retry after error +void TransferThreadAsync::putAtBottom() +{ + emit tryPutAtBottom(); +} + +#ifdef ULTRACOPIER_PLUGIN_RSYNC +/// \brief set rsync +void TransferThreadAsync::setRsync(const bool rsync) +{ + this->rsync=rsync; +} +#endif + +#ifdef ULTRACOPIER_PLUGIN_DEBUG +//to set the id +void TransferThreadAsync::setId(int id) +{ + TransferThread::setId(id); +} + +char TransferThreadAsync::readingLetter() const +{ + switch(static_cast<TransferStat>(readThread.status)) + { + case TransferStat_Idle: + return '_'; + break; + case TransferStat_PreOperation: + return 'I'; + break; + case TransferStat_WaitForTheTransfer: + return 'W'; + break; + case TransferStat_Transfer: + return 'C'; + break; + case TransferStat_PostTransfer: + return 'R'; + break; + case TransferStat_PostOperation: + return 'P'; + break; + default: + return '?'; + } +} + +char TransferThreadAsync::writingLetter() const +{ + switch(static_cast<TransferStat>(writeThread.status)) + { + case TransferStat_Idle: + return '_'; + break; + case TransferStat_PreOperation: + return 'I'; + break; + case TransferStat_WaitForTheTransfer: + return 'W'; + break; + case TransferStat_Transfer: + return 'C'; + break; + case TransferStat_PostTransfer: + return 'R'; + break; + case TransferStat_PostOperation: + return 'P'; + break; + default: + return '?'; + } +} +#endif + +//not copied size, ... +uint64_t TransferThreadAsync::realByteTransfered() const +{ + const uint64_t &l=readThread.getLastGoodPosition(); + switch(static_cast<TransferStat>(transfer_stat)) + { + case TransferStat_Transfer: + case TransferStat_PostTransfer: + return l; + case TransferStat_PostOperation: + return l; + default: + return 0; + } +} + +//first is read, second is write +std::pair<uint64_t, uint64_t> TransferThreadAsync::progression() const +{ + std::pair<uint64_t,uint64_t> returnVar; + switch(static_cast<TransferStat>(transfer_stat)) + { + case TransferStat_Transfer: + returnVar.first=readThread.getLastGoodPosition(); + returnVar.second=writeThread.getLastGoodPosition(); + /*if(returnVar.first<returnVar.second) + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Warning,"["+std::to_string(id)+QStringLiteral("] read is smaller than write"));*/ + break; + case TransferStat_PostTransfer: + returnVar.first=transferSize; + returnVar.second=transferSize; + /*if(returnVar.first<returnVar.second) + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Warning,"["+std::to_string(id)+QStringLiteral("] read is smaller than write"));*/ + break; + case TransferStat_PostOperation: + returnVar.first=transferSize; + returnVar.second=transferSize; + break; + default: + returnVar.first=0; + returnVar.second=0; + } + return returnVar; +} + +void TransferThreadAsync::setFileExistsAction(const FileExistsAction &action) +{ + if(transfer_stat!=TransferStat_PreOperation) + { + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Critical,"["+std::to_string(id)+("] already used, source: ")+ + TransferThread::internalStringTostring(source)+(", destination: ")+TransferThread::internalStringTostring(destination)); + return; + } + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+("] action: ")+std::to_string(action)); + if(action!=FileExists_Rename) + fileExistsAction = action; + else + { + //always rename pass here + fileExistsAction = action; + alwaysDoFileExistsAction=action; + } + if(action==FileExists_Skip) + { + skip(); + return; + } + resetExtraVariable(); + emit internalStartPreOperation(); +} + +#ifndef Q_OS_WIN32 +/*bool TransferThreadAsync::copy(const char *from,const char *to) +{ + transferProgression=0; + int fd_to, fd_from; + char buf[4096]; + ssize_t nread; + int saved_errno; + + fd_from = open(from, O_RDONLY); + if (fd_from < 0) + { + readError=true; + return false; + } + #ifdef Q_OS_LINUX + posix_fadvise(fd_from, 0, 0, POSIX_FADV_WILLNEED); + posix_fadvise(fd_from, 0, 0, POSIX_FADV_SEQUENTIAL); + posix_fadvise(fd_from, 0, 0, POSIX_FADV_NOREUSE); + #endif + + // | O_DSYNC slow down + // | O_SYNC slow down + // O_DIRECT Invalid argument + int flags=O_WRONLY | O_CREAT; + //if(!buffer) flags|=??; + fd_to = open(to, flags, 0666); + if (fd_to < 0) + { + writeError=true; + goto out_error; + } + #ifdef Q_OS_LINUX + posix_fadvise(fd_to, 0, 0, POSIX_FADV_WILLNEED); + posix_fadvise(fd_to, 0, 0, POSIX_FADV_SEQUENTIAL); + posix_fadvise(fd_to, 0, 0, POSIX_FADV_NOREUSE); + #endif + + while (nread = read(fd_from, buf, sizeof buf), nread > 0) + { + if(stopIt) + { + close(fd_to); + close(fd_from); + return false; + } + char *out_ptr = buf; + ssize_t nwritten; + + do { + nwritten = write(fd_to, out_ptr, nread); + if(stopIt) + { + close(fd_to); + close(fd_from); + return false; + } + + if (nwritten >= 0) + { + nread -= nwritten; + out_ptr += nwritten; + transferProgression += nwritten; + } + else if (errno != EINTR) + { + writeError=true; + goto out_error; + } + } while (nread > 0); + } + + if (nread == 0) + { + ftruncate(fd_to,transferProgression); + if (close(fd_to) < 0) + { + fd_to = -1; + readError=true; + goto out_error; + } + if (close(fd_from) < 0) + return -1; + if(stopIt) + return -1; + + emit readStopped(); + return true; + } + + out_error: + saved_errno = errno; + + close(fd_from); + if (fd_to >= 0) + close(fd_to); + + errno = saved_errno; + return false; +}*/ +#endif + +//implemente to connect async +void TransferThreadAsync::read_error() +{ + if(readError) + { + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] already in read error!"); + return; + } + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] start"); + fileContentError = true; + readError = true; + //writeIsReadyVariable = false;//wrong because write can be ready here + if(!writeError)//already display error for the write + emit errorOnFile(source,readThread.errorString()); +} + +void TransferThreadAsync::read_readIsStopped() +{ + if(realMove) + return; + if(!sended_state_readStopped) + { + sended_state_readStopped=true; + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] emit readIsStopped()"); + emit readStopped(); + } + else + { + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Warning,"["+std::to_string(id)+"] drop dual read stopped"); + return; + } + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] start"); + canStartTransfer=false; + //check here if need start checksuming or not + transfer_stat=TransferStat_PostTransfer; + emit pushStat(transfer_stat,transferId); +} + +void TransferThreadAsync::read_closed() +{ + if(realMove) + return; + if(readIsClosedVariable) + { + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Critical,"["+std::to_string(id)+("] double event dropped")); + return; + } + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] start"); + readIsClosedVariable=true; + checkIfAllIsClosedAndDoOperations(); +} + +void TransferThreadAsync::write_error() +{ + if(writeError) + { + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] already in write error!"); + return; + } + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] start"); + fileContentError = true; + writeError = true; + if(!readError)//already display error for the read + emit errorOnFile(destination,writeThread.errorString()); +} + +void TransferThreadAsync::write_closed() +{ + if(realMove) + return; + if(writeIsClosedVariable) + { + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Critical,"["+std::to_string(id)+"] double event dropped"); + return; + } + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] start"); + writeIsClosedVariable=true; + if(stopIt && needRemove && source!=destination) + { + if(is_file(source)) + unlink(destination); + else + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Critical,"["+std::to_string(id)+("] try destroy the destination when the source don't exists")); + } + checkIfAllIsClosedAndDoOperations(); +} + +#ifdef ULTRACOPIER_PLUGIN_SPEED_SUPPORT + + +//set block size in Bytes for speed limitation +bool TransferThreadAsync::setBlockSize(const unsigned int blockSize) +{ + bool read=readThread.setBlockSize(blockSize); + bool write=writeThread.setBlockSize(blockSize); + return (read && write); +} + +//set the current max speed in KB/s +void TransferThreadAsync::setMultiForBigSpeed(const int &multiForBigSpeed) +{ + readThread.setMultiForBigSpeed(multiForBigSpeed); + writeThread.setMultiForBigSpeed(multiForBigSpeed); +} + +void TransferThreadAsync::timeOfTheBlockCopyFinished() +{ + readThread.timeOfTheBlockCopyFinished(); + writeThread.timeOfTheBlockCopyFinished(); +} +#endif + +//pause the copy +void TransferThreadAsync::pause() +{ + //only pause/resume during the transfer of file data + //from transfer_stat!=TransferStat_Idle because it resume at wrong order + if(transfer_stat!=TransferStat_Transfer && transfer_stat!=TransferStat_PostTransfer) + { + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] wrong stat to put in pause"); + return; + } + haveStartTime=false; + readThread.pause(); + writeThread.pause(); +} + +//resume the copy +void TransferThreadAsync::resume() +{ + //only pause/resume during the transfer of file data + //from transfer_stat!=TransferStat_Idle because it resume at wrong order + if(transfer_stat!=TransferStat_Transfer && transfer_stat!=TransferStat_PostTransfer) + { + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] wrong stat to put in pause"); + return; + } + readThread.resume(); + writeThread.resume(); +} + +//when both is ready, startRead() +void TransferThreadAsync::read_opened() +{ + if(readIsOpenVariable) + { + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] already readIsOpenVariable=true"); + return; + } + readIsOpenVariable=true; + transferSize=readThread.size(); + if(writeIsOpenVariable) + readThread.startRead(); +} + +void TransferThreadAsync::write_opened() +{ + if(writeIsOpenVariable) + { + ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"["+std::to_string(id)+"] already writeIsOpenVariable=true"); + return; + } + writeIsOpenVariable=true; + if(readIsOpenVariable) + readThread.startRead(); +} + +#ifdef Q_OS_WIN32 +bool TransferThreadAsync::mkJunction(LPCWSTR szJunction, LPCWSTR szPath) +{ + BYTE buf[sizeof(REPARSE_DATA_BUFFER) + MAX_PATH * sizeof(WCHAR)]; + REPARSE_DATA_BUFFER& ReparseBuffer = (REPARSE_DATA_BUFFER&)buf; + + if (!::CreateDirectoryW(szJunction, NULL)) + return false; + HANDLE hDir = ::CreateFileW(szJunction, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL); + if (hDir == INVALID_HANDLE_VALUE) + return false; + + memset(buf, 0, sizeof(buf)); + ReparseBuffer.ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; + int len = wcslen(szPath)+1; + ReparseBuffer.MountPointReparseBuffer.PrintNameOffset = (len--) * sizeof(WCHAR); + ReparseBuffer.MountPointReparseBuffer.SubstituteNameLength = len * sizeof(WCHAR); + ReparseBuffer.ReparseDataLength = ReparseBuffer.MountPointReparseBuffer.SubstituteNameLength + 12; + wcscpy(ReparseBuffer.MountPointReparseBuffer.PathBuffer, szPath); + + DWORD dwRet; + if (!::DeviceIoControl(hDir, FSCTL_SET_REPARSE_POINT, &ReparseBuffer, + ReparseBuffer.ReparseDataLength+REPARSE_MOUNTPOINT_HEADER_SIZE, NULL, 0, &dwRet, NULL)) + { + ::CloseHandle(hDir); + ::RemoveDirectoryW(szJunction); + return false; + } + + ::CloseHandle(hDir); + return true; +} +#endif + +void TransferThreadAsync::setOsSpecFlags(bool os_spec_flags) +{ + readThread.setOsSpecFlags(os_spec_flags); + writeThread.setOsSpecFlags(os_spec_flags); +} + +void TransferThreadAsync::setNativeCopy(bool native_copy) +{ + this->native_copy=native_copy; +} |