Remove obsolete w32-qt code
* configure.ac (w32-qt): Remove option and Qt checks. * src/Makefile.am: Remove BUILD_W32_QT handling. * src/kdpipeiodevice.cpp, src/kdpipeiodevice.h, src/kdpipeiodevice.moc, src/w32-qt-io.cpp: Removed. -- This code was intended for Kleopatra but Kleopatra is not using it anymore. QGpgme/dataprovider is a better replacement for this.
This commit is contained in:
parent
a06603d75e
commit
58ed9c17f0
16
configure.ac
16
configure.ac
@ -180,20 +180,9 @@ case "${host}" in
|
|||||||
AC_ARG_ENABLE(w32-glib,
|
AC_ARG_ENABLE(w32-glib,
|
||||||
AC_HELP_STRING([--enable-w32-glib], [build GPGME Glib for W32]),
|
AC_HELP_STRING([--enable-w32-glib], [build GPGME Glib for W32]),
|
||||||
build_w32_glib=$enableval)
|
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)
|
AC_CHECK_LIB(pthread,pthread_create,have_pthread=yes)
|
||||||
if test "$have_pthread" = yes; then
|
if test "$have_pthread" = yes; then
|
||||||
AC_DEFINE(HAVE_PTHREAD, ,[Define if we have pthread.])
|
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(HAVE_ANDROID_SYSTEM, test "$have_android_system" = yes)
|
||||||
|
|
||||||
AM_CONDITIONAL(BUILD_W32_GLIB, test "$build_w32_glib" = 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")
|
AM_CONDITIONAL(HAVE_PTHREAD, test "$have_pthread" = "yes")
|
||||||
|
|
||||||
|
@ -41,12 +41,6 @@ else
|
|||||||
ltlib_gpgme_glib =
|
ltlib_gpgme_glib =
|
||||||
endif
|
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) \
|
lib_LTLIBRARIES = libgpgme.la $(ltlib_gpgme_glib) $(ltlib_gpgme_qt) \
|
||||||
$(ltlib_gpgme_pthread)
|
$(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
|
libgpgme_glib_la_SOURCES = $(main_sources) ath.h ath.c w32-glib-io.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if BUILD_W32_QT
|
# We use a global CFLAGS setting for all library
|
||||||
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
|
|
||||||
# versions, because then every object file is only compiled once.
|
# versions, because then every object file is only compiled once.
|
||||||
AM_CPPFLAGS = @GPG_ERROR_CFLAGS@ @QT4_CORE_CFLAGS@
|
AM_CFLAGS = @LIBASSUAN_CFLAGS@ @GLIB_CFLAGS@
|
||||||
AM_CFLAGS = @LIBASSUAN_CFLAGS@ @GLIB_CFLAGS@ @QT4_CORE_CFLAGS@
|
|
||||||
|
|
||||||
gpgme_tool_SOURCES = gpgme-tool.c argparse.c argparse.h
|
gpgme_tool_SOURCES = gpgme-tool.c argparse.c argparse.h
|
||||||
gpgme_tool_LDADD = libgpgme.la @LIBASSUAN_LIBS@
|
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@
|
@GPG_ERROR_LIBS@ @GLIB_LIBS@
|
||||||
endif
|
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
|
install-data-local: install-def-file
|
||||||
|
|
||||||
uninstall-local: uninstall-def-file
|
uninstall-local: uninstall-def-file
|
||||||
|
@ -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 <QtCore>
|
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
#include <memory>
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
#ifdef Q_OS_WIN32
|
|
||||||
# ifndef NOMINMAX
|
|
||||||
# define NOMINMAX
|
|
||||||
# endif
|
|
||||||
# include <windows.h>
|
|
||||||
# include <io.h>
|
|
||||||
#else
|
|
||||||
# include <unistd.h>
|
|
||||||
# include <errno.h>
|
|
||||||
#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<Private> 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> reader_;
|
|
||||||
std::auto_ptr<Writer> 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<long>(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 <typename T>
|
|
||||||
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<bool> 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<qint64>( 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<int>( 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<long>(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<int>( 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*,KDPipeIODevice*> 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"
|
|
@ -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 <QIODevice>
|
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
//#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<KDPipeIODevice*, KDPipeIODevice*> 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__ */
|
|
||||||
|
|
@ -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 <QObject>."
|
|
||||||
#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<void*>(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<void*>(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<void*>(reinterpret_cast<const void*>(&_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<void*>(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;
|
|
||||||
}
|
|
@ -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 <config.h>
|
|
||||||
#endif
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <windows.h>
|
|
||||||
#include <io.h>
|
|
||||||
|
|
||||||
#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<char *>(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;
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user