#include "ListThread.h" ListThread::ListThread(FacilityInterface * facilityInterface) { qRegisterMetaType("DebugLevel"); qRegisterMetaType("ItemOfCopyList"); qRegisterMetaType("QFileInfo"); qRegisterMetaType("CopyMode"); qRegisterMetaType >("QList"); qRegisterMetaType("TransferStat"); moveToThread(this); start(HighPriority); this->facilityInterface = facilityInterface; putInPause = false; sourceDrive = ""; sourceDriveMultiple = false; destinationDrive = ""; destinationDriveMultiple = false; stopIt = false; bytesToTransfer = 0; bytesTransfered = 0; idIncrementNumber = 1; actualRealByteTransfered = 0; preOperationNumber = 0; numberOfTranferRuning = 0; numberOfTransferIntoToDoList = 0; numberOfInodeOperation = 0; maxSpeed = 0; doRightTransfer = false; rsync = false; keepDate = false; blockSize = 1024; osBufferLimit = 512; alwaysDoThisActionForFileExists = FileExists_NotSet; doChecksum = false; checksumIgnoreIfImpossible = true; checksumOnlyOnError = true; osBuffer = false; osBufferLimited = false; forcedMode = false; #if ! defined (Q_CC_GNU) ui->keepDate->setEnabled(false); ui->keepDate->setToolTip("Not supported with this compiler"); #endif #ifdef ULTRACOPIER_PLUGIN_DEBUG_WINDOW connect(&timerUpdateDebugDialog,SIGNAL(timeout()),this,SLOT(timedUpdateDebugDialog())); timerUpdateDebugDialog.start(ULTRACOPIER_PLUGIN_DEBUG_WINDOW_TIMER); #endif connect(this, SIGNAL(tryCancel()), this,SLOT(cancel()), Qt::QueuedConnection); connect(this, SIGNAL(askNewTransferThread()), this,SLOT(createTransferThread()), Qt::QueuedConnection); connect(&mkPathQueue, SIGNAL(firstFolderFinish()), this,SLOT(mkPathFirstFolderFinish()), Qt::QueuedConnection); connect(&rmPathQueue, SIGNAL(firstFolderFinish()), this,SLOT(rmPathFirstFolderFinish()), Qt::QueuedConnection); connect(&mkPathQueue, SIGNAL(errorOnFolder(QFileInfo,QString)), this,SIGNAL(mkPathErrorOnFolder(QFileInfo,QString)), Qt::QueuedConnection); connect(&rmPathQueue, SIGNAL(errorOnFolder(QFileInfo,QString)), this,SIGNAL(rmPathErrorOnFolder(QFileInfo,QString)), Qt::QueuedConnection); connect(this, SIGNAL(send_syncTransferList()), this,SLOT(syncTransferList_internal()), Qt::QueuedConnection); #ifdef ULTRACOPIER_PLUGIN_DEBUG connect(&mkPathQueue, SIGNAL(debugInformation(DebugLevel,QString,QString,QString,int)), this,SIGNAL(debugInformation(DebugLevel,QString,QString,QString,int)), Qt::QueuedConnection); connect(&rmPathQueue, SIGNAL(debugInformation(DebugLevel,QString,QString,QString,int)), this,SIGNAL(debugInformation(DebugLevel,QString,QString,QString,int)), Qt::QueuedConnection); #endif // ULTRACOPIER_PLUGIN_DEBUG emit askNewTransferThread(); mkpathTransfer.release(); } ListThread::~ListThread() { emit tryCancel(); waitCancel.acquire(); quit(); wait(); } //transfer is finished void ListThread::transferInodeIsClosed() { numberOfInodeOperation--; temp_transfer_thread=qobject_cast(QObject::sender()); if(temp_transfer_thread==NULL) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,QString("transfer thread not located!")); return; } isFound=false; #ifdef ULTRACOPIER_PLUGIN_DEBUG int countLocalParse=0; #endif if(temp_transfer_thread->getStat()!=TransferStat_Idle) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,QString("transfer thread not idle!")); return; } int_for_internal_loop=0; loop_size=actionToDoListTransfer.size(); while(int_for_internal_looptransferId) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("[%1] have finish, put at idle; for id: %2").arg(int_for_internal_loop).arg(temp_transfer_thread->transferId)); returnActionOnCopyList newAction; newAction.type=RemoveItem; newAction.addAction.id=temp_transfer_thread->transferId; newAction.userAction.position=int_for_internal_loop; actionDone << newAction; /// \todo check if item is at the right thread actionToDoListTransfer.removeAt(int_for_internal_loop); if(actionToDoListTransfer.size()==0 && actionToDoListInode.size()==0 && actionToDoListInode_afterTheTransfer.size()==0) updateTheStatus(); temp_transfer_thread->transferId=0; temp_transfer_thread->transferSize=0; #ifdef ULTRACOPIER_PLUGIN_DEBUG countLocalParse++; #endif isFound=true; //emit newActionOnList(); ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"numberOfTranferRuning: "+QString::number(numberOfTranferRuning)); if(actionToDoListTransfer.size()==0) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"numberOfTranferRuning==0"); actionToDoListInode << actionToDoListInode_afterTheTransfer; actionToDoListInode_afterTheTransfer.clear(); doNewActions_inode_manipulation(); } break; } int_for_internal_loop++; } if(!isFound) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,QString("unable to found item into the todo list, id: %1, index: %2").arg(temp_transfer_thread->transferId).arg(int_for_loop)); temp_transfer_thread->transferId=0; temp_transfer_thread->transferSize=0; } ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("countLocalParse: %1, actionToDoList.size(): %2").arg(countLocalParse).arg(actionToDoListTransfer.size())); #ifdef ULTRACOPIER_PLUGIN_DEBUG if(countLocalParse!=1) ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,QString("countLocalParse != 1")); #endif doNewActions_inode_manipulation(); } //transfer is finished void ListThread::transferIsFinished() { temp_transfer_thread=qobject_cast(QObject::sender()); if(temp_transfer_thread==NULL) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,QString("transfer thread not located!")); return; } //add the current size of file, to general size because it's finish copiedSize=temp_transfer_thread->copiedSize(); if(copiedSize>(qint64)temp_transfer_thread->transferSize) { oversize=copiedSize-temp_transfer_thread->transferSize; bytesToTransfer+=oversize; bytesTransfered+=oversize; } bytesTransfered+=temp_transfer_thread->transferSize; // emit newTransferStop(temp_transfer_thread->transferId); numberOfTranferRuning--; ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start transferIsFinished(), numberOfTranferRuning: "+QString::number(numberOfTranferRuning)); doNewActions_start_transfer(); } /** \brief put the current file at bottom in case of error \note ONLY IN CASE OF ERROR */ void ListThread::transferPutAtBottom() { TransferThread *transfer=qobject_cast(QObject::sender()); if(transfer==NULL) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,QString("transfer thread not located!")); return; } transfer->skip(); bool isFound=false; #ifdef ULTRACOPIER_PLUGIN_DEBUG int countLocalParse=0; #endif int indexAction=0; while(indexActiontransferId) { //push for interface at the end returnActionOnCopyList newAction; newAction.type=MoveItem; newAction.addAction.id=transfer->transferId; newAction.userAction.position=actionToDoListTransfer.size()-1; actionDone << newAction; //do the wait stat actionToDoListTransfer[indexAction].isRunning=false; //move at the end actionToDoListTransfer.move(indexAction,actionToDoListTransfer.size()-1); //reset the thread list stat transfer->transferId=0; transfer->transferSize=0; #ifdef ULTRACOPIER_PLUGIN_DEBUG countLocalParse++; #endif isFound=true; break; } indexAction++; } if(!isFound) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,QString("unable to found item into the todo list, id: %1, index: %2").arg(transfer->transferId)); transfer->transferId=0; transfer->transferSize=0; } ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("countLocalParse: %1").arg(countLocalParse)); #ifdef ULTRACOPIER_PLUGIN_DEBUG if(countLocalParse!=1) ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,QString("countLocalParse != 1")); #endif } //set the copy info and options before runing void ListThread::setRightTransfer(const bool doRightTransfer) { this->doRightTransfer=doRightTransfer; int index=0; loop_sub_size_transfer_thread_search=transferThreadList.size(); while(indexsetRightTransfer(doRightTransfer); index++; } } //set keep date void ListThread::setKeepDate(const bool keepDate) { this->keepDate=keepDate; int index=0; loop_sub_size_transfer_thread_search=transferThreadList.size(); while(indexsetKeepDate(keepDate); index++; } } //set block size in KB void ListThread::setBlockSize(const int blockSize) { this->blockSize=blockSize; int index=0; loop_sub_size_transfer_thread_search=transferThreadList.size(); while(indexsetBlockSize(blockSize); index++; } } //set auto start void ListThread::setAutoStart(const bool autoStart) { this->autoStart=autoStart; } /// \brief set rsync void ListThread::setRsync(const bool rsync) { this->rsync=rsync; int index=0; loop_sub_size_transfer_thread_search=transferThreadList.size(); while(indexsetRsync(rsync); index++; } for(int i=0;isetRsync(rsync); } //set check destination folder void ListThread::setCheckDestinationFolderExists(const bool checkDestinationFolderExists) { this->checkDestinationFolderExists=checkDestinationFolderExists; for(int i=0;isetCheckDestinationFolderExists(checkDestinationFolderExists && alwaysDoThisActionForFolderExists!=FolderExists_Merge); } void ListThread::fileTransfer(const QFileInfo &sourceFileInfo,const QFileInfo &destinationFileInfo,const CopyMode &mode) { addToTransfer(sourceFileInfo,destinationFileInfo,mode); } // -> add thread safe, by Qt::BlockingQueuedConnection bool ListThread::haveSameSource(QStringList sources) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start"); if(sourceDriveMultiple) return false; if(sourceDrive.isEmpty()) return true; int index=0; while(index add thread safe, by Qt::BlockingQueuedConnection bool ListThread::haveSameDestination(QString destination) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start"); if(destinationDriveMultiple) return false; if(destinationDrive.isEmpty()) return true; int index=0; while(indexsetRsync(rsync); scanFileOrFolderThreadsPool.last()->setFilters(include,exclude); scanFileOrFolderThreadsPool.last()->setCheckDestinationFolderExists(checkDestinationFolderExists && alwaysDoThisActionForFolderExists!=FolderExists_Merge); if(scanFileOrFolderThreadsPool.size()==1) updateTheStatus(); scanFileOrFolderThreadsPool.last()->setRenamingRules(firstRenamingRule,otherRenamingRule); return scanFileOrFolderThreadsPool.last(); } void ListThread::scanThreadHaveFinish(bool skipFirstRemove) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"listing thread have finish, skipFirstRemove: "+QString::number(skipFirstRemove)); if(!skipFirstRemove) { scanFileOrFolder * senderThread = qobject_cast(QObject::sender()); if(senderThread==NULL) ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,"sender pointer null (plugin copy engine)"); else { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start the next thread, scanFileOrFolderThreadsPool.size(): "+QString::number(scanFileOrFolderThreadsPool.size())); delete senderThread; scanFileOrFolderThreadsPool.removeOne(senderThread); if(scanFileOrFolderThreadsPool.size()==0) updateTheStatus(); } } ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start the next thread, scanFileOrFolderThreadsPool.size(): "+QString::number(scanFileOrFolderThreadsPool.size())); if(scanFileOrFolderThreadsPool.size()>0) { //then start the next listing threads if(scanFileOrFolderThreadsPool.first()->isFinished()) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"Start listing thread"); scanFileOrFolderThreadsPool.first()->start(); } else ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,"The listing thread is already running"); } else { if(autoStart) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Information,"Auto start the copy"); startGeneralTransfer(); } else { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Information,"Put the copy engine in pause"); putInPause=true; emit isInPause(true); } } } void ListThread::startGeneralTransfer() { doNewActions_inode_manipulation(); } // -> add thread safe, by Qt::BlockingQueuedConnection bool ListThread::newCopy(QStringList sources,QString destination) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start: "+sources.join(";")+", destination: "+destination); scanFileOrFolder * scanFileOrFolderThread = newScanThread(Copy); if(scanFileOrFolderThread==NULL) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"unable to get new thread"); return false; } ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start the listing"); scanFileOrFolderThread->addToList(sources,destination); scanThreadHaveFinish(true); return true; } // -> add thread safe, by Qt::BlockingQueuedConnection bool ListThread::newMove(QStringList sources,QString destination) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start"); scanFileOrFolder * scanFileOrFolderThread = newScanThread(Move); if(scanFileOrFolderThread==NULL) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"unable to get new thread"); return false; } scanFileOrFolderThread->addToList(sources,destination); scanThreadHaveFinish(true); /* int index=0; while(indexdrives=drives; int index=0; loop_sub_size_transfer_thread_search=transferThreadList.size(); while(indexsetDrive(drives); index++; } } void ListThread::setCollisionAction(FileExistsAction alwaysDoThisActionForFileExists) { this->alwaysDoThisActionForFileExists=alwaysDoThisActionForFileExists; int index=0; loop_sub_size_transfer_thread_search=transferThreadList.size(); while(indexsetAlwaysFileExistsAction(alwaysDoThisActionForFileExists); index++; } } /** \brief to sync the transfer list * Used when the interface is changed, useful to minimize the memory size */ void ListThread::syncTransferList() { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start"); emit send_syncTransferList(); } //set the folder local colision void ListThread::setFolderColision(FolderExistsAction alwaysDoThisActionForFolderExists) { this->alwaysDoThisActionForFolderExists=alwaysDoThisActionForFolderExists; } bool ListThread::getReturnBoolToCopyEngine() { return returnBoolToCopyEngine; } QPair ListThread::getReturnPairQuint64ToCopyEngine() { return returnPairQuint64ToCopyEngine; } ItemOfCopyList ListThread::getReturnItemOfCopyListToCopyEngine() { return returnItemOfCopyListToCopyEngine; } void ListThread::set_doChecksum(bool doChecksum) { this->doChecksum=doChecksum; int index=0; loop_sub_size_transfer_thread_search=transferThreadList.size(); while(indexset_doChecksum(doChecksum); index++; } } void ListThread::set_checksumIgnoreIfImpossible(bool checksumIgnoreIfImpossible) { this->checksumIgnoreIfImpossible=checksumIgnoreIfImpossible; int index=0; loop_sub_size_transfer_thread_search=transferThreadList.size(); while(indexset_checksumIgnoreIfImpossible(checksumIgnoreIfImpossible); index++; } } void ListThread::set_checksumOnlyOnError(bool checksumOnlyOnError) { this->checksumOnlyOnError=checksumOnlyOnError; int index=0; loop_sub_size_transfer_thread_search=transferThreadList.size(); while(indexset_checksumOnlyOnError(checksumOnlyOnError); index++; } } void ListThread::set_osBuffer(bool osBuffer) { this->osBuffer=osBuffer; int index=0; loop_sub_size_transfer_thread_search=transferThreadList.size(); while(indexset_osBuffer(osBuffer); index++; } } void ListThread::set_osBufferLimited(bool osBufferLimited) { this->osBufferLimited=osBufferLimited; int index=0; loop_sub_size_transfer_thread_search=transferThreadList.size(); while(indexset_osBufferLimited(osBufferLimited); index++; } } void ListThread::realByteTransfered() { quint64 totalRealByteTransfered=0; int index=0; loop_sub_size_transfer_thread_search=transferThreadList.size(); while(indexrealByteTransfered(); index++; } emit send_realBytesTransfered(totalRealByteTransfered); } void ListThread::pause() { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start"); if(putInPause) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"Seam already in pause!"); return; } putInPause=true; int index=0; loop_sub_size_transfer_thread_search=transferThreadList.size(); while(indexpause(); index++; } emit isInPause(true); } void ListThread::resume() { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start"); if(!putInPause) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"Seam already resumed!"); return; } putInPause=false; startGeneralTransfer(); doNewActions_start_transfer(); int index=0; loop_sub_size_transfer_thread_search=transferThreadList.size(); while(indexresume(); index++; } emit isInPause(false); } void ListThread::skip(const quint64 &id) { skipInternal(id); // emit newActionOnList(); } bool ListThread::skipInternal(const quint64 &id) { int index=0; loop_sub_size_transfer_thread_search=transferThreadList.size(); while(indextransferId==id) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("skip one transfer: %1").arg(id)); transferThreadList.at(index)->skip(); return true; } index++; } int_for_internal_loop=0; loop_size=actionToDoListTransfer.size(); while(int_for_internal_loopstop(); delete transferThreadList.at(index);//->deleteLayer(); transferThreadList[index]=NULL; index++; } index=0; loop_size=scanFileOrFolderThreadsPool.size(); while(indexstop(); delete scanFileOrFolderThreadsPool.at(index);//->deleteLayer(); scanFileOrFolderThreadsPool[index]=NULL; index++; } quit(); waitCancel.release(); emit canBeDeleted(); } //speed limitation qint64 ListThread::getSpeedLimitation() { return maxSpeed; } bool ListThread::setSpeedLimitation(const qint64 &speedLimitation) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"maxSpeed: "+QString::number(speedLimitation)); maxSpeed=speedLimitation; int_for_loop=0; loop_size=transferThreadList.size(); while(int_for_loopsetMaxSpeed(speedLimitation/ULTRACOPIER_PLUGIN_MAXPARALLELTRANFER); int_for_loop++; } return true; } void ListThread::updateTheStatus() { /*if(threadOfTheTransfer.haveContent()) copy=true;*/ updateTheStatus_listing=scanFileOrFolderThreadsPool.size()>0; updateTheStatus_copying=actionToDoListTransfer.size()>0 || actionToDoListInode.size()>0 || actionToDoListInode_afterTheTransfer.size()>0; if(updateTheStatus_copying && updateTheStatus_listing) updateTheStatus_action_in_progress=CopyingAndListing; else if(updateTheStatus_listing) updateTheStatus_action_in_progress=Listing; else if(updateTheStatus_copying) updateTheStatus_action_in_progress=Copying; else updateTheStatus_action_in_progress=Idle; ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"emit actionInProgess("+QString::number(updateTheStatus_action_in_progress)+")"); emit actionInProgess(updateTheStatus_action_in_progress); if(updateTheStatus_action_in_progress==Idle) sendActionDone(); } //set data local to the thread void ListThread::setAlwaysFileExistsAction(FileExistsAction alwaysDoThisActionForFileExists) { this->alwaysDoThisActionForFileExists=alwaysDoThisActionForFileExists; int_for_loop=0; loop_size=transferThreadList.size(); while(int_for_loopsetAlwaysFileExistsAction(alwaysDoThisActionForFileExists); int_for_loop++; } } //mk path to do quint64 ListThread::addToMkPath(const QString& folder) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"folder: "+folder); actionToDoInode temp; temp.type = ActionType_MkPath; temp.id = generateIdNumber(); temp.folder.setFile(folder); temp.isRunning = false; actionToDoListInode << temp; return temp.id; } //add rm path to do void ListThread::addToRmPath(const QString& folder,const int& inodeToRemove) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"folder: "+folder+",inodeToRemove: "+QString::number(inodeToRemove)); actionToDoInode temp; temp.type = ActionType_RmPath; temp.id = generateIdNumber(); temp.size = inodeToRemove; temp.folder.setFile(folder); temp.isRunning = false; if(inodeToRemove==0) actionToDoListInode << temp; else actionToDoListInode_afterTheTransfer << temp; } //rsync rm void ListThread::addToRmForRsync(const QString& inode) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"inode: "+inode); actionToDoInode temp; temp.type = ActionType_RmSync; temp.id = generateIdNumber(); temp.folder.setFile(inode); temp.isRunning = false; actionToDoListInode << temp; } //send action done void ListThread::sendActionDone() { if(actionDone.size()>0) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start"); emit newActionOnList(actionDone); actionDone.clear(); } } //send progression void ListThread::sendProgression() { if(actionToDoListTransfer.size()==0) return; oversize=0; currentProgression=0; int_for_loop=0; loop_size=transferThreadList.size(); while(int_for_loopgetStat()==TransferStat_Transfer || temp_transfer_thread->getStat()==TransferStat_Checksum) { copiedSize=temp_transfer_thread->copiedSize(); //for the general progression currentProgression+=copiedSize; //the oversize (when the file is bigger after/during the copy then what was during the listing) if(copiedSize>(qint64)temp_transfer_thread->transferSize) localOverSize=copiedSize-temp_transfer_thread->transferSize; else localOverSize=0; //the current size copied totalSize=temp_transfer_thread->transferSize+localOverSize; if(temp_transfer_thread->getStat()==TransferStat_Checksum) tempItem.current=temp_transfer_thread->realByteTransfered(); else tempItem.current=copiedSize; tempItem.id=temp_transfer_thread->transferId; tempItem.total=totalSize; progressionList << tempItem; //add the oversize to the general progression oversize+=localOverSize; } int_for_loop++; } emit pushFileProgression(progressionList); progressionList.clear(); emit pushGeneralProgression(bytesTransfered+currentProgression,bytesToTransfer+oversize); realByteTransfered(); } //send the progression, after full reset of the interface (then all is empty) void ListThread::syncTransferList_internal() { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start"); emit syncReady(); actionDone.clear(); //do list operation TransferThread *transferThread; loop_size=actionToDoListTransfer.size(); loop_sub_size=transferThreadList.size(); //this loop to have at max ULTRACOPIER_PLUGIN_MAXPARALLELINODEOPT*ULTRACOPIER_PLUGIN_MAXPARALLELINODEOPT, not ULTRACOPIER_PLUGIN_MAXPARALLELINODEOPT*transferThreadList.size() for(int_for_loop=0; int_for_loopgetStat()!=TransferStat_PreOperation) { returnActionOnCopyList newAction; switch(transferThread->getStat()) { case TransferStat_Transfer: newAction.type=Transfer; break; case TransferStat_PostTransfer: newAction.type=PostOperation; break; default: break; } newAction.addAction.id = item.id; actionDone << newAction; } } } } } //add file transfer to do quint64 ListThread::addToTransfer(const QFileInfo& source,const QFileInfo& destination,const CopyMode& mode) { //add to transfer list numberOfTransferIntoToDoList++; bytesToTransfer+= source.size(); actionToDoTransfer temp; temp.id = generateIdNumber(); temp.size = source.size(); temp.source = source; temp.destination= destination; temp.mode = mode; temp.isRunning = false; actionToDoListTransfer << temp; //push the new transfer to interface returnActionOnCopyList newAction; newAction.type = AddingItem; newAction.addAction.id = temp.id; newAction.addAction.sourceFullPath = source.absoluteFilePath(); newAction.addAction.sourceFileName = source.fileName(); newAction.addAction.destinationFullPath = destination.absoluteFilePath(); newAction.addAction.destinationFileName = destination.fileName(); newAction.addAction.size = temp.size; newAction.addAction.mode = mode; actionDone << newAction; ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("source: %1, destination: %2, add entry: %3, size: %4, size2: %5").arg(source.absoluteFilePath()).arg(destination.absoluteFilePath()).arg(temp.id).arg(temp.size).arg(newAction.addAction.size)); return temp.id; } //generate id number quint64 ListThread::generateIdNumber() { idIncrementNumber++; if(idIncrementNumber>(((quint64)1024*1024)*1024*1024*2)) idIncrementNumber=0; return idIncrementNumber; } //warning the first entry is accessible will copy void ListThread::removeItems(const QList &ids) { for(int i=0;i ids) { if(actionToDoListTransfer.size()<=1) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"list size is empty"); return; } ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start"); //do list operation int indexToMove=0; loop_size=actionToDoListTransfer.size(); for (int i=0; i ids) { if(actionToDoListTransfer.size()<=1) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"list size is empty"); return; } ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start"); //do list operation int lastGoodPositionExtern=0; int lastGoodPositionReal=0; bool haveGoodPosition=false; bool haveChanged=false; loop_size=actionToDoListTransfer.size(); for (int i=0; i ids) { if(actionToDoListTransfer.size()<=1) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"list size is empty"); return; } ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start"); //do list operation int lastGoodPositionExtern=numberOfTransferIntoToDoList; int lastGoodPositionReal=0; bool haveGoodPosition=false; bool haveChanged=false; for (int i=actionToDoListTransfer.size()-1; i>=0; --i) { if(ids.contains(actionToDoListTransfer.at(i).id)) { if(haveGoodPosition) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("move item ")+QString::number(i)+" to "+QString::number(i+1)); returnActionOnCopyList newAction; newAction.type=MoveItem; newAction.addAction.id=actionToDoListTransfer.at(i).id; newAction.userAction.moveAt=lastGoodPositionReal; newAction.userAction.position=i; actionDone << newAction; actionToDoListTransfer.swap(i,lastGoodPositionReal); haveChanged=true; } else { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("Try move up false, item ")+QString::number(i)); } ids.removeOne(actionToDoListTransfer.at(i).id); if(ids.size()==0) { /* if(haveChanged) emit newActionOnList();*/ return; } } else { lastGoodPositionExtern--; lastGoodPositionReal=i; haveGoodPosition=true; } } //emit newActionOnList(); ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"stop"); } //put on bottom void ListThread::moveItemsOnBottom(QList ids) { if(actionToDoListTransfer.size()<=1) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"list size is empty"); return; } ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start"); //do list operation int lastGoodPositionExtern=numberOfTransferIntoToDoList; int lastGoodPositionReal=actionToDoListTransfer.size()-1; for (int i=lastGoodPositionReal; i>=0; --i) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("Check action on item ")+QString::number(i)); if(ids.contains(actionToDoListTransfer.at(i).id)) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("move item ")+QString::number(i)+" to "+QString::number(lastGoodPositionReal)); ids.removeOne(actionToDoListTransfer.at(i).id); returnActionOnCopyList newAction; newAction.type=MoveItem; newAction.addAction.id=actionToDoListTransfer.at(i).id; newAction.userAction.moveAt=lastGoodPositionExtern; newAction.userAction.position=i; actionDone << newAction; actionToDoListTransfer.move(i,lastGoodPositionReal); lastGoodPositionReal--; lastGoodPositionExtern--; if(ids.size()==0) { // emit newActionOnList(); return; } } } // emit newActionOnList(); ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"stop"); } /** \brief give the forced mode, to export/import transfer list */ void ListThread::forceMode(const CopyMode &mode) { if(mode==Copy) ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("Force mode to copy")); else ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("Force mode to move")); this->mode=mode; forcedMode=true; } void ListThread::exportTransferList(const QString &fileName) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start"); QFile transferFile(fileName); if(transferFile.open(QIODevice::WriteOnly|QIODevice::Truncate)) { transferFile.write(QString("Ultracopier-0.3;Transfer-list;").toUtf8()); if(!forcedMode) transferFile.write(QString("Transfer;").toUtf8()); else { if(mode==Copy) transferFile.write(QString("Copy;").toUtf8()); else transferFile.write(QString("Move;").toUtf8()); } transferFile.write(QString("Ultracopier-0.3\n").toUtf8()); bool haveError=false; int size=actionToDoListTransfer.size(); for (int index=0;index0) { content=QString::fromUtf8(data); //do the import here if(content.contains(correctLine)) { content.remove("\n"); args=content.split(";"); if(forcedMode) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("New data to import in forced mode: %2,%3").arg(args.at(0)).arg(args.at(1))); addToTransfer(QFileInfo(args.at(0)),QFileInfo(args.at(1)),mode); } else { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("New data to import: %1,%2,%3").arg(args.at(0)).arg(args.at(1)).arg(args.at(2))); if(args.at(0)=="Copy") tempMode=Copy; else tempMode=Move; addToTransfer(QFileInfo(args.at(1)),QFileInfo(args.at(2)),tempMode); } } else { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,QString("Wrong line syntax: %1").arg(content)); errorFound=true; } } } while(data.size()>0); transferFile.close(); if(errorFound) emit warningTransferList(tr("Some error have been found during the line parsing")); // emit newActionOnList(); } else { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,QString("Unable to open the transfer list: %1").arg(transferFile.errorString())); emit errorTransferList(tr("Unable to open the transfer list: %1").arg(transferFile.errorString())); return; } } //do new actions void ListThread::doNewActions_start_transfer() { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("actionToDoListTransfer.size(): %1, numberOfTranferRuning: %2").arg(actionToDoListTransfer.size()).arg(numberOfTranferRuning)); if(stopIt || putInPause) return; ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start"); //lunch the transfer in WaitForTheTransfer int_for_loop=0; loop_size=transferThreadList.size(); while(int_for_loopgetStat()==TransferStat_WaitForTheTransfer) { transferThreadList.at(int_for_loop)->startTheTransfer(); numberOfTranferRuning++; } int_for_loop++; } int_for_loop=0; while(int_for_loopgetStat()==TransferStat_PreOperation) { transferThreadList.at(int_for_loop)->startTheTransfer(); numberOfTranferRuning++; } int_for_loop++; } ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"numberOfTranferRuning: "+QString::number(numberOfTranferRuning)); } /** \brief lunch the pre-op or inode op 1) locate the next next item to do into the both list 1a) optimisation posible on the mkpath/rmpath 2) determine what need be lunched 3) lunch it, rerun the 2) */ void ListThread::doNewActions_inode_manipulation() { //ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("actionToDoList.size(): %1").arg(actionToDoList.size())); if(stopIt || putInPause) return; //ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start"); //lunch the pre-op or inode op int_for_loop=0; int_for_internal_loop=0; number_rm_path_moved=0; int_for_transfer_thread_search=0; actionToDoListTransfer_count=actionToDoListTransfer.count(); actionToDoListInode_count=actionToDoListInode.count(); loop_sub_size_transfer_thread_search=transferThreadList.size(); //search the next transfer action to do while(int_for_looptransferId==0) /!\ important! Because the other thread can have call doNewAction before than this thread have the finish event parsed! I this case it lose all data */ currentTransferThread=transferThreadList[int_for_transfer_thread_search]; if(currentTransferThread->getStat()==TransferStat_Idle && currentTransferThread->transferId==0) // /!\ important! { currentTransferThread->transferId=currentActionToDoTransfer.id; currentTransferThread->transferSize=currentActionToDoTransfer.size; currentTransferThread->setFiles( currentActionToDoTransfer.source.absoluteFilePath(), currentActionToDoTransfer.size, currentActionToDoTransfer.destination.absoluteFilePath(), currentActionToDoTransfer.mode ); currentActionToDoTransfer.isRunning=true; ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("[%1] id: %2 is idle, use it for %3").arg(int_for_loop).arg(currentTransferThread->transferId).arg(currentActionToDoTransfer.destination.absoluteFilePath())); /// \note wrong position? Else write why it's here returnActionOnCopyList newAction; newAction.type = PreOperation; newAction.addAction.id = currentActionToDoTransfer.id; newAction.addAction.sourceFullPath = currentActionToDoTransfer.source.absoluteFilePath(); newAction.addAction.sourceFileName = currentActionToDoTransfer.source.fileName(); newAction.addAction.destinationFullPath = currentActionToDoTransfer.destination.absoluteFilePath(); newAction.addAction.destinationFileName = currentActionToDoTransfer.destination.fileName(); newAction.addAction.size = currentActionToDoTransfer.size; newAction.addAction.mode = currentActionToDoTransfer.mode; actionDone << newAction; int_for_transfer_thread_search++; break; } int_for_transfer_thread_search++; } if(int_for_internal_loop==loop_sub_size_transfer_thread_search) { /// \note Can be normal when all thread is not initialized //ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,"unable to found free thread to do the transfer"); break; } numberOfInodeOperation++; if(numberOfInodeOperation>=ULTRACOPIER_PLUGIN_MAXPARALLELINODEOPT) return; } int_for_loop++; } //search the next inode action to do while(int_for_internal_loopULTRACOPIER_PLUGIN_MAXPARALLELINODEOPT) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,QString("The index have been detected as out of max range: %1>%2").arg(actionToDoListTransfer_count+actionToDoListInode_count).arg(ULTRACOPIER_PLUGIN_MAXPARALLELINODEOPT)); return; } } //restart transfer if it can void ListThread::restartTransferIfItCan() { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start"); TransferThread *transfer=qobject_cast(QObject::sender()); if(transfer==NULL) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,QString("transfer thread not located!")); return; } if(numberOfTranferRuninggetStat()==TransferStat_WaitForTheTransfer) { transfer->startTheTransfer(); numberOfTranferRuning++; } doNewActions_start_transfer(); } /// \brief update the transfer stat void ListThread::newTransferStat(TransferStat stat,quint64 id) { returnActionOnCopyList newAction; switch(stat) { case TransferStat_Idle: return; break; case TransferStat_PreOperation: return; break; case TransferStat_WaitForTheTransfer: return; break; case TransferStat_Transfer: newAction.type=Transfer; break; case TransferStat_PostTransfer: case TransferStat_PostOperation: newAction.type=PostOperation; break; case TransferStat_Checksum: newAction.type=CustomOperation; break; default: return; break; } newAction.addAction.id = id; actionDone << newAction; } void ListThread::set_osBufferLimit(unsigned int osBufferLimit) { this->osBufferLimit=osBufferLimit; int index=0; loop_sub_size_transfer_thread_search=transferThreadList.size(); while(indexset_osBufferLimit(osBufferLimit); index++; } } void ListThread::set_setFilters(QList include,QList exclude) { ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("include.size(): %1, exclude.size(): %2").arg(include.size()).arg(exclude.size())); this->include=include; this->exclude=exclude; int index=0; while(indexsetFilters(include,exclude); index++; } } void ListThread::set_sendNewRenamingRules(QString firstRenamingRule,QString otherRenamingRule) { this->firstRenamingRule=firstRenamingRule; this->otherRenamingRule=otherRenamingRule; emit send_sendNewRenamingRules(firstRenamingRule,otherRenamingRule); } void ListThread::mkPathFirstFolderFinish() { int_for_loop=0; loop_size=actionToDoListInode.size(); while(int_for_loopgetStat()) { case TransferStat_Idle: stat="Idle"; break; case TransferStat_PreOperation: stat="PreOperation"; break; case TransferStat_WaitForTheTransfer: stat="WaitForTheTransfer"; break; case TransferStat_Transfer: stat="Transfer"; break; case TransferStat_PostOperation: stat="PostOperation"; break; case TransferStat_PostTransfer: stat="PostTransfer"; break; case TransferStat_Checksum: stat="Checksum"; break; default: stat=QString("??? (%1)").arg(transferThreadList.at(index)->getStat()); break; } newList << QString("%1) (%3,%4) %2") .arg(index) .arg(stat) .arg(transferThreadList.at(index)->readingLetter()) .arg(transferThreadList.at(index)->writingLetter()); index++; } QStringList newList2; index=0; loop_size=actionToDoListTransfer.size(); while(index(actionToDoListTransfer.size()+2)) { newList2 << QString("..."); break; } index++; } emit updateTheDebugInfo(newList,newList2,numberOfInodeOperation); } #endif /// \note Can be call without queue because all call will be serialized void ListThread::fileAlreadyExists(const QFileInfo &source,const QFileInfo &destination,const bool &isSame) { emit send_fileAlreadyExists(source,destination,isSame,qobject_cast(sender())); } /// \note Can be call without queue because all call will be serialized void ListThread::errorOnFile(const QFileInfo &fileInfo,const QString &errorString) { emit send_errorOnFile(fileInfo,errorString,qobject_cast(sender())); } /// \note Can be call without queue because all call will be serialized void ListThread::folderAlreadyExists(const QFileInfo &source,const QFileInfo &destination,const bool &isSame) { emit send_folderAlreadyExists(source,destination,isSame,qobject_cast(sender())); } /// \note Can be call without queue because all call will be serialized /// \todo all this part void ListThread::errorOnFolder(const QFileInfo &fileInfo,const QString &errorString) { emit send_errorOnFolder(fileInfo,errorString,qobject_cast(sender())); } //to run the thread void ListThread::run() { exec(); } /// \to create transfer thread void ListThread::createTransferThread() { if(stopIt) return; transferThreadList << new TransferThread(); TransferThread * last=transferThreadList.last(); last->transferId=0; last->transferSize=0; last->setRightTransfer(doRightTransfer); last->setKeepDate(keepDate); last->setBlockSize(blockSize); last->setDrive(drives); last->setAlwaysFileExistsAction(alwaysDoThisActionForFileExists); last->setMaxSpeed(maxSpeed/ULTRACOPIER_PLUGIN_MAXPARALLELTRANFER); last->set_doChecksum(doChecksum); last->set_checksumIgnoreIfImpossible(checksumIgnoreIfImpossible); last->set_checksumOnlyOnError(checksumOnlyOnError); last->set_osBuffer(osBuffer); last->set_osBufferLimited(osBufferLimited); last->set_osBufferLimit(osBufferLimit); last->setRsync(rsync); #ifdef ULTRACOPIER_PLUGIN_DEBUG connect(last,SIGNAL(debugInformation(DebugLevel,QString,QString,QString,int)),this,SIGNAL(debugInformation(DebugLevel,QString,QString,QString,int)), Qt::QueuedConnection); #endif // ULTRACOPIER_PLUGIN_DEBUG connect(last,SIGNAL(errorOnFile(QFileInfo,QString)), this,SLOT(errorOnFile(QFileInfo,QString)), Qt::QueuedConnection); connect(last,SIGNAL(fileAlreadyExists(QFileInfo,QFileInfo,bool)), this,SLOT(fileAlreadyExists(QFileInfo,QFileInfo,bool)), Qt::QueuedConnection); connect(last,SIGNAL(tryPutAtBottom()), this,SLOT(transferPutAtBottom()), Qt::QueuedConnection); connect(last,SIGNAL(readStopped()), this,SLOT(transferIsFinished()), Qt::QueuedConnection); connect(last,SIGNAL(preOperationStopped()), this,SLOT(doNewActions_start_transfer()), Qt::QueuedConnection); connect(last,SIGNAL(postOperationStopped()), this,SLOT(transferInodeIsClosed()), Qt::QueuedConnection); connect(last,SIGNAL(checkIfItCanBeResumed()), this,SLOT(restartTransferIfItCan()), Qt::QueuedConnection); connect(last,SIGNAL(pushStat(TransferStat,quint64)), this,SLOT(newTransferStat(TransferStat,quint64)), Qt::QueuedConnection); connect(this,SIGNAL(send_sendNewRenamingRules(QString,QString)), last,SLOT(setRenamingRules(QString,QString)), Qt::QueuedConnection); last->start(); last->setObjectName(QString("transfer %1").arg(transferThreadList.size()-1)); last->setMkpathTransfer(&mkpathTransfer); last->setRenamingRules(firstRenamingRule,otherRenamingRule); #ifdef ULTRACOPIER_PLUGIN_DEBUG last->setId(transferThreadList.size()-1); #endif if(transferThreadList.size()>=ULTRACOPIER_PLUGIN_MAXPARALLELINODEOPT) return; if(stopIt) return; doNewActions_inode_manipulation(); emit askNewTransferThread(); }