diff options
Diffstat (limited to 'tdeioslave/tar')
-rw-r--r-- | tdeioslave/tar/CMakeLists.txt | 37 | ||||
-rw-r--r-- | tdeioslave/tar/Makefile.am | 24 | ||||
-rw-r--r-- | tdeioslave/tar/ar.protocol | 12 | ||||
-rw-r--r-- | tdeioslave/tar/ktartest.cpp | 201 | ||||
-rw-r--r-- | tdeioslave/tar/tar.cc | 623 | ||||
-rw-r--r-- | tdeioslave/tar/tar.h | 55 | ||||
-rw-r--r-- | tdeioslave/tar/tar.protocol | 12 | ||||
-rw-r--r-- | tdeioslave/tar/zip.protocol | 12 |
8 files changed, 976 insertions, 0 deletions
diff --git a/tdeioslave/tar/CMakeLists.txt b/tdeioslave/tar/CMakeLists.txt new file mode 100644 index 000000000..0e5ce7684 --- /dev/null +++ b/tdeioslave/tar/CMakeLists.txt @@ -0,0 +1,37 @@ +################################################# +# +# (C) 2010-2011 Serghei Amelian +# serghei (DOT) amelian (AT) gmail.com +# +# Improvements and feedback are welcome +# +# This file is released under GPL >= 2 +# +################################################# + +include_directories( + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_BINARY_DIR} + ${TDE_INCLUDE_DIR} + ${TQT_INCLUDE_DIRS} +) + +link_directories( + ${TQT_LIBRARY_DIRS} +) + + +##### other data ################################ + +install( FILES tar.protocol ar.protocol zip.protocol DESTINATION ${SERVICES_INSTALL_DIR} ) + + +##### kio_tar (module) ####################### + +set( target kio_tar ) + +tde_add_kpart( ${target} AUTOMOC + SOURCES tar.cc + LINK tdeio-shared + DESTINATION ${PLUGIN_INSTALL_DIR} +) diff --git a/tdeioslave/tar/Makefile.am b/tdeioslave/tar/Makefile.am new file mode 100644 index 000000000..31fd98ebf --- /dev/null +++ b/tdeioslave/tar/Makefile.am @@ -0,0 +1,24 @@ +## Makefile.am of tdebase/tdeioslave/tar + +INCLUDES = $(all_includes) +AM_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_QT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_KIO) -ltdetexteditor +METASOURCES = AUTO + +kde_module_LTLIBRARIES = kio_tar.la + +kio_tar_la_SOURCES = tar.cc +kio_tar_la_LIBADD = $(LIB_KSYCOCA) +kio_tar_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) + +check_PROGRAMS = ktartest + +ktartest_SOURCES = ktartest.cpp +ktartest_LDADD = $(LIB_KSYCOCA) + +noinst_HEADERS = tar.h + +kdelnk_DATA = tar.protocol ar.protocol zip.protocol +kdelnkdir = $(kde_servicesdir) + +messages: + $(XGETTEXT) *.cc -o $(podir)/tdeio_tar.pot diff --git a/tdeioslave/tar/ar.protocol b/tdeioslave/tar/ar.protocol new file mode 100644 index 000000000..31e765a7a --- /dev/null +++ b/tdeioslave/tar/ar.protocol @@ -0,0 +1,12 @@ +[Protocol] +exec=kio_tar +protocol=ar +mimetype=application/x-archive +input=filesystem +output=filesystem +listing=Name,Type,Size,Date,Access,Owner,Group,Link +reading=true +source=true +DocPath=tdeioslave/ar.html +Icon=ar +Class=:local diff --git a/tdeioslave/tar/ktartest.cpp b/tdeioslave/tar/ktartest.cpp new file mode 100644 index 000000000..efb1e42fe --- /dev/null +++ b/tdeioslave/tar/ktartest.cpp @@ -0,0 +1,201 @@ +#include "ktar.h" +#include <stdio.h> +#include <tqfile.h> +#include <kinstance.h> +#include <kdebug.h> + +void recursive_print( const KTarDirectory * dir, const TQString & path ) +{ + TQStringList l = dir->entries(); + TQStringList::Iterator it = l.begin(); + for( ; it != l.end(); ++it ) + { + const KTarEntry* entry = dir->entry( (*it) ); + printf("mode=%07o %s %s %s%s\n", entry->permissions(), entry->user().latin1(), entry->group().latin1(), path.latin1(), (*it).latin1()); + if (entry->isDirectory()) + recursive_print( (KTarDirectory *)entry, path+(*it)+"/" ); + } +} + +static void usage() +{ + printf("\n" + " Usage :\n" + " ./ktartest list /path/to/existing_file.tar.gz tests listing an existing tar.gz\n" + " ./ktartest get /path/to/existing_file.tar.gz filename tests extracting a file.\n" + " ./ktartest readwrite newfile.tar.gz will create the tar.gz, then close and reopen it.\n" + " ./ktartest maxlength newfile.tar.gz tests the maximum filename length allowed.\n" + " ./ktartest bytearray /path/to/existing_file.tar.gz tests KTarData\n"); +} + +int main( int argc, char** argv ) +{ + if (argc < 3) + { + usage(); + return 1; + } + TDEInstance instance("ktartest"); + + TQString command = argv[1]; + kdDebug() << "main: command=" << command << endl; + if ( command == "list" ) + { + KTarGz tar( argv[2] ); + + if ( !tar.open( IO_ReadOnly ) ) + { + printf("Could not open %s for reading\n", argv[1] ); + return 1; + } + + const KTarDirectory* dir = tar.directory(); + + //printf("calling recursive_print\n"); + recursive_print( dir, "" ); + //printf("recursive_print called\n"); + + tar.close(); + + return 0; + } + else if ( command == "get" ) + { + if ( argc != 4 ) + { + usage(); + return 1; + } + + KTarGz tar( argv[2] ); + + if ( !tar.open( IO_ReadOnly ) ) + { + printf("Could not open %s for reading\n", argv[1] ); + return 1; + } + + const KTarDirectory* dir = tar.directory(); + + const KTarEntry* e = dir->entry( argv[3] ); + Q_ASSERT( e && e->isFile() ); + const KTarFile* f = (KTarFile*)e; + + TQByteArray arr( f->data() ); + printf("SIZE=%i\n",arr.size() ); + TQString str( arr ); + printf("DATA=%s\n", str.latin1()); + + /* + // This is what KGzipDev::readAll could do, if TQIODevice::readAll was virtual.... + TQByteArray array(1024); + int n; + while ( ( n = dev.readBlock( array.data(), array.size() ) ) ) + { + kdDebug() << "readBlock returned " << n << endl << endl; + TQCString s(array,n+1); // Terminate with 0 before printing + printf("%s", s.data()); + } + dev.close(); + */ + + + tar.close(); + } + else if (command == "readwrite" ) + { + kdDebug() << " --- readwrite --- " << endl; + KTarGz tar( argv[2] ); + + if ( !tar.open( IO_WriteOnly ) ) + { + printf("Could not open %s for writing\n", argv[1]); + return 1; + } + + tar.writeFile( "empty", "weis", "users", 0, "" ); + tar.writeFile( "test1", "weis", "users", 5, "Hallo" ); + tar.writeFile( "test2", "weis", "users", 8, "Hallo Du" ); + tar.writeFile( "mydir/test3", "weis", "users", 13, "Noch so einer" ); + tar.writeFile( "my/dir/test3", "dfaure", "hackers", 29, "I don't speak German (David)" ); + +#define SIZE1 100 + // Now a medium file : 100 null bytes + char medium[ SIZE1 ]; + memset( medium, 0, SIZE1 ); + tar.writeFile( "mediumfile", "user", "group", SIZE1, medium ); + // Another one, with an absolute path + tar.writeFile( "/dir/subdir/mediumfile2", "user", "group", SIZE1, medium ); + + // Now a huge file : 20000 null bytes + int n = 20000; + char * huge = new char[ n ]; + memset( huge, 0, n ); + tar.writeFile( "hugefile", "user", "group", n, huge ); + delete [] huge; + + tar.close(); + + printf("-----------------------\n"); + + if ( !tar.open( IO_ReadOnly ) ) + { + printf("Could not open %s for reading\n", argv[1] ); + return 1; + } + + const KTarDirectory* dir = tar.directory(); + recursive_print(dir, ""); + + const KTarEntry* e = dir->entry( "mydir/test3" ); + Q_ASSERT( e && e->isFile() ); + const KTarFile* f = (KTarFile*)e; + + TQByteArray arr( f->data() ); + printf("SIZE=%i\n",arr.size() ); + TQString str( arr ); + printf("DATA=%s\n", str.latin1()); + + tar.close(); + + return 0; + } + else if ( command == "maxlength" ) + { + KTarGz tar( argv[2] ); + + if ( !tar.open( IO_WriteOnly ) ) + { + printf("Could not open %s for writing\n", argv[1]); + return 1; + } + // Generate long filenames of each possible length bigger than 98... + for (int i = 98; i < 500 ; i++ ) + { + TQString str, num; + str.fill( 'a', i-10 ); + num.setNum( i ); + num = num.rightJustify( 10, '0' ); + tar.writeFile( str+num, "testu", "testg", 3, "hum" ); + } + // Result of this test : it fails at 482 (instead of 154 previously). + // Ok, I think we can do with that :) + tar.close(); + printf("Now run 'tar tvzf %s'\n", argv[2]); + return 0; + } + else if ( command == "bytearray" ) + { + TQFile file( argv[2] ); + if ( !file.open( IO_ReadOnly ) ) + return 1; + KTarGz tar( &file ); + tar.open( IO_ReadOnly ); + const KTarDirectory* dir = tar.directory(); + recursive_print( dir, "" ); + return 0; + } + else + printf("Unknown command\n"); +} + diff --git a/tdeioslave/tar/tar.cc b/tdeioslave/tar/tar.cc new file mode 100644 index 000000000..bce89644d --- /dev/null +++ b/tdeioslave/tar/tar.cc @@ -0,0 +1,623 @@ +#include <config.h> + +#include <sys/types.h> +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#include <stdlib.h> +#include <unistd.h> + +#include <tqfile.h> + +#include <kglobal.h> +#include <kurl.h> +#include <kdebug.h> +#include <kinstance.h> +#include <ktar.h> +#include <kzip.h> +#include <kar.h> +#include <kmimemagic.h> +#include <klocale.h> +#include <kde_file.h> +#include <tdeio/global.h> +#include <kremoteencoding.h> + +#include <errno.h> // to be removed + +#include "tar.h" + +using namespace TDEIO; + +extern "C" { int KDE_EXPORT kdemain(int argc, char **argv); } + +int kdemain( int argc, char **argv ) +{ + TDEInstance instance( "kio_tar" ); + + kdDebug(7109) << "Starting " << getpid() << endl; + + if (argc != 4) + { + fprintf(stderr, "Usage: kio_tar protocol domain-socket1 domain-socket2\n"); + exit(-1); + } + + ArchiveProtocol slave(argv[2], argv[3]); + slave.dispatchLoop(); + + kdDebug(7109) << "Done" << endl; + return 0; +} + +ArchiveProtocol::ArchiveProtocol( const TQCString &pool, const TQCString &app ) : SlaveBase( "tar", pool, app ) +{ + kdDebug( 7109 ) << "ArchiveProtocol::ArchiveProtocol" << endl; + m_archiveFile = 0L; +} + +ArchiveProtocol::~ArchiveProtocol() +{ + delete m_archiveFile; +} + +bool ArchiveProtocol::checkNewFile( const KURL & url, TQString & path, TDEIO::Error& errorNum ) +{ + TQString fullPath = url.path(); + kdDebug(7109) << "ArchiveProtocol::checkNewFile " << fullPath << endl; + + + // Are we already looking at that file ? + if ( m_archiveFile && m_archiveName == fullPath.left(m_archiveName.length()) ) + { + // Has it changed ? + KDE_struct_stat statbuf; + if ( KDE_stat( TQFile::encodeName( m_archiveName ), &statbuf ) == 0 ) + { + if ( m_mtime == statbuf.st_mtime ) + { + path = fullPath.mid( m_archiveName.length() ); + kdDebug(7109) << "ArchiveProtocol::checkNewFile returning " << path << endl; + return true; + } + } + } + kdDebug(7109) << "Need to open a new file" << endl; + + // Close previous file + if ( m_archiveFile ) + { + m_archiveFile->close(); + delete m_archiveFile; + m_archiveFile = 0L; + } + + // Find where the tar file is in the full path + int pos = 0; + TQString archiveFile; + path = TQString::null; + + int len = fullPath.length(); + if ( len != 0 && fullPath[ len - 1 ] != '/' ) + fullPath += '/'; + + kdDebug(7109) << "the full path is " << fullPath << endl; + KDE_struct_stat statbuf; + statbuf.st_mode = 0; // be sure to clear the directory bit + while ( (pos=fullPath.find( '/', pos+1 )) != -1 ) + { + TQString tryPath = fullPath.left( pos ); + kdDebug(7109) << fullPath << " trying " << tryPath << endl; + if ( KDE_stat( TQFile::encodeName(tryPath), &statbuf ) == -1 ) + { + // We are not in the file system anymore, either we have already enough data or we will never get any useful data anymore + break; + } + if ( !S_ISDIR(statbuf.st_mode) ) + { + archiveFile = tryPath; + m_mtime = statbuf.st_mtime; + path = fullPath.mid( pos + 1 ); + kdDebug(7109) << "fullPath=" << fullPath << " path=" << path << endl; + len = path.length(); + if ( len > 1 ) + { + if ( path[ len - 1 ] == '/' ) + path.truncate( len - 1 ); + } + else + path = TQString::fromLatin1("/"); + kdDebug(7109) << "Found. archiveFile=" << archiveFile << " path=" << path << endl; + break; + } + } + if ( archiveFile.isEmpty() ) + { + kdDebug(7109) << "ArchiveProtocol::checkNewFile: not found" << endl; + if ( S_ISDIR(statbuf.st_mode) ) // Was the last stat about a directory? + { + // Too bad, it is a directory, not an archive. + kdDebug(7109) << "Path is a directory, not an archive." << endl; + errorNum = TDEIO::ERR_IS_DIRECTORY; + } + else + errorNum = TDEIO::ERR_DOES_NOT_EXIST; + return false; + } + + // Open new file + if ( url.protocol() == "tar" ) { + kdDebug(7109) << "Opening KTar on " << archiveFile << endl; + m_archiveFile = new KTar( archiveFile ); + } else if ( url.protocol() == "ar" ) { + kdDebug(7109) << "Opening KAr on " << archiveFile << endl; + m_archiveFile = new KAr( archiveFile ); + } else if ( url.protocol() == "zip" ) { + kdDebug(7109) << "Opening KZip on " << archiveFile << endl; + m_archiveFile = new KZip( archiveFile ); + } else { + kdWarning(7109) << "Protocol " << url.protocol() << " not supported by this IOSlave" << endl; + errorNum = TDEIO::ERR_UNSUPPORTED_PROTOCOL; + return false; + } + + if ( !m_archiveFile->open( IO_ReadOnly ) ) + { + kdDebug(7109) << "Opening " << archiveFile << "failed." << endl; + delete m_archiveFile; + m_archiveFile = 0L; + errorNum = TDEIO::ERR_CANNOT_OPEN_FOR_READING; + return false; + } + + m_archiveName = archiveFile; + return true; +} + + +void ArchiveProtocol::createUDSEntry( const KArchiveEntry * archiveEntry, UDSEntry & entry ) +{ + UDSAtom atom; + entry.clear(); + atom.m_uds = UDS_NAME; + atom.m_str = remoteEncoding()->decode(archiveEntry->name().local8Bit()); + entry.append(atom); + + atom.m_uds = UDS_FILE_TYPE; + atom.m_long = archiveEntry->permissions() & S_IFMT; // keep file type only + entry.append( atom ); + + atom.m_uds = UDS_SIZE; + atom.m_long = archiveEntry->isFile() ? ((KArchiveFile *)archiveEntry)->size() : 0L ; + entry.append( atom ); + + atom.m_uds = UDS_MODIFICATION_TIME; + atom.m_long = archiveEntry->date(); + entry.append( atom ); + + atom.m_uds = UDS_ACCESS; + atom.m_long = archiveEntry->permissions() & 07777; // keep permissions only + entry.append( atom ); + + atom.m_uds = UDS_USER; + atom.m_str = remoteEncoding()->decode(archiveEntry->user().local8Bit()); + entry.append( atom ); + + atom.m_uds = UDS_GROUP; + atom.m_str = remoteEncoding()->decode(archiveEntry->group().local8Bit()); + entry.append( atom ); + + atom.m_uds = UDS_LINK_DEST; + atom.m_str = remoteEncoding()->decode(archiveEntry->symlink().local8Bit()); + entry.append( atom ); +} + +void ArchiveProtocol::listDir( const KURL & url ) +{ + kdDebug( 7109 ) << "ArchiveProtocol::listDir " << url << endl; + + TQString path; + TDEIO::Error errorNum; + if ( !checkNewFile( url, path, errorNum ) ) + { + if ( errorNum == TDEIO::ERR_CANNOT_OPEN_FOR_READING ) + { + // If we cannot open, it might be a problem with the archive header (e.g. unsupported format) + // Therefore give a more specific error message + error( TDEIO::ERR_SLAVE_DEFINED, + i18n( "Could not open the file, probably due to an unsupported file format.\n%1") + .arg( url.prettyURL() ) ); + return; + } + else if ( errorNum != ERR_IS_DIRECTORY ) + { + // We have any other error + error( errorNum, url.prettyURL() ); + return; + } + // It's a real dir -> redirect + KURL redir; + redir.setPath( url.path() ); + kdDebug( 7109 ) << "Ok, redirection to " << redir.url() << endl; + redirection( redir ); + finished(); + // And let go of the tar file - for people who want to unmount a cdrom after that + delete m_archiveFile; + m_archiveFile = 0L; + return; + } + + if ( path.isEmpty() ) + { + KURL redir( url.protocol() + TQString::fromLatin1( ":/") ); + kdDebug( 7109 ) << "url.path()==" << url.path() << endl; + redir.setPath( url.path() + TQString::fromLatin1("/") ); + kdDebug( 7109 ) << "ArchiveProtocol::listDir: redirection " << redir.url() << endl; + redirection( redir ); + finished(); + return; + } + + path = TQString::fromLocal8Bit(remoteEncoding()->encode(path)); + + kdDebug( 7109 ) << "checkNewFile done" << endl; + const KArchiveDirectory* root = m_archiveFile->directory(); + const KArchiveDirectory* dir; + if (!path.isEmpty() && path != "/") + { + kdDebug(7109) << TQString(TQString("Looking for entry %1").arg(path)) << endl; + const KArchiveEntry* e = root->entry( path ); + if ( !e ) + { + error( TDEIO::ERR_DOES_NOT_EXIST, url.prettyURL() ); + return; + } + if ( ! e->isDirectory() ) + { + error( TDEIO::ERR_IS_FILE, url.prettyURL() ); + return; + } + dir = (KArchiveDirectory*)e; + } else { + dir = root; + } + + TQStringList l = dir->entries(); + totalSize( l.count() ); + + UDSEntry entry; + TQStringList::Iterator it = l.begin(); + for( ; it != l.end(); ++it ) + { + kdDebug(7109) << (*it) << endl; + const KArchiveEntry* archiveEntry = dir->entry( (*it) ); + + createUDSEntry( archiveEntry, entry ); + + listEntry( entry, false ); + } + + listEntry( entry, true ); // ready + + finished(); + + kdDebug( 7109 ) << "ArchiveProtocol::listDir done" << endl; +} + +void ArchiveProtocol::stat( const KURL & url ) +{ + TQString path; + UDSEntry entry; + TDEIO::Error errorNum; + if ( !checkNewFile( url, path, errorNum ) ) + { + // We may be looking at a real directory - this happens + // when pressing up after being in the root of an archive + if ( errorNum == TDEIO::ERR_CANNOT_OPEN_FOR_READING ) + { + // If we cannot open, it might be a problem with the archive header (e.g. unsupported format) + // Therefore give a more specific error message + error( TDEIO::ERR_SLAVE_DEFINED, + i18n( "Could not open the file, probably due to an unsupported file format.\n%1") + .arg( url.prettyURL() ) ); + return; + } + else if ( errorNum != ERR_IS_DIRECTORY ) + { + // We have any other error + error( errorNum, url.prettyURL() ); + return; + } + // Real directory. Return just enough information for KRun to work + UDSAtom atom; + atom.m_uds = TDEIO::UDS_NAME; + atom.m_str = url.fileName(); + entry.append( atom ); + kdDebug( 7109 ) << "ArchiveProtocol::stat returning name=" << url.fileName() << endl; + + KDE_struct_stat buff; + if ( KDE_stat( TQFile::encodeName( url.path() ), &buff ) == -1 ) + { + // Should not happen, as the file was already stated by checkNewFile + error( TDEIO::ERR_COULD_NOT_STAT, url.prettyURL() ); + return; + } + + atom.m_uds = TDEIO::UDS_FILE_TYPE; + atom.m_long = buff.st_mode & S_IFMT; + entry.append( atom ); + + statEntry( entry ); + + finished(); + + // And let go of the tar file - for people who want to unmount a cdrom after that + delete m_archiveFile; + m_archiveFile = 0L; + return; + } + + const KArchiveDirectory* root = m_archiveFile->directory(); + const KArchiveEntry* archiveEntry; + if ( path.isEmpty() ) + { + path = TQString::fromLatin1( "/" ); + archiveEntry = root; + } else { + path = TQString::fromLocal8Bit(remoteEncoding()->encode(path)); + archiveEntry = root->entry( path ); + } + if ( !archiveEntry ) + { + error( TDEIO::ERR_DOES_NOT_EXIST, url.prettyURL() ); + return; + } + + createUDSEntry( archiveEntry, entry ); + statEntry( entry ); + + finished(); +} + +void ArchiveProtocol::get( const KURL & url ) +{ + kdDebug( 7109 ) << "ArchiveProtocol::get " << url << endl; + + TQString path; + TDEIO::Error errorNum; + if ( !checkNewFile( url, path, errorNum ) ) + { + if ( errorNum == TDEIO::ERR_CANNOT_OPEN_FOR_READING ) + { + // If we cannot open, it might be a problem with the archive header (e.g. unsupported format) + // Therefore give a more specific error message + error( TDEIO::ERR_SLAVE_DEFINED, + i18n( "Could not open the file, probably due to an unsupported file format.\n%1") + .arg( url.prettyURL() ) ); + return; + } + else + { + // We have any other error + error( errorNum, url.prettyURL() ); + return; + } + } + + path = TQString::fromLocal8Bit(remoteEncoding()->encode(path)); + + const KArchiveDirectory* root = m_archiveFile->directory(); + const KArchiveEntry* archiveEntry = root->entry( path ); + + if ( !archiveEntry ) + { + error( TDEIO::ERR_DOES_NOT_EXIST, url.prettyURL() ); + return; + } + if ( archiveEntry->isDirectory() ) + { + error( TDEIO::ERR_IS_DIRECTORY, url.prettyURL() ); + return; + } + const KArchiveFile* archiveFileEntry = static_cast<const KArchiveFile *>(archiveEntry); + if ( !archiveEntry->symlink().isEmpty() ) + { + kdDebug(7109) << "Redirection to " << archiveEntry->symlink() << endl; + KURL realURL; + if (archiveEntry->symlink().startsWith("/")) { // absolute path + realURL.setPath(archiveEntry->symlink() ); // goes out of tar:/, back into file: + } else { + realURL = KURL( url, archiveEntry->symlink() ); + } + kdDebug(7109) << "realURL= " << realURL << endl; + redirection( realURL ); + finished(); + return; + } + + //kdDebug(7109) << "Preparing to get the archive data" << endl; + + /* + * The easy way would be to get the data by calling archiveFileEntry->data() + * However this has drawbacks: + * - the complete file must be read into the memory + * - errors are skipped, resulting in an empty file + */ + + TQIODevice* io = 0; + // Getting the device is hard, as archiveFileEntry->device() is not virtual! + if ( url.protocol() == "tar" ) + { + io = archiveFileEntry->device(); + } + else if ( url.protocol() == "ar" ) + { + io = archiveFileEntry->device(); + } + else if ( url.protocol() == "zip" ) + { + io = ((KZipFileEntry*) archiveFileEntry)->device(); + } + else + { + // Wrong protocol? Why was this not catched by checkNewFile? + kdWarning(7109) << "Protocol " << url.protocol() << " not supported by this IOSlave; " << k_funcinfo << endl; + error( TDEIO::ERR_UNSUPPORTED_PROTOCOL, url.protocol() ); + return; + } + + if (!io) + { + error( TDEIO::ERR_SLAVE_DEFINED, + i18n( "The archive file could not be opened, perhaps because the format is unsupported.\n%1" ) + .arg( url.prettyURL() ) ); + return; + } + + if ( !io->open( IO_ReadOnly ) ) + { + error( TDEIO::ERR_CANNOT_OPEN_FOR_READING, url.prettyURL() ); + return; + } + + totalSize( archiveFileEntry->size() ); + + // Size of a TQIODevice read. It must be large enough so that the mime type check will not fail + const int maxSize = 0x100000; // 1MB + + int bufferSize = kMin( maxSize, archiveFileEntry->size() ); + TQByteArray buffer ( bufferSize ); + if ( buffer.isEmpty() && bufferSize > 0 ) + { + // Something went wrong + error( TDEIO::ERR_OUT_OF_MEMORY, url.prettyURL() ); + return; + } + + bool firstRead = true; + + // How much file do we still have to process? + int fileSize = archiveFileEntry->size(); + TDEIO::filesize_t processed = 0; + + while ( !io->atEnd() && fileSize > 0 ) + { + if ( !firstRead ) + { + bufferSize = kMin( maxSize, fileSize ); + buffer.resize( bufferSize, TQGArray::SpeedOptim ); + } + const TQ_LONG read = io->readBlock( buffer.data(), buffer.size() ); // Avoid to use bufferSize here, in case something went wrong. + if ( read != bufferSize ) + { + kdWarning(7109) << "Read " << read << " bytes but expected " << bufferSize << endl; + error( TDEIO::ERR_COULD_NOT_READ, url.prettyURL() ); + return; + } + if ( firstRead ) + { + // We use the magic one the first data read + // (As magic detection is about fixed positions, we can be sure that it is enough data.) + KMimeMagicResult * result = KMimeMagic::self()->findBufferFileType( buffer, path ); + kdDebug(7109) << "Emitting mimetype " << result->mimeType() << endl; + mimeType( result->mimeType() ); + firstRead = false; + } + data( buffer ); + processed += read; + processedSize( processed ); + fileSize -= bufferSize; + } + io->close(); + delete io; + + data( TQByteArray() ); + + finished(); +} + +/* + In case someone wonders how the old filter stuff looked like : :) +void TARProtocol::slotData(void *_p, int _len) +{ + switch (m_cmd) { + case CMD_PUT: + assert(m_pFilter); + m_pFilter->send(_p, _len); + break; + default: + abort(); + break; + } +} + +void TARProtocol::slotDataEnd() +{ + switch (m_cmd) { + case CMD_PUT: + assert(m_pFilter && m_pJob); + m_pFilter->finish(); + m_pJob->dataEnd(); + m_cmd = CMD_NONE; + break; + default: + abort(); + break; + } +} + +void TARProtocol::jobData(void *_p, int _len) +{ + switch (m_cmd) { + case CMD_GET: + assert(m_pFilter); + m_pFilter->send(_p, _len); + break; + case CMD_COPY: + assert(m_pFilter); + m_pFilter->send(_p, _len); + break; + default: + abort(); + } +} + +void TARProtocol::jobDataEnd() +{ + switch (m_cmd) { + case CMD_GET: + assert(m_pFilter); + m_pFilter->finish(); + dataEnd(); + break; + case CMD_COPY: + assert(m_pFilter); + m_pFilter->finish(); + m_pJob->dataEnd(); + break; + default: + abort(); + } +} + +void TARProtocol::filterData(void *_p, int _len) +{ +debug("void TARProtocol::filterData"); + switch (m_cmd) { + case CMD_GET: + data(_p, _len); + break; + case CMD_PUT: + assert (m_pJob); + m_pJob->data(_p, _len); + break; + case CMD_COPY: + assert(m_pJob); + m_pJob->data(_p, _len); + break; + default: + abort(); + } +} +*/ + +// kate: space-indent on; indent-width 4; replace-tabs on; diff --git a/tdeioslave/tar/tar.h b/tdeioslave/tar/tar.h new file mode 100644 index 000000000..42cb2457a --- /dev/null +++ b/tdeioslave/tar/tar.h @@ -0,0 +1,55 @@ +/* This file is part of the KDE libraries + Copyright (C) 2000 David Faure <faure@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef _TAR_H +#define _TAR_H + +#include <sys/types.h> + +#include <tdeio/global.h> +#include <tdeio/slavebase.h> + +class ArchiveProtocol : public TDEIO::SlaveBase +{ +public: + ArchiveProtocol( const TQCString &pool, const TQCString &app ); + virtual ~ArchiveProtocol(); + + virtual void listDir( const KURL & url ); + virtual void stat( const KURL & url ); + virtual void get( const KURL & url ); + +protected: + void createUDSEntry( const KArchiveEntry * tarEntry, TDEIO::UDSEntry & entry ); + + /** + * \brief find, check and open the archive file + * \param url The URL of the archive + * \param path Path where the archive really is (returned value) + * \param errNum KIO error number (undefined if the function returns true) + * \return true if file was found, false if there was an error + */ + bool checkNewFile( const KURL & url, TQString & path, TDEIO::Error& errorNum ); + + KArchive * m_archiveFile; + TQString m_archiveName; + time_t m_mtime; +}; + +#endif diff --git a/tdeioslave/tar/tar.protocol b/tdeioslave/tar/tar.protocol new file mode 100644 index 000000000..bd97ba6bb --- /dev/null +++ b/tdeioslave/tar/tar.protocol @@ -0,0 +1,12 @@ +[Protocol] +exec=kio_tar +protocol=tar +mimetype=application/x-tar +input=filesystem +output=filesystem +listing=Name,Type,Size,Date,Access,Owner,Group,Link +reading=true +source=true +DocPath=tdeioslave/tar.html +Icon=tar +Class=:local diff --git a/tdeioslave/tar/zip.protocol b/tdeioslave/tar/zip.protocol new file mode 100644 index 000000000..d67d5b2ff --- /dev/null +++ b/tdeioslave/tar/zip.protocol @@ -0,0 +1,12 @@ +[Protocol] +exec=kio_tar +protocol=zip +mimetype=application/x-zip +input=filesystem +output=filesystem +listing=Name,Type,Size,Date,Access,Owner,Group,Link +reading=true +source=true +DocPath=tdeioslave/zip.html +Icon=zip +Class=:local |