30 #include <sys/types.h>
33 #include <tqptrlist.h>
34 #include <tqptrstack.h>
35 #include <tqvaluestack.h>
37 #include <tqcstring.h>
42 #include <kfilterdev.h>
43 #include <kfilterbase.h>
47 #include "klimitediodevice.h"
49 template class TQDict<KArchiveEntry>;
52 class KArchive::KArchivePrivate
59 class PosSortedPtrList :
public TQPtrList<KArchiveFile> {
61 int compareItems( TQPtrCollection::Item i1,
62 TQPtrCollection::Item i2 )
66 return ( pos1 - pos2 );
77 d =
new KArchivePrivate;
93 if ( m_dev && !m_dev->open( mode ) )
102 Q_ASSERT( d->rootDir == 0L );
126 return d->closeSucceeded;
138 TQFileInfo fileInfo( fileName );
139 if ( !fileInfo.isFile() && !fileInfo.isSymLink() )
141 kdWarning() <<
"KArchive::addLocalFile " << fileName <<
" doesn't exist or is not a regular file." << endl;
146 if (KDE_lstat(TQFile::encodeName(fileName),&fi) == -1) {
147 kdWarning() <<
"KArchive::addLocalFile stating " << fileName
148 <<
" failed: " << strerror(errno) << endl;
152 if (fileInfo.isSymLink()) {
153 return writeSymLink(destName, fileInfo.readLink(), fileInfo.owner(),
154 fileInfo.group(), fi.st_mode, fi.st_atime, fi.st_mtime,
158 uint size = fileInfo.size();
163 TQFile file( fileName );
164 if ( !file.open( IO_ReadOnly ) )
166 kdWarning() <<
"KArchive::addLocalFile couldn't open file " << fileName << endl;
170 if ( !
prepareWriting( destName, fileInfo.owner(), fileInfo.group(), size,
171 fi.st_mode, fi.st_atime, fi.st_mtime, fi.st_ctime ) )
173 kdWarning() <<
"KArchive::addLocalFile prepareWriting " << destName <<
" failed" << endl;
178 TQByteArray array(8*1024);
181 while ( ( n = file.readBlock( array.data(), array.size() ) ) > 0 )
185 kdWarning() <<
"KArchive::addLocalFile writeData failed" << endl;
190 Q_ASSERT( total == size );
194 kdWarning() <<
"KArchive::addLocalFile doneWriting failed" << endl;
203 TQString dotdot =
"..";
207 dir.setFilter(dir.filter() | TQDir::Hidden);
208 TQStringList files = dir.entryList();
209 for ( TQStringList::Iterator it = files.begin(); it != files.end(); ++it )
211 if ( *it != dot && *it != dotdot )
213 TQString fileName = path +
"/" + *it;
215 TQString dest = destName.isEmpty() ? *it : (destName +
"/" + *it);
216 TQFileInfo fileInfo( fileName );
218 if ( fileInfo.isFile() || fileInfo.isSymLink() )
220 else if ( fileInfo.isDir() )
228 bool KArchive::writeFile(
const TQString& name,
const TQString& user,
const TQString& group, uint size,
const char* data )
230 mode_t perm = 0100644;
231 time_t the_time = time(0);
232 return writeFile(name,user,group,size,perm,the_time,the_time,the_time,data);
236 const TQString& group, uint size, mode_t perm,
237 time_t atime, time_t mtime, time_t ctime ) {
238 PrepareWritingParams params;
241 params.group = &group;
244 params.atime = atime;
245 params.mtime = mtime;
246 params.ctime = ctime;
247 virtual_hook(VIRTUAL_PREPARE_WRITING,¶ms);
248 return params.retval;
251 bool KArchive::prepareWriting_impl(
const TQString &name,
const TQString &user,
252 const TQString &group, uint size, mode_t ,
253 time_t , time_t , time_t ) {
254 kdWarning(7040) <<
"New prepareWriting API not implemented in this class." << endl
255 <<
"Falling back to old API (metadata information will be lost)" << endl;
260 const TQString& group, uint size, mode_t perm,
261 time_t atime, time_t mtime, time_t ctime,
263 WriteFileParams params;
266 params.group = &group;
269 params.atime = atime;
270 params.mtime = mtime;
271 params.ctime = ctime;
273 virtual_hook(VIRTUAL_WRITE_FILE,¶ms);
274 return params.retval;
277 bool KArchive::writeFile_impl(
const TQString& name,
const TQString& user,
278 const TQString& group, uint size, mode_t perm,
279 time_t atime, time_t mtime, time_t ctime,
282 if ( !
prepareWriting( name, user, group, size, perm, atime, mtime, ctime ) )
284 kdWarning() <<
"KArchive::writeFile prepareWriting failed" << endl;
290 if ( data && size && !
writeData( data, size ) )
292 kdWarning() <<
"KArchive::writeFile writeData failed" << endl;
298 kdWarning() <<
"KArchive::writeFile doneWriting failed" << endl;
305 const TQString& group, mode_t perm,
306 time_t atime, time_t mtime, time_t ctime) {
307 WriteDirParams params;
310 params.group = &group;
312 params.atime = atime;
313 params.mtime = mtime;
314 params.ctime = ctime;
315 virtual_hook(VIRTUAL_WRITE_DIR,¶ms);
316 return params.retval;
319 bool KArchive::writeDir_impl(
const TQString &name,
const TQString &user,
320 const TQString &group, mode_t ,
321 time_t , time_t , time_t ) {
322 kdWarning(7040) <<
"New writeDir API not implemented in this class." << endl
323 <<
"Falling back to old API (metadata information will be lost)" << endl;
328 const TQString &user,
const TQString &group,
329 mode_t perm, time_t atime, time_t mtime, time_t ctime) {
330 WriteSymlinkParams params;
332 params.target = ⌖
334 params.group = &group;
336 params.atime = atime;
337 params.mtime = mtime;
338 params.ctime = ctime;
339 virtual_hook(VIRTUAL_WRITE_SYMLINK,¶ms);
340 return params.retval;
343 bool KArchive::writeSymLink_impl(
const TQString &,
const TQString &,
344 const TQString &,
const TQString &,
345 mode_t , time_t , time_t ,
347 kdWarning(7040) <<
"writeSymLink not implemented in this class." << endl
348 <<
"No fallback available." << endl;
355 WriteDataParams params;
358 virtual_hook( VIRTUAL_WRITE_DATA, ¶ms );
359 return params.retval;
362 bool KArchive::writeData_impl(
const char* data, uint size )
365 return device()->writeBlock( data, size ) == (TQ_LONG)size;
373 struct passwd* pw = getpwuid( getuid() );
374 struct group* grp = getgrgid( getgid() );
375 TQString username = pw ? TQFile::decodeName(pw->pw_name) : TQString::number( getuid() );
376 TQString groupname = grp ? TQFile::decodeName(grp->gr_name) : TQString::number( getgid() );
378 d->rootDir =
new KArchiveDirectory(
this, TQString::fromLatin1(
"/"), (
int)(0777 + S_IFDIR), 0, username, groupname, TQString::null );
386 if ( path.isEmpty() || path ==
"/" || path ==
"." )
405 kdWarning() <<
"Found " << path <<
" but it's not a directory" << endl;
409 int pos = path.findRev(
'/' );
419 TQString left = path.left( pos );
420 dirname = path.mid( pos + 1 );
427 d->rootDir->date(), d->rootDir->user(),
428 d->rootDir->group(), TQString::null );
429 parent->addEntry( e );
433 void KArchive::setDevice( TQIODevice * dev )
440 Q_ASSERT( !d->rootDir );
448 const TQString& user,
const TQString& group,
const
464 d.setTime_t( m_date );
473 const TQString& user,
const TQString& group,
474 const TQString & symlink,
476 :
KArchiveEntry( t, name, access, date, user, group, symlink )
494 archive()->
device()->at( m_pos );
497 TQByteArray arr( m_size );
500 assert( arr.data() );
501 int n = archive()->
device()->readBlock( arr.data(), m_size );
516 TQFile f( dest +
"/" +
name() );
517 f.open( IO_ReadWrite | IO_Truncate );
518 f.writeBlock(
data() );
529 const TQString& user,
const TQString& group,
530 const TQString &symlink)
531 :
KArchiveEntry( t, name, access, date, user, group, symlink )
533 m_entries.setAutoDelete(
true );
540 TQDictIterator<KArchiveEntry> it( m_entries );
541 for( ; it.current(); ++it )
542 l.append( it.currentKey() );
551 int pos = name.find(
'/' );
556 name = name.mid( 1 );
557 pos = name.find(
'/' );
563 if ( pos != -1 && pos == (
int)name.length()-1 )
565 name = name.left( pos );
566 pos = name.find(
'/' );
570 TQString left = name.left( pos );
571 TQString right = name.mid( pos + 1 );
581 return m_entries[
name ];
591 if( entry->
name().isEmpty() ) {
594 if( m_entries[ entry->
name() ] ) {
595 kdWarning() <<
"KArchiveDirectory::addEntry: directory " <<
name()
596 <<
" has entry " << entry->
name() <<
" already" << endl;
598 m_entries.insert( entry->
name(),
entry );
604 const TQString destDir(TQDir(dest).absPath());
606 PosSortedPtrList fileList;
607 TQMap<int, TQString> fileToDir;
609 TQStringList::Iterator it;
615 TQStringList dirEntries;
620 TQPtrStack<KArchiveDirectory> dirStack;
621 TQValueStack<TQString> dirNameStack;
623 dirStack.push(
this );
624 dirNameStack.push( destDir );
626 curDir = dirStack.pop();
630 TQString curDirName = dirNameStack.pop();
631 if (!TQDir(curDirName).absPath().startsWith(destDir)) {
632 kdWarning() <<
"Attempted export into folder" << curDirName
633 <<
"which is outside of the extraction root folder" << destDir <<
"."
634 <<
"Changing export of contained files to extraction root folder.";
635 curDirName = destDir;
637 root.mkdir(curDirName);
639 dirEntries = curDir->
entries();
640 for ( it = dirEntries.begin(); it != dirEntries.end(); ++it ) {
641 curEntry = curDir->
entry(*it);
642 if (!curEntry->
symlink().isEmpty()) {
643 const TQString linkName = curDirName+
'/'+curEntry->
name();
644 kdDebug() <<
"symlink(" << curEntry->
symlink() <<
',' << linkName <<
')';
646 if (!::
symlink(curEntry->
symlink().local8Bit(), linkName.local8Bit())) {
647 kdDebug() <<
"symlink(" << curEntry->
symlink() <<
',' << linkName <<
") failed:" << strerror(errno);
651 if ( curEntry->
isFile() ) {
654 fileList.append( curFile );
655 fileToDir.insert( curFile->
position(), curDirName );
660 if ( recursiveCopy ) {
664 dirNameStack.push( curDirName +
"/" + curEntry->
name() );
669 }
while (!dirStack.isEmpty());
674 for ( f = fileList.first(); f; f = fileList.next() ) {
676 f->
copyTo( fileToDir[pos] );
680 void KArchive::virtual_hook(
int id,
void* data )
683 case VIRTUAL_WRITE_DATA: {
684 WriteDataParams* params =
reinterpret_cast<WriteDataParams *
>(data);
685 params->retval = writeData_impl( params->data, params->size );
688 case VIRTUAL_WRITE_SYMLINK: {
689 WriteSymlinkParams *params =
reinterpret_cast<WriteSymlinkParams *
>(data);
690 params->retval = writeSymLink_impl(*params->name,*params->target,
691 *params->user,*params->group,params->perm,
692 params->atime,params->mtime,params->ctime);
695 case VIRTUAL_WRITE_DIR: {
696 WriteDirParams *params =
reinterpret_cast<WriteDirParams *
>(data);
697 params->retval = writeDir_impl(*params->name,*params->user,
698 *params->group,params->perm,
699 params->atime,params->mtime,params->ctime);
702 case VIRTUAL_WRITE_FILE: {
703 WriteFileParams *params =
reinterpret_cast<WriteFileParams *
>(data);
704 params->retval = writeFile_impl(*params->name,*params->user,
705 *params->group,params->size,params->perm,
706 params->atime,params->mtime,params->ctime,
710 case VIRTUAL_PREPARE_WRITING: {
711 PrepareWritingParams *params =
reinterpret_cast<PrepareWritingParams *
>(data);
712 params->retval = prepareWriting_impl(*params->name,*params->user,
713 *params->group,params->size,params->perm,
714 params->atime,params->mtime,params->ctime);
722 void KArchiveEntry::virtual_hook(
int,
void* )
725 void KArchiveFile::virtual_hook(
int id,
void* data )
726 { KArchiveEntry::virtual_hook(
id, data ); }
728 void KArchiveDirectory::virtual_hook(
int id,
void* data )
729 { KArchiveEntry::virtual_hook(
id, data ); }