35
|
1 |
#include <stdlib.h>
|
|
2 |
#include <assert.h>
|
|
3 |
#include <string.h>
|
|
4 |
|
|
5 |
#include "trans.h"
|
|
6 |
#include "../lib/log.h"
|
|
7 |
|
|
8 |
struct dbfs_mk_ctx {
|
|
9 |
struct dbfs_trans base;
|
|
10 |
|
|
11 |
const char *type, *data_expr;
|
|
12 |
char *link, *name;
|
|
13 |
uint16_t mode;
|
|
14 |
uint32_t ino, parent;
|
|
15 |
};
|
|
16 |
|
|
17 |
// default mode for symlinks
|
|
18 |
#define DBFS_SYMLINK_MODE 0777
|
|
19 |
|
|
20 |
// max. size for an dbfs_mk INSERT query
|
|
21 |
#define DBFS_MK_SQL_MAX 512
|
|
22 |
|
|
23 |
void dbfs_mk_free (struct dbfs_trans *ctx_base) {
|
|
24 |
struct dbfs_mk_ctx *ctx = (struct dbfs_mk_ctx *) ctx_base;
|
|
25 |
|
|
26 |
free(ctx->link);
|
|
27 |
free(ctx->name);
|
|
28 |
}
|
|
29 |
|
|
30 |
void dbfs_mk_commit (struct dbfs_trans *ctx_base) {
|
|
31 |
struct dbfs_mk_ctx *ctx = (struct dbfs_mk_ctx *) ctx_base;
|
|
32 |
struct fuse_entry_param e;
|
|
33 |
int err;
|
|
34 |
|
|
35 |
// build entry
|
|
36 |
e.ino = e.attr.st_ino = ctx->ino;
|
|
37 |
e.attr.st_mode = _dbfs_mode(ctx->type) | ctx->mode;
|
|
38 |
e.attr.st_size = ctx->link ? strlen(ctx->link) : 0;
|
|
39 |
e.attr.st_nlink = 1;
|
|
40 |
e.attr_timeout = e.entry_timeout = CACHE_TIMEOUT;
|
|
41 |
|
|
42 |
// reply
|
|
43 |
if ((err = fuse_reply_entry(ctx_base->req, &e)))
|
|
44 |
goto error;
|
|
45 |
|
|
46 |
// req good
|
|
47 |
ctx_base->req = NULL;
|
|
48 |
|
|
49 |
// free
|
|
50 |
dbfs_trans_free(ctx_base);
|
|
51 |
|
|
52 |
// return
|
|
53 |
return;
|
|
54 |
|
|
55 |
error:
|
|
56 |
dbfs_trans_fail(ctx_base, err);
|
|
57 |
}
|
|
58 |
|
|
59 |
void dbfs_mk_filetree (const struct evsql_result_info *res, void *arg) {
|
|
60 |
struct dbfs_mk_ctx *ctx = arg;
|
|
61 |
int err = EIO;
|
|
62 |
|
|
63 |
// check results
|
|
64 |
if (_dbfs_check_res(res, 0, 0) < 0)
|
|
65 |
goto error;
|
|
66 |
|
|
67 |
// commit
|
|
68 |
dbfs_trans_commit(&ctx->base);
|
|
69 |
|
|
70 |
// fallthrough for result_free
|
|
71 |
err = 0;
|
|
72 |
|
|
73 |
error:
|
|
74 |
if (err)
|
|
75 |
dbfs_trans_fail(&ctx->base, err);
|
|
76 |
|
|
77 |
evsql_result_free(res);
|
|
78 |
}
|
|
79 |
|
|
80 |
void dbfs_mk_inode (const struct evsql_result_info *res, void *arg) {
|
|
81 |
struct dbfs_mk_ctx *ctx = arg;
|
|
82 |
struct dbfs *dbfs_ctx = fuse_req_userdata(ctx->base.req);
|
|
83 |
int err = EIO;
|
|
84 |
|
|
85 |
// check result
|
|
86 |
if ((err = _dbfs_check_res(res, 1, 1)))
|
|
87 |
SERROR(err = err > 0 ? ENOENT : EIO);
|
|
88 |
|
|
89 |
// get ino
|
|
90 |
if (evsql_result_uint32(res, 0, 0, &ctx->ino, 0))
|
|
91 |
goto error;
|
|
92 |
|
|
93 |
// insert file_tree entry
|
|
94 |
const char *sql =
|
|
95 |
"INSERT"
|
|
96 |
" INTO file_tree (name, parent, ino)"
|
|
97 |
" VALUES ($1::varchar, $2::int4, $3::int4)";
|
|
98 |
|
|
99 |
static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) {
|
|
100 |
EVSQL_PARAM ( STRING ),
|
|
101 |
EVSQL_PARAM ( UINT32 ),
|
|
102 |
EVSQL_PARAM ( UINT32 ),
|
|
103 |
|
|
104 |
EVSQL_PARAMS_END
|
|
105 |
};
|
|
106 |
|
|
107 |
if (0
|
|
108 |
|| evsql_param_string(¶ms, 0, ctx->name)
|
|
109 |
|| evsql_param_uint32(¶ms, 1, ctx->parent)
|
|
110 |
|| evsql_param_uint32(¶ms, 2, ctx->ino)
|
|
111 |
)
|
|
112 |
goto error;
|
|
113 |
|
|
114 |
// query
|
|
115 |
if (evsql_query_params(dbfs_ctx->db, ctx->base.trans, sql, ¶ms, dbfs_mk_filetree, ctx))
|
|
116 |
goto error;
|
|
117 |
|
|
118 |
// fallthrough for result_free
|
|
119 |
err = 0;
|
|
120 |
|
|
121 |
error:
|
|
122 |
if (err)
|
|
123 |
dbfs_trans_fail(&ctx->base, err);
|
|
124 |
|
|
125 |
evsql_result_free(res);
|
|
126 |
}
|
|
127 |
|
|
128 |
void dbfs_mk_begin (struct dbfs_trans *ctx_base) {
|
|
129 |
struct dbfs_mk_ctx *ctx = (struct dbfs_mk_ctx *) ctx_base;
|
|
130 |
struct dbfs *dbfs_ctx = fuse_req_userdata(ctx_base->req);
|
|
131 |
int ret;
|
|
132 |
|
|
133 |
// insert inode
|
|
134 |
char sql_buf[DBFS_MK_SQL_MAX];
|
|
135 |
|
|
136 |
if ((ret = snprintf(sql_buf, DBFS_MK_SQL_MAX,
|
|
137 |
"INSERT"
|
|
138 |
" INTO inodes (type, mode, data, link_path)"
|
|
139 |
" VALUES ($1::char(3), $2::int2, %s, $3::varchar)"
|
|
140 |
" RETURNING inodes.ino", ctx->data_expr ? ctx->data_expr : "NULL"
|
|
141 |
)) >= DBFS_MK_SQL_MAX)
|
|
142 |
ERROR("sql_buf is too small: %d", ret);
|
|
143 |
|
|
144 |
static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) {
|
|
145 |
EVSQL_PARAM ( STRING ),
|
|
146 |
EVSQL_PARAM ( UINT16 ),
|
|
147 |
EVSQL_PARAM ( STRING ),
|
|
148 |
|
|
149 |
EVSQL_PARAMS_END
|
|
150 |
};
|
|
151 |
|
|
152 |
if (0
|
|
153 |
|| evsql_param_string(¶ms, 0, ctx->type)
|
|
154 |
|| evsql_param_uint16(¶ms, 1, ctx->mode)
|
|
155 |
|| evsql_param_string(¶ms, 2, ctx->link)
|
|
156 |
)
|
|
157 |
goto error;
|
|
158 |
|
|
159 |
if (evsql_query_params(dbfs_ctx->db, ctx_base->trans, sql_buf, ¶ms, dbfs_mk_inode, ctx) == NULL)
|
|
160 |
goto error;
|
|
161 |
|
|
162 |
return;
|
|
163 |
|
|
164 |
error:
|
|
165 |
dbfs_trans_fail(ctx_base, EIO);
|
|
166 |
}
|
|
167 |
|
|
168 |
/*
|
|
169 |
* It is assumed that name and link_path must be copied, but type remains useable
|
|
170 |
*/
|
|
171 |
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) {
|
|
172 |
struct dbfs_mk_ctx *ctx = NULL;
|
|
173 |
|
|
174 |
// alloc
|
|
175 |
if ((ctx = calloc(1, sizeof(*ctx))) == NULL)
|
|
176 |
ERROR("calloc");
|
|
177 |
|
|
178 |
// start trans
|
|
179 |
if (dbfs_trans_init(&ctx->base, req))
|
|
180 |
goto error;
|
|
181 |
|
|
182 |
// callbacks
|
|
183 |
ctx->base.free_fn = dbfs_mk_free;
|
|
184 |
ctx->base.begin_fn = dbfs_mk_begin;
|
|
185 |
ctx->base.commit_fn = dbfs_mk_commit;
|
|
186 |
|
|
187 |
// state
|
|
188 |
ctx->ino = 0;
|
|
189 |
ctx->parent = parent;
|
|
190 |
ctx->type = type;
|
|
191 |
ctx->data_expr = data_expr;
|
|
192 |
ctx->mode = mode;
|
|
193 |
|
|
194 |
// copy volatile strings
|
|
195 |
if (
|
|
196 |
(link && (ctx->link = strdup(link)) == NULL)
|
|
197 |
|| (name && (ctx->name = strdup(name)) == NULL)
|
|
198 |
)
|
|
199 |
ERROR("strdup");
|
|
200 |
|
|
201 |
// log
|
|
202 |
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);
|
|
203 |
|
|
204 |
// wait
|
|
205 |
return;
|
|
206 |
|
|
207 |
error:
|
|
208 |
if (ctx)
|
|
209 |
dbfs_trans_fail(&ctx->base, EIO);
|
|
210 |
}
|
|
211 |
|
|
212 |
/*
|
|
213 |
* These are all just aliases to dbfs_mk
|
|
214 |
*/
|
|
215 |
void dbfs_mknod (struct fuse_req *req, fuse_ino_t parent, const char *name, mode_t mode, dev_t rdev) {
|
|
216 |
int err;
|
|
217 |
|
|
218 |
if ((mode & S_IFMT) != S_IFREG)
|
|
219 |
EERROR(err = EINVAL, "mode is not REG: %#08o", mode);
|
|
220 |
|
|
221 |
dbfs_mk(req, parent, name, "REG", mode & 07777, "lo_create(0)", NULL);
|
|
222 |
|
|
223 |
return;
|
|
224 |
|
|
225 |
error:
|
|
226 |
if ((err = fuse_reply_err(req, err)))
|
|
227 |
EWARNING(err, "fuse_reply_error");
|
|
228 |
}
|
|
229 |
|
|
230 |
void dbfs_mkdir (struct fuse_req *req, fuse_ino_t parent, const char *name, mode_t mode) {
|
|
231 |
dbfs_mk(req, parent, name, "DIR", mode, NULL, NULL);
|
|
232 |
}
|
|
233 |
|
|
234 |
|
|
235 |
void dbfs_symlink (struct fuse_req *req, const char *link, fuse_ino_t parent, const char *name) {
|
|
236 |
dbfs_mk(req, parent, name, "LNK", DBFS_SYMLINK_MODE, NULL, link);
|
|
237 |
}
|
|
238 |
|