27#include <QtCore/QFile>
46class KTar::KTarPrivate
49 KTarPrivate(
KTar *parent)
61 QByteArray origFileName;
65 void fillBuffer(
char * buffer,
const char *
mode,
qint64 size, time_t mtime,
67 void writeLonglink(
char *buffer,
const QByteArray &name,
char typeflag,
69 qint64 readRawHeader(
char *buffer);
70 bool readLonglink(
char *buffer, QByteArray &
longlink);
89 if (d->mimetype.isEmpty()) {
93 if (mode != QIODevice::WriteOnly && QFile::exists(
fileName())) {
107 if (
mime->is(QString::fromLatin1(
"application/x-compressed-tar")) ||
mime->is(QString::fromLatin1(
application_gzip))) {
110 }
else if (
mime->is(QString::fromLatin1(
"application/x-bzip-compressed-tar")) ||
mime->is(QString::fromLatin1(
application_bzip))) {
113 }
else if (
mime->is(QString::fromLatin1(
"application/x-lzma-compressed-tar")) ||
mime->is(QString::fromLatin1(
application_lzma))) {
116 }
else if (
mime->is(QString::fromLatin1(
"application/x-xz-compressed-tar")) ||
mime->is(QString::fromLatin1(
application_xz))) {
124 }
else if (mode == QIODevice::WriteOnly) {
127 if (!d->mimetype.isEmpty()) {
169 if ( !
isOpen() || !(
mode() & QIODevice::WriteOnly) )
171 kWarning(7041) <<
"KTar::setOrigFileName: File must be opened for writing first.\n";
174 d->origFileName = fileName;
177qint64 KTar::KTarPrivate::readRawHeader(
char *buffer ) {
179 qint64 n = q->device()->read( buffer, 0x200 );
182 if (
n == 0x200 && (buffer[0] != 0 || buffer[0x159] != 0) ) {
184 if (
strncmp(buffer + 257,
"ustar", 5)) {
188 for( uint
j = 0;
j < 0x200; ++
j )
192 for( uint
j = 0;
j < 8 ;
j++ )
196 QByteArray
s = QByteArray::number(
check, 8 );
201 if(
strncmp( buffer + 148 + 6 -
s.length(),
s.data(),
s.length() )
202 &&
strncmp( buffer + 148 + 7 -
s.length(),
s.data(),
s.length() )
203 &&
strncmp( buffer + 148 + 8 -
s.length(),
s.data(),
s.length() ) ) {
204 kWarning(7041) <<
"KTar: invalid TAR file. Header is:" << QByteArray( buffer+257, 5 )
205 <<
"instead of ustar. Reading from wrong pos in file?"
206 <<
"checksum=" << QByteArray( buffer + 148 + 6 -
s.length(),
s.length() );
212 if (
n == 0x200)
n = 0;
217bool KTar::KTarPrivate::readLonglink(
char *buffer,QByteArray &
longlink) {
223 qint64 size = QByteArray( buffer + 0x7c, 12 ).trimmed().toLongLong( 0, 8 );
231 if (
n == -1)
return false;
236 const int skip = 0x200 - (
n % 0x200);
248 qint64 n = readRawHeader(buffer);
249 if (
n != 0x200)
return n;
252 if (
strcmp(buffer,
"././@LongLink") == 0) {
257 case 'L': name = QFile::decodeName(
longlink);
break;
258 case 'K': symlink = QFile::decodeName(
longlink);
break;
269 name = QFile::decodeName(QByteArray(buffer, 100));
270 if (symlink.isEmpty())
271 symlink = QFile::decodeName(QByteArray(buffer + 0x9d , 100));
281bool KTar::KTarPrivate::fillTempFile(
const QString & fileName) {
294 QFile* file = tmpFile;
296 Q_ASSERT(file->openMode() & QIODevice::WriteOnly);
299 buffer.resize(8*1024);
300 if ( !
filterDev->open( QIODevice::ReadOnly ) )
306 while ( !
filterDev->atEnd() && len != 0 ) {
307 len =
filterDev->read(buffer.data(),buffer.size());
312 if ( file->write(buffer.data(), len) != len ) {
323 Q_ASSERT(file->openMode() & QIODevice::ReadOnly);
325 kDebug(7041) <<
"no filterdevice found!";
334 if ( !(mode & QIODevice::ReadOnly) )
337 if ( !d->fillTempFile( fileName() ) )
352 char buffer[ 0x200 ];
360 qint64 n = d->readHeader( buffer, name, symlink );
361 if (
n < 0)
return false;
369 name.truncate( name.length() - 1 );
372 QByteArray
prefix = QByteArray(buffer + 0x159, 155);
378 QString nm = ( pos == -1 ) ? name : name.mid( pos + 1 );
383 const char* p = buffer + 0x64;
384 while( *p ==
' ' ) ++p;
385 int access = (int)
strtol( p, &dummy, 8 );
388 QString user = QString::fromLocal8Bit( buffer + 0x109 );
389 QString group = QString::fromLocal8Bit( buffer + 0x129 );
394 while( *p ==
' ' ) ++p;
395 int time = (int)
strtol( p, &dummy, 8 );
417 (
void)dev->read( buffer, 0x200 );
449 kDebug(7041) <<
"Hard link, setting size to 0 instead of" << size;
462 if (! dev->seek( dev->pos() +
skip ) )
480 QString path = QDir::cleanPath( name.left( pos ) );
489 d->tarEnd = dev->pos() -
n;
501bool KTar::KTarPrivate::writeBackTempFile(
const QString & fileName )
519 QFile* file = tmpFile;
520 if ( !dev->open(QIODevice::WriteOnly) )
527 static_cast<KFilterDev *
>(dev)->setOrigFileName( origFileName );
530 buffer.resize(8*1024);
532 while ( !file->atEnd()) {
533 len = file->read(buffer.data(), buffer.size());
534 dev->write(buffer.data(),len);
553 if (d->tmpFile && (
mode() & QIODevice::WriteOnly)) {
554 ok = d->writeBackTempFile( fileName() );
565 int rest = size % 0x200;
566 if ( (
mode() & QIODevice::ReadWrite ) == QIODevice::ReadWrite )
570 char buffer[ 0x201 ];
571 for( uint i = 0; i < 0x200; ++i )
602void KTar::KTarPrivate::fillBuffer(
char * buffer,
607 memcpy( buffer+0x64, mode, 6 );
608 buffer[ 0x6a ] =
' ';
609 buffer[ 0x6b ] =
'\0';
612 strcpy( buffer + 0x6c,
" 765 ");
614 strcpy( buffer + 0x74,
" 144 ");
617 QByteArray
s = QByteArray::number( size, 8 );
618 s =
s.rightJustified( 11,
'0' );
619 memcpy( buffer + 0x7c,
s.data(), 11 );
620 buffer[ 0x87 ] =
' ';
623 s = QByteArray::number(
static_cast<qulonglong
>(mtime), 8 );
624 s =
s.rightJustified( 11,
'0' );
625 memcpy( buffer + 0x88,
s.data(), 11 );
626 buffer[ 0x93 ] =
' ';
629 buffer[ 0x94 ] = 0x20;
630 buffer[ 0x95 ] = 0x20;
631 buffer[ 0x96 ] = 0x20;
632 buffer[ 0x97 ] = 0x20;
633 buffer[ 0x98 ] = 0x20;
634 buffer[ 0x99 ] = 0x20;
641 buffer[ 0x9a ] =
'\0';
642 buffer[ 0x9b ] =
' ';
648 strcpy( buffer + 0x101,
"ustar");
649 strcpy( buffer + 0x107,
"00" );
658 for( uint
j = 0;
j < 0x200; ++
j )
660 s = QByteArray::number(
check, 8 );
661 s =
s.rightJustified( 6,
'0' );
662 memcpy( buffer + 0x94,
s.constData(), 6 );
665void KTar::KTarPrivate::writeLonglink(
char *buffer,
const QByteArray &name,
char typeflag,
667 strcpy( buffer,
"././@LongLink" );
670 q->device()->write( buffer, 0x200 );
676 q->device()->write( buffer, 0x200 );
685 time_t , time_t mtime, time_t ) {
688 kWarning(7041) <<
"You must open the tar file before writing to it\n";
692 if ( !(mode() & QIODevice::WriteOnly) )
694 kWarning(7041) <<
"You must open the tar file for writing\n";
699 QString fileName ( QDir::cleanPath( name ) );
720 char buffer[ 0x201 ];
721 memset( buffer, 0, 0x200 );
722 if ( ( mode() & QIODevice::ReadWrite ) == QIODevice::ReadWrite )
723 device()->seek(d->tarEnd);
727 const QByteArray
uname = user.toLocal8Bit();
728 const QByteArray
gname = group.toLocal8Bit();
731 if ( fileName.length() > 99 )
738 memset(buffer+0x9d, 0, 0x200 - 0x9d);
740 QByteArray
permstr = QByteArray::number( (
unsigned int)perm, 8 );
745 return device()->write( buffer, 0x200 ) == 0x200;
749 const QString &group, mode_t perm,
750 time_t , time_t mtime, time_t ) {
753 kWarning(7041) <<
"You must open the tar file before writing to it\n";
757 if ( !(mode() & QIODevice::WriteOnly) )
759 kWarning(7041) <<
"You must open the tar file for writing\n";
770 if ( d->dirList.contains(
dirName ) )
773 char buffer[ 0x201 ];
774 memset( buffer, 0, 0x200 );
775 if ( ( mode() & QIODevice::ReadWrite ) == QIODevice::ReadWrite )
776 device()->seek(d->tarEnd);
780 QByteArray
uname = user.toLocal8Bit();
781 QByteArray
gname = group.toLocal8Bit();
791 memset(buffer+0x9d, 0, 0x200 - 0x9d);
793 QByteArray
permstr = QByteArray::number( (
unsigned int)perm, 8 );
798 device()->write( buffer, 0x200 );
799 if ( ( mode() & QIODevice::ReadWrite ) == QIODevice::ReadWrite )
800 d->tarEnd =
device()->pos();
808 mode_t perm, time_t , time_t mtime, time_t ) {
811 kWarning(7041) <<
"You must open the tar file before writing to it\n";
815 if ( !(mode() & QIODevice::WriteOnly) )
817 kWarning(7041) <<
"You must open the tar file for writing\n";
822 QString fileName ( QDir::cleanPath( name ) );
824 char buffer[ 0x201 ];
825 memset( buffer, 0, 0x200 );
826 if ( ( mode() & QIODevice::ReadWrite ) == QIODevice::ReadWrite )
827 device()->seek(d->tarEnd);
832 QByteArray
uname = user.toLocal8Bit();
833 QByteArray
gname = group.toLocal8Bit();
838 if ( fileName.length() > 99 )
848 memset(buffer+0x9d+100, 0, 0x200 - 100 - 0x9d);
850 QByteArray
permstr = QByteArray::number( (
unsigned int)perm, 8 );
855 bool retval =
device()->write( buffer, 0x200 ) == 0x200;
856 if ( ( mode() & QIODevice::ReadWrite ) == QIODevice::ReadWrite )
857 d->tarEnd =
device()->pos();
Represents a directory entry in a KArchive.
void addEntry(KArchiveEntry *)
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.
QIODevice * device() const
The underlying device.
virtual bool createDevice(QIODevice::OpenMode mode)
Can be reimplemented in order to change the creation of the device (when using the fileName construct...
virtual bool close()
Closes the archive.
virtual KArchiveDirectory * rootDir()
Retrieves or create the root directory.
virtual void virtual_hook(int id, void *data)
KArchiveDirectory * findOrCreate(const QString &path)
Ensures that path exists, create otherwise.
QIODevice::OpenMode mode() const
Returns the mode in which the archive was opened.
QString fileName() const
The name of the archive file, as passed to the constructor that takes a fileName, or an empty string ...
void setRootDir(KArchiveDirectory *rootDir)
Derived classes call setRootDir from openArchive, to set the root directory after parsing an existing...
bool isOpen() const
Checks whether the archive is open.
void setDevice(QIODevice *dev)
Can be called by derived classes in order to set the underlying device.
A class for reading and writing compressed data onto a device (e.g.
virtual bool seek(qint64)
That one can be quite slow, when going back.
static QIODevice * deviceForFile(const QString &fileName, const QString &mimetype=QString(), bool forceFilter=false)
Reimplemented to return true.
static QIODevice * device(QIODevice *inDevice, const QString &mimetype, bool autoDeleteInDevice=true)
Creates an i/o device that is able to read from the QIODevice inDevice, whether the data is compresse...
static Ptr findByFileContent(const QString &fileName, int *accuracy=0)
Tries to find out the MIME type of a file by looking for certain magic numbers and characteristic str...
static Ptr findByPath(const QString &path, mode_t mode=0, bool fast_mode=false, int *accuracy=0)
Finds a KMimeType with the given url.
static KMimeType::Ptr defaultMimeTypePtr()
Returns the default mimetype.
A class for reading / writing (optionally compressed) tar archives.
virtual bool doFinishWriting(qint64 size)
Reimplemented from KArchive.
virtual void virtual_hook(int id, void *data)
KTar(const QString &filename, const QString &mimetype=QString())
Creates an instance that operates on the given filename using the compression filter associated to gi...
virtual bool doPrepareWriting(const QString &name, const QString &user, const QString &group, qint64 size, mode_t perm, time_t atime, time_t mtime, time_t ctime)
Reimplemented from KArchive.
virtual bool doWriteSymLink(const QString &name, const QString &target, const QString &user, const QString &group, mode_t perm, time_t atime, time_t mtime, time_t ctime)
Reimplemented from KArchive.
virtual bool doWriteDir(const QString &name, const QString &user, const QString &group, mode_t perm, time_t atime, time_t mtime, time_t ctime)
Reimplemented from KArchive.
virtual bool createDevice(QIODevice::OpenMode mode)
Can be reimplemented in order to change the creation of the device (when using the fileName construct...
void setOrigFileName(const QByteArray &fileName)
Special function for setting the "original file name" in the gzip header, when writing a tar....
virtual bool openArchive(QIODevice::OpenMode 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.
A QTemporaryFile that will save in the KDE temp directory.
static const char application_bzip[]
static const char application_zip[]
static const char application_xz[]
static const char application_lzma[]
static const char application_gzip[]