src/server/plugins/postgresql/vfs.c

branch
webdav
changeset 279
79029fe26aae
parent 278
38bf7b42b58c
child 280
d0d5a970292f
--- a/src/server/plugins/postgresql/vfs.c	Sun Jan 30 15:25:29 2022 +0100
+++ b/src/server/plugins/postgresql/vfs.c	Mon Jan 31 17:18:12 2022 +0100
@@ -28,6 +28,8 @@
 
 #include "vfs.h"
 
+#include <inttypes.h>
+
 #include "../../util/util.h"
 
 static VFS pg_vfs_class = {
@@ -62,7 +64,7 @@
  * SQL Queries
  */
 
-// Resolvs a path into resource_id and parent_id
+// Resolves a path into resource_id and parent_id
 // params: $1: path string
 static const char *sql_resolve_path = 
     "with recursive resolvepath as (\n\
@@ -79,17 +81,24 @@
         select\n\
             r.resource_id,\n\
             r.parent_id,\n\
-            iscollection,\n\
+            r.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\
-    )\
+    )\n\
     select resource_id, parent_id, fullpath, iscollection from resolvepath\n\
-    where fullpath = '$1;";
+    where fullpath = $1 ;";
 
+// Same as sql_resolve_path, but it returns the root collection
+// params: $1: path string (should be '/')
+static const char *sql_get_root = "select resource_id, parent_id, $1 as fullpath, true as iscollection from Resource where parent_id is null;";
+
+// Get all children of a specific collection
+// params: $1: parent resource_id
+static const char *sql_get_children = "select resource_id, nodename, iscollection from Resource where parent_id = $1;";
 
 
 VFS* pg_vfs_create(Session *sn, Request *rq, pblock *pb) {
@@ -121,6 +130,8 @@
         pool_free(sn->pool, vfs);
         return NULL;
     }
+    vfs_priv->connection = resdata->data;
+    vfs_priv->pg_resource = resdata;
     
     memcpy(vfs, &pg_vfs_class, sizeof(VFS));
     vfs->flags = 0;
@@ -144,17 +155,17 @@
     
     VFS *vfs = ctx->vfs;
     PgVFS *pg = vfs->instance;
-
     
+    const char *sql = pathlen == 1 ? sql_get_root : sql_resolve_path;
     PGresult *result = PQexecParams(
             pg->connection,
-            sql_resolve_path,
+            sql,
             1,     // number of parameters
             NULL,
             &path, // parameter value
             NULL,
             NULL,
-            0);    // 1: result in text format
+            0);    // 0: result in text format
     
     if(!result) return 1;
     
@@ -164,11 +175,13 @@
     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);
+        char *iscol = PQgetvalue(result, 0, 3);
         if(resource_id_str && parent_id_str) {
-            if(util_strtoint(resource_id_str, resource_id) && util_strtoint(parent_id_str, parent_id)) {
+            if(util_strtoint(resource_id_str, resource_id)) {
                 ret = 0; // success
             }
+            // optionally get parent_id
+            util_strtoint(parent_id_str, parent_id);
         }
         if(iscol) {
             *iscollection = iscol[0] == 't' ? TRUE : FALSE;
@@ -188,8 +201,10 @@
 SYS_FILE pg_vfs_open(VFSContext *ctx, const char *path, int oflags) {
     const char *resname;
     int64_t resource_id, parent_id;
+    resource_id = -1;
+    parent_id = -1;
     WSBool iscollection;
-    if(pg_resolve_path(ctx, path, &resource_id, &parent_id, &resname, &iscollection)) {
+    if(pg_resolve_path(ctx, path, &parent_id, &resource_id, &resname, &iscollection)) {
         return NULL;
     }
     
@@ -224,11 +239,41 @@
 }
 
 VFS_DIR pg_vfs_opendir(VFSContext *ctx, const char *path) {
-    
+    VFSFile *file = pg_vfs_open(ctx, path, O_RDONLY);
+    if(!file) return NULL;
+    return pg_vfs_fdopendir(ctx, file);
 }
 
 VFS_DIR pg_vfs_fdopendir(VFSContext *ctx, SYS_FILE fd) {
+    PgFile *pg = fd->data;
+    if(!pg->iscollection) {
+        ctx->vfs_errno = ENOTDIR;
+        return NULL;
+    }
     
+    VFSDir *dir = pool_malloc(ctx->pool, sizeof(VFSDir));
+    if(!dir) {
+        fd->io->close(fd);
+        ctx->vfs_errno = ENOMEM;
+        return NULL;
+    }
+    
+    PgDir *pgdir = pool_malloc(ctx->pool, sizeof(PgDir));
+    if(!pgdir) {
+        fd->io->close(fd);
+        pool_free(ctx->pool, dir);
+        ctx->vfs_errno = ENOMEM;
+        return NULL;
+    }
+    memset(pgdir, 0, sizeof(PgDir));
+    pgdir->file = fd;
+    
+    dir->ctx = ctx;
+    dir->io = &pg_vfs_dirio_class;
+    dir->data = pgdir;
+    dir->fd = -1;
+    
+    return dir;
 }
 
 int pg_vfs_mkdir(VFSContext *ctx, const char *path) {
@@ -273,8 +318,51 @@
 
 /* -------------------------- VFS_DIRIO functions -------------------------- */
 
+static int load_dir(VFSDir *dir, PgDir *pg) {
+    VFS *vfs = dir->ctx->vfs;
+    PgVFS *pgvfs = vfs->instance;
+    PgFile *pgfd = pg->file->data;
+    PgDir *pgdir = dir->data;
+    
+    char resid_param[32];
+    snprintf(resid_param, 32, "%" PRId64, pgfd->resource_id);
+    
+    const char *param = resid_param;
+    
+    PGresult *result = PQexecParams(
+            pgvfs->connection,
+            sql_get_children,
+            1,                                  // number of parameters
+            NULL,
+            &param,  // param: parent resource_id 
+            NULL,
+            NULL,
+            0);                                 // 0: result in text format
+    if(!result) return 1;
+    
+    pgdir->result = result;
+    pgdir->nrows = PQntuples(result);
+    return 0;
+}
+
 int pg_vfs_dirio_readdir(VFS_DIR dir, VFS_ENTRY *entry, int getstat) {
+    PgDir *pg = dir->data;
+    if(!pg->result) {
+        if(load_dir(dir, pg)) {
+            return 0;
+        }
+    }
     
+    if(pg->row >= pg->nrows) {
+        return 0; // EOF
+    }
+    
+    entry->name = PQgetvalue(pg->result, pg->row, 1);
+        
+    // TODO: stat
+
+    pg->row++;
+    return 1;
 }
 
 void pg_vfs_dirio_close(VFS_DIR dir) {

mercurial