working mknod, mkdir, symlink
authorTero Marttila <terom@fixme.fi>
Fri, 17 Oct 2008 20:12:20 +0300
changeset 35 4f10421681d2
parent 34 460f995d3769
child 36 56427f22e969
working mknod, mkdir, symlink
Makefile
doc/fuse_db.sql
src/dbfs/dbfs.c
src/dbfs/fileop.c
src/dbfs/link.c
src/dbfs/mk.c
src/dbfs/ops.h
--- a/Makefile	Fri Oct 17 19:28:27 2008 +0300
+++ b/Makefile	Fri Oct 17 20:12:20 2008 +0300
@@ -20,7 +20,7 @@
 
 # complex modules
 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/trans.o obj/dbfs/dirop.o obj/dirbuf.o obj/dbfs/fileop.o obj/dbfs/attr.o obj/dbfs/link.o obj/dbfs/tree.o
+DBFS_OBJS = obj/dbfs/dbfs.o obj/dbfs/common.o obj/dbfs/core.o obj/dbfs/op_base.o obj/dbfs/trans.o obj/dbfs/dirop.o obj/dirbuf.o obj/dbfs/fileop.o obj/dbfs/attr.o obj/dbfs/link.o obj/dbfs/tree.o obj/dbfs/mk.o
 
 # first target
 all: ${BIN_PATHS}
--- a/doc/fuse_db.sql	Fri Oct 17 19:28:27 2008 +0300
+++ b/doc/fuse_db.sql	Fri Oct 17 20:12:20 2008 +0300
@@ -31,6 +31,7 @@
 ALTER TABLE inodes ALTER COLUMN ino SET DEFAULT nextval('ino_seq'::regclass);
 
 ALTER TABLE file_tree ADD COLUMN ino int4;
+ALTER TABLE file_tree ADD CONSTRAINT file_tree_ino_fkey FOREIGN KEY (ino) REFERENCES inodes (ino);
 UPDATE file_tree SET ino = inode;
 ALTER TABLE file_tree DROP COLUMN inode;
 
@@ -41,4 +42,3 @@
         ELSE 0 
     END;
 $$;
-
--- a/src/dbfs/dbfs.c	Fri Oct 17 19:28:27 2008 +0300
+++ b/src/dbfs/dbfs.c	Fri Oct 17 20:12:20 2008 +0300
@@ -15,7 +15,9 @@
     .getattr        = dbfs_getattr,
     .setattr        = dbfs_setattr,
     .readlink       = dbfs_readlink,
-
+    .mknod          = dbfs_mknod,
+    .mkdir          = dbfs_mkdir,
+    
     .symlink        = dbfs_symlink,
     .rename         = dbfs_rename,
 
--- a/src/dbfs/fileop.c	Fri Oct 17 19:28:27 2008 +0300
+++ b/src/dbfs/fileop.c	Fri Oct 17 20:12:20 2008 +0300
@@ -39,7 +39,7 @@
 
     // is it a dir?
     if (_dbfs_mode(type) != S_IFREG)
-        EERROR(err = ENOENT, "wrong type: %s", type);
+        EERROR(err = EINVAL, "wrong type: %s", type);
     
     INFO("[dbfs.open %p:%p] -> ino=%lu, type=%s", fop, fop->base.req, (unsigned long int) fop->base.ino, type);
     
--- a/src/dbfs/link.c	Fri Oct 17 19:28:27 2008 +0300
+++ b/src/dbfs/link.c	Fri Oct 17 20:12:20 2008 +0300
@@ -1,9 +1,4 @@
-#include <stdlib.h>
-#include <assert.h>
-#include <string.h>
-
 #include "dbfs.h"
-#include "trans.h"
 
 #include "../lib/log.h"
 
@@ -83,184 +78,3 @@
 
 }
 
