add pg vfs stat/fstat implementation webdav

Tue, 01 Feb 2022 17:47:50 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Tue, 01 Feb 2022 17:47:50 +0100
branch
webdav
changeset 281
e9dc53661df4
parent 280
d0d5a970292f
child 282
cfb588e27198

add pg vfs stat/fstat implementation

doc/development/postgresql_vfs.sql file | annotate | diff | comparison | revisions
doc/development/postgresql_vfs_testdata.sql file | annotate | diff | comparison | revisions
src/server/plugins/postgresql/vfs.c file | annotate | diff | comparison | revisions
src/server/plugins/postgresql/vfs.h file | annotate | diff | comparison | revisions
--- a/doc/development/postgresql_vfs.sql	Mon Jan 31 21:33:46 2022 +0100
+++ b/doc/development/postgresql_vfs.sql	Tue Feb 01 17:47:50 2022 +0100
@@ -3,7 +3,12 @@
     resource_id       serial    primary key,
     parent_id         int       references Resource(resource_id),
     nodename          text      not null,
-    iscollection      boolean   not null default(false),
+    iscollection      boolean   not null default false,
+	
+    lastmodified      timestamp not null default current_date,
+    creationdate      timestamp not null default current_date,
+    contentlength     bigint    not null default 0,
     
     unique(parent_id, nodename)
 );
+
--- a/doc/development/postgresql_vfs_testdata.sql	Mon Jan 31 21:33:46 2022 +0100
+++ b/doc/development/postgresql_vfs_testdata.sql	Tue Feb 01 17:47:50 2022 +0100
@@ -1,20 +1,29 @@
-
-
-insert into Resource (nodename, iscollection) values ('', true);
-
-insert into Resource(parent_id,  nodename) values
-((select resource_id from Resource where parent_id is null), 'file1.txt'),
-((select resource_id from Resource where parent_id is null), 'file2.txt'),
-((select resource_id from Resource where parent_id is null), 'file3.txt'),
-((select resource_id from Resource where parent_id is null), 'file4.txt');
 
-insert into Resource(parent_id,  nodename, iscollection) values
-((select resource_id from Resource where parent_id is null), 'dir1', true);
+do $$
+declare
+    res_id int;
+begin
+    insert into Resource (nodename, iscollection) values ('', true);
+    res_id := lastval();
+   
+    insert into Resource(parent_id,  nodename) values
+    (res_id, 'file1.txt'),
+    (res_id, 'file2.txt'),
+    (res_id, 'file3.txt'),
+    (res_id, 'file4.txt');
+    
+    insert into Resource(parent_id,  nodename, iscollection) values
+    (res_id, 'dir1', true);
+    res_id := lastval();
+    
+    insert into Resource(parent_id,  nodename, iscollection) values
+    (res_id, 'dir2', true);
+    res_id := lastval();
+    
+    insert into Resource(parent_id,  nodename) values
+    (res_id, 'd1file1.txt'),
+    (res_id, 'd2file1.txt'),
+    (res_id, 'd2file2.txt');
 
-insert into Resource(parent_id,  nodename, iscollection) values
-((select resource_id from Resource where nodename = 'dir1'), 'dir2', true);
+end $$;
 
-insert into Resource(parent_id,  nodename) values
-((select resource_id from Resource where nodename = 'dir1'), 'd1file1.txt'),
-((select resource_id from Resource where nodename = 'dir2'), 'd2file1.txt'),
-((select resource_id from Resource where nodename = 'dir2'), 'd2file2.txt');
--- a/src/server/plugins/postgresql/vfs.c	Mon Jan 31 21:33:46 2022 +0100
+++ b/src/server/plugins/postgresql/vfs.c	Tue Feb 01 17:47:50 2022 +0100
@@ -71,9 +71,12 @@
         select\n\
             resource_id,\n\
             parent_id,\n\
+            '' as fullpath,\n\
             iscollection,\n\
+            lastmodified,\n\
+            creationdate,\n\
+            contentlength,\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\
@@ -81,9 +84,12 @@
         select\n\
             r.resource_id,\n\
             r.parent_id,\n\
+            p.fullpath || '/' || r.nodename,\n\
             r.iscollection,\n\
+            r.lastmodified,\n\
+            r.creationdate,\n\
+            r.contentlength,\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\
@@ -94,12 +100,15 @@
 
 // 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;";
+static const char *sql_get_root = "select resource_id, parent_id, $1 as fullpath, true as iscollection, lastmodified, creationdate, contentlength 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;";
+static const char *sql_get_children = "select resource_id, nodename, iscollection, lastmodified, creationdate, contentlength from Resource where parent_id = $1;";
 
+// Get resource
+// params: $1: resource_id
+static const char *sql_get_resource = "select resource_id, nodename, iscollection, lastmodified, creationdate, contentlength from Resource where resource_id = $1;";
 
 VFS* pg_vfs_create(Session *sn, Request *rq, pblock *pb) {
     // resourcepool is required
@@ -141,7 +150,15 @@
 }
 
 
