# HG changeset patch # User Tero Marttila # Date 1223812626 -10800 # Node ID 82cfdb6680d12df4c06f3996f9c2ebfd3b8378a8 # Parent 1dee73ae4ad06fd3c2346529b7ca76b340622fc7 working dbfs.lookup diff -r 1dee73ae4ad0 -r 82cfdb6680d1 Makefile --- a/Makefile Sun Oct 12 01:09:00 2008 +0300 +++ b/Makefile Sun Oct 12 14:57:06 2008 +0300 @@ -9,7 +9,7 @@ DEFINES = -D_FILE_OFFSET_BITS=64 MY_CFLAGS = -Wall -g -std=gnu99 -BIN_NAMES = helloworld hello simple_hello evpq_test url_test +BIN_NAMES = helloworld hello simple_hello evpq_test url_test dbfs BIN_PATHS = $(addprefix bin/,$(BIN_NAMES)) # first target @@ -21,6 +21,7 @@ bin/simple_hello: obj/evfuse.o obj/dirbuf.o obj/lib/log.o obj/lib/signals.o obj/simple.o bin/evpq_test: obj/evpq.o obj/lib/log.o bin/url_test: obj/lib/url.o obj/lib/lex.o obj/lib/log.o +bin/dbfs: obj/evsql.o obj/evpq.o obj/evfuse.o obj/dirbuf.o obj/lib/log.o obj/lib/signals.o # computed LDFLAGS = ${LIBRARY_PATHS} ${LIBRARY_LIST} diff -r 1dee73ae4ad0 -r 82cfdb6680d1 doc/evfuse_db.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/evfuse_db.txt Sun Oct 12 14:57:06 2008 +0300 @@ -0,0 +1,19 @@ + +Just a simple pure-data filesystem stored in a SQL database. Implementation using PostgreSQL. +No weird dynamic magic. + + +file_tree: + offset serial4 ephemeral counter used to tell one file entry from another + name varchar(256) the filename + parent int4 -> inodes.ino file entry's parent + inode int4 -> inodes.ino the file's data + +inodes: + ino serial4 inode number + type char(3) + REG normal file + DIR directory + mode int2 file access modes + size int8 file content size (?) + diff -r 1dee73ae4ad0 -r 82cfdb6680d1 doc/fuse_db.sql --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/fuse_db.sql Sun Oct 12 14:57:06 2008 +0300 @@ -0,0 +1,7 @@ +CREATE TABLE inodes (ino serial4 primary key, type char(3), mode int2, size int8); +CREATE TABLE file_tree ("offset" serial4 primary key, name varchar(256) NOT NULL, parent int4 references inodes(ino) NOT NULL, inode int4 references inodes(ino) NOT NULL); + +INSERT INTO inodes VALUES (1, 'DIR', 365, 0); +INSERT INTO inodes VALUES (2, 'REG', 292, 0); +INSERT INTO file_tree (name, parent, inode) VALUES ('foo', 1, 2); + diff -r 1dee73ae4ad0 -r 82cfdb6680d1 src/dbfs.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dbfs.c Sun Oct 12 14:57:06 2008 +0300 @@ -0,0 +1,223 @@ + +/* + * A simple PostgreSQL-based filesystem. + */ + +#include +#include + +#include + +#include "evfuse.h" +#include "evsql.h" +#include "dirbuf.h" +#include "lib/log.h" +#include "lib/signals.h" +#include "lib/misc.h" + +#define SERROR(val) do { (val); goto error; } while(0) + +struct dbfs { + struct event_base *ev_base; + struct signals *signals; + + const char *db_conninfo; + struct evsql *db; + + struct evfuse *ev_fuse; +}; + +#define CONNINFO_DEFAULT "dbname=test" + +// XXX: not sure how this should work +#define CACHE_TIMEOUT 1.0 + +mode_t _dbfs_mode (const char *type) { + if (!strcmp(type, "DIR")) + return S_IFDIR; + + if (!strcmp(type, "REG")) + return S_IFREG; + + else { + WARNING("[dbfs] weird mode-type: %s", type); + return 0; + } +} + +void dbfs_init (void *userdata, struct fuse_conn_info *conn) { + INFO("[dbfs.init] userdata=%p, conn=%p", userdata, conn); + +} + +void dbfs_destroy (void *userdata) { + INFO("[dbfs.destroy] userdata=%p", userdata); + + +} + +void _dbfs_lookup_result (const struct evsql_result_info *res, void *arg) { + struct fuse_req *req = arg; + struct fuse_entry_param e; ZINIT(e); + int err = 0; + + uint16_t mode; + uint32_t ino; + uint64_t size, nlink; + const char *type; + + // check if it failed + if (res->error && (err = EIO)) + NERROR(evsql_result_error(res)); + + // duplicate rows? + if (evsql_result_rows(res) > 1) + EERROR(err = EIO, "multiple rows returned"); + + // not found? + if (evsql_result_rows(res) == 0) + SERROR(err = ENOENT); + + // correct number of columns + if (evsql_result_cols(res) != 5) + EERROR(err = EIO, "wrong number of columns: %zu", evsql_result_cols(res)); + + // get the data + if (0 + || evsql_result_uint32(res, 0, 0, &ino, 0 ) // inodes.ino + || evsql_result_string(res, 0, 1, &type, 0 ) // inodes.type + || evsql_result_uint16(res, 0, 2, &mode, 0 ) // inodes.mode + || evsql_result_uint64(res, 0, 3, &size, 0 ) // inodes.size + || evsql_result_uint64(res, 0, 4, &nlink, 0 ) // count(*) + ) + EERROR(err = EIO, "invalid db data"); + + INFO("[dbfs.look] -> ino=%u, st_mode=S_IF%s | %ho, st_nlink=%llu, st_size=%llu", ino, type, mode, (long long unsigned int) nlink, (long long unsigned int) size); + + // convert and store + e.ino = e.attr.st_ino = ino; + e.attr.st_mode = _dbfs_mode(type) | mode; + e.attr.st_nlink = nlink; + e.attr.st_size = size; + + // XXX: timeouts + e.attr_timeout = CACHE_TIMEOUT; + e.entry_timeout = CACHE_TIMEOUT; + + // reply + if ((err = fuse_reply_entry(req, &e))) + EERROR(err, "fuse_reply_entry"); + +error: + if (err && (err = fuse_reply_err(req, err))) + EWARNING(err, "fuse_reply_err"); + + // free + evsql_result_free(res); +} + +void dbfs_lookup (struct fuse_req *req, fuse_ino_t parent, const char *name) { + struct dbfs *ctx = fuse_req_userdata(req); + int err; + + INFO("[dbfs.lookup] parent=%lu name=%s", parent, name); + + // query and params + const char *sql = + "SELECT" + " inodes.ino, inodes.type, inodes.mode, inodes.size, count(*)" + " FROM file_tree INNER JOIN inodes ON (file_tree.inode = inodes.ino)" + " WHERE file_tree.parent = $1::int AND file_tree.name = $2::varchar" + " GROUP BY inodes.ino, inodes.type, inodes.mode, inodes.size"; + + static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) { + EVSQL_PARAM ( UINT32 ), + EVSQL_PARAM ( STRING ), + + EVSQL_PARAMS_END + }; + + // build params + if (0 + || evsql_param_uint32(¶ms, 0, parent) + || evsql_param_string(¶ms, 1, name) + ) + EERROR(err = EIO, "evsql_param_*"); + + // query + if (evsql_query_params(ctx->db, sql, ¶ms, _dbfs_lookup_result, req) == NULL) + EERROR(err = EIO, "evsql_query_params"); + + // XXX: handle interrupts + + // wait + return; + +error: + if ((err = fuse_reply_err(req, err))) + EWARNING(err, "fuse_reply_err"); +} + +struct fuse_lowlevel_ops dbfs_llops = { + .init = dbfs_init, + .destroy = dbfs_destroy, + + .lookup = dbfs_lookup, +}; + +void dbfs_sql_error (struct evsql *evsql, void *arg) { + struct dbfs *ctx = arg; + + // AAAAAAAAAA.... panic + WARNING("[dbfs] SQL error: BREAKING MAIN LOOP LIEK NAO"); + + event_base_loopbreak(ctx->ev_base); +} + +int main (int argc, char **argv) { + struct fuse_args fuse_args = FUSE_ARGS_INIT(argc, argv); + struct dbfs ctx; ZINIT(ctx); + + // parse args, XXX: fuse_args + ctx.db_conninfo = CONNINFO_DEFAULT; + + // init libevent + if ((ctx.ev_base = event_base_new()) == NULL) + ERROR("event_base_new"); + + // setup signals + if ((ctx.signals = signals_default(ctx.ev_base)) == NULL) + ERROR("signals_default"); + + // open sql + if ((ctx.db = evsql_new_pq(ctx.ev_base, ctx.db_conninfo, dbfs_sql_error, &ctx)) == NULL) + ERROR("evsql_new_pq"); + + // open fuse + if ((ctx.ev_fuse = evfuse_new(ctx.ev_base, &fuse_args, &dbfs_llops, &ctx)) == NULL) + ERROR("evfuse_new"); + + // run libevent + INFO("running libevent loop"); + + if (event_base_dispatch(ctx.ev_base)) + PERROR("event_base_dispatch"); + + // clean shutdown + +error : + // cleanup + if (ctx.ev_fuse) + evfuse_close(ctx.ev_fuse); + + // XXX: ctx.db + + if (ctx.signals) + signals_free(ctx.signals); + + if (ctx.ev_base) + event_base_free(ctx.ev_base); + + fuse_opt_free_args(&fuse_args); +} + diff -r 1dee73ae4ad0 -r 82cfdb6680d1 src/evpq.c --- a/src/evpq.c Sun Oct 12 01:09:00 2008 +0300 +++ b/src/evpq.c Sun Oct 12 14:57:06 2008 +0300 @@ -288,7 +288,7 @@ ERROR("PQsendQuery: %s", PQerrorMessage(conn->pg_conn)); // handle it - if (_evpq_handle_query(con)) + if (_evpq_handle_query(conn)) goto error; // success @@ -308,7 +308,7 @@ ERROR("PQsendQueryParams: %s", PQerrorMessage(conn->pg_conn)); // handle it - if (_evpq_handle_query(con)) + if (_evpq_handle_query(conn)) goto error; // success diff -r 1dee73ae4ad0 -r 82cfdb6680d1 src/evsql.c --- a/src/evsql.c Sun Oct 12 01:09:00 2008 +0300 +++ b/src/evsql.c Sun Oct 12 14:57:06 2008 +0300 @@ -114,14 +114,13 @@ /* * Dequeue the query, execute the callback, and free it. */ -static void _evsql_query_done (struct evsql_query *query, const struct evsql_result_info *result_info) { - +static void _evsql_query_done (struct evsql_query *query, const struct evsql_result_info *res) { // dequeue TAILQ_REMOVE(&query->evsql->queue, query, entry); - if (result_info) + if (res) // call the callback - query->cb_fn(*result_info, query->cb_arg); + query->cb_fn(res, query->cb_arg); // free _evsql_query_free(query); @@ -131,14 +130,14 @@ * A query has failed, notify the user and remove it. */ static void _evsql_query_failure (struct evsql *evsql, struct evsql_query *query) { - struct evsql_result_info result; ZINIT(result); + struct evsql_result_info res; ZINIT(res); // set up the result_info - result.evsql = evsql; - result.error = 1; + res.evsql = evsql; + res.error = 1; // finish it off - _evsql_query_done(query, &result); + _evsql_query_done(query, &res); } /* @@ -146,18 +145,18 @@ * * If result_info is given, each query will also recieve it via their callback, and the error_fn will be called. */ -static void _evsql_destroy (struct evsql *evsql, const struct evsql_result_info *result_info) { +static void _evsql_destroy (struct evsql *evsql, const struct evsql_result_info *res) { struct evsql_query *query; // clear the queue while ((query = TAILQ_FIRST(&evsql->queue)) != NULL) { - _evsql_query_done(query, result_info); + _evsql_query_done(query, res); TAILQ_REMOVE(&evsql->queue, query, entry); } // do the error callback if required - if (result_info) + if (res) evsql->error_fn(evsql, evsql->cb_arg); // free @@ -214,27 +213,32 @@ static void _evsql_evpq_done (struct evpq_conn *conn, void *arg) { struct evsql *evsql = arg; struct evsql_query *query; - struct evsql_result_info result; ZINIT(result); + struct evsql_result_info res; ZINIT(res); assert((query = TAILQ_FIRST(&evsql->queue)) != NULL); // set up the result_info - result.evsql = evsql; + res.evsql = evsql; if (query->result.evpq == NULL) { // if a query didn't return any results (bug?), warn and fail the query WARNING("[evsql] evpq query didn't return any results"); - result.error = 1; + res.error = 1; + + } else if (strcmp(PQresultErrorMessage(query->result.evpq), "") != 0) { + // the query failed with some error + res.error = 1; + res.result.pq = query->result.evpq; } else { - result.error = 0; - result.result.pq = query->result.evpq; + res.error = 0; + res.result.pq = query->result.evpq; } // finish it off - _evsql_query_done(query, &result); + _evsql_query_done(query, &res); // pump the next one _evsql_pump(evsql); @@ -311,7 +315,7 @@ * 0 connection idle, can query immediately * 1 connection busy, must queue query */ -static int _evsql_query_idle (struct evsql *evsql) { +static int _evsql_query_busy (struct evsql *evsql) { switch (evsql->type) { case EVSQL_EVPQ: { enum evpq_state state = evpq_state(evsql->engine.evpq); @@ -359,23 +363,24 @@ } static int _evsql_query_enqueue (struct evsql *evsql, struct evsql_query *query, const char *command) { - int idle; + int busy; // check state - if ((idle = _evsql_query_idle(evsql)) < 0) + if ((busy = _evsql_query_busy(evsql)) < 0) ERROR("connection is not valid"); - if (idle) { + if (busy) { + // copy the command for later execution + if ((query->command = strdup(command)) == NULL) + ERROR("strdup"); + + } else { assert(TAILQ_EMPTY(&evsql->queue)); // execute directly if (_evsql_query_exec(evsql, query, command)) goto error; - } else { - // copy the command for later execution - if ((query->command = strdup(command)) == NULL) - ERROR("strdup"); } // store it on the list @@ -408,9 +413,9 @@ return NULL; } -struct evsql_query *evsql_query_params (struct evsql *evsql, const char *command, struct evsql_query_params params, evsql_query_cb query_fn, void *cb_arg) { +struct evsql_query *evsql_query_params (struct evsql *evsql, const char *command, const struct evsql_query_params *params, evsql_query_cb query_fn, void *cb_arg) { struct evsql_query *query = NULL; - struct evsql_query_param *param; + const struct evsql_query_param *param; int idx; // alloc new query @@ -418,7 +423,7 @@ goto error; // count the params - for (param = params.list; param->value || param->length; param++) + for (param = params->list; param->type; param++) query->params.count++; // allocate the vertical storage for the parameters @@ -432,22 +437,31 @@ ERROR("calloc"); // transform - for (param = params.list, idx = 0; param->value || param->length; param++, idx++) { + for (param = params->list, idx = 0; param->type; param++, idx++) { // `types` stays NULL // query->params.types[idx] = 0; // values - query->params.values[idx] = param->value; + query->params.values[idx] = param->data_raw; - // lengths (nonzero for NULLs) - query->params.lengths[idx] = param->value ? param->length : 0; + // lengths + query->params.lengths[idx] = param->length; // formats, binary if length is nonzero - query->params.formats[idx] = param->value && param->length; + query->params.formats[idx] = param->length ? 1 : 0; } // result format - query->params.result_format = params.result_binary ? 1 : 0; + switch (params->result_fmt) { + case EVSQL_FMT_TEXT: + query->params.result_format = 0; break; + + case EVSQL_FMT_BINARY: + query->params.result_format = 1; break; + + default: + FATAL("params.result_fmt: %d", params->result_fmt); + } // execute it if (_evsql_query_enqueue(evsql, query, command)) @@ -462,3 +476,166 @@ return NULL; } +int evsql_param_string (struct evsql_query_params *params, size_t param, const char *ptr) { + struct evsql_query_param *p = ¶ms->list[param]; + + assert(p->type == EVSQL_PARAM_STRING); + + p->data_raw = ptr; + p->length = 0; + + return 0; +} + +int evsql_param_uint32 (struct evsql_query_params *params, size_t param, uint32_t uval) { + struct evsql_query_param *p = ¶ms->list[param]; + + assert(p->type == EVSQL_PARAM_UINT32); + + p->data.uint32 = htonl(uval); + p->data_raw = (const char *) &p->data.uint32; + p->length = sizeof(uval); + + return 0; +} + +const char *evsql_result_error (const struct evsql_result_info *res) { + if (!res->error) + return "No error"; + + switch (res->evsql->type) { + case EVSQL_EVPQ: + if (!res->result.pq) + return "unknown error (no result)"; + + return PQresultErrorMessage(res->result.pq); + + default: + FATAL("res->evsql->type"); + } + +} + +size_t evsql_result_rows (const struct evsql_result_info *res) { + switch (res->evsql->type) { + case EVSQL_EVPQ: + return PQntuples(res->result.pq); + + default: + FATAL("res->evsql->type"); + } +} + +size_t evsql_result_cols (const struct evsql_result_info *res) { + switch (res->evsql->type) { + case EVSQL_EVPQ: + return PQnfields(res->result.pq); + + default: + FATAL("res->evsql->type"); + } +} + +int evsql_result_binary (const struct evsql_result_info *res, size_t row, size_t col, const char **ptr, size_t size, int nullok) { + *ptr = NULL; + + switch (res->evsql->type) { + case EVSQL_EVPQ: + if (PQgetisnull(res->result.pq, row, col)) { + if (nullok) + return 0; + else + ERROR("[%zu:%zu] field is null", row, col); + } + + if (PQfformat(res->result.pq, col) != 1) + ERROR("[%zu:%zu] PQfformat is not binary: %d", row, col, PQfformat(res->result.pq, col)); + + if (size && PQgetlength(res->result.pq, row, col) != size) + ERROR("[%zu:%zu] field size mismatch: %zu -> %d", row, col, size, PQgetlength(res->result.pq, row, col)); + + *ptr = PQgetvalue(res->result.pq, row, col); + + return 0; + + default: + FATAL("res->evsql->type"); + } + +error: + return -1; +} + +int evsql_result_string (const struct evsql_result_info *res, size_t row, size_t col, const char **ptr, int nullok) { + return evsql_result_binary(res, row, col, ptr, 0, nullok); +} + +int evsql_result_uint16 (const struct evsql_result_info *res, size_t row, size_t col, uint16_t *uval, int nullok) { + const char *data; + int16_t sval; + + if (evsql_result_binary(res, row, col, &data, sizeof(*uval), nullok)) + goto error; + + sval = ntohs(*((int16_t *) data)); + + if (sval < 0) + ERROR("negative value for unsigned: %d", sval); + + *uval = sval; + + return 0; + +error: + return nullok ? 0 : -1; +} + +int evsql_result_uint32 (const struct evsql_result_info *res, size_t row, size_t col, uint32_t *uval, int nullok) { + const char *data; + int32_t sval; + + if (evsql_result_binary(res, row, col, &data, sizeof(*uval), nullok)) + goto error; + + sval = ntohl(*(int32_t *) data); + + if (sval < 0) + ERROR("negative value for unsigned: %d", sval); + + *uval = sval; + + return 0; + +error: + return nullok ? 0 : -1; +} + +int evsql_result_uint64 (const struct evsql_result_info *res, size_t row, size_t col, uint64_t *uval, int nullok) { + const char *data; + int64_t sval; + + if (evsql_result_binary(res, row, col, &data, sizeof(*uval), nullok)) + goto error; + + sval = ntohq(*(int64_t *) data); + + if (sval < 0) + ERROR("negative value for unsigned: %ld", sval); + + *uval = sval; + + return 0; + +error: + return nullok ? 0 : -1; +} + +void evsql_result_free (const struct evsql_result_info *res) { + switch (res->evsql->type) { + case EVSQL_EVPQ: + return PQclear(res->result.pq); + + default: + FATAL("res->evsql->type"); + } +} diff -r 1dee73ae4ad0 -r 82cfdb6680d1 src/evsql.h --- a/src/evsql.h Sun Oct 12 01:09:00 2008 +0300 +++ b/src/evsql.h Sun Oct 12 14:57:06 2008 +0300 @@ -20,42 +20,74 @@ struct evsql_query; /* + * Parameter type + */ +enum evsql_param_format { + EVSQL_FMT_TEXT, + EVSQL_FMT_BINARY, +}; + +enum evsql_param_type { + EVSQL_PARAM_INVALID, + + EVSQL_PARAM_NULL, + + EVSQL_PARAM_STRING, + EVSQL_PARAM_UINT16, + EVSQL_PARAM_UINT32, + EVSQL_PARAM_UINT64, +}; + +/* * Query parameter info. * * Use the EVSQL_PARAM_* macros to define the value of list */ struct evsql_query_params { // nonzero to get results in binary format - int result_binary; + enum evsql_param_format result_fmt; // the list of parameters, terminated by { 0, 0 } struct evsql_query_param { - // the textual or binary value for this parameter - char *value; + // the param type + enum evsql_param_type type; + + // pointer to the raw data + const char *data_raw; + + // the value + union { + uint16_t uint16; + uint32_t uint32; + uint64_t uint64; + } data; - // the explicit length of the parameter if it's binary. Must be non-zero for NULL values. - int length; + // the explicit length of the parameter if it's binary, zero for text. + // set to -1 to indicate that the value is still missing + ssize_t length; } list[]; }; // macros for defining evsql_query_params -#define EVSQL_PARAM_NULL { NULL, 1 } -#define EVSQL_PARAM_TEXT(value) { value, 0 } -#define EVSQL_PARAM_BINARY(value, length) { value, length } +#define EVSQL_PARAMS(result_fmt) { result_fmt, +#define EVSQL_PARAM(typenam) { EVSQL_PARAM_ ## typenam, NULL } +#define EVSQL_PARAMS_END { EVSQL_PARAM_INVALID, NULL } \ + } // <<< /* * Result type */ +union evsql_result { + // libpq + PGresult *pq; +}; + struct evsql_result_info { struct evsql *evsql; int error; - union { - // XXX: libpq - PGresult *pq; - - } result; + union evsql_result result; }; /* @@ -64,7 +96,7 @@ * The query has completed, either succesfully or unsuccesfully (look at info.error). * info.result contains the result à la the evsql's type. */ -typedef void (*evsql_query_cb)(struct evsql_result_info info, void *arg); +typedef void (*evsql_query_cb)(const struct evsql_result_info *res, void *arg); /* * Callback for handling connection-level errors. @@ -86,7 +118,48 @@ /* * Same, but uses the SQL-level support for binding parameters. */ -struct evsql_query *evsql_query_params (struct evsql *evsql, const char *command, struct evsql_query_params params, evsql_query_cb query_fn, void *cb_arg); +struct evsql_query *evsql_query_params (struct evsql *evsql, const char *command, const struct evsql_query_params *params, evsql_query_cb query_fn, void *cb_arg); + +/* + * Param-building functions + */ +int evsql_param_string (struct evsql_query_params *params, size_t param, const char *ptr); +int evsql_param_uint32 (struct evsql_query_params *params, size_t param, uint32_t uval); + +/* + * Result-handling functions + */ + +// get error message associated with function +const char *evsql_result_error (const struct evsql_result_info *res); + +// number of rows in the result +size_t evsql_result_rows (const struct evsql_result_info *res); + +// number of columns in the result +size_t evsql_result_cols (const struct evsql_result_info *res); + +// fetch the raw binary value from a result set, and return it via ptr +// if size is nonzero, check that the size of the field data matches +int evsql_result_binary (const struct evsql_result_info *res, size_t row, size_t col, const char **ptr, size_t size, int nullok); +int evsql_result_string (const struct evsql_result_info *res, size_t row, size_t col, const char **ptr, int nullok); + +// fetch certain kinds of values from a binary result set +int evsql_result_uint16 (const struct evsql_result_info *res, size_t row, size_t col, uint16_t *uval, int nullok); +int evsql_result_uint32 (const struct evsql_result_info *res, size_t row, size_t col, uint32_t *uval, int nullok); +int evsql_result_uint64 (const struct evsql_result_info *res, size_t row, size_t col, uint64_t *uval, int nullok); + +// release the result set, freeing its memory +void evsql_result_free (const struct evsql_result_info *res); + +// platform-dependant aliases +#define evsql_result_ushort evsql_result_uint16 + +#if _LP64 +#define evsql_result_ulong evsql_result_uint64 +#else +#define evsql_result_ulong evsql_result_uint32 +#endif /* _LP64 */ /* * Close a connection. Callbacks for waiting queries will not be run. diff -r 1dee73ae4ad0 -r 82cfdb6680d1 src/lib/error.h --- a/src/lib/error.h Sun Oct 12 01:09:00 2008 +0300 +++ b/src/lib/error.h Sun Oct 12 14:57:06 2008 +0300 @@ -6,6 +6,7 @@ #define ERROR(...) do { err_func(__func__, __VA_ARGS__); goto error; } while (0) #define PERROR(...) do { perr_func(__func__, __VA_ARGS__); goto error; } while (0) #define EERROR(_err, ...) do { eerr_func(__func__, (_err), __VA_ARGS__); goto error; } while (0) +#define NERROR(...) do { err_func_nonl(__func__, __VA_ARGS__); goto error; } while (0) #define FATAL(...) err_func_exit(__func__, __VA_ARGS__) #define PFATAL(...) perr_func_exit(__func__, __VA_ARGS__) diff -r 1dee73ae4ad0 -r 82cfdb6680d1 src/lib/log.c --- a/src/lib/log.c Sun Oct 12 01:09:00 2008 +0300 +++ b/src/lib/log.c Sun Oct 12 14:57:06 2008 +0300 @@ -15,7 +15,7 @@ vfprintf(stream, fmt, va); if (flags & LOG_DISPLAY_PERR) - fprintf(stream, ": %s\n", strerror(err == 0 ? errno : -err)); + fprintf(stream, ": %s\n", strerror(err == 0 ? errno : err)); if (!(flags & LOG_DISPLAY_NONL)) fprintf(stream, "\n"); diff -r 1dee73ae4ad0 -r 82cfdb6680d1 src/lib/log.h --- a/src/lib/log.h Sun Oct 12 01:09:00 2008 +0300 +++ b/src/lib/log.h Sun Oct 12 14:57:06 2008 +0300 @@ -41,6 +41,7 @@ #define perr(...) _generic_err( LOG_DISPLAY_STDERR | LOG_DISPLAY_PERR, NULL, 0, __VA_ARGS__ ) #define perr_exit(...) _generic_err_exit( LOG_DISPLAY_STDERR | LOG_DISPLAY_PERR, NULL, 0, __VA_ARGS__ ) #define err_func(func, ...) _generic_err( LOG_DISPLAY_STDERR, func, 0, __VA_ARGS__ ) +#define err_func_nonl(func, ...) _generic_err( LOG_DISPLAY_STDERR | LOG_DISPLAY_NONL, func, 0, __VA_ARGS__ ) #define err_func_exit(func, ...) _generic_err_exit( LOG_DISPLAY_STDERR, func, 0, __VA_ARGS__ ) #define perr_func(func, ...) _generic_err( LOG_DISPLAY_STDERR | LOG_DISPLAY_PERR, func, 0, __VA_ARGS__ ) #define perr_func_exit(func, ...) _generic_err_exit( LOG_DISPLAY_STDERR | LOG_DISPLAY_PERR, func, 0, __VA_ARGS__ ) diff -r 1dee73ae4ad0 -r 82cfdb6680d1 src/lib/misc.h --- a/src/lib/misc.h Sun Oct 12 01:09:00 2008 +0300 +++ b/src/lib/misc.h Sun Oct 12 14:57:06 2008 +0300 @@ -1,10 +1,24 @@ #ifndef LIB_UTIL_H #define LIB_UTIL_H +#include + /* * Initialize the given *value* with zeros */ #define ZINIT(obj) memset(&(obj), 0, sizeof((obj))) +/* + * 64-bit hton{s,l,q} + */ +#ifndef WORDS_BIGENDIAN /* i.e. if (little endian) */ +#define htonq(x) (((uint64_t)htonl((x)>>32))|(((uint64_t)htonl(x))<<32)) +#define ntohq(x) htonq(x) +#else +#define htonq(x) ((uint64_t)(x)) +#define ntohq(x) ((uint64_t)(x)) +#endif + + #endif /* LIB_UTIL_H */