# HG changeset patch # User Olaf Wintermann # Date 1652030967 -7200 # Node ID 784b24381bed045212362e423d8b20ff7604dd26 # Parent 5832e10fc59a8e959dd53024a12cbab1ad462439 extend postgresql vfs to store an etag in the file diff -r 5832e10fc59a -r 784b24381bed doc/development/postgresql_vfs.sql --- 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, diff -r 5832e10fc59a -r 784b24381bed src/server/plugins/postgresql/vfs.c --- 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 -------------------------- */ diff -r 5832e10fc59a -r 784b24381bed src/server/plugins/postgresql/vfs.h --- 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( diff -r 5832e10fc59a -r 784b24381bed src/server/plugins/postgresql/webdav.c --- 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) { diff -r 5832e10fc59a -r 784b24381bed src/server/safs/service.c --- 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; }