io_file.c

Go to the documentation of this file.
00001 /***************************************************************************
00002  $RCSfile$
00003                              -------------------
00004     cvs         : $Id: crypttoken.h 1113 2007-01-10 09:14:16Z martin $
00005     begin       : Wed Mar 16 2005
00006     copyright   : (C) 2005 by Martin Preuss
00007     email       : martin@libchipcard.de
00008 
00009  ***************************************************************************
00010  *          Please see toplevel file COPYING for license details           *
00011  ***************************************************************************/
00012 
00013 #ifdef HAVE_CONFIG_H
00014 # include <config.h>
00015 #endif
00016 
00017 
00018 #include "io_file_p.h"
00019 #include <gwenhywfar/iolayer_be.h>
00020 #include <gwenhywfar/iorequest_be.h>
00021 
00022 #include "i18n_l.h"
00023 #include <gwenhywfar/misc.h>
00024 #include <gwenhywfar/debug.h>
00025 #include <gwenhywfar/gui.h>
00026 
00027 #include <assert.h>
00028 #include <errno.h>
00029 #include <string.h>
00030 #include <unistd.h>
00031 #include <fcntl.h>
00032 
00033 
00034 
00035 
00036 GWEN_INHERIT(GWEN_IO_LAYER, GWEN_IO_LAYER_FILE)
00037 
00038 
00039 
00040 GWEN_IO_LAYER *GWEN_Io_LayerFile_new(int fdRead, int fdWrite) {
00041   GWEN_IO_LAYER *io;
00042   GWEN_IO_LAYER_FILE *xio;
00043 
00044   io=GWEN_Io_Layer_new(GWEN_IO_LAYER_FILE_TYPE, NULL);
00045   assert(io);
00046   GWEN_NEW_OBJECT(GWEN_IO_LAYER_FILE, xio);
00047   assert(xio);
00048   GWEN_INHERIT_SETDATA(GWEN_IO_LAYER, GWEN_IO_LAYER_FILE, io, xio, GWEN_Io_LayerFile_freeData);
00049 
00050   GWEN_Io_Layer_SetWorkOnRequestsFn(io, GWEN_Io_LayerFile_WorkOnRequests);
00051   GWEN_Io_Layer_SetAddRequestFn(io, GWEN_Io_LayerFile_AddRequest);
00052   GWEN_Io_Layer_SetDelRequestFn(io, GWEN_Io_LayerFile_DelRequest);
00053   GWEN_Io_Layer_SetHasWaitingRequestsFn(io, GWEN_Io_LayerFile_HasWaitingRequests);
00054 
00055   xio->fdRead=fdRead;
00056   xio->fdWrite=fdWrite;
00057 
00058 #ifndef OS_WIN32
00059   /* TODO: How can we make a file non-blocking under win32? */
00060   if (fdRead!=-1) {
00061     int rv;
00062     long fl;
00063 
00064     /* get and save previous flags */
00065     xio->readFlags=fcntl(fdRead, F_GETFL);
00066 
00067     /* set new flags (-> nonblocking!) */
00068     fl=xio->readFlags | O_NONBLOCK;
00069     rv=fcntl(fdRead, F_SETFL, fl);
00070     if (rv) {
00071       DBG_ERROR(GWEN_LOGDOMAIN, "fcntl(%d, F_SETFL): %s", fdRead, strerror(errno));
00072       xio->fdRead=-1;
00073     }
00074   }
00075 
00076   if (fdWrite!=-1) {
00077     int rv;
00078     long fl;
00079 
00080     /* get and save previous flags */
00081     xio->writeFlags=fcntl(fdWrite, F_GETFL);
00082 
00083     /* set new flags (-> nonblocking!) */
00084     fl=xio->writeFlags | O_NONBLOCK;
00085     rv=fcntl(fdWrite, F_SETFL, fl);
00086     if (rv) {
00087       DBG_ERROR(GWEN_LOGDOMAIN, "fcntl(%d, F_SETFL): %s", fdWrite, strerror(errno));
00088       xio->fdWrite=-1;
00089     }
00090   }
00091 #endif
00092 
00093   GWEN_Io_Layer_SetStatus(io, GWEN_Io_Layer_StatusConnected);
00094 
00095 
00096   return io;
00097 }
00098 
00099 
00100 
00101 GWENHYWFAR_CB
00102 void GWEN_Io_LayerFile_freeData(void *bp, void *p) {
00103   GWEN_IO_LAYER *io;
00104   GWEN_IO_LAYER_FILE *xio;
00105 
00106   io=(GWEN_IO_LAYER*) bp;
00107   assert(io);
00108   xio=(GWEN_IO_LAYER_FILE*) p;
00109   assert(xio);
00110   if (xio->readRequest) {
00111     GWEN_IO_REQUEST *r;
00112 
00113     r=xio->readRequest;
00114     xio->readRequest=NULL;
00115     GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, GWEN_ERROR_ABORTED);
00116     GWEN_Io_Request_free(r);
00117   }
00118   if (xio->writeRequest) {
00119     GWEN_IO_REQUEST *r;
00120 
00121     r=xio->writeRequest;
00122     xio->writeRequest=NULL;
00123     GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, GWEN_ERROR_ABORTED);
00124     GWEN_Io_Request_free(r);
00125   }
00126   if (xio->fdRead!=-1) {
00127     if (!(GWEN_Io_Layer_GetFlags(io) & GWEN_IO_LAYER_FLAGS_DONTCLOSE))
00128       close(xio->fdRead);
00129   }
00130   if (xio->fdWrite!=-1) {
00131     if (!(GWEN_Io_Layer_GetFlags(io) & GWEN_IO_LAYER_FLAGS_DONTCLOSE))
00132       close(xio->fdWrite);
00133   }
00134   GWEN_FREE_OBJECT(xio);
00135 }
00136 
00137 
00138 
00139 int GWEN_Io_LayerFile_GetReadFileDescriptor(const GWEN_IO_LAYER *io) {
00140   GWEN_IO_LAYER_FILE *xio;
00141 
00142   assert(io);
00143   xio=GWEN_INHERIT_GETDATA(GWEN_IO_LAYER, GWEN_IO_LAYER_FILE, io);
00144   assert(xio);
00145 
00146   return xio->fdRead;
00147 }
00148 
00149 
00150 
00151 int GWEN_Io_LayerFile_GetWriteFileDescriptor(const GWEN_IO_LAYER *io) {
00152   GWEN_IO_LAYER_FILE *xio;
00153 
00154   assert(io);
00155   xio=GWEN_INHERIT_GETDATA(GWEN_IO_LAYER, GWEN_IO_LAYER_FILE, io);
00156   assert(xio);
00157 
00158   return xio->fdWrite;
00159 }
00160 
00161 
00162 
00163 GWEN_IO_LAYER_WORKRESULT GWEN_Io_LayerFile_WorkOnRequests(GWEN_IO_LAYER *io) {
00164   GWEN_IO_LAYER_FILE *xio;
00165   int doneSomething=0;
00166 
00167   assert(io);
00168   xio=GWEN_INHERIT_GETDATA(GWEN_IO_LAYER, GWEN_IO_LAYER_FILE, io);
00169   assert(xio);
00170 
00171   /* work on read request */
00172   if (xio->readRequest) {
00173     ssize_t rv;
00174     ssize_t bytesLeft;
00175     GWEN_IO_REQUEST *r;
00176 
00177     r=xio->readRequest;
00178     bytesLeft=GWEN_Io_Request_GetBufferSize(r)-GWEN_Io_Request_GetBufferPos(r);
00179     rv=read(xio->fdRead,
00180             GWEN_Io_Request_GetBufferPtr(r),
00181             bytesLeft);
00182     if (rv==(ssize_t)-1) {
00183       if (errno!=EAGAIN && errno!=EINTR) {
00184         DBG_INFO(GWEN_LOGDOMAIN, "read(%d): %s", xio->fdRead, strerror(errno));
00185         xio->readRequest=NULL;
00186         GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, GWEN_ERROR_IO);
00187         GWEN_Io_Request_free(r);
00188         doneSomething=1;
00189       }
00190       /* nothing to read, nothing done, so we don't set doneSomething=1 here ! */
00191     }
00192     else if (rv==0) {
00193       /* end of stream reached */
00194       DBG_INFO(GWEN_LOGDOMAIN, "EOF met");
00195       xio->readRequest=NULL;
00196       GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, GWEN_ERROR_EOF);
00197       GWEN_Io_Request_free(r);
00198       doneSomething=1;
00199     }
00200     else {
00201       uint32_t newPos;
00202 
00203       /* some data returned */
00204       newPos=GWEN_Io_Request_GetBufferPos(r)+rv;
00205       GWEN_Io_Request_SetBufferPos(r, newPos);
00206 
00207       if (rv<bytesLeft) {
00208         /* fewer bytes read, is that ok? */
00209         if (!(GWEN_Io_Request_GetFlags(r) & GWEN_IO_REQUEST_FLAGS_READALL)) {
00210           /* it is, return the data we already have */
00211           xio->readRequest=NULL;
00212           GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, 0);
00213           GWEN_Io_Request_free(r);
00214         }
00215         /* otherwise we are forced to read the rest in the next session */
00216       }
00217       else {
00218         /* all data read */
00219         xio->readRequest=NULL;
00220         GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, 0);
00221         GWEN_Io_Request_free(r);
00222       }
00223       doneSomething=1;
00224     }
00225   }
00226 
00227   /* work on write request */
00228   if (xio->writeRequest) {
00229     ssize_t rv;
00230     ssize_t bytesLeft;
00231     GWEN_IO_REQUEST *r;
00232 
00233     r=xio->writeRequest;
00234     bytesLeft=GWEN_Io_Request_GetBufferSize(r)-GWEN_Io_Request_GetBufferPos(r);
00235     rv=write(xio->fdWrite,
00236             GWEN_Io_Request_GetBufferPtr(r),
00237             bytesLeft);
00238     if (rv==(ssize_t)-1) {
00239       if (errno!=EAGAIN && errno!=EINTR) {
00240         DBG_INFO(GWEN_LOGDOMAIN, "write(%d): %s", xio->fdWrite, strerror(errno));
00241         xio->writeRequest=NULL;
00242         GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, GWEN_ERROR_IO);
00243         GWEN_Io_Request_free(r);
00244         doneSomething=1;
00245       }
00246       /* nothing to write, nothing done, so we don't set doneSomething=1 here ! */
00247     }
00248     else {
00249       uint32_t newPos;
00250 
00251       /* some data returned */
00252       newPos=GWEN_Io_Request_GetBufferPos(r)+rv;
00253       GWEN_Io_Request_SetBufferPos(r, newPos);
00254 
00255       if (newPos>=GWEN_Io_Request_GetBufferSize(r) ||
00256           !(GWEN_Io_Request_GetFlags(r) & GWEN_IO_REQUEST_FLAGS_WRITEALL)) {
00257         /* request complete */
00258         xio->writeRequest=NULL;
00259         GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, 0);
00260         GWEN_Io_Request_free(r);
00261       }
00262       doneSomething=1;
00263     }
00264   }
00265 
00266   return (doneSomething==0)?GWEN_Io_Layer_WorkResultBlocking:GWEN_Io_Layer_WorkResultOk;
00267 }
00268 
00269 
00270 
00271 int GWEN_Io_LayerFile_AddRequest(GWEN_IO_LAYER *io, GWEN_IO_REQUEST *r) {
00272   GWEN_IO_LAYER_FILE *xio;
00273   GWEN_IO_LAYER_STATUS st;
00274 
00275   assert(io);
00276   xio=GWEN_INHERIT_GETDATA(GWEN_IO_LAYER, GWEN_IO_LAYER_FILE, io);
00277   assert(xio);
00278 
00279   st=GWEN_Io_Layer_GetStatus(io);
00280 
00281   switch(GWEN_Io_Request_GetType(r)) {
00282   case GWEN_Io_Request_TypeRead:
00283     /* check status */
00284     if (st!=GWEN_Io_Layer_StatusConnected) {
00285       DBG_INFO(GWEN_LOGDOMAIN, "File is not open");
00286       GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, GWEN_ERROR_NOT_OPEN);
00287       return GWEN_ERROR_NOT_OPEN;
00288     }
00289 
00290     /* check whether we already have a read request */
00291     if (xio->readRequest) {
00292       DBG_INFO(GWEN_LOGDOMAIN, "There already is a read request");
00293       return GWEN_ERROR_TRY_AGAIN;
00294     }
00295 
00296     /* check whether the file is open */
00297     if (xio->fdRead==-1) {
00298       DBG_INFO(GWEN_LOGDOMAIN, "File is not open for reading");
00299       GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, GWEN_ERROR_NOT_OPEN);
00300       return GWEN_ERROR_NOT_OPEN;
00301     }
00302 
00303     /* enqueue request */
00304     xio->readRequest=r;
00305     GWEN_Io_Request_Attach(xio->readRequest);
00306     break;
00307 
00308   case GWEN_Io_Request_TypeWrite:
00309     /* check status */
00310     if (st!=GWEN_Io_Layer_StatusConnected) {
00311       DBG_INFO(GWEN_LOGDOMAIN, "File is not open");
00312       GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, GWEN_ERROR_NOT_OPEN);
00313       return GWEN_ERROR_NOT_OPEN;
00314     }
00315 
00316     /* check whether we already have a read request */
00317     if (xio->writeRequest) {
00318       DBG_INFO(GWEN_LOGDOMAIN, "There already is a write request");
00319       return GWEN_ERROR_TRY_AGAIN;
00320     }
00321 
00322     /* check whether the file is open */
00323     if (xio->fdWrite==-1) {
00324       DBG_INFO(GWEN_LOGDOMAIN, "File is not open for writing");
00325       GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, GWEN_ERROR_NOT_OPEN);
00326       return GWEN_ERROR_NOT_OPEN;
00327     }
00328 
00329     /* enqueue request */
00330     xio->writeRequest=r;
00331     GWEN_Io_Request_Attach(xio->writeRequest);
00332     break;
00333 
00334   case GWEN_Io_Request_TypeDisconnect:
00335     /* check status */
00336     if (st!=GWEN_Io_Layer_StatusConnected) {
00337       DBG_INFO(GWEN_LOGDOMAIN, "File is not open");
00338       GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, GWEN_ERROR_NOT_OPEN);
00339       return GWEN_ERROR_NOT_OPEN;
00340     }
00341     else {
00342       int rv=0, rv1=0, rv2=0, rv3=0, rv4=0;
00343 
00344       /* restore old flags */
00345 #ifndef OS_WIN32
00346       if (xio->fdRead!=-1)
00347         rv1=fcntl(xio->fdRead, F_SETFL, xio->readFlags);
00348       if (xio->fdWrite!=-1)
00349         rv2=fcntl(xio->fdWrite, F_SETFL, xio->writeFlags);
00350 #endif
00351 
00352       /* close files if not forbidden */
00353       if (!(GWEN_Io_Layer_GetFlags(io) & GWEN_IO_LAYER_FLAGS_DONTCLOSE)) {
00354         if (xio->fdRead!=-1)
00355           rv3=close(xio->fdRead);
00356         if (xio->fdWrite!=-1 && xio->fdRead!=xio->fdWrite)
00357           rv4=close(xio->fdWrite);
00358 
00359         /* overwrite descriptors */
00360         xio->fdRead=-1;
00361         xio->fdWrite=-1;
00362       }
00363 
00364       /* sample all error codes */
00365       if (rv1) rv=rv1;
00366       if (rv2) rv=rv2;
00367       if (rv3) rv=rv3;
00368       if (rv4) rv=rv4;
00369       if (rv) {
00370         DBG_INFO(GWEN_LOGDOMAIN, "Error closing file: %s", strerror(errno));
00371         GWEN_Io_Layer_SetStatus(io, GWEN_Io_Layer_StatusDisconnected);
00372         GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, rv);
00373         return rv;
00374       }
00375 
00376       /* closed */
00377       GWEN_Io_Layer_SetStatus(io, GWEN_Io_Layer_StatusDisconnected);
00378       GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, 0);
00379     }
00380     break;
00381 
00382   default:
00383     DBG_INFO(GWEN_LOGDOMAIN, "This request type is not supported (%d)", GWEN_Io_Request_GetType(r));
00384     GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, GWEN_ERROR_NOT_SUPPORTED);
00385     return GWEN_ERROR_NOT_SUPPORTED;
00386   }
00387 
00388   return 0;
00389 }
00390 
00391 
00392 
00393 int GWEN_Io_LayerFile_DelRequest(GWEN_IO_LAYER *io, GWEN_IO_REQUEST *r) {
00394   GWEN_IO_LAYER_FILE *xio;
00395 
00396   assert(io);
00397   xio=GWEN_INHERIT_GETDATA(GWEN_IO_LAYER, GWEN_IO_LAYER_FILE, io);
00398   assert(xio);
00399 
00400   switch(GWEN_Io_Request_GetType(r)) {
00401   case GWEN_Io_Request_TypeRead:
00402     if (xio->readRequest==r) {
00403       DBG_DEBUG(GWEN_LOGDOMAIN, "Aborted read request");
00404       GWEN_Io_Request_Finished(xio->readRequest, GWEN_Io_Request_StatusFinished, GWEN_ERROR_ABORTED);
00405       GWEN_Io_Request_free(xio->readRequest);
00406       xio->readRequest=NULL;
00407     }
00408     else {
00409       /* not my request */
00410       DBG_INFO(GWEN_LOGDOMAIN, "Read request not registered with this io layer");
00411       return GWEN_ERROR_INVALID;
00412     }
00413     break;
00414 
00415   case GWEN_Io_Request_TypeWrite:
00416     if (xio->writeRequest==r) {
00417       DBG_DEBUG(GWEN_LOGDOMAIN, "Aborted write request");
00418       GWEN_Io_Request_Finished(xio->writeRequest, GWEN_Io_Request_StatusFinished, GWEN_ERROR_ABORTED);
00419       GWEN_Io_Request_free(xio->writeRequest);
00420       xio->writeRequest=NULL;
00421     }
00422     else {
00423       /* not my request */
00424       DBG_INFO(GWEN_LOGDOMAIN, "Write request not registered with this io layer");
00425       return GWEN_ERROR_INVALID;
00426     }
00427     break;
00428 
00429   default:
00430     break;
00431   }
00432 
00433   return 0;
00434 }
00435 
00436 
00437 
00438 int GWEN_Io_LayerFile_HasWaitingRequests(GWEN_IO_LAYER *io) {
00439   GWEN_IO_LAYER_FILE *xio;
00440 
00441   assert(io);
00442   xio=GWEN_INHERIT_GETDATA(GWEN_IO_LAYER, GWEN_IO_LAYER_FILE, io);
00443   assert(xio);
00444 
00445   if (xio->readRequest || xio->writeRequest)
00446     return 1;
00447   else
00448     return 0;
00449 }
00450 
00451 
00452 
00453 
00454 
00455 
00456 
00457 
00458 
00459 
00460 
00461 
00462 
00463 
Generated on Mon Jul 5 22:51:13 2010 for gwenhywfar by  doxygen 1.6.3