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