# HG changeset patch # User Olaf Wintermann # Date 1643645892 -3600 # Node ID 79029fe26aae791511091567bb4f578bfb051e26 # Parent 38bf7b42b58c4ad7917fdae32d8c428123823fc7 add basic postgresql vfs directory functions diff -r 38bf7b42b58c -r 79029fe26aae src/server/plugins/postgresql/vfs.c --- 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 + #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, + ¶m, // 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) { diff -r 38bf7b42b58c -r 79029fe26aae src/server/plugins/postgresql/vfs.h --- a/src/server/plugins/postgresql/vfs.h Sun Jan 30 15:25:29 2022 +0100 +++ b/src/server/plugins/postgresql/vfs.h Mon Jan 31 17:18:12 2022 +0100 @@ -49,6 +49,13 @@ WSBool iscollection; } PgFile; +typedef struct PgDir { + VFSFile *file; + PGresult *result; + int row; + int nrows; +} PgDir; + VFS* pg_vfs_create(Session *sn, Request *rq, pblock *pb);