• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tdeio/tdeio
 

tdeio/tdeio

  • tdeio
  • tdeio
ktar.cpp
1 /* This file is part of the KDE libraries
2  Copyright (C) 2000 David Faure <faure@kde.org>
3  Copyright (C) 2003 Leo Savernik <l.savernik@aon.at>
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Library General Public
7  License version 2 as published by the Free Software Foundation.
8 
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  Library General Public License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to
16  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  Boston, MA 02110-1301, USA.
18 */
19 
20 //#include <stdio.h>
21 #include <stdlib.h> // strtol
22 #include <time.h> // time()
23 /*#include <unistd.h>
24 #include <grp.h>
25 #include <pwd.h>*/
26 #include <assert.h>
27 
28 #include <tqcstring.h>
29 #include <tqdir.h>
30 #include <tqfile.h>
31 #include <kdebug.h>
32 #include <kmimetype.h>
33 #include <tdetempfile.h>
34 
35 #include <kfilterdev.h>
36 #include <kfilterbase.h>
37 
38 #include "ktar.h"
39 #include <kstandarddirs.h>
40 
44 
45 class KTar::KTarPrivate
46 {
47 public:
48  KTarPrivate() : tarEnd( 0 ), tmpFile( 0 ) {}
49  TQStringList dirList;
50  int tarEnd;
51  KTempFile* tmpFile;
52  TQString mimetype;
53  TQCString origFileName;
54 
55  bool fillTempFile(const TQString & filename);
56  bool writeBackTempFile( const TQString & filename );
57 };
58 
59 KTar::KTar( const TQString& filename, const TQString & _mimetype )
60  : KArchive( 0 )
61 {
62  m_filename = filename;
63  d = new KTarPrivate;
64  TQString mimetype( _mimetype );
65  bool forced = true;
66  if ( mimetype.isEmpty() ) // Find out mimetype manually
67  {
68  if ( TQFile::exists( filename ) )
69  mimetype = KMimeType::findByFileContent( filename )->name();
70  else
71  mimetype = KMimeType::findByPath( filename, 0, true )->name();
72  kdDebug(7041) << "KTar::KTar mimetype = " << mimetype << endl;
73 
74  // Don't move to prepareDevice - the other constructor theoretically allows ANY filter
75  if ( mimetype == "application/x-tgz" || mimetype == "application/x-targz" || // the latter is deprecated but might still be around
76  mimetype == "application/x-webarchive" )
77  {
78  // that's a gzipped tar file, so ask for gzip filter
79  mimetype = "application/x-gzip";
80  }
81  else if ( mimetype == "application/x-tbz" ) // that's a bzipped2 tar file, so ask for bz2 filter
82  {
83  mimetype = "application/x-bzip2";
84  }
85  else
86  {
87  // Something else. Check if it's not really gzip though (e.g. for KOffice docs)
88  TQFile file( filename );
89  if ( file.open( IO_ReadOnly ) )
90  {
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 )
99  {
100  unsigned char fourthByte = file.getch();
101  if ( fourthByte == 4 )
102  mimetype = "application/x-zip";
103  }
104  else if ( firstByte == 0xfd && secondByte == '7' && thirdByte == 'z' )
105  {
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";
111  }
112  else if ( firstByte == 0x5d && secondByte == 0x00 && thirdByte == 0x00 )
113  {
114  unsigned char fourthByte = file.getch();
115  if ( fourthByte == 0x80 )
116  mimetype = "application/x-lzma";
117  }
118  }
119  file.close();
120  }
121  forced = false;
122  }
123  d->mimetype = mimetype;
124 
125  prepareDevice( filename, mimetype, forced );
126 }
127 
128 void KTar::prepareDevice( const TQString & filename,
129  const TQString & mimetype, bool /*forced*/ )
130 {
131  if( "application/x-tar" == mimetype )
132  setDevice( new TQFile( filename ) );
133  else
134  {
135  // The compression filters are very slow with random access.
136  // So instead of applying the filter to the device,
137  // the file is completly extracted instead,
138  // and we work on the extracted tar file.
139  // This improves the extraction speed by the tar ioslave dramatically,
140  // if the archive file contains many files.
141  // This is because the tar ioslave extracts one file after the other and normally
142  // has to walk through the decompression filter each time.
143  // Which is in fact nearly as slow as a complete decompression for each file.
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);
147 
148  // KTempFile opens the file automatically,
149  // the device must be closed, however, for KArchive.setDevice()
150  TQFile* file = d->tmpFile->file();
151  file->close();
152  setDevice(file);
153  }
154 }
155 
156 KTar::KTar( TQIODevice * dev )
157  : KArchive( dev )
158 {
159  Q_ASSERT( dev );
160  d = new KTarPrivate;
161 }
162 
163 KTar::~KTar()
164 {
165  // mjarrett: Closes to prevent ~KArchive from aborting w/o device
166  if( isOpened() )
167  close();
168 
169  if (d->tmpFile)
170  delete d->tmpFile; // will delete the device
171  else if ( !m_filename.isEmpty() )
172  delete device(); // we created it ourselves
173 
174 
175  delete d;
176 }
177 
178 void KTar::setOrigFileName( const TQCString & fileName )
179 {
180  if ( !isOpened() || !(mode() & IO_WriteOnly) )
181  {
182  kdWarning(7041) << "KTar::setOrigFileName: File must be opened for writing first.\n";
183  return;
184  }
185  d->origFileName = fileName;
186 }
187 
188 TQ_LONG KTar::readRawHeader(char *buffer) {
189  // Read header
190  TQ_LONG n = device()->readBlock( buffer, 0x200 );
191  if ( n == 0x200 && buffer[0] != 0 ) {
192  // Make sure this is actually a tar header
193  if (strncmp(buffer + 257, "ustar", 5)) {
194  // The magic isn't there (broken/old tars), but maybe a correct checksum?
195  TQCString s;
196 
197  int check = 0;
198  for( uint j = 0; j < 0x200; ++j )
199  check += buffer[j];
200 
201  // adjust checksum to count the checksum fields as blanks
202  for( uint j = 0; j < 8 /*size of the checksum field including the \0 and the space*/; j++ )
203  check -= buffer[148 + j];
204  check += 8 * ' ';
205 
206  s.sprintf("%o", check );
207 
208  // only compare those of the 6 checksum digits that mean something,
209  // because the other digits are filled with all sorts of different chars by different tars ...
210  // Some tars right-justify the checksum so it could start in one of three places - we have to check each.
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;
215  return -1;
216  }
217  }/*end if*/
218  } else {
219  // reset to 0 if 0x200 because logical end of archive has been reached
220  if (n == 0x200) n = 0;
221  }/*end if*/
222  return n;
223 }
224 
225 bool KTar::readLonglink(char *buffer,TQCString &longlink) {
226  TQ_LONG n = 0;
227  TQIODevice *dev = device();
228  // read size of longlink from size field in header
229  // size is in bytes including the trailing null (which we ignore)
230  buffer[ 0x88 ] = 0; // was 0x87, but 0x88 fixes BR #26437
231  char *dummy;
232  const char* p = buffer + 0x7c;
233  while( *p == ' ' ) ++p;
234  int size = (int)strtol( p, &dummy, 8 );
235 
236  longlink.resize(size);
237  size--; // ignore trailing null
238  dummy = longlink.data();
239  int offset = 0;
240  while (size > 0) {
241  int chunksize = TQMIN(size, 0x200);
242  n = dev->readBlock( dummy + offset, chunksize );
243  if (n == -1) return false;
244  size -= chunksize;
245  offset += 0x200;
246  }/*wend*/
247  // jump over the rest
248  int skip = 0x200 - (n % 0x200);
249  if (skip < 0x200) {
250  if (dev->readBlock(buffer,skip) != skip) return false;
251  }
252  return true;
253 }
254 
255 TQ_LONG KTar::readHeader(char *buffer,TQString &name,TQString &symlink) {
256  name.truncate(0);
257  symlink.truncate(0);
258  while (true) {
259  TQ_LONG n = readRawHeader(buffer);
260  if (n != 0x200) return n;
261 
262  // is it a longlink?
263  if (strcmp(buffer,"././@LongLink") == 0) {
264  char typeflag = buffer[0x9c];
265  TQCString longlink;
266  readLonglink(buffer,longlink);
267  switch (typeflag) {
268  case 'L': name = TQFile::decodeName(longlink); break;
269  case 'K': symlink = TQFile::decodeName(longlink); break;
270  }/*end switch*/
271  } else {
272  break;
273  }/*end if*/
274  }/*wend*/
275 
276  // if not result of longlink, read names directly from the header
277  if (name.isEmpty())
278  // there are names that are exactly 100 bytes long
279  // and neither longlink nor \0 terminated (bug:101472)
280  name = TQFile::decodeName(TQCString(buffer, 101));
281  if (symlink.isEmpty())
282  symlink = TQFile::decodeName(TQCString(buffer + 0x9d, 101));
283 
284  return 0x200;
285 }
286 
287 /*
288  * If we have created a temporary file, we have
289  * to decompress the original file now and write
290  * the contents to the temporary file.
291  */
292 bool KTar::KTarPrivate::fillTempFile( const TQString & filename) {
293  if ( ! tmpFile )
294  return true;
295 
296  kdDebug( 7041 ) <<
297  "KTar::openArchive: filling tmpFile of mimetype '" << mimetype <<
298  "' ... " << endl;
299 
300  bool forced = false;
301  if( "application/x-gzip" == mimetype
302  || "application/x-bzip2" == mimetype
303  || "application/x-lzma" == mimetype
304  || "application/x-xz" == mimetype)
305  forced = true;
306 
307  TQIODevice *filterDev = KFilterDev::deviceForFile( filename, mimetype, forced );
308 
309  if( filterDev ) {
310  TQFile* file = tmpFile->file();
311  file->close();
312  if ( ! file->open( IO_WriteOnly ) )
313  {
314  delete filterDev;
315  return false;
316  }
317  TQByteArray buffer(8*1024);
318  if ( ! filterDev->open( IO_ReadOnly ) )
319  {
320  delete filterDev;
321  return false;
322  }
323  TQ_LONG len = -1;
324  while ( !filterDev->atEnd() && len != 0) {
325  len = filterDev->readBlock(buffer.data(),buffer.size());
326  if ( len < 0 ) { // corrupted archive
327  delete filterDev;
328  return false;
329  }
330  file->writeBlock(buffer.data(),len);
331  }
332  filterDev->close();
333  delete filterDev;
334 
335  file->close();
336  if ( ! file->open( IO_ReadOnly ) )
337  return false;
338  }
339  else
340  kdDebug( 7041 ) << "KTar::openArchive: no filterdevice found!" << endl;
341 
342  kdDebug( 7041 ) << "KTar::openArchive: filling tmpFile finished." << endl;
343  return true;
344 }
345 
346 bool KTar::openArchive( int mode )
347 {
348  kdDebug( 7041 ) << "KTar::openArchive" << endl;
349  if ( !(mode & IO_ReadOnly) )
350  return true;
351 
352  if ( !d->fillTempFile( m_filename ) )
353  return false;
354 
355  // We'll use the permission and user/group of d->rootDir
356  // for any directory we emulate (see findOrCreate)
357  //struct stat buf;
358  //stat( m_filename, &buf );
359 
360  d->dirList.clear();
361  TQIODevice* dev = device();
362 
363  if ( !dev )
364  return false;
365 
366  // read dir infos
367  char buffer[ 0x200 ];
368  bool ende = false;
369  do
370  {
371  TQString name;
372  TQString symlink;
373 
374  // Read header
375  TQ_LONG n = readHeader(buffer,name,symlink);
376  if (n < 0) return false;
377  if (n == 0x200)
378  {
379  bool isdir = false;
380  TQString nm;
381 
382  if ( name.right(1) == "/" )
383  {
384  isdir = true;
385  name = name.left( name.length() - 1 );
386  }
387 
388  int pos = name.findRev( '/' );
389  if ( pos == -1 )
390  nm = name;
391  else
392  nm = name.mid( pos + 1 );
393 
394  // read access
395  buffer[ 0x6b ] = 0;
396  char *dummy;
397  const char* p = buffer + 0x64;
398  while( *p == ' ' ) ++p;
399  int access = (int)strtol( p, &dummy, 8 );
400 
401  // read user and group
402  TQString user( buffer + 0x109 );
403  TQString group( buffer + 0x129 );
404 
405  // read time
406  buffer[ 0x93 ] = 0;
407  p = buffer + 0x88;
408  while( *p == ' ' ) ++p;
409  int time = (int)strtol( p, &dummy, 8 );
410 
411  // read type flag
412  char typeflag = buffer[ 0x9c ];
413  // '0' for files, '1' hard link, '2' symlink, '5' for directory
414  // (and 'L' for longlink filenames, 'K' for longlink symlink targets)
415  // and 'D' for GNU tar extension DUMPDIR
416  if ( typeflag == '5' )
417  isdir = true;
418 
419  bool isDumpDir = false;
420  if ( typeflag == 'D' )
421  {
422  isdir = false;
423  isDumpDir = true;
424  }
425  //bool islink = ( typeflag == '1' || typeflag == '2' );
426  //kdDebug(7041) << "typeflag=" << typeflag << " islink=" << islink << endl;
427 
428  if (isdir)
429  access |= S_IFDIR; // f*cking broken tar files
430 
431  KArchiveEntry* e;
432  if ( isdir )
433  {
434  //kdDebug(7041) << "KTar::openArchive directory " << nm << endl;
435  e = new KArchiveDirectory( this, nm, access, time, user, group, symlink );
436  }
437  else
438  {
439  // read size
440  buffer[ 0x88 ] = 0; // was 0x87, but 0x88 fixes BR #26437
441  char *dummy;
442  const char* p = buffer + 0x7c;
443  while( *p == ' ' ) ++p;
444  int size = (int)strtol( p, &dummy, 8 );
445 
446  // for isDumpDir we will skip the additional info about that dirs contents
447  if ( isDumpDir )
448  {
449  //kdDebug(7041) << "KTar::openArchive " << nm << " isDumpDir" << endl;
450  e = new KArchiveDirectory( this, nm, access, time, user, group, symlink );
451  }
452  else
453  {
454 
455  // Let's hack around hard links. Our classes don't support that, so make them symlinks
456  if ( typeflag == '1' )
457  {
458  kdDebug(7041) << "HARD LINK, setting size to 0 instead of " << size << endl;
459  size = 0; // no contents
460  }
461 
462  //kdDebug(7041) << "KTar::openArchive file " << nm << " size=" << size << endl;
463  e = new KArchiveFile( this, nm, access, time, user, group, symlink,
464  dev->at(), size );
465  }
466 
467  // Skip contents + align bytes
468  int rest = size % 0x200;
469  int skip = size + (rest ? 0x200 - rest : 0);
470  //kdDebug(7041) << "KTar::openArchive, at()=" << dev->at() << " rest=" << rest << " skipping " << skip << endl;
471  if (! dev->at( dev->at() + skip ) )
472  kdWarning(7041) << "KTar::openArchive skipping " << skip << " failed" << endl;
473  }
474 
475  if ( pos == -1 )
476  {
477  if ( nm == "." ) // special case
478  {
479  Q_ASSERT( isdir );
480  if ( isdir )
481  setRootDir( static_cast<KArchiveDirectory *>( e ) );
482  }
483  else
484  rootDir()->addEntry( e );
485  }
486  else
487  {
488  // In some tar files we can find dir/./file => call cleanDirPath
489  TQString path = TQDir::cleanDirPath( name.left( pos ) );
490  // Ensure container directory exists, create otherwise
491  KArchiveDirectory * d = findOrCreate( path );
492  d->addEntry( e );
493  }
494  }
495  else
496  {
497  //tqDebug("Terminating. Read %d bytes, first one is %d", n, buffer[0]);
498  d->tarEnd = dev->at() - n; // Remember end of archive
499  ende = true;
500  }
501  } while( !ende );
502  return true;
503 }
504 
505 /*
506  * Writes back the changes of the temporary file
507  * to the original file.
508  * Must only be called if in IO_WriteOnly mode
509  */
510 bool KTar::KTarPrivate::writeBackTempFile( const TQString & filename ) {
511  if ( ! tmpFile )
512  return true;
513 
514  kdDebug(7041) << "Write temporary file to compressed file" << endl;
515  kdDebug(7041) << filename << " " << mimetype << endl;
516 
517  bool forced = false;
518  if( "application/x-gzip" == mimetype
519  || "application/x-bzip2" == mimetype
520  || "application/x-lzma" == mimetype
521  || "application/x-xz" == mimetype)
522  forced = true;
523 
524  TQIODevice *dev = KFilterDev::deviceForFile( filename, mimetype, forced );
525  if( dev ) {
526  TQFile* file = tmpFile->file();
527  file->close();
528  if ( ! file->open(IO_ReadOnly) || ! dev->open(IO_WriteOnly) )
529  {
530  file->close();
531  delete dev;
532  return false;
533  }
534  if ( forced )
535  static_cast<KFilterDev *>(dev)->setOrigFileName( origFileName );
536  TQByteArray buffer(8*1024);
537  TQ_LONG len;
538  while ( ! file->atEnd()) {
539  len = file->readBlock(buffer.data(),buffer.size());
540  dev->writeBlock(buffer.data(),len);
541  }
542  file->close();
543  dev->close();
544  delete dev;
545  }
546 
547  kdDebug(7041) << "Write temporary file to compressed file done." << endl;
548  return true;
549 }
550 
551 bool KTar::closeArchive()
552 {
553  d->dirList.clear();
554 
555  // If we are in write mode and had created
556  // a temporary tar file, we have to write
557  // back the changes to the original file
558  if( mode() == IO_WriteOnly)
559  return d->writeBackTempFile( m_filename );
560 
561  return true;
562 }
563 
564 bool KTar::writeDir( const TQString& name, const TQString& user, const TQString& group )
565 {
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);
569 #if 0
570  if ( !isOpened() )
571  {
572  kdWarning(7041) << "KTar::writeDir: You must open the tar file before writing to it\n";
573  return false;
574  }
575 
576  if ( !(mode() & IO_WriteOnly) )
577  {
578  kdWarning(7041) << "KTar::writeDir: You must open the tar file for writing\n";
579  return false;
580  }
581 
582  // In some tar files we can find dir/./ => call cleanDirPath
583  TQString dirName ( TQDir::cleanDirPath( name ) );
584 
585  // Need trailing '/'
586  if ( dirName.right(1) != "/" )
587  dirName += "/";
588 
589  if ( d->dirList.contains( dirName ) )
590  return true; // already there
591 
592  char buffer[ 0x201 ];
593  memset( buffer, 0, 0x200 );
594  if ( mode() & IO_ReadWrite ) device()->at(d->tarEnd); // Go to end of archive as might have moved with a read
595 
596  // If more than 100 chars, we need to use the LongLink trick
597  if ( dirName.length() > 99 )
598  {
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 );
603  buffer[0x200] = 0;
604  // write long name
605  device()->writeBlock( buffer, 0x200 );
606  // not even needed to reclear the buffer, tar doesn't do it
607  }
608  else
609  {
610  // Write name
611  strncpy( buffer, TQFile::encodeName(dirName), 0x200 );
612  buffer[0x200] = 0;
613  }
614 
615  fillBuffer( buffer, " 40755", 0, 0x35, user.local8Bit(), group.local8Bit());
616 
617  // Write header
618  device()->writeBlock( buffer, 0x200 );
619  if ( mode() & IO_ReadWrite ) d->tarEnd = device()->at();
620 
621  d->dirList.append( dirName ); // contains trailing slash
622  return true; // TODO if wanted, better error control
623 #endif
624 }
625 
626 bool KTar::prepareWriting( const TQString& name, const TQString& user, const TQString& group, uint size )
627 {
628  mode_t dflt_perm = 0100644;
629  time_t the_time = time(0);
630  return prepareWriting(name,user,group,size,dflt_perm,
631  the_time,the_time,the_time);
632 }
633 
634 bool KTar::doneWriting( uint size )
635 {
636  // Write alignment
637  int rest = size % 0x200;
638  if ( mode() & IO_ReadWrite )
639  d->tarEnd = device()->at() + (rest ? 0x200 - rest : 0); // Record our new end of archive
640  if ( rest )
641  {
642  char buffer[ 0x201 ];
643  for( uint i = 0; i < 0x200; ++i )
644  buffer[i] = 0;
645  TQ_LONG nwritten = device()->writeBlock( buffer, 0x200 - rest );
646  return nwritten == 0x200 - rest;
647  }
648  return true;
649 }
650 
651 /*** Some help from the tar sources
652 struct posix_header
653 { byte offset
654  char name[100]; * 0 * 0x0
655  char mode[8]; * 100 * 0x64
656  char uid[8]; * 108 * 0x6c
657  char gid[8]; * 116 * 0x74
658  char size[12]; * 124 * 0x7c
659  char mtime[12]; * 136 * 0x88
660  char chksum[8]; * 148 * 0x94
661  char typeflag; * 156 * 0x9c
662  char linkname[100]; * 157 * 0x9d
663  char magic[6]; * 257 * 0x101
664  char version[2]; * 263 * 0x107
665  char uname[32]; * 265 * 0x109
666  char gname[32]; * 297 * 0x129
667  char devmajor[8]; * 329 * 0x149
668  char devminor[8]; * 337 * ...
669  char prefix[155]; * 345 *
670  * 500 *
671 };
672 */
673 
674 void KTar::fillBuffer( char * buffer,
675  const char * mode, int size, time_t mtime, char typeflag,
676  const char * uname, const char * gname )
677 {
678  // mode (as in stat())
679  assert( strlen(mode) == 6 );
680  strcpy( buffer+0x64, mode );
681  buffer[ 0x6a ] = ' ';
682  buffer[ 0x6b ] = '\0';
683 
684  // dummy uid
685  strcpy( buffer + 0x6c, " 765 ");
686  // dummy gid
687  strcpy( buffer + 0x74, " 144 ");
688 
689  // size
690  TQCString s;
691  s.sprintf("%o", size); // OCT
692  s = s.rightJustify( 11, ' ' );
693  strcpy( buffer + 0x7c, s.data() );
694  buffer[ 0x87 ] = ' '; // space-terminate (no null after)
695 
696  // modification time
697  s.sprintf("%lo", static_cast<unsigned long>(mtime) ); // OCT
698  s = s.rightJustify( 11, ' ' );
699  strcpy( buffer + 0x88, s.data() );
700  buffer[ 0x93 ] = ' '; // space-terminate (no null after)
701 
702  // spaces, replaced by the check sum later
703  buffer[ 0x94 ] = 0x20;
704  buffer[ 0x95 ] = 0x20;
705  buffer[ 0x96 ] = 0x20;
706  buffer[ 0x97 ] = 0x20;
707  buffer[ 0x98 ] = 0x20;
708  buffer[ 0x99 ] = 0x20;
709 
710  /* From the tar sources :
711  Fill in the checksum field. It's formatted differently from the
712  other fields: it has [6] digits, a null, then a space -- rather than
713  digits, a space, then a null. */
714 
715  buffer[ 0x9a ] = '\0';
716  buffer[ 0x9b ] = ' ';
717 
718  // type flag (dir, file, link)
719  buffer[ 0x9c ] = typeflag;
720 
721  // magic + version
722  strcpy( buffer + 0x101, "ustar");
723  strcpy( buffer + 0x107, "00" );
724 
725  // user
726  strcpy( buffer + 0x109, uname );
727  // group
728  strcpy( buffer + 0x129, gname );
729 
730  // Header check sum
731  int check = 32;
732  for( uint j = 0; j < 0x200; ++j )
733  check += buffer[j];
734  s.sprintf("%o", check ); // OCT
735  s = s.rightJustify( 7, ' ' );
736  strcpy( buffer + 0x94, s.data() );
737 }
738 
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 );
745  int offset = 0;
746  while (namelen > 0) {
747  int chunksize = TQMIN(namelen, 0x200);
748  memcpy(buffer, name.data()+offset, chunksize);
749  // write long name
750  device()->writeBlock( buffer, 0x200 );
751  // not even needed to reclear the buffer, tar doesn't do it
752  namelen -= chunksize;
753  offset += 0x200;
754  }/*wend*/
755 }
756 
757 bool KTar::prepareWriting(const TQString& name, const TQString& user,
758  const TQString& group, uint size, mode_t perm,
759  time_t atime, time_t mtime, time_t ctime) {
760  return KArchive::prepareWriting(name,user,group,size,perm,atime,mtime,ctime);
761 }
762 
763 bool KTar::prepareWriting_impl(const TQString &name, const TQString &user,
764  const TQString &group, uint size, mode_t perm,
765  time_t /*atime*/, time_t mtime, time_t /*ctime*/) {
766  if ( !isOpened() )
767  {
768  kdWarning(7041) << "KTar::prepareWriting: You must open the tar file before writing to it\n";
769  return false;
770  }
771 
772  if ( !(mode() & IO_WriteOnly) )
773  {
774  kdWarning(7041) << "KTar::prepareWriting: You must open the tar file for writing\n";
775  return false;
776  }
777 
778  // In some tar files we can find dir/./file => call cleanDirPath
779  TQString fileName ( TQDir::cleanDirPath( name ) );
780 
781  /*
782  // Create toplevel dirs
783  // Commented out by David since it's not necessary, and if anybody thinks it is,
784  // he needs to implement a findOrCreate equivalent in writeDir.
785  // But as KTar and the "tar" program both handle tar files without
786  // dir entries, there's really no need for that
787  TQString tmp ( fileName );
788  int i = tmp.findRev( '/' );
789  if ( i != -1 )
790  {
791  TQString d = tmp.left( i + 1 ); // contains trailing slash
792  if ( !m_dirList.contains( d ) )
793  {
794  tmp = tmp.mid( i + 1 );
795  writeDir( d, user, group ); // WARNING : this one doesn't create its toplevel dirs
796  }
797  }
798  */
799 
800  char buffer[ 0x201 ];
801  memset( buffer, 0, 0x200 );
802  if ( mode() & IO_ReadWrite ) device()->at(d->tarEnd); // Go to end of archive as might have moved with a read
803 
804  // provide converted stuff we need lateron
805  TQCString encodedFilename = TQFile::encodeName(fileName);
806  TQCString uname = user.local8Bit();
807  TQCString gname = group.local8Bit();
808 
809  // If more than 100 chars, we need to use the LongLink trick
810  if ( fileName.length() > 99 )
811  writeLonglink(buffer,encodedFilename,'L',uname,gname);
812 
813  // Write (potentially truncated) name
814  strncpy( buffer, encodedFilename, 99 );
815  buffer[99] = 0;
816  // zero out the rest (except for what gets filled anyways)
817  memset(buffer+0x9d, 0, 0x200 - 0x9d);
818 
819  TQCString permstr;
820  permstr.sprintf("%o",perm);
821  permstr = permstr.rightJustify(6, ' ');
822  fillBuffer(buffer, permstr, size, mtime, 0x30, uname, gname);
823 
824  // Write header
825  return device()->writeBlock( buffer, 0x200 ) == 0x200;
826 }
827 
828 bool KTar::writeDir(const TQString& name, const TQString& user,
829  const TQString& group, mode_t perm,
830  time_t atime, time_t mtime, time_t ctime) {
831  return KArchive::writeDir(name,user,group,perm,atime,mtime,ctime);
832 }
833 
834 bool KTar::writeDir_impl(const TQString &name, const TQString &user,
835  const TQString &group, mode_t perm,
836  time_t /*atime*/, time_t mtime, time_t /*ctime*/) {
837  if ( !isOpened() )
838  {
839  kdWarning(7041) << "KTar::writeDir: You must open the tar file before writing to it\n";
840  return false;
841  }
842 
843  if ( !(mode() & IO_WriteOnly) )
844  {
845  kdWarning(7041) << "KTar::writeDir: You must open the tar file for writing\n";
846  return false;
847  }
848 
849  // In some tar files we can find dir/./ => call cleanDirPath
850  TQString dirName ( TQDir::cleanDirPath( name ) );
851 
852  // Need trailing '/'
853  if ( dirName.right(1) != "/" )
854  dirName += "/";
855 
856  if ( d->dirList.contains( dirName ) )
857  return true; // already there
858 
859  char buffer[ 0x201 ];
860  memset( buffer, 0, 0x200 );
861  if ( mode() & IO_ReadWrite ) device()->at(d->tarEnd); // Go to end of archive as might have moved with a read
862 
863  // provide converted stuff we need lateron
864  TQCString encodedDirname = TQFile::encodeName(dirName);
865  TQCString uname = user.local8Bit();
866  TQCString gname = group.local8Bit();
867 
868  // If more than 100 chars, we need to use the LongLink trick
869  if ( dirName.length() > 99 )
870  writeLonglink(buffer,encodedDirname,'L',uname,gname);
871 
872  // Write (potentially truncated) name
873  strncpy( buffer, encodedDirname, 99 );
874  buffer[99] = 0;
875  // zero out the rest (except for what gets filled anyways)
876  memset(buffer+0x9d, 0, 0x200 - 0x9d);
877 
878  TQCString permstr;
879  permstr.sprintf("%o",perm);
880  permstr = permstr.rightJustify(6, ' ');
881  fillBuffer( buffer, permstr, 0, mtime, 0x35, uname, gname);
882 
883  // Write header
884  device()->writeBlock( buffer, 0x200 );
885  if ( mode() & IO_ReadWrite ) d->tarEnd = device()->at();
886 
887  d->dirList.append( dirName ); // contains trailing slash
888  return true; // TODO if wanted, better error control
889 }
890 
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) {
894  return KArchive::writeSymLink(name,target,user,group,perm,atime,mtime,ctime);
895 }
896 
897 bool KTar::writeSymLink_impl(const TQString &name, const TQString &target,
898  const TQString &user, const TQString &group,
899  mode_t perm, time_t /*atime*/, time_t mtime, time_t /*ctime*/) {
900  if ( !isOpened() )
901  {
902  kdWarning(7041) << "KTar::writeSymLink: You must open the tar file before writing to it\n";
903  return false;
904  }
905 
906  if ( !(mode() & IO_WriteOnly) )
907  {
908  kdWarning(7041) << "KTar::writeSymLink: You must open the tar file for writing\n";
909  return false;
910  }
911 
912  device()->flush();
913 
914  // In some tar files we can find dir/./file => call cleanDirPath
915  TQString fileName ( TQDir::cleanDirPath( name ) );
916 
917  char buffer[ 0x201 ];
918  memset( buffer, 0, 0x200 );
919  if ( mode() & IO_ReadWrite ) device()->at(d->tarEnd); // Go to end of archive as might have moved with a read
920 
921  // provide converted stuff we need lateron
922  TQCString encodedFilename = TQFile::encodeName(fileName);
923  TQCString encodedTarget = TQFile::encodeName(target);
924  TQCString uname = user.local8Bit();
925  TQCString gname = group.local8Bit();
926 
927  // If more than 100 chars, we need to use the LongLink trick
928  if (target.length() > 99)
929  writeLonglink(buffer,encodedTarget,'K',uname,gname);
930  if ( fileName.length() > 99 )
931  writeLonglink(buffer,encodedFilename,'L',uname,gname);
932 
933  // Write (potentially truncated) name
934  strncpy( buffer, encodedFilename, 99 );
935  buffer[99] = 0;
936  // Write (potentially truncated) symlink target
937  strncpy(buffer+0x9d, encodedTarget, 99);
938  buffer[0x9d+99] = 0;
939  // zero out the rest
940  memset(buffer+0x9d+100, 0, 0x200 - 100 - 0x9d);
941 
942  TQCString permstr;
943  permstr.sprintf("%o",perm);
944  permstr = permstr.rightJustify(6, ' ');
945  fillBuffer(buffer, permstr, 0, mtime, 0x32, uname, gname);
946 
947  // Write header
948  bool retval = device()->writeBlock( buffer, 0x200 ) == 0x200;
949  if ( mode() & IO_ReadWrite ) d->tarEnd = device()->at();
950  return retval;
951 }
952 
953 void KTar::virtual_hook( int id, void* data ) {
954  switch (id) {
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);
960  break;
961  }
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);
967  break;
968  }
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);
974  break;
975  }
976  default:
977  KArchive::virtual_hook( id, data );
978  }/*end switch*/
979 }
980 
KArchiveDirectory
Represents a directory entry in a KArchive.
Definition: karchive.h:574
KArchiveEntry
A base class for entries in an KArchive.
Definition: karchive.h:396
KArchiveFile
Represents a file entry in a KArchive.
Definition: karchive.h:491
KArchive
KArchive is a base class for reading and writing archives.
Definition: karchive.h:43
KArchive::writeDir
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.
KArchive::rootDir
virtual KArchiveDirectory * rootDir()
Retrieves or create the root directory.
Definition: karchive.cpp:368
KArchive::findOrCreate
KArchiveDirectory * findOrCreate(const TQString &path)
Ensures that path exists, create otherwise.
Definition: karchive.cpp:383
KArchive::close
virtual void close()
Closes the archive.
Definition: karchive.cpp:108
KArchive::mode
int mode() const
Returns the mode in which the archive was opened.
Definition: karchive.h:90
KArchive::isOpened
bool isOpened() const
Checks whether the archive is open.
Definition: karchive.h:83
KArchive::device
TQIODevice * device() const
The underlying device.
Definition: karchive.h:96
KArchive::writeSymLink
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.
Definition: karchive.cpp:327
KArchive::prepareWriting
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...
KFilterDev
A class for reading and writing compressed data onto a device (e.g.
Definition: kfilterdev.h:37
KFilterDev::deviceForFile
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.
Definition: kfilterdev.cpp:81
KMimeType::findByPath
static Ptr findByPath(const TQString &path, mode_t mode=0, bool fast_mode=false)
Finds a KMimeType with the given _url.
Definition: kmimetype.cpp:308
KMimeType::findByFileContent
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...
Definition: kmimetype.cpp:323
KTar::setOrigFileName
void setOrigFileName(const TQCString &fileName)
Special function for setting the "original file name" in the gzip header, when writing a tar....
Definition: ktar.cpp:178
KTar::fileName
TQString fileName()
The name of the tar file, as passed to the constructor Null if you used the TQIODevice constructor.
Definition: ktar.h:77
KTar::doneWriting
virtual bool doneWriting(uint size)
Call doneWriting after writing the data.
Definition: ktar.cpp:634
KTar::openArchive
virtual bool openArchive(int mode)
Opens the archive for reading.
Definition: ktar.cpp:346
KTar::~KTar
virtual ~KTar()
If the tar ball is still opened, then it will be closed automatically by the destructor.
Definition: ktar.cpp:163
KTar::closeArchive
virtual bool closeArchive()
Closes the archive.
Definition: ktar.cpp:551
KTar::KTar
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...
Definition: ktar.cpp:59
KTar::prepareWriting
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...
Definition: ktar.cpp:626
KTar::writeDir
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.
Definition: ktar.cpp:564
TDEIO::symlink
TDEIO_EXPORT SimpleJob * symlink(const TQString &target, const KURL &dest, bool overwrite, bool showProgressInfo=true)
Create or move a symlink.
Definition: job.cpp:808
TDEIO::mimetype
TDEIO_EXPORT MimetypeJob * mimetype(const KURL &url, bool showProgressInfo=true)
Find mimetype for one file or directory.
Definition: job.cpp:1573

tdeio/tdeio

Skip menu "tdeio/tdeio"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

tdeio/tdeio

Skip menu "tdeio/tdeio"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdeio/tdeio by doxygen 1.9.1
This website is maintained by Timothy Pearson.