-int pg_resolve_path(VFSContext *ctx, const char *path, int64_t *parent_id, int64_t *resource_id, const char **resource_name, WSBool *iscollection) {
+int pg_resolve_path(
+        VFSContext *ctx,
+        const char *path,
+        int64_t *parent_id,
+        int64_t *resource_id,
+        const char **resource_name,
+        WSBool *iscollection,
+        struct stat *s)
+{
     // basic path validation
     if(!path) return 1;
     size_t pathlen = strlen(path);
@@ -150,13 +167,21 @@
         return 1;
     }
     
+    char *pathf = NULL;
+    if(pathlen > 1 && path[pathlen-1] == '/') {
+        pathf = malloc(pathlen);
+        memcpy(pathf, path, pathlen);
+        pathf[pathlen-1] = 0; // remove trailing '/'
+        path = pathf;
+    }
+    
     // get last node of path
     *resource_name = util_resource_name(path);
     
     VFS *vfs = ctx->vfs;
     PgVFS *pg = vfs->instance;
     
-    const char *sql = pathlen == 1 ? sql_get_root : sql_resolve_path;
+    const char *sql = pathlen == 1 ? sql_get_root : sql_resolve_path;  
     PGresult *result = PQexecParams(
             pg->connection,
             sql,
@@ -167,15 +192,22 @@
             NULL,
             0);    // 0: result in text format
     
+    if(pathf) {
+        free(pathf);
+    }
+    
     if(!result) return 1;
     
     int ret = 1;
-    int nfields = PQnfields(result);
+    //int nfields = PQnfields(result);
     int nrows = PQntuples(result);
-    if(nrows == 1 && nfields == 4) {
+    if(nrows == 1) {
         char *resource_id_str = PQgetvalue(result, 0, 0);
         char *parent_id_str = PQgetvalue(result, 0, 1);
         char *iscol = PQgetvalue(result, 0, 3);
+        char *lastmodified = PQgetvalue(result, 0, 4);
+        char *creationdate = PQgetvalue(result, 0, 5);
+        char *contentlength = PQgetvalue(result, 0, 6);
         if(resource_id_str && parent_id_str) {
             if(util_strtoint(resource_id_str, resource_id)) {
                 ret = 0; // success
@@ -183,9 +215,31 @@
             // optionally get parent_id
             util_strtoint(parent_id_str, parent_id);
         }
-        if(iscol) {
+        
+        if(iscollection && iscol) {
             *iscollection = iscol[0] == 't' ? TRUE : FALSE;
         }
+        
+        if(s) {
+            memset(s, 0, sizeof(struct stat));
+            
+            s->st_ino = *resource_id;
+            if(iscol) {
+                s->st_mode |= 0x4000;
+            }
+            if(lastmodified) {
+                // TODO
+            }
+            if(creationdate) {
+                // TODO
+            }
+            if(contentlength) {
+                int64_t len;
+                if(util_strtoint(contentlength, &len)) {
+                    s->st_size = len;
+                }
+            }
+        }
     } else {
         ctx->vfs_errno = ENOENT;
     }
@@ -204,7 +258,8 @@
     resource_id = -1;
     parent_id = -1;
     WSBool iscollection;
-    if(pg_resolve_path(ctx, path, &parent_id, &resource_id, &resname, &iscollection)) {
+    struct stat s;
+    if(pg_resolve_path(ctx, path, &parent_id, &resource_id, &resname, &iscollection, &s)) {
         return NULL;
     }
     
@@ -221,9 +276,10 @@
     pgfile->iscollection = iscollection;
     pgfile->resource_id = resource_id;
     pgfile->parent_id = parent_id;
+    pgfile->s = s;
     
     file->ctx = ctx;
-    file->io = iscollection ? NULL : &pg_vfs_io_class;
+    file->io = iscollection ? &pg_vfs_io_class : &pg_vfs_io_class;
     file->fd = -1;
     file->data = pgfile;
     
@@ -231,11 +287,16 @@
 }
 
 int pg_vfs_stat(VFSContext *ctx, const char *path, struct stat *buf) {
-    
+    int64_t parent_id, resource_id;
+    const char *resname;
+    WSBool iscollection;
+    return pg_resolve_path(ctx, path, &parent_id, &resource_id, &resname, &iscollection, buf);
 }
 
 int pg_vfs_fstat(VFSContext *ctx, SYS_FILE fd, struct stat *buf) {
-    
+    PgFile *pgfile = fd->data;
+    memcpy(buf, &pgfile->s, sizeof(struct stat));
+    return 0;
 }
 
 VFS_DIR pg_vfs_opendir(VFSContext *ctx, const char *path) {
@@ -334,7 +395,7 @@
             sql_get_children,
             1,                                  // number of parameters
             NULL,
-            &param,  // param: parent resource_id 
+            &param,                             // param: parent resource_id 
             NULL,
             NULL,
             0);                                 // 0: result in text format
--- a/src/server/plugins/postgresql/vfs.h	Mon Jan 31 21:33:46 2022 +0100
+++ b/src/server/plugins/postgresql/vfs.h	Tue Feb 01 17:47:50 2022 +0100
@@ -47,6 +47,8 @@
     int64_t resource_id;
     int64_t parent_id;
     WSBool  iscollection;
+    
+    struct stat s;
 } PgFile;
 
 typedef struct PgDir {
@@ -66,7 +68,14 @@
  * 
  * If the resource is not found, ctx->vfs_errno is set to ENOENT
  */
-int pg_resolve_path(VFSContext *ctx, const char *path, int64_t *parent_id, int64_t *resource_id, const char **resource_name, WSBool *iscollection);
+int pg_resolve_path(
+        VFSContext *ctx,
+        const char *path,
+        int64_t *parent_id,
+        int64_t *resource_id,
+        const char **resource_name,
+        WSBool *iscollection,
+        struct stat *s);
     
 SYS_FILE pg_vfs_open(VFSContext *ctx, const char *path, int oflags);
 int pg_vfs_stat(VFSContext *ctx, const char *path, struct stat *buf);

mercurial