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

KDECore

  • sources
  • kde-4.12
  • kdelibs
  • kdecore
  • io
karchive.cpp
Go to the documentation of this file.
1 /* This file is part of the KDE libraries
2  Copyright (C) 2000-2005 David Faure <faure@kde.org>
3  Copyright (C) 2003 Leo Savernik <l.savernik@aon.at>
4 
5  Moved from ktar.cpp by Roberto Teixeira <maragato@kde.org>
6 
7  This library is free software; you can redistribute it and/or
8  modify it under the terms of the GNU Library General Public
9  License version 2 as published by the Free Software Foundation.
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 "karchive.h"
23 #include "klimitediodevice_p.h"
24 
25 #include <config.h>
26 
27 #include <kdebug.h>
28 #include <ksavefile.h>
29 #include <kde_file.h>
30 
31 #include <QStack>
32 #include <QtCore/QMap>
33 #include <QtCore/QDir>
34 #include <QtCore/QFile>
35 
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <time.h>
39 #include <unistd.h>
40 #include <errno.h>
41 #include <grp.h>
42 #include <pwd.h>
43 #include <assert.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #ifdef Q_OS_UNIX
47 #include <limits.h> // PATH_MAX
48 #endif
49 
50 class KArchivePrivate
51 {
52 public:
53  KArchivePrivate()
54  : rootDir( 0 ),
55  saveFile( 0 ),
56  dev ( 0 ),
57  fileName(),
58  mode( QIODevice::NotOpen ),
59  deviceOwned( false )
60  {}
61  ~KArchivePrivate()
62  {
63  delete saveFile;
64  delete rootDir;
65  }
66  void abortWriting();
67 
68  KArchiveDirectory* rootDir;
69  KSaveFile* saveFile;
70  QIODevice * dev;
71  QString fileName;
72  QIODevice::OpenMode mode;
73  bool deviceOwned; // if true, we (KArchive) own dev and must delete it
74 };
75 
76 
80 
81 KArchive::KArchive( const QString& fileName )
82  : d(new KArchivePrivate)
83 {
84  Q_ASSERT( !fileName.isEmpty() );
85  d->fileName = fileName;
86  // This constructor leaves the device set to 0.
87  // This is for the use of KSaveFile, see open().
88 }
89 
90 KArchive::KArchive( QIODevice * dev )
91  : d(new KArchivePrivate)
92 {
93  d->dev = dev;
94 }
95 
96 KArchive::~KArchive()
97 {
98  if ( isOpen() )
99  close(); // WARNING: won't call the virtual method close in the derived class!!!
100 
101  delete d;
102 }
103 
104 bool KArchive::open( QIODevice::OpenMode mode )
105 {
106  Q_ASSERT( mode != QIODevice::NotOpen );
107 
108  if ( isOpen() )
109  close();
110 
111  if ( !d->fileName.isEmpty() )
112  {
113  Q_ASSERT( !d->dev );
114  if ( !createDevice( mode ) )
115  return false;
116  }
117 
118  Q_ASSERT( d->dev );
119 
120  if ( !d->dev->isOpen() && !d->dev->open( mode ) )
121  return false;
122 
123  d->mode = mode;
124 
125  Q_ASSERT( !d->rootDir );
126  d->rootDir = 0;
127 
128  return openArchive( mode );
129 }
130 
131 bool KArchive::createDevice( QIODevice::OpenMode mode )
132 {
133  switch( mode ) {
134  case QIODevice::WriteOnly:
135  if ( !d->fileName.isEmpty() ) {
136  // The use of KSaveFile can't be done in the ctor (no mode known yet)
137  //kDebug() << "Writing to a file using KSaveFile";
138  d->saveFile = new KSaveFile( d->fileName );
139  if ( !d->saveFile->open() ) {
140  kWarning() << "KSaveFile creation for " << d->fileName << " failed, " << d->saveFile->errorString();
141  delete d->saveFile;
142  d->saveFile = 0;
143  return false;
144  }
145  d->dev = d->saveFile;
146  Q_ASSERT( d->dev );
147  }
148  break;
149  case QIODevice::ReadOnly:
150  case QIODevice::ReadWrite:
151  // ReadWrite mode still uses QFile for now; we'd need to copy to the tempfile, in fact.
152  if ( !d->fileName.isEmpty() ) {
153  d->dev = new QFile( d->fileName );
154  d->deviceOwned = true;
155  }
156  break; // continued below
157  default:
158  kWarning() << "Unsupported mode " << d->mode;
159  return false;
160  }
161  return true;
162 }
163 
164 bool KArchive::close()
165 {
166  if ( !isOpen() )
167  return false; // already closed (return false or true? arguable...)
168 
169  // moved by holger to allow kzip to write the zip central dir
170  // to the file in closeArchive()
171  // DF: added d->dev so that we skip closeArchive if saving aborted.
172  bool closeSucceeded = true;
173  if ( d->dev ) {
174  closeSucceeded = closeArchive();
175  if ( d->mode == QIODevice::WriteOnly && !closeSucceeded )
176  d->abortWriting();
177  }
178 
179  if ( d->dev )
180  d->dev->close();
181 
182  // if d->saveFile is not null then it is equal to d->dev.
183  if ( d->saveFile ) {
184  closeSucceeded = d->saveFile->finalize();
185  delete d->saveFile;
186  d->saveFile = 0;
187  } if ( d->deviceOwned ) {
188  delete d->dev; // we created it ourselves in open()
189  }
190 
191  delete d->rootDir;
192  d->rootDir = 0;
193  d->mode = QIODevice::NotOpen;
194  d->dev = 0;
195  return closeSucceeded;
196 }
197 
198 const KArchiveDirectory* KArchive::directory() const
199 {
200  // rootDir isn't const so that parsing-on-demand is possible
201  return const_cast<KArchive *>(this)->rootDir();
202 }
203 
204 
205 bool KArchive::addLocalFile( const QString& fileName, const QString& destName )
206 {
207  QFileInfo fileInfo( fileName );
208  if ( !fileInfo.isFile() && !fileInfo.isSymLink() )
209  {
210  kWarning() << fileName << "doesn't exist or is not a regular file.";
211  return false;
212  }
213 
214  KDE_struct_stat fi;
215  if (KDE::lstat(fileName,&fi) == -1) {
216  kWarning() << "stat'ing" << fileName
217  << "failed:" << strerror(errno);
218  return false;
219  }
220 
221  if (fileInfo.isSymLink()) {
222  QString symLinkTarget;
223  // Do NOT use fileInfo.readLink() for unix symlinks!
224  // It returns the -full- path to the target, while we want the target string "as is".
225 #if defined(Q_OS_UNIX) && !defined(Q_OS_OS2EMX)
226  const QByteArray encodedFileName = QFile::encodeName(fileName);
227  QByteArray s;
228 #if defined(PATH_MAX)
229  s.resize(PATH_MAX+1);
230 #else
231  int path_max = pathconf(encodedFileName.data(), _PC_PATH_MAX);
232  if (path_max <= 0) {
233  path_max = 4096;
234  }
235  s.resize(path_max);
236 #endif
237  int len = readlink(encodedFileName.data(), s.data(), s.size() - 1);
238  if ( len >= 0 ) {
239  s[len] = '\0';
240  symLinkTarget = QFile::decodeName(s);
241  }
242 #endif
243  if (symLinkTarget.isEmpty()) // Mac or Windows
244  symLinkTarget = fileInfo.symLinkTarget();
245  return writeSymLink(destName, symLinkTarget, fileInfo.owner(),
246  fileInfo.group(), fi.st_mode, fi.st_atime, fi.st_mtime,
247  fi.st_ctime);
248  }/*end if*/
249 
250  qint64 size = fileInfo.size();
251 
252  // the file must be opened before prepareWriting is called, otherwise
253  // if the opening fails, no content will follow the already written
254  // header and the tar file is effectively f*cked up
255  QFile file( fileName );
256  if ( !file.open( QIODevice::ReadOnly ) )
257  {
258  kWarning() << "couldn't open file " << fileName;
259  return false;
260  }
261 
262  if ( !prepareWriting( destName, fileInfo.owner(), fileInfo.group(), size,
263  fi.st_mode, fi.st_atime, fi.st_mtime, fi.st_ctime ) )
264  {
265  kWarning() << " prepareWriting" << destName << "failed";
266  return false;
267  }
268 
269  // Read and write data in chunks to minimize memory usage
270  QByteArray array;
271  array.resize( int( qMin( qint64( 1024 * 1024 ), size ) ) );
272  qint64 n;
273  qint64 total = 0;
274  while ( ( n = file.read( array.data(), array.size() ) ) > 0 )
275  {
276  if ( !writeData( array.data(), n ) )
277  {
278  kWarning() << "writeData failed";
279  return false;
280  }
281  total += n;
282  }
283  Q_ASSERT( total == size );
284 
285  if ( !finishWriting( size ) )
286  {
287  kWarning() << "finishWriting failed";
288  return false;
289  }
290  return true;
291 }
292 
293 bool KArchive::addLocalDirectory( const QString& path, const QString& destName )
294 {
295  QDir dir( path );
296  if ( !dir.exists() )
297  return false;
298  dir.setFilter(dir.filter() | QDir::Hidden);
299  const QStringList files = dir.entryList();
300  for ( QStringList::ConstIterator it = files.begin(); it != files.end(); ++it )
301  {
302  if ( *it != QLatin1String(".") && *it != QLatin1String("..") )
303  {
304  QString fileName = path + QLatin1Char('/') + *it;
305 // kDebug() << "storing " << fileName;
306  QString dest = destName.isEmpty() ? *it : (destName + QLatin1Char('/') + *it);
307  QFileInfo fileInfo( fileName );
308 
309  if ( fileInfo.isFile() || fileInfo.isSymLink() )
310  addLocalFile( fileName, dest );
311  else if ( fileInfo.isDir() )
312  addLocalDirectory( fileName, dest );
313  // We omit sockets
314  }
315  }
316  return true;
317 }
318 
319 bool KArchive::writeFile( const QString& name, const QString& user,
320  const QString& group, const char* data, qint64 size,
321  mode_t perm, time_t atime, time_t mtime, time_t ctime )
322 {
323  if ( !prepareWriting( name, user, group, size, perm, atime, mtime, ctime ) )
324  {
325  kWarning() << "prepareWriting failed";
326  return false;
327  }
328 
329  // Write data
330  // Note: if data is 0L, don't call write, it would terminate the KFilterDev
331  if ( data && size && !writeData( data, size ) )
332  {
333  kWarning() << "writeData failed";
334  return false;
335  }
336 
337  if ( !finishWriting( size ) )
338  {
339  kWarning() << "finishWriting failed";
340  return false;
341  }
342  return true;
343 }
344 
345 bool KArchive::writeData( const char* data, qint64 size )
346 {
347  bool ok = device()->write( data, size ) == size;
348  if ( !ok )
349  d->abortWriting();
350  return ok;
351 }
352 
353 // The writeDir -> doWriteDir pattern allows to avoid propagating the default
354 // values into all virtual methods of subclasses, and it allows more extensibility:
355 // if a new argument is needed, we can add a writeDir overload which stores the
356 // additional argument in the d pointer, and doWriteDir reimplementations can fetch
357 // it from there.
358 
359 bool KArchive::writeDir( const QString& name, const QString& user, const QString& group,
360  mode_t perm, time_t atime,
361  time_t mtime, time_t ctime )
362 {
363  return doWriteDir( name, user, group, perm | 040000, atime, mtime, ctime );
364 }
365 
366 bool KArchive::writeSymLink(const QString &name, const QString &target,
367  const QString &user, const QString &group,
368  mode_t perm, time_t atime,
369  time_t mtime, time_t ctime )
370 {
371  return doWriteSymLink( name, target, user, group, perm, atime, mtime, ctime );
372 }
373 
374 
375 bool KArchive::prepareWriting( const QString& name, const QString& user,
376  const QString& group, qint64 size,
377  mode_t perm, time_t atime,
378  time_t mtime, time_t ctime )
379 {
380  bool ok = doPrepareWriting( name, user, group, size, perm, atime, mtime, ctime );
381  if ( !ok )
382  d->abortWriting();
383  return ok;
384 }
385 
386 bool KArchive::finishWriting( qint64 size )
387 {
388  return doFinishWriting( size );
389 }
390 
391 KArchiveDirectory * KArchive::rootDir()
392 {
393  if ( !d->rootDir )
394  {
395  //kDebug() << "Making root dir ";
396  struct passwd* pw = getpwuid( getuid() );
397  struct group* grp = getgrgid( getgid() );
398  QString username = pw ? QFile::decodeName(pw->pw_name) : QString::number( getuid() );
399  QString groupname = grp ? QFile::decodeName(grp->gr_name) : QString::number( getgid() );
400 
401  d->rootDir = new KArchiveDirectory( this, QLatin1String("/"), (int)(0777 + S_IFDIR), 0, username, groupname, QString() );
402  }
403  return d->rootDir;
404 }
405 
406 KArchiveDirectory * KArchive::findOrCreate( const QString & path )
407 {
408  //kDebug() << path;
409  if ( path.isEmpty() || path == QLatin1String("/") || path == QLatin1String(".") ) // root dir => found
410  {
411  //kDebug() << "returning rootdir";
412  return rootDir();
413  }
414  // Important note : for tar files containing absolute paths
415  // (i.e. beginning with "/"), this means the leading "/" will
416  // be removed (no KDirectory for it), which is exactly the way
417  // the "tar" program works (though it displays a warning about it)
418  // See also KArchiveDirectory::entry().
419 
420  // Already created ? => found
421  const KArchiveEntry* ent = rootDir()->entry( path );
422  if ( ent )
423  {
424  if ( ent->isDirectory() )
425  //kDebug() << "found it";
426  return (KArchiveDirectory *) ent;
427  else
428  kWarning() << "Found" << path << "but it's not a directory";
429  }
430 
431  // Otherwise go up and try again
432  int pos = path.lastIndexOf( QLatin1Char('/') );
433  KArchiveDirectory * parent;
434  QString dirname;
435  if ( pos == -1 ) // no more slash => create in root dir
436  {
437  parent = rootDir();
438  dirname = path;
439  }
440  else
441  {
442  QString left = path.left( pos );
443  dirname = path.mid( pos + 1 );
444  parent = findOrCreate( left ); // recursive call... until we find an existing dir.
445  }
446 
447  //kDebug() << "found parent " << parent->name() << " adding " << dirname << " to ensure " << path;
448  // Found -> add the missing piece
449  KArchiveDirectory * e = new KArchiveDirectory( this, dirname, d->rootDir->permissions(),
450  d->rootDir->date(), d->rootDir->user(),
451  d->rootDir->group(), QString() );
452  parent->addEntry( e );
453  return e; // now a directory to <path> exists
454 }
455 
456 void KArchive::setDevice( QIODevice * dev )
457 {
458  if ( d->deviceOwned )
459  delete d->dev;
460  d->dev = dev;
461  d->deviceOwned = false;
462 }
463 
464 void KArchive::setRootDir( KArchiveDirectory *rootDir )
465 {
466  Q_ASSERT( !d->rootDir ); // Call setRootDir only once during parsing please ;)
467  d->rootDir = rootDir;
468 }
469 
470 QIODevice::OpenMode KArchive::mode() const
471 {
472  return d->mode;
473 }
474 
475 QIODevice * KArchive::device() const
476 {
477  return d->dev;
478 }
479 
480 bool KArchive::isOpen() const
481 {
482  return d->mode != QIODevice::NotOpen;
483 }
484 
485 QString KArchive::fileName() const
486 {
487  return d->fileName;
488 }
489 
490 void KArchivePrivate::abortWriting()
491 {
492  if ( saveFile ) {
493  saveFile->abort();
494  delete saveFile;
495  saveFile = 0;
496  dev = 0;
497  }
498 }
499 
503 
504 class KArchiveEntryPrivate
505 {
506 public:
507  KArchiveEntryPrivate( KArchive* _archive, const QString& _name, int _access,
508  int _date, const QString& _user, const QString& _group,
509  const QString& _symlink) :
510  name(_name),
511  date(_date),
512  access(_access),
513  user(_user),
514  group(_group),
515  symlink(_symlink),
516  archive(_archive)
517  {}
518  QString name;
519  int date;
520  mode_t access;
521  QString user;
522  QString group;
523  QString symlink;
524  KArchive* archive;
525 };
526 
527 KArchiveEntry::KArchiveEntry( KArchive* t, const QString& name, int access, int date,
528  const QString& user, const QString& group, const
529  QString& symlink) :
530  d(new KArchiveEntryPrivate(t,name,access,date,user,group,symlink))
531 {
532 }
533 
534 KArchiveEntry::~KArchiveEntry()
535 {
536  delete d;
537 }
538 
539 QDateTime KArchiveEntry::datetime() const
540 {
541  QDateTime datetimeobj;
542  datetimeobj.setTime_t( d->date );
543  return datetimeobj;
544 }
545 
546 int KArchiveEntry::date() const
547 {
548  return d->date;
549 }
550 
551 QString KArchiveEntry::name() const
552 {
553  return d->name;
554 }
555 
556 mode_t KArchiveEntry::permissions() const
557 {
558  return d->access;
559 }
560 
561 QString KArchiveEntry::user() const
562 {
563  return d->user;
564 }
565 
566 QString KArchiveEntry::group() const
567 {
568  return d->group;
569 }
570 
571 QString KArchiveEntry::symLinkTarget() const
572 {
573  return d->symlink;
574 }
575 
576 bool KArchiveEntry::isFile() const
577 {
578  return false;
579 }
580 
581 bool KArchiveEntry::isDirectory() const
582 {
583  return false;
584 }
585 
586 KArchive* KArchiveEntry::archive() const
587 {
588  return d->archive;
589 }
590 
594 
595 class KArchiveFilePrivate
596 {
597 public:
598  KArchiveFilePrivate( qint64 _pos, qint64 _size ) :
599  pos(_pos),
600  size(_size)
601  {}
602  qint64 pos;
603  qint64 size;
604 };
605 
606 KArchiveFile::KArchiveFile( KArchive* t, const QString& name, int access, int date,
607  const QString& user, const QString& group,
608  const QString & symlink,
609  qint64 pos, qint64 size )
610  : KArchiveEntry( t, name, access, date, user, group, symlink ),
611  d( new KArchiveFilePrivate(pos, size) )
612 {
613 }
614 
615 KArchiveFile::~KArchiveFile()
616 {
617  delete d;
618 }
619 
620 qint64 KArchiveFile::position() const
621 {
622  return d->pos;
623 }
624 
625 qint64 KArchiveFile::size() const
626 {
627  return d->size;
628 }
629 
630 void KArchiveFile::setSize( qint64 s )
631 {
632  d->size = s;
633 }
634 
635 QByteArray KArchiveFile::data() const
636 {
637  bool ok = archive()->device()->seek( d->pos );
638  if (!ok) {
639  kWarning() << "Failed to sync to" << d->pos << "to read" << name();
640  }
641 
642  // Read content
643  QByteArray arr;
644  if ( d->size )
645  {
646  arr = archive()->device()->read( d->size );
647  Q_ASSERT( arr.size() == d->size );
648  }
649  return arr;
650 }
651 
652 QIODevice * KArchiveFile::createDevice() const
653 {
654  return new KLimitedIODevice( archive()->device(), d->pos, d->size );
655 }
656 
657 bool KArchiveFile::isFile() const
658 {
659  return true;
660 }
661 
662 void KArchiveFile::copyTo(const QString& dest) const
663 {
664  QFile f( dest + QLatin1Char('/') + name() );
665  if ( f.open( QIODevice::ReadWrite | QIODevice::Truncate ) )
666  {
667  QIODevice* inputDev = createDevice();
668 
669  // Read and write data in chunks to minimize memory usage
670  const qint64 chunkSize = 1024 * 1024;
671  qint64 remainingSize = d->size;
672  QByteArray array;
673  array.resize( int( qMin( chunkSize, remainingSize ) ) );
674 
675  while ( remainingSize > 0 ) {
676  const qint64 currentChunkSize = qMin( chunkSize, remainingSize );
677  const qint64 n = inputDev->read( array.data(), currentChunkSize );
678  Q_ASSERT( n == currentChunkSize );
679  f.write( array.data(), currentChunkSize );
680  remainingSize -= currentChunkSize;
681  }
682  f.close();
683 
684  delete inputDev;
685  }
686 }
687 
691 
692 class KArchiveDirectoryPrivate
693 {
694 public:
695  ~KArchiveDirectoryPrivate()
696  {
697  qDeleteAll(entries);
698  }
699  QHash<QString, KArchiveEntry *> entries;
700 };
701 
702 KArchiveDirectory::KArchiveDirectory( KArchive* t, const QString& name, int access,
703  int date,
704  const QString& user, const QString& group,
705  const QString &symlink)
706  : KArchiveEntry( t, name, access, date, user, group, symlink ),
707  d( new KArchiveDirectoryPrivate )
708 {
709 }
710 
711 KArchiveDirectory::~KArchiveDirectory()
712 {
713  delete d;
714 }
715 
716 QStringList KArchiveDirectory::entries() const
717 {
718  return d->entries.keys();
719 }
720 
721 const KArchiveEntry* KArchiveDirectory::entry( const QString& _name ) const
722 {
723  QString name = QDir::cleanPath(_name);
724  int pos = name.indexOf( QLatin1Char('/') );
725  if ( pos == 0 ) // ouch absolute path (see also KArchive::findOrCreate)
726  {
727  if (name.length()>1)
728  {
729  name = name.mid( 1 ); // remove leading slash
730  pos = name.indexOf( QLatin1Char('/') ); // look again
731  }
732  else // "/"
733  return this;
734  }
735  // trailing slash ? -> remove
736  if ( pos != -1 && pos == name.length()-1 )
737  {
738  name = name.left( pos );
739  pos = name.indexOf( QLatin1Char('/') ); // look again
740  }
741  if ( pos != -1 )
742  {
743  const QString left = name.left(pos);
744  const QString right = name.mid(pos + 1);
745 
746  //kDebug() << "left=" << left << "right=" << right;
747 
748  const KArchiveEntry* e = d->entries.value( left );
749  if ( !e || !e->isDirectory() )
750  return 0;
751  return static_cast<const KArchiveDirectory*>(e)->entry( right );
752  }
753 
754  return d->entries.value( name );
755 }
756 
757 void KArchiveDirectory::addEntry( KArchiveEntry* entry )
758 {
759  if( entry->name().isEmpty() )
760  return;
761 
762  if( d->entries.value( entry->name() ) ) {
763  kWarning() << "directory " << name()
764  << "has entry" << entry->name() << "already";
765  return;
766  }
767  d->entries.insert( entry->name(), entry );
768 }
769 
770 void KArchiveDirectory::removeEntry( KArchiveEntry* entry )
771 {
772  if (!entry) {
773  return;
774  }
775 
776  QHash<QString, KArchiveEntry*>::Iterator it = d->entries.find(entry->name());
777  // nothing removed?
778  if (it == d->entries.end()) {
779  kWarning() << "directory " << name()
780  << "has no entry with name " << entry->name();
781  return;
782  }
783  if (it.value() != entry) {
784  kWarning() << "directory " << name()
785  << "has another entry for name " << entry->name();
786  return;
787  }
788  d->entries.erase(it);
789 }
790 
791 bool KArchiveDirectory::isDirectory() const
792 {
793  return true;
794 }
795 
796 static bool sortByPosition( const KArchiveFile* file1, const KArchiveFile* file2 ) {
797  return file1->position() < file2->position();
798 }
799 
800 void KArchiveDirectory::copyTo(const QString& dest, bool recursiveCopy ) const
801 {
802  QDir root;
803 
804  QList<const KArchiveFile*> fileList;
805  QMap<qint64, QString> fileToDir;
806 
807  // placeholders for iterated items
808  QStack<const KArchiveDirectory *> dirStack;
809  QStack<QString> dirNameStack;
810 
811  dirStack.push( this ); // init stack at current directory
812  dirNameStack.push( dest ); // ... with given path
813  do {
814  const KArchiveDirectory* curDir = dirStack.pop();
815  const QString curDirName = dirNameStack.pop();
816  root.mkdir(curDirName);
817 
818  const QStringList dirEntries = curDir->entries();
819  for ( QStringList::const_iterator it = dirEntries.begin(); it != dirEntries.end(); ++it ) {
820  const KArchiveEntry* curEntry = curDir->entry(*it);
821  if (!curEntry->symLinkTarget().isEmpty()) {
822  const QString linkName = curDirName+QLatin1Char('/')+curEntry->name();
823 #ifdef Q_OS_UNIX
824  if (!::symlink(curEntry->symLinkTarget().toLocal8Bit(), linkName.toLocal8Bit())) {
825  kDebug() << "symlink(" << curEntry->symLinkTarget() << ',' << linkName << ") failed:" << strerror(errno);
826  }
827 #else
828  // TODO - how to create symlinks on other platforms?
829 #endif
830  } else {
831  if ( curEntry->isFile() ) {
832  const KArchiveFile* curFile = dynamic_cast<const KArchiveFile*>( curEntry );
833  if (curFile) {
834  fileList.append( curFile );
835  fileToDir.insert( curFile->position(), curDirName );
836  }
837  }
838 
839  if ( curEntry->isDirectory() && recursiveCopy ) {
840  const KArchiveDirectory *ad = dynamic_cast<const KArchiveDirectory*>( curEntry );
841  if (ad) {
842  dirStack.push( ad );
843  dirNameStack.push( curDirName + QLatin1Char('/') + curEntry->name() );
844  }
845  }
846  }
847  }
848  } while (!dirStack.isEmpty());
849 
850  qSort( fileList.begin(), fileList.end(), sortByPosition ); // sort on d->pos, so we have a linear access
851 
852  for ( QList<const KArchiveFile*>::const_iterator it = fileList.constBegin(), end = fileList.constEnd() ;
853  it != end ; ++it ) {
854  const KArchiveFile* f = *it;
855  qint64 pos = f->position();
856  f->copyTo( fileToDir[pos] );
857  }
858 }
859 
860 void KArchive::virtual_hook( int, void* )
861 { /*BASE::virtual_hook( id, data )*/; }
862 
863 void KArchiveEntry::virtual_hook( int, void* )
864 { /*BASE::virtual_hook( id, data );*/ }
865 
866 void KArchiveFile::virtual_hook( int id, void* data )
867 { KArchiveEntry::virtual_hook( id, data ); }
868 
869 void KArchiveDirectory::virtual_hook( int id, void* data )
870 { KArchiveEntry::virtual_hook( id, data ); }
KArchiveDirectory::removeEntry
void removeEntry(KArchiveEntry *)
Definition: karchive.cpp:770
KArchive::writeDir
virtual bool writeDir(const QString &name, const QString &user, const QString &group, mode_t perm=040755, time_t atime=UnknownTime, time_t mtime=UnknownTime, time_t ctime=UnknownTime)
If an archive is opened for writing then you can add new directories using this function.
Definition: karchive.cpp:359
qint64
KArchiveEntry::KArchiveEntry
KArchiveEntry(KArchive *archive, const QString &name, int access, int date, const QString &user, const QString &group, const QString &symlink)
Creates a new entry.
Definition: karchive.cpp:527
KArchiveEntry::symLinkTarget
QString symLinkTarget() const
Symlink if there is one.
Definition: karchive.cpp:571
KArchive::virtual_hook
virtual void virtual_hook(int id, void *data)
Definition: karchive.cpp:860
kdebug.h
KArchive::rootDir
virtual KArchiveDirectory * rootDir()
Retrieves or create the root directory.
Definition: karchive.cpp:391
KArchiveEntry::isDirectory
virtual bool isDirectory() const
Checks whether the entry is a directory.
Definition: karchive.cpp:581
KArchive::KArchive
KArchive(const QString &fileName)
Base constructor (protected since this is a pure virtual class).
Definition: karchive.cpp:81
KArchive::device
QIODevice * device() const
The underlying device.
Definition: karchive.cpp:475
KArchive::createDevice
virtual bool createDevice(QIODevice::OpenMode mode)
Can be reimplemented in order to change the creation of the device (when using the fileName construct...
Definition: karchive.cpp:131
KMacroExpander::group
Definition: kmacroexpander_unix.cpp:34
KArchiveFile::size
qint64 size() const
Size of the data.
Definition: karchive.cpp:625
KArchive
KArchive is a base class for reading and writing archives.
Definition: karchive.h:43
ksavefile.h
KArchiveDirectory::isDirectory
virtual bool isDirectory() const
Checks whether this entry is a directory.
Definition: karchive.cpp:791
KSaveFile
Class to allow for atomic file I/O, as well as utility functions.
Definition: ksavefile.h:96
QString
QHash< QString, KArchiveEntry * >
KArchiveFile::setSize
void setSize(qint64 s)
Set size of data, usually after writing the file.
Definition: karchive.cpp:630
KArchive::openArchive
virtual bool openArchive(QIODevice::OpenMode mode)=0
Opens an archive for reading or writing.
KArchive::close
virtual bool close()
Closes the archive.
Definition: karchive.cpp:164
KArchive::mode
QIODevice::OpenMode mode() const
Returns the mode in which the archive was opened.
Definition: karchive.cpp:470
KArchiveEntry::group
QString group() const
Group of the user who created the file.
Definition: karchive.cpp:566
KArchive::writeFile
virtual bool writeFile(const QString &name, const QString &user, const QString &group, const char *data, qint64 size, mode_t perm=0100644, time_t atime=UnknownTime, time_t mtime=UnknownTime, time_t ctime=UnknownTime)
If an archive is opened for writing then you can add a new file using this function.
Definition: karchive.cpp:319
KArchiveFile::position
qint64 position() const
Position of the data in the [uncompressed] archive.
Definition: karchive.cpp:620
KArchiveFile::KArchiveFile
KArchiveFile(KArchive *archive, const QString &name, int access, int date, const QString &user, const QString &group, const QString &symlink, qint64 pos, qint64 size)
Creates a new file entry.
Definition: karchive.cpp:606
KArchiveFile::~KArchiveFile
virtual ~KArchiveFile()
Destructor.
Definition: karchive.cpp:615
KArchive::writeData
virtual bool writeData(const char *data, qint64 size)
Write data into the current file - to be called after calling prepareWriting.
Definition: karchive.cpp:345
KArchive::prepareWriting
virtual bool prepareWriting(const QString &name, const QString &user, const QString &group, qint64 size, mode_t perm=0100644, time_t atime=UnknownTime, time_t mtime=UnknownTime, time_t ctime=UnknownTime)
Here's another way of writing a file into an archive: Call prepareWriting(), then call writeData() as...
Definition: karchive.cpp:375
karchive.h
KArchive::open
virtual bool open(QIODevice::OpenMode mode)
Opens the archive for reading or writing.
Definition: karchive.cpp:104
KArchiveFile::virtual_hook
virtual void virtual_hook(int id, void *data)
Definition: karchive.cpp:866
sortByPosition
static bool sortByPosition(const KArchiveFile *file1, const KArchiveFile *file2)
Definition: karchive.cpp:796
KArchiveFile::createDevice
virtual QIODevice * createDevice() const
This method returns QIODevice (internal class: KLimitedIODevice) on top of the underlying QIODevice...
Definition: karchive.cpp:652
KArchive::fileName
QString fileName() const
The name of the archive file, as passed to the constructor that takes a fileName, or an empty string ...
Definition: karchive.cpp:485
QStringList
klimitediodevice_p.h
KArchiveEntry
A base class for entries in an KArchive.
Definition: karchive.h:369
KArchive::finishWriting
virtual bool finishWriting(qint64 size)
Call finishWriting after writing the data.
Definition: karchive.cpp:386
KArchiveFile::copyTo
void copyTo(const QString &dest) const
Extracts the file to the directory dest.
Definition: karchive.cpp:662
KLimitedIODevice
A readonly device that reads from an underlying device from a given point to another (e...
Definition: klimitediodevice_p.h:31
KArchiveDirectory::KArchiveDirectory
KArchiveDirectory(KArchive *archive, const QString &name, int access, int date, const QString &user, const QString &group, const QString &symlink)
Creates a new directory entry.
Definition: karchive.cpp:702
KArchiveEntry::user
QString user() const
User who created the file.
Definition: karchive.cpp:561
KArchive::doWriteSymLink
virtual bool doWriteSymLink(const QString &name, const QString &target, const QString &user, const QString &group, mode_t perm, time_t atime, time_t mtime, time_t ctime)=0
Writes a symbolic link to the archive.
KArchiveFile::isFile
virtual bool isFile() const
Checks whether this entry is a file.
Definition: karchive.cpp:657
KArchiveDirectory::~KArchiveDirectory
virtual ~KArchiveDirectory()
Definition: karchive.cpp:711
KArchive::addLocalFile
bool addLocalFile(const QString &fileName, const QString &destName)
Writes a local file into the archive.
Definition: karchive.cpp:205
KArchive::doWriteDir
virtual bool doWriteDir(const QString &name, const QString &user, const QString &group, mode_t perm, time_t atime, time_t mtime, time_t ctime)=0
Write a directory to the archive.
KArchive::isOpen
bool isOpen() const
Checks whether the archive is open.
Definition: karchive.cpp:480
KArchiveDirectory::copyTo
void copyTo(const QString &dest, bool recursive=true) const
Extracts all entries in this archive directory to the directory dest.
Definition: karchive.cpp:800
KArchiveDirectory::entry
const KArchiveEntry * entry(const QString &name) const
Returns the entry with the given name.
Definition: karchive.cpp:721
kWarning
#define kWarning
Definition: kdebug.h:322
KDE::lstat
int lstat(const QString &path, KDE_struct_stat *buf)
Definition: kde_file_win.cpp:148
KArchive::doPrepareWriting
virtual bool doPrepareWriting(const QString &name, const QString &user, const QString &group, qint64 size, mode_t perm, time_t atime, time_t mtime, time_t ctime)=0
This virtual method must be implemented by subclasses.
KArchiveDirectory::addEntry
void addEntry(KArchiveEntry *)
Definition: karchive.cpp:757
QDateTime
KArchive::findOrCreate
KArchiveDirectory * findOrCreate(const QString &path)
Ensures that path exists, create otherwise.
Definition: karchive.cpp:406
KArchiveDirectory
Represents a directory entry in a KArchive.
Definition: karchive.h:542
KArchiveEntry::date
int date() const
Creation date of the file.
Definition: karchive.cpp:546
KDE::access
int access(const QString &path, int mode)
Definition: kde_file_win.cpp:123
KArchive::closeArchive
virtual bool closeArchive()=0
Closes the archive.
KArchive::writeSymLink
virtual bool writeSymLink(const QString &name, const QString &target, const QString &user, const QString &group, mode_t perm=0120755, time_t atime=UnknownTime, time_t mtime=UnknownTime, time_t ctime=UnknownTime)
Writes a symbolic link to the archive if supported.
Definition: karchive.cpp:366
KArchiveFile
Represents a file entry in a KArchive.
Definition: karchive.h:457
KArchive::setRootDir
void setRootDir(KArchiveDirectory *rootDir)
Derived classes call setRootDir from openArchive, to set the root directory after parsing an existing...
Definition: karchive.cpp:464
KArchiveEntry::name
QString name() const
Name of the file without path.
Definition: karchive.cpp:551
kDebug
#define kDebug
Definition: kdebug.h:316
KArchive::directory
const KArchiveDirectory * directory() const
If an archive is opened for reading, then the contents of the archive can be accessed via this functi...
Definition: karchive.cpp:198
KArchiveDirectory::virtual_hook
virtual void virtual_hook(int id, void *data)
Definition: karchive.cpp:869
KArchive::doFinishWriting
virtual bool doFinishWriting(qint64 size)=0
Called after writing the data.
KArchive::setDevice
void setDevice(QIODevice *dev)
Can be called by derived classes in order to set the underlying device.
Definition: karchive.cpp:456
KArchiveEntry::~KArchiveEntry
virtual ~KArchiveEntry()
Definition: karchive.cpp:534
KArchive::addLocalDirectory
bool addLocalDirectory(const QString &path, const QString &destName)
Writes a local directory into the archive, including all its contents, recursively.
Definition: karchive.cpp:293
KArchive::~KArchive
virtual ~KArchive()
Definition: karchive.cpp:96
QIODevice
KArchiveFile::data
virtual QByteArray data() const
Returns the data of the file.
Definition: karchive.cpp:635
KArchiveEntry::permissions
mode_t permissions() const
The permissions and mode flags as returned by the stat() function in st_mode.
Definition: karchive.cpp:556
KArchiveEntry::datetime
QDateTime datetime() const
Creation date of the file.
Definition: karchive.cpp:539
KArchiveEntry::isFile
virtual bool isFile() const
Checks whether the entry is a file.
Definition: karchive.cpp:576
KArchiveDirectory::entries
QStringList entries() const
Returns a list of sub-entries.
Definition: karchive.cpp:716
QMap
QList
Definition: kaboutdata.h:33
KArchiveEntry::archive
KArchive * archive() const
Definition: karchive.cpp:586
KArchiveEntry::virtual_hook
virtual void virtual_hook(int id, void *data)
Definition: karchive.cpp:863
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:47:07 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDECore

Skip menu "KDECore"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • 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
  • kjsembed
  •   WTF
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Nepomuk-Core
  • 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