28 #include <tqcstring.h>
32 #include <kmimetype.h>
33 #include <tdetempfile.h>
35 #include <kfilterdev.h>
36 #include <kfilterbase.h>
39 #include <kstandarddirs.h>
45 class KTar::KTarPrivate
48 KTarPrivate() : tarEnd( 0 ), tmpFile( 0 ) {}
53 TQCString origFileName;
55 bool fillTempFile(
const TQString & filename);
56 bool writeBackTempFile(
const TQString & filename );
59 KTar::KTar(
const TQString& filename,
const TQString & _mimetype )
62 m_filename = filename;
64 TQString mimetype( _mimetype );
66 if ( mimetype.isEmpty() )
68 if ( TQFile::exists( filename ) )
72 kdDebug(7041) <<
"KTar::KTar mimetype = " << mimetype << endl;
75 if ( mimetype ==
"application/x-tgz" || mimetype ==
"application/x-targz" ||
76 mimetype ==
"application/x-webarchive" )
79 mimetype =
"application/x-gzip";
81 else if ( mimetype ==
"application/x-tbz" )
83 mimetype =
"application/x-bzip2";
88 TQFile file( filename );
89 if ( file.open( IO_ReadOnly ) )
91 unsigned char firstByte = file.getch();
92 unsigned char secondByte = file.getch();
93 unsigned char thirdByte = file.getch();
94 if ( firstByte == 0037 && secondByte == 0213 )
95 mimetype =
"application/x-gzip";
96 else if ( firstByte ==
'B' && secondByte ==
'Z' && thirdByte ==
'h' )
97 mimetype =
"application/x-bzip2";
98 else if ( firstByte ==
'P' && secondByte ==
'K' && thirdByte == 3 )
100 unsigned char fourthByte = file.getch();
101 if ( fourthByte == 4 )
102 mimetype =
"application/x-zip";
104 else if ( firstByte == 0xfd && secondByte ==
'7' && thirdByte ==
'z' )
106 unsigned char fourthByte = file.getch();
107 unsigned char fifthByte = file.getch();
108 unsigned char sixthByte = file.getch();
109 if ( fourthByte ==
'X' && fifthByte ==
'Z' && sixthByte == 0x00 )
110 mimetype =
"application/x-xz";
112 else if ( firstByte == 0x5d && secondByte == 0x00 && thirdByte == 0x00 )
114 unsigned char fourthByte = file.getch();
115 if ( fourthByte == 0x80 )
116 mimetype =
"application/x-lzma";
123 d->mimetype = mimetype;
125 prepareDevice( filename, mimetype, forced );
128 void KTar::prepareDevice(
const TQString & filename,
129 const TQString & mimetype,
bool )
131 if(
"application/x-tar" == mimetype )
132 setDevice(
new TQFile( filename ) );
144 d->tmpFile =
new KTempFile(locateLocal(
"tmp",
"ktar-"),
".tar");
145 kdDebug( 7041 ) <<
"KTar::prepareDevice creating TempFile: " << d->tmpFile->name() << endl;
146 d->tmpFile->setAutoDelete(
true);
150 TQFile* file = d->tmpFile->file();
171 else if ( !m_filename.isEmpty() )
182 kdWarning(7041) <<
"KTar::setOrigFileName: File must be opened for writing first.\n";
188 TQ_LONG KTar::readRawHeader(
char *buffer) {
190 TQ_LONG n =
device()->readBlock( buffer, 0x200 );
191 if ( n == 0x200 && buffer[0] != 0 ) {
193 if (strncmp(buffer + 257,
"ustar", 5)) {
198 for( uint j = 0; j < 0x200; ++j )
202 for( uint j = 0; j < 8 ; j++ )
203 check -= buffer[148 + j];
206 s.sprintf(
"%o", check );
211 if( strncmp( buffer + 148 + 6 - s.length(), s.data(), s.length() )
212 && strncmp( buffer + 148 + 7 - s.length(), s.data(), s.length() )
213 && strncmp( buffer + 148 + 8 - s.length(), s.data(), s.length() ) ) {
214 kdWarning(7041) <<
"KTar: invalid TAR file. Header is: " << TQCString( buffer+257, 5 ) << endl;
220 if (n == 0x200) n = 0;
225 bool KTar::readLonglink(
char *buffer,TQCString &longlink) {
227 TQIODevice *dev =
device();
232 const char* p = buffer + 0x7c;
233 while( *p ==
' ' ) ++p;
234 int size = (int)strtol( p, &dummy, 8 );
236 longlink.resize(size);
238 dummy = longlink.data();
241 int chunksize = TQMIN(size, 0x200);
242 n = dev->readBlock( dummy + offset, chunksize );
243 if (n == -1)
return false;
248 int skip = 0x200 - (n % 0x200);
250 if (dev->readBlock(buffer,skip) != skip)
return false;
255 TQ_LONG KTar::readHeader(
char *buffer,TQString &name,TQString &symlink) {
259 TQ_LONG n = readRawHeader(buffer);
260 if (n != 0x200)
return n;
263 if (strcmp(buffer,
"././@LongLink") == 0) {
264 char typeflag = buffer[0x9c];
266 readLonglink(buffer,longlink);
268 case 'L': name = TQFile::decodeName(longlink);
break;
269 case 'K':
symlink = TQFile::decodeName(longlink);
break;
280 name = TQFile::decodeName(TQCString(buffer, 101));
282 symlink = TQFile::decodeName(TQCString(buffer + 0x9d, 101));
292 bool KTar::KTarPrivate::fillTempFile(
const TQString & filename) {
297 "KTar::openArchive: filling tmpFile of mimetype '" <<
mimetype <<
301 if(
"application/x-gzip" == mimetype
302 ||
"application/x-bzip2" == mimetype
303 ||
"application/x-lzma" == mimetype
304 ||
"application/x-xz" == mimetype)
310 TQFile* file = tmpFile->file();
312 if ( ! file->open( IO_WriteOnly ) )
317 TQByteArray buffer(8*1024);
318 if ( ! filterDev->open( IO_ReadOnly ) )
324 while ( !filterDev->atEnd() && len != 0) {
325 len = filterDev->readBlock(buffer.data(),buffer.size());
330 file->writeBlock(buffer.data(),len);
336 if ( ! file->open( IO_ReadOnly ) )
340 kdDebug( 7041 ) <<
"KTar::openArchive: no filterdevice found!" << endl;
342 kdDebug( 7041 ) <<
"KTar::openArchive: filling tmpFile finished." << endl;
348 kdDebug( 7041 ) <<
"KTar::openArchive" << endl;
349 if ( !(
mode & IO_ReadOnly) )
352 if ( !d->fillTempFile( m_filename ) )
361 TQIODevice* dev =
device();
367 char buffer[ 0x200 ];
375 TQ_LONG n = readHeader(buffer,name,symlink);
376 if (n < 0)
return false;
382 if ( name.right(1) ==
"/" )
385 name = name.left( name.length() - 1 );
388 int pos = name.findRev(
'/' );
392 nm = name.mid( pos + 1 );
397 const char* p = buffer + 0x64;
398 while( *p ==
' ' ) ++p;
399 int access = (int)strtol( p, &dummy, 8 );
402 TQString user( buffer + 0x109 );
403 TQString group( buffer + 0x129 );
408 while( *p ==
' ' ) ++p;
409 int time = (int)strtol( p, &dummy, 8 );
412 char typeflag = buffer[ 0x9c ];
416 if ( typeflag ==
'5' )
419 bool isDumpDir =
false;
420 if ( typeflag ==
'D' )
442 const char* p = buffer + 0x7c;
443 while( *p ==
' ' ) ++p;
444 int size = (int)strtol( p, &dummy, 8 );
456 if ( typeflag ==
'1' )
458 kdDebug(7041) <<
"HARD LINK, setting size to 0 instead of " << size << endl;
463 e =
new KArchiveFile(
this, nm, access, time, user, group, symlink,
468 int rest = size % 0x200;
469 int skip = size + (rest ? 0x200 - rest : 0);
471 if (! dev->at( dev->at() + skip ) )
472 kdWarning(7041) <<
"KTar::openArchive skipping " << skip <<
" failed" << endl;
489 TQString path = TQDir::cleanDirPath( name.left( pos ) );
498 d->tarEnd = dev->at() - n;
510 bool KTar::KTarPrivate::writeBackTempFile(
const TQString & filename ) {
514 kdDebug(7041) <<
"Write temporary file to compressed file" << endl;
515 kdDebug(7041) << filename <<
" " << mimetype << endl;
518 if(
"application/x-gzip" == mimetype
519 ||
"application/x-bzip2" == mimetype
520 ||
"application/x-lzma" == mimetype
521 ||
"application/x-xz" == mimetype)
526 TQFile* file = tmpFile->file();
528 if ( ! file->open(IO_ReadOnly) || ! dev->open(IO_WriteOnly) )
535 static_cast<KFilterDev *
>(dev)->setOrigFileName( origFileName );
536 TQByteArray buffer(8*1024);
538 while ( ! file->atEnd()) {
539 len = file->readBlock(buffer.data(),buffer.size());
540 dev->writeBlock(buffer.data(),len);
547 kdDebug(7041) <<
"Write temporary file to compressed file done." << endl;
558 if(
mode() == IO_WriteOnly)
559 return d->writeBackTempFile( m_filename );
564 bool KTar::writeDir(
const TQString& name,
const TQString& user,
const TQString& group )
566 mode_t perm = 040755;
567 time_t the_time = time(0);
568 return writeDir(name,user,group,perm,the_time,the_time,the_time);
572 kdWarning(7041) <<
"KTar::writeDir: You must open the tar file before writing to it\n";
576 if ( !(
mode() & IO_WriteOnly) )
578 kdWarning(7041) <<
"KTar::writeDir: You must open the tar file for writing\n";
583 TQString dirName ( TQDir::cleanDirPath( name ) );
586 if ( dirName.right(1) !=
"/" )
589 if ( d->dirList.contains( dirName ) )
592 char buffer[ 0x201 ];
593 memset( buffer, 0, 0x200 );
594 if (
mode() & IO_ReadWrite )
device()->at(d->tarEnd);
597 if ( dirName.length() > 99 )
599 strcpy( buffer,
"././@LongLink" );
600 fillBuffer( buffer,
" 0", dirName.length()+1,
'L', user.local8Bit(), group.local8Bit() );
601 device()->writeBlock( buffer, 0x200 );
602 strncpy( buffer, TQFile::encodeName(dirName), 0x200 );
605 device()->writeBlock( buffer, 0x200 );
611 strncpy( buffer, TQFile::encodeName(dirName), 0x200 );
615 fillBuffer( buffer,
" 40755", 0, 0x35, user.local8Bit(), group.local8Bit());
618 device()->writeBlock( buffer, 0x200 );
619 if (
mode() & IO_ReadWrite ) d->tarEnd =
device()->at();
621 d->dirList.append( dirName );
628 mode_t dflt_perm = 0100644;
629 time_t the_time = time(0);
631 the_time,the_time,the_time);
637 int rest = size % 0x200;
638 if (
mode() & IO_ReadWrite )
639 d->tarEnd =
device()->at() + (rest ? 0x200 - rest : 0);
642 char buffer[ 0x201 ];
643 for( uint i = 0; i < 0x200; ++i )
645 TQ_LONG nwritten =
device()->writeBlock( buffer, 0x200 - rest );
646 return nwritten == 0x200 - rest;
674 void KTar::fillBuffer(
char * buffer,
675 const char * mode,
int size, time_t mtime,
char typeflag,
676 const char * uname,
const char * gname )
679 assert( strlen(
mode) == 6 );
680 strcpy( buffer+0x64,
mode );
681 buffer[ 0x6a ] =
' ';
682 buffer[ 0x6b ] =
'\0';
685 strcpy( buffer + 0x6c,
" 765 ");
687 strcpy( buffer + 0x74,
" 144 ");
691 s.sprintf(
"%o", size);
692 s = s.rightJustify( 11,
' ' );
693 strcpy( buffer + 0x7c, s.data() );
694 buffer[ 0x87 ] =
' ';
697 s.sprintf(
"%lo",
static_cast<unsigned long>(mtime) );
698 s = s.rightJustify( 11,
' ' );
699 strcpy( buffer + 0x88, s.data() );
700 buffer[ 0x93 ] =
' ';
703 buffer[ 0x94 ] = 0x20;
704 buffer[ 0x95 ] = 0x20;
705 buffer[ 0x96 ] = 0x20;
706 buffer[ 0x97 ] = 0x20;
707 buffer[ 0x98 ] = 0x20;
708 buffer[ 0x99 ] = 0x20;
715 buffer[ 0x9a ] =
'\0';
716 buffer[ 0x9b ] =
' ';
719 buffer[ 0x9c ] = typeflag;
722 strcpy( buffer + 0x101,
"ustar");
723 strcpy( buffer + 0x107,
"00" );
726 strcpy( buffer + 0x109, uname );
728 strcpy( buffer + 0x129, gname );
732 for( uint j = 0; j < 0x200; ++j )
734 s.sprintf(
"%o", check );
735 s = s.rightJustify( 7,
' ' );
736 strcpy( buffer + 0x94, s.data() );
739 void KTar::writeLonglink(
char *buffer,
const TQCString &name,
char typeflag,
740 const char *uname,
const char *gname) {
741 strcpy( buffer,
"././@LongLink" );
742 int namelen = name.length() + 1;
743 fillBuffer( buffer,
" 0", namelen, 0, typeflag, uname, gname );
744 device()->writeBlock( buffer, 0x200 );
746 while (namelen > 0) {
747 int chunksize = TQMIN(namelen, 0x200);
748 memcpy(buffer, name.data()+offset, chunksize);
750 device()->writeBlock( buffer, 0x200 );
752 namelen -= chunksize;
758 const TQString& group, uint size, mode_t perm,
759 time_t atime, time_t mtime, time_t ctime) {
763 bool KTar::prepareWriting_impl(
const TQString &name,
const TQString &user,
764 const TQString &group, uint size, mode_t perm,
765 time_t , time_t mtime, time_t ) {
768 kdWarning(7041) <<
"KTar::prepareWriting: You must open the tar file before writing to it\n";
772 if ( !(
mode() & IO_WriteOnly) )
774 kdWarning(7041) <<
"KTar::prepareWriting: You must open the tar file for writing\n";
779 TQString
fileName ( TQDir::cleanDirPath( name ) );
800 char buffer[ 0x201 ];
801 memset( buffer, 0, 0x200 );
802 if (
mode() & IO_ReadWrite )
device()->at(d->tarEnd);
805 TQCString encodedFilename = TQFile::encodeName(
fileName);
806 TQCString uname = user.local8Bit();
807 TQCString gname = group.local8Bit();
811 writeLonglink(buffer,encodedFilename,
'L',uname,gname);
814 strncpy( buffer, encodedFilename, 99 );
817 memset(buffer+0x9d, 0, 0x200 - 0x9d);
820 permstr.sprintf(
"%o",perm);
821 permstr = permstr.rightJustify(6,
' ');
822 fillBuffer(buffer, permstr, size, mtime, 0x30, uname, gname);
825 return device()->writeBlock( buffer, 0x200 ) == 0x200;
829 const TQString& group, mode_t perm,
830 time_t atime, time_t mtime, time_t ctime) {
834 bool KTar::writeDir_impl(
const TQString &name,
const TQString &user,
835 const TQString &group, mode_t perm,
836 time_t , time_t mtime, time_t ) {
839 kdWarning(7041) <<
"KTar::writeDir: You must open the tar file before writing to it\n";
843 if ( !(
mode() & IO_WriteOnly) )
845 kdWarning(7041) <<
"KTar::writeDir: You must open the tar file for writing\n";
850 TQString dirName ( TQDir::cleanDirPath( name ) );
853 if ( dirName.right(1) !=
"/" )
856 if ( d->dirList.contains( dirName ) )
859 char buffer[ 0x201 ];
860 memset( buffer, 0, 0x200 );
861 if (
mode() & IO_ReadWrite )
device()->at(d->tarEnd);
864 TQCString encodedDirname = TQFile::encodeName(dirName);
865 TQCString uname = user.local8Bit();
866 TQCString gname = group.local8Bit();
869 if ( dirName.length() > 99 )
870 writeLonglink(buffer,encodedDirname,
'L',uname,gname);
873 strncpy( buffer, encodedDirname, 99 );
876 memset(buffer+0x9d, 0, 0x200 - 0x9d);
879 permstr.sprintf(
"%o",perm);
880 permstr = permstr.rightJustify(6,
' ');
881 fillBuffer( buffer, permstr, 0, mtime, 0x35, uname, gname);
884 device()->writeBlock( buffer, 0x200 );
885 if (
mode() & IO_ReadWrite ) d->tarEnd =
device()->at();
887 d->dirList.append( dirName );
891 bool KTar::writeSymLink(
const TQString &name,
const TQString &target,
892 const TQString &user,
const TQString &group,
893 mode_t perm, time_t atime, time_t mtime, time_t ctime) {
897 bool KTar::writeSymLink_impl(
const TQString &name,
const TQString &target,
898 const TQString &user,
const TQString &group,
899 mode_t perm, time_t , time_t mtime, time_t ) {
902 kdWarning(7041) <<
"KTar::writeSymLink: You must open the tar file before writing to it\n";
906 if ( !(
mode() & IO_WriteOnly) )
908 kdWarning(7041) <<
"KTar::writeSymLink: You must open the tar file for writing\n";
915 TQString
fileName ( TQDir::cleanDirPath( name ) );
917 char buffer[ 0x201 ];
918 memset( buffer, 0, 0x200 );
919 if (
mode() & IO_ReadWrite )
device()->at(d->tarEnd);
922 TQCString encodedFilename = TQFile::encodeName(
fileName);
923 TQCString encodedTarget = TQFile::encodeName(target);
924 TQCString uname = user.local8Bit();
925 TQCString gname = group.local8Bit();
928 if (target.length() > 99)
929 writeLonglink(buffer,encodedTarget,
'K',uname,gname);
931 writeLonglink(buffer,encodedFilename,
'L',uname,gname);
934 strncpy( buffer, encodedFilename, 99 );
937 strncpy(buffer+0x9d, encodedTarget, 99);
940 memset(buffer+0x9d+100, 0, 0x200 - 100 - 0x9d);
943 permstr.sprintf(
"%o",perm);
944 permstr = permstr.rightJustify(6,
' ');
945 fillBuffer(buffer, permstr, 0, mtime, 0x32, uname, gname);
948 bool retval =
device()->writeBlock( buffer, 0x200 ) == 0x200;
949 if (
mode() & IO_ReadWrite ) d->tarEnd =
device()->at();
953 void KTar::virtual_hook(
int id,
void* data ) {
955 case VIRTUAL_WRITE_SYMLINK: {
956 WriteSymlinkParams *params =
reinterpret_cast<WriteSymlinkParams *
>(data);
957 params->retval = writeSymLink_impl(*params->name,*params->target,
958 *params->user,*params->group,params->perm,
959 params->atime,params->mtime,params->ctime);
962 case VIRTUAL_WRITE_DIR: {
963 WriteDirParams *params =
reinterpret_cast<WriteDirParams *
>(data);
964 params->retval = writeDir_impl(*params->name,*params->user,
965 *params->group,params->perm,
966 params->atime,params->mtime,params->ctime);
969 case VIRTUAL_PREPARE_WRITING: {
970 PrepareWritingParams *params =
reinterpret_cast<PrepareWritingParams *
>(data);
971 params->retval = prepareWriting_impl(*params->name,*params->user,
972 *params->group,params->size,params->perm,
973 params->atime,params->mtime,params->ctime);
977 KArchive::virtual_hook(
id, data );
Represents a directory entry in a KArchive.
A base class for entries in an KArchive.
Represents a file entry in a KArchive.
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.
KArchiveDirectory * findOrCreate(const TQString &path)
Ensures that path exists, create otherwise.
virtual void close()
Closes the archive.
int mode() const
Returns the mode in which the archive was opened.
bool isOpened() const
Checks whether the archive is open.
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...
A class for reading and writing compressed data onto a device (e.g.
static TQIODevice * deviceForFile(const TQString &fileName, const TQString &mimetype=TQString::null, bool forceFilter=false)
Creates an i/o device that is able to read from fileName, whether it's compressed or not.
static Ptr findByPath(const TQString &path, mode_t mode=0, bool fast_mode=false)
Finds a KMimeType with the given _url.
static Ptr findByFileContent(const TQString &fileName, int *accuracy=0)
Tries to find out the MIME type of a file by looking for certain magic numbers and characteristic str...
void setOrigFileName(const TQCString &fileName)
Special function for setting the "original file name" in the gzip header, when writing a tar....
TQString fileName()
The name of the tar file, as passed to the constructor Null if you used the TQIODevice constructor.
virtual bool doneWriting(uint size)
Call doneWriting after writing the data.
virtual bool openArchive(int mode)
Opens the archive for reading.
virtual ~KTar()
If the tar ball is still opened, then it will be closed automatically by the destructor.
virtual bool closeArchive()
Closes the archive.
KTar(const TQString &filename, const TQString &mimetype=TQString::null)
Creates an instance that operates on the given filename using the compression filter associated to gi...
virtual bool prepareWriting(const TQString &name, const TQString &user, const TQString &group, uint size)
Here's another way of writing a file into an archive: Call prepareWriting, then call writeData() as m...
virtual bool writeDir(const TQString &name, const TQString &user, const TQString &group)
If an archive is opened for writing then you can add new directories using this function.
TDEIO_EXPORT SimpleJob * symlink(const TQString &target, const KURL &dest, bool overwrite, bool showProgressInfo=true)
Create or move a symlink.
TDEIO_EXPORT MimetypeJob * mimetype(const KURL &url, bool showProgressInfo=true)
Find mimetype for one file or directory.