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,¶ms); 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,¶ms); 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,¶ms); 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 = ⌖ 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,¶ms); 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, ¶ms ); 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 ); }