summaryrefslogtreecommitdiffstats
path: root/krArc/krarc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'krArc/krarc.cpp')
-rw-r--r--krArc/krarc.cpp1668
1 files changed, 1668 insertions, 0 deletions
diff --git a/krArc/krarc.cpp b/krArc/krarc.cpp
new file mode 100644
index 0000000..663236a
--- /dev/null
+++ b/krArc/krarc.cpp
@@ -0,0 +1,1668 @@
+/***************************************************************************
+ krarc.cpp
+ -------------------
+ begin : Sat Jun 14 14:42:49 IDT 2003
+ copyright : (C) 2003 by Rafi Yanai & Shie Erlich
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <stdlib.h>
+
+#include <qdir.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qregexp.h>
+#include <qdir.h>
+
+#include <kfileitem.h>
+#include <kdebug.h>
+#include <kmessagebox.h>
+#include <kinstance.h>
+#include <klocale.h>
+#include <kurl.h>
+#include <ktempfile.h>
+#include <klargefile.h>
+#include <kstandarddirs.h>
+#include <kio/job.h>
+#include <ktar.h>
+
+#include <iostream>
+#include "krarc.h"
+
+#define MAX_IPC_SIZE (1024*32)
+#define TRIES_WITH_PASSWORDS 3
+
+#if 0
+#define KRDEBUG(X...) do{ \
+ QFile f("/tmp/debug"); \
+ f.open(IO_WriteOnly | IO_Append); \
+ QTextStream stream( &f ); \
+ stream << "Pid:" << (int)getpid() << " " <<__FUNCTION__<<"(" <<__LINE__<<"): "; \
+ stream << X << endl; \
+ f.close(); \
+} while(0);
+#else
+#define KRDEBUG(X...)
+#endif
+
+using namespace KIO;
+extern "C" {
+
+int kdemain( int argc, char **argv ){
+ KInstance instance( "kio_krarc" );
+
+ if (argc != 4) {
+ kdWarning() << "Usage: kio_krarc protocol domain-socket1 domain-socket2" << endl;
+ exit(-1);
+ }
+
+ kio_krarcProtocol slave(argv[2], argv[3]);
+ slave.dispatchLoop();
+
+ return 0;
+}
+
+} // extern "C"
+
+kio_krarcProtocol::kio_krarcProtocol(const QCString &pool_socket, const QCString &app_socket)
+ : SlaveBase("kio_krarc", pool_socket, app_socket), archiveChanged(true), arcFile(0L),extArcReady(false),
+ password(QString::null) {
+
+ krConfig = new KConfig( "krusaderrc" );
+ krConfig->setGroup( "Dependencies" );
+
+ dirDict.setAutoDelete(true);
+
+ arcTempDir = locateLocal("tmp",QString::null);
+ QString dirName = "krArc"+QDateTime::currentDateTime().toString(Qt::ISODate);
+ dirName.replace(QRegExp(":"),"_");
+ QDir(arcTempDir).mkdir(dirName);
+ arcTempDir = arcTempDir+dirName+"/";
+}
+
+/* ---------------------------------------------------------------------------------- */
+kio_krarcProtocol::~kio_krarcProtocol(){
+ // delete the temp directory
+ KrShellProcess proc;
+ proc << "rm -rf "<< arcTempDir;
+ proc.start(KProcess::Block);
+}
+
+/* ---------------------------------------------------------------------------------- */
+void kio_krarcProtocol::receivedData(KProcess*,char* buf,int len){
+ QByteArray d(len);
+ d.setRawData(buf,len);
+ data(d);
+ d.resetRawData(buf,len);
+ processedSize(len);
+ decompressedLen += len;
+}
+
+void kio_krarcProtocol::mkdir(const KURL& url,int permissions){
+ KRDEBUG(url.path());
+
+ if( !setArcFile( url ) ) {
+ error(ERR_CANNOT_ENTER_DIRECTORY,url.path());
+ return;
+ }
+ if( newArchiveURL && !initDirDict(url) ){
+ error(ERR_CANNOT_ENTER_DIRECTORY,url.path());
+ return;
+ }
+
+ if( putCmd.isEmpty() ){
+ error(ERR_UNSUPPORTED_ACTION,
+ i18n("Creating directories is not supported with %1 archives").arg(arcType) );
+ return;
+ }
+
+ if( arcType == "arj" || arcType == "lha" ) {
+ QString arcDir = url.path().mid(arcFile->url().path().length());
+ if( arcDir.right(1) != "/") arcDir = arcDir+"/";
+
+ if( dirDict.find( arcDir ) == 0 )
+ addNewDir( arcDir );
+ finished();
+ return;
+ }
+
+ //QString tmpDir = arcTempDir+url.path();
+ QString arcDir = findArcDirectory(url);
+ QString tmpDir = arcTempDir + arcDir.mid(1) + url.path().mid(url.path().findRev("/")+1);
+ if( tmpDir.right(1) != "/" ) tmpDir = tmpDir+"/";
+
+ if( permissions == -1 ) permissions = 0777; //set default permissions
+ for( unsigned int i=arcTempDir.length();i<tmpDir.length(); i=tmpDir.find("/",i+1)){
+ ::mkdir(tmpDir.left(i).local8Bit(),permissions);
+ }
+
+ if( tmpDir.endsWith( "/" ) )
+ tmpDir.truncate( tmpDir.length() - 1 );
+
+ // pack the directory
+ KrShellProcess proc;
+ proc << putCmd << convertName( arcFile->url().path() ) + " " << convertFileName( tmpDir.mid(arcTempDir.length()) );
+ infoMessage(i18n("Creating %1 ...").arg( url.fileName() ) );
+ QDir::setCurrent(arcTempDir);
+ proc.start(KProcess::Block,KProcess::AllOutput);
+
+ // delete the temp directory
+ QDir().rmdir(arcTempDir);
+
+ if( !proc.normalExit() || !checkStatus( proc.exitStatus() ) ) {
+ error(ERR_COULD_NOT_WRITE,url.path() + "\n\n" + proc.getErrorMsg() );
+ return;
+ }
+
+ // force a refresh of archive information
+ initDirDict(url,true);
+ finished();
+}
+
+void kio_krarcProtocol::put(const KURL& url,int permissions,bool overwrite,bool resume){
+ KRDEBUG(url.path());
+ if( !setArcFile( url ) ) {
+ error(ERR_CANNOT_ENTER_DIRECTORY,url.path());
+ return;
+ }
+ if( newArchiveURL && !initDirDict(url) ){
+ error(ERR_CANNOT_ENTER_DIRECTORY,url.path());
+ return;
+ }
+
+ if( putCmd.isEmpty() ){
+ error(ERR_UNSUPPORTED_ACTION,
+ i18n("Writing to %1 archives is not supported").arg(arcType) );
+ return;
+ }
+ if( !overwrite && findFileEntry(url) ){
+ error( ERR_FILE_ALREADY_EXIST,url.path() );
+ return;
+ }
+
+ QString arcDir = findArcDirectory(url);
+ QString tmpFile = arcTempDir + arcDir.mid(1) + url.path().mid(url.path().findRev("/")+1);
+
+ QString tmpDir = arcTempDir+arcDir.mid(1)+"/";
+ for( unsigned int i=arcTempDir.length();i<tmpDir.length(); i=tmpDir.find("/",i+1)){
+ QDir("/").mkdir(tmpDir.left(i));
+ }
+ int fd;
+ if ( resume ) {
+ fd = KDE_open( tmpFile.local8Bit(), O_RDWR ); // append if resuming
+ KDE_lseek(fd, 0, SEEK_END); // Seek to end
+ } else {
+ // WABA: Make sure that we keep writing permissions ourselves,
+ // otherwise we can be in for a surprise on NFS.
+ mode_t initialMode;
+ if ( permissions != -1)
+ initialMode = permissions | S_IWUSR | S_IRUSR;
+ else
+ initialMode = 0666;
+
+ fd = KDE_open(tmpFile.local8Bit(), O_CREAT | O_TRUNC | O_WRONLY, initialMode);
+ }
+ QByteArray buffer;
+ int readResult;
+ do{
+ dataReq();
+ readResult = readData(buffer);
+ write(fd,buffer.data(),buffer.size());
+ } while( readResult > 0 );
+ close(fd);
+ // pack the file
+ KrShellProcess proc;
+ proc << putCmd << convertName( arcFile->url().path() )+ " " <<convertFileName( tmpFile.mid(arcTempDir.length()) );
+ infoMessage(i18n("Packing %1 ...").arg( url.fileName() ) );
+ QDir::setCurrent(arcTempDir);
+ proc.start(KProcess::Block,KProcess::AllOutput);
+ // remove the file
+ QFile::remove(tmpFile);
+
+ if( !proc.normalExit() || !checkStatus( proc.exitStatus() ) ) {
+ error(ERR_COULD_NOT_WRITE,url.path() + "\n\n" + proc.getErrorMsg() );
+ return;
+ }
+ // force a refresh of archive information
+ initDirDict(url,true);
+ finished();
+}
+
+void kio_krarcProtocol::get(const KURL& url ){
+ get( url, TRIES_WITH_PASSWORDS );
+}
+
+void kio_krarcProtocol::get(const KURL& url, int tries ){
+ bool decompressToFile = false;
+ KRDEBUG(url.path());
+
+ if( !setArcFile( url ) ) {
+ error(ERR_CANNOT_ENTER_DIRECTORY,url.path());
+ return;
+ }
+ if( newArchiveURL && !initDirDict(url) ){
+ error(ERR_CANNOT_ENTER_DIRECTORY,url.path());
+ return;
+ }
+
+ if( getCmd.isEmpty() ){
+ error(ERR_UNSUPPORTED_ACTION,
+ i18n("Retrieving data from %1 archives is not supported").arg(arcType) );
+ return;
+ }
+ UDSEntry* entry = findFileEntry(url);
+ if( !entry ){
+ error(KIO::ERR_DOES_NOT_EXIST,url.path());
+ return;
+ }
+ if(KFileItem(*entry,url).isDir()){
+ error(KIO::ERR_IS_DIRECTORY,url.path());
+ return;
+ }
+ KIO::filesize_t expectedSize = KFileItem(*entry,url).size();
+ // for RPM files extract the cpio file first
+ if( !extArcReady && arcType == "rpm"){
+ KrShellProcess cpio;
+ cpio << "rpm2cpio" << convertName( arcFile->url().path(-1) ) << " > " << arcTempDir+"contents.cpio";
+ cpio.start(KProcess::Block,KProcess::AllOutput);
+ if( !cpio.normalExit() || cpio.exitStatus() != 0 ) {
+ error(ERR_COULD_NOT_READ,url.path() + "\n\n" + cpio.getErrorMsg() );
+ return;
+ }
+ extArcReady = true;
+ }
+ // for DEB files extract the tar file first
+ if ( !extArcReady && arcType == "deb" ) {
+ KrShellProcess dpkg;
+ dpkg << cmd + " --fsys-tarfile" << convertName( arcFile->url().path( -1 ) ) << " > " << arcTempDir + "contents.cpio";
+ dpkg.start( KProcess::Block, KProcess::AllOutput );
+ if( !dpkg.normalExit() || dpkg.exitStatus() != 0 ) {
+ error(ERR_COULD_NOT_READ,url.path() + "\n\n" + dpkg.getErrorMsg() );
+ return;
+ }
+ extArcReady = true;
+ }
+
+ // Use the external unpacker to unpack the file
+ QString file = url.path().mid(arcFile->url().path().length()+1);
+ KrShellProcess proc;
+ if( extArcReady ){
+ proc << getCmd << arcTempDir+"contents.cpio " << convertName( "*"+file );
+ } else if( arcType == "arj" || arcType == "ace" || arcType == "7z" ) {
+ proc << getCmd << convertName( arcFile->url().path(-1) )+ " " << convertFileName( file );
+ if( arcType == "ace" && QFile( "/dev/ptmx" ).exists() ) // Don't remove, unace crashes if missing!!!
+ proc << "<" << "/dev/ptmx";
+ file = url.fileName();
+ decompressToFile = true;
+ } else {
+ decompressedLen = 0;
+ // Determine the mimetype of the file to be retrieved, and emit it.
+ // This is mandatory in all slaves (for KRun/BrowserRun to work).
+ KMimeType::Ptr mt = KMimeType::findByURL( arcTempDir+file, 0, false /* NOT local URL */ );
+ emit mimeType( mt->name() );
+ proc << getCmd << convertName( arcFile->url().path() )+" ";
+ if( arcType != "gzip" && arcType != "bzip2" ) proc << convertFileName( file );
+ connect(&proc,SIGNAL(receivedStdout(KProcess*,char*,int)),
+ this,SLOT(receivedData(KProcess*,char*,int)) );
+ }
+ infoMessage(i18n("Unpacking %1 ...").arg( url.fileName() ) );
+ // change the working directory to our arcTempDir
+ QDir::setCurrent(arcTempDir);
+ proc.start(KProcess::Block,KProcess::AllOutput);
+
+ if( !extArcReady && !decompressToFile ) {
+ if( !proc.normalExit() || !checkStatus( proc.exitStatus() ) || ( arcType != "bzip2" && expectedSize != decompressedLen ) ) {
+ if( encrypted && tries ) {
+ invalidatePassword();
+ get( url, tries - 1 );
+ return;
+ }
+ error( KIO::ERR_ACCESS_DENIED, url.path() + "\n\n" + proc.getErrorMsg() );
+ return;
+ }
+ }
+ else{
+ if( !proc.normalExit() || !checkStatus( proc.exitStatus() ) || !QFileInfo( arcTempDir+file ).exists() ) {
+ if( decompressToFile )
+ QFile(arcTempDir+file).remove();
+ if( encrypted && tries ) {
+ invalidatePassword();
+ get( url, tries - 1 );
+ return;
+ }
+ error( KIO::ERR_ACCESS_DENIED, url.path() );
+ return;
+ }
+ // the follwing block is ripped from KDE file KIO::Slave
+ // $Id: krarc.cpp,v 1.43 2007/01/13 13:39:51 ckarai Exp $
+ QCString _path( QFile::encodeName(arcTempDir+file) );
+ KDE_struct_stat buff;
+ if( KDE_lstat( _path.data(), &buff ) == -1 ) {
+ if ( errno == EACCES )
+ error( KIO::ERR_ACCESS_DENIED, url.path() );
+ else
+ error( KIO::ERR_DOES_NOT_EXIST, url.path() );
+ return;
+ }
+ if ( S_ISDIR( buff.st_mode ) ) {
+ error( KIO::ERR_IS_DIRECTORY, url.path() );
+ return;
+ }
+ if ( !S_ISREG(buff.st_mode) ) {
+ error( KIO::ERR_CANNOT_OPEN_FOR_READING, url.path() );
+ return;
+ }
+ int fd = KDE_open( _path.data(), O_RDONLY );
+ if ( fd < 0 ) {
+ error( KIO::ERR_CANNOT_OPEN_FOR_READING, url.path() );
+ return;
+ }
+ // Determine the mimetype of the file to be retrieved, and emit it.
+ // This is mandatory in all slaves (for KRun/BrowserRun to work).
+ KMimeType::Ptr mt = KMimeType::findByURL( arcTempDir+file, buff.st_mode, true /* local URL */ );
+ emit mimeType( mt->name() );
+
+ KIO::filesize_t processed_size = 0;
+
+ QString resumeOffset = metaData("resume");
+ if ( !resumeOffset.isEmpty() ){
+ bool ok;
+#if QT_VERSION >= 0x030200
+ KIO::fileoffset_t offset = resumeOffset.toLongLong(&ok);
+#else
+ KIO::fileoffset_t offset = resumeOffset.toULong(&ok);
+#endif
+ if (ok && (offset > 0) && (offset < buff.st_size)){
+ if (KDE_lseek(fd, offset, SEEK_SET) == offset){
+ canResume ();
+ processed_size = offset;
+ }
+ }
+ }
+
+ totalSize( buff.st_size );
+
+ char buffer[ MAX_IPC_SIZE ];
+ QByteArray array;
+ while( 1 ){
+ int n = ::read( fd, buffer, MAX_IPC_SIZE );
+ if (n == -1){
+ if (errno == EINTR)
+ continue;
+ error( KIO::ERR_COULD_NOT_READ, url.path());
+ close(fd);
+ return;
+ }
+ if (n == 0)
+ break; // Finished
+
+ array.setRawData(buffer, n);
+ data( array );
+ array.resetRawData(buffer, n);
+
+ processed_size += n;
+ }
+
+ data( QByteArray() );
+ close( fd );
+ processedSize( buff.st_size );
+ finished();
+
+ if( decompressToFile )
+ QFile(arcTempDir+file).remove();
+ return;
+ }
+ // send empty buffer to mark EOF
+ data(QByteArray());
+ finished();
+}
+
+void kio_krarcProtocol::del(KURL const & url, bool isFile){
+ KRDEBUG(url.path());
+
+ if( !setArcFile( url ) ) {
+ error(ERR_CANNOT_ENTER_DIRECTORY,url.path());
+ return;
+ }
+ if( newArchiveURL && !initDirDict(url) ){
+ error(ERR_CANNOT_ENTER_DIRECTORY,url.path());
+ return;
+ }
+
+ if( delCmd.isEmpty() ){
+ error(ERR_UNSUPPORTED_ACTION,
+ i18n("Deleting files from %1 archives is not supported").arg(arcType) );
+ return;
+ }
+ if( !findFileEntry(url) ){
+ if( ( arcType != "arj" && arcType != "lha" ) || isFile ) {
+ error(KIO::ERR_DOES_NOT_EXIST,url.path());
+ return;
+ }
+ }
+
+ QString file = url.path().mid(arcFile->url().path().length()+1);
+ if( !isFile && file.right(1) != "/" ) {
+ if(arcType == "zip") file = file + "/";
+ }
+ KrShellProcess proc;
+ proc << delCmd << convertName( arcFile->url().path() )+" " << convertFileName( file );
+ infoMessage(i18n("Deleting %1 ...").arg( url.fileName() ) );
+ proc.start(KProcess::Block, KProcess::AllOutput);
+ if( !proc.normalExit() || !checkStatus( proc.exitStatus() ) ) {
+ error(ERR_COULD_NOT_WRITE,url.path() + "\n\n" + proc.getErrorMsg() );
+ return;
+ }
+ // force a refresh of archive information
+ initDirDict(url,true);
+ finished();
+}
+
+void kio_krarcProtocol::stat( const KURL & url ){
+ KRDEBUG(url.path());
+ if( !setArcFile( url ) ) {
+ error(ERR_CANNOT_ENTER_DIRECTORY,url.path());
+ return;
+ }
+ if( newArchiveURL && !initDirDict(url) ){
+ error(ERR_CANNOT_ENTER_DIRECTORY,url.path());
+ return;
+ }
+
+ if( listCmd.isEmpty() ){
+ error(ERR_UNSUPPORTED_ACTION,
+ i18n("Accessing files is not supported with the %1 archives").arg(arcType) );
+ return;
+ }
+ QString path = url.path(-1);
+ KURL newUrl = url;
+
+ // but treat the archive itself as the archive root
+ if( path == arcFile->url().path(-1) ){
+ newUrl.setPath(path+"/");
+ path = newUrl.path();
+ }
+ // we might be stating a real file
+ if( QFileInfo(path).exists() ){
+ KDE_struct_stat buff;
+ KDE_stat( path.local8Bit(), &buff );
+ QString mime = KMimeType::findByPath(path,buff.st_mode)->name();
+ statEntry(KFileItem(path,mime,buff.st_mode).entry());
+ finished();
+ return;
+ }
+ UDSEntry* entry = findFileEntry(newUrl);
+ if( entry ){
+ statEntry( *entry );
+ finished();
+ } else error( KIO::ERR_DOES_NOT_EXIST, path );
+}
+
+void kio_krarcProtocol::copy (const KURL &url, const KURL &dest, int, bool overwrite) {
+ KRDEBUG(url.path());
+
+ // KDE HACK: opening the password dlg in copy causes error for the COPY, and further problems
+ // that's why encrypted files are not allowed to copy
+ if( !encrypted && dest.isLocalFile() )
+ do {
+ if( url.fileName() != dest.fileName() )
+ break;
+
+ //the file exists and we don't want to overwrite
+ if ((!overwrite) && ( QFile( dest.path() ).exists() ) ) {
+ error(ERR_FILE_ALREADY_EXIST, QFile::encodeName(dest.path()) );
+ return;
+ };
+
+ if( !setArcFile( url ) ) {
+ error(ERR_CANNOT_ENTER_DIRECTORY,url.path());
+ return;
+ }
+ if( newArchiveURL && !initDirDict(url) ){
+ error(ERR_CANNOT_ENTER_DIRECTORY,url.path());
+ return;
+ }
+
+ UDSEntry* entry = findFileEntry(url);
+ if( copyCmd.isEmpty() || !entry )
+ break;
+
+ QString file = url.path().mid(arcFile->url().path().length()+1);
+
+ QString destDir = dest.path( -1 );
+ if( !QDir( destDir ).exists() ) {
+ int ndx = destDir.findRev( '/' );
+ if( ndx != -1 )
+ destDir.truncate( ndx+1 );
+ }
+
+ QDir::setCurrent( destDir.local8Bit() );
+
+ KrShellProcess proc;
+ proc << copyCmd << convertName( arcFile->url().path(-1) )+" " << convertFileName( file );
+ if( arcType == "ace" && QFile( "/dev/ptmx" ).exists() ) // Don't remove, unace crashes if missing!!!
+ proc << "<" << "/dev/ptmx";
+
+ infoMessage(i18n("Unpacking %1 ...").arg( url.fileName() ) );
+ proc.start(KProcess::Block, KProcess::AllOutput);
+ if( !proc.normalExit() || !checkStatus( proc.exitStatus() ) ) {
+ error(KIO::ERR_COULD_NOT_WRITE, dest.path(-1) + "\n\n" + proc.getErrorMsg() );
+ return;
+ }
+ if( !QFileInfo( dest.path(-1) ).exists() ) {
+ error( KIO::ERR_COULD_NOT_WRITE, dest.path(-1) );
+ return;
+ }
+
+ processedSize( KFileItem(*entry,url).size() );
+ finished();
+ QDir::setCurrent( "/" ); /* for being able to umount devices after copying*/
+ return;
+ }while( 0 );
+
+ error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_COPY));
+}
+
+void kio_krarcProtocol::listDir(const KURL& url){
+ KRDEBUG(url.path());
+ if( !setArcFile( url ) ) {
+ error(ERR_CANNOT_ENTER_DIRECTORY,url.path());
+ return;
+ }
+ if( listCmd.isEmpty() ){
+ error(ERR_UNSUPPORTED_ACTION,
+ i18n("Listing directories is not supported for %1 archives").arg(arcType) );
+ return;
+ }
+ QString path = url.path();
+ if( path.right(1) != "/" ) path = path+"/";
+
+ // it might be a real dir !
+ if( QFileInfo(path).exists() ){
+ if( QFileInfo(path).isDir() ){
+ KURL redir;
+ redir.setPath( url.path() );
+ redirection(redir);
+ finished();
+ } else { // maybe it's an archive !
+ error(ERR_IS_FILE,path);
+ }
+ return;
+ }
+ if( !initDirDict(url) ){
+ error( ERR_CANNOT_ENTER_DIRECTORY, url.path());
+ return;
+ }
+ QString arcDir = path.mid(arcFile->url().path().length());
+ arcDir.truncate(arcDir.findRev("/"));
+ if(arcDir.right(1) != "/") arcDir = arcDir+"/";
+
+ UDSEntryList* dirList = dirDict.find(arcDir);
+ if( dirList == 0 ){
+ error(ERR_CANNOT_ENTER_DIRECTORY,url.path());
+ return;
+ }
+ totalSize(dirList->size());
+ listEntries(*dirList);
+ finished();
+}
+
+bool kio_krarcProtocol::setArcFile(const KURL& url){
+ QString path = url.path();
+ time_t currTime = time( 0 );
+ archiveChanged = true;
+ newArchiveURL = true;
+ // is the file already set ?
+ if( arcFile && arcFile->url().path(-1) == path.left(arcFile->url().path(-1).length()) ){
+ newArchiveURL = false;
+ // Has it changed ?
+ KFileItem* newArcFile = new KFileItem(arcFile->url(),QString::null,arcFile->mode());
+ if( !newArcFile->cmp( *arcFile ) ){
+ delete arcFile;
+ password = QString::null;
+ extArcReady = false;
+ arcFile = newArcFile;
+ } else { // same old file
+ delete newArcFile;
+ archiveChanged = false;
+ if( encrypted && password.isNull() )
+ initArcParameters();
+ }
+ } else { // it's a new file...
+ extArcReady = false;
+ if( arcFile ){
+ delete arcFile;
+ password = QString::null;
+ arcFile = 0L;
+ }
+ QString newPath = path;
+ if(newPath.right(1) != "/") newPath = newPath+"/";
+ for(int pos=0; pos >= 0; pos = newPath.find("/",pos+1)){
+ QFileInfo qfi(newPath.left(pos));
+ if( qfi.exists() && !qfi.isDir() ){
+ KDE_struct_stat stat_p;
+ KDE_lstat(newPath.left(pos).local8Bit(),&stat_p);
+ arcFile = new KFileItem(KURL::fromPathOrURL( newPath.left(pos) ),QString::null,stat_p.st_mode);
+ break;
+ }
+ }
+ if( !arcFile ){
+ error( ERR_DOES_NOT_EXIST,path );
+ return false; // file not found
+ }
+ }
+
+ /* FIX: file change can only be detected if the timestamp between the two consequent
+ changes is more than 1s. If the archive is continuously changing (check: move files
+ inside the archive), krarc may erronously think, that the archive file is unchanged,
+ because the timestamp is the same as the previous one. This situation can only occur
+ if the modification time equals with the current time. While this condition is true,
+ we can say, that the archive is changing, so content reread is always necessary
+ during that period. */
+ if( archiveChanging )
+ archiveChanged = true;
+ archiveChanging = ( currTime == arcFile->time( UDS_MODIFICATION_TIME ) );
+
+ arcPath = arcFile->url().path(-1);
+ arcType = detectArchive( encrypted, arcPath );
+
+ if( arcType == "tbz" )
+ arcType = "bzip2";
+ else if( arcType == "tgz" )
+ arcType = "gzip";
+
+ if( arcType.isEmpty() ) {
+ arcType = arcFile->mimetype();
+ arcType = arcType.mid(arcType.findRev("-")+1);
+
+ if( arcType == "jar" )
+ arcType = "zip";
+ }
+
+ return initArcParameters();
+}
+
+bool kio_krarcProtocol::initDirDict(const KURL&url, bool forced){
+ // set the archive location
+ //if( !setArcFile(url.path()) ) return false;
+ // no need to rescan the archive if it's not changed
+ if( !archiveChanged && !forced ) return true;
+ extArcReady = false;
+
+ if( !setArcFile( url ) )
+ return false; /* if the archive was changed refresh the file information */
+
+ // write the temp file
+ KrShellProcess proc;
+ KTempFile temp( QString::null, "tmp" );
+ temp.setAutoDelete(true);
+ if( arcType != "bzip2" ){
+ if( arcType == "rpm" )
+ proc << listCmd << convertName( arcPath ) <<" > " << temp.name();
+ else
+ proc << listCmd << convertName( arcFile->url().path(-1) ) <<" > " << temp.name();
+ if( arcType == "ace" && QFile( "/dev/ptmx" ).exists() ) // Don't remove, unace crashes if missing!!!
+ proc << "<" << "/dev/ptmx";
+ proc.start(KProcess::Block,KProcess::AllOutput);
+ if( !proc.normalExit() || !checkStatus( proc.exitStatus() ) ) return false;
+ }
+ // clear the dir dictionary
+ dirDict.clear();
+
+ // add the "/" directory
+ UDSEntryList* root = new UDSEntryList();
+ dirDict.insert("/",root);
+ // and the "/" UDSEntry
+ UDSEntry entry;
+ UDSAtom atom;
+ atom.m_uds = UDS_NAME;
+ atom.m_str = ".";
+ entry.append(atom);
+ mode_t mode = parsePermString("drwxr-xr-x");
+ atom.m_uds = UDS_FILE_TYPE;
+ atom.m_long = mode & S_IFMT; // keep file type only
+ entry.append( atom );
+ atom.m_uds = UDS_ACCESS;
+ atom.m_long = mode & 07777; // keep permissions only
+ entry.append( atom );
+
+ root->append(entry);
+
+ if( arcType == "bzip2" ){
+ KRDEBUG("Got me here...");
+ parseLine(0,"",temp.file());
+ return true;
+ }
+
+ // parse the temp file
+ temp.file()->open(IO_ReadOnly);
+ char buf[1000];
+ QString line;
+
+ int lineNo = 0;
+ bool invalidLine = false;
+ // the rar list is started with a ------ line.
+ if(arcType == "rar" || arcType == "arj" || arcType == "lha" || arcType == "7z" ){
+ while(temp.file()->readLine(buf,1000) != -1){
+ line = QString::fromLocal8Bit(buf);
+ if( line.startsWith("----------") ) break;
+ }
+ }
+ while(temp.file()->readLine(buf,1000) != -1) {
+ line = QString::fromLocal8Bit(buf);
+ if( arcType == "rar" ) {
+ // the rar list is ended with a ------ line.
+ if( line.startsWith("----------") ) {
+ invalidLine = !invalidLine;
+ continue;
+ }
+ if( invalidLine )
+ continue;
+ else{
+ temp.file()->readLine(buf,1000);
+ line = line+QString::fromLocal8Bit(buf);
+ if( line[0]=='*' ) // encrypted archives starts with '*'
+ line[0]=' ';
+ }
+ }
+ if( arcType == "ace" ) {
+ // the ace list begins with a number.
+ if( !line[0].isDigit() ) continue;
+ }
+ if( arcType == "arj" ) {
+ // the arj list is ended with a ------ line.
+ if( line.startsWith("----------") ) {
+ invalidLine = !invalidLine;
+ continue;
+ }
+ if( invalidLine )
+ continue;
+ else {
+ temp.file()->readLine(buf,1000);
+ line = line+QString::fromLocal8Bit(buf);
+ temp.file()->readLine(buf,1000);
+ line = line+QString::fromLocal8Bit(buf);
+ temp.file()->readLine(buf,1000);
+ line = line+QString::fromLocal8Bit(buf);
+ }
+ }
+ if( arcType == "lha" || arcType == "7z" ) {
+ // the arj list is ended with a ------ line.
+ if( line.startsWith("----------") ) break;
+ }
+ parseLine(lineNo++,line.stripWhiteSpace(),temp.file());
+ }
+ // close and delete our file
+ temp.file()->close();
+
+ archiveChanged = false;
+ return true;
+}
+
+QString kio_krarcProtocol::findArcDirectory(const KURL& url){
+ QString path = url.path();
+ if( path.right(1) == "/" ) path.truncate(path.length()-1);
+
+ if( !initDirDict(url) ){
+ return QString::null;
+ }
+ QString arcDir = path.mid(arcFile->url().path().length());
+ arcDir.truncate(arcDir.findRev("/"));
+ if(arcDir.right(1) != "/") arcDir = arcDir+"/";
+
+ return arcDir;
+}
+
+UDSEntry* kio_krarcProtocol::findFileEntry(const KURL& url){
+ QString arcDir = findArcDirectory(url);
+ if( arcDir.isEmpty() ) return 0;
+
+ UDSEntryList* dirList = dirDict.find(arcDir);
+ if( !dirList ){
+ return 0;
+ }
+ QString name = url.path();
+ if( arcFile->url().path(-1) == url.path(-1) ) name = "."; // the "/" case
+ else{
+ if( name.right(1) == "/" ) name.truncate(name.length()-1);
+ name = name.mid(name.findRev("/")+1);
+ }
+
+ UDSEntryList::iterator entry;
+ UDSEntry::iterator atom;
+
+ for ( entry = dirList->begin(); entry != dirList->end(); ++entry ){
+ for( atom = (*entry).begin(); atom != (*entry).end(); ++atom ){
+ if( (*atom).m_uds == UDS_NAME ){
+ if((*atom).m_str == name){
+ return &(*entry);
+ } else break;
+ }
+ }
+ }
+ return 0;
+}
+
+QString kio_krarcProtocol::nextWord(QString &s,char d) {
+ s=s.stripWhiteSpace();
+ int j=s.find(d,0);
+ QString temp=s.left(j); // find the leftmost word.
+ s.remove(0,j);
+ return temp;
+}
+
+mode_t kio_krarcProtocol::parsePermString(QString perm){
+ mode_t mode=0;
+ // file type
+ if(perm[0] == 'd') mode |= S_IFDIR;
+ if(perm[0] == 'l') mode |= S_IFLNK;
+ if(perm[0] == '-') mode |= S_IFREG;
+ // owner permissions
+ if(perm[1] != '-') mode |= S_IRUSR;
+ if(perm[2] != '-') mode |= S_IWUSR;
+ if(perm[3] != '-') mode |= S_IXUSR;
+ // group permissions
+ if(perm[4] != '-') mode |= S_IRGRP;
+ if(perm[5] != '-') mode |= S_IWGRP;
+ if(perm[6] != '-') mode |= S_IXGRP;
+ // other permissions
+ if(perm[7] != '-') mode |= S_IROTH;
+ if(perm[8] != '-') mode |= S_IWOTH;
+ if(perm[9] != '-') mode |= S_IXOTH;
+
+ return mode;
+}
+
+UDSEntryList* kio_krarcProtocol::addNewDir(QString path){
+ UDSEntryList* dir;
+
+ // check if the current dir exists
+ dir = dirDict.find(path);
+ if(dir != 0) return dir; // dir exists- return it !
+
+ // set dir to the parent dir
+ dir = addNewDir(path.left(path.findRev("/",-2)+1));
+
+ // add a new entry in the parent dir
+ QString name = path.mid(path.findRev("/",-2)+1);
+ name = name.left(name.length()-1);
+
+ UDSEntry entry;
+ UDSAtom atom;
+ atom.m_uds = UDS_NAME;
+ atom.m_str = name;
+ entry.append(atom);
+
+ mode_t mode = parsePermString("drwxr-xr-x");
+
+ atom.m_uds = UDS_FILE_TYPE;
+ atom.m_long = mode & S_IFMT; // keep file type only
+ entry.append( atom );
+
+ atom.m_uds = UDS_ACCESS;
+ atom.m_long = mode & 07777; // keep permissions only
+ entry.append( atom );
+
+ atom.m_uds = UDS_SIZE;
+ atom.m_long = 0;
+ entry.append( atom );
+
+ atom.m_uds = UDS_MODIFICATION_TIME;
+ atom.m_long = arcFile->time(UDS_MODIFICATION_TIME);
+ entry.append( atom );
+
+ dir->append(entry);
+
+ // create a new directory entry and add it..
+ dir = new UDSEntryList();
+ dirDict.insert(path,dir);
+
+ return dir;
+}
+
+void kio_krarcProtocol::parseLine(int lineNo, QString line, QFile*) {
+ UDSEntryList* dir;
+ UDSEntry entry;
+ UDSAtom atom;
+
+ QString owner = QString::null;
+ QString group = QString::null;
+ QString symlinkDest = QString::null;
+ QString perm = QString::null;
+ mode_t mode = 0666;
+ size_t size = 0;
+ time_t time = ::time(0);
+ QString fullName = QString::null;
+
+ if(arcType == "zip"){
+ // permissions
+ perm = nextWord(line);
+ // ignore the next 2 fields
+ nextWord(line); nextWord(line);
+ // size
+ size = nextWord(line).toLong();
+ // ignore the next 2 fields
+ nextWord(line);nextWord(line);
+ // date & time
+ QString d = nextWord(line);
+ QDate qdate(d.mid(0,4).toInt(),d.mid(4,2).toInt(),d.mid(6,2).toInt());
+ QTime qtime(d.mid(9,2).toInt(),d.mid(11,2).toInt(),d.mid(13,2).toInt());
+ time = QDateTime(qdate,qtime).toTime_t();
+ // full name
+ fullName = nextWord(line,'\n');
+
+ if(perm.length() != 10)
+ perm = (perm.at(0)=='d' || fullName.endsWith( "/" )) ? "drwxr-xr-x" : "-rw-r--r--" ;
+ mode = parsePermString(perm);
+ }
+ if(arcType == "rar") {
+ // full name
+ fullName = nextWord(line,'\n');
+ // size
+ size = nextWord(line).toLong();
+ // ignore the next 2 fields
+ nextWord(line); nextWord(line);
+ // date & time
+ QString d = nextWord(line);
+ int year = 1900 + d.mid(6,2).toInt();
+ if( year < 1930 ) year+=100;
+ QDate qdate( year, d.mid(3,2).toInt(), d.mid(0,2).toInt() );
+ QString t = nextWord(line);
+ QTime qtime(t.mid(0,2).toInt(),t.mid(3,2).toInt(),0);
+ time = QDateTime(qdate,qtime).toTime_t();
+ // permissions
+ perm = nextWord(line);
+
+ if( perm.length() == 7 ) // windows rar permission format
+ {
+ bool isDir = ( perm.at(1).lower() == 'd' );
+ bool isReadOnly = ( perm.at(2).lower() == 'r' );
+
+ perm = isDir ? "drwxr-xr-x" : "-rw-r--r--";
+
+ if( isReadOnly )
+ perm.at( 2 ) = '-';
+ }
+
+ if(perm.length() != 10) perm = (perm.at(0)=='d')? "drwxr-xr-x" : "-rw-r--r--" ;
+ mode = parsePermString(perm);
+ }
+ if(arcType == "arj"){
+ nextWord(line);
+ // full name
+ fullName = nextWord(line,'\n');
+ // ignore the next 2 fields
+ nextWord(line); nextWord(line);
+ // size
+ size = nextWord(line).toLong();
+ // ignore the next 2 fields
+ nextWord(line); nextWord(line);
+ // date & time
+ QString d = nextWord(line);
+ int year = 1900 + d.mid(0,2).toInt();
+ if( year < 1930 ) year+=100;
+ QDate qdate( year, d.mid(3,2).toInt(), d.mid(6,2).toInt() );
+ QString t = nextWord(line);
+ QTime qtime(t.mid(0,2).toInt(),t.mid(3,2).toInt(),0);
+ time = QDateTime(qdate,qtime).toTime_t();
+ // permissions
+ perm = nextWord(line);
+ if(perm.length() != 10) perm = (perm.at(0)=='d')? "drwxr-xr-x" : "-rw-r--r--" ;
+ mode = parsePermString(perm);
+ }
+ if(arcType == "rpm"){
+ // full name
+ fullName = nextWord(line);
+ // size
+ size = nextWord(line).toULong();
+ // date & time
+ time = nextWord(line).toULong();
+ // next field is md5sum, ignore it
+ nextWord(line);
+ // permissions
+ mode = nextWord(line).toULong(0,8);
+ // Owner & Group
+ owner = nextWord(line);
+ group = nextWord(line);
+ // symlink destination
+ if( S_ISLNK(mode) ){
+ // ignore the next 3 fields
+ nextWord(line); nextWord(line); nextWord(line);
+ symlinkDest = nextWord(line);
+ }
+ }
+ if( arcType == "gzip" ){
+ if( !lineNo ) return; //ignore the first line
+ // first field is uncompressed size - ignore it
+ nextWord(line);
+ // size
+ size = nextWord(line).toULong();
+ // ignore the next field
+ nextWord(line);
+ // full name
+ fullName = nextWord(line);
+ fullName = fullName.mid(fullName.findRev("/")+1);
+ }
+ if( arcType == "bzip2" ){
+ // There is no way to list bzip2 files, so we take our information from
+ // the archive itself...
+ fullName = arcFile->name();
+ if( fullName.endsWith("bz2") ) fullName.truncate(fullName.length()-4);
+ mode = arcFile->mode();
+ size = arcFile->size();
+ }
+ if(arcType == "lha"){
+ // permissions
+ perm = nextWord(line);
+ if(perm.length() != 10) perm = (perm.at(0)=='d')? "drwxr-xr-x" : "-rw-r--r--" ;
+ mode = parsePermString(perm);
+ // ignore the next field
+ nextWord(line);
+ // size
+ size = nextWord(line).toLong();
+ // ignore the next field
+ nextWord(line);
+ // date & time
+ int month = (QStringList::split(',', "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec")).findIndex( nextWord(line) ) + 1;
+ int day = nextWord(line).toInt();
+ int year = QDate::currentDate().year();
+ QString third = nextWord(line);
+ QTime qtime;
+
+ if( third.contains(":" ) )
+ qtime = QTime::fromString( third );
+ else
+ year = third.toInt();
+
+ QDate qdate(year, month, day );
+
+ time = QDateTime(qdate, qtime).toTime_t();
+ // full name
+ fullName = nextWord(line,'\n');
+ }
+ if(arcType == "ace"){
+ // date & time
+ QString d = nextWord(line);
+ int year = 1900 + d.mid(6,2).toInt();
+ if( year < 1930 ) year+=100;
+ QDate qdate( year, d.mid(3,2).toInt(), d.mid(0,2).toInt() );
+ QString t = nextWord(line);
+ QTime qtime(t.mid(0,2).toInt(),t.mid(3,2).toInt(),0);
+ time = QDateTime(qdate,qtime).toTime_t();
+ // ignore the next field
+ nextWord(line);
+ // size
+ size = nextWord(line).toLong();
+ // ignore the next field
+ nextWord(line);
+ // full name
+ fullName = nextWord(line,'\n');
+ if( fullName[ 0 ] == '*' ) // encrypted archives starts with '*'
+ fullName = fullName.mid( 1 );
+ }
+ if( arcType == "deb" ){
+ // permissions
+ perm = nextWord( line );
+ mode = parsePermString( perm );
+ // Owner & Group
+ owner = nextWord( line,'/' );
+ group = nextWord( line ).mid(1);
+ // size
+ size = nextWord( line ).toLong();
+ // date & time
+ QString d = nextWord( line );
+ QDate qdate( d.mid( 0, 4 ).toInt(), d.mid( 5, 2 ).toInt(), d.mid( 8, 2 ).toInt() );
+ QString t = nextWord( line );
+ QTime qtime( t.mid( 0, 2 ).toInt(), t.mid( 3, 2 ).toInt(), 0 );
+ time = QDateTime( qdate, qtime ).toTime_t();
+ // full name
+ fullName = nextWord( line, '\n' ).mid( 1 );
+ //if ( fullName.right( 1 ) == "/" ) return;
+ if( fullName.contains("->") ){
+ symlinkDest = fullName.mid(fullName.find("->")+2);
+ fullName = fullName.left(fullName.find("->")-1);
+ }
+ }
+ if(arcType == "7z"){
+ // date & time
+ QString d = nextWord(line);
+ QDate qdate( d.mid(0,4).toInt(), d.mid(5,2).toInt(), d.mid(8,2).toInt() );
+ QString t = nextWord(line);
+ QTime qtime(t.mid(0,2).toInt(),t.mid(3,2).toInt(),t.mid(6,2).toInt() );
+ time = QDateTime(qdate,qtime).toTime_t();
+
+ // permissions
+ perm = nextWord(line);
+ bool isDir = ( perm.at(0).lower() == 'd' );
+ bool isReadOnly = ( perm.at(1).lower() == 'r' );
+ perm = isDir ? "drwxr-xr-x" : "-rw-r--r--";
+ if( isReadOnly )
+ perm.at( 2 ) = '-';
+
+ mode = parsePermString(perm);
+
+ // size
+ size = nextWord(line).toLong();
+
+ // ignore the next 15 characters
+ line = line.mid( 15 );
+
+ // full name
+ fullName = nextWord(line,'\n');
+ }
+
+ if( fullName.right(1) == "/" ) fullName = fullName.left(fullName.length()-1);
+ if( !fullName.startsWith("/") ) fullName = "/"+fullName;
+ QString path = fullName.left(fullName.findRev("/")+1);
+ // set/create the directory UDSEntryList
+ dir = dirDict.find(path);
+ if(dir == 0) dir = addNewDir(path);
+ QString name = fullName.mid(fullName.findRev("/")+1);
+ // file name
+ atom.m_uds = UDS_NAME;
+ atom.m_str = name;
+ entry.append(atom);
+ // file type
+ atom.m_uds = UDS_FILE_TYPE;
+ atom.m_long = mode & S_IFMT; // keep file type only
+ entry.append( atom );
+ // file permissions
+ atom.m_uds = UDS_ACCESS;
+ atom.m_long = mode & 07777; // keep permissions only
+ entry.append( atom );
+ // file size
+ atom.m_uds = UDS_SIZE;
+ atom.m_long = size;
+ entry.append( atom );
+ // modification time
+ atom.m_uds = UDS_MODIFICATION_TIME;
+ atom.m_long = time;
+ entry.append( atom );
+ // link destination
+ if( !symlinkDest.isEmpty() ){
+ atom.m_uds = UDS_LINK_DEST;
+ atom.m_str = symlinkDest;
+ entry.append( atom );
+ }
+ if( S_ISDIR(mode) ){
+ fullName=fullName+"/";
+ if(dirDict.find(fullName) == 0)
+ dirDict.insert(fullName,new UDSEntryList());
+ else {
+ // try to overwrite an existing entry
+ UDSEntryList::iterator entryIt;
+ UDSEntry::iterator atomIt;
+
+ for ( entryIt = dir->begin(); entryIt != dir->end(); ++entryIt )
+ for( atomIt = (*entryIt).begin(); atomIt != (*entryIt).end(); ++atomIt )
+ if( (*atomIt).m_uds == UDS_NAME )
+ if((*atomIt).m_str == name) {
+ for( atomIt = (*entryIt).begin(); atomIt != (*entryIt).end(); ++atomIt ) {
+ switch( (*atomIt).m_uds ) {
+ case UDS_MODIFICATION_TIME:
+ (*atomIt).m_long = time;
+ break;
+ case UDS_ACCESS:
+ (*atomIt).m_long = mode & 07777;
+ break;
+ }
+ }
+ return;
+ }
+ return; // there is alreay an entry for this directory
+ }
+ }
+
+ // multi volume archives can add a file twice, use only one
+ UDSEntryList::iterator dirEntryIt;
+ UDSEntry::iterator dirAtomIt;
+ for ( dirEntryIt = dir->begin(); dirEntryIt != dir->end(); ++dirEntryIt )
+ for( dirAtomIt = (*dirEntryIt).begin(); dirAtomIt != (*dirEntryIt).end(); ++dirAtomIt )
+ if( (*dirAtomIt).m_uds == UDS_NAME && (*dirAtomIt).m_str == name )
+ return;
+
+ dir->append(entry);
+}
+
+bool kio_krarcProtocol::initArcParameters() {
+ KRDEBUG("arcType: "<<arcType);
+
+ if(arcType == "zip"){
+ cmd = fullPathName( "unzip" );
+ listCmd = fullPathName( "unzip" ) + " -ZTs-z-t-h ";
+ getCmd = fullPathName( "unzip" ) + " -p ";
+ copyCmd = fullPathName( "unzip" ) + " -jo ";
+
+ if( KStandardDirs::findExe( "zip" ).isEmpty() ) {
+ delCmd = QString::null;
+ putCmd = QString::null;
+ } else {
+ delCmd = fullPathName( "zip" ) + " -d ";
+ putCmd = fullPathName( "zip" ) + " -ry ";
+ }
+
+ if( !getPassword().isEmpty() ) {
+ getCmd += "-P '"+password+"' ";
+ copyCmd += "-P '"+password+"' ";
+ putCmd += "-P '"+password+"' ";
+ }
+ } else if (arcType == "rar") {
+ if( KStandardDirs::findExe( "rar" ).isEmpty() ) {
+ cmd = fullPathName( "unrar" );
+ listCmd = fullPathName( "unrar" ) + " -c- -v v ";
+ getCmd = fullPathName( "unrar" ) + " p -ierr -idp -c- -y ";
+ copyCmd = fullPathName( "unrar" ) + " e -y ";
+ delCmd = QString::null;
+ putCmd = QString::null;
+ } else {
+ cmd = fullPathName( "rar" );
+ listCmd = fullPathName( "rar" ) + " -c- -v v ";
+ getCmd = fullPathName( "rar" ) + " p -ierr -idp -c- -y ";
+ copyCmd = fullPathName( "rar" ) + " e -y ";
+ delCmd = fullPathName( "rar" ) + " d ";
+ putCmd = fullPathName( "rar" ) + " -r a ";
+ }
+ if( !getPassword().isEmpty() ) {
+ getCmd += "-p'"+password+"' ";
+ listCmd += "-p'"+password+"' ";
+ copyCmd += "-p'"+password+"' ";
+ if( !putCmd.isEmpty() ) {
+ putCmd += "-p'"+password+"' ";
+ delCmd += "-p'"+password+"' ";
+ }
+ }
+ } else if(arcType == "rpm") {
+ cmd = fullPathName( "rpm" );
+ listCmd = fullPathName( "rpm" ) + " --dump -lpq ";
+ getCmd = fullPathName( "cpio" ) + " --force-local --no-absolute-filenames -iuvdF";
+ delCmd = QString::null;
+ putCmd = QString::null;
+ copyCmd = QString::null;
+ } else if(arcType == "gzip") {
+ cmd = fullPathName( "gzip" );
+ listCmd = fullPathName( "gzip" ) + " -l";
+ getCmd = fullPathName( "gzip" ) + " -dc";
+ copyCmd = QString::null;
+ delCmd = QString::null;
+ putCmd = QString::null;
+ } else if(arcType == "bzip2") {
+ cmd = fullPathName( "bzip2" );
+ listCmd = fullPathName( "bzip2" );
+ getCmd = fullPathName( "bzip2" ) + " -dc";
+ copyCmd = QString::null;
+ delCmd = QString::null;
+ putCmd = QString::null;
+ } else if(arcType == "arj"){
+ cmd = fullPathName( "arj" );
+ listCmd = fullPathName( "arj" ) + " v -y -v ";
+ getCmd = fullPathName( "arj" ) + " -jyov -v e ";
+ copyCmd = fullPathName( "arj" ) + " -jyov -v e ";
+ delCmd = fullPathName( "arj" ) + " d ";
+ putCmd = fullPathName( "arj" ) + " -r a ";
+ if( !getPassword().isEmpty() ) {
+ getCmd += "-g'"+password+"' ";
+ copyCmd += "-g'"+password+"' ";
+ putCmd += "-g'"+password+"' ";
+ }
+ } else if(arcType == "lha") {
+ cmd = fullPathName( "lha" );
+ listCmd = fullPathName( "lha" ) + " l ";
+ getCmd = fullPathName( "lha" ) + " pq ";
+ copyCmd = fullPathName( "lha" ) + " eif ";
+ delCmd = fullPathName( "lha" ) + " d ";
+ putCmd = fullPathName( "lha" ) + " a ";
+ } else if(arcType == "ace") {
+ cmd = fullPathName( "unace" );
+ listCmd = fullPathName( "unace" ) + " v";
+ getCmd = fullPathName( "unace" ) + " e -o ";
+ copyCmd = fullPathName( "unace" ) + " e -o ";
+ delCmd = QString::null;
+ putCmd = QString::null;
+ if( !getPassword().isEmpty() ) {
+ getCmd += "-p'"+password+"' ";
+ copyCmd += "-p'"+password+"' ";
+ }
+ } else if ( arcType == "deb" ) {
+ cmd = fullPathName("dpkg");
+ listCmd = fullPathName("dpkg")+" -c";
+ getCmd = fullPathName("tar")+" xvf ";
+ copyCmd = QString::null;
+ delCmd = QString::null;
+ putCmd = QString::null;
+ } else if (arcType == "7z") {
+ cmd = fullPathName( "7z" );
+ if( KStandardDirs::findExe(cmd).isEmpty() )
+ cmd = fullPathName( "7za" );
+
+ listCmd = cmd + " l -y ";
+ getCmd = cmd + " e -y ";
+ copyCmd = cmd + " e -y ";
+ delCmd = cmd + " d -y ";
+ putCmd = cmd + " a -y ";
+ if( !getPassword().isEmpty() ) {
+ getCmd += "-p'"+password+"' ";
+ listCmd += "-p'"+password+"' ";
+ copyCmd += "-p'"+password+"' ";
+ if( !putCmd.isEmpty() ) {
+ putCmd += "-p'"+password+"' ";
+ delCmd += "-p'"+password+"' ";
+ }
+ }
+ }
+ else {
+ cmd = QString::null;
+ listCmd = QString::null;
+ getCmd = QString::null;
+ copyCmd = QString::null;
+ delCmd = QString::null;
+ putCmd = QString::null;
+ }
+
+ if( KStandardDirs::findExe(cmd).isEmpty() ){
+ error( KIO::ERR_CANNOT_LAUNCH_PROCESS,
+ cmd+
+ i18n("\nMake sure that the %1 binary are installed properly on your system.").arg(cmd));
+ KRDEBUG("Failed to find cmd: " << cmd);
+ return false;
+ }
+ return true;
+}
+
+bool kio_krarcProtocol::checkStatus( int exitCode ) {
+ KRDEBUG( exitCode );
+
+ if( arcType == "zip" || arcType == "rar" || arcType == "7z" )
+ return exitCode == 0 || exitCode == 1;
+ else if( arcType == "ace" || arcType == "bzip2" || arcType == "lha" || arcType == "rpm" || arcType == "arj" )
+ return exitCode == 0;
+ else if( arcType == "gzip" )
+ return exitCode == 0 || exitCode == 2;
+ else
+ return exitCode == 0;
+}
+
+struct AutoDetectParams {
+ QString type;
+ int location;
+ QString detectionString;
+};
+
+QString kio_krarcProtocol::detectArchive( bool &encrypted, QString fileName ) {
+ static AutoDetectParams autoDetectParams[] = {{"zip", 0, "PK\x03\x04"},
+ {"rar", 0, "Rar!\x1a" },
+ {"arj", 0, "\x60\xea" },
+ {"rpm", 0, "\xed\xab\xee\xdb"},
+ {"ace", 7, "**ACE**" },
+ {"bzip2",0, "\x42\x5a\x68\x39\x31" },
+ {"gzip", 0, "\x1f\x8b"},
+ {"deb", 0, "!<arch>\ndebian-binary " },
+ {"7z", 0, "7z\xbc\xaf\x27\x1c" } };
+ static int autoDetectElems = sizeof( autoDetectParams ) / sizeof( AutoDetectParams );
+
+ encrypted = false;
+
+ QFile arcFile( fileName );
+ if ( arcFile.open( IO_ReadOnly ) ) {
+ char buffer[ 1024 ];
+ long sizeMax = arcFile.readBlock( buffer, sizeof( buffer ) );
+ arcFile.close();
+
+ for( int i=0; i < autoDetectElems; i++ ) {
+ QString detectionString = autoDetectParams[ i ].detectionString;
+ int location = autoDetectParams[ i ].location;
+
+ int endPtr = detectionString.length() + location;
+ if( endPtr > sizeMax )
+ continue;
+
+ unsigned int j=0;
+ for(; j != detectionString.length(); j++ ) {
+ if( detectionString[ j ] == '?' )
+ continue;
+ if( buffer[ location + j ] != detectionString[ j ] )
+ break;
+ }
+
+ if( j == detectionString.length() ) {
+ QString type = autoDetectParams[ i ].type;
+ if( type == "bzip2" || type == "gzip" ) {
+ KTar tapeArchive( fileName );
+ if( tapeArchive.open( IO_ReadOnly ) ) {
+ tapeArchive.close();
+ if( type == "bzip2" )
+ type = "tbz";
+ else
+ type = "tgz";
+ }
+ }
+ else if( type == "zip" )
+ encrypted = (buffer[6] & 1);
+ else if( type == "arj" ) {
+ if( sizeMax > 4 ) {
+ long headerSize = ((unsigned char *)buffer)[ 2 ] + 256*((unsigned char *)buffer)[ 3 ];
+ long fileHeader = headerSize + 10;
+ if( fileHeader + 9 < sizeMax && buffer[ fileHeader ] == (char)0x60 && buffer[ fileHeader + 1 ] == (char)0xea )
+ encrypted = (buffer[ fileHeader + 8 ] & 1 );
+ }
+ }
+ else if( type == "rar" ) {
+ if( sizeMax > 13 && buffer[ 9 ] == (char)0x73 ) {
+ if( buffer[ 10 ] & 0x80 ) { // the header is encrypted?
+ encrypted = true;
+ } else {
+ long offset = 7;
+ long mainHeaderSize = ((unsigned char *)buffer)[ offset+5 ] + 256*((unsigned char *)buffer)[ offset+6 ];
+ offset += mainHeaderSize;
+ while( offset + 10 < sizeMax ) {
+ long headerSize = ((unsigned char *)buffer)[ offset+5 ] + 256*((unsigned char *)buffer)[ offset+6 ];
+ bool isDir = (buffer[ offset+7 ] == '\0' ) && (buffer[ offset+8 ] == '\0' ) &&
+ (buffer[ offset+9 ] == '\0' ) && (buffer[ offset+10 ] == '\0' );
+
+ if( buffer[ offset + 2 ] != (char)0x74 )
+ break;
+ if( !isDir ) {
+ encrypted = ( buffer[ offset + 3 ] & 4 ) != 0;
+ break;
+ }
+ offset += headerSize;
+ }
+ }
+ }
+ }
+ else if( type == "ace" ) {
+ long offset = 0;
+ long mainHeaderSize = ((unsigned char *)buffer)[ offset+2 ] + 256*((unsigned char *)buffer)[ offset+3 ] + 4;
+ offset += mainHeaderSize;
+ while( offset + 10 < sizeMax ) {
+ long headerSize = ((unsigned char *)buffer)[ offset+2 ] + 256*((unsigned char *)buffer)[ offset+3 ] + 4;
+ bool isDir = (buffer[ offset+11 ] == '\0' ) && (buffer[ offset+12 ] == '\0' ) &&
+ (buffer[ offset+13 ] == '\0' ) && (buffer[ offset+14 ] == '\0' );
+
+ if( buffer[ offset + 4 ] != (char)0x01 )
+ break;
+ if( !isDir ) {
+ encrypted = ( buffer[ offset + 6 ] & 64 ) != 0;
+ break;
+ }
+ offset += headerSize;
+ }
+ }
+ else if( type == "7z" ) {
+ if( encryptedArchPath == fileName )
+ encrypted = true;
+ else { // we try to find whether the 7z archive is encrypted
+ // this is hard as the headers are also compresseds
+ QString tester = fullPathName( "7z" );
+ if( KStandardDirs::findExe( tester ).isEmpty() ) {
+ tester = fullPathName( "7za" );
+ if( KStandardDirs::findExe( tester ).isEmpty() ) {
+ return type;
+ }
+ }
+
+ QString testCmd = tester + " t -y ";
+ lastData = encryptedArchPath = "";
+
+ KrShellProcess proc;
+ proc << testCmd << convertName( fileName );
+ connect( &proc, SIGNAL( receivedStdout(KProcess*,char*,int) ),
+ this, SLOT( checkOutputForPassword( KProcess*,char*,int ) ) );
+ proc.start(KProcess::Block,KProcess::AllOutput);
+ encrypted = this->encrypted;
+
+ if( encrypted )
+ encryptedArchPath = fileName;
+ }
+ }
+ return type;
+ }
+ }
+
+ if( sizeMax >= 512 ) {
+ /* checking if it's a tar file */
+ unsigned checksum = 32*8;
+ char chksum[ 9 ];
+ for( int i=0; i != 512; i++ )
+ checksum += ((unsigned char *)buffer)[ i ];
+ for( int i=148; i != 156; i++ )
+ checksum -= ((unsigned char *)buffer)[ i ];
+ sprintf( chksum, "0%o", checksum );
+ if( !memcmp( buffer + 148, chksum, strlen( chksum ) ) ) {
+ int k = strlen( chksum );
+ for(; k < 8; k++ )
+ if( buffer[148+k] != 0 && buffer[148+k] != 32 )
+ break;
+ if( k==8 )
+ return "tar";
+ }
+ }
+ }
+ return QString::null;
+}
+
+void kio_krarcProtocol::checkOutputForPassword( KProcess *proc,char *buf,int len ) {
+ QByteArray d(len);
+ d.setRawData(buf,len);
+ QString data = QString( d );
+ d.resetRawData(buf,len);
+
+ QString checkable = lastData + data;
+
+ QStringList lines = QStringList::split( '\n', checkable );
+ lastData = lines[ lines.count() - 1 ];
+ for( unsigned i=0; i != lines.count(); i++ ) {
+ QString line = lines[ i ].stripWhiteSpace().lower();
+ int ndx = line.find( "testing" );
+ if( ndx >=0 )
+ line.truncate( ndx );
+ if( line.isEmpty() )
+ continue;
+
+ if( line.contains( "password" ) && line.contains( "enter" ) ) {
+ KRDEBUG( "Encrypted 7z archive found!" );
+ encrypted = true;
+ proc->kill();
+ }
+ }
+}
+
+void kio_krarcProtocol::invalidatePassword() {
+ KRDEBUG( arcFile->url().path(-1) + "/" );
+
+ if( !encrypted )
+ return;
+
+ KIO::AuthInfo authInfo;
+ authInfo.caption= i18n( "Krarc Password Dialog" );
+ authInfo.username= "archive";
+ authInfo.readOnly = true;
+ authInfo.keepPassword = true;
+ authInfo.verifyPath = true;
+ QString fileName = arcFile->url().path(-1);
+ authInfo.url = KURL::fromPathOrURL( "/" );
+ authInfo.url.setHost( fileName /*.replace('/','_')*/ );
+ authInfo.url.setProtocol( "krarc" );
+
+ password = QString::null;
+
+ cacheAuthentication( authInfo );
+}
+
+QString kio_krarcProtocol::getPassword() {
+ KRDEBUG( encrypted );
+
+ if( !password.isNull() )
+ return password;
+ if( !encrypted )
+ return (password = "" );
+
+ KIO::AuthInfo authInfo;
+ authInfo.caption= i18n( "Krarc Password Dialog" );
+ authInfo.username= "archive";
+ authInfo.readOnly = true;
+ authInfo.keepPassword = true;
+ authInfo.verifyPath = true;
+ QString fileName = arcFile->url().path(-1);
+ authInfo.url = KURL::fromPathOrURL( "/" );
+ authInfo.url.setHost( fileName /*.replace('/','_')*/ );
+ authInfo.url.setProtocol( "krarc" );
+
+ if( checkCachedAuthentication( authInfo ) && !authInfo.password.isNull() ) {
+ KRDEBUG( authInfo.password );
+ return ( password = authInfo.password );
+ }
+
+ authInfo.password = QString::null;
+
+ if ( openPassDlg( authInfo, i18n("Accessing the file requires password.") ) && !authInfo.password.isNull() ) {
+ KRDEBUG( authInfo.password );
+ return ( password = authInfo.password );
+ }
+
+ KRDEBUG( password );
+ return password;
+}
+
+QString kio_krarcProtocol::fullPathName( QString name ) {
+ QString supposedName = krConfig->readEntry( name, name );
+ if( supposedName.isEmpty() )
+ supposedName = name;
+ return escape( supposedName );
+}
+
+QString kio_krarcProtocol::convertFileName( QString name ) {
+ if( arcType == "zip" )
+ name = name.replace( "[", "[[]" );
+ return convertName( name );
+}
+
+QString kio_krarcProtocol::convertName( QString name ) {
+ if( !name.contains( '\'' ) )
+ return "'" + name + "'";
+ if( !name.contains( '"' ) && !name.contains( '$' ) )
+ return "\"" + name + "\"";
+ return escape( name );
+}
+
+QString kio_krarcProtocol::escape( QString name ) {
+ const QString evilstuff = "\\\"'`()[]{}!?;$&<>| "; // stuff that should get escaped
+
+ for ( unsigned int i = 0; i < evilstuff.length(); ++i )
+ name.replace( evilstuff[ i ], ('\\' + evilstuff[ i ]) );
+
+ return name;
+}
+
+#include "krarc.moc"