extend postgresql vfs to store an etag in the file webdav

Sun, 08 May 2022 19:29:27 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sun, 08 May 2022 19:29:27 +0200
branch
webdav
changeset 346
784b24381bed
parent 345
5832e10fc59a
child 347
b6d71e504294

extend postgresql vfs to store an etag in the file

doc/development/postgresql_vfs.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
src/server/plugins/postgresql/webdav.c file | annotate | diff | comparison | revisions
src/server/safs/service.c file | annotate | diff | comparison | revisions
--- a/doc/development/postgresql_vfs.sql	Sun May 08 18:55:36 2022 +0200
+++ b/doc/development/postgresql_vfs.sql	Sun May 08 19:29:27 2022 +0200
@@ -8,6 +8,8 @@
     lastmodified      timestamp not null default current_date,
     creationdate      timestamp not null default current_date,
     contentlength     bigint    not null default 0,
+	
+	etag              uuid,
 
     resoid            oid,
     
--- a/src/server/plugins/postgresql/vfs.c	Sun May 08 18:55:36 2022 +0200
+++ b/src/server/plugins/postgresql/vfs.c	Sun May 08 19:29:27 2022 +0200
@@ -78,6 +78,7 @@
             lastmodified,\n\
             creationdate,\n\
             contentlength,\n\
+            etag,\n\
             regexp_split_to_array($1, '/') as pathelm,\n\
             1 as pathdepth\n\
         from Resource\n\
@@ -92,26 +93,27 @@
             r.lastmodified,\n\
             r.creationdate,\n\
             r.contentlength,\n\
+            r.etag,\n\
             p.pathelm,\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, resoid, iscollection, lastmodified, creationdate, contentlength from resolvepath\n\
+    select resource_id, parent_id, fullpath, resoid, iscollection, lastmodified, creationdate, contentlength, etag from resolvepath\n\
     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, resoid, true as iscollection, lastmodified, creationdate, contentlength from Resource where parent_id is null;";
+static const char *sql_get_root = "select resource_id, parent_id, $1 as fullpath, resoid, true as iscollection, lastmodified, creationdate, contentlength, etag 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, lastmodified, creationdate, contentlength from Resource where parent_id = $1;";
+static const char *sql_get_children = "select resource_id, nodename, iscollection, lastmodified, creationdate, contentlength, etag 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;";
+static const char *sql_get_resource = "select resource_id, nodename, iscollection, lastmodified, creationdate, contentlength, etag from Resource where resource_id = $1;";
 
 // Create resource
 // params: $1: parent_id
@@ -191,6 +193,7 @@
         const char **resource_name,
         WSBool *iscollection,
         struct stat *s,
