diff options
Diffstat (limited to 'src/app/Synchronizer/synchronizer.cpp')
-rw-r--r-- | src/app/Synchronizer/synchronizer.cpp | 1493 |
1 files changed, 1493 insertions, 0 deletions
diff --git a/src/app/Synchronizer/synchronizer.cpp b/src/app/Synchronizer/synchronizer.cpp new file mode 100644 index 0000000..7388dd4 --- /dev/null +++ b/src/app/Synchronizer/synchronizer.cpp @@ -0,0 +1,1493 @@ +/*************************************************************************** + synchronizer.cpp - description + ------------------- + copyright : (C) 2003 + by Csaba Karai + e-mail : krusader@users.sourceforge.net + web site : http://krusader.sourceforge.net + --------------------------------------------------------------------------- + Description + *************************************************************************** + + A + + db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. + 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D + 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' + 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b + 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. + YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD + + S o u r c e F i l e + + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "synchronizer.h" +#include "synchronizerdirlist.h" +#include "../krusader.h" +#include "../krservices.h" +#include "../VFS/vfs.h" +#include "../VFS/krquery.h" +#include "config.h" +#include <kurl.h> +#include <tdemessagebox.h> +#include <tdelocale.h> +#include <tqapplication.h> +#include <tqregexp.h> +#include <tqdir.h> +#include <tqtimer.h> +#include <tdeio/job.h> +#include <kdialogbase.h> +#include <tdeio/observer.h> +#include <tdeio/renamedlg.h> +#include <tdeio/skipdlg.h> +#include <unistd.h> +#include <tqeventloop.h> +#include <tqpushbutton.h> +#include <tqdatetime.h> +#include <tdeprocess.h> +#include <kdialogbase.h> +#include <kprogress.h> +#include <tqlayout.h> +#include <kurlcompletion.h> + +#include <sys/types.h> +#include <sys/time.h> +#include <utime.h> +#include <pwd.h> +#include <grp.h> +#include <tqlabel.h> + + + +#if KDE_IS_VERSION(3,5,0) && defined( HAVE_POSIX_ACL ) +#include <sys/acl.h> +#ifdef HAVE_NON_POSIX_ACL_EXTENSIONS +#include <acl/libacl.h> +#endif +#endif + + +#define DISPLAY_UPDATE_PERIOD 2 + +Synchronizer::Synchronizer() : displayUpdateCount( 0 ), markEquals( true ), + markDiffers ( true ), markCopyToLeft( true ), markCopyToRight( true ), markDeletable( true ), + stack(), jobMap(), receivedMap(), parentWidget( 0 ) +{ + resultList.setAutoDelete( true ); + stack.setAutoDelete( true ); +} + +void Synchronizer::reset() +{ + displayUpdateCount = 0; + markEquals = markDiffers = markCopyToLeft = markCopyToRight = markDeletable = true; + stopped = false; + recurseSubDirs = followSymLinks = ignoreDate = asymmetric = cmpByContent = ignoreCase = autoScroll = false; + markEquals = markDiffers = markCopyToLeft = markCopyToRight = markDeletable = markDuplicates = markSingles = false; + leftCopyEnabled = rightCopyEnabled = deleteEnabled = overWrite = autoSkip = paused = false; + leftCopyNr = rightCopyNr = deleteNr = 0; + leftCopySize = rightCopySize = deleteSize = 0; + comparedDirs = fileCount = 0; + leftBaseDir = rightBaseDir = TQString(); + resultList.clear(); + temporaryList.clear(); + stack.clear(); +} + +int Synchronizer::compare( TQString leftURL, TQString rightURL, KRQuery *query, bool subDirs, + bool symLinks, bool igDate, bool asymm, bool cmpByCnt, bool igCase, + bool autoSc, TQStringList &selFiles, int equThres, int timeOffs, int parThreads, bool hiddenFiles ) +{ + resultList.clear(); + temporaryList.clear(); + + recurseSubDirs = subDirs; + followSymLinks = symLinks; + ignoreDate = igDate; + asymmetric = asymm; + cmpByContent = cmpByCnt; + autoScroll = autoSc; + ignoreCase = igCase; + selectedFiles = selFiles; + equalsThreshold= equThres; + timeOffset = timeOffs; + parallelThreads= parThreads; + ignoreHidden = hiddenFiles; + + stopped = false; + + this->query = query; + + leftURL = KURLCompletion::replacedPath( leftURL, true, true ); + rightURL = KURLCompletion::replacedPath( rightURL, true, true ); + + if( !leftURL.endsWith("/" )) leftURL+="/"; + if( !rightURL.endsWith("/" )) rightURL+="/"; + + excludedPaths = query->dontSearchInDirs().toStringList(); + for( unsigned i = 0; i != excludedPaths.count(); i++ ) + if( excludedPaths[ i ].endsWith( "/" ) ) + excludedPaths[ i ].truncate( excludedPaths[ i ].length() - 1 ); + + comparedDirs = fileCount = 0; + + stack.append( new CompareTask( 0, leftBaseDir = leftURL, rightBaseDir = rightURL, "", "", ignoreHidden ) ); + compareLoop(); + + SynchronizerFileItem *item = temporaryList.first(); + while( item ) + { + if( item->isTemporary() ) + delete item; + item = temporaryList.next(); + } + temporaryList.clear(); + + + if( !autoScroll ) + refresh( true ); + + emit statusInfo( i18n( "Number of files: %1" ).arg( fileCount ) ); + return fileCount; +} + +void Synchronizer::compareLoop() { + while( !stopped && !stack.isEmpty() ) { + for( int thread=0; thread < (int)stack.count() && thread < parallelThreads; thread++ ) { + SynchronizerTask * entry = stack.at( thread ); + + if( entry->state() == ST_STATE_NEW ) + entry->start( parentWidget ); + + if( entry->inherits("CompareTask") ) { + if( entry->state() == ST_STATE_READY ) { + CompareTask *ctentry = (CompareTask *) entry; + if( ctentry->isDuplicate() ) + compareDirectory( ctentry->parent(), ctentry->leftDirList(), ctentry->rightDirList(), + ctentry->leftDir(), ctentry->rightDir() ); + else + addSingleDirectory( ctentry->parent(), ctentry->dirList(), ctentry->dir(), + ctentry->isLeft() ); + } + if( entry->state() == ST_STATE_READY || entry->state() == ST_STATE_ERROR ) + comparedDirs++; + } + switch( entry->state() ) { + case ST_STATE_STATUS: + emit statusInfo( entry->status() ); + break; + case ST_STATE_READY: + case ST_STATE_ERROR: + emit statusInfo( i18n( "Number of compared directories: %1" ).arg( comparedDirs ) ); + stack.removeRef( entry ); + continue; + default: + break; + } + } + if( !stack.isEmpty() ) + tqApp->processEvents(); + } + stack.clear(); +} + +void Synchronizer::compareDirectory( SynchronizerFileItem *parent, SynchronizerDirList * left_directory, + SynchronizerDirList * right_directory, const TQString &leftDir, + const TQString &rightDir ) +{ + const TQString &leftURL = left_directory->url(); + const TQString &rightURL = right_directory->url(); + vfile * left_file; + vfile * right_file; + + TQString file_name; + bool checkIfSelected = false; + + if( leftDir.isEmpty() && rightDir.isEmpty() && selectedFiles.count() ) + checkIfSelected = true; + + /* walking through in the left directory */ + for( left_file=left_directory->first(); left_file != 0 && !stopped ; + left_file=left_directory->next() ) + { + if ( isDir( left_file ) ) + continue; + + file_name = left_file->vfile_getName(); + + if( checkIfSelected && !selectedFiles.contains( file_name ) ) + continue; + + if( !query->match( left_file ) ) + continue; + + if( (right_file = right_directory->search( file_name, ignoreCase )) == 0 ) + addLeftOnlyItem( parent, file_name, leftDir, left_file->vfile_getSize(), left_file->vfile_getTime_t(), + readLink( left_file ), left_file->vfile_getOwner(), left_file->vfile_getGroup(), + left_file->vfile_getMode(), left_file->vfile_getACL() ); + else + { + if( isDir( right_file ) ) + continue; + + addDuplicateItem( parent, file_name, right_file->vfile_getName(), leftDir, rightDir, left_file->vfile_getSize(), right_file->vfile_getSize(), + left_file->vfile_getTime_t(), right_file->vfile_getTime_t(), readLink( left_file ), + readLink( right_file ), left_file->vfile_getOwner(), right_file->vfile_getOwner(), + left_file->vfile_getGroup(), right_file->vfile_getGroup(), + left_file->vfile_getMode(), right_file->vfile_getMode(), + left_file->vfile_getACL(), right_file->vfile_getACL() ); + } + } + + /* walking through in the right directory */ + for( right_file=right_directory->first(); right_file != 0 && !stopped ; + right_file=right_directory->next() ) + { + if( isDir( right_file ) ) + continue; + + file_name = right_file->vfile_getName(); + + if( checkIfSelected && !selectedFiles.contains( file_name ) ) + continue; + + if( !query->match( right_file ) ) + continue; + + if( left_directory->search( file_name, ignoreCase ) == 0 ) + addRightOnlyItem( parent, file_name, rightDir, right_file->vfile_getSize(), right_file->vfile_getTime_t(), + readLink( right_file ), right_file->vfile_getOwner(), right_file->vfile_getGroup(), + right_file->vfile_getMode(), right_file->vfile_getACL() ); + } + + /* walking through the subdirectories */ + if( recurseSubDirs ) + { + for( left_file=left_directory->first(); left_file != 0 && !stopped ; + left_file=left_directory->next() ) + { + if ( left_file->vfile_isDir() && ( followSymLinks || !left_file->vfile_isSymLink()) ) + { + TQString left_file_name = left_file->vfile_getName(); + + if( checkIfSelected && !selectedFiles.contains( left_file_name ) ) + continue; + + if( excludedPaths.contains( leftDir.isEmpty() ? left_file_name : leftDir+"/"+left_file_name ) ) + continue; + + if( !query->matchDirName( left_file_name ) ) + continue; + + if( (right_file = right_directory->search( left_file_name, ignoreCase )) == 0 ) + { + SynchronizerFileItem *me = addLeftOnlyItem( parent, left_file_name, leftDir, 0, + left_file->vfile_getTime_t(), readLink( left_file ), + left_file->vfile_getOwner(), left_file->vfile_getGroup(), + left_file->vfile_getMode(), left_file->vfile_getACL(), + true, !query->match( left_file ) ); + stack.append( new CompareTask( me, leftURL+left_file_name+"/", + leftDir.isEmpty() ? left_file_name : leftDir+"/"+left_file_name, true, ignoreHidden ) ); + } else { + TQString right_file_name = right_file->vfile_getName(); + SynchronizerFileItem *me = addDuplicateItem( parent, left_file_name, right_file_name, + leftDir, rightDir, 0, 0, + left_file->vfile_getTime_t(), right_file->vfile_getTime_t(), + readLink( left_file ), readLink( right_file ), + left_file->vfile_getOwner(), right_file->vfile_getOwner(), + left_file->vfile_getGroup(), right_file->vfile_getGroup(), + left_file->vfile_getMode(), right_file->vfile_getMode(), + left_file->vfile_getACL(), right_file->vfile_getACL(), + true, !query->match( left_file ) ); + stack.append( new CompareTask( me, leftURL+left_file_name+"/", rightURL+right_file_name+"/", + leftDir.isEmpty() ? left_file_name : leftDir+"/"+left_file_name, + rightDir.isEmpty() ? right_file_name : rightDir+"/"+right_file_name, ignoreHidden ) ); + } + } + } + + /* walking through the the right side subdirectories */ + for( right_file=right_directory->first(); right_file != 0 && !stopped ; + right_file=right_directory->next() ) + { + if ( right_file->vfile_isDir() && (followSymLinks || !right_file->vfile_isSymLink()) ) + { + file_name = right_file->vfile_getName(); + + if( checkIfSelected && !selectedFiles.contains( file_name ) ) + continue; + + if( excludedPaths.contains( rightDir.isEmpty() ? file_name : rightDir+"/"+file_name ) ) + continue; + + if( !query->matchDirName( file_name ) ) + continue; + + if( left_directory->search( file_name, ignoreCase ) == 0 ) + { + SynchronizerFileItem *me = addRightOnlyItem( parent, file_name, rightDir, 0, + right_file->vfile_getTime_t(), readLink( right_file ), + right_file->vfile_getOwner(), right_file->vfile_getGroup(), + right_file->vfile_getMode(), right_file->vfile_getACL(), + true, !query->match( right_file ) ); + stack.append( new CompareTask( me, rightURL+file_name+"/", + rightDir.isEmpty() ? file_name : rightDir+"/"+file_name, false, ignoreHidden ) ); + } + } + } + } +} + +TQString Synchronizer::getTaskTypeName( TaskType taskType ) +{ + static TQString names[] = {"=","!=","<-","->","DEL","?","?","?","?","?"}; + + return names[taskType]; +} + +SynchronizerFileItem * Synchronizer::addItem( SynchronizerFileItem *parent, const TQString &leftFile, + const TQString &rightFile, const TQString &leftDir, + const TQString &rightDir, bool existsLeft, bool existsRight, + TDEIO::filesize_t leftSize, TDEIO::filesize_t rightSize, + time_t leftDate, time_t rightDate, const TQString &leftLink, + const TQString &rightLink, const TQString &leftOwner, + const TQString &rightOwner, const TQString &leftGroup, + const TQString &rightGroup, mode_t leftMode, mode_t rightMode, + const TQString &leftACL, const TQString &rightACL, TaskType tsk, + bool isDir, bool isTemp ) +{ + bool marked = autoScroll ? !isTemp && isMarked( tsk, existsLeft && existsRight ) : false; + SynchronizerFileItem *item = new SynchronizerFileItem( leftFile, rightFile, leftDir, rightDir, marked, + existsLeft, existsRight, leftSize, rightSize, leftDate, rightDate, leftLink, rightLink, + leftOwner, rightOwner, leftGroup, rightGroup, leftMode, rightMode, leftACL, rightACL, tsk, isDir, + isTemp, parent ); + + if( !isTemp ) + { + while( parent && parent->isTemporary() ) + setPermanent( parent ); + + bool doRefresh = false; + + if( marked ) + { + fileCount++; + if( autoScroll && markParentDirectories( item ) ) + doRefresh = true; + } + + resultList.append( item ); + emit comparedFileData( item ); + + if( doRefresh ) + refresh( true ); + + if( marked && (displayUpdateCount++ % DISPLAY_UPDATE_PERIOD == (DISPLAY_UPDATE_PERIOD-1) ) ) + tqApp->processEvents(); + } + else + temporaryList.append( item ); + + return item; +} + +void Synchronizer::compareContentResult( SynchronizerFileItem * item, bool res ) { + item->compareContentResult( res ); + bool marked = autoScroll ? isMarked( item->task(), item->existsInLeft() && item->existsInRight() ) : false; + item->setMarked( marked ); + if( marked ) { + markParentDirectories( item ); + fileCount++; + emit markChanged( item, true ); + } +} + +void Synchronizer::setPermanent( SynchronizerFileItem *item ) +{ + if( item->parent() && item->parent()->isTemporary() ) + setPermanent( item->parent() ); + + item->setPermanent(); + resultList.append( item ); + emit comparedFileData( item ); +} + +SynchronizerFileItem * Synchronizer::addLeftOnlyItem( SynchronizerFileItem *parent, + const TQString &file_name, const TQString &dir, TDEIO::filesize_t size, + time_t date, const TQString &link, const TQString &owner, + const TQString &group, mode_t mode, const TQString &acl, bool isDir, + bool isTemp ) +{ + return addItem( parent, file_name, file_name, dir, dir, true, false, size, 0, date, 0, link, TQString(), + owner, TQString(), group, TQString(), mode, (mode_t)-1, acl, TQString(), + asymmetric ? TT_DELETE : TT_COPY_TO_RIGHT, isDir, isTemp ); +} + +SynchronizerFileItem * Synchronizer::addRightOnlyItem( SynchronizerFileItem *parent, + const TQString &file_name, const TQString &dir, TDEIO::filesize_t size, + time_t date, const TQString &link, const TQString &owner, + const TQString &group, mode_t mode, const TQString &acl, bool isDir, + bool isTemp ) +{ + return addItem( parent, file_name, file_name, dir, dir, false, true, 0, size, 0, date, TQString(), link, + TQString(), owner, TQString(), group, (mode_t)-1, mode, TQString(), acl, + TT_COPY_TO_LEFT, isDir, isTemp ); +} + +SynchronizerFileItem * Synchronizer::addDuplicateItem( SynchronizerFileItem *parent, + const TQString &leftName, const TQString &rightName, + const TQString &leftDir, const TQString &rightDir, + TDEIO::filesize_t leftSize, TDEIO::filesize_t rightSize, time_t leftDate, time_t rightDate, + const TQString &leftLink, const TQString &rightLink, + const TQString &leftOwner, const TQString &rightOwner, + const TQString &leftGroup, const TQString &rightGroup, + mode_t leftMode, mode_t rightMode, + const TQString &leftACL, const TQString &rightACL, + bool isDir, bool isTemp ) +{ + TaskType task; + + int checkedRightDate = rightDate - timeOffset; + int uncertain = 0; + + do + { + if( isDir ) + { + task = TT_EQUALS; + break; + } + if( leftSize == rightSize ) + { + if( !leftLink.isNull() || !rightLink.isNull() ) { + if( leftLink == rightLink ) { + task = TT_EQUALS; + break; + } + } else if( cmpByContent ) + uncertain = TT_UNKNOWN; + else { + if( ignoreDate || leftDate == checkedRightDate ) { + task = TT_EQUALS; + break; + } + time_t diff = ( leftDate > checkedRightDate ) ? leftDate - checkedRightDate : checkedRightDate - leftDate; + if( diff <= equalsThreshold ) { + task = TT_EQUALS; + break; + } + } + } + + if( asymmetric ) + task = TT_COPY_TO_LEFT; + else if( ignoreDate ) + task = TT_DIFFERS; + else if( leftDate > checkedRightDate ) + task = TT_COPY_TO_RIGHT; + else if( leftDate < checkedRightDate ) + task = TT_COPY_TO_LEFT; + else + task = TT_DIFFERS; + + }while( false ); + + SynchronizerFileItem * item = addItem( parent, leftName, rightName, leftDir, rightDir, true, true, + leftSize, rightSize, leftDate, rightDate, leftLink, rightLink, + leftOwner, rightOwner, leftGroup, rightGroup, + leftMode, rightMode, leftACL, rightACL, + (TaskType)(task + uncertain), isDir, isTemp ); + + if( uncertain == TT_UNKNOWN ) { + KURL leftURL = vfs::fromPathOrURL( leftDir.isEmpty() ? leftBaseDir + leftName : leftBaseDir + leftDir + "/" + leftName ); + KURL rightURL = vfs::fromPathOrURL( rightDir.isEmpty() ? rightBaseDir + rightName : rightBaseDir + rightDir + "/" + rightName ); + stack.append( new CompareContentTask( this, item, leftURL, rightURL, leftSize ) ); + } + + return item; +} + +void Synchronizer::addSingleDirectory( SynchronizerFileItem *parent, SynchronizerDirList *directory, + const TQString &dirName, bool isLeft ) +{ + const TQString &url = directory->url(); + vfile * file; + TQString file_name; + + /* walking through the directory files */ + for( file=directory->first(); file != 0 && !stopped; file = directory->next() ) + { + if ( isDir( file ) ) + continue; + + file_name = file->vfile_getName(); + + if( !query->match( file ) ) + continue; + + if( isLeft ) + addLeftOnlyItem( parent, file_name, dirName, file->vfile_getSize(), file->vfile_getTime_t(), readLink( file ), + file->vfile_getOwner(), file->vfile_getGroup(), file->vfile_getMode(), file->vfile_getACL() ); + else + addRightOnlyItem( parent, file_name, dirName, file->vfile_getSize(), file->vfile_getTime_t(), readLink( file ), + file->vfile_getOwner(), file->vfile_getGroup(), file->vfile_getMode(), file->vfile_getACL() ); + } + + /* walking through the subdirectories */ + for( file=directory->first(); file != 0 && !stopped; file=directory->next() ) + { + if ( file->vfile_isDir() && (followSymLinks || !file->vfile_isSymLink()) ) + { + file_name = file->vfile_getName(); + + if( excludedPaths.contains( dirName.isEmpty() ? file_name : dirName+"/"+file_name ) ) + continue; + + if( !query->matchDirName( file_name ) ) + continue; + + SynchronizerFileItem *me; + + if( isLeft ) + me = addLeftOnlyItem( parent, file_name, dirName, 0, file->vfile_getTime_t(), readLink( file ), + file->vfile_getOwner(), file->vfile_getGroup(), file->vfile_getMode(), + file->vfile_getACL(), true, !query->match( file ) ); + else + me = addRightOnlyItem( parent, file_name, dirName, 0, file->vfile_getTime_t(), readLink( file ), + file->vfile_getOwner(), file->vfile_getGroup(), file->vfile_getMode(), + file->vfile_getACL(), true, !query->match( file ) ); + stack.append( new CompareTask( me, url+file_name+"/", + dirName.isEmpty() ? file_name : dirName+"/"+file_name, isLeft, ignoreHidden ) ); + } + } +} + +void Synchronizer::setMarkFlags( bool left, bool equal, bool differs, bool right, bool dup, bool sing, + bool del ) +{ + markEquals = equal; + markDiffers = differs; + markCopyToLeft = left; + markCopyToRight = right; + markDeletable = del; + markDuplicates = dup; + markSingles = sing; +} + +bool Synchronizer::isMarked( TaskType task, bool isDuplicate ) +{ + if( (isDuplicate && !markDuplicates) || (!isDuplicate && !markSingles) ) + return false; + + switch( task ) + { + case TT_EQUALS: + return markEquals; + case TT_DIFFERS: + return markDiffers; + case TT_COPY_TO_LEFT: + return markCopyToLeft; + case TT_COPY_TO_RIGHT: + return markCopyToRight; + case TT_DELETE: + return markDeletable; + default: + return false; + } +} + +bool Synchronizer::markParentDirectories( SynchronizerFileItem *item ) +{ + if( item->parent() == 0 || item->parent()->isMarked() ) + return false; + + markParentDirectories( item->parent() ); + + item->parent()->setMarked( true ); + + fileCount++; + emit markChanged( item->parent(), false ); + return true; +} + +int Synchronizer::refresh(bool nostatus) +{ + fileCount = 0; + + SynchronizerFileItem *item = resultList.first(); + + while( item ) + { + bool marked = isMarked( item->task(), item->existsInLeft() && item->existsInRight() ); + item->setMarked( marked ); + + if( marked ) + { + markParentDirectories( item ); + fileCount++; + } + + item = resultList.next(); + } + + item = resultList.first(); + while( item ) + { + emit markChanged( item, false ); + item = resultList.next(); + } + + if( !nostatus ) + emit statusInfo( i18n( "Number of files: %1" ).arg( fileCount ) ); + + return fileCount; +} + +void Synchronizer::operate( SynchronizerFileItem *item, + void (*executeOperation)(SynchronizerFileItem *) ) +{ + executeOperation( item ); + + if( item->isDir() ) + { + TQString leftDirName = ( item->leftDirectory() == "" ) ? + item->leftName() : item->leftDirectory() + "/" + item->leftName() ; + TQString rightDirName = ( item->rightDirectory() == "" ) ? + item->rightName() : item->rightDirectory() + "/" + item->rightName() ; + + item = resultList.first(); + while( item ) + { + if( item->leftDirectory() == leftDirName || item->leftDirectory().startsWith( leftDirName + "/" ) || + item->rightDirectory() == rightDirName || item->rightDirectory().startsWith( rightDirName + "/" ) ) + executeOperation( item ); + + item = resultList.next(); + } + } +} + +void Synchronizer::excludeOperation( SynchronizerFileItem *item ) +{ + item->setTask( TT_DIFFERS ); +} + +void Synchronizer::exclude( SynchronizerFileItem *item ) +{ + if( !item->parent() || item->parent()->task() != TT_DELETE ) + operate( item, excludeOperation ); /* exclude only if the parent task is not DEL */ +} + +void Synchronizer::restoreOperation( SynchronizerFileItem *item ) +{ + item->restoreOriginalTask(); +} + +void Synchronizer::restore( SynchronizerFileItem *item ) +{ + operate( item, restoreOperation ); + + while( ( item = item->parent() ) != 0 ) /* in case of restore, the parent directories */ + { /* must be changed for being consistent */ + if( item->task() != TT_DIFFERS ) + break; + + if( item->originalTask() == TT_DELETE ) /* if the parent original task is delete */ + break; /* don't touch it */ + + item->restoreOriginalTask(); /* restore */ + } +} + +void Synchronizer::reverseDirectionOperation( SynchronizerFileItem *item ) +{ + if( item->existsInRight() && item->existsInLeft() ) + { + if( item->task() == TT_COPY_TO_LEFT ) + item->setTask( TT_COPY_TO_RIGHT ); + else if( item->task() == TT_COPY_TO_RIGHT ) + item->setTask( TT_COPY_TO_LEFT ); + } +} + +void Synchronizer::reverseDirection( SynchronizerFileItem *item ) +{ + operate( item, reverseDirectionOperation ); +} + +void Synchronizer::deleteLeftOperation( SynchronizerFileItem *item ) +{ + if( !item->existsInRight() && item->existsInLeft() ) + item->setTask( TT_DELETE ); +} + +void Synchronizer::deleteLeft( SynchronizerFileItem *item ) +{ + operate( item, deleteLeftOperation ); +} + +void Synchronizer::copyToLeftOperation( SynchronizerFileItem *item ) +{ + if( item->existsInRight() ) + { + if( !item->isDir() ) + item->setTask( TT_COPY_TO_LEFT ); + else + { + if( item->existsInLeft() && item->existsInRight() ) + item->setTask( TT_EQUALS ); + else if( !item->existsInLeft() && item->existsInRight() ) + item->setTask( TT_COPY_TO_LEFT ); + } + } +} + +void Synchronizer::copyToLeft( SynchronizerFileItem *item ) +{ + operate( item, copyToLeftOperation ); + + while( ( item = item->parent() ) != 0 ) + { + if( item->task() != TT_DIFFERS ) + break; + + if( item->existsInLeft() && item->existsInRight() ) + item->setTask( TT_EQUALS ); + else if( !item->existsInLeft() && item->existsInRight() ) + item->setTask( TT_COPY_TO_LEFT ); + } +} + +void Synchronizer::copyToRightOperation( SynchronizerFileItem *item ) +{ + if( item->existsInLeft() ) + { + if( !item->isDir() ) + item->setTask( TT_COPY_TO_RIGHT ); + else + { + if( item->existsInLeft() && item->existsInRight() ) + item->setTask( TT_EQUALS ); + else if( item->existsInLeft() && !item->existsInRight() ) + item->setTask( TT_COPY_TO_RIGHT ); + } + } +} + +void Synchronizer::copyToRight( SynchronizerFileItem *item ) +{ + operate( item, copyToRightOperation ); + + while( ( item = item->parent() ) != 0 ) + { + if( item->task() != TT_DIFFERS && item->task() != TT_DELETE ) + break; + + if( item->existsInLeft() && item->existsInRight() ) + item->setTask( TT_EQUALS ); + else if( item->existsInLeft() && !item->existsInRight() ) + item->setTask( TT_COPY_TO_RIGHT ); + } +} + +bool Synchronizer::totalSizes( int * leftCopyNr, TDEIO::filesize_t *leftCopySize, int * rightCopyNr, + TDEIO::filesize_t *rightCopySize, int *deleteNr, TDEIO::filesize_t *deletableSize ) +{ + bool hasAnythingToDo = false; + + *leftCopySize = *rightCopySize = *deletableSize = 0; + *leftCopyNr = *rightCopyNr = *deleteNr = 0; + + SynchronizerFileItem *item = resultList.first(); + + while( item ) + { + if( item->isMarked() ) + { + switch( item->task() ) + { + case TT_COPY_TO_LEFT: + *leftCopySize += item->rightSize(); + (*leftCopyNr)++; + hasAnythingToDo = true; + break; + case TT_COPY_TO_RIGHT: + *rightCopySize += item->leftSize(); + (*rightCopyNr)++; + hasAnythingToDo = true; + break; + case TT_DELETE: + *deletableSize += item->leftSize(); + (*deleteNr)++; + hasAnythingToDo = true; + break; + default: + break; + } + } + item = resultList.next(); + } + + return hasAnythingToDo; +} + +void Synchronizer::swapSides() +{ + TQString leftTmp = leftBaseDir; + leftBaseDir = rightBaseDir; + rightBaseDir = leftTmp; + + SynchronizerFileItem *item = resultList.first(); + + while( item ) + { + item->swap( asymmetric ); + item = resultList.next(); + } +} + +void Synchronizer::setScrolling( bool scroll ) +{ + if( autoScroll = scroll ) + { + int oldFileCount = fileCount; + refresh( true ); + fileCount = oldFileCount; + } +} + +void Synchronizer::synchronize( TQWidget *syncWdg, bool leftCopyEnabled, bool rightCopyEnabled, + bool deleteEnabled, bool overWrite, int parThreads ) +{ + this->leftCopyEnabled = leftCopyEnabled; + this->rightCopyEnabled = rightCopyEnabled; + this->deleteEnabled = deleteEnabled; + this->overWrite = overWrite; + this->parallelThreads = parThreads; + this->syncDlgWidget = syncWdg; + + autoSkip = paused = disableNewTasks = false; + + leftCopyNr = rightCopyNr = deleteNr = 0; + leftCopySize = rightCopySize = deleteSize = 0; + + inTaskFinished = 0; + lastTask = 0; + + jobMap.clear(); + receivedMap.clear(); + + resultList.first(); + synchronizeLoop(); +} + +void Synchronizer::synchronizeLoop() { + if( disableNewTasks ) { + if( resultList.current() == 0 && jobMap.count() == 0 ) + emit synchronizationFinished(); + return; + } + + while( (int)jobMap.count() < parallelThreads ) { + SynchronizerFileItem *task = getNextTask(); + if( task == 0 ) { + if( jobMap.count() == 0 ) + emit synchronizationFinished(); + return; + } + executeTask( task ); + if( disableNewTasks ) + break; + } +} + +SynchronizerFileItem * Synchronizer::getNextTask() { + TaskType task; + SynchronizerFileItem * currentTask = resultList.current(); + + do { + if( currentTask == 0 ) + return 0; + + if( currentTask->isMarked() ) + { + task = currentTask->task(); + + if( leftCopyEnabled && task == TT_COPY_TO_LEFT ) + break; + else if( rightCopyEnabled && task == TT_COPY_TO_RIGHT ) + break; + else if( deleteEnabled && task == TT_DELETE ) + break; + } + + currentTask = resultList.next(); + }while( true ); + + resultList.next(); + return lastTask = currentTask; +} + + +void Synchronizer::executeTask( SynchronizerFileItem * task ) +{ + TQString leftDirName = task->leftDirectory(); + if( !leftDirName.isEmpty() ) + leftDirName += "/"; + TQString rightDirName = task->rightDirectory(); + if( !rightDirName.isEmpty() ) + rightDirName += "/"; + + KURL leftURL = vfs::fromPathOrURL( leftBaseDir + leftDirName + task->leftName() ); + KURL rightURL = vfs::fromPathOrURL( rightBaseDir + rightDirName + task->rightName() ); + + switch( task->task() ) + { + case TT_COPY_TO_LEFT: + if( task->isDir() ) + { + TDEIO::SimpleJob *job = TDEIO::mkdir( leftURL ); + connect(job,TQ_SIGNAL(result(TDEIO::Job*)),this,TQ_SLOT(slotTaskFinished(TDEIO::Job*))); + jobMap[ job ] = task; + disableNewTasks = true; + } + else + { + KURL destURL( leftURL ); + if( !task->destination().isNull() ) + destURL = vfs::fromPathOrURL( task->destination() ); + + if( task->rightLink().isNull() ) { + TDEIO::FileCopyJob *job = TDEIO::file_copy(rightURL, destURL, -1, + overWrite || task->overWrite(), false, false ); + connect(job,TQ_SIGNAL(processedSize (TDEIO::Job *, TDEIO::filesize_t )), this, + TQ_SLOT (slotProcessedSize (TDEIO::Job *, TDEIO::filesize_t ))); + connect(job,TQ_SIGNAL(result(TDEIO::Job*)),this,TQ_SLOT(slotTaskFinished(TDEIO::Job*))); + jobMap[ job ] = task; + } else { + TDEIO::SimpleJob *job = TDEIO::symlink( task->rightLink(), destURL, + overWrite || task->overWrite(), false ); + connect(job,TQ_SIGNAL(result(TDEIO::Job*)),this,TQ_SLOT(slotTaskFinished(TDEIO::Job*))); + jobMap[ job ] = task; + } + } + break; + case TT_COPY_TO_RIGHT: + if( task->isDir() ) + { + TDEIO::SimpleJob *job = TDEIO::mkdir( rightURL ); + connect(job,TQ_SIGNAL(result(TDEIO::Job*)),this,TQ_SLOT(slotTaskFinished(TDEIO::Job*))); + jobMap[ job ] = task; + disableNewTasks = true; + } + else + { + KURL destURL( rightURL ); + if( !task->destination().isNull() ) + destURL = vfs::fromPathOrURL( task->destination() ); + + if( task->leftLink().isNull() ) { + TDEIO::FileCopyJob *job = TDEIO::file_copy(leftURL, destURL, -1, + overWrite || task->overWrite(), false, false ); + connect(job,TQ_SIGNAL(processedSize (TDEIO::Job *, TDEIO::filesize_t )), this, + TQ_SLOT (slotProcessedSize (TDEIO::Job *, TDEIO::filesize_t ))); + connect(job,TQ_SIGNAL(result(TDEIO::Job*)),this,TQ_SLOT(slotTaskFinished(TDEIO::Job*))); + jobMap[ job ] = task; + } else { + TDEIO::SimpleJob *job = TDEIO::symlink( task->leftLink(), destURL, + overWrite || task->overWrite(), false ); + connect(job,TQ_SIGNAL(result(TDEIO::Job*)),this,TQ_SLOT(slotTaskFinished(TDEIO::Job*))); + jobMap[ job ] = task; + } + } + break; + case TT_DELETE: + { + TDEIO::DeleteJob *job = TDEIO::del( leftURL, false ); + connect(job,TQ_SIGNAL(result(TDEIO::Job*)),this,TQ_SLOT(slotTaskFinished(TDEIO::Job*))); + jobMap[ job ] = task; + } + break; + default: + break; + } +} + +void Synchronizer::slotTaskFinished(TDEIO::Job *job ) +{ + inTaskFinished++; + + SynchronizerFileItem * item = jobMap[ job ]; + jobMap.remove( job ); + + TDEIO::filesize_t receivedSize = 0; + + if( receivedMap.contains( job ) ) { + receivedSize = receivedMap[ job ]; + receivedMap.remove( job ); + } + + if( disableNewTasks && item == lastTask ) + disableNewTasks = false; // the blocker task finished + + TQString leftDirName = item->leftDirectory().isEmpty() ? "" : item->leftDirectory() + "/"; + TQString rightDirName = item->rightDirectory().isEmpty() ? "" : item->rightDirectory() + "/"; + KURL leftURL = vfs::fromPathOrURL( leftBaseDir + leftDirName + item->leftName() ); + KURL rightURL = vfs::fromPathOrURL( rightBaseDir + rightDirName + item->rightName() ); + + do { + if( !job->error() ) + { + switch( item->task() ) + { + case TT_COPY_TO_LEFT: + if( leftURL.isLocalFile() ) + { + struct utimbuf timestamp; + + timestamp.actime = time( 0 ); + timestamp.modtime = item->rightDate() - timeOffset; + + utime( (const char *)( leftURL.path( -1 ).local8Bit() ), ×tamp ); + + uid_t newOwnerID = (uid_t)-1; // chown(2) : -1 means no change + if ( !item->rightOwner().isEmpty() ) + { + struct passwd* pw = getpwnam(TQFile::encodeName(item->rightOwner())); + if ( pw != 0L ) + newOwnerID = pw->pw_uid; + } + gid_t newGroupID = (gid_t)-1; // chown(2) : -1 means no change + if ( !item->rightGroup().isEmpty() ) + { + struct group* g = getgrnam(TQFile::encodeName(item->rightGroup())); + if ( g != 0L ) + newGroupID = g->gr_gid; + } + chown( (const char *)( leftURL.path( -1 ).local8Bit() ), newOwnerID, (gid_t)-1 ); + chown( (const char *)( leftURL.path( -1 ).local8Bit() ), (uid_t)-1, newGroupID ); + + chmod( (const char *)( leftURL.path( -1 ).local8Bit() ), item->rightMode() & 07777 ); + +#if KDE_IS_VERSION(3,5,0) && defined( HAVE_POSIX_ACL ) + if( !item->rightACL().isNull() ) + { + acl_t acl = acl_from_text( item->rightACL().latin1() ); + if( acl && !acl_valid( acl ) ) + acl_set_file( leftURL.path( -1 ).local8Bit(), ACL_TYPE_ACCESS, acl ); + if( acl ) + acl_free( acl ); + } +#endif + } + break; + case TT_COPY_TO_RIGHT: + if( rightURL.isLocalFile() ) + { + struct utimbuf timestamp; + + timestamp.actime = time( 0 ); + timestamp.modtime = item->leftDate() + timeOffset; + + utime( (const char *)( rightURL.path( -1 ).local8Bit() ), ×tamp ); + + uid_t newOwnerID = (uid_t)-1; // chown(2) : -1 means no change + if ( !item->leftOwner().isEmpty() ) + { + struct passwd* pw = getpwnam(TQFile::encodeName(item->leftOwner())); + if ( pw != 0L ) + newOwnerID = pw->pw_uid; + } + gid_t newGroupID = (gid_t)-1; // chown(2) : -1 means no change + if ( !item->leftGroup().isEmpty() ) + { + struct group* g = getgrnam(TQFile::encodeName(item->leftGroup())); + if ( g != 0L ) + newGroupID = g->gr_gid; + } + chown( (const char *)( rightURL.path( -1 ).local8Bit() ), newOwnerID, (uid_t)-1 ); + chown( (const char *)( rightURL.path( -1 ).local8Bit() ), (uid_t)-1, newGroupID ); + + chmod( (const char *)( rightURL.path( -1 ).local8Bit() ), item->leftMode() & 07777 ); + +#if KDE_IS_VERSION(3,5,0) && defined( HAVE_POSIX_ACL ) + if( !item->leftACL().isNull() ) + { + acl_t acl = acl_from_text( item->leftACL().latin1() ); + if( acl && !acl_valid( acl ) ) + acl_set_file( rightURL.path( -1 ).local8Bit(), ACL_TYPE_ACCESS, acl ); + if( acl ) + acl_free( acl ); + } +#endif + } + break; + default: + break; + } + } + else + { + if( job->error() == TDEIO::ERR_FILE_ALREADY_EXIST && item->task() != TT_DELETE ) + { + TDEIO::RenameDlg_Result result; + TQString newDest; + + if( autoSkip ) + break; + + if ( item->task() == TT_COPY_TO_LEFT ) + { + TQWidget *mainWidget = tqApp->mainWidget(); // WORKAROUND, don't give focus to the main widget + tqApp->setMainWidget( syncDlgWidget ); + + result = Observer::self()->open_RenameDlg ( job, i18n("File Already Exists"), + vfs::pathOrURL( rightURL ), vfs::pathOrURL( leftURL ), + (TDEIO::RenameDlg_Mode)( TDEIO::M_OVERWRITE | TDEIO::M_SKIP | TDEIO::M_MULTI ), newDest, + item->rightSize(), item->leftSize(), (time_t)-1, (time_t)-1, + item->rightDate(), item->leftDate()); + + tqApp->setMainWidget( mainWidget ); + } + else + { + TQWidget *mainWidget = tqApp->mainWidget(); // WORKAROUND, don't give focus to the main widget + tqApp->setMainWidget( syncDlgWidget ); + + result = Observer::self()->open_RenameDlg ( job, i18n("File Already Exists"), + vfs::pathOrURL( leftURL ), vfs::pathOrURL( rightURL ), + (TDEIO::RenameDlg_Mode)( TDEIO::M_OVERWRITE | TDEIO::M_SKIP | TDEIO::M_MULTI ), newDest, + item->leftSize(), item->rightSize(), (time_t)-1, (time_t)-1, + item->leftDate(), item->rightDate()); + + tqApp->setMainWidget( mainWidget ); + } + + switch ( result ) + { + case TDEIO::R_RENAME: + item->setDestination( newDest ); + executeTask( item ); + inTaskFinished--; + return; + case TDEIO::R_OVERWRITE: + item->setOverWrite(); + executeTask( item ); + inTaskFinished--; + return; + case TDEIO::R_OVERWRITE_ALL: + overWrite = true; + executeTask( item ); + inTaskFinished--; + return; + case TDEIO::R_AUTO_SKIP: + autoSkip = true; + case TDEIO::R_SKIP: + default: + break; + } + break; + } + + if( job->error() != TDEIO::ERR_DOES_NOT_EXIST || item->task() != TT_DELETE ) + { + if( autoSkip ) + break; + + TQString error; + + switch( item->task() ) + { + case TT_COPY_TO_LEFT: + error = i18n("Error at copying file %1 to %2!") + .arg( vfs::pathOrURL( rightURL ) ) + .arg( vfs::pathOrURL( leftURL ) ); + break; + case TT_COPY_TO_RIGHT: + error = i18n("Error at copying file %1 to %2!") + .arg( vfs::pathOrURL( leftURL ) ) + .arg( vfs::pathOrURL( rightURL ) ); + break; + case TT_DELETE: + error = i18n("Error at deleting file %1!").arg( vfs::pathOrURL( leftURL ) ); + break; + default: + break; + } + + TQWidget *mainWidget = tqApp->mainWidget(); // WORKAROUND, don't give focus to the main widget + tqApp->setMainWidget( syncDlgWidget ); + + TDEIO::SkipDlg_Result result = Observer::self()->open_SkipDlg( job, true, error ); + + tqApp->setMainWidget( mainWidget ); + + switch( result ) + { + case TDEIO::S_CANCEL: + executeTask( item ); /* simply retry */ + inTaskFinished--; + return; + case TDEIO::S_AUTO_SKIP: + autoSkip = true; + default: + break; + } + } + } + }while( false ); + + switch( item->task() ) + { + case TT_COPY_TO_LEFT: + leftCopyNr++; + leftCopySize += item->rightSize() - receivedSize; + break; + case TT_COPY_TO_RIGHT: + rightCopyNr++; + rightCopySize += item->leftSize() - receivedSize; + break; + case TT_DELETE: + deleteNr++; + deleteSize += item->leftSize() - receivedSize; + break; + default: + break; + } + + emit processedSizes( leftCopyNr, leftCopySize, rightCopyNr, rightCopySize, deleteNr, deleteSize ); + + if( --inTaskFinished == 0 ) { + if( paused ) + emit pauseAccepted(); + else + synchronizeLoop(); + } +} + +void Synchronizer::slotProcessedSize( TDEIO::Job * job , TDEIO::filesize_t size) +{ + TDEIO::filesize_t dl = 0, dr = 0, dd = 0; + SynchronizerFileItem * item = jobMap[ job ]; + + TDEIO::filesize_t lastProcessedSize = 0; + if( receivedMap.contains( job ) ) + lastProcessedSize = receivedMap[ job ]; + + receivedMap[ job ] = size; + + switch( item->task() ) + { + case TT_COPY_TO_LEFT: + dl = size - lastProcessedSize; + break; + case TT_COPY_TO_RIGHT: + dr = size - lastProcessedSize; + break; + case TT_DELETE: + dd = size - lastProcessedSize; + break; + default: + break; + } + + emit processedSizes( leftCopyNr, leftCopySize+=dl, rightCopyNr, rightCopySize+=dr, deleteNr, deleteSize+=dd ); +} + +void Synchronizer::pause() +{ + paused = true; +} + +void Synchronizer::resume() +{ + paused = false; + synchronizeLoop(); +} + +TQString Synchronizer::leftBaseDirectory() +{ + return leftBaseDir; +} + +TQString Synchronizer::rightBaseDirectory() +{ + return rightBaseDir; +} + +class KgetProgressDialog : public KDialogBase +{ +public: + KgetProgressDialog( TQWidget *parent=0, const char *name=0, const TQString &caption=TQString(), + const TQString &text=TQString(), bool modal=false) : KDialogBase( KDialogBase::Plain, + caption, KDialogBase::User1 | KDialogBase::Cancel, KDialogBase::Cancel, parent, name, modal ) + { + showButton(KDialogBase::Close, false); + + TQFrame* mainWidget = plainPage(); + TQVBoxLayout* layout = new TQVBoxLayout(mainWidget, 10); + + TQLabel *mLabel = new TQLabel(text, mainWidget); + layout->addWidget(mLabel); + + mProgressBar = new KProgress(mainWidget); + layout->addWidget(mProgressBar); + + setButtonText( KDialogBase::User1, i18n( "Pause" ) ); + + mCancelled = mPaused = false; + } + + KProgress *progressBar() { return mProgressBar; } + + void slotUser1() + { + if( ( mPaused = !mPaused ) == false ) + setButtonText( KDialogBase::User1, i18n( "Pause" ) ); + else + setButtonText( KDialogBase::User1, i18n( "Resume" ) ); + } + + void slotCancel() + { + mCancelled = true; + + KDialogBase::slotCancel(); + } + + bool wasCancelled() { return mCancelled; } + bool isPaused() { return mPaused; } + +private: + KProgress *mProgressBar; + bool mCancelled; + bool mPaused; +}; + + +void Synchronizer::synchronizeWithKGet() +{ + bool isLeftLocal = vfs::fromPathOrURL( leftBaseDirectory() ).isLocalFile(); + KgetProgressDialog *progDlg = 0; + int processedCount = 0, totalCount = 0; + + SynchronizerFileItem *item = resultList.first(); + for(; item; item = resultList.next() ) + if( item->isMarked() ) + totalCount++; + + item = resultList.first(); + while( item ) + { + if( item->isMarked() ) + { + KURL downloadURL, destURL; + TQString leftDirName = item->leftDirectory().isEmpty() ? "" : item->leftDirectory() + "/"; + TQString rightDirName = item->rightDirectory().isEmpty() ? "" : item->rightDirectory() + "/"; + TQString destDir; + + if( progDlg == 0 ) + { + progDlg = new KgetProgressDialog( krApp, "Synchronizer Progress Dlg", i18n("Krusader::Synchronizer"), + i18n( "Feeding the URLs to Kget" ), true ); + progDlg->progressBar()->setTotalSteps( totalCount ); + progDlg->show(); + tqApp->processEvents(); + } + + if( item->task() == TT_COPY_TO_RIGHT && !isLeftLocal ) + { + downloadURL = vfs::fromPathOrURL( leftBaseDirectory() + leftDirName + item->leftName() ); + destDir = rightBaseDirectory() + rightDirName; + destURL = vfs::fromPathOrURL( destDir + item->rightName() ); + + if( item->isDir() ) + destDir += item->leftName(); + } + if( item->task() == TT_COPY_TO_LEFT && isLeftLocal ) + { + downloadURL = vfs::fromPathOrURL( rightBaseDirectory() + rightDirName + item->rightName() ); + destDir = leftBaseDirectory() + leftDirName; + destURL = vfs::fromPathOrURL( destDir + item->leftName() ); + + if( item->isDir() ) + destDir += item->rightName(); + } + + // creating the directory system + for( int i=0; i >= 0 ; i= destDir.find('/',i+1) ) + if( !TQDir( destDir.left(i) ).exists() ) + TQDir().mkdir( destDir.left(i) ); + + if( !item->isDir() && !downloadURL.isEmpty() ) + { + if( TQFile( destURL.path() ).exists() ) + TQFile( destURL.path() ).remove(); + + TQString source = downloadURL.prettyURL(); + if( source.contains( '@' ) >= 2 ) /* is this an ftp proxy URL? */ + { + int lastAt = source.findRev( '@' ); + TQString startString = source.left( lastAt ); + TQString endString = source.mid( lastAt ); + startString.replace( "@", "%40" ); + source = startString+endString; + } + + TDEProcess p; + + p << KrServices::fullPathName( "kget" ) << source << destURL.path(); + if (!p.start(TDEProcess::Block)) + KMessageBox::error(parentWidget,i18n("Error executing ")+KrServices::fullPathName( "kget" )+" !"); + else + p.detach(); + } + + progDlg->progressBar()->setProgress( ++processedCount ); + + do + { + tqApp->processEvents(); + + if( progDlg->wasCancelled() ) + break; + + if( progDlg->isPaused() ) + usleep( 100000 ); + + }while( progDlg->isPaused() ); + + if( progDlg->wasCancelled() ) + break; + } + item = resultList.next(); + } + + if( progDlg ) + delete progDlg; +} + +bool Synchronizer::isDir( const vfile * file ) { + if( followSymLinks ) { + return file->vfile_isDir(); + } + else { + return file->vfile_isDir() && !file->vfile_isSymLink(); + } +} + +TQString Synchronizer::readLink( const vfile * file ) { + if( file->vfile_isSymLink() ) + return file->vfile_getSymDest(); + else + return TQString(); +} + +#include "synchronizer.moc" |