87 } |
87 } |
88 |
88 |
89 return ret; |
89 return ret; |
90 } |
90 } |
91 |
91 |
|
92 typedef struct PathSearchElm { |
|
93 char *href; |
|
94 char *path; |
|
95 size_t hreflen; |
|
96 size_t pathlen; |
|
97 } PathSearchElm; |
|
98 |
|
99 /* |
|
100 * concats base + / + elm |
|
101 * if baseinit is true, only elm is copied |
|
102 */ |
|
103 static int path_buf_concat( |
|
104 pool_handle_t *pool, |
|
105 char **buf, |
|
106 size_t * restrict len, |
|
107 WSBool * restrict baseinit, |
|
108 const char *base, |
|
109 size_t baselen, |
|
110 const char *elm, |
|
111 size_t elmlen) |
|
112 { |
|
113 if(base[baselen-1] == '/') { |
|
114 baselen--; |
|
115 } |
|
116 |
|
117 size_t newlen = baselen + elmlen + 1; |
|
118 if(newlen > WEBDAV_PATH_MAX) { |
|
119 log_ereport(LOG_FAILURE, "webdav: maximal path length exceeded"); |
|
120 return 1; |
|
121 } |
|
122 |
|
123 // check if new path + terminator fits in the buffer |
|
124 if(newlen + 1 > *len) { |
|
125 *len = newlen + 128; |
|
126 char *newbuf = pool_realloc(pool, *buf, newlen); |
|
127 if(newbuf) { |
|
128 log_ereport(LOG_FAILURE, "webdav: path memory allocation failed"); |
|
129 return 1; |
|
130 } |
|
131 *baseinit = FALSE; |
|
132 |
|
133 *buf = newbuf; |
|
134 } |
|
135 |
|
136 // if baseinit is true, the parent is already in the buffer |
|
137 // and we don't need to memcpy it again |
|
138 if(!(*baseinit)) { |
|
139 memcpy(*buf, base, baselen); |
|
140 (*buf)[baselen] = '/'; |
|
141 *baseinit = TRUE; |
|
142 } |
|
143 // copy child and terminate string |
|
144 memcpy((*buf) + baselen + 1, elm, elmlen); |
|
145 (*buf)[newlen] = '\0'; |
|
146 |
|
147 return 0; |
|
148 } |
|
149 |
92 int webdav_op_propfind_children( |
150 int webdav_op_propfind_children( |
93 WebdavOperation *op, |
151 WebdavOperation *op, |
94 VFSContext *vfs, |
152 VFSContext *vfs, |
95 char *path) |
153 const char *href, |
|
154 const char *path) |
96 { |
155 { |
97 WebdavPropfindRequest *request = op->requests->data; |
156 WebdavPropfindRequest *request = op->requests->data; |
98 |
157 |
99 UcxAllocator *a = session_get_allocator(request->sn); |
158 UcxAllocator *a = session_get_allocator(request->sn); |
100 pool_handle_t *pool = request->sn->pool; |
159 pool_handle_t *pool = request->sn->pool; |
101 UcxList *stack = ucx_list_prepend_a(a, NULL, path); |
160 |
|
161 PathSearchElm *start_elm = pool_malloc(pool, sizeof(PathSearchElm)); |
|
162 start_elm->href = pool_strdup(pool, href); |
|
163 start_elm->path = pool_strdup(pool, path); |
|
164 start_elm->hreflen = strlen(href); |
|
165 start_elm->pathlen = strlen(path); |
|
166 |
|
167 UcxList *stack = ucx_list_prepend_a(a, NULL, start_elm); |
102 UcxList *stack_end = stack; |
168 UcxList *stack_end = stack; |
103 if(!stack) { |
169 if(!stack) { |
104 return 1; |
170 return 1; |
105 } |
171 } |
106 |
172 |
107 // reusable buffer for full child path |
173 // reusable buffer for full child path and href |
108 char *newpath = NULL; |
174 char *newpath = pool_malloc(pool, 256); |
109 size_t newpathlen = 0; |
175 size_t newpathlen = 256; |
|
176 |
|
177 char *newhref = pool_malloc(pool, 256); |
|
178 size_t newhreflen = 256; |
110 |
179 |
111 int err = 0; |
180 int err = 0; |
112 while(stack && !err) { |
181 while(stack && !err) { |
113 char *cur_path = stack->data; |
182 PathSearchElm *cur_elm = stack->data; |
114 size_t parent_len = strlen(cur_path); |
|
115 if(parent_len > WEBDAV_PATH_MAX) { |
|
116 log_ereport(LOG_FAILURE, "webdav: maximal path length exceeded"); |
|
117 err = 1; |
|
118 break; |
|
119 } |
|
120 if(cur_path[parent_len-1] == '/') { |
|
121 parent_len--; |
|
122 } |
|
123 size_t max_child_len = WEBDAV_PATH_MAX - parent_len; |
|
124 |
183 |
125 // when newpath is initialized with the parent path |
184 // when newpath is initialized with the parent path |
126 // set path_buf_init to TRUE |
185 // set path_buf_init to TRUE |
|
186 WSBool href_buf_init = FALSE; |
127 WSBool path_buf_init = FALSE; |
187 WSBool path_buf_init = FALSE; |
128 |
188 |
129 VFS_DIR dir = vfs_opendir(vfs, path); |
189 VFS_DIR dir = vfs_opendir(vfs, cur_elm->path); |
130 if(!dir) { |
190 if(!dir) { |
131 log_ereport( |
191 log_ereport( |
132 LOG_FAILURE, |
192 LOG_FAILURE, |
133 "webdav: propfind: cannot open directory %d", |
193 "webdav: propfind: cannot open directory %d", |
134 vfs->vfs_errno); |
194 vfs->vfs_errno); |
141 if(f.stat_errno != 0) { |
201 if(f.stat_errno != 0) { |
142 continue; |
202 continue; |
143 } |
203 } |
144 |
204 |
145 size_t child_len = strlen(f.name); |
205 size_t child_len = strlen(f.name); |
146 if(child_len > max_child_len) { |
206 |
147 log_ereport(LOG_FAILURE, "webdav: maximal path length exceeded"); |
207 // create new path and href for the child |
|
208 if(path_buf_concat( |
|
209 pool, |
|
210 &newhref, |
|
211 &newhreflen, |
|
212 &href_buf_init, |
|
213 cur_elm->href, |
|
214 cur_elm->hreflen, |
|
215 f.name, |
|
216 child_len)) |
|
217 { |
148 err = 1; |
218 err = 1; |
149 break; |
219 break; |
150 } |
220 } |
151 size_t childpathlen = parent_len + child_len + 1; // +1 '/' |
221 if(path_buf_concat( |
152 if(childpathlen > newpathlen) { |
222 pool, |
153 // we're gonna need a bigger boa^H^H^Hbuffer |
223 &newpath, |
154 if(newpath) { |
224 &newpathlen, |
155 pool_free(pool, newpath); |
225 &path_buf_init, |
156 } |
226 cur_elm->path, |
157 newpath = pool_malloc(pool, childpathlen + 1); |
227 cur_elm->pathlen, |
158 if(!newpath) { |
228 f.name, |
159 err = 1; |
229 child_len)) |
160 break; |
230 { |
161 } |
231 err = 1; |
162 newpathlen = childpathlen; |
232 break; |
163 path_buf_init = FALSE; |
233 } |
164 } |
234 size_t childhreflen = cur_elm->hreflen + 1 + child_len; |
165 // create full path string for this child |
235 size_t childpathlen = cur_elm->pathlen + 1 + child_len; |
166 if(!path_buf_init) { |
|
167 memcpy(newpath, cur_path, parent_len); |
|
168 newpath[parent_len] = '/'; |
|
169 } |
|
170 memcpy(newpath+parent_len+1, f.name, child_len); |
|
171 newpath[childpathlen] = 0; |
|
172 |
236 |
173 // propfind for this child |
237 // propfind for this child |
174 if(webdav_op_propfind_begin(op, newpath, dir, &f.stat)) { |
238 if(webdav_op_propfind_begin(op, newpath, dir, &f.stat)) { |
175 err = 1; |
239 err = 1; |
176 break; |
240 break; |
177 } |
241 } |
178 |
242 |
179 // depth of -1 means infinity |
243 // depth of -1 means infinity |
180 if(request->depth == -1 && S_ISDIR(f.stat.st_mode)) { |
244 if(request->depth == -1 && S_ISDIR(f.stat.st_mode)) { |
|
245 char *hrefcp = pool_malloc(pool, childhreflen + 1); |
|
246 memcpy(hrefcp, newhref, childhreflen + 1); |
|
247 hrefcp[childhreflen] = '\0'; |
|
248 |
181 char *pathcp = pool_malloc(pool, childpathlen + 1); |
249 char *pathcp = pool_malloc(pool, childpathlen + 1); |
182 memcpy(pathcp, newpath, childpathlen + 1); |
250 memcpy(pathcp, newpath, childpathlen + 1); |
|
251 pathcp[childpathlen] = '\0'; |
183 |
252 |
184 // add the newpath copy to the stack |
253 PathSearchElm *new_elm = pool_malloc(pool, |
|
254 sizeof(PathSearchElm)); |
|
255 new_elm->href = hrefcp; |
|
256 new_elm->path = pathcp; |
|
257 new_elm->hreflen = childhreflen; |
|
258 new_elm->pathlen = childpathlen; |
|
259 |
|
260 // add the new_elm to the stack |
185 // stack_end is always not NULL here, because we remove |
261 // stack_end is always not NULL here, because we remove |
186 // the first stack element at the end of the loop |
262 // the first stack element at the end of the loop |
187 UcxList *newlistelm = ucx_list_append_a(a, stack_end, pathcp); |
263 UcxList *newlistelm = ucx_list_append_a(a, stack_end, new_elm); |
188 if(!newlistelm) { |
264 if(!newlistelm) { |
189 err = 1; |
265 err = 1; |
190 break; |
266 break; |
191 } |
267 } |
192 stack_end = newlistelm; |
268 stack_end = newlistelm; |
193 } |
269 } |
194 } |
270 } |
195 |
271 |
196 vfs_closedir(dir); |
272 vfs_closedir(dir); |
197 |
273 |
198 if(cur_path != path) { |
274 pool_free(pool, cur_elm->path); |
199 pool_free(pool, cur_path); |
275 pool_free(pool, cur_elm->href); |
200 } |
276 pool_free(pool, cur_elm); |
|
277 |
201 stack = ucx_list_remove_a(a, stack, stack); |
278 stack = ucx_list_remove_a(a, stack, stack); |
202 } |
279 } |
203 |
280 |
204 // in case of an error, we have to free all remaining stack elements |
281 // in case of an error, we have to free all remaining stack elements |
205 UCX_FOREACH(elm, stack) { |
282 UCX_FOREACH(elm, stack) { |