00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 #include <stdlib.h> 
00022 #include <time.h> 
00023 
00024 
00025 
00026 #include <assert.h>
00027 
00028 #include <qcstring.h>
00029 #include <qdir.h>
00030 #include <qfile.h>
00031 #include <kdebug.h>
00032 #include <kmimetype.h>
00033 
00034 #include <kfilterdev.h>
00035 #include <kfilterbase.h>
00036 
00037 #include "ktar.h"
00038 
00042 
00043 class KTar::KTarPrivate
00044 {
00045 public:
00046     KTarPrivate() : tarEnd( 0 ) {}
00047     QStringList dirList;
00048     int tarEnd;
00049 };
00050 
00051 KTar::KTar( const QString& filename, const QString & _mimetype )
00052     : KArchive( 0L )
00053 {
00054     m_filename = filename;
00055     d = new KTarPrivate;
00056     QString mimetype( _mimetype );
00057     bool forced = true;
00058     if ( mimetype.isEmpty() )
00059     {
00060     if ( QFile::exists( filename ) )
00061             mimetype = KMimeType::findByFileContent( filename )->name();
00062     else
00063         mimetype = KMimeType::findByPath( filename, 0, true )->name();
00064         kdDebug(7041) << "KTar::KTar mimetype=" << mimetype << endl;
00065 
00066         
00067         if ( mimetype == "application/x-tgz" || mimetype == "application/x-targz" || 
00068              mimetype == "application/x-webarchive" )
00069             
00070             mimetype = "application/x-gzip";
00071         else if ( mimetype == "application/x-tbz" ) 
00072             mimetype = "application/x-bzip2";
00073         else
00074         {
00075             
00076             QFile file( filename );
00077             if ( file.open( IO_ReadOnly ) )
00078             {
00079                 unsigned char firstByte = file.getch();
00080                 unsigned char secondByte = file.getch();
00081                 unsigned char thirdByte = file.getch();
00082                 if ( firstByte == 0037 && secondByte == 0213 )
00083                     mimetype = "application/x-gzip";
00084                 else if ( firstByte == 'B' && secondByte == 'Z' && thirdByte == 'h' )
00085                     mimetype = "application/x-bzip2";
00086                 else if ( firstByte == 'P' && secondByte == 'K' && thirdByte == 3 )
00087                 {
00088                     unsigned char fourthByte = file.getch();
00089                     if ( fourthByte == 4 )
00090                         mimetype = "application/x-zip";
00091                 }
00092             }
00093         }
00094         forced = false;
00095     }
00096 
00097     prepareDevice( filename, mimetype, forced );
00098 }
00099 
00100 void KTar::prepareDevice( const QString & filename,
00101                             const QString & mimetype, bool forced )
00102 {
00103   if( "application/x-tar" == mimetype )
00104       setDevice( new QFile( filename ) );
00105   else
00106   {
00107     if( "application/x-gzip" == mimetype
00108        || "application/x-bzip2" == mimetype)
00109         forced = true;
00110 
00111     QIODevice *dev = KFilterDev::deviceForFile( filename, mimetype, forced );
00112     if( dev )
00113       setDevice( dev );
00114   }
00115 }
00116 
00117 KTar::KTar( QIODevice * dev )
00118     : KArchive( dev )
00119 {
00120     d = new KTarPrivate;
00121 }
00122 
00123 KTar::~KTar()
00124 {
00125     
00126     if( isOpened() )
00127         close();
00128     if ( !m_filename.isEmpty() )
00129         delete device(); 
00130     delete d;
00131 }
00132 
00133 void KTar::setOrigFileName( const QCString & fileName )
00134 {
00135     if ( !isOpened() || !(mode() & IO_WriteOnly) )
00136     {
00137         kdWarning(7041) << "KTar::setOrigFileName: File must be opened for writing first.\n";
00138         return;
00139     }
00140     static_cast<KFilterDev *>(device())->setOrigFileName( fileName );
00141 }
00142 
00143 Q_LONG KTar::readRawHeader(char *buffer) {
00144   
00145   Q_LONG n = device()->readBlock( buffer, 0x200 );
00146   if ( n == 0x200 && buffer[0] != 0 ) {
00147     
00148     if (strncmp(buffer + 257, "ustar", 5)) {
00149       
00150       QCString s;
00151 
00152       int check = 0;
00153       for( uint j = 0; j < 0x200; ++j )
00154         check += buffer[j];
00155 
00156       
00157       for( uint j = 0; j < 8 ; j++ )
00158         check -= buffer[148 + j];
00159       check += 8 * ' ';
00160 
00161       s.sprintf("%o", check );
00162 
00163       
00164       
00165       if( strncmp( buffer + 148 + 6 - s.length(), s.data(), s.length() ) ) {
00166         kdWarning(7041) << "KTar: invalid TAR file. Header is: " << QCString( buffer+257, 5 ) << endl;
00167         return -1;
00168       }
00169     }
00170   } else {
00171     
00172     if (n == 0x200) n = 0;
00173   }
00174   return n;
00175 }
00176 
00177 bool KTar::readLonglink(char *buffer,QCString &longlink) {
00178   Q_LONG n = 0;
00179   QIODevice *dev = device();
00180   
00181   
00182   buffer[ 0x88 ] = 0; 
00183   char *dummy;
00184   const char* p = buffer + 0x7c;
00185   while( *p == ' ' ) ++p;
00186   int size = (int)strtol( p, &dummy, 8 );
00187 
00188   longlink.resize(size);
00189   size--;   
00190   dummy = longlink.data();
00191   int offset = 0;
00192   while (size > 0) {
00193     int chunksize = QMIN(size, 0x200);
00194     n = dev->readBlock( dummy + offset, chunksize );
00195     if (n == -1) return false;
00196     size -= chunksize;
00197     offset += 0x200;
00198   }
00199   
00200   int skip = 0x200 - (n % 0x200);
00201   if (skip < 0x200) {
00202     if (dev->readBlock(buffer,skip) != skip) return false;
00203   }
00204   return true;
00205 }
00206 
00207 Q_LONG KTar::readHeader(char *buffer,QString &name,QString &symlink) {
00208   name.truncate(0);
00209   symlink.truncate(0);
00210   while (true) {
00211     Q_LONG n = readRawHeader(buffer);
00212     if (n != 0x200) return n;
00213 
00214     
00215     if (strcmp(buffer,"././@LongLink") == 0) {
00216       char typeflag = buffer[0x9c];
00217       QCString longlink;
00218       readLonglink(buffer,longlink);
00219       switch (typeflag) {
00220         case 'L': name = QFile::decodeName(longlink); break;
00221         case 'K': symlink = QFile::decodeName(longlink); break;
00222       }
00223     } else {
00224       break;
00225     }
00226   }
00227 
00228   
00229   if (name.isEmpty())
00230     name = QFile::decodeName(buffer);
00231   if (symlink.isEmpty())
00232     symlink = QFile::decodeName(buffer + 0x9d);
00233 
00234   return 0x200;
00235 }
00236 
00237 bool KTar::openArchive( int mode )
00238 {
00239     if ( !(mode & IO_ReadOnly) )
00240         return true;
00241 
00242     
00243     
00244     
00245     
00246 
00247     d->dirList.clear();
00248     QIODevice* dev = device();
00249 
00250     
00251     char buffer[ 0x200 ];
00252     bool ende = false;
00253     do
00254     {
00255         QString name;
00256         QString symlink;
00257 
00258         
00259         Q_LONG n = readHeader(buffer,name,symlink);
00260         if (n < 0) return false;
00261         if (n == 0x200)
00262         {
00263             bool isdir = false;
00264             QString nm;
00265 
00266             if ( name.right(1) == "/" )
00267             {
00268                 isdir = true;
00269                 name = name.left( name.length() - 1 );
00270             }
00271 
00272             int pos = name.findRev( '/' );
00273             if ( pos == -1 )
00274                 nm = name;
00275             else
00276                 nm = name.mid( pos + 1 );
00277 
00278             
00279             buffer[ 0x6b ] = 0;
00280             char *dummy;
00281             const char* p = buffer + 0x64;
00282             while( *p == ' ' ) ++p;
00283             int access = (int)strtol( p, &dummy, 8 );
00284 
00285             
00286             QString user( buffer + 0x109 );
00287             QString group( buffer + 0x129 );
00288 
00289             
00290             buffer[ 0x93 ] = 0;
00291             p = buffer + 0x88;
00292             while( *p == ' ' ) ++p;
00293             int time = (int)strtol( p, &dummy, 8 );
00294 
00295             
00296             char typeflag = buffer[ 0x9c ];
00297             
00298             
00299             
00300             if ( typeflag == '1' )
00301                 isdir = true;
00302 
00303             bool isDumpDir = false;
00304             if ( typeflag == 'D' )
00305             {
00306                 isdir = false;
00307                 isDumpDir = true;
00308             }
00309             
00310             
00311 
00312             if (isdir)
00313                 access |= S_IFDIR; 
00314 
00315             KArchiveEntry* e;
00316             if ( isdir )
00317             {
00318                 
00319                 e = new KArchiveDirectory( this, nm, access, time, user, group, symlink );
00320             }
00321             else
00322             {
00323                 
00324                 buffer[ 0x88 ] = 0; 
00325                 char *dummy;
00326                 const char* p = buffer + 0x7c;
00327                 while( *p == ' ' ) ++p;
00328                 int size = (int)strtol( p, &dummy, 8 );
00329 
00330                 
00331                 if ( isDumpDir )
00332                 {
00333             e = new KArchiveDirectory( this, nm, access, time, user, group, symlink );
00334                 }
00335         else
00336         {
00337 
00338                     
00339                     if ( typeflag == '1' )
00340                     {
00341                         size = nm.length(); 
00342                         kdDebug(7041) << "HARD LINK, setting size to " << size << endl;
00343                     }
00344 
00345                     
00346 
00347                     e = new KArchiveFile( this, nm, access, time, user, group, symlink,
00348                                           dev->at(), size );
00349         }
00350 
00351                 
00352                 int rest = size % 0x200;
00353                 int skip = size + (rest ? 0x200 - rest : 0);
00354                 
00355                 if (! dev->at( dev->at() + skip ) )
00356                     kdWarning(7041) << "KArchive::open skipping " << skip << " failed" << endl;
00357             }
00358 
00359             if ( pos == -1 )
00360             {
00361                 if ( nm == "." ) 
00362                 {
00363                     Q_ASSERT( isdir );
00364                     if ( isdir )
00365                         setRootDir( static_cast<KArchiveDirectory *>( e ) );
00366                 }
00367                 else
00368                     rootDir()->addEntry( e );
00369             }
00370             else
00371             {
00372                 
00373                 QString path = QDir::cleanDirPath( name.left( pos ) );
00374                 
00375                 KArchiveDirectory * d = findOrCreate( path );
00376                 d->addEntry( e );
00377             }
00378         }
00379         else
00380         {
00381             
00382             d->tarEnd = dev->at() - n; 
00383             ende = true;
00384         }
00385     } while( !ende );
00386     return true;
00387 }
00388 
00389 bool KTar::closeArchive()
00390 {
00391     d->dirList.clear();
00392     return true;
00393 }
00394 
00395 bool KTar::writeDir( const QString& name, const QString& user, const QString& group )
00396 {
00397     mode_t perm = 040755;
00398     time_t the_time = time(0);
00399     return writeDir(name,user,group,perm,the_time,the_time,the_time);
00400 #if 0
00401     if ( !isOpened() )
00402     {
00403         kdWarning(7041) << "KTar::writeDir: You must open the tar file before writing to it\n";
00404         return false;
00405     }
00406 
00407     if ( !(mode() & IO_WriteOnly) )
00408     {
00409         kdWarning(7041) << "KTar::writeDir: You must open the tar file for writing\n";
00410         return false;
00411     }
00412 
00413     
00414     QString dirName ( QDir::cleanDirPath( name ) );
00415 
00416     
00417     if ( dirName.right(1) != "/" )
00418         dirName += "/";
00419 
00420     if ( d->dirList.contains( dirName ) )
00421         return true; 
00422 
00423     char buffer[ 0x201 ];
00424     memset( buffer, 0, 0x200 );
00425     if ( mode() & IO_ReadWrite ) device()->at(d->tarEnd); 
00426 
00427     
00428     if ( dirName.length() > 99 )
00429     {
00430         strcpy( buffer, "././@LongLink" );
00431         fillBuffer( buffer, "     0", dirName.length()+1, 'L', user.local8Bit(), group.local8Bit() );
00432         device()->writeBlock( buffer, 0x200 );
00433         strncpy( buffer, QFile::encodeName(dirName), 0x200 );
00434         buffer[0x200] = 0;
00435         
00436         device()->writeBlock( buffer, 0x200 );
00437         
00438     }
00439     else
00440     {
00441         
00442         strncpy( buffer, QFile::encodeName(dirName), 0x200 );
00443         buffer[0x200] = 0;
00444     }
00445 
00446     fillBuffer( buffer, " 40755", 0, 0x35, user.local8Bit(), group.local8Bit());
00447 
00448     
00449     device()->writeBlock( buffer, 0x200 );
00450     if ( mode() & IO_ReadWrite )  d->tarEnd = device()->at();
00451 
00452     d->dirList.append( dirName ); 
00453     return true; 
00454 #endif
00455 }
00456 
00457 bool KTar::prepareWriting( const QString& name, const QString& user, const QString& group, uint size )
00458 {
00459     mode_t dflt_perm = 0100644;
00460     time_t the_time = time(0);
00461     return prepareWriting(name,user,group,size,dflt_perm,
00462             the_time,the_time,the_time);
00463 }
00464 
00465 bool KTar::doneWriting( uint size )
00466 {
00467     
00468     int rest = size % 0x200;
00469     if ( mode() & IO_ReadWrite )
00470         d->tarEnd = device()->at() + (rest ? 0x200 - rest : 0); 
00471     if ( rest )
00472     {
00473         char buffer[ 0x201 ];
00474         for( uint i = 0; i < 0x200; ++i )
00475             buffer[i] = 0;
00476         Q_LONG nwritten = device()->writeBlock( buffer, 0x200 - rest );
00477         return nwritten == 0x200 - rest;
00478     }
00479     return true;
00480 }
00481 
00482 
00483 
00484 
00485 
00486 
00487 
00488 
00489 
00490 
00491 
00492 
00493 
00494 
00495 
00496 
00497 
00498 
00499 
00500 
00501 
00502 
00503 
00504 
00505 void KTar::fillBuffer( char * buffer,
00506     const char * mode, int size, time_t mtime, char typeflag,
00507     const char * uname, const char * gname )
00508 {
00509   
00510   assert( strlen(mode) == 6 );
00511   strcpy( buffer+0x64, mode );
00512   buffer[ 0x6a ] = ' ';
00513   buffer[ 0x6b ] = '\0';
00514 
00515   
00516   strcpy( buffer + 0x6c, "   765 ");
00517   
00518   strcpy( buffer + 0x74, "   144 ");
00519 
00520   
00521   QCString s;
00522   s.sprintf("%o", size); 
00523   s = s.rightJustify( 11, ' ' );
00524   strcpy( buffer + 0x7c, s.data() );
00525   buffer[ 0x87 ] = ' '; 
00526 
00527   
00528   s.sprintf("%lo", static_cast<unsigned long>(mtime) ); 
00529   s = s.rightJustify( 11, ' ' );
00530   strcpy( buffer + 0x88, s.data() );
00531   buffer[ 0x93 ] = ' '; 
00532 
00533   
00534   buffer[ 0x94 ] = 0x20;
00535   buffer[ 0x95 ] = 0x20;
00536   buffer[ 0x96 ] = 0x20;
00537   buffer[ 0x97 ] = 0x20;
00538   buffer[ 0x98 ] = 0x20;
00539   buffer[ 0x99 ] = 0x20;
00540 
00541   
00542 
00543 
00544 
00545 
00546   buffer[ 0x9a ] = '\0';
00547   buffer[ 0x9b ] = ' ';
00548 
00549   
00550   buffer[ 0x9c ] = typeflag;
00551 
00552  
00553   strcpy( buffer + 0x101, "ustar");
00554   strcpy( buffer + 0x107, "00" );
00555 
00556   
00557   strcpy( buffer + 0x109, uname );
00558   
00559   strcpy( buffer + 0x129, gname );
00560 
00561   
00562   int check = 32;
00563   for( uint j = 0; j < 0x200; ++j )
00564     check += buffer[j];
00565   s.sprintf("%o", check ); 
00566   s = s.rightJustify( 7, ' ' );
00567   strcpy( buffer + 0x94, s.data() );
00568 }
00569 
00570 void KTar::writeLonglink(char *buffer, const QCString &name, char typeflag,
00571     const char *uname, const char *gname) {
00572   strcpy( buffer, "././@LongLink" );
00573   int namelen = name.length() + 1;
00574   fillBuffer( buffer, "     0", namelen, 0, typeflag, uname, gname );
00575   device()->writeBlock( buffer, 0x200 );
00576   int offset = 0;
00577   while (namelen > 0) {
00578     int chunksize = QMIN(namelen, 0x200);
00579     memcpy(buffer, name.data()+offset, chunksize);
00580     
00581     device()->writeBlock( buffer, 0x200 );
00582     
00583     namelen -= chunksize;
00584     offset += 0x200;
00585   } 
00586 }
00587 
00588 bool KTar::prepareWriting(const QString& name, const QString& user,
00589                 const QString& group, uint size, mode_t perm,
00590                 time_t atime, time_t mtime, time_t ctime) {
00591   return KArchive::prepareWriting(name,user,group,size,perm,atime,mtime,ctime);
00592 }
00593 
00594 bool KTar::prepareWriting_impl(const QString &name, const QString &user,
00595                 const QString &group, uint size, mode_t perm,
00596                 time_t , time_t mtime, time_t ) {
00597     if ( !isOpened() )
00598     {
00599         kdWarning(7041) << "KTar::prepareWriting: You must open the tar file before writing to it\n";
00600         return false;
00601     }
00602 
00603     if ( !(mode() & IO_WriteOnly) )
00604     {
00605         kdWarning(7041) << "KTar::prepareWriting: You must open the tar file for writing\n";
00606         return false;
00607     }
00608 
00609     
00610     QString fileName ( QDir::cleanDirPath( name ) );
00611 
00612     
00613 
00614 
00615 
00616 
00617 
00618 
00619 
00620 
00621 
00622 
00623 
00624 
00625 
00626 
00627 
00628 
00629 
00630 
00631     char buffer[ 0x201 ];
00632     memset( buffer, 0, 0x200 );
00633     if ( mode() & IO_ReadWrite ) device()->at(d->tarEnd); 
00634 
00635     
00636     QCString encodedFilename = QFile::encodeName(fileName);
00637     QCString uname = user.local8Bit();
00638     QCString gname = group.local8Bit();
00639 
00640     
00641     if ( fileName.length() > 99 )
00642         writeLonglink(buffer,encodedFilename,'L',uname,gname);
00643 
00644     
00645     strncpy( buffer, encodedFilename, 99 );
00646     buffer[99] = 0;
00647     
00648     memset(buffer+0x9d, 0, 0x200 - 0x9d);
00649 
00650     QCString permstr;
00651     permstr.sprintf("%o",perm);
00652     permstr.rightJustify(6, ' ');
00653     fillBuffer(buffer, permstr, size, mtime, 0x30, uname, gname);
00654 
00655     
00656     return device()->writeBlock( buffer, 0x200 ) == 0x200;
00657 }
00658 
00659 bool KTar::writeDir(const QString& name, const QString& user,
00660                 const QString& group, mode_t perm,
00661                 time_t atime, time_t mtime, time_t ctime) {
00662   return KArchive::writeDir(name,user,group,perm,atime,mtime,ctime);
00663 }
00664 
00665 bool KTar::writeDir_impl(const QString &name, const QString &user,
00666                 const QString &group, mode_t perm,
00667                 time_t , time_t mtime, time_t ) {
00668     if ( !isOpened() )
00669     {
00670         kdWarning(7041) << "KTar::writeDir: You must open the tar file before writing to it\n";
00671         return false;
00672     }
00673 
00674     if ( !(mode() & IO_WriteOnly) )
00675     {
00676         kdWarning(7041) << "KTar::writeDir: You must open the tar file for writing\n";
00677         return false;
00678     }
00679 
00680     
00681     QString dirName ( QDir::cleanDirPath( name ) );
00682 
00683     
00684     if ( dirName.right(1) != "/" )
00685         dirName += "/";
00686 
00687     if ( d->dirList.contains( dirName ) )
00688         return true; 
00689 
00690     char buffer[ 0x201 ];
00691     memset( buffer, 0, 0x200 );
00692     if ( mode() & IO_ReadWrite ) device()->at(d->tarEnd); 
00693 
00694     
00695     QCString encodedDirname = QFile::encodeName(dirName);
00696     QCString uname = user.local8Bit();
00697     QCString gname = group.local8Bit();
00698     
00699     
00700     if ( dirName.length() > 99 )
00701         writeLonglink(buffer,encodedDirname,'L',uname,gname);
00702 
00703     
00704     strncpy( buffer, encodedDirname, 99 );
00705     buffer[99] = 0;
00706     
00707     memset(buffer+0x9d, 0, 0x200 - 0x9d);
00708 
00709     QCString permstr;
00710     permstr.sprintf("%o",perm);
00711     permstr.rightJustify(6, ' ');
00712     fillBuffer( buffer, permstr, 0, mtime, 0x35, uname, gname);
00713 
00714     
00715     device()->writeBlock( buffer, 0x200 );
00716     if ( mode() & IO_ReadWrite )  d->tarEnd = device()->at();
00717 
00718     d->dirList.append( dirName ); 
00719     return true; 
00720 }
00721 
00722 bool KTar::writeSymLink(const QString &name, const QString &target,
00723                 const QString &user, const QString &group,
00724                 mode_t perm, time_t atime, time_t mtime, time_t ctime) {
00725   return KArchive::writeSymLink(name,target,user,group,perm,atime,mtime,ctime);
00726 }
00727 
00728 bool KTar::writeSymLink_impl(const QString &name, const QString &target,
00729                 const QString &user, const QString &group,
00730                 mode_t perm, time_t , time_t mtime, time_t ) {
00731     if ( !isOpened() )
00732     {
00733         kdWarning(7041) << "KTar::writeSymLink: You must open the tar file before writing to it\n";
00734         return false;
00735     }
00736 
00737     if ( !(mode() & IO_WriteOnly) )
00738     {
00739         kdWarning(7041) << "KTar::writeSymLink: You must open the tar file for writing\n";
00740         return false;
00741     }
00742 
00743     device()->flush();
00744 
00745     
00746     QString fileName ( QDir::cleanDirPath( name ) );
00747 
00748     char buffer[ 0x201 ];
00749     memset( buffer, 0, 0x200 );
00750     if ( mode() & IO_ReadWrite ) device()->at(d->tarEnd); 
00751 
00752     
00753     QCString encodedFilename = QFile::encodeName(fileName);
00754     QCString encodedTarget = QFile::encodeName(target);
00755     QCString uname = user.local8Bit();
00756     QCString gname = group.local8Bit();
00757 
00758     
00759     if (target.length() > 99)
00760         writeLonglink(buffer,encodedTarget,'K',uname,gname);
00761     if ( fileName.length() > 99 )
00762         writeLonglink(buffer,encodedFilename,'L',uname,gname);
00763 
00764     
00765     strncpy( buffer, encodedFilename, 99 );
00766     buffer[99] = 0;
00767     
00768     strncpy(buffer+0x9d, encodedTarget, 99);
00769     buffer[0x9d+99] = 0;
00770     
00771     memset(buffer+0x9d+100, 0, 0x200 - 100 - 0x9d);
00772 
00773     QCString permstr;
00774     permstr.sprintf("%o",perm);
00775     permstr.rightJustify(6, ' ');
00776     fillBuffer(buffer, permstr, 0, mtime, 0x32, uname, gname);
00777 
00778     
00779     bool retval = device()->writeBlock( buffer, 0x200 ) == 0x200;
00780     if ( mode() & IO_ReadWrite )  d->tarEnd = device()->at();
00781     return retval;
00782 }
00783 
00784 void KTar::virtual_hook( int id, void* data ) {
00785   switch (id) {
00786     case VIRTUAL_WRITE_SYMLINK: {
00787       WriteSymlinkParams *params = reinterpret_cast<WriteSymlinkParams *>(data);
00788       params->retval = writeSymLink_impl(*params->name,*params->target,
00789                 *params->user,*params->group,params->perm,
00790                 params->atime,params->mtime,params->ctime);
00791       break;
00792     }
00793     case VIRTUAL_WRITE_DIR: {
00794       WriteDirParams *params = reinterpret_cast<WriteDirParams *>(data);
00795       params->retval = writeDir_impl(*params->name,*params->user,
00796             *params->group,params->perm,
00797                 params->atime,params->mtime,params->ctime);
00798       break;
00799     }
00800     case VIRTUAL_PREPARE_WRITING: {
00801       PrepareWritingParams *params = reinterpret_cast<PrepareWritingParams *>(data);
00802       params->retval = prepareWriting_impl(*params->name,*params->user,
00803                 *params->group,params->size,params->perm,
00804                 params->atime,params->mtime,params->ctime);
00805       break;
00806     }
00807     default:
00808       KArchive::virtual_hook( id, data );
00809   }
00810 }
00811