add support for O_CREAT flag in postgresql vfs webdav

Fri, 04 Feb 2022 18:12:23 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Fri, 04 Feb 2022 18:12:23 +0100
branch
webdav
changeset 285
96e53bd94958
parent 284
eab579b8c80d
child 286
864e2d701dd4

add support for O_CREAT flag in postgresql vfs

src/server/plugins/postgresql/vfs.c file | annotate | diff | comparison | revisions
src/server/plugins/postgresql/vfs.h file | annotate | diff | comparison | revisions
src/server/util/util.c file | annotate | diff | comparison | revisions
src/server/util/util.h file | annotate | diff | comparison | revisions
--- a/src/server/plugins/postgresql/vfs.c	Thu Feb 03 18:03:27 2022 +0100
+++ b/src/server/plugins/postgresql/vfs.c	Fri Feb 04 18:12:23 2022 +0100
@@ -112,6 +112,14 @@
 // params: $1: resource_id
 static const char *sql_get_resource = "select resource_id, nodename, iscollection, lastmodified, creationdate, contentlength from Resource where resource_id = $1;";
 
+// Create resource
+// params: $1: parent_id
+//         $2: node name
+static const char *sql_create_resource =
+        "insert into Resource (parent_id, nodename, iscollection, lastmodified, creationdate, contentlength, resoid) values\n\
+        ($1, $2, false, now(), now(), 0, lo_creat(-1))\n\
+        returning resource_id, resoid, lastmodified, creationdate;";
+
 VFS* pg_vfs_create(Session *sn, Request *rq, pblock *pb) {
     // resourcepool is required
     char *resource_pool = pblock_findval("resourcepool", pb);
@@ -270,6 +278,100 @@
     }
 }
 
+int pg_create_file(
+        VFSContext *ctx,
+        PgVFS *pg,
+        const char *path,
+        int64_t *new_resource_id,
+        int64_t *res_parent_id,
+        Oid *oid,
+        const char **resource_name,
+        struct stat *s)
+{
+    char *parent_path = util_parent_path(path);
+    if(!parent_path) return 1;
+    
+    const char *nodename = util_resource_name(path);
+    
+    // resolve the parent path
+    // if the parent path can't be resolved, we are done
+    const char *resname;
+    int64_t resource_id, parent_id;
+    resource_id = -1;
+    parent_id = -1;
+    WSBool iscollection;
+    Oid unused_oid = 0;
+    
+    int err = pg_resolve_path(ctx, parent_path, &parent_id, &resource_id, &unused_oid, &resname, &iscollection, NULL);
+    FREE(parent_path);
+    if(err) {
+        return 1;
+    }
+    
+    // parent path exists, check if it is a collection
+    if(!iscollection) {
+        return 1;
+    }
+    
+    // create new Resource
+    char resid_str[32];
+    snprintf(resid_str, 32, "%" PRId64, resource_id); // convert parent resource_id to string
+    
+    const char* params[2] = { resid_str, nodename };
+    PGresult *result = PQexecParams(
+            pg->connection,
+            sql_create_resource,
+            2,     // number of parameters
+            NULL,
+            params, // parameter value
+            NULL,
+            NULL,
+            0);    // 0: result in text format
+    
+    if(!result) return 1;
+    
+    int ret = 1;
+    if(PQntuples(result) == 1) {
+        // sql insert succesful
+        ret = 0;
+        
+        char *id_str = PQgetvalue(result, 0, 0);
+        char *oid_str = PQgetvalue(result, 0, 1);
+        char *lastmodified = PQgetvalue(result, 0, 2);
+        char *creationdate = PQgetvalue(result, 0, 3);
+        
+        if(new_resource_id) {
+            if(!id_str || !util_strtoint(id_str, new_resource_id)) {
+                ret = 1; // shouldn't happen
+                log_ereport(LOG_FAILURE, "Postgresql VFS: sql_create_resource: Could not convert resource_id to int");
+            }
+        }
+        if(res_parent_id) {
+            // resource_id is still the id of the parent from previous pg_resolve_path call
+            *res_parent_id = resource_id;
+        }
+        if(oid) {
+            int64_t i;
+            if(!oid_str || !util_strtoint(oid_str, &i)) {
+                ret = 1; // shouldn't happen
+                log_ereport(LOG_FAILURE, "Postgresql VFS: sql_create_resource: Could not convert oid to int");
+            } else {
+                *oid = i;
+            }
+        }
+        if(resource_name) {
+            *resource_name = nodename;
+        }
+        if(s) {
+            pg_set_stat(s, 0, lastmodified, creationdate, NULL);
+        }
+    }
+    
+    PQclear(result);
+    
+    return ret;
+}
+
 /* -------------------------- VFS functions -------------------------- */
 
 SYS_FILE pg_vfs_open(VFSContext *ctx, const char *path, int oflags) {
@@ -284,7 +386,14 @@
     struct stat s;
     Oid oid = 0;
     if(pg_resolve_path(ctx, path, &parent_id, &resource_id, &oid, &resname, &iscollection, &s)) {
-        return NULL;
+        if((oflags & O_CREAT) == O_CREAT) {
+            if(pg_create_file(ctx, pg, path, &resource_id, &parent_id, &oid, &resname, &s)) {
+                return NULL;
+            }
+            iscollection = 0;
+        } else {
+            return NULL;
+        }
     }
     
     VFSFile *file = pool_malloc(ctx->pool, sizeof(VFSFile));
--- a/src/server/plugins/postgresql/vfs.h	Thu Feb 03 18:03:27 2022 +0100
+++ b/src/server/plugins/postgresql/vfs.h	Fri Feb 04 18:12:23 2022 +0100
@@ -87,6 +87,16 @@
         const char *lastmodified,
         const char *creationdate,
         const char *contentlength);
+
+int pg_create_file(
+        VFSContext *ctx,
+        PgVFS *pg,
+        const char *path,
+        int64_t *new_resource_id,
+        int64_t *res_parent_id,
+        Oid *oid,
+        const char **resource_name,
+        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);
--- a/src/server/util/util.c	Thu Feb 03 18:03:27 2022 +0100
+++ b/src/server/util/util.c	Fri Feb 04 18:12:23 2022 +0100
@@ -432,6 +432,16 @@
     }
 }
 
+NSAPI_PUBLIC char* util_parent_path(const char *path) {
+    char *name = util_resource_name((char*)path);
+    size_t namelen = strlen(name);
+    size_t pathlen = strlen(path);
+    size_t parentlen = pathlen - namelen;
+    char *parent = MALLOC(parentlen + 1);
+    memcpy(parent, path, parentlen);
+    parent[parentlen] = '\0';
+    return parent;
+}
 
 /* ------------------------------ util_itoa ------------------------------- */
 /*
--- a/src/server/util/util.h	Thu Feb 03 18:03:27 2022 +0100
+++ b/src/server/util/util.h	Fri Feb 04 18:12:23 2022 +0100
@@ -202,6 +202,7 @@
 // new
 NSAPI_PUBLIC int util_strtoint(const char *str, int64_t *value);
 NSAPI_PUBLIC const char* util_resource_name(const char *url);
+NSAPI_PUBLIC char* util_parent_path(const char *path);
 
 // TODO
 //NSAPI_PUBLIC PRIntervalTime INTutil_getinterval(const char *v, PRIntervalTime def);

mercurial