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(
'/' );
557 pos =
name.find(
'/' );
563 if ( pos != -1 && pos == (
int)
name.length()-1 )
566 pos =
name.find(
'/' );
570 TQString left =
name.left( pos );
571 TQString right =
name.mid( pos + 1 );
581 return m_entries[
name ];
595 kdWarning() <<
"KArchiveDirectory::addEntry: directory " <<
name()
596 <<
" has entry " <<
entry->
name() <<
" already" << endl;
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 ); }
Represents a directory entry in a KArchive.
TQStringList entries() const
Returns a list of sub-entries.
KArchiveDirectory(KArchive *archive, const TQString &name, int access, int date, const TQString &user, const TQString &group, const TQString &symlink)
Creates a new directory entry.
void copyTo(const TQString &dest, bool recursive=true) const
Extracts all entries in this archive directory to the directory dest.
KArchiveEntry * entry(TQString name)
Returns the entry with the given name.
A base class for entries in an KArchive.
virtual bool isDirectory() const
Checks whether the entry is a directory.
int date() const
Creation date of the file.
TQString group() const
Group of the user who created the file.
TQString user() const
User who created the file.
virtual bool isFile() const
Checks whether the entry is a file.
TQString name() const
Name of the file without path.
TQDateTime datetime() const
Creation date of the file.
TQString symlink() const
Symlink if there is one.
KArchiveEntry(KArchive *archive, const TQString &name, int access, int date, const TQString &user, const TQString &group, const TQString &symlink)
Creates a new entry.
Represents a file entry in a KArchive.
void copyTo(const TQString &dest) const
Extracts the file to the directory dest.
KArchiveFile(KArchive *archive, const TQString &name, int access, int date, const TQString &user, const TQString &group, const TQString &symlink, int pos, int size)
Creates a new file entry.
int size() const
Size of the data.
TQIODevice * device() const
This method returns TQIODevice (internal class: KLimitedIODevice) on top of the underlying TQIODevice...
virtual TQByteArray data() const
Returns the data of the file.
int position() const
Position of the data in the [uncompressed] archive.
KArchive is a base class for reading and writing archives.
virtual bool writeDir(const TQString &name, const TQString &user, const TQString &group)=0
If an archive is opened for writing then you can add new directories using this function.
virtual KArchiveDirectory * rootDir()
Retrieves or create the root directory.
virtual bool open(int mode)
Opens the archive for reading or writing.
KArchive(TQIODevice *dev)
Base constructor (protected since this is a pure virtual class).
bool addLocalFile(const TQString &fileName, const TQString &destName)
Writes a local file into the archive.
KArchiveDirectory * findOrCreate(const TQString &path)
Ensures that path exists, create otherwise.
virtual void close()
Closes the archive.
bool addLocalDirectory(const TQString &path, const TQString &destName)
Writes a local directory into the archive, including all its contents, recursively.
virtual bool closeArchive()=0
Closes the archive.
const KArchiveDirectory * directory() const
If an archive is opened for reading, then the contents of the archive can be accessed via this functi...
int mode() const
Returns the mode in which the archive was opened.
virtual bool doneWriting(uint size)=0
Call doneWriting after writing the data.
virtual bool openArchive(int mode)=0
Opens an archive for reading or writing.
bool closeSucceeded() const
Use to check if close had any problem.
bool writeData(const char *data, uint size)
Write data into the current file - to be called after calling prepareWriting.
TQIODevice * device() const
The underlying device.
bool writeSymLink(const TQString &name, const TQString &target, const TQString &user, const TQString &group, mode_t perm, time_t atime, time_t mtime, time_t ctime)
Writes a symbolic link to the archive if the archive must be opened for writing.
virtual bool prepareWriting(const TQString &name, const TQString &user, const TQString &group, uint size)=0
Here's another way of writing a file into an archive: Call prepareWriting, then call writeData() as m...
virtual bool writeFile(const TQString &name, const TQString &user, const TQString &group, uint size, const char *data)
If an archive is opened for writing then you can add a new file using this function.
A readonly device that reads from an underlying device from a given point to another (e....