src/server/plugins/postgresql/vfs.c

branch
webdav
changeset 279
79029fe26aae
parent 278
38bf7b42b58c
child 280
d0d5a970292f
equal deleted inserted replaced
278:38bf7b42b58c 279:79029fe26aae
26 * POSSIBILITY OF SUCH DAMAGE. 26 * POSSIBILITY OF SUCH DAMAGE.
27 */ 27 */
28 28
29 #include "vfs.h" 29 #include "vfs.h"
30 30
31 #include <inttypes.h>
32
31 #include "../../util/util.h" 33 #include "../../util/util.h"
32 34
33 static VFS pg_vfs_class = { 35 static VFS pg_vfs_class = {
34 pg_vfs_open, 36 pg_vfs_open,
35 pg_vfs_stat, 37 pg_vfs_stat,
60 62
61 /* 63 /*
62 * SQL Queries 64 * SQL Queries
63 */ 65 */
64 66
65 // Resolvs a path into resource_id and parent_id 67 // Resolves a path into resource_id and parent_id
66 // params: $1: path string 68 // params: $1: path string
67 static const char *sql_resolve_path = 69 static const char *sql_resolve_path =
68 "with recursive resolvepath as (\n\ 70 "with recursive resolvepath as (\n\
69 select\n\ 71 select\n\
70 resource_id,\n\ 72 resource_id,\n\
77 where parent_id is null\n\ 79 where parent_id is null\n\
78 union\n\ 80 union\n\
79 select\n\ 81 select\n\
80 r.resource_id,\n\ 82 r.resource_id,\n\
81 r.parent_id,\n\ 83 r.parent_id,\n\
82 iscollection,\n\ 84 r.iscollection,\n\
83 p.pathelm,\n\ 85 p.pathelm,\n\
84 p.fullpath || '/' || r.nodename,\n\ 86 p.fullpath || '/' || r.nodename,\n\
85 p.pathdepth + 1\n\ 87 p.pathdepth + 1\n\
86 from Resource r\n\ 88 from Resource r\n\
87 inner join resolvepath p on r.parent_id = p.resource_id\n\ 89 inner join resolvepath p on r.parent_id = p.resource_id\n\
88 where p.pathelm[p.pathdepth+1] = r.nodename\n\ 90 where p.pathelm[p.pathdepth+1] = r.nodename\n\
89 )\ 91 )\n\
90 select resource_id, parent_id, fullpath, iscollection from resolvepath\n\ 92 select resource_id, parent_id, fullpath, iscollection from resolvepath\n\
91 where fullpath = '$1;"; 93 where fullpath = $1 ;";
92 94
95 // Same as sql_resolve_path, but it returns the root collection
96 // params: $1: path string (should be '/')
97 static const char *sql_get_root = "select resource_id, parent_id, $1 as fullpath, true as iscollection from Resource where parent_id is null;";
98
99 // Get all children of a specific collection
100 // params: $1: parent resource_id
101 static const char *sql_get_children = "select resource_id, nodename, iscollection from Resource where parent_id = $1;";
93 102
94 103
95 VFS* pg_vfs_create(Session *sn, Request *rq, pblock *pb) { 104 VFS* pg_vfs_create(Session *sn, Request *rq, pblock *pb) {
96 // resourcepool is required 105 // resourcepool is required
97 char *resource_pool = pblock_findval("resourcepool", pb); 106 char *resource_pool = pblock_findval("resourcepool", pb);
119 PgVFS *vfs_priv = pool_malloc(sn->pool, sizeof(PgVFS)); 128 PgVFS *vfs_priv = pool_malloc(sn->pool, sizeof(PgVFS));
120 if(!vfs_priv) { 129 if(!vfs_priv) {
121 pool_free(sn->pool, vfs); 130 pool_free(sn->pool, vfs);
122 return NULL; 131 return NULL;
123 } 132 }
133 vfs_priv->connection = resdata->data;
134 vfs_priv->pg_resource = resdata;
124 135
125 memcpy(vfs, &pg_vfs_class, sizeof(VFS)); 136 memcpy(vfs, &pg_vfs_class, sizeof(VFS));
126 vfs->flags = 0; 137 vfs->flags = 0;
127 vfs->instance = vfs_priv; 138 vfs->instance = vfs_priv;
128 139
142 // get last node of path 153 // get last node of path
143 *resource_name = util_resource_name(path); 154 *resource_name = util_resource_name(path);
144 155
145 VFS *vfs = ctx->vfs; 156 VFS *vfs = ctx->vfs;
146 PgVFS *pg = vfs->instance; 157 PgVFS *pg = vfs->instance;
147 158
148 159 const char *sql = pathlen == 1 ? sql_get_root : sql_resolve_path;
149 PGresult *result = PQexecParams( 160 PGresult *result = PQexecParams(
150 pg->connection, 161 pg->connection,
151 sql_resolve_path, 162 sql,
152 1, // number of parameters 163 1, // number of parameters
153 NULL, 164 NULL,
154 &path, // parameter value 165 &path, // parameter value
155 NULL, 166 NULL,
156 NULL, 167 NULL,
157 0); // 1: result in text format 168 0); // 0: result in text format
158 169
159 if(!result) return 1; 170 if(!result) return 1;
160 171
161 int ret = 1; 172 int ret = 1;
162 int nfields = PQnfields(result); 173 int nfields = PQnfields(result);
163 int nrows = PQntuples(result); 174 int nrows = PQntuples(result);
164 if(nrows == 1 && nfields == 4) { 175 if(nrows == 1 && nfields == 4) {
165 char *resource_id_str = PQgetvalue(result, 0, 0); 176 char *resource_id_str = PQgetvalue(result, 0, 0);
166 char *parent_id_str = PQgetvalue(result, 0, 1); 177 char *parent_id_str = PQgetvalue(result, 0, 1);
167 char *iscol = PQgetvalue(result, 0, 2); 178 char *iscol = PQgetvalue(result, 0, 3);
168 if(resource_id_str && parent_id_str) { 179 if(resource_id_str && parent_id_str) {
169 if(util_strtoint(resource_id_str, resource_id) && util_strtoint(parent_id_str, parent_id)) { 180 if(util_strtoint(resource_id_str, resource_id)) {
170 ret = 0; // success 181 ret = 0; // success
171 } 182 }
183 // optionally get parent_id
184 util_strtoint(parent_id_str, parent_id);
172 } 185 }
173 if(iscol) { 186 if(iscol) {
174 *iscollection = iscol[0] == 't' ? TRUE : FALSE; 187 *iscollection = iscol[0] == 't' ? TRUE : FALSE;
175 } 188 }
176 } else { 189 } else {
186 /* -------------------------- VFS functions -------------------------- */ 199 /* -------------------------- VFS functions -------------------------- */
187 200
188 SYS_FILE pg_vfs_open(VFSContext *ctx, const char *path, int oflags) { 201 SYS_FILE pg_vfs_open(VFSContext *ctx, const char *path, int oflags) {
189 const char *resname; 202 const char *resname;
190 int64_t resource_id, parent_id; 203 int64_t resource_id, parent_id;
204 resource_id = -1;
205 parent_id = -1;
191 WSBool iscollection; 206 WSBool iscollection;
192 if(pg_resolve_path(ctx, path, &resource_id, &parent_id, &resname, &iscollection)) { 207 if(pg_resolve_path(ctx, path, &parent_id, &resource_id, &resname, &iscollection)) {
193 return NULL; 208 return NULL;
194 } 209 }
195 210
196 VFSFile *file = pool_malloc(ctx->pool, sizeof(VFSFile)); 211 VFSFile *file = pool_malloc(ctx->pool, sizeof(VFSFile));
197 if(!file) { 212 if(!file) {
222 int pg_vfs_fstat(VFSContext *ctx, SYS_FILE fd, struct stat *buf) { 237 int pg_vfs_fstat(VFSContext *ctx, SYS_FILE fd, struct stat *buf) {
223 238
224 } 239 }
225 240
226 VFS_DIR pg_vfs_opendir(VFSContext *ctx, const char *path) { 241 VFS_DIR pg_vfs_opendir(VFSContext *ctx, const char *path) {
227 242 VFSFile *file = pg_vfs_open(ctx, path, O_RDONLY);
243 if(!file) return NULL;
244 return pg_vfs_fdopendir(ctx, file);
228 } 245 }
229 246
230 VFS_DIR pg_vfs_fdopendir(VFSContext *ctx, SYS_FILE fd) { 247 VFS_DIR pg_vfs_fdopendir(VFSContext *ctx, SYS_FILE fd) {
231 248 PgFile *pg = fd->data;
249 if(!pg->iscollection) {
250 ctx->vfs_errno = ENOTDIR;
251 return NULL;
252 }
253
254 VFSDir *dir = pool_malloc(ctx->pool, sizeof(VFSDir));
255 if(!dir) {
256 fd->io->close(fd);
257 ctx->vfs_errno = ENOMEM;
258 return NULL;
259 }
260
261 PgDir *pgdir = pool_malloc(ctx->pool, sizeof(PgDir));
262 if(!pgdir) {
263 fd->io->close(fd);
264 pool_free(ctx->pool, dir);
265 ctx->vfs_errno = ENOMEM;
266 return NULL;
267 }
268 memset(pgdir, 0, sizeof(PgDir));
269 pgdir->file = fd;
270
271 dir->ctx = ctx;
272 dir->io = &pg_vfs_dirio_class;
273 dir->data = pgdir;
274 dir->fd = -1;
275
276 return dir;
232 } 277 }
233 278
234 int pg_vfs_mkdir(VFSContext *ctx, const char *path) { 279 int pg_vfs_mkdir(VFSContext *ctx, const char *path) {
235 280
236 } 281 }
271 } 316 }
272 317
273 318
274 /* -------------------------- VFS_DIRIO functions -------------------------- */ 319 /* -------------------------- VFS_DIRIO functions -------------------------- */
275 320
321 static int load_dir(VFSDir *dir, PgDir *pg) {
322 VFS *vfs = dir->ctx->vfs;
323 PgVFS *pgvfs = vfs->instance;
324 PgFile *pgfd = pg->file->data;
325 PgDir *pgdir = dir->data;
326
327 char resid_param[32];
328 snprintf(resid_param, 32, "%" PRId64, pgfd->resource_id);
329
330 const char *param = resid_param;
331
332 PGresult *result = PQexecParams(
333 pgvfs->connection,
334 sql_get_children,
335 1, // number of parameters
336 NULL,
337 &param, // param: parent resource_id
338 NULL,
339 NULL,
340 0); // 0: result in text format
341 if(!result) return 1;
342
343 pgdir->result = result;
344 pgdir->nrows = PQntuples(result);
345 return 0;
346 }
347
276 int pg_vfs_dirio_readdir(VFS_DIR dir, VFS_ENTRY *entry, int getstat) { 348 int pg_vfs_dirio_readdir(VFS_DIR dir, VFS_ENTRY *entry, int getstat) {
277 349 PgDir *pg = dir->data;
350 if(!pg->result) {
351 if(load_dir(dir, pg)) {
352 return 0;
353 }
354 }
355
356 if(pg->row >= pg->nrows) {
357 return 0; // EOF
358 }
359
360 entry->name = PQgetvalue(pg->result, pg->row, 1);
361
362 // TODO: stat
363
364 pg->row++;
365 return 1;
278 } 366 }
279 367
280 void pg_vfs_dirio_close(VFS_DIR dir) { 368 void pg_vfs_dirio_close(VFS_DIR dir) {
281 369
282 } 370 }

mercurial