--- a/Makefile Thu Oct 16 22:04:53 2008 +0300
+++ b/Makefile Thu Oct 16 22:56:29 2008 +0300
@@ -19,8 +19,8 @@
BIN_PATHS = $(addprefix bin/,$(BIN_NAMES))
# complex modules
-EVSQL_OBJS = obj/evsql.o obj/evsql_util.o obj/evpq.o
-DBFS_OBJS = obj/dbfs/dbfs.o obj/dbfs/common.o obj/dbfs/core.o obj/dbfs/op_base.o obj/dbfs/dirop.o obj/dirbuf.o
+EVSQL_OBJS = obj/evsql/evsql.o obj/evsql/util.o obj/evpq.o
+DBFS_OBJS = obj/dbfs/dbfs.o obj/dbfs/common.o obj/dbfs/core.o obj/dbfs/op_base.o obj/dbfs/dirop.o obj/dirbuf.o obj/dbfs/fileop.o
# first target
all: ${BIN_PATHS}
--- a/src/dbfs.c Thu Oct 16 22:04:53 2008 +0300
+++ b/src/dbfs.c Thu Oct 16 22:56:29 2008 +0300
@@ -38,8 +38,8 @@
ERROR("signals_default");
// setup dbfs
- if ((ctx = dbfs_open(ev_base, &fuse_args, db_conninfo)) == NULL)
- ERROR("dbfs_open");
+ if ((ctx = dbfs_new(ev_base, &fuse_args, db_conninfo)) == NULL)
+ ERROR("dbfs_new");
// run libevent
INFO("running libevent loop");
@@ -51,7 +51,7 @@
error :
if (ctx)
- dbfs_release(ctx);
+ dbfs_free(ctx);
if (signals)
signals_free(signals);
--- a/src/dbfs.h Thu Oct 16 22:04:53 2008 +0300
+++ b/src/dbfs.h Thu Oct 16 22:56:29 2008 +0300
@@ -15,11 +15,11 @@
/*
* Create the evsql and evfuse contexts and run the fs
*/
-struct dbfs *dbfs_open (struct event_base *ev_base, struct fuse_args *args, const char *db_conninfo);
+struct dbfs *dbfs_new (struct event_base *ev_base, struct fuse_args *args, const char *db_conninfo);
/*
* Release the dbfs's resources and free it
*/
-void dbfs_release (struct dbfs *ctx);
+void dbfs_free (struct dbfs *ctx);
#endif /* DBFS_H */
--- a/src/dbfs/common.c Thu Oct 16 22:04:53 2008 +0300
+++ b/src/dbfs/common.c Thu Oct 16 22:56:29 2008 +0300
@@ -50,14 +50,15 @@
int err = 0;
uint16_t mode;
- uint64_t size, nlink;
+ uint32_t size = 0; // NULL for non-REG inodes
+ uint64_t nlink;
const char *type;
// extract the data
if (0
|| evsql_result_string(res, row, col_offset + 0, &type, 0 ) // inodes.type
|| evsql_result_uint16(res, row, col_offset + 1, &mode, 0 ) // inodes.mode
- || evsql_result_uint64(res, row, col_offset + 2, &size, 0 ) // inodes.size
+ || evsql_result_uint32(res, row, col_offset + 2, &size, 1 ) // size
|| evsql_result_uint64(res, row, col_offset + 3, &nlink, 0 ) // count(*)
)
EERROR(err = EIO, "invalid db data");
--- a/src/dbfs/core.c Thu Oct 16 22:04:53 2008 +0300
+++ b/src/dbfs/core.c Thu Oct 16 22:56:29 2008 +0300
@@ -57,10 +57,10 @@
// query and params
const char *sql =
"SELECT"
- " inodes.ino, inodes.type, inodes.mode, inodes.size, count(*)"
+ " inodes.ino, inodes.type, inodes.mode, dbfs_lo_size(data), count(*)"
" FROM file_tree INNER JOIN inodes ON (file_tree.inode = inodes.ino)"
" WHERE file_tree.parent = $1::int4 AND file_tree.name = $2::varchar"
- " GROUP BY inodes.ino, inodes.type, inodes.mode, inodes.size";
+ " GROUP BY inodes.ino, inodes.type, inodes.mode, data";
static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) {
EVSQL_PARAM ( UINT32 ),
@@ -130,10 +130,10 @@
const char *sql =
"SELECT"
- " inodes.type, inodes.mode, inodes.size, count(*)"
+ " inodes.type, inodes.mode, dbfs_lo_size(data), count(*)"
" FROM inodes"
" WHERE inodes.ino = $1::int4"
- " GROUP BY inodes.type, inodes.mode, inodes.size";
+ " GROUP BY inodes.type, inodes.mode, data";
static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) {
EVSQL_PARAM ( UINT32 ),
--- a/src/dbfs/dbfs.c Thu Oct 16 22:04:53 2008 +0300
+++ b/src/dbfs/dbfs.c Thu Oct 16 22:56:29 2008 +0300
@@ -4,7 +4,6 @@
#include "dbfs.h"
#include "../dbfs.h"
#include "../lib/log.h"
-#include "../lib/misc.h"
static struct fuse_lowlevel_ops dbfs_llops = {
@@ -15,6 +14,12 @@
.getattr = dbfs_getattr,
+ .open = dbfs_open,
+ .read = dbfs_read,
+ // .write = dbfs_write,
+ .flush = dbfs_flush,
+ .release = dbfs_release,
+
.opendir = dbfs_opendir,
.readdir = dbfs_readdir,
.releasedir = dbfs_releasedir,
@@ -43,7 +48,7 @@
event_base_loopbreak(ctx->ev_base);
}
-struct dbfs *dbfs_open (struct event_base *ev_base, struct fuse_args *args, const char *db_conninfo) {
+struct dbfs *dbfs_new (struct event_base *ev_base, struct fuse_args *args, const char *db_conninfo) {
struct dbfs *ctx = NULL;
// alloc ctx
@@ -66,12 +71,12 @@
error:
if (ctx)
- dbfs_release(ctx);
+ dbfs_free(ctx);
return NULL;
}
-void dbfs_release (struct dbfs *ctx) {
+void dbfs_free (struct dbfs *ctx) {
// cleanup
if (ctx->ev_fuse) {
evfuse_free(ctx->ev_fuse);
--- a/src/dbfs/dirop.c Thu Oct 16 22:04:53 2008 +0300
+++ b/src/dbfs/dirop.c Thu Oct 16 22:56:29 2008 +0300
@@ -228,12 +228,12 @@
*/
void dbfs_readdir (struct fuse_req *req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) {
struct dbfs *ctx = fuse_req_userdata(req);
- struct dbfs_dirop *dirop = (struct dbfs_dirop *) fi->fh;
+ struct dbfs_dirop *dirop;
int err;
// get the op
if ((dirop = (struct dbfs_dirop *) dbfs_op_req(req, ino, fi)) == NULL)
- SERROR(err = EIO);
+ return;
INFO("[dbfs.readdir %p:%p] ino=%lu, size=%zu, off=%zu, fi=%p : trans=%p", dirop, req, ino, size, off, fi, dirop->base.trans);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dbfs/fileop.c Thu Oct 16 22:56:29 2008 +0300
@@ -0,0 +1,245 @@
+#include <stdlib.h>
+#include <assert.h>
+
+#include <postgresql/libpq/libpq-fs.h>
+
+#include "dbfs.h"
+#include "op_base.h"
+#include "../lib/log.h"
+
+struct dbfs_fileop {
+ struct dbfs_op base;
+
+ uint32_t lo_fd;
+};
+
+static void _dbfs_fileop_free (struct dbfs_op *op_base) {
+ struct dbfs_fileop *fop = (struct dbfs_fileop *) op_base;
+
+ /* no-op */
+ (void) fop;
+}
+
+static void dbfs_open_res (const struct evsql_result_info *res, void *arg) {
+ struct dbfs_fileop *fop = arg;
+ int err;
+
+ // check the results
+ if ((err = _dbfs_check_res(res, 1, 2)))
+ SERROR(err = (err == 1 ? ENOENT : EIO));
+
+ const char *type;
+
+ // extract the data
+ if (0
+ || evsql_result_string(res, 0, 0, &type, 0 ) // inodes.type
+ || evsql_result_uint32(res, 0, 1, &fop->lo_fd, 0 ) // fd
+ )
+ SERROR(err = EIO);
+
+ // is it a dir?
+ if (_dbfs_mode(type) != S_IFREG)
+ EERROR(err = ENOENT, "wrong type: %s", type);
+
+ INFO("[dbfs.open %p:%p] -> ino=%lu, type=%s", fop, fop->base.req, (unsigned long int) fop->base.ino, type);
+
+ // open_fn done, do the open_reply
+ if ((err = dbfs_op_open_reply(&fop->base)))
+ goto error;
+
+ // success, fallthrough for evsql_result_free
+ err = 0;
+
+error:
+ if (err)
+ // fail it
+ dbfs_op_fail(&fop->base, err);
+
+ // free
+ evsql_result_free(res);
+}
+
+static void dbfs_fileop_open (struct dbfs_op *op_base) {
+ struct dbfs_fileop *fop = (struct dbfs_fileop *) op_base;
+ struct dbfs *ctx = fuse_req_userdata(fop->base.req);
+ int err;
+
+ // make sure the file actually exists
+ const char *sql =
+ "SELECT"
+ " inodes.type, lo_open(inodes.data, $1::int4) AS fd"
+ " FROM inodes"
+ " WHERE inodes.ino = $2::int4";
+
+ static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) {
+ EVSQL_PARAM ( UINT32 ),
+ EVSQL_PARAM ( UINT32 ),
+
+ EVSQL_PARAMS_END
+ };
+
+ // build params
+ if (0
+ || evsql_param_uint32(¶ms, 0, INV_READ | INV_WRITE)
+ || evsql_param_uint32(¶ms, 1, fop->base.ino)
+ )
+ SERROR(err = EIO);
+
+ // query
+ if (evsql_query_params(ctx->db, fop->base.trans, sql, ¶ms, dbfs_open_res, fop) == NULL)
+ SERROR(err = EIO);
+
+ // ok, wait for the info results
+ return;
+
+error:
+ // fail it
+ dbfs_op_fail(&fop->base, err);
+}
+
+void dbfs_open (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi) {
+ struct dbfs *ctx = fuse_req_userdata(req);
+ struct dbfs_fileop *fop = NULL;
+ int err;
+
+ // allocate it
+ if ((fop = calloc(1, sizeof(*fop))) == NULL && (err = EIO))
+ ERROR("calloc");
+
+ // do the op_open
+ if ((err = dbfs_op_open(ctx, &fop->base, req, ino, fi, _dbfs_fileop_free, dbfs_fileop_open)))
+ ERROR("dbfs_op_open");
+
+ // log
+ INFO("[dbfs.open %p:%p] ino=%lu, fi->flags=%04X", fop, req, ino, fi->flags);
+
+ // wait
+ return;
+
+error:
+ if (fop) {
+ // we can fail normally
+ dbfs_op_fail(&fop->base, err);
+
+ } else {
+ // must error out manually as we couldn't alloc the context
+ if ((err = fuse_reply_err(req, err)))
+ EWARNING(err, "fuse_reply_err");
+ }
+}
+
+void dbfs_read_res (const struct evsql_result_info *res, void *arg) {
+ struct dbfs_fileop *fop = arg;
+ int err;
+ const char *buf;
+ size_t size;
+
+ // check the results
+ if ((err = _dbfs_check_res(res, 1, 1)) < 0)
+ SERROR(err = EIO);
+
+ // get the data
+ if (evsql_result_buf(res, 0, 0, &buf, &size, 0))
+ SERROR(err = EIO);
+
+ INFO("[dbfs.read %p:%p] -> size=%zu", fop, fop->base.req, size);
+
+ // send it
+ if ((err = fuse_reply_buf(fop->base.req, buf, size)))
+ EERROR(err, "fuse_reply_buf");
+
+ // ok, req handled
+ if ((err = dbfs_op_req_done(&fop->base)))
+ goto error;
+
+ // good, fallthrough
+ err = 0;
+
+error:
+ if (err)
+ dbfs_op_fail(&fop->base, err);
+
+ // free
+ evsql_result_free(res);
+}
+
+void dbfs_read (struct fuse_req *req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) {
+ struct dbfs *ctx = fuse_req_userdata(req);
+ struct dbfs_fileop *fop;
+ int err;
+
+ // get the op
+ if ((fop = (struct dbfs_fileop *) dbfs_op_req(req, ino, fi)) == NULL)
+ return;
+
+ // log
+ INFO("[dbfs.read %p:%p] ino=%lu, size=%zu, off=%lu, fi->flags=%04X", fop, req, ino, size, off, fi->flags);
+
+ // query
+ const char *sql =
+ "SELECT"
+ " lo_pread($1::int4, $2::int4, $3::int4)";
+
+ static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) {
+ EVSQL_PARAM ( UINT32 ), // fd
+ EVSQL_PARAM ( UINT32 ), // len
+ EVSQL_PARAM ( UINT32 ), // off
+
+ EVSQL_PARAMS_END
+ };
+
+ // build params
+ if (0
+ || evsql_param_uint32(¶ms, 0, fop->lo_fd)
+ || evsql_param_uint32(¶ms, 1, size)
+ || evsql_param_uint32(¶ms, 2, off)
+ )
+ SERROR(err = EIO);
+
+ // query
+ if (evsql_query_params(ctx->db, fop->base.trans, sql, ¶ms, dbfs_read_res, fop) == NULL)
+ SERROR(err = EIO);
+
+ // ok, wait for the info results
+ return;
+
+error:
+ // fail it
+ dbfs_op_fail(&fop->base, err);
+}
+
+void dbfs_write (struct fuse_req *req, fuse_ino_t ino, const char *buf, size_t size, off_t off, struct fuse_file_info *fi) {
+
+}
+
+void dbfs_flush (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi) {
+ struct dbfs_fileop *fop;
+ int err;
+
+ // get the fop
+ if ((fop = (struct dbfs_fileop *) dbfs_op_req(req, ino, fi)) == NULL)
+ return;
+
+ // log
+ INFO("[dbfs.flush %p:%p] ino=%lu", fop, req, ino);
+
+ // and reply...
+ if ((err = fuse_reply_err(req, 0)))
+ EWARNING(err, "fuse_reply_err");
+
+ // done
+ if ((err = dbfs_op_req_done(&fop->base)))
+ goto error;
+
+ // good
+ return;
+
+error:
+ dbfs_op_fail(&fop->base, err);
+}
+
+void dbfs_release (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi) {
+ // just passthrough to dbfs_op
+ // the lo_fd will be closed automatically
+ dbfs_op_release(req, ino, fi);
+}
--- a/src/dbfs/op_base.h Thu Oct 16 22:04:53 2008 +0300
+++ b/src/dbfs/op_base.h Thu Oct 16 22:56:29 2008 +0300
@@ -73,6 +73,8 @@
* Lookup the op for the given fi, validate params, and assign the new req.
*
* In case the op failed previously, this will error the req and return NULL, indicating that the req has been handled.
+ *
+ * Repeat, if this returns NULL, consider req invalid.
*/
struct dbfs_op *dbfs_op_req (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi);
--- a/src/dbfs/ops.h Thu Oct 16 22:04:53 2008 +0300
+++ b/src/dbfs/ops.h Thu Oct 16 22:56:29 2008 +0300
@@ -16,4 +16,10 @@
void dbfs_readdir (struct fuse_req *req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi);
void dbfs_releasedir (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi);
+/* fileop.c */
+void dbfs_open (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi);
+void dbfs_read (struct fuse_req *req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi);
+void dbfs_flush (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi);
+void dbfs_release (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi);
+
#endif /* DBFS_OPS_H */
--- a/src/evsql.h Thu Oct 16 22:04:53 2008 +0300
+++ b/src/evsql.h Thu Oct 16 22:56:29 2008 +0300
@@ -231,6 +231,7 @@
// 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_buf (const struct evsql_result_info *res, size_t row, size_t col, const char **ptr, size_t *size, int nullok);
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);
--- a/src/evsql/util.c Thu Oct 16 22:04:53 2008 +0300
+++ b/src/evsql/util.c Thu Oct 16 22:56:29 2008 +0300
@@ -64,7 +64,7 @@
}
}
-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_buf (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) {
@@ -79,10 +79,8 @@
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);
+ *size = PQgetlength(res->result.pq, row, col);
+ *ptr = PQgetvalue(res->result.pq, row, col);
return 0;
@@ -94,6 +92,21 @@
return -1;
}
+int evsql_result_binary (const struct evsql_result_info *res, size_t row, size_t col, const char **ptr, size_t size, int nullok) {
+ size_t real_size;
+
+ if (evsql_result_buf(res, row, col, ptr, &real_size, nullok))
+ goto error;
+
+ if (size && real_size != size)
+ ERROR("[%zu:%zu] field size mismatch: %zu -> %zu", row, col, size, real_size);
+
+ return 0;
+
+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);
}