00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "copyjob.h"
00023 #include "deletejob.h"
00024
00025 #include <klocale.h>
00026 #include <kdesktopfile.h>
00027 #include <kdebug.h>
00028 #include <kde_file.h>
00029
00030 #include "slave.h"
00031 #include "scheduler.h"
00032 #include "kdirwatch.h"
00033 #include "kprotocolmanager.h"
00034
00035 #include "jobuidelegate.h"
00036
00037 #include <kdirnotify.h>
00038 #include <ktemporaryfile.h>
00039 #include <kuiserverjobtracker.h>
00040
00041 #ifdef Q_OS_UNIX
00042 #include <utime.h>
00043 #endif
00044 #include <assert.h>
00045
00046 #include <QtCore/QTimer>
00047 #include <QtCore/QFile>
00048 #include <sys/stat.h>
00049 #include <QPointer>
00050
00051 #include "job_p.h"
00052
00053 using namespace KIO;
00054
00055
00056 #define REPORT_TIMEOUT 200
00057
00058 #define KIO_ARGS QByteArray packedArgs; QDataStream stream( &packedArgs, QIODevice::WriteOnly ); stream
00059
00060 enum DestinationState {
00061 DEST_NOT_STATED,
00062 DEST_IS_DIR,
00063 DEST_IS_FILE,
00064 DEST_DOESNT_EXIST
00065 };
00066
00081 enum CopyJobState {
00082 STATE_STATING,
00083 STATE_RENAMING,
00084 STATE_LISTING,
00085 STATE_CREATING_DIRS,
00086 STATE_CONFLICT_CREATING_DIRS,
00087 STATE_COPYING_FILES,
00088 STATE_CONFLICT_COPYING_FILES,
00089 STATE_DELETING_DIRS,
00090 STATE_SETTING_DIR_ATTRIBUTES
00091 };
00092
00094 class KIO::CopyJobPrivate: public KIO::JobPrivate
00095 {
00096 public:
00097 CopyJobPrivate(const KUrl::List& src, const KUrl& dest,
00098 CopyJob::CopyMode mode, bool asMethod)
00099 : m_globalDest(dest)
00100 , m_globalDestinationState(DEST_NOT_STATED)
00101 , m_defaultPermissions(false)
00102 , m_bURLDirty(false)
00103 , m_mode(mode)
00104 , m_asMethod(asMethod)
00105 , destinationState(DEST_NOT_STATED)
00106 , state(STATE_STATING)
00107 , m_totalSize(0)
00108 , m_processedSize(0)
00109 , m_fileProcessedSize(0)
00110 , m_processedFiles(0)
00111 , m_processedDirs(0)
00112 , m_srcList(src)
00113 , m_currentStatSrc(m_srcList.begin())
00114 , m_bCurrentOperationIsLink(false)
00115 , m_bSingleFileCopy(false)
00116 , m_bOnlyRenames(mode==CopyJob::Move)
00117 , m_dest(dest)
00118 , m_bAutoSkip( false )
00119 , m_bOverwriteAll( false )
00120 , m_conflictError(0)
00121 , m_reportTimer(0)
00122 {
00123 }
00124
00125
00126
00127
00128
00129 KUrl m_globalDest;
00130
00131 DestinationState m_globalDestinationState;
00132
00133 bool m_defaultPermissions;
00134
00135 bool m_bURLDirty;
00136
00137
00138 QLinkedList<CopyInfo> m_directoriesCopied;
00139 QLinkedList<CopyInfo>::const_iterator m_directoriesCopiedIterator;
00140
00141 CopyJob::CopyMode m_mode;
00142 bool m_asMethod;
00143 DestinationState destinationState;
00144 CopyJobState state;
00145 KIO::filesize_t m_totalSize;
00146 KIO::filesize_t m_processedSize;
00147 KIO::filesize_t m_fileProcessedSize;
00148 int m_processedFiles;
00149 int m_processedDirs;
00150 QList<CopyInfo> files;
00151 QList<CopyInfo> dirs;
00152 KUrl::List dirsToRemove;
00153 KUrl::List m_srcList;
00154 KUrl::List::Iterator m_currentStatSrc;
00155 bool m_bCurrentSrcIsDir;
00156 bool m_bCurrentOperationIsLink;
00157 bool m_bSingleFileCopy;
00158 bool m_bOnlyRenames;
00159 KUrl m_dest;
00160 KUrl m_currentDest;
00161
00162 QStringList m_skipList;
00163 QStringList m_overwriteList;
00164 bool m_bAutoSkip;
00165 bool m_bOverwriteAll;
00166 int m_conflictError;
00167
00168 QTimer *m_reportTimer;
00169
00170 KUrl m_currentSrcURL;
00171 KUrl m_currentDestURL;
00172
00173 void statCurrentSrc();
00174 void statNextSrc();
00175
00176
00177 void slotResultStating( KJob * job );
00178 void startListing( const KUrl & src );
00179 void slotResultCreatingDirs( KJob * job );
00180 void slotResultConflictCreatingDirs( KJob * job );
00181 void createNextDir();
00182 void slotResultCopyingFiles( KJob * job );
00183 void slotResultConflictCopyingFiles( KJob * job );
00184
00185 KIO::Job* linkNextFile( const KUrl& uSource, const KUrl& uDest, JobFlags flags );
00186 void copyNextFile();
00187 void slotResultDeletingDirs( KJob * job );
00188 void deleteNextDir();
00189 void skip( const KUrl & sourceURL );
00190 void slotResultRenaming( KJob * job );
00191 void slotResultSettingDirAttributes( KJob * job );
00192 void setNextDirAttribute();
00193
00194 void startRenameJob(const KUrl &slave_url);
00195 bool shouldOverwrite( const QString& path ) const;
00196 bool shouldSkip( const QString& path ) const;
00197 void skipSrc();
00198
00199 void slotStart();
00200 void slotEntries( KIO::Job*, const KIO::UDSEntryList& list );
00204 void slotProcessedSize( KJob*, qulonglong data_size );
00209 void slotTotalSize( KJob*, qulonglong size );
00210
00211 void slotReport();
00212
00213 Q_DECLARE_PUBLIC(CopyJob)
00214
00215 static inline CopyJob *newJob(const KUrl::List& src, const KUrl& dest,
00216 CopyJob::CopyMode mode, bool asMethod, JobFlags flags)
00217 {
00218 CopyJob *job = new CopyJob(*new CopyJobPrivate(src,dest,mode,asMethod));
00219 job->setUiDelegate(new JobUiDelegate);
00220 if (!(flags & HideProgressInfo))
00221 KIO::getJobTracker()->registerJob(job);
00222 return job;
00223 }
00224 };
00225
00226 CopyJob::CopyJob(CopyJobPrivate &dd)
00227 : Job(dd)
00228 {
00229 QTimer::singleShot(0, this, SLOT(slotStart()));
00230 }
00231
00232 CopyJob::~CopyJob()
00233 {
00234 }
00235
00236 KUrl::List CopyJob::srcUrls() const
00237 {
00238 return d_func()->m_srcList;
00239 }
00240
00241 KUrl CopyJob::destUrl() const
00242 {
00243 return d_func()->m_dest;
00244 }
00245
00246 void CopyJobPrivate::slotStart()
00247 {
00248 Q_Q(CopyJob);
00254 m_reportTimer = new QTimer(q);
00255
00256 q->connect(m_reportTimer,SIGNAL(timeout()),q,SLOT(slotReport()));
00257 m_reportTimer->start(REPORT_TIMEOUT);
00258
00259
00260 KIO::Job * job = KIO::stat( m_dest, StatJob::DestinationSide, 2, KIO::HideProgressInfo );
00261
00262 q->addSubjob(job);
00263 }
00264
00265
00266 KIO_EXPORT bool kio_resolve_local_urls = true;
00267
00268 void CopyJobPrivate::slotResultStating( KJob *job )
00269 {
00270 Q_Q(CopyJob);
00271
00272
00273 if (job->error() && destinationState != DEST_NOT_STATED )
00274 {
00275 KUrl srcurl = ((SimpleJob*)job)->url();
00276 if ( !srcurl.isLocalFile() )
00277 {
00278
00279
00280
00281 kDebug(7007) << "Error while stating source. Activating hack";
00282 q->removeSubjob( job );
00283 assert ( !q->hasSubjobs() );
00284 struct CopyInfo info;
00285 info.permissions = (mode_t) -1;
00286 info.mtime = (time_t) -1;
00287 info.ctime = (time_t) -1;
00288 info.size = (KIO::filesize_t)-1;
00289 info.uSource = srcurl;
00290 info.uDest = m_dest;
00291
00292 if ( destinationState == DEST_IS_DIR && !m_asMethod )
00293 info.uDest.addPath( srcurl.fileName() );
00294
00295 files.append( info );
00296 statNextSrc();
00297 return;
00298 }
00299
00300
00301 q->Job::slotResult( job );
00302 return;
00303 }
00304
00305
00306 const UDSEntry entry = static_cast<StatJob*>(job)->statResult();
00307 const QString sLocalPath = entry.stringValue( KIO::UDSEntry::UDS_LOCAL_PATH );
00308 const bool isDir = entry.isDir();
00309
00310 if ( destinationState == DEST_NOT_STATED )
00311
00312 {
00313 if (job->error())
00314 destinationState = DEST_DOESNT_EXIST;
00315 else {
00316
00317 destinationState = isDir ? DEST_IS_DIR : DEST_IS_FILE;
00318
00319 }
00320 const bool isGlobalDest = m_dest == m_globalDest;
00321 if ( isGlobalDest )
00322 m_globalDestinationState = destinationState;
00323
00324 if ( !sLocalPath.isEmpty() && kio_resolve_local_urls ) {
00325 m_dest = KUrl();
00326 m_dest.setPath(sLocalPath);
00327 if ( isGlobalDest )
00328 m_globalDest = m_dest;
00329 }
00330
00331 q->removeSubjob( job );
00332 assert ( !q->hasSubjobs() );
00333
00334
00335 statCurrentSrc();
00336 return;
00337 }
00338
00339
00340 const QString sName = entry.stringValue( KIO::UDSEntry::UDS_NAME );
00341
00342
00343 m_currentDest = m_dest;
00344
00345 UDSEntryList lst;
00346 lst.append(entry);
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360 m_bCurrentSrcIsDir = false;
00361 slotEntries(static_cast<KIO::Job*>( job ), lst);
00362
00363 KUrl srcurl;
00364 if (!sLocalPath.isEmpty())
00365 srcurl.setPath(sLocalPath);
00366 else
00367 srcurl = ((SimpleJob*)job)->url();
00368
00369 q->removeSubjob( job );
00370 assert ( !q->hasSubjobs() );
00371
00372 if ( isDir
00373
00374 && !entry.isLink()
00375 && m_mode != CopyJob::Link )
00376 {
00377
00378
00379 m_bCurrentSrcIsDir = true;
00380 if ( destinationState == DEST_IS_DIR )
00381 {
00382 if ( !m_asMethod )
00383 {
00384
00385 QString directory = srcurl.fileName();
00386 if ( !sName.isEmpty() && KProtocolManager::fileNameUsedForCopying( srcurl ) == KProtocolInfo::Name )
00387 {
00388 directory = sName;
00389 }
00390 m_currentDest.addPath( directory );
00391 }
00392 }
00393 else if ( destinationState == DEST_IS_FILE )
00394 {
00395 q->setError( ERR_IS_FILE );
00396 q->setErrorText( m_dest.prettyUrl() );
00397 q->emitResult();
00398 return;
00399 }
00400 else
00401 {
00402
00403
00404
00405
00406 destinationState = DEST_IS_DIR;
00407 if ( m_dest == m_globalDest )
00408 m_globalDestinationState = destinationState;
00409 }
00410
00411 startListing( srcurl );
00412 }
00413 else
00414 {
00415
00416 statNextSrc();
00417 }
00418 }
00419
00420 bool CopyJob::doSuspend()
00421 {
00422 Q_D(CopyJob);
00423 d->slotReport();
00424 return Job::doSuspend();
00425 }
00426
00427 void CopyJobPrivate::slotReport()
00428 {
00429 Q_Q(CopyJob);
00430 if ( q->isSuspended() )
00431 return;
00432
00433 switch (state) {
00434 case STATE_COPYING_FILES:
00435 q->setProcessedAmount( KJob::Files, m_processedFiles );
00436 if (m_bURLDirty)
00437 {
00438
00439 m_bURLDirty = false;
00440 if (m_mode==CopyJob::Move)
00441 {
00442 emitMoving(q, m_currentSrcURL, m_currentDestURL);
00443 emit q->moving( q, m_currentSrcURL, m_currentDestURL);
00444 }
00445 else if (m_mode==CopyJob::Link)
00446 {
00447 emitCopying( q, m_currentSrcURL, m_currentDestURL );
00448 emit q->linking( q, m_currentSrcURL.path(), m_currentDestURL );
00449 }
00450 else
00451 {
00452 emitCopying( q, m_currentSrcURL, m_currentDestURL );
00453 emit q->copying( q, m_currentSrcURL, m_currentDestURL );
00454 }
00455 }
00456 break;
00457
00458 case STATE_CREATING_DIRS:
00459 q->setProcessedAmount( KJob::Directories, m_processedDirs );
00460 if (m_bURLDirty)
00461 {
00462 m_bURLDirty = false;
00463 emit q->creatingDir( q, m_currentDestURL );
00464 emitCreatingDir( q, m_currentDestURL );
00465 }
00466 break;
00467
00468 case STATE_STATING:
00469 case STATE_LISTING:
00470 if (m_bURLDirty)
00471 {
00472 m_bURLDirty = false;
00473 emitCopying( q, m_currentSrcURL, m_currentDestURL );
00474 }
00475 q->setTotalAmount(KJob::Bytes, m_totalSize);
00476 q->setTotalAmount(KJob::Files, files.count());
00477 q->setTotalAmount(KJob::Directories, dirs.count());
00478 break;
00479
00480 default:
00481 break;
00482 }
00483 }
00484
00485 void CopyJobPrivate::slotEntries(KIO::Job* job, const UDSEntryList& list)
00486 {
00487
00488 UDSEntryList::ConstIterator it = list.begin();
00489 UDSEntryList::ConstIterator end = list.end();
00490 for (; it != end; ++it) {
00491 const UDSEntry& entry = *it;
00492 struct CopyInfo info;
00493 info.permissions = entry.numberValue( KIO::UDSEntry::UDS_ACCESS, -1 );
00494 info.mtime = (time_t) entry.numberValue( KIO::UDSEntry::UDS_MODIFICATION_TIME, -1 );
00495 info.ctime = (time_t) entry.numberValue( KIO::UDSEntry::UDS_CREATION_TIME, -1 );
00496 info.size = (KIO::filesize_t) entry.numberValue( KIO::UDSEntry::UDS_SIZE, -1 );
00497 if ( info.size != (KIO::filesize_t) -1 )
00498 m_totalSize += info.size;
00499
00500
00501 const QString displayName = entry.stringValue( KIO::UDSEntry::UDS_NAME );
00502 const QString urlStr = entry.stringValue( KIO::UDSEntry::UDS_URL );
00503 KUrl url;
00504 if ( !urlStr.isEmpty() )
00505 url = urlStr;
00506 QString localPath = entry.stringValue( KIO::UDSEntry::UDS_LOCAL_PATH );
00507 const bool isDir = entry.isDir();
00508 info.linkDest = entry.stringValue( KIO::UDSEntry::UDS_LINK_DEST );
00509
00510 if (displayName != ".." && displayName != ".")
00511 {
00512 bool hasCustomURL = !url.isEmpty() || !localPath.isEmpty();
00513 if( !hasCustomURL ) {
00514
00515 url = static_cast<SimpleJob *>(job)->url();
00516 if ( m_bCurrentSrcIsDir ) {
00517
00518 url.addPath( displayName );
00519 }
00520 }
00521
00522 if (!localPath.isEmpty() && kio_resolve_local_urls) {
00523 url = KUrl();
00524 url.setPath(localPath);
00525 }
00526
00527 info.uSource = url;
00528 info.uDest = m_currentDest;
00529
00530
00531 if ( destinationState == DEST_IS_DIR &&
00532
00533
00534 ( ! ( m_asMethod && state == STATE_STATING ) ) )
00535 {
00536 QString destFileName;
00537 if ( hasCustomURL &&
00538 KProtocolManager::fileNameUsedForCopying( url ) == KProtocolInfo::FromUrl ) {
00539
00540
00541 int numberOfSlashes = displayName.count( '/' );
00542 QString path = url.path();
00543 int pos = 0;
00544 for ( int n = 0; n < numberOfSlashes + 1; ++n ) {
00545 pos = path.lastIndexOf( '/', pos - 1 );
00546 if ( pos == -1 ) {
00547 kWarning(7007) << "kioslave bug: not enough slashes in UDS_URL " << path << " - looking for " << numberOfSlashes << " slashes";
00548 break;
00549 }
00550 }
00551 if ( pos >= 0 ) {
00552 destFileName = path.mid( pos + 1 );
00553 }
00554
00555 } else {
00556 destFileName = displayName;
00557 }
00558
00559
00560
00561
00562 if ( destFileName.isEmpty() )
00563 destFileName = KIO::encodeFileName( info.uSource.prettyUrl() );
00564
00565
00566 info.uDest.addPath( destFileName );
00567 }
00568
00569
00570 if ( info.linkDest.isEmpty() && isDir && m_mode != CopyJob::Link )
00571 {
00572 dirs.append( info );
00573 if (m_mode == CopyJob::Move)
00574 dirsToRemove.append( info.uSource );
00575 }
00576 else {
00577 files.append( info );
00578 }
00579 }
00580 }
00581 }
00582
00583 void CopyJobPrivate::skipSrc()
00584 {
00585 m_dest = m_globalDest;
00586 destinationState = m_globalDestinationState;
00587 ++m_currentStatSrc;
00588 skip( m_currentSrcURL );
00589 statCurrentSrc();
00590 }
00591
00592 void CopyJobPrivate::statNextSrc()
00593 {
00594
00595
00596
00597
00598 m_dest = m_globalDest;
00599 destinationState = m_globalDestinationState;
00600 ++m_currentStatSrc;
00601 statCurrentSrc();
00602 }
00603
00604 void CopyJobPrivate::statCurrentSrc()
00605 {
00606 Q_Q(CopyJob);
00607 if ( m_currentStatSrc != m_srcList.end() )
00608 {
00609 m_currentSrcURL = (*m_currentStatSrc);
00610 m_bURLDirty = true;
00611 if ( m_mode == CopyJob::Link )
00612 {
00613
00614 m_currentDest = m_dest;
00615 struct CopyInfo info;
00616 info.permissions = -1;
00617 info.mtime = (time_t) -1;
00618 info.ctime = (time_t) -1;
00619 info.size = (KIO::filesize_t)-1;
00620 info.uSource = m_currentSrcURL;
00621 info.uDest = m_currentDest;
00622
00623 if ( destinationState == DEST_IS_DIR && !m_asMethod )
00624 {
00625 if (
00626 (m_currentSrcURL.protocol() == info.uDest.protocol()) &&
00627 (m_currentSrcURL.host() == info.uDest.host()) &&
00628 (m_currentSrcURL.port() == info.uDest.port()) &&
00629 (m_currentSrcURL.user() == info.uDest.user()) &&
00630 (m_currentSrcURL.pass() == info.uDest.pass()) )
00631 {
00632
00633 info.uDest.addPath( m_currentSrcURL.fileName() );
00634 }
00635 else
00636 {
00637
00638
00639
00640 info.uDest.addPath( KIO::encodeFileName( m_currentSrcURL.prettyUrl() )+".desktop" );
00641 }
00642 }
00643 files.append( info );
00644 statNextSrc();
00645 return;
00646 }
00647 else if ( m_mode == CopyJob::Move && (
00648
00649 KProtocolManager::fileNameUsedForCopying( m_currentSrcURL ) == KProtocolInfo::FromUrl ||
00650 destinationState != DEST_IS_DIR || m_asMethod )
00651 )
00652 {
00653
00654
00655 if ( (m_currentSrcURL.protocol() == m_dest.protocol()) &&
00656 (m_currentSrcURL.host() == m_dest.host()) &&
00657 (m_currentSrcURL.port() == m_dest.port()) &&
00658 (m_currentSrcURL.user() == m_dest.user()) &&
00659 (m_currentSrcURL.pass() == m_dest.pass()) )
00660 {
00661 startRenameJob( m_currentSrcURL );
00662 return;
00663 }
00664 else if ( m_currentSrcURL.isLocalFile() && KProtocolManager::canRenameFromFile( m_dest ) )
00665 {
00666 startRenameJob( m_dest );
00667 return;
00668 }
00669 else if ( m_dest.isLocalFile() && KProtocolManager::canRenameToFile( m_currentSrcURL ) )
00670 {
00671 startRenameJob( m_currentSrcURL );
00672 return;
00673 }
00674 }
00675
00676
00677 if (m_mode == CopyJob::Move && !KProtocolManager::supportsDeleting(m_currentSrcURL)) {
00678 QPointer<CopyJob> that = q;
00679 emit q->warning( q, buildErrorString(ERR_CANNOT_DELETE, m_currentSrcURL.prettyUrl()) );
00680 if (that)
00681 statNextSrc();
00682 return;
00683 }
00684
00685
00686 Job * job = KIO::stat( m_currentSrcURL, StatJob::SourceSide, 2, KIO::HideProgressInfo );
00687
00688 state = STATE_STATING;
00689 q->addSubjob(job);
00690 m_currentDestURL=m_dest;
00691 m_bOnlyRenames = false;
00692 m_bURLDirty = true;
00693 }
00694 else
00695 {
00696
00697
00698 state = STATE_STATING;
00699 m_bURLDirty = true;
00700 slotReport();
00701 if (!dirs.isEmpty())
00702 emit q->aboutToCreate( q, dirs );
00703 if (!files.isEmpty())
00704 emit q->aboutToCreate( q, files );
00705
00706 m_bSingleFileCopy = ( files.count() == 1 && dirs.isEmpty() );
00707
00708 state = STATE_CREATING_DIRS;
00709 createNextDir();
00710 }
00711 }
00712
00713 void CopyJobPrivate::startRenameJob( const KUrl& slave_url )
00714 {
00715 Q_Q(CopyJob);
00716 KUrl dest = m_dest;
00717
00718 if ( destinationState == DEST_IS_DIR && !m_asMethod )
00719 dest.addPath( m_currentSrcURL.fileName() );
00720 kDebug(7007) << "This seems to be a suitable case for trying to rename before stat+[list+]copy+del";
00721 state = STATE_RENAMING;
00722
00723 struct CopyInfo info;
00724 info.permissions = -1;
00725 info.mtime = (time_t) -1;
00726 info.ctime = (time_t) -1;
00727 info.size = (KIO::filesize_t)-1;
00728 info.uSource = m_currentSrcURL;
00729 info.uDest = dest;
00730 QList<CopyInfo> files;
00731 files.append(info);
00732 emit q->aboutToCreate( q, files );
00733
00734 KIO_ARGS << m_currentSrcURL << dest << (qint8) false ;
00735 SimpleJob * newJob = SimpleJobPrivate::newJob(slave_url, CMD_RENAME, packedArgs);
00736 newJob->setUiDelegate(new JobUiDelegate());
00737 Scheduler::scheduleJob(newJob);
00738 q->addSubjob( newJob );
00739 if ( m_currentSrcURL.directory() != dest.directory() )
00740 m_bOnlyRenames = false;
00741 }
00742
00743 void CopyJobPrivate::startListing( const KUrl & src )
00744 {
00745 Q_Q(CopyJob);
00746 state = STATE_LISTING;
00747 m_bURLDirty = true;
00748 ListJob * newjob = listRecursive(src, KIO::HideProgressInfo);
00749 newjob->setUiDelegate(new JobUiDelegate());
00750 newjob->setUnrestricted(true);
00751 q->connect(newjob, SIGNAL(entries( KIO::Job *,const KIO::UDSEntryList& )),
00752 SLOT( slotEntries( KIO::Job*, const KIO::UDSEntryList& )));
00753 q->addSubjob( newjob );
00754 }
00755
00756 void CopyJobPrivate::skip( const KUrl & sourceUrl )
00757 {
00758
00759
00760
00761 m_srcList.removeAll( sourceUrl );
00762 dirsToRemove.removeAll( sourceUrl );
00763 }
00764
00765 bool CopyJobPrivate::shouldOverwrite( const QString& path ) const
00766 {
00767 if ( m_bOverwriteAll )
00768 return true;
00769 QStringList::ConstIterator sit = m_overwriteList.begin();
00770 for( ; sit != m_overwriteList.end(); ++sit )
00771 if ( path.startsWith( *sit ) )
00772 return true;
00773 return false;
00774 }
00775
00776 bool CopyJobPrivate::shouldSkip( const QString& path ) const
00777 {
00778 QStringList::ConstIterator sit = m_skipList.begin();
00779 for( ; sit != m_skipList.end(); ++sit )
00780 if ( path.startsWith( *sit ) )
00781 return true;
00782 return false;
00783 }
00784
00785 void CopyJobPrivate::slotResultCreatingDirs( KJob * job )
00786 {
00787 Q_Q(CopyJob);
00788
00789 QList<CopyInfo>::Iterator it = dirs.begin();
00790
00791 if ( job->error() )
00792 {
00793 m_conflictError = job->error();
00794 if ( (m_conflictError == ERR_DIR_ALREADY_EXIST)
00795 || (m_conflictError == ERR_FILE_ALREADY_EXIST) )
00796 {
00797 KUrl oldURL = ((SimpleJob*)job)->url();
00798
00799 if ( m_bAutoSkip ) {
00800
00801 m_skipList.append( oldURL.path( KUrl::AddTrailingSlash ) );
00802 skip( oldURL );
00803 dirs.erase( it );
00804 } else {
00805
00806 const QString destFile = (*it).uDest.path();
00807 if ( shouldOverwrite( destFile ) ) {
00808 emit q->copyingDone( q, (*it).uSource, (*it).uDest, (*it).mtime, true , false );
00809 dirs.erase( it );
00810 } else {
00811 if ( !q->isInteractive() ) {
00812 q->Job::slotResult( job );
00813 return;
00814 }
00815
00816 assert( ((SimpleJob*)job)->url().url() == (*it).uDest.url() );
00817 q->removeSubjob( job );
00818 assert ( !q->hasSubjobs() );
00819
00820
00821 KUrl existingDest( (*it).uDest );
00822 SimpleJob * newJob = KIO::stat( existingDest, StatJob::DestinationSide, 2, KIO::HideProgressInfo );
00823 Scheduler::scheduleJob(newJob);
00824 kDebug(7007) << "KIO::stat for resolving conflict on " << existingDest;
00825 state = STATE_CONFLICT_CREATING_DIRS;
00826 q->addSubjob(newJob);
00827 return;
00828 }
00829 }
00830 }
00831 else
00832 {
00833
00834 q->Job::slotResult( job );
00835 return;
00836 }
00837 }
00838 else
00839 {
00840
00841 emit q->copyingDone( q, (*it).uSource, (*it).uDest, (*it).mtime, true, false );
00842 m_directoriesCopied.append( *it );
00843 dirs.erase( it );
00844 }
00845
00846 m_processedDirs++;
00847
00848 q->removeSubjob( job );
00849 assert( !q->hasSubjobs() );
00850 createNextDir();
00851 }
00852
00853 void CopyJobPrivate::slotResultConflictCreatingDirs( KJob * job )
00854 {
00855 Q_Q(CopyJob);
00856
00857
00858
00859 QList<CopyInfo>::Iterator it = dirs.begin();
00860
00861 const UDSEntry entry = ((KIO::StatJob*)job)->statResult();
00862
00863
00864 const time_t destmtime = (time_t) entry.numberValue( KIO::UDSEntry::UDS_MODIFICATION_TIME, -1 );
00865 const time_t destctime = (time_t) entry.numberValue( KIO::UDSEntry::UDS_CREATION_TIME, -1 );
00866
00867 const KIO::filesize_t destsize = entry.numberValue( KIO::UDSEntry::UDS_SIZE );
00868 const QString linkDest = entry.stringValue( KIO::UDSEntry::UDS_LINK_DEST );
00869
00870 q->removeSubjob( job );
00871 assert ( !q->hasSubjobs() );
00872
00873
00874 RenameDialog_Mode mode = (RenameDialog_Mode)( M_MULTI | M_SKIP );
00875
00876 if ( m_conflictError == ERR_DIR_ALREADY_EXIST )
00877 {
00878 if( (*it).uSource == (*it).uDest ||
00879 ((*it).uSource.protocol() == (*it).uDest.protocol() &&
00880 (*it).uSource.path( KUrl::RemoveTrailingSlash ) == linkDest) )
00881 mode = (RenameDialog_Mode)( mode | M_OVERWRITE_ITSELF);
00882 else
00883 mode = (RenameDialog_Mode)( mode | M_OVERWRITE );
00884 }
00885
00886 QString existingDest = (*it).uDest.path();
00887 QString newPath;
00888 if (m_reportTimer)
00889 m_reportTimer->stop();
00890 RenameDialog_Result r = q->ui()->askFileRename( q, i18n("Folder Already Exists"),
00891 (*it).uSource.url(),
00892 (*it).uDest.url(),
00893 mode, newPath,
00894 (*it).size, destsize,
00895 (*it).ctime, destctime,
00896 (*it).mtime, destmtime );
00897 if (m_reportTimer)
00898 m_reportTimer->start(REPORT_TIMEOUT);
00899 switch ( r ) {
00900 case R_CANCEL:
00901 q->setError( ERR_USER_CANCELED );
00902 q->emitResult();
00903 return;
00904 case R_RENAME:
00905 {
00906 QString oldPath = (*it).uDest.path( KUrl::AddTrailingSlash );
00907 KUrl newUrl( (*it).uDest );
00908 newUrl.setPath( newPath );
00909 emit q->renamed( q, (*it).uDest, newUrl );
00910
00911
00912 (*it).uDest.setPath( newUrl.path( KUrl::RemoveTrailingSlash ) );
00913 newPath = newUrl.path( KUrl::AddTrailingSlash );
00914 QList<CopyInfo>::Iterator renamedirit = it;
00915 ++renamedirit;
00916
00917 for( ; renamedirit != dirs.end() ; ++renamedirit )
00918 {
00919 QString path = (*renamedirit).uDest.path();
00920 if ( path.startsWith( oldPath ) ) {
00921 QString n = path;
00922 n.replace( 0, oldPath.length(), newPath );
00923 kDebug(7007) << "dirs list: " << (*renamedirit).uSource.path()
00924 << " was going to be " << path
00925 << ", changed into " << n << endl;
00926 (*renamedirit).uDest.setPath( n );
00927 }
00928 }
00929
00930 QList<CopyInfo>::Iterator renamefileit = files.begin();
00931 for( ; renamefileit != files.end() ; ++renamefileit )
00932 {
00933 QString path = (*renamefileit).uDest.path();
00934 if ( path.startsWith( oldPath ) ) {
00935 QString n = path;
00936 n.replace( 0, oldPath.length(), newPath );
00937 kDebug(7007) << "files list: " << (*renamefileit).uSource.path()
00938 << " was going to be " << path
00939 << ", changed into " << n << endl;
00940 (*renamefileit).uDest.setPath( n );
00941 }
00942 }
00943 if (!dirs.isEmpty())
00944 emit q->aboutToCreate( q, dirs );
00945 if (!files.isEmpty())
00946 emit q->aboutToCreate( q, files );
00947 }
00948 break;
00949 case R_AUTO_SKIP:
00950 m_bAutoSkip = true;
00951
00952 case R_SKIP:
00953 m_skipList.append( existingDest );
00954 skip( (*it).uSource );
00955
00956 dirs.erase( it );
00957 m_processedDirs++;
00958 break;
00959 case R_OVERWRITE:
00960 m_overwriteList.append( existingDest );
00961 emit q->copyingDone( q, (*it).uSource, (*it).uDest, (*it).mtime, true , false );
00962
00963 dirs.erase( it );
00964 m_processedDirs++;
00965 break;
00966 case R_OVERWRITE_ALL:
00967 m_bOverwriteAll = true;
00968 emit q->copyingDone( q, (*it).uSource, (*it).uDest, (*it).mtime, true , false );
00969
00970 dirs.erase( it );
00971 m_processedDirs++;
00972 break;
00973 default:
00974 assert( 0 );
00975 }
00976 state = STATE_CREATING_DIRS;
00977
00978 createNextDir();
00979 }
00980
00981 void CopyJobPrivate::createNextDir()
00982 {
00983 Q_Q(CopyJob);
00984 KUrl udir;
00985 if ( !