dbrw.c

Go to the documentation of this file.
00001 /***************************************************************************
00002  $RCSfile$
00003  -------------------
00004  cvs         : $Id: db.c 1231 2007-06-12 01:54:15Z martin $
00005  begin       : Tue Sep 09 2003
00006  copyright   : (C) 2003 by Martin Preuss
00007  email       : martin@libchipcard.de
00008 
00009  ***************************************************************************
00010  *                                                                         *
00011  *   This library is free software; you can redistribute it and/or         *
00012  *   modify it under the terms of the GNU Lesser General Public            *
00013  *   License as published by the Free Software Foundation; either          *
00014  *   version 2.1 of the License, or (at your option) any later version.    *
00015  *                                                                         *
00016  *   This library is distributed in the hope that it will be useful,       *
00017  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00018  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00019  *   Lesser General Public License for more details.                       *
00020  *                                                                         *
00021  *   You should have received a copy of the GNU Lesser General Public      *
00022  *   License along with this library; if not, write to the Free Software   *
00023  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston,                 *
00024  *   MA  02111-1307  USA                                                   *
00025  *                                                                         *
00026  ***************************************************************************/
00027 
00028 
00029 /* This file is included from db.c */
00030 
00031 
00032 
00033 int GWEN_DB_EscapeToBufferTolerant(const char *src, GWEN_BUFFER *buf) {
00034   while(*src) {
00035     unsigned char x;
00036 
00037     x=(unsigned char)*src;
00038     if (!(
00039           (x>='A' && x<='Z') ||
00040           (x>='a' && x<='z') ||
00041           (x>='0' && x<='9') ||
00042           x=='%' ||
00043           x=='.' ||
00044           x==',' ||
00045           x=='.' ||
00046           x=='_' ||
00047           x=='-' ||
00048           x=='*' ||
00049           x=='?'
00050          )) {
00051       unsigned char c;
00052 
00053       GWEN_Buffer_AppendByte(buf, '&');
00054       c=(((unsigned char)(*src))>>4)&0xf;
00055       if (c>9)
00056         c+=7;
00057       c+='0';
00058       GWEN_Buffer_AppendByte(buf, c);
00059       c=((unsigned char)(*src))&0xf;
00060       if (c>9)
00061         c+=7;
00062       c+='0';
00063       GWEN_Buffer_AppendByte(buf, c);
00064     }
00065     else
00066       GWEN_Buffer_AppendByte(buf, *src);
00067 
00068     src++;
00069   } /* while */
00070 
00071   return 0;
00072 }
00073 
00074 
00075 
00076 int GWEN_DB_UnescapeToBufferTolerant(const char *src, GWEN_BUFFER *buf) {
00077   while(*src) {
00078     const char *srcBak;
00079     int charHandled;
00080 
00081     srcBak=src;
00082     charHandled=0;
00083     if (*src=='&') {
00084       if (strlen(src)>2) {
00085         unsigned char d1, d2;
00086         unsigned char c;
00087 
00088         if (isxdigit((int)src[1]) && isxdigit((int)src[2])) {
00089           /* skip '%' */
00090           src++;
00091           /* read first digit */
00092           d1=(unsigned char)(toupper(*src));
00093 
00094           /* get second digit */
00095           src++;
00096           d2=(unsigned char)(toupper(*src));
00097           /* compute character */
00098           d1-='0';
00099           if (d1>9)
00100             d1-=7;
00101           c=(d1<<4)&0xf0;
00102           d2-='0';
00103           if (d2>9)
00104             d2-=7;
00105           c+=(d2&0xf);
00106           /* store character */
00107           GWEN_Buffer_AppendByte(buf, (char)c);
00108           charHandled=1;
00109         }
00110       }
00111     }
00112     if (!charHandled)
00113       GWEN_Buffer_AppendByte(buf, *src);
00114     src++;
00115   } /* while */
00116 
00117   return 0;
00118 }
00119 
00120 
00121 
00122 
00123 
00124 
00125 int GWEN_DB_ReadFileAs(GWEN_DB_NODE *db,
00126                        const char *fname,
00127                        const char *type,
00128                        GWEN_DB_NODE *params,
00129                        uint32_t dbflags,
00130                        uint32_t guiid,
00131                        int msecs){
00132   GWEN_IO_LAYER *io;
00133   GWEN_DBIO *dbio;
00134   int fd;
00135   int rv;
00136 
00137   dbio=GWEN_DBIO_GetPlugin(type);
00138   if (!dbio) {
00139     DBG_ERROR(GWEN_LOGDOMAIN, "Plugin \"%s\" is not supported", type);
00140     return GWEN_ERROR_NOT_SUPPORTED;
00141   }
00142 
00143   fd=open(fname, O_RDONLY);
00144   if (fd==-1) {
00145     DBG_ERROR(GWEN_LOGDOMAIN, "open(%s, O_RDONLY): %s", fname, strerror(errno));
00146     return GWEN_ERROR_IO;
00147   }
00148 
00149   /* create io layer for this file (readonly) */
00150   io=GWEN_Io_LayerFile_new(fd, -1);
00151   assert(io);
00152 
00153   rv=GWEN_Io_Manager_RegisterLayer(io);
00154   if (rv) {
00155     DBG_ERROR(GWEN_LOGDOMAIN, "Internal error: Could not register io layer (%d)", rv);
00156     GWEN_Io_Layer_DisconnectRecursively(io, NULL, GWEN_IO_REQUEST_FLAGS_FORCE, guiid, msecs);
00157     GWEN_Io_Layer_free(io);
00158     return rv;
00159   }
00160 
00161   rv=GWEN_DBIO_Import(dbio, io, db, params, dbflags, guiid, msecs);
00162   if (rv) {
00163     DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00164   }
00165   GWEN_Io_Layer_DisconnectRecursively(io, NULL, GWEN_IO_REQUEST_FLAGS_FORCE, guiid, msecs);
00166   GWEN_Io_Layer_free(io);
00167 
00168   return rv;
00169 }
00170 
00171 
00172 
00173 int GWEN_DB_WriteFileAs(GWEN_DB_NODE *db,
00174                         const char *fname,
00175                         const char *type,
00176                         GWEN_DB_NODE *params,
00177                         uint32_t dbflags,
00178                         uint32_t guiid,
00179                         int msecs){
00180   int rv;
00181   GWEN_DBIO *dbio;
00182 
00183   dbio=GWEN_DBIO_GetPlugin(type);
00184   if (!dbio) {
00185     DBG_ERROR(GWEN_LOGDOMAIN, "Plugin \"%s\" is not supported", type);
00186     return GWEN_ERROR_NOT_SUPPORTED;
00187   }
00188 
00189   rv=GWEN_DBIO_ExportToFile(dbio, fname, db, params, dbflags, guiid, msecs);
00190   if (rv) {
00191     DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00192     return rv;
00193   }
00194 
00195   return 0;
00196 }
00197 
00198 
00199 
00200 int GWEN_DB_WriteGroupToIoLayer(GWEN_DB_NODE *node,
00201                                 GWEN_FAST_BUFFER *fb,
00202                                 uint32_t dbflags,
00203                                 int insert) {
00204   GWEN_DB_NODE *n;
00205   GWEN_DB_NODE *cn;
00206   int i;
00207   int err;
00208   int lastWasVar;
00209 
00210   lastWasVar=0;
00211 
00212   n=GWEN_DB_Node_List_First(node->children);
00213   while(n) {
00214     if (!(n->nodeFlags & GWEN_DB_NODE_FLAGS_VOLATILE)) {
00215       DBG_VERBOUS(GWEN_LOGDOMAIN, "Writing node");
00216       switch(n->typ) {
00217       case GWEN_DB_NodeType_Group:
00218         if (dbflags & GWEN_DB_FLAGS_WRITE_SUBGROUPS) {
00219           GWEN_BUFFER *tbuf;
00220 
00221           if (dbflags & GWEN_DB_FLAGS_ADD_GROUP_NEWLINES) {
00222             if (lastWasVar) {
00223               /* only insert newline if the last one before this group was a
00224                * variable */
00225               GWEN_FASTBUFFER_WRITELINE(fb, err, "");
00226               if (err<0) {
00227                 DBG_INFO(GWEN_LOGDOMAIN, "called from here");
00228                 return err;
00229               }
00230             }
00231           }
00232 
00233           /* indend */
00234           if (dbflags & GWEN_DB_FLAGS_INDEND) {
00235             for (i=0; i<insert; i++) {
00236               GWEN_FASTBUFFER_WRITEBYTE(fb, err, ' ');
00237               if (err<0) {
00238                 DBG_INFO(GWEN_LOGDOMAIN, "called from here");
00239                 return err;
00240               }
00241             } /* for */
00242           } /* if indend */
00243 
00244           tbuf=GWEN_Buffer_new(0, 128, 0, 1);
00245           err=GWEN_DB_EscapeToBufferTolerant(n->data.dataName, tbuf);
00246           if (err<0) {
00247             DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", err);
00248             GWEN_Buffer_free(tbuf);
00249             return err;
00250           }
00251 
00252           GWEN_FASTBUFFER_WRITEFORCED(fb, err,
00253                                       GWEN_Buffer_GetStart(tbuf),
00254                                       GWEN_Buffer_GetUsedBytes(tbuf));
00255           GWEN_Buffer_free(tbuf);
00256           if (err<0) {
00257             DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", err);
00258             return err;
00259           }
00260           GWEN_FASTBUFFER_WRITELINE(fb, err, " {");
00261           if (err<0) {
00262             DBG_INFO(GWEN_LOGDOMAIN, "called from here");
00263             return err;
00264           }
00265           err=GWEN_DB_WriteGroupToIoLayer(n, fb, dbflags, insert+2);
00266           if (err<0)
00267             return err;
00268 
00269           /* indend */
00270           if (dbflags & GWEN_DB_FLAGS_INDEND) {
00271             for (i=0; i<insert; i++) {
00272               GWEN_FASTBUFFER_WRITEBYTE(fb, err, ' ');
00273               if (err<0) {
00274                 DBG_INFO(GWEN_LOGDOMAIN, "called from here");
00275                 return err;
00276               }
00277             } /* for */
00278           } /* if indend */
00279 
00280           if (dbflags & GWEN_DB_FLAGS_DETAILED_GROUPS) {
00281             GWEN_FASTBUFFER_WRITEFORCED(fb, err, "} #", -1);
00282             if (err<0) {
00283               DBG_INFO(GWEN_LOGDOMAIN, "called from here");
00284               return err;
00285             }
00286             GWEN_FASTBUFFER_WRITELINE(fb, err, n->data.dataName);
00287             if (err<0) {
00288               DBG_INFO(GWEN_LOGDOMAIN, "called from here");
00289               return err;
00290             }
00291           } /* if detailed groups */
00292           else {
00293             GWEN_FASTBUFFER_WRITELINE(fb, err, "}");
00294             if (err<0) {
00295               DBG_INFO(GWEN_LOGDOMAIN, "called from here");
00296               return err;
00297             }
00298           }
00299           if (dbflags & GWEN_DB_FLAGS_ADD_GROUP_NEWLINES) {
00300             if (GWEN_DB_Node_List_Next(n)) {
00301               /* only insert newline if something
00302                * is following on the same level */
00303               GWEN_FASTBUFFER_WRITELINE(fb, err, "");
00304               if (err<0) {
00305                 DBG_INFO(GWEN_LOGDOMAIN, "called from here");
00306                 return err;
00307               }
00308             }
00309           }
00310         }
00311         lastWasVar=0;
00312         break;
00313 
00314       case GWEN_DB_NodeType_Var:
00315         cn=GWEN_DB_Node_List_First(n->children);
00316         if (cn) {
00317           char *typname;
00318           int namewritten;
00319           int values;
00320 
00321           typname=0;
00322           namewritten=0;
00323           values=0;
00324           while(cn) {
00325             char numbuffer[32];
00326             char *binbuffer=NULL;
00327             unsigned int bbsize;
00328             const char *pvalue=NULL;
00329             GWEN_BUFFER *vbuf=NULL;
00330 
00331             switch(cn->typ) {
00332             case GWEN_DB_NodeType_ValueChar:
00333               typname="char ";
00334               pvalue=cn->data.dataChar;
00335               if (dbflags & GWEN_DB_FLAGS_ESCAPE_CHARVALUES) {
00336                 vbuf=GWEN_Buffer_new(0, strlen(pvalue)+32, 0, 1);
00337                 if (GWEN_Text_EscapeToBufferTolerant(pvalue, vbuf)) {
00338                   DBG_INFO(GWEN_LOGDOMAIN, "called from here");
00339                   GWEN_Buffer_free(vbuf);
00340                   return 1;
00341                 }
00342                 pvalue=GWEN_Buffer_GetStart(vbuf);
00343               }
00344               break;
00345 
00346             case GWEN_DB_NodeType_ValueInt:
00347               typname="int  ";
00348               if (GWEN_Text_NumToString(cn->data.dataInt,
00349                                         numbuffer,
00350                                         sizeof(numbuffer)-1,
00351                                         0)<1) {
00352                 DBG_ERROR(GWEN_LOGDOMAIN, "Error writing numeric value");
00353                 return GWEN_ERROR_GENERIC;
00354               }
00355               pvalue=numbuffer;
00356               break;
00357 
00358             case GWEN_DB_NodeType_ValueBin:
00359               bbsize=cn->dataSize*2+1;
00360               binbuffer=(char*)GWEN_Memory_malloc(bbsize);
00361               assert(binbuffer);
00362               typname="bin  ";
00363               if (!GWEN_Text_ToHex(cn->data.dataBin,
00364                                    cn->dataSize,
00365                                    binbuffer,
00366                                    bbsize)) {
00367                 DBG_ERROR(GWEN_LOGDOMAIN, "Error writing binary value");
00368                 return GWEN_ERROR_GENERIC;
00369               }
00370               pvalue=binbuffer;
00371               break;
00372 
00373             case GWEN_DB_NodeType_ValuePtr:
00374               DBG_DEBUG(GWEN_LOGDOMAIN, "Not writing ptr type");
00375               break;
00376 
00377             default:
00378               DBG_DEBUG(GWEN_LOGDOMAIN, "Unhandled type [%d]", cn->typ);
00379               break;
00380             }
00381 
00382             if (pvalue) {
00383               if (!namewritten) {
00384                 /* write name */
00385                 /* indend */
00386                 if (dbflags & GWEN_DB_FLAGS_INDEND) {
00387                   for (i=0; i<insert; i++) {
00388                     GWEN_FASTBUFFER_WRITEBYTE(fb, err, ' ');
00389                     if (err<0) {
00390                       DBG_INFO(GWEN_LOGDOMAIN, "called from here");
00391                       GWEN_Memory_dealloc(binbuffer);
00392                       GWEN_Buffer_free(vbuf);
00393                       return 1;
00394                     }
00395                   } /* for */
00396                 } /* if indend */
00397                 if (!(dbflags & GWEN_DB_FLAGS_OMIT_TYPES)) {
00398                   GWEN_FASTBUFFER_WRITEFORCED(fb, err, typname, -1);
00399                   if (err<0) {
00400                     DBG_INFO(GWEN_LOGDOMAIN, "called from here");
00401                     GWEN_Memory_dealloc(binbuffer);
00402                     GWEN_Buffer_free(vbuf);
00403                     return 1;
00404                   }
00405                 }
00406                 if (dbflags & GWEN_DB_FLAGS_QUOTE_VARNAMES) {
00407                   GWEN_FASTBUFFER_WRITEBYTE(fb, err, '\"');
00408                   if (err<0) {
00409                     DBG_INFO(GWEN_LOGDOMAIN, "called from here");
00410                     GWEN_Memory_dealloc(binbuffer);
00411                     GWEN_Buffer_free(vbuf);
00412                     return 1;
00413                   }
00414                 }
00415                 GWEN_FASTBUFFER_WRITEFORCED(fb, err, n->data.dataName, -1);
00416                 if (err<0) {
00417                   DBG_INFO(GWEN_LOGDOMAIN, "called from here");
00418                   GWEN_Memory_dealloc(binbuffer);
00419                   GWEN_Buffer_free(vbuf);
00420                   return 1;
00421                 }
00422                 if (dbflags & GWEN_DB_FLAGS_QUOTE_VARNAMES) {
00423                   GWEN_FASTBUFFER_WRITEBYTE(fb, err, '\"');
00424                   if (err<0) {
00425                     DBG_INFO(GWEN_LOGDOMAIN, "called from here");
00426                     GWEN_Memory_dealloc(binbuffer);
00427                     GWEN_Buffer_free(vbuf);
00428                     return 1;
00429                   }
00430                 }
00431                 GWEN_FASTBUFFER_WRITEFORCED(fb, err, ((dbflags & GWEN_DB_FLAGS_USE_COLON)?": ":"="), -1);
00432                 if (err<0) {
00433                   DBG_INFO(GWEN_LOGDOMAIN, "called from here");
00434                   GWEN_Memory_dealloc(binbuffer);
00435                   GWEN_Buffer_free(vbuf);
00436                   return 1;
00437                 }
00438                 namewritten=1;
00439               } /* if !namewritten */
00440 
00441               if (values) {
00442                 GWEN_FASTBUFFER_WRITEFORCED(fb, err, ", ", -1);
00443                 if (err<0) {
00444                   DBG_INFO(GWEN_LOGDOMAIN, "called from here");
00445                   GWEN_Memory_dealloc(binbuffer);
00446                   GWEN_Buffer_free(vbuf);
00447                   return 1;
00448                 }
00449               }
00450               values++;
00451               if (dbflags & GWEN_DB_FLAGS_QUOTE_VALUES) {
00452                 GWEN_FASTBUFFER_WRITEBYTE(fb, err, '\"');
00453                 if (err<0) {
00454                   DBG_INFO(GWEN_LOGDOMAIN, "called from here");
00455                   GWEN_Memory_dealloc(binbuffer);
00456                   GWEN_Buffer_free(vbuf);
00457                   return 1;
00458                 }
00459               }
00460 
00461               GWEN_FASTBUFFER_WRITEFORCED(fb, err, pvalue, -1);
00462               if (err<0) {
00463                 DBG_INFO(GWEN_LOGDOMAIN, "called from here");
00464                 GWEN_Memory_dealloc(binbuffer);
00465                 GWEN_Buffer_free(vbuf);
00466                 return 1;
00467               }
00468 
00469               if (dbflags & GWEN_DB_FLAGS_QUOTE_VALUES) {
00470                 GWEN_FASTBUFFER_WRITEBYTE(fb, err, '\"');
00471                 if (err<0) {
00472                   DBG_INFO(GWEN_LOGDOMAIN, "called from here");
00473                   GWEN_Memory_dealloc(binbuffer);
00474                   GWEN_Buffer_free(vbuf);
00475                   return 1;
00476                 }
00477               }
00478             } /* if pvalue */
00479 
00480             GWEN_Memory_dealloc(binbuffer);
00481             GWEN_Buffer_free(vbuf);
00482             cn=GWEN_DB_Node_List_Next(cn);
00483           } /* while cn */
00484 
00485           if (namewritten) {
00486             GWEN_FASTBUFFER_WRITELINE(fb, err, "");
00487             if (err<0) {
00488               DBG_INFO(GWEN_LOGDOMAIN, "called from here");
00489               return GWEN_ERROR_GENERIC;
00490             }
00491           }
00492         } /* if children */
00493         lastWasVar=1;
00494         break;
00495 
00496       default:
00497         DBG_WARN(GWEN_LOGDOMAIN, "[unhandled node type %d]", n->typ);
00498       } /* switch */
00499     } /* if not volatile */
00500     else {
00501       DBG_DEBUG(GWEN_LOGDOMAIN, "Node is volatile, not writing it");
00502     }
00503     n=GWEN_DB_Node_List_Next(n);
00504   } /* while */
00505 
00506   return 0;
00507 }
00508 
00509 
00510 
00511 int GWEN_DB_WriteToFastBuffer(GWEN_DB_NODE *node,
00512                               GWEN_FAST_BUFFER *fb,
00513                               uint32_t dbflags) {
00514   int rv;
00515 
00516   rv=GWEN_DB_WriteGroupToIoLayer(node, fb, dbflags, 0);
00517   if (rv<0) {
00518     return rv;
00519   }
00520   GWEN_FASTBUFFER_FLUSH(fb, rv);
00521   return rv;
00522 }
00523 
00524 
00525 
00526 int GWEN_DB_WriteToIo(GWEN_DB_NODE *node,
00527                       GWEN_IO_LAYER *io,
00528                       uint32_t dbflags,
00529                       uint32_t guiid,
00530                       int msecs) {
00531   int rv;
00532   GWEN_FAST_BUFFER *fb;
00533 
00534   fb=GWEN_FastBuffer_new(512, io, guiid, msecs);
00535   if (dbflags & GWEN_DB_FLAGS_DOSMODE)
00536     GWEN_FastBuffer_AddFlags(fb, GWEN_FAST_BUFFER_FLAGS_DOSMODE);
00537   rv=GWEN_DB_WriteGroupToIoLayer(node, fb, dbflags, 0);
00538   if (rv<0) {
00539     GWEN_FastBuffer_free(fb);
00540     return rv;
00541   }
00542   GWEN_FASTBUFFER_FLUSH(fb, rv);
00543   GWEN_FastBuffer_free(fb);
00544   return rv;
00545 }
00546 
00547 
00548 
00549 int GWEN_DB_WriteToFd(GWEN_DB_NODE *n, int fd, uint32_t dbflags, uint32_t guiid, int msecs){
00550   GWEN_IO_LAYER *io;
00551   int rv;
00552 
00553   /* create io layer for this file */
00554   io=GWEN_Io_LayerFile_new(-1, fd);
00555   assert(io);
00556   GWEN_Io_Layer_AddFlags(io, GWEN_IO_LAYER_FLAGS_DONTCLOSE);
00557 
00558   rv=GWEN_Io_Manager_RegisterLayer(io);
00559   if (rv) {
00560     DBG_ERROR(GWEN_LOGDOMAIN, "Internal error: Could not register io layer (%d)", rv);
00561     GWEN_Io_Layer_DisconnectRecursively(io, NULL, GWEN_IO_REQUEST_FLAGS_FORCE, guiid, msecs);
00562     GWEN_Io_Layer_free(io);
00563     return rv;
00564   }
00565 
00566   /* write to file */
00567   rv=GWEN_DB_WriteToIo(n, io, dbflags, guiid, msecs);
00568   if (rv<0) {
00569     DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00570     GWEN_Io_Layer_Disconnect(io, GWEN_IO_REQUEST_FLAGS_FORCE, guiid, 1000);
00571     GWEN_Io_Layer_free(io);
00572     return rv;
00573   }
00574 
00575   /* close io layer */
00576   rv=GWEN_Io_Layer_DisconnectRecursively(io, NULL, 0, guiid, 30000);
00577   if (rv<0) {
00578     DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00579     GWEN_Io_Layer_Disconnect(io, GWEN_IO_REQUEST_FLAGS_FORCE, guiid, 1000);
00580     GWEN_Io_Layer_free(io);
00581     return rv;
00582   }
00583 
00584   GWEN_Io_Layer_free(io);
00585 
00586   return 0;
00587 }
00588 
00589 
00590 
00591 int GWEN_DB_WriteFile(GWEN_DB_NODE *n, const char *fname, uint32_t dbflags, uint32_t guiid, int msecs){
00592   int fd;
00593   int rv;
00594   GWEN_FSLOCK *lck=0;
00595 
00596   /* if locking requested */
00597   if (dbflags & GWEN_DB_FLAGS_LOCKFILE) {
00598     GWEN_FSLOCK_RESULT res;
00599 
00600     lck=GWEN_FSLock_new(fname, GWEN_FSLock_TypeFile);
00601     assert(lck);
00602     res=GWEN_FSLock_Lock(lck, GWEN_DB_DEFAULT_LOCK_TIMEOUT, 0);
00603     if (res!=GWEN_FSLock_ResultOk) {
00604       DBG_ERROR(GWEN_LOGDOMAIN,
00605                 "Could not apply lock to file \"%s\" (%d)",
00606                 fname, res);
00607       GWEN_FSLock_free(lck);
00608       return -1;
00609     }
00610   }
00611 
00612   /* open file */
00613   if (dbflags & GWEN_DB_FLAGS_APPEND_FILE)
00614     fd=open(fname, O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
00615   else
00616     fd=open(fname, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
00617   if (fd==-1) {
00618     DBG_ERROR(GWEN_LOGDOMAIN, "Error opening file \"%s\": %s",
00619               fname,
00620               strerror(errno));
00621     if (lck) {
00622       GWEN_FSLock_Unlock(lck);
00623       GWEN_FSLock_free(lck);
00624     }
00625     return GWEN_ERROR_IO;
00626   }
00627 
00628   rv=GWEN_DB_WriteToFd(n, fd, dbflags, guiid, msecs);
00629   if (rv<0) {
00630     DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00631     close(fd);
00632     if (lck) {
00633       GWEN_FSLock_Unlock(lck);
00634       GWEN_FSLock_free(lck);
00635     }
00636     return rv;
00637   }
00638 
00639   if (close(fd)) {
00640     DBG_ERROR(GWEN_LOGDOMAIN, "Error closing file \"%s\": %s",
00641               fname,
00642               strerror(errno));
00643     if (lck) {
00644       GWEN_FSLock_Unlock(lck);
00645       GWEN_FSLock_free(lck);
00646     }
00647     return GWEN_ERROR_IO;
00648   }
00649 
00650   /* remove lock, if any */
00651   if (lck) {
00652     GWEN_FSLOCK_RESULT res;
00653 
00654     res=GWEN_FSLock_Unlock(lck);
00655     if (res!=GWEN_FSLock_ResultOk) {
00656       DBG_WARN(GWEN_LOGDOMAIN,
00657                "Could not remove lock on file \"%s\" (%d)",
00658                fname, res);
00659     }
00660     GWEN_FSLock_free(lck);
00661   }
00662 
00663   return 0;
00664 }
00665 
00666 
00667 
00668 int GWEN_DB__ReadValues(GWEN_DB_NODE *n,
00669                         uint32_t dbflags,
00670                         const char *typeName,
00671                         const char *varName,
00672                         uint8_t *p) {
00673   GWEN_DB_NODE_TYPE nodeType=GWEN_DB_NodeType_ValueChar;
00674   GWEN_DB_NODE *dbVar;
00675   GWEN_BUFFER *wbuf;
00676   uint8_t *pDebug;
00677 
00678   pDebug=p;
00679 
00680   if (typeName==NULL)
00681     typeName="char";
00682   if (strcasecmp(typeName, "int")==0)
00683     nodeType=GWEN_DB_NodeType_ValueInt;
00684   else if (strcasecmp(typeName, "char")==0)
00685     nodeType=GWEN_DB_NodeType_ValueChar;
00686   else if (strcasecmp(typeName, "bin")==0)
00687     nodeType=GWEN_DB_NodeType_ValueBin;
00688   else {
00689     DBG_ERROR(GWEN_LOGDOMAIN, "Unknown type \"%s\"", typeName);
00690     return GWEN_ERROR_BAD_DATA;
00691   }
00692 
00693   dbVar=GWEN_DB_GetNode(n, varName, dbflags | GWEN_PATH_FLAGS_VARIABLE);
00694   if (dbVar==NULL) {
00695     DBG_INFO(GWEN_LOGDOMAIN, "Variable [%s] is not available", varName);
00696     return GWEN_ERROR_GENERIC;
00697   }
00698 
00699   wbuf=GWEN_Buffer_new(0, 32, 0, 1);
00700   for (;;) {
00701     int quotes=0;
00702     GWEN_DB_NODE *dbVal=NULL;
00703     const char *v;
00704 
00705     while(*p && isspace(*p))
00706       p++;
00707     if (!*p) {
00708       DBG_INFO(GWEN_LOGDOMAIN, "Missing value");
00709       GWEN_Buffer_free(wbuf);
00710       return GWEN_ERROR_BAD_DATA;
00711     }
00712 
00713     if (*p=='"') {
00714       quotes=1;
00715       p++;
00716     }
00717 
00718     while(*p) {
00719       if (*p=='%') {
00720         uint8_t c;
00721         uint8_t cHex;
00722 
00723         /* get first nibble */
00724         p++;
00725         if (!*p) {
00726           DBG_INFO(GWEN_LOGDOMAIN, "Incomplete escape sequence");
00727           GWEN_Buffer_free(wbuf);
00728           return GWEN_ERROR_BAD_DATA;
00729         }
00730         c=toupper(*p)-'0';
00731         if (c>9) c-=7;
00732         cHex=c<<4;
00733 
00734         p++;
00735         if (!*p) {
00736           DBG_INFO(GWEN_LOGDOMAIN, "Incomplete escape sequence");
00737           GWEN_Buffer_free(wbuf);
00738           return GWEN_ERROR_BAD_DATA;
00739         }
00740         c=toupper(*p)-'0';
00741         if (c>9) c-=7;
00742         cHex|=c;
00743         GWEN_Buffer_AppendByte(wbuf, cHex);
00744       }
00745       else
00746         if (quotes) {
00747           if (*p=='"') {
00748             p++;
00749             break;
00750           }
00751           else
00752             GWEN_Buffer_AppendByte(wbuf, *p);
00753         }
00754         else {
00755           if (*p==',' || *p==';' || *p=='#')
00756             break;
00757           else if (*p=='"') {
00758             DBG_INFO(GWEN_LOGDOMAIN, "Unexpected quotation mark (Line: [%s], parsed: [%s]",
00759                      pDebug, GWEN_Buffer_GetStart(wbuf));
00760             GWEN_Buffer_free(wbuf);
00761             return GWEN_ERROR_BAD_DATA;
00762           }
00763           else
00764             GWEN_Buffer_AppendByte(wbuf, *p);
00765         }
00766       p++;
00767     }
00768 
00769     v=GWEN_Buffer_GetStart(wbuf);
00770     if (nodeType==GWEN_DB_NodeType_ValueInt) {
00771       int i;
00772 
00773       if (1!=sscanf(v, "%d", &i)) {
00774         DBG_INFO(GWEN_LOGDOMAIN, "Not an integer value [%s]", v);
00775         GWEN_Buffer_free(wbuf);
00776         return GWEN_ERROR_BAD_DATA;
00777       }
00778       dbVal=GWEN_DB_ValueInt_new(i);
00779     }
00780     else if (nodeType==GWEN_DB_NodeType_ValueChar)
00781       dbVal=GWEN_DB_ValueChar_new(v);
00782     else if (nodeType==GWEN_DB_NodeType_ValueBin) {
00783       GWEN_BUFFER *bbuf;
00784       int rv;
00785 
00786       bbuf=GWEN_Buffer_new(0, (GWEN_Buffer_GetUsedBytes(wbuf)/2)+1, 0, 1);
00787       rv=GWEN_Text_FromHexBuffer(v, bbuf);
00788       if (rv) {
00789         DBG_INFO(GWEN_LOGDOMAIN, "Bad bin value [%s]", v);
00790         GWEN_Buffer_free(bbuf);
00791         GWEN_Buffer_free(wbuf);
00792         return GWEN_ERROR_BAD_DATA;
00793       }
00794       dbVal=GWEN_DB_ValueBin_new(GWEN_Buffer_GetStart(bbuf),
00795                                  GWEN_Buffer_GetUsedBytes(bbuf));
00796       GWEN_Buffer_free(bbuf);
00797     }
00798     else {
00799       /* should never reach this point */
00800       assert(0);
00801     }
00802     GWEN_DB_Node_Append(dbVar, dbVal);
00803 
00804     /* skip blanks if any */
00805     while(*p && isspace(*p))
00806       p++;
00807     if (!*p || *p==';' || *p=='#')
00808       break;
00809     else if (*p!=',') {
00810       DBG_INFO(GWEN_LOGDOMAIN, "Unexpected character [%s]", p);
00811       GWEN_Buffer_free(wbuf);
00812       return GWEN_ERROR_BAD_DATA;
00813     }
00814     p++;
00815     GWEN_Buffer_Reset(wbuf);
00816   }
00817 
00818   GWEN_Buffer_free(wbuf);
00819   return 0;
00820 }
00821 
00822 
00823 
00824 int GWEN_DB_ReadFromFastBuffer(GWEN_DB_NODE *n,
00825                                GWEN_FAST_BUFFER *fb,
00826                                uint32_t dbflags) {
00827   GWEN_BUFFER *lbuf;
00828   GWEN_BUFFER *tbuf;
00829   int level=0;
00830   int someLinesRead=0;
00831 
00832   lbuf=GWEN_Buffer_new(0, 128, 0, 1);
00833   tbuf=GWEN_Buffer_new(0, 128, 0, 1);
00834 
00835   for (;;) {
00836     int rv;
00837     uint8_t *p;
00838 
00839     rv=GWEN_FastBuffer_ReadLineToBuffer(fb, lbuf);
00840     if (rv<0) {
00841       if (rv==GWEN_ERROR_EOF) {
00842         if (!someLinesRead && !(dbflags & GWEN_DB_FLAGS_ALLOW_EMPTY_STREAM)){
00843           DBG_INFO(GWEN_LOGDOMAIN, "Unexpected EOF (%d)", rv);
00844           GWEN_Buffer_free(tbuf);
00845           GWEN_Buffer_free(lbuf);
00846           return rv;
00847         }
00848         break;
00849       }
00850       DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00851       GWEN_Buffer_free(tbuf);
00852       GWEN_Buffer_free(lbuf);
00853       return rv;
00854     }
00855 
00856     if (GWEN_Buffer_GetUsedBytes(lbuf)==0) {
00857       if (dbflags & GWEN_DB_FLAGS_UNTIL_EMPTY_LINE) {
00858         break;
00859       }
00860     }
00861     else {
00862       someLinesRead=1;
00863       p=(uint8_t*)GWEN_Buffer_GetStart(lbuf);
00864       while(*p && isspace(*p))
00865         p++;
00866       if (*p) {
00867         uint8_t *p1begin=NULL, *p1end=NULL;
00868         uint8_t *p2begin=NULL, *p2end=NULL;
00869   
00870         /* non-empty line */
00871         if (*p=='}') {
00872           /* found end of current group */
00873           if (level<1) {
00874             DBG_INFO(GWEN_LOGDOMAIN, "Unbalanced number of curly bracket");
00875             GWEN_Buffer_free(tbuf);
00876             GWEN_Buffer_free(lbuf);
00877             return GWEN_ERROR_BAD_DATA;
00878           }
00879           n=n->parent;
00880           assert(n); /* internal error if parent not found */
00881           assert(n->typ==GWEN_DB_NodeType_Group); /* internal error if parent is not a group */
00882           level--;
00883         }
00884         else if (*p=='#') {
00885           /* comment only line */
00886         }
00887         else {
00888           p1begin=p;
00889           /* read first token */
00890           while(*p && !isspace(*p) &&
00891                 *p!='{' &&
00892                 *p!=((dbflags & GWEN_DB_FLAGS_USE_COLON)?':':'=') &&
00893                 *p!='}' &&
00894                 *p!=',' &&
00895                 *p!=';')
00896             p++;
00897           if (!*p) {
00898             DBG_INFO(GWEN_LOGDOMAIN, "Missing 2nd token");
00899             GWEN_Buffer_Dump(lbuf, stderr, 2);
00900             GWEN_Buffer_free(tbuf);
00901             GWEN_Buffer_free(lbuf);
00902             return GWEN_ERROR_BAD_DATA;
00903           }
00904           p1end=p;
00905 
00906           /* get to start of 2nd token */
00907           while(*p && isspace(*p))
00908             p++;
00909           if (!*p) {
00910             DBG_INFO(GWEN_LOGDOMAIN, "Missing 2nd token");
00911             GWEN_Buffer_free(tbuf);
00912             GWEN_Buffer_free(lbuf);
00913             return GWEN_ERROR_BAD_DATA;
00914           }
00915   
00916           if (*p=='{') {
00917             GWEN_DB_NODE *newGr;
00918   
00919             /* found start of group */
00920             *p1end=0;
00921             rv=GWEN_DB_UnescapeToBufferTolerant((const char*)p1begin, tbuf);
00922             if (rv<0) {
00923               DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00924               GWEN_Buffer_free(tbuf);
00925               GWEN_Buffer_free(lbuf);
00926               return rv;
00927             }
00928             newGr=GWEN_DB_GetGroup(n, dbflags, GWEN_Buffer_GetStart(tbuf));
00929             if (newGr==NULL) {
00930               DBG_INFO(GWEN_LOGDOMAIN, "Could not create group [%s]", GWEN_Buffer_GetStart(tbuf));
00931               GWEN_Buffer_free(tbuf);
00932               GWEN_Buffer_free(lbuf);
00933               return GWEN_ERROR_GENERIC;
00934             }
00935             GWEN_Buffer_Reset(tbuf);
00936             n=newGr;
00937             level++;
00938           }
00939           else if (*p=='=' || *p==':') {
00940             /* found short variable definition */
00941             *p1end=0;
00942             p++;
00943             rv=GWEN_DB__ReadValues(n, dbflags, NULL, (const char*)p1begin, p);
00944             if (rv) {
00945               DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00946               GWEN_Buffer_free(tbuf);
00947               GWEN_Buffer_free(lbuf);
00948               return rv;
00949             }
00950           }
00951           else if (*p==',' || *p==';') {
00952             DBG_INFO(GWEN_LOGDOMAIN, "Unexpected delimiter found");
00953             GWEN_Buffer_free(tbuf);
00954             GWEN_Buffer_free(lbuf);
00955             return GWEN_ERROR_BAD_DATA;
00956           }
00957           else {
00958             /* 2nd token, so this should be a standard variable definition */
00959             p2begin=p;
00960             while(*p &&
00961                   !isspace(*p) &&
00962                   *p!='{' &&
00963                   *p!=((dbflags & GWEN_DB_FLAGS_USE_COLON)?':':'=') &&
00964                   *p!='}' &&
00965                   *p!=',' &&
00966                   *p!=';')
00967               p++;
00968             if (!*p) {
00969               DBG_INFO(GWEN_LOGDOMAIN, "Missing 2nd token [%s], [%s]", p1begin, p2begin);
00970               GWEN_Buffer_free(tbuf);
00971               GWEN_Buffer_free(lbuf);
00972               return GWEN_ERROR_BAD_DATA;
00973             }
00974             p2end=p;
00975             if (isspace(*p)) {
00976               while(*p && isspace(*p))
00977                 p++;
00978               if (!*p) {
00979                 DBG_INFO(GWEN_LOGDOMAIN, "Missing 2nd token");
00980                 GWEN_Buffer_free(tbuf);
00981                 GWEN_Buffer_free(lbuf);
00982                 return GWEN_ERROR_BAD_DATA;
00983               }
00984             }
00985             if (*p!='=' && *p!=':') {
00986               DBG_INFO(GWEN_LOGDOMAIN, "Equation mark expected");
00987               GWEN_Buffer_free(tbuf);
00988               GWEN_Buffer_free(lbuf);
00989               return GWEN_ERROR_BAD_DATA;
00990             }
00991             p++;
00992   
00993             *p1end=0;
00994             *p2end=0;
00995             rv=GWEN_DB__ReadValues(n, dbflags, (const char*)p1begin, (const char*)p2begin, p);
00996             if (rv) {
00997               DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00998               GWEN_Buffer_free(tbuf);
00999               GWEN_Buffer_free(lbuf);
01000               return rv;
01001             }
01002           }
01003         }
01004       }
01005     }
01006     GWEN_Buffer_Reset(lbuf);
01007   }
01008 
01009   if (level) {
01010     DBG_INFO(GWEN_LOGDOMAIN, "Unbalanced number of curly bracket (too few)");
01011     GWEN_Buffer_free(tbuf);
01012     GWEN_Buffer_free(lbuf);
01013     return GWEN_ERROR_BAD_DATA;
01014   }
01015 
01016   GWEN_Buffer_free(tbuf);
01017   GWEN_Buffer_free(lbuf);
01018 
01019   return 0;
01020 }
01021 
01022 
01023 
01024 int GWEN_DB_ReadFromIo(GWEN_DB_NODE *n,
01025                        GWEN_IO_LAYER *io,
01026                        uint32_t dbflags,
01027                        uint32_t guiid,
01028                        int msecs) {
01029   GWEN_FAST_BUFFER *fb;
01030   int rv;
01031 
01032   /* prepare fast buffer */
01033   fb=GWEN_FastBuffer_new(1024, io, guiid, msecs);
01034   if (dbflags & GWEN_DB_FLAGS_DOSMODE)
01035     GWEN_FastBuffer_AddFlags(fb, GWEN_FAST_BUFFER_FLAGS_DOSMODE);
01036 
01037   /* read from it */
01038   rv=GWEN_DB_ReadFromFastBuffer(n, fb, dbflags);
01039   if (rv) {
01040     DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
01041     GWEN_FastBuffer_free(fb);
01042     return rv;
01043   }
01044 
01045   GWEN_FastBuffer_free(fb);
01046   return 0;
01047 }
01048 
01049 
01050 
01051 int GWEN_DB_ReadFromFd(GWEN_DB_NODE *n,
01052                        int fd,
01053                        uint32_t dbflags,
01054                        uint32_t guiid,
01055                        int msecs) {
01056   GWEN_IO_LAYER *io;
01057   int rv;
01058 
01059   /* create io layer for this file (readonly) */
01060   io=GWEN_Io_LayerFile_new(fd, -1);
01061   assert(io);
01062   GWEN_Io_Layer_AddFlags(io, GWEN_IO_LAYER_FLAGS_DONTCLOSE);
01063 
01064   rv=GWEN_Io_Manager_RegisterLayer(io);
01065   if (rv) {
01066     DBG_ERROR(GWEN_LOGDOMAIN, "Internal error: Could not register io layer (%d)", rv);
01067     GWEN_Io_Layer_free(io);
01068     return rv;
01069   }
01070 
01071   rv=GWEN_DB_ReadFromIo(n, io, dbflags, guiid, msecs);
01072   if (rv) {
01073     DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
01074   }
01075   GWEN_Io_Layer_DisconnectRecursively(io, NULL, GWEN_IO_REQUEST_FLAGS_FORCE, guiid, msecs);
01076   GWEN_Io_Layer_free(io);
01077 
01078   return rv;
01079 }
01080 
01081 
01082 
01083 int GWEN_DB_ReadFile(GWEN_DB_NODE *n,
01084                      const char *fname,
01085                      uint32_t dbflags,
01086                      uint32_t guiid,
01087                      int msecs) {
01088   int fd;
01089   int rv;
01090 
01091   fd=open(fname, O_RDONLY);
01092   if (fd==-1) {
01093     DBG_ERROR(GWEN_LOGDOMAIN, "open(%s, O_RDONLY): %s", fname, strerror(errno));
01094     return GWEN_ERROR_IO;
01095   }
01096 
01097   rv=GWEN_DB_ReadFromFd(n, fd, dbflags, guiid, msecs);
01098   close(fd);
01099 
01100   return rv;
01101 }
01102 
01103 
01104 
01105 int GWEN_DB_ReadFromString(GWEN_DB_NODE *n,
01106                            const char *str,
01107                            int len,
01108                            uint32_t dbflags,
01109                            uint32_t guiid,
01110                            int msecs) {
01111   GWEN_IO_LAYER *io;
01112   int rv;
01113 
01114   if (len==0)
01115     len=strlen(str);
01116 
01117   /* create io layer */
01118   io=GWEN_Io_LayerMemory_fromString((const uint8_t*)str, len);
01119   assert(io);
01120 
01121   rv=GWEN_Io_Manager_RegisterLayer(io);
01122   if (rv) {
01123     DBG_ERROR(GWEN_LOGDOMAIN, "Internal error: Could not register io layer (%d)", rv);
01124     GWEN_Io_Layer_DisconnectRecursively(io, NULL, GWEN_IO_REQUEST_FLAGS_FORCE, guiid, msecs);
01125     GWEN_Io_Layer_free(io);
01126     return rv;
01127   }
01128 
01129   rv=GWEN_DB_ReadFromIo(n, io, dbflags, guiid, msecs);
01130   if (rv) {
01131     DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
01132   }
01133   GWEN_Io_Layer_DisconnectRecursively(io, NULL, GWEN_IO_REQUEST_FLAGS_FORCE, guiid, msecs);
01134   GWEN_Io_Layer_free(io);
01135 
01136   return rv;
01137 }
01138 
01139 
01140 
01141 int GWEN_DB_WriteToBuffer(GWEN_DB_NODE *n,
01142                           GWEN_BUFFER *buf,
01143                           uint32_t dbflags,
01144                           uint32_t guiid,
01145                           int msecs) {
01146   GWEN_IO_LAYER *io;
01147   int rv;
01148 
01149   /* create io layer */
01150   io=GWEN_Io_LayerMemory_new(buf);
01151   assert(io);
01152 
01153   rv=GWEN_Io_Manager_RegisterLayer(io);
01154   if (rv) {
01155     DBG_ERROR(GWEN_LOGDOMAIN, "Internal error: Could not register io layer (%d)", rv);
01156     GWEN_Io_Layer_DisconnectRecursively(io, NULL, GWEN_IO_REQUEST_FLAGS_FORCE, guiid, msecs);
01157     GWEN_Io_Layer_free(io);
01158     return rv;
01159   }
01160 
01161   rv=GWEN_DB_WriteToIo(n, io, dbflags, guiid, msecs);
01162   if (rv<0) {
01163     DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
01164     GWEN_Io_Layer_Disconnect(io, GWEN_IO_REQUEST_FLAGS_FORCE, 0, 1000);
01165     GWEN_Io_Layer_free(io);
01166     return rv;
01167   }
01168 
01169   /* flush data */
01170   rv=GWEN_Io_Layer_WriteString(io, "",
01171                                GWEN_IO_REQUEST_FLAGS_FLUSH,
01172                                guiid,
01173                                30000);
01174   if (rv<0) {
01175     DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
01176     GWEN_Io_Layer_Disconnect(io, GWEN_IO_REQUEST_FLAGS_FORCE, 0, 1000);
01177     GWEN_Io_Layer_free(io);
01178     return rv;
01179   }
01180 
01181   /* close io layer */
01182   rv=GWEN_Io_Layer_DisconnectRecursively(io, NULL, 0, guiid, 30000);
01183   if (rv<0) {
01184     DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
01185     GWEN_Io_Layer_Disconnect(io, GWEN_IO_REQUEST_FLAGS_FORCE, guiid, 1000);
01186     GWEN_Io_Layer_free(io);
01187     return rv;
01188   }
01189 
01190   GWEN_Io_Layer_free(io);
01191 
01192   return 0;
01193 }
01194 
01195 
01196 
01197 
01198 
01199 
01200 
01201 
01202 
01203 
01204 
01205 
Generated on Mon Jul 5 22:51:13 2010 for gwenhywfar by  doxygen 1.6.3