Main Page | Modules | File List

localkdb.c

00001 /***************************************************************************
00002             localkdb.c  -  Methods for accessing the Key Database
00003                              -------------------
00004     begin                : Mon Dec 29 2003
00005     copyright            : (C) 2003 by Avi Alkalay
00006     email                : avi@unix.sh
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00018 
00019 
00020 /***************************************************************************
00021  *                                                                         *
00022  *   This is the implementation of a filesystem backend for the            *
00023  *   Elektra Project. Each Key is a file in the filesystem.                *
00024  *   It is as secure as filesystem security. It is as reliable             *
00025  *   as filesystem. It uses only standards C calls, which makes it         *
00026  *   usable by very low level or early boot stage software, like           *
00027  *   /sbin/init.                                                           *
00028  *                                                                         *
00029  ***************************************************************************/
00030 
00031 
00032 /* Subversion stuff
00033 
00034 $Id: localkdb.c 54 2004-08-31 10:40:22Z aviram $
00035 $LastChangedBy: aviram $
00036 
00037 */
00038 
00039 
00040 #include "kdb.h"
00041 #include "kdbprivate.h"
00042 
00043 
00044 #include <sys/types.h>
00045 #include <sys/stat.h>
00046 #include <fcntl.h>
00047 #include <stdlib.h>
00048 #include <unistd.h>
00049 #include <pwd.h>
00050 #include <dirent.h>
00051 #include <errno.h>
00052 #include <stdio.h>
00053 #include <iconv.h>
00054 #include <locale.h>
00055 #include <langinfo.h>
00056 #include <ctype.h>
00057 #include <string.h>
00058 
00059 
00060 #define UTF8_TO   1
00061 #define UTF8_FROM 0
00062 
00063 extern int errno;
00064 
00065 
00066 
00067 
00079 /*
00080  * @defgroup internals Elektra internals
00081  * @brief These methods are not to be used by your application.
00082  *
00083  */
00084 
00085 
00086 
00095 int kdbOpen() {
00096     return 0;
00097 }
00098 
00106 int kdbClose() {
00107     return 0;
00108 }
00109 
00120 size_t keyGetSerializedSize(const Key *key) {
00121     size_t size,tmp;
00122 
00123 
00124     size=5+sizeof(u_int8_t)+1; /* RG000\nT\n */
00125     if (key->comment) size+=strblen(key->comment);
00126     size++;
00127     tmp=keyGetDataSize(key);
00128     size+=tmp;
00129     return size;
00130 }
00131 
00145 size_t unencode(char *encoded,void *returned) {
00146     char byteInHexa[5]="0x";
00147     char *readCursor=encoded;
00148     char *writeCursor=returned;
00149 
00150     if (!encoded) {
00151         if (returned) *(char *)returned=0;
00152         return 0;
00153     }
00154 
00155     byteInHexa[4]=0;
00156     while (*readCursor) {
00157         if (isspace((int)*readCursor)) readCursor++;
00158         if (isxdigit((int)*readCursor)) {
00159             long int converted;
00160             byteInHexa[2]=readCursor[0];
00161             byteInHexa[3]=readCursor[1];
00162             converted=strtol(byteInHexa,0,16); /* convert from hexa to a byte */
00163             *writeCursor=(unsigned char)converted;
00164 
00165             readCursor+=2;
00166             writeCursor++;
00167         } else {
00168             /* This is suposed to be a hex-digit stream. But is not, so return. */
00169             errno=KDB_RET_TYPEMISMATCH;
00170             return 0;
00171         }
00172     }
00173     return (long int)writeCursor-(long int)returned;
00174 }
00175 
00182 int kdbNeedsUTF8Conversion() {
00183     setlocale(LC_ALL,0);
00184     return strcmp(nl_langinfo(CODESET),"UTF-8");
00185 }
00186 
00187 
00196 int UTF8Engine(int direction, char **string, size_t *inputByteSize) {
00197     char *currentCharset=0;
00198     char *converted=0;
00199     char *readCursor, *writeCursor;
00200     size_t bufferSize;
00201     iconv_t converter;
00202 
00203     if (kdbNeedsUTF8Conversion()) currentCharset=nl_langinfo(CODESET);
00204     else return 0;
00205 
00206     if (direction) converter=iconv_open("UTF-8",currentCharset);
00207     else converter=iconv_open(currentCharset,"UTF-8");
00208 
00209     if (converter == (iconv_t)(-1)) return -1;
00210 
00211     bufferSize=*inputByteSize*2; /* work with worst case */
00212     converted=malloc(bufferSize);
00213     if (!converted) return -1;
00214 
00215     readCursor=*string;
00216     writeCursor=converted;
00217     if (iconv(converter,
00218             &readCursor,inputByteSize,
00219             &writeCursor,&bufferSize) == (size_t)(-1)) {
00220         free(converted);
00221         iconv_close(converter);
00222         return -1;
00223     }
00224 
00225     /* calculate the UTF-8 string byte size, that will be returned */
00226     *inputByteSize=writeCursor-converted;
00227     /* store the current unencoded string for future free */
00228     readCursor=*string;
00229     /* allocate an optimal size area to store the converted string */
00230     *string=malloc(*inputByteSize);
00231     /* copy all that matters for returning */
00232     memcpy(*string,converted,*inputByteSize);
00233     /* release memory used by passed string */
00234     free(readCursor);
00235     /* release buffer memory */
00236     free(converted);
00237     /* release the conversor engine */
00238     iconv_close(converter);
00239 
00240     return 0;
00241 }
00242 
00243 
00244 
00245 
00252 int handleOldKeyFileVersion(Key *key,FILE *input,u_int16_t nversion) {
00253     char generalBuffer[100];
00254     size_t currentBufferSize;
00255 
00256     char type[5];
00257     char *data=0;
00258     size_t dataSize=0;
00259     char *comment=0;
00260     size_t commentSize=0;
00261 
00262     int readComment=1;
00263     int eof=0;
00264 
00265     /*
00266         This is a very dirty helper.
00267         It has the parsing code for old version of key files.
00268         If your editor doesn't have code folding it will be a pain.
00269     */
00270 
00271 
00272     switch (nversion) {
00273         case 1: {
00274             if (!fgets(type,    sizeof(type),    input)) return -1;
00275 
00276             while (readComment) {
00277                 if (fgets(generalBuffer,sizeof(generalBuffer),input)) {
00278                     if (memcmp(generalBuffer,"<DATA>\n\0",8)) {
00279                         /* This is not the begining of the data part so it is part of comment */
00280                         currentBufferSize=strblen(generalBuffer);
00281                         if (!comment) {
00282                             comment=(char *)malloc(commentSize=currentBufferSize);
00283                             strcpy(comment,generalBuffer);
00284                         } else {
00285                             char *buffer=0;
00286 
00287                             buffer=malloc(commentSize+currentBufferSize);
00288                             strcpy(buffer,comment);
00289                             strcat(buffer,generalBuffer);
00290                             comment=realloc(comment,commentSize+=currentBufferSize);
00291                             strcpy(comment,buffer);
00292                             free(buffer);
00293                         }
00294                     } else readComment=0;
00295                 } else {
00296                     readComment=0;
00297                     eof=1;
00298                 }
00299             }
00300 
00301             /* Remove last \n */
00302             if (commentSize > 1 && (*(comment+commentSize-2) == '\n')) {
00303                 *(comment+commentSize-2)=0;
00304                 --commentSize;
00305             }
00306 
00307 
00308             if (comment && UTF8Engine(UTF8_FROM,&comment,&commentSize)) {
00309                 free(comment);
00310                 return -1;
00311             }
00312 
00313             /* Now read the data section */
00314             if (!eof) {
00315                 while (fgets(generalBuffer,sizeof(generalBuffer),input)) {
00316                     currentBufferSize=strlen(generalBuffer);
00317                     if (!data) {
00318                         data=(char *)malloc(dataSize=(currentBufferSize+1));
00319                         strcpy(data,generalBuffer);
00320                     } else {
00321                         char *buffer=0;
00322 
00323                         buffer=malloc(dataSize+currentBufferSize);
00324                         strcpy(buffer,data);
00325                         strcat(buffer,generalBuffer);
00326                         data=realloc(data,dataSize+=currentBufferSize);
00327                         strcpy(data,buffer);
00328                         free(buffer);
00329                     }
00330                 }
00331             }
00332 
00333             /* Put in the Key object */
00334             keySetComment(key,comment);
00335             if (comment) free(comment);
00336 
00337             /* This is what changed from version 1 to
00338                version 2 format: key type numbers */
00339             {
00340                 u_int8_t oldVersion=atoi(type);
00341                 switch (oldVersion) {
00342                     case 1: keySetType(key,KEY_TYPE_BINARY); break;
00343                     case 2: keySetType(key,KEY_TYPE_STRING); break;
00344                     default: keySetType(key,oldVersion);
00345                 }
00346             }
00347             if (!dataSize) {
00348                 keySetRaw(key,0,0);
00349                 return 0;
00350             }
00351 
00352             if (keyGetType(key) <= KEY_TYPE_BINARY) {
00353                 /* Binary data. Unencode. */
00354                 char *unencoded=0;
00355                 size_t unencodedSize;
00356 
00357                 /* raw data is maximum half the size of text-encoded data */
00358                 unencodedSize=dataSize/2;
00359 
00360                 unencoded=malloc(unencodedSize);
00361                 if (!(unencodedSize=unencode(data,unencoded))) return -1;
00362                 keySetRaw(key,unencoded,unencodedSize);
00363                 free(unencoded);
00364             } else {
00365                 if (UTF8Engine(UTF8_FROM,&data,&dataSize)) {
00366                     free(data);
00367                     return -1;
00368                 }
00369                 keySetRaw(key,data,dataSize);
00370             }
00371 
00372             free(data);
00373 
00374             return 0;
00375         } /* version 1 */
00376     } /* switch */
00377     return -1;
00378 }
00379 
00380 
00381 
00382 
00383 
00392 int keyFileUnserialize(Key *key,FILE *input) {
00393     char generalBuffer[100];
00394     size_t currentBufferSize;
00395 
00396     char version[10];
00397     u_int16_t nversion=0;
00398     char type[5];
00399     char *data=0;
00400     size_t dataSize=0;
00401     char *comment=0;
00402     size_t commentSize=0;
00403 
00404     int readComment=1;
00405     int eof=0;
00406 
00407     /* The serialized format is
00408        -------------------------
00409        RG001\n
00410        type\n
00411        comment (with newlines)\n
00412        <DATA>\n
00413        The data encoded as text
00414        -------------------------
00415     */
00416 
00417     if (!fgets(version, sizeof(version), input)) return -1;
00418     if (strncmp(version,"RG",2)) {
00419         /* Doesn't look like a key file */
00420         errno=KDB_RET_INVALIDKEY;
00421         return -1;
00422     }
00423 
00424     nversion=atoi(version+2);
00425     if (!nversion || nversion > RG_KEY_FORMAT_VERSION) {
00426         errno=KDB_RET_INVALIDKEY;
00427         return -1;
00428     }
00429 
00430     if (nversion != RG_KEY_FORMAT_VERSION)
00431         return handleOldKeyFileVersion(key,input,nversion);
00432 
00433     if (!fgets(type,    sizeof(type),    input)) return -1;
00434 
00435     while (readComment) {
00436         if (fgets(generalBuffer,sizeof(generalBuffer),input)) {
00437             if (memcmp(generalBuffer,"<DATA>\n\0",8)) {
00438                 /* This is not the begining of the data part so it is part of comment */
00439                 currentBufferSize=strblen(generalBuffer);
00440                 if (!comment) {
00441                     comment=(char *)malloc(commentSize=currentBufferSize);
00442                     strcpy(comment,generalBuffer);
00443                 } else {
00444                     char *buffer=0;
00445 
00446                     buffer=malloc(commentSize+currentBufferSize);
00447                     strcpy(buffer,comment);
00448                     strcat(buffer,generalBuffer);
00449                     comment=realloc(comment,commentSize+=currentBufferSize);
00450                     strcpy(comment,buffer);
00451                     free(buffer);
00452                 }
00453             } else readComment=0;
00454         } else {
00455             readComment=0;
00456             eof=1;
00457         }
00458     }
00459 
00460     /* Remove last \n */
00461     if (commentSize > 1 && (*(comment+commentSize-2) == '\n')) {
00462         *(comment+commentSize-2)=0;
00463         --commentSize;
00464     }
00465 
00466     if (comment && UTF8Engine(UTF8_FROM,&comment,&commentSize)) {
00467         free(comment);
00468         return -1;
00469     }
00470 
00471     /* Now read the data section */
00472     if (!eof) {
00473         while (fgets(generalBuffer,sizeof(generalBuffer),input)) {
00474             currentBufferSize=strlen(generalBuffer);
00475             if (!data) {
00476                 data=(char *)malloc(dataSize=(currentBufferSize+1));
00477                 strcpy(data,generalBuffer);
00478             } else {
00479                 char *buffer=0;
00480 
00481                 buffer=malloc(dataSize+currentBufferSize);
00482                 strcpy(buffer,data);
00483                 strcat(buffer,generalBuffer);
00484                 data=realloc(data,dataSize+=currentBufferSize);
00485                 strcpy(data,buffer);
00486                 free(buffer);
00487             }
00488         }
00489     }
00490 
00491     /* Put in the Key object */
00492     keySetComment(key,comment);
00493     if (comment) free(comment);
00494     keySetType(key,atoi(type));
00495     if (!dataSize) {
00496         keySetRaw(key,0,0);
00497         return 0;
00498     }
00499 
00500     if (keyGetType(key) <= KEY_TYPE_BINARY) {
00501         /* Binary data. Unencode. */
00502         char *unencoded=0;
00503         size_t unencodedSize;
00504 
00505         /* raw data is maximum half the size of text-encoded data */
00506         unencodedSize=dataSize/2;
00507 
00508         unencoded=malloc(unencodedSize);
00509         if (!(unencodedSize=unencode(data,unencoded))) return -1;
00510         keySetRaw(key,unencoded,unencodedSize);
00511         free(unencoded);
00512     } else {
00513         if (UTF8Engine(UTF8_FROM,&data,&dataSize)) {
00514             free(data);
00515             return -1;
00516         }
00517         keySetRaw(key,data,dataSize);
00518     }
00519 
00520     free(data);
00521 
00522     return 0;
00523 }
00524 
00525 
00526 
00541 size_t encode(void *unencoded, size_t size, char *returned) {
00542     void *readCursor=unencoded;
00543     void *writeCursor=returned;
00544     int blockStep=4; /* 4 bytes per block */
00545     int lineStep=8*blockStep; /* 8 blocks per line */
00546     int currentInBlock=0;
00547     int currentInLine=0;
00548 
00549     while ((readCursor-unencoded)<size) {
00550         sprintf(writeCursor,"%01x",*(u_int8_t *)readCursor);
00551         readCursor++;
00552         writeCursor+=2;
00553         currentInBlock++;
00554         currentInLine++;
00555         if (currentInLine==lineStep) {
00556             *(char *)writeCursor='\n'; writeCursor++;
00557             currentInLine=0;
00558             currentInBlock=0;
00559         }
00560         if (currentInBlock==blockStep) {
00561             *(char *)writeCursor=' '; writeCursor++;
00562             currentInBlock=0;
00563         }
00564     }
00565     *(char *)writeCursor='\n';
00566     *(char *)++writeCursor=0;
00567     return (writeCursor)-(void *)returned;
00568 }
00569 
00570 
00571 
00572 
00573 
00584 int keyFileSerialize(Key *key, FILE *output) {
00585     /* The serialized format is
00586        -------------------------
00587        RG001\n
00588        type\n
00589        comment (with newlines)\n
00590        <DATA>\n
00591        The data encoded as text
00592        -------------------------
00593     */
00594 
00595     size_t dataSize;
00596 
00597     fprintf(output,"RG%03d\n",RG_KEY_FORMAT_VERSION);
00598     fprintf(output,"%d\n",key->type);
00599     if (key->comment) {
00600         if (kdbNeedsUTF8Conversion()) {
00601             size_t convertedCommentSize=key->commentSize;
00602             char *convertedComment=malloc(convertedCommentSize);
00603 
00604             memcpy(convertedComment,key->comment,key->commentSize);
00605             if (UTF8Engine(UTF8_TO,&convertedComment,&convertedCommentSize)) {
00606                 free(convertedComment);
00607                 return -1;
00608             }
00609             fprintf(output,"%s\n",convertedComment);
00610             free(convertedComment);
00611         } else fprintf(output,"%s\n",key->comment);
00612     }
00613 
00614     fputs("<DATA>\n",output);
00615     fflush(output);
00616 
00617     dataSize=keyGetDataSize(key);
00618     if (dataSize) {
00619         /* There is some data to write */
00620         if (keyGetType(key) > KEY_TYPE_BINARY) {
00621             if (kdbNeedsUTF8Conversion()) {
00622                 size_t convertedDataSize=key->dataSize;
00623                 char *convertedData=malloc(convertedDataSize);
00624 
00625                 memcpy(convertedData,key->data,key->dataSize);
00626                 if (UTF8Engine(UTF8_TO,&convertedData,&convertedDataSize)) {
00627                     free(convertedData);
00628                     return -1;
00629                 }
00630                 fprintf(output,"%s",convertedData);
00631                 free(convertedData);
00632             } else fputs(key->data,output);
00633         } else {
00634             char *encoded=malloc(3*dataSize);
00635             size_t encodedSize;
00636 
00637             encodedSize=encode(key->data,dataSize,encoded);
00638             fwrite(encoded,encodedSize,1,output);
00639             free(encoded);
00640         }
00641     }
00642     return 0;
00643 }
00644 
00645 
00655 size_t keyCalcRelativeFileName(Key *key,char *relativeFileName,size_t maxSize) {
00656     if (!key || !keyIsInitialized(key)) {
00657         errno=KDB_RET_UNINITIALIZED;
00658         return 0;
00659     }
00660     if (!key->key) {
00661         errno=KDB_RET_NOKEY;
00662         return 0;
00663     }
00664 
00665 //  cursor=key->key;
00666 //  while (*cursor) {
00667 //      if (pos+1 > maxSize) {
00668 //          errno=E2BIG;
00669 //          return -1;
00670 //      }
00671 //      switch (*cursor) {
00672 //          case '\\':
00673 //              cursor++;
00674 //              relativeFileName[pos]=*cursor;
00675 //              break;
00676 //          case '.':
00677 //              relativeFileName[pos]='/';
00678 //              break;
00679 //          default:
00680 //              relativeFileName[pos]=*cursor;
00681 //      }
00682 //      cursor++;
00683 //      pos++;
00684 //  }
00685 //  relativeFileName[pos]=0;
00686 //  pos++;
00687 
00688     if (kdbNeedsUTF8Conversion()) {
00689         char *converted;
00690         size_t size;
00691 
00692         if (!(size=keyGetNameSize(key))) return 0;
00693 
00694         converted=malloc(size);
00695         keyGetName(key,converted,size);
00696 
00697 //      memcpy(converted,relativeFileName,convertedSize);
00698 
00699         if (UTF8Engine(UTF8_TO,&converted,&size)) {
00700             free(converted);
00701             return 0;
00702         }
00703 
00704         if (size>maxSize) {
00705             free(converted);
00706             errno=E2BIG;
00707             return 0;
00708         }
00709 
00710         memcpy(relativeFileName,converted,size);
00711         free(converted);
00712 
00713         return size;
00714     } else return keyGetName(key,relativeFileName,maxSize);
00715 
00716     return 0;
00717 }
00718 
00719 
00720 
00721 
00722 
00723 
00735 int keyFromStat(Key *key,struct stat *stat) {
00736     if (!key) {
00737         errno=KDB_RET_NULLKEY;
00738         return -1;
00739     }
00740 
00741     keySetAccess(key,stat->st_mode);
00742     keySetUID(key,stat->st_uid);
00743     keySetGID(key,stat->st_gid);
00744     if (S_ISDIR(stat->st_mode)) keySetType(key,KEY_TYPE_DIR);
00745     key->atime=stat->st_atime;
00746     key->mtime=stat->st_mtime;
00747     key->ctime=stat->st_ctime;
00748     key->recordSize=stat->st_size;
00749     return 0;
00750 }
00751 
00752 
00753 
00754 
00764 size_t kdbGetFilename(Key *forKey,char *returned,size_t maxSize) {
00765     size_t length=0;
00766 
00767     switch (keyGetNamespace(forKey)) {
00768         case KEY_NS_SYSTEM: {
00769             /* Prepare to use the 'system/ *' database */
00770             strncpy(returned,RG_DB_SYSTEM,maxSize);
00771             length=strlen(returned);
00772             break;
00773         }
00774         case KEY_NS_USER: {
00775             /* Prepare to use the 'user:????/ *' database */
00776             struct passwd *user=0;
00777             char userName[100];
00778 
00779             length=keyGetOwner(forKey,userName,sizeof(userName));
00780             if (!length) strncpy(userName,getenv("USER"),sizeof(userName));
00781 
00782             user=getpwnam(userName);
00783                         if (!user) return 0; /* propagate errno */
00784             length=snprintf(returned,maxSize,"%s/%s",user->pw_dir,RG_DB_USER);
00785             break;
00786         }
00787         default: {
00788             errno=KDB_RET_INVALIDKEY;
00789             return 0;
00790         }
00791     }
00792 
00793     returned[length]='/'; length++;
00794     length+=keyCalcRelativeFileName(forKey,returned+length,maxSize-length);
00795 
00796     return length;
00797 }
00798 
00799 
00800 
00817 int kdbGetValue(const char *keyname, char *returned,size_t maxSize) {
00818     Key key;
00819     int rc=0;
00820 
00821     keyInit(&key);
00822     keySetName(&key,keyname);
00823     rc=kdbGetKey(&key);
00824     if (rc == 0) keyGetString(&key,returned,maxSize);
00825     else rc=errno; /* store errno before a possible change */
00826     keyClose(&key);
00827     errno=rc;
00828     return rc;
00829 }
00830 
00831 
00832 
00848 int kdbSetValue(const char *keyname, const char *value) {
00849     Key key;
00850     int rc;
00851 
00852 /* TODO: check key type first */
00853     keySetName(&key,keyname);
00854     rc=kdbGetKey(&key);
00855     keySetString(&key,value);
00856     rc=kdbSetKey(&key);
00857     keyClose(&key);
00858     return rc;
00859 }
00860 
00861 
00862 
00889 int kdbGetValueByParent(const char *parentName, const char *baseName, char *returned, size_t maxSize) {
00890     char name[strblen(parentName)+strblen(baseName)];
00891 
00892     sprintf(name,"%s/%s",parentName,baseName);
00893     return kdbGetValue(name,returned,maxSize);
00894 }
00895 
00896 
00897 
00907 int kdbSetValueByParent(const char *parentName, const char *baseName, const char *value) {
00908     char name[strblen(parentName)+strblen(baseName)];
00909 
00910     sprintf(name,"%s/%s",parentName,baseName);
00911     return kdbSetValue(name,value);
00912 }
00913 
00914 
00915 
00932 int kdbGetKeyByParent(const char *parentName, const char *baseName, Key *returned) {
00933     char name[strblen(parentName)+strblen(baseName)];
00934 
00935     sprintf(name,"%s/%s",parentName,baseName);
00936     keySetName(returned,name);
00937 
00938     return kdbGetKey(returned);
00939 }
00940 
00941 
00951 int kdbGetKeyByParentKey(const Key *parent, const char *baseName, Key *returned) {
00952     size_t size=keyGetFullNameSize(parent);
00953     char name[size+strblen(baseName)];
00954 
00955     keyGetFullName(parent,name,size);
00956     name[size-1]='/';
00957     strcpy((char *)(parent+size),baseName);
00958 
00959     keySetName(returned,name);
00960 
00961     return kdbGetKey(returned);
00962 }
00963 
00964 
00965 
00966 
00967 /* Used by the qsort() function */
00968 int keyCompareByName(const void *p1, const void *p2) {
00969     Key *key1=*(Key **)p1;
00970     Key *key2=*(Key **)p2;
00971 
00972     return strcmp(key1->key, key2->key);
00973 }
00974 
00975 
00976 
01040 int kdbGetChildKeys(const char *parentName, KeySet *returned, unsigned long options) {
01041     char *realParentName=0;
01042     size_t parentNameSize;
01043     DIR *parentDir;
01044     Key parentKey;
01045     char buffer[800];
01046     struct dirent *entry;
01047 
01048     /*
01049         - Convert parent key name into a real filename
01050         - Check if it is a directory. Open it
01051         - Browse, read and include in the KeySet
01052     */
01053     keyInit(&parentKey);
01054     keySetName(&parentKey,parentName);
01055     kdbGetFilename(&parentKey,buffer,sizeof(buffer));
01056     parentDir=opendir(buffer);
01057 
01058     /* Check if Key is not a directory or doesn't exist.
01059      * Propagate errno */
01060     if (!parentDir) return -1;
01061 
01062     parentNameSize=keyGetFullNameSize(&parentKey);
01063     realParentName=realloc(realParentName,parentNameSize);
01064     keyGetFullName(&parentKey,realParentName,parentNameSize);
01065 
01066     while ((entry=readdir(parentDir))) {
01067         Key *keyEntry;
01068         char *transformedName=0;
01069         size_t keyNameSize=0;
01070 
01071         /* Ignore '.' and '..' directory entries */
01072         if (!strcmp(entry->d_name,".") || !strcmp(entry->d_name,"..")) continue;
01073 
01074         /* If key name starts with '.', and don't want INACTIVE keys, ignore it */
01075         if ((*entry->d_name == '.') && !(options & KDB_O_INACTIVE)) continue;
01076 
01077         /* Next 2 ifs are required to transform filename from UTF-8 */
01078         if (!transformedName) {
01079             transformedName=
01080                 realloc(transformedName,keyNameSize=strblen(entry->d_name));
01081             strcpy(transformedName,entry->d_name);
01082         }
01083         if (UTF8Engine(UTF8_FROM,&transformedName,&keyNameSize)) {
01084             free(transformedName);
01085             return -1;
01086         }
01087 
01088         /* Copy the entire transformed key name to our final buffer */
01089         sprintf(buffer,"%s/%s",realParentName,transformedName);
01090         free(transformedName); /* don't need it anymore */
01091 
01092         keyEntry=(Key *)malloc(sizeof(Key)); keyInit(keyEntry);
01093         keySetName(keyEntry,buffer);
01094 
01095         if (options & KDB_O_STATONLY) kdbStatKey(keyEntry);
01096         else if (options & KDB_O_NFOLLOWLINK) {
01097             kdbStatKey(keyEntry);
01098             if (!keyIsLink(keyEntry)) kdbGetKey(keyEntry);
01099         } else {
01100             int rc=kdbGetKey(keyEntry);
01101             /* If this is a permission problem, at least stat the key */
01102             if (rc && errno==KDB_RET_NOCRED) kdbStatKey(keyEntry);
01103         }
01104 
01105         if (S_ISDIR(keyEntry->access)) {
01106             if (options & KDB_O_RECURSIVE) {
01107                 KeySet children;
01108                 char *fullName;
01109                 size_t fullNameSize;
01110 
01111                 fullName=malloc(fullNameSize=keyGetFullNameSize(keyEntry));
01112                 keyGetFullName(keyEntry,fullName,fullNameSize);
01113 
01114                 ksInit(&children);
01115                 /* Act recursively, without sorting. Sort in the end, once */
01116                 kdbGetChildKeys(fullName,&children, ~(KDB_O_SORT) & options);
01117 
01118                 /* Insert the current directory key in the returned list before its children */
01119                 if (options & KDB_O_DIR) ksAppend(returned,keyEntry);
01120                 else {
01121                     keyClose(keyEntry);
01122                     free(keyEntry);
01123                 }
01124 
01125                 /* Insert the children */
01126                 ksAppendKeys(returned,&children);
01127                 free(fullName);
01128             } else if (options & KDB_O_DIR) ksAppend(returned,keyEntry);
01129                 else {
01130                     keyClose(keyEntry);
01131                     free(keyEntry);
01132                 }
01133         } else if (options & KDB_O_NOVALUE) {
01134             keyClose(keyEntry);
01135             free(keyEntry);
01136         } else ksAppend(returned,keyEntry);
01137     } /* while(readdir) */
01138     keyClose(&parentKey);
01139     free(realParentName);
01140 
01141     if ((options & (KDB_O_SORT)) && (returned->size > 1)) {
01142         Key *keys[returned->size];
01143         Key *cursor;
01144         size_t c=0;
01145 
01146         for (cursor=returned->start; cursor; cursor=cursor->next, c++)
01147             keys[c]=cursor;
01148 
01149         qsort(keys,returned->size,sizeof(Key *),keyCompareByName);
01150 
01151         returned->start=cursor=keys[0];
01152         for (c=1; c<returned->size; c++) {
01153             cursor->next=keys[c];
01154             cursor=cursor->next;
01155         }
01156         cursor->next=0;
01157         returned->end=cursor;
01158     }
01159 
01160     return 0;
01161 }
01162 
01163 
01164 
01165 
01166 
01167 
01168 
01169 
01180 int kdbGetRootKeys(KeySet *returned) {
01181     Key *system=0,*user=0;
01182 
01183     system=malloc(sizeof(Key));
01184     keyInit(system);
01185     keySetName(system,"system");
01186     if (kdbGetKey(system)) {
01187         free(system);
01188         system=0;
01189     }
01190 
01191     user=malloc(sizeof(Key));
01192     keyInit(user);
01193     keySetName(user,"user");
01194     if (kdbGetKey(user)) {
01195         free(user);
01196         user=0;
01197     }
01198 
01199     if (system) ksInsert(returned,system);
01200     if (user) ksAppend(returned,user);
01201 
01202     return 0;
01203 }
01204 
01205 
01206 
01218 int kdbStatKey(Key *key) {
01219     char keyFileName[800];
01220     struct stat keyFileNameInfo;
01221     size_t pos;
01222     u_int32_t semiflag;
01223 
01224     pos=kdbGetFilename(key,keyFileName,sizeof(keyFileName));
01225     if (!pos) return -1; /* something is wrong */
01226 
01227     if (lstat(keyFileName,&keyFileNameInfo)) return -1;
01228     keyFromStat(key,&keyFileNameInfo);
01229 
01230     if (keyIsLink(key) && key->recordSize) {
01231         char *data=malloc(key->recordSize+1); /* Add 1 byte for ending 0 */
01232 
01233         readlink(keyFileName,data,key->recordSize);
01234         data[key->recordSize]=0; /* null terminate it */
01235         keySetLink(key,data);
01236         free(data);
01237     }
01238 
01239     /* Remove the NEEDSYNC flag */
01240     semiflag=KEY_FLAG_NEEDSYNC;
01241     semiflag=~semiflag;
01242     key->flags &= semiflag;
01243     key->flags |= KEY_FLAG_ACTIVE;
01244 
01245     return 0;
01246 }
01247 
01248 
01249 
01258 int kdbGetKey(Key *key) {
01259     char keyFileName[500];
01260     struct stat keyFileNameInfo;
01261     int fd;
01262     size_t pos;
01263     u_int32_t semiflag;
01264 
01265     pos=kdbGetFilename(key,keyFileName,sizeof(keyFileName));
01266     if (!pos) return -1; /* something is wrong */
01267 
01268     if ((fd=open(keyFileName,O_RDONLY))==-1) return -1;
01269     /* TODO: lock at this point */
01270     fstat(fd,&keyFileNameInfo);
01271     keyFromStat(key,&keyFileNameInfo);
01272     if (!keyIsDir(key)) {
01273         FILE *input;
01274 
01275         input=fdopen(fd,"r");
01276         if (keyFileUnserialize(key,input)) {
01277             fclose(input);
01278             return -1;
01279         }
01280         /* TODO: unlock at this point */
01281         fclose(input);
01282     } else close(fd);
01283 
01284     /* Remove the NEEDSYNC flag */
01285     semiflag=KEY_FLAG_NEEDSYNC;
01286     semiflag=~semiflag;
01287     key->flags &= semiflag;
01288 
01289     return 0;
01290 }
01291 
01292 
01293 
01306 int kdbSetKeys(KeySet *ks) {
01307     Key *current;
01308 
01309     for (current=ks->start; current; current=current->next) {
01310         if (keyNeedsSync(current)) {
01311             kdbSetKey(current);
01312         }
01313     }
01314 
01315     return 0;
01316 }
01317 
01318 
01319 
01330 int kdbSetKey(Key *key) {
01331     char keyFileName[800];
01332     char folderMaker[800];
01333     char *cursor, *last;
01334     int fd;
01335     FILE *output=0;
01336     size_t pos;
01337     u_int32_t semiflag;
01338     struct stat stated;
01339 
01340     pos=kdbGetFilename(key,keyFileName,sizeof(keyFileName));
01341     if (!pos) return -1; /* Something is wrong. Propagate errno. */
01342 
01343     if (stat(keyFileName,&stated))
01344         if (errno==ENOENT) {
01345             /* check if parent dir already exists */
01346             last=rindex(keyFileName,'/');
01347             strncpy(folderMaker,keyFileName,last-keyFileName);
01348             folderMaker[last-keyFileName]=0;
01349             if (stat(folderMaker,&stated)) {
01350                 /* create all path recursively until before our basename */
01351                 last   =rindex(keyFileName,'/');
01352                 cursor = index(keyFileName,'/'); cursor++; /* skip first occurence */
01353                 if (!last || !cursor) { /* bizarre key name */
01354                     errno=KDB_RET_INVALIDKEY;
01355                     return -1;
01356                 }
01357                 for (cursor=index(cursor,'/');
01358                         cursor && (cursor <= last);
01359                         cursor=index(cursor,'/')) {
01360                     strncpy(folderMaker,keyFileName,cursor-keyFileName);
01361                     folderMaker[cursor-keyFileName]=0;
01362                     if (mkdir(folderMaker,0775)<0 && errno!=EEXIST) return -1;
01363                     cursor++;
01364                 }
01365             }
01366         } else return -1; /* propagate errno */
01367     else { /* A file or dir or link is already there. Lets check details */
01368         /* TODO: Check for existing link */
01369         if ( S_ISDIR(stated.st_mode) && !keyIsDir(key)) {
01370             errno=EISDIR;
01371             return -1;
01372         }
01373         if (!S_ISDIR(stated.st_mode) &&  keyIsDir(key)) {
01374             errno=ENOTDIR;
01375             return -1;
01376         }
01377     }
01378 
01379     /* Enough of checking. Now real write stuff, with a bit other checks :-)  */
01380 
01381     if (keyIsLink(key)) {
01382         char *targetName=0;
01383         Key target;
01384         int rc;
01385 
01386         /*
01387             If targetName starts with:
01388             - "system" | "user" | any future root name: Convert to a FS path,
01389               and symlink it
01390             - other: It is an absolute FS path, or relative inside-kdb
01391               namespace path, and symlink it
01392         */
01393 
01394         keyInit(&target);
01395         if (key->data) targetName=malloc(key->dataSize);
01396         keyGetLink(key,targetName,key->dataSize);
01397 
01398         /* Setting the name will let us know if this is a valid keyname */
01399         if (keySetName(&target,targetName)) {
01400             /* target has a valid key name */
01401             targetName=realloc(targetName,800);
01402             kdbGetFilename(&target,targetName,800);
01403             keyClose(&target);
01404         } else if (errno==KDB_RET_INVALIDKEY) {
01405             /* Is an invalid key name. So treat it as a regular file */
01406             keyClose(&target); /* get rid of invalid stuff */
01407         } else {
01408             keyClose(&target); /* get rid of invalid stuff */
01409             return -1; /* propagate errno from keySetName() */
01410         }
01411 
01412 
01413         /* Now, targetName has the real destination of our link */
01414 
01415         /* TODO: handle null targetName */
01416         rc=symlink(targetName,keyFileName);
01417         free(targetName);
01418 
01419         return rc; /* propagate errno */
01420     } else if (keyIsDir(key)) {
01421         if (mkdir(keyFileName,keyGetAccess(key))<0 &&
01422                 errno!=EEXIST) return -1;
01423     } else {
01424         /* Try to open key file with its full file name */
01425         /* TODO: Make it more "transactional" without truncating */
01426         fd=open(keyFileName,O_CREAT | O_RDWR | O_TRUNC, keyGetAccess(key));
01427         /* TODO: lock file here */
01428         if (fd==-1) return -1;
01429         if (getuid() == 0) fchown(fd,keyGetUID(key),keyGetGID(key));
01430         if (!(output=fdopen(fd,"w+"))) return -1;
01431         if (keyFileSerialize(key,output)) {
01432             fclose(output);
01433             return -1;
01434         }
01435         /* TODO: unlock file here */
01436         fclose(output);
01437     }
01438 
01439     /* Remove the NEEDSYNC flag */
01440     semiflag=KEY_FLAG_NEEDSYNC;
01441     semiflag=~semiflag;
01442     key->flags &= semiflag;
01443 
01444     return 0;
01445 }
01446 
01447 
01448 
01449 
01450 
01451 
01461 int kdbRemove(const char *keyName) {
01462     Key key;
01463     char fileName[800];
01464     off_t rc;
01465 
01466     keyInit(&key);
01467     rc=keySetName(&key,keyName);
01468     if (rc==-1) return -1;
01469     rc=kdbGetFilename(&key,fileName,sizeof(fileName));
01470     keyClose(&key);
01471     if (!rc) return -1;
01472 
01473     return remove(fileName);
01474 }
01475 
01476 
01477 
01478 
01479 
01491 int kdbLink(const char *oldPath, const char *newKeyName) {
01492     Key key;
01493     int rc;
01494 
01495     keyInit(&key);
01496     keySetName(&key,newKeyName);
01497     keySetLink(&key,oldPath);
01498 
01499     rc=kdbSetKey(&key);
01500     keyClose(&key);
01501 
01502     return rc;
01503 }
01504 
01505 
01506 
01507 
01508 
01569 u_int32_t kdbMonitorKeys(KeySet *interests, u_int32_t diffMask,
01570         unsigned long iterations, unsigned sleep) {
01571     Key *start,*current;
01572     u_int32_t diff;
01573     int infinitum=0;
01574 
01575     if (!interests || !interests->size) return 0;
01576 
01577     /* Unacceptable 0 usecs sleep. Defaults to 1 second */
01578     if (!sleep) sleep=1000;
01579 
01580     if (!iterations) infinitum=1;
01581     else infinitum=0;
01582 
01583     current=start=ksCurrent(interests);
01584 
01585     while (infinitum || --iterations) {
01586         do {
01587             diff=kdbMonitorKey(current,diffMask,1,0);
01588             if (diff) return diff;
01589             current=ksNext(interests);
01590         } while (current!=start);
01591 
01592         /* Test if some iterations left . . . */
01593         if (infinitum || iterations) usleep(sleep);
01594     }
01595     return 0;
01596 }
01597 
01598 
01599 
01639 u_int32_t kdbMonitorKey(Key *interest, u_int32_t diffMask,
01640         unsigned long iterations, unsigned sleep) {
01641     Key tested;
01642     int rc;
01643     u_int32_t diff;
01644     int infinitum=0;
01645 
01646     /* consistency */
01647     if (!interest || !keyGetNameSize(interest)) return 0;
01648 
01649     /* Unacceptable 0 usecs sleep. Defaults to 1 second */
01650     if (!sleep) sleep=1000;
01651 
01652     if (!iterations) infinitum=1;
01653     else infinitum=0;
01654 
01655     /* Work with a copy of the key */
01656     keyInit(&tested);
01657     keyDup(interest,&tested);
01658 
01659     while (infinitum || --iterations) {
01660         rc=kdbGetKey(&tested);
01661         if (rc) {
01662             /* check what type of problem happened.... */
01663             switch (errno) {
01664                 case KDB_RET_NOCRED:
01665                     return KEY_FLAG_NEEDSYNC;
01666                 case KDB_RET_NOTFOUND:
01667                     return KEY_FLAG_FLAG;
01668             }
01669         }
01670         diff=keyCompare(&tested,interest);
01671         if (diff & diffMask) {
01672             /* If differences are in the diff mask...*/
01673             keyDup(&tested,interest);
01674             keyClose(&tested);
01675             return diff;
01676         }
01677         /* Test if some iterations left . . . */
01678         if (infinitum || iterations) usleep(sleep);
01679     }
01680 
01681     return 0;
01682 }
01683 
01684 
01685 

Generated on Tue Aug 31 08:40:42 2004 for Elektra Project by doxygen 1.3.6