00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <stdio.h>
00022 #include <stdlib.h>
00023 #include <time.h>
00024 #include <unistd.h>
00025 #include <grp.h>
00026 #include <pwd.h>
00027 #include <assert.h>
00028
00029 #include <qptrlist.h>
00030 #include <qptrstack.h>
00031 #include <qvaluestack.h>
00032 #include <qmap.h>
00033 #include <qcstring.h>
00034 #include <qdir.h>
00035 #include <qfile.h>
00036
00037 #include <kdebug.h>
00038 #include <kfilterdev.h>
00039 #include <kfilterbase.h>
00040
00041 #include "karchive.h"
00042 #include "klimitediodevice.h"
00043
00044 template class QDict<KArchiveEntry>;
00045
00046
00047 class KArchive::KArchivePrivate
00048 {
00049 public:
00050 KArchiveDirectory* rootDir;
00051 };
00052
00053 class PosSortedPtrList : public QPtrList<KArchiveFile> {
00054 protected:
00055 int compareItems( QPtrCollection::Item i1,
00056 QPtrCollection::Item i2 )
00057 {
00058 int pos1 = static_cast<KArchiveFile*>( i1 )->position();
00059 int pos2 = static_cast<KArchiveFile*>( i2 )->position();
00060 return ( pos1 - pos2 );
00061 }
00062 };
00063
00064
00068
00069 KArchive::KArchive( QIODevice * dev )
00070 {
00071 d = new KArchivePrivate;
00072 d->rootDir = 0;
00073 m_dev = dev;
00074 m_open = false;
00075 }
00076
00077 KArchive::~KArchive()
00078 {
00079 if ( m_open )
00080 close();
00081 delete d->rootDir;
00082 delete d;
00083 }
00084
00085 bool KArchive::open( int mode )
00086 {
00087 if(0 == m_dev)
00088 return false;
00089
00090 if ( !m_dev->open( mode ) )
00091 return false;
00092
00093 if ( m_open )
00094 close();
00095
00096 m_mode = mode;
00097 m_open = true;
00098
00099 Q_ASSERT( d->rootDir == 0L );
00100 d->rootDir = 0L;
00101
00102 return openArchive( mode );
00103 }
00104
00105 void KArchive::close()
00106 {
00107 if ( !m_open )
00108 return;
00109
00110
00111 closeArchive();
00112
00113 m_dev->close();
00114
00115 delete d->rootDir;
00116 d->rootDir = 0;
00117 m_open = false;
00118 }
00119
00120 const KArchiveDirectory* KArchive::directory() const
00121 {
00122
00123 return const_cast<KArchive *>(this)->rootDir();
00124 }
00125
00126 bool KArchive::writeFile( const QString& name, const QString& user, const QString& group, uint size, const char* data )
00127 {
00128
00129 if ( !prepareWriting( name, user, group, size ) )
00130 {
00131 kdWarning() << "KArchive::writeFile prepareWriting failed" << endl;
00132 return false;
00133 }
00134
00135
00136
00137 if ( data && device()->writeBlock( data, size ) != (int)size )
00138 {
00139 kdWarning() << "KArchive::writeFile writeBlock failed" << endl;
00140 return false;
00141 }
00142
00143 if ( ! doneWriting( size ) )
00144 {
00145 kdWarning() << "KArchive::writeFile doneWriting failed" << endl;
00146 return false;
00147 }
00148 return true;
00149 }
00150
00151 KArchiveDirectory * KArchive::rootDir()
00152 {
00153 if ( !d->rootDir )
00154 {
00155
00156 struct passwd* pw = getpwuid( getuid() );
00157 struct group* grp = getgrgid( getgid() );
00158 QString username = pw ? QFile::decodeName(pw->pw_name) : QString::number( getuid() );
00159 QString groupname = grp ? QFile::decodeName(grp->gr_name) : QString::number( getgid() );
00160
00161 d->rootDir = new KArchiveDirectory( this, QString::fromLatin1("/"), (int)(0777 + S_IFDIR), 0, username, groupname, QString::null );
00162 }
00163 return d->rootDir;
00164 }
00165
00166 KArchiveDirectory * KArchive::findOrCreate( const QString & path )
00167 {
00168
00169 if ( path == "" || path == "/" || path == "." )
00170 {
00171
00172 return rootDir();
00173 }
00174
00175
00176
00177
00178
00179
00180
00181 KArchiveEntry* ent = rootDir()->entry( path );
00182 if ( ent && ent->isDirectory() )
00183 {
00184
00185 return (KArchiveDirectory *) ent;
00186 }
00187
00188
00189 int pos = path.findRev( '/' );
00190 KArchiveDirectory * parent;
00191 QString dirname;
00192 if ( pos == -1 )
00193 {
00194 parent = rootDir();
00195 dirname = path;
00196 }
00197 else
00198 {
00199 QString left = path.left( pos );
00200 dirname = path.mid( pos + 1 );
00201 parent = findOrCreate( left );
00202 }
00203
00204
00205
00206 KArchiveDirectory * e = new KArchiveDirectory( this, dirname, d->rootDir->permissions(),
00207 d->rootDir->date(), d->rootDir->user(),
00208 d->rootDir->group(), QString::null );
00209 parent->addEntry( e );
00210 return e;
00211 }
00212
00213 void KArchive::setDevice( QIODevice * dev )
00214 {
00215 m_dev = dev;
00216 }
00217
00218 void KArchive::setRootDir( KArchiveDirectory *rootDir )
00219 {
00220 Q_ASSERT( !d->rootDir );
00221 d->rootDir = rootDir;
00222 }
00223
00227 KArchiveEntry::KArchiveEntry( KArchive* t, const QString& name, int access, int date,
00228 const QString& user, const QString& group, const
00229 QString& symlink)
00230 {
00231 m_name = name;
00232 m_access = access;
00233 m_date = date;
00234 m_user = user;
00235 m_group = group;
00236 m_symlink = symlink;
00237 m_archive = t;
00238
00239 }
00240
00241 QDateTime KArchiveEntry::datetime() const
00242 {
00243 QDateTime d;
00244 d.setTime_t( m_date );
00245 return d;
00246 }
00247
00251
00252 KArchiveFile::KArchiveFile( KArchive* t, const QString& name, int access, int date,
00253 const QString& user, const QString& group,
00254 const QString & symlink,
00255 int pos, int size )
00256 : KArchiveEntry( t, name, access, date, user, group, symlink )
00257 {
00258 m_pos = pos;
00259 m_size = size;
00260 }
00261
00262 int KArchiveFile::position() const
00263 {
00264 return m_pos;
00265 }
00266
00267 int KArchiveFile::size() const
00268 {
00269 return m_size;
00270 }
00271
00272 QByteArray KArchiveFile::data() const
00273 {
00274 archive()->device()->at( m_pos );
00275
00276
00277 QByteArray arr( m_size );
00278 if ( m_size )
00279 {
00280 assert( arr.data() );
00281 int n = archive()->device()->readBlock( arr.data(), m_size );
00282 if ( n != m_size )
00283 arr.resize( n );
00284 }
00285 return arr;
00286 }
00287
00288
00289 QIODevice *KArchiveFile::device() const
00290 {
00291 return new KLimitedIODevice( archive()->device(), m_pos, m_size );
00292 }
00293
00294 void KArchiveFile::copyTo(const QString& dest) const
00295 {
00296 QFile f( dest + "/" + name() );
00297 f.open( IO_ReadWrite | IO_Truncate );
00298 f.writeBlock( data() );
00299 f.close();
00300 }
00301
00305
00306
00307 KArchiveDirectory::KArchiveDirectory( KArchive* t, const QString& name, int access,
00308 int date,
00309 const QString& user, const QString& group,
00310 const QString &symlink)
00311 : KArchiveEntry( t, name, access, date, user, group, symlink )
00312 {
00313 m_entries.setAutoDelete( true );
00314 }
00315
00316 QStringList KArchiveDirectory::entries() const
00317 {
00318 QStringList l;
00319
00320 QDictIterator<KArchiveEntry> it( m_entries );
00321 for( ; it.current(); ++it )
00322 l.append( it.currentKey() );
00323
00324 return l;
00325 }
00326
00327 KArchiveEntry* KArchiveDirectory::entry( QString name )
00328
00329
00330 {
00331 int pos = name.find( '/' );
00332 if ( pos == 0 )
00333 {
00334 if (name.length()>1)
00335 {
00336 name = name.mid( 1 );
00337 pos = name.find( '/' );
00338 }
00339 else
00340 return this;
00341 }
00342
00343 if ( pos != -1 && pos == (int)name.length()-1 )
00344 {
00345 name = name.left( pos );
00346 pos = name.find( '/' );
00347 }
00348 if ( pos != -1 )
00349 {
00350 QString left = name.left( pos );
00351 QString right = name.mid( pos + 1 );
00352
00353
00354
00355 KArchiveEntry* e = m_entries[ left ];
00356 if ( !e || !e->isDirectory() )
00357 return 0;
00358 return ((KArchiveDirectory*)e)->entry( right );
00359 }
00360
00361 return m_entries[ name ];
00362 }
00363
00364 const KArchiveEntry* KArchiveDirectory::entry( QString name ) const
00365 {
00366 return ((KArchiveDirectory*)this)->entry( name );
00367 }
00368
00369 void KArchiveDirectory::addEntry( KArchiveEntry* entry )
00370 {
00371 Q_ASSERT( !entry->name().isEmpty() );
00372 m_entries.insert( entry->name(), entry );
00373 }
00374
00375 void KArchiveDirectory::copyTo(const QString& dest, bool recursiveCopy ) const
00376 {
00377 QDir root;
00378
00379 PosSortedPtrList fileList;
00380 QMap<int, QString> fileToDir;
00381
00382 QStringList::Iterator it;
00383
00384
00385 KArchiveDirectory* curDir;
00386 QString curDirName;
00387
00388 QStringList dirEntries;
00389 KArchiveEntry* curEntry;
00390 KArchiveFile* curFile;
00391
00392
00393 QPtrStack<KArchiveDirectory> dirStack;
00394 QValueStack<QString> dirNameStack;
00395
00396 dirStack.push( this );
00397 dirNameStack.push( dest );
00398 do {
00399 curDir = dirStack.pop();
00400 curDirName = dirNameStack.pop();
00401 root.mkdir(curDirName);
00402
00403 dirEntries = curDir->entries();
00404 for ( it = dirEntries.begin(); it != dirEntries.end(); ++it ) {
00405 curEntry = curDir->entry(*it);
00406 if ( curEntry->isFile() ) {
00407 curFile = dynamic_cast<KArchiveFile*>( curEntry );
00408 fileList.append( curFile );
00409 fileToDir.insert( curFile->position(), curDirName );
00410 }
00411
00412 if ( curEntry->isDirectory() )
00413 if ( recursiveCopy ) {
00414 dirStack.push( dynamic_cast<KArchiveDirectory*>( curEntry ) );
00415 dirNameStack.push( curDirName + "/" + curEntry->name() );
00416 }
00417 }
00418 } while (!dirStack.isEmpty());
00419
00420 fileList.sort();
00421
00422 KArchiveFile* f;
00423 for ( f = fileList.first(); f; f = fileList.next() ) {
00424 int pos = f->position();
00425 f->copyTo( fileToDir[pos] );
00426 }
00427 }
00428
00429
00430 void KArchive::virtual_hook( int, void* )
00431 { }
00432
00433 void KArchiveEntry::virtual_hook( int, void* )
00434 { }
00435
00436 void KArchiveFile::virtual_hook( int id, void* data )
00437 { KArchiveEntry::virtual_hook( id, data ); }
00438
00439 void KArchiveDirectory::virtual_hook( int id, void* data )
00440 { KArchiveEntry::virtual_hook( id, data ); }
00441