diff --git a/configure.ac b/configure.ac index 5aad9f40..c3a46ae7 100644 --- a/configure.ac +++ b/configure.ac @@ -180,20 +180,9 @@ case "${host}" in AC_ARG_ENABLE(w32-glib, AC_HELP_STRING([--enable-w32-glib], [build GPGME Glib for W32]), build_w32_glib=$enableval) - - # Check disabled, because the qt-dev packages in gpg4win do - # not provide any support for cross compilation. - # PKG_CHECK_MODULES(QT4_CORE, QtCore) - - # Use it like this: - # ./configure --enable-w32-qt QT4_CORE_CFLAGS="..." QT4_CORE_LIBS="..." - AC_SUBST(QT4_CORE_CFLAGS) - AC_SUBST(QT4_CORE_LIBS) - AC_ARG_ENABLE(w32-qt, - AC_HELP_STRING([--enable-w32-qt], [build GPGME Qt for W32]), - build_w32_qt=$enableval) - ;; + ;; *) + AC_CHECK_LIB(pthread,pthread_create,have_pthread=yes) if test "$have_pthread" = yes; then AC_DEFINE(HAVE_PTHREAD, ,[Define if we have pthread.]) @@ -239,7 +228,6 @@ fi AM_CONDITIONAL(HAVE_ANDROID_SYSTEM, test "$have_android_system" = yes) AM_CONDITIONAL(BUILD_W32_GLIB, test "$build_w32_glib" = yes) -AM_CONDITIONAL(BUILD_W32_QT, test "$build_w32_qt" = yes) AM_CONDITIONAL(HAVE_PTHREAD, test "$have_pthread" = "yes") diff --git a/src/Makefile.am b/src/Makefile.am index 698c6322..951fc00b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -41,12 +41,6 @@ else ltlib_gpgme_glib = endif -if BUILD_W32_QT -ltlib_gpgme_qt = libgpgme-qt.la -else -ltlib_gpgme_qt = -endif - lib_LTLIBRARIES = libgpgme.la $(ltlib_gpgme_glib) $(ltlib_gpgme_qt) \ $(ltlib_gpgme_pthread) @@ -110,23 +104,9 @@ if BUILD_W32_GLIB libgpgme_glib_la_SOURCES = $(main_sources) ath.h ath.c w32-glib-io.c endif -if BUILD_W32_QT -libgpgme_qt_la_SOURCES = $(main_sources) ath.h ath.c w32-qt-io.cpp \ - kdpipeiodevice.h kdpipeiodevice.cpp kdpipeiodevice.moc -# FIXME: Add extra depedency: moc_kdpipeiodevice.cpp - -# These are built sources (normally). -# moc_kdpipeiodevice.cpp: kdpipeiodevice.h -# $(MOC4) -o $@ $< -# -# kdpipeiodevice.moc: kdpipeiodevice.cpp -# $(MOC4) -o $@ $< -endif - -# We use a global CFLAGS and CPPFLAGS setting for all library +# We use a global CFLAGS setting for all library # versions, because then every object file is only compiled once. -AM_CPPFLAGS = @GPG_ERROR_CFLAGS@ @QT4_CORE_CFLAGS@ -AM_CFLAGS = @LIBASSUAN_CFLAGS@ @GLIB_CFLAGS@ @QT4_CORE_CFLAGS@ +AM_CFLAGS = @LIBASSUAN_CFLAGS@ @GLIB_CFLAGS@ gpgme_tool_SOURCES = gpgme-tool.c argparse.c argparse.h gpgme_tool_LDADD = libgpgme.la @LIBASSUAN_LIBS@ @@ -202,15 +182,6 @@ libgpgme_glib_la_LIBADD = $(gpgme_res) @LIBASSUAN_LIBS@ @LTLIBOBJS@ \ @GPG_ERROR_LIBS@ @GLIB_LIBS@ endif -if BUILD_W32_QT -libgpgme_qt_la_LDFLAGS = $(no_undefined) \ - $(export_symbols) $(libgpgme_version_script_cmd) -version-info \ - @LIBGPGME_LT_CURRENT@:@LIBGPGME_LT_REVISION@:@LIBGPGME_LT_AGE@ -libgpgme_qt_la_DEPENDENCIES = @LTLIBOBJS@ $(srcdir)/libgpgme.vers $(gpgme_deps) -libgpgme_qt_la_LIBADD = $(gpgme_res) @LIBASSUAN_LIBS@ @LTLIBOBJS@ \ - @GPG_ERROR_LIBS@ @QT4_CORE_LIBS@ -endif - install-data-local: install-def-file uninstall-local: uninstall-def-file diff --git a/src/kdpipeiodevice.cpp b/src/kdpipeiodevice.cpp deleted file mode 100644 index 5661790a..00000000 --- a/src/kdpipeiodevice.cpp +++ /dev/null @@ -1,951 +0,0 @@ -/* - Copyright (C) 2007 Klarälvdalens Datakonsult AB - - KDPipeIODevice is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - KDPipeIODevice is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with KDPipeIODevice; see the file COPYING.LIB. If not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include "kdpipeiodevice.h" - -#include - -#include -#include -#include - -#ifdef Q_OS_WIN32 -# ifndef NOMINMAX -# define NOMINMAX -# endif -# include -# include -#else -# include -# include -#endif - -using namespace _gpgme_; - -#ifndef KDAB_CHECK_THIS -# define KDAB_CHECK_CTOR (void)1 -# define KDAB_CHECK_DTOR KDAB_CHECK_CTOR -# define KDAB_CHECK_THIS KDAB_CHECK_CTOR -#endif - -#define LOCKED( d ) const QMutexLocker locker( &d->mutex ) -#define synchronized( d ) if ( int i = 0 ) {} else for ( const QMutexLocker locker( &d->mutex ) ; !i ; ++i ) - -const unsigned int BUFFER_SIZE = 4096; -const bool ALLOW_QIODEVICE_BUFFERING = true; - -// comment to get trace output: -//#define qDebug if(1){}else qDebug - -namespace { -class Reader : public QThread { - Q_OBJECT -public: - Reader( int fd, Qt::HANDLE handle ); - ~Reader(); - - qint64 readData( char * data, qint64 maxSize ); - - unsigned int bytesInBuffer() const { - return ( wptr + sizeof buffer - rptr ) % sizeof buffer ; - } - - bool bufferFull() const { - return bytesInBuffer() == sizeof buffer - 1; - } - - bool bufferEmpty() const { - return bytesInBuffer() == 0; - } - - bool bufferContains( char ch ) { - const unsigned int bib = bytesInBuffer(); - for ( unsigned int i = rptr ; i < rptr + bib ; ++i ) - if ( buffer[i%sizeof buffer] == ch ) - return true; - return false; - } - - void notifyReadyRead(); - -Q_SIGNALS: - void readyRead(); - -protected: - /* reimp */ void run(); - -private: - int fd; - Qt::HANDLE handle; -public: - QMutex mutex; - QWaitCondition waitForCancelCondition; - QWaitCondition bufferNotFullCondition; - QWaitCondition bufferNotEmptyCondition; - QWaitCondition hasStarted; - QWaitCondition readyReadSentCondition; - QWaitCondition blockedConsumerIsDoneCondition; - bool cancel; - bool eof; - bool error; - bool eofShortCut; - int errorCode; - bool isReading; - bool consumerBlocksOnUs; - -private: - unsigned int rptr, wptr; - char buffer[BUFFER_SIZE+1]; // need to keep one byte free to detect empty state -}; - - -Reader::Reader( int fd_, Qt::HANDLE handle_ ) - : QThread(), - fd( fd_ ), - handle( handle_ ), - mutex(), - bufferNotFullCondition(), - bufferNotEmptyCondition(), - hasStarted(), - cancel( false ), - eof( false ), - error( false ), - eofShortCut( false ), - errorCode( 0 ), - isReading( false ), - consumerBlocksOnUs( false ), - rptr( 0 ), wptr( 0 ) -{ - -} - -Reader::~Reader() {} - - -class Writer : public QThread { - Q_OBJECT -public: - Writer( int fd, Qt::HANDLE handle ); - ~Writer(); - - qint64 writeData( const char * data, qint64 size ); - - unsigned int bytesInBuffer() const { return numBytesInBuffer; } - - bool bufferFull() const { - return numBytesInBuffer == sizeof buffer; - } - - bool bufferEmpty() const { - return numBytesInBuffer == 0; - } - -Q_SIGNALS: - void bytesWritten( qint64 ); - -protected: - /* reimp */ void run(); - -private: - int fd; - Qt::HANDLE handle; -public: - QMutex mutex; - QWaitCondition bufferEmptyCondition; - QWaitCondition bufferNotEmptyCondition; - QWaitCondition hasStarted; - bool cancel; - bool error; - int errorCode; -private: - unsigned int numBytesInBuffer; - char buffer[BUFFER_SIZE]; -}; -} - -Writer::Writer( int fd_, Qt::HANDLE handle_ ) - : QThread(), - fd( fd_ ), - handle( handle_ ), - mutex(), - bufferEmptyCondition(), - bufferNotEmptyCondition(), - hasStarted(), - cancel( false ), - error( false ), - errorCode( 0 ), - numBytesInBuffer( 0 ) -{ - -} - -Writer::~Writer() {} - - -class KDPipeIODevice::Private : public QObject { -Q_OBJECT - friend class ::KDPipeIODevice; - KDPipeIODevice * const q; -public: - explicit Private( KDPipeIODevice * qq ); - ~Private(); - - bool doOpen( int, Qt::HANDLE, OpenMode ); - bool startReaderThread(); - bool startWriterThread(); - void stopThreads(); - -public Q_SLOTS: - void emitReadyRead(); - -private: - int fd; - Qt::HANDLE handle; - Reader * reader; - Writer * writer; - bool triedToStartReader; - bool triedToStartWriter; -}; - -KDPipeIODevice::Private::Private( KDPipeIODevice * qq ) - : QObject( qq ), q( qq ), - fd( -1 ), - handle( 0 ), - reader( 0 ), - writer( 0 ), - triedToStartReader( false ), triedToStartWriter( false ) -{ - -} - -KDPipeIODevice::Private::~Private() { - qDebug( "KDPipeIODevice::~Private(): Destroying %p", q ); -} - -KDPipeIODevice::KDPipeIODevice( QObject * p ) - : QIODevice( p ), d( new Private( this ) ) -{ - KDAB_CHECK_CTOR; -} - -KDPipeIODevice::KDPipeIODevice( int fd, OpenMode mode, QObject * p ) - : QIODevice( p ), d( new Private( this ) ) -{ - KDAB_CHECK_CTOR; - open( fd, mode ); -} - -KDPipeIODevice::KDPipeIODevice( Qt::HANDLE handle, OpenMode mode, QObject * p ) - : QIODevice( p ), d( new Private( this ) ) -{ - KDAB_CHECK_CTOR; - open( handle, mode ); -} - -KDPipeIODevice::~KDPipeIODevice() { KDAB_CHECK_DTOR; - if ( isOpen() ) - close(); - delete d; d = 0; -} - - -bool KDPipeIODevice::open( int fd, OpenMode mode ) { KDAB_CHECK_THIS; - -#ifdef Q_OS_WIN32 - return d->doOpen( fd, (HANDLE)_get_osfhandle( fd ), mode ); -#else - return d->doOpen( fd, 0, mode ); -#endif - -} - -bool KDPipeIODevice::open( Qt::HANDLE h, OpenMode mode ) { KDAB_CHECK_THIS; - -#ifdef Q_OS_WIN32 - return d->doOpen( -1, h, mode ); -#else - Q_UNUSED( h ); - Q_UNUSED( mode ); - assert( !"KDPipeIODevice::open( Qt::HANDLE, OpenMode ) should never be called except on Windows." ); -#endif - -} - -bool KDPipeIODevice::Private::startReaderThread() -{ - if ( triedToStartReader ) - return true; - triedToStartReader = true; - if ( reader && !reader->isRunning() && !reader->isFinished() ) { - qDebug("KDPipeIODevice::Private::startReaderThread(): locking reader (CONSUMER THREAD)" ); - LOCKED( reader ); - qDebug("KDPipeIODevice::Private::startReaderThread(): locked reader (CONSUMER THREAD)" ); - reader->start( QThread::HighestPriority ); - qDebug("KDPipeIODevice::Private::startReaderThread(): waiting for hasStarted (CONSUMER THREAD)" ); - const bool hasStarted = reader->hasStarted.wait( &reader->mutex, 1000 ); - qDebug("KDPipeIODevice::Private::startReaderThread(): returned from hasStarted (CONSUMER THREAD)" ); - - return hasStarted; - } - return true; -} - -bool KDPipeIODevice::Private::startWriterThread() -{ - if ( triedToStartWriter ) - return true; - triedToStartWriter = true; - if ( writer && !writer->isRunning() && !writer->isFinished() ) { - LOCKED( writer ); - - writer->start( QThread::HighestPriority ); - if ( !writer->hasStarted.wait( &writer->mutex, 1000 ) ) - return false; - } - return true; -} - -void KDPipeIODevice::Private::emitReadyRead() -{ - QPointer thisPointer( this ); - qDebug( "KDPipeIODevice::Private::emitReadyRead %p", this ); - - emit q->readyRead(); - - if ( !thisPointer ) - return; - - bool mustNotify = false; - - if ( reader ) { - qDebug( "KDPipeIODevice::Private::emitReadyRead %p: locking reader (CONSUMER THREAD)", this ); - synchronized( reader ) { - qDebug( "KDPipeIODevice::Private::emitReadyRead %p: locked reader (CONSUMER THREAD)", this ); - reader->readyReadSentCondition.wakeAll(); - mustNotify = !reader->bufferEmpty() && reader->isReading; - qDebug( "KDPipeIODevice::emitReadyRead %p: bufferEmpty: %d reader in ReadFile: %d", this, reader->bufferEmpty(), reader->isReading ); - } - } - if ( mustNotify ) - QTimer::singleShot( 100, this, SLOT( emitReadyRead() ) ); - qDebug( "KDPipeIODevice::Private::emitReadyRead %p leaving", this ); - -} - -bool KDPipeIODevice::Private::doOpen( int fd_, Qt::HANDLE handle_, OpenMode mode_ ) { - - if ( q->isOpen() ) - return false; - -#ifdef Q_OS_WIN32 - if ( !handle_ ) - return false; -#else - if ( fd_ < 0 ) - return false; -#endif - - if ( !(mode_ & ReadWrite) ) - return false; // need to have at least read -or- write - - - std::auto_ptr reader_; - std::auto_ptr writer_; - - if ( mode_ & ReadOnly ) { - reader_.reset( new Reader( fd_, handle_ ) ); - qDebug( "KDPipeIODevice::doOpen (%p): created reader (%p) for fd %d", this, reader_.get(), fd_ ); - connect( reader_.get(), SIGNAL(readyRead()), this, SLOT(emitReadyRead()), -Qt::QueuedConnection ); - } - if ( mode_ & WriteOnly ) { - writer_.reset( new Writer( fd_, handle_ ) ); - qDebug( "KDPipeIODevice::doOpen (%p): created writer (%p) for fd %d", this, writer_.get(), fd_ ); - connect( writer_.get(), SIGNAL(bytesWritten(qint64)), q, SIGNAL(bytesWritten(qint64)), -Qt::QueuedConnection ); - } - - // commit to *this: - fd = fd_; - handle = handle_; - reader = reader_.release(); - writer = writer_.release(); - - q->setOpenMode( mode_|Unbuffered ); - return true; -} - -int KDPipeIODevice::descriptor() const { KDAB_CHECK_THIS; - return d->fd; -} - - -Qt::HANDLE KDPipeIODevice::handle() const { KDAB_CHECK_THIS; - return d->handle; -} - -qint64 KDPipeIODevice::bytesAvailable() const { KDAB_CHECK_THIS; - const qint64 base = QIODevice::bytesAvailable(); - if ( !d->triedToStartReader ) { - d->startReaderThread(); - return base; - } - if ( d->reader ) - synchronized( d->reader ) { - const qint64 inBuffer = d->reader->bytesInBuffer(); - return base + inBuffer; - } - return base; -} - -qint64 KDPipeIODevice::bytesToWrite() const { KDAB_CHECK_THIS; - d->startWriterThread(); - const qint64 base = QIODevice::bytesToWrite(); - if ( d->writer ) - synchronized( d->writer ) return base + d->writer->bytesInBuffer(); - return base; -} - -bool KDPipeIODevice::canReadLine() const { KDAB_CHECK_THIS; - d->startReaderThread(); - if ( QIODevice::canReadLine() ) - return true; - if ( d->reader ) - synchronized( d->reader ) return d->reader->bufferContains( '\n' ); - return true; -} - -bool KDPipeIODevice::isSequential() const { - return true; -} - -bool KDPipeIODevice::atEnd() const { KDAB_CHECK_THIS; - d->startReaderThread(); - if ( !QIODevice::atEnd() ) { - qDebug( "%p: KDPipeIODevice::atEnd returns false since QIODevice::atEnd does (with bytesAvailable=%ld)", this, static_cast(bytesAvailable()) ); - return false; - } - if ( !isOpen() ) - return true; - if ( d->reader->eofShortCut ) - return true; - LOCKED( d->reader ); - const bool eof = ( d->reader->error || d->reader->eof ) && d->reader->bufferEmpty(); - if ( !eof ) { - if ( !d->reader->error && !d->reader->eof ) - qDebug( "%p: KDPipeIODevice::atEnd returns false since !reader->error && !reader->eof", this ); - if ( !d->reader->bufferEmpty() ) - qDebug( "%p: KDPipeIODevice::atEnd returns false since !reader->bufferEmpty()", this ); - } - return eof; -} - -bool KDPipeIODevice::waitForBytesWritten( int msecs ) { KDAB_CHECK_THIS; - d->startWriterThread(); - Writer * const w = d->writer; - if ( !w ) - return true; - LOCKED( w ); - qDebug( "KDPipeIODevice::waitForBytesWritten (%p,w=%p): entered locked area", this, w -); - return w->bufferEmpty() || w->error || w->bufferEmptyCondition.wait( &w->mutex, msecs ) ; -} - -bool KDPipeIODevice::waitForReadyRead( int msecs ) { KDAB_CHECK_THIS; - qDebug( "KDPipeIODEvice::waitForReadyRead()(%p)", this); - d->startReaderThread(); - if ( ALLOW_QIODEVICE_BUFFERING ) { - if ( bytesAvailable() > 0 ) - return true; - } - Reader * const r = d->reader; - if ( !r || r->eofShortCut ) - return true; - LOCKED( r ); - if ( r->bytesInBuffer() != 0 || r->eof || r->error ) - return true; - - return msecs >= 0 ? r->bufferNotEmptyCondition.wait( &r->mutex, msecs ) : r->bufferNotEmptyCondition.wait( &r->mutex ); -} - -template -class TemporaryValue { -public: - TemporaryValue( T& var_, const T& tv ) : var( var_ ), oldValue( var_ ) { var = tv; } - ~TemporaryValue() { var = oldValue; } -private: - T& var; - const T oldValue; -}; - - -bool KDPipeIODevice::readWouldBlock() const -{ - d->startReaderThread(); - LOCKED( d->reader ); - return d->reader->bufferEmpty() && !d->reader->eof && !d->reader->error; -} - -bool KDPipeIODevice::writeWouldBlock() const -{ - d->startWriterThread(); - LOCKED( d->writer ); - return !d->writer->bufferEmpty() && !d->writer->error; -} - - -qint64 KDPipeIODevice::readData( char * data, qint64 maxSize ) { KDAB_CHECK_THIS; - qDebug( "%p: KDPipeIODevice::readData: data=%p, maxSize=%lld", this, data, maxSize ); - d->startReaderThread(); - Reader * const r = d->reader; - - assert( r ); - - - //assert( r->isRunning() ); // wrong (might be eof, error) - assert( data || maxSize == 0 ); - assert( maxSize >= 0 ); - - if ( r->eofShortCut ) { - qDebug( "%p: KDPipeIODevice::readData: hit eofShortCut, returning 0", this ); - return 0; - } - - if ( maxSize < 0 ) - maxSize = 0; - - if ( ALLOW_QIODEVICE_BUFFERING ) { - if ( bytesAvailable() > 0 ) - maxSize = std::min( maxSize, bytesAvailable() ); // don't block - } - qDebug( "%p: KDPipeIODevice::readData: try to lock reader (CONSUMER THREAD)", this ); - LOCKED( r ); - qDebug( "%p: KDPipeIODevice::readData: locked reader (CONSUMER THREAD)", this ); - - r->readyReadSentCondition.wakeAll(); - if ( /* maxSize > 0 && */ r->bufferEmpty() && !r->error && !r->eof ) { // ### block on maxSize == 0? - qDebug( "%p: KDPipeIODevice::readData: waiting for bufferNotEmptyCondition (CONSUMER THREAD)", this ); - const TemporaryValue tmp( d->reader->consumerBlocksOnUs, true ); - r->bufferNotEmptyCondition.wait( &r->mutex ); - r->blockedConsumerIsDoneCondition.wakeAll(); - qDebug( "%p: KDPipeIODevice::readData: woke up from bufferNotEmptyCondition (CONSUMER THREAD)", this ); - } - - if ( r->bufferEmpty() ) { - qDebug( "%p: KDPipeIODevice::readData: got empty buffer, signal eof", this ); - // woken with an empty buffer must mean either EOF or error: - assert( r->eof || r->error ); - r->eofShortCut = true; - return r->eof ? 0 : -1 ; - } - - qDebug( "%p: KDPipeIODevice::readData: got bufferNotEmptyCondition, trying to read %lld bytes", this, maxSize ); - const qint64 bytesRead = r->readData( data, maxSize ); - qDebug( "%p: KDPipeIODevice::readData: read %lld bytes", this, bytesRead ); - qDebug( "%p (fd=%d): KDPipeIODevice::readData: %s", this, d->fd, data ); - - return bytesRead; -} - -qint64 Reader::readData( char * data, qint64 maxSize ) { - qint64 numRead = rptr < wptr ? wptr - rptr : sizeof buffer - rptr ; - if ( numRead > maxSize ) - numRead = maxSize; - - qDebug( "%p: KDPipeIODevice::readData: data=%p, maxSize=%lld; rptr=%u, wptr=%u (bytesInBuffer=%u); -> numRead=%lld", this, - data, maxSize, rptr, wptr, bytesInBuffer(), numRead ); - - std::memcpy( data, buffer + rptr, numRead ); - - rptr = ( rptr + numRead ) % sizeof buffer ; - - if ( !bufferFull() ) { - qDebug( "%p: KDPipeIODevice::readData: signal bufferNotFullCondition", this ); - bufferNotFullCondition.wakeAll(); - } - - return numRead; -} - -qint64 KDPipeIODevice::writeData( const char * data, qint64 size ) { KDAB_CHECK_THIS; - d->startWriterThread(); - Writer * const w = d->writer; - - assert( w ); - assert( w->error || w->isRunning() ); - assert( data || size == 0 ); - assert( size >= 0 ); - - LOCKED( w ); - - while ( !w->error && !w->bufferEmpty() ) { - qDebug( "%p: KDPipeIODevice::writeData: wait for empty buffer", this ); - w->bufferEmptyCondition.wait( &w->mutex ); - qDebug( "%p: KDPipeIODevice::writeData: empty buffer signaled", this ); - - } - if ( w->error ) - return -1; - - assert( w->bufferEmpty() ); - - return w->writeData( data, size ); -} - -qint64 Writer::writeData( const char * data, qint64 size ) { - assert( bufferEmpty() ); - - if ( size > static_cast( sizeof buffer ) ) - size = sizeof buffer; - - std::memcpy( buffer, data, size ); - - numBytesInBuffer = size; - - if ( !bufferEmpty() ) { - bufferNotEmptyCondition.wakeAll(); - } - return size; -} - -void KDPipeIODevice::Private::stopThreads() -{ - if ( triedToStartWriter ) - { - if ( writer && q->bytesToWrite() > 0 ) - q->waitForBytesWritten( -1 ); - - assert( q->bytesToWrite() == 0 ); - } - if ( Reader * & r = reader ) { - disconnect( r, SIGNAL( readyRead() ), this, SLOT( emitReadyRead() ) ); - synchronized( r ) { - // tell thread to cancel: - r->cancel = true; - // and wake it, so it can terminate: - r->waitForCancelCondition.wakeAll(); - r->bufferNotFullCondition.wakeAll(); - r->readyReadSentCondition.wakeAll(); - } - } - if ( Writer * & w = writer ) { - synchronized( w ) { - // tell thread to cancel: - w->cancel = true; - // and wake it, so it can terminate: - w->bufferNotEmptyCondition.wakeAll(); - } - } -} - -void KDPipeIODevice::close() { KDAB_CHECK_THIS; - qDebug( "KDPipeIODevice::close(%p)", this ); - if ( !isOpen() ) - return; - - // tell clients we're about to close: - emit aboutToClose(); - d->stopThreads(); - -#define waitAndDelete( t ) if ( t ) { t->wait(); QThread* const t2 = t; t = 0; delete t2; } - qDebug( "KPipeIODevice::close(%p): wait and closing writer %p", this, d->writer ); - waitAndDelete( d->writer ); - qDebug( "KPipeIODevice::close(%p): wait and closing reader %p", this, d->reader ); - if ( d->reader ) { - LOCKED( d->reader ); - d->reader->readyReadSentCondition.wakeAll(); - } - waitAndDelete( d->reader ); -#undef waitAndDelete -#ifdef Q_OS_WIN32 - if ( d->fd != -1 ) - _close( d->fd ); - else - CloseHandle( d->handle ); -#else - ::close( d->fd ); -#endif - - setOpenMode( NotOpen ); - d->fd = -1; - d->handle = 0; -} - -void Reader::run() { - - LOCKED( this ); - - // too bad QThread doesn't have that itself; a signal isn't enough - hasStarted.wakeAll(); - - qDebug( "%p: Reader::run: started", this ); - - while ( true ) { - if ( !cancel && ( eof || error ) ) { - //notify the client until the buffer is empty and then once - //again so he receives eof/error. After that, wait for him - //to cancel - const bool wasEmpty = bufferEmpty(); - qDebug( "%p: Reader::run: received eof(%d) or error(%d), waking everyone", this, eof, error ); - notifyReadyRead(); - if ( !cancel && wasEmpty ) - waitForCancelCondition.wait( &mutex ); - } else if ( !cancel && !bufferFull() && !bufferEmpty() ) { - qDebug( "%p: Reader::run: buffer no longer empty, waking everyone", this ); - notifyReadyRead(); - } - - while ( !cancel && !error && bufferFull() ) { - notifyReadyRead(); - if ( !cancel && bufferFull() ) { - qDebug( "%p: Reader::run: buffer is full, going to sleep", this ); - bufferNotFullCondition.wait( &mutex ); - } - } - - if ( cancel ) { - qDebug( "%p: Reader::run: detected cancel", this ); - goto leave; - } - - if ( !eof && !error ) { - if ( rptr == wptr ) // optimize for larger chunks in case the buffer is empty - rptr = wptr = 0; - - unsigned int numBytes = ( rptr + sizeof buffer - wptr - 1 ) % sizeof buffer; - if ( numBytes > sizeof buffer - wptr ) - numBytes = sizeof buffer - wptr; - - qDebug( "%p: Reader::run: rptr=%d, wptr=%d -> numBytes=%d", this, rptr, wptr, numBytes ); - - assert( numBytes > 0 ); - - qDebug( "%p: Reader::run: trying to read %d bytes", this, numBytes ); -#ifdef Q_OS_WIN32 - isReading = true; - mutex.unlock(); - DWORD numRead; - const bool ok = ReadFile( handle, buffer + wptr, numBytes, &numRead, 0 ); - mutex.lock(); - isReading = false; - if ( ok ) { - if ( numRead == 0 ) { - qDebug( "%p: Reader::run: got eof (numRead==0)", this ); - eof = true; - } - } else { // !ok - errorCode = static_cast( GetLastError() ); - if ( errorCode == ERROR_BROKEN_PIPE ) { - assert( numRead == 0 ); - qDebug( "%p: Reader::run: got eof (broken pipe)", this ); - eof = true; - } else { - assert( numRead == 0 ); - qDebug( "%p: Reader::run: got error: %s (%d)", this, strerror( errorCode ), errorCode ); - error = true; - } - } -#else - qint64 numRead; - mutex.unlock(); - do { - numRead = ::read( fd, buffer + wptr, numBytes ); - } while ( numRead == -1 && errno == EINTR ); - mutex.lock(); - - if ( numRead < 0 ) { - errorCode = errno; - error = true; - qDebug( "%p: Reader::run: got error: %d", this, errorCode ); - } else if ( numRead == 0 ) { - qDebug( "%p: Reader::run: eof detected", this ); - eof = true; - } -#endif - qDebug( "%p: Reader::run: read %ld bytes", this, static_cast(numRead) ); - qDebug( "%p: Reader::run(fd=%d): %s", this, fd, buffer ); - - if ( numRead > 0 ) { - qDebug( "%p: Reader::run: buffer before: rptr=%4d, wptr=%4d", this, rptr, wptr ); - wptr = ( wptr + numRead ) % sizeof buffer; - qDebug( "%p: Reader::run: buffer after: rptr=%4d, wptr=%4d", this, rptr, wptr ); - } - } - } - leave: - qDebug( "%p: Reader::run: terminated", this ); -} - -void Reader::notifyReadyRead() -{ - qDebug( "notifyReadyRead: %d bytes available", bytesInBuffer() ); - assert( !cancel ); - - if ( consumerBlocksOnUs ) { - bufferNotEmptyCondition.wakeAll(); - blockedConsumerIsDoneCondition.wait( &mutex ); - return; - } - qDebug( "notifyReadyRead: emit signal" ); - emit readyRead(); - readyReadSentCondition.wait( &mutex ); - qDebug( "notifyReadyRead: returning from waiting, leave" ); -} - -void Writer::run() { - - LOCKED( this ); - - // too bad QThread doesn't have that itself; a signal isn't enough - hasStarted.wakeAll(); - - qDebug( "%p: Writer::run: started", this ); - - while ( true ) { - - while ( !cancel && bufferEmpty() ) { - qDebug( "%p: Writer::run: buffer is empty, wake bufferEmptyCond listeners", this ); - bufferEmptyCondition.wakeAll(); - emit bytesWritten( 0 ); - qDebug( "%p: Writer::run: buffer is empty, going to sleep", this ); - bufferNotEmptyCondition.wait( &mutex ); - qDebug( "%p: Writer::run: woke up", this ); - } - - if ( cancel ) { - qDebug( "%p: Writer::run: detected cancel", this ); - goto leave; - } - - assert( numBytesInBuffer > 0 ); - - qDebug( "%p: Writer::run: Trying to write %u bytes", this, numBytesInBuffer ); - qint64 totalWritten = 0; - do { - mutex.unlock(); -#ifdef Q_OS_WIN32 - DWORD numWritten; - qDebug( "%p (fd=%d): Writer::run: buffer before WriteFile (numBytes=%lld): %s:", this, fd, numBytesInBuffer, buffer ); - qDebug( "%p (fd=%d): Writer::run: Going into WriteFile", this, fd ); - if ( !WriteFile( handle, buffer + totalWritten, numBytesInBuffer - totalWritten, &numWritten, 0 ) ) { - mutex.lock(); - errorCode = static_cast( GetLastError() ); - qDebug( "%p: Writer::run: got error code: %d", this, errorCode ); - error = true; - goto leave; - } -#else - qint64 numWritten; - do { - numWritten = ::write( fd, buffer + totalWritten, numBytesInBuffer - totalWritten ); - } while ( numWritten == -1 && errno == EINTR ); - - if ( numWritten < 0 ) { - mutex.lock(); - errorCode = errno; - qDebug( "%p: Writer::run: got error code: %d", this, errorCode ); - error = true; - goto leave; - } -#endif - qDebug( "%p (fd=%d): Writer::run: buffer after WriteFile (numBytes=%u): %s:", this, fd, numBytesInBuffer, buffer ); - totalWritten += numWritten; - mutex.lock(); - } while ( totalWritten < numBytesInBuffer ); - - qDebug( "%p: Writer::run: wrote %lld bytes", this, totalWritten ); - - numBytesInBuffer = 0; - - qDebug( "%p: Writer::run: buffer is empty, wake bufferEmptyCond listeners", this ); - bufferEmptyCondition.wakeAll(); - emit bytesWritten( totalWritten ); - } - leave: - qDebug( "%p: Writer::run: terminating", this ); - numBytesInBuffer = 0; - qDebug( "%p: Writer::run: buffer is empty, wake bufferEmptyCond listeners", this ); - bufferEmptyCondition.wakeAll(); - emit bytesWritten( 0 ); -} - -// static -std::pair KDPipeIODevice::makePairOfConnectedPipes() { - KDPipeIODevice * read = 0; - KDPipeIODevice * write = 0; -#ifdef Q_OS_WIN32 - HANDLE rh; - HANDLE wh; - SECURITY_ATTRIBUTES sa; - memset( &sa, 0, sizeof(sa) ); - sa.nLength = sizeof(sa); - sa.bInheritHandle = TRUE; - if ( CreatePipe( &rh, &wh, &sa, BUFFER_SIZE ) ) { - read = new KDPipeIODevice; - read->open( rh, ReadOnly ); - write = new KDPipeIODevice; - write->open( wh, WriteOnly ); - } -#else - int fds[2]; - if ( pipe( fds ) == 0 ) { - read = new KDPipeIODevice; - read->open( fds[0], ReadOnly ); - write = new KDPipeIODevice; - write->open( fds[1], WriteOnly ); - } -#endif - return std::make_pair( read, write ); -} - -#ifdef KDAB_DEFINE_CHECKS -KDAB_DEFINE_CHECKS( KDPipeIODevice ) { - if ( !isOpen() ) { - assert( openMode() == NotOpen ); - assert( !d->reader ); - assert( !d->writer ); -#ifdef Q_OS_WIN32 - assert( !d->handle ); -#else - assert( d->fd < 0 ); -#endif - } else { - assert( openMode() != NotOpen ); - assert( openMode() & ReadWrite ); - if ( openMode() & ReadOnly ) { - assert( d->reader ); - synchronized( d->reader ) - assert( d->reader->eof || d->reader->error || d->reader->isRunning() ); - } - if ( openMode() & WriteOnly ) { - assert( d->writer ); - synchronized( d->writer ) - assert( d->writer->error || d->writer->isRunning() ); - } -#ifdef Q_OS_WIN32 - assert( d->handle ); -#else - assert( d->fd >= 0 ); -#endif - } -} -#endif // KDAB_DEFINE_CHECKS - -#include "moc_kdpipeiodevice.cpp" -#include "kdpipeiodevice.moc" diff --git a/src/kdpipeiodevice.h b/src/kdpipeiodevice.h deleted file mode 100644 index 8da6af68..00000000 --- a/src/kdpipeiodevice.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - Copyright (C) 2007 Klarälvdalens Datakonsult AB - - KDPipeIODevice is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - KDPipeIODevice is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with KDPipeIODevice; see the file COPYING.LIB. If not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#ifndef __KDTOOLSCORE_KDPIPEIODEVICE_H__ -#define __KDTOOLSCORE_KDPIPEIODEVICE_H__ - -#include - -#include - -//#include "checker.h" - -namespace _gpgme_ { - -class KDPipeIODevice : public QIODevice { - Q_OBJECT - //KDAB_MAKE_CHECKABLE( KDPipeIODevice ) -public: - explicit KDPipeIODevice( QObject * parent=0 ); - explicit KDPipeIODevice( int fd, OpenMode=ReadOnly, QObject * parent=0 ); - explicit KDPipeIODevice( Qt::HANDLE handle, OpenMode=ReadOnly, QObject * parent=0 ); - ~KDPipeIODevice(); - - static std::pair makePairOfConnectedPipes(); - - bool open( int fd, OpenMode mode=ReadOnly ); - bool open( Qt::HANDLE handle, OpenMode mode=ReadOnly ); - - Qt::HANDLE handle() const; - int descriptor() const; - - bool readWouldBlock() const; - bool writeWouldBlock() const; - - /* reimp */ qint64 bytesAvailable() const; - /* reimp */ qint64 bytesToWrite() const; - /* reimp */ bool canReadLine() const; - /* reimp */ void close(); - /* reimp */ bool isSequential() const; - /* reimp */ bool atEnd() const; - - /* reimp */ bool waitForBytesWritten( int msecs ); - /* reimp */ bool waitForReadyRead( int msecs ); - -protected: - /* reimp */ qint64 readData( char * data, qint64 maxSize ); - /* reimp */ qint64 writeData( const char * data, qint64 maxSize ); - -private: - class Private; - Private * d; -}; - -} /* namespace _gpgme_ */ - -#endif /* __KDTOOLSCORE_KDPIPEIODEVICE_H__ */ - diff --git a/src/kdpipeiodevice.moc b/src/kdpipeiodevice.moc deleted file mode 100644 index 457f371a..00000000 --- a/src/kdpipeiodevice.moc +++ /dev/null @@ -1,183 +0,0 @@ -/**************************************************************************** -** Meta object code from reading C++ file 'kdpipeiodevice.cpp' -** -** Created: Tue Oct 2 19:30:13 2007 -** by: The Qt Meta Object Compiler version 59 (Qt 4.3.1) -** -** WARNING! All changes made in this file will be lost! -*****************************************************************************/ - -#if !defined(Q_MOC_OUTPUT_REVISION) -#error "The header file 'kdpipeiodevice.cpp' doesn't include ." -#elif Q_MOC_OUTPUT_REVISION != 59 -#error "This file was generated using the moc from 4.3.1. It" -#error "cannot be used with the include files from this version of Qt." -#error "(The moc has changed too much.)" -#endif - -static const uint qt_meta_data_Reader[] = { - - // content: - 1, // revision - 0, // classname - 0, 0, // classinfo - 1, 10, // methods - 0, 0, // properties - 0, 0, // enums/sets - - // signals: signature, parameters, type, tag, flags - 8, 7, 7, 7, 0x05, - - 0 // eod -}; - -static const char qt_meta_stringdata_Reader[] = { - "Reader\0\0readyRead()\0" -}; - -const QMetaObject Reader::staticMetaObject = { - { &QThread::staticMetaObject, qt_meta_stringdata_Reader, - qt_meta_data_Reader, 0 } -}; - -const QMetaObject *Reader::metaObject() const -{ - return &staticMetaObject; -} - -void *Reader::qt_metacast(const char *_clname) -{ - if (!_clname) return 0; - if (!strcmp(_clname, qt_meta_stringdata_Reader)) - return static_cast(const_cast< Reader*>(this)); - return QThread::qt_metacast(_clname); -} - -int Reader::qt_metacall(QMetaObject::Call _c, int _id, void **_a) -{ - _id = QThread::qt_metacall(_c, _id, _a); - if (_id < 0) - return _id; - if (_c == QMetaObject::InvokeMetaMethod) { - switch (_id) { - case 0: readyRead(); break; - } - _id -= 1; - } - return _id; -} - -// SIGNAL 0 -void Reader::readyRead() -{ - QMetaObject::activate(this, &staticMetaObject, 0, 0); -} -static const uint qt_meta_data_Writer[] = { - - // content: - 1, // revision - 0, // classname - 0, 0, // classinfo - 1, 10, // methods - 0, 0, // properties - 0, 0, // enums/sets - - // signals: signature, parameters, type, tag, flags - 8, 7, 7, 7, 0x05, - - 0 // eod -}; - -static const char qt_meta_stringdata_Writer[] = { - "Writer\0\0bytesWritten(qint64)\0" -}; - -const QMetaObject Writer::staticMetaObject = { - { &QThread::staticMetaObject, qt_meta_stringdata_Writer, - qt_meta_data_Writer, 0 } -}; - -const QMetaObject *Writer::metaObject() const -{ - return &staticMetaObject; -} - -void *Writer::qt_metacast(const char *_clname) -{ - if (!_clname) return 0; - if (!strcmp(_clname, qt_meta_stringdata_Writer)) - return static_cast(const_cast< Writer*>(this)); - return QThread::qt_metacast(_clname); -} - -int Writer::qt_metacall(QMetaObject::Call _c, int _id, void **_a) -{ - _id = QThread::qt_metacall(_c, _id, _a); - if (_id < 0) - return _id; - if (_c == QMetaObject::InvokeMetaMethod) { - switch (_id) { - case 0: bytesWritten((*reinterpret_cast< qint64(*)>(_a[1]))); break; - } - _id -= 1; - } - return _id; -} - -// SIGNAL 0 -void Writer::bytesWritten(qint64 _t1) -{ - void *_a[] = { 0, const_cast(reinterpret_cast(&_t1)) }; - QMetaObject::activate(this, &staticMetaObject, 0, _a); -} -static const uint qt_meta_data_KDPipeIODevice__Private[] = { - - // content: - 1, // revision - 0, // classname - 0, 0, // classinfo - 1, 10, // methods - 0, 0, // properties - 0, 0, // enums/sets - - // slots: signature, parameters, type, tag, flags - 25, 24, 24, 24, 0x0a, - - 0 // eod -}; - -static const char qt_meta_stringdata_KDPipeIODevice__Private[] = { - "KDPipeIODevice::Private\0\0emitReadyRead()\0" -}; - -const QMetaObject KDPipeIODevice::Private::staticMetaObject = { - { &QObject::staticMetaObject, qt_meta_stringdata_KDPipeIODevice__Private, - qt_meta_data_KDPipeIODevice__Private, 0 } -}; - -const QMetaObject *KDPipeIODevice::Private::metaObject() const -{ - return &staticMetaObject; -} - -void *KDPipeIODevice::Private::qt_metacast(const char *_clname) -{ - if (!_clname) return 0; - if (!strcmp(_clname, qt_meta_stringdata_KDPipeIODevice__Private)) - return static_cast(const_cast< Private*>(this)); - return QObject::qt_metacast(_clname); -} - -int KDPipeIODevice::Private::qt_metacall(QMetaObject::Call _c, int _id, void **_a) -{ - _id = QObject::qt_metacall(_c, _id, _a); - if (_id < 0) - return _id; - if (_c == QMetaObject::InvokeMetaMethod) { - switch (_id) { - case 0: emitReadyRead(); break; - } - _id -= 1; - } - return _id; -} diff --git a/src/w32-qt-io.cpp b/src/w32-qt-io.cpp deleted file mode 100644 index 44655ecb..00000000 --- a/src/w32-qt-io.cpp +++ /dev/null @@ -1,700 +0,0 @@ -/* w32-qt-io.c - W32 Glib I/O functions - Copyright (C) 2000 Werner Koch (dd9jn) - Copyright (C) 2001, 2002, 2004, 2005, 2007 g10 Code GmbH - - This file is part of GPGME. - - GPGME is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of - the License, or (at your option) any later version. - - GPGME is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - 02111-1307, USA. */ - -#ifdef HAVE_CONFIG_H -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "kdpipeiodevice.h" - -extern "C" -{ -#include "util.h" -#include "priv-io.h" -#include "sema.h" -#include "debug.h" -} - -#ifndef O_BINARY -#ifdef _O_BINARY -#define O_BINARY _O_BINARY -#else -#define O_BINARY 0 -#endif -#endif - -using _gpgme_::KDPipeIODevice; - - -/* This file is an ugly hack to get GPGME working with Qt on Windows - targets. On Windows, you can not select() on file descriptors. - - The only way to check if there is something to read is to read - something. This means that GPGME can not let Qt check for data - without letting Qt also handle the data on Windows targets. - - The ugly consequence is that we need to work on QIODevices in - GPGME, creating a Qt dependency. Also, we need to export an - interface for the application to get at GPGME's QIODevices. There - is no good way to abstract all this with callbacks, because the - whole thing is also interconnected with the creation of pipes and - child processes. - - The following rule applies only to this I/O backend: - - * ALL operations must use the user defined event loop. GPGME can - not anymore provide its own event loop. This is mostly a sanity - requirement: Although we have in theory all information we need to - make the GPGME W32 code for select still work, it would be a big - complication and require changes throughout GPGME. - - Eventually, we probably have to bite the bullet and make some - really nice callback interfaces to let the user control all this at - a per-context level. */ - -#define MAX_SLAFD 1024 - -struct DeviceEntry { - DeviceEntry() : iodev( 0 ), refCount( 1 ), blocking( true ) {} - KDPipeIODevice* iodev; - bool blocking; - mutable int refCount; - void ref() const { ++refCount; } - int unref() const { assert( refCount > 0 ); return --refCount; } -}; - -DeviceEntry* iodevice_table[MAX_SLAFD]; - - -static KDPipeIODevice * -find_channel (int fd, int create) -{ - assert( fd < MAX_SLAFD ); - if (fd < 0 || fd >= MAX_SLAFD) - return NULL; - - if (create && !iodevice_table[fd]) - { - DeviceEntry* entry = new DeviceEntry; - entry->iodev = new KDPipeIODevice - (fd, QIODevice::ReadWrite|QIODevice::Unbuffered); - iodevice_table[fd] = entry; - } - return iodevice_table[fd] ? iodevice_table[fd]->iodev : 0; -} - -/* Write the printable version of FD to the buffer BUF of length - BUFLEN. The printable version is the representation on the command - line that the child process expects. */ -int -_gpgme_io_fd2str (char *buf, int buflen, int fd) -{ - return snprintf (buf, buflen, "%d", (long)_get_osfhandle( fd ) ); -} - - -void -_gpgme_io_subsystem_init (void) -{ -} - - -static struct -{ - _gpgme_close_notify_handler_t handler; - void *value; -} notify_table[MAX_SLAFD]; - - -int -_gpgme_io_read (int fd, void *buffer, size_t count) -{ - int saved_errno = 0; - qint64 nread; - KDPipeIODevice *chan; - TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_read", fd, - "buffer=%p, count=%u", buffer, count); - - chan = find_channel (fd, 0); - if (!chan) - { - TRACE_LOG ("no channel registered"); - errno = EINVAL; - return TRACE_SYSRES (-1); - } - TRACE_LOG1 ("channel %p", chan); - if ( iodevice_table[fd] && !iodevice_table[fd]->blocking && chan->readWouldBlock() ) { - errno = EAGAIN; - return TRACE_SYSRES( -1 ); - } - - nread = chan->read ((char *) buffer, count); - if (nread < 0) - { - TRACE_LOG1 ("err %s", qPrintable (chan->errorString ())); - saved_errno = EIO; - nread = -1; - } - - TRACE_LOGBUF ((char *) buffer, nread); - - errno = saved_errno; - return TRACE_SYSRES (nread); -} - - -int -_gpgme_io_write (int fd, const void *buffer, size_t count) -{ - qint64 nwritten; - KDPipeIODevice *chan; - TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_write", fd, - "buffer=%p, count=%u", buffer, count); - TRACE_LOGBUF ((char *) buffer, count); - - chan = find_channel (fd, 0); - if (!chan) - { - TRACE_LOG ("fd %d: no channel registered"); - errno = EINVAL; - return -1; - } - - if ( iodevice_table[fd] && !iodevice_table[fd]->blocking && chan->writeWouldBlock() ) - { - errno = EAGAIN; - return TRACE_SYSRES( -1 ); - } - nwritten = chan->write ((char *) buffer, count); - - if (nwritten < 0) - { - nwritten = -1; - errno = EIO; - return TRACE_SYSRES(-1); - } - errno = 0; - return TRACE_SYSRES (nwritten); -} - - -int -_gpgme_io_pipe (int filedes[2], int inherit_idx) -{ - KDPipeIODevice *chan; - TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_pipe", filedes, - "inherit_idx=%i (GPGME uses it for %s)", - inherit_idx, inherit_idx ? "reading" : "writing"); - -#define PIPEBUF_SIZE 4096 - if (_pipe (filedes, PIPEBUF_SIZE, O_NOINHERIT | O_BINARY) == -1) - return TRACE_SYSRES (-1); - - /* Make one end inheritable. */ - if (inherit_idx == 0) - { - int new_read; - - new_read = _dup (filedes[0]); - _close (filedes[0]); - filedes[0] = new_read; - - if (new_read < 0) - { - _close (filedes[1]); - return TRACE_SYSRES (-1); - } - } - else if (inherit_idx == 1) - { - int new_write; - - new_write = _dup (filedes[1]); - _close (filedes[1]); - filedes[1] = new_write; - - if (new_write < 0) - { - _close (filedes[0]); - return TRACE_SYSRES (-1); - } - } - - /* Now we have a pipe with the right end inheritable. The other end - should have a giochannel. */ - - chan = find_channel (filedes[1 - inherit_idx], 1); - - if (!chan) - { - int saved_errno = errno; - _close (filedes[0]); - _close (filedes[1]); - errno = saved_errno; - return TRACE_SYSRES (-1); - } - - return TRACE_SUC5 ("read=0x%x/%p, write=0x%x/%p, channel=%p", - filedes[0], (HANDLE) _get_osfhandle (filedes[0]), - filedes[1], (HANDLE) _get_osfhandle (filedes[1]), - chan); -} - -int -_gpgme_io_close (int fd) -{ - KDPipeIODevice *chan; - TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_close", fd); - - if (fd < 0 || fd >= MAX_SLAFD) - { - errno = EBADF; - return TRACE_SYSRES (-1); - } - - /* First call the notify handler. */ - if (notify_table[fd].handler) - { - notify_table[fd].handler (fd, notify_table[fd].value); - notify_table[fd].handler = NULL; - notify_table[fd].value = NULL; - } - - /* Then do the close. */ - - DeviceEntry* const entry = iodevice_table[fd]; - if ( entry ) { - if ( entry->unref() == 0 ) { - entry->iodev->close(); - delete entry->iodev; - delete entry; - iodevice_table[fd] = 0; - } - } else { - _close( fd ); - } - - - - return 0; -} - - -int -_gpgme_io_set_close_notify (int fd, _gpgme_close_notify_handler_t handler, - void *value) -{ - TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_set_close_notify", fd, - "close_handler=%p/%p", handler, value); - - assert (fd != -1); - - if (fd < 0 || fd >= (int) DIM (notify_table)) - { - errno = EINVAL; - return TRACE_SYSRES (-1); - } - notify_table[fd].handler = handler; - notify_table[fd].value = value; - return TRACE_SYSRES (0); -} - - -int -_gpgme_io_set_nonblocking (int fd) -{ - DeviceEntry* const entry = iodevice_table[fd]; - assert( entry ); - entry->blocking = false; - TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_set_nonblocking", fd); - return TRACE_SYSRES (0); -} - - -static char * -build_commandline (char **argv) -{ - int i; - int n = 0; - char *buf; - char *p; - - /* We have to quote some things because under Windows the program - parses the commandline and does some unquoting. We enclose the - whole argument in double-quotes, and escape literal double-quotes - as well as backslashes with a backslash. We end up with a - trailing space at the end of the line, but that is harmless. */ - for (i = 0; argv[i]; i++) - { - p = argv[i]; - /* The leading double-quote. */ - n++; - while (*p) - { - /* An extra one for each literal that must be escaped. */ - if (*p == '\\' || *p == '"') - n++; - n++; - p++; - } - /* The trailing double-quote and the delimiter. */ - n += 2; - } - /* And a trailing zero. */ - n++; - - buf = p = (char *) malloc (n); - if (!buf) - return NULL; - for (i = 0; argv[i]; i++) - { - char *argvp = argv[i]; - - *(p++) = '"'; - while (*argvp) - { - if (*argvp == '\\' || *argvp == '"') - *(p++) = '\\'; - *(p++) = *(argvp++); - } - *(p++) = '"'; - *(p++) = ' '; - } - *(p++) = 0; - - return buf; -} - - -int -_gpgme_io_spawn (const char *path, char * const argv[], unsigned int flags, - struct spawn_fd_item_s *fd_list, - void (*atfork) (void *opaque, int reserved), - void *atforkvalue, pid_t *r_pid) -{ - SECURITY_ATTRIBUTES sec_attr; - PROCESS_INFORMATION pi = - { - NULL, /* returns process handle */ - 0, /* returns primary thread handle */ - 0, /* returns pid */ - 0 /* returns tid */ - }; - STARTUPINFO si; - int cr_flags = CREATE_DEFAULT_ERROR_MODE - | GetPriorityClass (GetCurrentProcess ()); - int i; - char **args; - char *arg_string; - /* FIXME. */ - int debug_me = 0; - int tmp_fd; - char *tmp_name; - - TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path, - "path=%s", path); - i = 0; - while (argv[i]) - { - TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]); - i++; - } - - /* We do not inherit any handles by default, and just insert those - handles we want the child to have afterwards. But some handle - values occur on the command line, and we need to move - stdin/out/err to the right location. So we use a wrapper program - which gets the information from a temporary file. */ - if (_gpgme_mkstemp (&tmp_fd, &tmp_name) < 0) - { - TRACE_LOG1 ("_gpgme_mkstemp failed: %s", strerror (errno)); - return TRACE_SYSRES (-1); - } - TRACE_LOG1 ("tmp_name = %s", tmp_name); - - args = (char **) calloc (2 + i + 1, sizeof (*args)); - args[0] = (char *) _gpgme_get_w32spawn_path (); - args[1] = tmp_name; - args[2] = const_cast(path); - memcpy (&args[3], &argv[1], i * sizeof (*args)); - - memset (&sec_attr, 0, sizeof sec_attr); - sec_attr.nLength = sizeof sec_attr; - sec_attr.bInheritHandle = FALSE; - - arg_string = build_commandline (args); - free (args); - if (!arg_string) - { - close (tmp_fd); - DeleteFile (tmp_name); - return TRACE_SYSRES (-1); - } - - memset (&si, 0, sizeof si); - si.cb = sizeof (si); - si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; - si.wShowWindow = debug_me ? SW_SHOW : SW_HIDE; - si.hStdInput = INVALID_HANDLE_VALUE; - si.hStdOutput = INVALID_HANDLE_VALUE; - si.hStdError = INVALID_HANDLE_VALUE; - - cr_flags |= CREATE_SUSPENDED; - if ((flags & IOSPAWN_FLAG_DETACHED)) - cr_flags |= DETACHED_PROCESS; - if (!CreateProcessA (_gpgme_get_w32spawn_path (), - arg_string, - &sec_attr, /* process security attributes */ - &sec_attr, /* thread security attributes */ - FALSE, /* inherit handles */ - cr_flags, /* creation flags */ - NULL, /* environment */ - NULL, /* use current drive/directory */ - &si, /* startup information */ - &pi)) /* returns process information */ - { - TRACE_LOG1 ("CreateProcess failed: ec=%d", (int) GetLastError ()); - free (arg_string); - close (tmp_fd); - DeleteFile (tmp_name); - - /* FIXME: Should translate the error code. */ - errno = EIO; - return TRACE_SYSRES (-1); - } - - free (arg_string); - - if (flags & IOSPAWN_FLAG_ALLOW_SET_FG) - _gpgme_allow_set_foreground_window ((pid_t)pi.dwProcessId); - - /* Insert the inherited handles. */ - for (i = 0; fd_list[i].fd != -1; i++) - { - HANDLE hd; - - if (!DuplicateHandle (GetCurrentProcess(), - (HANDLE) _get_osfhandle (fd_list[i].fd), - pi.hProcess, &hd, 0, TRUE, DUPLICATE_SAME_ACCESS)) - { - TRACE_LOG1 ("DuplicateHandle failed: ec=%d", (int) GetLastError ()); - TerminateProcess (pi.hProcess, 0); - /* Just in case TerminateProcess didn't work, let the - process fail on its own. */ - ResumeThread (pi.hThread); - CloseHandle (pi.hThread); - CloseHandle (pi.hProcess); - - close (tmp_fd); - DeleteFile (tmp_name); - - /* FIXME: Should translate the error code. */ - errno = EIO; - return TRACE_SYSRES (-1); - } - /* Return the child name of this handle. */ - fd_list[i].peer_name = (int) hd; - } - - /* Write the handle translation information to the temporary - file. */ - { - /* Hold roughly MAX_TRANS quadruplets of 64 bit numbers in hex - notation: "0xFEDCBA9876543210" with an extra white space after - every quadruplet. 10*(19*4 + 1) - 1 = 769. This plans ahead - for a time when a HANDLE is 64 bit. */ -#define BUFFER_MAX 800 - char line[BUFFER_MAX + 1]; - int res; - int written; - size_t len; - - if ((flags & IOSPAWN_FLAG_ALLOW_SET_FG)) - strcpy (line, "~1 \n"); - else - strcpy (line, "\n"); - for (i = 0; fd_list[i].fd != -1; i++) - { - /* Strip the newline. */ - len = strlen (line) - 1; - - /* Format is: Local name, stdin/stdout/stderr, peer name, argv idx. */ - snprintf (&line[len], BUFFER_MAX - len, "0x%x %d 0x%x %d \n", - fd_list[i].fd, fd_list[i].dup_to, - fd_list[i].peer_name, fd_list[i].arg_loc); - /* Rather safe than sorry. */ - line[BUFFER_MAX - 1] = '\n'; - line[BUFFER_MAX] = '\0'; - } - len = strlen (line); - written = 0; - do - { - res = write (tmp_fd, &line[written], len - written); - if (res > 0) - written += res; - } - while (res > 0 || (res < 0 && errno == EAGAIN)); - } - close (tmp_fd); - /* The temporary file is deleted by the gpgme-w32spawn process - (hopefully). */ - - TRACE_LOG4 ("CreateProcess ready: hProcess=%p, hThread=%p, " - "dwProcessID=%d, dwThreadId=%d", - pi.hProcess, pi.hThread, - (int) pi.dwProcessId, (int) pi.dwThreadId); - - if (r_pid) - *r_pid = (pid_t)pi.dwProcessId; - - if (ResumeThread (pi.hThread) < 0) - TRACE_LOG1 ("ResumeThread failed: ec=%d", (int) GetLastError ()); - - if (!CloseHandle (pi.hThread)) - TRACE_LOG1 ("CloseHandle of thread failed: ec=%d", - (int) GetLastError ()); - - TRACE_LOG1 ("process=%p", pi.hProcess); - - /* We don't need to wait for the process. */ - if (!CloseHandle (pi.hProcess)) - TRACE_LOG1 ("CloseHandle of process failed: ec=%d", - (int) GetLastError ()); - - for (i = 0; fd_list[i].fd != -1; i++) - _gpgme_io_close (fd_list[i].fd); - - for (i = 0; fd_list[i].fd != -1; i++) - if (fd_list[i].dup_to == -1) - TRACE_LOG3 ("fd[%i] = 0x%x -> 0x%x", i, fd_list[i].fd, - fd_list[i].peer_name); - else - TRACE_LOG4 ("fd[%i] = 0x%x -> 0x%x (std%s)", i, fd_list[i].fd, - fd_list[i].peer_name, (fd_list[i].dup_to == 0) ? "in" : - ((fd_list[i].dup_to == 1) ? "out" : "err")); - - return TRACE_SYSRES (0); -} - - -/* Select on the list of fds. Returns: -1 = error, 0 = timeout or - nothing to select, > 0 = number of signaled fds. */ -int -_gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock) -{ - /* Use a 1s timeout. */ - - void *dbg_help = NULL; - TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_select", fds, - "nfds=%u, nonblock=%u", nfds, nonblock); - - int count = 0; - - TRACE_SEQ (dbg_help, "select on [ "); - for (int i = 0; i < nfds; i++) - { - if (fds[i].fd == -1) - { - fds[i].signaled = 0; - } - else if (fds[i].for_read ) - { - KDPipeIODevice * const chan = find_channel (fds[i].fd, 0); - assert (chan); - if ( nonblock ) - fds[i].signaled = chan->readWouldBlock() ? 0 : 1; - else - fds[i].signaled = chan->waitForReadyRead( 1000 ) ? 1 : 0; - TRACE_ADD1 (dbg_help, "w0x%x ", fds[i].fd); - if ( fds[i].signaled ) - count++; - } - else if (fds[i].for_write) - { - const KDPipeIODevice * const chan = find_channel (fds[i].fd, 0); - assert (chan); - fds[i].signaled = nonblock ? ( chan->writeWouldBlock() ? 0 : 1 ) : 1; - TRACE_ADD1 (dbg_help, "w0x%x ", fds[i].fd); - if ( fds[i].signaled ) - count++; - } - } - TRACE_END (dbg_help, "]"); - - return TRACE_SYSRES (count); -} - - -/* Look up the qiodevice for file descriptor FD. */ -extern "C" -void * -gpgme_get_fdptr (int fd) -{ - return find_channel (fd, 0); -} - - -/* Obsolete compatibility interface. */ -extern "C" -void * -gpgme_get_giochannel (int fd) -{ - return NULL; -} - - -int -_gpgme_io_dup (int fd) -{ - assert( iodevice_table[fd] ); - iodevice_table[fd]->ref(); - return fd; -} - - -extern "C" -int -_gpgme_io_socket (int domain, int type, int proto) -{ - errno = EIO; - return -1; -} - - -extern "C" -int -_gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen) -{ - errno = EIO; - return -1; -}