diff options
Diffstat (limited to 'src/app/VFS')
29 files changed, 6998 insertions, 0 deletions
diff --git a/src/app/VFS/Makefile.am b/src/app/VFS/Makefile.am new file mode 100644 index 0000000..63ef663 --- /dev/null +++ b/src/app/VFS/Makefile.am @@ -0,0 +1,19 @@ +noinst_LIBRARIES = libVFS.a + +INCLUDES = $(all_includes) + +libVFS_a_METASOURCES = AUTO + +libVFS_a_SOURCES = \ + krvfshandler.cpp \ + virt_vfs.cpp \ + vfs.cpp \ + vfile.cpp \ + temp_vfs.cpp \ + normal_vfs.cpp \ + krpermhandler.cpp \ + krdirwatch.cpp \ + krarchandler.cpp \ + preservingcopyjob.cpp \ + virtualcopyjob.cpp \ + ftp_vfs.cpp krquery.cpp diff --git a/src/app/VFS/arc_vfs.cpp b/src/app/VFS/arc_vfs.cpp new file mode 100644 index 0000000..4af6c74 --- /dev/null +++ b/src/app/VFS/arc_vfs.cpp @@ -0,0 +1,866 @@ +/*************************************************************************** + arc_vfs.cpp + ------------------- + copyright : (C) 2000 by Shie Erlich & Rafi Yanai + e-mail : krusader@users.sourceforge.net + web site : http://krusader.sourceforge.net + --------------------------------------------------------------------------- + Description + *************************************************************************** + + A + + db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. + 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D + 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' + 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b + 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. + YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD + + S o u r c e F i l e + + *************************************************************************** + * * + * 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 <unistd.h> +#include <sys/param.h> +#include <sys/types.h> +#include <dirent.h> +#include <time.h> +// TQt includes +#include <tqregexp.h> +#include <tqdir.h> +#include <tqdatetime.h> +#include <tqfileinfo.h> +// TDE includes +#include <tdemessagebox.h> +#include <tdelocale.h> +#include <kprocess.h> +#include <tdeio/jobclasses.h> +#include <tqprogressdialog.h> +#include <tdeglobalsettings.h> +#include <kmimetype.h> +#include <kcursor.h> +#include <klargefile.h> +// krusader includes +#include "arc_vfs.h" +#include "krpermhandler.h" +#include "krarchandler.h" +#include "../krusader.h" +#include "../defaults.h" +#include "../resources.h" +#include "../Dialogs/krdialogs.h" + +#define MAX_FILES 500 + +//constructor +arc_vfs::arc_vfs(TQString origin,TQString type,TQObject* panel,bool write): + vfs(panel),arcFile(origin),changed(false),prefix(""),ignoreLines(0){ + + if ( type == "tarz" ) type = "-tgz"; + + // set the cursor to busy mode + if (!quietMode) krApp->setCursor(KCursor::waitCursor()); + + // set the writable attribute + isWritable = KRpermHandler::fileWriteable(origin); + isWritable = ( write && isWritable ); + + vfs_type = vfs::ERROR; + + // create the temp dir.. + tmpDir = krApp->getTempDir(); + if( tmpDir.isEmpty() ){ + error = true; + return; + } + + TQString password = TQString(); + krConfig->setGroup("Archives"); + // fill the command options + if( type == "gzip" ){ + cmd = KrServices::fullPathName ( "gzip" ); + listCmd = "-l"; + delCmd = ""; + addCmd = KrServices::fullPathName ( "gzip" ) + " -c"; + getCmd = "-dc"; + ignoreLines = -1; + isWritable = false; + } + if(type == "zip2"){ + cmd = KrServices::fullPathName( "bzip2" ); + listCmd = ""; + delCmd = ""; + addCmd = KrServices::fullPathName( "bzip2" )+ " -c"; + getCmd = "-dc"; + ignoreLines = -1; + isWritable = false; + } + if(type == "-tar"){ + cmd = KrServices::fullPathName( "tar" ); + listCmd = " -tvf"; + delCmd = cmd+" --delete -vf"; + addCmd = cmd+" -uvf"; + getCmd = " -xvf"; + } + if(type == "-tgz"){ + cmd = KrServices::fullPathName( "tar" ); + listCmd = " -tzvf"; + delCmd = ""; + addCmd = cmd+" -uvzf"; + getCmd = " -xzvf"; + isWritable = false; + } + if(type == "-tbz"){ + cmd = KrServices::fullPathName( "tar" ); + listCmd = " -tjvf"; + delCmd = ""; + addCmd = cmd+" -uvjf"; + getCmd = " -xjvf"; + isWritable = false; + } + if(type == "-zip"){ + password = KRarcHandler::getPassword(arcFile,type); + cmd = KrServices::fullPathName( "unzip" ); + listCmd = "-ZTs "; + TQString zipcmd = KrServices::fullPathName( "zip" ); + delCmd = zipcmd+" -d"; + addCmd = zipcmd+" -ry"; + getCmd = " -o"; + if( !password.isEmpty() ){ + //listCmd = listCmd + " -P "+password; + delCmd = delCmd + " -P "+password; + addCmd = addCmd + " -P "+password; + getCmd = getCmd + " -P "+password; + } + ignoreLines = 1; + } + // "-rpm" is used only to list the rpm - to extract files use "+rpm" + if(type == "-rpm"){ + //rpm can't handle files with " " in them so replace " " with "\ " + arcFile.replace(TQRegExp(" "),"\\ "); + + cmd = KrServices::fullPathName( "rpm" ); + listCmd = " --dump -lpq "; + delCmd = ""; + addCmd = ""; + getCmd = ""; + isWritable = false; + } + if( type == "+rpm" ){ + // extract the cpio archive from the rpm + KShellProcess rpm; + rpm << "rpm2cpio"<<"\""+arcFile+"\""+" > "+tmpDir+"/contents.cpio"; + rpm.start(TDEProcess::Block); + arcFile = tmpDir+"/contents.cpio"; + } + if(type == "cpio" || type == "+rpm" ){ + cmd = KrServices::fullPathName( "cpio" ); + listCmd = "-tvF "; + delCmd = ""; + addCmd = ""; + getCmd = " --force-local --no-absolute-filenames -ivdF"; + isWritable = false; + } + if(type == "-rar"){ + bool doRar = krConfig->readBoolEntry("Do Rar",_DoRar); + cmd = KrServices::fullPathName( "unrar" ); + listCmd = " -c- v "; + delCmd = ""; + addCmd = (doRar ? TQString(KrServices::fullPathName( "rar" ) + " -r a ") : TQString("")) ; + getCmd = " x -y "; + ignoreLines = 8; + isWritable = (doRar && isWritable ); + } + + getDirs(); + // set the cursor to normal mode + if (!quietMode) krApp->setCursor(KCursor::arrowCursor()); +} + +// return the working dir +TQString arc_vfs::vfs_workingDir(){ + // get the path inside the archive + TQString path = vfs_origin.right((vfs_origin.length()-vfs_origin.findRev('\\'))-1); + if(path.left(1) != "/") path = "/"+path; + TQDir().mkdir(tmpDir+path); + return tmpDir+path; +} + +arc_vfs::~arc_vfs(){ + // set the cursor to busy mode + if (!quietMode) krApp->setCursor(KCursor::waitCursor()); + // don't touch messed-up archives + if(!error) repack(); + // delete the temp dir + KShellProcess proc; + proc<<"rm"<<"-rf"<<tmpDir; + proc.start(TDEProcess::Block); + + // set the cursor to normal mode + if (!quietMode) krApp->setCursor(KCursor::arrowCursor()); +} + +bool arc_vfs::getDirs(){ + if( !listCmd.isEmpty() ){ + // write the temp file + KShellProcess proc; + proc << cmd << listCmd << "\""+arcFile+"\"" <<" > " << tmpDir+"/tempfilelist"; + proc.start(TDEProcess::Block); + if( !proc.normalExit() || !proc.exitStatus() == 0 ){ + if (!quietMode) KMessageBox::error(krApp, i18n("<qt>Can't read <b>%1</b>. Archive " + "might be corrupted!</qt>").arg(arcFile.mid(arcFile.findRev('/')+1))); + error = true; + return false; + } + + // clear the dir list + dirList.clear(); + + // prepare the first dir entry - the "" entry + arc_dir *tempdir = new arc_dir(""); + vfs_filesP = &(tempdir->entries); + dirList.append(tempdir); + + // parse the temp file + TQFile temp(tmpDir+"/tempfilelist"); + temp.open(IO_ReadOnly); + char buf[1000]; + TQString line; + if(vfs_type == "gzip" || vfs_type == "-zip" ) + temp.readLine(line,10000); // skip the first line - it's garbage + if( vfs_type == "-rar" ){ + while(temp.readLine(line,10000) != -1) + if ( line.contains("----------") ) break; + } + while(temp.readLine(buf,1000) != -1){ + line = TQString::fromLocal8Bit(buf); + if ( line.contains("----------") ) break; + parseLine(line.stripWhiteSpace(),&temp); + + } + temp.close(); + TQDir().remove(tmpDir+"/tempfilelist"); + } + else { // bzip2 + // clear the dir list + dirList.clear(); + + // prepare the first dir entry - the "" entry + arc_dir *tempdir = new arc_dir(""); + vfs_filesP = &(tempdir->entries); + dirList.append(tempdir); + + parseLine("",0); + } + return true; +} + + +// copy a file to the vfs (physical) +void arc_vfs::vfs_addFiles(KURL::List *fileUrls,TDEIO::CopyJob::CopyMode mode,TQObject* toNotify,TQString dir, PreserveMode /*pmode*/ ){ + if ( addCmd.isEmpty() ) return; + + // get the path inside the archive + TQString path = vfs_origin.right((vfs_origin.length()-vfs_origin.findRev('\\'))-1); + path = path+"/"; + if(dir != "" ) dir = "/"+dir; + if(path.left(1) != "/") path = "/"+path; + + // make sure the destination exist + for( int i=0; i >= 0 ; i= TQString(tmpDir+path+dir).find('/',i+1) ){ + TQDir().mkdir(TQString(tmpDir+path+dir).left(i)); + } + + changed = true; //rescan the archive + + KURL dest; + dest.setPath(tmpDir+path+dir); + + TDEIO::Job* job = new TDEIO::CopyJob(*fileUrls,dest,mode,false,true); + connect(job,TQ_SIGNAL(result(TDEIO::Job*)),this,TQ_SLOT(vfs_refresh(TDEIO::Job*)) ); + if(mode == TDEIO::CopyJob::Move) // notify the other panel + connect(job,TQ_SIGNAL(result(TDEIO::Job*)),toNotify,TQ_SLOT(vfs_refresh(TDEIO::Job*)) ); +} + + +// remove a file from the vfs (physical) +void arc_vfs::vfs_delFiles(TQStringList *fileNames){ + if ( delCmd.isEmpty() ) return; + // if we move to trash - just extract files and move them to trash - + // the repack() will delete them for us + krConfig->setGroup("General"); + if( krConfig->readBoolEntry("Move To Trash",_MoveToTrash) ) { + KURL::List* filesUrls = vfs_getFiles(fileNames); // extract + changed = true; + + TDEIO::Job *job = new TDEIO::CopyJob(*filesUrls,TDEGlobalSettings::trashPath(),TDEIO::CopyJob::Move,false,true ); + connect(job,TQ_SIGNAL(result(TDEIO::Job*)),this,TQ_SLOT(vfs_refresh(TDEIO::Job*))); + } + // else we have to delete the files from both the archive and the temp dir + else { + // change dir to the temp dir + TQString save = getcwd(0,0); + chdir(tmpDir.local8Bit()); + + TQStringList files; + TDEIO::filesize_t totalSizeVal = 0; + unsigned long totalFilesVal = 0; + + // names -> urls + for(TQStringList::Iterator name = fileNames->begin(); name != fileNames->end(); ++name ) + processName(*name,&files,&totalSizeVal,&totalFilesVal); + + + KShellProcess proc1 , proc2; + krApp->startWaiting(i18n("Deleting Files..."),files.count()+ignoreLines); + connect(&proc1,TQ_SIGNAL(receivedStdout(TDEProcess*,char*,int)), + krApp, TQ_SLOT(incProgress(TDEProcess*,char*,int)) ); + + proc1 << delCmd << "\""+arcFile+"\""; + proc2 << "rm -rf"; + for(unsigned int i =0; i < files.count(); ){ + proc1 << (prefix+*files.at(i)); + proc2 << tmpDir+"/"+(*files.at(i)); + extFiles.remove(*files.at(i++)); + if ( i%MAX_FILES==0 || i==files.count() ){ + proc1.start(TDEProcess::NotifyOnExit,TDEProcess::AllOutput); + proc2.start(); + while( proc1.isRunning() || proc2.isRunning() ) tqApp->processEvents(); // busy wait - need to find something better... + proc1.clearArguments() ; proc2.clearArguments(); + proc1 << delCmd << "\""+arcFile+"\""; + proc2 << "rm -rf"; + } + } + krApp->stopWait(); + + changed = true; + chdir (save.local8Bit()); + vfs_refresh(vfs_origin); + } +} + +// return a path to the file +TQString arc_vfs::vfs_getFile(TQString name){ + // get the current file path + TQString path = vfs_origin.right((vfs_origin.length()-vfs_origin.findRev('\\'))-1); + if(path.left(1)=="/") path.remove(0,1); + if(path != "") path = path+"/"; + + TQStringList temp(name); + vfs_getFiles(&temp); + + return tmpDir+"/"+path+name; +} + +KURL::List* arc_vfs::vfs_getFiles(TQStringList* names){ + KURL url; + KURL::List* urls = new KURL::List(); + + // get the current file path + TQString path = vfs_origin.right((vfs_origin.length()-vfs_origin.findRev('\\'))-1); + if(path.left(1)=="/") path.remove(0,1); + if(path != "") path = path+"/"; + + // change dir to the temp dir + TQString save = getcwd(0,0); + chdir(tmpDir.local8Bit()); + // names -> urls + TQStringList files; + TDEIO::filesize_t totalSize = 0; + unsigned long totalFiles = 0; + for(TQStringList::Iterator name = names->begin(); name != names->end(); ++name ){ + processName(*name,&files,&totalSize,&totalFiles); + url.setPath(tmpDir+"/"+path+(*name)); + urls->append(url); + } + // check the urls for unpacked files and directories + for(TQStringList::Iterator file = files.begin(); file != files.end(); ++file ){ + if ( (*file).right(1)=="/" ){ + TQDir(tmpDir).mkdir(*file); + if( vfs_type == "-rar" ) file = files.remove(file--); + } + // don't unpack the same file twice + else if( extFiles.contains(*file) ){ + file = files.remove(file--); + } + } + // unpack ( if needed ) + if ( files.count() > 0 ){ + krApp->startWaiting(i18n("Unpacking Files"),files.count()+ignoreLines); + KShellProcess proc; + connect(&proc,TQ_SIGNAL(receivedStdout(TDEProcess*,char*,int)), + krApp, TQ_SLOT(incProgress(TDEProcess*,char*,int)) ); + + proc << cmd << getCmd << "\""+arcFile+"\""; + if( vfs_type == "gzip" || vfs_type == "zip2" ) proc << ">"; + for(unsigned int i=0 ; i < files.count() ; ){ + proc << (prefix+*files.at(i++)); + if ( i%MAX_FILES==0 || i==files.count() ){ + proc.start(TDEProcess::NotifyOnExit,TDEProcess::AllOutput); + while( proc.isRunning() ) tqApp->processEvents(); + proc.clearArguments(); + proc << cmd << getCmd << "\""+arcFile+"\""; + } + } + getExtFiles(); // this will update the extFiles list. + krApp->stopWait(); + } + // restore dir + chdir(save.local8Bit()); + + return urls; +} + +// make dir +void arc_vfs::vfs_mkdir(TQString name){ + TQString path = vfs_origin.right((vfs_origin.length()-vfs_origin.findRev('\\'))-1); + if(path.left(1)=="/") path.remove(0,1); + if(path != "") path = path+"/"; + + TQDir(tmpDir).mkdir(path+name); + changed = true; //rescan the archive + vfs_refresh(vfs_origin); +} + +// rename file +void arc_vfs::vfs_rename(TQString fileName,TQString newName){ + KURL::List temp; + temp.append(vfs_getFile(fileName)); + TQString path = vfs_origin.right((vfs_origin.length()-vfs_origin.findRev('\\'))-1); + if(path.left(1)=="/") path.remove(0,1); + if(path != "") path = path+"/"; + + TQDir(tmpDir).mkdir(path); + changed = true; //rescan the archive + + KURL dest; + dest.setPath(tmpDir+path+"/"+newName); + + TDEIO::Job* job = new TDEIO::CopyJob(temp,dest,TDEIO::CopyJob::Move,false,false); + connect(job,TQ_SIGNAL(result(TDEIO::Job*)),this,TQ_SLOT(vfs_refresh(TDEIO::Job*)) ); +} + +bool arc_vfs::vfs_refresh(TQString origin){ + if ( error ) return false; + + if ( changed || origin == vfs_origin ){ + repack(); // repack dirs only if needed + if ( !getDirs() ){ + if (!quietMode) emit startUpdate(); + return true; + } + changed = false; + } + + vfs_origin = origin; + // get the directory... + TQString path = origin.right((origin.length()-origin.findRev('\\'))-1); + if(path.left(1) =="/") path.remove(0,1); + + vfs_filesP = findDir(path); + + if (!quietMode) emit startUpdate(); + return true; +} + +// service functions +TQString arc_vfs::nextWord(TQString &s,char d) { + s=s.stripWhiteSpace(); + int j=s.find(d,0); + TQString temp=s.left(j); // find the leftmost word. + s.remove(0,j); + return temp; +} + +void arc_vfs::getFilesToPack(TQStringList* filesToPack,TQString dir_name){ + bool newDir = false; + vfileDict *vfs_filesP_backup = vfs_filesP; // save vfs_filesP + + // init all the diffrent lists (and list pointers); + vfs_filesP=findDir(dir_name); + if ( vfs_filesP == 0) newDir = true; + if(dir_name != "") dir_name = dir_name+"/"; + + DIR* dir = opendir(tmpDir.local8Bit()+"/"+dir_name.local8Bit()); + if(!dir) return ; + + struct dirent* dirEnt; + TQString name; + KDE_struct_stat stat_p; + while( (dirEnt=readdir(dir)) != NULL ){ + name = dirEnt->d_name; + if ( name == ".." || name == "." ) continue; + if( KDE_lstat(tmpDir.local8Bit()+"/"+dir_name.local8Bit()+name.local8Bit(),&stat_p) ) continue; + extFile temp(dir_name+name,stat_p.st_mtime,stat_p.st_size); + // add to the list file that are diffrent than the ones packed + if( S_ISDIR(stat_p.st_mode) ){ // recurse on all sub dirs + if( !findDir(dir_name+name) ){ + // add to the list only new && empty dirs + if( newDir && TQDir(dir_name+name).entryList(TQDir::All | TQDir::AccessMask).count() <= 2 ) + filesToPack->append( dir_name+name); + } + getFilesToPack(filesToPack,dir_name+name); + continue; + } + + // if the file don't exist add it to the archive and to the extFiles + if( newDir || !extFiles.contains( dir_name+name ) ){ + filesToPack->append( dir_name+name ); + extFiles.append( temp ); + } // else if the file exist but was modified - repack it; + else if( !extFiles.contains( temp ) ){ + filesToPack->append( dir_name+name ); + extFiles.remove( dir_name+name ); + extFiles.append( temp ); + } + } + vfs_filesP = vfs_filesP_backup; // restore vfs_filesP +} + +void arc_vfs::getFilesToDelete(TQStringList* filesToDelete,TQString){ + // sync the extFiles - and find out which files were deleted + TQString file; + for(unsigned int i=0 ; i<extFiles.count(); ){ + file = tmpDir+"/"+(*extFiles.at(i)).url; + if( !KRpermHandler::fileExist(file) ){ + filesToDelete->append( (*extFiles.at(i)).url ); + extFiles.remove(extFiles.at(i)); + } + else ++i; + } +} + +void arc_vfs::getExtFiles(TQString dir_name){ + DIR* dir = opendir(tmpDir.local8Bit()+"/"+dir_name.local8Bit()); + if(!dir){ + kdWarning() << "faild to opendir(): " << tmpDir.local8Bit()+"/"+dir_name.local8Bit() << endl; + return ; + } + + if( dir_name != "") dir_name = dir_name+"/"; + + struct dirent* dirEnt; + TQString name; + KDE_struct_stat stat_p; + while( (dirEnt=readdir(dir)) != NULL ){ + name = dirEnt->d_name; + if ( name == ".." || name == "." ) continue; + if( KDE_lstat(tmpDir.local8Bit()+"/"+dir_name.local8Bit()+name.local8Bit(),&stat_p) ) continue; + extFile temp(dir_name+name,stat_p.st_mtime,stat_p.st_size); + // recurse on all sub dirs + if( S_ISDIR(stat_p.st_mode) ){ + getExtFiles(dir_name+name); + } + // if the file is not in extFiles - it is newly extracted. + // note: getFilesToPack() updates time + size ! + else if( !extFiles.contains( dir_name+name ) ){ + extFiles.append( temp ); + } + } +} + +void arc_vfs::repack(){ + TQString save = getcwd(0,0); + chdir(tmpDir.local8Bit()); + + // delete from the archive files that were unpacked and deleted + if( vfs_isWritable() ){ + TQStringList filesToDelete; + getFilesToDelete(&filesToDelete); + if( !filesToDelete.isEmpty() ){ + KShellProcess delProc; + krApp->startWaiting(i18n("Deleting Files..."),filesToDelete.count()+ignoreLines); + connect(&delProc,TQ_SIGNAL(receivedStdout(TDEProcess*,char*,int)), + krApp, TQ_SLOT(incProgress(TDEProcess*,char*,int)) ); + + delProc << delCmd << "\""+arcFile+"\""; + for( unsigned int i=0 ; i < filesToDelete.count() ;){ + delProc << (*filesToDelete.at(i++)); + if( i%MAX_FILES==0 || i==filesToDelete.count() ){ + delProc.start(TDEProcess::NotifyOnExit,TDEProcess::AllOutput); + while( delProc.isRunning() ) tqApp->processEvents(); + delProc.clearArguments(); + delProc << delCmd << "\""+arcFile+"\""; + } + } + krApp->stopWait(); + } + } + + // finaly repack tmpDir + if( vfs_isWritable() || vfs_type=="gzip" || vfs_type=="zip2" ){ + TQStringList filesToPack; + getFilesToPack(&filesToPack); + if( !filesToPack.isEmpty() ){ + KShellProcess addProc; + krApp->startWaiting(i18n("Repacking..."),filesToPack.count()+ignoreLines); + connect(&addProc,TQ_SIGNAL(receivedStdout(TDEProcess*,char*,int)), + krApp, TQ_SLOT(incProgress(TDEProcess*,char*,int)) ); + + if( vfs_type=="gzip" || vfs_type=="zip2" ){ + addProc << addCmd << *filesToPack.at(0)<< ">" << "\""+arcFile+"\""; + addProc.start(TDEProcess::NotifyOnExit); + while( addProc.isRunning() ) tqApp->processEvents(); + } + else { + addProc << addCmd << "\""+arcFile+"\""; + for( unsigned int i=0 ; i<filesToPack.count(); ){ + addProc << "\""+prefix+(*filesToPack.at(i++))+"\""; + if( i%MAX_FILES==0 || i==filesToPack.count() ){ + addProc.start(TDEProcess::NotifyOnExit,TDEProcess::AllOutput); + while( addProc.isRunning() ) tqApp->processEvents(); // busy wait - need to find something better... + addProc.clearArguments(); + addProc << addCmd << "\""+arcFile+"\""; + } + } + } + krApp->stopWait(); + } + } + chdir(save.local8Bit()); +} + +vfileDict* arc_vfs::findDir(TQString name){ + for(arc_dir* temp = dirList.first();temp != 0 ; temp = dirList.next()){ + if(temp->name == name) return &(temp->entries); + } + return 0; +} + +arc_vfs::arc_dir* arc_vfs::findArcDir(TQString name){ +for(arc_dir* temp = dirList.first();temp != 0 ; temp = dirList.next()){ + if(temp->name == name) return temp; + } + return 0; +} + +TQString arc_vfs::changeDir(TQString name){ + if(name.left(2) == "./") { + prefix = "./"; + name.remove(0,2); + } + + if(!name.contains('/')){ + vfs_filesP = findDir(""); + return name; + } + // seperate the path from the name + TQString path = name.left(name.findRev('/')); + name = name.mid(name.findRev('/')+1); + // see if the path exists + if ((vfs_filesP=findDir(path)) == 0){ + //create a new dir entry + TQString Pname = path.mid(path.findRev('/')+1); + if(Pname.isEmpty()) return name; + TQString tempName = arcFile; + TQFileInfo qfi(tempName.replace(TQRegExp("\\"),"")); + vfile* vf=new vfile(Pname,0,"drwxr-xr-x",qfi.lastModified().toTime_t(),false, + qfi.owner(),qfi.group(),"inode/directory","",0 ); + // add dirs if needed + changeDir(path); + + vfile* vf2 = vfs_search(Pname); + if(vf2 != 0) vfs_removeFromList(vf2); + vfs_addToList(vf); + + // add a new arc_dir + dirList.append(new arc_dir(path)); + vfs_filesP = findDir(path); + } + return name; +} + +// calculate space +void arc_vfs::vfs_calcSpace(TQString name ,TDEIO::filesize_t *totalSize,unsigned long *totalFiles,unsigned long *totalDirs,bool* stop){ + if ( *stop ) return; + vfile* vf = vfs_search(name); + + // get the path inside the archive + TQString path = vfs_origin.right((vfs_origin.length()-vfs_origin.findRev('\\'))-1); + path = path+"/"; + if(path.left(1) == "/") path.remove(0,1); + + if( !vf->vfile_isDir() ){ // single files are simple :) + ++(*totalFiles); + (*totalSize) += vf->vfile_getSize(); + } + else { // handle directories : ( + ++(*totalDirs); + + TQString origin_backup = vfs_origin; // backup the vfs origin + vfs_origin = vfs_origin+"/"+name; + vfileDict* vfs_filesP_backup = vfs_filesP; // backup the vfs_filesP + vfs_filesP = findDir(path+name); + + // process all the files in the directory. + for( vf = vfs_getFirstFile(); vf != 0; vf = vfs_getNextFile() ){ + if (*stop) return; + vfs_calcSpace(vf->vfile_getName(),totalSize,totalFiles,totalDirs,stop); + } + + vfs_origin = origin_backup; // restore origin + vfs_filesP = vfs_filesP_backup; // restore vfs_filesP + } +} + +void arc_vfs::processName(const TQString& name, TQStringList *urls,TDEIO::filesize_t *totalSize,unsigned long *totalFiles ){ + vfile* vf = vfs_search(name); + if ( vf == 0 ) return; + + // get the path inside the archive + TQString path = vfs_origin.right((vfs_origin.length()-vfs_origin.findRev('\\'))-1); + path = path+"/"; + if(path.left(1) == "/") path.remove(0,1); + + if( !vf->vfile_isDir() || vf->vfile_isSymLink() ){ // single files are simple :) + ++(*totalFiles); + (*totalSize) += vf->vfile_getSize(); + urls->append(path+name); + } else { // handle directories : ( + urls->append(path+name+"/"); + TQString origin_backup = vfs_origin; // backup the vfs origin + vfs_origin = vfs_origin+"/"+name; + vfileDict* vfs_filesP_backup = vfs_filesP; // backup the vfs_filesP + vfs_filesP = findDir(path+name); + + // process all the files in the directory. + for( vf = vfs_getFirstFile(); vf != 0; vf = vfs_getNextFile() ) + processName(vf->vfile_getName(),urls,totalSize,totalFiles); + + vfs_origin = origin_backup; // restore origin + vfs_filesP = vfs_filesP_backup; // restore vfs_filesP + } +} + +void arc_vfs::parseLine(TQString line, TQFile* temp){ + TQString name; + TDEIO::filesize_t size = 0; + TQString perm; + TQFileInfo qfi(arcFile); + time_t mtime = qfi.lastModified().toTime_t(); + bool link = false; + uid_t owner = getuid(); + gid_t group = getgid(); + TQString dest = ""; + mode_t mode = 0; + + + // parse gziped files + if(vfs_type == "gzip"){ + KDE_struct_stat stat_p; + KDE_stat(arcFile.local8Bit(),&stat_p); + + nextWord(line); + size = nextWord(line).toLong(); + nextWord(line); + name = nextWord(line,'\n'); + if(name.contains('/')) name = name.mid(name.findRev('/')+1,name.length()); + perm = KRpermHandler::mode2TQString(stat_p.st_mode) ; + owner = KRpermHandler::user2uid(qfi.owner()); + group = KRpermHandler::group2gid(qfi.group()); + mode = stat_p.st_mode; + } + + // parse bzip2ed files + if( vfs_type == "zip2" ){ + KDE_struct_stat stat_p; + KDE_stat(arcFile.local8Bit(),&stat_p); + + name = qfi.fileName(); + name = name.left(name.findRev('.')); + //long size = qfi.size(); + perm = KRpermHandler::mode2TQString(stat_p.st_mode) ; + owner = KRpermHandler::user2uid(qfi.owner()); + group = KRpermHandler::group2gid(qfi.group()); + mode = stat_p.st_mode; + } + + // parse tar files + if(vfs_type == "-tar" || vfs_type == "-tbz" || vfs_type == "-tgz" ){ + perm = nextWord(line); + TQString temp = nextWord(line); + owner = temp.left(temp.findRev('/')).toInt(); + group = temp.mid(temp.find('/')+1,temp.length()).toInt(); + size = nextWord(line).toLong(); + temp = nextWord(line); + name = nextWord(line,'\n'); + if (name.startsWith("/")) // fix full-paths problem in tar (thanks to Heiner!) + name.remove(0, 1); + if( name.contains(" -> ") ){ + link = true; + dest = name.mid(name.find(" -> ")+4); + name = name.left(name.find(" -> ")); + } + } + + // parse zipped files + if(vfs_type == "-zip"){ + perm = nextWord(line); + if(perm.length() != 10) + perm = (perm.at(0)=='d')? "drwxr-xr-x" : "-rw-r--r--" ; + if (nextWord(line).contains("file")) return; + nextWord(line); + size = nextWord(line).toLong(); + nextWord(line);nextWord(line); + TQString temp = nextWord(line); + name = nextWord(line,'\n'); + } + + // parse cpio packages + if(vfs_type == "cpio" || vfs_type == "+rpm"){ + perm = nextWord(line); + nextWord(line);nextWord(line);nextWord(line); + size = nextWord(line).toLong(); + nextWord(line);nextWord(line);nextWord(line); + TQString tempName = arcFile; + TQFileInfo qfi(tempName.replace(TQRegExp("\\"),"")); + name = nextWord(line,'\n'); + if ( name.left(1) == "/" ) name.remove(0,1); + if( name.contains(" -> ") ){ + link = true; + dest = name.mid(name.find(" -> ")+4); + name = name.left(name.find(" -> ")); + } + } + // parse rared files + if(vfs_type == "-rar"){ + name = nextWord(line,'\n'); + temp->readLine(line,10000); + size = nextWord(line).toLong(); + nextWord(line); + nextWord(line); + perm = nextWord(line); + if(perm.length() != 10) + perm = (perm.at(1)=='D')? "drwxr-xr-x" : "-rw-r--r--" ; + } + // parse rpm packages + if(vfs_type == "-rpm"){ + name = nextWord(line); + if ( name.left(1) == "/" ) name.remove(0,1); + size = nextWord(line).toLong(); + mtime = nextWord(line).toLong(); + nextWord(line); + perm = KRpermHandler::mode2TQString(nextWord(line).toLong()); + perm = (perm.at(0)=='d')? "drwxr-xr-x" : "-rw-r--r--" ; + } + + if ( perm[0]=='d' && name.right(1) != "/" ) name = name+"/"; + name = changeDir(name); + if(name.length() < 1) return; + + + TQString mime = KMimeType::findByURL( "/"+name,0,true,true)->name(); + vfile* vf=new vfile(name,size,perm,mtime,link,owner,group,mime,dest,mode); + vfile* vf2 = vfs_search(name); + if(vf2 != 0) vfs_removeFromList(vf2); + vfs_addToList(vf); +} + +#include "arc_vfs.moc" diff --git a/src/app/VFS/arc_vfs.h b/src/app/VFS/arc_vfs.h new file mode 100644 index 0000000..bb7dd0c --- /dev/null +++ b/src/app/VFS/arc_vfs.h @@ -0,0 +1,131 @@ +/*************************************************************************** + arc_vfs.h + ------------------- + begin : Thu May 4 2000 + copyright : (C) 2000 by Shie Erlich & Rafi Yanai + e-mail : krusader@users.sourceforge.net + web site : http://krusader.sourceforge.net + --------------------------------------------------------------------------- + Description + *************************************************************************** + + A + + db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. + 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D + 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' + 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b + 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. + YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD + + H e a d e r F i l e + + *************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +#ifndef ARC_VFS_H +#define ARC_VFS_H + +#include <sys/types.h> +#include "vfs.h" +#include <tqvaluestack.h> +#include <kprocess.h> +#include <tqfile.h> +#include <tqprogressdialog.h> + +class arc_vfs : public vfs { + TQ_OBJECT + + class arc_dir; + class extFile; +public: + arc_vfs(TQString origin,TQString type,TQObject* panel,bool write); + ~arc_vfs(); + + // copy a file to the vfs (physical) + void vfs_addFiles(KURL::List *fileUrls,TDEIO::CopyJob::CopyMode mode,TQObject* toNotify=0,TQString dir = "", PreserveMode pmode = PM_DEFAULT ); + // remove a file from the vfs (physical) + void vfs_delFiles(TQStringList *fileNames); + // return a path to the file + TQString vfs_getFile(TQString name); + KURL::List* vfs_getFiles(TQStringList* names); + // make dir + void vfs_mkdir(TQString name); + // rename file + void vfs_rename(TQString fileName,TQString newName); + // calculate space + void vfs_calcSpace(TQString name ,TDEIO::filesize_t *totalSize,unsigned long *totalFiles,unsigned long *totalDirs, bool* stop); + // return the working dir + TQString vfs_workingDir(); + +public slots: + // actually reads files and stats + bool vfs_refresh(TQString origin); + void repack(); + +protected: + TQString tmpDir; // the temp directory tha archive is using + TQString arcFile; // the archive file URL + bool changed; // true if repack changed the archive + TQPtrList<arc_dir> dirList; + TQValueList<extFile> extFiles; // the name, time & size of files unpacked from this archive + + void processName(const TQString& name,TQStringList *urls,TDEIO::filesize_t *totalSize,unsigned long *totalFiles ); + bool getDirs(); // fill the dir list + vfileDict* findDir(TQString name); + arc_dir* findArcDir(TQString name); + void getFilesToPack (TQStringList* filesToPack,TQString dir_name = ""); + void getFilesToDelete(TQStringList* filesToDelete,TQString dir_name = ""); + void getExtFiles( TQString dir_name="" ); + TQString nextWord( TQString &s, char d=' ' ); + TQString changeDir(TQString name); + + void parseLine(TQString line,TQFile* temp); + + TQString prefix; + TQString cmd; // the archiver main command + TQString listCmd; // the file listing option + TQString delCmd; // the delete option + TQString addCmd; // the add files option + TQString getCmd; // the extract files option + + // the interl progress bar variale + int ignoreLines; // no of lines to ignore on stdout + +private: + class arc_dir{ + public: + arc_dir(TQString _name){ + name = _name; + entries.setAutoDelete(true); + } + TQString name; // the name of the dir + vfileDict entries; // the file and dir in this dir + }; + + class extFile{ + public: + extFile(): url(""),time(0),size(0){} + extFile(TQString u): url(u),time(0),size(0){} + extFile(TQString u,time_t t,off_t s): url(u),time(t),size(s){} + bool operator==(const extFile& ef) const{ + if( url != ef.url ) return false; + if( size*ef.size && size!=ef.size )return false; + if( time*ef.time && time!=ef.time )return false; + return true; + } + TQString url; + time_t time; + off_t size; + }; + + + +}; + +#endif diff --git a/src/app/VFS/ftp_vfs.cpp b/src/app/VFS/ftp_vfs.cpp new file mode 100644 index 0000000..2da0665 --- /dev/null +++ b/src/app/VFS/ftp_vfs.cpp @@ -0,0 +1,297 @@ +/*************************************************************************** + ftp_vfs.cpp + ------------------- + copyright : (C) 2000 by Rafi Yanai + e-mail : krusader@users.sourceforge.net + web site : http://krusader.sourceforge.net +--------------------------------------------------------------------------- + +*************************************************************************** + + A + + db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. + 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D + 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' + 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b + 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. + YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD + + S o u r c e F i l e + +*************************************************************************** +* * +* 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. * +* * +***************************************************************************/ + +// Sys includes +#include <time.h> +#include <sys/param.h> +#include <unistd.h> +#ifdef BSD +#include <sys/types.h> +#endif +// TQt includes +#include <tqdir.h> +#include <tqregexp.h> +#include <tqtimer.h> +#include <tqeventloop.h> +// TDE includes +#include <tdeio/jobclasses.h> +#include <tdelocale.h> +#include <tdeio/job.h> +#include <tdemessagebox.h> +#include <kprotocolinfo.h> +#include <kdebug.h> +// Krusader includes +#include "ftp_vfs.h" +#include "krpermhandler.h" +#include "../Dialogs/krdialogs.h" +#include "../Dialogs/krprogress.h" +#include "../krusader.h" +#include "../defaults.h" +#include "../resources.h" + +ftp_vfs::ftp_vfs( TQObject* panel ) : vfs( panel ), busy( false ) { + // set the writable attribute + isWritable = true; + vfs_type = FTP; +} + +ftp_vfs::~ftp_vfs() { + busy = false; +} + +void ftp_vfs::slotAddFiles( TDEIO::Job *, const TDEIO::UDSEntryList& entries ) { + int rwx = -1; + + TQString prot = vfs_origin.protocol(); + if( prot == "krarc" || prot == "tar" || prot == "zip" ) + rwx = PERM_ALL; + + TDEIO::UDSEntryListConstIterator it = entries.begin(); + TDEIO::UDSEntryListConstIterator end = entries.end(); + + // as long as u can find files - add them to the vfs + for ( ; it != end; ++it ) { + KFileItem kfi( *it, vfs_origin, true, true ); + vfile *temp; + + // get file statistics + TQString name = kfi.text(); + // ignore un-needed entries + if ( name.isEmpty() || name == "." || name == ".." ) continue; + + TDEIO::filesize_t size = kfi.size(); + time_t mtime = kfi.time( TDEIO::UDS_MODIFICATION_TIME ); + bool symLink = kfi.isLink(); + mode_t mode = kfi.mode() | kfi.permissions(); + TQString perm = KRpermHandler::mode2TQString( mode ); + // set the mimetype + TQString mime = kfi.mimetype(); + TQString symDest = ""; + if ( symLink ) { + symDest = kfi.linkDest(); + if ( kfi.isDir() ) perm[ 0 ] = 'd'; + } + + // create a new virtual file object + if ( kfi.user().isEmpty() ) + temp = new vfile( name, size, perm, mtime, symLink, getuid(), getgid(), mime, symDest, mode, rwx ); + else { + TQString currentUser = vfs_origin.user(); + if ( currentUser.contains( "@" ) ) /* remove the FTP proxy tags from the username */ + currentUser.truncate( currentUser.find( '@' ) ); + if ( currentUser.isEmpty() ) { + if( vfs_origin.host().isEmpty() ) + currentUser = KRpermHandler::uid2user( getuid() ); + else { + currentUser = ""; // empty, but not TQString() + } + } +#if KDE_IS_VERSION(3,5,0) + temp = new vfile( name, size, perm, mtime, symLink, + kfi.user(), kfi.group(), currentUser, + mime, symDest, mode, rwx, kfi.ACL().asString(), + kfi.defaultACL().asString() ); +#else + temp = new vfile( name, size, perm, mtime, symLink, kfi.user(), kfi.group(), currentUser, mime, symDest, mode, rwx ); +#endif + } + +#if KDE_IS_VERSION(3,4,0) + if( !kfi.localPath().isEmpty() ){ + temp->vfile_setUrl( kfi.localPath() ); + } else { + temp->vfile_setUrl( kfi.url() ); + } +#else + temp->vfile_setUrl( kfi.url() ); +#endif + temp->vfile_setIcon( kfi.iconName() ); + foundVfile( temp ); + } +} + +void ftp_vfs::slotPermanentRedirection( TDEIO::Job*, const KURL&, const KURL& newUrl ) { + vfs_origin = newUrl; + vfs_origin.adjustPath(-1); +} + +void ftp_vfs::slotRedirection( TDEIO::Job *, const KURL &url ) { + // update the origin + vfs_origin = url; + vfs_origin.adjustPath(-1); +} + +void ftp_vfs::slotListResult( TDEIO::Job *job ) { + if ( job && job->error() ) { + // we failed to refresh + listError = true; + // display error message + if ( !quietMode ) job->showErrorDialog( krApp ); + } + busy = false; +} + +bool ftp_vfs::populateVfsList( const KURL& origin, bool showHidden ) { + TQString errorMsg = TQString(); + if ( !origin.isValid() ) + errorMsg = i18n( "Malformed URL:\n%1" ).arg( origin.url() ); + if ( !KProtocolInfo::supportsListing( origin ) ) { + if( origin.protocol() == "ftp" && KProtocolInfo::supportsReading( origin ) ) + errorMsg = i18n( "Krusader doesn't support FTP access via HTTP.\nIf it is not the case, please check and change the Proxy settings in kcontrol." ); + else + errorMsg = i18n( "Protocol not supported by Krusader:\n%1" ).arg( origin.url() ); + } + + if ( !errorMsg.isEmpty() ) { + if ( !quietMode ) KMessageBox::sorry( krApp, errorMsg ); + return false; + } + + busy = true; + + vfs_origin = origin; + vfs_origin.adjustPath(-1); + + //TQTimer::singleShot( 0,this,TQ_SLOT(startLister()) ); + listError = false; + // Open the directory marked by origin + krConfig->setGroup( "Look&Feel" ); + //vfs_origin.adjustPath(+1); + TDEIO::Job *job = TDEIO::listDir( vfs_origin, false, showHidden ); + connect( job, TQ_SIGNAL( entries( TDEIO::Job*, const TDEIO::UDSEntryList& ) ), + this, TQ_SLOT( slotAddFiles( TDEIO::Job*, const TDEIO::UDSEntryList& ) ) ); + connect( job, TQ_SIGNAL( redirection( TDEIO::Job*, const KURL& ) ), + this, TQ_SLOT( slotRedirection( TDEIO::Job*, const KURL& ) ) ); + connect( job, TQ_SIGNAL( permanentRedirection( TDEIO::Job*, const KURL&, const KURL& ) ), + this, TQ_SLOT( slotPermanentRedirection( TDEIO::Job*, const KURL&, const KURL& ) ) ); + + connect( job, TQ_SIGNAL( result( TDEIO::Job* ) ), + this, TQ_SLOT( slotListResult( TDEIO::Job* ) ) ); + + job->setWindow( krApp ); + + if ( !quietMode ) { + emit startJob( job ); + //new KrProgress(job); ==> disabled because of in-panel refresh + } + + while ( busy && vfs_processEvents()); + + if ( listError ) return false; + + return true; +} + + +// copy a file to the vfs (physical) +void ftp_vfs::vfs_addFiles( KURL::List *fileUrls, TDEIO::CopyJob::CopyMode mode, TQObject* toNotify, TQString dir, PreserveMode /*pmode*/ ) { + KURL destUrl = vfs_origin; + + if ( dir != "" ) { + destUrl.addPath( dir ); + destUrl.cleanPath(); // removes the '..', '.' and extra slashes from the URL. + + if ( destUrl.protocol() == "tar" || destUrl.protocol() == "zip" || destUrl.protocol() == "krarc" ) { + if ( TQDir( destUrl.path( -1 ) ).exists() ) + destUrl.setProtocol( "file" ); // if we get out from the archive change the protocol + } + } + + TDEIO::Job* job = new TDEIO::CopyJob( *fileUrls, destUrl, mode, false, true ); + connect( job, TQ_SIGNAL( result( TDEIO::Job* ) ), this, TQ_SLOT( vfs_refresh( TDEIO::Job* ) ) ); + if ( mode == TDEIO::CopyJob::Move ) // notify the other panel + connect( job, TQ_SIGNAL( result( TDEIO::Job* ) ), toNotify, TQ_SLOT( vfs_refresh( TDEIO::Job* ) ) ); +} + +// remove a file from the vfs (physical) +void ftp_vfs::vfs_delFiles( TQStringList *fileNames ) { + KURL::List filesUrls; + KURL url; + + // names -> urls + for ( uint i = 0 ; i < fileNames->count(); ++i ) { + TQString filename = ( *fileNames ) [ i ]; + url = vfs_origin; + url.addPath( filename ); + filesUrls.append( url ); + } + TDEIO::Job *job = new TDEIO::DeleteJob( filesUrls, false, true ); + connect( job, TQ_SIGNAL( result( TDEIO::Job* ) ), this, TQ_SLOT( vfs_refresh( TDEIO::Job* ) ) ); +} + + +KURL::List* ftp_vfs::vfs_getFiles( TQStringList* names ) { + KURL url; + KURL::List* urls = new KURL::List(); + for ( TQStringList::Iterator name = names->begin(); name != names->end(); ++name ) { + url = vfs_getFile( *name ); + urls->append( url ); + } + return urls; +} + + +// return a path to the file +KURL ftp_vfs::vfs_getFile( const TQString& name ) { + vfile * vf = vfs_search( name ); + if ( !vf ) return KURL(); // empty + + KURL url = vf->vfile_getUrl(); + if ( vf->vfile_isDir() ) url.adjustPath( + 1 ); + return url; +} + +void ftp_vfs::vfs_mkdir( const TQString& name ) { + KURL url = vfs_origin; + url.addPath( name ); + + TDEIO::SimpleJob* job = TDEIO::mkdir( url ); + connect( job, TQ_SIGNAL( result( TDEIO::Job* ) ), this, TQ_SLOT( vfs_refresh( TDEIO::Job* ) ) ); +} + +void ftp_vfs::vfs_rename( const TQString& fileName, const TQString& newName ) { + KURL::List fileUrls; + KURL oldUrl = vfs_origin; + oldUrl.addPath( fileName ) ; + + fileUrls.append( oldUrl ); + + KURL newUrl = vfs_origin; + newUrl.addPath( newName ); + + TDEIO::Job *job = new TDEIO::CopyJob( fileUrls, newUrl, TDEIO::CopyJob::Move, true, true ); + connect( job, TQ_SIGNAL( result( TDEIO::Job* ) ), this, TQ_SLOT( vfs_refresh( TDEIO::Job* ) ) ); +} + +TQString ftp_vfs::vfs_workingDir() { + return vfs_origin.url( -1 ); +} + +#include "ftp_vfs.moc" diff --git a/src/app/VFS/ftp_vfs.h b/src/app/VFS/ftp_vfs.h new file mode 100644 index 0000000..486efc9 --- /dev/null +++ b/src/app/VFS/ftp_vfs.h @@ -0,0 +1,80 @@ +/*************************************************************************** + ftp_vfs.h + ------------------- + begin : Thu May 4 2000 + copyright : (C) 2000 by Shie Erlich & Rafi Yanai + e-mail : krusader@users.sourceforge.net + web site : http://krusader.sourceforge.net + --------------------------------------------------------------------------- + A vfs class that handels "ftp/samba" directory enteris + inherits: vfs + *************************************************************************** + + A + + db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. + 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D + 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' + 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b + 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. + YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD + + H e a d e r F i l e + + *************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +#ifndef FTP_VFS +#define FTP_VFS + +// TDE includes +#include <kdirlister.h> +// Krusader includes +#include "vfs.h" + +class ftp_vfs : public vfs{ + TQ_OBJECT + +public: + // the constructor simply uses the inherited constructor + ftp_vfs(TQObject* panel); + ~ftp_vfs(); + + /// Copy a file to the vfs (physical). + virtual void vfs_addFiles(KURL::List *fileUrls,TDEIO::CopyJob::CopyMode mode,TQObject* toNotify,TQString dir = "", PreserveMode pmode = PM_DEFAULT ); + /// Remove a file from the vfs (physical) + virtual void vfs_delFiles(TQStringList *fileNames); + /// Return a list of URLs for multiple files + virtual KURL::List* vfs_getFiles(TQStringList* names); + /// Return a URL to a single file + virtual KURL vfs_getFile(const TQString& name); + /// Create a new directory + virtual void vfs_mkdir(const TQString& name); + /// Rename file + virtual void vfs_rename(const TQString& fileName,const TQString& newName); + /// Return the VFS working dir + TQString vfs_workingDir(); + +public slots: + /// Handles new files from the dir lister + void slotAddFiles(TDEIO::Job * job, const TDEIO::UDSEntryList& entries); + /// Redirection signal handlers + void slotRedirection(TDEIO::Job *, const KURL &url); + void slotPermanentRedirection(TDEIO::Job*,const KURL&,const KURL& newUrl); + /// Called when the dir listing job is finished (for better or worst) + void slotListResult(TDEIO::Job *job); + /// Active the dir listing job + bool populateVfsList(const KURL& origin, bool showHidden); + +protected: + KURL origin_backup; //< used to backup the old URL when refreshing to a new one, + bool busy; + bool listError; +}; + +#endif diff --git a/src/app/VFS/krarchandler.cpp b/src/app/VFS/krarchandler.cpp new file mode 100644 index 0000000..faba80b --- /dev/null +++ b/src/app/VFS/krarchandler.cpp @@ -0,0 +1,785 @@ +/*************************************************************************** + krarchandler.cpp + ------------------- + copyright : (C) 2001 by Shie Erlich & Rafi Yanai + email : krusader@users.sourceforge.net + web site : http://krusader.sourceforge.net +--------------------------------------------------------------------------- + Description +*************************************************************************** + + A + + db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. + 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D + 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' + 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b + 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. + YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD + + S o u r c e F i l e + +*************************************************************************** +* * +* 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. * +* * +***************************************************************************/ +// TQt includes +#include <tqtextstream.h> +// TDE includes +#include <kprocess.h> +#include <tdetempfile.h> +#include <tdelocale.h> +#include <tdemessagebox.h> +#include <tdeio/passdlg.h> +#include <tqfile.h> +#include <kstandarddirs.h> +#include <ktar.h> +#include <tdeio/global.h> +// Krusader includes +#include "krarchandler.h" +#include "../krusader.h" +#include "../defaults.h" +#include "../krservices.h" +#include "../Dialogs/krpleasewait.h" + +static TQStringList arcProtocols = TQStringList::split(";", "tar;bzip;bzip2;gzip;krarc;zip;xz"); + +TDEWallet::Wallet * KRarcHandler::wallet = 0; + +TQStringList KRarcHandler::supportedPackers() { + TQStringList packers; + + // we will simply try to find the packers here.. + if ( KrServices::cmdExist( "tar" ) ) packers.append( "tar" ); + if ( KrServices::cmdExist( "gzip" ) ) packers.append( "gzip" ); + if ( KrServices::cmdExist( "bzip2" ) ) packers.append( "bzip2" ); + if ( KrServices::cmdExist( "unzip" ) ) packers.append( "unzip" ); + if ( KrServices::cmdExist( "zip" ) ) packers.append( "zip" ); + if ( KrServices::cmdExist( "lha" ) ) packers.append( "lha" ); + if ( KrServices::cmdExist( "cpio" ) ) packers.append( "cpio" ); + if ( KrServices::cmdExist( "unrar" ) ) packers.append( "unrar" ); + if ( KrServices::cmdExist( "rar" ) ) packers.append( "rar" ); + if ( KrServices::cmdExist( "arj" ) ) packers.append( "arj" ); + if ( KrServices::cmdExist( "unarj" ) ) packers.append( "unarj" ); + if ( KrServices::cmdExist( "unace" ) ) packers.append( "unace" ); + if ( KrServices::cmdExist( "dpkg" ) ) packers.append( "dpkg" ); + if ( KrServices::cmdExist( "7z" ) || KrServices::cmdExist( "7za" ) ) packers.append( "7z" ); + if ( KrServices::cmdExist( "rpm" ) && KrServices::cmdExist( "rpm2cpio" ) ) packers.append( "rpm" ); + if ( KrServices::cmdExist( "xz" ) ) packers.append( "xz" ); + // kdDebug() << "Supported Packers:" << endl; + //TQStringList::Iterator it; + //for( it = packers.begin(); it != packers.end(); ++it ) + // kdDebug() << *it << endl; + + return packers; + } + +bool KRarcHandler::arcSupported( TQString type ) { + // lst will contain the supported unpacker list... + krConfig->setGroup( "Archives" ); + TQStringList lst = krConfig->readListEntry( "Supported Packers" ); + + if ( type == "-zip" && lst.contains( "unzip" ) ) + return true; + else if ( type == "-tar" && lst.contains( "tar" ) ) + return true; + else if ( type == "-tbz" && lst.contains( "tar" ) ) + return true; + else if ( type == "-tgz" && lst.contains( "tar" ) ) + return true; + else if ( type == "-txz" && lst.contains( "tar" ) ) + return true; + else if ( type == "tarz" && lst.contains( "tar" ) ) + return true; + else if ( type == "gzip" && lst.contains( "gzip" ) ) + return true; + else if ( type == "zip2" && lst.contains( "bzip2" ) ) + return true; + else if ( type == "-lha" && lst.contains( "lha" ) ) + return true; + else if ( type == "-ace" && lst.contains( "unace" ) ) + return true; + else if ( type == "-rpm" && lst.contains( "cpio" ) ) + return true; + else if ( type == "cpio" && lst.contains( "cpio" ) ) + return true; + else if ( type == "-rar" && ( lst.contains( "unrar" ) || lst.contains( "rar" ) ) ) + return true; + else if ( type == "-arj" && ( lst.contains( "unarj" ) || lst.contains( "arj" ) ) ) + return true; + else if ( type == "-deb" && ( lst.contains( "dpkg" ) && lst.contains( "tar" ) ) ) + return true; + else if ( type == "-7z" && lst.contains( "7z" ) ) + return true; + else if ( type == "-xz" && lst.contains( "xz" ) ) + return true; + // not supported : ( + return false; + } + +bool KRarcHandler::arcHandled( TQString type ) { + // first check if supported + if ( !arcSupported( type ) ) return false; + + krConfig->setGroup( "Archives" ); + if ( ( type == "-tgz" && krConfig->readBoolEntry( "Do GZip" , _DoGZip ) ) || + ( type == "tarz" && krConfig->readBoolEntry( "Do GZip" , _DoGZip ) ) || + ( type == "-tar" && krConfig->readBoolEntry( "Do Tar" , _DoTar ) ) || + ( type == "-tbz" && krConfig->readBoolEntry( "Do BZip2", _DoBZip2 ) ) || + ( type == "-txz" && krConfig->readBoolEntry( "Do Xz" , _DoXz ) ) || + ( type == "gzip" && krConfig->readBoolEntry( "Do GZip" , _DoGZip ) ) || + ( type == "zip2" && krConfig->readBoolEntry( "Do BZip2", _DoBZip2 ) ) || + ( type == "-zip" && krConfig->readBoolEntry( "Do UnZip", _DoUnZip ) ) || + ( type == "-lha" && krConfig->readBoolEntry( "Do Lha" , _DoUnZip ) ) || + ( type == "-rar" && krConfig->readBoolEntry( "Do UnRar", _DoUnRar ) ) || + ( type == "-arj" && krConfig->readBoolEntry( "Do UnArj", _DoUnarj ) ) || + ( type == "-ace" && krConfig->readBoolEntry( "Do UnAce", _DoUnAce ) ) || + ( type == "cpio" && krConfig->readBoolEntry( "Do RPM" , _DoRPM ) ) || + ( type == "-rpm" && krConfig->readBoolEntry( "Do RPM" , _DoRPM ) ) || + ( type == "-deb" && krConfig->readBoolEntry( "Do DEB" , _DoDEB ) ) || + ( type == "-7z" && krConfig->readBoolEntry( "Do 7z" , _Do7z ) ) || + ( type == "-xz" && krConfig->readBoolEntry( "Do Xz" , _DoXz ) ) ) + return true; + else + return false; + } + + +long KRarcHandler::arcFileCount( TQString archive, TQString type, TQString password ) { + int divideWith = 1; + + // first check if supported + if ( !arcSupported( type ) ) return 0; + + // bzip, gzip and xz archives contain only one file + if ( type == "zip2" || type == "gzip" || type == "-xz") return 1L; + + // set the right lister to do the job + TQString lister; + + if ( type == "-zip" ) lister = KrServices::fullPathName( "unzip" ) + " -ZTs"; + else if ( type == "-tar" ) lister = KrServices::fullPathName( "tar" ) + " -tvf"; + else if ( type == "-tgz" ) lister = KrServices::fullPathName( "tar" ) + " -tvzf"; + else if ( type == "tarz" ) lister = KrServices::fullPathName( "tar" ) + " -tvzf"; + else if ( type == "-tbz" ) lister = KrServices::fullPathName( "tar" ) + " -tjvf"; + else if ( type == "-txz" ) lister = KrServices::fullPathName( "tar" ) + " -tJvf"; + else if ( type == "-lha" ) lister = KrServices::fullPathName( "lha" ) + " l"; + else if ( type == "-rar" ) lister = KrServices::fullPathName( KrServices::cmdExist( "rar" ) ? "rar" : "unrar" ) + " l -v"; + else if ( type == "-ace" ) lister = KrServices::fullPathName( "unace" ) + " l"; + else if ( type == "-arj" ) { if( KrServices::cmdExist( "arj" ) ) + lister = KrServices::fullPathName( "arj" ) + " v -y -v", + divideWith = 4; + else + lister = KrServices::fullPathName( "unarj" ) + " l"; + } + else if ( type == "-rpm" ) lister = KrServices::fullPathName( "rpm" ) + " --dump -lpq"; + else if ( type == "-deb" ) lister = KrServices::fullPathName( "dpkg" ) + " -c"; + else if ( type == "-7z" ) lister = KrServices::fullPathName( "7z" ) + " -y l"; + else if ( type == "-xz" ) lister = KrServices::fullPathName( "xz" ) + " -l"; + else return 0L; + + if ( !password.isNull() ) { + if ( type == "-arj" ) + lister += " -g'" + password + "'"; + if ( type == "-ace" || type == "-rar" || type == "-7z" ) + lister += " -p'" + password + "'"; + } + + // tell the user to wait + krApp->startWaiting( i18n( "Counting files in archive" ), 0, true ); + + // count the number of files in the archive + long count = 1; + KTempFile tmpFile( /*"tmp"*/ TQString(), "krusader-unpack" ); // commented out as it created files in the current dir! + KrShellProcess list; + list << lister << KrServices::quote( archive ) << ">" << tmpFile.name() ; + if( type == "-ace" && TQFile( "/dev/ptmx" ).exists() ) // Don't remove, unace crashes if missing!!! + list<< "<" << "/dev/ptmx"; + list.start( TDEProcess::NotifyOnExit, TDEProcess::AllOutput ); + while ( list.isRunning() ) { + usleep( 1000 ); + tqApp->processEvents(); + if( krApp->wasWaitingCancelled() ) + list.kill(); + } + ; // busy wait - need to find something better... + + krApp->stopWait(); + + if( !list.normalExit() || !checkStatus( type, list.exitStatus() ) ) { + KMessageBox::detailedError (krApp, i18n( "Failed to list the content of the archive (%1)!" ).arg( archive ), + list.getErrorMsg(), i18n("Error" ) ); + return 0; + } + + TQTextStream *stream = tmpFile.textStream(); + while ( stream && stream->readLine() != TQString() ) ++count; + tmpFile.unlink(); + + //make sure you call stopWait after this function return... + //krApp->stopWait(); + + return count / divideWith; + } + +bool KRarcHandler::unpack( TQString archive, TQString type, TQString password, TQString dest ) { + krConfig->setGroup( "Archives" ); + if ( krConfig->readBoolEntry( "Test Before Unpack", _TestBeforeUnpack ) ) { + // test first - or be sorry later... + if ( type != "-rpm" && type != "-deb" && !test( archive, type, password, 0 ) ) { + KMessageBox::error( krApp, i18n( "Failed to unpack" ) + " \"" + archive + "\" !" ); + return false; + } + } + + // count the files in the archive + long count = arcFileCount( archive, type, password ); + if ( count == 0 ) return false; // not supported + if ( count == 1 ) count = 0 ; + + // choose the right packer for the job + TQString packer, cpioName = TQString(); + + // set the right packer to do the job + if ( type == "-zip" ) packer = KrServices::fullPathName( "unzip" ) + " -o" ; + else if ( type == "-tar" ) packer = KrServices::fullPathName( "tar" ) + " -xvf"; + else if ( type == "-tgz" ) packer = KrServices::fullPathName( "tar" ) + " -xvzf"; + else if ( type == "tarz" ) packer = KrServices::fullPathName( "tar" ) + " -xvzf"; + else if ( type == "-tbz" ) packer = KrServices::fullPathName( "tar" ) + " -xjvf"; + else if ( type == "-txz" ) packer = KrServices::fullPathName( "tar" ) + " -xJvf"; + else if ( type == "gzip" ) packer = KrServices::fullPathName( "gzip" ) + " -cd"; + else if ( type == "zip2" ) packer = KrServices::fullPathName( "bzip2" ) + " -cdk"; + else if ( type == "-lha" ) packer = KrServices::fullPathName( "lha" ) + " xf"; + else if ( type == "-rar" ) packer = KrServices::fullPathName( KrServices::cmdExist( "rar" ) ? "rar" : "unrar" ) + " -y x"; + else if ( type == "-ace" ) packer = KrServices::fullPathName( "unace" ) + " x"; + else if ( type == "-arj" ) packer = KrServices::cmdExist( "arj" ) ? + KrServices::fullPathName( "arj" ) + " -y -v x" : + KrServices::fullPathName( "unarj" ) + " x"; + else if ( type == "-7z" ) packer = KrServices::fullPathName( "7z" ) + " -y x"; + else if ( type == "-xz" ) packer = KrServices::fullPathName( "xz" ) + " -cdk"; + else if ( type == "-rpm" ) { + TQString tempDir = locateLocal("tmp",TQString()); + + cpioName = tempDir+"/contents.cpio"; + + KrShellProcess cpio; + cpio << KrServices::fullPathName( "rpm2cpio" ) << " " + KrServices::quote( archive ) << " > " << cpioName; + cpio.start(TDEProcess::Block, TDEProcess::AllOutput ); + if( !cpio.normalExit() || !checkStatus( "cpio", cpio.exitStatus() ) ) { + KMessageBox::detailedError (krApp, i18n( "Failed to convert rpm (%1) to cpio!" ).arg( archive ), + cpio.getErrorMsg(), i18n("Error" ) ); + return 0; + } + + archive = cpioName; + packer = KrServices::fullPathName( "cpio" ) + " --force-local --no-absolute-filenames -iuvdF"; + } + else if ( type == "-deb" ) { + TQString tempDir = locateLocal("tmp",TQString()); + + cpioName = tempDir+"/contents.tar"; + + KrShellProcess dpkg; + dpkg << KrServices::fullPathName( "dpkg" ) << " --fsys-tarfile " + KrServices::quote( archive ) << " > " << cpioName; + dpkg.start(TDEProcess::Block, TDEProcess::AllOutput ); + if( !dpkg.normalExit() || !checkStatus( "-deb", dpkg.exitStatus() ) ) { + KMessageBox::detailedError (krApp, i18n( "Failed to convert deb (%1) to tar!" ).arg( archive ), + dpkg.getErrorMsg(), i18n("Error" ) ); + return 0; + } + + archive = cpioName; + packer = KrServices::fullPathName( "tar" ) + " xvf "; + } + else return false; + + if ( !password.isNull() ) { + if ( type == "-zip" ) + packer += " -P '" + password + "'"; + if ( type == "-arj" ) + packer += " -g'" + password + "'"; + if ( type == "-ace" || type == "-rar" || type == "-7z" ) + packer += " -p'" + password + "'"; + } + + // unpack the files + KrShellProcess proc; + proc << packer << " " + KrServices::quote( archive ); + if( type == "zip2" || type=="gzip" ){ + TQString arcname = archive.mid(archive.findRev("/")+1); + if( arcname.contains(".") ) arcname = arcname.left(arcname.findRev(".")); + proc << ">" << KrServices::quote( dest+"/"+arcname ); + } + if( type == "-ace" && TQFile( "/dev/ptmx" ).exists() ) // Don't remove, unace crashes if missing!!! + proc << "<" << "/dev/ptmx"; + + TQString save = getcwd( 0, 0 ); + chdir( dest.local8Bit() ); + + // tell the user to wait + krApp->startWaiting( i18n( "Unpacking File(s)" ), count, true ); + if ( count != 0 ) { + connect( &proc, TQ_SIGNAL( receivedStdout( TDEProcess*, char*, int ) ), + krApp, TQ_SLOT( incProgress( TDEProcess*, char*, int ) ) ); + if( type == "-rpm" ) + connect( &proc, TQ_SIGNAL( receivedStderr( TDEProcess*, char*, int ) ), + krApp, TQ_SLOT( incProgress( TDEProcess*, char*, int ) ) ); + } + + // start the unpacking process + proc.start( TDEProcess::NotifyOnExit, TDEProcess::AllOutput ); + while ( proc.isRunning() ) { + usleep( 1000 ); + tqApp->processEvents(); + if( krApp->wasWaitingCancelled() ) + proc.kill(); + } + ; // busy wait - need to find something better... + krApp->stopWait(); + chdir( save.local8Bit() ); + + if( !cpioName.isEmpty() ) + TQFile( cpioName ).remove(); /* remove the cpio file */ + + // check the return value + if ( !proc.normalExit() || !checkStatus( type, proc.exitStatus() ) ) { + KMessageBox::detailedError (krApp, i18n( "Failed to unpack %1!" ).arg( archive ), + krApp->wasWaitingCancelled() ? i18n( "User cancelled." ) : + proc.getErrorMsg(), i18n("Error" ) ); + return false; + } + return true; // SUCCESS + } + +bool KRarcHandler::test( TQString archive, TQString type, TQString password, long count ) { + // choose the right packer for the job + TQString packer; + + // set the right packer to do the job + if ( type == "-zip" ) packer = KrServices::fullPathName( "unzip" ) + " -t"; + else if ( type == "-tar" ) packer = KrServices::fullPathName( "tar" ) + " -tvf"; + else if ( type == "-tgz" ) packer = KrServices::fullPathName( "tar" ) + " -tvzf"; + else if ( type == "tarz" ) packer = KrServices::fullPathName( "tar" ) + " -tvzf"; + else if ( type == "-tbz" ) packer = KrServices::fullPathName( "tar" ) + " -tjvf"; + else if ( type == "-txz" ) packer = KrServices::fullPathName( "tar" ) + " -tJvf"; + else if ( type == "gzip" ) packer = KrServices::fullPathName( "gzip" ) + " -tv"; + else if ( type == "zip2" ) packer = KrServices::fullPathName( "bzip2" ) + " -tv"; + else if ( type == "-rar" ) packer = KrServices::fullPathName( KrServices::cmdExist( "rar" ) ? "rar" : "unrar" ) + " t"; + else if ( type == "-ace" ) packer = KrServices::fullPathName( "unace" ) + " t"; + else if ( type == "-lha" ) packer = KrServices::fullPathName( "lha" ) + " t"; + else if ( type == "-arj" ) packer = KrServices::fullPathName( KrServices::cmdExist( "arj" ) ? "arj" : "unarj" ) + " t"; + else if ( type == "cpio" ) packer = KrServices::fullPathName( "cpio" ) + " --only-verify-crc -tvF" ; + else if ( type == "-7z" ) packer = KrServices::fullPathName( "7z" ) + " -y t"; + else if ( type == "-xz" ) packer = KrServices::fullPathName( "xz" ) + " -tv"; + else return false; + + if ( !password.isNull() ) { + if ( type == "-zip" ) + packer += " -P '" + password + "'"; + if ( type == "-arj" ) + packer += " -g'" + password + "'"; + if ( type == "-ace" || type == "-rar" || type == "-7z" ) + packer += " -p'" + password + "'"; + } + + // unpack the files + KrShellProcess proc; + proc << packer << KrServices::quote( archive ); + + if( type == "-ace" && TQFile( "/dev/ptmx" ).exists() ) // Don't remove, unace crashes if missing!!! + proc << "<" << "/dev/ptmx"; + + // tell the user to wait + krApp->startWaiting( i18n( "Testing Archive" ), count, true ); + if ( count != 0 ) connect( &proc, TQ_SIGNAL( receivedStdout( TDEProcess*, char*, int ) ), + krApp, TQ_SLOT( incProgress( TDEProcess*, char*, int ) ) ); + + // start the unpacking process + proc.start( TDEProcess::NotifyOnExit, TDEProcess::AllOutput ); + while ( proc.isRunning() ) { + usleep( 1000 ); + tqApp->processEvents(); + if( krApp->wasWaitingCancelled() ) + proc.kill(); + } + ; // busy wait - need to find something better... + krApp->stopWait(); + + // check the return value + if ( !proc.normalExit() || !checkStatus( type, proc.exitStatus() ) ) + return false; + + return true; // SUCCESS + } + +bool KRarcHandler::pack( TQStringList fileNames, TQString type, TQString dest, long count, TQMap<TQString,TQString> extraProps ) { + // set the right packer to do the job + TQString packer; + + if ( type == "zip" ) { packer = KrServices::fullPathName( "zip" ) + " -ry"; type = "-zip"; } + else if ( type == "tar" ) { packer = KrServices::fullPathName( "tar" ) + " -cvf"; type = "-tar"; } + else if ( type == "tar.gz" ) { packer = KrServices::fullPathName( "tar" ) + " -cvzf"; type = "-tgz"; } + else if ( type == "tar.bz2" ) { packer = KrServices::fullPathName( "tar" ) + " -cvjf"; type = "-tbz"; } + else if ( type == "tar.xz" ) { packer = KrServices::fullPathName( "tar" ) + " -cvJf"; type = "-txz"; } + else if ( type == "rar" ) { packer = KrServices::fullPathName( "rar" ) + " -r a"; type = "-rar"; } + else if ( type == "lha" ) { packer = KrServices::fullPathName( "lha" ) + " a"; type = "-lha"; } + else if ( type == "arj" ) { packer = KrServices::fullPathName( "arj" ) + " -r -y a"; type = "-arj"; } + else if ( type == "7z" ) { packer = KrServices::fullPathName( "7z" ) + " -y a"; type = "-7z"; } + else if ( type == "xz" ) { packer = KrServices::fullPathName( "xz" ) + " -z"; type = "-xz"; } + else return false; + + TQString password = TQString(); + + if( extraProps.count( "Password" ) > 0 ) { + password = extraProps[ "Password" ]; + + if ( !password.isNull() ) { + if ( type == "-zip" ) + packer += " -P '" + password + "'"; + else if ( type == "-arj" ) + packer += " -g'" + password + "'"; + else if ( type == "-ace" || type == "-7z" ) + packer += " -p'" + password + "'"; + else if ( type == "-rar" ) { + if( extraProps.count( "EncryptHeaders" ) > 0 ) + packer += " -hp'" + password + "'"; + else + packer += " -p'" + password + "'"; + } + else + password = TQString(); + } + } + + if( extraProps.count( "VolumeSize" ) > 0 ) { + TQString sizeStr = extraProps[ "VolumeSize" ]; + TDEIO::filesize_t size = sizeStr.toLongLong(); + + if( size >= 10000 ) { + if( type == "-arj" || type == "-rar" ) + packer += TQString( " -v%1b" ).arg( sizeStr ); + } + } + + if( extraProps.count( "CompressionLevel" ) > 0 ) { + int level = extraProps[ "CompressionLevel" ].toInt() - 1; + if ( level < 0 ) + level = 0; + if ( level > 8 ) + level = 8; + + if( type == "-rar" ) { + static const int rarLevels[] = { 0, 1, 2, 2, 3, 3, 4, 4, 5 }; + packer += TQString( " -m%1" ).arg( rarLevels[ level ] ); + } + else if( type == "-arj" ) { + static const int arjLevels[] = { 0, 4, 4, 3, 3, 2, 2, 1, 1 }; + packer += TQString( " -m%1" ).arg( arjLevels[ level ] ); + } + else if( type == "-zip" ) { + static const int zipLevels[] = { 0, 1, 2, 4, 5, 6, 7, 8, 9 }; + packer += TQString( " -%1" ).arg( zipLevels[ level ] ); + } + else if( type == "-7z" ) { + static const int sevenZipLevels[] = { 0, 1, 2, 4, 5, 6, 7, 8, 9 }; + packer += TQString( " -mx%1" ).arg( sevenZipLevels[ level ] ); + } + else if( type == "-xz" ) { + static const int xzLevels[] = { 0, 1, 2, 4, 5, 6, 7, 8, 9 }; + packer += TQString( " -%1" ).arg( xzLevels[ level ] ); + } + } + + if( extraProps.count( "CommandLineSwitches" ) > 0 ) + packer += TQString( " %1" ).arg( extraProps[ "CommandLineSwitches" ] ); + + // prepare to pack + KrShellProcess proc; + proc << packer << KrServices::quote( dest ); + + for ( TQStringList::Iterator file = fileNames.begin(); file != fileNames.end(); ++file ) { + proc << KrServices::quote( *file ); + } + + // tell the user to wait + krApp->startWaiting( i18n( "Packing File(s)" ), count, true ); + if ( count != 0 ) + connect( &proc, TQ_SIGNAL( receivedStdout( TDEProcess*, char*, int ) ), + krApp, TQ_SLOT( incProgress( TDEProcess*, char*, int ) ) ); + + // start the packing process + proc.start( TDEProcess::NotifyOnExit, TDEProcess::AllOutput ); + while ( proc.isRunning() ) { + usleep( 1000 ); + tqApp->processEvents(); + if( krApp->wasWaitingCancelled() ) + proc.kill(); + } + ; // busy wait - need to find something better... + krApp->stopWait(); + + // check the return value + if ( !proc.normalExit() || !checkStatus( type, proc.exitStatus() ) ) { + KMessageBox::detailedError (krApp, i18n( "Failed to pack %1!" ).arg( dest ), + krApp->wasWaitingCancelled() ? i18n( "User cancelled." ) : proc.getErrorMsg(), + i18n("Error" ) ); + return false; + } + + krConfig->setGroup( "Archives" ); + if ( krConfig->readBoolEntry( "Test Archives", _TestArchives ) && + !test( dest, type, password, count ) ) { + KMessageBox::error( krApp, i18n( "Failed to pack: " ) + dest, i18n( "Error" ) ); + return false; + } + return true; // SUCCESS + } + +TQString KRarcHandler::getPassword( TQString path ) { + TQString password; + + TQString key = "krarc-" + path; + + if( !TDEWallet::Wallet::keyDoesNotExist(TDEWallet::Wallet::NetworkWallet(), TDEWallet::Wallet::PasswordFolder(), key ) ) { + if( !TDEWallet::Wallet::isOpen( TDEWallet::Wallet::NetworkWallet() ) && wallet != 0 ) { + delete wallet; + wallet = 0; + } + if( wallet == 0 ) + wallet = TDEWallet::Wallet::openWallet( TDEWallet::Wallet::NetworkWallet() ); + if ( wallet && wallet->hasFolder( TDEWallet::Wallet::PasswordFolder() ) ) { + wallet->setFolder( TDEWallet::Wallet::PasswordFolder() ); + TQMap<TQString,TQString> map; + if ( wallet->readMap( key, map ) == 0 ) { + TQMap<TQString, TQString>::ConstIterator it = map.find( "password" ); + if ( it != map.end() ) + password = it.data(); + } + } + } + + bool keep = true; + TQString user = "archive"; + TDEIO::PasswordDialog passDlg( i18n("This archive is encrypted, please supply the password:"), + user, true ); + passDlg.setPassword( password ); + if (passDlg.exec() == TDEIO::PasswordDialog::Accepted) { + password = passDlg.password(); + if ( keep ) { + if( !TDEWallet::Wallet::isOpen( TDEWallet::Wallet::NetworkWallet() ) && wallet != 0 ) { + delete wallet; + wallet = 0; + } + if ( !wallet ) + wallet = TDEWallet::Wallet::openWallet( TDEWallet::Wallet::NetworkWallet() ); + if ( wallet ) { + bool ok = true; + if ( !wallet->hasFolder( TDEWallet::Wallet::PasswordFolder() ) ) + ok = wallet->createFolder( TDEWallet::Wallet::PasswordFolder() ); + if ( ok ) { + wallet->setFolder( TDEWallet::Wallet::PasswordFolder() ); + TQMap<TQString,TQString> map; + map.insert( "login", "archive" ); + map.insert( "password", password ); + wallet->writeMap( key, map ); + } + } + } + return password; + } + + return ""; +} + +bool KRarcHandler::isArchive(const KURL& url) { + TQString protocol = url.protocol(); + if (arcProtocols.find(protocol) != arcProtocols.end()) + return true; + else return false; +} + +TQString KRarcHandler::getType( bool &encrypted, TQString fileName, TQString mime, bool checkEncrypted ) { + TQString result = detectArchive( encrypted, fileName, checkEncrypted ); + if( result.isNull() ) + result = mime; + else + result = "-" + result; + + if (result.endsWith("-7z")) + { + result = "-7z"; + } + if (result.endsWith("-xz")) + { + result = "-xz"; + } + + return result.right( 4 ); +} + + +bool KRarcHandler::checkStatus( TQString type, int exitCode ) { + if( type == "-zip" || type == "-rar" || type == "-7z" ) + return exitCode == 0 || exitCode == 1; + else if( type == "-ace" || type == "zip2" || type == "-lha" || type == "-rpm" || type == "cpio" || + type == "-tar" || type == "tarz" || type == "-tbz" || type == "-tgz" || type == "-arj" || + type == "-deb" || type == "-txz" || type == "-xz") + return exitCode == 0; + else if (type == "gzip" || type == "-xz") + return exitCode == 0 || exitCode == 2; + else + return exitCode == 0; +} + +struct AutoDetectParams { + TQString type; + int location; + TQString detectionString; +}; + +TQString KRarcHandler::detectArchive( bool &encrypted, TQString fileName, bool checkEncrypted ) { + 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" }, + {"xz", 0, "\xfd" "7zXZ\x00" } }; + static int autoDetectElems = sizeof( autoDetectParams ) / sizeof( AutoDetectParams ); + + encrypted = false; + + TQFile 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++ ) { + TQString 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() ) { + TQString 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( checkEncrypted ) { // encryption check is expensive + // check only if it's necessary + Kr7zEncryptionChecker proc; + proc << KrServices::fullPathName( "7z" ) << " -y t"; + proc << KrServices::quote( fileName ); + proc.start(TDEProcess::Block,TDEProcess::AllOutput); + encrypted = proc.isEncrypted(); + } + } + else if( type == "xz" && (fileName.endsWith(".tar.xz") || fileName.endsWith(".txz")) ) + type = "txz"; + 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 TQString(); +} + +#include "krarchandler.moc" + diff --git a/src/app/VFS/krarchandler.h b/src/app/VFS/krarchandler.h new file mode 100644 index 0000000..506162a --- /dev/null +++ b/src/app/VFS/krarchandler.h @@ -0,0 +1,151 @@ +/*************************************************************************** + krarchandler.h + ------------------- + copyright : (C) 2001 by Shie Erlich & Rafi Yanai + email : krusader@users.sourceforge.net + web site : http://krusader.sourceforge.net + --------------------------------------------------------------------------- + Description: this class will supply static archive handling functions. + *************************************************************************** + + A + + db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. + 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D + 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' + 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b + 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. + YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD + + H e a d e r F i l e + + *************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +#ifndef KRARCHANDLER_H +#define KRARCHANDLER_H + +#include <tqstringlist.h> +#include <tqobject.h> +#include <kprocess.h> +#include <kurl.h> +#include <tdewallet.h> + +class KRarcHandler: public TQObject { + TQ_OBJECT + +public: + // return the number of files in the archive + static long arcFileCount(TQString archive, TQString type, TQString password); + // unpack an archive to destination directory + static bool unpack(TQString archive, TQString type, TQString password, TQString dest ); + // pack an archive to destination directory + static bool pack(TQStringList fileNames, TQString type, TQString dest, long count, TQMap<TQString,TQString> extraProps ); + // test an archive + static bool test(TQString archive, TQString type, TQString password, long count = 0L ); + // true - if the right unpacker exist in the system + static bool arcSupported(TQString type); + // true - if supported and the user want us to handle this kind of archive + static bool arcHandled(TQString type); + // return the a list of supported packers + static TQStringList supportedPackers(); + // true - if the url is an archive (ie: tar:/home/test/file.tar.bz2) + static bool isArchive(const KURL& url); + // used to determine the type of the archive + static TQString getType( bool &encrypted, TQString fileName, TQString mime, bool checkEncrypted = true ); + // queries the password from the user + static TQString getPassword( TQString path ); + // detects the archive type + static TQString detectArchive( bool &encrypted, TQString fileName, bool checkEncrypted = true ); +private: + // checks if the returned status is correct + static bool checkStatus( TQString type, int exitCode ); + + static TDEWallet::Wallet * wallet; +}; + +class KrShellProcess : public KShellProcess { + TQ_OBJECT + +public: + KrShellProcess() : KShellProcess(), errorMsg( TQString() ), outputMsg( TQString() ) { + connect(this,TQ_SIGNAL(receivedStderr(TDEProcess*,char*,int)), + this,TQ_SLOT(receivedErrorMsg(TDEProcess*,char*,int)) ); + connect(this,TQ_SIGNAL(receivedStdout(TDEProcess*,char*,int)), + this,TQ_SLOT(receivedOutputMsg(TDEProcess*,char*,int)) ); + } + + TQString getErrorMsg() { + if( errorMsg.stripWhiteSpace().isEmpty() ) + return outputMsg.right( 500 ); + else + return errorMsg.right( 500 ); + } + +public slots: + void receivedErrorMsg(TDEProcess*, char *buf, int len) { + errorMsg += TQString::fromLocal8Bit( buf, len ); + if( errorMsg.length() > 500 ) + errorMsg = errorMsg.right( 500 ); + receivedOutputMsg( 0, buf, len ); + } + + void receivedOutputMsg(TDEProcess*, char *buf, int len) { + outputMsg += TQString::fromLocal8Bit( buf, len ); + if( outputMsg.length() > 500 ) + outputMsg = outputMsg.right( 500 ); + } + +private: + TQString errorMsg; + TQString outputMsg; +}; + +class Kr7zEncryptionChecker : public KrShellProcess { + TQ_OBJECT + + +public: + Kr7zEncryptionChecker() : KrShellProcess(), encrypted( false ), lastData() { + connect(this,TQ_SIGNAL(receivedStdout(TDEProcess*,char*,int)), + this,TQ_SLOT(processStdout(TDEProcess*,char*,int)) ); + } + +public slots: + void processStdout( TDEProcess *proc,char *buf,int len ) { + TQByteArray d(len); + d.setRawData(buf,len); + TQString data = TQString( d ); + d.resetRawData(buf,len); + + TQString checkable = lastData + data; + + TQStringList lines = TQStringList::split( '\n', checkable ); + lastData = lines[ lines.count() - 1 ]; + for( unsigned i=0; i != lines.count(); i++ ) { + TQString 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" ) ) { + encrypted = true; + proc->kill(); + } + } + } + + bool isEncrypted() { return encrypted; } +private: + bool encrypted; + TQString lastData; +}; + +#endif diff --git a/src/app/VFS/krdirwatch.cpp b/src/app/VFS/krdirwatch.cpp new file mode 100644 index 0000000..fe4e2de --- /dev/null +++ b/src/app/VFS/krdirwatch.cpp @@ -0,0 +1,124 @@ +/*************************************************************************** + krdirwatch.cpp + ------------------- + copyright : (C) 2000 by Shie Erlich & Rafi Yanai + e-mail : krusader@users.sourceforge.net + web site : http://krusader.sourceforge.net + --------------------------------------------------------------------------- + Description + *************************************************************************** + + A + + db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. + 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D + 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' + 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b + 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. + YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD + + S o u rc e F i l e + + *************************************************************************** + * * + * 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 "krdirwatch.h" +#include <unistd.h> +#include <sys/types.h> +#include <kdebug.h> +#include "krpermhandler.h" +#include "tqstringlist.h" +#include <tqdir.h> + +KRdirWatch::KRdirWatch(int msec,bool dirOnly): + delay(msec),t(this), changed(false) { + if(dirOnly) dir.setFilter( TQDir::Dirs | TQDir::Hidden | TQDir::NoSymLinks ); + watched.setAutoDelete(true); + connect(&t,TQ_SIGNAL(timeout()),this, TQ_SLOT(checkDirs())); + startScan(); +} + +KRdirWatch::~KRdirWatch(){ + clearList(); + stopScan(); +} + +void KRdirWatch::removeDir(TQString path){ + t.stop(); + for ( it = watched.first(); it != 0; ) + if (it->path == path) watched.remove(); + else it = watched.next(); + if (!stopped) startScan(); +} + +void KRdirWatch::addDir(TQString path, bool checkPermissions){ + t.stop(); + + krDirEntry* temp = new krDirEntry; + if (!dir.cd(path)){ // if it's not a dir or don't exist - don't add it + //kdDebug() << "KRDirWatch: can't watch " + path +", (don't exist)" << endl; + return; + } + if( checkPermissions ) { + // if we can't read it - don't bother + if (getgid() != 0 && !KRpermHandler::fileReadable(path) ){ + //kdDebug() << "KRDirWatch: can't watch " + path +", (not readable)" << endl; + return; + } + if (!KRpermHandler::fileWriteable(path) ){ // read-only directorys can't be changed + //kdDebug() << "KRDirWatch: not watching " + path +", (read-only directory)" << endl; + return; + } + } + qfi.setFile(path); + + temp->path = dir.path(); + temp->count = dir.entryList(TQDir::All | TQDir::AccessMask).count(); + temp->lastModified = qfi.lastModified(); + + watched.append(temp); + if (!stopped) startScan(); +} + +// here we do the actual checking +void KRdirWatch::checkDirs(){ + t.stop(); + + TQString path; + unsigned long count; + TQDateTime dt; + + for ( it = watched.first(); it != 0; it = watched.next() ){ + path = it->path; + qfi.setFile(path); + if (!dir.cd(path)){ + clearList(); + emit dirty(); + return; + } + dt = qfi.lastModified(); + count = dir.entryList(TQDir::All | TQDir::AccessMask).count(); + // check for changes + if(it->lastModified!=dt || it->count!=count){ + changed = true; + it->lastModified=dt; + it->count=count; + startScan(); + return; + } + if(changed){ + changed = false; + clearList(); + emit dirty(); + return; + } + } + if (!stopped) startScan(); +} + +#include "krdirwatch.moc" diff --git a/src/app/VFS/krdirwatch.h b/src/app/VFS/krdirwatch.h new file mode 100644 index 0000000..e99618b --- /dev/null +++ b/src/app/VFS/krdirwatch.h @@ -0,0 +1,80 @@ +/*************************************************************************** + krdirwatch.h + ------------------- + begin : Thu May 4 2000 + copyright : (C) 2000 by Shie Erlich & Rafi Yanai + e-mail : krusader@users.sourceforge.net + web site : http://krusader.sourceforge.net + --------------------------------------------------------------------------- + Description + *************************************************************************** + + A + + db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. + 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D + 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' + 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b + 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. + YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD + + H e a d e r F i l e + + *************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + + +#ifndef KRDIRWATCH_H +#define KRDIRWATCH_H + +#include <tqobject.h> +#include <tqstring.h> +#include <tqptrlist.h> +#include <tqtimer.h> +#include <tqdatetime.h> +#include <tqdir.h> + + +typedef struct krDirEntry_s{ + TQString path; + unsigned long count; // number of files + TQDateTime lastModified; +} krDirEntry ; + +class KRdirWatch : public TQObject { + TQ_OBJECT + +public: + KRdirWatch(int msec = 250 , bool dirOnly = false ); + ~KRdirWatch(); + void addDir(TQString path,bool checkPermissions = true ); + void removeDir(TQString path); + + inline void clearList(){watched.clear();} + inline void startScan(){t.start(delay);stopped=false;} + inline void stopScan() {t.stop(); stopped=true;} + +public slots: + void checkDirs(); // here we do the actual checking + +signals: + void dirty(); + +protected: + int delay; // time in msec between updates + TQPtrList<krDirEntry> watched; + TQTimer t; + TQDir dir; + TQFileInfo qfi; + krDirEntry* it; + bool changed; // true if something happend to the watched dirs + bool stopped; // true if the watcher is stopped +}; + +#endif diff --git a/src/app/VFS/krpermhandler.cpp b/src/app/VFS/krpermhandler.cpp new file mode 100644 index 0000000..aa955aa --- /dev/null +++ b/src/app/VFS/krpermhandler.cpp @@ -0,0 +1,355 @@ +/*************************************************************************** + krpermhandler.cpp + ------------------- + copyright : (C) 2000 by Shie Erlich & Rafi Yanai + email : krusader@users.sourceforge.net + web site : http://krusader.sourceforge.net +--------------------------------------------------------------------------- + Description +*************************************************************************** + + A + + db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. + 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D + 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' + 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b + 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. + YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD + + S o u r c e F i l e + +*************************************************************************** +* * +* 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. * +* * +***************************************************************************/ + + +// System includes +#include <unistd.h> +#include <math.h> +#include <pwd.h> +#include <grp.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <dirent.h> +#include <time.h> +#include <tdelocale.h> +#include <tdeglobal.h> +#include <klargefile.h> +// TQt includes +#include <tqdatetime.h> +#include <tqdir.h> +// krusader includes +#include <tdeversion.h> +#include "krpermhandler.h" +#include "../resources.h" + +TQDict<uid_t> *KRpermHandler::passwdCache = 0L; +TQDict<gid_t> *KRpermHandler::groupCache = 0L; +TQIntDict<char> *KRpermHandler::currentGroups = 0L; +TQIntDict<TQString> *KRpermHandler::uidCache = 0L; +TQIntDict<TQString> *KRpermHandler::gidCache = 0L; + +char KRpermHandler::writeable( TQString perm, gid_t gid, uid_t uid, int rwx ) { + if( rwx != -1 ) + return ( rwx & W_OK ) ? ALLOWED_PERM : NO_PERM; + // root override + if ( getuid() == 0 ) + return ALLOWED_PERM; + // first check other permissions. + if ( perm[ 8 ] != '-' ) return ALLOWED_PERM; + // now check group permission + if ( ( perm[ 5 ] != '-' ) && ( currentGroups->find( gid ) ) ) + return ALLOWED_PERM; + // the last chance - user permissions + if ( ( perm[ 2 ] != '-' ) && ( uid == getuid() ) ) + return ALLOWED_PERM; + // sorry ! + return NO_PERM; +} + +char KRpermHandler::readable( TQString perm, gid_t gid, uid_t uid, int rwx ) { + if( rwx != -1 ) + return ( rwx & R_OK ) ? ALLOWED_PERM : NO_PERM; + // root override + if ( getuid() == 0 ) + return ALLOWED_PERM; + // first check other permissions. + if ( perm[ 7 ] != '-' ) return ALLOWED_PERM; + // now check group permission + if ( ( perm[ 4 ] != '-' ) && ( currentGroups->find( gid ) ) ) + return ALLOWED_PERM; + // the last chance - user permissions + if ( ( perm[ 1 ] != '-' ) && ( uid == getuid() ) ) + return ALLOWED_PERM; + // sorry ! + return NO_PERM; +} + +char KRpermHandler::executable( TQString perm, gid_t gid, uid_t uid, int rwx ) { + if( rwx != -1 ) + return ( rwx & X_OK ) ? ALLOWED_PERM : NO_PERM; + // first check other permissions. + if ( perm[ 9 ] != '-' ) return ALLOWED_PERM; + // now check group permission + if ( ( perm[ 6 ] != '-' ) && ( currentGroups->find( gid ) ) ) + return ALLOWED_PERM; + // the last chance - user permissions + if ( ( perm[ 3 ] != '-' ) && ( uid == getuid() ) ) + return ALLOWED_PERM; + // sorry ! + return NO_PERM; +} + +bool KRpermHandler::fileWriteable( TQString localFile ) { + KDE_struct_stat stat_p; + if ( KDE_stat( localFile.local8Bit(), &stat_p ) == -1 ) return false; + mode_t m = stat_p.st_mode; + TQString perm = mode2TQString( m ); + return writeable( perm, stat_p.st_gid, stat_p.st_uid ); +} + +bool KRpermHandler::fileReadable( TQString localFile ) { + KDE_struct_stat stat_p; + if ( KDE_stat( localFile.local8Bit(), &stat_p ) == -1 ) return false; + mode_t m = stat_p.st_mode; + TQString perm = mode2TQString( m ); + return readable( perm, stat_p.st_gid, stat_p.st_uid ); +} + +bool KRpermHandler::fileExecutable( TQString localFile ) { + KDE_struct_stat stat_p; + if ( KDE_stat( localFile.local8Bit(), &stat_p ) == -1 ) return false; + mode_t m = stat_p.st_mode; + TQString perm = mode2TQString( m ); + return executable( perm, stat_p.st_gid, stat_p.st_uid ); +} + +TQString KRpermHandler::mode2TQString( mode_t m ) { + char perm[ 11 ]; + for( int i=0; i != 10; i++ ) + perm[ i ] = '-'; + perm[ 10 ] = 0; + + if ( S_ISLNK( m ) ) perm[ 0 ] = 'l'; // check for symLink + if ( S_ISDIR( m ) ) perm[ 0 ] = 'd'; // check for directory + + //ReadUser = 0400, WriteUser = 0200, ExeUser = 0100, Suid = 04000 + if ( m & 0400 ) perm[ 1 ] = 'r'; + if ( m & 0200 ) perm[ 2 ] = 'w'; + if ( m & 0100 ) perm[ 3 ] = 'x'; + if ( m & 04000 ) perm[ 3 ] = 's'; + //ReadGroup = 0040, WriteGroup = 0020, ExeGroup = 0010, Gid = 02000 + if ( m & 0040 ) perm[ 4 ] = 'r'; + if ( m & 0020 ) perm[ 5 ] = 'w'; + if ( m & 0010 ) perm[ 6 ] = 'x'; + if ( m & 02000 ) perm[ 6 ] = 's'; + //ReadOther = 0004, WriteOther = 0002, ExeOther = 0001, Sticky = 01000 + if ( m & 0004 ) perm[ 7 ] = 'r'; + if ( m & 0002 ) perm[ 8 ] = 'w'; + if ( m & 0001 ) perm[ 9 ] = 'x'; + if ( m & 01000 ) perm[ 9 ] = 't'; + + return TQString( perm ); +} + +void KRpermHandler::init() { + // set the umask to 022 + //umask( 022 ); + + // 50 groups should be enough + gid_t groupList[ 50 ]; + int groupNo = getgroups( 50, groupList ); + + // init the groups and user caches + passwdCache = new TQDict<uid_t>( 317 ); + groupCache = new TQDict<gid_t>( 317 ); + currentGroups = new TQIntDict<char>( 317 ); + uidCache = new TQIntDict<TQString>( 317 ); + gidCache = new TQIntDict<TQString>( 317 ); + + + passwdCache->setAutoDelete( true ); + groupCache->setAutoDelete( true ); + currentGroups->setAutoDelete( true ); + uidCache->setAutoDelete( true ); + gidCache->setAutoDelete( true ); + + // fill the UID cache + struct passwd *pass; + uid_t* uid_temp; + while ( ( pass = getpwent() ) != 0L ) { + uid_temp = new uid_t( pass->pw_uid ); + passwdCache->insert( pass->pw_name, uid_temp ); + uidCache->insert( pass->pw_uid, new TQString( pass->pw_name ) ); + } + delete pass; + endpwent(); + + // fill the GID cache + struct group *gr; + gid_t* gid_temp; + while ( ( gr = getgrent() ) != 0L ) { + gid_temp = new gid_t( gr->gr_gid ); + groupCache->insert( gr->gr_name, gid_temp ); + gidCache->insert( gr->gr_gid, new TQString( gr->gr_name ) ); + } + delete gr; + endgrent(); + + // fill the groups for the current user + char * t = new char( 1 ); + for ( int i = 0; i < groupNo; ++i ) { + currentGroups->insert( groupList[ i ], t ); + } + // just to be sure add the effective gid... + currentGroups->insert( getegid(), t ); +} + +char KRpermHandler::ftpWriteable ( TQString fileOwner, TQString userName, TQString perm ) { + // first check other permissions. + if ( perm[ 8 ] != '-' ) return ALLOWED_PERM; + // can't check group permission ! + // so check the user permissions + if ( ( perm[ 2 ] != '-' ) && ( fileOwner == userName ) ) + return ALLOWED_PERM; + if ( ( perm[ 2 ] != '-' ) && ( userName.isEmpty() ) ) + return UNKNOWN_PERM; + if ( perm[ 5 ] != '-' ) return UNKNOWN_PERM; + return NO_PERM; +} + +char KRpermHandler::ftpReadable ( TQString fileOwner, TQString userName, TQString perm ) { + // first check other permissions. + if ( perm[ 7 ] != '-' ) return ALLOWED_PERM; + // can't check group permission ! + // so check the user permissions + if ( ( perm[ 1 ] != '-' ) && ( fileOwner == userName ) ) + return ALLOWED_PERM; + if ( ( perm[ 1 ] != '-' ) && ( userName.isEmpty() ) ) + return UNKNOWN_PERM; + if ( perm[ 4 ] != '-' ) return UNKNOWN_PERM; + return NO_PERM; +} + +char KRpermHandler::ftpExecutable( TQString fileOwner, TQString userName, TQString perm ) { + // first check other permissions. + if ( perm[ 9 ] != '-' ) return ALLOWED_PERM; + // can't check group permission ! + // so check the user permissions + if ( ( perm[ 3 ] != '-' ) && ( fileOwner == userName ) ) + return ALLOWED_PERM; + if ( ( perm[ 3 ] != '-' ) && ( userName.isEmpty() ) ) + return UNKNOWN_PERM; + if ( perm[ 6 ] != '-' ) return UNKNOWN_PERM; + return NO_PERM; +} + +bool KRpermHandler::dirExist( TQString path ) { + DIR * dir = opendir( path.local8Bit() ); + if ( !dir ) return false; + closedir( dir ); // bug fix Karai Csaba (ckarai) + return true; +} + +bool KRpermHandler::fileExist( TQString fullPath ) { + if ( fullPath.right( 1 ) == "/" ) fullPath = fullPath.left( fullPath.length() - 1 ) ; + if ( fullPath.left( 1 ) != "/" ) return fileExist( "/", fullPath ); + return fileExist( fullPath.left( fullPath.findRev( "/" ) ) , + fullPath.mid( fullPath.findRev( "/" ) + 1 ) ); +} + +bool KRpermHandler::fileExist( TQString path, TQString name ) { + if ( TQDir( path ).exists( name ) ) return true; + DIR* dir = opendir( path.local8Bit() ); + if ( !dir ) return false; + struct dirent* dirEnt; + while ( ( dirEnt = readdir( dir ) ) ) { + if ( dirEnt->d_name == name ) { + closedir( dir ); + return true; + } + } + closedir( dir ); + return false; +} + +TQString KRpermHandler::parseSize( TDEIO::filesize_t val ) { +#if (TDE_VERSION_MAJOR >= 3) && (TDE_VERSION_MINOR >= 5) + return TDEGlobal::locale()->formatNumber(TQString::number(val), false, 0); +#else + return TDEGlobal::locale()->formatNumber(val); +#endif + +#if 0 + TQString temp; + temp.sprintf( "%llu", val ); + if ( temp.length() <= 3 ) return temp; + unsigned int i = temp.length() % 3; + if ( i == 0 ) i = 3; + TQString size = temp.left( i ) + ","; + while ( i + 3 < temp.length() ) { + size = size + temp.mid( i, 3 ) + ","; + i += 3; + } + size = size + temp.right( 3 ); + + return size; +#endif +} + +TQString KRpermHandler::date2qstring( TQString date ) { + TQString temp; + int year; + + year = date[ 6 ].digitValue() * 10 + date[ 7 ].digitValue(); + year > 80 ? year += 1900 : year += 2000; + + temp.sprintf( "%d", year ); + temp = temp + date[ 3 ] + date[ 4 ] + date[ 0 ] + date[ 1 ] + date[ 9 ] + date[ 10 ] + date[ 12 ] + date[ 13 ]; + + return temp; +} + +time_t KRpermHandler::TQString2time( TQString date ) { + struct tm t; + t.tm_sec = 0; + t.tm_min = ( TQString( date[ 12 ] ) + TQString( date[ 13 ] ) ).toInt(); + t.tm_hour = ( TQString( date[ 9 ] ) + TQString( date[ 10 ] ) ).toInt(); + t.tm_mday = ( TQString( date[ 0 ] ) + TQString( date[ 1 ] ) ).toInt(); + t.tm_mon = ( TQString( date[ 3 ] ) + TQString( date[ 4 ] ) ).toInt() - 1; + t.tm_year = ( TQString( date[ 6 ] ) + TQString( date[ 7 ] ) ).toInt(); + if ( t.tm_year < 70 ) t.tm_year += 100; + t.tm_isdst = -1; // daylight saving time information isn't availble + + return mktime( &t ); +} + +gid_t KRpermHandler::group2gid( TQString group ) { + gid_t * gid = groupCache->find( group ); + if ( gid ) return * gid; + return getgid(); +} +uid_t KRpermHandler::user2uid ( TQString user ) { + uid_t * uid = passwdCache->find( user ); + if ( uid ) return * uid; + return getuid(); +} + +TQString KRpermHandler::gid2group( gid_t groupId ) { + TQString * group = gidCache->find( groupId ); + if ( group ) return * group; + return TQString( "???" ); +} + +TQString KRpermHandler::uid2user ( uid_t userId ) { + TQString * user = uidCache->find( userId ); + if ( user ) return * user; + return TQString( "???" ); +} + diff --git a/src/app/VFS/krpermhandler.h b/src/app/VFS/krpermhandler.h new file mode 100644 index 0000000..02a2928 --- /dev/null +++ b/src/app/VFS/krpermhandler.h @@ -0,0 +1,89 @@ +/*************************************************************************** + krpermhandler.h + ------------------- + copyright : (C) 2000 by Shie Erlich & Rafi Yanai + email : krusader@users.sourceforge.net + web site : http://krusader.sourceforge.net + --------------------------------------------------------------------------- + Description + *************************************************************************** + + A + + db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. + 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D + 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' + 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b + 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. + YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD + + H e a d e r F i l e + + *************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + + +#ifndef KRPERMHANDLER_H +#define KRPERMHANDLER_H + +#include <tqstring.h> +#include <tqfileinfo.h> +#include <sys/types.h> +#include <tqdict.h> +#include <tqintdict.h> +#include <tdeio/global.h> + +#define NO_PERM 0 +#define UNKNOWN_PERM 1 +#define ALLOWED_PERM 2 + +class KRpermHandler { +public: + KRpermHandler(){} + ~KRpermHandler(){} + + static void init(); + + static gid_t group2gid(TQString group); + static uid_t user2uid (TQString user); + + static TQString gid2group(gid_t groupId); + static TQString uid2user (uid_t userId); + + static char writeable (TQString perm, gid_t gid, uid_t uid, int rwx=-1); + static char readable (TQString perm, gid_t gid, uid_t uid, int rwx=-1); + static char executable(TQString perm, gid_t gid, uid_t uid, int rwx=-1); + + static bool fileWriteable (TQString localFile); + static bool fileReadable (TQString localFile); + static bool fileExecutable(TQString localFile); + + static char ftpWriteable ( TQString fileOwner, TQString userName, TQString perm ); + static char ftpReadable ( TQString fileOwner, TQString userName, TQString perm ); + static char ftpExecutable( TQString fileOwner, TQString userName, TQString perm ); + + static bool dirExist (TQString path); + static bool fileExist(TQString fullPath); + static bool fileExist(TQString Path, TQString name); + + static TQString mode2TQString(mode_t m); + static TQString parseSize(TDEIO::filesize_t val); + static TQString date2qstring(TQString date); + static time_t TQString2time(TQString date); + +private: + // cache for passwd and group entries + static TQDict<uid_t> *passwdCache; + static TQDict<gid_t> *groupCache; + static TQIntDict<char> *currentGroups; + static TQIntDict<TQString> *uidCache; + static TQIntDict<TQString> *gidCache; +}; + +#endif diff --git a/src/app/VFS/krquery.cpp b/src/app/VFS/krquery.cpp new file mode 100644 index 0000000..7ceeca9 --- /dev/null +++ b/src/app/VFS/krquery.cpp @@ -0,0 +1,653 @@ +/*************************************************************************** + krquery.cpp + ------------------- + copyright : (C) 2001 by Shie Erlich & Rafi Yanai + email : krusader@users.sourceforge.net + web site : http://krusader.sourceforge.net + --------------------------------------------------------------------------- + Description + *************************************************************************** + + A + + db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. + 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D + 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' + 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b + 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. + YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD + + S o u r c e F i l e + + *************************************************************************** + * * + * 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 "krquery.h" +#include "../krusader.h" +#include "../resources.h" +#include "vfs.h" +#include "krarchandler.h" +#include "krpermhandler.h" + +#include <tqtextstream.h> +#include <tqtextcodec.h> +#include <tqregexp.h> +#include <klargefile.h> +#include <tdelocale.h> +#include <kmimetype.h> +#include <tqfile.h> +#include <kurlcompletion.h> +#include <tdeio/job.h> +#include <tdefileitem.h> + +#define STATUS_SEND_DELAY 250 +#define MAX_LINE_LEN 500 + +// set the defaults +KRQuery::KRQuery(): TQObject(), matchesCaseSensitive(true), bNull( true ), + contain(TQString()),containCaseSensetive(true), + containWholeWord(false),containOnRemote(false), + minSize(0),maxSize(0),newerThen(0),olderThen(0), + owner(TQString()),group(TQString()),perm(TQString()), + type(TQString()),inArchive(false),recurse(true), + followLinksP(true), receivedBuffer( 0 ), processEventsConnected(0) {} + +// set the defaults +KRQuery::KRQuery( const TQString &name, bool matchCase ) : TQObject(), + bNull( true ),contain(TQString()),containCaseSensetive(true), + containWholeWord(false), containOnRemote(false), + minSize(0),maxSize(0),newerThen(0),olderThen(0), + owner(TQString()),group(TQString()),perm(TQString()), + type(TQString()),inArchive(false),recurse(true), + followLinksP(true), receivedBuffer( 0 ), processEventsConnected(0) { + setNameFilter( name, matchCase ); +} + +KRQuery::KRQuery( const KRQuery & that ) : TQObject(), receivedBuffer( 0 ), processEventsConnected(0) { + *this = that; +} + +KRQuery::~KRQuery() { + if( receivedBuffer ) + delete []receivedBuffer; + receivedBuffer = 0; +} + +KRQuery& KRQuery::operator=(const KRQuery &old) { + matches = old.matches; + excludes = old.excludes; + includedDirs = old.includedDirs; + excludedDirs = old.excludedDirs; + matchesCaseSensitive = old.matchesCaseSensitive; + bNull = old.bNull; + contain = old.contain; + containCaseSensetive = old.containCaseSensetive; + containWholeWord = old.containWholeWord; + containOnRemote = old.containOnRemote; + minSize = old.minSize; + maxSize = old.maxSize; + newerThen = old.newerThen; + olderThen = old.olderThen; + owner = old.owner; + group = old.group; + perm = old.perm; + type = old.type; + customType = old.customType; + inArchive = old.inArchive; + recurse = old.recurse; + followLinksP = old.followLinksP; + whereToSearch = old.whereToSearch; + whereNotToSearch = old.whereNotToSearch; + origFilter = old.origFilter; + + return *this; +} + +void KRQuery::connectNotify ( const char * signal ) { + TQString signalString = TQString( signal ).replace( " ", "" ); + TQString processString = TQString( TQ_SIGNAL( processEvents( bool & ) ) ).replace( " ", "" ); + if( signalString == processString ) + processEventsConnected++; +} + +void KRQuery::disconnectNotify ( const char * signal ) { + TQString signalString = TQString( signal ).replace( " ", "" ); + TQString processString = TQString( TQ_SIGNAL( processEvents( bool & ) ) ).replace( " ", "" ); + if( signalString == processString ) + processEventsConnected--; +} + +bool KRQuery::checkPerm( TQString filePerm ) const +{ + for ( int i = 0; i < 9; ++i ) + if ( perm[ i ] != '?' && perm[ i ] != filePerm[ i + 1 ] ) return false; + return true; +} + +bool KRQuery::checkType( TQString mime ) const +{ + if ( type == mime ) return true; + if ( type == i18n( "Archives" ) ) return KRarcHandler::arcSupported( mime.right( 4 ) ); + if ( type == i18n( "Directories" ) ) return mime.contains( "directory" ); + if ( type == i18n( "Image Files" ) ) return mime.contains( "image/" ); + if ( type == i18n( "Text Files" ) ) return mime.contains( "text/" ); + if ( type == i18n( "Video Files" ) ) return mime.contains( "video/" ); + if ( type == i18n( "Audio Files" ) ) return mime.contains( "audio/" ); + if ( type == i18n( "Custom" ) ) return customType.contains( mime ); + return false; +} + +bool KRQuery::match( const TQString & name ) const { + return matchCommon( name, matches, excludes ); +} + +bool KRQuery::matchDirName( const TQString & name ) const { + return matchCommon( name, includedDirs, excludedDirs ); +} + +bool KRQuery::matchCommon( const TQString &nameIn, const TQStringList &matchList, const TQStringList &excludeList ) const +{ + if( excludeList.count() == 0 && matchList.count() == 0 ) /* true if there's no match condition */ + return true; + + TQString name( nameIn ); + int ndx = nameIn.findRev( '/' ); // virtual filenames may contain '/' + if( ndx != -1 ) // but the end of the filename is OK + name = nameIn.mid( ndx + 1 ); + + unsigned int len; + for ( unsigned int i = 0; i < excludeList.count(); ++i ) + { + TQRegExp( *excludeList.at( i ), matchesCaseSensitive, true ).match( name, 0, ( int* ) & len ); + if ( len == name.length() ) return false; + } + + if( matchList.count() == 0 ) + return true; + + for ( unsigned int i = 0; i < matchList.count(); ++i ) + { + TQRegExp( *matchList.at( i ), matchesCaseSensitive, true ).match( name, 0, ( int* ) & len ); + if ( len == name.length() ) return true; + } + return false; +} + +bool KRQuery::match( vfile *vf ) const +{ + if( vf->vfile_isDir() && !matchDirName( vf->vfile_getName() ) ) return false; + // see if the name matches + if ( !match( vf->vfile_getName() ) ) return false; + // checking the mime + if( !type.isEmpty() && !checkType( vf->vfile_getMime( true ) ) ) return false; + // check that the size fit + TDEIO::filesize_t size = vf->vfile_getSize(); + if ( minSize && size < minSize ) return false; + if ( maxSize && size > maxSize ) return false; + // check the time frame + time_t mtime = vf->vfile_getTime_t(); + if ( olderThen && mtime > olderThen ) return false; + if ( newerThen && mtime < newerThen ) return false; + // check owner name + if ( !owner.isEmpty() && vf->vfile_getOwner() != owner ) return false; + // check group name + if ( !group.isEmpty() && vf->vfile_getGroup() != group ) return false; + //check permission + if ( !perm.isEmpty() && !checkPerm( vf->vfile_getPerm() ) ) return false; + + if ( !contain.isEmpty() ) + { + if( (totalBytes = vf->vfile_getSize()) == 0 ) + totalBytes++; // sanity + receivedBytes = 0; + if( receivedBuffer ) { + delete []receivedBuffer; + receivedBuffer = 0; + } + fileName = vf->vfile_getName(); + timer.start(); + + if( vf->vfile_getUrl().isLocalFile() ) + { + if( !containsContent( vf->vfile_getUrl().path() ) ) return false; + } + else + { + if( containOnRemote ) { + if( processEventsConnected == 0 ) return false; + if( !containsContent( vf->vfile_getUrl() ) ) return false; + } + } + } + + return true; +} + +bool KRQuery::match( KFileItem *kfi ) const { + mode_t mode = kfi->mode() | kfi->permissions(); + TQString perm = KRpermHandler::mode2TQString( mode ); + if ( kfi->isDir() ) + perm[ 0 ] = 'd'; + + vfile temp( kfi->text(), kfi->size(), perm, kfi->time( TDEIO::UDS_MODIFICATION_TIME ), + kfi->isLink(), kfi->user(), kfi->group(), kfi->user(), + kfi->mimetype(), kfi->linkDest(), mode ); + + return match( &temp ); +} + +// takes the string and adds BOLD to it, so that when it is displayed, +// the grepped text will be bold +void fixFoundTextForDisplay(TQString& haystack, int start, int length) { + TQString before = haystack.left( start ); + TQString text = haystack.mid( start, length ); + TQString after = haystack.mid( start + length ); + + before.replace( '&', "&" ); + before.replace( '<', "<" ); + before.replace( '>', ">" ); + + text.replace( '&', "&" ); + text.replace( '<', "<" ); + text.replace( '>', ">" ); + + after.replace( '&', "&" ); + after.replace( '<', "<" ); + after.replace( '>', ">" ); + + haystack = ("<qt>"+before+"<b>"+text+"</b>"+after+"</qt>" ); +} + +bool KRQuery::checkBuffer( const char *buf, int len ) const { + if( len == 0 ) { // last block? + if( receivedBuffer ) { + bool result = checkLines( receivedBuffer, receivedBufferLen ); + delete []receivedBuffer; + receivedBuffer = 0; + return result; + } + return false; + } + + int after = len; + while( buf[ after-1 ] != '\n' && buf[ after-1 ] != 0 ) { + after--; + if( after <= 0 || after <= len - MAX_LINE_LEN ) { + after = len; // if there's no <ENTER> in MAX_LINE_LEN, we break the line + break; // breaking the line causes problems at Unicode characters + } + } + + if( receivedBuffer ) { + int previous = 0; + while( previous < after && previous < MAX_LINE_LEN && buf[previous] != '\n' && buf[previous] != 0 ) + previous++; + + char * str = new char[ receivedBufferLen + previous ]; + memcpy( str, receivedBuffer, receivedBufferLen ); + delete []receivedBuffer; + receivedBuffer = 0; + memcpy( str + receivedBufferLen, buf, previous ); + + if( checkLines( str, receivedBufferLen+previous ) ) { + delete []str; + return true; + } + delete []str; + + if( after > previous && checkLines( buf+previous, after-previous ) ) + return true; + + } else if( checkLines( buf, after ) ) + return true; + + if( after < len ) { + receivedBufferLen = len-after; + receivedBuffer = new char [ receivedBufferLen ]; + memcpy( receivedBuffer, buf+after, receivedBufferLen ); + } + return false; +} + +bool KRQuery::checkLines( const char * buf, int len ) const +{ + TQStringList list; + + int start = 0; + int k = 0; + while( k < len ) + { + if( buf[ k ] == 0 || buf[ k ] == '\n' ) + { + if( k != start ) + { + TQString line = TQTextCodec::codecForLocale()->toUnicode( buf + start, k - start ); + if( !line.isEmpty() ) + list << line; + } + start = k + 1; + } + k++; + } + if( start != k ) + { + TQString line = TQTextCodec::codecForLocale()->toUnicode( buf + start, k - start ); + if( !line.isEmpty() ) + list << line; + } + + for( unsigned int i=0; i != list.count(); i++ ) { + TQString line = list[ i ]; + + int ndx = 0; + if ( line.isNull() ) return false; + if ( containWholeWord ) + { + while ( ( ndx = line.find( contain, ndx, containCaseSensetive ) ) != -1 ) + { + TQChar before = line.at( ndx - 1 ); + TQChar after = line.at( ndx + contain.length() ); + + if ( !before.isLetterOrNumber() && !after.isLetterOrNumber() && + after != '_' && before != '_' ) { + lastSuccessfulGrep = line; + fixFoundTextForDisplay(lastSuccessfulGrep, ndx, contain.length()); + return true; + } + ndx++; + } + } + else if ( (ndx = line.find( contain, 0, containCaseSensetive )) != -1 ) { + lastSuccessfulGrep = line; + fixFoundTextForDisplay(lastSuccessfulGrep, ndx, contain.length()); + return true; + } + } + return false; +} + +bool KRQuery::containsContent( TQString file ) const +{ + TQFile qf( file ); + if( !qf.open( IO_ReadOnly ) ) + return false; + + char buffer[ 1440 ]; // 2k buffer + + while ( !qf.atEnd() ) + { + int bytes = qf.readBlock( buffer, sizeof( buffer ) ); + if( bytes <= 0 ) + break; + + receivedBytes += bytes; + + if( checkBuffer( buffer, bytes ) ) + return true; + + if( checkTimer() ) { + bool stopped = false; + emit ((KRQuery *)this)->processEvents( stopped ); + if( stopped ) + return false; + } + } + if( checkBuffer( buffer, 0 ) ) + return true; + + lastSuccessfulGrep = TQString(); // nothing was found + return false; +} + +bool KRQuery::containsContent( KURL url ) const +{ + TDEIO::TransferJob *contentReader = TDEIO::get( url, false, false ); + connect(contentReader, TQ_SIGNAL(data(TDEIO::Job *, const TQByteArray &)), + this, TQ_SLOT(containsContentData(TDEIO::Job *, const TQByteArray &))); + connect(contentReader, TQ_SIGNAL( result( TDEIO::Job* ) ), + this, TQ_SLOT(containsContentFinished( TDEIO::Job* ) ) ); + + busy = true; + containsContentResult = false; + bool stopped = false; + + while( busy && !stopped ) { + checkTimer(); + emit ((KRQuery *)this)->processEvents( stopped ); + } + + if( busy ) { + contentReader->kill(); + busy = false; + } + + return containsContentResult; +} + +void KRQuery::containsContentData(TDEIO::Job *job, const TQByteArray &array) { + receivedBytes += array.size(); + if( checkBuffer( array.data(), array.size() ) ) { + containsContentResult = true; + containsContentFinished( job ); + job->kill(); + return; + } + checkTimer(); +} + +void KRQuery::containsContentFinished( TDEIO::Job * ) { + busy = false; +} + +bool KRQuery::checkTimer() const { + if( timer.elapsed() >= STATUS_SEND_DELAY ) { + int pcnt = (int)(100.*(double)receivedBytes/(double)totalBytes + .5); + TQString message = i18n( "Searching content of '%1' (%2%)" ) + .arg( fileName ).arg( pcnt ); + timer.start(); + emit ((KRQuery *)this)->status( message ); + return true; + } + return false; +} + +TQStringList KRQuery::split( TQString str ) +{ + TQStringList list; + unsigned splitNdx = 0; + unsigned startNdx = 0; + bool quotation = false; + + while( splitNdx < str.length() ) + { + if( str[ splitNdx ] == '"' ) + quotation = !quotation; + + if( !quotation && str[ splitNdx ] == ' ') + { + TQString section = str.mid( startNdx, splitNdx - startNdx ); + startNdx = splitNdx+1; + if( section.startsWith( "\"" ) && section.endsWith( "\"" ) && section.length() >=2 ) + section = section.mid( 1, section.length()-2 ); + if( !section.isEmpty() ) + list.append( section ); + } + splitNdx++; + } + + if( startNdx < splitNdx ) + { + TQString section = str.mid( startNdx, splitNdx - startNdx ); + if( section.startsWith( "\"" ) && section.endsWith( "\"" ) && section.length() >=2 ) + section = section.mid( 1, section.length()-2 ); + if( !section.isEmpty() ) + list.append( section ); + } + + return list; +} + +void KRQuery::setNameFilter( const TQString &text, bool cs ) +{ + bNull = false; + matchesCaseSensitive = cs; + origFilter = text; + + TQString matchText = text; + TQString excludeText; + + unsigned excludeNdx = 0; + bool quotationMark = 0; + while( excludeNdx < matchText.length() ) + { + if( matchText[ excludeNdx ] == '"' ) + quotationMark = !quotationMark; + if( !quotationMark ) + { + if( matchText[ excludeNdx ] == '|' ) + break; + } + excludeNdx++; + } + + if( excludeNdx < matchText.length() ) + { + excludeText = matchText.mid( excludeNdx + 1 ).stripWhiteSpace(); + matchText.truncate( excludeNdx ); + matchText = matchText.stripWhiteSpace(); + if( matchText.isEmpty() ) + matchText = "*"; + } + + unsigned i; + + matches = split( matchText ); + includedDirs.clear(); + + for( i=0; i < matches.count(); ) { + if( matches[ i ].endsWith( "/" ) ) { + includedDirs.push_back( matches[ i ].left( matches[ i ].length() - 1 ) ); + matches.remove( matches.at( i ) ); + continue; + } + + if( !matches[ i ].contains( "*" ) && !matches[ i ].contains( "?" ) ) + matches[ i ] = "*" + matches[ i ] + "*"; + + i++; + } + + excludes = split( excludeText ); + excludedDirs.clear(); + + for( i=0; i < excludes.count(); ) { + if( excludes[ i ].endsWith( "/" ) ) { + excludedDirs.push_back( excludes[ i ].left( excludes[ i ].length() - 1 ) ); + excludes.remove( excludes.at( i ) ); + continue; + } + + if( !excludes[ i ].contains( "*" ) && !excludes[ i ].contains( "?" ) ) + excludes[ i ] = "*" + excludes[ i ] + "*"; + + i++; + } +} + +void KRQuery::setContent( const TQString &content, bool cs, bool wholeWord, bool remoteSearch ) +{ + bNull = false; + contain = content; + containCaseSensetive = cs; + containWholeWord = wholeWord; + containOnRemote = remoteSearch; +} + +void KRQuery::setMinimumFileSize( TDEIO::filesize_t minimumSize ) +{ + bNull = false; + minSize = minimumSize; +} + +void KRQuery::setMaximumFileSize( TDEIO::filesize_t maximumSize ) +{ + bNull = false; + maxSize = maximumSize; +} + +void KRQuery::setNewerThan( time_t time ) +{ + bNull = false; + newerThen = time; +} + +void KRQuery::setOlderThan( time_t time ) +{ + bNull = false; + olderThen = time; +} + +void KRQuery::setOwner( const TQString &ownerIn ) +{ + bNull = false; + owner = ownerIn; +} + +void KRQuery::setGroup( const TQString &groupIn ) +{ + bNull = false; + group = groupIn; +} + +void KRQuery::setPermissions( const TQString &permIn ) +{ + bNull = false; + perm = permIn; +} + +void KRQuery::setMimeType( const TQString &typeIn, TQStringList customList ) +{ + bNull = false; + type = typeIn; + customType = customList; +} + +bool KRQuery::isExcluded( const KURL &url ) +{ + for ( unsigned int i = 0; i < whereNotToSearch.count(); ++i ) + if( whereNotToSearch [ i ].isParentOf( url ) || url.equals( whereNotToSearch [ i ], true ) ) + return true; + + if( !matchDirName( url.fileName() ) ) + return true; + + return false; +} + +void KRQuery::setSearchInDirs( const KURL::List &urls ) { + whereToSearch.clear(); + for( unsigned int i = 0; i < urls.count(); ++i ) { + TQString url = urls[ i ].url(); + KURL completed = vfs::fromPathOrURL( KURLCompletion::replacedPath( url, true, true ) ); + whereToSearch.append( completed ); + } +} + +void KRQuery::setDontSearchInDirs( const KURL::List &urls ) { + whereNotToSearch.clear(); + for( unsigned int i = 0; i < urls.count(); ++i ) { + TQString url = urls[ i ].url(); + KURL completed = vfs::fromPathOrURL( KURLCompletion::replacedPath( url, true, true ) ); + whereNotToSearch.append( completed ); + } +} + +#include "krquery.moc" diff --git a/src/app/VFS/krquery.h b/src/app/VFS/krquery.h new file mode 100644 index 0000000..6481782 --- /dev/null +++ b/src/app/VFS/krquery.h @@ -0,0 +1,209 @@ +/*************************************************************************** + krquery.h + ------------------- + copyright : (C) 2001 by Shie Erlich & Rafi Yanai + email : krusader@users.sourceforge.net + web site : http://krusader.sourceforge.net + --------------------------------------------------------------------------- + Description + *************************************************************************** + + A + + db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. + 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D + 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' + 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b + 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. + YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD + + H e a d e r F i l e + + *************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +#ifndef KRQUERY_H +#define KRQUERY_H + +#include <tqstringlist.h> +#include <tqdatetime.h> +#include <time.h> +#include <kurl.h> +#include <tdeio/jobclasses.h> +#include "vfile.h" + +class KFileItem; + +class KRQuery : public TQObject { + TQ_OBJECT + + +public: + // null query + KRQuery(); + // query only with name filter + KRQuery( const TQString &name, bool matchCase = true ); + // copy constructor + KRQuery( const KRQuery & ); + // let operator + KRQuery& operator=(const KRQuery &); + // destructor + virtual ~KRQuery(); + + // matching a file with the query + bool match( vfile *file ) const;// checks if the given vfile object matches the conditions + // matching a TDEIO file with the query + bool match( KFileItem *file ) const;// checks if the given vfile object matches the conditions + // matching a name with the query + bool match( const TQString &name ) const;// matching the filename only + // matching the name of the directory + bool matchDirName( const TQString &name ) const; + + // sets the text for name filtering + void setNameFilter( const TQString &text, bool cs=true ); + // returns the current filter mask + const TQString& nameFilter() const { return origFilter; } + // returns whether the filter is case sensitive + bool isCaseSensitive() { return matchesCaseSensitive; } + + // returns if the filter is null (was cancelled) + bool isNull() {return bNull;}; + + // sets the content part of the query + void setContent( const TQString &content, bool cs=true, bool wholeWord=false, bool remoteSearch=false ); + + // sets the minimum file size limit + void setMinimumFileSize( TDEIO::filesize_t ); + // sets the maximum file size limit + void setMaximumFileSize( TDEIO::filesize_t ); + + // sets the time the file newer than + void setNewerThan( time_t time ); + // sets the time the file older than + void setOlderThan( time_t time ); + + // sets the owner + void setOwner( const TQString &ownerIn ); + // sets the group + void setGroup( const TQString &groupIn ); + // sets the permissions + void setPermissions( const TQString &permIn ); + + // sets the mimetype for the query + // type, must be one of the following: + // 1. a valid mime type name + // 2. one of: i18n("Archives"), i18n("Directories"), i18n("Image Files") + // i18n("Text Files"), i18n("Video Files"), i18n("Audio Files") + // 3. i18n("Custom") in which case you must supply a list of valid mime-types + // in the member TQStringList customType + void setMimeType( const TQString &typeIn, TQStringList customList = TQStringList() ); + // true if setMimeType was called + bool hasMimeType() { return type.isEmpty(); } + + // sets the search in archive flag + void setSearchInArchives( bool flag ) { inArchive = flag; } + // gets the search in archive flag + bool searchInArchives() { return inArchive; } + // sets the recursive flag + void setRecursive( bool flag ) { recurse = flag; } + // gets the recursive flag + bool isRecursive() { return recurse; } + // sets whether to follow symbolic links + void setFollowLinks( bool flag ) { followLinksP = flag; } + // gets whether to follow symbolic links + bool followLinks() { return followLinksP; } + + // sets the folders where the searcher will search + void setSearchInDirs( const KURL::List &urls ); + // gets the folders where the searcher searches + const KURL::List & searchInDirs() { return whereToSearch; } + // sets the folders where search is not permitted + void setDontSearchInDirs( const KURL::List &urls ); + // gets the folders where search is not permitted + const KURL::List & dontSearchInDirs() { return whereNotToSearch; } + // checks if a URL is excluded + bool isExcluded( const KURL &url ); + // gives whether we search for content + bool isContentSearched() const { return !contain.isEmpty(); } + + const TQString& foundText() const { return lastSuccessfulGrep; } + +protected: + // important to know whether the event processor is connected + virtual void connectNotify ( const char * signal ); + // important to know whether the event processor is connected + virtual void disconnectNotify ( const char * signal ); + +protected: + TQStringList matches; // what to search + TQStringList excludes; // what to exclude + TQStringList includedDirs; // what dirs to include + TQStringList excludedDirs; // what dirs to exclude + bool matchesCaseSensitive; + + bool bNull; // flag if the query is null + + TQString contain; // file must contain this string + bool containCaseSensetive; + bool containWholeWord; + bool containOnRemote; + + TDEIO::filesize_t minSize; + TDEIO::filesize_t maxSize; + + time_t newerThen; + time_t olderThen; + + TQString owner; + TQString group; + TQString perm; + + TQString type; + TQStringList customType; + + bool inArchive; // if true- search in archive. + bool recurse; // if true recurse ob sub-dirs... + bool followLinksP; + + KURL::List whereToSearch; // directorys to search + KURL::List whereNotToSearch; // directorys NOT to search + +signals: + void status( const TQString &name ); + void processEvents( bool & stopped ); + +private: + bool matchCommon( const TQString &, const TQStringList &, const TQStringList & ) const; + bool checkPerm(TQString perm) const; + bool checkType(TQString mime) const; + bool containsContent( TQString file ) const; + bool containsContent( KURL url ) const; + bool checkBuffer( const char *buffer, int len ) const; + bool checkLines( const char *buffer, int len ) const; + bool checkTimer() const; + TQStringList split( TQString ); + +private slots: + void containsContentData(TDEIO::Job *, const TQByteArray &); + void containsContentFinished(TDEIO::Job*); + +private: + TQString origFilter; + mutable bool busy; + mutable bool containsContentResult; + mutable char * receivedBuffer; + mutable int receivedBufferLen; + mutable TQString lastSuccessfulGrep; + mutable TQString fileName; + mutable TDEIO::filesize_t receivedBytes; + mutable TDEIO::filesize_t totalBytes; + mutable int processEventsConnected; + mutable TQTime timer; +}; + +#endif diff --git a/src/app/VFS/krvfshandler.cpp b/src/app/VFS/krvfshandler.cpp new file mode 100644 index 0000000..553c55d --- /dev/null +++ b/src/app/VFS/krvfshandler.cpp @@ -0,0 +1,71 @@ +/*************************************************************************** + krvfshandler.cpp - description + ------------------- + begin : Fri Dec 5 2003 + copyright : (C) 2003 by Shie Erlich & Rafi Yanai + email : + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 "krvfshandler.h" +#include "normal_vfs.h" +#include "temp_vfs.h" +#include "ftp_vfs.h" +#include "virt_vfs.h" + +#include <tqdir.h> + +#include <kdebug.h> + + +KrVfsHandler::KrVfsHandler(){ +} +KrVfsHandler::~KrVfsHandler(){ +} + +vfs::VFS_TYPE KrVfsHandler::getVfsType(const KURL& url){ + TQString protocol = url.protocol(); + + if( ( protocol == "krarc" || protocol == "tar" || protocol == "zip" ) && + TQDir(url.path(-1)).exists() ) + return vfs::NORMAL; + + if( url.isLocalFile() ){ + return vfs::NORMAL; + } + else{ + if(url.protocol() == "virt") return vfs::VIRT; + else return vfs::FTP; + } + return vfs::ERROR; +} + +vfs* KrVfsHandler::getVfs(const KURL& url,TQObject* parent,vfs* oldVfs){ + vfs::VFS_TYPE newType,oldType = vfs::ERROR; + + if(oldVfs) oldType = oldVfs->vfs_getType(); + newType = getVfsType(url); + + + vfs* newVfs = oldVfs; + + if( oldType != newType ){ + switch( newType ){ + case (vfs::NORMAL) : newVfs = new normal_vfs(parent); break; + case (vfs::FTP ) : newVfs = new ftp_vfs(parent) ; break; + case (vfs::TEMP ) : newVfs = 0/*new temp_vfs(parent)*/ ; break; + case (vfs::VIRT ) : newVfs = new virt_vfs(parent) ; break; + case (vfs::ERROR ) : newVfs = 0 ; break; + } + } + + return newVfs; +} diff --git a/src/app/VFS/krvfshandler.h b/src/app/VFS/krvfshandler.h new file mode 100644 index 0000000..b061b53 --- /dev/null +++ b/src/app/VFS/krvfshandler.h @@ -0,0 +1,40 @@ +/*************************************************************************** + krvfshandler.h - description + ------------------- + begin : Fri Dec 5 2003 + copyright : (C) 2003 by Shie Erlich & Rafi Yanai + email : + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef KRVFSHANDLER_H +#define KRVFSHANDLER_H + +#include <tqobject.h> + +#include <kurl.h> + +#include "vfs.h" + +/** + *@author Shie Erlich & Rafi Yanai + */ + +class KrVfsHandler : public TQObject { +public: + KrVfsHandler(); + ~KrVfsHandler(); + + static vfs::VFS_TYPE getVfsType(const KURL& url); + static vfs* getVfs(const KURL& url,TQObject* parent=0,vfs* oldVfs=0); +}; + +#endif diff --git a/src/app/VFS/normal_vfs.cpp b/src/app/VFS/normal_vfs.cpp new file mode 100644 index 0000000..f81ab9a --- /dev/null +++ b/src/app/VFS/normal_vfs.cpp @@ -0,0 +1,437 @@ +/*************************************************************************** + normal_vfs.cpp + ------------------- + copyright : (C) 2000 by Rafi Yanai + e-mail : krusader@users.sourceforge.net + web site : http://krusader.sourceforge.net + --------------------------------------------------------------------------- + + *************************************************************************** + + A + + db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. + 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D + 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' + 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b + 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. + YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD + + S o u r c e F i l e + + *************************************************************************** + * * + * 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 <strings.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include <dirent.h> +// TQt includes +#include <tqdir.h> +#include <tqtimer.h> +// TDE includes +#include <tdemessagebox.h> +#include <kmimetype.h> +#include <tdeio/jobclasses.h> +#include <tdelocale.h> +#include <tdeglobalsettings.h> +#include <kdebug.h> +#include <klargefile.h> +#include <tdefileitem.h> +// Krusader includes +#include "normal_vfs.h" +#include "../Dialogs/krdialogs.h" +#include "../MountMan/kmountman.h" +#include "krpermhandler.h" +#include "../krusader.h" +#include "../defaults.h" +#include "../resources.h" +#include "../krslots.h" + +// header files for ACL +#if KDE_IS_VERSION(3,5,0) +#ifdef HAVE_POSIX_ACL +#include <sys/acl.h> +#ifdef HAVE_NON_POSIX_ACL_EXTENSIONS +#include <acl/libacl.h> +#endif +#endif +#endif + +normal_vfs::normal_vfs(TQObject* panel):vfs(panel), watcher(0) { + vfs_type=NORMAL; +} + +bool normal_vfs::populateVfsList(const KURL& origin, bool showHidden){ + TQString path = origin.path(-1); + + // set the writable attribute to true, if that's not the case - the TDEIO job + // will give the warnings and errors + isWritable = true; + + if( watcher ) delete watcher; //stop watching the old dir + watcher = 0; + + // set the origin... + vfs_origin = origin; + vfs_origin.adjustPath(-1); + vfs_origin.setProtocol("file"); // do not remove ! + vfs_origin.cleanPath(-1); + + // check that the new origin exists + if ( !TQDir(path).exists() ) + { + if( !quietMode ) KMessageBox::error(krApp, i18n("Directory %1 does not exist!").arg( path ), i18n("Error")); + return false; + } + + krConfig->setGroup("Advanced"); + if (krConfig->readBoolEntry("AutoMount",_AutoMount)) krMtMan.autoMount(path); + + DIR* dir = opendir(path.local8Bit()); + if(!dir) + { + if( !quietMode ) KMessageBox::error(krApp, i18n("Can't open the %1 directory!").arg( path ), i18n("Error")); + return false; + } + + // change directory to the new directory + TQString save = getcwd( 0, 0 ); + if (chdir(path.local8Bit()) != 0) { + if( !quietMode ) KMessageBox::error(krApp, i18n("Access denied to")+path, i18n("Error")); + closedir(dir); + return false; + } + + struct dirent* dirEnt; + TQString name; + + while( (dirEnt=readdir(dir)) != NULL ){ + name = TQString::fromLocal8Bit(dirEnt->d_name); + + // show hidden files ? + if ( !showHidden && name.left(1) == "." ) continue ; + // we dont need the ".",".." enteries + if (name=="." || name == "..") continue; + + vfile* temp = vfileFromName(name); + foundVfile(temp); + } + // clean up + closedir(dir); + chdir( save.local8Bit() ); + + if( panelConnected ) + { + watcher = new KDirWatch(); + // connect the watcher + connect(watcher,TQ_SIGNAL(dirty(const TQString&)),this,TQ_SLOT(vfs_slotDirty(const TQString&))); + connect(watcher,TQ_SIGNAL(created(const TQString&)),this, TQ_SLOT(vfs_slotCreated(const TQString&))); + connect(watcher,TQ_SIGNAL(deleted(const TQString&)),this, TQ_SLOT(vfs_slotDeleted(const TQString&))); + watcher->addDir(vfs_getOrigin().path(-1),true); //start watching the new dir + watcher->startScan(true); + } + + return true; +} + +// copy a file to the vfs (physical) +void normal_vfs::vfs_addFiles(KURL::List *fileUrls,TDEIO::CopyJob::CopyMode mode,TQObject* toNotify,TQString dir, PreserveMode pmode ){ + //if( watcher ) watcher->stopScan(); // we will refresh manually this time... + if( watcher ) { + delete watcher; // stopScan is buggy, leaves reference on the directory, that's why we delete the watcher + watcher = 0; + } + + KURL dest; + dest.setPath(vfs_workingDir()+"/"+dir); + + TDEIO::Job* job = PreservingCopyJob::createCopyJob( pmode, *fileUrls,dest,mode,false,true ); + connect(job,TQ_SIGNAL(result(TDEIO::Job*)),this,TQ_SLOT(vfs_refresh()) ); + if(mode == TDEIO::CopyJob::Move) // notify the other panel + connect(job,TQ_SIGNAL(result(TDEIO::Job*)),toNotify,TQ_SLOT(vfs_refresh(TDEIO::Job*)) ); + else + job->setAutoErrorHandlingEnabled( true ); +} + +// remove a file from the vfs (physical) +void normal_vfs::vfs_delFiles(TQStringList *fileNames){ + KURL::List filesUrls; + KURL url; + TQDir local( vfs_workingDir() ); + vfile* vf; + +// if( watcher ) watcher->stopScan(); // we will refresh manually this time... + if( watcher ) { + delete watcher; // stopScan is buggy, leaves reference on the directory, that's why we delete the watcher + watcher = 0; + } + + // names -> urls + for(uint i=0 ; i<fileNames->count(); ++i){ + TQString filename = (*fileNames)[i]; + vf = vfs_search(filename); + url.setPath( vfs_workingDir()+"/"+filename); + filesUrls.append(url); + } + TDEIO::Job *job; + + // delete of move to trash ? + krConfig->setGroup("General"); + if( krConfig->readBoolEntry("Move To Trash",_MoveToTrash) ){ +#if KDE_IS_VERSION(3,4,0) + job = TDEIO::trash(filesUrls, true ); +#else + job = new TDEIO::CopyJob(filesUrls,TDEGlobalSettings::trashPath(),TDEIO::CopyJob::Move,false,true ); +#endif + connect(job,TQ_SIGNAL(result(TDEIO::Job*)),SLOTS,TQ_SLOT(changeTrashIcon())); + } + else + job = new TDEIO::DeleteJob(filesUrls, false, true); + + connect(job,TQ_SIGNAL(result(TDEIO::Job*)),this,TQ_SLOT(vfs_refresh(TDEIO::Job*))); +} + +// return a path to the file +KURL normal_vfs::vfs_getFile(const TQString& name){ + TQString url; + if ( vfs_workingDir() == "/" ) url = "/"+name; + else url = vfs_workingDir()+"/"+name; + + return vfs::fromPathOrURL(url); +} + +KURL::List* normal_vfs::vfs_getFiles(TQStringList* names){ + KURL::List* urls = new KURL::List(); + for(TQStringList::Iterator name = names->begin(); name != names->end(); ++name){ + urls->append( vfs_getFile(*name) ); + } + return urls; +} + +void normal_vfs::vfs_mkdir(const TQString& name){ + if (!TQDir(vfs_workingDir()).mkdir(name)) + if (!quietMode) KMessageBox::sorry(krApp,i18n("Can't create a directory. Check your permissions.")); + vfs::vfs_refresh(); +} + +void normal_vfs::vfs_rename(const TQString& fileName,const TQString& newName){ + KURL::List fileUrls; + KURL url , dest; + + //if( watcher ) watcher->stopScan(); // we will refresh manually this time... + if( watcher ) { + delete watcher; // stopScan is buggy, leaves reference on the directory, that's why we delete the watcher + watcher = 0; + } + + url.setPath( vfs_workingDir()+"/"+fileName ); + fileUrls.append(url); + dest.setPath(vfs_workingDir()+"/"+newName); + + TDEIO::Job *job = new TDEIO::CopyJob(fileUrls,dest,TDEIO::CopyJob::Move,true,false ); + connect(job,TQ_SIGNAL(result(TDEIO::Job*)),this,TQ_SLOT(vfs_refresh(TDEIO::Job*))); +} + +vfile* normal_vfs::vfileFromName(const TQString& name){ + TQString path = vfs_workingDir()+"/"+name; + TQCString fileName = path.local8Bit(); + + KDE_struct_stat stat_p; + KDE_lstat(fileName.data(),&stat_p); + TDEIO::filesize_t size = stat_p.st_size; + TQString perm = KRpermHandler::mode2TQString(stat_p.st_mode); + bool symLink= S_ISLNK(stat_p.st_mode); + if( S_ISDIR(stat_p.st_mode) ) perm[0] = 'd'; + + KURL mimeUrl = fromPathOrURL(path); + TQString mime=TQString(); + + char symDest[256]; + bzero(symDest,256); + if( S_ISLNK(stat_p.st_mode) ){ // who the link is pointing to ? + int endOfName=0; + endOfName=readlink(fileName.data(),symDest,256); + if ( endOfName != -1 ){ + if ( TQDir(TQString::fromLocal8Bit( symDest ) ).exists() ) perm[0] = 'd'; + if ( !TQDir(vfs_workingDir()).exists( TQString::fromLocal8Bit ( symDest ) ) ) mime = "Broken Link !"; + } + else krOut << "Failed to read link: "<< path<<endl; + } + + int rwx = 0; + if( ::access( fileName.data(), R_OK ) == 0 ) + rwx |= R_OK; + if( ::access( fileName.data(), W_OK ) == 0 ) + rwx |= W_OK; + if( ::access( fileName.data(), X_OK ) == 0 ) + rwx |= X_OK; + + // create a new virtual file object + vfile* temp=new vfile(name,size,perm,stat_p.st_mtime,symLink,stat_p.st_uid, + stat_p.st_gid,mime,TQString::fromLocal8Bit( symDest ),stat_p.st_mode, rwx); + temp->vfile_setUrl( mimeUrl ); + return temp; +} + +void normal_vfs::getACL( vfile *file, TQString &acl, TQString &defAcl ) +{ + acl = defAcl = TQString(); +#if KDE_IS_VERSION(3,5,0) && defined( HAVE_POSIX_ACL ) + TQCString fileName = file->vfile_getUrl().path( -1 ).local8Bit(); +#if HAVE_NON_POSIX_ACL_EXTENSIONS + if ( acl_extended_file( fileName.data() ) ) + { +#endif + acl = getACL( fileName.data(), ACL_TYPE_ACCESS ); + if( file->vfile_isDir() ) + defAcl = getACL( fileName.data(), ACL_TYPE_DEFAULT ); +#if HAVE_NON_POSIX_ACL_EXTENSIONS + } +#endif +#endif +} + +TQString normal_vfs::getACL( const TQString & path, int type ) +{ +#if KDE_IS_VERSION(3,5,0) && defined( HAVE_POSIX_ACL ) + acl_t acl = 0; + // do we have an acl for the file, and/or a default acl for the dir, if it is one? + if ( ( acl = acl_get_file( path.ascii(), type ) ) != 0 ) + { + bool aclExtended = false; + +#if HAVE_NON_POSIX_ACL_EXTENSIONS + aclExtended = acl_equiv_mode( acl, 0 ); +#else + acl_entry_t entry; + int ret = acl_get_entry( acl, ACL_FIRST_ENTRY, &entry ); + while ( ret == 1 ) { + acl_tag_t currentTag; + acl_get_tag_type( entry, ¤tTag ); + if ( currentTag != ACL_USER_OBJ && + currentTag != ACL_GROUP_OBJ && + currentTag != ACL_OTHER ) + { + aclExtended = true; + break; + } + ret = acl_get_entry( acl, ACL_NEXT_ENTRY, &entry ); + } +#endif + + if ( !aclExtended ) + { + acl_free( acl ); + acl = 0; + } + } + + if( acl == 0 ) + return TQString(); + + char *aclString = acl_to_text( acl, 0 ); + TQString ret = TQString::fromLatin1( aclString ); + acl_free( (void*)aclString ); + acl_free( acl ); + + return ret; +#else + return TQString(); +#endif +} + +void normal_vfs::vfs_slotRefresh() +{ + krConfig->setGroup("Advanced"); + int maxRefreshFrequency = krConfig->readNumEntry("Max Refresh Frequency", 1000); + vfs_refresh(); + disconnect( &refreshTimer, TQ_SIGNAL( timeout() ), this, TQ_SLOT( vfs_slotRefresh() ) ); + refreshTimer.start( maxRefreshFrequency, true ); +} + +bool normal_vfs::burstRefresh(const TQString& path ){ + if( path == vfs_getOrigin().path(-1) ) { + if( !refreshTimer.isActive() ) { + // the directory itself is dirty - full refresh is needed + TQTimer::singleShot(0, this, TQ_SLOT( vfs_slotRefresh() ) ); // safety: dirty signal comes from KDirWatch! + return true; + } + disconnect( &refreshTimer, TQ_SIGNAL( timeout() ), this, TQ_SLOT( vfs_slotRefresh() ) ); + connect( &refreshTimer, TQ_SIGNAL( timeout() ), this, TQ_SLOT( vfs_slotRefresh() ) ); + postponedRefreshURL = fromPathOrURL(path); + return true; + } + return false; +} + +void normal_vfs::vfs_slotDirty(const TQString& path){ + if( disableRefresh ){ + postponedRefreshURL = fromPathOrURL(path); + return; + } + + if( burstRefresh( path ) ) + return; + + KURL url = fromPathOrURL(path); + TQString name = url.fileName(); + + // do we have it already ? + if( !vfs_search(name ) ) return vfs_slotCreated(path); + + // we have an updated file.. + removeFromList(name); + vfile* vf = vfileFromName(name); + addToList(vf); + emit updatedVfile(vf); +} + +void normal_vfs::vfs_slotCreated(const TQString& path){ + if( disableRefresh ){ + postponedRefreshURL = fromPathOrURL(path); + return; + } + + if( burstRefresh( path ) ) + return; + + + KURL url = fromPathOrURL(path); + TQString name = url.fileName(); + // if it's in the CVS - it's an update not new file + if( vfs_search(name) ) + return vfs_slotDirty(path); + + vfile* vf = vfileFromName(name); + addToList(vf); + emit addedVfile(vf); +} + +void normal_vfs::vfs_slotDeleted(const TQString& path){ + if( disableRefresh ){ + postponedRefreshURL = fromPathOrURL(path); + return; + } + + if( burstRefresh( path ) ) + return; + + + KURL url = fromPathOrURL(path); + TQString name = url.fileName(); + + // if it's not in the CVS - do nothing + if( vfs_search(name) ){ + emit deletedVfile(name); + removeFromList(name); + } +} + +#include "normal_vfs.moc" diff --git a/src/app/VFS/normal_vfs.h b/src/app/VFS/normal_vfs.h new file mode 100644 index 0000000..0df0ea6 --- /dev/null +++ b/src/app/VFS/normal_vfs.h @@ -0,0 +1,93 @@ +/*************************************************************************** + normal_vfs.h + ------------------- + begin : Thu May 4 2000 + copyright : (C) 2000 by Shie Erlich & Rafi Yanai + e-mail : krusader@users.sourceforge.net + web site : http://krusader.sourceforge.net + + *************************************************************************** + + A + + db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. + 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D + 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' + 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b + 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. + YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD + + H e a d e r F i l e + + *************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef NORMAL_VFS +#define NORMAL_VFS + +// TQt includes +#include <tqstring.h> +// TDE includes +#include <tdefileitem.h> +#include <kdirwatch.h> +#include <kurl.h> +// Krusader includes +#include "vfs.h" + +/** + * The normal_vfs class is Kruasder implemention for local directories. + * As this is the most common case, we try to make it as fast and efficent as possible. + */ +class normal_vfs : public vfs{ + TQ_OBJECT + +public: + // the constructor simply uses the inherited constructor + normal_vfs(TQObject* panel); + ~normal_vfs(){if( watcher ) delete watcher;} + + /// Copy a file to the vfs (physical). + virtual void vfs_addFiles(KURL::List *fileUrls,TDEIO::CopyJob::CopyMode mode,TQObject* toNotify,TQString dir = "", PreserveMode pmode = PM_DEFAULT ); + /// Remove a file from the vfs (physical) + virtual void vfs_delFiles(TQStringList *fileNames); + /// Return a list of URLs for multiple files + virtual KURL::List* vfs_getFiles(TQStringList* names); + /// Return a URL to a single file + virtual KURL vfs_getFile(const TQString& name); + /// Create a new directory + virtual void vfs_mkdir(const TQString& name); + /// Rename file + virtual void vfs_rename(const TQString& fileName,const TQString& newName); + + /// return the VFS working dir + virtual TQString vfs_workingDir() { return vfs_origin.path(-1); } + + /// Get ACL permissions + static void getACL( vfile *file, TQString &acl, TQString &defAcl ); + +public slots: + void vfs_slotRefresh(); + void vfs_slotDirty(const TQString& path); + void vfs_slotCreated(const TQString& path); + void vfs_slotDeleted(const TQString& path); + +protected: + /// Re-reads files and stats and fills the vfile list + virtual bool populateVfsList(const KURL& origin, bool showHidden); + + TQTimer refreshTimer; //< Timer to exclude sudden refreshes + KDirWatch *watcher; //< The internal dir watcher - use to detect changes in directories + vfile* vfileFromName(const TQString& name); + +private: + bool burstRefresh( const TQString &path ); + static TQString getACL( const TQString & path, int type ); +}; + +#endif diff --git a/src/app/VFS/preservingcopyjob.cpp b/src/app/VFS/preservingcopyjob.cpp new file mode 100644 index 0000000..04c3195 --- /dev/null +++ b/src/app/VFS/preservingcopyjob.cpp @@ -0,0 +1,319 @@ +/*************************************************************************** + preservingcopyjob.cpp - description + ------------------- + copyright : (C) 2005 + by Csaba Karai + e-mail : krusader@users.sourceforge.net + web site : http://krusader.sourceforge.net + --------------------------------------------------------------------------- + Description + *************************************************************************** + + A + + db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. + 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D + 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' + 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b + 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. + YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD + + S o u r c e F i l e + + *************************************************************************** + * * + * 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 "preservingcopyjob.h" +#include "../defaults.h" +#include "../krusader.h" +#include <utime.h> +#include <klargefile.h> +#include <tdeio/job.h> +#include <tdeio/jobclasses.h> +#include <tdefileitem.h> +#include <tqfile.h> +#include <pwd.h> +#include <grp.h> + + +#if KDE_IS_VERSION(3,5,0) && defined( HAVE_POSIX_ACL ) +#include <sys/acl.h> +#ifdef HAVE_NON_POSIX_ACL_EXTENSIONS +#include <acl/libacl.h> +#endif +#endif + +Attributes::Attributes() +{ + time = (time_t)-1; + uid = (uid_t)-1; + gid = (gid_t)-1; + mode = (mode_t)-1; + acl = TQString(); +} + +Attributes::Attributes( time_t tIn, uid_t uIn, gid_t gIn, mode_t modeIn, const TQString & aclIn ) +{ + time = tIn, uid = uIn, gid = gIn, mode = modeIn, acl = aclIn; +} + +Attributes::Attributes( time_t tIn, TQString user, TQString group, mode_t modeIn, const TQString & aclIn ) +{ + time = tIn; + uid = (uid_t)-1; + struct passwd* pw = getpwnam(TQFile::encodeName( user )); + if ( pw != 0L ) + uid = pw->pw_uid; + gid = (gid_t)-1; + struct group* g = getgrnam(TQFile::encodeName( group )); + if ( g != 0L ) + gid = g->gr_gid; + mode = modeIn; + acl = aclIn; +} + +PreservingCopyJob::PreservingCopyJob( const KURL::List& src, const KURL& dest, CopyMode mode, + bool asMethod, bool showProgressInfo ) : TDEIO::CopyJob( src, dest, mode, asMethod, showProgressInfo ) +{ + if( dest.isLocalFile() ) + { + connect( this, TQ_SIGNAL( aboutToCreate (TDEIO::Job *, const TQValueList< TDEIO::CopyInfo > &) ), + this, TQ_SLOT( slotAboutToCreate (TDEIO::Job *, const TQValueList< TDEIO::CopyInfo > &) ) ); + connect( this, TQ_SIGNAL( copyingDone( TDEIO::Job *, const KURL &, const KURL &, bool, bool) ), + this, TQ_SLOT( slotCopyingDone( TDEIO::Job *, const KURL &, const KURL &, bool, bool) ) ); + connect( this, TQ_SIGNAL( result( TDEIO::Job * ) ), + this, TQ_SLOT( slotFinished() ) ); + } +} + +void PreservingCopyJob::slotAboutToCreate( TDEIO::Job */*job*/, const TQValueList< TDEIO::CopyInfo > &files ) +{ + for ( TQValueList< TDEIO::CopyInfo >::ConstIterator it = files.begin(); it != files.end(); ++it ) { + + if( (*it).uSource.isLocalFile() ) { + KDE_struct_stat stat_p; + KDE_lstat( (*it).uSource.path(-1).local8Bit(),&stat_p); /* getting the date information */ + + TQString aclStr; +#if KDE_IS_VERSION(3,5,0) && defined( HAVE_POSIX_ACL ) + acl_t acl = acl_get_file( (*it).uSource.path(-1).local8Bit(), ACL_TYPE_ACCESS ); + + bool aclExtended = false; + if( acl ) + { +#if HAVE_NON_POSIX_ACL_EXTENSIONS + aclExtended = acl_equiv_mode( acl, 0 ); +#else + acl_entry_t entry; + int ret = acl_get_entry( acl, ACL_FIRST_ENTRY, &entry ); + while ( ret == 1 ) { + acl_tag_t currentTag; + acl_get_tag_type( entry, ¤tTag ); + if ( currentTag != ACL_USER_OBJ && + currentTag != ACL_GROUP_OBJ && + currentTag != ACL_OTHER ) + { + aclExtended = true; + break; + } + ret = acl_get_entry( acl, ACL_NEXT_ENTRY, &entry ); + } +#endif + } + + + if ( acl && !aclExtended ) { + acl_free( acl ); + acl = NULL; + } + if( acl ) + { + char *aclString = acl_to_text( acl, 0 ); + aclStr = TQString::fromLatin1( aclString ); + acl_free( (void*)aclString ); + acl_free( acl ); + } +#endif + fileAttributes[ (*it).uSource ] = Attributes( stat_p.st_mtime, stat_p.st_uid, stat_p.st_gid, stat_p.st_mode & 07777, aclStr ); + } + else { + time_t mtime = (*it).mtime; + + if( mtime != 0 && mtime != ((time_t) -1 ) ) /* is it correct? */ + fileAttributes[ (*it).uSource ].time = mtime; + + int permissions = (*it).permissions; + fileAttributes[ (*it).uSource ].mode = permissions; + } + } +} + +void PreservingCopyJob::slotResult( Job *job ) { + if( !job->error() ) { + if( job->inherits( "TDEIO::StatJob" ) ) { /* Unfortunately TDEIO forgets to set times when the file is in the */ + KURL url = ((TDEIO::SimpleJob *)job)->url(); /* base directory. That's why we capture every StatJob and set the */ + /* time manually. */ + TDEIO::UDSEntry entry = static_cast<TDEIO::StatJob*>(job)->statResult(); + KFileItem kfi(entry, url ); + +#if KDE_IS_VERSION(3,5,0) && defined( HAVE_POSIX_ACL ) + fileAttributes[ url ] = Attributes( kfi.time( TDEIO::UDS_MODIFICATION_TIME ), kfi.user(), kfi.group(), kfi.mode(), kfi.ACL().asString() ); +#else + fileAttributes[ url ] = Attributes( kfi.time( TDEIO::UDS_MODIFICATION_TIME ), kfi.user(), kfi.group(), kfi.mode(), TQString() ); +#endif + } + } + + CopyJob::slotResult( job ); + + for( unsigned j=0; j != subjobs.count(); j++ ) { + if( subjobs.at( j )->inherits( "TDEIO::ListJob" ) ) { + disconnect( subjobs.at( j ), TQ_SIGNAL( entries (TDEIO::Job *, const TDEIO::UDSEntryList &) ), + this, TQ_SLOT( slotListEntries (TDEIO::Job *, const TDEIO::UDSEntryList &) ) ); + connect( subjobs.at( j ), TQ_SIGNAL( entries (TDEIO::Job *, const TDEIO::UDSEntryList &) ), + this, TQ_SLOT( slotListEntries (TDEIO::Job *, const TDEIO::UDSEntryList &) ) ); + } + } +} + +void PreservingCopyJob::slotListEntries(TDEIO::Job *job, const TDEIO::UDSEntryList &list) { + TDEIO::UDSEntryListConstIterator it = list.begin(); + TDEIO::UDSEntryListConstIterator end = list.end(); + for (; it != end; ++it) { + KURL url = ((TDEIO::SimpleJob *)job)->url(); + TQString relName, user, group; + time_t mtime = (time_t)-1; + mode_t mode = 0755; + TQString acl; + + TDEIO::UDSEntry::ConstIterator it2 = (*it).begin(); + for( ; it2 != (*it).end(); it2++ ) { + switch ((*it2).m_uds) { + case TDEIO::UDS_NAME: + if( relName.isEmpty() ) + relName = (*it2).m_str; + break; + case TDEIO::UDS_URL: + relName = KURL((*it2).m_str).fileName(); + break; + case TDEIO::UDS_MODIFICATION_TIME: + mtime = (time_t)((*it2).m_long); + break; + case TDEIO::UDS_USER: + user = (*it2).m_str; + break; + case TDEIO::UDS_GROUP: + group = (*it2).m_str; + break; + case TDEIO::UDS_ACCESS: + mode = (*it2).m_long; + break; +#if KDE_IS_VERSION(3,5,0) && defined( HAVE_POSIX_ACL ) + case TDEIO::UDS_ACL_STRING: + acl = (*it2).m_str; + break; +#endif + } + } + url.addPath( relName ); + + fileAttributes[ url ] = Attributes( mtime, user, group, mode, acl ); + } +} + +void PreservingCopyJob::slotCopyingDone( TDEIO::Job *, const KURL &from, const KURL &to, bool postpone, bool) +{ + if( postpone ) { // the directories are stamped at the last step, so if it's a directory, we postpone + unsigned i=0; + TQString path = to.path( -1 ); + + for( ; i != directoriesToStamp.count(); i++ ) // sort the URL-s to avoid parent time stamp modification + if( path >= directoriesToStamp[ i ].path( -1 ) ) + break; + + directoriesToStamp.insert( directoriesToStamp.at( i ), to ); + originalDirectories.insert( originalDirectories.at( i ), from ); + } + else if( fileAttributes.count( from ) ) { + Attributes attrs = fileAttributes[ from ]; + fileAttributes.remove( from ); + + time_t mtime = attrs.time; + + if( to.isLocalFile() ) + { + if( mtime != 0 && mtime != ((time_t) -1 ) ) + { + struct utimbuf timestamp; + + timestamp.actime = time( 0 ); + timestamp.modtime = mtime; + + utime( (const char *)( to.path( -1 ).local8Bit() ), ×tamp ); + } + + if( attrs.uid != (uid_t)-1 ) + chown( (const char *)( to.path( -1 ).local8Bit() ), attrs.uid, (gid_t)-1 ); + if( attrs.gid != (gid_t)-1 ) + chown( (const char *)( to.path( -1 ).local8Bit() ), (uid_t)-1, attrs.gid ); + + if( attrs.mode != (mode_t) -1 ) + chmod( (const char *)( to.path( -1 ).local8Bit() ), attrs.mode ); + +#if KDE_IS_VERSION(3,5,0) && defined( HAVE_POSIX_ACL ) + if( !attrs.acl.isNull() ) + { + acl_t acl = acl_from_text( attrs.acl.latin1() ); + if( acl && !acl_valid( acl ) ) + acl_set_file( to.path( -1 ).local8Bit(), ACL_TYPE_ACCESS, acl ); + if( acl ) + acl_free( acl ); + } +#endif + } + } +} + +void PreservingCopyJob::slotFinished() { + for( unsigned i=0; i != directoriesToStamp.count(); i++ ) { + KURL from = originalDirectories[ i ]; + KURL to = directoriesToStamp[ i ]; + + slotCopyingDone( 0, from, to, false, false ); + } +} + +TDEIO::CopyJob * PreservingCopyJob::createCopyJob( PreserveMode pmode, const KURL::List& src, const KURL& dest, CopyMode mode, bool asMethod, bool showProgressInfo ) +{ + if( ! dest.isLocalFile() ) + pmode = PM_NONE; + if( mode == TDEIO::CopyJob::Link ) + pmode = PM_NONE; + + switch( pmode ) + { + case PM_PRESERVE_ATTR: + return new PreservingCopyJob( src, dest, mode, asMethod, showProgressInfo ); + case PM_DEFAULT: + { + TQString group = krConfig->group(); + krConfig->setGroup( "Advanced" ); + bool preserve = krConfig->readBoolEntry( "PreserveAttributes", _PreserveAttributes ); + krConfig->setGroup( group ); + if( preserve ) + return new PreservingCopyJob( src, dest, mode, asMethod, showProgressInfo ); + else + return new TDEIO::CopyJob( src, dest, mode, asMethod, showProgressInfo ); + } + case PM_NONE: + default: + return new TDEIO::CopyJob( src, dest, mode, asMethod, showProgressInfo ); + } +} + +#include "preservingcopyjob.moc" diff --git a/src/app/VFS/preservingcopyjob.h b/src/app/VFS/preservingcopyjob.h new file mode 100644 index 0000000..e51783b --- /dev/null +++ b/src/app/VFS/preservingcopyjob.h @@ -0,0 +1,85 @@ +/*************************************************************************** + preservingcopyjob.h - description + ------------------- + copyright : (C) 2005 + by Csaba Karai + e-mail : krusader@users.sourceforge.net + web site : http://krusader.sourceforge.net + --------------------------------------------------------------------------- + Description + *************************************************************************** + + A + + db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. + 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D + 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' + 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b + 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. + YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD + + H e a d e r F i l e + + *************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef __PRESERVING_COPY_JOB_H__ +#define __PRESERVING_COPY_JOB_H__ + +#include "config.h" +#include <time.h> +#include <tdeio/jobclasses.h> +#include <tqmap.h> +#include <tqvaluelist.h> + +typedef enum { + PM_NONE = 0, + PM_PRESERVE_ATTR = 1, + PM_DEFAULT = 2 +} PreserveMode; + + +class Attributes { +public: + Attributes(); + Attributes( time_t tIn, uid_t uIn, gid_t gIn, mode_t modeIn, const TQString & aclIn ); + Attributes( time_t tIn, TQString user, TQString group, mode_t modeIn, const TQString & aclIn ); + + time_t time; + uid_t uid; + gid_t gid; + mode_t mode; + TQString acl; +}; + +class PreservingCopyJob : public TDEIO::CopyJob +{ + TQ_OBJECT + + +public: + + PreservingCopyJob( const KURL::List& src, const KURL& dest, CopyMode mode, bool asMethod, bool showProgressInfo ); + + static TDEIO::CopyJob *createCopyJob( PreserveMode pmode, const KURL::List& src, const KURL& dest, CopyMode mode, bool asMethod, bool showProgressInfo ); + +public slots: + void slotAboutToCreate (TDEIO::Job *, const TQValueList< TDEIO::CopyInfo > &); + void slotCopyingDone( TDEIO::Job *, const KURL &, const KURL &, bool, bool); + void slotFinished(); + virtual void slotResult( Job *job ); + void slotListEntries(TDEIO::Job *job, const TDEIO::UDSEntryList &list); + +private: + TQMap<KURL, Attributes> fileAttributes; + TQMap<TDEIO::Job *, KURL> pendingJobs; + TQValueList<KURL> directoriesToStamp; + TQValueList<KURL> originalDirectories; +}; + +#endif /* __PRESERVING_COPY_JOB_H__ */ diff --git a/src/app/VFS/temp_vfs.cpp b/src/app/VFS/temp_vfs.cpp new file mode 100644 index 0000000..4dc8185 --- /dev/null +++ b/src/app/VFS/temp_vfs.cpp @@ -0,0 +1,136 @@ +/*************************************************************************** + temp_vfs.cpp + ------------------- + copyright : (C) 2001 by Shie Erlich & Rafi Yanai + email : krusader@users.sourceforge.net + web site : http://krusader.sourceforge.net + --------------------------------------------------------------------------- + Description + *************************************************************************** + + A + + db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. + 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D + 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' + 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b + 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. + YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD + + S o u r c e F i l e + + *************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +// TQt includes +#include <tqdir.h> +// TDE includes +#include <tdemessagebox.h> +#include <kprocess.h> +// Krusader includes +#include "temp_vfs.h" +#include "../krusader.h" +#include "../defaults.h" +#include "../VFS/krarchandler.h" +#include "../resources.h" +#include "../krservices.h" + +temp_vfs::temp_vfs( TQString origin, TQString type, TQWidget* panel, bool ): + normal_vfs(panel){ + vfs_type=TEMP; + // first we need to create a temp diretory + tmpDir = krApp->getTempDir(); + // then we must get the files from the origin to the tmp dir + if( type == "-arj" || type == "-ace" ) handleAceArj(origin,type); + else if( type == "-rpm" ) handleRpm(origin); + else if( type == "-iso" ) handleIso(origin); + else{ + if (!quietMode) KMessageBox::error(krApp,"Unknown temp_vfs type."); + return; + } +} + +temp_vfs::~temp_vfs(){ + if( tmpvfs_type == ISO ){ + // unmount the ISO image + KShellProcess umount; + umount << "umount -f" << tmpDir; + umount.start(TDEProcess::Block); + } + // delete the temp dir + KShellProcess proc; + proc << "rm -rf" << tmpDir; + proc.start(TDEProcess::DontCare); +} + +// return the working dir +TQString temp_vfs::vfs_workingDir(){ + // get the path inside the archive + TQString path = vfs_origin.path(-1); + path = path.mid(path.findRev('\\')+1); + if(path.left(1) != "/") path = "/"+path; + TQDir().mkdir(tmpDir+path); + return tmpDir+path; +} + +bool temp_vfs::vfs_refresh(const KURL& origin){ + KURL backup = vfs_origin; + vfs_origin = origin; + vfs_origin.adjustPath(-1); + // get the directory... + TQString path = origin.path(-1).mid(origin.path(-1).findRev('\\')+1); + if(path.left(1) =="/") path.remove(0,1); + if ( !normal_vfs::vfs_refresh(tmpDir+"/"+path) ){ + vfs_origin = backup; + vfs_origin.adjustPath(-1); + return false; + } + return true; +} + +void temp_vfs::handleAceArj(TQString origin, TQString type){ + if (type == "-ace") { + tmpvfs_type = ACE; + } + else if (type == "-arj") { + tmpvfs_type = ARJ; + } + + // for ace and arj we just unpack to the tmpDir + if( !KRarcHandler::arcHandled(type) ){ + if (!quietMode) KMessageBox::error(krApp,"This archive type is NOT supported"); + return; + } + else if( !KRarcHandler::unpack(origin,type, TQString(), tmpDir) ){ + return; + } +} + +void temp_vfs::handleRpm(TQString origin){ + // then extract the cpio archive from the rpm + KShellProcess rpm; + rpm << "rpm2cpio"<<"\""+origin+"\""+" > "+tmpDir+"/contents.cpio"; + rpm.start(TDEProcess::Block); + // and write a nice header + rpm.clearArguments(); + rpm << "rpm -qip"<<"\""+origin+"\""+" > "+tmpDir+"/header.txt"; + rpm.start(TDEProcess::Block); + // and a file list + rpm.clearArguments(); + rpm << "rpm -lpq"<<"\""+origin+"\""+" > "+tmpDir+"/filelist.txt"; + rpm.start(TDEProcess::Block); + tmpvfs_type = RPM; +} + +void temp_vfs::handleIso(TQString origin){ + // mount the ISO image + KShellProcess mount; + mount << KrServices::fullPathName( "mount" ) << "-o loop" << origin << tmpDir; + mount.start(TDEProcess::Block); + tmpvfs_type = ISO; +} diff --git a/src/app/VFS/temp_vfs.h b/src/app/VFS/temp_vfs.h new file mode 100644 index 0000000..d35169b --- /dev/null +++ b/src/app/VFS/temp_vfs.h @@ -0,0 +1,60 @@ +/*************************************************************************** + temp_vfs.h + ------------------- + copyright : (C) 2001 by Shie Erlich & Rafi Yanai + email : krusader@users.sourceforge.net + web site : http://krusader.sourceforge.net + --------------------------------------------------------------------------- + Description + *************************************************************************** + + A + + db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. + 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D + 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' + 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b + 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. + YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD + + H e a d e r F i l e + + *************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + + + +#ifndef TEMP_VFS_H +#define TEMP_VFS_H + +#include "normal_vfs.h" + +class temp_vfs : public normal_vfs { +public: + enum TMPVFS_TYPE{ERROR=0,ACE,ARJ,RPM,ISO}; + + temp_vfs( TQString origin, TQString type, TQWidget* panel, bool writeable); + ~temp_vfs(); + TQString vfs_workingDir(); + bool vfs_isWritable() { return false; } // temp vfs is not writable ! + +public slots: + // actually reads files and stats + bool vfs_refresh(const KURL& origin); + +protected: + void handleAceArj(TQString origin, TQString type); + void handleRpm(TQString origin); + void handleIso(TQString origin); + TMPVFS_TYPE tmpvfs_type; //< the tmp vfs type. + TQString tmpDir; + +}; + +#endif diff --git a/src/app/VFS/vfile.cpp b/src/app/VFS/vfile.cpp new file mode 100644 index 0000000..c333f45 --- /dev/null +++ b/src/app/VFS/vfile.cpp @@ -0,0 +1,311 @@ +/*************************************************************************** + vfile.cpp + ------------------- + copyright : (C) 2000 by Rafi Yanai + e-mail : krusader@users.sourceforge.net + web site : http://krusader.sourceforge.net + --------------------------------------------------------------------------- + + *************************************************************************** + + A + + db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. + 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D + 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' + 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b + 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. + YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD + + S o u r c e F i l e + + *************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +// System includes +#include <unistd.h> +#include <pwd.h> +#include <grp.h> +#include <sys/types.h> +#include <sys/stat.h> +// TQt includes +#include <tqdatetime.h> +// TDE includes +#include <kmimetype.h> +#include <tdeversion.h> +// Krusader includes +#include "vfile.h" +#include "krpermhandler.h" +#include "normal_vfs.h" + +#include <kdebug.h> + +vfile::vfile(const TQString& name, // useful construtor + const TDEIO::filesize_t size, + const TQString& perm, + const time_t mtime, + const bool symLink, + const uid_t owner, + const gid_t group, + const TQString& mime, + const TQString& symDest, + const mode_t mode, + const int rwx) +{ + vfile_name=name; + vfile_size=size; + vfile_owner=TQString(); + vfile_ownerId=owner; + vfile_group=TQString(); + vfile_groupId=group; + vfile_userName=TQString(); + vfile_perm=perm; + vfile_time_t=mtime; + vfile_symLink=symLink; + vfile_mimeType=mime; + vfile_symDest=symDest; + vfile_mode=mode; + vfile_isdir = ( perm[ 0 ] == 'd' ); + if (vfile_isDir() && !vfile_symLink ) + vfile_size = 0; + vfile_rwx = rwx; + vfile_acl_loaded = false; +} + +vfile::vfile(const TQString& name, // useful construtor + const TDEIO::filesize_t size, + const TQString& perm, + const time_t mtime, + const bool symLink, + const TQString& owner, + const TQString& group, + const TQString& userName, + const TQString& mime, + const TQString& symDest, + const mode_t mode, + const int rwx, + const TQString& aclString, + const TQString& aclDfltString ){ + vfile_name=name; + vfile_size=size; + vfile_owner=owner; + vfile_group=group; + vfile_userName=userName; + vfile_ownerId=KRpermHandler::user2uid(owner) ; + vfile_groupId=KRpermHandler::group2gid(group); + vfile_perm=perm; + vfile_time_t=mtime; + vfile_symLink=symLink; + vfile_mimeType=mime; + vfile_symDest=symDest; + vfile_mode=mode; + vfile_isdir = ( perm[ 0 ] == 'd' ); + if ( vfile_isDir() && !vfile_symLink ) + vfile_size = 0; + vfile_acl = aclString; + vfile_def_acl = aclDfltString; + vfile_has_acl = !aclString.isNull() || !aclDfltString.isNull(); + vfile_acl_loaded = true; + vfile_rwx = rwx; +} + +char vfile::vfile_isReadable() const { + if( vfile_rwx == PERM_ALL ) + return ALLOWED_PERM; + else if( vfile_userName.isNull() ) + return KRpermHandler::readable(vfile_perm,vfile_groupId,vfile_ownerId,vfile_rwx); + else + return KRpermHandler::ftpReadable(vfile_owner, vfile_userName, vfile_perm); +} + +char vfile::vfile_isWriteable() const { + if( vfile_rwx == PERM_ALL ) + return ALLOWED_PERM; + else if( vfile_userName.isNull() ) + return KRpermHandler::writeable(vfile_perm,vfile_groupId,vfile_ownerId,vfile_rwx); + else + return KRpermHandler::ftpWriteable(vfile_owner, vfile_userName, vfile_perm); +} + +char vfile::vfile_isExecutable() const { + if( vfile_rwx == PERM_ALL ) + { + if(( vfile_mode & 0111 ) || vfile_isdir ) + return ALLOWED_PERM; + else + return NO_PERM; + } + else if( vfile_userName.isNull() ) + return KRpermHandler::executable(vfile_perm,vfile_groupId,vfile_ownerId,vfile_rwx); + else + return KRpermHandler::ftpExecutable(vfile_owner, vfile_userName, vfile_perm); +} + +const TQString& vfile::vfile_getMime(bool fast){ + if( vfile_mimeType == TQString() ){ // mimetype == "" is OK so don't check mimetype.empty() ! + vfile_mimeType = KMimeType::findByURL( vfile_getUrl(),vfile_getMode(),vfile_getUrl().isLocalFile(),fast)->name(); + if( vfile_mimeType.contains("directory") ) vfile_perm[0] = 'd', vfile_isdir = true; + } + return vfile_mimeType; +} + +const TQString& vfile::vfile_getOwner(){ + if( vfile_owner.isEmpty() ) + vfile_owner=KRpermHandler::uid2user(vfile_getUid()); + return vfile_owner; +} + +const TQString& vfile::vfile_getGroup(){ + if( vfile_group.isEmpty() ) + vfile_group=KRpermHandler::gid2group(vfile_getGid()); + return vfile_group; +} + +const TQString& vfile::vfile_getACL(){ + if( !vfile_acl_loaded ) + vfile_loadACL(); + return vfile_acl; +} + +const TQString& vfile::vfile_getDefaultACL(){ + if( !vfile_acl_loaded ) + vfile_loadACL(); + return vfile_def_acl; +} + +void vfile::vfile_loadACL() +{ + if( vfile_url.isLocalFile() ) + { + normal_vfs::getACL( this, vfile_acl, vfile_def_acl ); + vfile_has_acl = !vfile_acl.isNull() || !vfile_def_acl.isNull(); + } + vfile_acl_loaded = true; +} + +const TDEIO::UDSEntry vfile::vfile_getEntry() { + TDEIO::UDSEntry entry; + TDEIO::UDSAtom atom; + + atom.m_uds = TDEIO::UDS_NAME; + atom.m_str = vfile_getName(); + entry.append(atom); + + atom.m_uds = TDEIO::UDS_SIZE; + atom.m_long = vfile_getSize(); + entry.append(atom); + + atom.m_uds = TDEIO::UDS_MODIFICATION_TIME; + atom.m_long = vfile_getTime_t(); + entry.append(atom); + + atom.m_uds = TDEIO::UDS_USER; + atom.m_str = vfile_getOwner(); + entry.append(atom); + + atom.m_uds = TDEIO::UDS_GROUP; + atom.m_str = vfile_getGroup(); + entry.append(atom); + + atom.m_uds = TDEIO::UDS_MIME_TYPE; + atom.m_str = vfile_getMime(); + entry.append(atom); + + atom.m_uds = TDEIO::UDS_FILE_TYPE; + atom.m_long = vfile_getMode() & S_IFMT; + entry.append(atom); + + atom.m_uds = TDEIO::UDS_ACCESS; + atom.m_long = vfile_getMode() & 07777; // keep permissions only + entry.append( atom ); + + atom.m_uds = TDEIO::UDS_MIME_TYPE; + atom.m_str = vfile_getMime(); + entry.append(atom); + + if( vfile_isSymLink() ){ + atom.m_uds = TDEIO::UDS_LINK_DEST; + atom.m_str = vfile_getSymDest(); + entry.append(atom); + } + +#if KDE_IS_VERSION(3,5,0) + if( !vfile_acl_loaded ) + vfile_loadACL(); + if( vfile_has_acl ) { + atom.m_uds = TDEIO::UDS_EXTENDED_ACL; + atom.m_long = 1; + entry.append( atom ); + + if( !vfile_acl.isNull() ) + { + atom.m_uds = TDEIO::UDS_ACL_STRING; + atom.m_str = vfile_acl; + entry.append(atom); + } + + if( !vfile_def_acl.isNull() ) + { + atom.m_uds = TDEIO::UDS_DEFAULT_ACL_STRING; + atom.m_str = vfile_acl; + entry.append(atom); + } + } +#endif + + return entry; +} + +bool vfile::operator==(const vfile& vf) const{ + bool equal; + + if( !vfile_acl_loaded ) + const_cast<vfile *>( this )->vfile_loadACL(); + if( !vf.vfile_acl_loaded ) + const_cast<vfile *>( &vf )->vfile_loadACL(); + + equal = (vfile_name == vf.vfile_getName() ) && + (vfile_size == vf.vfile_getSize() ) && + (vfile_perm == vf.vfile_getPerm() ) && + (vfile_time_t == vf.vfile_getTime_t() ) && + (vfile_ownerId == vf.vfile_getUid() ) && + (vfile_groupId == vf.vfile_getGid() ) && + (vfile_has_acl == vf.vfile_has_acl ) && + (!vfile_has_acl || + (vfile_acl == vf.vfile_acl ) && + (vfile_def_acl == vf.vfile_def_acl ) );; + + return equal; +} + +vfile& vfile::operator= (const vfile& vf){ + vfile_name = vf.vfile_name ; + vfile_size = vf.vfile_size ; + vfile_mode = vf.vfile_mode ; + vfile_ownerId = vf.vfile_ownerId ; + vfile_groupId = vf.vfile_groupId ; + vfile_owner = vf.vfile_owner ; + vfile_group = vf.vfile_group ; + vfile_userName = vf.vfile_userName ; + vfile_perm = vf.vfile_perm ; + vfile_time_t = vf.vfile_time_t ; + vfile_symLink = vf.vfile_symLink ; + vfile_mimeType = vf.vfile_mimeType ; + vfile_symDest = vf.vfile_symDest ; + vfile_url = vf.vfile_url ; + vfile_isdir = vf.vfile_isdir ; + vfile_has_acl = vf.vfile_has_acl ; + vfile_acl = vf.vfile_acl ; + vfile_def_acl = vf.vfile_def_acl ; + vfile_rwx = vf.vfile_rwx ; + vfile_acl_loaded = vf.vfile_acl_loaded; + + return (*this); +} + +#include "vfile.moc" diff --git a/src/app/VFS/vfile.h b/src/app/VFS/vfile.h new file mode 100644 index 0000000..b2fc9e8 --- /dev/null +++ b/src/app/VFS/vfile.h @@ -0,0 +1,167 @@ +/*************************************************************************** + vfile.h + ------------------- + begin : Thu May 4 2000 + copyright : (C) 2000 by Shie Erlich & Rafi Yanai + e-mail : krusader@users.sourceforge.net + web site : http://krusader.sourceforge.net + *************************************************************************** + + A + + db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. + 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D + 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' + 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b + 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. + YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD + + H e a d e r F i l e + + *************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +#ifndef VFILE_H +#define VFILE_H + +// TQt includes +#include <tqstring.h> +#include <tqobject.h> +// System includes +#include <sys/types.h> +// TDE includes +#include <tdeio/global.h> +#include <kmimetype.h> + +#define PERM_ALL -2 + +/** + * The Virtual File class handles all the details of maintaining a single + * file component within the virtual file system (vfs). a vfile object + * contains the nessecery details about a file and member functions which + * allow the object to give out the needed details about the file. + */ +class vfile : public TQObject{ + TQ_OBJECT + + +public: + vfile(){} + + /** + * Use this constructor when you know the following files properties: \n + * file name, file size, file permissions,is the file a link,owner uid & group uid. + */ + vfile(const TQString& name, + const TDEIO::filesize_t size, + const TQString& perm, + const time_t mtime, + const bool symLink, + const uid_t owner, + const gid_t group, + const TQString& mime, + const TQString& symDest, + const mode_t mode, + const int rwx = -1 ); + + vfile(const TQString& name, + const TDEIO::filesize_t size, + const TQString& perm, + const time_t mtime, + const bool symLink, + const TQString& owner, + const TQString& group, + const TQString& userName, + const TQString& mime, + const TQString& symDest, + const mode_t mode, + const int rwx = -1, + const TQString& aclString = TQString(), + const TQString& aclDfltString = TQString() ); + + bool operator==(const vfile& vf) const; + vfile& operator= (const vfile& vf); + inline bool operator!=(const vfile& vf){ return !((*this)==vf); } + + // following functions give-out file details + inline const TQString& vfile_getName() const { return vfile_name; } + inline TDEIO::filesize_t vfile_getSize() const { return vfile_size; } + inline const TQString& vfile_getPerm() const { return vfile_perm; } + inline bool vfile_isDir() const { return vfile_isdir; } + inline bool vfile_isSymLink() const { return vfile_symLink; } + inline const TQString& vfile_getSymDest() const { return vfile_symDest; } + inline mode_t vfile_getMode() const { return vfile_mode; } + inline uid_t vfile_getUid() const { return vfile_ownerId; } + inline gid_t vfile_getGid() const { return vfile_groupId; } + inline time_t vfile_getTime_t() const { return vfile_time_t; } + inline const KURL& vfile_getUrl() const { return vfile_url; } + + const TQString& vfile_getMime(bool fast=false); + const TQString& vfile_getOwner(); + const TQString& vfile_getGroup(); + const TQString& vfile_getACL(); + const TQString& vfile_getDefaultACL(); + const TDEIO::UDSEntry vfile_getEntry(); //< return the UDSEntry from the vfile + char vfile_isReadable() const; + char vfile_isWriteable() const; + char vfile_isExecutable() const; + /** + * Set the file size. + * used ONLY when calculating a directory's space, needs to change the + * displayed size of the viewitem and thus the vfile. For INTERNAL USE ! + */ + inline void vfile_setSize(TDEIO::filesize_t size) {vfile_size = size;} + inline void vfile_setUrl(const KURL& url) {vfile_url = url; } + + inline void vfile_setIcon(const TQString& icn) {vfile_icon = icn; } + inline TQString vfile_getIcon(); + + virtual ~vfile(){} + +private: + void vfile_loadACL(); + +protected: + // the file information list + TQString vfile_name; //< file name + TDEIO::filesize_t vfile_size; //< file size + mode_t vfile_mode; //< file mode + uid_t vfile_ownerId; //< file owner id + gid_t vfile_groupId; //< file group id + TQString vfile_owner; //< file owner name + TQString vfile_group; //< file group name + TQString vfile_userName; //< the current username + TQString vfile_perm; //< file permissions string + time_t vfile_time_t; //< file modification in time_t format + bool vfile_symLink; //< true if the file is a symlink + TQString vfile_mimeType; //< file mimetype + TQString vfile_symDest; //< if it's a sym link - its detination + KURL vfile_url; //< file URL - empty by default + TQString vfile_icon; //< the name of the icon file + bool vfile_isdir; //< flag, if it's a directory + int vfile_rwx; //< flag, showing read, write, execute properties + bool vfile_acl_loaded;//<flag, indicates that ACL permissions already loaded + bool vfile_has_acl; //< flag, indicates ACL permissions + TQString vfile_acl; //< ACL permission string + TQString vfile_def_acl; //< ACL default string +}; + + +TQString vfile::vfile_getIcon(){ + if( vfile_icon.isEmpty() ){ + TQString mime = this->vfile_getMime(); + if ( mime == "Broken Link !" ) + vfile_icon = "file_broken"; + else { + vfile_icon = KMimeType::mimeType( mime ) ->icon( TQString(), true ); + } + } + return vfile_icon; +} + +#endif diff --git a/src/app/VFS/vfs.cpp b/src/app/VFS/vfs.cpp new file mode 100644 index 0000000..e6804e6 --- /dev/null +++ b/src/app/VFS/vfs.cpp @@ -0,0 +1,393 @@ +/*************************************************************************** + vfs.cpp + ------------------- + copyright : (C) 2000 by Shie Erlich & Rafi Yanai + e-mail : krusader@users.sourceforge.net + web site : http://krusader.sourceforge.net + ------------------------------------------------------------------------ + the vfs class is an extendable class which by itself does (almost) + nothing. other VFSs like the normal_vfs inherits from this class and + make it possible to use a consistent API for all types of VFSs. + + *************************************************************************** + + A + + db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. + 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D + 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' + 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b + 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. + YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD + + S o u r c e F i l e + + *************************************************************************** + * * + * 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 <unistd.h> +#include <time.h> +#include <tqeventloop.h> +#include <tdeapplication.h> +#include <klargefile.h> +#include <tqdir.h> +#include "vfs.h" +#include "../krusader.h" +#include "../defaults.h" + +vfs::vfs(TQObject* panel, bool quiet): vfs_busy(false), quietMode(quiet),disableRefresh(false),postponedRefreshURL(), + invalidated(true),panelConnected(false),vfs_tempFilesP(0),vfileIterator(0),deletePossible( true ), + deleteRequested( false ) { + + + setVfsFilesP( new vfileDict() ); + if ( panel ){ + panelConnected = true; + connect(this,TQ_SIGNAL(startUpdate()),panel,TQ_SLOT(slotStartUpdate())); + connect(this,TQ_SIGNAL(incrementalRefreshFinished( const KURL& )),panel,TQ_SLOT(slotGetStats( const KURL& ))); + } + else quietMode = true; +} + +vfs::~vfs() { + if( !deletePossible ) + fprintf( stderr, "INTERNAL ERROR: trying to delete vfs while it is used! This may cause crash. Hoping the best...\n" ); + clear(); // please don't remove this line. This informs the view about deleting the references + delete vfs_filesP; +} + +TDEIO::filesize_t vfs::vfs_totalSize(){ + TDEIO::filesize_t temp=0; + class vfile* vf=vfs_getFirstFile(); + + while (vf!=0){ + if ( (vf->vfile_getName() != ".") && ( vf->vfile_getName() != "..") + && !(vf->vfile_isDir()) ) + temp+=vf->vfile_getSize(); + vf=vfs_getNextFile(); + } + return temp; +} + +bool vfs::vfs_refresh(TDEIO::Job* job){ + if(job && job->error()){ + job->showErrorDialog(krApp); + } + return vfs_refresh(vfs_origin); +} + +KURL vfs::fromPathOrURL( const TQString &originIn ) +{ + TQString password, loginName, origin = originIn; + bool bugfix = false; + + if ( originIn.contains( ":/" ) && !originIn.startsWith( "/" ) ) + { + // breakdown the url; + /* FIXME: untill KDE fixes the bug we have to check for + passwords and users with @ in them... */ + bugfix = origin.find("@") != origin.findRev("@"); + if(bugfix){ + if(origin.find(":") != origin.findRev(":", origin.findRev("@") )){ + int passStart = origin.find( ":",origin.find(":")+1 )+1; + int passLen = origin.findRev("@")-passStart; + password = origin.mid(passStart,passLen); + origin = origin.remove(passStart-1,passLen+1); + } + if(origin.find("@") != origin.findRev("@")){ + int usrStart = origin.find( "/" )+1; + if(origin.at(usrStart) == '/') ++usrStart; + int usrLen = origin.findRev("@")-usrStart; + loginName = origin.mid(usrStart,usrLen); + origin = origin.remove(usrStart,usrLen+1); + } + } + } + KURL url = KURL::fromPathOrURL( origin ); + if(loginName.isEmpty()) loginName = url.user(); + if(password.isEmpty()) password = url.pass(); + if(bugfix){ + url.setPass(password); + url.setUser(loginName); + } + + return url; +} + +TQString vfs::pathOrURL( const KURL &originIn, int trailingSlash ) +{ + if( originIn.isLocalFile() ) + return originIn.path( trailingSlash ); + return originIn.prettyURL( trailingSlash ); +} + +void vfs::setVfsFilesP(vfileDict* dict){ + vfs_filesP=dict; + vfs_tempFilesP = new vfileDict(); + vfs_tempFilesP->setAutoDelete( true ); + dict->setAutoDelete(true); + if( vfileIterator ) delete vfileIterator; + vfileIterator = new TQDictIterator<vfile>(*dict); +} + +bool vfs::vfs_refresh(){ + if( vfs_busy ) + return false; + + if( invalidated ) // invalidated fs requires total refresh + return vfs_refresh( vfs_getOrigin() ); + + if( disableRefresh ) + { + postponedRefreshURL = vfs_getOrigin(); + return false; + } + + vfs_busy = true; + // and populate it + krConfig->setGroup("Advanced"); + int maxIncrementalRefreshFileNr = krConfig->readNumEntry("Max Incremental Refresh File Nr", 50); + krConfig->setGroup("Look&Feel"); + bool showHidden = krConfig->readBoolEntry("Show Hidden",_ShowHidden); + bool res = populateVfsList(vfs_getOrigin(),showHidden); + + TQString name; + if( res ){ + // check if the maximum incremental refresh number is achieved + int diff = vfs_filesP->count() - vfs_tempFilesP->count(); + if( diff < 0 ) + diff = -diff; + if( diff >= maxIncrementalRefreshFileNr ) + { + // total filesystem refresh is cheaper than incremental refresh for many files + clear(); + delete vfs_filesP; + setVfsFilesP( vfs_tempFilesP ); + vfs_busy = false; + + emit startUpdate(); + return true; + } + + // compare the two list emiting signals when needed;; + for( vfile* vf = vfs_getFirstFile(); vf ; ){ + name = vf->vfile_getName(); + vfile* newVf = (*vfs_tempFilesP)[name]; + if( !newVf ){ + // the file was deleted.. + emit deletedVfile(name); + vfs_filesP->remove(name); + // the remove() advance our iterator ! + vf = vfileIterator->current(); + } else { + if( *vf != *newVf ){ + // the file was changed.. + *vf = *newVf; + emit updatedVfile(vf); + } + vf=vfs_getNextFile(); + } + vfs_tempFilesP->remove(name); + } + // everything thats left is a new file + TQDictIterator<vfile> it(*vfs_tempFilesP); + for(vfile* vf=it.toFirst(); vf; vf=(++it)){ + // sanity checking + if( !vf || (*vfs_filesP)[vf->vfile_getName()] ) continue; + + vfile* newVf = new vfile(); + *newVf = *vf; + vfs_filesP->insert(newVf->vfile_getName(),newVf); + emit addedVfile(newVf); + } + } + + // delete the temporary vfiles + vfs_tempFilesP->clear(); + vfs_busy = false; + + emit incrementalRefreshFinished( vfs_origin ); + + return res; +} + +bool vfs::vfs_refresh(const KURL& origin){ + if( vfs_busy ) + return false; + + if( disableRefresh ) + { + postponedRefreshURL = origin; + return true; + } + + if( !invalidated && origin.equals(vfs_getOrigin(),true) ) return vfs_refresh(); + + vfs_busy = true; + + krConfig->setGroup("Look&Feel"); + bool showHidden = krConfig->readBoolEntry("Show Hidden",_ShowHidden); + + vfs_tempFilesP->clear(); + // and re-populate it + if (!populateVfsList(origin,showHidden) ) + { + vfs_busy = false; + return false; + } + + clear(); + delete vfs_filesP; + setVfsFilesP( vfs_tempFilesP ); + vfs_busy = false; + + emit startUpdate(); + + invalidated = false; + return true; +} + +void vfs::vfs_enableRefresh(bool enable){ + if (vfs_type != NORMAL) return; + if (disableRefresh == !enable) return; // if gets called twice by mistake + disableRefresh = quietMode = !enable; + if( enable && !postponedRefreshURL.isEmpty() ) vfs_refresh( postponedRefreshURL ); + postponedRefreshURL = KURL(); +} + +void vfs::clear() +{ + emit cleared(); + vfs_filesP->clear(); +} + +bool vfs::vfs_processEvents() { + if( deleteRequested ) + return false; + deletePossible = false; + tqApp->eventLoop() ->processEvents( TQEventLoop::AllEvents | TQEventLoop::WaitForMore ); + deletePossible = true; + if( deleteRequested ) { + emit deleteAllowed(); + return false; + } + return true; +} + +void vfs::vfs_requestDelete() { + if( deletePossible ) + emit deleteAllowed(); + deleteRequested = true; +} + +/// to be implemented +#if KDE_IS_VERSION(3,3,0) +#include <kdirsize.h> +void vfs::slotKdsResult( TDEIO::Job* job){ + if( job && !job->error() ){ + KDirSize* kds = static_cast<KDirSize*>(job); + *kds_totalSize += kds->totalSize(); + *kds_totalFiles += kds->totalFiles(); + *kds_totalDirs += kds->totalSubdirs(); + } + *kds_busy = true; +} + +void vfs::vfs_calcSpace( TQString name , TDEIO::filesize_t* totalSize, unsigned long* totalFiles, unsigned long* totalDirs, bool* stop ) { + calculateURLSize( vfs_getFile( name ), totalSize, totalFiles, totalDirs, stop ); +} + +void vfs::calculateURLSize( KURL url, TDEIO::filesize_t* totalSize, unsigned long* totalFiles, unsigned long* totalDirs, bool* stop ) { + if ( stop && *stop ) return ; + kds_busy = stop; + kds_totalSize = totalSize ; + kds_totalFiles = totalFiles; + kds_totalDirs = totalDirs; + + if( url.isLocalFile() ) { + vfs_calcSpaceLocal( url.path(-1), totalSize, totalFiles, totalDirs, stop ); + return; + } else { + stat_busy = true; + TDEIO::StatJob* statJob = TDEIO::stat( url, false ); + connect( statJob, TQ_SIGNAL( result( TDEIO::Job* ) ), this, TQ_SLOT( slotStatResultArrived( TDEIO::Job* ) ) ); + while ( !(*stop) && stat_busy ) {usleep(1000);} + if( entry.isEmpty() ) return; // statJob failed + KFileItem kfi(entry, url, true ); + if( kfi.isFile() || kfi.isLink() ) { + *totalFiles++; + *totalSize += kfi.size(); + return; + } + } + + KDirSize* kds = KDirSize::dirSizeJob( url ); + connect( kds, TQ_SIGNAL( result( TDEIO::Job* ) ), this, TQ_SLOT( slotKdsResult( TDEIO::Job* ) ) ); + while ( !(*stop) ){ + // we are in a sepetate thread - so sleeping is OK + usleep(1000); + } +} + +void vfs::vfs_calcSpaceLocal(TQString name ,TDEIO::filesize_t *totalSize,unsigned long *totalFiles,unsigned long *totalDirs, bool* stop){ + if ( *stop ) return; + if (!name.contains("/")) name = vfs_workingDir()+"/"+name; + if (name == "/proc") return; + + KDE_struct_stat stat_p; // KDE lstat is necessary as TQFileInfo and KFileItem + KDE_lstat(name.local8Bit(),&stat_p); // reports wrong size for a symbolic link + + if( S_ISLNK(stat_p.st_mode) || !S_ISDIR(stat_p.st_mode) ) { // single files are easy : ) + ++(*totalFiles); + (*totalSize) += stat_p.st_size; + } + else{ // handle directories + // avoid a nasty crash on un-readable dirs + bool readable = ::access( name.local8Bit(), R_OK | X_OK ) == 0; + if( !readable ) + return; + + TQDir dir(name); + if ( !dir.exists() ) return; + + ++(*totalDirs); + dir.setFilter(TQDir::All | TQDir::System | TQDir::Hidden); + dir.setSorting(TQDir::Name | TQDir::DirsFirst); + + // recurse on all the files in the directory + TQFileInfoList* fileList = const_cast<TQFileInfoList*>(dir.entryInfoList()); + for (TQFileInfo* qfiP = fileList->first(); qfiP != 0; qfiP = fileList->next()){ + if ( *stop ) return; + if (qfiP->fileName() != "." && qfiP->fileName() != "..") + vfs_calcSpaceLocal(name+"/"+qfiP->fileName(),totalSize,totalFiles,totalDirs,stop); + } + } +} + + +void vfs::slotStatResultArrived( TDEIO::Job* job ) { + if( !job || job->error() ) entry = TDEIO::UDSEntry(); + else entry = static_cast<TDEIO::StatJob*>(job)->statResult(); + stat_busy = false; +} + +#else +void vfs::slotKdsResult(TDEIO::Job *job){/* empty */} +void vfs::vfs_calcSpace( TQString /*name*/ , TDEIO::filesize_t* /*totalSize*/, unsigned long* /*totalFiles*/, unsigned long* /*totalDirs*/, bool* /*stop*/ ) {/* empty*/} +#endif + +TQValueList<vfile*> vfs::vfs_search(const KRQuery& filter) { + TQValueList<vfile*> result; + for ( vfile *vf = vfs_getFirstFile(); vf != 0 ; vf = vfs_getNextFile() ) + if (filter.match(vf)) + result.append(vf); + return result; +} + +#include "vfs.moc" diff --git a/src/app/VFS/vfs.h b/src/app/VFS/vfs.h new file mode 100644 index 0000000..9253de0 --- /dev/null +++ b/src/app/VFS/vfs.h @@ -0,0 +1,187 @@ +/*************************************************************************** + vfs.h + ------------------- + begin : Thu May 4 2000 + copyright : (C) 2000 by Shie Erlich & Rafi Yanai + e-mail : krusader@users.sourceforge.net + web site : http://krusader.sourceforge.net + *************************************************************************** + + A + + db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. + 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D + 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' + 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b + 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. + YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD + + H e a d e r F i l e + + *************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef VFS_H +#define VFS_H + +// TQt includes +#include <tqstring.h> +#include <tqvaluelist.h> +#include <tqobject.h> +#include <tqdict.h> +// TDE includes +#include <kurl.h> +#include <tdeio/jobclasses.h> +// Krusader includes +#include "vfile.h" +#include "preservingcopyjob.h" +#include "krquery.h" + +/** + * The vfs class is an extendable class which by itself does (almost) + * nothing. other VFSs like the normal_vfs inherits from this class and + * make it possible to use a consistent API for all types of VFSs. + */ +class vfs: public TQObject{ + TQ_OBJECT + +public: + typedef TQDict<vfile> vfileDict; + enum VFS_TYPE{ERROR=0,NORMAL,FTP,TEMP,VIRT}; + + /** + * Creates a vfs. + * @param panel the panel father. the VFS will connect it's signals to this object. + * @param quiet if true, the VFS will not display error messages + */ + vfs(TQObject* panel, bool quiet=false); + virtual ~vfs(); + + /// Copy a file to the vfs (physical). + virtual void vfs_addFiles(KURL::List *fileUrls,TDEIO::CopyJob::CopyMode mode,TQObject* toNotify,TQString dir = "", PreserveMode pmode = PM_DEFAULT)=0; + /// Remove a file from the vfs (physical) + virtual void vfs_delFiles(TQStringList *fileNames)=0; + /// Return a list of URLs for multiple files + virtual KURL::List* vfs_getFiles(TQStringList* names)=0; + /// Return a URL to a single file + virtual KURL vfs_getFile(const TQString& name)=0; + /// Create a new directory + virtual void vfs_mkdir(const TQString& name)=0; + /// Rename file + virtual void vfs_rename(const TQString& fileName,const TQString& newName)=0; + /// Calculate the amount of space occupied by a file or directory (recursive). + virtual void vfs_calcSpace(TQString name ,TDEIO::filesize_t *totalSize,unsigned long *totalFiles,unsigned long *totalDirs, bool * stop); + /// Calculate the amount of space occupied by a local file or directory (recursive). + virtual void vfs_calcSpaceLocal(TQString name ,TDEIO::filesize_t *totalSize,unsigned long *totalFiles,unsigned long *totalDirs, bool * stop); + + /// Return the VFS working dir + virtual TQString vfs_workingDir()=0; + /// Return true if the VFS url is writable + virtual bool vfs_isWritable() { return isWritable; } + /// Return vfile* or 0 if not found + inline vfile* vfs_search(const TQString& name){ return (*vfs_filesP)[name]; } + /// Return an empty vfile* list if not found + TQValueList<vfile*> vfs_search(const KRQuery& filter); + /// The total size of all the files in the VFS, + TDEIO::filesize_t vfs_totalSize(); + /// The number of files in the VFS + inline unsigned long vfs_noOfFiles() { return vfs_filesP->count(); } + /// Returns the VFS url. + inline KURL vfs_getOrigin() { return vfs_origin; } + /// Return the VFS type. + inline VFS_TYPE vfs_getType() { return vfs_type; } + /// Returns true if vfs is busy + inline bool vfs_isBusy() { return vfs_busy; } + /// Return the first file in the VFS and set the internal iterator to the beginning of the list. + inline vfile* vfs_getFirstFile(){ return (vfileIterator ? vfileIterator->toFirst() : 0); } + /// Return the the next file in the list and advance the iterator. + inline vfile* vfs_getNextFile() { return (vfileIterator ? ++(*vfileIterator) : 0); } + /// returns true if the vfs can be deleted without crash + virtual bool vfs_canDelete() { return deletePossible; } + /// process the application events + virtual bool vfs_processEvents(); + /// process the application events + virtual void vfs_requestDelete(); + /// process the application events + virtual bool vfs_isDeleting() { return deleteRequested; } + // KDE FTP proxy bug correction + static KURL fromPathOrURL( const TQString &originIn ); + static TQString pathOrURL( const KURL &originIn, int trailingSlash = 0 ); + + +public slots: + /// Re-reads files and stats and fills the vfile list + bool vfs_refresh(const KURL& origin); + /// Used to refresh the VFS when a job finishs. it calls the refresh() slot + /// or display a error message if the job fails + bool vfs_refresh(TDEIO::Job* job); + bool vfs_refresh(); + void vfs_setQuiet(bool beQuiet){ quietMode=beQuiet; } + void vfs_enableRefresh(bool enable); + void vfs_invalidate() { invalidated = true; } + +signals: + void startUpdate(); //< emitted when the VFS starts to refresh its list of vfiles. + void startJob(TDEIO::Job* job); + void incrementalRefreshFinished( const KURL& ); //< emitted when the incremental refresh was finished + void addedVfile(vfile* vf); + void deletedVfile(const TQString& name); + void updatedVfile(vfile* vf); + void cleared(); + void deleteAllowed(); + +protected: + /// Feel the vfs dictionary with vfiles, must be implemented for each vfs + virtual bool populateVfsList(const KURL& origin, bool showHidden) = 0; + /// Called by populateVfsList for each file + void foundVfile( vfile *vf ) { vfs_tempFilesP->insert(vf->vfile_getName(),vf); } + /// Set the vfile list pointer + void setVfsFilesP(vfileDict* dict); + /// clear and delete all current vfiles + inline void clear(); + /// Add a new vfile to the list. + inline void addToList(vfile *data){ vfs_filesP->insert(data->vfile_getName(),data); } + /// Deletes a vfile from the list. + inline void removeFromList(TQString name){ vfs_filesP->remove(name); } + + /// Deletes a vfile from the list. + void calculateURLSize(KURL url,TDEIO::filesize_t *totalSize,unsigned long *totalFiles,unsigned long *totalDirs, bool * stop); + + VFS_TYPE vfs_type; //< the vfs type. + KURL vfs_origin; //< the path or file the VFS originates from. + bool vfs_busy; //< true if vfs is busy with refreshing + bool quietMode; //< if true the vfs won't display error messages or emit signals + bool disableRefresh; //< true if refresh is disabled + bool isWritable; //< true if it's writable + KURL postponedRefreshURL; //< true if vfs_refresh() was called when refresh is disabled. + bool invalidated; //< the content of the cache is invalidated + bool panelConnected; //< indicates that there's a panel connected. Important for disabling the dir watcher + +protected slots: + /// The slot for the KDirSize job + void slotKdsResult(TDEIO::Job *job); + void slotStatResultArrived(TDEIO::Job *job); + +private: + vfileDict* vfs_filesP; //< Point to a lists of virtual files (vfile). + vfileDict* vfs_tempFilesP;//< Temporary files are stored here + TQDictIterator<vfile>* vfileIterator; //< Point to a dictionary of virtual files (vfile). + + // used in the calcSpace function + bool* kds_busy; + bool stat_busy; + bool deletePossible; + bool deleteRequested; + TDEIO::UDSEntry entry; + TDEIO::filesize_t* kds_totalSize; + unsigned long* kds_totalFiles; + unsigned long* kds_totalDirs; +}; + +#endif diff --git a/src/app/VFS/virt_vfs.cpp b/src/app/VFS/virt_vfs.cpp new file mode 100644 index 0000000..3c70231 --- /dev/null +++ b/src/app/VFS/virt_vfs.cpp @@ -0,0 +1,341 @@ +/*************************************************************************** + virt_vfs.cpp - description + ------------------- + begin : Fri Dec 5 2003 + copyright : (C) 2003 by Shie Erlich & Rafi Yanai + email : +***************************************************************************/ + +/*************************************************************************** + * * + * 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 <unistd.h> +#include <time.h> + +#include <tdefileitem.h> +#include <tdeglobalsettings.h> +#include <kurl.h> +#include <tdemessagebox.h> +#include <tdelocale.h> +#include <kdirsize.h> +#include <kstandarddirs.h> + +#include "krpermhandler.h" +#include "../krusader.h" +#include "../defaults.h" +#include "virt_vfs.h" + +#define VIRT_VFS_DB "virt_vfs.db" + +TQDict<KURL::List> virt_vfs::virtVfsDict; +TDEConfig* virt_vfs::virt_vfs_db=0; + +virt_vfs::virt_vfs( TQObject* panel, bool quiet ) : vfs( panel, quiet ) { + // set the writable attribute + isWritable = true; + + virtVfsDict.setAutoDelete( true ); + if ( virtVfsDict.isEmpty() ) { + restore(); + } + + vfs_type = VIRT; +} + +virt_vfs::~virt_vfs() {} + +bool virt_vfs::populateVfsList( const KURL& origin, bool /*showHidden*/ ) { + vfs_origin = origin; + vfs_origin.adjustPath(-1); + path = origin.path( -1 ).mid( 1 ); + if ( path.isEmpty() ) path = "/"; + + KURL::List* urlList = virtVfsDict[ path ]; + if ( !urlList ) { + urlList = new KURL::List(); + virtVfsDict.insert( path, urlList ); + virtVfsDict[ "/" ] ->append( KURL::fromPathOrURL( "virt:/" + path ) ); + } + + if ( urlList->isEmpty() ) return true; + KURL::List::iterator it; + for ( it = urlList->begin() ; it != urlList->end() ; /*++it*/ ) { + KURL url = *it; + // translate url->vfile and remove urls that no longer exist from the list + vfile* vf = stat(url); + if ( !vf ) { + it = urlList->remove( it ); + // the iterator is advanced automaticly + continue; + } + foundVfile( vf ); + ++it; + } + save(); + return true; +} + +void virt_vfs::vfs_addFiles( KURL::List *fileUrls, TDEIO::CopyJob::CopyMode /*mode*/, TQObject* /*toNotify*/, TQString /*dir*/, PreserveMode /*pmode*/ ) { + if ( path == "/" ) { + if ( !quietMode ) + KMessageBox::error( krApp, i18n( "You can't copy files directly to the 'virt:/' directory.\nYou can create a sub directory and copy your files into it." ), i18n( "Error" ) ); + return ; + } + + KURL::List* urlList = virtVfsDict[ path ]; + for( unsigned i=0; i != fileUrls->count(); i++ ) { + if( !urlList->contains( (*fileUrls)[ i ] ) ) + urlList->push_back( (*fileUrls)[ i ] ); + } + + vfs_refresh(); +} + +void virt_vfs::vfs_delFiles( TQStringList *fileNames ) { + if ( path == "/" ) { + for ( uint i = 0 ; i < fileNames->count(); ++i ) { + TQString filename = ( *fileNames ) [ i ]; + virtVfsDict[ "/" ] ->remove( TQString("virt:/")+filename ); + virtVfsDict.remove( filename ); + } + vfs_refresh(); + return ; + } + + KURL::List filesUrls; + KURL url; + + // names -> urls + for ( uint i = 0 ; i < fileNames->count(); ++i ) { + TQString filename = ( *fileNames ) [ i ]; + filesUrls.append( vfs_getFile( filename ) ); + } + TDEIO::Job *job; + + // delete of move to trash ? + krConfig->setGroup( "General" ); + if ( krConfig->readBoolEntry( "Move To Trash", _MoveToTrash ) ) { +#if KDE_IS_VERSION(3,4,0) + job = TDEIO::trash( filesUrls, true ); +#else + job = new TDEIO::CopyJob( filesUrls, TDEGlobalSettings::trashPath(), TDEIO::CopyJob::Move, false, true ); +#endif + connect( job, TQ_SIGNAL( result( TDEIO::Job* ) ), krApp, TQ_SLOT( changeTrashIcon() ) ); + } else + job = new TDEIO::DeleteJob( filesUrls, false, true ); + + // refresh will remove the deleted files... + connect( job, TQ_SIGNAL( result( TDEIO::Job* ) ), this, TQ_SLOT( vfs_refresh( TDEIO::Job* ) ) ); +} + +void virt_vfs::vfs_removeFiles( TQStringList *fileNames ) { + if ( path == "/" ) + return; + + // removing the URLs from the collection + for ( uint i = 0 ; i < fileNames->count(); ++i ) { + KURL::List* urlList = virtVfsDict[ path ]; + if( urlList ) + urlList->remove( vfs_getFile( ( *fileNames ) [ i ] ) ); + } + + vfs_refresh(); +} + +KURL::List* virt_vfs::vfs_getFiles( TQStringList* names ) { + KURL url; + KURL::List* urls = new KURL::List(); + for ( TQStringList::Iterator name = names->begin(); name != names->end(); ++name ) { + url = vfs_getFile( *name ); + urls->append( url ); + } + return urls; +} + +KURL virt_vfs::vfs_getFile( const TQString& name ) { + vfile * vf = vfs_search( name ); + if ( !vf ) return KURL(); // empty + + KURL url = vf->vfile_getUrl(); + if ( vf->vfile_isDir() ) url.adjustPath( + 1 ); + return url; +} + +void virt_vfs::vfs_mkdir( const TQString& name ) { + if ( path != "/" ) { + if ( !quietMode ) + KMessageBox::error( krApp, i18n( "Creating new directories is allowed only in the 'virt:/' directory." ), i18n( "Error" ) ); + return ; + } + KURL::List* temp = new KURL::List(); + virtVfsDict.insert( name, temp ); + virtVfsDict[ "/" ] ->append( TQString( "virt:/" )+name ); + + vfs_refresh(); +} + +void virt_vfs::vfs_rename( const TQString& fileName, const TQString& newName ) { + KURL::List fileUrls; + KURL url , dest; + + vfile* vf = vfs_search( fileName ); + if ( !vf ) return ; // not found + + if ( path == "/" ) { + virtVfsDict[ "/" ] ->append( TQString( "virt:/" ) + newName ); + virtVfsDict[ "/" ] ->remove( TQString( "virt:/" ) + fileName ); + virtVfsDict.insert( newName, virtVfsDict.take( fileName ) ); + vfs_refresh(); + return ; + } + + url = vf->vfile_getUrl(); + fileUrls.append( url ); + + dest = fromPathOrURL( newName ); + // add the new url to the list + // the the list is refreshed only existing files remain - + // so we don't have to worry if the job was successful + virtVfsDict[ path ] ->append( dest ); + + TDEIO::Job *job = new TDEIO::CopyJob( fileUrls, dest, TDEIO::CopyJob::Move, true, false ); + connect( job, TQ_SIGNAL( result( TDEIO::Job* ) ), this, TQ_SLOT( vfs_refresh( TDEIO::Job* ) ) ); +} + +void virt_vfs::slotStatResult( TDEIO::Job* job ) { + if( !job || job->error() ) entry = TDEIO::UDSEntry(); + else entry = static_cast<TDEIO::StatJob*>(job)->statResult(); + busy = false; +} + +vfile* virt_vfs::stat( const KURL& url ) { + if( url.protocol() == "virt" ){ + TQString path = url.path().mid(1); + if( path.isEmpty() ) path = "/"; + vfile * temp = new vfile( path, 0, "drwxr-xr-x", time( 0 ), false, getuid(), getgid(), "inode/directory", "", 0 ); + temp->vfile_setUrl( url ); + return temp; + } + KFileItem* kfi; + if ( url.isLocalFile() ) { + kfi = new KFileItem( KFileItem::Unknown, KFileItem::Unknown, url, true ); + } + else { + busy = true; + TDEIO::StatJob* statJob = TDEIO::stat( url, false ); + connect( statJob, TQ_SIGNAL( result( TDEIO::Job* ) ), this, TQ_SLOT( slotStatResult( TDEIO::Job* ) ) ); + while ( busy && vfs_processEvents() ); + if( entry.isEmpty() ) return 0; // statJob failed + + kfi = new KFileItem(entry, url, true ); + } + + if ( !kfi->time( TDEIO::UDS_MODIFICATION_TIME ) ){ + delete kfi; + return 0; // file not found + } + + vfile *temp; + + // get file statistics + TQString name; + if( url.isLocalFile() ) + name = url.path(); + else + name = url.prettyURL(); + + TDEIO::filesize_t size = kfi->size(); + time_t mtime = kfi->time( TDEIO::UDS_MODIFICATION_TIME ); + bool symLink = kfi->isLink(); + mode_t mode = kfi->mode() | kfi->permissions(); + TQString perm = KRpermHandler::mode2TQString( mode ); +// set the mimetype + TQString mime = TQString(); + TQString symDest = ""; + if ( symLink ) { + symDest = kfi->linkDest(); + if ( kfi->isDir() ) perm[ 0 ] = 'd'; + } + + // create a new virtual file object + if ( kfi->user().isEmpty() ) + temp = new vfile( name, size, perm, mtime, symLink, getuid(), getgid(), mime, symDest, mode ); + else { + TQString currentUser = url.user(); + if ( currentUser.contains( "@" ) ) /* remove the FTP proxy tags from the username */ + currentUser.truncate( currentUser.find( '@' ) ); + if ( currentUser.isEmpty() ) + currentUser = KRpermHandler::uid2user( getuid() ); + temp = new vfile( name, size, perm, mtime, symLink, kfi->user(), kfi->group(), currentUser, mime, symDest, mode ); + } + + temp->vfile_setUrl( kfi->url() ); + delete kfi; + return temp; +} + +TDEConfig* virt_vfs::getVirtDB(){ + if( !virt_vfs_db ){ + virt_vfs_db = new TDEConfig(VIRT_VFS_DB,false,"data"); + } + return virt_vfs_db; +} + +bool virt_vfs::save(){ + TDEConfig* db = getVirtDB(); + + db->setGroup("virt_db"); + TQDictIterator<KURL::List> it( virtVfsDict ); // See TQDictIterator + for( ; it.current(); ++it ){ + KURL::List::iterator url; + TQStringList entry; + for ( url = it.current()->begin() ; url != it.current()->end() ; ++url ) { + entry.append( (*url).prettyURL() ); + } + db->writeEntry(it.currentKey(),entry); + } + + db->sync(); + + return true; +} + +bool virt_vfs::restore(){ + TDEConfig* db = getVirtDB(); + db->setGroup("virt_db"); + + TQMap<TQString, TQString> map = db->entryMap("virt_db"); + TQMap<TQString, TQString>::Iterator it; + KURL::List* urlList; + for ( it = map.begin(); it != map.end(); ++it ) { + urlList = new KURL::List( db->readListEntry(it.key()) ); + virtVfsDict.insert( it.key(),urlList ); + } + + if( !virtVfsDict["/" ]){ + urlList = new KURL::List(); + virtVfsDict.insert( "/", urlList ); + } + + return true; +} + +void virt_vfs::vfs_calcSpace( TQString name , TDEIO::filesize_t* totalSize, unsigned long* totalFiles, unsigned long* totalDirs, bool* stop ) { + if ( stop && *stop ) return ; + if( path == "/" ) { + KURL::List* urlList = virtVfsDict[ name ]; + if ( urlList ) + for( unsigned i=0; (i != urlList->size()) && !(*stop); i++ ) + calculateURLSize( (*urlList)[ i ], totalSize, totalFiles, totalDirs, stop ); + return; + } + return vfs::vfs_calcSpace( name, totalSize, totalFiles, totalDirs, stop ); +} + +#include "virt_vfs.moc" diff --git a/src/app/VFS/virt_vfs.h b/src/app/VFS/virt_vfs.h new file mode 100644 index 0000000..6663e21 --- /dev/null +++ b/src/app/VFS/virt_vfs.h @@ -0,0 +1,77 @@ +/*************************************************************************** + virt_vfs.h - description + ------------------- + begin : Fri Dec 5 2003 + copyright : (C) 2003 by Shie Erlich & Rafi Yanai + email : + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef VIRT_VFS_H +#define VIRT_VFS_H + +#include <tdeconfig.h> + +#include "vfs.h" + +/** + *@author Shie Erlich & Rafi Yanai + */ + +class virt_vfs : public vfs { +TQ_OBJECT + +public: + virt_vfs(TQObject* panel, bool quiet=false); + ~virt_vfs(); + + /// Copy a file to the vfs (physical). + void vfs_addFiles(KURL::List *fileUrls,TDEIO::CopyJob::CopyMode mode,TQObject* toNotify,TQString dir = "", PreserveMode pmode = PM_DEFAULT ); + /// Remove a file from the vfs (physical) + void vfs_delFiles(TQStringList *fileNames); + /// Remove a file from the collection (only its link, not the file) + void vfs_removeFiles(TQStringList *fileNames); + /// Return a list of URLs for multiple files + KURL::List* vfs_getFiles(TQStringList* names); + /// Return a URL to a single file + KURL vfs_getFile(const TQString& name); + /// Create a new directory + void vfs_mkdir(const TQString& name); + /// Rename file + void vfs_rename(const TQString& fileName,const TQString& newName); + /// Calculate the amount of space occupied by a file or directory (recursive). + virtual void vfs_calcSpace(TQString name ,TDEIO::filesize_t *totalSize,unsigned long *totalFiles,unsigned long *totalDirs, bool * stop); + + /// Return the VFS working dir + TQString vfs_workingDir(){ return TQString(); } + +protected slots: + void slotStatResult(TDEIO::Job *job); + +protected: + /// Save the dictionary to file + bool save(); + /// Restore the dictionary from file + bool restore(); + /// return the URLs DB + TDEConfig* getVirtDB(); + + bool populateVfsList(const KURL& origin, bool showHidden); + vfile* stat(const KURL& url); + + static TQDict<KURL::List> virtVfsDict; + static TDEConfig* virt_vfs_db; + bool busy; + TQString path; + TDEIO::UDSEntry entry; +}; + +#endif diff --git a/src/app/VFS/virtualcopyjob.cpp b/src/app/VFS/virtualcopyjob.cpp new file mode 100644 index 0000000..15be7fa --- /dev/null +++ b/src/app/VFS/virtualcopyjob.cpp @@ -0,0 +1,316 @@ +/*************************************************************************** + virtualcopyjob.cpp - description + ------------------- + copyright : (C) 2006 + by Csaba Karai + e-mail : krusader@users.sourceforge.net + web site : http://krusader.sourceforge.net + --------------------------------------------------------------------------- + Description + *************************************************************************** + + A + + db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. + 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D + 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' + 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b + 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. + YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD + + S o u r c e F i l e + + *************************************************************************** + * * + * 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 "virtualcopyjob.h" +#include "vfs.h" +#include "vfile.h" +#include "../krusader.h" +#include <tdeio/observer.h> +#include <tdeio/global.h> +#include <tdeio/jobclasses.h> +#include <kdirsize.h> + +#define REPORT_TIMEOUT 200 + +VirtualCopyJob::VirtualCopyJob( const TQStringList *names, vfs * vfs, const KURL& dest, const KURL& baseURL, + PreserveMode pmode, TDEIO::CopyJob::CopyMode mode, bool asMethod, bool showProgressInfo ) : + TDEIO::Job( showProgressInfo ), m_totalSize( 0 ), m_totalFiles( 0 ), m_totalSubdirs( 0 ), + m_processedSize( 0 ), m_processedFiles( 0 ), m_processedSubdirs( 0 ), m_tempSize( 0 ), m_tempFiles( 0 ), + m_tempSubdirs( 0 ), m_dirsToGetSize(), m_filesToCopy(), m_size(), m_filenum(), m_subdirs(), m_baseURL( baseURL ), + m_dest( dest ), m_pmode( pmode ), m_mode( mode ), m_asMethod( asMethod ), m_showProgressInfo( showProgressInfo ), + m_state( ST_STARTING ), m_reportTimer(), m_current(), m_currentDir(), m_dirStack() { + + m_filesToCopy.setAutoDelete( true ); + m_dest.adjustPath( 1 ); + + vfile * file = vfs->vfs_getFirstFile(); + while( file ) { + if( names->contains( file->vfile_getName() ) ) { + TQString relativeDir = KURL::relativeURL( baseURL, file->vfile_getUrl().upURL() ); + + KURL::List *list = m_filesToCopy.find( relativeDir ); + if( list == 0 ) { + list = new KURL::List(); + m_filesToCopy.insert( relativeDir, list ); + // initialize the dir content + m_size[ relativeDir ] = 0; + m_filenum[ relativeDir ] = 0; + m_subdirs[ relativeDir ] = 0; + } + + if( !list->contains( file->vfile_getUrl() ) ) { + if( file->vfile_isDir() ) { + m_dirsToGetSize.append( file->vfile_getUrl() ); + m_totalSubdirs++; + m_subdirs[ relativeDir ]++; + } else { + m_totalFiles++; + m_filenum[ relativeDir ]++; + m_totalSize += file->vfile_getSize(); + m_size[ relativeDir ] += file->vfile_getSize(); + } + list->append( file->vfile_getUrl() ); + } + } + file = vfs->vfs_getNextFile(); + } + + if ( showProgressInfo ) { + connect( this, TQ_SIGNAL( totalFiles( TDEIO::Job*, unsigned long ) ), + Observer::self(), TQ_SLOT( slotTotalFiles( TDEIO::Job*, unsigned long ) ) ); + connect( this, TQ_SIGNAL( totalDirs( TDEIO::Job*, unsigned long ) ), + Observer::self(), TQ_SLOT( slotTotalDirs( TDEIO::Job*, unsigned long ) ) ); + connect( this, TQ_SIGNAL( processedFiles( TDEIO::Job*, unsigned long ) ), + Observer::self(), TQ_SLOT( slotProcessedFiles( TDEIO::Job*, unsigned long ) ) ); + connect( this, TQ_SIGNAL( processedDirs( TDEIO::Job*, unsigned long ) ), + Observer::self(), TQ_SLOT( slotProcessedDirs( TDEIO::Job*, unsigned long ) ) ); + connect( this, TQ_SIGNAL( percent( TDEIO::Job*, unsigned long ) ), + Observer::self(), TQ_SLOT( slotPercent( TDEIO::Job*, unsigned long ) ) ); + } + + TQTimer::singleShot( 0, this, TQ_SLOT( slotStart() ) ); +} + +void VirtualCopyJob::slotStart() { + if( m_showProgressInfo ) { + if( m_mode == TDEIO::CopyJob::Move ) + Observer::self()->slotMoving( this, m_baseURL, m_dest ); + else + Observer::self()->slotCopying( this, m_baseURL, m_dest ); + } + + connect(&m_reportTimer,TQ_SIGNAL(timeout()),this,TQ_SLOT(slotReport())); + m_reportTimer.start(REPORT_TIMEOUT,false); + + statNextDir(); +} + +void VirtualCopyJob::slotReport() { + switch( m_state ) { + case ST_CREATING_DIRECTORY: + if( m_showProgressInfo ) { + Observer::self()->slotCreatingDir( this, m_current ); + Observer::self()->slotProcessedDirs( this, m_processedSubdirs ); + emit processedDirs( this, m_processedSubdirs ); + } + break; + case ST_CALCULATING_TOTAL_SIZE: + emit totalSize( this, m_totalSize ); + emit totalDirs( this, m_totalSubdirs ); + emit totalFiles( this, m_totalFiles ); + break; + case ST_COPYING: + { + emit processedDirs( this, m_processedSubdirs + m_tempSubdirs ); + emit processedFiles( this, m_processedFiles + m_tempFiles ); + setProcessedSize( m_processedSize + m_tempSize ); + emit processedSize( this, m_processedSize + m_tempSize ); + double percDbl = ((double)( m_processedSize + m_tempSize )/(double)m_totalSize) * 100. + 0.5; + unsigned long perc = (long)percDbl; + if( perc > 100 ) + perc = 100; + emit percent( this, perc ); + break; + } + default: + break; + } +} + +void VirtualCopyJob::statNextDir() { + m_state = ST_CALCULATING_TOTAL_SIZE; + + if( m_dirsToGetSize.count() == 0 ) { + slotReport(); // report the total size values + createNextDir(); + return; + } + KURL dirToCheck = m_dirsToGetSize.first(); + m_dirsToGetSize.pop_front(); + + m_currentDir = KURL::relativeURL( m_baseURL, dirToCheck.upURL() ); + + KDirSize* kds = KDirSize::dirSizeJob( dirToCheck ); + connect( kds, TQ_SIGNAL( result( TDEIO::Job* ) ), this, TQ_SLOT( slotKdsResult( TDEIO::Job* ) ) ); +} + +void VirtualCopyJob::slotKdsResult( TDEIO::Job * job ) { + KDirSize* kds = static_cast<KDirSize*>(job); + m_totalSize += kds->totalSize(); + m_totalFiles += kds->totalFiles(); + m_totalSubdirs += kds->totalSubdirs(); + + m_size[ m_currentDir ] += kds->totalSize(); + m_filenum[ m_currentDir ] += kds->totalFiles(); + m_subdirs[ m_currentDir ] += kds->totalSubdirs(); + statNextDir(); +} + +void VirtualCopyJob::createNextDir() { + m_state = ST_CREATING_DIRECTORY; + + if( m_filesToCopy.count() == 0 ) { + emitResult(); + return; + } + + TQDictIterator<KURL::List> diter( m_filesToCopy ); + + m_currentDir = diter.currentKey(); + m_current = m_dest; + if( m_currentDir != "./" && !m_currentDir.isEmpty() ) + m_current.addPath( m_currentDir ); + + TDEIO::Job *job = TDEIO::stat( m_current ); + connect( job, TQ_SIGNAL( result( TDEIO::Job* ) ), this, TQ_SLOT( slotStatResult( TDEIO::Job* ) ) ); +} + +void VirtualCopyJob::slotStatResult( TDEIO::Job *job ) { + KURL url = (static_cast<TDEIO::SimpleJob*>(job) )->url(); + + if ( job && job->error() ) { + if( job->error() == TDEIO::ERR_DOES_NOT_EXIST && !url.equals( url.upURL(),true ) ) { + m_dirStack.push_back( url.fileName() ); + TDEIO::Job *job = TDEIO::stat( url.upURL() ); + connect( job, TQ_SIGNAL( result( TDEIO::Job* ) ), this, TQ_SLOT( slotStatResult( TDEIO::Job* ) ) ); + return; + } + job->showErrorDialog( krApp ); + directoryFinished( m_currentDir ); + createNextDir(); + return; + } + + if( m_dirStack.count() ) { + url.adjustPath( 1 ); + url.addPath( m_dirStack.last() ); + m_dirStack.pop_back(); + + TDEIO::Job *mkdir_job = TDEIO::mkdir( url ); + connect( mkdir_job, TQ_SIGNAL( result( TDEIO::Job* ) ), this, TQ_SLOT( slotMkdirResult( TDEIO::Job* ) ) ); + } + else + copyCurrentDir(); +} + +void VirtualCopyJob::slotMkdirResult( TDEIO::Job *job ) { + KURL url = (static_cast<TDEIO::SimpleJob*>(job) )->url(); + + if ( job && job->error() ) { + job->showErrorDialog( krApp ); + directoryFinished( m_currentDir ); + createNextDir(); + return; + } + + if( m_dirStack.count() ) { + url.adjustPath( 1 ); + url.addPath( m_dirStack.last() ); + m_dirStack.pop_back(); + + TDEIO::Job *mkdir_job = TDEIO::mkdir( url ); + connect( mkdir_job, TQ_SIGNAL( result( TDEIO::Job* ) ), this, TQ_SLOT( slotMkdirResult( TDEIO::Job* ) ) ); + } + else + copyCurrentDir(); +} + +void VirtualCopyJob::copyCurrentDir() { + m_state = ST_COPYING; + + TDEIO::CopyJob * copy_job = PreservingCopyJob::createCopyJob( m_pmode, *m_filesToCopy[ m_currentDir ], m_current, + m_mode, m_asMethod, false ); + + connect( copy_job, TQ_SIGNAL( copying(TDEIO::Job *, const KURL &, const KURL &) ), + this, TQ_SLOT( slotCopying(TDEIO::Job *, const KURL &, const KURL &) ) ); + connect( copy_job, TQ_SIGNAL( moving(TDEIO::Job *, const KURL &, const KURL &) ), + this, TQ_SLOT( slotMoving(TDEIO::Job *, const KURL &, const KURL &) ) ); + connect( copy_job, TQ_SIGNAL( creatingDir(TDEIO::Job *, const KURL &) ), + this, TQ_SLOT( slotCreatingDir(TDEIO::Job *, const KURL &) ) ); + connect( copy_job, TQ_SIGNAL( processedFiles (TDEIO::Job *, unsigned long) ), + this, TQ_SLOT( slotProcessedFiles (TDEIO::Job *, unsigned long) ) ); + connect( copy_job, TQ_SIGNAL( processedDirs (TDEIO::Job *, unsigned long) ), + this, TQ_SLOT( slotProcessedDirs (TDEIO::Job *, unsigned long) ) ); + connect( copy_job, TQ_SIGNAL( processedSize (TDEIO::Job *, TDEIO::filesize_t) ), + this, TQ_SLOT( slotProcessedSize (TDEIO::Job *, TDEIO::filesize_t) ) ); + connect( copy_job, TQ_SIGNAL( result( TDEIO::Job* ) ), this, TQ_SLOT( slotCopyResult( TDEIO::Job* ) ) ); +} + +void VirtualCopyJob::slotCopyResult( TDEIO::Job *job ) { + if ( job && job->error() ) { + job->showErrorDialog( krApp ); + } + + directoryFinished( m_currentDir ); + createNextDir(); +} + +void VirtualCopyJob::directoryFinished( const TQString &name ) { + m_filesToCopy.remove( name ); + + m_processedSize += m_size[ name ]; + m_processedFiles += m_filenum[ name ]; + m_processedSubdirs += m_subdirs[ name ]; + + m_tempSize = m_tempFiles = m_tempSubdirs = 0; + + m_size.remove( name ); + m_filenum.remove( name ); + m_subdirs.remove( name ); +} + +void VirtualCopyJob::slotCopying(TDEIO::Job *, const KURL &from, const KURL &to) { + if( m_showProgressInfo ) + Observer::self()->slotCopying( this, from, to ); +} + +void VirtualCopyJob::slotMoving(TDEIO::Job *, const KURL &from, const KURL &to) { + if( m_showProgressInfo ) + Observer::self()->slotMoving( this, from, to ); +} + +void VirtualCopyJob::slotCreatingDir(TDEIO::Job *, const KURL &to) { + if( m_showProgressInfo ) + Observer::self()->slotCreatingDir( this, to ); +} + +void VirtualCopyJob::slotProcessedFiles (TDEIO::Job *, unsigned long filenum) { + m_tempFiles = filenum; +} + +void VirtualCopyJob::slotProcessedDirs (TDEIO::Job *, unsigned long subdirs) { + m_tempSubdirs = subdirs; +} + +void VirtualCopyJob::slotProcessedSize (TDEIO::Job *, TDEIO::filesize_t size) { + m_tempSize = size; +} + +#include "virtualcopyjob.moc" diff --git a/src/app/VFS/virtualcopyjob.h b/src/app/VFS/virtualcopyjob.h new file mode 100644 index 0000000..c9600ad --- /dev/null +++ b/src/app/VFS/virtualcopyjob.h @@ -0,0 +1,126 @@ +/*************************************************************************** + virtualcopyjob.h - description + ------------------- + copyright : (C) 2006 + by Csaba Karai + e-mail : krusader@users.sourceforge.net + web site : http://krusader.sourceforge.net + --------------------------------------------------------------------------- + Description + *************************************************************************** + + A + + db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. + 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D + 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' + 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b + 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. + YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD + + H e a d e r F i l e + + *************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef __VIRTUAL_COPY_JOB_H__ +#define __VIRTUAL_COPY_JOB_H__ + +#include <tdeio/job.h> +#include "preservingcopyjob.h" +#include <tqvaluelist.h> +#include <tqtimer.h> +#include <tqdict.h> +#include <tqmap.h> + +class vfs; + +typedef enum { + ST_STARTING = 0, + ST_CALCULATING_TOTAL_SIZE = 1, + ST_CREATING_DIRECTORY = 2, + ST_COPYING = 3 +} State; + +class VirtualCopyJob : public TDEIO::Job +{ + TQ_OBJECT + + +public: + VirtualCopyJob( const TQStringList *names, vfs * vfs, const KURL& dest, const KURL& baseURL, + PreserveMode pmode, TDEIO::CopyJob::CopyMode mode, bool asMethod, bool showProgressInfo ); + +protected: + void statNextDir(); + void createNextDir(); + void copyCurrentDir(); + void directoryFinished( const TQString & ); + +protected slots: + void slotStart(); + void slotReport(); + + void slotKdsResult( TDEIO::Job * ); + void slotStatResult( TDEIO::Job * ); + void slotMkdirResult( TDEIO::Job * ); + void slotCopyResult( TDEIO::Job * ); + + void slotCopying(TDEIO::Job *, const KURL &, const KURL &); + void slotMoving(TDEIO::Job *, const KURL &, const KURL &); + void slotCreatingDir(TDEIO::Job *, const KURL &); + + void slotProcessedFiles (TDEIO::Job *, unsigned long); + void slotProcessedDirs (TDEIO::Job *, unsigned long); + void slotProcessedSize (TDEIO::Job *, TDEIO::filesize_t); + +signals: + void totalFiles( TDEIO::Job *job, unsigned long files ); + void totalDirs( TDEIO::Job *job, unsigned long dirs ); + void processedFiles( TDEIO::Job *job, unsigned long files ); + void processedDirs( TDEIO::Job *job, unsigned long dirs ); + +private: + TDEIO::filesize_t m_totalSize; + unsigned long m_totalFiles; + unsigned long m_totalSubdirs; + + TDEIO::filesize_t m_processedSize; + unsigned long m_processedFiles; + unsigned long m_processedSubdirs; + + TDEIO::filesize_t m_tempSize; + unsigned long m_tempFiles; + unsigned long m_tempSubdirs; + + TQValueList<KURL> m_dirsToGetSize; + + TQDict<KURL::List> m_filesToCopy; + + TQMap<TQString,int> m_size; + TQMap<TQString,int> m_filenum; + TQMap<TQString,int> m_subdirs; + + KURL m_baseURL; + KURL m_dest; + PreserveMode m_pmode; + TDEIO::CopyJob::CopyMode m_mode; + bool m_asMethod; + bool m_showProgressInfo; + + State m_state; + + TQTimer m_reportTimer; + + KURL m_current; + TQString m_currentDir; + + TQStringList m_dirStack; +}; + +#endif /* __VIRTUAL_COPY_JOB_H__ */ |