/*************************************************************************** * Copyright (C) 2003 by Joachim Eibl * * joachim.eibl at gmx.de * * * * 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 "fileaccess.h" #include #include #include #include #include "optiondialog.h" #include #include #include #include #include #include "common.h" #include #include #include #include #include #include #include #include #ifdef _WIN32 #include #include #include #include #else #include // Needed for creating symbolic links via symlink(). #include #endif ProgressDialog* g_pProgressDialog=0; FileAccess::FileAccess( const TQString& name, bool bWantToWrite ) : m_workingDir(TQString::null) { setFile( name, bWantToWrite ); } FileAccess::FileAccess( const TQString& workingDir, const TQString& name, bool bWantToWrite ) : m_workingDir(workingDir) { setFile( name, bWantToWrite ); } FileAccess::FileAccess() { m_bValidData = false; m_size = 0; m_creationTime = TQDateTime(); m_accessTime = TQDateTime(); m_modificationTime = TQDateTime(); m_bReadable = false; m_bWritable = false; m_bExecutable = false; m_bLocal = false; m_bHidden = false; m_bExists = false; m_bFile = false; m_bDir = false; m_bSymLink = false; } FileAccess::~FileAccess() { if( !m_localCopy.isEmpty() ) { removeTempFile( m_localCopy ); } } void FileAccess::setFile( const TQString& name, bool bWantToWrite ) { m_url = KURL::fromPathOrURL( name ); m_bValidData = false; m_size = 0; m_creationTime = TQDateTime(); m_accessTime = TQDateTime(); m_modificationTime = TQDateTime(); m_bReadable = false; m_bWritable = false; m_bExecutable = false; m_bHidden = false; m_bExists = false; m_bFile = false; m_bDir = false; m_bSymLink = false; m_linkTarget = ""; m_fileType = -1; m_bLocal = true; // Note: Checking if the filename-string is empty is necessary for Win95/98/ME. // The isFile() / isDir() queries would cause the program to crash. // (This is a Win95-bug which has been corrected only in WinNT/2000/XP.) if ( !name.isEmpty() ) { // FileAccess tries to detect if the given name is an URL or a local file. // This is a problem if the filename looks like an URL (i.e. contains a colon ':'). // e.g. "file:f.txt" is a valid filename. // Most of the time it is sufficient to check if the file exists locally. // 2 Problems remain: // 1. When the local file exists and the remote location is wanted nevertheless. (unlikely) // 2. When the local file doesn't exist and should be written to. bool bExistsLocal = false; if (!m_workingDir.isEmpty()) { bExistsLocal = TQDir(m_workingDir).exists(name); } else { bExistsLocal = TQDir().exists(name); } if ( m_url.isLocalFile() || !m_url.isValid() || bExistsLocal ) // assuming that invalid means relative { TQString localName = name; if ( !bExistsLocal && m_url.isLocalFile() && name.left(5).lower()=="file:" ) { localName = m_url.path(); // I want the path without preceding "file:" } TQFileInfo fi; if (!m_workingDir.isEmpty()) { fi = TQFileInfo( m_workingDir, localName ); } else { fi = TQFileInfo( localName ); } #if defined(TQ_WS_WIN) // On some windows machines in a network this takes very long. // and it's not so important anyway. m_bReadable = true; m_bWritable = true; // in certain situations this might become a problem though m_bExecutable = false; #else m_bReadable = fi.isReadable(); m_bWritable = fi.isWritable(); m_bExecutable = fi.isExecutable(); #endif m_creationTime = fi.created(); m_bHidden = fi.isHidden(); m_modificationTime = fi.lastModified(); m_accessTime = fi.lastRead(); m_size = fi.size(); m_bSymLink = fi.isSymLink(); m_bFile = fi.isFile(); m_bDir = fi.isDir(); m_bExists = fi.exists(); m_name = fi.fileName(); m_path = fi.filePath(); m_absFilePath= fi.absFilePath(); if ( m_bSymLink ) m_linkTarget = fi.readLink(); m_bLocal = true; m_bValidData = true; if ( ! m_url.isValid() ) { m_url.setPath( m_absFilePath ); } if ( !m_bExists && m_absFilePath.contains("@@") ) { // Try reading a clearcase file m_localCopy = FileAccess::tempFileName(); TQString cmd = "cleartool get -to \"" + m_localCopy + "\" \"" + m_absFilePath + "\""; ::system( cmd.local8Bit() ); TQFileInfo fi; if (!m_workingDir.isEmpty()) { fi = TQFileInfo( m_workingDir, m_localCopy ); } else { fi = TQFileInfo( m_localCopy ); } #if defined(TQ_WS_WIN) m_bReadable = true;//fi.isReadable(); m_bWritable = true;//fi.isWritable(); m_bExecutable = false;//fi.isExecutable(); #else m_bReadable = fi.isReadable(); m_bWritable = fi.isWritable(); m_bExecutable = fi.isExecutable(); #endif m_creationTime = fi.created(); m_bHidden = fi.isHidden(); m_modificationTime = fi.lastModified(); m_accessTime = fi.lastRead(); m_size = fi.size(); m_bSymLink = fi.isSymLink(); m_bFile = fi.isFile(); m_bDir = fi.isDir(); m_bExists = fi.exists(); } } else { m_absFilePath = name; m_name = m_url.fileName(); m_bLocal = false; FileAccessJobHandler jh( this ); // A friend, which writes to the parameters of this class! jh.stat(2/*all details*/, bWantToWrite); // returns bSuccess, ignored m_path = name; m_bValidData = true; // After running stat() the variables are initialised // and valid even if the file doesn't exist and the stat // query failed. } } } void FileAccess::addPath( const TQString& txt ) { if ( m_url.isValid() ) { m_url.addPath( txt ); setFile( m_url.url() ); // reinitialise } else { TQString slash = (txt.isEmpty() || txt[0]=='/') ? "" : "/"; setFile( absFilePath() + slash + txt ); } } /* Filetype: S_IFMT 0170000 bitmask for the file type bitfields S_IFSOCK 0140000 socket S_IFLNK 0120000 symbolic link S_IFREG 0100000 regular file S_IFBLK 0060000 block device S_IFDIR 0040000 directory S_IFCHR 0020000 character device S_IFIFO 0010000 fifo S_ISUID 0004000 set UID bit S_ISGID 0002000 set GID bit (see below) S_ISVTX 0001000 sticky bit (see below) Access: S_IRWXU 00700 mask for file owner permissions S_IRUSR 00400 owner has read permission S_IWUSR 00200 owner has write permission S_IXUSR 00100 owner has execute permission S_IRWXG 00070 mask for group permissions S_IRGRP 00040 group has read permission S_IWGRP 00020 group has write permission S_IXGRP 00010 group has execute permission S_IRWXO 00007 mask for permissions for others (not in group) S_IROTH 00004 others have read permission S_IWOTH 00002 others have write permisson S_IXOTH 00001 others have execute permission */ #ifdef KREPLACEMENTS_H void FileAccess::setUdsEntry( const TDEIO::UDSEntry& ){} // not needed if KDE is not available #else void FileAccess::setUdsEntry( const TDEIO::UDSEntry& e ) { TDEIO::UDSEntry::const_iterator ei; long acc = 0; long fileType = 0; for( ei=e.begin(); ei!=e.end(); ++ei ) { const TDEIO::UDSAtom& a = *ei; switch( a.m_uds ) { case TDEIO::UDS_SIZE : m_size = a.m_long; break; case TDEIO::UDS_USER : m_user = a.m_str; break; case TDEIO::UDS_GROUP : m_group = a.m_str; break; case TDEIO::UDS_NAME : m_path = a.m_str; break; // During listDir the relative path is given here. case TDEIO::UDS_MODIFICATION_TIME : m_modificationTime.setTime_t( a.m_long ); break; case TDEIO::UDS_ACCESS_TIME : m_accessTime.setTime_t( a.m_long ); break; case TDEIO::UDS_CREATION_TIME : m_creationTime.setTime_t( a.m_long ); break; case TDEIO::UDS_LINK_DEST : m_linkTarget = a.m_str; break; case TDEIO::UDS_ACCESS : { acc = a.m_long; m_bReadable = (acc & S_IRUSR)!=0; m_bWritable = (acc & S_IWUSR)!=0; m_bExecutable = (acc & S_IXUSR)!=0; break; } case TDEIO::UDS_FILE_TYPE : { fileType = a.m_long; m_bDir = ( fileType & S_IFMT ) == S_IFDIR; m_bFile = ( fileType & S_IFMT ) == S_IFREG; m_bSymLink = ( fileType & S_IFMT ) == S_IFLNK; m_bExists = fileType != 0; m_fileType = fileType; break; } case TDEIO::UDS_URL : // m_url = KURL( a.str ); break; case TDEIO::UDS_MIME_TYPE : break; case TDEIO::UDS_GUESSED_MIME_TYPE : break; case TDEIO::UDS_XML_PROPERTIES : break; default: break; } } m_bExists = acc!=0 || fileType!=0; m_bLocal = false; m_bValidData = true; m_bSymLink = !m_linkTarget.isEmpty(); if ( m_name.isEmpty() ) { int pos = m_path.findRev('/') + 1; m_name = m_path.mid( pos ); } m_bHidden = m_name[0]=='.'; } #endif bool FileAccess::isValid() const { return m_bValidData; } bool FileAccess::isFile() const { return m_bFile; } bool FileAccess::isDir() const { return m_bDir; } bool FileAccess::isSymLink() const { return m_bSymLink; } bool FileAccess::exists() const { return m_bExists; } long FileAccess::size() const { return m_size; } KURL FileAccess::url() const { return m_url; } bool FileAccess::isLocal() const { return m_bLocal; } bool FileAccess::isReadable() const { return m_bReadable; } bool FileAccess::isWritable() const { return m_bWritable; } bool FileAccess::isExecutable() const { return m_bExecutable; } bool FileAccess::isHidden() const { return m_bHidden; } TQString FileAccess::readLink() const { return m_linkTarget; } TQString FileAccess::absFilePath() const{ return m_absFilePath; } // Full abs path TQString FileAccess::fileName() const { return m_name; } // Just the name-part of the path, without parent directories TQString FileAccess::filePath() const { return m_path; } // The path-string that was used during construction TQString FileAccess::prettyAbsPath() const { return isLocal() ? m_absFilePath : m_url.prettyURL(); } TQDateTime FileAccess::created() const { return ( m_creationTime.isValid() ? m_creationTime : m_modificationTime ); } TQDateTime FileAccess::lastModified() const { return m_modificationTime; } TQDateTime FileAccess::lastRead() const { return ( m_accessTime.isValid() ? m_accessTime : m_modificationTime ); } static bool interruptableReadFile( TQFile& f, void* pDestBuffer, unsigned long maxLength ) { ProgressProxy pp; const unsigned long maxChunkSize = 100000; unsigned long i=0; while( i " + bakName; return false; } } return true; } FileAccessJobHandler::FileAccessJobHandler( FileAccess* pFileAccess ) { m_pFileAccess = pFileAccess; m_bSuccess = false; } bool FileAccessJobHandler::stat( int detail, bool bWantToWrite ) { m_bSuccess = false; m_pFileAccess->m_statusText = TQString(); TDEIO::StatJob* pStatJob = TDEIO::stat( m_pFileAccess->m_url, ! bWantToWrite, detail, false ); connect( pStatJob, TQT_SIGNAL(result(TDEIO::Job*)), this, TQT_SLOT(slotStatResult(TDEIO::Job*))); g_pProgressDialog->enterEventLoop( pStatJob, i18n("Getting file status: %1").arg(m_pFileAccess->prettyAbsPath()) ); return m_bSuccess; } void FileAccessJobHandler::slotStatResult(TDEIO::Job* pJob) { if ( pJob->error() ) { //pJob->showErrorDialog(g_pProgressDialog); m_pFileAccess->m_bExists = false; m_bSuccess = true; } else { m_bSuccess = true; m_pFileAccess->m_bValidData = true; const TDEIO::UDSEntry e = static_cast(pJob)->statResult(); m_pFileAccess->setUdsEntry( e ); } g_pProgressDialog->exitEventLoop(); } bool FileAccessJobHandler::get(void* pDestBuffer, long maxLength ) { ProgressProxy pp; // Implicitly used in slotPercent() if ( maxLength>0 && !pp.wasCancelled() ) { TDEIO::TransferJob* pJob = TDEIO::get( m_pFileAccess->m_url, false /*reload*/, false ); m_transferredBytes = 0; m_pTransferBuffer = (char*)pDestBuffer; m_maxLength = maxLength; m_bSuccess = false; m_pFileAccess->m_statusText = TQString(); connect( pJob, TQT_SIGNAL(result(TDEIO::Job*)), this, TQT_SLOT(slotSimpleJobResult(TDEIO::Job*))); connect( pJob, TQT_SIGNAL(data(TDEIO::Job*,const TQByteArray &)), this, TQT_SLOT(slotGetData(TDEIO::Job*, const TQByteArray&))); connect( pJob, TQT_SIGNAL(percent(TDEIO::Job*,unsigned long)), this, TQT_SLOT(slotPercent(TDEIO::Job*, unsigned long))); g_pProgressDialog->enterEventLoop( pJob, i18n("Reading file: %1").arg(m_pFileAccess->prettyAbsPath()) ); return m_bSuccess; } else return true; } void FileAccessJobHandler::slotGetData( TDEIO::Job* pJob, const TQByteArray& newData ) { if ( pJob->error() ) { pJob->showErrorDialog(g_pProgressDialog); } else { long length = min2( long(newData.size()), m_maxLength - m_transferredBytes ); ::memcpy( m_pTransferBuffer + m_transferredBytes, newData.data(), newData.size() ); m_transferredBytes += length; } } bool FileAccessJobHandler::put(const void* pSrcBuffer, long maxLength, bool bOverwrite, bool bResume, int permissions ) { if ( maxLength>0 ) { TDEIO::TransferJob* pJob = TDEIO::put( m_pFileAccess->m_url, permissions, bOverwrite, bResume, false ); m_transferredBytes = 0; m_pTransferBuffer = (char*)pSrcBuffer; m_maxLength = maxLength; m_bSuccess = false; m_pFileAccess->m_statusText = TQString(); connect( pJob, TQT_SIGNAL(result(TDEIO::Job*)), this, TQT_SLOT(slotPutJobResult(TDEIO::Job*))); connect( pJob, TQT_SIGNAL(dataReq(TDEIO::Job*, TQByteArray&)), this, TQT_SLOT(slotPutData(TDEIO::Job*, TQByteArray&))); connect( pJob, TQT_SIGNAL(percent(TDEIO::Job*,unsigned long)), this, TQT_SLOT(slotPercent(TDEIO::Job*, unsigned long))); g_pProgressDialog->enterEventLoop( pJob, i18n("Writing file: %1").arg(m_pFileAccess->prettyAbsPath()) ); return m_bSuccess; } else return true; } void FileAccessJobHandler::slotPutData( TDEIO::Job* pJob, TQByteArray& data ) { if ( pJob->error() ) { pJob->showErrorDialog(g_pProgressDialog); } else { long maxChunkSize = 100000; long length = min2( maxChunkSize, m_maxLength - m_transferredBytes ); bool bSuccess = data.resize( length ); if ( bSuccess ) { if ( length>0 ) { ::memcpy( data.data(), m_pTransferBuffer + m_transferredBytes, data.size() ); m_transferredBytes += length; } } else { KMessageBox::error( g_pProgressDialog, i18n("Out of memory") ); data.resize(0); m_bSuccess = false; } } } void FileAccessJobHandler::slotPutJobResult(TDEIO::Job* pJob) { if ( pJob->error() ) { pJob->showErrorDialog(g_pProgressDialog); } else { m_bSuccess = (m_transferredBytes == m_maxLength); // Special success condition } g_pProgressDialog->exitEventLoop(); // Close the dialog, return from exec() } bool FileAccessJobHandler::mkDir( const TQString& dirName ) { KURL dirURL = KURL::fromPathOrURL( dirName ); if ( dirName.isEmpty() ) return false; else if ( dirURL.isLocalFile() ) { return TQDir().mkdir( dirURL.path() ); } else { m_bSuccess = false; TDEIO::SimpleJob* pJob = TDEIO::mkdir( dirURL ); connect( pJob, TQT_SIGNAL(result(TDEIO::Job*)), this, TQT_SLOT(slotSimpleJobResult(TDEIO::Job*))); g_pProgressDialog->enterEventLoop( pJob, i18n("Making directory: %1").arg(dirName) ); return m_bSuccess; } } bool FileAccessJobHandler::rmDir( const TQString& dirName ) { KURL dirURL = KURL::fromPathOrURL( dirName ); if ( dirName.isEmpty() ) return false; else if ( dirURL.isLocalFile() ) { return TQDir().rmdir( dirURL.path() ); } else { m_bSuccess = false; TDEIO::SimpleJob* pJob = TDEIO::rmdir( dirURL ); connect( pJob, TQT_SIGNAL(result(TDEIO::Job*)), this, TQT_SLOT(slotSimpleJobResult(TDEIO::Job*))); g_pProgressDialog->enterEventLoop(pJob, i18n("Removing directory: %1").arg(dirName)); return m_bSuccess; } } bool FileAccessJobHandler::removeFile( const TQString& fileName ) { if ( fileName.isEmpty() ) return false; else { m_bSuccess = false; TDEIO::SimpleJob* pJob = TDEIO::file_delete( KURL::fromPathOrURL(fileName), false ); connect( pJob, TQT_SIGNAL(result(TDEIO::Job*)), this, TQT_SLOT(slotSimpleJobResult(TDEIO::Job*))); g_pProgressDialog->enterEventLoop( pJob, i18n("Removing file: %1").arg(fileName) ); return m_bSuccess; } } bool FileAccessJobHandler::symLink( const TQString& linkTarget, const TQString& linkLocation ) { if ( linkTarget.isEmpty() || linkLocation.isEmpty() ) return false; else { m_bSuccess = false; TDEIO::CopyJob* pJob = TDEIO::link( KURL::fromPathOrURL(linkTarget), KURL::fromPathOrURL(linkLocation), false ); connect( pJob, TQT_SIGNAL(result(TDEIO::Job*)), this, TQT_SLOT(slotSimpleJobResult(TDEIO::Job*))); g_pProgressDialog->enterEventLoop( pJob, i18n("Creating symbolic link: %1 -> %2").arg(linkLocation).arg(linkTarget) ); return m_bSuccess; } } bool FileAccessJobHandler::rename( const TQString& dest ) { if ( dest.isEmpty() ) return false; KURL kurl = KURL::fromPathOrURL( dest ); if ( !kurl.isValid() ) kurl = KURL::fromPathOrURL( TQDir().absFilePath(dest) ); // assuming that invalid means relative if ( m_pFileAccess->isLocal() && kurl.isLocalFile() ) { return TQDir().rename( m_pFileAccess->absFilePath(), kurl.path() ); } else { bool bOverwrite = false; bool bResume = false; bool bShowProgress = false; int permissions=-1; m_bSuccess = false; TDEIO::FileCopyJob* pJob = TDEIO::file_move( m_pFileAccess->m_url, kurl, permissions, bOverwrite, bResume, bShowProgress ); connect( pJob, TQT_SIGNAL(result(TDEIO::Job*)), this, TQT_SLOT(slotSimpleJobResult(TDEIO::Job*))); connect( pJob, TQT_SIGNAL(percent(TDEIO::Job*,unsigned long)), this, TQT_SLOT(slotPercent(TDEIO::Job*, unsigned long))); g_pProgressDialog->enterEventLoop( pJob, i18n("Renaming file: %1 -> %2").arg(m_pFileAccess->prettyAbsPath()).arg(dest) ); return m_bSuccess; } } void FileAccessJobHandler::slotSimpleJobResult(TDEIO::Job* pJob) { if ( pJob->error() ) { pJob->showErrorDialog(g_pProgressDialog); } else { m_bSuccess = true; } g_pProgressDialog->exitEventLoop(); // Close the dialog, return from exec() } // Copy local or remote files. bool FileAccessJobHandler::copyFile( const TQString& dest ) { ProgressProxy pp; KURL destUrl = KURL::fromPathOrURL( dest ); m_pFileAccess->m_statusText = TQString(); if ( ! m_pFileAccess->isLocal() || ! destUrl.isLocalFile() ) // if either url is nonlocal { bool bOverwrite = false; bool bResume = false; bool bShowProgress = false; int permissions = (m_pFileAccess->isExecutable()?0111:0)+(m_pFileAccess->isWritable()?0222:0)+(m_pFileAccess->isReadable()?0444:0); m_bSuccess = false; TDEIO::FileCopyJob* pJob = TDEIO::file_copy ( m_pFileAccess->m_url, destUrl, permissions, bOverwrite, bResume, bShowProgress ); connect( pJob, TQT_SIGNAL(result(TDEIO::Job*)), this, TQT_SLOT(slotSimpleJobResult(TDEIO::Job*))); connect( pJob, TQT_SIGNAL(percent(TDEIO::Job*,unsigned long)), this, TQT_SLOT(slotPercent(TDEIO::Job*, unsigned long))); g_pProgressDialog->enterEventLoop( pJob, i18n("Copying file: %1 -> %2").arg(m_pFileAccess->prettyAbsPath()).arg(dest) ); return m_bSuccess; // Note that the TDEIO-slave preserves the original date, if this is supported. } // Both files are local: TQString srcName = m_pFileAccess->absFilePath(); TQString destName = dest; TQFile srcFile( srcName ); TQFile destFile( destName ); bool bReadSuccess = srcFile.open( IO_ReadOnly ); if ( bReadSuccess == false ) { m_pFileAccess->m_statusText = i18n("Error during file copy operation: Opening file for reading failed. Filename: %1").arg(srcName); return false; } bool bWriteSuccess = destFile.open( IO_WriteOnly ); if ( bWriteSuccess == false ) { m_pFileAccess->m_statusText = i18n("Error during file copy operation: Opening file for writing failed. Filename: %1").arg(destName); return false; } std::vector buffer(100000); TQ_LONG bufSize = buffer.size(); TQ_LONG srcSize = srcFile.size(); while ( srcSize > 0 && !pp.wasCancelled() ) { TQ_LONG readSize = srcFile.readBlock( &buffer[0], min2( srcSize, bufSize ) ); if ( readSize==-1 || readSize==0 ) { m_pFileAccess->m_statusText = i18n("Error during file copy operation: Reading failed. Filename: %1").arg(srcName); return false; } srcSize -= readSize; while ( readSize > 0 ) { TQ_LONG writeSize = destFile.writeBlock( &buffer[0], readSize ); if ( writeSize==-1 || writeSize==0 ) { m_pFileAccess->m_statusText = i18n("Error during file copy operation: Writing failed. Filename: %1").arg(destName); return false; } readSize -= writeSize; } destFile.flush(); pp.setCurrent( (double)(srcFile.size()-srcSize)/srcFile.size(), false ); } srcFile.close(); destFile.close(); // Update the times of the destFile #ifdef _WIN32 struct _stat srcFileStatus; int statResult = ::_stat( srcName.ascii(), &srcFileStatus ); if (statResult==0) { _utimbuf destTimes; destTimes.actime = srcFileStatus.st_atime;/* time of last access */ destTimes.modtime = srcFileStatus.st_mtime;/* time of last modification */ _utime ( destName.ascii(), &destTimes ); _chmod ( destName.ascii(), srcFileStatus.st_mode ); } #else struct stat srcFileStatus; int statResult = ::stat( srcName.ascii(), &srcFileStatus ); if (statResult==0) { utimbuf destTimes; destTimes.actime = srcFileStatus.st_atime;/* time of last access */ destTimes.modtime = srcFileStatus.st_mtime;/* time of last modification */ utime ( destName.ascii(), &destTimes ); chmod ( destName.ascii(), srcFileStatus.st_mode ); } #endif return true; } bool wildcardMultiMatch( const TQString& wildcard, const TQString& testString, bool bCaseSensitive ) { TQStringList sl = TQStringList::split( ";", wildcard ); for ( TQStringList::Iterator it = sl.begin(); it != sl.end(); ++it ) { TQRegExp pattern( *it, bCaseSensitive, true /*wildcard mode*/); if ( pattern.exactMatch( testString ) ) return true; } return false; } // class CvsIgnoreList from Cervisia cvsdir.cpp // Copyright (C) 1999-2002 Bernd Gehrmann // with elements from class StringMatcher // Copyright (c) 2003 André Woebeking // Modifications for KDiff3 by Joachim Eibl class CvsIgnoreList { public: CvsIgnoreList(){} void init(FileAccess& dir, bool bUseLocalCvsIgnore ); bool matches(const TQString& fileName, bool bCaseSensitive ) const; private: void addEntriesFromString(const TQString& str); void addEntriesFromFile(const TQString& name); void addEntry(const TQString& entry); TQStringList m_exactPatterns; TQStringList m_startPatterns; TQStringList m_endPatterns; TQStringList m_generalPatterns; }; void CvsIgnoreList::init( FileAccess& dir, bool bUseLocalCvsIgnore ) { static const char *ignorestr = ". .. core RCSLOG tags TAGS RCS SCCS .make.state " ".nse_depinfo #* .#* cvslog.* ,* CVS CVS.adm .del-* *.a *.olb *.o *.obj " "*.so *.Z *~ *.old *.elc *.ln *.bak *.BAK *.orig *.rej *.exe _$* *$"; addEntriesFromString(TQString::fromLatin1(ignorestr)); addEntriesFromFile(TQDir::homeDirPath() + "/.cvsignore"); addEntriesFromString(TQString::fromLocal8Bit(::getenv("CVSIGNORE"))); if (bUseLocalCvsIgnore) { FileAccess file(dir); file.addPath( ".cvsignore" ); int size = file.exists() ? file.sizeForReading() : 0; if ( size>0 ) { char* buf=new char[size]; if (buf!=0) { file.readFile( buf, size ); int pos1 = 0; for ( int pos = 0; pos<=size; ++pos ) { if( pos==size || buf[pos]==' ' || buf[pos]=='\t' || buf[pos]=='\n' || buf[pos]=='\r' ) { if (pos>pos1) { addEntry( TQString::fromLatin1( &buf[pos1], pos-pos1 ) ); } ++pos1; } } delete buf; } } } } void CvsIgnoreList::addEntriesFromString(const TQString& str) { int posLast(0); int pos; while ((pos = str.find(' ', posLast)) >= 0) { if (pos > posLast) addEntry(str.mid(posLast, pos - posLast)); posLast = pos + 1; } if (posLast < static_cast(str.length())) addEntry(str.mid(posLast)); } void CvsIgnoreList::addEntriesFromFile(const TQString &name) { TQFile file(name); if( file.open(IO_ReadOnly) ) { TQTextStream stream(&file); while( !stream.eof() ) { addEntriesFromString(stream.readLine()); } } } void CvsIgnoreList::addEntry(const TQString& pattern) { if (pattern != TQString("!")) { if (pattern.isEmpty()) return; // The general match is general but slow. // Special tests for '*' and '?' at the beginning or end of a pattern // allow fast checks. // Count number of '*' and '?' unsigned int nofMetaCharacters = 0; const TQChar* pos; pos = pattern.unicode(); const TQChar* posEnd; posEnd=pos + pattern.length(); while (pos < posEnd) { if( *pos==TQChar('*') || *pos==TQChar('?') ) ++nofMetaCharacters; ++pos; } if ( nofMetaCharacters==0 ) { m_exactPatterns.append(pattern); } else if ( nofMetaCharacters==1 ) { if ( pattern.constref(0) == TQChar('*') ) { m_endPatterns.append( pattern.right( pattern.length() - 1) ); } else if (pattern.constref(pattern.length() - 1) == TQChar('*')) { m_startPatterns.append( pattern.left( pattern.length() - 1) ); } else { m_generalPatterns.append(pattern.local8Bit()); } } else { m_generalPatterns.append(pattern.local8Bit()); } } else { m_exactPatterns.clear(); m_startPatterns.clear(); m_endPatterns.clear(); m_generalPatterns.clear(); } } bool CvsIgnoreList::matches(const TQString& text, bool bCaseSensitive ) const { if (m_exactPatterns.find(text) != m_exactPatterns.end()) { return true; } TQStringList::ConstIterator it; TQStringList::ConstIterator itEnd; for ( it=m_startPatterns.begin(), itEnd=m_startPatterns.end(); it != itEnd; ++it) { if (text.startsWith(*it)) { return true; } } for ( it = m_endPatterns.begin(), itEnd=m_endPatterns.end(); it != itEnd; ++it) { if (text.mid( text.length() - (*it).length() )==*it) //(text.endsWith(*it)) { return true; } } /* for (TQValueList::const_iterator it(m_generalPatterns.begin()), itEnd(m_generalPatterns.end()); it != itEnd; ++it) { if (::fnmatch(*it, text.local8Bit(), FNM_PATHNAME) == 0) { return true; } } */ for ( it = m_generalPatterns.begin(); it != m_generalPatterns.end(); ++it ) { TQRegExp pattern( *it, bCaseSensitive, true /*wildcard mode*/); if ( pattern.exactMatch( text ) ) return true; } return false; } static TQString nicePath( const TQFileInfo& fi ) { TQString fp = fi.filePath(); if ( fp.length()>2 && fp[0] == '.' && fp[1] == '/' ) { return fp.mid(2); } return fp; } static bool cvsIgnoreExists( t_DirectoryList* pDirList ) { t_DirectoryList::iterator i; for( i = pDirList->begin(); i!=pDirList->end(); ++i ) { if ( i->fileName()==".cvsignore" ) return true; } return false; } bool FileAccessJobHandler::listDir( t_DirectoryList* pDirList, bool bRecursive, bool bFindHidden, const TQString& filePattern, const TQString& fileAntiPattern, const TQString& dirAntiPattern, bool bFollowDirLinks, bool bUseCvsIgnore ) { ProgressProxy pp; m_pDirList = pDirList; m_pDirList->clear(); m_bFindHidden = bFindHidden; m_bRecursive = bRecursive; m_bFollowDirLinks = bFollowDirLinks; // Only relevant if bRecursive==true. m_fileAntiPattern = fileAntiPattern; m_filePattern = filePattern; m_dirAntiPattern = dirAntiPattern; if ( pp.wasCancelled() ) return true; // Cancelled is not an error. pp.setInformation( i18n("Reading directory: ") + m_pFileAccess->absFilePath(), 0, false ); if( m_pFileAccess->isLocal() ) { TQString currentPath = TQDir::currentDirPath(); m_bSuccess = TQDir::setCurrent( m_pFileAccess->absFilePath() ); if ( m_bSuccess ) { #ifndef _WIN32 m_bSuccess = true; TQDir dir( "." ); dir.setSorting( TQDir::Name | TQDir::DirsFirst ); dir.setFilter( TQDir::Files | TQDir::Dirs | TQDir::Hidden ); dir.setMatchAllDirs( true ); const TQFileInfoList *fiList = dir.entryInfoList(); if ( fiList == 0 ) { // No Permission to read directory or other error. m_bSuccess = false; } else { TQFileInfoListIterator it( *fiList ); // create list iterator for ( ; it.current() != 0; ++it ) // for each file... { TQFileInfo* fi = it.current(); if ( fi->fileName() == "." || fi->fileName()==".." ) continue; pDirList->push_back( FileAccess( nicePath(*fi) ) ); } } #else TQString pattern ="*.*"; WIN32_FIND_DATA findData; WIN32_FIND_DATAA& findDataA=*(WIN32_FIND_DATAA*)&findData; // Needed for Win95 HANDLE searchHandle = TQT_WA_INLINE( FindFirstFile( (TCHAR*)pattern.ucs2(), &findData ), FindFirstFileA( pattern.local8Bit(), &findDataA ) ); if ( searchHandle != INVALID_HANDLE_VALUE ) { TQString absPath = m_pFileAccess->absFilePath(); TQString relPath = m_pFileAccess->filePath(); bool bFirst=true; while( ! pp.wasCancelled() ) { if (!bFirst) { if ( ! TQT_WA_INLINE( FindNextFile(searchHandle,&findData), FindNextFileA(searchHandle,&findDataA)) ) break; } bFirst = false; FileAccess fa; fa.m_size = findData.nFileSizeLow ;//+ findData.nFileSizeHigh; FILETIME ft; SYSTEMTIME t; FileTimeToLocalFileTime( &findData.ftLastWriteTime, &ft ); FileTimeToSystemTime(&ft,&t); fa.m_modificationTime = TQDateTime( TQDate(t.wYear, t.wMonth, t.wDay), TQTime(t.wHour, t.wMinute, t.wSecond) ); FileTimeToLocalFileTime( &findData.ftLastAccessTime, &ft ); FileTimeToSystemTime(&ft,&t); fa.m_accessTime = TQDateTime( TQDate(t.wYear, t.wMonth, t.wDay), TQTime(t.wHour, t.wMinute, t.wSecond) ); FileTimeToLocalFileTime( &findData.ftCreationTime, &ft ); FileTimeToSystemTime(&ft,&t); fa.m_creationTime = TQDateTime( TQDate(t.wYear, t.wMonth, t.wDay), TQTime(t.wHour, t.wMinute, t.wSecond) ); int a = findData.dwFileAttributes; fa.m_bWritable = ( a & FILE_ATTRIBUTE_READONLY) == 0; fa.m_bDir = ( a & FILE_ATTRIBUTE_DIRECTORY ) != 0; fa.m_bFile = !fa.m_bDir; fa.m_bHidden = ( a & FILE_ATTRIBUTE_HIDDEN) != 0; fa.m_bExecutable = false; // Useless on windows fa.m_bExists = true; fa.m_bReadable = true; fa.m_bLocal = true; fa.m_bValidData = true; fa.m_bSymLink = false; fa.m_fileType = 0; fa.m_name = TQT_WA_INLINE( TQString::fromUcs2((const ushort*)findData.cFileName), TQString::fromLocal8Bit(findDataA.cFileName) ); fa.m_path = fa.m_name; fa.m_absFilePath = absPath + "/" + fa.m_name; fa.m_url.setPath( fa.m_absFilePath ); if ( fa.m_name!="." && fa.m_name!=".." ) pDirList->push_back( fa ); } FindClose( searchHandle ); } else { TQDir::setCurrent( currentPath ); // restore current path return false; } #endif } TQDir::setCurrent( currentPath ); // restore current path } else { bool bShowProgress = false; TDEIO::ListJob* pListJob=0; pListJob = TDEIO::listDir( m_pFileAccess->m_url, bShowProgress, true /*bFindHidden*/ ); m_bSuccess = false; if ( pListJob!=0 ) { connect( pListJob, TQT_SIGNAL( entries( TDEIO::Job *, const TDEIO::UDSEntryList& ) ), this, TQT_SLOT( slotListDirProcessNewEntries( TDEIO::Job *, const TDEIO::UDSEntryList& )) ); connect( pListJob, TQT_SIGNAL( result( TDEIO::Job* )), this, TQT_SLOT( slotSimpleJobResult(TDEIO::Job*) ) ); connect( pListJob, TQT_SIGNAL( infoMessage(TDEIO::Job*, const TQString&)), this, TQT_SLOT( slotListDirInfoMessage(TDEIO::Job*, const TQString&) )); // This line makes the transfer via fish unreliable.:-( //connect( pListJob, TQT_SIGNAL(percent(TDEIO::Job*,unsigned long)), this, TQT_SLOT(slotPercent(TDEIO::Job*, unsigned long))); g_pProgressDialog->enterEventLoop( pListJob, i18n("Listing directory: %1").arg(m_pFileAccess->prettyAbsPath()) ); } } CvsIgnoreList cvsIgnoreList; if ( bUseCvsIgnore ) { cvsIgnoreList.init( *m_pFileAccess, cvsIgnoreExists(pDirList) ); } #ifdef _WIN32 bool bCaseSensitive = false; #else bool bCaseSensitive = true; #endif // Now remove all entries that don't match: t_DirectoryList::iterator i; for( i = pDirList->begin(); i!=pDirList->end(); ) { t_DirectoryList::iterator i2=i; ++i2; TQString fn = i->fileName(); if ( (!bFindHidden && i->isHidden() ) || (i->isFile() && ( !wildcardMultiMatch( filePattern, i->fileName(), bCaseSensitive ) || wildcardMultiMatch( fileAntiPattern, i->fileName(), bCaseSensitive ) ) ) || (i->isDir() && wildcardMultiMatch( dirAntiPattern, i->fileName(), bCaseSensitive ) ) || cvsIgnoreList.matches( i->fileName(), bCaseSensitive ) ) { // Remove it pDirList->erase( i ); i = i2; } else { ++i; } } if ( bRecursive ) { t_DirectoryList subDirsList; t_DirectoryList::iterator i; for( i = m_pDirList->begin(); i!=m_pDirList->end(); ++i ) { if ( i->isDir() && (!i->isSymLink() || m_bFollowDirLinks)) { t_DirectoryList dirList; i->listDir( &dirList, bRecursive, bFindHidden, filePattern, fileAntiPattern, dirAntiPattern, bFollowDirLinks, bUseCvsIgnore ); t_DirectoryList::iterator j; for( j = dirList.begin(); j!=dirList.end(); ++j ) { j->m_path = i->fileName() + "/" + j->m_path; } // append data onto the main list subDirsList.splice( subDirsList.end(), dirList ); } } m_pDirList->splice( m_pDirList->end(), subDirsList ); } return m_bSuccess; } void FileAccessJobHandler::slotListDirProcessNewEntries( TDEIO::Job *, const TDEIO::UDSEntryList& l ) { KURL parentUrl( m_pFileAccess->m_absFilePath ); TDEIO::UDSEntryList::ConstIterator i; for ( i=l.begin(); i!=l.end(); ++i ) { const TDEIO::UDSEntry& e = *i; FileAccess fa; fa.setUdsEntry( e ); if ( fa.filePath() != "." && fa.filePath() != ".." ) { fa.m_url = parentUrl; fa.m_url.addPath( fa.filePath() ); fa.m_absFilePath = fa.m_url.url(); m_pDirList->push_back( fa ); } } } void FileAccessJobHandler::slotListDirInfoMessage( TDEIO::Job*, const TQString& msg ) { g_pProgressDialog->setInformation( msg, 0.0 ); } void FileAccessJobHandler::slotPercent( TDEIO::Job*, unsigned long percent ) { g_pProgressDialog->setCurrent( percent/100.0 ); } ProgressDialog::ProgressDialog( TQWidget* pParent ) : TQDialog( pParent, 0, true ) { m_bStayHidden = false; TQVBoxLayout* layout = new TQVBoxLayout(this); m_pInformation = new TQLabel( " ", this ); layout->addWidget( m_pInformation ); m_pProgressBar = new KProgress(1000, this); layout->addWidget( m_pProgressBar ); m_pSubInformation = new TQLabel( " ", this); layout->addWidget( m_pSubInformation ); m_pSubProgressBar = new KProgress(1000, this); layout->addWidget( m_pSubProgressBar ); m_pSlowJobInfo = new TQLabel( " ", this); layout->addWidget( m_pSlowJobInfo ); TQHBoxLayout* hlayout = new TQHBoxLayout( layout ); hlayout->addStretch(1); m_pAbortButton = new TQPushButton( i18n("&Cancel"), this); hlayout->addWidget( m_pAbortButton ); connect( m_pAbortButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotAbort()) ); m_progressDelayTimer = 0; resize( 400, 100 ); m_t1.start(); m_t2.start(); m_bWasCancelled = false; m_pJob = 0; } void ProgressDialog::setStayHidden( bool bStayHidden ) { m_bStayHidden = bStayHidden; } void ProgressDialog::push() { ProgressLevelData pld; if ( !m_progressStack.empty() ) { pld.m_dRangeMax = m_progressStack.back().m_dSubRangeMax; pld.m_dRangeMin = m_progressStack.back().m_dSubRangeMin; } else { m_bWasCancelled = false; m_t1.restart(); m_t2.restart(); if ( !m_bStayHidden ) show(); } m_progressStack.push_back( pld ); } void ProgressDialog::pop( bool bRedrawUpdate ) { if ( !m_progressStack.empty() ) { m_progressStack.pop_back(); if ( m_progressStack.empty() ) hide(); else recalc(bRedrawUpdate); } } void ProgressDialog::setInformation(const TQString& info, double dCurrent, bool bRedrawUpdate ) { if ( m_progressStack.empty() ) return; ProgressLevelData& pld = m_progressStack.back(); pld.m_dCurrent = dCurrent; int level = m_progressStack.size(); if ( level==1 ) { m_pInformation->setText( info ); m_pSubInformation->setText(""); } else if ( level==2 ) { m_pSubInformation->setText( info ); } recalc(bRedrawUpdate); } void ProgressDialog::setInformation(const TQString& info, bool bRedrawUpdate ) { if ( m_progressStack.empty() ) return; //ProgressLevelData& pld = m_progressStack.back(); int level = m_progressStack.size(); if ( level==1 ) { m_pInformation->setText( info ); m_pSubInformation->setText( "" ); } else if ( level==2 ) { m_pSubInformation->setText( info ); } recalc(bRedrawUpdate); } void ProgressDialog::setMaxNofSteps( int maxNofSteps ) { if ( m_progressStack.empty() ) return; ProgressLevelData& pld = m_progressStack.back(); pld.m_maxNofSteps = maxNofSteps; pld.m_dCurrent = 0; } void ProgressDialog::step( bool bRedrawUpdate ) { if ( m_progressStack.empty() ) return; ProgressLevelData& pld = m_progressStack.back(); pld.m_dCurrent += 1.0/pld.m_maxNofSteps; recalc(bRedrawUpdate); } void ProgressDialog::setCurrent( double dSubCurrent, bool bRedrawUpdate ) { if ( m_progressStack.empty() ) return; ProgressLevelData& pld = m_progressStack.back(); pld.m_dCurrent = dSubCurrent; recalc( bRedrawUpdate ); } // The progressbar goes from 0 to 1 usually. // By supplying a subrange transformation the subCurrent-values // 0 to 1 will be transformed to dMin to dMax instead. // Requirement: 0 < dMin < dMax < 1 void ProgressDialog::setRangeTransformation( double dMin, double dMax ) { if ( m_progressStack.empty() ) return; ProgressLevelData& pld = m_progressStack.back(); pld.m_dRangeMin = dMin; pld.m_dRangeMax = dMax; pld.m_dCurrent = 0; } void ProgressDialog::setSubRangeTransformation( double dMin, double dMax ) { if ( m_progressStack.empty() ) return; ProgressLevelData& pld = m_progressStack.back(); pld.m_dSubRangeMin = dMin; pld.m_dSubRangeMax = dMax; } void tqt_enter_modal(TQWidget*); void tqt_leave_modal(TQWidget*); void ProgressDialog::enterEventLoop( TDEIO::Job* pJob, const TQString& jobInfo ) { m_pJob = pJob; m_pSlowJobInfo->setText(""); m_currentJobInfo = jobInfo; killTimer( m_progressDelayTimer ); m_progressDelayTimer = startTimer( 3000 ); /* 3 s delay */ // instead of using exec() the eventloop is entered and exited often without hiding/showing the window. tqt_enter_modal(this); tqApp->eventLoop()->enterLoop(); tqt_leave_modal(this); } void ProgressDialog::exitEventLoop() { killTimer( m_progressDelayTimer ); m_progressDelayTimer = 0; m_pJob = 0; tqApp->eventLoop()->exitLoop(); } void ProgressDialog::recalc( bool bUpdate ) { killTimer( m_progressDelayTimer ); m_progressDelayTimer = startTimer( 3000 ); /* 3 s delay */ int level = m_progressStack.size(); if( ( bUpdate && level==1) || m_t1.elapsed()>200 ) { if (m_progressStack.empty() ) { m_pProgressBar->setProgress( 0 ); m_pSubProgressBar->setProgress( 0 ); } else { std::list::iterator i = m_progressStack.begin(); m_pProgressBar->setProgress( int( 1000.0 * ( i->m_dCurrent * (i->m_dRangeMax - i->m_dRangeMin) + i->m_dRangeMin ) ) ); ++i; if ( i!=m_progressStack.end() ) m_pSubProgressBar->setProgress( int( 1000.0 * ( i->m_dCurrent * (i->m_dRangeMax - i->m_dRangeMin) + i->m_dRangeMin ) ) ); else m_pSubProgressBar->setProgress( int( 1000.0 * m_progressStack.front().m_dSubRangeMin ) ); } if ( !m_bStayHidden && !isVisible() ) show(); tqApp->processEvents(); m_t1.restart(); } } #include void ProgressDialog::show() { killTimer( m_progressDelayTimer ); m_progressDelayTimer = 0; if ( !isVisible() && (parentWidget()==0 || parentWidget()->isVisible()) ) { TQDialog::show(); } } void ProgressDialog::hide() { killTimer( m_progressDelayTimer ); m_progressDelayTimer = 0; // Calling TQDialog::hide() directly doesn't always work. (?) TQTimer::singleShot( 100, this, TQT_SLOT(delayedHide()) ); } void ProgressDialog::delayedHide() { if (m_pJob!=0) { m_pJob->kill(false); m_pJob = 0; } TQDialog::hide(); m_pInformation->setText( "" ); //m_progressStack.clear(); m_pProgressBar->setProgress( 0 ); m_pSubProgressBar->setProgress( 0 ); m_pSubInformation->setText(""); m_pSlowJobInfo->setText(""); } void ProgressDialog::reject() { m_bWasCancelled = true; TQDialog::reject(); } void ProgressDialog::slotAbort() { reject(); } bool ProgressDialog::wasCancelled() { if( m_t2.elapsed()>100 ) { tqApp->processEvents(); m_t2.restart(); } return m_bWasCancelled; } void ProgressDialog::timerEvent(TQTimerEvent*) { if( !isVisible() ) { show(); } m_pSlowJobInfo->setText( m_currentJobInfo ); } ProgressProxy::ProgressProxy() { g_pProgressDialog->push(); } ProgressProxy::~ProgressProxy() { g_pProgressDialog->pop(false); } void ProgressProxy::setInformation( const TQString& info, bool bRedrawUpdate ) { g_pProgressDialog->setInformation( info, bRedrawUpdate ); } void ProgressProxy::setInformation( const TQString& info, double dCurrent, bool bRedrawUpdate ) { g_pProgressDialog->setInformation( info, dCurrent, bRedrawUpdate ); } void ProgressProxy::setCurrent( double dCurrent, bool bRedrawUpdate ) { g_pProgressDialog->setCurrent( dCurrent, bRedrawUpdate ); } void ProgressProxy::step( bool bRedrawUpdate ) { g_pProgressDialog->step( bRedrawUpdate ); } void ProgressProxy::setMaxNofSteps( int maxNofSteps ) { g_pProgressDialog->setMaxNofSteps( maxNofSteps ); } bool ProgressProxy::wasCancelled() { return g_pProgressDialog->wasCancelled(); } void ProgressProxy::setRangeTransformation( double dMin, double dMax ) { g_pProgressDialog->setRangeTransformation( dMin, dMax ); } void ProgressProxy::setSubRangeTransformation( double dMin, double dMax ) { g_pProgressDialog->setSubRangeTransformation( dMin, dMax ); } #include "fileaccess.moc"