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

KIO

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

Skip menu "kdelibs 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

Search



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