77 where parent_id is null\n\ |
79 where parent_id is null\n\ |
78 union\n\ |
80 union\n\ |
79 select\n\ |
81 select\n\ |
80 r.resource_id,\n\ |
82 r.resource_id,\n\ |
81 r.parent_id,\n\ |
83 r.parent_id,\n\ |
82 iscollection,\n\ |
84 r.iscollection,\n\ |
83 p.pathelm,\n\ |
85 p.pathelm,\n\ |
84 p.fullpath || '/' || r.nodename,\n\ |
86 p.fullpath || '/' || r.nodename,\n\ |
85 p.pathdepth + 1\n\ |
87 p.pathdepth + 1\n\ |
86 from Resource r\n\ |
88 from Resource r\n\ |
87 inner join resolvepath p on r.parent_id = p.resource_id\n\ |
89 inner join resolvepath p on r.parent_id = p.resource_id\n\ |
88 where p.pathelm[p.pathdepth+1] = r.nodename\n\ |
90 where p.pathelm[p.pathdepth+1] = r.nodename\n\ |
89 )\ |
91 )\n\ |
90 select resource_id, parent_id, fullpath, iscollection from resolvepath\n\ |
92 select resource_id, parent_id, fullpath, iscollection from resolvepath\n\ |
91 where fullpath = '$1;"; |
93 where fullpath = $1 ;"; |
92 |
94 |
|
95 // Same as sql_resolve_path, but it returns the root collection |
|
96 // 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;"; |
|
98 |
|
99 // Get all children of a specific collection |
|
100 // params: $1: parent resource_id |
|
101 static const char *sql_get_children = "select resource_id, nodename, iscollection from Resource where parent_id = $1;"; |
93 |
102 |
94 |
103 |
95 VFS* pg_vfs_create(Session *sn, Request *rq, pblock *pb) { |
104 VFS* pg_vfs_create(Session *sn, Request *rq, pblock *pb) { |
96 // resourcepool is required |
105 // resourcepool is required |
97 char *resource_pool = pblock_findval("resourcepool", pb); |
106 char *resource_pool = pblock_findval("resourcepool", pb); |
119 PgVFS *vfs_priv = pool_malloc(sn->pool, sizeof(PgVFS)); |
128 PgVFS *vfs_priv = pool_malloc(sn->pool, sizeof(PgVFS)); |
120 if(!vfs_priv) { |
129 if(!vfs_priv) { |
121 pool_free(sn->pool, vfs); |
130 pool_free(sn->pool, vfs); |
122 return NULL; |
131 return NULL; |
123 } |
132 } |
|
133 vfs_priv->connection = resdata->data; |
|
134 vfs_priv->pg_resource = resdata; |
124 |
135 |
125 memcpy(vfs, &pg_vfs_class, sizeof(VFS)); |
136 memcpy(vfs, &pg_vfs_class, sizeof(VFS)); |
126 vfs->flags = 0; |
137 vfs->flags = 0; |
127 vfs->instance = vfs_priv; |
138 vfs->instance = vfs_priv; |
128 |
139 |
142 // get last node of path |
153 // get last node of path |
143 *resource_name = util_resource_name(path); |
154 *resource_name = util_resource_name(path); |
144 |
155 |
145 VFS *vfs = ctx->vfs; |
156 VFS *vfs = ctx->vfs; |
146 PgVFS *pg = vfs->instance; |
157 PgVFS *pg = vfs->instance; |
147 |
158 |
148 |
159 const char *sql = pathlen == 1 ? sql_get_root : sql_resolve_path; |
149 PGresult *result = PQexecParams( |
160 PGresult *result = PQexecParams( |
150 pg->connection, |
161 pg->connection, |
151 sql_resolve_path, |
162 sql, |
152 1, // number of parameters |
163 1, // number of parameters |
153 NULL, |
164 NULL, |
154 &path, // parameter value |
165 &path, // parameter value |
155 NULL, |
166 NULL, |
156 NULL, |
167 NULL, |
157 0); // 1: result in text format |
168 0); // 0: result in text format |
158 |
169 |
159 if(!result) return 1; |
170 if(!result) return 1; |
160 |
171 |
161 int ret = 1; |
172 int ret = 1; |
162 int nfields = PQnfields(result); |
173 int nfields = PQnfields(result); |
163 int nrows = PQntuples(result); |
174 int nrows = PQntuples(result); |
164 if(nrows == 1 && nfields == 4) { |
175 if(nrows == 1 && nfields == 4) { |
165 char *resource_id_str = PQgetvalue(result, 0, 0); |
176 char *resource_id_str = PQgetvalue(result, 0, 0); |
166 char *parent_id_str = PQgetvalue(result, 0, 1); |
177 char *parent_id_str = PQgetvalue(result, 0, 1); |
167 char *iscol = PQgetvalue(result, 0, 2); |
178 char *iscol = PQgetvalue(result, 0, 3); |
168 if(resource_id_str && parent_id_str) { |
179 if(resource_id_str && parent_id_str) { |
169 if(util_strtoint(resource_id_str, resource_id) && util_strtoint(parent_id_str, parent_id)) { |
180 if(util_strtoint(resource_id_str, resource_id)) { |
170 ret = 0; // success |
181 ret = 0; // success |
171 } |
182 } |
|
183 // optionally get parent_id |
|
184 util_strtoint(parent_id_str, parent_id); |
172 } |
185 } |
173 if(iscol) { |
186 if(iscol) { |
174 *iscollection = iscol[0] == 't' ? TRUE : FALSE; |
187 *iscollection = iscol[0] == 't' ? TRUE : FALSE; |
175 } |
188 } |
176 } else { |
189 } else { |
186 /* -------------------------- VFS functions -------------------------- */ |
199 /* -------------------------- VFS functions -------------------------- */ |
187 |
200 |
188 SYS_FILE pg_vfs_open(VFSContext *ctx, const char *path, int oflags) { |
201 SYS_FILE pg_vfs_open(VFSContext *ctx, const char *path, int oflags) { |
189 const char *resname; |
202 const char *resname; |
190 int64_t resource_id, parent_id; |
203 int64_t resource_id, parent_id; |
|
204 resource_id = -1; |
|
205 parent_id = -1; |
191 WSBool iscollection; |
206 WSBool iscollection; |
192 if(pg_resolve_path(ctx, path, &resource_id, &parent_id, &resname, &iscollection)) { |
207 if(pg_resolve_path(ctx, path, &parent_id, &resource_id, &resname, &iscollection)) { |
193 return NULL; |
208 return NULL; |
194 } |
209 } |
195 |
210 |
196 VFSFile *file = pool_malloc(ctx->pool, sizeof(VFSFile)); |
211 VFSFile *file = pool_malloc(ctx->pool, sizeof(VFSFile)); |
197 if(!file) { |
212 if(!file) { |
222 int pg_vfs_fstat(VFSContext *ctx, SYS_FILE fd, struct stat *buf) { |
237 int pg_vfs_fstat(VFSContext *ctx, SYS_FILE fd, struct stat *buf) { |
223 |
238 |
224 } |
239 } |
225 |
240 |
226 VFS_DIR pg_vfs_opendir(VFSContext *ctx, const char *path) { |
241 VFS_DIR pg_vfs_opendir(VFSContext *ctx, const char *path) { |
227 |
242 VFSFile *file = pg_vfs_open(ctx, path, O_RDONLY); |
|
243 if(!file) return NULL; |
|
244 return pg_vfs_fdopendir(ctx, file); |
228 } |
245 } |
229 |
246 |
230 VFS_DIR pg_vfs_fdopendir(VFSContext *ctx, SYS_FILE fd) { |
247 VFS_DIR pg_vfs_fdopendir(VFSContext *ctx, SYS_FILE fd) { |
231 |
248 PgFile *pg = fd->data; |
|
249 if(!pg->iscollection) { |
|
250 ctx->vfs_errno = ENOTDIR; |
|
251 return NULL; |
|
252 } |
|
253 |
|
254 VFSDir *dir = pool_malloc(ctx->pool, sizeof(VFSDir)); |
|
255 if(!dir) { |
|
256 fd->io->close(fd); |
|
257 ctx->vfs_errno = ENOMEM; |
|
258 return NULL; |
|
259 } |
|
260 |
|
261 PgDir *pgdir = pool_malloc(ctx->pool, sizeof(PgDir)); |
|
262 if(!pgdir) { |
|
263 fd->io->close(fd); |
|
264 pool_free(ctx->pool, dir); |
|
265 ctx->vfs_errno = ENOMEM; |
|
266 return NULL; |
|
267 } |
|
268 memset(pgdir, 0, sizeof(PgDir)); |
|
269 pgdir->file = fd; |
|
270 |
|
271 dir->ctx = ctx; |
|
272 dir->io = &pg_vfs_dirio_class; |
|
273 dir->data = pgdir; |
|
274 dir->fd = -1; |
|
275 |
|
276 return dir; |
232 } |
277 } |
233 |
278 |
234 int pg_vfs_mkdir(VFSContext *ctx, const char *path) { |
279 int pg_vfs_mkdir(VFSContext *ctx, const char *path) { |
235 |
280 |
236 } |
281 } |
271 } |
316 } |
272 |
317 |
273 |
318 |
274 /* -------------------------- VFS_DIRIO functions -------------------------- */ |
319 /* -------------------------- VFS_DIRIO functions -------------------------- */ |
275 |
320 |
|
321 static int load_dir(VFSDir *dir, PgDir *pg) { |
|
322 VFS *vfs = dir->ctx->vfs; |
|
323 PgVFS *pgvfs = vfs->instance; |
|
324 PgFile *pgfd = pg->file->data; |
|
325 PgDir *pgdir = dir->data; |
|
326 |
|
327 char resid_param[32]; |
|
328 snprintf(resid_param, 32, "%" PRId64, pgfd->resource_id); |
|
329 |
|
330 const char *param = resid_param; |
|
331 |
|
332 PGresult *result = PQexecParams( |
|
333 pgvfs->connection, |
|
334 sql_get_children, |
|
335 1, // number of parameters |
|
336 NULL, |
|
337 ¶m, // param: parent resource_id |
|
338 NULL, |
|
339 NULL, |
|
340 0); // 0: result in text format |
|
341 if(!result) return 1; |
|
342 |
|
343 pgdir->result = result; |
|
344 pgdir->nrows = PQntuples(result); |
|
345 return 0; |
|
346 } |
|
347 |
276 int pg_vfs_dirio_readdir(VFS_DIR dir, VFS_ENTRY *entry, int getstat) { |
348 int pg_vfs_dirio_readdir(VFS_DIR dir, VFS_ENTRY *entry, int getstat) { |
277 |
349 PgDir *pg = dir->data; |
|
350 if(!pg->result) { |
|
351 if(load_dir(dir, pg)) { |
|
352 return 0; |
|
353 } |
|
354 } |
|
355 |
|
356 if(pg->row >= pg->nrows) { |
|
357 return 0; // EOF |
|
358 } |
|
359 |
|
360 entry->name = PQgetvalue(pg->result, pg->row, 1); |
|
361 |
|
362 // TODO: stat |
|
363 |
|
364 pg->row++; |
|
365 return 1; |
278 } |
366 } |
279 |
367 |
280 void pg_vfs_dirio_close(VFS_DIR dir) { |
368 void pg_vfs_dirio_close(VFS_DIR dir) { |
281 |
369 |
282 } |
370 } |