src/server/plugins/postgresql/vfs.c

branch
webdav
changeset 281
e9dc53661df4
parent 280
d0d5a970292f
child 282
cfb588e27198
equal deleted inserted replaced
280:d0d5a970292f 281:e9dc53661df4
69 static const char *sql_resolve_path = 69 static const char *sql_resolve_path =
70 "with recursive resolvepath as (\n\ 70 "with recursive resolvepath as (\n\
71 select\n\ 71 select\n\
72 resource_id,\n\ 72 resource_id,\n\
73 parent_id,\n\ 73 parent_id,\n\
74 '' as fullpath,\n\
74 iscollection,\n\ 75 iscollection,\n\
76 lastmodified,\n\
77 creationdate,\n\
78 contentlength,\n\
75 regexp_split_to_array($1, '/') as pathelm,\n\ 79 regexp_split_to_array($1, '/') as pathelm,\n\
76 '' as fullpath,\n\
77 1 as pathdepth\n\ 80 1 as pathdepth\n\
78 from Resource\n\ 81 from Resource\n\
79 where parent_id is null\n\ 82 where parent_id is null\n\
80 union\n\ 83 union\n\
81 select\n\ 84 select\n\
82 r.resource_id,\n\ 85 r.resource_id,\n\
83 r.parent_id,\n\ 86 r.parent_id,\n\
87 p.fullpath || '/' || r.nodename,\n\
84 r.iscollection,\n\ 88 r.iscollection,\n\
89 r.lastmodified,\n\
90 r.creationdate,\n\
91 r.contentlength,\n\
85 p.pathelm,\n\ 92 p.pathelm,\n\
86 p.fullpath || '/' || r.nodename,\n\
87 p.pathdepth + 1\n\ 93 p.pathdepth + 1\n\
88 from Resource r\n\ 94 from Resource r\n\
89 inner join resolvepath p on r.parent_id = p.resource_id\n\ 95 inner join resolvepath p on r.parent_id = p.resource_id\n\
90 where p.pathelm[p.pathdepth+1] = r.nodename\n\ 96 where p.pathelm[p.pathdepth+1] = r.nodename\n\
91 )\n\ 97 )\n\
92 select resource_id, parent_id, fullpath, iscollection from resolvepath\n\ 98 select resource_id, parent_id, fullpath, iscollection from resolvepath\n\
93 where fullpath = $1 ;"; 99 where fullpath = $1 ;";
94 100
95 // Same as sql_resolve_path, but it returns the root collection 101 // Same as sql_resolve_path, but it returns the root collection
96 // params: $1: path string (should be '/') 102 // params: $1: path string (should be '/')
97 static const char *sql_get_root = "select resource_id, parent_id, $1 as fullpath, true as iscollection from Resource where parent_id is null;"; 103 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;";
98 104
99 // Get all children of a specific collection 105 // Get all children of a specific collection
100 // params: $1: parent resource_id 106 // params: $1: parent resource_id
101 static const char *sql_get_children = "select resource_id, nodename, iscollection from Resource where parent_id = $1;"; 107 static const char *sql_get_children = "select resource_id, nodename, iscollection, lastmodified, creationdate, contentlength from Resource where parent_id = $1;";
102 108
109 // Get resource
110 // params: $1: resource_id
111 static const char *sql_get_resource = "select resource_id, nodename, iscollection, lastmodified, creationdate, contentlength from Resource where resource_id = $1;";
103 112
104 VFS* pg_vfs_create(Session *sn, Request *rq, pblock *pb) { 113 VFS* pg_vfs_create(Session *sn, Request *rq, pblock *pb) {
105 // resourcepool is required 114 // resourcepool is required
106 char *resource_pool = pblock_findval("resourcepool", pb); 115 char *resource_pool = pblock_findval("resourcepool", pb);
107 if(!resource_pool) { 116 if(!resource_pool) {
139 148
140 return vfs; 149 return vfs;
141 } 150 }
142 151
143 152
144 int pg_resolve_path(VFSContext *ctx, const char *path, int64_t *parent_id, int64_t *resource_id, const char **resource_name, WSBool *iscollection) { 153 int pg_resolve_path(
154 VFSContext *ctx,
155 const char *path,
156 int64_t *parent_id,
157 int64_t *resource_id,
158 const char **resource_name,
159 WSBool *iscollection,
160 struct stat *s)
161 {
145 // basic path validation 162 // basic path validation
146 if(!path) return 1; 163 if(!path) return 1;
147 size_t pathlen = strlen(path); 164 size_t pathlen = strlen(path);
148 if(pathlen == 0) return 1; 165 if(pathlen == 0) return 1;
149 if(path[0] != '/') { 166 if(path[0] != '/') {
150 return 1; 167 return 1;
151 } 168 }
152 169
170 char *pathf = NULL;
171 if(pathlen > 1 && path[pathlen-1] == '/') {
172 pathf = malloc(pathlen);
173 memcpy(pathf, path, pathlen);
174 pathf[pathlen-1] = 0; // remove trailing '/'
175 path = pathf;
176 }
177
153 // get last node of path 178 // get last node of path
154 *resource_name = util_resource_name(path); 179 *resource_name = util_resource_name(path);
155 180
156 VFS *vfs = ctx->vfs; 181 VFS *vfs = ctx->vfs;
157 PgVFS *pg = vfs->instance; 182 PgVFS *pg = vfs->instance;
158 183
159 const char *sql = pathlen == 1 ? sql_get_root : sql_resolve_path; 184 const char *sql = pathlen == 1 ? sql_get_root : sql_resolve_path;
160 PGresult *result = PQexecParams( 185 PGresult *result = PQexecParams(
161 pg->connection, 186 pg->connection,
162 sql, 187 sql,
163 1, // number of parameters 188 1, // number of parameters
164 NULL, 189 NULL,
165 &path, // parameter value 190 &path, // parameter value
166 NULL, 191 NULL,
167 NULL, 192 NULL,
168 0); // 0: result in text format 193 0); // 0: result in text format
169 194
195 if(pathf) {
196 free(pathf);
197 }
198
170 if(!result) return 1; 199 if(!result) return 1;
171 200
172 int ret = 1; 201 int ret = 1;
173 int nfields = PQnfields(result); 202 //int nfields = PQnfields(result);
174 int nrows = PQntuples(result); 203 int nrows = PQntuples(result);
175 if(nrows == 1 && nfields == 4) { 204 if(nrows == 1) {
176 char *resource_id_str = PQgetvalue(result, 0, 0); 205 char *resource_id_str = PQgetvalue(result, 0, 0);
177 char *parent_id_str = PQgetvalue(result, 0, 1); 206 char *parent_id_str = PQgetvalue(result, 0, 1);
178 char *iscol = PQgetvalue(result, 0, 3); 207 char *iscol = PQgetvalue(result, 0, 3);
208 char *lastmodified = PQgetvalue(result, 0, 4);
209 char *creationdate = PQgetvalue(result, 0, 5);
210 char *contentlength = PQgetvalue(result, 0, 6);
179 if(resource_id_str && parent_id_str) { 211 if(resource_id_str && parent_id_str) {
180 if(util_strtoint(resource_id_str, resource_id)) { 212 if(util_strtoint(resource_id_str, resource_id)) {
181 ret = 0; // success 213 ret = 0; // success
182 } 214 }
183 // optionally get parent_id 215 // optionally get parent_id
184 util_strtoint(parent_id_str, parent_id); 216 util_strtoint(parent_id_str, parent_id);
185 } 217 }
186 if(iscol) { 218
219 if(iscollection && iscol) {
187 *iscollection = iscol[0] == 't' ? TRUE : FALSE; 220 *iscollection = iscol[0] == 't' ? TRUE : FALSE;
221 }
222
223 if(s) {
224 memset(s, 0, sizeof(struct stat));
225
226 s->st_ino = *resource_id;
227 if(iscol) {
228 s->st_mode |= 0x4000;
229 }
230 if(lastmodified) {
231 // TODO
232 }
233 if(creationdate) {
234 // TODO
235 }
236 if(contentlength) {
237 int64_t len;
238 if(util_strtoint(contentlength, &len)) {
239 s->st_size = len;
240 }
241 }
188 } 242 }
189 } else { 243 } else {
190 ctx->vfs_errno = ENOENT; 244 ctx->vfs_errno = ENOENT;
191 } 245 }
192 246
202 const char *resname; 256 const char *resname;
203 int64_t resource_id, parent_id; 257 int64_t resource_id, parent_id;
204 resource_id = -1; 258 resource_id = -1;
205 parent_id = -1; 259 parent_id = -1;
206 WSBool iscollection; 260 WSBool iscollection;
207 if(pg_resolve_path(ctx, path, &parent_id, &resource_id, &resname, &iscollection)) { 261 struct stat s;
262 if(pg_resolve_path(ctx, path, &parent_id, &resource_id, &resname, &iscollection, &s)) {
208 return NULL; 263 return NULL;
209 } 264 }
210 265
211 VFSFile *file = pool_malloc(ctx->pool, sizeof(VFSFile)); 266 VFSFile *file = pool_malloc(ctx->pool, sizeof(VFSFile));
212 if(!file) { 267 if(!file) {
219 } 274 }
220 275
221 pgfile->iscollection = iscollection; 276 pgfile->iscollection = iscollection;
222 pgfile->resource_id = resource_id; 277 pgfile->resource_id = resource_id;
223 pgfile->parent_id = parent_id; 278 pgfile->parent_id = parent_id;
279 pgfile->s = s;
224 280
225 file->ctx = ctx; 281 file->ctx = ctx;
226 file->io = iscollection ? NULL : &pg_vfs_io_class; 282 file->io = iscollection ? &pg_vfs_io_class : &pg_vfs_io_class;
227 file->fd = -1; 283 file->fd = -1;
228 file->data = pgfile; 284 file->data = pgfile;
229 285
230 return file; 286 return file;
231 } 287 }
232 288
233 int pg_vfs_stat(VFSContext *ctx, const char *path, struct stat *buf) { 289 int pg_vfs_stat(VFSContext *ctx, const char *path, struct stat *buf) {
234 290 int64_t parent_id, resource_id;
291 const char *resname;
292 WSBool iscollection;
293 return pg_resolve_path(ctx, path, &parent_id, &resource_id, &resname, &iscollection, buf);
235 } 294 }
236 295
237 int pg_vfs_fstat(VFSContext *ctx, SYS_FILE fd, struct stat *buf) { 296 int pg_vfs_fstat(VFSContext *ctx, SYS_FILE fd, struct stat *buf) {
238 297 PgFile *pgfile = fd->data;
298 memcpy(buf, &pgfile->s, sizeof(struct stat));
299 return 0;
239 } 300 }
240 301
241 VFS_DIR pg_vfs_opendir(VFSContext *ctx, const char *path) { 302 VFS_DIR pg_vfs_opendir(VFSContext *ctx, const char *path) {
242 VFSFile *file = pg_vfs_open(ctx, path, O_RDONLY); 303 VFSFile *file = pg_vfs_open(ctx, path, O_RDONLY);
243 if(!file) return NULL; 304 if(!file) return NULL;
332 PGresult *result = PQexecParams( 393 PGresult *result = PQexecParams(
333 pgvfs->connection, 394 pgvfs->connection,
334 sql_get_children, 395 sql_get_children,
335 1, // number of parameters 396 1, // number of parameters
336 NULL, 397 NULL,
337 &param, // param: parent resource_id 398 &param, // param: parent resource_id
338 NULL, 399 NULL,
339 NULL, 400 NULL,
340 0); // 0: result in text format 401 0); // 0: result in text format
341 if(!result) return 1; 402 if(!result) return 1;
342 403

mercurial