• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.10.5 API Reference
  • KDE Home
  • Contact Us
 

KIO

  • kio
  • kio
copyjob.cpp
Go to the documentation of this file.
1 /* This file is part of the KDE libraries
2  Copyright 2000 Stephan Kulow <coolo@kde.org>
3  Copyright 2000-2006 David Faure <faure@kde.org>
4  Copyright 2000 Waldo Bastian <bastian@kde.org>
5 
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Library General Public
8  License as published by the Free Software Foundation; either
9  version 2 of the License, or (at your option) any later version.
10 
11  This library is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  Library General Public License for more details.
15 
16  You should have received a copy of the GNU Library General Public License
17  along with this library; see the file COPYING.LIB. If not, write to
18  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  Boston, MA 02110-1301, USA.
20 */
21 
22 #include "copyjob.h"
23 #include <errno.h>
24 #include "kdirlister.h"
25 #include "kfileitem.h"
26 #include "deletejob.h"
27 
28 #include <klocale.h>
29 #include <kdesktopfile.h>
30 #include <kdebug.h>
31 #include <kde_file.h>
32 
33 #include "slave.h"
34 #include "scheduler.h"
35 #include "kdirwatch.h"
36 #include "kprotocolmanager.h"
37 
38 #include "jobuidelegate.h"
39 
40 #include <kdirnotify.h>
41 #include <ktemporaryfile.h>
42 
43 #ifdef Q_OS_UNIX
44 #include <utime.h>
45 #endif
46 #include <assert.h>
47 
48 #include <QtCore/QTimer>
49 #include <QtCore/QFile>
50 #include <sys/stat.h> // mode_t
51 #include <QPointer>
52 
53 #include "job_p.h"
54 #include <kdiskfreespaceinfo.h>
55 #include <kfilesystemtype_p.h>
56 
57 using namespace KIO;
58 
59 //this will update the report dialog with 5 Hz, I think this is fast enough, aleXXX
60 #define REPORT_TIMEOUT 200
61 
62 enum DestinationState {
63  DEST_NOT_STATED,
64  DEST_IS_DIR,
65  DEST_IS_FILE,
66  DEST_DOESNT_EXIST
67 };
68 
85 enum CopyJobState {
86  STATE_STATING,
87  STATE_RENAMING,
88  STATE_LISTING,
89  STATE_CREATING_DIRS,
90  STATE_CONFLICT_CREATING_DIRS,
91  STATE_COPYING_FILES,
92  STATE_CONFLICT_COPYING_FILES,
93  STATE_DELETING_DIRS,
94  STATE_SETTING_DIR_ATTRIBUTES
95 };
96 
98 class KIO::CopyJobPrivate: public KIO::JobPrivate
99 {
100 public:
101  CopyJobPrivate(const KUrl::List& src, const KUrl& dest,
102  CopyJob::CopyMode mode, bool asMethod)
103  : m_globalDest(dest)
104  , m_globalDestinationState(DEST_NOT_STATED)
105  , m_defaultPermissions(false)
106  , m_bURLDirty(false)
107  , m_mode(mode)
108  , m_asMethod(asMethod)
109  , destinationState(DEST_NOT_STATED)
110  , state(STATE_STATING)
111  , m_freeSpace(-1)
112  , m_totalSize(0)
113  , m_processedSize(0)
114  , m_fileProcessedSize(0)
115  , m_processedFiles(0)
116  , m_processedDirs(0)
117  , m_srcList(src)
118  , m_currentStatSrc(m_srcList.constBegin())
119  , m_bCurrentOperationIsLink(false)
120  , m_bSingleFileCopy(false)
121  , m_bOnlyRenames(mode==CopyJob::Move)
122  , m_dest(dest)
123  , m_bAutoRenameFiles(false)
124  , m_bAutoRenameDirs(false)
125  , m_bAutoSkipFiles( false )
126  , m_bAutoSkipDirs( false )
127  , m_bOverwriteAllFiles( false )
128  , m_bOverwriteAllDirs( false )
129  , m_conflictError(0)
130  , m_reportTimer(0)
131  {
132  }
133 
134  // This is the dest URL that was initially given to CopyJob
135  // It is copied into m_dest, which can be changed for a given src URL
136  // (when using the RENAME dialog in slotResult),
137  // and which will be reset for the next src URL.
138  KUrl m_globalDest;
139  // The state info about that global dest
140  DestinationState m_globalDestinationState;
141  // See setDefaultPermissions
142  bool m_defaultPermissions;
143  // Whether URLs changed (and need to be emitted by the next slotReport call)
144  bool m_bURLDirty;
145  // Used after copying all the files into the dirs, to set mtime (TODO: and permissions?)
146  // after the copy is done
147  QLinkedList<CopyInfo> m_directoriesCopied;
148  QLinkedList<CopyInfo>::const_iterator m_directoriesCopiedIterator;
149 
150  CopyJob::CopyMode m_mode;
151  bool m_asMethod;
152  DestinationState destinationState;
153  CopyJobState state;
154 
155  KIO::filesize_t m_freeSpace;
156 
157  KIO::filesize_t m_totalSize;
158  KIO::filesize_t m_processedSize;
159  KIO::filesize_t m_fileProcessedSize;
160  int m_processedFiles;
161  int m_processedDirs;
162  QList<CopyInfo> files;
163  QList<CopyInfo> dirs;
164  KUrl::List dirsToRemove;
165  KUrl::List m_srcList;
166  KUrl::List m_successSrcList; // Entries in m_srcList that have successfully been moved
167  KUrl::List::const_iterator m_currentStatSrc;
168  bool m_bCurrentSrcIsDir;
169  bool m_bCurrentOperationIsLink;
170  bool m_bSingleFileCopy;
171  bool m_bOnlyRenames;
172  KUrl m_dest;
173  KUrl m_currentDest; // set during listing, used by slotEntries
174  //
175  QStringList m_skipList;
176  QSet<QString> m_overwriteList;
177  bool m_bAutoRenameFiles;
178  bool m_bAutoRenameDirs;
179  bool m_bAutoSkipFiles;
180  bool m_bAutoSkipDirs;
181  bool m_bOverwriteAllFiles;
182  bool m_bOverwriteAllDirs;
183  int m_conflictError;
184 
185  QTimer *m_reportTimer;
186 
187  // The current src url being stat'ed or copied
188  // During the stat phase, this is initially equal to *m_currentStatSrc but it can be resolved to a local file equivalent (#188903).
189  KUrl m_currentSrcURL;
190  KUrl m_currentDestURL;
191 
192  QSet<QString> m_parentDirs;
193 
194  void statCurrentSrc();
195  void statNextSrc();
196 
197  // Those aren't slots but submethods for slotResult.
198  void slotResultStating( KJob * job );
199  void startListing( const KUrl & src );
200  void slotResultCreatingDirs( KJob * job );
201  void slotResultConflictCreatingDirs( KJob * job );
202  void createNextDir();
203  void slotResultCopyingFiles( KJob * job );
204  void slotResultConflictCopyingFiles( KJob * job );
205 // KIO::Job* linkNextFile( const KUrl& uSource, const KUrl& uDest, bool overwrite );
206  KIO::Job* linkNextFile( const KUrl& uSource, const KUrl& uDest, JobFlags flags );
207  void copyNextFile();
208  void slotResultDeletingDirs( KJob * job );
209  void deleteNextDir();
210  void sourceStated(const UDSEntry& entry, const KUrl& sourceUrl);
211  void skip(const KUrl & sourceURL, bool isDir);
212  void slotResultRenaming( KJob * job );
213  void slotResultSettingDirAttributes( KJob * job );
214  void setNextDirAttribute();
215 
216  void startRenameJob(const KUrl &slave_url);
217  bool shouldOverwriteDir( const QString& path ) const;
218  bool shouldOverwriteFile( const QString& path ) const;
219  bool shouldSkip( const QString& path ) const;
220  void skipSrc(bool isDir);
221 
222  void slotStart();
223  void slotEntries( KIO::Job*, const KIO::UDSEntryList& list );
224  void slotSubError(KIO::ListJob* job, KIO::ListJob *subJob);
225  void addCopyInfoFromUDSEntry(const UDSEntry& entry, const KUrl& srcUrl, bool srcIsDir, const KUrl& currentDest);
229  void slotProcessedSize( KJob*, qulonglong data_size );
234  void slotTotalSize( KJob*, qulonglong size );
235 
236  void slotReport();
237 
238  Q_DECLARE_PUBLIC(CopyJob)
239 
240  static inline CopyJob *newJob(const KUrl::List& src, const KUrl& dest,
241  CopyJob::CopyMode mode, bool asMethod, JobFlags flags)
242  {
243  CopyJob *job = new CopyJob(*new CopyJobPrivate(src,dest,mode,asMethod));
244  job->setUiDelegate(new JobUiDelegate);
245  if (!(flags & HideProgressInfo))
246  KIO::getJobTracker()->registerJob(job);
247  if (flags & KIO::Overwrite) {
248  job->d_func()->m_bOverwriteAllDirs = true;
249  job->d_func()->m_bOverwriteAllFiles = true;
250  }
251  return job;
252  }
253 };
254 
255 CopyJob::CopyJob(CopyJobPrivate &dd)
256  : Job(dd)
257 {
258  setProperty("destUrl", d_func()->m_dest.url());
259  QTimer::singleShot(0, this, SLOT(slotStart()));
260  qRegisterMetaType<KIO::UDSEntry>("KIO::UDSEntry");
261 }
262 
263 CopyJob::~CopyJob()
264 {
265 }
266 
267 KUrl::List CopyJob::srcUrls() const
268 {
269  return d_func()->m_srcList;
270 }
271 
272 KUrl CopyJob::destUrl() const
273 {
274  return d_func()->m_dest;
275 }
276 
277 void CopyJobPrivate::slotStart()
278 {
279  Q_Q(CopyJob);
285  m_reportTimer = new QTimer(q);
286 
287  q->connect(m_reportTimer,SIGNAL(timeout()),q,SLOT(slotReport()));
288  m_reportTimer->start(REPORT_TIMEOUT);
289 
290  // Stat the dest
291  KIO::Job * job = KIO::stat( m_dest, StatJob::DestinationSide, 2, KIO::HideProgressInfo );
292  //kDebug(7007) << "CopyJob:stating the dest " << m_dest;
293  q->addSubjob(job);
294 }
295 
296 // For unit test purposes
297 KIO_EXPORT bool kio_resolve_local_urls = true;
298 
299 void CopyJobPrivate::slotResultStating( KJob *job )
300 {
301  Q_Q(CopyJob);
302  //kDebug(7007);
303  // Was there an error while stating the src ?
304  if (job->error() && destinationState != DEST_NOT_STATED )
305  {
306  const KUrl srcurl = static_cast<SimpleJob*>(job)->url();
307  if ( !srcurl.isLocalFile() )
308  {
309  // Probably : src doesn't exist. Well, over some protocols (e.g. FTP)
310  // this info isn't really reliable (thanks to MS FTP servers).
311  // We'll assume a file, and try to download anyway.
312  kDebug(7007) << "Error while stating source. Activating hack";
313  q->removeSubjob( job );
314  assert ( !q->hasSubjobs() ); // We should have only one job at a time ...
315  struct CopyInfo info;
316  info.permissions = (mode_t) -1;
317  info.mtime = (time_t) -1;
318  info.ctime = (time_t) -1;
319  info.size = (KIO::filesize_t)-1;
320  info.uSource = srcurl;
321  info.uDest = m_dest;
322  // Append filename or dirname to destination URL, if allowed
323  if ( destinationState == DEST_IS_DIR && !m_asMethod )
324  info.uDest.addPath( srcurl.fileName() );
325 
326  files.append( info );
327  statNextSrc();
328  return;
329  }
330  // Local file. If stat fails, the file definitely doesn't exist.
331  // yes, q->Job::, because we don't want to call our override
332  q->Job::slotResult( job ); // will set the error and emit result(this)
333  return;
334  }
335 
336  // Keep copy of the stat result
337  const UDSEntry entry = static_cast<StatJob*>(job)->statResult();
338 
339  if ( destinationState == DEST_NOT_STATED ) {
340  if ( m_dest.isLocalFile() ) { //works for dirs as well
341  QString path = m_dest.toLocalFile();
342  if (m_asMethod) {
343  // In copy-as mode, we want to check the directory to which we're
344  // copying. The target file or directory does not exist yet, which
345  // might confuse KDiskFreeSpaceInfo.
346  path = QFileInfo(path).absolutePath();
347  }
348  KFileSystemType::Type fsType = KFileSystemType::fileSystemType( path );
349  if ( fsType != KFileSystemType::Nfs && fsType != KFileSystemType::Smb ) {
350  m_freeSpace = KDiskFreeSpaceInfo::freeSpaceInfo( path ).available();
351  }
352  //TODO actually preliminary check is even more valuable for slow NFS/SMB mounts,
353  //but we need to find a way to report connection errors to user
354  }
355 
356  const bool isGlobalDest = m_dest == m_globalDest;
357  const bool isDir = entry.isDir();
358  // we were stating the dest
359  if (job->error()) {
360  destinationState = DEST_DOESNT_EXIST;
361  //kDebug(7007) << "dest does not exist";
362  } else {
363  // Treat symlinks to dirs as dirs here, so no test on isLink
364  destinationState = isDir ? DEST_IS_DIR : DEST_IS_FILE;
365  //kDebug(7007) << "dest is dir:" << isDir;
366 
367  const QString sLocalPath = entry.stringValue( KIO::UDSEntry::UDS_LOCAL_PATH );
368  if ( !sLocalPath.isEmpty() && kio_resolve_local_urls && destinationState != DEST_DOESNT_EXIST ) {
369  m_dest = KUrl();
370  m_dest.setPath(sLocalPath);
371  if ( isGlobalDest )
372  m_globalDest = m_dest;
373  }
374  }
375  if ( isGlobalDest )
376  m_globalDestinationState = destinationState;
377 
378  q->removeSubjob( job );
379  assert ( !q->hasSubjobs() );
380 
381  // After knowing what the dest is, we can start stat'ing the first src.
382  statCurrentSrc();
383  } else {
384  sourceStated(entry, static_cast<SimpleJob*>(job)->url());
385  q->removeSubjob( job );
386  }
387 }
388 
389 void CopyJobPrivate::sourceStated(const UDSEntry& entry, const KUrl& sourceUrl)
390 {
391  const QString sLocalPath = entry.stringValue( KIO::UDSEntry::UDS_LOCAL_PATH );
392  const bool isDir = entry.isDir();
393 
394  // We were stating the current source URL
395  // Is it a file or a dir ?
396 
397  // There 6 cases, and all end up calling addCopyInfoFromUDSEntry first :
398  // 1 - src is a dir, destination is a directory,
399  // slotEntries will append the source-dir-name to the destination
400  // 2 - src is a dir, destination is a file -- will offer to overwrite, later on.
401  // 3 - src is a dir, destination doesn't exist, then it's the destination dirname,
402  // so slotEntries will use it as destination.
403 
404  // 4 - src is a file, destination is a directory,
405  // slotEntries will append the filename to the destination.
406  // 5 - src is a file, destination is a file, m_dest is the exact destination name
407  // 6 - src is a file, destination doesn't exist, m_dest is the exact destination name
408 
409  KUrl srcurl;
410  if (!sLocalPath.isEmpty() && destinationState != DEST_DOESNT_EXIST) {
411  kDebug() << "Using sLocalPath. destinationState=" << destinationState;
412  // Prefer the local path -- but only if we were able to stat() the dest.
413  // Otherwise, renaming a desktop:/ url would copy from src=file to dest=desktop (#218719)
414  srcurl.setPath(sLocalPath);
415  } else {
416  srcurl = sourceUrl;
417  }
418  addCopyInfoFromUDSEntry(entry, srcurl, false, m_dest);
419 
420  m_currentDest = m_dest;
421  m_bCurrentSrcIsDir = false;
422 
423  if ( isDir
424  // treat symlinks as files (no recursion)
425  && !entry.isLink()
426  && m_mode != CopyJob::Link ) // No recursion in Link mode either.
427  {
428  //kDebug(7007) << "Source is a directory";
429 
430  if (srcurl.isLocalFile()) {
431  const QString parentDir = srcurl.toLocalFile(KUrl::RemoveTrailingSlash);
432  m_parentDirs.insert(parentDir);
433  }
434 
435  m_bCurrentSrcIsDir = true; // used by slotEntries
436  if ( destinationState == DEST_IS_DIR ) // (case 1)
437  {
438  if ( !m_asMethod )
439  {
440  // Use <desturl>/<directory_copied> as destination, from now on
441  QString directory = srcurl.fileName();
442  const QString sName = entry.stringValue( KIO::UDSEntry::UDS_NAME );
443  KProtocolInfo::FileNameUsedForCopying fnu = KProtocolManager::fileNameUsedForCopying(srcurl);
444  if (fnu == KProtocolInfo::Name) {
445  if (!sName.isEmpty())
446  directory = sName;
447  } else if (fnu == KProtocolInfo::DisplayName) {
448  const QString dispName = entry.stringValue( KIO::UDSEntry::UDS_DISPLAY_NAME );
449  if (!dispName.isEmpty())
450  directory = dispName;
451  else if (!sName.isEmpty())
452  directory = sName;
453  }
454  m_currentDest.addPath( directory );
455  }
456  }
457  else // (case 3)
458  {
459  // otherwise dest is new name for toplevel dir
460  // so the destination exists, in fact, from now on.
461  // (This even works with other src urls in the list, since the
462  // dir has effectively been created)
463  destinationState = DEST_IS_DIR;
464  if ( m_dest == m_globalDest )
465  m_globalDestinationState = destinationState;
466  }
467 
468  startListing( srcurl );
469  }
470  else
471  {
472  //kDebug(7007) << "Source is a file (or a symlink), or we are linking -> no recursive listing";
473 
474  if (srcurl.isLocalFile()) {
475  const QString parentDir = srcurl.directory(KUrl::ObeyTrailingSlash);
476  m_parentDirs.insert(parentDir);
477  }
478 
479  statNextSrc();
480  }
481 }
482 
483 bool CopyJob::doSuspend()
484 {
485  Q_D(CopyJob);
486  d->slotReport();
487  return Job::doSuspend();
488 }
489 
490 void CopyJobPrivate::slotReport()
491 {
492  Q_Q(CopyJob);
493  if ( q->isSuspended() )
494  return;
495  // If showProgressInfo was set, progressId() is > 0.
496  switch (state) {
497  case STATE_RENAMING:
498  q->setTotalAmount(KJob::Files, m_srcList.count());
499  // fall-through intended
500  case STATE_COPYING_FILES:
501  q->setProcessedAmount( KJob::Files, m_processedFiles );
502  if (m_bURLDirty)
503  {
504  // Only emit urls when they changed. This saves time, and fixes #66281
505  m_bURLDirty = false;
506  if (m_mode==CopyJob::Move)
507  {
508  emitMoving(q, m_currentSrcURL, m_currentDestURL);
509  emit q->moving( q, m_currentSrcURL, m_currentDestURL);
510  }
511  else if (m_mode==CopyJob::Link)
512  {
513  emitCopying( q, m_currentSrcURL, m_currentDestURL ); // we don't have a delegate->linking
514  emit q->linking( q, m_currentSrcURL.path(), m_currentDestURL );
515  }
516  else
517  {
518  emitCopying( q, m_currentSrcURL, m_currentDestURL );
519  emit q->copying( q, m_currentSrcURL, m_currentDestURL );
520  }
521  }
522  break;
523 
524  case STATE_CREATING_DIRS:
525  q->setProcessedAmount( KJob::Directories, m_processedDirs );
526  if (m_bURLDirty)
527  {
528  m_bURLDirty = false;
529  emit q->creatingDir( q, m_currentDestURL );
530  emitCreatingDir( q, m_currentDestURL );
531  }
532  break;
533 
534  case STATE_STATING:
535  case STATE_LISTING:
536  if (m_bURLDirty)
537  {
538  m_bURLDirty = false;
539  if (m_mode==CopyJob::Move)
540  {
541  emitMoving( q, m_currentSrcURL, m_currentDestURL );
542  }
543  else
544  {
545  emitCopying( q, m_currentSrcURL, m_currentDestURL );
546  }
547  }
548  q->setTotalAmount(KJob::Bytes, m_totalSize);
549  q->setTotalAmount(KJob::Files, files.count());
550  q->setTotalAmount(KJob::Directories, dirs.count());
551  break;
552 
553  default:
554  break;
555  }
556 }
557 
558 void CopyJobPrivate::slotEntries(KIO::Job* job, const UDSEntryList& list)
559 {
560  //Q_Q(CopyJob);
561  UDSEntryList::ConstIterator it = list.constBegin();
562  UDSEntryList::ConstIterator end = list.constEnd();
563  for (; it != end; ++it) {
564  const UDSEntry& entry = *it;
565  addCopyInfoFromUDSEntry(entry, static_cast<SimpleJob *>(job)->url(), m_bCurrentSrcIsDir, m_currentDest);
566  }
567 }
568 
569 void CopyJobPrivate::slotSubError(ListJob* job, ListJob* subJob)
570 {
571  const KUrl url = subJob->url();
572  kWarning() << url << subJob->errorString();
573 
574  Q_Q(CopyJob);
575 
576  emit q->warning(job, subJob->errorString(), QString());
577  skip(url, true);
578 }
579 
580 
581 void CopyJobPrivate::addCopyInfoFromUDSEntry(const UDSEntry& entry, const KUrl& srcUrl, bool srcIsDir, const KUrl& currentDest)
582 {
583  struct CopyInfo info;
584  info.permissions = entry.numberValue(KIO::UDSEntry::UDS_ACCESS, -1);
585  info.mtime = (time_t) entry.numberValue(KIO::UDSEntry::UDS_MODIFICATION_TIME, -1);
586  info.ctime = (time_t) entry.numberValue(KIO::UDSEntry::UDS_CREATION_TIME, -1);
587  info.size = (KIO::filesize_t) entry.numberValue(KIO::UDSEntry::UDS_SIZE, -1);
588  if (info.size != (KIO::filesize_t) -1)
589  m_totalSize += info.size;
590 
591  // recursive listing, displayName can be a/b/c/d
592  const QString fileName = entry.stringValue(KIO::UDSEntry::UDS_NAME);
593  const QString urlStr = entry.stringValue(KIO::UDSEntry::UDS_URL);
594  KUrl url;
595  if (!urlStr.isEmpty())
596  url = urlStr;
597  QString localPath = entry.stringValue(KIO::UDSEntry::UDS_LOCAL_PATH);
598  const bool isDir = entry.isDir();
599  info.linkDest = entry.stringValue(KIO::UDSEntry::UDS_LINK_DEST);
600 
601  if (fileName != QLatin1String("..") && fileName != QLatin1String(".")) {
602  const bool hasCustomURL = !url.isEmpty() || !localPath.isEmpty();
603  if (!hasCustomURL) {
604  // Make URL from displayName
605  url = srcUrl;
606  if (srcIsDir) { // Only if src is a directory. Otherwise uSource is fine as is
607  //kDebug(7007) << "adding path" << displayName;
608  url.addPath(fileName);
609  }
610  }
611  //kDebug(7007) << "displayName=" << displayName << "url=" << url;
612  if (!localPath.isEmpty() && kio_resolve_local_urls && destinationState != DEST_DOESNT_EXIST) {
613  url = KUrl(localPath);
614  }
615 
616  info.uSource = url;
617  info.uDest = currentDest;
618  //kDebug(7007) << "uSource=" << info.uSource << "uDest(1)=" << info.uDest;
619  // Append filename or dirname to destination URL, if allowed
620  if (destinationState == DEST_IS_DIR &&
621  // "copy/move as <foo>" means 'foo' is the dest for the base srcurl
622  // (passed here during stating) but not its children (during listing)
623  (! (m_asMethod && state == STATE_STATING)))
624  {
625  QString destFileName;
626  KProtocolInfo::FileNameUsedForCopying fnu = KProtocolManager::fileNameUsedForCopying(url);
627  if (hasCustomURL &&
628  fnu == KProtocolInfo::FromUrl) {
629  //destFileName = url.fileName(); // Doesn't work for recursive listing
630  // Count the number of prefixes used by the recursive listjob
631  int numberOfSlashes = fileName.count('/'); // don't make this a find()!
632  QString path = url.path();
633  int pos = 0;
634  for (int n = 0; n < numberOfSlashes + 1; ++n) {
635  pos = path.lastIndexOf('/', pos - 1);
636  if (pos == -1) { // error
637  kWarning(7007) << "kioslave bug: not enough slashes in UDS_URL" << path << "- looking for" << numberOfSlashes << "slashes";
638  break;
639  }
640  }
641  if (pos >= 0) {
642  destFileName = path.mid(pos + 1);
643  }
644 
645  } else if ( fnu == KProtocolInfo::Name ) { // destination filename taken from UDS_NAME
646  destFileName = fileName;
647  } else { // from display name (with fallback to name)
648  const QString displayName = entry.stringValue(KIO::UDSEntry::UDS_DISPLAY_NAME);
649  destFileName = displayName.isEmpty() ? fileName : displayName;
650  }
651 
652  // Here we _really_ have to add some filename to the dest.
653  // Otherwise, we end up with e.g. dest=..../Desktop/ itself.
654  // (This can happen when dropping a link to a webpage with no path)
655  if (destFileName.isEmpty()) {
656  destFileName = KIO::encodeFileName(info.uSource.prettyUrl());
657  }
658 
659  //kDebug(7007) << " adding destFileName=" << destFileName;
660  info.uDest.addPath(destFileName);
661  }
662  //kDebug(7007) << " uDest(2)=" << info.uDest;
663  //kDebug(7007) << " " << info.uSource << "->" << info.uDest;
664  if (info.linkDest.isEmpty() && isDir && m_mode != CopyJob::Link) { // Dir
665  dirs.append(info); // Directories
666  if (m_mode == CopyJob::Move) {
667  dirsToRemove.append(info.uSource);
668  }
669  } else {
670  files.append(info); // Files and any symlinks
671  }
672  }
673 }
674 
675 void CopyJobPrivate::skipSrc(bool isDir)
676 {
677  m_dest = m_globalDest;
678  destinationState = m_globalDestinationState;
679  skip(*m_currentStatSrc, isDir);
680  ++m_currentStatSrc;
681  statCurrentSrc();
682 }
683 
684 void CopyJobPrivate::statNextSrc()
685 {
686  /* Revert to the global destination, the one that applies to all source urls.
687  * Imagine you copy the items a b and c into /d, but /d/b exists so the user uses "Rename" to put it in /foo/b instead.
688  * d->m_dest is /foo/b for b, but we have to revert to /d for item c and following.
689  */
690  m_dest = m_globalDest;
691  destinationState = m_globalDestinationState;
692  ++m_currentStatSrc;
693  statCurrentSrc();
694 }
695 
696 void CopyJobPrivate::statCurrentSrc()
697 {
698  Q_Q(CopyJob);
699  if (m_currentStatSrc != m_srcList.constEnd()) {
700  m_currentSrcURL = (*m_currentStatSrc);
701  m_bURLDirty = true;
702  if (m_mode == CopyJob::Link) {
703  // Skip the "stating the source" stage, we don't need it for linking
704  m_currentDest = m_dest;
705  struct CopyInfo info;
706  info.permissions = -1;
707  info.mtime = (time_t) -1;
708  info.ctime = (time_t) -1;
709  info.size = (KIO::filesize_t)-1;
710  info.uSource = m_currentSrcURL;
711  info.uDest = m_currentDest;
712  // Append filename or dirname to destination URL, if allowed
713  if (destinationState == DEST_IS_DIR && !m_asMethod) {
714  if (
715  (m_currentSrcURL.protocol() == info.uDest.protocol()) &&
716  (m_currentSrcURL.host() == info.uDest.host()) &&
717  (m_currentSrcURL.port() == info.uDest.port()) &&
718  (m_currentSrcURL.user() == info.uDest.user()) &&
719  (m_currentSrcURL.pass() == info.uDest.pass()) ) {
720  // This is the case of creating a real symlink
721  info.uDest.addPath( m_currentSrcURL.fileName() );
722  } else {
723  // Different protocols, we'll create a .desktop file
724  // We have to change the extension anyway, so while we're at it,
725  // name the file like the URL
726  info.uDest.addPath(KIO::encodeFileName(m_currentSrcURL.prettyUrl()) + ".desktop");
727  }
728  }
729  files.append( info ); // Files and any symlinks
730  statNextSrc(); // we could use a loop instead of a recursive call :)
731  return;
732  }
733 
734  // Let's see if we can skip stat'ing, for the case where a directory view has the info already
735  const KFileItem cachedItem = KDirLister::cachedItemForUrl(m_currentSrcURL);
736  KIO::UDSEntry entry;
737  if (!cachedItem.isNull()) {
738  entry = cachedItem.entry();
739  if (destinationState != DEST_DOESNT_EXIST) { // only resolve src if we could resolve dest (#218719)
740  bool dummyIsLocal;
741  m_currentSrcURL = cachedItem.mostLocalUrl(dummyIsLocal); // #183585
742  }
743  }
744 
745  if (m_mode == CopyJob::Move && (
746  // Don't go renaming right away if we need a stat() to find out the destination filename
747  KProtocolManager::fileNameUsedForCopying(m_currentSrcURL) == KProtocolInfo::FromUrl ||
748  destinationState != DEST_IS_DIR || m_asMethod)
749  ) {
750  // If moving, before going for the full stat+[list+]copy+del thing, try to rename
751  // The logic is pretty similar to FileCopyJobPrivate::slotStart()
752  if ( (m_currentSrcURL.protocol() == m_dest.protocol()) &&
753  (m_currentSrcURL.host() == m_dest.host()) &&
754  (m_currentSrcURL.port() == m_dest.port()) &&
755  (m_currentSrcURL.user() == m_dest.user()) &&
756  (m_currentSrcURL.pass() == m_dest.pass()) )
757  {
758  startRenameJob( m_currentSrcURL );
759  return;
760  }
761  else if ( m_currentSrcURL.isLocalFile() && KProtocolManager::canRenameFromFile( m_dest ) )
762  {
763  startRenameJob( m_dest );
764  return;
765  }
766  else if ( m_dest.isLocalFile() && KProtocolManager::canRenameToFile( m_currentSrcURL ) )
767  {
768  startRenameJob( m_currentSrcURL );
769  return;
770  }
771  }
772 
773  // if the file system doesn't support deleting, we do not even stat
774  if (m_mode == CopyJob::Move && !KProtocolManager::supportsDeleting(m_currentSrcURL)) {
775  QPointer<CopyJob> that = q;
776  emit q->warning( q, buildErrorString(ERR_CANNOT_DELETE, m_currentSrcURL.prettyUrl()) );
777  if (that)
778  statNextSrc(); // we could use a loop instead of a recursive call :)
779  return;
780  }
781 
782  m_bOnlyRenames = false;
783 
784  // Testing for entry.count()>0 here is not good enough; KFileItem inserts
785  // entries for UDS_USER and UDS_GROUP even on initially empty UDSEntries (#192185)
786  if (entry.contains(KIO::UDSEntry::UDS_NAME)) {
787  kDebug(7007) << "fast path! found info about" << m_currentSrcURL << "in KDirLister";
788  // sourceStated(entry, m_currentSrcURL); // don't recurse, see #319747, use queued invokeMethod instead
789  QMetaObject::invokeMethod(q, "sourceStated", Qt::QueuedConnection, Q_ARG(KIO::UDSEntry, entry), Q_ARG(KUrl, m_currentSrcURL));
790  return;
791  }
792 
793  // Stat the next src url
794  Job * job = KIO::stat( m_currentSrcURL, StatJob::SourceSide, 2, KIO::HideProgressInfo );
795  //kDebug(7007) << "KIO::stat on" << m_currentSrcURL;
796  state = STATE_STATING;
797  q->addSubjob(job);
798  m_currentDestURL = m_dest;
799  m_bURLDirty = true;
800  }
801  else
802  {
803  // Finished the stat'ing phase
804  // First make sure that the totals were correctly emitted
805  state = STATE_STATING;
806  m_bURLDirty = true;
807  slotReport();
808 
809  kDebug(7007)<<"Stating finished. To copy:"<<m_totalSize<<", available:"<<m_freeSpace;
810  //TODO warn user beforehand if space is not enough
811 
812  if (!dirs.isEmpty())
813  emit q->aboutToCreate( q, dirs );
814  if (!files.isEmpty())
815  emit q->aboutToCreate( q, files );
816  // Check if we are copying a single file
817  m_bSingleFileCopy = ( files.count() == 1 && dirs.isEmpty() );
818  // Then start copying things
819  state = STATE_CREATING_DIRS;
820  createNextDir();
821  }
822 }
823 
824 void CopyJobPrivate::startRenameJob( const KUrl& slave_url )
825 {
826  Q_Q(CopyJob);
827 
828  // Silence KDirWatch notifications, otherwise performance is horrible
829  if (m_currentSrcURL.isLocalFile()) {
830  const QString parentDir = m_currentSrcURL.directory(KUrl::ObeyTrailingSlash);
831  if (!m_parentDirs.contains(parentDir)) {
832  KDirWatch::self()->stopDirScan(parentDir);
833  m_parentDirs.insert(parentDir);
834  }
835  }
836 
837  KUrl dest = m_dest;
838  // Append filename or dirname to destination URL, if allowed
839  if ( destinationState == DEST_IS_DIR && !m_asMethod )
840  dest.addPath( m_currentSrcURL.fileName() );
841  m_currentDestURL = dest;
842  kDebug(7007) << m_currentSrcURL << "->" << dest << "trying direct rename first";
843  state = STATE_RENAMING;
844 
845  struct CopyInfo info;
846  info.permissions = -1;
847  info.mtime = (time_t) -1;
848  info.ctime = (time_t) -1;
849  info.size = (KIO::filesize_t)-1;
850  info.uSource = m_currentSrcURL;
851  info.uDest = dest;
852  QList<CopyInfo> files;
853  files.append(info);
854  emit q->aboutToCreate( q, files );
855 
856  KIO_ARGS << m_currentSrcURL << dest << (qint8) false /*no overwrite*/;
857  SimpleJob * newJob = SimpleJobPrivate::newJobNoUi(slave_url, CMD_RENAME, packedArgs);
858  Scheduler::setJobPriority(newJob, 1);
859  q->addSubjob( newJob );
860  if ( m_currentSrcURL.directory() != dest.directory() ) // For the user, moving isn't renaming. Only renaming is.
861  m_bOnlyRenames = false;
862 }
863 
864 void CopyJobPrivate::startListing( const KUrl & src )
865 {
866  Q_Q(CopyJob);
867  state = STATE_LISTING;
868  m_bURLDirty = true;
869  ListJob * newjob = listRecursive(src, KIO::HideProgressInfo);
870  newjob->setUnrestricted(true);
871  q->connect(newjob, SIGNAL(entries(KIO::Job*,KIO::UDSEntryList)),
872  SLOT(slotEntries(KIO::Job*,KIO::UDSEntryList)));
873  q->connect(newjob, SIGNAL(subError(KIO::ListJob*,KIO::ListJob*)),
874  SLOT(slotSubError(KIO::ListJob*,KIO::ListJob*)));
875  q->addSubjob( newjob );
876 }
877 
878 void CopyJobPrivate::skip(const KUrl & sourceUrl, bool isDir)
879 {
880  KUrl dir = sourceUrl;
881  if (!isDir) {
882  // Skipping a file: make sure not to delete the parent dir (#208418)
883  dir.setPath(dir.directory());
884  }
885  while (dirsToRemove.removeAll(dir) > 0) {
886  // Do not rely on rmdir() on the parent directories aborting.
887  // Exclude the parent dirs explicitly.
888  dir.setPath(dir.directory());
889  }
890 }
891 
892 bool CopyJobPrivate::shouldOverwriteDir( const QString& path ) const
893 {
894  if ( m_bOverwriteAllDirs )
895  return true;
896  return m_overwriteList.contains(path);
897 }
898 
899 bool CopyJobPrivate::shouldOverwriteFile( const QString& path ) const
900 {
901  if ( m_bOverwriteAllFiles )
902  return true;
903  return m_overwriteList.contains(path);
904 }
905 
906 bool CopyJobPrivate::shouldSkip( const QString& path ) const
907 {
908  Q_FOREACH(const QString& skipPath, m_skipList) {
909  if ( path.startsWith(skipPath) )
910  return true;
911  }
912  return false;
913 }
914 
915 void CopyJobPrivate::slotResultCreatingDirs( KJob * job )
916 {
917  Q_Q(CopyJob);
918  // The dir we are trying to create:
919  QList<CopyInfo>::Iterator it = dirs.begin();
920  // Was there an error creating a dir ?
921  if ( job->error() )
922  {
923  m_conflictError = job->error();
924  if ( (m_conflictError == ERR_DIR_ALREADY_EXIST)
925  || (m_conflictError == ERR_FILE_ALREADY_EXIST) ) // can't happen?
926  {
927  KUrl oldURL = ((SimpleJob*)job)->url();
928  // Should we skip automatically ?
929  if ( m_bAutoSkipDirs ) {
930  // We don't want to copy files in this directory, so we put it on the skip list
931  m_skipList.append( oldURL.path( KUrl::AddTrailingSlash ) );
932  skip(oldURL, true);
933  dirs.erase( it ); // Move on to next dir
934  } else {
935  // Did the user choose to overwrite already?
936  const QString destDir = (*it).uDest.path();
937  if ( shouldOverwriteDir( destDir ) ) { // overwrite => just skip
938  emit q->copyingDone( q, (*it).uSource, (*it).uDest, (*it).mtime, true /* directory */, false /* renamed */ );
939  dirs.erase( it ); // Move on to next dir
940  } else {
941  if (m_bAutoRenameDirs) {
942  QString oldPath = (*it).uDest.path(KUrl::AddTrailingSlash);
943 
944  KUrl destDirectory((*it).uDest);
945  destDirectory.setPath(destDirectory.directory());
946  QString newName = KIO::RenameDialog::suggestName(destDirectory, (*it).uDest.fileName());
947 
948  KUrl newUrl((*it).uDest);
949  newUrl.setFileName(newName);
950 
951  emit q->renamed(q, (*it).uDest, newUrl); // for e.g. kpropsdlg
952 
953  // Change the current one and strip the trailing '/'
954  (*it).uDest.setPath(newUrl.path(KUrl::RemoveTrailingSlash));
955 
956  QString newPath = newUrl.path(KUrl::AddTrailingSlash); // With trailing slash
957  QList<CopyInfo>::Iterator renamedirit = it;
958  ++renamedirit;
959  // Change the name of subdirectories inside the directory
960  for(; renamedirit != dirs.end() ; ++renamedirit) {
961  QString path = (*renamedirit).uDest.path();
962  if (path.startsWith(oldPath)) {
963  QString n = path;
964  n.replace(0, oldPath.length(), newPath);
965  kDebug(7007) << "dirs list:" << (*renamedirit).uSource.path()
966  << "was going to be" << path
967  << ", changed into" << n;
968  (*renamedirit).uDest.setPath(n);
969  }
970  }
971  // Change filenames inside the directory
972  QList<CopyInfo>::Iterator renamefileit = files.begin();
973  for(; renamefileit != files.end() ; ++renamefileit) {
974  QString path = (*renamefileit).uDest.path();
975  if (path.startsWith(oldPath)) {
976  QString n = path;
977  n.replace(0, oldPath.length(), newPath);
978  kDebug(7007) << "files list:" << (*renamefileit).uSource.path()
979  << "was going to be" << path
980  << ", changed into" << n;
981  (*renamefileit).uDest.setPath(n);
982  }
983  }
984  if (!dirs.isEmpty()) {
985  emit q->aboutToCreate(q, dirs);
986  }
987  if (!files.isEmpty()) {
988  emit q->aboutToCreate(q, files);
989  }
990 
991  }
992  else {
993  if (!q->isInteractive()) {
994  q->Job::slotResult(job); // will set the error and emit result(this)
995  return;
996  }
997 
998  assert(((SimpleJob*)job)->url().url() == (*it).uDest.url());
999  q->removeSubjob(job);
1000  assert (!q->hasSubjobs()); // We should have only one job at a time ...
1001 
1002  // We need to stat the existing dir, to get its last-modification time
1003  KUrl existingDest((*it).uDest);
1004  SimpleJob * newJob = KIO::stat(existingDest, StatJob::DestinationSide, 2, KIO::HideProgressInfo);
1005  Scheduler::setJobPriority(newJob, 1);
1006  kDebug(7007) << "KIO::stat for resolving conflict on " << existingDest;
1007  state = STATE_CONFLICT_CREATING_DIRS;
1008  q->addSubjob(newJob);
1009  return; // Don't move to next dir yet !
1010  }
1011  }
1012  }
1013  }
1014  else
1015  {
1016  // Severe error, abort
1017  q->Job::slotResult( job ); // will set the error and emit result(this)
1018  return;
1019  }
1020  }
1021  else // no error : remove from list, to move on to next dir
1022  {
1023  //this is required for the undo feature
1024  emit q->copyingDone( q, (*it).uSource, (*it).uDest, (*it).mtime, true, false );
1025  m_directoriesCopied.append( *it );
1026  dirs.erase( it );
1027  }
1028 
1029  m_processedDirs++;
1030  //emit processedAmount( this, KJob::Directories, m_processedDirs );
1031  q->removeSubjob( job );
1032  assert( !q->hasSubjobs() ); // We should have only one job at a time ...
1033  createNextDir();
1034 }
1035 
1036 void CopyJobPrivate::slotResultConflictCreatingDirs( KJob * job )
1037 {
1038  Q_Q(CopyJob);
1039  // We come here after a conflict has been detected and we've stated the existing dir
1040 
1041  // The dir we were trying to create:
1042  QList<CopyInfo>::Iterator it = dirs.begin();
1043 
1044  const UDSEntry entry = ((KIO::StatJob*)job)->statResult();
1045 
1046  // Its modification time:
1047  const time_t destmtime = (time_t) entry.numberValue( KIO::UDSEntry::UDS_MODIFICATION_TIME, -1 );
1048  const time_t destctime = (time_t) entry.numberValue( KIO::UDSEntry::UDS_CREATION_TIME, -1 );
1049 
1050  const KIO::filesize_t destsize = entry.numberValue( KIO::UDSEntry::UDS_SIZE );
1051  const QString linkDest = entry.stringValue( KIO::UDSEntry::UDS_LINK_DEST );
1052 
1053  q->removeSubjob( job );
1054  assert ( !q->hasSubjobs() ); // We should have only one job at a time ...
1055 
1056  // Always multi and skip (since there are files after that)
1057  RenameDialog_Mode mode = (RenameDialog_Mode)( M_MULTI | M_SKIP | M_ISDIR );
1058  // Overwrite only if the existing thing is a dir (no chance with a file)
1059  if ( m_conflictError == ERR_DIR_ALREADY_EXIST )
1060  {
1061  if( (*it).uSource == (*it).uDest ||
1062  ((*it).uSource.protocol() == (*it).uDest.protocol() &&
1063  (*it).uSource.path( KUrl::RemoveTrailingSlash ) == linkDest) )
1064  mode = (RenameDialog_Mode)( mode | M_OVERWRITE_ITSELF);
1065  else
1066  mode = (RenameDialog_Mode)( mode | M_OVERWRITE );
1067  }
1068 
1069  QString existingDest = (*it).uDest.path();
1070  QString newPath;
1071  if (m_reportTimer)
1072  m_reportTimer->stop();
1073  RenameDialog_Result r = q->ui()->askFileRename( q, i18n("Folder Already Exists"),
1074  (*it).uSource.url(),
1075  (*it).uDest.url(),
1076  mode, newPath,
1077  (*it).size, destsize,
1078  (*it).ctime, destctime,
1079  (*it).mtime, destmtime );
1080  if (m_reportTimer)
1081  m_reportTimer->start(REPORT_TIMEOUT);
1082  switch ( r ) {
1083  case R_CANCEL:
1084  q->setError( ERR_USER_CANCELED );
1085  q->emitResult();
1086  return;
1087  case R_AUTO_RENAME:
1088  m_bAutoRenameDirs = true;
1089  // fall through
1090  case R_RENAME:
1091  {
1092  QString oldPath = (*it).uDest.path( KUrl::AddTrailingSlash );
1093  KUrl newUrl( (*it).uDest );
1094  newUrl.setPath( newPath );
1095  emit q->renamed( q, (*it).uDest, newUrl ); // for e.g. kpropsdlg
1096 
1097  // Change the current one and strip the trailing '/'
1098  (*it).uDest.setPath( newUrl.path( KUrl::RemoveTrailingSlash ) );
1099  newPath = newUrl.path( KUrl::AddTrailingSlash ); // With trailing slash
1100  QList<CopyInfo>::Iterator renamedirit = it;
1101  ++renamedirit;
1102  // Change the name of subdirectories inside the directory
1103  for( ; renamedirit != dirs.end() ; ++renamedirit )
1104  {
1105  QString path = (*renamedirit).uDest.path();
1106  if ( path.startsWith( oldPath ) ) {
1107  QString n = path;
1108  n.replace( 0, oldPath.length(), newPath );
1109  kDebug(7007) << "dirs list:" << (*renamedirit).uSource.path()
1110  << "was going to be" << path
1111  << ", changed into" << n;
1112  (*renamedirit).uDest.setPath( n );
1113  }
1114  }
1115  // Change filenames inside the directory
1116  QList<CopyInfo>::Iterator renamefileit = files.begin();
1117  for( ; renamefileit != files.end() ; ++renamefileit )
1118  {
1119  QString path = (*renamefileit).uDest.path();
1120  if ( path.startsWith( oldPath ) ) {
1121  QString n = path;
1122  n.replace( 0, oldPath.length(), newPath );
1123  kDebug(7007) << "files list:" << (*renamefileit).uSource.path()
1124  << "was going to be" << path
1125  << ", changed into" << n;
1126  (*renamefileit).uDest.setPath( n );
1127  }
1128  }
1129  if (!dirs.isEmpty())
1130  emit q->aboutToCreate( q, dirs );
1131  if (!files.isEmpty())
1132  emit q->aboutToCreate( q, files );
1133  }
1134  break;
1135  case R_AUTO_SKIP:
1136  m_bAutoSkipDirs = true;
1137  // fall through
1138  case R_SKIP:
1139  m_skipList.append( existingDest );
1140  skip((*it).uSource, true);
1141  // Move on to next dir
1142  dirs.erase( it );
1143  m_processedDirs++;
1144  break;
1145  case R_OVERWRITE:
1146  m_overwriteList.insert( existingDest );
1147  emit q->copyingDone( q, (*it).uSource, (*it).uDest, (*it).mtime, true /* directory */, false /* renamed */ );
1148  // Move on to next dir
1149  dirs.erase( it );
1150  m_processedDirs++;
1151  break;
1152  case R_OVERWRITE_ALL:
1153  m_bOverwriteAllDirs = true;
1154  emit q->copyingDone( q, (*it).uSource, (*it).uDest, (*it).mtime, true /* directory */, false /* renamed */ );
1155  // Move on to next dir
1156  dirs.erase( it );
1157  m_processedDirs++;
1158  break;
1159  default:
1160  assert( 0 );
1161  }
1162  state = STATE_CREATING_DIRS;
1163  //emit processedAmount( this, KJob::Directories, m_processedDirs );
1164  createNextDir();
1165 }
1166 
1167 void CopyJobPrivate::createNextDir()
1168 {
1169  Q_Q(CopyJob);
1170  KUrl udir;
1171  if ( !dirs.isEmpty() )
1172  {
1173  // Take first dir to create out of list
1174  QList<CopyInfo>::Iterator it = dirs.begin();
1175  // Is this URL on the skip list or the overwrite list ?
1176  while( it != dirs.end() && udir.isEmpty() )
1177  {
1178  const QString dir = (*it).uDest.path();
1179  if ( shouldSkip( dir ) ) {
1180  dirs.erase( it );
1181  it = dirs.begin();
1182  } else
1183  udir = (*it).uDest;
1184  }
1185  }
1186  if ( !udir.isEmpty() ) // any dir to create, finally ?
1187  {
1188  // Create the directory - with default permissions so that we can put files into it
1189  // TODO : change permissions once all is finished; but for stuff coming from CDROM it sucks...
1190  KIO::SimpleJob *newjob = KIO::mkdir( udir, -1 );
1191  Scheduler::setJobPriority(newjob, 1);
1192  if (shouldOverwriteFile(udir.path())) { // if we are overwriting an existing file or symlink
1193  newjob->addMetaData("overwrite", "true");
1194  }
1195 
1196  m_currentDestURL = udir;
1197  m_bURLDirty = true;
1198 
1199  q->addSubjob(newjob);
1200  return;
1201  }
1202  else // we have finished creating dirs
1203  {
1204  q->setProcessedAmount( KJob::Directories, m_processedDirs ); // make sure final number appears
1205 
1206  if (m_mode == CopyJob::Move) {
1207  // Now we know which dirs hold the files we're going to delete.
1208  // To speed things up and prevent double-notification, we disable KDirWatch
1209  // on those dirs temporarily (using KDirWatch::self, that's the instanced
1210  // used by e.g. kdirlister).
1211  for ( QSet<QString>::const_iterator it = m_parentDirs.constBegin() ; it != m_parentDirs.constEnd() ; ++it )
1212  KDirWatch::self()->stopDirScan( *it );
1213  }
1214 
1215  state = STATE_COPYING_FILES;
1216  m_processedFiles++; // Ralf wants it to start at 1, not 0
1217  copyNextFile();
1218  }
1219 }
1220 
1221 void CopyJobPrivate::slotResultCopyingFiles( KJob * job )
1222 {
1223  Q_Q(CopyJob);
1224  // The file we were trying to copy:
1225  QList<CopyInfo>::Iterator it = files.begin();
1226  if ( job->error() )
1227  {
1228  // Should we skip automatically ?
1229  if ( m_bAutoSkipFiles )
1230  {
1231  skip((*it).uSource, false);
1232  m_fileProcessedSize = (*it).size;
1233  files.erase( it ); // Move on to next file
1234  }
1235  else
1236  {
1237  m_conflictError = job->error(); // save for later
1238  // Existing dest ?
1239  if ( ( m_conflictError == ERR_FILE_ALREADY_EXIST )
1240  || ( m_conflictError == ERR_DIR_ALREADY_EXIST )
1241  || ( m_conflictError == ERR_IDENTICAL_FILES ) )
1242  {
1243  if (m_bAutoRenameFiles) {
1244  KUrl destDirectory((*it).uDest);
1245  destDirectory.setPath(destDirectory.directory());
1246  const QString newName = KIO::RenameDialog::suggestName(destDirectory, (*it).uDest.fileName());
1247 
1248  KUrl newUrl((*it).uDest);
1249  newUrl.setFileName(newName);
1250 
1251  emit q->renamed(q, (*it).uDest, newUrl); // for e.g. kpropsdlg
1252  (*it).uDest = newUrl;
1253 
1254  QList<CopyInfo> files;
1255  files.append(*it);
1256  emit q->aboutToCreate(q, files);
1257  }
1258  else {
1259  if ( !q->isInteractive() ) {
1260  q->Job::slotResult( job ); // will set the error and emit result(this)
1261  return;
1262  }
1263 
1264  q->removeSubjob(job);
1265  assert (!q->hasSubjobs());
1266  // We need to stat the existing file, to get its last-modification time
1267  KUrl existingFile((*it).uDest);
1268  SimpleJob * newJob = KIO::stat(existingFile, StatJob::DestinationSide, 2, KIO::HideProgressInfo);
1269  Scheduler::setJobPriority(newJob, 1);
1270  kDebug(7007) << "KIO::stat for resolving conflict on " << existingFile;
1271  state = STATE_CONFLICT_COPYING_FILES;
1272  q->addSubjob(newJob);
1273  return; // Don't move to next file yet !
1274  }
1275  }
1276  else
1277  {
1278  if ( m_bCurrentOperationIsLink && qobject_cast<KIO::DeleteJob*>( job ) )
1279  {
1280  // Very special case, see a few lines below
1281  // We are deleting the source of a symlink we successfully moved... ignore error
1282  m_fileProcessedSize = (*it).size;
1283  files.erase( it );
1284  } else {
1285  if ( !q->isInteractive() ) {
1286  q->Job::slotResult( job ); // will set the error and emit result(this)
1287  return;
1288  }
1289 
1290  // Go directly to the conflict resolution, there is nothing to stat
1291  slotResultConflictCopyingFiles( job );
1292  return;
1293  }
1294  }
1295  }
1296  } else // no error
1297  {
1298  // Special case for moving links. That operation needs two jobs, unlike others.
1299  if ( m_bCurrentOperationIsLink && m_mode == CopyJob::Move
1300  && !qobject_cast<KIO::DeleteJob *>( job ) // Deleting source not already done
1301  )
1302  {
1303  q->removeSubjob( job );
1304  assert ( !q->hasSubjobs() );
1305  // The only problem with this trick is that the error handling for this del operation
1306  // is not going to be right... see 'Very special case' above.
1307  KIO::Job * newjob = KIO::del( (*it).uSource, HideProgressInfo );
1308  q->addSubjob( newjob );
1309  return; // Don't move to next file yet !
1310  }
1311 
1312  if ( m_bCurrentOperationIsLink )
1313  {
1314  QString target = ( m_mode == CopyJob::Link ? (*it).uSource.path() : (*it).linkDest );
1315  //required for the undo feature
1316  emit q->copyingLinkDone( q, (*it).uSource, target, (*it).uDest );
1317  }
1318  else {
1319  //required for the undo feature
1320  emit q->copyingDone( q, (*it).uSource, (*it).uDest, (*it).mtime, false, false );
1321  if (m_mode == CopyJob::Move)
1322  {
1323  org::kde::KDirNotify::emitFileMoved( (*it).uSource.url(), (*it).uDest.url() );
1324  }
1325  m_successSrcList.append((*it).uSource);
1326  if (m_freeSpace != (KIO::filesize_t)-1 && (*it).size != (KIO::filesize_t)-1) {
1327  m_freeSpace -= (*it).size;
1328  }
1329 
1330  }
1331  // remove from list, to move on to next file
1332  files.erase( it );
1333  }
1334  m_processedFiles++;
1335 
1336  // clear processed size for last file and add it to overall processed size
1337  m_processedSize += m_fileProcessedSize;
1338  m_fileProcessedSize = 0;
1339 
1340  //kDebug(7007) << files.count() << "files remaining";
1341 
1342  // Merge metadata from subjob
1343  KIO::Job* kiojob = dynamic_cast<KIO::Job*>(job);
1344  Q_ASSERT(kiojob);
1345  m_incomingMetaData += kiojob->metaData();
1346  q->removeSubjob( job );
1347  assert( !q->hasSubjobs() ); // We should have only one job at a time ...
1348  copyNextFile();
1349 }
1350 
1351 void CopyJobPrivate::slotResultConflictCopyingFiles( KJob * job )
1352 {
1353  Q_Q(CopyJob);
1354  // We come here after a conflict has been detected and we've stated the existing file
1355  // The file we were trying to create:
1356  QList<CopyInfo>::Iterator it = files.begin();
1357 
1358  RenameDialog_Result res;
1359  QString newPath;
1360 
1361  if (m_reportTimer)
1362  m_reportTimer->stop();
1363 
1364  if ( ( m_conflictError == ERR_FILE_ALREADY_EXIST )
1365  || ( m_conflictError == ERR_DIR_ALREADY_EXIST )
1366  || ( m_conflictError == ERR_IDENTICAL_FILES ) )
1367  {
1368  // Its modification time:
1369  const UDSEntry entry = ((KIO::StatJob*)job)->statResult();
1370 
1371  const time_t destmtime = (time_t) entry.numberValue( KIO::UDSEntry::UDS_MODIFICATION_TIME, -1 );
1372  const time_t destctime = (time_t) entry.numberValue( KIO::UDSEntry::UDS_CREATION_TIME, -1 );
1373  const KIO::filesize_t destsize = entry.numberValue( KIO::UDSEntry::UDS_SIZE );
1374  const QString linkDest = entry.stringValue( KIO::UDSEntry::UDS_LINK_DEST );
1375 
1376  // Offer overwrite only if the existing thing is a file
1377  // If src==dest, use "overwrite-itself"
1378  RenameDialog_Mode mode;
1379  bool isDir = true;
1380 
1381  if( m_conflictError == ERR_DIR_ALREADY_EXIST )
1382  mode = M_ISDIR;
1383  else
1384  {
1385  if ( (*it).uSource == (*it).uDest ||
1386  ((*it).uSource.protocol() == (*it).uDest.protocol() &&
1387  (*it).uSource.path( KUrl::RemoveTrailingSlash ) == linkDest) )
1388  mode = M_OVERWRITE_ITSELF;
1389  else
1390  mode = M_OVERWRITE;
1391  isDir = false;
1392  }
1393 
1394  if ( !m_bSingleFileCopy )
1395  mode = (RenameDialog_Mode) ( mode | M_MULTI | M_SKIP );
1396 
1397  res = q->ui()->askFileRename( q, !isDir ?
1398  i18n("File Already Exists") : i18n("Already Exists as Folder"),
1399  (*it).uSource.url(),
1400  (*it).uDest.url(),
1401  mode, newPath,
1402  (*it).size, destsize,
1403  (*it).ctime, destctime,
1404  (*it).mtime, destmtime );
1405 
1406  }
1407  else
1408  {
1409  if ( job->error() == ERR_USER_CANCELED )
1410  res = R_CANCEL;
1411  else if ( !q->isInteractive() ) {
1412  q->Job::slotResult( job ); // will set the error and emit result(this)
1413  return;
1414  }
1415  else
1416  {
1417  SkipDialog_Result skipResult = q->ui()->askSkip( q, files.count() > 1,
1418  job->errorString() );
1419 
1420  // Convert the return code from SkipDialog into a RenameDialog code
1421  res = ( skipResult == S_SKIP ) ? R_SKIP :
1422  ( skipResult == S_AUTO_SKIP ) ? R_AUTO_SKIP :
1423  R_CANCEL;
1424  }
1425  }
1426 
1427  if (m_reportTimer)
1428  m_reportTimer->start(REPORT_TIMEOUT);
1429 
1430  q->removeSubjob( job );
1431  assert ( !q->hasSubjobs() );
1432  switch ( res ) {
1433  case R_CANCEL:
1434  q->setError( ERR_USER_CANCELED );
1435  q->emitResult();
1436  return;
1437  case R_AUTO_RENAME:
1438  m_bAutoRenameFiles = true;
1439  // fall through
1440  case R_RENAME:
1441  {
1442  KUrl newUrl( (*it).uDest );
1443  newUrl.setPath( newPath );
1444  emit q->renamed( q, (*it).uDest, newUrl ); // for e.g. kpropsdlg
1445  (*it).uDest = newUrl;
1446 
1447  QList<CopyInfo> files;
1448  files.append(*it);
1449  emit q->aboutToCreate( q, files );
1450  }
1451  break;
1452  case R_AUTO_SKIP:
1453  m_bAutoSkipFiles = true;
1454  // fall through
1455  case R_SKIP:
1456  // Move on to next file
1457  skip((*it).uSource, false);
1458  m_processedSize += (*it).size;
1459  files.erase( it );
1460  m_processedFiles++;
1461  break;
1462  case R_OVERWRITE_ALL:
1463  m_bOverwriteAllFiles = true;
1464  break;
1465  case R_OVERWRITE:
1466  // Add to overwrite list, so that copyNextFile knows to overwrite
1467  m_overwriteList.insert( (*it).uDest.path() );
1468  break;
1469  default:
1470  assert( 0 );
1471  }
1472  state = STATE_COPYING_FILES;
1473  copyNextFile();
1474 }
1475 
1476 KIO::Job* CopyJobPrivate::linkNextFile( const KUrl& uSource, const KUrl& uDest, JobFlags flags )
1477 {
1478  //kDebug(7007) << "Linking";
1479  if (
1480  (uSource.protocol() == uDest.protocol()) &&
1481  (uSource.host() == uDest.host()) &&
1482  (uSource.port() == uDest.port()) &&
1483  (uSource.user() == uDest.user()) &&
1484  (uSource.pass() == uDest.pass()) )
1485  {
1486  // This is the case of creating a real symlink
1487  KIO::SimpleJob *newJob = KIO::symlink( uSource.path(), uDest, flags|HideProgressInfo /*no GUI*/ );
1488  Scheduler::setJobPriority(newJob, 1);
1489  //kDebug(7007) << "Linking target=" << uSource.path() << "link=" << uDest;
1490  //emit linking( this, uSource.path(), uDest );
1491  m_bCurrentOperationIsLink = true;
1492  m_currentSrcURL=uSource;
1493  m_currentDestURL=uDest;
1494  m_bURLDirty = true;
1495  //Observer::self()->slotCopying( this, uSource, uDest ); // should be slotLinking perhaps
1496  return newJob;
1497  } else {
1498  Q_Q(CopyJob);
1499  //kDebug(7007) << "Linking URL=" << uSource << "link=" << uDest;
1500  if ( uDest.isLocalFile() ) {
1501  // if the source is a devices url, handle it a littlebit special
1502 
1503  QString path = uDest.toLocalFile();
1504  //kDebug(7007) << "path=" << path;
1505  QFile f( path );
1506  if ( f.open( QIODevice::ReadWrite ) )
1507  {
1508  f.close();
1509  KDesktopFile desktopFile( path );
1510  KConfigGroup config = desktopFile.desktopGroup();
1511  KUrl url = uSource;
1512  url.setPass( "" );
1513  config.writePathEntry( "URL", url.url() );
1514  config.writeEntry( "Name", url.url() );
1515  config.writeEntry( "Type", QString::fromLatin1("Link") );
1516  QString protocol = uSource.protocol();
1517  if ( protocol == QLatin1String("ftp") )
1518  config.writeEntry( "Icon", QString::fromLatin1("folder-remote") );
1519  else if ( protocol == QLatin1String("http") )
1520  config.writeEntry( "Icon", QString::fromLatin1("text-html") );
1521  else if ( protocol == QLatin1String("info") )
1522  config.writeEntry( "Icon", QString::fromLatin1("text-x-texinfo") );
1523  else if ( protocol == QLatin1String("mailto") ) // sven:
1524  config.writeEntry( "Icon", QString::fromLatin1("internet-mail") ); // added mailto: support
1525  else
1526  config.writeEntry( "Icon", QString::fromLatin1("unknown") );
1527  config.sync();
1528  files.erase( files.begin() ); // done with this one, move on
1529  m_processedFiles++;
1530  //emit processedAmount( this, KJob::Files, m_processedFiles );
1531  copyNextFile();
1532  return 0;
1533  }
1534  else
1535  {
1536  kDebug(7007) << "ERR_CANNOT_OPEN_FOR_WRITING";
1537  q->setError( ERR_CANNOT_OPEN_FOR_WRITING );
1538  q->setErrorText( uDest.toLocalFile() );
1539  q->emitResult();
1540  return 0;
1541  }
1542  } else {
1543  // Todo: not show "link" on remote dirs if the src urls are not from the same protocol+host+...
1544  q->setError( ERR_CANNOT_SYMLINK );
1545  q->setErrorText( uDest.prettyUrl() );
1546  q->emitResult();
1547  return 0;
1548  }
1549  }
1550 }
1551 
1552 void CopyJobPrivate::copyNextFile()
1553 {
1554  Q_Q(CopyJob);
1555  bool bCopyFile = false;
1556  //kDebug(7007);
1557  // Take the first file in the list
1558  QList<CopyInfo>::Iterator it = files.begin();
1559  // Is this URL on the skip list ?
1560  while (it != files.end() && !bCopyFile)
1561  {
1562  const QString destFile = (*it).uDest.path();
1563  bCopyFile = !shouldSkip( destFile );
1564  if ( !bCopyFile ) {
1565  files.erase( it );
1566  it = files.begin();
1567  }
1568  }
1569 
1570  if (bCopyFile) // any file to create, finally ?
1571  {
1572  //kDebug()<<"preparing to copy"<<(*it).uSource<<(*it).size<<m_freeSpace;
1573  if (m_freeSpace != (KIO::filesize_t)-1 && (*it).size != (KIO::filesize_t)-1) {
1574  if (m_freeSpace < (*it).size) {
1575  q->setError( ERR_DISK_FULL );
1576  q->emitResult();
1577  return;
1578  }
1579  //TODO check if dst mount is msdos and (*it).size exceeds it's limits
1580  }
1581 
1582  const KUrl& uSource = (*it).uSource;
1583  const KUrl& uDest = (*it).uDest;
1584  // Do we set overwrite ?
1585  bool bOverwrite;
1586  const QString destFile = uDest.path();
1587  // kDebug(7007) << "copying" << destFile;
1588  if ( uDest == uSource )
1589  bOverwrite = false;
1590  else
1591  bOverwrite = shouldOverwriteFile( destFile );
1592 
1593  m_bCurrentOperationIsLink = false;
1594  KIO::Job * newjob = 0;
1595  if ( m_mode == CopyJob::Link ) {
1596  // User requested that a symlink be made
1597  const JobFlags flags = bOverwrite ? Overwrite : DefaultFlags;
1598  newjob = linkNextFile(uSource, uDest, flags);
1599  if (!newjob)
1600  return;
1601  } else if ( !(*it).linkDest.isEmpty() &&
1602  (uSource.protocol() == uDest.protocol()) &&
1603  (uSource.host() == uDest.host()) &&
1604  (uSource.port() == uDest.port()) &&
1605  (uSource.user() == uDest.user()) &&
1606  (uSource.pass() == uDest.pass()))
1607  // Copying a symlink - only on the same protocol/host/etc. (#5601, downloading an FTP file through its link),
1608  {
1609  const JobFlags flags = bOverwrite ? Overwrite : DefaultFlags;
1610  KIO::SimpleJob *newJob = KIO::symlink( (*it).linkDest, uDest, flags | HideProgressInfo /*no GUI*/ );
1611  Scheduler::setJobPriority(newJob, 1);
1612  newjob = newJob;
1613  //kDebug(7007) << "Linking target=" << (*it).linkDest << "link=" << uDest;
1614  m_currentSrcURL = KUrl( (*it).linkDest );
1615  m_currentDestURL = uDest;
1616  m_bURLDirty = true;
1617  //emit linking( this, (*it).linkDest, uDest );
1618  //Observer::self()->slotCopying( this, m_currentSrcURL, uDest ); // should be slotLinking perhaps
1619  m_bCurrentOperationIsLink = true;
1620  // NOTE: if we are moving stuff, the deletion of the source will be done in slotResultCopyingFiles
1621  } else if (m_mode == CopyJob::Move) // Moving a file
1622  {
1623  JobFlags flags = bOverwrite ? Overwrite : DefaultFlags;
1624  KIO::FileCopyJob * moveJob = KIO::file_move( uSource, uDest, (*it).permissions, flags | HideProgressInfo/*no GUI*/ );
1625  moveJob->setSourceSize( (*it).size );
1626  if ((*it).mtime != -1) {
1627  moveJob->setModificationTime( QDateTime::fromTime_t( (*it).mtime ) ); // #55804
1628  }
1629  newjob = moveJob;
1630  //kDebug(7007) << "Moving" << uSource << "to" << uDest;
1631  //emit moving( this, uSource, uDest );
1632  m_currentSrcURL=uSource;
1633  m_currentDestURL=uDest;
1634  m_bURLDirty = true;
1635  //Observer::self()->slotMoving( this, uSource, uDest );
1636  }
1637  else // Copying a file
1638  {
1639  // If source isn't local and target is local, we ignore the original permissions
1640  // Otherwise, files downloaded from HTTP end up with -r--r--r--
1641  bool remoteSource = !KProtocolManager::supportsListing(uSource);
1642  int permissions = (*it).permissions;
1643  if ( m_defaultPermissions || ( remoteSource && uDest.isLocalFile() ) )
1644  permissions = -1;
1645  JobFlags flags = bOverwrite ? Overwrite : DefaultFlags;
1646  KIO::FileCopyJob * copyJob = KIO::file_copy( uSource, uDest, permissions, flags | HideProgressInfo/*no GUI*/ );
1647  copyJob->setParentJob( q ); // in case of rename dialog
1648  copyJob->setSourceSize( (*it).size );
1649  if ((*it).mtime != -1) {
1650  copyJob->setModificationTime( QDateTime::fromTime_t( (*it).mtime ) );
1651  }
1652  newjob = copyJob;
1653  //kDebug(7007) << "Copying" << uSource << "to" << uDest;
1654  m_currentSrcURL=uSource;
1655  m_currentDestURL=uDest;
1656  m_bURLDirty = true;
1657  }
1658  q->addSubjob(newjob);
1659  q->connect( newjob, SIGNAL(processedSize(KJob*,qulonglong)),
1660  SLOT(slotProcessedSize(KJob*,qulonglong)) );
1661  q->connect( newjob, SIGNAL(totalSize(KJob*,qulonglong)),
1662  SLOT(slotTotalSize(KJob*,qulonglong)) );
1663  }
1664  else
1665  {
1666  // We're done
1667  //kDebug(7007) << "copyNextFile finished";
1668  deleteNextDir();
1669  }
1670 }
1671 
1672 void CopyJobPrivate::deleteNextDir()
1673 {
1674  Q_Q(CopyJob);
1675  if ( m_mode == CopyJob::Move && !dirsToRemove.isEmpty() ) // some dirs to delete ?
1676  {
1677  state = STATE_DELETING_DIRS;
1678  m_bURLDirty = true;
1679  // Take first dir to delete out of list - last ones first !
1680  KUrl::List::Iterator it = --dirsToRemove.end();
1681  SimpleJob *job = KIO::rmdir( *it );
1682  Scheduler::setJobPriority(job, 1);
1683  dirsToRemove.erase(it);
1684  q->addSubjob( job );
1685  }
1686  else
1687  {
1688  // This step is done, move on
1689  state = STATE_SETTING_DIR_ATTRIBUTES;
1690  m_directoriesCopiedIterator = m_directoriesCopied.constBegin();
1691  setNextDirAttribute();
1692  }
1693 }
1694 
1695 void CopyJobPrivate::setNextDirAttribute()
1696 {
1697  Q_Q(CopyJob);
1698  while (m_directoriesCopiedIterator != m_directoriesCopied.constEnd() &&
1699  (*m_directoriesCopiedIterator).mtime == -1) {
1700  ++m_directoriesCopiedIterator;
1701  }
1702  if ( m_directoriesCopiedIterator != m_directoriesCopied.constEnd() ) {
1703  const KUrl url = (*m_directoriesCopiedIterator).uDest;
1704  const time_t mtime = (*m_directoriesCopiedIterator).mtime;
1705  const QDateTime dt = QDateTime::fromTime_t(mtime);
1706  ++m_directoriesCopiedIterator;
1707 
1708  KIO::SimpleJob *job = KIO::setModificationTime( url, dt );
1709  Scheduler::setJobPriority(job, 1);
1710  q->addSubjob( job );
1711 
1712 
1713 #if 0 // ifdef Q_OS_UNIX
1714  // TODO: can be removed now. Or reintroduced as a fast path for local files
1715  // if launching even more jobs as done above is a performance problem.
1716  //
1717  QLinkedList<CopyInfo>::const_iterator it = m_directoriesCopied.constBegin();
1718  for ( ; it != m_directoriesCopied.constEnd() ; ++it ) {
1719  const KUrl& url = (*it).uDest;
1720  if ( url.isLocalFile() && (*it).mtime != (time_t)-1 ) {
1721  KDE_struct_stat statbuf;
1722  if (KDE::lstat(url.path(), &statbuf) == 0) {
1723  struct utimbuf utbuf;
1724  utbuf.actime = statbuf.st_atime; // access time, unchanged
1725  utbuf.modtime = (*it).mtime; // modification time
1726  utime( path, &utbuf );
1727  }
1728 
1729  }
1730  }
1731  m_directoriesCopied.clear();
1732  // but then we need to jump to the else part below. Maybe with a recursive call?
1733 #endif
1734  } else {
1735  if (m_reportTimer)
1736  m_reportTimer->stop();
1737  --m_processedFiles; // undo the "start at 1" hack
1738  slotReport(); // display final numbers, important if progress dialog stays up
1739 
1740  q->emitResult();
1741  }
1742 }
1743 
1744 void CopyJob::emitResult()
1745 {
1746  Q_D(CopyJob);
1747  // Before we go, tell the world about the changes that were made.
1748  // Even if some error made us abort midway, we might still have done
1749  // part of the job so we better update the views! (#118583)
1750  if (!d->m_bOnlyRenames) {
1751  // If only renaming happened, KDirNotify::FileRenamed was emitted by the rename jobs
1752  KUrl url(d->m_globalDest);
1753  if (d->m_globalDestinationState != DEST_IS_DIR || d->m_asMethod)
1754  url.setPath(url.directory());
1755  //kDebug(7007) << "KDirNotify'ing FilesAdded" << url;
1756  org::kde::KDirNotify::emitFilesAdded( url.url() );
1757 
1758  if (d->m_mode == CopyJob::Move && !d->m_successSrcList.isEmpty()) {
1759  kDebug(7007) << "KDirNotify'ing FilesRemoved" << d->m_successSrcList.toStringList();
1760  org::kde::KDirNotify::emitFilesRemoved(d->m_successSrcList.toStringList());
1761  }
1762  }
1763 
1764  // Re-enable watching on the dirs that held the deleted/moved files
1765  if (d->m_mode == CopyJob::Move) {
1766  for (QSet<QString>::const_iterator it = d->m_parentDirs.constBegin() ; it != d->m_parentDirs.constEnd() ; ++it)
1767  KDirWatch::self()->restartDirScan( *it );
1768  }
1769  Job::emitResult();
1770 }
1771 
1772 void CopyJobPrivate::slotProcessedSize( KJob*, qulonglong data_size )
1773 {
1774  Q_Q(CopyJob);
1775  //kDebug(7007) << data_size;
1776  m_fileProcessedSize = data_size;
1777  q->setProcessedAmount(KJob::Bytes, m_processedSize + m_fileProcessedSize);
1778 
1779  if ( m_processedSize + m_fileProcessedSize > m_totalSize )
1780  {
1781  // Example: download any attachment from bugs.kde.org
1782  m_totalSize = m_processedSize + m_fileProcessedSize;
1783  //kDebug(7007) << "Adjusting m_totalSize to" << m_totalSize;
1784  q->setTotalAmount(KJob::Bytes, m_totalSize); // safety
1785  }
1786  //kDebug(7007) << "emit processedSize" << (unsigned long) (m_processedSize + m_fileProcessedSize);
1787  q->setProcessedAmount(KJob::Bytes, m_processedSize + m_fileProcessedSize);
1788 }
1789 
1790 void CopyJobPrivate::slotTotalSize( KJob*, qulonglong size )
1791 {
1792  Q_Q(CopyJob);
1793  //kDebug(7007) << size;
1794  // Special case for copying a single file
1795  // This is because some protocols don't implement stat properly
1796  // (e.g. HTTP), and don't give us a size in some cases (redirection)
1797  // so we'd rather rely on the size given for the transfer
1798  if ( m_bSingleFileCopy && size != m_totalSize)
1799  {
1800  //kDebug(7007) << "slotTotalSize: updating totalsize to" << size;
1801  m_totalSize = size;
1802  q->setTotalAmount(KJob::Bytes, size);
1803  }
1804 }
1805 
1806 void CopyJobPrivate::slotResultDeletingDirs( KJob * job )
1807 {
1808  Q_Q(CopyJob);
1809  if (job->error()) {
1810  // Couldn't remove directory. Well, perhaps it's not empty
1811  // because the user pressed Skip for a given file in it.
1812  // Let's not display "Could not remove dir ..." for each of those dir !
1813  } else {
1814  m_successSrcList.append(static_cast<KIO::SimpleJob*>(job)->url());
1815  }
1816  q->removeSubjob( job );
1817  assert( !q->hasSubjobs() );
1818  deleteNextDir();
1819 }
1820 
1821 void CopyJobPrivate::slotResultSettingDirAttributes( KJob * job )
1822 {
1823  Q_Q(CopyJob);
1824  if (job->error())
1825  {
1826  // Couldn't set directory attributes. Ignore the error, it can happen
1827  // with inferior file systems like VFAT.
1828  // Let's not display warnings for each dir like "cp -a" does.
1829  }
1830  q->removeSubjob( job );
1831  assert( !q->hasSubjobs() );
1832  setNextDirAttribute();
1833 }
1834 
1835 // We were trying to do a direct renaming, before even stat'ing
1836 void CopyJobPrivate::slotResultRenaming( KJob* job )
1837 {
1838  Q_Q(CopyJob);
1839  int err = job->error();
1840  const QString errText = job->errorText();
1841  // Merge metadata from subjob
1842  KIO::Job* kiojob = dynamic_cast<KIO::Job*>(job);
1843  Q_ASSERT(kiojob);
1844  m_incomingMetaData += kiojob->metaData();
1845  q->removeSubjob( job );
1846  assert ( !q->hasSubjobs() );
1847  // Determine dest again
1848  KUrl dest = m_dest;
1849  if ( destinationState == DEST_IS_DIR && !m_asMethod )
1850  dest.addPath( m_currentSrcURL.fileName() );
1851  if ( err )
1852  {
1853  // Direct renaming didn't work. Try renaming to a temp name,
1854  // this can help e.g. when renaming 'a' to 'A' on a VFAT partition.
1855  // In that case it's the _same_ dir, we don't want to copy+del (data loss!)
1856  if ( m_currentSrcURL.isLocalFile() && m_currentSrcURL.url(KUrl::RemoveTrailingSlash) != dest.url(KUrl::RemoveTrailingSlash) &&
1857  m_currentSrcURL.url(KUrl::RemoveTrailingSlash).toLower() == dest.url(KUrl::RemoveTrailingSlash).toLower() &&
1858  ( err == ERR_FILE_ALREADY_EXIST ||
1859  err == ERR_DIR_ALREADY_EXIST ||
1860  err == ERR_IDENTICAL_FILES ) )
1861  {
1862  kDebug(7007) << "Couldn't rename directly, dest already exists. Detected special case of lower/uppercase renaming in same dir, try with 2 rename calls";
1863  const QString _src( m_currentSrcURL.toLocalFile() );
1864  const QString _dest( dest.toLocalFile() );
1865  const QString _tmpPrefix = m_currentSrcURL.directory(KUrl::ObeyTrailingSlash|KUrl::AppendTrailingSlash);
1866  KTemporaryFile tmpFile;
1867  tmpFile.setPrefix(_tmpPrefix);
1868  const bool openOk = tmpFile.open();
1869  if (!openOk) {
1870  kWarning(7007) << "Couldn't open temp file in" << _tmpPrefix;
1871  } else {
1872  const QString _tmp( tmpFile.fileName() );
1873  tmpFile.close();
1874  tmpFile.remove();
1875  kDebug(7007) << "KTemporaryFile using" << _tmp << "as intermediary";
1876  if (KDE::rename( _src, _tmp ) == 0) {
1877  //kDebug(7007) << "Renaming" << _src << "to" << _tmp << "succeeded";
1878  if (!QFile::exists( _dest ) && KDE::rename(_tmp, _dest) == 0) {
1879  err = 0;
1880  org::kde::KDirNotify::emitFileRenamed(m_currentSrcURL.url(), dest.url());
1881  } else {
1882  kDebug(7007) << "Didn't manage to rename" << _tmp << "to" << _dest << ", reverting";
1883  // Revert back to original name!
1884  if (KDE::rename( _tmp, _src ) != 0) {
1885  kError(7007) << "Couldn't rename" << _tmp << "back to" << _src << '!';
1886  // Severe error, abort
1887  q->Job::slotResult(job); // will set the error and emit result(this)
1888  return;
1889  }
1890  }
1891  } else {
1892  kDebug(7007) << "mv" << _src << _tmp << "failed:" << strerror(errno);
1893  }
1894  }
1895  }
1896  }
1897  if ( err )
1898  {
1899  // This code is similar to CopyJobPrivate::slotResultConflictCopyingFiles
1900  // but here it's about the base src url being moved/renamed
1901  // (m_currentSrcURL) and its dest (m_dest), not about a single file.
1902  // It also means we already stated the dest, here.
1903  // On the other hand we haven't stated the src yet (we skipped doing it
1904  // to save time, since it's not necessary to rename directly!)...
1905 
1906  // Existing dest?
1907  if ( err == ERR_DIR_ALREADY_EXIST ||
1908  err == ERR_FILE_ALREADY_EXIST ||
1909  err == ERR_IDENTICAL_FILES )
1910  {
1911  // Should we skip automatically ?
1912  bool isDir = (err == ERR_DIR_ALREADY_EXIST); // ## technically, isDir means "source is dir", not "dest is dir" #######
1913  if ((isDir && m_bAutoSkipDirs) || (!isDir && m_bAutoSkipFiles)) {
1914  // Move on to next source url
1915  skipSrc(isDir);
1916  return;
1917  } else if ((isDir && m_bOverwriteAllDirs) || (!isDir && m_bOverwriteAllFiles)) {
1918  ; // nothing to do, stat+copy+del will overwrite
1919  } else if ((isDir && m_bAutoRenameDirs) || (!isDir && m_bAutoRenameFiles)) {
1920  KUrl destDirectory(m_currentDestURL); // dest including filename
1921  destDirectory.setPath(destDirectory.directory());
1922  const QString newName = KIO::RenameDialog::suggestName(destDirectory, m_currentDestURL.fileName());
1923 
1924  m_dest.setPath(m_currentDestURL.path());
1925  m_dest.setFileName(newName);
1926  KIO::Job* job = KIO::stat(m_dest, StatJob::DestinationSide, 2, KIO::HideProgressInfo);
1927  state = STATE_STATING;
1928  destinationState = DEST_NOT_STATED;
1929  q->addSubjob(job);
1930  return;
1931  } else if ( q->isInteractive() ) {
1932  QString newPath;
1933  // we lack mtime info for both the src (not stated)
1934  // and the dest (stated but this info wasn't stored)
1935  // Let's do it for local files, at least
1936  KIO::filesize_t sizeSrc = (KIO::filesize_t) -1;
1937  KIO::filesize_t sizeDest = (KIO::filesize_t) -1;
1938  time_t ctimeSrc = (time_t) -1;
1939  time_t ctimeDest = (time_t) -1;
1940  time_t mtimeSrc = (time_t) -1;
1941  time_t mtimeDest = (time_t) -1;
1942 
1943  bool destIsDir = err == ERR_DIR_ALREADY_EXIST;
1944 
1945  // ## TODO we need to stat the source using KIO::stat
1946  // so that this code is properly network-transparent.
1947 
1948  KDE_struct_stat stat_buf;
1949  if ( m_currentSrcURL.isLocalFile() &&
1950  KDE::stat(m_currentSrcURL.toLocalFile(), &stat_buf) == 0 ) {
1951  sizeSrc = stat_buf.st_size;
1952  ctimeSrc = stat_buf.st_ctime;
1953  mtimeSrc = stat_buf.st_mtime;
1954  isDir = S_ISDIR(stat_buf.st_mode);
1955  }
1956  if ( dest.isLocalFile() &&
1957  KDE::stat(dest.toLocalFile(), &stat_buf) == 0 ) {
1958  sizeDest = stat_buf.st_size;
1959  ctimeDest = stat_buf.st_ctime;
1960  mtimeDest = stat_buf.st_mtime;
1961  destIsDir = S_ISDIR(stat_buf.st_mode);
1962  }
1963 
1964  // If src==dest, use "overwrite-itself"
1965  RenameDialog_Mode mode = ( m_currentSrcURL == dest ) ? M_OVERWRITE_ITSELF : M_OVERWRITE;
1966  if (!isDir && destIsDir) {
1967  // We can't overwrite a dir with a file.
1968  mode = (RenameDialog_Mode) 0;
1969  }
1970 
1971  if ( m_srcList.count() > 1 )
1972  mode = (RenameDialog_Mode) ( mode | M_MULTI | M_SKIP );
1973  if (destIsDir)
1974  mode = (RenameDialog_Mode) ( mode | M_ISDIR );
1975 
1976  if (m_reportTimer)
1977  m_reportTimer->stop();
1978 
1979  RenameDialog_Result r = q->ui()->askFileRename(
1980  q,
1981  err != ERR_DIR_ALREADY_EXIST ? i18n("File Already Exists") : i18n("Already Exists as Folder"),
1982  m_currentSrcURL.url(),
1983  dest.url(),
1984  mode, newPath,
1985  sizeSrc, sizeDest,
1986  ctimeSrc, ctimeDest,
1987  mtimeSrc, mtimeDest );
1988 
1989  if (m_reportTimer)
1990  m_reportTimer->start(REPORT_TIMEOUT);
1991 
1992  switch ( r )
1993  {
1994  case R_CANCEL:
1995  {
1996  q->setError( ERR_USER_CANCELED );
1997  q->emitResult();
1998  return;
1999  }
2000  case R_AUTO_RENAME:
2001  if (isDir) {
2002  m_bAutoRenameDirs = true;
2003  }
2004  else {
2005  m_bAutoRenameFiles = true;
2006  }
2007  // fall through
2008  case R_RENAME:
2009  {
2010  // Set m_dest to the chosen destination
2011  // This is only for this src url; the next one will revert to m_globalDest
2012  m_dest.setPath( newPath );
2013  KIO::Job* job = KIO::stat( m_dest, StatJob::DestinationSide, 2, KIO::HideProgressInfo );
2014  state = STATE_STATING;
2015  destinationState = DEST_NOT_STATED;
2016  q->addSubjob(job);
2017  return;
2018  }
2019  case R_AUTO_SKIP:
2020  if (isDir)
2021  m_bAutoSkipDirs = true;
2022  else
2023  m_bAutoSkipFiles = true;
2024  // fall through
2025  case R_SKIP:
2026  // Move on to next url
2027  skipSrc(isDir);
2028  return;
2029  case R_OVERWRITE_ALL:
2030  if (destIsDir)
2031  m_bOverwriteAllDirs = true;
2032  else
2033  m_bOverwriteAllFiles = true;
2034  break;
2035  case R_OVERWRITE:
2036  // Add to overwrite list
2037  // Note that we add dest, not m_dest.
2038  // This ensures that when moving several urls into a dir (m_dest),
2039  // we only overwrite for the current one, not for all.
2040  // When renaming a single file (m_asMethod), it makes no difference.
2041  kDebug(7007) << "adding to overwrite list: " << dest.path();
2042  m_overwriteList.insert( dest.path() );
2043  break;
2044  default:
2045  //assert( 0 );
2046  break;
2047  }
2048  } else if ( err != KIO::ERR_UNSUPPORTED_ACTION ) {
2049  // Dest already exists, and job is not interactive -> abort with error
2050  q->setError( err );
2051  q->setErrorText( errText );
2052  q->emitResult();
2053  return;
2054  }
2055  } else if ( err != KIO::ERR_UNSUPPORTED_ACTION ) {
2056  kDebug(7007) << "Couldn't rename" << m_currentSrcURL << "to" << dest << ", aborting";
2057  q->setError( err );
2058  q->setErrorText( errText );
2059  q->emitResult();
2060  return;
2061  }
2062  kDebug(7007) << "Couldn't rename" << m_currentSrcURL << "to" << dest << ", reverting to normal way, starting with stat";
2063  //kDebug(7007) << "KIO::stat on" << m_currentSrcURL;
2064  KIO::Job* job = KIO::stat( m_currentSrcURL, StatJob::SourceSide, 2, KIO::HideProgressInfo );
2065  state = STATE_STATING;
2066  q->addSubjob(job);
2067  m_bOnlyRenames = false;
2068  }
2069  else
2070  {
2071  kDebug(7007) << "Renaming succeeded, move on";
2072  ++m_processedFiles;
2073  emit q->copyingDone( q, *m_currentStatSrc, dest, -1 /*mtime unknown, and not needed*/, true, true );
2074  m_successSrcList.append(*m_currentStatSrc);
2075  statNextSrc();
2076  }
2077 }
2078 
2079 void CopyJob::slotResult( KJob *job )
2080 {
2081  Q_D(CopyJob);
2082  //kDebug(7007) << "d->state=" << (int) d->state;
2083  // In each case, what we have to do is :
2084  // 1 - check for errors and treat them
2085  // 2 - removeSubjob(job);
2086  // 3 - decide what to do next
2087 
2088  switch ( d->state ) {
2089  case STATE_STATING: // We were trying to stat a src url or the dest
2090  d->slotResultStating( job );
2091  break;
2092  case STATE_RENAMING: // We were trying to do a direct renaming, before even stat'ing
2093  {
2094  d->slotResultRenaming( job );
2095  break;
2096  }
2097  case STATE_LISTING: // recursive listing finished
2098  //kDebug(7007) << "totalSize:" << (unsigned int) d->m_totalSize << "files:" << d->files.count() << "d->dirs:" << d->dirs.count();
2099  // Was there an error ?
2100  if (job->error())
2101  {
2102  Job::slotResult( job ); // will set the error and emit result(this)
2103  return;
2104  }
2105 
2106  removeSubjob( job );
2107  assert ( !hasSubjobs() );
2108 
2109  d->statNextSrc();
2110  break;
2111  case STATE_CREATING_DIRS:
2112  d->slotResultCreatingDirs( job );
2113  break;
2114  case STATE_CONFLICT_CREATING_DIRS:
2115  d->slotResultConflictCreatingDirs( job );
2116  break;
2117  case STATE_COPYING_FILES:
2118  d->slotResultCopyingFiles( job );
2119  break;
2120  case STATE_CONFLICT_COPYING_FILES:
2121  d->slotResultConflictCopyingFiles( job );
2122  break;
2123  case STATE_DELETING_DIRS:
2124  d->slotResultDeletingDirs( job );
2125  break;
2126  case STATE_SETTING_DIR_ATTRIBUTES:
2127  d->slotResultSettingDirAttributes( job );
2128  break;
2129  default:
2130  assert( 0 );
2131  }
2132 }
2133 
2134 void KIO::CopyJob::setDefaultPermissions( bool b )
2135 {
2136  d_func()->m_defaultPermissions = b;
2137 }
2138 
2139 KIO::CopyJob::CopyMode KIO::CopyJob::operationMode() const
2140 {
2141  return d_func()->m_mode;
2142 }
2143 
2144 void KIO::CopyJob::setAutoSkip(bool autoSkip)
2145 {
2146  d_func()->m_bAutoSkipFiles = autoSkip;
2147  d_func()->m_bAutoSkipDirs = autoSkip;
2148 }
2149 
2150 void KIO::CopyJob::setAutoRename(bool autoRename)
2151 {
2152  d_func()->m_bAutoRenameFiles = autoRename;
2153  d_func()->m_bAutoRenameDirs = autoRename;
2154 }
2155 
2156 void KIO::CopyJob::setWriteIntoExistingDirectories(bool overwriteAll) // #65926
2157 {
2158  d_func()->m_bOverwriteAllDirs = overwriteAll;
2159 }
2160 
2161 CopyJob *KIO::copy(const KUrl& src, const KUrl& dest, JobFlags flags)
2162 {
2163  //kDebug(7007) << "src=" << src << "dest=" << dest;
2164  KUrl::List srcList;
2165  srcList.append( src );
2166  return CopyJobPrivate::newJob(srcList, dest, CopyJob::Copy, false, flags);
2167 }
2168 
2169 CopyJob *KIO::copyAs(const KUrl& src, const KUrl& dest, JobFlags flags)
2170 {
2171  //kDebug(7007) << "src=" << src << "dest=" << dest;
2172  KUrl::List srcList;
2173  srcList.append( src );
2174  return CopyJobPrivate::newJob(srcList, dest, CopyJob::Copy, true, flags);
2175 }
2176 
2177 CopyJob *KIO::copy( const KUrl::List& src, const KUrl& dest, JobFlags flags )
2178 {
2179  //kDebug(7007) << src << dest;
2180  return CopyJobPrivate::newJob(src, dest, CopyJob::Copy, false, flags);
2181 }
2182 
2183 CopyJob *KIO::move(const KUrl& src, const KUrl& dest, JobFlags flags)
2184 {
2185  //kDebug(7007) << src << dest;
2186  KUrl::List srcList;
2187  srcList.append( src );
2188  return CopyJobPrivate::newJob(srcList, dest, CopyJob::Move, false, flags);
2189 }
2190 
2191 CopyJob *KIO::moveAs(const KUrl& src, const KUrl& dest, JobFlags flags)
2192 {
2193  //kDebug(7007) << src << dest;
2194  KUrl::List srcList;
2195  srcList.append( src );
2196  return CopyJobPrivate::newJob(srcList, dest, CopyJob::Move, true, flags);
2197 }
2198 
2199 CopyJob *KIO::move( const KUrl::List& src, const KUrl& dest, JobFlags flags)
2200 {
2201  //kDebug(7007) << src << dest;
2202  return CopyJobPrivate::newJob(src, dest, CopyJob::Move, false, flags);
2203 }
2204 
2205 CopyJob *KIO::link(const KUrl& src, const KUrl& destDir, JobFlags flags)
2206 {
2207  KUrl::List srcList;
2208  srcList.append( src );
2209  return CopyJobPrivate::newJob(srcList, destDir, CopyJob::Link, false, flags);
2210 }
2211 
2212 CopyJob *KIO::link(const KUrl::List& srcList, const KUrl& destDir, JobFlags flags)
2213 {
2214  return CopyJobPrivate::newJob(srcList, destDir, CopyJob::Link, false, flags);
2215 }
2216 
2217 CopyJob *KIO::linkAs(const KUrl& src, const KUrl& destDir, JobFlags flags )
2218 {
2219  KUrl::List srcList;
2220  srcList.append( src );
2221  return CopyJobPrivate::newJob(srcList, destDir, CopyJob::Link, false, flags);
2222 }
2223 
2224 CopyJob *KIO::trash(const KUrl& src, JobFlags flags)
2225 {
2226  KUrl::List srcList;
2227  srcList.append( src );
2228  return CopyJobPrivate::newJob(srcList, KUrl( "trash:/" ), CopyJob::Move, false, flags);
2229 }
2230 
2231 CopyJob *KIO::trash(const KUrl::List& srcList, JobFlags flags)
2232 {
2233  return CopyJobPrivate::newJob(srcList, KUrl( "trash:/" ), CopyJob::Move, false, flags);
2234 }
2235 
2236 #include "copyjob.moc"
KIO::UDSEntry::UDS_URL
An alternative URL (If different from the caption).
Definition: udsentry.h:190
kdirlister.h
KIO::CopyJob::Link
Definition: copyjob.h:73
STATE_DELETING_DIRS
Definition: copyjob.cpp:93
i18n
QString i18n(const char *text)
KIO::Overwrite
When set, automatically overwrite the destination if it exists already.
Definition: jobclasses.h:67
KIO::filesize_t
qulonglong filesize_t
64-bit file size
Definition: global.h:56
KUrl::directory
QString directory(const DirectoryOptions &options=IgnoreTrailingSlash) const
KUrl::RemoveTrailingSlash
OrgKdeKDirNotifyInterface::emitFileRenamed
static void emitFileRenamed(const QString &src, const QString &dst)
Definition: kdirnotify.cpp:37
KDirWatch::self
static KDirWatch * self()
KIO::ERR_DISK_FULL
Definition: global.h:255
KIO::UDSEntry::isLink
bool isLink() const
Definition: udsentry.cpp:89
STATE_CONFLICT_COPYING_FILES
Definition: copyjob.cpp:92
KIO::S_SKIP
Definition: skipdialog.h:29
KIO::Job::addMetaData
void addMetaData(const QString &key, const QString &value)
Add key/value pair to the meta data that is sent to the slave.
Definition: job.cpp:263
KFileSystemType::Type
Type
KConfigGroup::writePathEntry
void writePathEntry(const QString &pKey, const QString &path, WriteConfigFlags pFlags=Normal)
kio_resolve_local_urls
bool kio_resolve_local_urls
Definition: copyjob.cpp:297
kdebug.h
KIO::CopyJob::destUrl
KUrl destUrl() const
Returns the destination URL.
Definition: copyjob.cpp:272
KIO::CopyJob::setAutoSkip
void setAutoSkip(bool autoSkip)
Skip copying or moving any file when the destination already exists, instead of the default behavior ...
Definition: copyjob.cpp:2144
KCompositeJob::emitResult
void emitResult()
DEST_DOESNT_EXIST
Definition: copyjob.cpp:66
KUrl::AddTrailingSlash
KIO::CopyInfo::permissions
int permissions
Definition: copyjob.h:46
KCompositeJob::setUiDelegate
void setUiDelegate(KJobUiDelegate *delegate)
KTemporaryFile::setPrefix
void setPrefix(const QString &prefix)
KIO::UDSEntry
Universal Directory Service.
Definition: udsentry.h:58
KIO::Scheduler::setJobPriority
static void setJobPriority(SimpleJob *job, int priority)
Changes the priority of job; jobs of the same priority run in the order in which they were created...
Definition: scheduler.cpp:809
kdirwatch.h
timeout
int timeout
KIO::R_OVERWRITE
Definition: renamedialog.h:61
KIO::ListJob
A ListJob is allows you to get the get the content of a directory.
Definition: jobclasses.h:936
kdirnotify.h
KFileItem::isNull
bool isNull() const
Return true if default-constructed.
Definition: kfileitem.cpp:1720
KIO::S_AUTO_SKIP
Definition: skipdialog.h:29
slave.h
KIO::HideProgressInfo
Hide progress information dialog, i.e.
Definition: jobclasses.h:51
KIO::ERR_CANNOT_DELETE
Definition: global.h:234
KIO::CopyInfo::uSource
KUrl uSource
Definition: copyjob.h:43
KIO::ERR_FILE_ALREADY_EXIST
Definition: global.h:205
dirs
KStandardDirs * dirs()
KIO::ERR_USER_CANCELED
Definition: global.h:213
KIO::mkdir
SimpleJob * mkdir(const KUrl &url, int permissions=-1)
Creates a single directory.
Definition: job.cpp:679
KDE::stat
int stat(const QString &path, KDE_struct_stat *buf)
KDE::rename
int rename(const QString &in, const QString &out)
KIO::UDSEntry::isDir
bool isDir() const
Definition: udsentry.cpp:84
KIO::SimpleJob::url
const KUrl & url() const
Returns the SimpleJob&#39;s URL.
Definition: job.cpp:340
kError
static QDebug kError(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
KIO::stat
StatJob * stat(const KUrl &url, JobFlags flags=DefaultFlags)
Find all details for one file or directory.
Definition: job.cpp:906
f
static quint32 f(DES_KEY *key, quint32 r, char *subkey)
Definition: des.cpp:378
KIO::FileCopyJob::setSourceSize
void setSourceSize(KIO::filesize_t size)
If you know the size of the source file, call this method to inform this job.
Definition: job.cpp:2053
REPORT_TIMEOUT
#define REPORT_TIMEOUT
Definition: copyjob.cpp:60
STATE_STATING
Definition: copyjob.cpp:86
KConfigGroup::writeEntry
void writeEntry(const QString &key, const QVariant &value, WriteConfigFlags pFlags=Normal)
KIO::StatJob
A KIO job that retrieves information about a file or directory.
Definition: jobclasses.h:440
KDirLister::cachedItemForUrl
static KFileItem cachedItemForUrl(const KUrl &url)
Return the KFileItem for the given URL, if we listed it recently and it&#39;s still in the cache - which ...
Definition: kdirlister.cpp:2783
DEST_NOT_STATED
Definition: copyjob.cpp:63
KIO::file_move
FileCopyJob * file_move(const KUrl &src, const KUrl &dest, int permissions=-1, JobFlags flags=DefaultFlags)
Move a single file.
Definition: job.cpp:2464
KUrl::toLocalFile
QString toLocalFile(AdjustPathOption trailing=LeaveTrailingSlash) const
KIO::UDSEntry::UDS_LOCAL_PATH
A local file path if the ioslave display files sitting on the local filesystem (but in another hierar...
Definition: udsentry.h:166
STATE_CREATING_DIRS
Definition: copyjob.cpp:89
QString
KTemporaryFile
KIO::Job::removeSubjob
virtual bool removeSubjob(KJob *job)
Mark a sub job as being done.
Definition: job.cpp:117
KIO::CopyInfo::mtime
time_t mtime
Definition: copyjob.h:48
kdesktopfile.h
kDebug
static QDebug kDebug(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
klocale.h
STATE_RENAMING
Definition: copyjob.cpp:87
CopyJobState
CopyJobState
States: STATE_STATING for the dest statCurrentSrc then does, for each src url: STATE_RENAMING if dire...
Definition: copyjob.cpp:85
KIO::R_OVERWRITE_ALL
Definition: renamedialog.h:61
KProtocolManager::canRenameToFile
static bool canRenameToFile(const KUrl &url)
Returns whether the protocol can rename (i.e.
Definition: kprotocolmanager.cpp:1144
OrgKdeKDirNotifyInterface::emitFilesAdded
static void emitFilesAdded(const QString &directory)
Definition: kdirnotify.cpp:47
KIO::M_OVERWRITE_ITSELF
Definition: renamedialog.h:56
KUrl
KIO::copyAs
CopyJob * copyAs(const KUrl &src, const KUrl &dest, JobFlags flags=DefaultFlags)
Copy a file or directory src into the destination dest, which is the destination name in any case...
Definition: copyjob.cpp:2169
KFileSystemType::fileSystemType
Type fileSystemType(const QString &path)
KIO::ListJob::setUnrestricted
void setUnrestricted(bool unrestricted)
Do not apply any KIOSK restrictions to this job.
Definition: job.cpp:2714
DestinationState
DestinationState
Definition: copyjob.cpp:62
config
KSharedConfigPtr config()
KIO::SkipDialog_Result
SkipDialog_Result
Definition: skipdialog.h:29
kprotocolmanager.h
KDirWatch::stopDirScan
bool stopDirScan(const QString &path)
KUrl::setPath
void setPath(const QString &path)
KIO::CopyJob::srcUrls
KUrl::List srcUrls() const
Returns the list of source URLs.
Definition: copyjob.cpp:267
scheduler.h
KIO::CopyJob::Move
Definition: copyjob.h:73
KIO::DefaultFlags
Show the progress info GUI, no Resume and no Overwrite.
Definition: jobclasses.h:46
KIO::StatJob::DestinationSide
Definition: jobclasses.h:447
KIO::CopyJob::CopyJob
CopyJob(CopyJobPrivate &dd)
Definition: copyjob.cpp:255
KIO::R_CANCEL
Definition: renamedialog.h:61
kdiskfreespaceinfo.h
KUrl::addPath
void addPath(const QString &txt)
OrgKdeKDirNotifyInterface::emitFilesRemoved
static void emitFilesRemoved(const QStringList &fileList)
Definition: kdirnotify.cpp:57
KIO::SimpleJobPrivate::newJobNoUi
static SimpleJob * newJobNoUi(const KUrl &url, int command, const QByteArray &packedArgs)
Definition: job_p.h:185
KIO::file_copy
FileCopyJob * file_copy(const KUrl &src, const KUrl &dest, int permissions=-1, JobFlags flags=DefaultFlags)
Copy a single file.
Definition: job.cpp:2458
KIO::ERR_CANNOT_OPEN_FOR_WRITING
Definition: global.h:195
KIO::FileCopyJob::setModificationTime
void setModificationTime(const QDateTime &mtime)
Sets the modification time of the file.
Definition: job.cpp:2061
KIO::CopyJob::setWriteIntoExistingDirectories
void setWriteIntoExistingDirectories(bool overwriteAllDirs)
Reuse any directory that already exists, instead of the default behavior (interactive mode: showing a...
Definition: copyjob.cpp:2156
KIO::UDSEntry::numberValue
long long numberValue(uint field, long long defaultValue=0) const
Definition: udsentry.cpp:78
KProtocolManager::supportsDeleting
static bool supportsDeleting(const KUrl &url)
Returns whether the protocol can delete files/objects.
Definition: kprotocolmanager.cpp:1079
STATE_LISTING
Definition: copyjob.cpp:88
KIO::encodeFileName
QString encodeFileName(const QString &str)
Encodes (from the text displayed to the real filename) This translates &#39;/&#39; into a &quot;unicode fraction s...
Definition: global.cpp:146
KIO::JobUiDelegate
A UI delegate tuned to be used with KIO Jobs.
Definition: jobuidelegate.h:37
KUrl::user
QString user() const
KIO::CopyJob::~CopyJob
virtual ~CopyJob()
Definition: copyjob.cpp:263
KUrl::protocol
QString protocol() const
KUrl::pass
QString pass() const
KCompositeJob::slotResult
virtual void slotResult(KJob *job)
QStringList
KIO::buildErrorString
QString buildErrorString(int errorCode, const QString &errorText)
Returns a translated error message for errorCode using the additional error information provided by e...
Definition: global.cpp:164
KUrl::setPass
void setPass(const QString &pass)
KIO::UDSEntry::stringValue
QString stringValue(uint field) const
Definition: udsentry.cpp:73
copyjob.h
KIO::getJobTracker
KJobTrackerInterface * getJobTracker()
Definition: global.cpp:1246
KIO::Job::metaData
MetaData metaData() const
Get meta data received from the slave.
Definition: job.cpp:247
KIO::rmdir
SimpleJob * rmdir(const KUrl &url)
Removes a single directory.
Definition: job.cpp:686
KIO::link
CopyJob * link(const KUrl &src, const KUrl &destDir, JobFlags flags=DefaultFlags)
Create a link.
Definition: copyjob.cpp:2205
KIO::R_AUTO_SKIP
Definition: renamedialog.h:61
KUrl::path
QString path(AdjustPathOption trailing=LeaveTrailingSlash) const
KIO::ERR_IDENTICAL_FILES
Definition: global.h:256
KIO::RenameDialog_Mode
RenameDialog_Mode
M_OVERWRITE: We have an existing dest, show details about it and offer to overwrite it...
Definition: renamedialog.h:56
KIO::Job::doSuspend
virtual bool doSuspend()
Suspend this job.
Definition: job.cpp:185
KIO::CopyJob::Copy
Definition: copyjob.h:73
KIO::CMD_RENAME
Definition: global.h:164
KIO::R_SKIP
Definition: renamedialog.h:61
KIO::CopyJob::setDefaultPermissions
void setDefaultPermissions(bool b)
By default the permissions of the copied files will be those of the source files. ...
Definition: copyjob.cpp:2134
KIO::ERR_DIR_ALREADY_EXIST
Definition: global.h:206
KIO::M_SKIP
Definition: renamedialog.h:56
KIO::UDSEntry::UDS_MODIFICATION_TIME
The last time the file was modified.
Definition: udsentry.h:173
jobuidelegate.h
KIO::move
CopyJob * move(const KUrl &src, const KUrl &dest, JobFlags flags=DefaultFlags)
Moves a file or directory src to the given destination dest.
Definition: copyjob.cpp:2183
KIO::symlink
SimpleJob * symlink(const QString &target, const KUrl &dest, JobFlags flags=DefaultFlags)
Create or move a symlink.
Definition: job.cpp:720
KIO::R_RENAME
Definition: renamedialog.h:61
QSet< QString >
KIO::UDSEntry::contains
bool contains(uint field) const
check existence of a field
Definition: udsentry.cpp:118
KDesktopFile
KIO::setModificationTime
SimpleJob * setModificationTime(const KUrl &url, const QDateTime &mtime)
Changes the modification time on a file or directory.
Definition: job.cpp:706
KDE::lstat
int lstat(const QString &path, KDE_struct_stat *buf)
QDateTime
KIO::moveAs
CopyJob * moveAs(const KUrl &src, const KUrl &dest, JobFlags flags=DefaultFlags)
Moves a file or directory src to the given destination dest.
Definition: copyjob.cpp:2191
KIO::CopyJob::slotResult
virtual void slotResult(KJob *job)
Definition: copyjob.cpp:2079
KConfigGroup
KIO::del
DeleteJob * del(const KUrl &src, JobFlags flags=DefaultFlags)
Delete a file or directory.
Definition: deletejob.cpp:484
job_p.h
STATE_CONFLICT_CREATING_DIRS
Definition: copyjob.cpp:90
KUrl::List
KIO::M_ISDIR
Definition: renamedialog.h:56
KIO::CopyInfo::uDest
KUrl uDest
Definition: copyjob.h:44
ktemporaryfile.h
KIO::Job::setParentJob
void setParentJob(Job *parentJob)
Set the parent Job.
Definition: job.cpp:234
KIO::CopyJob::CopyMode
CopyMode
Defines the mode of the operation.
Definition: copyjob.h:73
KIO::R_AUTO_RENAME
Definition: renamedialog.h:61
kfilesystemtype_p.h
KFileSystemType::Nfs
KProtocolInfo::FileNameUsedForCopying
FileNameUsedForCopying
KIO::linkAs
CopyJob * linkAs(const KUrl &src, const KUrl &dest, JobFlags flags=DefaultFlags)
Create a link.
Definition: copyjob.cpp:2217
KRecentDirs::dir
QString dir(const QString &fileClass)
Returns the most recently used directory accociated with this file-class.
Definition: krecentdirs.cpp:68
KIO::M_OVERWRITE
Definition: renamedialog.h:56
KIO::Job::errorString
QString errorString() const
Converts an error code and a non-i18n error message into an error message in the current language...
Definition: global.cpp:159
KIO::UDSEntry::UDS_ACCESS
Access permissions (part of the mode returned by stat)
Definition: udsentry.h:171
KUrl::fileName
QString fileName(const DirectoryOptions &options=IgnoreTrailingSlash) const
KProtocolInfo::FromUrl
KIO::FileCopyJob
The FileCopyJob copies data from one place to another.
Definition: jobclasses.h:856
KIO::listRecursive
ListJob * listRecursive(const KUrl &url, JobFlags flags=DefaultFlags, bool includeHidden=true)
The same as the previous method, but recurses subdirectories.
Definition: job.cpp:2709
KIO::UDSEntry::UDS_NAME
Filename - as displayed in directory listings etc.
Definition: udsentry.h:163
KIO::UDSEntry::UDS_LINK_DEST
Name of the file where the link points to Allows to check for a symlink (don&#39;t use S_ISLNK !) ...
Definition: udsentry.h:184
DEST_IS_FILE
Definition: copyjob.cpp:65
KIO::ERR_UNSUPPORTED_ACTION
Definition: global.h:201
KIO_ARGS
#define KIO_ARGS
Definition: job_p.h:31
KUrl::ObeyTrailingSlash
KIO::CopyJob::doSuspend
virtual bool doSuspend()
Reimplemented for internal reasons.
Definition: copyjob.cpp:483
KIO::RenameDialog_Result
RenameDialog_Result
The result of open_RenameDialog().
Definition: renamedialog.h:61
KIO::Job
The base class for all jobs.
Definition: jobclasses.h:94
KIO::copy
CopyJob * copy(const KUrl &src, const KUrl &dest, JobFlags flags=DefaultFlags)
Copy a file or directory src into the destination dest, which can be a file (including the final file...
Definition: copyjob.cpp:2161
KProtocolInfo::Name
KIO::RenameDialog::suggestName
static QString suggestName(const KUrl &baseURL, const QString &oldName)
Given a directory path and a filename (which usually exists already), this function returns a suggest...
Definition: renamedialog.cpp:419
KIO::UDSEntry::UDS_CREATION_TIME
The time the file was created.
Definition: udsentry.h:177
KUrl::AppendTrailingSlash
KFileSystemType::Smb
kWarning
static QDebug kWarning(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
KIO::UDSEntry::UDS_DISPLAY_NAME
If set, contains the label to display instead of the &#39;real name&#39; in UDS_NAME.
Definition: udsentry.h:211
KIO::CopyJob::setAutoRename
void setAutoRename(bool autoRename)
Rename files automatically when the destination already exists, instead of the default behavior (inte...
Definition: copyjob.cpp:2150
KCompositeJob::hasSubjobs
bool hasSubjobs()
STATE_SETTING_DIR_ATTRIBUTES
Definition: copyjob.cpp:94
KIO::ERR_CANNOT_SYMLINK
Definition: global.h:253
STATE_COPYING_FILES
Definition: copyjob.cpp:91
deletejob.h
KIO::CopyInfo
Definition: copyjob.h:41
KUrl::url
QString url(AdjustPathOption trailing=LeaveTrailingSlash) const
KIO::StatJob::SourceSide
Definition: jobclasses.h:446
KProtocolManager::supportsListing
static bool supportsListing(const KUrl &url)
Returns whether the protocol can list files/objects.
Definition: kprotocolmanager.cpp:1034
KConfigGroup::sync
void sync()
KIO::CopyJob::emitResult
void emitResult()
Definition: copyjob.cpp:1744
KIO::CopyInfo::ctime
time_t ctime
Definition: copyjob.h:47
KJobTrackerInterface::registerJob
virtual void registerJob(KJob *job)
DEST_IS_DIR
Definition: copyjob.cpp:64
KFileItem::entry
KIO::UDSEntry entry() const
Returns the UDS entry.
Definition: kfileitem.cpp:1678
KUrl::isLocalFile
bool isLocalFile() const
KIO::CopyJob::operationMode
CopyMode operationMode() const
Returns the mode of the operation (copy, move, or link), depending on whether KIO::copy(), KIO::move() or KIO::link() was called.
Definition: copyjob.cpp:2139
KIO::JobPrivate
Definition: job_p.h:36
KProtocolManager::fileNameUsedForCopying
static KProtocolInfo::FileNameUsedForCopying fileNameUsedForCopying(const KUrl &url)
This setting defines the strategy to use for generating a filename, when copying a file or directory ...
Definition: kprotocolmanager.cpp:1162
end
const KShortcut & end()
utime
int utime(const QString &filename, struct utimbuf *buf)
KProtocolManager::canRenameFromFile
static bool canRenameFromFile(const KUrl &url)
Returns whether the protocol can rename (i.e.
Definition: kprotocolmanager.cpp:1134
KJob
KDirWatch::restartDirScan
bool restartDirScan(const QString &path)
KIO::UDSEntry::UDS_SIZE
Size of the file.
Definition: udsentry.h:144
kfileitem.h
KUrl::prettyUrl
QString prettyUrl(AdjustPathOption trailing=LeaveTrailingSlash) const
KProtocolInfo::DisplayName
KIO::trash
CopyJob * trash(const KUrl &src, JobFlags flags=DefaultFlags)
Trash a file or directory.
Definition: copyjob.cpp:2224
KFileItem::mostLocalUrl
KUrl mostLocalUrl(bool &local) const
Tries to give a local URL for this file item if possible.
Definition: kfileitem.cpp:1476
KFileItem
A KFileItem is a generic class to handle a file, local or remote.
Definition: kfileitem.h:45
KIO::CopyJob
CopyJob is used to move, copy or symlink files and directories.
Definition: copyjob.h:65
QList
KRecentDirs::list
QStringList list(const QString &fileClass)
Returns a list of directories associated with this file-class.
Definition: krecentdirs.cpp:60
OrgKdeKDirNotifyInterface::emitFileMoved
static void emitFileMoved(const QString &src, const QString &dst)
Definition: kdirnotify.cpp:42
KIO::CopyInfo::size
KIO::filesize_t size
Definition: copyjob.h:49
KIO::SimpleJob
A simple job (one url and one command).
Definition: jobclasses.h:322
KIO::M_MULTI
Definition: renamedialog.h:56
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Mon Jun 9 2014 22:00:59 by doxygen 1.8.5 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KIO

Skip menu "KIO"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs-4.10.5 API Reference

Skip menu "kdelibs-4.10.5 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal