28 #include <tqcstring.h>
32 #include <kmimetype.h>
33 #include <tdetempfile.h>
35 #include <kfilterdev.h>
36 #include <kfilterbase.h>
39 #include <tdestandarddirs.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";
118 else if ( firstByte ==
'L' && secondByte ==
'Z' && thirdByte ==
'I' )
120 unsigned char fourthByte = file.getch();
121 unsigned char fifthByte = file.getch();
122 if ( fourthByte ==
'P' && fifthByte == 0x01 )
123 mimetype =
"application/x-lzip";
130 d->mimetype = mimetype;
132 prepareDevice( filename, mimetype, forced );
135 void KTar::prepareDevice(
const TQString & filename,
136 const TQString & mimetype,
bool )
138 if(
"application/x-tar" == mimetype )
139 setDevice(
new TQFile( filename ) );
151 d->tmpFile =
new KTempFile(locateLocal(
"tmp",
"ktar-"),
".tar");
152 kdDebug( 7041 ) <<
"KTar::prepareDevice creating TempFile: " << d->tmpFile->name() << endl;
153 d->tmpFile->setAutoDelete(
true);
157 TQFile* file = d->tmpFile->file();
178 else if ( !m_filename.isEmpty() )
189 kdWarning(7041) <<
"KTar::setOrigFileName: File must be opened for writing first.\n";
195 TQ_LONG KTar::readRawHeader(
char *buffer) {
197 TQ_LONG n =
device()->readBlock( buffer, 0x200 );
198 if ( n == 0x200 && buffer[0] != 0 ) {
200 if (strncmp(buffer + 257,
"ustar", 5)) {
205 for( uint j = 0; j < 0x200; ++j )
209 for( uint j = 0; j < 8 ; j++ )
210 check -= buffer[148 + j];
213 s.sprintf(
"%o", check );
218 if( strncmp( buffer + 148 + 6 - s.length(), s.data(), s.length() )
219 && strncmp( buffer + 148 + 7 - s.length(), s.data(), s.length() )
220 && strncmp( buffer + 148 + 8 - s.length(), s.data(), s.length() ) ) {
221 kdWarning(7041) <<
"KTar: invalid TAR file. Header is: " << TQCString( buffer+257, 5 ) << endl;
227 if (n == 0x200) n = 0;
232 bool KTar::readLonglink(
char *buffer,TQCString &longlink) {
234 TQIODevice *dev =
device();
239 const char* p = buffer + 0x7c;
240 while( *p ==
' ' ) ++p;
241 int size = (int)strtol( p, &dummy, 8 );
243 longlink.resize(size);
245 dummy = longlink.data();
248 int chunksize = TQMIN(size, 0x200);
249 n = dev->readBlock( dummy + offset, chunksize );
250 if (n == -1)
return false;
255 int skip = 0x200 - (n % 0x200);
257 if (dev->readBlock(buffer,skip) != skip)
return false;
262 TQ_LONG KTar::readHeader(
char *buffer,TQString &name,TQString &symlink) {
266 TQ_LONG n = readRawHeader(buffer);
267 if (n != 0x200)
return n;
270 if (strcmp(buffer,
"././@LongLink") == 0) {
271 char typeflag = buffer[0x9c];
273 readLonglink(buffer,longlink);
275 case 'L': name = TQFile::decodeName(longlink);
break;
276 case 'K':
symlink = TQFile::decodeName(longlink);
break;
287 name = TQFile::decodeName(TQCString(buffer, 101));
289 symlink = TQFile::decodeName(TQCString(buffer + 0x9d, 101));
299 bool KTar::KTarPrivate::fillTempFile(
const TQString & filename) {
304 "KTar::openArchive: filling tmpFile of mimetype '" <<
mimetype <<
308 if(
"application/x-gzip" == mimetype
309 ||
"application/x-bzip2" == mimetype
310 ||
"application/x-lzma" == mimetype
311 ||
"application/x-xz" == mimetype
312 ||
"application/x-lzip" == mimetype)
318 TQFile* file = tmpFile->file();
320 if ( ! file->open( IO_WriteOnly ) )
325 TQByteArray buffer(8*1024);
326 if ( ! filterDev->open( IO_ReadOnly ) )
332 while ( !filterDev->atEnd() && len != 0) {
333 len = filterDev->readBlock(buffer.data(),buffer.size());
338 file->writeBlock(buffer.data(),len);
344 if ( ! file->open( IO_ReadOnly ) )
348 kdDebug( 7041 ) <<
"KTar::openArchive: no filterdevice found!" << endl;
350 kdDebug( 7041 ) <<
"KTar::openArchive: filling tmpFile finished." << endl;
356 kdDebug( 7041 ) <<
"KTar::openArchive" << endl;
357 if ( !(
mode & IO_ReadOnly) )
360 if ( !d->fillTempFile( m_filename ) )
369 TQIODevice* dev =
device();
375 char buffer[ 0x200 ];
383 TQ_LONG n = readHeader(buffer,name,symlink);
384 if (n < 0)
return false;
390 if ( name.right(1) ==
"/" )
393 name = name.left( name.length() - 1 );
396 int pos = name.findRev(
'/' );
400 nm = name.mid( pos + 1 );
405 const char* p = buffer + 0x64;
406 while( *p ==
' ' ) ++p;
407 int access = (int)strtol( p, &dummy, 8 );
410 TQString user( buffer + 0x109 );
411 TQString group( buffer + 0x129 );
416 while( *p ==
' ' ) ++p;
417 int time = (int)strtol( p, &dummy, 8 );
420 char typeflag = buffer[ 0x9c ];
424 if ( typeflag ==
'5' )
427 bool isDumpDir =
false;
428 if ( typeflag ==
'D' )
450 const char* p = buffer + 0x7c;
451 while( *p ==
' ' ) ++p;
452 int size = (int)strtol( p, &dummy, 8 );
464 if ( typeflag ==
'1' )
466 kdDebug(7041) <<
"HARD LINK, setting size to 0 instead of " << size << endl;
471 e =
new KArchiveFile(
this, nm, access, time, user, group, symlink,
476 int rest = size % 0x200;
477 int skip = size + (rest ? 0x200 - rest : 0);
479 if (! dev->at( dev->at() + skip ) )
480 kdWarning(7041) <<
"KTar::openArchive skipping " << skip <<
" failed" << endl;
497 TQString path = TQDir::cleanDirPath( name.left( pos ) );
506 d->tarEnd = dev->at() - n;
518 bool KTar::KTarPrivate::writeBackTempFile(
const TQString & filename ) {
522 kdDebug(7041) <<
"Write temporary file to compressed file" << endl;
523 kdDebug(7041) << filename <<
" " << mimetype << endl;
526 if(
"application/x-gzip" == mimetype
527 ||
"application/x-bzip2" == mimetype
528 ||
"application/x-lzma" == mimetype
529 ||
"application/x-xz" == mimetype
530 ||
"application/x-lzip" == mimetype)
535 TQFile* file = tmpFile->file();
537 if ( ! file->open(IO_ReadOnly) || ! dev->open(IO_WriteOnly) )
544 static_cast<KFilterDev *
>(dev)->setOrigFileName( origFileName );
545 TQByteArray buffer(8*1024);
547 while ( ! file->atEnd()) {
548 len = file->readBlock(buffer.data(),buffer.size());
549 dev->writeBlock(buffer.data(),len);
556 kdDebug(7041) <<
"Write temporary file to compressed file done." << endl;
567 if(
mode() == IO_WriteOnly)
568 return d->writeBackTempFile( m_filename );
573 bool KTar::writeDir(
const TQString& name,
const TQString& user,
const TQString& group )
575 mode_t perm = 040755;
576 time_t the_time = time(0);
577 return writeDir(name,user,group,perm,the_time,the_time,the_time);
581 kdWarning(7041) <<
"KTar::writeDir: You must open the tar file before writing to it\n";
585 if ( !(
mode() & IO_WriteOnly) )
587 kdWarning(7041) <<
"KTar::writeDir: You must open the tar file for writing\n";
592 TQString dirName ( TQDir::cleanDirPath( name ) );
595 if ( dirName.right(1) !=
"/" )
598 if ( d->dirList.contains( dirName ) )
601 char buffer[ 0x201 ];
602 memset( buffer, 0, 0x200 );
603 if (
mode() & IO_ReadWrite )
device()->at(d->tarEnd);
606 if ( dirName.length() > 99 )
608 strcpy( buffer,
"././@LongLink" );
609 fillBuffer( buffer,
" 0", dirName.length()+1,
'L', user.local8Bit(), group.local8Bit() );
610 device()->writeBlock( buffer, 0x200 );
611 strncpy( buffer, TQFile::encodeName(dirName), 0x200 );
614 device()->writeBlock( buffer, 0x200 );
620 strncpy( buffer, TQFile::encodeName(dirName), 0x200 );
624 fillBuffer( buffer,
" 40755", 0, 0x35, user.local8Bit(), group.local8Bit());
627 device()->writeBlock( buffer, 0x200 );
628 if (
mode() & IO_ReadWrite ) d->tarEnd =
device()->at();
630 d->dirList.append( dirName );
637 mode_t dflt_perm = 0100644;
638 time_t the_time = time(0);
640 the_time,the_time,the_time);
646 int rest = size % 0x200;
647 if (
mode() & IO_ReadWrite )
648 d->tarEnd =
device()->at() + (rest ? 0x200 - rest : 0);
651 char buffer[ 0x201 ];
652 for( uint i = 0; i < 0x200; ++i )
654 TQ_LONG nwritten =
device()->writeBlock( buffer, 0x200 - rest );
655 return nwritten == 0x200 - rest;
683 void KTar::fillBuffer(
char * buffer,
684 const char * mode,
int size, time_t mtime,
char typeflag,
685 const char * uname,
const char * gname )
688 assert( strlen(
mode) == 6 );
689 strcpy( buffer+0x64,
mode );
690 buffer[ 0x6a ] =
' ';
691 buffer[ 0x6b ] =
'\0';
694 strcpy( buffer + 0x6c,
" 765 ");
696 strcpy( buffer + 0x74,
" 144 ");
700 s.sprintf(
"%o", size);
701 s = s.rightJustify( 11,
' ' );
702 strcpy( buffer + 0x7c, s.data() );
703 buffer[ 0x87 ] =
' ';
706 s.sprintf(
"%lo",
static_cast<unsigned long>(mtime) );
707 s = s.rightJustify( 11,
' ' );
708 strcpy( buffer + 0x88, s.data() );
709 buffer[ 0x93 ] =
' ';
712 buffer[ 0x94 ] = 0x20;
713 buffer[ 0x95 ] = 0x20;
714 buffer[ 0x96 ] = 0x20;
715 buffer[ 0x97 ] = 0x20;
716 buffer[ 0x98 ] = 0x20;
717 buffer[ 0x99 ] = 0x20;
724 buffer[ 0x9a ] =
'\0';
725 buffer[ 0x9b ] =
' ';
728 buffer[ 0x9c ] = typeflag;
731 strcpy( buffer + 0x101,
"ustar");
732 strcpy( buffer + 0x107,
"00" );
735 strcpy( buffer + 0x109, uname );
737 strcpy( buffer + 0x129, gname );
741 for( uint j = 0; j < 0x200; ++j )
743 s.sprintf(
"%o", check );
744 s = s.rightJustify( 7,
' ' );
745 strcpy( buffer + 0x94, s.data() );
748 void KTar::writeLonglink(
char *buffer,
const TQCString &name,
char typeflag,
749 const char *uname,
const char *gname) {
750 strcpy( buffer,
"././@LongLink" );
751 int namelen = name.length() + 1;
752 fillBuffer( buffer,
" 0", namelen, 0, typeflag, uname, gname );
753 device()->writeBlock( buffer, 0x200 );
755 while (namelen > 0) {
756 int chunksize = TQMIN(namelen, 0x200);
757 memcpy(buffer, name.data()+offset, chunksize);
759 device()->writeBlock( buffer, 0x200 );
761 namelen -= chunksize;
767 const TQString& group, uint size, mode_t perm,
768 time_t atime, time_t mtime, time_t ctime) {
772 bool KTar::prepareWriting_impl(
const TQString &name,
const TQString &user,
773 const TQString &group, uint size, mode_t perm,
774 time_t , time_t mtime, time_t ) {
777 kdWarning(7041) <<
"KTar::prepareWriting: You must open the tar file before writing to it\n";
781 if ( !(
mode() & IO_WriteOnly) )
783 kdWarning(7041) <<
"KTar::prepareWriting: You must open the tar file for writing\n";
788 TQString
fileName ( TQDir::cleanDirPath( name ) );
809 char buffer[ 0x201 ];
810 memset( buffer, 0, 0x200 );
811 if (
mode() & IO_ReadWrite )
device()->at(d->tarEnd);
814 TQCString encodedFilename = TQFile::encodeName(
fileName);
815 TQCString uname = user.local8Bit();
816 TQCString gname = group.local8Bit();
820 writeLonglink(buffer,encodedFilename,
'L',uname,gname);
823 strncpy( buffer, encodedFilename, 99 );
826 memset(buffer+0x9d, 0, 0x200 - 0x9d);
829 permstr.sprintf(
"%o",perm);
830 permstr = permstr.rightJustify(6,
' ');
831 fillBuffer(buffer, permstr, size, mtime, 0x30, uname, gname);
834 return device()->writeBlock( buffer, 0x200 ) == 0x200;
838 const TQString& group, mode_t perm,
839 time_t atime, time_t mtime, time_t ctime) {
843 bool KTar::writeDir_impl(
const TQString &name,
const TQString &user,
844 const TQString &group, mode_t perm,
845 time_t , time_t mtime, time_t ) {
848 kdWarning(7041) <<
"KTar::writeDir: You must open the tar file before writing to it\n";
852 if ( !(
mode() & IO_WriteOnly) )
854 kdWarning(7041) <<
"KTar::writeDir: You must open the tar file for writing\n";
859 TQString dirName ( TQDir::cleanDirPath( name ) );
862 if ( dirName.right(1) !=
"/" )
865 if ( d->dirList.contains( dirName ) )
868 char buffer[ 0x201 ];
869 memset( buffer, 0, 0x200 );
870 if (
mode() & IO_ReadWrite )
device()->at(d->tarEnd);
873 TQCString encodedDirname = TQFile::encodeName(dirName);
874 TQCString uname = user.local8Bit();
875 TQCString gname = group.local8Bit();
878 if ( dirName.length() > 99 )
879 writeLonglink(buffer,encodedDirname,
'L',uname,gname);
882 strncpy( buffer, encodedDirname, 99 );
885 memset(buffer+0x9d, 0, 0x200 - 0x9d);
888 permstr.sprintf(
"%o",perm);
889 permstr = permstr.rightJustify(6,
' ');
890 fillBuffer( buffer, permstr, 0, mtime, 0x35, uname, gname);
893 device()->writeBlock( buffer, 0x200 );
894 if (
mode() & IO_ReadWrite ) d->tarEnd =
device()->at();
896 d->dirList.append( dirName );
900 bool KTar::writeSymLink(
const TQString &name,
const TQString &target,
901 const TQString &user,
const TQString &group,
902 mode_t perm, time_t atime, time_t mtime, time_t ctime) {
906 bool KTar::writeSymLink_impl(
const TQString &name,
const TQString &target,
907 const TQString &user,
const TQString &group,
908 mode_t perm, time_t , time_t mtime, time_t ) {
911 kdWarning(7041) <<
"KTar::writeSymLink: You must open the tar file before writing to it\n";
915 if ( !(
mode() & IO_WriteOnly) )
917 kdWarning(7041) <<
"KTar::writeSymLink: You must open the tar file for writing\n";
924 TQString
fileName ( TQDir::cleanDirPath( name ) );
926 char buffer[ 0x201 ];
927 memset( buffer, 0, 0x200 );
928 if (
mode() & IO_ReadWrite )
device()->at(d->tarEnd);
931 TQCString encodedFilename = TQFile::encodeName(
fileName);
932 TQCString encodedTarget = TQFile::encodeName(target);
933 TQCString uname = user.local8Bit();
934 TQCString gname = group.local8Bit();
937 if (target.length() > 99)
938 writeLonglink(buffer,encodedTarget,
'K',uname,gname);
940 writeLonglink(buffer,encodedFilename,
'L',uname,gname);
943 strncpy( buffer, encodedFilename, 99 );
946 strncpy(buffer+0x9d, encodedTarget, 99);
949 memset(buffer+0x9d+100, 0, 0x200 - 100 - 0x9d);
952 permstr.sprintf(
"%o",perm);
953 permstr = permstr.rightJustify(6,
' ');
954 fillBuffer(buffer, permstr, 0, mtime, 0x32, uname, gname);
957 bool retval =
device()->writeBlock( buffer, 0x200 ) == 0x200;
958 if (
mode() & IO_ReadWrite ) d->tarEnd =
device()->at();
962 void KTar::virtual_hook(
int id,
void* data ) {
964 case VIRTUAL_WRITE_SYMLINK: {
965 WriteSymlinkParams *params =
reinterpret_cast<WriteSymlinkParams *
>(data);
966 params->retval = writeSymLink_impl(*params->name,*params->target,
967 *params->user,*params->group,params->perm,
968 params->atime,params->mtime,params->ctime);
971 case VIRTUAL_WRITE_DIR: {
972 WriteDirParams *params =
reinterpret_cast<WriteDirParams *
>(data);
973 params->retval = writeDir_impl(*params->name,*params->user,
974 *params->group,params->perm,
975 params->atime,params->mtime,params->ctime);
978 case VIRTUAL_PREPARE_WRITING: {
979 PrepareWritingParams *params =
reinterpret_cast<PrepareWritingParams *
>(data);
980 params->retval = prepareWriting_impl(*params->name,*params->user,
981 *params->group,params->size,params->perm,
982 params->atime,params->mtime,params->ctime);
986 KArchive::virtual_hook(
id, data );