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

KDECore

  • 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
50class KArchivePrivate
51{
52public:
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
81KArchive::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
90KArchive::KArchive( QIODevice * dev )
91 : d(new KArchivePrivate)
92{
93 d->dev = dev;
94}
95
96KArchive::~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
104bool 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
131bool 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
164bool 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
198const 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
205bool 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
293bool 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
319bool 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
345bool 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
359bool 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
366bool 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
375bool 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
386bool KArchive::finishWriting( qint64 size )
387{
388 return doFinishWriting( size );
389}
390
391KArchiveDirectory * 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
406KArchiveDirectory * 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
456void KArchive::setDevice( QIODevice * dev )
457{
458 if ( d->deviceOwned )
459 delete d->dev;
460 d->dev = dev;
461 d->deviceOwned = false;
462}
463
464void KArchive::setRootDir( KArchiveDirectory *rootDir )
465{
466 Q_ASSERT( !d->rootDir ); // Call setRootDir only once during parsing please ;)
467 d->rootDir = rootDir;
468}
469
470QIODevice::OpenMode KArchive::mode() const
471{
472 return d->mode;
473}
474
475QIODevice * KArchive::device() const
476{
477 return d->dev;
478}
479
480bool KArchive::isOpen() const
481{
482 return d->mode != QIODevice::NotOpen;
483}
484
485QString KArchive::fileName() const
486{
487 return d->fileName;
488}
489
490void KArchivePrivate::abortWriting()
491{
492 if ( saveFile ) {
493 saveFile->abort();
494 delete saveFile;
495 saveFile = 0;
496 dev = 0;
497 }
498}
499
503
504class KArchiveEntryPrivate
505{
506public:
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
527KArchiveEntry::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
534KArchiveEntry::~KArchiveEntry()
535{
536 delete d;
537}
538
539QDateTime KArchiveEntry::datetime() const
540{
541 QDateTime datetimeobj;
542 datetimeobj.setTime_t( d->date );
543 return datetimeobj;
544}
545
546int KArchiveEntry::date() const
547{
548 return d->date;
549}
550
551QString KArchiveEntry::name() const
552{
553 return d->name;
554}
555
556mode_t KArchiveEntry::permissions() const
557{
558 return d->access;
559}
560
561QString KArchiveEntry::user() const
562{
563 return d->user;
564}
565
566QString KArchiveEntry::group() const
567{
568 return d->group;
569}
570
571QString KArchiveEntry::symLinkTarget() const
572{
573 return d->symlink;
574}
575
576bool KArchiveEntry::isFile() const
577{
578 return false;
579}
580
581bool KArchiveEntry::isDirectory() const
582{
583 return false;
584}
585
586KArchive* KArchiveEntry::archive() const
587{
588 return d->archive;
589}
590
594
595class KArchiveFilePrivate
596{
597public:
598 KArchiveFilePrivate( qint64 _pos, qint64 _size ) :
599 pos(_pos),
600 size(_size)
601 {}
602 qint64 pos;
603 qint64 size;
604};
605
606KArchiveFile::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
615KArchiveFile::~KArchiveFile()
616{
617 delete d;
618}
619
620qint64 KArchiveFile::position() const
621{
622 return d->pos;
623}
624
625qint64 KArchiveFile::size() const
626{
627 return d->size;
628}
629
630void KArchiveFile::setSize( qint64 s )
631{
632 d->size = s;
633}
634
635QByteArray 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
652QIODevice * KArchiveFile::createDevice() const
653{
654 return new KLimitedIODevice( archive()->device(), d->pos, d->size );
655}
656
657bool KArchiveFile::isFile() const
658{
659 return true;
660}
661
662void 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
692class KArchiveDirectoryPrivate
693{
694public:
695 ~KArchiveDirectoryPrivate()
696 {
697 qDeleteAll(entries);
698 }
699 QHash<QString, KArchiveEntry *> entries;
700};
701
702KArchiveDirectory::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
711KArchiveDirectory::~KArchiveDirectory()
712{
713 delete d;
714}
715
716QStringList KArchiveDirectory::entries() const
717{
718 return d->entries.keys();
719}
720
721const 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
757void 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
770void 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
791bool KArchiveDirectory::isDirectory() const
792{
793 return true;
794}
795
796static bool sortByPosition( const KArchiveFile* file1, const KArchiveFile* file2 ) {
797 return file1->position() < file2->position();
798}
799
800void KArchiveDirectory::copyTo(const QString& dest, bool recursiveCopy ) const
801{
802 QDir root;
803 const QString destDir(QDir(dest).absolutePath()); // get directory path without any "." or ".."
804
805 QList<const KArchiveFile*> fileList;
806 QMap<qint64, QString> fileToDir;
807
808 // placeholders for iterated items
809 QStack<const KArchiveDirectory *> dirStack;
810 QStack<QString> dirNameStack;
811
812 dirStack.push( this ); // init stack at current directory
813 dirNameStack.push( destDir ); // ... with given path
814 do {
815 const KArchiveDirectory* curDir = dirStack.pop();
816
817 // extract only to specified folder if it is located within archive's extraction folder
818 // otherwise put file under root position in extraction folder
819 QString curDirName = dirNameStack.pop();
820 if (!QDir(curDirName).absolutePath().startsWith(destDir)) {
821 qWarning() << "Attempted export into folder" << curDirName
822 << "which is outside of the extraction root folder" << destDir << "."
823 << "Changing export of contained files to extraction root folder.";
824 curDirName = destDir;
825 }
826
827 root.mkdir(curDirName);
828
829 const QStringList dirEntries = curDir->entries();
830 for ( QStringList::const_iterator it = dirEntries.begin(); it != dirEntries.end(); ++it ) {
831 const KArchiveEntry* curEntry = curDir->entry(*it);
832 if (!curEntry->symLinkTarget().isEmpty()) {
833 const QString linkName = curDirName+QLatin1Char('/')+curEntry->name();
834#ifdef Q_OS_UNIX
835 if (!::symlink(curEntry->symLinkTarget().toLocal8Bit(), linkName.toLocal8Bit())) {
836 kDebug() << "symlink(" << curEntry->symLinkTarget() << ',' << linkName << ") failed:" << strerror(errno);
837 }
838#else
839 // TODO - how to create symlinks on other platforms?
840#endif
841 } else {
842 if ( curEntry->isFile() ) {
843 const KArchiveFile* curFile = dynamic_cast<const KArchiveFile*>( curEntry );
844 if (curFile) {
845 fileList.append( curFile );
846 fileToDir.insert( curFile->position(), curDirName );
847 }
848 }
849
850 if ( curEntry->isDirectory() && recursiveCopy ) {
851 const KArchiveDirectory *ad = dynamic_cast<const KArchiveDirectory*>( curEntry );
852 if (ad) {
853 dirStack.push( ad );
854 dirNameStack.push( curDirName + QLatin1Char('/') + curEntry->name() );
855 }
856 }
857 }
858 }
859 } while (!dirStack.isEmpty());
860
861 qSort( fileList.begin(), fileList.end(), sortByPosition ); // sort on d->pos, so we have a linear access
862
863 for ( QList<const KArchiveFile*>::const_iterator it = fileList.constBegin(), end = fileList.constEnd() ;
864 it != end ; ++it ) {
865 const KArchiveFile* f = *it;
866 qint64 pos = f->position();
867 f->copyTo( fileToDir[pos] );
868 }
869}
870
871void KArchive::virtual_hook( int, void* )
872{ /*BASE::virtual_hook( id, data )*/; }
873
874void KArchiveEntry::virtual_hook( int, void* )
875{ /*BASE::virtual_hook( id, data );*/ }
876
877void KArchiveFile::virtual_hook( int id, void* data )
878{ KArchiveEntry::virtual_hook( id, data ); }
879
880void KArchiveDirectory::virtual_hook( int id, void* data )
881{ KArchiveEntry::virtual_hook( id, data ); }
KArchiveDirectory
Represents a directory entry in a KArchive.
Definition: karchive.h:543
KArchiveDirectory::~KArchiveDirectory
virtual ~KArchiveDirectory()
Definition: karchive.cpp:711
KArchiveDirectory::addEntry
void addEntry(KArchiveEntry *)
Definition: karchive.cpp:757
KArchiveDirectory::virtual_hook
virtual void virtual_hook(int id, void *data)
Definition: karchive.cpp:880
KArchiveDirectory::entries
QStringList entries() const
Returns a list of sub-entries.
Definition: karchive.cpp:716
KArchiveDirectory::removeEntry
void removeEntry(KArchiveEntry *)
Definition: karchive.cpp:770
KArchiveDirectory::entry
const KArchiveEntry * entry(const QString &name) const
Returns the entry with the given name.
Definition: karchive.cpp:721
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
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::isDirectory
virtual bool isDirectory() const
Checks whether this entry is a directory.
Definition: karchive.cpp:791
KArchiveEntry
A base class for entries in an KArchive.
Definition: karchive.h:370
KArchiveEntry::~KArchiveEntry
virtual ~KArchiveEntry()
Definition: karchive.cpp:534
KArchiveEntry::date
int date() const
Creation date of the file.
Definition: karchive.cpp:546
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::user
QString user() const
User who created the file.
Definition: karchive.cpp:561
KArchiveEntry::virtual_hook
virtual void virtual_hook(int id, void *data)
Definition: karchive.cpp:874
KArchiveEntry::archive
KArchive * archive() const
Definition: karchive.cpp:586
KArchiveEntry::isDirectory
virtual bool isDirectory() const
Checks whether the entry is a directory.
Definition: karchive.cpp:581
KArchiveEntry::group
QString group() const
Group of the user who created the file.
Definition: karchive.cpp:566
KArchiveEntry::name
QString name() const
Name of the file without path.
Definition: karchive.cpp:551
KArchiveEntry::symLinkTarget
QString symLinkTarget() const
Symlink if there is one.
Definition: karchive.cpp:571
KArchiveEntry::datetime
QDateTime datetime() const
Creation date of the file.
Definition: karchive.cpp:539
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::isFile
virtual bool isFile() const
Checks whether the entry is a file.
Definition: karchive.cpp:576
KArchiveFile
Represents a file entry in a KArchive.
Definition: karchive.h:458
KArchiveFile::virtual_hook
virtual void virtual_hook(int id, void *data)
Definition: karchive.cpp:877
KArchiveFile::size
qint64 size() const
Size of the data.
Definition: karchive.cpp:625
KArchiveFile::createDevice
virtual QIODevice * createDevice() const
This method returns QIODevice (internal class: KLimitedIODevice) on top of the underlying QIODevice.
Definition: karchive.cpp:652
KArchiveFile::data
virtual QByteArray data() const
Returns the data of the file.
Definition: karchive.cpp:635
KArchiveFile::setSize
void setSize(qint64 s)
Set size of data, usually after writing the file.
Definition: karchive.cpp:630
KArchiveFile::~KArchiveFile
virtual ~KArchiveFile()
Destructor.
Definition: karchive.cpp:615
KArchiveFile::copyTo
void copyTo(const QString &dest) const
Extracts the file to the directory dest.
Definition: karchive.cpp:662
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::isFile
virtual bool isFile() const
Checks whether this entry is a file.
Definition: karchive.cpp:657
KArchive
KArchive is a base class for reading and writing archives.
Definition: karchive.h:44
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
KArchive::close
virtual bool close()
Closes the archive.
Definition: karchive.cpp:164
KArchive::doFinishWriting
virtual bool doFinishWriting(qint64 size)=0
Called after writing the data.
KArchive::addLocalFile
bool addLocalFile(const QString &fileName, const QString &destName)
Writes a local file into the archive.
Definition: karchive.cpp:205
KArchive::rootDir
virtual KArchiveDirectory * rootDir()
Retrieves or create the root directory.
Definition: karchive.cpp:391
KArchive::finishWriting
virtual bool finishWriting(qint64 size)
Call finishWriting after writing the data.
Definition: karchive.cpp:386
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::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::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
KArchive::KArchive
KArchive(const QString &fileName)
Base constructor (protected since this is a pure virtual class).
Definition: karchive.cpp:81
KArchive::~KArchive
virtual ~KArchive()
Definition: karchive.cpp:96
KArchive::virtual_hook
virtual void virtual_hook(int id, void *data)
Definition: karchive.cpp:871
KArchive::open
virtual bool open(QIODevice::OpenMode mode)
Opens the archive for reading or writing.
Definition: karchive.cpp:104
KArchive::closeArchive
virtual bool closeArchive()=0
Closes the archive.
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
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
KArchive::openArchive
virtual bool openArchive(QIODevice::OpenMode mode)=0
Opens an archive for reading or writing.
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::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.
KArchive::findOrCreate
KArchiveDirectory * findOrCreate(const QString &path)
Ensures that path exists, create otherwise.
Definition: karchive.cpp:406
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::mode
QIODevice::OpenMode mode() const
Returns the mode in which the archive was opened.
Definition: karchive.cpp:470
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.
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
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
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
KArchive::isOpen
bool isOpen() const
Checks whether the archive is open.
Definition: karchive.cpp:480
KArchive::setDevice
void setDevice(QIODevice *dev)
Can be called by derived classes in order to set the underlying device.
Definition: karchive.cpp:456
KLimitedIODevice
A readonly device that reads from an underlying device from a given point to another (e....
Definition: klimitediodevice_p.h:32
KSaveFile
Class to allow for atomic file I/O, as well as utility functions.
Definition: ksavefile.h:97
QDateTime
QHash
Definition: ksycocafactory.h:28
QIODevice
QList
Definition: kaboutdata.h:33
QMap
QStringList
QString
qint64
kDebug
#define kDebug
Definition: kdebug.h:316
kWarning
#define kWarning
Definition: kdebug.h:322
sortByPosition
static bool sortByPosition(const KArchiveFile *file1, const KArchiveFile *file2)
Definition: karchive.cpp:796
karchive.h
kdebug.h
klimitediodevice_p.h
ksavefile.h
KDE::lstat
int lstat(const QString &path, KDE_struct_stat *buf)
Definition: kde_file_win.cpp:148
KDE::access
int access(const QString &path, int mode)
Definition: kde_file_win.cpp:123
KMacroExpander::group
@ group
Definition: kmacroexpander_unix.cpp:34
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 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-4.14.38 API Reference

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

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