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 |
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; |