src/server/plugins/postgresql/vfs.c

branch
webdav
changeset 278
38bf7b42b58c
parent 276
0cb4eda146c4
child 279
79029fe26aae
--- a/src/server/plugins/postgresql/vfs.c	Fri Jan 28 16:01:05 2022 +0100
+++ b/src/server/plugins/postgresql/vfs.c	Sun Jan 30 15:25:29 2022 +0100
@@ -28,6 +28,8 @@
 
 #include "vfs.h"
 
+#include "../../util/util.h"
+
 static VFS pg_vfs_class = {
     pg_vfs_open,
     pg_vfs_stat,
@@ -56,10 +58,43 @@
 };
 
 
+/*
+ * SQL Queries
+ */
+
+// Resolvs a path into resource_id and parent_id
+// params: $1: path string
+static const char *sql_resolve_path = 
+    "with recursive resolvepath as (\n\
+        select\n\
+            resource_id,\n\
+            parent_id,\n\
+            iscollection,\n\
+            regexp_split_to_array($1, '/') as pathelm,\n\
+            '' as fullpath,\n\
+            1 as pathdepth\n\
+        from Resource\n\
+        where parent_id is null\n\
+        union\n\
+        select\n\
+            r.resource_id,\n\
+            r.parent_id,\n\
+            iscollection,\n\
+            p.pathelm,\n\
+            p.fullpath || '/' || r.nodename,\n\
+            p.pathdepth + 1\n\
+        from Resource r\n\
+        inner join resolvepath p on r.parent_id = p.resource_id\n\
+        where p.pathelm[p.pathdepth+1] = r.nodename\n\
+    )\
+    select resource_id, parent_id, fullpath, iscollection from resolvepath\n\
+    where fullpath = '$1;";
+
+
 
 VFS* pg_vfs_create(Session *sn, Request *rq, pblock *pb) {
     // resourcepool is required
-    char *resource_pool = pblock_find("resourcepool", pb);
+    char *resource_pool = pblock_findval("resourcepool", pb);
     if(!resource_pool) {
         log_ereport(LOG_MISCONFIG, "pg_vfs_create: missing resourcepool parameter");
         return NULL;
@@ -95,10 +130,89 @@
 }
 
 
+int pg_resolve_path(VFSContext *ctx, const char *path, int64_t *parent_id, int64_t *resource_id, const char **resource_name, WSBool *iscollection) {
+    // basic path validation
+    if(!path) return 1;
+    size_t pathlen = strlen(path);
+    if(pathlen == 0) return 1;
+    if(path[0] != '/') {
+        return 1;
+    }
+    
+    // get last node of path
+    *resource_name = util_resource_name(path);
+    
+    VFS *vfs = ctx->vfs;
+    PgVFS *pg = vfs->instance;
+
+    
+    PGresult *result = PQexecParams(
+            pg->connection,
+            sql_resolve_path,
+            1,     // number of parameters
+            NULL,
+            &path, // parameter value
+            NULL,
+            NULL,
+            0);    // 1: result in text format
+    
+    if(!result) return 1;
+    
+    int ret = 1;
+    int nfields = PQnfields(result);
+    int nrows = PQntuples(result);
+    if(nrows == 1 && nfields == 4) {
+        char *resource_id_str = PQgetvalue(result, 0, 0);
+        char *parent_id_str = PQgetvalue(result, 0, 1);
+        char *iscol = PQgetvalue(result, 0, 2);
+        if(resource_id_str && parent_id_str) {
+            if(util_strtoint(resource_id_str, resource_id) && util_strtoint(parent_id_str, parent_id)) {
+                ret = 0; // success
+            }
+        }
+        if(iscol) {
+            *iscollection = iscol[0] == 't' ? TRUE : FALSE;
+        }
+    } else {
+        ctx->vfs_errno = ENOENT;
+    }
+    
+    PQclear(result);
+    
+    return ret;
+}
+
+
 /* -------------------------- VFS functions -------------------------- */
 
 SYS_FILE pg_vfs_open(VFSContext *ctx, const char *path, int oflags) {
+    const char *resname;
+    int64_t resource_id, parent_id;
+    WSBool iscollection;
+    if(pg_resolve_path(ctx, path, &resource_id, &parent_id, &resname, &iscollection)) {
+        return NULL;
+    }
     
+    VFSFile *file = pool_malloc(ctx->pool, sizeof(VFSFile));
+    if(!file) {
+        return NULL;
+    }
+    PgFile *pgfile = pool_malloc(ctx->pool, sizeof(PgFile));
+    if(!pgfile) {
+        pool_free(ctx->pool, file);
+        return NULL;
+    }
+    
+    pgfile->iscollection = iscollection;
+    pgfile->resource_id = resource_id;
+    pgfile->parent_id = parent_id;
+    
+    file->ctx = ctx;
+    file->io = iscollection ? NULL : &pg_vfs_io_class;
+    file->fd = -1;
+    file->data = pgfile;
+    
+    return file;
 }
 
 int pg_vfs_stat(VFSContext *ctx, const char *path, struct stat *buf) {

mercurial