00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 #include <fcntl.h>
00010 
00011 #include "global.h"
00012 #include "waa.h"
00013 #include "helper.h"
00014 #include "hash_ops.h"
00015 
00016 
00184 int hsh___new_bare(char *wcfile, char *name, int gdbm_mode, 
00185         GDBM_FILE *output, 
00186         char **fname_out)
00187 {
00188     int status;
00189     char *cp, *eos;
00190     GDBM_FILE db;
00191 
00192 
00193     status=0;
00194     db=NULL;
00195 
00196     if (gdbm_mode == HASH_TEMPORARY)
00197     {
00198         cp=waa_tmp_path;
00199         
00200         eos=waa_tmp_fn;
00201     }
00202     else
00203         STOPIF( waa__get_waa_directory(wcfile, &cp, &eos, NULL,
00204                     ( (gdbm_mode == GDBM_READER) ? 0 : GWD_MKDIR)  
00205                     | waa__get_gwd_flag(name)), NULL);
00206     strcpy(eos, name);
00207 
00208     if (gdbm_mode == GDBM_NEWDB || gdbm_mode == HASH_TEMPORARY)
00209     {
00210         
00211 
00212 
00214         
00215         STOPIF_CODE_ERR( (unlink(cp) == -1) && (errno != ENOENT), errno,
00216                 "Removing database file '%s'", cp);
00217         status=0;
00218     }
00219 
00220     db = gdbm_open(cp, 0, gdbm_mode, 0777, NULL);
00221     if (!db)
00222     {
00223         status=errno;
00224         if (status != ENOENT)
00225             STOPIF(status, "Cannot open database file %s", cp);
00226     }
00227     else
00228     {
00229         
00230         if (gdbm_mode == HASH_TEMPORARY)
00231             STOPIF_CODE_ERR( unlink(cp) == -1, errno,
00232                     "Removing database file '%s'", cp);
00233 
00234         if (fname_out) 
00235             STOPIF( hlp__strdup( fname_out, cp), NULL);
00236     }
00237 
00238 ex:
00239     if (status)
00240     {
00241         if (db) gdbm_close(db);
00242     }
00243     else
00244         *output=db;
00245 
00246     return status;
00247 }
00248 
00249 
00258 int hsh__new(char *wcfile, char *name, int gdbm_mode, 
00259         hash_t *output)
00260 {
00261     int status;
00262     hash_t hash;
00263 
00264 
00265     STOPIF( hlp__calloc( &hash, 1, sizeof(*hash)), NULL);
00266 
00267     
00268     status=hsh___new_bare(wcfile, name, 
00269             gdbm_mode & ~HASH_REMEMBER_FILENAME, 
00270             & (hash->db), 
00271             gdbm_mode & HASH_REMEMBER_FILENAME ? &(hash->filename) : NULL);
00272 
00273 ex:
00274     if (status)
00275         IF_FREE(hash);
00276     else
00277         *output=hash;
00278 
00279     return status;
00280 }
00281 
00282 
00287 int hsh__collect_garbage(hash_t db, int *did_remove)
00288 {
00289     int status;
00290     int have_removed;
00291     datum key, next;
00292 
00293     status=0;
00294     have_removed=0;
00295     if (db && db->to_delete)
00296     {
00297         key=gdbm_firstkey(db->to_delete);
00298         while (key.dptr)
00299         {
00300             next=gdbm_nextkey(db->to_delete, key);
00301             STOPIF_CODE_ERR( gdbm_delete(db->db, key)!=0, gdbm_errno,
00302                     "Removing entry");
00303 
00304             free(key.dptr);
00305             key=next;
00306             have_removed++;
00307         }
00308 
00309         DEBUGP("%d cleanups", have_removed);
00310 
00311         gdbm_close(db->to_delete);
00312         db->to_delete=NULL;
00313     }
00314 
00315     if (did_remove) *did_remove=have_removed;
00316 
00317 ex:
00318     return status;
00319 }
00320 
00321 
00326 int hsh__close(hash_t db, int has_failed)
00327 {
00328     int status;
00329     int have_removed;
00330     datum key;
00331 
00332 
00333     status=0;
00334     if (!db) goto ex;
00335 
00336     have_removed=0;
00337     if (db->to_delete)
00338     {
00339         if (!has_failed)
00340             STOPIF( hsh__collect_garbage(db, &have_removed), NULL);
00341     }
00342 
00343     
00344     if (hsh__first(db, &key) == ENOENT &&
00345             db->filename)
00346     {
00347         DEBUGP("nothing found, removing %s", db->filename);
00348         STOPIF( waa__delete_byext(db->filename, NULL, 0), 
00349                 "Cleaning up the empty hash '%s'", db->filename);
00350     }
00351     else
00352     {
00353         DEBUGP("reorganize?");
00354         
00355         if (have_removed)
00356             gdbm_reorganize(db->db);
00357     }
00358 
00359     DEBUGP("closing hash");
00360     
00361 
00362     if (db->db)
00363     {
00364         gdbm_close(db->db);
00365         db->db=NULL;
00366     }
00367 
00368 ex:
00369     if (db)
00370         IF_FREE(db->filename);
00371     IF_FREE(db);
00372 
00373     return status;
00374 }
00375 
00376 
00378 int hsh__fetch(hash_t db, datum key, datum *value)
00379 {
00380     static datum vl;
00381 
00382     if (!db) return ENOENT;
00383 
00384     vl=gdbm_fetch(db->db, key);
00385 
00386     if (value) *value=vl;
00387     else IF_FREE(vl.dptr);
00388     return (vl.dptr) ? 0 : ENOENT;
00389 }
00390 
00391 
00394 int hsh__first(hash_t db, datum *key)
00395 {
00396     datum k;
00397 
00398     if (!db) return ENOENT;
00399 
00400     k=gdbm_firstkey(db->db);
00401     if (key) *key=k;
00402     return (k.dptr) ? 0 : ENOENT;
00403 }
00404 
00405 
00410 int hsh__next(hash_t db, datum *key, const datum *oldkey)
00411 {
00412     datum k;
00413 
00414     
00415     k=gdbm_nextkey(db->db, *oldkey);
00416 
00417     
00418     if (oldkey == key) 
00419         
00420 
00421         IF_FREE(key->dptr);
00422 
00423     
00424     *key=k;
00425 
00426     return (k.dptr) ? 0 : ENOENT;
00427 }
00428 
00429 
00432 int hsh__store(hash_t db, datum key, datum value)
00433 {
00434     int status;
00435 
00436     if (value.dsize == 0 || value.dptr == NULL)
00437         status=gdbm_delete(db->db, key);
00438     else
00439         status=gdbm_store(db->db, key, value, GDBM_REPLACE);
00440 
00441     STOPIF_CODE_ERR(status < 0, errno,
00442             "Error writing property %s", key.dptr);
00443 
00444 ex:
00445     return status;
00446 }
00447 
00448 
00451 int hsh__store_charp(hash_t db, char *keyp, char *valuep)
00452 {   
00453     datum key, value;
00454 
00455     key.dptr=keyp;
00456     value.dptr=valuep;
00457 
00458     key.dsize=strlen(key.dptr)+1;
00459     value.dsize=strlen(value.dptr)+1;
00460 
00461     return hsh__store(db, key, value);
00462 }
00463 
00473 struct hsh___list
00474 {
00484     int count;
00486     void *entries[HASH__LIST_MAX];
00487 };
00488 
00489 
00494 int hsh__insert_pointer(hash_t hash, datum key, void *value)
00495 {
00496     int status;
00497     datum listd;
00498     struct hsh___list list, *dst;
00499 
00500     status=hsh__fetch(hash, key, &listd);
00501     if (status == ENOENT)
00502     {
00503         
00504         
00505 
00506         listd.dptr= (char*)&list;
00507         listd.dsize=sizeof(list);
00508 
00509         memset(&list, 0, sizeof(list));
00510         list.count=1;
00511         list.entries[0]=value;
00512 
00513         status=0;
00514     }
00515     else
00516     {
00517         
00518 
00519         BUG_ON(listd.dsize != sizeof(list));
00520 
00521         
00522         dst=(struct hsh___list*)listd.dptr;
00523         if (dst->count == HASH__LIST_MAX)
00524         {
00525             
00526 
00527             
00528 
00529             dst->count++;
00530         }
00531         else if (dst->count > HASH__LIST_MAX)
00532         {
00533             
00534             status=EFBIG;
00535         }
00536         else
00537         {
00538             
00539             dst->entries[ dst->count ] = value;
00540             dst->count++;
00541         }
00542     }
00543 
00544     if (status != EFBIG)
00545         STOPIF( hsh__store(hash, key, listd), NULL);
00546 
00547 ex:
00548     return status;
00549 }
00550 
00551 
00563 int hsh__list_get(hash_t hash, 
00564         datum current_key, datum *next_key, 
00565         struct estat **arr[], int *found)
00566 {
00567     int status;
00568     
00569     static struct estat *data[HASH__LIST_MAX+1];
00570     datum value;
00571     struct hsh___list *list;
00572     int c;
00573 
00574 
00575     status=0;
00576     *found=0;
00577     *arr=NULL;
00578     
00579     if (next_key) 
00580     {
00581         next_key->dsize=0;
00582         next_key->dptr=0;
00583     }
00584 
00585     status=hsh__fetch( hash, current_key, &value);
00586     
00587   if (status == ENOENT) goto ex;
00588     STOPIF(status, NULL);
00589 
00590     list=(struct hsh___list*)value.dptr;
00591 
00592     memset(data, 0, sizeof(data));
00593 
00594     c=list->count;
00595     
00596     if (c == HASH__LIST_MAX+1) c=HASH__LIST_MAX;
00597 
00598     BUG_ON( c<=0 || c>HASH__LIST_MAX, "number of entries=%d", c);
00599     memcpy(data, list->entries, c*sizeof(data[0]));
00600 
00601     *found=c;
00602     *arr=data;
00603 
00604 ex:
00605     return status;
00606 }
00607 
00608 
00609 int hsh__register_delete(hash_t db, datum key)
00610 {
00611     int status;
00612     const datum data= { .dsize=1, .dptr="\0", };
00613 
00614     status=0;
00615 
00616     if (!db->to_delete)
00617     {
00618         STOPIF( hsh___new_bare(NULL, "del", HASH_TEMPORARY,
00619                     &(db->to_delete), NULL), 
00620                 NULL);
00621     }
00622 
00623     DEBUGP("storing %s", key.dptr);
00624 
00625     status=gdbm_store(db->to_delete, key, data, GDBM_REPLACE);
00626     STOPIF_CODE_ERR(status < 0, errno, "Error writing key");
00627 
00628 ex:
00629     return status;
00630 }
00631 
00632