mirror of
https://github.com/mtheall/registry.git
synced 2025-06-18 18:45:37 -04:00
793 lines
18 KiB
C
793 lines
18 KiB
C
#include <assert.h>
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sqlite3.h>
|
|
#include "registry.h"
|
|
|
|
static char query[1024];
|
|
sqlite3 *db = NULL;
|
|
|
|
typedef uint64_t KeyId;
|
|
|
|
typedef enum {
|
|
Q_GETKEY,
|
|
Q_ADDKEY,
|
|
Q_ADDKEY2,
|
|
Q_ADDKEY3,
|
|
Q_GETKEYTYPE,
|
|
Q_SETNUMBER,
|
|
Q_SETSTRING,
|
|
Q_SETRAW,
|
|
Q_SETRAW2,
|
|
Q_SETRAW3,
|
|
Q_DELKEY,
|
|
Q_GETKPNUM,
|
|
Q_GETKPSTR,
|
|
Q_GETKPRAW,
|
|
} Query;
|
|
|
|
static struct {
|
|
sqlite3_stmt *stmt;
|
|
const char * const query;
|
|
} queries[] = {
|
|
[Q_GETKEY] = { NULL, "select rowid from key where name = ? and parent = ?;", },
|
|
[Q_ADDKEY] = { NULL, "select * from key where parent = ? and name = ?;", },
|
|
[Q_ADDKEY2] = { NULL, "insert into key (parent, name, type) values(?, ?, ?);", },
|
|
[Q_ADDKEY3] = { NULL, "update key set parent = ? where rowid = ?;", },
|
|
[Q_GETKEYTYPE] = { NULL, "select type from key where rowid = ?;", },
|
|
[Q_SETNUMBER] = { NULL, "update number set value = ? where parent = ?;", },
|
|
[Q_SETSTRING] = { NULL, "update string set value = ? where parent = ?;", },
|
|
[Q_SETRAW] = { NULL, "update raw set value = ? where parent = ?;", },
|
|
[Q_SETRAW2] = { NULL, "insert into raw (parent, value) values(?, ?);", },
|
|
[Q_SETRAW3] = { NULL, "update key set type = ? where rowid = ?;", },
|
|
[Q_DELKEY] = { NULL, "delete from key where rowid = ?;", },
|
|
[Q_GETKPNUM] = { NULL, "select value from number where parent = ?;", },
|
|
[Q_GETKPSTR] = { NULL, "select value from string where parent = ?;", },
|
|
[Q_GETKPRAW] = { NULL, "select value from raw where parent = ?;", },
|
|
};
|
|
|
|
static char errs[] = {
|
|
[SQLITE_OK] = 0,
|
|
[SQLITE_ERROR] = EIO,
|
|
[SQLITE_INTERNAL] = EIO,
|
|
[SQLITE_PERM] = EPERM,
|
|
[SQLITE_ABORT] = EIO,
|
|
[SQLITE_BUSY] = EBUSY,
|
|
[SQLITE_LOCKED] = EIO,
|
|
[SQLITE_NOMEM] = ENOMEM,
|
|
[SQLITE_READONLY] = EBADF,
|
|
[SQLITE_INTERRUPT] = EINTR,
|
|
[SQLITE_IOERR] = EIO,
|
|
[SQLITE_CORRUPT] = EILSEQ,
|
|
[SQLITE_NOTFOUND] = EIO,
|
|
[SQLITE_FULL] = ENOSPC,
|
|
[SQLITE_CANTOPEN] = EIO,
|
|
[SQLITE_PROTOCOL] = EIO,
|
|
[SQLITE_EMPTY] = ENODATA,
|
|
[SQLITE_SCHEMA] = EIO,
|
|
[SQLITE_TOOBIG] = EOVERFLOW,
|
|
[SQLITE_CONSTRAINT] = EIO,
|
|
[SQLITE_MISMATCH] = EIO,
|
|
[SQLITE_MISUSE] = EIO,
|
|
[SQLITE_NOLFS] = ENOSYS,
|
|
[SQLITE_AUTH] = EPERM,
|
|
[SQLITE_FORMAT] = EIO,
|
|
[SQLITE_RANGE] = ERANGE,
|
|
[SQLITE_NOTADB] = ENODEV,
|
|
};
|
|
|
|
static inline KeyId regGetKey(const char *path);
|
|
static inline KeyType regGetKeyType(KeyId id);
|
|
static inline int regInit(void);
|
|
|
|
static inline int errmap(int sqlite_err) {
|
|
if(sqlite_err >= SQLITE_OK && sqlite_err <= SQLITE_NOTADB)
|
|
return errs[sqlite_err];
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
static inline sqlite3_stmt* LOAD(int x) {
|
|
int rc;
|
|
if(queries[x].stmt == NULL) {
|
|
rc = sqlite3_prepare_v2(db, queries[x].query, strlen(queries[x].query)+1, &queries[x].stmt, NULL);
|
|
if(rc != SQLITE_OK) {
|
|
errno = errmap(sqlite3_errcode(db));
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
return queries[x].stmt;
|
|
}
|
|
|
|
int regOpen(void) {
|
|
int rc;
|
|
int flags = SQLITE_OPEN_READWRITE;
|
|
if(db == NULL) {
|
|
rc = sqlite3_open_v2("/data/FeOS/registry.bin", &db, flags, NULL);
|
|
if(rc == SQLITE_CANTOPEN) {
|
|
flags |= SQLITE_OPEN_CREATE;
|
|
rc = sqlite3_open_v2("/data/FeOS/registry.bin", &db, flags, NULL);
|
|
}
|
|
if(rc != SQLITE_OK) {
|
|
errno = errmap(sqlite3_errcode(db));
|
|
return -1;
|
|
}
|
|
rc = sqlite3_exec(db, "pragma journal_mode = memory;", NULL, NULL, NULL);
|
|
assert(rc == SQLITE_OK);
|
|
rc = sqlite3_exec(db, "pragma foreign_keys = on;", NULL, NULL, NULL);
|
|
assert(rc == SQLITE_OK);
|
|
|
|
if((flags & SQLITE_OPEN_CREATE) && regInit()) {
|
|
errno = errmap(sqlite3_errcode(db));
|
|
return -1;
|
|
}
|
|
}
|
|
else {
|
|
errno = EBUSY;
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int regClose(void) {
|
|
int rc;
|
|
int i;
|
|
|
|
for(i = 0; i < sizeof(queries)/sizeof(queries[0]); i++) {
|
|
rc = sqlite3_finalize(queries[i].stmt);
|
|
assert(rc == SQLITE_OK);
|
|
queries[i].stmt = NULL;
|
|
}
|
|
|
|
rc = sqlite3_close(db);
|
|
assert(rc == SQLITE_OK);
|
|
(void)rc;
|
|
db = NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static inline int regInit(void) {
|
|
int rc;
|
|
|
|
rc = sqlite3_exec(db, "drop table if exists key; "
|
|
"drop table if exists number; "
|
|
"drop table if exists string; "
|
|
"drop table if exists raw; "
|
|
"create table key (id integer primary key autoincrement, parent int references key(id) on delete cascade, name text, type int); "
|
|
"create table number(id integer primary key autoincrement, parent int references key(id) on delete cascade, value int); "
|
|
"create table string(id integer primary key autoincrement, parent int references key(id) on delete cascade, value text); "
|
|
"create table raw (id integer primary key autoincrement, parent int references key(id) on delete cascade, value blob); "
|
|
"insert into key (id, parent, name, type) values (0, 0, '/', 0)",
|
|
NULL, NULL, NULL);
|
|
if(rc != SQLITE_OK) {
|
|
errno = errmap(sqlite3_errcode(db));
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
KeyId regGetKey(const char *path) {
|
|
sqlite3_stmt *stmt;
|
|
int rc;
|
|
char *_path;
|
|
char *part;
|
|
sqlite3_int64 parent = 0;
|
|
sqlite3_int64 id;
|
|
|
|
stmt = LOAD(Q_GETKEY); /* "select rowid from key where name = ? and parent = ?;" */
|
|
if(stmt == NULL)
|
|
return 0;
|
|
|
|
_path = strdup(path);
|
|
if(_path == NULL) {
|
|
errno = ENOMEM;
|
|
return 0;
|
|
}
|
|
|
|
part = strtok(_path, "/");
|
|
if(part == NULL) {
|
|
free(_path);
|
|
errno = EINVAL;
|
|
return 0;
|
|
}
|
|
|
|
while(part) {
|
|
rc = sqlite3_reset(stmt);
|
|
assert(rc == SQLITE_OK);
|
|
rc = sqlite3_bind_text(stmt, 1, part, strlen(part), SQLITE_STATIC);
|
|
assert(rc == SQLITE_OK);
|
|
rc = sqlite3_bind_int64(stmt, 2, parent);
|
|
assert(rc == SQLITE_OK);
|
|
|
|
rc = sqlite3_step(stmt);
|
|
if(rc == SQLITE_DONE) { /* empty result */
|
|
errno = ENOENT;
|
|
free(_path);
|
|
return 0;
|
|
}
|
|
assert(rc == SQLITE_ROW);
|
|
|
|
part = strtok(NULL, "/");
|
|
if(part)
|
|
parent = sqlite3_column_int64(stmt, 0);
|
|
}
|
|
|
|
id = sqlite3_column_int64(stmt, 0);
|
|
free(_path);
|
|
return id;
|
|
}
|
|
|
|
int regAddKey(const char *path) {
|
|
sqlite3_stmt *stmt;
|
|
int rc;
|
|
int len;
|
|
const char *name;
|
|
char *base;
|
|
sqlite3_int64 parent = 0;
|
|
sqlite3_int64 id;
|
|
|
|
len = strlen(path);
|
|
|
|
stmt = LOAD(Q_ADDKEY); /* "select * from key where parent = ? and name = ?;" */
|
|
if(stmt == NULL)
|
|
/* errno from LOAD */
|
|
return -1;
|
|
|
|
base = strdup(path);
|
|
if(base == NULL) {
|
|
errno = ENOMEM;
|
|
return -1;
|
|
}
|
|
|
|
while(len && path[len] != '/')
|
|
len--;
|
|
name = path+len+1;
|
|
base[len] = 0;
|
|
|
|
if(strcmp(base, "") == 0)
|
|
parent = 0;
|
|
else if((parent = regGetKey(base)) == 0) {
|
|
if(errno == ENOENT) {
|
|
if(regAddKey(base)) {
|
|
free(base);
|
|
/* errno from regAddKey */
|
|
return -1;
|
|
}
|
|
if((parent = regGetKey(base)) == 0) {
|
|
free(base);
|
|
/* errno from regGetKey */
|
|
return -1;
|
|
}
|
|
}
|
|
else {
|
|
free(base);
|
|
/* errno from regGetKey */
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
rc = sqlite3_reset(stmt);
|
|
assert(rc == SQLITE_OK);
|
|
rc = sqlite3_bind_int64(stmt, 1, parent);
|
|
assert(rc == SQLITE_OK);
|
|
rc = sqlite3_bind_text(stmt, 2, name, strlen(name), SQLITE_STATIC);
|
|
assert(rc == SQLITE_OK);
|
|
|
|
rc = sqlite3_step(stmt);
|
|
if(rc == SQLITE_DONE) {
|
|
stmt = LOAD(Q_ADDKEY2); /* "insert into key (parent, name, type) values(?, ?, ?);" */
|
|
if(stmt == NULL)
|
|
/* errno from LOAD */
|
|
return -1;
|
|
|
|
if(LOAD(Q_ADDKEY3) == NULL)
|
|
/* errno from LOAD */
|
|
return -1;
|
|
|
|
rc = sqlite3_reset(stmt);
|
|
assert(rc == SQLITE_OK);
|
|
rc = sqlite3_bind_int64(stmt, 1, parent);
|
|
assert(rc == SQLITE_OK);
|
|
rc = sqlite3_bind_text(stmt, 2, name, strlen(name), SQLITE_STATIC);
|
|
assert(rc == SQLITE_OK);
|
|
rc = sqlite3_bind_int(stmt, 3, KEY_VOID);
|
|
assert(rc == SQLITE_OK);
|
|
|
|
rc = sqlite3_step(stmt);
|
|
if(rc != SQLITE_DONE) {
|
|
errno = errmap(sqlite3_errcode(db));
|
|
return -1;
|
|
}
|
|
id = sqlite3_last_insert_rowid(db);
|
|
|
|
stmt = LOAD(Q_ADDKEY3); /* "update key set parent = ? where rowid = ?;" */
|
|
assert(stmt != NULL);
|
|
|
|
rc = sqlite3_reset(stmt);
|
|
assert(rc == SQLITE_OK);
|
|
rc = sqlite3_bind_int64(stmt, 1, parent);
|
|
assert(rc == SQLITE_OK);
|
|
rc = sqlite3_bind_int64(stmt, 2, id);
|
|
assert(rc == SQLITE_OK);
|
|
|
|
rc = sqlite3_step(stmt);
|
|
assert(rc == SQLITE_DONE);
|
|
|
|
free(base);
|
|
return 0;
|
|
}
|
|
|
|
assert(rc == SQLITE_ROW);
|
|
errno = EEXIST;
|
|
|
|
free(base);
|
|
return -1;
|
|
}
|
|
|
|
KeyType regGetKeyType(KeyId id) {
|
|
int rc;
|
|
sqlite3_stmt *stmt;
|
|
KeyType type;
|
|
|
|
stmt = LOAD(Q_GETKEYTYPE); /* "select type from key where rowid = ?;" */
|
|
if(stmt == NULL)
|
|
/* errno from LOAD */
|
|
return -1;
|
|
|
|
rc = sqlite3_reset(stmt);
|
|
assert(rc == SQLITE_OK);
|
|
rc = sqlite3_bind_int64(stmt, 1, id);
|
|
assert(rc == SQLITE_OK);
|
|
|
|
rc = sqlite3_step(stmt);
|
|
if(rc == SQLITE_DONE) {
|
|
errno = ENOENT;
|
|
return -1;
|
|
}
|
|
assert(rc == SQLITE_ROW);
|
|
|
|
type = sqlite3_column_int(stmt, 0);
|
|
if(type < KEY_VOID || type > KEY_RAW) {
|
|
errno = EILSEQ;
|
|
return -1;
|
|
}
|
|
|
|
return type;
|
|
}
|
|
|
|
int regDelKey(const char *path) {
|
|
int rc;
|
|
sqlite3_stmt *stmt;
|
|
KeyId id;
|
|
|
|
stmt = LOAD(Q_DELKEY); /* "delete from key where rowid = ?;" */
|
|
if(stmt == NULL)
|
|
/* errno from LOAD */
|
|
return -1;
|
|
|
|
id = regGetKey(path);
|
|
if(id == 0)
|
|
/* errno from regGetKey */
|
|
return -1;
|
|
|
|
rc = sqlite3_reset(stmt);
|
|
assert(rc == SQLITE_OK);
|
|
rc = sqlite3_bind_int64(stmt, 1, id);
|
|
assert(rc == SQLITE_OK);
|
|
|
|
|
|
rc = sqlite3_step(stmt);
|
|
if(rc != SQLITE_DONE) {
|
|
errno = errmap(sqlite3_errcode(db));
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int regSetVoid(const char *path) {
|
|
int rc;
|
|
KeyId id;
|
|
KeyType type;
|
|
|
|
id = regGetKey(path);
|
|
if(id == 0) {
|
|
if(errno == ENOENT) {
|
|
if(regAddKey(path))
|
|
/* errno from regAddKey */
|
|
return -1;
|
|
id = regGetKey(path);
|
|
if(id == 0)
|
|
/* errno from regGetKey */
|
|
return -1;
|
|
}
|
|
else
|
|
/* errno from regGetKey */
|
|
return -1;
|
|
}
|
|
|
|
type = regGetKeyType(id);
|
|
switch(type) {
|
|
case KEY_NUMBER:
|
|
sprintf(query, "delete from number where parent = %lld;", id);
|
|
rc = sqlite3_exec(db, query, NULL, NULL, NULL);
|
|
assert(rc == SQLITE_OK);
|
|
break;
|
|
case KEY_STRING:
|
|
sprintf(query, "delete from string where parent = %lld;", id);
|
|
rc = sqlite3_exec(db, query, NULL, NULL, NULL);
|
|
assert(rc == SQLITE_OK);
|
|
break;
|
|
case KEY_RAW:
|
|
sprintf(query, "delete from raw where parent = %lld;", id);
|
|
rc = sqlite3_exec(db, query, NULL, NULL, NULL);
|
|
assert(rc == SQLITE_OK);
|
|
break;
|
|
case KEY_VOID:
|
|
return 0;
|
|
default:
|
|
/* errno from regGetKeyType */
|
|
return -1;
|
|
}
|
|
|
|
sprintf(query, "update key set type = %d where rowid = %lld;", KEY_VOID, id);
|
|
rc = sqlite3_exec(db, query, NULL, NULL, NULL);
|
|
assert(rc == SQLITE_OK);
|
|
(void)rc;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int regSetNumber(const char *path, uint64_t value) {
|
|
int rc;
|
|
KeyId id;
|
|
KeyType type;
|
|
sqlite3_stmt *stmt;
|
|
|
|
id = regGetKey(path);
|
|
if(id == 0) {
|
|
if(errno == ENOENT) {
|
|
if(regAddKey(path))
|
|
/* errno from regAddKey */
|
|
return -1;
|
|
id = regGetKey(path);
|
|
if(id == 0)
|
|
/* errno from regGetKey */
|
|
return -1;
|
|
}
|
|
else
|
|
/* errno from regGetKey */
|
|
return -1;
|
|
}
|
|
|
|
type = regGetKeyType(id);
|
|
if(type == -1)
|
|
/* errno from regGetKeyType */
|
|
return -1;
|
|
if(type == KEY_NUMBER) {
|
|
stmt = LOAD(Q_SETNUMBER); /* "update number set value = ? where parent = ?;" */
|
|
if(stmt == NULL)
|
|
/* errno from LOAD */
|
|
return -1;
|
|
|
|
rc = sqlite3_reset(stmt);
|
|
assert(rc == SQLITE_OK);
|
|
rc = sqlite3_bind_int64(stmt, 1, value);
|
|
assert(rc == SQLITE_OK);
|
|
rc = sqlite3_bind_int64(stmt, 2, id);
|
|
assert(rc == SQLITE_OK);
|
|
|
|
rc = sqlite3_step(stmt);
|
|
if(rc != SQLITE_DONE) {
|
|
errno = errmap(sqlite3_errcode(db));
|
|
return -1;
|
|
}
|
|
}
|
|
else if(type != KEY_VOID && regSetVoid(path))
|
|
/* errno from regSetVoid */
|
|
return -1;
|
|
else {
|
|
sprintf(query,
|
|
"insert into number (parent, value) values(%lld, %lld); update key set type = %d where rowid = %lld;",
|
|
id, value,
|
|
KEY_NUMBER, id);
|
|
rc = sqlite3_exec(db, query, NULL, NULL, NULL);
|
|
if(rc != SQLITE_OK) {
|
|
errno = errmap(sqlite3_errcode(db));
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int regSetString(const char *path, const char *value) {
|
|
int rc;
|
|
KeyId id;
|
|
KeyType type;
|
|
sqlite3_stmt *stmt;
|
|
|
|
id = regGetKey(path);
|
|
if(id == 0) {
|
|
if(errno == ENOENT) {
|
|
if(regAddKey(path))
|
|
/* errno from regAddKey */
|
|
return -1;
|
|
id = regGetKey(path);
|
|
if(id == 0)
|
|
/* errno from regGetKey */
|
|
return -1;
|
|
}
|
|
else
|
|
/* errno from regGetKey */
|
|
return -1;
|
|
}
|
|
|
|
type = regGetKeyType(id);
|
|
if(type == -1)
|
|
/* errno from regGetKeyType */
|
|
return -1;
|
|
if(type == KEY_STRING) {
|
|
stmt = LOAD(Q_SETSTRING); /* "update string set value = ? where parent = ?;" */
|
|
if(stmt == NULL)
|
|
/* errno from LOAD */
|
|
return -1;
|
|
|
|
rc = sqlite3_reset(stmt);
|
|
assert(rc == SQLITE_OK);
|
|
rc = sqlite3_bind_text(stmt, 1, value, strlen(value), SQLITE_STATIC);
|
|
assert(rc == SQLITE_OK);
|
|
rc = sqlite3_bind_int64(stmt, 2, id);
|
|
assert(rc == SQLITE_OK);
|
|
|
|
rc = sqlite3_step(stmt);
|
|
if(rc != SQLITE_DONE) {
|
|
errno = errmap(sqlite3_errcode(db));
|
|
return -1;
|
|
}
|
|
}
|
|
else if(type != KEY_VOID && regSetVoid(path))
|
|
/* errno from regSetVoid */
|
|
return -1;
|
|
else {
|
|
sqlite3_snprintf(sizeof(query), query,
|
|
"insert into string (parent, value) values(%lld, %Q); update key set type = %d where rowid = %lld;",
|
|
id, value,
|
|
KEY_STRING, id);
|
|
rc = sqlite3_exec(db, query, NULL, NULL, NULL);
|
|
if(rc != SQLITE_OK) {
|
|
errno = errmap(sqlite3_errcode(db));
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int regSetRaw(const char *path, const void *value, size_t length) {
|
|
int rc;
|
|
KeyId id;
|
|
KeyType type;
|
|
sqlite3_stmt *stmt;
|
|
|
|
stmt = LOAD(Q_SETRAW); /* "update raw set value = ? where parent = ?;" */
|
|
if(stmt == NULL)
|
|
/* errno from LOAD */
|
|
return -1;
|
|
|
|
id = regGetKey(path);
|
|
if(id == 0) {
|
|
if(errno == ENOENT) {
|
|
if(regAddKey(path))
|
|
/* errno from regAddKey */
|
|
return -1;
|
|
id = regGetKey(path);
|
|
if(id == 0)
|
|
/* errno from regGetKey */
|
|
return -1;
|
|
}
|
|
else
|
|
/* errno from regGetKey */
|
|
return -1;
|
|
}
|
|
|
|
type = regGetKeyType(id);
|
|
if(type == -1)
|
|
/* errno from regGetKeyType */
|
|
return -1;
|
|
if(type == KEY_RAW) {
|
|
rc = sqlite3_reset(stmt);
|
|
assert(rc == SQLITE_OK);
|
|
rc = sqlite3_bind_blob(stmt, 1, value, length, SQLITE_STATIC);
|
|
assert(rc == SQLITE_OK);
|
|
rc = sqlite3_bind_int64(stmt, 2, id) != SQLITE_OK;
|
|
assert(rc == SQLITE_OK);
|
|
|
|
rc = sqlite3_step(stmt);
|
|
assert(rc == SQLITE_DONE);
|
|
}
|
|
else if(type != KEY_VOID && regSetVoid(path))
|
|
/* errno from regSetVoid */
|
|
return -1;
|
|
else {
|
|
stmt = LOAD(Q_SETRAW2); /* "insert into raw (parent, value) values(?, ?);" */
|
|
if(stmt == NULL)
|
|
/* errno from LOAD */
|
|
return -1;
|
|
|
|
if(LOAD(Q_SETRAW3) == NULL)
|
|
/* errno from LOAD */
|
|
return -1;
|
|
|
|
rc = sqlite3_reset(stmt);
|
|
assert(rc == SQLITE_OK);
|
|
rc = sqlite3_bind_int64(stmt, 1, id);
|
|
assert(rc == SQLITE_OK);
|
|
rc = sqlite3_bind_blob(stmt, 2, value, length, SQLITE_STATIC);
|
|
assert(rc == SQLITE_OK);
|
|
|
|
rc = sqlite3_step(stmt);
|
|
if(rc != SQLITE_DONE) {
|
|
errno = errmap(sqlite3_errcode(db));
|
|
return -1;
|
|
}
|
|
|
|
stmt = LOAD(Q_SETRAW3); /* "update key set type = ? where rowid = ?;" */
|
|
assert(stmt != NULL);
|
|
|
|
rc = sqlite3_reset(stmt);
|
|
assert(rc == SQLITE_OK);
|
|
rc = sqlite3_bind_int(stmt, 1, KEY_RAW);
|
|
assert(rc == SQLITE_OK);
|
|
rc = sqlite3_bind_int64(stmt, 2, id);
|
|
assert(rc == SQLITE_OK);
|
|
|
|
rc = sqlite3_step(stmt);
|
|
if(rc != SQLITE_DONE) {
|
|
errno = errmap(sqlite3_errcode(db));
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
KeyPair* regGetKeyPair(const char *name) {
|
|
sqlite3_int64 id;
|
|
KeyPair *key;
|
|
sqlite3_stmt *stmt;
|
|
int rc;
|
|
(void)rc;
|
|
|
|
key = malloc(sizeof(KeyPair));
|
|
if(key == NULL) {
|
|
errno = ENOMEM;
|
|
return NULL;
|
|
}
|
|
|
|
key->name = strdup(name);
|
|
if(key->name == NULL) {
|
|
errno = ENOMEM;
|
|
free(key);
|
|
return NULL;
|
|
}
|
|
|
|
id = regGetKey(name);
|
|
if(id == 0) {
|
|
errno = ENOENT;
|
|
goto err;
|
|
}
|
|
|
|
key->type = regGetKeyType(id);
|
|
|
|
switch(key->type) {
|
|
case KEY_VOID:
|
|
break;
|
|
|
|
case KEY_NUMBER:
|
|
stmt = LOAD(Q_GETKPNUM); /* "select value from number where parent = ?;" */
|
|
if(stmt == NULL)
|
|
goto err;
|
|
|
|
rc = sqlite3_reset(stmt);
|
|
assert(rc == SQLITE_OK);
|
|
rc = sqlite3_bind_int64(stmt, 1, id);
|
|
assert(rc == SQLITE_OK);
|
|
|
|
rc = sqlite3_step(stmt);
|
|
assert(rc == SQLITE_ROW);
|
|
key->number = sqlite3_column_int64(stmt, 0);
|
|
key->length = sizeof(key->number);
|
|
|
|
break;
|
|
|
|
case KEY_STRING:
|
|
stmt = LOAD(Q_GETKPSTR); /* "select value from string where parent = ?;" */
|
|
if(stmt == NULL)
|
|
goto err;
|
|
|
|
rc = sqlite3_reset(stmt);
|
|
assert(rc == SQLITE_OK);
|
|
rc = sqlite3_bind_int64(stmt, 1, id);
|
|
assert(rc == SQLITE_OK);
|
|
|
|
rc = sqlite3_step(stmt);
|
|
assert(rc == SQLITE_ROW);
|
|
key->string = strdup((char*)sqlite3_column_text(stmt, 0));
|
|
|
|
if(key->string == NULL) {
|
|
errno = ENOMEM;
|
|
goto err;
|
|
}
|
|
key->length = strlen(key->string)+1;
|
|
|
|
break;
|
|
|
|
case KEY_RAW:
|
|
stmt = LOAD(Q_GETKPRAW); /* "select value from raw where parent = ?;" */
|
|
if(stmt == NULL)
|
|
goto err;
|
|
|
|
rc = sqlite3_reset(stmt);
|
|
assert(rc == SQLITE_OK);
|
|
rc = sqlite3_bind_int64(stmt, 1, id);
|
|
assert(rc == SQLITE_OK);
|
|
|
|
rc = sqlite3_step(stmt);
|
|
assert(rc == SQLITE_ROW);
|
|
key->length = sqlite3_column_bytes(stmt, 0);
|
|
|
|
key->raw = malloc(key->length);
|
|
if(key->raw == NULL) {
|
|
errno = ENOMEM;
|
|
goto err;
|
|
}
|
|
memcpy(key->raw, sqlite3_column_blob(stmt, 0), key->length);
|
|
|
|
break;
|
|
|
|
default:
|
|
/* errno from regGetKeyType */
|
|
goto err;
|
|
}
|
|
|
|
return key;
|
|
|
|
err:
|
|
free(key->name);
|
|
free(key);
|
|
return NULL;
|
|
}
|
|
|
|
int regFreeKeyPair(KeyPair *kp) {
|
|
if(kp) {
|
|
switch(kp->type) {
|
|
case KEY_VOID:
|
|
case KEY_NUMBER:
|
|
break;
|
|
case KEY_STRING:
|
|
free(kp->string);
|
|
break;
|
|
case KEY_RAW:
|
|
free(kp->raw);
|
|
break;
|
|
default:
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
free(kp->name);
|
|
free(kp);
|
|
return 0;
|
|
}
|
|
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
|