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     dir.setFilter(dir.filter() | QDir::Hidden);
00210     QStringList files = dir.entryList();
00211     for ( QStringList::Iterator it = files.begin(); it != files.end(); ++it )
00212     {
00213         if ( *it != dot && *it != dotdot )
00214         {
00215             QString fileName = path + "/" + *it;
00216 //            kdDebug() << "storing " << fileName << endl;
00217             QString dest = destName.isEmpty() ? *it : (destName + "/" + *it);
00218             QFileInfo fileInfo( fileName );
00219 
00220             if ( fileInfo.isFile() || fileInfo.isSymLink() )
00221                 addLocalFile( fileName, dest );
00222             else if ( fileInfo.isDir() )
00223                 addLocalDirectory( fileName, dest );
00224             // We omit sockets
00225         }
00226     }
00227     return true;
00228 }
00229 
00230 bool KArchive::writeFile( const QString& name, const QString& user, const QString& group, uint size, const char* data )
00231 {
00232     mode_t perm = 0100644;
00233     time_t the_time = time(0);
00234     return writeFile(name,user,group,size,perm,the_time,the_time,the_time,data);
00235 }
00236 
00237 bool KArchive::prepareWriting( const QString& name, const QString& user,
00238                 const QString& group, uint size, mode_t perm,
00239                 time_t atime, time_t mtime, time_t ctime ) {
00240   PrepareWritingParams params;
00241   params.name = &name;
00242   params.user = &user;
00243   params.group = &group;
00244   params.size = size;
00245   params.perm = perm;
00246   params.atime = atime;
00247   params.mtime = mtime;
00248   params.ctime = ctime;
00249   virtual_hook(VIRTUAL_PREPARE_WRITING,&params);
00250   return params.retval;
00251 }
00252 
00253 bool KArchive::prepareWriting_impl(const QString &name, const QString &user,
00254                 const QString &group, uint size, mode_t /*perm*/,
00255                 time_t /*atime*/, time_t /*mtime*/, time_t /*ctime*/ ) {
00256   kdWarning(7040) << "New prepareWriting API not implemented in this class." << endl
00257         << "Falling back to old API (metadata information will be lost)" << endl;
00258   return prepareWriting(name,user,group,size);
00259 }
00260 
00261 bool KArchive::writeFile( const QString& name, const QString& user,
00262                 const QString& group, uint size, mode_t perm,
00263                 time_t atime, time_t mtime, time_t ctime,
00264                 const char* data ) {
00265   WriteFileParams params;
00266   params.name = &name;
00267   params.user = &user;
00268   params.group = &group;
00269   params.size = size;
00270   params.perm = perm;
00271   params.atime = atime;
00272   params.mtime = mtime;
00273   params.ctime = ctime;
00274   params.data = data;
00275   virtual_hook(VIRTUAL_WRITE_FILE,&params);
00276   return params.retval;
00277 }
00278 
00279 bool KArchive::writeFile_impl( const QString& name, const QString& user,
00280                 const QString& group, uint size, mode_t perm,
00281                 time_t atime, time_t mtime, time_t ctime,
00282                 const char* data ) {
00283 
00284     if ( !prepareWriting( name, user, group, size, perm, atime, mtime, ctime ) )
00285     {
00286         kdWarning() << "KArchive::writeFile prepareWriting failed" << endl;
00287         return false;
00288     }
00289 
00290     // Write data
00291     // Note: if data is 0L, don't call writeBlock, it would terminate the KFilterDev
00292     if ( data && size && !writeData( data, size ) )
00293     {
00294         kdWarning() << "KArchive::writeFile writeData failed" << endl;
00295         return false;
00296     }
00297 
00298     if ( !doneWriting( size ) )
00299     {
00300         kdWarning() << "KArchive::writeFile doneWriting failed" << endl;
00301         return false;
00302     }
00303     return true;
00304 }
00305 
00306 bool KArchive::writeDir(const QString& name, const QString& user,
00307                 const QString& group, mode_t perm,
00308                 time_t atime, time_t mtime, time_t ctime) {
00309   WriteDirParams params;
00310   params.name = &name;
00311   params.user = &user;
00312   params.group = &group;
00313   params.perm = perm;
00314   params.atime = atime;
00315   params.mtime = mtime;
00316   params.ctime = ctime;
00317   virtual_hook(VIRTUAL_WRITE_DIR,&params);
00318   return params.retval;
00319 }
00320 
00321 bool KArchive::writeDir_impl(const QString &name, const QString &user,
00322                 const QString &group, mode_t /*perm*/,
00323                 time_t /*atime*/, time_t /*mtime*/, time_t /*ctime*/ ) {
00324   kdWarning(7040) << "New writeDir API not implemented in this class." << endl
00325         << "Falling back to old API (metadata information will be lost)" << endl;
00326   return writeDir(name,user,group);
00327 }
00328 
00329 bool KArchive::writeSymLink(const QString &name, const QString &target,
00330                 const QString &user, const QString &group,
00331                 mode_t perm, time_t atime, time_t mtime, time_t ctime) {
00332   WriteSymlinkParams params;
00333   params.name = &name;
00334   params.target = &target;
00335   params.user = &user;
00336   params.group = &group;
00337   params.perm = perm;
00338   params.atime = atime;
00339   params.mtime = mtime;
00340   params.ctime = ctime;
00341   virtual_hook(VIRTUAL_WRITE_SYMLINK,&params);
00342   return params.retval;
00343 }
00344 
00345 bool KArchive::writeSymLink_impl(const QString &/*name*/,const QString &/*target*/,
00346                 const QString &/*user*/, const QString &/*group*/,
00347                 mode_t /*perm*/, time_t /*atime*/, time_t /*mtime*/,
00348                 time_t /*ctime*/) {
00349   kdWarning(7040) << "writeSymLink not implemented in this class." << endl
00350         << "No fallback available." << endl;
00351   // FIXME: better return true here for compatibility with KDE < 3.2
00352   return false;
00353 }
00354 
00355 bool KArchive::writeData( const char* data, uint size )
00356 {
00357     WriteDataParams params;
00358     params.data = data;
00359     params.size = size;
00360     virtual_hook( VIRTUAL_WRITE_DATA, &params );
00361     return params.retval;
00362 }
00363 
00364 bool KArchive::writeData_impl( const char* data, uint size )
00365 {
00366     Q_ASSERT( device() );
00367     return device()->writeBlock( data, size ) == (Q_LONG)size;
00368 }
00369 
00370 KArchiveDirectory * KArchive::rootDir()
00371 {
00372     if ( !d->rootDir )
00373     {
00374         //kdDebug() << "Making root dir " << endl;
00375         struct passwd* pw =  getpwuid( getuid() );
00376         struct group* grp = getgrgid( getgid() );
00377         QString username = pw ? QFile::decodeName(pw->pw_name) : QString::number( getuid() );
00378         QString groupname = grp ? QFile::decodeName(grp->gr_name) : QString::number( getgid() );
00379 
00380         d->rootDir = new KArchiveDirectory( this, QString::fromLatin1("/"), (int)(0777 + S_IFDIR), 0, username, groupname, QString::null );
00381     }
00382     return d->rootDir;
00383 }
00384 
00385 KArchiveDirectory * KArchive::findOrCreate( const QString & path )
00386 {
00387     //kdDebug() << "KArchive::findOrCreate " << path << endl;
00388     if ( path.isEmpty() || path == "/" || path == "." ) // root dir => found
00389     {
00390         //kdDebug() << "KArchive::findOrCreate returning rootdir" << endl;
00391         return rootDir();
00392     }
00393     // Important note : for tar files containing absolute paths
00394     // (i.e. beginning with "/"), this means the leading "/" will
00395     // be removed (no KDirectory for it), which is exactly the way
00396     // the "tar" program works (though it displays a warning about it)
00397     // See also KArchiveDirectory::entry().
00398 
00399     // Already created ? => found
00400     KArchiveEntry* ent = rootDir()->entry( path );
00401     if ( ent )
00402     {
00403         if ( ent->isDirectory() )
00404             //kdDebug() << "KArchive::findOrCreate found it" << endl;
00405             return (KArchiveDirectory *) ent;
00406         else
00407             kdWarning() << "Found " << path << " but it's not a directory" << endl;
00408     }
00409 
00410     // Otherwise go up and try again
00411     int pos = path.findRev( '/' );
00412     KArchiveDirectory * parent;
00413     QString dirname;
00414     if ( pos == -1 ) // no more slash => create in root dir
00415     {
00416         parent =  rootDir();
00417         dirname = path;
00418     }
00419     else
00420     {
00421         QString left = path.left( pos );
00422         dirname = path.mid( pos + 1 );
00423         parent = findOrCreate( left ); // recursive call... until we find an existing dir.
00424     }
00425 
00426     //kdDebug() << "KTar : found parent " << parent->name() << " adding " << dirname << " to ensure " << path << endl;
00427     // Found -> add the missing piece
00428     KArchiveDirectory * e = new KArchiveDirectory( this, dirname, d->rootDir->permissions(),
00429                                                    d->rootDir->date(), d->rootDir->user(),
00430                                                    d->rootDir->group(), QString::null );
00431     parent->addEntry( e );
00432     return e; // now a directory to <path> exists
00433 }
00434 
00435 void KArchive::setDevice( QIODevice * dev )
00436 {
00437     m_dev = dev;
00438 }
00439 
00440 void KArchive::setRootDir( KArchiveDirectory *rootDir )
00441 {
00442     Q_ASSERT( !d->rootDir ); // Call setRootDir only once during parsing please ;)
00443     d->rootDir = rootDir;
00444 }
00445 
00446 QString KArchive::decodeEntryName( const QCString & name )
00447 {
00448     QTextCodec *codec = NULL;
00449     char *src = name.data();
00450     int len = name.length();
00451 
00452     if (strncmp(setlocale(LC_CTYPE,""), "ja_JP", 5) != 0)
00453         return QFile::decodeName(name);
00454 
00455     for (; len>0 && *src != '\0'; len--) {
00456         //int c1 = (int)(*src), c2 = (int)(*(src ++)), c3;
00457         int c1, c2, c3;
00458         c1 = *src & 0xff;
00459         src++;
00460         c2 = *(src++) & 0xff;
00461 
00462         if (c2 == '\0') {
00463             if (c1 > 0xa0 && c1 < 0xe0)
00464                 /* CP932 */
00465                 codec = QTextCodec::codecForName( "Shift-JIS" );
00466             break;
00467         }
00468         else if (c1 == 0x1b) {
00469             if (c2 == '$' || c2 == '&')
00470                 /* ISO-2022-JP */
00471                 codec = QTextCodec::codecForName( "Shift-JIS" );
00472             break;
00473         }
00474         else if (c1 < 0x80) { continue; }
00475         else if (((c1 > 0x80 && c1 < 0xa0) || (c1 >= 0xe0 && c1 < 0xfd))
00476             && ((c2 >= 0x40 && c2 < 0x7f) || (c2 >= 0x80 && c2 < 0xfd))) {
00477             /* CP932 Full-width Kanji */
00478             codec = QTextCodec::codecForName( "Shift-JIS" );
00479             break;
00480         }
00481         else if (c1 == 0x8f && c2 > 0xa0 && c2 < 0xff) {
00482             c3 = *(src++) & 0xff;
00483             if (c3 > 0x0a && c3 < 0xff)
00484                 /* 3 byte EUC-JP */
00485                 codec = QTextCodec::codecForName( "eucJP" );
00486             break;
00487         }
00488         else if (c1 > 0xa0 && c1 < 0xff) {
00489             if (c2 > 0xa0 && c2 < 0xff)
00490                 /* 2byte EUC-JP */
00491                 codec = QTextCodec::codecForName( "eucJP" );
00492             else if (c1 < 0xe0)
00493                 /* CP932 Half-width Kana */
00494                 codec = QTextCodec::codecForName( "Shift-JIS" );
00495             break;
00496         }
00497     }
00498 
00499     if (codec == NULL)
00500         return QFile::decodeName(name);
00501     else
00502         return codec->toUnicode(name);
00503 }
00504 
00508 KArchiveEntry::KArchiveEntry( KArchive* t, const QString& name, int access, int date,
00509                       const QString& user, const QString& group, const
00510                       QString& symlink)
00511 {
00512   m_name = name;
00513   m_access = access;
00514   m_date = date;
00515   m_user = user;
00516   m_group = group;
00517   m_symlink = symlink;
00518   m_archive = t;
00519 
00520 }
00521 
00522 QDateTime KArchiveEntry::datetime() const
00523 {
00524   QDateTime d;
00525   d.setTime_t( m_date );
00526   return d;
00527 }
00528 
00532 
00533 KArchiveFile::KArchiveFile( KArchive* t, const QString& name, int access, int date,
00534                     const QString& user, const QString& group,
00535                     const QString & symlink,
00536                     int pos, int size )
00537   : KArchiveEntry( t, name, access, date, user, group, symlink )
00538 {
00539   m_pos = pos;
00540   m_size = size;
00541 }
00542 
00543 int KArchiveFile::position() const
00544 {
00545   return m_pos;
00546 }
00547 
00548 int KArchiveFile::size() const
00549 {
00550   return m_size;
00551 }
00552 
00553 QByteArray KArchiveFile::data() const
00554 {
00555   archive()->device()->at( m_pos );
00556 
00557   // Read content
00558   QByteArray arr( m_size );
00559   if ( m_size )
00560   {
00561     assert( arr.data() );
00562     int n = archive()->device()->readBlock( arr.data(), m_size );
00563     if ( n != m_size )
00564       arr.resize( n );
00565   }
00566   return arr;
00567 }
00568 
00569 // ** This should be a virtual method, and this code should be in ktar.cpp
00570 QIODevice *KArchiveFile::device() const
00571 {
00572     return new KLimitedIODevice( archive()->device(), m_pos, m_size );
00573 }
00574 
00575 void KArchiveFile::copyTo(const QString& dest) const
00576 {
00577   QFile f( dest + "/"  + name() );
00578   f.open( IO_ReadWrite | IO_Truncate );
00579   f.writeBlock( data() );
00580   f.close();
00581 }
00582 
00586 
00587 
00588 KArchiveDirectory::KArchiveDirectory( KArchive* t, const QString& name, int access,
00589                               int date,
00590                               const QString& user, const QString& group,
00591                               const QString &symlink)
00592   : KArchiveEntry( t, name, access, date, user, group, symlink )
00593 {
00594   m_entries.setAutoDelete( true );
00595 }
00596 
00597 QStringList KArchiveDirectory::entries() const
00598 {
00599   QStringList l;
00600 
00601   QDictIterator<KArchiveEntry> it( m_entries );
00602   for( ; it.current(); ++it )
00603     l.append( it.currentKey() );
00604 
00605   return l;
00606 }
00607 
00608 KArchiveEntry* KArchiveDirectory::entry( QString name )
00609   // not "const QString & name" since we want a local copy
00610   // (to remove leading slash if any)
00611 {
00612   int pos = name.find( '/' );
00613   if ( pos == 0 ) // ouch absolute path (see also KArchive::findOrCreate)
00614   {
00615     if (name.length()>1)
00616     {
00617       name = name.mid( 1 ); // remove leading slash
00618       pos = name.find( '/' ); // look again
00619     }
00620     else // "/"
00621       return this;
00622   }
00623   // trailing slash ? -> remove
00624   if ( pos != -1 && pos == (int)name.length()-1 )
00625   {
00626     name = name.left( pos );
00627     pos = name.find( '/' ); // look again
00628   }
00629   if ( pos != -1 )
00630   {
00631     QString left = name.left( pos );
00632     QString right = name.mid( pos + 1 );
00633 
00634     //kdDebug() << "KArchiveDirectory::entry left=" << left << " right=" << right << endl;
00635 
00636     KArchiveEntry* e = m_entries[ left ];
00637     if ( !e || !e->isDirectory() )
00638       return 0;
00639     return ((KArchiveDirectory*)e)->entry( right );
00640   }
00641 
00642   return m_entries[ name ];
00643 }
00644 
00645 const KArchiveEntry* KArchiveDirectory::entry( QString name ) const
00646 {
00647   return ((KArchiveDirectory*)this)->entry( name );
00648 }
00649 
00650 void KArchiveDirectory::addEntry( KArchiveEntry* entry )
00651 {
00652   Q_ASSERT( !entry->name().isEmpty() );
00653   if( m_entries[ entry->name() ] ) {
00654       kdWarning() << "KArchiveDirectory::addEntry: directory " << name()
00655                   << " has entry " << entry->name() << " already" << endl;
00656   }
00657   m_entries.insert( entry->name(), entry );
00658 }
00659 
00660 void KArchiveDirectory::copyTo(const QString& dest, bool recursiveCopy ) const
00661 {
00662   QDir root;
00663 
00664   PosSortedPtrList fileList;
00665   QMap<int, QString> fileToDir;
00666 
00667   QStringList::Iterator it;
00668 
00669   // placeholders for iterated items
00670   KArchiveDirectory* curDir;
00671   QString curDirName;
00672 
00673   QStringList dirEntries;
00674   KArchiveEntry* curEntry;
00675   KArchiveFile* curFile;
00676 
00677 
00678   QPtrStack<KArchiveDirectory> dirStack;
00679   QValueStack<QString> dirNameStack;
00680 
00681   dirStack.push( this );     // init stack at current directory
00682   dirNameStack.push( dest ); // ... with given path
00683   do {
00684     curDir = dirStack.pop();
00685     curDirName = dirNameStack.pop();
00686     root.mkdir(curDirName);
00687 
00688     dirEntries = curDir->entries();
00689     for ( it = dirEntries.begin(); it != dirEntries.end(); ++it ) {
00690       curEntry = curDir->entry(*it);
00691       if (!curEntry->symlink().isEmpty()) {
00692           const QString linkName = curDirName+'/'+curEntry->name();
00693           kdDebug() << "symlink(" << curEntry->symlink() << ',' << linkName << ')';
00694 #ifdef Q_OS_UNIX
00695           if (!::symlink(curEntry->symlink().local8Bit(), linkName.local8Bit())) {
00696               kdDebug() << "symlink(" << curEntry->symlink() << ',' << linkName << ") failed:" << strerror(errno);
00697           }
00698 #endif
00699       } else {
00700           if ( curEntry->isFile() ) {
00701               curFile = dynamic_cast<KArchiveFile*>( curEntry );
00702               if (curFile) {
00703                   fileList.append( curFile );
00704                   fileToDir.insert( curFile->position(), curDirName );
00705               }
00706           }
00707 
00708           if ( curEntry->isDirectory() )
00709               if ( recursiveCopy ) {
00710                   KArchiveDirectory *ad = dynamic_cast<KArchiveDirectory*>( curEntry );
00711                   if (ad) {
00712                       dirStack.push( ad );
00713                       dirNameStack.push( curDirName + "/" + curEntry->name() );
00714                   }
00715               }
00716       }
00717     }
00718   } while (!dirStack.isEmpty());
00719 
00720   fileList.sort();  // sort on m_pos, so we have a linear access
00721 
00722   KArchiveFile* f;
00723   for ( f = fileList.first(); f; f = fileList.next() ) {
00724     int pos = f->position();
00725     f->copyTo( fileToDir[pos] );
00726   }
00727 }
00728 
00729 void KArchive::virtual_hook( int id, void* data )
00730 {
00731     switch (id) {
00732       case VIRTUAL_WRITE_DATA: {
00733         WriteDataParams* params = reinterpret_cast<WriteDataParams *>(data);
00734         params->retval = writeData_impl( params->data, params->size );
00735         break;
00736       }
00737       case VIRTUAL_WRITE_SYMLINK: {
00738         WriteSymlinkParams *params = reinterpret_cast<WriteSymlinkParams *>(data);
00739         params->retval = writeSymLink_impl(*params->name,*params->target,
00740                 *params->user,*params->group,params->perm,
00741                 params->atime,params->mtime,params->ctime);
00742         break;
00743       }
00744       case VIRTUAL_WRITE_DIR: {
00745         WriteDirParams *params = reinterpret_cast<WriteDirParams *>(data);
00746         params->retval = writeDir_impl(*params->name,*params->user,
00747                 *params->group,params->perm,
00748                 params->atime,params->mtime,params->ctime);
00749         break;
00750       }
00751       case VIRTUAL_WRITE_FILE: {
00752         WriteFileParams *params = reinterpret_cast<WriteFileParams *>(data);
00753         params->retval = writeFile_impl(*params->name,*params->user,
00754                 *params->group,params->size,params->perm,
00755                 params->atime,params->mtime,params->ctime,
00756                     params->data);
00757         break;
00758       }
00759       case VIRTUAL_PREPARE_WRITING: {
00760         PrepareWritingParams *params = reinterpret_cast<PrepareWritingParams *>(data);
00761         params->retval = prepareWriting_impl(*params->name,*params->user,
00762                 *params->group,params->size,params->perm,
00763                 params->atime,params->mtime,params->ctime);
00764         break;
00765       }
00766       default:
00767         /*BASE::virtual_hook( id, data )*/;
00768     }/*end switch*/
00769 }
00770 
00771 void KArchiveEntry::virtual_hook( int, void* )
00772 { /*BASE::virtual_hook( id, data );*/ }
00773 
00774 void KArchiveFile::virtual_hook( int id, void* data )
00775 { KArchiveEntry::virtual_hook( id, data ); }
00776 
00777 void KArchiveDirectory::virtual_hook( int id, void* data )
00778 { KArchiveEntry::virtual_hook( id, data ); }
KDE Home | KDE Accessibility Home | Description of Access Keys