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

KDECore

karchive.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE libraries
00002    Copyright (C) 2000-2005 David Faure <faure@kde.org>
00003    Copyright (C) 2003 Leo Savernik <l.savernik@aon.at>
00004 
00005    Moved from ktar.cpp by Roberto Teixeira <maragato@kde.org>
00006 
00007    This library is free software; you can redistribute it and/or
00008    modify it under the terms of the GNU Library General Public
00009    License version 2 as published by the Free Software Foundation.
00010 
00011    This library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Library General Public License for more details.
00015 
00016    You should have received a copy of the GNU Library General Public License
00017    along with this library; see the file COPYING.LIB.  If not, write to
00018    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019    Boston, MA 02110-1301, USA.
00020 */
00021 
00022 #include "karchive.h"
00023 #include "klimitediodevice_p.h"
00024 
00025 #include <config.h>
00026 
00027 #include <kdebug.h>
00028 #include <ksavefile.h>
00029 #include <kde_file.h>
00030 
00031 #include <QStack>
00032 #include <QtCore/QMap>
00033 #include <QtCore/QDir>
00034 #include <QtCore/QFile>
00035 
00036 #include <stdio.h>
00037 #include <stdlib.h>
00038 #include <time.h>
00039 #include <unistd.h>
00040 #include <errno.h>
00041 #include <grp.h>
00042 #include <pwd.h>
00043 #include <assert.h>
00044 #include <sys/types.h>
00045 #include <sys/stat.h>
00046 #ifdef Q_OS_UNIX
00047 #include <limits.h>  // PATH_MAX
00048 #endif
00049 
00050 class KArchivePrivate
00051 {
00052 public:
00053     KArchivePrivate()
00054         : rootDir( 0 ),
00055           saveFile( 0 ),
00056           dev ( 0 ),
00057           fileName(),
00058           mode( QIODevice::NotOpen ),
00059           deviceOwned( false )
00060     {}
00061     ~KArchivePrivate()
00062     {
00063         delete saveFile;
00064         delete rootDir;
00065     }
00066     void abortWriting();
00067 
00068     KArchiveDirectory* rootDir;
00069     KSaveFile* saveFile;
00070     QIODevice * dev;
00071     QString fileName;
00072     QIODevice::OpenMode mode;
00073     bool deviceOwned; // if true, we (KArchive) own dev and must delete it
00074 };
00075 
00076 
00080 
00081 KArchive::KArchive( const QString& fileName )
00082     : d(new KArchivePrivate)
00083 {
00084     Q_ASSERT( !fileName.isEmpty() );
00085     d->fileName = fileName;
00086     // This constructor leaves the device set to 0.
00087     // This is for the use of KSaveFile, see open().
00088 }
00089 
00090 KArchive::KArchive( QIODevice * dev )
00091     : d(new KArchivePrivate)
00092 {
00093     d->dev = dev;
00094 }
00095 
00096 KArchive::~KArchive()
00097 {
00098     if ( isOpen() )
00099         close(); // WARNING: won't call the virtual method close in the derived class!!!
00100 
00101     delete d;
00102 }
00103 
00104 bool KArchive::open( QIODevice::OpenMode mode )
00105 {
00106     Q_ASSERT( mode != QIODevice::NotOpen );
00107 
00108     if ( isOpen() )
00109         close();
00110 
00111     if ( !d->fileName.isEmpty() )
00112     {
00113         Q_ASSERT( !d->dev );
00114         if ( !createDevice( mode ) )
00115             return false;
00116     }
00117 
00118     Q_ASSERT( d->dev );
00119 
00120     if ( !d->dev->isOpen() && !d->dev->open( mode ) )
00121         return false;
00122 
00123     d->mode = mode;
00124 
00125     Q_ASSERT( !d->rootDir );
00126     d->rootDir = 0;
00127 
00128     return openArchive( mode );
00129 }
00130 
00131 bool KArchive::createDevice( QIODevice::OpenMode mode )
00132 {
00133     switch( mode ) {
00134     case QIODevice::WriteOnly:
00135         if ( !d->fileName.isEmpty() ) {
00136             // The use of KSaveFile can't be done in the ctor (no mode known yet)
00137             //kDebug() << "Writing to a file using KSaveFile";
00138             d->saveFile = new KSaveFile( d->fileName );
00139             if ( !d->saveFile->open() ) {
00140                 kWarning() << "KSaveFile creation for " << d->fileName << " failed, " << d->saveFile->errorString();
00141                 delete d->saveFile;
00142                 d->saveFile = 0;
00143                 return false;
00144             }
00145             d->dev = d->saveFile;
00146             Q_ASSERT( d->dev );
00147         }
00148         break;
00149     case QIODevice::ReadOnly:
00150     case QIODevice::ReadWrite:
00151         // ReadWrite mode still uses QFile for now; we'd need to copy to the tempfile, in fact.
00152         if ( !d->fileName.isEmpty() ) {
00153             d->dev = new QFile( d->fileName );
00154             d->deviceOwned = true;
00155         }
00156         break; // continued below
00157     default:
00158         kWarning() << "Unsupported mode " << d->mode;
00159         return false;
00160     }
00161     return true;
00162 }
00163 
00164 bool KArchive::close()
00165 {
00166     if ( !isOpen() )
00167         return false; // already closed (return false or true? arguable...)
00168 
00169     // moved by holger to allow kzip to write the zip central dir
00170     // to the file in closeArchive()
00171     // DF: added d->dev so that we skip closeArchive if saving aborted.
00172     bool closeSucceeded = true;
00173     if ( d->dev ) {
00174         closeSucceeded = closeArchive();
00175         if ( d->mode == QIODevice::WriteOnly && !closeSucceeded )
00176             d->abortWriting();
00177     }
00178 
00179     if ( d->dev )
00180         d->dev->close();
00181 
00182     if ( d->deviceOwned ) {
00183         delete d->dev; // we created it ourselves in open()
00184     }
00185     if ( d->saveFile ) {
00186         closeSucceeded = d->saveFile->finalize();
00187         delete d->saveFile;
00188         d->saveFile = 0;
00189     }
00190 
00191     delete d->rootDir;
00192     d->rootDir = 0;
00193     d->mode = QIODevice::NotOpen;
00194     d->dev = 0;
00195     return closeSucceeded;
00196 }
00197 
00198 const KArchiveDirectory* KArchive::directory() const
00199 {
00200     // rootDir isn't const so that parsing-on-demand is possible
00201     return const_cast<KArchive *>(this)->rootDir();
00202 }
00203 
00204 
00205 bool KArchive::addLocalFile( const QString& fileName, const QString& destName )
00206 {
00207     QFileInfo fileInfo( fileName );
00208     if ( !fileInfo.isFile() && !fileInfo.isSymLink() )
00209     {
00210         kWarning() << fileName << "doesn't exist or is not a regular file.";
00211         return false;
00212     }
00213 
00214     KDE_struct_stat fi;
00215     if (KDE::lstat(fileName,&fi) == -1) {
00216         kWarning() << "stat'ing" << fileName
00217             << "failed:" << strerror(errno);
00218         return false;
00219     }
00220 
00221     if (fileInfo.isSymLink()) {
00222         QString symLinkTarget;
00223         // Do NOT use fileInfo.readLink() for unix symlinks!
00224         // It returns the -full- path to the target, while we want the target string "as is".
00225 #if defined(Q_OS_UNIX) && !defined(Q_OS_OS2EMX)
00226         const QByteArray encodedFileName = QFile::encodeName(fileName);
00227         QByteArray s;
00228 #if defined(PATH_MAX)
00229         s.resize(PATH_MAX+1);
00230 #else
00231         int path_max = pathconf(encodedFileName.data(), _PC_PATH_MAX);
00232         if (path_max <= 0) {
00233             path_max = 4096;
00234         }
00235         s.resize(path_max);
00236 #endif
00237         int len = readlink(encodedFileName.data(), s.data(), s.size() - 1);
00238         if ( len >= 0 ) {
00239             s[len] = '\0';
00240             symLinkTarget = QFile::decodeName(s);
00241         }
00242 #endif
00243         if (symLinkTarget.isEmpty()) // Mac or Windows
00244             symLinkTarget = fileInfo.symLinkTarget();
00245         return writeSymLink(destName, symLinkTarget, fileInfo.owner(),
00246                             fileInfo.group(), fi.st_mode, fi.st_atime, fi.st_mtime,
00247                             fi.st_ctime);
00248     }/*end if*/
00249 
00250     qint64 size = fileInfo.size();
00251 
00252     // the file must be opened before prepareWriting is called, otherwise
00253     // if the opening fails, no content will follow the already written
00254     // header and the tar file is effectively f*cked up
00255     QFile file( fileName );
00256     if ( !file.open( QIODevice::ReadOnly ) )
00257     {
00258         kWarning() << "couldn't open file " << fileName;
00259         return false;
00260     }
00261 
00262     if ( !prepareWriting( destName, fileInfo.owner(), fileInfo.group(), size,
00263             fi.st_mode, fi.st_atime, fi.st_mtime, fi.st_ctime ) )
00264     {
00265         kWarning() << " prepareWriting" << destName << "failed";
00266         return false;
00267     }
00268 
00269     // Read and write data in chunks to minimize memory usage
00270     QByteArray array;
00271     array.resize( int( qMin( qint64( 1024 * 1024 ), size ) ) );
00272     qint64 n;
00273     qint64 total = 0;
00274     while ( ( n = file.read( array.data(), array.size() ) ) > 0 )
00275     {
00276         if ( !writeData( array.data(), n ) )
00277         {
00278             kWarning() << "writeData failed";
00279             return false;
00280         }
00281         total += n;
00282     }
00283     Q_ASSERT( total == size );
00284 
00285     if ( !finishWriting( size ) )
00286     {
00287         kWarning() << "finishWriting failed";
00288         return false;
00289     }
00290     return true;
00291 }
00292 
00293 bool KArchive::addLocalDirectory( const QString& path, const QString& destName )
00294 {
00295     QDir dir( path );
00296     if ( !dir.exists() )
00297         return false;
00298     dir.setFilter(dir.filter() | QDir::Hidden);
00299     const QStringList files = dir.entryList();
00300     for ( QStringList::ConstIterator it = files.begin(); it != files.end(); ++it )
00301     {
00302         if ( *it != QLatin1String(".") && *it != QLatin1String("..") )
00303         {
00304             QString fileName = path + QLatin1Char('/') + *it;
00305 //            kDebug() << "storing " << fileName;
00306             QString dest = destName.isEmpty() ? *it : (destName + QLatin1Char('/') + *it);
00307             QFileInfo fileInfo( fileName );
00308 
00309             if ( fileInfo.isFile() || fileInfo.isSymLink() )
00310                 addLocalFile( fileName, dest );
00311             else if ( fileInfo.isDir() )
00312                 addLocalDirectory( fileName, dest );
00313             // We omit sockets
00314         }
00315     }
00316     return true;
00317 }
00318 
00319 bool KArchive::writeFile( const QString& name, const QString& user,
00320                           const QString& group, const char* data, qint64 size,
00321                           mode_t perm, time_t atime, time_t mtime, time_t ctime )
00322 {
00323     if ( !prepareWriting( name, user, group, size, perm, atime, mtime, ctime ) )
00324     {
00325         kWarning() << "prepareWriting failed";
00326         return false;
00327     }
00328 
00329     // Write data
00330     // Note: if data is 0L, don't call write, it would terminate the KFilterDev
00331     if ( data && size && !writeData( data, size ) )
00332     {
00333         kWarning() << "writeData failed";
00334         return false;
00335     }
00336 
00337     if ( !finishWriting( size ) )
00338     {
00339         kWarning() << "finishWriting failed";
00340         return false;
00341     }
00342     return true;
00343 }
00344 
00345 bool KArchive::writeData( const char* data, qint64 size )
00346 {
00347     bool ok = device()->write( data, size ) == size;
00348     if ( !ok )
00349         d->abortWriting();
00350     return ok;
00351 }
00352 
00353 // The writeDir -> doWriteDir pattern allows to avoid propagating the default
00354 // values into all virtual methods of subclasses, and it allows more extensibility:
00355 // if a new argument is needed, we can add a writeDir overload which stores the
00356 // additional argument in the d pointer, and doWriteDir reimplementations can fetch
00357 // it from there.
00358 
00359 bool KArchive::writeDir( const QString& name, const QString& user, const QString& group,
00360                          mode_t perm, time_t atime,
00361                          time_t mtime, time_t ctime )
00362 {
00363     return doWriteDir( name, user, group, perm | 040000, atime, mtime, ctime );
00364 }
00365 
00366 bool KArchive::writeSymLink(const QString &name, const QString &target,
00367                             const QString &user, const QString &group,
00368                             mode_t perm, time_t atime,
00369                             time_t mtime, time_t ctime )
00370 {
00371     return doWriteSymLink( name, target, user, group, perm, atime, mtime, ctime );
00372 }
00373 
00374 
00375 bool KArchive::prepareWriting( const QString& name, const QString& user,
00376                                const QString& group, qint64 size,
00377                                mode_t perm, time_t atime,
00378                                time_t mtime, time_t ctime )
00379 {
00380     bool ok = doPrepareWriting( name, user, group, size, perm, atime, mtime, ctime );
00381     if ( !ok )
00382         d->abortWriting();
00383     return ok;
00384 }
00385 
00386 bool KArchive::finishWriting( qint64 size )
00387 {
00388     return doFinishWriting( size );
00389 }
00390 
00391 KArchiveDirectory * KArchive::rootDir()
00392 {
00393     if ( !d->rootDir )
00394     {
00395         //kDebug() << "Making root dir ";
00396         struct passwd* pw =  getpwuid( getuid() );
00397         struct group* grp = getgrgid( getgid() );
00398         QString username = pw ? QFile::decodeName(pw->pw_name) : QString::number( getuid() );
00399         QString groupname = grp ? QFile::decodeName(grp->gr_name) : QString::number( getgid() );
00400 
00401         d->rootDir = new KArchiveDirectory( this, QLatin1String("/"), (int)(0777 + S_IFDIR), 0, username, groupname, QString() );
00402     }
00403     return d->rootDir;
00404 }
00405 
00406 KArchiveDirectory * KArchive::findOrCreate( const QString & path )
00407 {
00408     //kDebug() << path;
00409     if ( path.isEmpty() || path == QLatin1String("/") || path == QLatin1String(".") ) // root dir => found
00410     {
00411         //kDebug() << "returning rootdir";
00412         return rootDir();
00413     }
00414     // Important note : for tar files containing absolute paths
00415     // (i.e. beginning with "/"), this means the leading "/" will
00416     // be removed (no KDirectory for it), which is exactly the way
00417     // the "tar" program works (though it displays a warning about it)
00418     // See also KArchiveDirectory::entry().
00419 
00420     // Already created ? => found
00421     const KArchiveEntry* ent = rootDir()->entry( path );
00422     if ( ent )
00423     {
00424         if ( ent->isDirectory() )
00425             //kDebug() << "found it";
00426             return (KArchiveDirectory *) ent;
00427         else
00428             kWarning() << "Found" << path << "but it's not a directory";
00429     }
00430 
00431     // Otherwise go up and try again
00432     int pos = path.lastIndexOf( QLatin1Char('/') );
00433     KArchiveDirectory * parent;
00434     QString dirname;
00435     if ( pos == -1 ) // no more slash => create in root dir
00436     {
00437         parent =  rootDir();
00438         dirname = path;
00439     }
00440     else
00441     {
00442         QString left = path.left( pos );
00443         dirname = path.mid( pos + 1 );
00444         parent = findOrCreate( left ); // recursive call... until we find an existing dir.
00445     }
00446 
00447     //kDebug() << "found parent " << parent->name() << " adding " << dirname << " to ensure " << path;
00448     // Found -> add the missing piece
00449     KArchiveDirectory * e = new KArchiveDirectory( this, dirname, d->rootDir->permissions(),
00450                                                    d->rootDir->date(), d->rootDir->user(),
00451                                                    d->rootDir->group(), QString() );
00452     parent->addEntry( e );
00453     return e; // now a directory to <path> exists
00454 }
00455 
00456 void KArchive::setDevice( QIODevice * dev )
00457 {
00458     if ( d->deviceOwned )
00459         delete d->dev;
00460     d->dev = dev;
00461     d->deviceOwned = false;
00462 }
00463 
00464 void KArchive::setRootDir( KArchiveDirectory *rootDir )
00465 {
00466     Q_ASSERT( !d->rootDir ); // Call setRootDir only once during parsing please ;)
00467     d->rootDir = rootDir;
00468 }
00469 
00470 QIODevice::OpenMode KArchive::mode() const
00471 {
00472     return d->mode;
00473 }
00474 
00475 QIODevice * KArchive::device() const
00476 {
00477     return d->dev;
00478 }
00479 
00480 bool KArchive::isOpen() const
00481 {
00482     return d->mode != QIODevice::NotOpen;
00483 }
00484 
00485 QString KArchive::fileName() const
00486 {
00487     return d->fileName;
00488 }
00489 
00490 void KArchivePrivate::abortWriting()
00491 {
00492     if ( saveFile ) {
00493         saveFile->abort();
00494         delete saveFile;
00495         saveFile = 0;
00496         dev = 0;
00497     }
00498 }
00499 
00503 
00504 class KArchiveEntryPrivate
00505 {
00506 public:
00507     KArchiveEntryPrivate( KArchive* _archive, const QString& _name, int _access,
00508                           int _date, const QString& _user, const QString& _group,
00509                           const QString& _symlink) :
00510         name(_name),
00511         date(_date),
00512         access(_access),
00513         user(_user),
00514         group(_group),
00515         symlink(_symlink),
00516         archive(_archive)
00517     {}
00518     QString name;
00519     int date;
00520     mode_t access;
00521     QString user;
00522     QString group;
00523     QString symlink;
00524     KArchive* archive;
00525 };
00526 
00527 KArchiveEntry::KArchiveEntry( KArchive* t, const QString& name, int access, int date,
00528                       const QString& user, const QString& group, const
00529                       QString& symlink) :
00530     d(new KArchiveEntryPrivate(t,name,access,date,user,group,symlink))
00531 {
00532 }
00533 
00534 KArchiveEntry::~KArchiveEntry()
00535 {
00536     delete d;
00537 }
00538 
00539 QDateTime KArchiveEntry::datetime() const
00540 {
00541   QDateTime datetimeobj;
00542   datetimeobj.setTime_t( d->date );
00543   return datetimeobj;
00544 }
00545 
00546 int KArchiveEntry::date() const
00547 {
00548     return d->date;
00549 }
00550 
00551 QString KArchiveEntry::name() const
00552 {
00553     return d->name;
00554 }
00555 
00556 mode_t KArchiveEntry::permissions() const
00557 {
00558     return d->access;
00559 }
00560 
00561 QString KArchiveEntry::user() const
00562 {
00563     return d->user;
00564 }
00565 
00566 QString KArchiveEntry::group() const
00567 {
00568     return d->group;
00569 }
00570 
00571 QString KArchiveEntry::symLinkTarget() const
00572 {
00573     return d->symlink;
00574 }
00575 
00576 bool KArchiveEntry::isFile() const
00577 {
00578     return false;
00579 }
00580 
00581 bool KArchiveEntry::isDirectory() const
00582 {
00583     return false;
00584 }
00585 
00586 KArchive* KArchiveEntry::archive() const
00587 {
00588     return d->archive;
00589 }
00590 
00594 
00595 class KArchiveFilePrivate
00596 {
00597 public:
00598     KArchiveFilePrivate( qint64 _pos, qint64 _size ) :
00599         pos(_pos),
00600         size(_size)
00601     {}
00602     qint64 pos;
00603     qint64 size;
00604 };
00605 
00606 KArchiveFile::KArchiveFile( KArchive* t, const QString& name, int access, int date,
00607                             const QString& user, const QString& group,
00608                             const QString & symlink,
00609                             qint64 pos, qint64 size )
00610   : KArchiveEntry( t, name, access, date, user, group, symlink ),
00611     d( new KArchiveFilePrivate(pos, size) )
00612 {
00613 }
00614 
00615 KArchiveFile::~KArchiveFile()
00616 {
00617     delete d;
00618 }
00619 
00620 qint64 KArchiveFile::position() const
00621 {
00622   return d->pos;
00623 }
00624 
00625 qint64 KArchiveFile::size() const
00626 {
00627   return d->size;
00628 }
00629 
00630 void KArchiveFile::setSize( qint64 s )
00631 {
00632     d->size = s;
00633 }
00634 
00635 QByteArray KArchiveFile::data() const
00636 {
00637   bool ok = archive()->device()->seek( d->pos );
00638   if (!ok) {
00639       kWarning() << "Failed to sync to" << d->pos << "to read" << name();
00640   }
00641 
00642   // Read content
00643   QByteArray arr;
00644   if ( d->size )
00645   {
00646     arr = archive()->device()->read( d->size );
00647     Q_ASSERT( arr.size() == d->size );
00648   }
00649   return arr;
00650 }
00651 
00652 QIODevice * KArchiveFile::createDevice() const
00653 {
00654   return new KLimitedIODevice( archive()->device(), d->pos, d->size );
00655 }
00656 
00657 bool KArchiveFile::isFile() const
00658 {
00659     return true;
00660 }
00661 
00662 void KArchiveFile::copyTo(const QString& dest) const
00663 {
00664   QFile f( dest + QLatin1Char('/')  + name() );
00665   if ( f.open( QIODevice::ReadWrite | QIODevice::Truncate ) )
00666   {
00667       QIODevice* inputDev = createDevice();
00668 
00669       // Read and write data in chunks to minimize memory usage
00670       const qint64 chunkSize = 1024 * 1024;
00671       qint64 remainingSize = d->size;
00672       QByteArray array;
00673       array.resize( int( qMin( chunkSize, remainingSize ) ) );
00674 
00675       while ( remainingSize > 0 ) {
00676           const qint64 currentChunkSize = qMin( chunkSize, remainingSize );
00677           const qint64 n = inputDev->read( array.data(), currentChunkSize );
00678           Q_ASSERT( n == currentChunkSize );
00679           f.write( array.data(), currentChunkSize );
00680           remainingSize -= currentChunkSize;
00681       }
00682       f.close();
00683 
00684       delete inputDev;
00685   }
00686 }
00687 
00691 
00692 class KArchiveDirectoryPrivate
00693 {
00694 public:
00695     ~KArchiveDirectoryPrivate()
00696     {
00697         qDeleteAll(entries);
00698     }
00699     QHash<QString, KArchiveEntry *> entries;
00700 };
00701 
00702 KArchiveDirectory::KArchiveDirectory( KArchive* t, const QString& name, int access,
00703                               int date,
00704                               const QString& user, const QString& group,
00705                               const QString &symlink)
00706   : KArchiveEntry( t, name, access, date, user, group, symlink ),
00707     d( new KArchiveDirectoryPrivate )
00708 {
00709 }
00710 
00711 KArchiveDirectory::~KArchiveDirectory()
00712 {
00713   delete d;
00714 }
00715 
00716 QStringList KArchiveDirectory::entries() const
00717 {
00718   return d->entries.keys();
00719 }
00720 
00721 const KArchiveEntry* KArchiveDirectory::entry( const QString& _name ) const
00722 {
00723     QString name = QDir::cleanPath(_name);
00724     int pos = name.indexOf( QLatin1Char('/') );
00725   if ( pos == 0 ) // ouch absolute path (see also KArchive::findOrCreate)
00726   {
00727     if (name.length()>1)
00728     {
00729       name = name.mid( 1 ); // remove leading slash
00730       pos = name.indexOf( QLatin1Char('/') ); // look again
00731     }
00732     else // "/"
00733       return this;
00734   }
00735   // trailing slash ? -> remove
00736   if ( pos != -1 && pos == name.length()-1 )
00737   {
00738     name = name.left( pos );
00739     pos = name.indexOf( QLatin1Char('/') ); // look again
00740   }
00741   if ( pos != -1 )
00742   {
00743     const QString left = name.left(pos);
00744     const QString right = name.mid(pos + 1);
00745 
00746     //kDebug() << "left=" << left << "right=" << right;
00747 
00748     const KArchiveEntry* e = d->entries.value( left );
00749     if ( !e || !e->isDirectory() )
00750       return 0;
00751     return static_cast<const KArchiveDirectory*>(e)->entry( right );
00752   }
00753 
00754   return d->entries.value( name );
00755 }
00756 
00757 void KArchiveDirectory::addEntry( KArchiveEntry* entry )
00758 {
00759   if( entry->name().isEmpty() )
00760     return;
00761 
00762   if( d->entries.value( entry->name() ) ) {
00763       kWarning() << "directory " << name()
00764                   << "has entry" << entry->name() << "already";
00765   }
00766   d->entries.insert( entry->name(), entry );
00767 }
00768 
00769 bool KArchiveDirectory::isDirectory() const
00770 {
00771     return true;
00772 }
00773 
00774 static bool sortByPosition( const KArchiveFile* file1, const KArchiveFile* file2 ) {
00775     return file1->position() < file2->position();
00776 }
00777 
00778 void KArchiveDirectory::copyTo(const QString& dest, bool recursiveCopy ) const
00779 {
00780   QDir root;
00781 
00782   QList<const KArchiveFile*> fileList;
00783   QMap<qint64, QString> fileToDir;
00784 
00785   // placeholders for iterated items
00786   QStack<const KArchiveDirectory *> dirStack;
00787   QStack<QString> dirNameStack;
00788 
00789   dirStack.push( this );     // init stack at current directory
00790   dirNameStack.push( dest ); // ... with given path
00791   do {
00792     const KArchiveDirectory* curDir = dirStack.pop();
00793     const QString curDirName = dirNameStack.pop();
00794     root.mkdir(curDirName);
00795 
00796     const QStringList dirEntries = curDir->entries();
00797     for ( QStringList::const_iterator it = dirEntries.begin(); it != dirEntries.end(); ++it ) {
00798       const KArchiveEntry* curEntry = curDir->entry(*it);
00799       if (!curEntry->symLinkTarget().isEmpty()) {
00800           const QString linkName = curDirName+QLatin1Char('/')+curEntry->name();
00801 #ifdef Q_OS_UNIX
00802           if (!::symlink(curEntry->symLinkTarget().toLocal8Bit(), linkName.toLocal8Bit())) {
00803               kDebug() << "symlink(" << curEntry->symLinkTarget() << ',' << linkName << ") failed:" << strerror(errno);
00804           }
00805 #else
00806           // TODO - how to create symlinks on other platforms?
00807 #endif
00808       } else {
00809           if ( curEntry->isFile() ) {
00810               const KArchiveFile* curFile = dynamic_cast<const KArchiveFile*>( curEntry );
00811               if (curFile) {
00812                   fileList.append( curFile );
00813                   fileToDir.insert( curFile->position(), curDirName );
00814               }
00815           }
00816 
00817           if ( curEntry->isDirectory() && recursiveCopy ) {
00818               const KArchiveDirectory *ad = dynamic_cast<const KArchiveDirectory*>( curEntry );
00819               if (ad) {
00820                   dirStack.push( ad );
00821                   dirNameStack.push( curDirName + QLatin1Char('/') + curEntry->name() );
00822               }
00823           }
00824       }
00825     }
00826   } while (!dirStack.isEmpty());
00827 
00828   qSort( fileList.begin(), fileList.end(), sortByPosition );  // sort on d->pos, so we have a linear access
00829 
00830   for ( QList<const KArchiveFile*>::const_iterator it = fileList.constBegin(), end = fileList.constEnd() ;
00831         it != end ; ++it ) {
00832       const KArchiveFile* f = *it;
00833       qint64 pos = f->position();
00834       f->copyTo( fileToDir[pos] );
00835   }
00836 }
00837 
00838 void KArchive::virtual_hook( int, void* )
00839 { /*BASE::virtual_hook( id, data )*/; }
00840 
00841 void KArchiveEntry::virtual_hook( int, void* )
00842 { /*BASE::virtual_hook( id, data );*/ }
00843 
00844 void KArchiveFile::virtual_hook( int id, void* data )
00845 { KArchiveEntry::virtual_hook( id, data ); }
00846 
00847 void KArchiveDirectory::virtual_hook( int id, void* data )
00848 { KArchiveEntry::virtual_hook( id, data ); }

KDECore

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

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • 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
Generated for kdelibs by doxygen 1.7.3
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal