karchive.cpp

00001 /* This file is part of the KDE libraries
00002    Copyright (C) 2000 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 <stdio.h>
00023 #include <stdlib.h>
00024 #include <time.h>
00025 #include <unistd.h>
00026 #include <errno.h>
00027 #include <grp.h>
00028 #include <pwd.h>
00029 #include <assert.h>
00030 #include <sys/types.h>
00031 #include <sys/stat.h>
00032 #include <locale.h>
00033 
00034 #include <qptrlist.h>
00035 #include <qptrstack.h>
00036 #include <qvaluestack.h>
00037 #include <qmap.h>
00038 #include <qcstring.h>
00039 #include <qdir.h>
00040 #include <qfile.h>
00041 #include <qtextcodec.h>
00042 
00043 #include <kdebug.h>
00044 #include <kfilterdev.h>
00045 #include <kfilterbase.h>
00046 #include <kde_file.h>
00047 
00048 #include "karchive.h"
00049 #include "klimitediodevice.h"
00050 
00051 template class QDict<KArchiveEntry>;
00052 
00053 
00054 class KArchive::KArchivePrivate
00055 {
00056 public:
00057     KArchiveDirectory* rootDir;
00058     bool closeSucceeded;
00059 };
00060 
00061 class PosSortedPtrList : public QPtrList<KArchiveFile> {
00062 protected:
00063     int compareItems( QPtrCollection::Item i1,
00064                       QPtrCollection::Item i2 )
00065     {
00066         int pos1 = static_cast<KArchiveFile*>( i1 )->position();
00067         int pos2 = static_cast<KArchiveFile*>( i2 )->position();
00068         return ( pos1 - pos2 );
00069     }
00070 };
00071 
00072 
00076 
00077 KArchive::KArchive( QIODevice * dev )
00078 {
00079     d = new KArchivePrivate;
00080     d->rootDir = 0;
00081     m_dev = dev;
00082     m_open = false;
00083 }
00084 
00085 KArchive::~KArchive()
00086 {
00087     if ( m_open )
00088         close();
00089     delete d->rootDir;
00090     delete d;
00091 }
00092 
00093 bool KArchive::open( int mode )
00094 {
00095     if ( m_dev && !m_dev->open( mode ) )
00096         return false;
00097 
00098     if ( m_open )
00099         close();
00100 
00101     m_mode = mode;
00102     m_open = true;
00103 
00104     Q_ASSERT( d->rootDir == 0L );
00105     d->rootDir = 0L;
00106 
00107     return openArchive( mode );
00108 }
00109 
00110 void KArchive::close()
00111 {
00112     if ( !m_open )
00113         return;
00114     // moved by holger to allow kzip to write the zip central dir
00115     // to the file in closeArchive()
00116     d->closeSucceeded = closeArchive();
00117 
00118     if ( m_dev )
00119         m_dev->close();
00120 
00121     delete d->rootDir;
00122     d->rootDir = 0;
00123     m_open = false;
00124 }
00125 
00126 bool KArchive::closeSucceeded() const
00127 {
00128     return d->closeSucceeded;
00129 }
00130 
00131 const KArchiveDirectory* KArchive::directory() const
00132 {
00133     // rootDir isn't const so that parsing-on-demand is possible
00134     return const_cast<KArchive *>(this)->rootDir();
00135 }
00136 
00137 
00138 bool KArchive::addLocalFile( const QString& fileName, const QString& destName )
00139 {
00140     QFileInfo fileInfo( fileName );
00141     if ( !fileInfo.isFile() && !fileInfo.isSymLink() )
00142     {
00143         kdWarning() << "KArchive::addLocalFile " << fileName << " doesn't exist or is not a regular file." << endl;
00144         return false;
00145     }
00146 
00147     KDE_struct_stat fi;
00148     if (KDE_lstat(QFile::encodeName(fileName),&fi) == -1) {
00149         kdWarning() << "KArchive::addLocalFile stating " << fileName
00150             << " failed: " << strerror(errno) << endl;
00151         return false;
00152     }
00153 
00154     if (fileInfo.isSymLink()) {
00155         return writeSymLink(destName, fileInfo.readLink(), fileInfo.owner(),
00156                 fileInfo.group(), fi.st_mode, fi.st_atime, fi.st_mtime,
00157                 fi.st_ctime);
00158     }/*end if*/
00159 
00160     uint size = fileInfo.size();
00161 
00162     // the file must be opened before prepareWriting is called, otherwise
00163     // if the opening fails, no content will follow the already written
00164     // header and the tar file is effectively f*cked up
00165     QFile file( fileName );
00166     if ( !file.open( IO_ReadOnly ) )
00167     {
00168         kdWarning() << "KArchive::addLocalFile couldn't open file " << fileName << endl;
00169         return false;
00170     }
00171 
00172     if ( !prepareWriting( destName, fileInfo.owner(), fileInfo.group(), size,
00173             fi.st_mode, fi.st_atime, fi.st_mtime, fi.st_ctime ) )
00174     {
00175         kdWarning() << "KArchive::addLocalFile prepareWriting " << destName << " failed" << endl;
00176         return false;
00177     }
00178 
00179     // Read and write data in chunks to minimize memory usage
00180     QByteArray array(8*1024);
00181     int n;
00182     uint total = 0;
00183     while ( ( n = file.readBlock( array.data(), array.size() ) ) > 0 )
00184     {
00185         if ( !writeData( array.data(), n ) )
00186         {
00187             kdWarning() << "KArchive::addLocalFile writeData failed" << endl;
00188             return false;
00189         }
00190         total += n;
00191     }
00192     Q_ASSERT( total == size );
00193 
00194     if ( !doneWriting( size ) )
00195     {
00196         kdWarning() << "KArchive::addLocalFile doneWriting failed" << endl;
00197         return false;
00198     }
00199     return true;
00200 }
00201 
00202 bool KArchive::addLocalDirectory( const QString& path, const QString& destName )
00203 {
00204     QString dot = ".";
00205     QString dotdot = "..";
00206     QDir dir( path );
00207     if ( !dir.exists() )
00208         return false;
00209     QStringList files = dir.entryList();
00210     for ( QStringList::Iterator it = files.begin(); it != files.end(); ++it )
00211     {
00212         if ( *it != dot && *it != dotdot )
00213         {
00214             QString fileName = path + "/" + *it;
00215 //            kdDebug() << "storing " << fileName << endl;
00216             QString dest = destName.isEmpty() ? *it : (destName + "/" + *it);
00217             QFileInfo fileInfo( fileName );
00218 
00219             if ( fileInfo.isFile() || fileInfo.isSymLink() )
00220                 addLocalFile( fileName, dest );
00221             else if ( fileInfo.isDir() )
00222                 addLocalDirectory( fileName, dest );
00223             // We omit sockets
00224         }
00225     }
00226     return true;
00227 }
00228 
00229 bool KArchive::writeFile( const QString& name, const QString& user, const QString& group, uint size, const char* data )
00230 {
00231     mode_t perm = 0100644;
00232     time_t the_time = time(0);
00233     return writeFile(name,user,group,size,perm,the_time,the_time,the_time,data);
00234 }
00235 
00236 bool KArchive::prepareWriting( const QString& name, const QString& user,
00237                 const QString& group, uint size, mode_t perm,
00238                 time_t atime, time_t mtime, time_t ctime ) {
00239   PrepareWritingParams params;
00240   params.name = &name;
00241   params.user = &user;
00242   params.group = &group;
00243   params.size = size;
00244   params.perm = perm;
00245   params.atime = atime;
00246   params.mtime = mtime;
00247   params.ctime = ctime;
00248   virtual_hook(VIRTUAL_PREPARE_WRITING,&params);
00249   return params.retval;
00250 }
00251 
00252 bool KArchive::prepareWriting_impl(const QString &name, const QString &user,
00253                 const QString &group, uint size, mode_t /*perm*/,
00254                 time_t /*atime*/, time_t /*mtime*/, time_t /*ctime*/ ) {
00255   kdWarning(7040) << "New prepareWriting API not implemented in this class." << endl
00256         << "Falling back to old API (metadata information will be lost)" << endl;
00257   return prepareWriting(name,user,group,size);
00258 }
00259 
00260 bool KArchive::writeFile( const QString& name, const QString& user,
00261                 const QString& group, uint size, mode_t perm,
00262                 time_t atime, time_t mtime, time_t ctime,
00263                 const char* data ) {
00264   WriteFileParams params;
00265   params.name = &name;
00266   params.user = &user;
00267   params.group = &group;
00268   params.size = size;
00269   params.perm = perm;
00270   params.atime = atime;
00271   params.mtime = mtime;
00272   params.ctime = ctime;
00273   params.data = data;
00274   virtual_hook(VIRTUAL_WRITE_FILE,&params);
00275   return params.retval;
00276 }
00277 
00278 bool KArchive::writeFile_impl( const QString& name, const QString& user,
00279                 const QString& group, uint size, mode_t perm,
00280                 time_t atime, time_t mtime, time_t ctime,
00281                 const char* data ) {
00282 
00283     if ( !prepareWriting( name, user, group, size, perm, atime, mtime, ctime ) )
00284     {
00285         kdWarning() << "KArchive::writeFile prepareWriting failed" << endl;
00286         return false;
00287     }
00288 
00289     // Write data
00290     // Note: if data is 0L, don't call writeBlock, it would terminate the KFilterDev
00291     if ( data && size && !writeData( data, size ) )
00292     {
00293         kdWarning() << "KArchive::writeFile writeData failed" << endl;
00294         return false;
00295     }
00296 
00297     if ( !doneWriting( size ) )
00298     {
00299         kdWarning() << "KArchive::writeFile doneWriting failed" << endl;
00300         return false;
00301     }
00302     return true;
00303 }
00304 
00305 bool KArchive::writeDir(const QString& name, const QString& user,
00306                 const QString& group, mode_t perm,
00307                 time_t atime, time_t mtime, time_t ctime) {
00308   WriteDirParams params;
00309   params.name = &name;
00310   params.user = &user;
00311   params.group = &group;
00312   params.perm = perm;
00313   params.atime = atime;
00314   params.mtime = mtime;
00315   params.ctime = ctime;
00316   virtual_hook(VIRTUAL_WRITE_DIR,&params);
00317   return params.retval;
00318 }
00319 
00320 bool KArchive::writeDir_impl(const QString &name, const QString &user,
00321                 const QString &group, mode_t /*perm*/,
00322                 time_t /*atime*/, time_t /*mtime*/, time_t /*ctime*/ ) {
00323   kdWarning(7040) << "New writeDir API not implemented in this class." << endl
00324         << "Falling back to old API (metadata information will be lost)" << endl;
00325   return writeDir(name,user,group);
00326 }
00327 
00328 bool KArchive::writeSymLink(const QString &name, const QString &target,
00329                 const QString &user, const QString &group,
00330                 mode_t perm, time_t atime, time_t mtime, time_t ctime) {
00331   WriteSymlinkParams params;
00332   params.name = &name;
00333   params.target = &target;
00334   params.user = &user;
00335   params.group = &group;
00336   params.perm = perm;
00337   params.atime = atime;
00338   params.mtime = mtime;
00339   params.ctime = ctime;
00340   virtual_hook(VIRTUAL_WRITE_SYMLINK,&params);
00341   return params.retval;
00342 }
00343 
00344 bool KArchive::writeSymLink_impl(const QString &/*name*/,const QString &/*target*/,
00345                 const QString &/*user*/, const QString &/*group*/,
00346                 mode_t /*perm*/, time_t /*atime*/, time_t /*mtime*/,
00347                 time_t /*ctime*/) {
00348   kdWarning(7040) << "writeSymLink not implemented in this class." << endl
00349         << "No fallback available." << endl;
00350   // FIXME: better return true here for compatibility with KDE < 3.2
00351   return false;
00352 }
00353 
00354 bool KArchive::writeData( const char* data, uint size )
00355 {
00356     WriteDataParams params;
00357     params.data = data;
00358     params.size = size;
00359     virtual_hook( VIRTUAL_WRITE_DATA, &params );
00360     return params.retval;
00361 }
00362 
00363 bool KArchive::writeData_impl( const char* data, uint size )
00364 {
00365     Q_ASSERT( device() );
00366     return device()->writeBlock( data, size ) == (Q_LONG)size;
00367 }
00368 
00369 KArchiveDirectory * KArchive::rootDir()
00370 {
00371     if ( !d->rootDir )
00372     {
00373         //kdDebug() << "Making root dir " << endl;
00374         struct passwd* pw =  getpwuid( getuid() );
00375         struct group* grp = getgrgid( getgid() );
00376         QString username = pw ? QFile::decodeName(pw->pw_name) : QString::number( getuid() );
00377         QString groupname = grp ? QFile::decodeName(grp->gr_name) : QString::number( getgid() );
00378 
00379         d->rootDir = new KArchiveDirectory( this, QString::fromLatin1("/"), (int)(0777 + S_IFDIR), 0, username, groupname, QString::null );
00380     }
00381     return d->rootDir;
00382 }
00383 
00384 KArchiveDirectory * KArchive::findOrCreate( const QString & path )
00385 {
00386     //kdDebug() << "KArchive::findOrCreate " << path << endl;
00387     if ( path.isEmpty() || path == "/" || path == "." ) // root dir => found
00388     {
00389         //kdDebug() << "KArchive::findOrCreate returning rootdir" << endl;
00390         return rootDir();
00391     }
00392     // Important note : for tar files containing absolute paths
00393     // (i.e. beginning with "/"), this means the leading "/" will
00394     // be removed (no KDirectory for it), which is exactly the way
00395     // the "tar" program works (though it displays a warning about it)
00396     // See also KArchiveDirectory::entry().
00397 
00398     // Already created ? => found
00399     KArchiveEntry* ent = rootDir()->entry( path );
00400     if ( ent )
00401     {
00402         if ( ent->isDirectory() )
00403             //kdDebug() << "KArchive::findOrCreate found it" << endl;
00404             return (KArchiveDirectory *) ent;
00405         else
00406             kdWarning() << "Found " << path << " but it's not a directory" << endl;
00407     }
00408 
00409     // Otherwise go up and try again
00410     int pos = path.findRev( '/' );
00411     KArchiveDirectory * parent;
00412     QString dirname;
00413     if ( pos == -1 ) // no more slash => create in root dir
00414     {
00415         parent =  rootDir();
00416         dirname = path;
00417     }
00418     else
00419     {
00420         QString left = path.left( pos );
00421         dirname = path.mid( pos + 1 );
00422         parent = findOrCreate( left ); // recursive call... until we find an existing dir.
00423     }
00424 
00425     //kdDebug() << "KTar : found parent " << parent->name() << " adding " << dirname << " to ensure " << path << endl;
00426     // Found -> add the missing piece
00427     KArchiveDirectory * e = new KArchiveDirectory( this, dirname, d->rootDir->permissions(),
00428                                                    d->rootDir->date(), d->rootDir->user(),
00429                                                    d->rootDir->group(), QString::null );
00430     parent->addEntry( e );
00431     return e; // now a directory to <path> exists
00432 }
00433 
00434 void KArchive::setDevice( QIODevice * dev )
00435 {
00436     m_dev = dev;
00437 }
00438 
00439 void KArchive::setRootDir( KArchiveDirectory *rootDir )
00440 {
00441     Q_ASSERT( !d->rootDir ); // Call setRootDir only once during parsing please ;)
00442     d->rootDir = rootDir;
00443 }
00444 
00445 QString KArchive::decodeEntryName( const QCString & name )
00446 {
00447     QTextCodec *codec = NULL;
00448     char *src = name.data();
00449     int len = name.length();
00450 
00451     if (strncmp(setlocale(LC_CTYPE,""), "ja_JP", 5) != 0)
00452         return QFile::decodeName(name);
00453 
00454     for (; len>0 && *src != '\0'; len--) {
00455         //int c1 = (int)(*src), c2 = (int)(*(src ++)), c3;
00456         int c1, c2, c3;
00457         c1 = *src & 0xff;
00458         src++;
00459         c2 = *(src++) & 0xff;
00460 
00461         if (c2 == '\0') {
00462             if (c1 > 0xa0 && c1 < 0xe0)
00463                 /* CP932 */
00464                 codec = QTextCodec::codecForName( "Shift-JIS" );
00465             break;
00466         }
00467         else if (c1 == 0x1b) {
00468             if (c2 == '$' || c2 == '&')
00469                 /* ISO-2022-JP */
00470                 codec = QTextCodec::codecForName( "Shift-JIS" );
00471             break;
00472         }
00473         else if (c1 < 0x80) { continue; }
00474         else if (((c1 > 0x80 && c1 < 0xa0) || (c1 >= 0xe0 && c1 < 0xfd))
00475             && ((c2 >= 0x40 && c2 < 0x7f) || (c2 >= 0x80 && c2 < 0xfd))) {
00476             /* CP932 Full-width Kanji */
00477             codec = QTextCodec::codecForName( "Shift-JIS" );
00478             break;
00479         }
00480         else if (c1 == 0x8f && c2 > 0xa0 && c2 < 0xff) {
00481             c3 = *(src++) & 0xff;
00482             if (c3 > 0x0a && c3 < 0xff)
00483                 /* 3 byte EUC-JP */
00484                 codec = QTextCodec::codecForName( "eucJP" );
00485             break;
00486         }
00487         else if (c1 > 0xa0 && c1 < 0xff) {
00488             if (c2 > 0xa0 && c2 < 0xff)
00489                 /* 2byte EUC-JP */
00490                 codec = QTextCodec::codecForName( "eucJP" );
00491             else if (c1 < 0xe0)
00492                 /* CP932 Half-width Kana */
00493                 codec = QTextCodec::codecForName( "Shift-JIS" );
00494             break;
00495         }
00496     }
00497 
00498     if (codec == NULL)
00499         return QFile::decodeName(name);
00500     else
00501         return codec->toUnicode(name);
00502 }
00503 
00507 KArchiveEntry::KArchiveEntry( KArchive* t, const QString& name, int access, int date,
00508                       const QString& user, const QString& group, const
00509                       QString& symlink)
00510 {
00511   m_name = name;
00512   m_access = access;
00513   m_date = date;
00514   m_user = user;
00515   m_group = group;
00516   m_symlink = symlink;
00517   m_archive = t;
00518 
00519 }
00520 
00521 QDateTime KArchiveEntry::datetime() const
00522 {
00523   QDateTime d;
00524   d.setTime_t( m_date );
00525   return d;
00526 }
00527 
00531 
00532 KArchiveFile::KArchiveFile( KArchive* t, const QString& name, int access, int date,
00533                     const QString& user, const QString& group,
00534                     const QString & symlink,
00535                     int pos, int size )
00536   : KArchiveEntry( t, name, access, date, user, group, symlink )
00537 {
00538   m_pos = pos;
00539   m_size = size;
00540 }
00541 
00542 int KArchiveFile::position() const
00543 {
00544   return m_pos;
00545 }
00546 
00547 int KArchiveFile::size() const
00548 {
00549   return m_size;
00550 }
00551 
00552 QByteArray KArchiveFile::data() const
00553 {
00554   archive()->device()->at( m_pos );
00555 
00556   // Read content
00557   QByteArray arr( m_size );
00558   if ( m_size )
00559   {
00560     assert( arr.data() );
00561     int n = archive()->device()->readBlock( arr.data(), m_size );
00562     if ( n != m_size )
00563       arr.resize( n );
00564   }
00565   return arr;
00566 }
00567 
00568 // ** This should be a virtual method, and this code should be in ktar.cpp
00569 QIODevice *KArchiveFile::device() const
00570 {
00571     return new KLimitedIODevice( archive()->device(), m_pos, m_size );
00572 }
00573 
00574 void KArchiveFile::copyTo(const QString& dest) const
00575 {
00576   QFile f( dest + "/"  + name() );
00577   f.open( IO_ReadWrite | IO_Truncate );
00578   f.writeBlock( data() );
00579   f.close();
00580 }
00581 
00585 
00586 
00587 KArchiveDirectory::KArchiveDirectory( KArchive* t, const QString& name, int access,
00588                               int date,
00589                               const QString& user, const QString& group,
00590                               const QString &symlink)
00591   : KArchiveEntry( t, name, access, date, user, group, symlink )
00592 {
00593   m_entries.setAutoDelete( true );
00594 }
00595 
00596 QStringList KArchiveDirectory::entries() const
00597 {
00598   QStringList l;
00599 
00600   QDictIterator<KArchiveEntry> it( m_entries );
00601   for( ; it.current(); ++it )
00602     l.append( it.currentKey() );
00603 
00604   return l;
00605 }
00606 
00607 KArchiveEntry* KArchiveDirectory::entry( QString name )
00608   // not "const QString & name" since we want a local copy
00609   // (to remove leading slash if any)
00610 {
00611   int pos = name.find( '/' );
00612   if ( pos == 0 ) // ouch absolute path (see also KArchive::findOrCreate)
00613   {
00614     if (name.length()>1)
00615     {
00616       name = name.mid( 1 ); // remove leading slash
00617       pos = name.find( '/' ); // look again
00618     }
00619     else // "/"
00620       return this;
00621   }
00622   // trailing slash ? -> remove
00623   if ( pos != -1 && pos == (int)name.length()-1 )
00624   {
00625     name = name.left( pos );
00626     pos = name.find( '/' ); // look again
00627   }
00628   if ( pos != -1 )
00629   {
00630     QString left = name.left( pos );
00631     QString right = name.mid( pos + 1 );
00632 
00633     //kdDebug() << "KArchiveDirectory::entry left=" << left << " right=" << right << endl;
00634 
00635     KArchiveEntry* e = m_entries[ left ];
00636     if ( !e || !e->isDirectory() )
00637       return 0;
00638     return ((KArchiveDirectory*)e)->entry( right );
00639   }
00640 
00641   return m_entries[ name ];
00642 }
00643 
00644 const KArchiveEntry* KArchiveDirectory::entry( QString name ) const
00645 {
00646   return ((KArchiveDirectory*)this)->entry( name );
00647 }
00648 
00649 void KArchiveDirectory::addEntry( KArchiveEntry* entry )
00650 {
00651   Q_ASSERT( !entry->name().isEmpty() );
00652   if( m_entries[ entry->name() ] ) {
00653       kdWarning() << "KArchiveDirectory::addEntry: directory " << name()
00654                   << " has entry " << entry->name() << " already" << endl;
00655   }
00656   m_entries.insert( entry->name(), entry );
00657 }
00658 
00659 void KArchiveDirectory::copyTo(const QString& dest, bool recursiveCopy ) const
00660 {
00661   QDir root;
00662 
00663   PosSortedPtrList fileList;
00664   QMap<int, QString> fileToDir;
00665 
00666   QStringList::Iterator it;
00667 
00668   // placeholders for iterated items
00669   KArchiveDirectory* curDir;
00670   QString curDirName;
00671 
00672   QStringList dirEntries;
00673   KArchiveEntry* curEntry;
00674   KArchiveFile* curFile;
00675 
00676 
00677   QPtrStack<KArchiveDirectory> dirStack;
00678   QValueStack<QString> dirNameStack;
00679 
00680   dirStack.push( this );     // init stack at current directory
00681   dirNameStack.push( dest ); // ... with given path
00682   do {
00683     curDir = dirStack.pop();
00684     curDirName = dirNameStack.pop();
00685     root.mkdir(curDirName);
00686 
00687     dirEntries = curDir->entries();
00688     for ( it = dirEntries.begin(); it != dirEntries.end(); ++it ) {
00689       curEntry = curDir->entry(*it);
00690       if (!curEntry->symlink().isEmpty()) {
00691           const QString linkName = curDirName+'/'+curEntry->name();
00692           kdDebug() << "symlink(" << curEntry->symlink() << ',' << linkName << ')';
00693 #ifdef Q_OS_UNIX
00694           if (!::symlink(curEntry->symlink().local8Bit(), linkName.local8Bit())) {
00695               kdDebug() << "symlink(" << curEntry->symlink() << ',' << linkName << ") failed:" << strerror(errno);
00696           }
00697 #endif
00698       } else {
00699           if ( curEntry->isFile() ) {
00700               curFile = dynamic_cast<KArchiveFile*>( curEntry );
00701               if (curFile) {
00702                   fileList.append( curFile );
00703                   fileToDir.insert( curFile->position(), curDirName );
00704               }
00705           }
00706 
00707           if ( curEntry->isDirectory() )
00708               if ( recursiveCopy ) {
00709                   KArchiveDirectory *ad = dynamic_cast<KArchiveDirectory*>( curEntry );
00710                   if (ad) {
00711                       dirStack.push( ad );
00712                       dirNameStack.push( curDirName + "/" + curEntry->name() );
00713                   }
00714               }
00715       }
00716     }
00717   } while (!dirStack.isEmpty());
00718 
00719   fileList.sort();  // sort on m_pos, so we have a linear access
00720 
00721   KArchiveFile* f;
00722   for ( f = fileList.first(); f; f = fileList.next() ) {
00723     int pos = f->position();
00724     f->copyTo( fileToDir[pos] );
00725   }
00726 }
00727 
00728 void KArchive::virtual_hook( int id, void* data )
00729 {
00730     switch (id) {
00731       case VIRTUAL_WRITE_DATA: {
00732         WriteDataParams* params = reinterpret_cast<WriteDataParams *>(data);
00733         params->retval = writeData_impl( params->data, params->size );
00734         break;
00735       }
00736       case VIRTUAL_WRITE_SYMLINK: {
00737         WriteSymlinkParams *params = reinterpret_cast<WriteSymlinkParams *>(data);
00738         params->retval = writeSymLink_impl(*params->name,*params->target,
00739                 *params->user,*params->group,params->perm,
00740                 params->atime,params->mtime,params->ctime);
00741         break;
00742       }
00743       case VIRTUAL_WRITE_DIR: {
00744         WriteDirParams *params = reinterpret_cast<WriteDirParams *>(data);
00745         params->retval = writeDir_impl(*params->name,*params->user,
00746                 *params->group,params->perm,
00747                 params->atime,params->mtime,params->ctime);
00748         break;
00749       }
00750       case VIRTUAL_WRITE_FILE: {
00751         WriteFileParams *params = reinterpret_cast<WriteFileParams *>(data);
00752         params->retval = writeFile_impl(*params->name,*params->user,
00753                 *params->group,params->size,params->perm,
00754                 params->atime,params->mtime,params->ctime,
00755                     params->data);
00756         break;
00757       }
00758       case VIRTUAL_PREPARE_WRITING: {
00759         PrepareWritingParams *params = reinterpret_cast<PrepareWritingParams *>(data);
00760         params->retval = prepareWriting_impl(*params->name,*params->user,
00761                 *params->group,params->size,params->perm,
00762                 params->atime,params->mtime,params->ctime);
00763         break;
00764       }
00765       default:
00766         /*BASE::virtual_hook( id, data )*/;
00767     }/*end switch*/
00768 }
00769 
00770 void KArchiveEntry::virtual_hook( int, void* )
00771 { /*BASE::virtual_hook( id, data );*/ }
00772 
00773 void KArchiveFile::virtual_hook( int id, void* data )
00774 { KArchiveEntry::virtual_hook( id, data ); }
00775 
00776 void KArchiveDirectory::virtual_hook( int id, void* data )
00777 { KArchiveEntry::virtual_hook( id, data ); }
KDE Home | KDE Accessibility Home | Description of Access Keys