168 (*buf)[newlen] = '\0'; |
168 (*buf)[newlen] = '\0'; |
169 |
169 |
170 return 0; |
170 return 0; |
171 } |
171 } |
172 |
172 |
|
173 static int propfind_child_cb( |
|
174 VFSContext *vfs, |
|
175 const char *href, |
|
176 const char *path, |
|
177 VFSDir *parent, |
|
178 struct stat *s, |
|
179 void *op) |
|
180 { |
|
181 return webdav_op_propfind_begin(op, href, parent, s); |
|
182 } |
|
183 |
173 int webdav_op_propfind_children( |
184 int webdav_op_propfind_children( |
174 WebdavOperation *op, |
185 WebdavOperation *op, |
175 VFSContext *vfs, |
186 VFSContext *vfs, |
176 const char *href, |
187 const char *href, |
177 const char *path) |
188 const char *path) |
178 { |
189 { |
179 WebdavPropfindRequest *request = op->requests->data; |
190 WebdavPropfindRequest *request = op->requests->data; |
180 |
191 return webdav_op_iterate_children( |
181 UcxAllocator *a = session_get_allocator(request->sn); |
192 vfs, request->depth, href, path, propfind_child_cb, op); |
182 pool_handle_t *pool = request->sn->pool; |
193 } |
|
194 |
|
195 int webdav_op_propfiond_close_resource( |
|
196 WebdavOperation *op, |
|
197 WebdavResource *resource) |
|
198 { |
|
199 // start with second backend and request, because |
|
200 // the first one was already called by webdav_op_propfind_begin |
|
201 WebdavBackend *dav = op->dav->next; |
|
202 UcxList *request = op->requests->next; |
|
203 |
|
204 // call propfind_do of all remaining backends |
|
205 int ret = REQ_PROCEED; |
|
206 while(dav && request) { |
|
207 if(dav->propfind_do( |
|
208 request->data, |
|
209 op->response, |
|
210 op->parent, |
|
211 resource, |
|
212 op->stat)) |
|
213 { |
|
214 ret = REQ_ABORTED; |
|
215 } |
|
216 |
|
217 dav = dav->next; |
|
218 request = request->next; |
|
219 } |
|
220 return ret; |
|
221 } |
|
222 |
|
223 /* |
|
224 * Executes propfind_finish for each Backend |
|
225 */ |
|
226 int webdav_op_propfind_finish(WebdavOperation *op) { |
|
227 WebdavBackend *dav = op->dav; |
|
228 UcxList *requests = op->requests; |
|
229 |
|
230 int ret = REQ_PROCEED; |
|
231 while(dav && requests) { |
|
232 if(dav->propfind_finish(requests->data)) { |
|
233 ret = REQ_ABORTED; |
|
234 } |
|
235 |
|
236 dav = dav->next; |
|
237 requests = requests->next; |
|
238 } |
|
239 return ret; |
|
240 } |
|
241 |
|
242 /**************************************************************************** |
|
243 * |
|
244 * PROPPATCH OPERATION |
|
245 * |
|
246 ****************************************************************************/ |
|
247 |
|
248 WebdavOperation* webdav_create_proppatch_operation( |
|
249 Session *sn, |
|
250 Request *rq, |
|
251 WebdavBackend *dav, |
|
252 WebdavProppatchRequest *proppatch, |
|
253 WebdavResponse *response) |
|
254 { |
|
255 WebdavOperation *op = pool_malloc(sn->pool, sizeof(WebdavOperation)); |
|
256 ZERO(op, sizeof(WebdavOperation)); |
|
257 op->dav = dav; |
|
258 op->sn = sn; |
|
259 op->rq = rq; |
|
260 op->reqprops = NULL; |
|
261 op->response = response; |
|
262 op->proppatch = proppatch; |
|
263 op->response_close = webdav_op_proppatch_close_resource; |
|
264 response->op = op; |
|
265 |
|
266 return op; |
|
267 } |
|
268 |
|
269 |
|
270 |
|
271 int webdav_op_proppatch( |
|
272 WebdavOperation *op, |
|
273 const char *href, |
|
274 const char *path) |
|
275 { |
|
276 WebdavProppatchRequest *orig_request = op->proppatch; |
|
277 UcxAllocator *a = session_get_allocator(op->sn); |
|
278 |
|
279 // create WebdavResource object for the requested resource |
|
280 WebdavResource *resource = op->response->addresource(op->response, href); |
|
281 if(!resource) { |
|
282 return REQ_ABORTED; |
|
283 } |
|
284 |
|
285 VFSContext *ctx = NULL; |
|
286 VFSFile *file = NULL; |
|
287 |
|
288 // requests for each backends |
|
289 WebdavProppatchRequest **requests = pool_calloc( |
|
290 op->sn->pool, |
|
291 webdav_num_backends(op->dav), |
|
292 sizeof(WebdavProppatchRequest*)); |
|
293 if(requests == NULL) { |
|
294 return REQ_ABORTED; |
|
295 } |
|
296 |
|
297 WebdavPList *prev_set = orig_request->set; |
|
298 WebdavPList *prev_remove = orig_request->remove; |
|
299 size_t set_count = orig_request->setcount; |
|
300 size_t remove_count = orig_request->removecount; |
|
301 |
|
302 int ret = REQ_PROCEED; |
|
303 |
|
304 // iterate backends and execute proppatch_do |
|
305 WebdavBackend *dav = op->dav; |
|
306 size_t numrequests = 0; |
|
307 while(dav) { |
|
308 WebdavPList *set = webdav_plist_clone_s( |
|
309 op->sn->pool, |
|
310 prev_set, |
|
311 &set_count); |
|
312 WebdavPList *remove = webdav_plist_clone_s( |
|
313 op->sn->pool, |
|
314 prev_remove, |
|
315 &remove_count); |
|
316 if((prev_set && !set) || (prev_remove && !remove)) { |
|
317 // clone failed, OOM |
|
318 ret = REQ_ABORTED; |
|
319 break; |
|
320 } |
|
321 |
|
322 // create new WebdavProppatchRequest object for this backend |
|
323 WebdavProppatchRequest *req = pool_malloc( |
|
324 op->sn->pool, |
|
325 sizeof(WebdavProppatchRequest)); |
|
326 memcpy(req, orig_request, sizeof(WebdavProppatchRequest)); |
|
327 req->set = set; |
|
328 req->setcount = set_count; |
|
329 req->remove = remove; |
|
330 req->removecount = remove_count; |
|
331 req->userdata = NULL; |
|
332 |
|
333 // check if we need to open the file because the backend want's it |
|
334 if(!file && (dav->settings & WS_WEBDAV_PROPPATCH_USE_VFS) |
|
335 == WS_WEBDAV_PROPPATCH_USE_VFS) |
|
336 { |
|
337 ctx = vfs_request_context(op->sn, op->rq); |
|
338 if(!ctx) { |
|
339 ret = REQ_ABORTED; |
|
340 break; |
|
341 } |
|
342 |
|
343 file = vfs_open(ctx, path, O_RDONLY); |
|
344 if(!file) { |
|
345 protocol_status( |
|
346 op->sn, |
|
347 op->rq, |
|
348 util_errno2status(ctx->vfs_errno), |
|
349 NULL); |
|
350 ret = REQ_ABORTED; |
|
351 } |
|
352 } |
|
353 |
|
354 // execute proppatch_do |
|
355 if(dav->proppatch_do(req, resource, file, &set, &remove)) { |
|
356 // return later, because we need do execute proppatch_finish |
|
357 // for all successfully called backends |
|
358 ret = REQ_ABORTED; |
|
359 break; |
|
360 } |
|
361 |
|
362 // proppatch_do should remove all handled props from set and remove |
|
363 // in the next iteration, the backend must use these reduced lists |
|
364 prev_set = set; |
|
365 prev_remove = remove; |
|
366 |
|
367 requests[numrequests++] = req; |
|
368 |
|
369 // continue with next backend |
|
370 dav = dav->next; |
|
371 } |
|
372 |
|
373 WSBool commit = FALSE; |
|
374 if(ret == REQ_PROCEED && resource->err == 0) { |
|
375 // no errors, no properties with errors -> save the changes |
|
376 commit = TRUE; |
|
377 } |
|
378 |
|
379 // call proppatch_finish for each successfully called proppatch_do |
|
380 dav = op->dav; |
|
381 int i = 0; |
|
382 while(dav && i < numrequests) { |
|
383 if(dav->proppatch_finish(requests[i], resource, file, commit)) { |
|
384 ret = REQ_ABORTED; |
|
385 } |
|
386 i++; |
|
387 dav = dav->next; |
|
388 } |
|
389 |
|
390 if(file) { |
|
391 vfs_close(file); |
|
392 } |
|
393 |
|
394 if(resource->close(resource)) { |
|
395 ret = REQ_ABORTED; |
|
396 } |
|
397 |
|
398 return ret; |
|
399 } |
|
400 |
|
401 int webdav_op_proppatch_close_resource( |
|
402 WebdavOperation *op, |
|
403 WebdavResource *resource) |
|
404 { |
|
405 return 0; // NOP |
|
406 } |
|
407 |
|
408 |
|
409 /**************************************************************************** |
|
410 * |
|
411 * VFS OPERATION |
|
412 * |
|
413 ****************************************************************************/ |
|
414 |
|
415 WebdavVFSOperation* webdav_vfs_op( |
|
416 Session *sn, |
|
417 Request *rq, |
|
418 WebdavBackend *dav, |
|
419 WSBool precondition) |
|
420 { |
|
421 WebdavVFSOperation *op = pool_malloc(sn->pool, sizeof(WebdavVFSOperation)); |
|
422 if(!op) { |
|
423 return NULL; |
|
424 } |
|
425 ZERO(op, sizeof(WebdavVFSOperation)); |
|
426 |
|
427 op->sn = sn; |
|
428 op->rq = rq; |
|
429 op->dav = dav; |
|
430 op->stat = NULL; |
|
431 op->stat_errno = 0; |
|
432 |
|
433 // create VFS context |
|
434 VFSContext *vfs = vfs_request_context(sn, rq); |
|
435 if(!vfs) { |
|
436 pool_free(sn->pool, op); |
|
437 return NULL; |
|
438 } |
|
439 op->vfs = vfs; |
|
440 |
|
441 char *path = pblock_findkeyval(pb_key_path, rq->vars); |
|
442 op->path = path; |
|
443 |
|
444 return op; |
|
445 } |
|
446 |
|
447 int webdav_op_iterate_children( |
|
448 VFSContext *vfs, |
|
449 int depth, |
|
450 const char *href, |
|
451 const char *path, |
|
452 vfs_op_child_func func, |
|
453 void *userdata) |
|
454 { |
|
455 UcxAllocator *a = session_get_allocator(vfs->sn); |
|
456 pool_handle_t *pool = vfs->sn->pool; |
183 |
457 |
184 PathSearchElm *start_elm = pool_malloc(pool, sizeof(PathSearchElm)); |
458 PathSearchElm *start_elm = pool_malloc(pool, sizeof(PathSearchElm)); |
185 start_elm->href = pool_strdup(pool, href); |
459 start_elm->href = pool_strdup(pool, href); |
186 start_elm->path = pool_strdup(pool, path); |
460 start_elm->path = pool_strdup(pool, path); |
187 start_elm->hreflen = strlen(href); |
461 start_elm->hreflen = strlen(href); |
255 break; |
529 break; |
256 } |
530 } |
257 size_t childhreflen = cur_elm->hreflen + 1 + child_len; |
531 size_t childhreflen = cur_elm->hreflen + 1 + child_len; |
258 size_t childpathlen = cur_elm->pathlen + 1 + child_len; |
532 size_t childpathlen = cur_elm->pathlen + 1 + child_len; |
259 |
533 |
260 // propfind for this child |
534 // execute callback func for this file |
261 if(webdav_op_propfind_begin(op, newhref, dir, &f.stat)) { |
535 if(func(vfs, newhref, newpath, dir, &f.stat, userdata)) { |
262 err = 1; |
536 err = 1; |
263 break; |
537 break; |
264 } |
538 } |
265 |
539 |
266 // depth of -1 means infinity |
540 // depth of -1 means infinity |
267 if(request->depth == -1 && S_ISDIR(f.stat.st_mode)) { |
541 if(depth == -1 && S_ISDIR(f.stat.st_mode)) { |
268 char *hrefcp = pool_malloc(pool, childhreflen + 1); |
542 char *hrefcp = pool_malloc(pool, childhreflen + 1); |
269 memcpy(hrefcp, newhref, childhreflen + 1); |
543 memcpy(hrefcp, newhref, childhreflen + 1); |
270 hrefcp[childhreflen] = '\0'; |
544 hrefcp[childhreflen] = '\0'; |
271 |
545 |
272 char *pathcp = pool_malloc(pool, childpathlen + 1); |
546 char *pathcp = pool_malloc(pool, childpathlen + 1); |
310 } |
584 } |
311 |
585 |
312 return err; |
586 return err; |
313 } |
587 } |
314 |
588 |
315 int webdav_op_propfiond_close_resource( |
|
316 WebdavOperation *op, |
|
317 WebdavResource *resource) |
|
318 { |
|
319 // start with second backend and request, because |
|
320 // the first one was already called by webdav_op_propfind_begin |
|
321 WebdavBackend *dav = op->dav->next; |
|
322 UcxList *request = op->requests->next; |
|
323 |
|
324 // call propfind_do of all remaining backends |
|
325 int ret = REQ_PROCEED; |
|
326 while(dav && request) { |
|
327 if(dav->propfind_do( |
|
328 request->data, |
|
329 op->response, |
|
330 op->parent, |
|
331 resource, |
|
332 op->stat)) |
|
333 { |
|
334 ret = REQ_ABORTED; |
|
335 } |
|
336 |
|
337 dav = dav->next; |
|
338 request = request->next; |
|
339 } |
|
340 return ret; |
|
341 } |
|
342 |
|
343 /* |
|
344 * Executes propfind_finish for each Backend |
|
345 */ |
|
346 int webdav_op_propfind_finish(WebdavOperation *op) { |
|
347 WebdavBackend *dav = op->dav; |
|
348 UcxList *requests = op->requests; |
|
349 |
|
350 int ret = REQ_PROCEED; |
|
351 while(dav && requests) { |
|
352 if(dav->propfind_finish(requests->data)) { |
|
353 ret = REQ_ABORTED; |
|
354 } |
|
355 |
|
356 dav = dav->next; |
|
357 requests = requests->next; |
|
358 } |
|
359 return ret; |
|
360 } |
|
361 |
|
362 /**************************************************************************** |
|
363 * |
|
364 * PROPPATCH OPERATION |
|
365 * |
|
366 ****************************************************************************/ |
|
367 |
|
368 WebdavOperation* webdav_create_proppatch_operation( |
|
369 Session *sn, |
|
370 Request *rq, |
|
371 WebdavBackend *dav, |
|
372 WebdavProppatchRequest *proppatch, |
|
373 WebdavResponse *response) |
|
374 { |
|
375 WebdavOperation *op = pool_malloc(sn->pool, sizeof(WebdavOperation)); |
|
376 ZERO(op, sizeof(WebdavOperation)); |
|
377 op->dav = dav; |
|
378 op->sn = sn; |
|
379 op->rq = rq; |
|
380 op->reqprops = NULL; |
|
381 op->response = response; |
|
382 op->proppatch = proppatch; |
|
383 op->response_close = webdav_op_proppatch_close_resource; |
|
384 response->op = op; |
|
385 |
|
386 return op; |
|
387 } |
|
388 |
|
389 |
|
390 |
|
391 int webdav_op_proppatch( |
|
392 WebdavOperation *op, |
|
393 const char *href, |
|
394 const char *path) |
|
395 { |
|
396 WebdavProppatchRequest *orig_request = op->proppatch; |
|
397 UcxAllocator *a = session_get_allocator(op->sn); |
|
398 |
|
399 // create WebdavResource object for the requested resource |
|
400 WebdavResource *resource = op->response->addresource(op->response, href); |
|
401 if(!resource) { |
|
402 return REQ_ABORTED; |
|
403 } |
|
404 |
|
405 VFSContext *ctx = NULL; |
|
406 VFSFile *file = NULL; |
|
407 |
|
408 // requests for each backends |
|
409 WebdavProppatchRequest **requests = pool_calloc( |
|
410 op->sn->pool, |
|
411 webdav_num_backends(op->dav), |
|
412 sizeof(WebdavProppatchRequest*)); |
|
413 if(requests == NULL) { |
|
414 return REQ_ABORTED; |
|
415 } |
|
416 |
|
417 WebdavPList *prev_set = orig_request->set; |
|
418 WebdavPList *prev_remove = orig_request->remove; |
|
419 size_t set_count = orig_request->setcount; |
|
420 size_t remove_count = orig_request->removecount; |
|
421 |
|
422 int ret = REQ_PROCEED; |
|
423 |
|
424 // iterate backends and execute proppatch_do |
|
425 WebdavBackend *dav = op->dav; |
|
426 size_t numrequests = 0; |
|
427 while(dav) { |
|
428 WebdavPList *set = webdav_plist_clone_s( |
|
429 op->sn->pool, |
|
430 prev_set, |
|
431 &set_count); |
|
432 WebdavPList *remove = webdav_plist_clone_s( |
|
433 op->sn->pool, |
|
434 prev_remove, |
|
435 &remove_count); |
|
436 if((prev_set && !set) || (prev_remove && !remove)) { |
|
437 // clone failed, OOM |
|
438 ret = REQ_ABORTED; |
|
439 break; |
|
440 } |
|
441 |
|
442 // create new WebdavProppatchRequest object for this backend |
|
443 WebdavProppatchRequest *req = pool_malloc( |
|
444 op->sn->pool, |
|
445 sizeof(WebdavProppatchRequest)); |
|
446 memcpy(req, orig_request, sizeof(WebdavProppatchRequest)); |
|
447 req->set = set; |
|
448 req->setcount = set_count; |
|
449 req->remove = remove; |
|
450 req->removecount = remove_count; |
|
451 req->userdata = NULL; |
|
452 |
|
453 // check if we need to open the file because the backend want's it |
|
454 if(!file && (dav->settings & WS_WEBDAV_PROPPATCH_USE_VFS) |
|
455 == WS_WEBDAV_PROPPATCH_USE_VFS) |
|
456 { |
|
457 ctx = vfs_request_context(op->sn, op->rq); |
|
458 if(!ctx) { |
|
459 ret = REQ_ABORTED; |
|
460 break; |
|
461 } |
|
462 |
|
463 file = vfs_open(ctx, path, O_RDONLY); |
|
464 if(!file) { |
|
465 protocol_status( |
|
466 op->sn, |
|
467 op->rq, |
|
468 util_errno2status(ctx->vfs_errno), |
|
469 NULL); |
|
470 ret = REQ_ABORTED; |
|
471 } |
|
472 } |
|
473 |
|
474 // execute proppatch_do |
|
475 if(dav->proppatch_do(req, resource, file, &set, &remove)) { |
|
476 // return later, because we need do execute proppatch_finish |
|
477 // for all successfully called backends |
|
478 ret = REQ_ABORTED; |
|
479 break; |
|
480 } |
|
481 |
|
482 // proppatch_do should remove all handled props from set and remove |
|
483 // in the next iteration, the backend must use these reduced lists |
|
484 prev_set = set; |
|
485 prev_remove = remove; |
|
486 |
|
487 requests[numrequests++] = req; |
|
488 |
|
489 // continue with next backend |
|
490 dav = dav->next; |
|
491 } |
|
492 |
|
493 WSBool commit = FALSE; |
|
494 if(ret == REQ_PROCEED && resource->err == 0) { |
|
495 // no errors, no properties with errors -> save the changes |
|
496 commit = TRUE; |
|
497 } |
|
498 |
|
499 // call proppatch_finish for each successfully called proppatch_do |
|
500 dav = op->dav; |
|
501 int i = 0; |
|
502 while(dav && i < numrequests) { |
|
503 if(dav->proppatch_finish(requests[i], resource, file, commit)) { |
|
504 ret = REQ_ABORTED; |
|
505 } |
|
506 i++; |
|
507 dav = dav->next; |
|
508 } |
|
509 |
|
510 if(file) { |
|
511 vfs_close(file); |
|
512 } |
|
513 |
|
514 if(resource->close(resource)) { |
|
515 ret = REQ_ABORTED; |
|
516 } |
|
517 |
|
518 return ret; |
|
519 } |
|
520 |
|
521 int webdav_op_proppatch_close_resource( |
|
522 WebdavOperation *op, |
|
523 WebdavResource *resource) |
|
524 { |
|
525 return 0; // NOP |
|
526 } |
|
527 |
|
528 |
|
529 /**************************************************************************** |
|
530 * |
|
531 * VFS OPERATION |
|
532 * |
|
533 ****************************************************************************/ |
|
534 |
|
535 WebdavVFSOperation* webdav_vfs_op( |
|
536 Session *sn, |
|
537 Request *rq, |
|
538 WebdavBackend *dav, |
|
539 WSBool precondition) |
|
540 { |
|
541 WebdavVFSOperation *op = pool_malloc(sn->pool, sizeof(WebdavVFSOperation)); |
|
542 if(!op) { |
|
543 return NULL; |
|
544 } |
|
545 ZERO(op, sizeof(WebdavVFSOperation)); |
|
546 |
|
547 op->sn = sn; |
|
548 op->rq = rq; |
|
549 op->dav = dav; |
|
550 op->stat = NULL; |
|
551 op->stat_errno = 0; |
|
552 |
|
553 // create VFS context |
|
554 VFSContext *vfs = vfs_request_context(sn, rq); |
|
555 if(!vfs) { |
|
556 pool_free(sn->pool, op); |
|
557 return NULL; |
|
558 } |
|
559 op->vfs = vfs; |
|
560 |
|
561 char *path = pblock_findkeyval(pb_key_path, rq->vars); |
|
562 op->path = path; |
|
563 |
|
564 return op; |
|
565 } |
|
566 |
589 |
567 int webdav_vfs_stat(WebdavVFSOperation *op) { |
590 int webdav_vfs_stat(WebdavVFSOperation *op) { |
568 if(op->stat) { |
591 if(op->stat) { |
569 return 0; |
592 return 0; |
570 } else if(op->stat_errno != 0) { |
593 } else if(op->stat_errno != 0) { |