54 pg_vfs_dirio_readdir, |
56 pg_vfs_dirio_readdir, |
55 pg_vfs_dirio_close |
57 pg_vfs_dirio_close |
56 }; |
58 }; |
57 |
59 |
58 |
60 |
|
61 /* |
|
62 * SQL Queries |
|
63 */ |
|
64 |
|
65 // Resolvs a path into resource_id and parent_id |
|
66 // params: $1: path string |
|
67 static const char *sql_resolve_path = |
|
68 "with recursive resolvepath as (\n\ |
|
69 select\n\ |
|
70 resource_id,\n\ |
|
71 parent_id,\n\ |
|
72 iscollection,\n\ |
|
73 regexp_split_to_array($1, '/') as pathelm,\n\ |
|
74 '' as fullpath,\n\ |
|
75 1 as pathdepth\n\ |
|
76 from Resource\n\ |
|
77 where parent_id is null\n\ |
|
78 union\n\ |
|
79 select\n\ |
|
80 r.resource_id,\n\ |
|
81 r.parent_id,\n\ |
|
82 iscollection,\n\ |
|
83 p.pathelm,\n\ |
|
84 p.fullpath || '/' || r.nodename,\n\ |
|
85 p.pathdepth + 1\n\ |
|
86 from Resource r\n\ |
|
87 inner join resolvepath p on r.parent_id = p.resource_id\n\ |
|
88 where p.pathelm[p.pathdepth+1] = r.nodename\n\ |
|
89 )\ |
|
90 select resource_id, parent_id, fullpath, iscollection from resolvepath\n\ |
|
91 where fullpath = '$1;"; |
|
92 |
|
93 |
59 |
94 |
60 VFS* pg_vfs_create(Session *sn, Request *rq, pblock *pb) { |
95 VFS* pg_vfs_create(Session *sn, Request *rq, pblock *pb) { |
61 // resourcepool is required |
96 // resourcepool is required |
62 char *resource_pool = pblock_find("resourcepool", pb); |
97 char *resource_pool = pblock_findval("resourcepool", pb); |
63 if(!resource_pool) { |
98 if(!resource_pool) { |
64 log_ereport(LOG_MISCONFIG, "pg_vfs_create: missing resourcepool parameter"); |
99 log_ereport(LOG_MISCONFIG, "pg_vfs_create: missing resourcepool parameter"); |
65 return NULL; |
100 return NULL; |
66 } |
101 } |
67 |
102 |
93 |
128 |
94 return vfs; |
129 return vfs; |
95 } |
130 } |
96 |
131 |
97 |
132 |
|
133 int pg_resolve_path(VFSContext *ctx, const char *path, int64_t *parent_id, int64_t *resource_id, const char **resource_name, WSBool *iscollection) { |
|
134 // basic path validation |
|
135 if(!path) return 1; |
|
136 size_t pathlen = strlen(path); |
|
137 if(pathlen == 0) return 1; |
|
138 if(path[0] != '/') { |
|
139 return 1; |
|
140 } |
|
141 |
|
142 // get last node of path |
|
143 *resource_name = util_resource_name(path); |
|
144 |
|
145 VFS *vfs = ctx->vfs; |
|
146 PgVFS *pg = vfs->instance; |
|
147 |
|
148 |
|
149 PGresult *result = PQexecParams( |
|
150 pg->connection, |
|
151 sql_resolve_path, |
|
152 1, // number of parameters |
|
153 NULL, |
|
154 &path, // parameter value |
|
155 NULL, |
|
156 NULL, |
|
157 0); // 1: result in text format |
|
158 |
|
159 if(!result) return 1; |
|
160 |
|
161 int ret = 1; |
|
162 int nfields = PQnfields(result); |
|
163 int nrows = PQntuples(result); |
|
164 if(nrows == 1 && nfields == 4) { |
|
165 char *resource_id_str = PQgetvalue(result, 0, 0); |
|
166 char *parent_id_str = PQgetvalue(result, 0, 1); |
|
167 char *iscol = PQgetvalue(result, 0, 2); |
|
168 if(resource_id_str && parent_id_str) { |
|
169 if(util_strtoint(resource_id_str, resource_id) && util_strtoint(parent_id_str, parent_id)) { |
|
170 ret = 0; // success |
|
171 } |
|
172 } |
|
173 if(iscol) { |
|
174 *iscollection = iscol[0] == 't' ? TRUE : FALSE; |
|
175 } |
|
176 } else { |
|
177 ctx->vfs_errno = ENOENT; |
|
178 } |
|
179 |
|
180 PQclear(result); |
|
181 |
|
182 return ret; |
|
183 } |
|
184 |
|
185 |
98 /* -------------------------- VFS functions -------------------------- */ |
186 /* -------------------------- VFS functions -------------------------- */ |
99 |
187 |
100 SYS_FILE pg_vfs_open(VFSContext *ctx, const char *path, int oflags) { |
188 SYS_FILE pg_vfs_open(VFSContext *ctx, const char *path, int oflags) { |
101 |
189 const char *resname; |
|
190 int64_t resource_id, parent_id; |
|
191 WSBool iscollection; |
|
192 if(pg_resolve_path(ctx, path, &resource_id, &parent_id, &resname, &iscollection)) { |
|
193 return NULL; |
|
194 } |
|
195 |
|
196 VFSFile *file = pool_malloc(ctx->pool, sizeof(VFSFile)); |
|
197 if(!file) { |
|
198 return NULL; |
|
199 } |
|
200 PgFile *pgfile = pool_malloc(ctx->pool, sizeof(PgFile)); |
|
201 if(!pgfile) { |
|
202 pool_free(ctx->pool, file); |
|
203 return NULL; |
|
204 } |
|
205 |
|
206 pgfile->iscollection = iscollection; |
|
207 pgfile->resource_id = resource_id; |
|
208 pgfile->parent_id = parent_id; |
|
209 |
|
210 file->ctx = ctx; |
|
211 file->io = iscollection ? NULL : &pg_vfs_io_class; |
|
212 file->fd = -1; |
|
213 file->data = pgfile; |
|
214 |
|
215 return file; |
102 } |
216 } |
103 |
217 |
104 int pg_vfs_stat(VFSContext *ctx, const char *path, struct stat *buf) { |
218 int pg_vfs_stat(VFSContext *ctx, const char *path, struct stat *buf) { |
105 |
219 |
106 } |
220 } |