vsdb_ret_t vsdb_set(vsdb_t vsdb, const char *key, size_t key_length, const void *value, size_t value_size) { DB *db; DBT kt, dt; int ret; if ((db = getdb(vsdb)) == NULL) goto failed; if (key == NULL) goto failed; if (key_length == SIZE_T_MAX) key_length = strlen(key); if (key_length == 0) goto failed; kt.data = (void *)key; kt.size = key_length; if (value != NULL) { dt.data = (void *)value; dt.size = value_size; lockdb(vsdb); ret = db->put(db, &kt, &dt, 0); unlockdb(vsdb); if (ret != 0) { goto failed; } } else { lockdb(vsdb); ret = db->del(db, &kt, 0); unlockdb(vsdb); if (ret != 0) { goto failed; } } return vsdb_okay; failed: return vsdb_failed; }
int writedb(const char *iface, const char *dirname, int newdb) { FILE *db; char file[512], backup[512]; snprintf(file, 512, "%s/%s", dirname, iface); snprintf(backup, 512, "%s/.%s", dirname, iface); /* try to make backup of old data if this isn't a new database */ if (!newdb && !backupdb(file, backup)) { snprintf(errorstring, 512, "Unable to create database backup \"%s\".", backup); printe(PT_Error); return 0; } /* make sure version stays correct */ data.version=DBVERSION; if ((db=fopen(file,"w"))==NULL) { snprintf(errorstring, 512, "Unable to open database \"%s\" for writing: %s", file, strerror(errno)); printe(PT_Error); return 0; } /* lock file */ if (!lockdb(fileno(db), 1)) { fclose(db); return 0; } /* update timestamp when not merging */ if (newdb!=2) { data.lastupdated=time(NULL); } if (fwrite(&data,sizeof(DATA),1,db)==0) { snprintf(errorstring, 512, "Unable to write database \"%s\": %s", file, strerror(errno)); printe(PT_Error); fclose(db); return 0; } else { if (debug) { printf("db: Database \"%s\" saved.\n", file); } fclose(db); if ((newdb) && (noexit==0)) { snprintf(errorstring, 512, "-> A new database has been created."); printe(PT_Info); } } return 1; }
vsdb_ret_t vsdb_sync(vsdb_t vsdb) { DB *db; int ret; if ((db = getdb(vsdb)) != NULL) { lockdb(vsdb); ret = db->sync(db, 0); unlockdb(vsdb); if (ret == 0) { return vsdb_okay; } } return vsdb_failed; }
vsdb_ret_t vsdb_get(vsdb_t vsdb, const char *key, size_t key_length, const void **value, size_t *value_size) { DB *db; DBT kt, dt; DBT newdt; int ret; if ((db = getdb(vsdb)) == NULL) goto failed; if (key == NULL || value == NULL || value_size == NULL) goto failed; if (key_length == SIZE_T_MAX) key_length = strlen(key); if (key_length == 0) goto failed; kt.data = (void *)key; kt.size = key_length; lockdb(vsdb); ret = db->get(db, &kt, &dt, 0); unlockdb(vsdb); if (ret == 0) { dup_dbt(&newdt, &dt); *value = newdt.data; *value_size = newdt.size; return vsdb_okay; } failed: if (value != NULL) *value = NULL; if (value_size != NULL) *value_size = 0; return vsdb_failed; }
int readdb(const char *iface, const char *dirname) { FILE *db; char file[512], backup[512]; int newdb=0; snprintf(file, 512, "%s/%s", dirname, iface); snprintf(backup, 512, "%s/.%s", dirname, iface); if ((db=fopen(file,"r"))!=NULL) { /* lock file */ if (!lockdb(fileno(db), 0)) { return -1; } if (fread(&data,sizeof(DATA),1,db)==0) { data.version=-1; if (debug) { printf("db: Database read failed for file \"%s\".\n", file); } } else { if (debug) { printf("db: Database loaded for interface \"%s\"...\n", data.interface); } } /* convert old database to new format if necessary */ if (data.version<DBVERSION) { if (data.version!=-1) { snprintf(errorstring, 512, "Trying to convert database \"%s\" (v%d) to current db format", file, data.version); printe(PT_Info); } if ((data.version==-1) || (!convertdb(db))) { /* close current db and try using backup if database conversion failed */ fclose(db); if ((db=fopen(backup,"r"))!=NULL) { /* lock file */ if (!lockdb(fileno(db), 0)) { fclose(db); return -1; } if (fread(&data,sizeof(DATA),1,db)==0) { snprintf(errorstring, 512, "Database load failed even when using backup. Aborting."); printe(PT_Error); fclose(db); if (noexit) { return -1; } else { exit(EXIT_FAILURE); } } else { if (debug) { printf("db: Database loaded for interface \"%s\"...\n", data.interface); } } if (data.version!=DBVERSION) { if (!convertdb(db)) { snprintf(errorstring, 512, "Unable to use backup database."); printe(PT_Error); fclose(db); if (noexit) { return -1; } else { exit(EXIT_FAILURE); } } } snprintf(errorstring, 512, "Database possibly corrupted, using backup instead."); printe(PT_Info); } else { snprintf(errorstring, 512, "Unable to open backup database \"%s\".", backup); printe(PT_Error); if (noexit) { return -1; } else { exit(EXIT_FAILURE); } } } } else if (data.version>DBVERSION) { snprintf(errorstring, 512, "Downgrading database \"%s\" (v%d) is not supported.", file, data.version); printe(PT_Error); fclose(db); if (noexit) { return -1; } else { exit(EXIT_FAILURE); } } fclose(db); if (strcmp(data.interface,iface)) { snprintf(errorstring, 512, "Warning:\nThe previous interface for this file was \"%s\".",data.interface); printe(PT_Multiline); snprintf(errorstring, 512, "It has now been replaced with \"%s\".",iface); printe(PT_Multiline); snprintf(errorstring, 512, "You can ignore this message if you renamed the filename."); printe(PT_Multiline); snprintf(errorstring, 512, "Interface name mismatch, renamed \"%s\" -> \"%s\"", data.interface, iface); printe(PT_ShortMultiline); if (strcmp(data.interface, data.nick)==0) { strncpy(data.nick, iface, 32); } strncpy(data.interface, iface, 32); } } else { snprintf(errorstring, 512, "Unable to read database \"%s\".",file); printe(PT_Error); newdb=1; initdb(); strncpy(data.interface, iface, 32); strncpy(data.nick, data.interface, 32); } return newdb; }
vsdb_ret_t vsdb_glob(vsdb_t vsdb, const char *glob, size_t glob_length, const char ***keys, size_t **key_lengths, const void ***values, size_t **value_sizes, size_t *count) { DB *db; DBT kt, dt; vsdb_ret_t vsdb_ret; int ret; size_t i; struct { DBT *kts, *dts; size_t count; size_t capacity; } buf; vsdb_ret = vsdb_okay; bzero(&buf, sizeof(buf)); lockdb(vsdb); if ((db = getdb(vsdb)) == NULL) goto failed; if (glob == NULL) goto failed; if (glob_length == SIZE_T_MAX) glob_length = strlen(glob); if (glob_length == 0) goto failed; if (keys == NULL || key_lengths == NULL || values == NULL || value_sizes == NULL) goto failed; if (count == NULL) goto failed; if (glob_length == 1 && glob[0] == '*') { if ((ret = db->seq(db, &kt, &dt, R_FIRST)) < 0) { goto failed; } else if (ret == 0) { do { if (buf.count == buf.capacity) { if (buf.capacity == 0) { buf.capacity = 16; buf.kts = (DBT *)malloc(sizeof(DBT) * buf.capacity); buf.dts = (DBT *)malloc(sizeof(DBT) * buf.capacity); } else { buf.capacity <<= 1; buf.kts = (DBT *)realloc(buf.kts, sizeof(DBT) * buf.capacity); buf.dts = (DBT *)realloc(buf.dts, sizeof(DBT) * buf.capacity); } } dup_dbt(&buf.kts[buf.count], &kt); dup_dbt(&buf.dts[buf.count], &dt); buf.count++; } while ((ret = db->seq(db, &kt, &dt, R_NEXT)) == 0); if (ret < 0) { goto failed; } } } else if (glob_length > 0 && glob[glob_length - 1] == '*') { kt.data = (void *)glob; kt.size = glob_length - 1; if ((ret = db->seq(db, &kt, &dt, R_CURSOR)) < 0) { goto failed; } else if (ret == 0) { do { if (buf.count == buf.capacity) { if (buf.capacity == 0) { buf.capacity = 16; buf.kts = (DBT *)malloc(sizeof(DBT) * buf.capacity); buf.dts = (DBT *)malloc(sizeof(DBT) * buf.capacity); } else { buf.capacity <<= 1; buf.kts = (DBT *)realloc(buf.kts, sizeof(DBT) * buf.capacity); buf.dts = (DBT *)realloc(buf.dts, sizeof(DBT) * buf.capacity); } } if (strncmp((const char *)kt.data, glob, ((glob_length - 1) < kt.size) ? (glob_length - 1) : kt.size) != 0) { break; } dup_dbt(&buf.kts[buf.count], &kt); dup_dbt(&buf.dts[buf.count], &dt); buf.count++; } while ((ret = db->seq(db, &kt, &dt, R_NEXT)) == 0); if (ret < 0) { goto failed; } } } else { goto failed; } if (buf.count > 0) { *keys = (const char **)malloc(sizeof(const char *) * buf.count); *key_lengths = (size_t *)malloc(sizeof(size_t) * buf.count); *values = (const void **)malloc(sizeof(const void *) * buf.count); *value_sizes = (size_t *)malloc(sizeof(size_t) * buf.count); *count = buf.count; for (i = 0; i < buf.count; i++) { (*keys)[i] = (const char *)buf.kts[i].data; (*key_lengths)[i] = buf.kts[i].size; (*values)[i] = buf.dts[i].data; (*value_sizes)[i] = buf.dts[i].size; } goto cleanup; } else { goto reset; } failed: vsdb_ret = vsdb_failed; reset: if (keys != NULL) *keys = NULL; if (key_lengths != NULL) *key_lengths = NULL; if (values != NULL) *values = NULL; if (value_sizes != NULL) *value_sizes = NULL; if (count != NULL) *count = 0; cleanup: unlockdb(vsdb); if (buf.capacity > 0) { free(buf.kts); free(buf.dts); } return vsdb_ret; }