+        char *etag,
         int *res_errno)
 {
     // basic path validation
@@ -239,6 +242,7 @@
         char *lastmodified = PQgetvalue(result, 0, 5);
         char *creationdate = PQgetvalue(result, 0, 6);
         char *contentlength = PQgetvalue(result, 0, 7);
+        char *res_etag = PQgetvalue(result, 0, 8);
         if(resource_id_str && parent_id_str) {
             if(util_strtoint(resource_id_str, resource_id)) {
                 ret = 0; // success
@@ -262,6 +266,12 @@
         if(s) {
             pg_set_stat(s, iscol, lastmodified, creationdate, contentlength);
         }
+        
+        if(etag) {
+            size_t etag_len = strlen(res_etag);
+            if(etag_len < PG_ETAG_MAXLEN)
+            memcpy(etag, res_etag, etag_len+1);
+        }
     } else if(res_errno) {
         *res_errno = ENOENT;
     }
@@ -431,7 +441,7 @@
     WSBool iscollection;
     Oid unused_oid = 0;
     
-    int err = pg_resolve_path(pg->connection, parent_path, &parent_id, &resource_id, &unused_oid, &resname, &iscollection, NULL, &ctx->vfs_errno);
+    int err = pg_resolve_path(pg->connection, parent_path, &parent_id, &resource_id, &unused_oid, &resname, &iscollection, NULL, NULL, &ctx->vfs_errno);
     FREE(parent_path);
     if(err) {
         ctx->vfs_errno = ENOENT;
@@ -551,8 +561,9 @@
     parent_id = -1;
     WSBool iscollection;
     struct stat s;
+    char etag[PG_ETAG_MAXLEN];
     Oid oid = 0;
-    if(pg_resolve_path(pg->connection, path, &parent_id, &resource_id, &oid, &resname, &iscollection, &s, &ctx->vfs_errno)) {
+    if(pg_resolve_path(pg->connection, path, &parent_id, &resource_id, &oid, &resname, &iscollection, &s, etag, &ctx->vfs_errno)) {
         if((oflags & O_CREAT) == O_CREAT) {
             if(pg_create_file(ctx, pg, path, &resource_id, &parent_id, &oid, &resname, &s, FALSE)) {
                 return NULL;
@@ -610,6 +621,7 @@
     pgfile->fd = fd;
     pgfile->oflags = oflags;
     pgfile->s = s;
+    memcpy(pgfile->etag, etag, PG_ETAG_MAXLEN);
     
     file->ctx = ctx;
     file->io = iscollection ? &pg_vfs_io_class : &pg_vfs_io_class;
@@ -626,7 +638,7 @@
     int64_t parent_id, resource_id;
     const char *resname;
     WSBool iscollection;
-    return pg_resolve_path(pg->connection, path, &parent_id, &resource_id, NULL, &resname, &iscollection, buf, &ctx->vfs_errno);
+    return pg_resolve_path(pg->connection, path, &parent_id, &resource_id, NULL, &resname, &iscollection, buf, NULL, &ctx->vfs_errno);
 }
 
 int pg_vfs_fstat(VFSContext *ctx, SYS_FILE fd, struct stat *buf) {
@@ -684,7 +696,7 @@
     WSBool iscollection;
     struct stat s;
     Oid oid = 0;
-    if(!pg_resolve_path(pg->connection, path, &parent_id, &resource_id, &oid, &resname, &iscollection, &s, &ctx->vfs_errno)) {
+    if(!pg_resolve_path(pg->connection, path, &parent_id, &resource_id, &oid, &resname, &iscollection, &s, NULL, &ctx->vfs_errno)) {
         ctx->vfs_errno = EEXIST;
         return 1;
     }
@@ -706,7 +718,7 @@
     parent_id = -1;
     WSBool iscollection;
     Oid oid = 0;
-    if(pg_resolve_path(pg->connection, path, &parent_id, &resource_id, &oid, &resname, &iscollection, NULL, &ctx->vfs_errno)) {
+    if(pg_resolve_path(pg->connection, path, &parent_id, &resource_id, &oid, &resname, &iscollection, NULL, NULL, &ctx->vfs_errno)) {
         return 1;
     }
     
@@ -727,7 +739,7 @@
     resource_id = -1;
     parent_id = -1;
     WSBool iscollection;
-    if(pg_resolve_path(pg->connection, path, &parent_id, &resource_id, NULL, &resname, &iscollection, NULL, &ctx->vfs_errno)) {
+    if(pg_resolve_path(pg->connection, path, &parent_id, &resource_id, NULL, &resname, &iscollection, NULL, NULL, &ctx->vfs_errno)) {
         return 1;
     }
     
@@ -807,7 +819,8 @@
 }
 
 const char *pg_vfs_io_getetag(SYS_FILE fd) {
-    return NULL;
+    PgFile *pg = fd->data;
+    return pg->etag;
 }
 
 /* -------------------------- VFS_DIRIO functions -------------------------- */
--- a/src/server/plugins/postgresql/vfs.h	Sun May 08 18:55:36 2022 +0200
+++ b/src/server/plugins/postgresql/vfs.h	Sun May 08 19:29:27 2022 +0200
@@ -39,27 +39,29 @@
 extern "C" {
 #endif
 
+#define PG_ETAG_MAXLEN 48
+    
 typedef struct PgVFS {
     ResourceData *pg_resource;
     PGconn *connection;
 } PgVFS;
 
 typedef struct PgFile {
-    int64_t resource_id;
-    int64_t parent_id;
-    WSBool  iscollection;
-    Oid     oid;
-    int     fd;
-    int     oflags;
-    
-    struct stat s;
+    int64_t      resource_id;
+    int64_t      parent_id;
+    WSBool       iscollection;
+    Oid          oid;
+    int          fd;
+    int          oflags;
+    char         etag[PG_ETAG_MAXLEN];
+    struct stat  s;
 } PgFile;
 
 typedef struct PgDir {
-    VFSFile *file;
-    PGresult *result;
-    int row;
-    int nrows;
+    VFSFile      *file;
+    PGresult     *result;
+    int          row;
+    int          nrows;
 } PgDir;
 
 VFS* pg_vfs_create(Session *sn, Request *rq, pblock *pb);
@@ -83,6 +85,7 @@
         const char **resource_name,
         WSBool *iscollection,
         struct stat *s,
+        char *etag,
         int *res_errno);
 
 void pg_set_stat(
--- a/src/server/plugins/postgresql/webdav.c	Sun May 08 18:55:36 2022 +0200
+++ b/src/server/plugins/postgresql/webdav.c	Sun May 08 19:29:27 2022 +0200
@@ -370,6 +370,7 @@
             &resourcename,
             &iscollection,
             NULL, // stat
+            NULL, // etag
             &res_errno);
     
     if(err) {
@@ -836,6 +837,7 @@
             &resourcename,
             &iscollection,
             NULL, // stat
+            NULL, // etag
             &res_errno);
     
     if(err) {
--- a/src/server/safs/service.c	Sun May 08 18:55:36 2022 +0200
+++ b/src/server/safs/service.c	Sun May 08 19:29:27 2022 +0200
@@ -85,7 +85,8 @@
     }
     
     // sets last-modified, content-length and checks conditions
-    if(http_set_finfo(sn, rq, s) != REQ_PROCEED) {
+    const char *etag = vfs_getetag(fd); // optionally, get etag from file
+    if(http_set_finfo_etag(sn, rq, s, etag) != REQ_PROCEED) {
         vfs_close(fd);
         return NULL;
     }

mercurial