-struct dbfs_symlink_ctx {
-    struct dbfs_trans base;
-
-    char *link, *name;
-    uint32_t ino, parent;
-};
-
-#define DBFS_SYMLINK_MODE 0777
-
-void dbfs_symlink_free (struct dbfs_trans *ctx_base) {
-    struct dbfs_symlink_ctx *ctx = (struct dbfs_symlink_ctx *) ctx_base;
-    
-    free(ctx->link);
-    free(ctx->name);
-}
-
-void dbfs_symlink_commit (struct dbfs_trans *ctx_base) {
-    struct dbfs_symlink_ctx *ctx = (struct dbfs_symlink_ctx *) ctx_base;
-    struct fuse_entry_param e;
-    int err;
-    
-    // build entry
-    e.ino = e.attr.st_ino = ctx->ino;
-    e.attr.st_mode = S_IFLNK | DBFS_SYMLINK_MODE;
-    e.attr.st_size = strlen(ctx->link);
-    e.attr.st_nlink = 1;
-    e.attr_timeout = e.entry_timeout = CACHE_TIMEOUT;
-
-    // reply
-    if ((err = fuse_reply_entry(ctx_base->req, &e)))
-        goto error;
-
-    // req good
-    ctx_base->req = NULL;
-    
-    // free
-    dbfs_trans_free(ctx_base);
-
-    // return
-    return;
-
-error:
-    dbfs_trans_fail(ctx_base, err);
-}
-
-void dbfs_symlink_filetree (const struct evsql_result_info *res, void *arg) {
-    struct dbfs_symlink_ctx *ctx = arg;
-    int err = EIO;
-    
-    // check results
-    if (_dbfs_check_res(res, 0, 0) < 0)
-        goto error;
-    
-    // commit
-    dbfs_trans_commit(&ctx->base);
-
-    // fallthrough for result_free
-    err = 0;
-
-error:
-    if (err)
-        dbfs_trans_fail(&ctx->base, err);
-
-    evsql_result_free(res);
-}
-
-void dbfs_symlink_inode (const struct evsql_result_info *res, void *arg) {
-    struct dbfs_symlink_ctx *ctx = arg;
-    struct dbfs *dbfs_ctx = fuse_req_userdata(ctx->base.req);
-    int err = EIO;
-    
-    // check result
-    if ((err = _dbfs_check_res(res, 1, 1)))
-        SERROR(err = err > 0 ? ENOENT : EIO);
-    
-    // get ino
-    if (evsql_result_uint32(res, 0, 0, &ctx->ino, 0))
-        goto error;
-
-    // insert file_tree entry
-    const char *sql = 
-        "INSERT"
-        " INTO file_tree (name, parent, ino)"
-        " VALUES ($1::varchar, $2::int4, $3::int4)";
-    
-    static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) {
-        EVSQL_PARAM ( STRING ),
-        EVSQL_PARAM ( UINT32 ),
-        EVSQL_PARAM ( UINT32 ),
-
-        EVSQL_PARAMS_END
-    };
-
-    if (0
-        ||  evsql_param_string(&params, 0, ctx->name)
-        ||  evsql_param_uint32(&params, 1, ctx->parent)
-        ||  evsql_param_uint32(&params, 2, ctx->ino)
-    )
-        goto error;
-    
-    // query
-    if (evsql_query_params(dbfs_ctx->db, ctx->base.trans, sql, &params, dbfs_symlink_filetree, ctx))
-        goto error;
-    
-    // fallthrough for result_free
-    err = 0;
-
-error:
-    if (err)
-        dbfs_trans_fail(&ctx->base, err);
-
-    evsql_result_free(res);
-}
-
-void dbfs_symlink_begin (struct dbfs_trans *ctx_base) {
-    struct dbfs_symlink_ctx *ctx = (struct dbfs_symlink_ctx *) ctx_base;
-    struct dbfs *dbfs_ctx = fuse_req_userdata(ctx_base->req);
-
-    // insert inode
-    const char *sql = 
-        "INSERT"
-        " INTO inodes (type, mode, link_path)"
-        " VALUES ('LNK', $1::int2, $2::varchar)"
-        " RETURNING inodes.ino"; 
-    
-    static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) {
-        EVSQL_PARAM ( UINT16 ),
-        EVSQL_PARAM ( STRING ),
-
-        EVSQL_PARAMS_END
-    };
-
-    if (0
-        || evsql_param_uint16(&params, 0, DBFS_SYMLINK_MODE)
-        || evsql_param_string(&params, 1, ctx->link)
-    )
-        goto error;
-    
-    if (evsql_query_params(dbfs_ctx->db, ctx_base->trans, sql, &params, dbfs_symlink_inode, ctx) == NULL)
-        goto error;
-    
-    return;
-
-error:
-    dbfs_trans_fail(ctx_base, EIO);
-}
-
-void dbfs_symlink (struct fuse_req *req, const char *link, fuse_ino_t parent, const char *name) {
-    struct dbfs_symlink_ctx *ctx = NULL;
-
-    // alloc
-    if ((ctx = calloc(1, sizeof(*ctx))) == NULL)
-        ERROR("calloc");
-
-    // start trans
-    if (dbfs_trans_init(&ctx->base, req))
-        goto error;
- 
-    // callbacks
-    ctx->base.free_fn = dbfs_symlink_free;
-    ctx->base.begin_fn = dbfs_symlink_begin;
-    ctx->base.commit_fn = dbfs_symlink_commit;
-   
-    // state
-    ctx->ino = 0;
-    ctx->parent = parent;
-    if (!((ctx->link = strdup(link)) && (ctx->name = strdup(name))))
-        ERROR("strdup");
-    
-    // log
-    INFO("[dbfs.symlink %p:%p] link=%s, parent=%lu, name=%s", ctx, req, link, parent, name);
-
-    // wait
-    return;
-
-error:
-    if (ctx)
-        dbfs_trans_fail(&ctx->base, EIO);
-}
-
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dbfs/mk.c	Fri Oct 17 20:12:20 2008 +0300
@@ -0,0 +1,238 @@
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+#include "trans.h"
+#include "../lib/log.h"
+
+struct dbfs_mk_ctx {
+    struct dbfs_trans base;
+
+    const char *type, *data_expr;
+    char *link, *name;
+    uint16_t mode;
+    uint32_t ino, parent;
+};
+
+// default mode for symlinks
+#define DBFS_SYMLINK_MODE 0777
+
+// max. size for an dbfs_mk INSERT query
+#define DBFS_MK_SQL_MAX 512
+
+void dbfs_mk_free (struct dbfs_trans *ctx_base) {
+    struct dbfs_mk_ctx *ctx = (struct dbfs_mk_ctx *) ctx_base;
+    
+    free(ctx->link);
+    free(ctx->name);
+}
+
+void dbfs_mk_commit (struct dbfs_trans *ctx_base) {
+    struct dbfs_mk_ctx *ctx = (struct dbfs_mk_ctx *) ctx_base;
+    struct fuse_entry_param e;
+    int err;
+    
+    // build entry
+    e.ino = e.attr.st_ino = ctx->ino;
+    e.attr.st_mode = _dbfs_mode(ctx->type) | ctx->mode;
+    e.attr.st_size = ctx->link ? strlen(ctx->link) : 0;
+    e.attr.st_nlink = 1;
+    e.attr_timeout = e.entry_timeout = CACHE_TIMEOUT;
+
+    // reply
+    if ((err = fuse_reply_entry(ctx_base->req, &e)))
+        goto error;
+
+    // req good
+    ctx_base->req = NULL;
+    
+    // free
+    dbfs_trans_free(ctx_base);
+
+    // return
+    return;
+
+error:
+    dbfs_trans_fail(ctx_base, err);
+}
+
+void dbfs_mk_filetree (const struct evsql_result_info *res, void *arg) {
+    struct dbfs_mk_ctx *ctx = arg;
+    int err = EIO;
+    
+    // check results
+    if (_dbfs_check_res(res, 0, 0) < 0)
+        goto error;
+    
+    // commit
+    dbfs_trans_commit(&ctx->base);
+
+    // fallthrough for result_free
+    err = 0;
+
+error:
+    if (err)
+        dbfs_trans_fail(&ctx->base, err);
+
+    evsql_result_free(res);
+}
+
+void dbfs_mk_inode (const struct evsql_result_info *res, void *arg) {
+    struct dbfs_mk_ctx *ctx = arg;
+    struct dbfs *dbfs_ctx = fuse_req_userdata(ctx->base.req);
+    int err = EIO;
+    
+    // check result
+    if ((err = _dbfs_check_res(res, 1, 1)))
+        SERROR(err = err > 0 ? ENOENT : EIO);
+    
+    // get ino
+    if (evsql_result_uint32(res, 0, 0, &ctx->ino, 0))
+        goto error;
+
+    // insert file_tree entry
+    const char *sql = 
+        "INSERT"
+        " INTO file_tree (name, parent, ino)"
+        " VALUES ($1::varchar, $2::int4, $3::int4)";
+    
+    static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) {
+        EVSQL_PARAM ( STRING ),
+        EVSQL_PARAM ( UINT32 ),
+        EVSQL_PARAM ( UINT32 ),
+
+        EVSQL_PARAMS_END
+    };
+
+    if (0
+        ||  evsql_param_string(&params, 0, ctx->name)
+        ||  evsql_param_uint32(&params, 1, ctx->parent)
+        ||  evsql_param_uint32(&params, 2, ctx->ino)
+    )
+        goto error;
+    
+    // query
+    if (evsql_query_params(dbfs_ctx->db, ctx->base.trans, sql, &params, dbfs_mk_filetree, ctx))
+        goto error;
+    
+    // fallthrough for result_free
+    err = 0;
+
+error:
+    if (err)
+        dbfs_trans_fail(&ctx->base, err);
+
+    evsql_result_free(res);
+}
+
+void dbfs_mk_begin (struct dbfs_trans *ctx_base) {
+    struct dbfs_mk_ctx *ctx = (struct dbfs_mk_ctx *) ctx_base;
+    struct dbfs *dbfs_ctx = fuse_req_userdata(ctx_base->req);
+    int ret;
+
+    // insert inode
+    char sql_buf[DBFS_MK_SQL_MAX];
+    
+    if ((ret = snprintf(sql_buf, DBFS_MK_SQL_MAX, 
+        "INSERT"
+        " INTO inodes (type, mode, data, link_path)"
+        " VALUES ($1::char(3), $2::int2, %s, $3::varchar)"
+        " RETURNING inodes.ino", ctx->data_expr ? ctx->data_expr : "NULL"
+    )) >= DBFS_MK_SQL_MAX)
+        ERROR("sql_buf is too small: %d", ret);
+
+    static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) {
+        EVSQL_PARAM ( STRING ),
+        EVSQL_PARAM ( UINT16 ),
+        EVSQL_PARAM ( STRING ),
+
+        EVSQL_PARAMS_END
+    };
+
+    if (0
+        || evsql_param_string(&params, 0, ctx->type)
+        || evsql_param_uint16(&params, 1, ctx->mode)
+        || evsql_param_string(&params, 2, ctx->link)
+    )
+        goto error;
+    
+    if (evsql_query_params(dbfs_ctx->db, ctx_base->trans, sql_buf, &params, dbfs_mk_inode, ctx) == NULL)
+        goto error;
+    
+    return;
+
+error:
+    dbfs_trans_fail(ctx_base, EIO);
+}
+
+/*
+ * It is assumed that name and link_path must be copied, but type remains useable
+ */ 
+void dbfs_mk (struct fuse_req *req, fuse_ino_t parent, const char *name, const char *type, uint16_t mode, const char *data_expr, const char *link) {
+    struct dbfs_mk_ctx *ctx = NULL;
+
+    // alloc
+    if ((ctx = calloc(1, sizeof(*ctx))) == NULL)
+        ERROR("calloc");
+
+    // start trans
+    if (dbfs_trans_init(&ctx->base, req))
+        goto error;
+ 
+    // callbacks
+    ctx->base.free_fn = dbfs_mk_free;
+    ctx->base.begin_fn = dbfs_mk_begin;
+    ctx->base.commit_fn = dbfs_mk_commit;
+   
+    // state
+    ctx->ino = 0;
+    ctx->parent = parent;
+    ctx->type = type;
+    ctx->data_expr = data_expr;
+    ctx->mode = mode;
+
+    // copy volatile strings
+    if (
+            (link && (ctx->link = strdup(link)) == NULL)
+        ||  (name && (ctx->name = strdup(name)) == NULL)
+    )
+        ERROR("strdup");
+    
+    // log
+    INFO("[dbfs.mk %p:%p] parent=%lu, name=%s, type=%s, mode=%#04o data_expr=%s link=%s", ctx, req, parent, name, type, mode, data_expr, link);
+
+    // wait
+    return;
+
+error:
+    if (ctx)
+        dbfs_trans_fail(&ctx->base, EIO);
+}
+
+/*
+ * These are all just aliases to dbfs_mk
+ */ 
+void dbfs_mknod (struct fuse_req *req, fuse_ino_t parent, const char *name, mode_t mode, dev_t rdev) {
+    int err;
+
+    if ((mode & S_IFMT) != S_IFREG)
+        EERROR(err = EINVAL, "mode is not REG: %#08o", mode);
+
+    dbfs_mk(req, parent, name, "REG", mode & 07777, "lo_create(0)", NULL);
+
+    return;
+
+error:
+    if ((err = fuse_reply_err(req, err)))
+        EWARNING(err, "fuse_reply_error");
+}
+
+void dbfs_mkdir (struct fuse_req *req, fuse_ino_t parent, const char *name, mode_t mode) {
+    dbfs_mk(req, parent, name, "DIR", mode, NULL, NULL);
+}
+
+
+void dbfs_symlink (struct fuse_req *req, const char *link, fuse_ino_t parent, const char *name) {
+    dbfs_mk(req, parent, name, "LNK", DBFS_SYMLINK_MODE, NULL, link);
+}
+
--- a/src/dbfs/ops.h	Fri Oct 17 19:28:27 2008 +0300
+++ b/src/dbfs/ops.h	Fri Oct 17 20:12:20 2008 +0300
@@ -16,13 +16,17 @@
 
 /* link.c */
 void dbfs_readlink (struct fuse_req *req, fuse_ino_t ino);
-void dbfs_symlink (struct fuse_req *req, const char *link, fuse_ino_t parent, const char *name);
 
 /* dirop.c */
 void dbfs_opendir (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi);
 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);
 
+/* mk.c */
+void dbfs_mknod (struct fuse_req *req, fuse_ino_t parent, const char *name, mode_t mode, dev_t rdev);
+void dbfs_mkdir (struct fuse_req *req, fuse_ino_t parent, const char *name, mode_t mode);
+void dbfs_symlink (struct fuse_req *req, const char *link, fuse_ino_t parent, const char *name);
+
 /* tree.c */
 void dbfs_rename (struct fuse_req *req, fuse_ino_t parent, const char *name, fuse_ino_t newparent, const char *newname);