1 /*
2 * Copyright (C) 2020-2021 Bareos GmbH & Co. KG
3 * Copyright (C) 2010 SCALITY SA. All rights reserved.
4 * http://www.scality.com
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 *
13 * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY SCALITY SA ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL SCALITY SA OR CONTRIBUTORS BE LIABLE FOR
21 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 *
29 * The views and conclusions contained in the software and documentation
30 * are those of the authors and should not be interpreted as representing
31 * official policies, either expressed or implied, of SCALITY SA.
32 *
33 * https://github.com/scality/Droplet
34 */
35 #include "dropletp.h"
36 #include "droplet/async.h"
37
38 /** @file */
39
40 /**
41 * @defgroup async Asynchronous management
42 * @addtogroup async
43 * @{
44 * Asynchronous REST operations
45 */
46
47 //#define DPRINTF(fmt,...) fprintf(stderr, fmt, ##__VA_ARGS__)
48 #define DPRINTF(fmt, ...)
49
50 #define DUP_IF_NOT_NULL(Struct, Member) \
51 if (NULL != Member) { \
52 Struct.Member = strdup(Member); \
53 if (Struct.Member == NULL) goto bad; \
54 }
55
56 #define FREE_IF_NOT_NULL(StructMember) \
57 if (NULL != StructMember) free(StructMember);
58
dpl_buf_new()59 dpl_buf_t* dpl_buf_new()
60 {
61 dpl_buf_t* buf = NULL;
62
63 buf = malloc(sizeof(dpl_buf_t));
64 if (NULL == buf) return NULL;
65
66 buf->ptr = NULL;
67 buf->size = 0;
68 buf->refcnt = 0;
69
70 return buf;
71 }
72
dpl_buf_acquire(dpl_buf_t * buf)73 void dpl_buf_acquire(dpl_buf_t* buf) { buf->refcnt++; }
74
dpl_buf_release(dpl_buf_t * buf)75 void dpl_buf_release(dpl_buf_t* buf)
76 {
77 buf->refcnt--;
78 if (0 == buf->refcnt) {
79 free(buf->ptr);
80 free(buf);
81 }
82 }
83
dpl_async_task_free(dpl_async_task_t * task)84 void dpl_async_task_free(dpl_async_task_t* task)
85 {
86 switch (task->type) {
87 case DPL_TASK_LIST_ALL_MY_BUCKETS:
88 /* input */
89 /* output */
90 if (NULL != task->u.list_all_my_buckets.buckets)
91 dpl_vec_buckets_free(task->u.list_all_my_buckets.buckets);
92 break;
93 case DPL_TASK_LIST_BUCKET:
94 /* input */
95 FREE_IF_NOT_NULL(task->u.list_bucket.bucket);
96 FREE_IF_NOT_NULL(task->u.list_bucket.prefix);
97 FREE_IF_NOT_NULL(task->u.list_bucket.delimiter);
98 /* output */
99 if (NULL != task->u.list_bucket.objects)
100 dpl_vec_objects_free(task->u.list_bucket.objects);
101 if (NULL != task->u.list_bucket.common_prefixes)
102 dpl_vec_common_prefixes_free(task->u.list_bucket.common_prefixes);
103 break;
104 case DPL_TASK_MAKE_BUCKET:
105 /* input */
106 FREE_IF_NOT_NULL(task->u.make_bucket.bucket);
107 /* output */
108 break;
109 case DPL_TASK_DELETE_BUCKET:
110 /* input */
111 FREE_IF_NOT_NULL(task->u.delete_bucket.bucket);
112 /* output */
113 break;
114 case DPL_TASK_POST:
115 case DPL_TASK_POST_ID:
116 /* input */
117 FREE_IF_NOT_NULL(task->u.post.bucket);
118 FREE_IF_NOT_NULL(task->u.post.resource);
119 if (NULL != task->u.post.option) dpl_option_free(task->u.post.option);
120 if (NULL != task->u.post.condition)
121 dpl_condition_free(task->u.post.condition);
122 if (NULL != task->u.put.range) dpl_range_free(task->u.put.range);
123 if (NULL != task->u.post.metadata) dpl_dict_free(task->u.post.metadata);
124 if (NULL != task->u.post.sysmd) dpl_sysmd_free(task->u.post.sysmd);
125 if (NULL != task->u.post.buf) dpl_buf_release(task->u.post.buf);
126 if (NULL != task->u.post.query_params)
127 dpl_dict_free(task->u.post.query_params);
128 /* output */
129 break;
130 case DPL_TASK_PUT:
131 case DPL_TASK_PUT_ID:
132 /* input */
133 FREE_IF_NOT_NULL(task->u.put.bucket);
134 FREE_IF_NOT_NULL(task->u.put.resource);
135 if (NULL != task->u.put.option) dpl_option_free(task->u.put.option);
136 if (NULL != task->u.put.condition)
137 dpl_condition_free(task->u.put.condition);
138 if (NULL != task->u.put.range) dpl_range_free(task->u.put.range);
139 if (NULL != task->u.put.metadata) dpl_dict_free(task->u.put.metadata);
140 if (NULL != task->u.put.sysmd) dpl_sysmd_free(task->u.put.sysmd);
141 if (NULL != task->u.put.buf) dpl_buf_release(task->u.put.buf);
142 /* output */
143 break;
144 case DPL_TASK_GET:
145 case DPL_TASK_GET_ID:
146 /* inget */
147 FREE_IF_NOT_NULL(task->u.get.bucket);
148 FREE_IF_NOT_NULL(task->u.get.resource);
149 if (NULL != task->u.get.option) dpl_option_free(task->u.get.option);
150 if (NULL != task->u.get.condition)
151 dpl_condition_free(task->u.get.condition);
152 if (NULL != task->u.get.range) dpl_range_free(task->u.get.range);
153 /* output */
154 if (NULL != task->u.get.metadata) dpl_dict_free(task->u.get.metadata);
155 if (NULL != task->u.get.buf) dpl_buf_release(task->u.get.buf);
156 break;
157 case DPL_TASK_HEAD:
158 case DPL_TASK_HEAD_ID:
159 /* inhead */
160 FREE_IF_NOT_NULL(task->u.head.bucket);
161 FREE_IF_NOT_NULL(task->u.head.resource);
162 if (NULL != task->u.head.option) dpl_option_free(task->u.head.option);
163 if (NULL != task->u.head.condition)
164 dpl_condition_free(task->u.head.condition);
165 /* output */
166 if (NULL != task->u.head.metadata) dpl_dict_free(task->u.head.metadata);
167 break;
168 case DPL_TASK_DELETE:
169 case DPL_TASK_DELETE_ID:
170 /* indelete */
171 FREE_IF_NOT_NULL(task->u.delete.bucket);
172 FREE_IF_NOT_NULL(task->u.delete.resource);
173 if (NULL != task->u.delete.option) dpl_option_free(task->u.delete.option);
174 if (NULL != task->u.delete.condition)
175 dpl_condition_free(task->u.delete.condition);
176 /* output */
177 break;
178 case DPL_TASK_COPY:
179 case DPL_TASK_COPY_ID:
180 /* incopy */
181 FREE_IF_NOT_NULL(task->u.copy.src_bucket);
182 FREE_IF_NOT_NULL(task->u.copy.src_resource);
183 FREE_IF_NOT_NULL(task->u.copy.dst_bucket);
184 FREE_IF_NOT_NULL(task->u.copy.dst_resource);
185 if (NULL != task->u.copy.option) dpl_option_free(task->u.copy.option);
186 if (NULL != task->u.copy.metadata) dpl_dict_free(task->u.copy.metadata);
187 if (NULL != task->u.copy.sysmd) dpl_sysmd_free(task->u.copy.sysmd);
188 if (NULL != task->u.copy.condition)
189 dpl_condition_free(task->u.copy.condition);
190 /* output */
191 break;
192 }
193 free(task);
194 }
195
async_do(void * arg)196 static void async_do(void* arg)
197 {
198 dpl_async_task_t* task = (dpl_async_task_t*)arg;
199
200 switch (task->type) {
201 case DPL_TASK_LIST_ALL_MY_BUCKETS:
202 task->ret = dpl_list_all_my_buckets(task->ctx,
203 &task->u.list_all_my_buckets.buckets);
204 break;
205 case DPL_TASK_LIST_BUCKET:
206 task->ret = dpl_list_bucket(
207 task->ctx, task->u.list_bucket.bucket, task->u.list_bucket.prefix,
208 task->u.list_bucket.delimiter, task->u.list_bucket.max_keys,
209 &task->u.list_bucket.objects, &task->u.list_bucket.common_prefixes);
210 break;
211 case DPL_TASK_MAKE_BUCKET:
212 task->ret = dpl_make_bucket(task->ctx, task->u.make_bucket.bucket,
213 task->u.make_bucket.location_constraint,
214 task->u.make_bucket.canned_acl);
215 break;
216 case DPL_TASK_DELETE_BUCKET:
217 task->ret = dpl_delete_bucket(task->ctx, task->u.make_bucket.bucket);
218 break;
219 case DPL_TASK_POST:
220 task->ret = dpl_post(
221 task->ctx, task->u.post.bucket, task->u.post.resource,
222 task->u.post.option, task->u.post.object_type, task->u.post.condition,
223 task->u.post.range, task->u.post.metadata, task->u.post.sysmd,
224 NULL != task->u.post.buf ? dpl_buf_ptr(task->u.post.buf) : NULL,
225 NULL != task->u.post.buf ? dpl_buf_size(task->u.post.buf) : 0,
226 task->u.post.query_params, &task->u.post.sysmd_returned);
227 break;
228 case DPL_TASK_PUT:
229 task->ret = dpl_put(
230 task->ctx, task->u.put.bucket, task->u.put.resource,
231 task->u.put.option, task->u.put.object_type, task->u.put.condition,
232 task->u.put.range, task->u.put.metadata, task->u.put.sysmd,
233 NULL != task->u.put.buf ? dpl_buf_ptr(task->u.put.buf) : NULL,
234 NULL != task->u.put.buf ? dpl_buf_size(task->u.put.buf) : 0);
235 break;
236 case DPL_TASK_GET:
237 task->u.get.buf = dpl_buf_new();
238 if (NULL == task->u.get.buf) {
239 task->ret = DPL_ENOMEM;
240 break;
241 }
242 dpl_buf_acquire(task->u.get.buf);
243 task->ret = dpl_get(task->ctx, task->u.get.bucket, task->u.get.resource,
244 task->u.get.option, task->u.get.object_type,
245 task->u.get.condition, task->u.get.range,
246 &dpl_buf_ptr(task->u.get.buf),
247 &dpl_buf_size(task->u.get.buf), &task->u.get.metadata,
248 &task->u.get.sysmd);
249 break;
250 case DPL_TASK_HEAD:
251 task->ret = dpl_head(task->ctx, task->u.head.bucket,
252 task->u.head.resource, task->u.head.option,
253 task->u.head.object_type, task->u.head.condition,
254 &task->u.head.metadata, &task->u.head.sysmd);
255 break;
256 case DPL_TASK_DELETE:
257 task->ret
258 = dpl_delete(task->ctx, task->u.delete.bucket,
259 task->u.delete.resource, task->u.delete.option,
260 task->u.delete.object_type, task->u.delete.condition);
261 break;
262 case DPL_TASK_COPY:
263 task->ret = dpl_copy(task->ctx, task->u.copy.src_bucket,
264 task->u.copy.src_resource, task->u.copy.dst_bucket,
265 task->u.copy.dst_resource, task->u.copy.option,
266 task->u.copy.object_type,
267 task->u.copy.copy_directive, task->u.copy.metadata,
268 task->u.copy.sysmd, task->u.copy.condition);
269 break;
270 case DPL_TASK_POST_ID:
271 task->ret = dpl_post_id(
272 task->ctx, task->u.post.bucket, task->u.post.resource,
273 task->u.post.option, task->u.post.object_type, task->u.post.condition,
274 task->u.post.range, task->u.post.metadata, task->u.post.sysmd,
275 NULL != task->u.post.buf ? dpl_buf_ptr(task->u.post.buf) : NULL,
276 NULL != task->u.post.buf ? dpl_buf_size(task->u.post.buf) : 0,
277 task->u.post.query_params, &task->u.post.sysmd_returned);
278 break;
279 case DPL_TASK_PUT_ID:
280 task->ret = dpl_put_id(
281 task->ctx, task->u.put.bucket, task->u.put.resource,
282 task->u.put.option, task->u.put.object_type, task->u.put.condition,
283 task->u.put.range, task->u.put.metadata, task->u.put.sysmd,
284 NULL != task->u.put.buf ? dpl_buf_ptr(task->u.put.buf) : NULL,
285 NULL != task->u.put.buf ? dpl_buf_size(task->u.put.buf) : 0);
286 break;
287 case DPL_TASK_GET_ID:
288 task->u.get.buf = dpl_buf_new();
289 if (NULL == task->u.get.buf) {
290 task->ret = DPL_ENOMEM;
291 break;
292 }
293 dpl_buf_acquire(task->u.get.buf);
294 task->ret = dpl_get_id(task->ctx, task->u.get.bucket,
295 task->u.get.resource, task->u.get.option,
296 task->u.get.object_type, task->u.get.condition,
297 task->u.get.range, &dpl_buf_ptr(task->u.get.buf),
298 &dpl_buf_size(task->u.get.buf),
299 &task->u.get.metadata, &task->u.get.sysmd);
300 break;
301 case DPL_TASK_HEAD_ID:
302 task->ret = dpl_head_id(task->ctx, task->u.head.bucket,
303 task->u.head.resource, task->u.head.option,
304 task->u.head.object_type, task->u.head.condition,
305 &task->u.head.metadata, &task->u.head.sysmd);
306 break;
307 case DPL_TASK_DELETE_ID:
308 task->ret
309 = dpl_delete_id(task->ctx, task->u.delete.bucket,
310 task->u.delete.resource, task->u.delete.option,
311 task->u.delete.object_type, task->u.delete.condition);
312 break;
313 case DPL_TASK_COPY_ID:
314 task->ret = dpl_copy_id(
315 task->ctx, task->u.copy.src_bucket, task->u.copy.src_resource,
316 task->u.copy.dst_bucket, task->u.copy.dst_resource,
317 task->u.copy.option, task->u.copy.object_type,
318 task->u.copy.copy_directive, task->u.copy.metadata,
319 task->u.copy.sysmd, task->u.copy.condition);
320 break;
321 }
322 if (NULL != task->cb_func) task->cb_func(task->cb_arg);
323 }
324
325 /**
326 * list all buckets
327 *
328 * @param ctx the droplect context
329 * @param cb_func all callback returning a vector of dpl_bucket_t *
330 * @param cb_arg closure
331 *
332 * @return task
333 */
dpl_list_all_my_buckets_async_prepare(dpl_ctx_t * ctx)334 dpl_task_t* dpl_list_all_my_buckets_async_prepare(dpl_ctx_t* ctx)
335 {
336 dpl_async_task_t* task = NULL;
337
338 task = calloc(1, sizeof(*task));
339 if (NULL == task) goto bad;
340
341 task->ctx = ctx;
342 task->type = DPL_TASK_LIST_ALL_MY_BUCKETS;
343 task->task.func = async_do;
344
345 return (dpl_task_t*)task;
346
347 bad:
348
349 if (NULL != task) dpl_async_task_free(task);
350
351 return NULL;
352 }
353
354 /**
355 * list bucket or directory
356 *
357 * @param ctx the droplet context
358 * @param bucket can be NULL
359 * @param prefix directory can be NULL
360 * @param delimiter e.g. "/" can be NULL
361 * @param cb_func
362 * @param cb_arg
363 *
364 * @return task
365 */
dpl_list_bucket_async_prepare(dpl_ctx_t * ctx,const char * bucket,const char * prefix,const char * delimiter)366 dpl_task_t* dpl_list_bucket_async_prepare(dpl_ctx_t* ctx,
367 const char* bucket,
368 const char* prefix,
369 const char* delimiter)
370 {
371 dpl_async_task_t* task = NULL;
372
373 task = calloc(1, sizeof(*task));
374 if (NULL == task) goto bad;
375
376 task->ctx = ctx;
377 task->type = DPL_TASK_LIST_BUCKET;
378 task->task.func = async_do;
379 DUP_IF_NOT_NULL(task->u.list_bucket, bucket);
380 DUP_IF_NOT_NULL(task->u.list_bucket, prefix);
381 DUP_IF_NOT_NULL(task->u.list_bucket, delimiter);
382
383 return (dpl_task_t*)task;
384
385 bad:
386
387 if (NULL != task) dpl_async_task_free(task);
388
389 return NULL;
390 }
391
392 /**
393 * make a bucket
394 *
395 * @param ctx the droplet context
396 * @param bucket can be NULL
397 * @param location_constraint geographic location
398 * @param canned_acl simplified ACL
399 *
400 * @return task
401 */
dpl_make_bucket_async_prepare(dpl_ctx_t * ctx,const char * bucket,dpl_location_constraint_t location_constraint,dpl_canned_acl_t canned_acl)402 dpl_task_t* dpl_make_bucket_async_prepare(
403 dpl_ctx_t* ctx,
404 const char* bucket,
405 dpl_location_constraint_t location_constraint,
406 dpl_canned_acl_t canned_acl)
407 {
408 dpl_async_task_t* task = NULL;
409
410 task = calloc(1, sizeof(*task));
411 if (NULL == task) goto bad;
412
413 task->ctx = ctx;
414 task->type = DPL_TASK_MAKE_BUCKET;
415 task->task.func = async_do;
416 DUP_IF_NOT_NULL(task->u.make_bucket, bucket);
417 task->u.make_bucket.location_constraint = location_constraint;
418 task->u.make_bucket.canned_acl = canned_acl;
419
420 return (dpl_task_t*)task;
421
422 bad:
423
424 if (NULL != task) dpl_async_task_free(task);
425
426 return NULL;
427 }
428
429 /**
430 * delete a resource
431 *
432 * @param ctx the droplet context
433 * @param bucket can be NULL
434 *
435 * @return task
436 */
dpl_delete_bucket_prepare(dpl_ctx_t * ctx,const char * bucket)437 dpl_task_t* dpl_delete_bucket_prepare(dpl_ctx_t* ctx, const char* bucket)
438 {
439 dpl_async_task_t* task = NULL;
440
441 task = calloc(1, sizeof(*task));
442 if (NULL == task) goto bad;
443
444 task->ctx = ctx;
445 task->type = DPL_TASK_DELETE_BUCKET;
446 task->task.func = async_do;
447 DUP_IF_NOT_NULL(task->u.delete_bucket, bucket);
448
449 return (dpl_task_t*)task;
450
451 bad:
452
453 if (NULL != task) dpl_async_task_free(task);
454
455 return NULL;
456 }
457
458 /**
459 * create or post data into a resource
460 *
461 * @note this function is expected to return a newly created object
462 *
463 * @param ctx the droplet context
464 * @param bucket can be NULL
465 * @param resource can be NULL
466 * @param option DPL_OPTION_HTTP_COMPAT use if possible the HTTP compat mode
467 * @param object_type DPL_FTYPE_REG create a file
468 * @param metadata the user metadata. optional
469 * @param sysmd the system metadata. optional
470 * @param buf the data buffer
471 * @param query_params can be NULL
472 * @param returned_sysmdp the returned system metadata passed through stack
473 *
474 * @return DPL_SUCCESS
475 * @return DPL_FAILURE
476 */
dpl_post_async_prepare(dpl_ctx_t * ctx,const char * bucket,const char * resource,const dpl_option_t * option,dpl_ftype_t object_type,const dpl_condition_t * condition,const dpl_range_t * range,const dpl_dict_t * metadata,const dpl_sysmd_t * sysmd,dpl_buf_t * buf,const dpl_dict_t * query_params)477 dpl_task_t* dpl_post_async_prepare(dpl_ctx_t* ctx,
478 const char* bucket,
479 const char* resource,
480 const dpl_option_t* option,
481 dpl_ftype_t object_type,
482 const dpl_condition_t* condition,
483 const dpl_range_t* range,
484 const dpl_dict_t* metadata,
485 const dpl_sysmd_t* sysmd,
486 dpl_buf_t* buf,
487 const dpl_dict_t* query_params)
488 {
489 dpl_async_task_t* task = NULL;
490
491 task = calloc(1, sizeof(*task));
492 if (NULL == task) goto bad;
493
494 task->ctx = ctx;
495 task->type = DPL_TASK_POST;
496 task->task.func = async_do;
497 DUP_IF_NOT_NULL(task->u.post, bucket);
498 DUP_IF_NOT_NULL(task->u.post, resource);
499 if (NULL != option) task->u.post.option = dpl_option_dup(option);
500 task->u.post.object_type = object_type;
501 if (NULL != condition) task->u.post.condition = dpl_condition_dup(condition);
502 if (NULL != range) task->u.post.range = dpl_range_dup(range);
503 if (NULL != metadata) task->u.post.metadata = dpl_dict_dup(metadata);
504 if (NULL != sysmd) task->u.post.sysmd = dpl_sysmd_dup(sysmd);
505 if (NULL != buf) {
506 task->u.post.buf = buf;
507 dpl_buf_acquire(buf);
508 }
509 if (NULL != query_params)
510 task->u.post.query_params = dpl_dict_dup(query_params);
511
512 return (dpl_task_t*)task;
513
514 bad:
515
516 if (NULL != task) dpl_async_task_free(task);
517
518 return NULL;
519 }
520
521 /**
522 * put a resource
523 *
524 * @param ctx the droplet context
525 * @param bucket optional
526 * @param resource mandatory
527 * @param option DPL_OPTION_HTTP_COMPAT use if possible the HTTP compat mode
528 * @param object_type DPL_FTYPE_REG create a file
529 * @param object_type DPL_FTYPE_DIR create a directory
530 * @param condition the optional condition
531 * @param range optional range
532 * @param metadata the optional user metadata
533 * @param sysmd the optional system metadata
534 * @param buf the data buffer
535 *
536 * @return DPL_SUCCESS
537 * @return DPL_FAILURE
538 * @return DPL_EEXIST
539 */
dpl_put_async_prepare(dpl_ctx_t * ctx,const char * bucket,const char * resource,const dpl_option_t * option,dpl_ftype_t object_type,const dpl_condition_t * condition,const dpl_range_t * range,const dpl_dict_t * metadata,const dpl_sysmd_t * sysmd,dpl_buf_t * buf)540 dpl_task_t* dpl_put_async_prepare(dpl_ctx_t* ctx,
541 const char* bucket,
542 const char* resource,
543 const dpl_option_t* option,
544 dpl_ftype_t object_type,
545 const dpl_condition_t* condition,
546 const dpl_range_t* range,
547 const dpl_dict_t* metadata,
548 const dpl_sysmd_t* sysmd,
549 dpl_buf_t* buf)
550 {
551 dpl_async_task_t* task = NULL;
552
553 task = calloc(1, sizeof(*task));
554 if (NULL == task) goto bad;
555
556 task->ctx = ctx;
557 task->type = DPL_TASK_PUT;
558 task->task.func = async_do;
559 DUP_IF_NOT_NULL(task->u.put, bucket);
560 DUP_IF_NOT_NULL(task->u.put, resource);
561 if (NULL != option) task->u.put.option = dpl_option_dup(option);
562 task->u.put.object_type = object_type;
563 if (NULL != condition) task->u.put.condition = dpl_condition_dup(condition);
564 if (NULL != range) task->u.put.range = dpl_range_dup(range);
565 if (NULL != metadata) task->u.put.metadata = dpl_dict_dup(metadata);
566 if (NULL != sysmd) task->u.put.sysmd = dpl_sysmd_dup(sysmd);
567 if (NULL != buf) {
568 task->u.put.buf = buf;
569 dpl_buf_acquire(buf);
570 }
571
572 return (dpl_task_t*)task;
573
574 bad:
575
576 if (NULL != task) dpl_async_task_free(task);
577
578 return NULL;
579 }
580
581 /**
582 * get a resource with range
583 *
584 * @param ctx the droplet context
585 * @param bucket the optional bucket
586 * @param resource the mandat resource
587 * @param option DPL_OPTION_HTTP_COMPAT use if possible the HTTP compat mode
588 * @param object_type DPL_FTYPE_ANY get any type of resource
589 * @param condition the optional condition
590 * @param range the optional range
591 *
592 * @return DPL_SUCCESS
593 * @return DPL_FAILURE
594 * @return DPL_ENOENT resource does not exist
595 */
dpl_get_async_prepare(dpl_ctx_t * ctx,const char * bucket,const char * resource,const dpl_option_t * option,dpl_ftype_t object_type,const dpl_condition_t * condition,const dpl_range_t * range)596 dpl_task_t* dpl_get_async_prepare(dpl_ctx_t* ctx,
597 const char* bucket,
598 const char* resource,
599 const dpl_option_t* option,
600 dpl_ftype_t object_type,
601 const dpl_condition_t* condition,
602 const dpl_range_t* range)
603 {
604 dpl_async_task_t* task = NULL;
605
606 task = calloc(1, sizeof(*task));
607 if (NULL == task) goto bad;
608
609 task->ctx = ctx;
610 task->type = DPL_TASK_GET;
611 task->task.func = async_do;
612 DUP_IF_NOT_NULL(task->u.get, bucket);
613 DUP_IF_NOT_NULL(task->u.get, resource);
614 if (NULL != option) task->u.get.option = dpl_option_dup(option);
615 task->u.get.object_type = object_type;
616 if (NULL != condition) task->u.get.condition = dpl_condition_dup(condition);
617 if (NULL != range) task->u.get.range = dpl_range_dup(range);
618
619 return (dpl_task_t*)task;
620
621 bad:
622
623 if (NULL != task) dpl_async_task_free(task);
624
625 return NULL;
626 }
627
628 /**
629 * get user and system metadata
630 *
631 * @param ctx the droplet context
632 * @param bucket the optional bucket
633 * @param resource the mandat resource
634 * @param option DPL_OPTION_HTTP_COMPAT use if possible the HTTP compat mode
635 * @param object_type DPL_FTYPE_ANY get any type of resource
636 * @param condition the optional condition
637 * @param metadatap the returned user metadata client shall free
638 * @param sysmdp the returned system metadata passed through stack
639 *
640 * @return DPL_SUCCESS
641 * @return DPL_FAILURE
642 * @return DPL_ENOENT resource does not exist
643 */
dpl_head_async_prepare(dpl_ctx_t * ctx,const char * bucket,const char * resource,const dpl_option_t * option,dpl_ftype_t object_type,const dpl_condition_t * condition)644 dpl_task_t* dpl_head_async_prepare(dpl_ctx_t* ctx,
645 const char* bucket,
646 const char* resource,
647 const dpl_option_t* option,
648 dpl_ftype_t object_type,
649 const dpl_condition_t* condition)
650 {
651 dpl_async_task_t* task = NULL;
652
653 task = calloc(1, sizeof(*task));
654 if (NULL == task) goto bad;
655
656 task->ctx = ctx;
657 task->type = DPL_TASK_HEAD;
658 task->task.func = async_do;
659 DUP_IF_NOT_NULL(task->u.head, bucket);
660 DUP_IF_NOT_NULL(task->u.head, resource);
661 if (NULL != option) task->u.head.option = dpl_option_dup(option);
662 task->u.head.object_type = object_type;
663 if (NULL != condition) task->u.head.condition = dpl_condition_dup(condition);
664
665 return (dpl_task_t*)task;
666
667 bad:
668
669 if (NULL != task) dpl_async_task_free(task);
670
671 return NULL;
672 }
673
674 /**
675 * delete a resource
676 *
677 * @param ctx the droplet context
678 * @param bucket the optional bucket
679 * @param resource the mandat resource
680 * @param option DPL_OPTION_HTTP_COMPAT use if possible the HTTP compat mode
681 * @param condition the optional condition
682 *
683 * @return DPL_SUCCESS
684 * @return DPL_FAILURE
685 * @return DPL_ENOENT resource does not exist
686 */
dpl_delete_async_prepare(dpl_ctx_t * ctx,const char * bucket,const char * resource,const dpl_option_t * option,dpl_ftype_t object_type,const dpl_condition_t * condition)687 dpl_task_t* dpl_delete_async_prepare(dpl_ctx_t* ctx,
688 const char* bucket,
689 const char* resource,
690 const dpl_option_t* option,
691 dpl_ftype_t object_type,
692 const dpl_condition_t* condition)
693 {
694 dpl_async_task_t* task = NULL;
695
696 task = calloc(1, sizeof(*task));
697 if (NULL == task) goto bad;
698
699 task->ctx = ctx;
700 task->type = DPL_TASK_DELETE;
701 task->task.func = async_do;
702 DUP_IF_NOT_NULL(task->u.delete, bucket);
703 DUP_IF_NOT_NULL(task->u.delete, resource);
704 if (NULL != option) task->u.delete.option = dpl_option_dup(option);
705 task->u.delete.object_type = object_type;
706 if (NULL != condition)
707 task->u.delete.condition = dpl_condition_dup(condition);
708
709 return (dpl_task_t*)task;
710
711 bad:
712
713 if (NULL != task) dpl_async_task_free(task);
714
715 return NULL;
716 }
717
718 /**
719 * perform various flavors of server side copies
720 *
721 * @param ctx the droplet context
722 * @param src_bucket the optional source bucket
723 * @param src_resource the mandat source resource
724 * @param dst_bucket the optional destination bucket
725 * @param dst_resource the optional destination resource (if dst equals src)
726 * @param option unused
727 * @param object_type unused
728 * @param copy_directive DPL_COPY_DIRECTIVE_COPY server side copy
729 * @param copy_directive DPL_COPY_DIRECTIVE_METADATA_REPLACE setattr
730 * @param copy_directive DPL_COPY_DIRECTIVE_LINK hard link
731 * @param copy_directive DPL_COPY_DIRECTIVE_SYMLINK reference
732 * @param copy_directive DPL_COPY_DIRECTIVE_MOVE rename
733 * @param copy_directive DPL_COPY_DIRECTIVE_MKDENT create a directory entry
734 * @param metadata the optional user metadata
735 * @param sysmd the optional system metadata
736 * @param condition the optional condition
737 *
738 * @return DPL_SUCCESS
739 * @return DPL_FAILURE
740 */
dpl_copy_async_prepare(dpl_ctx_t * ctx,const char * src_bucket,const char * src_resource,const char * dst_bucket,const char * dst_resource,const dpl_option_t * option,dpl_ftype_t object_type,dpl_copy_directive_t copy_directive,const dpl_dict_t * metadata,const dpl_sysmd_t * sysmd,const dpl_condition_t * condition)741 dpl_task_t* dpl_copy_async_prepare(dpl_ctx_t* ctx,
742 const char* src_bucket,
743 const char* src_resource,
744 const char* dst_bucket,
745 const char* dst_resource,
746 const dpl_option_t* option,
747 dpl_ftype_t object_type,
748 dpl_copy_directive_t copy_directive,
749 const dpl_dict_t* metadata,
750 const dpl_sysmd_t* sysmd,
751 const dpl_condition_t* condition)
752 {
753 dpl_async_task_t* task = NULL;
754
755 task = calloc(1, sizeof(*task));
756 if (NULL == task) goto bad;
757
758 task->ctx = ctx;
759 task->type = DPL_TASK_COPY;
760 task->task.func = async_do;
761 DUP_IF_NOT_NULL(task->u.copy, src_bucket);
762 DUP_IF_NOT_NULL(task->u.copy, src_resource);
763 DUP_IF_NOT_NULL(task->u.copy, dst_bucket);
764 DUP_IF_NOT_NULL(task->u.copy, dst_resource);
765 if (NULL != option) task->u.copy.option = dpl_option_dup(option);
766 task->u.copy.object_type = object_type;
767 task->u.copy.copy_directive = copy_directive;
768 if (NULL != metadata) task->u.copy.metadata = dpl_dict_dup(metadata);
769 if (NULL != sysmd) task->u.copy.sysmd = dpl_sysmd_dup(sysmd);
770 if (NULL != condition) task->u.copy.condition = dpl_condition_dup(condition);
771
772 return (dpl_task_t*)task;
773
774 bad:
775
776 if (NULL != task) dpl_async_task_free(task);
777
778 return NULL;
779 }
780
781 /**
782 * create or post data into a resource
783 *
784 * @note this function is expected to return a newly created object
785 *
786 * @param ctx the droplet context
787 * @param bucket can be NULL
788 * @param option DPL_OPTION_HTTP_COMPAT use if possible the HTTP compat mode
789 * @param object_type DPL_FTYPE_REG create a file
790 * @param metadata the user metadata. optional
791 * @param sysmd the system metadata. optional
792 * @param buf the data buffer
793 * @param query_params can be NULL
794 * @param returned_sysmdp the returned system metadata passed through stack
795 *
796 * @return DPL_SUCCESS
797 * @return DPL_FAILURE
798 */
dpl_post_id_async_prepare(dpl_ctx_t * ctx,const char * bucket,const char * id,const dpl_option_t * option,dpl_ftype_t object_type,const dpl_condition_t * condition,const dpl_range_t * range,const dpl_dict_t * metadata,const dpl_sysmd_t * sysmd,dpl_buf_t * buf,const dpl_dict_t * query_params)799 dpl_task_t* dpl_post_id_async_prepare(dpl_ctx_t* ctx,
800 const char* bucket,
801 const char* id,
802 const dpl_option_t* option,
803 dpl_ftype_t object_type,
804 const dpl_condition_t* condition,
805 const dpl_range_t* range,
806 const dpl_dict_t* metadata,
807 const dpl_sysmd_t* sysmd,
808 dpl_buf_t* buf,
809 const dpl_dict_t* query_params)
810 {
811 dpl_async_task_t* task = NULL;
812
813 task = calloc(1, sizeof(*task));
814 if (NULL == task) goto bad;
815
816 task->ctx = ctx;
817 task->type = DPL_TASK_POST_ID;
818 task->task.func = async_do;
819 DUP_IF_NOT_NULL(task->u.post, bucket);
820 if (NULL != option) task->u.post.option = dpl_option_dup(option);
821 task->u.post.object_type = object_type;
822 if (NULL != condition) task->u.post.condition = dpl_condition_dup(condition);
823 if (NULL != range) task->u.post.range = dpl_range_dup(range);
824 if (NULL != metadata) task->u.post.metadata = dpl_dict_dup(metadata);
825 if (NULL != sysmd) task->u.post.sysmd = dpl_sysmd_dup(sysmd);
826 if (NULL != buf) {
827 task->u.post.buf = buf;
828 dpl_buf_acquire(buf);
829 }
830 if (NULL != query_params)
831 task->u.post.query_params = dpl_dict_dup(query_params);
832
833 return (dpl_task_t*)task;
834
835 bad:
836
837 if (NULL != task) dpl_async_task_free(task);
838
839 return NULL;
840 }
841
842 /**
843 * put a resource
844 *
845 * @param ctx the droplet context
846 * @param bucket optional
847 * @param resource mandatory
848 * @param option DPL_OPTION_HTTP_COMPAT use if possible the HTTP compat mode
849 * @param object_type DPL_FTYPE_REG create a file
850 * @param object_type DPL_FTYPE_DIR create a directory
851 * @param condition the optional condition
852 * @param range optional range
853 * @param metadata the optional user metadata
854 * @param sysmd the optional system metadata
855 * @param buf the data buffer
856 *
857 * @return DPL_SUCCESS
858 * @return DPL_FAILURE
859 * @return DPL_EEXIST
860 */
dpl_put_id_async_prepare(dpl_ctx_t * ctx,const char * bucket,const char * resource,const dpl_option_t * option,dpl_ftype_t object_type,const dpl_condition_t * condition,const dpl_range_t * range,const dpl_dict_t * metadata,const dpl_sysmd_t * sysmd,dpl_buf_t * buf)861 dpl_task_t* dpl_put_id_async_prepare(dpl_ctx_t* ctx,
862 const char* bucket,
863 const char* resource,
864 const dpl_option_t* option,
865 dpl_ftype_t object_type,
866 const dpl_condition_t* condition,
867 const dpl_range_t* range,
868 const dpl_dict_t* metadata,
869 const dpl_sysmd_t* sysmd,
870 dpl_buf_t* buf)
871 {
872 dpl_async_task_t* task = NULL;
873
874 task = calloc(1, sizeof(*task));
875 if (NULL == task) goto bad;
876
877 task->ctx = ctx;
878 task->type = DPL_TASK_PUT_ID;
879 task->task.func = async_do;
880 DUP_IF_NOT_NULL(task->u.put, bucket);
881 DUP_IF_NOT_NULL(task->u.put, resource);
882 if (NULL != option) task->u.put.option = dpl_option_dup(option);
883 task->u.put.object_type = object_type;
884 if (NULL != condition) task->u.put.condition = dpl_condition_dup(condition);
885 if (NULL != range) task->u.put.range = dpl_range_dup(range);
886 if (NULL != metadata) task->u.put.metadata = dpl_dict_dup(metadata);
887 if (NULL != sysmd) task->u.put.sysmd = dpl_sysmd_dup(sysmd);
888 if (NULL != buf) {
889 task->u.put.buf = buf;
890 dpl_buf_acquire(buf);
891 }
892
893 return (dpl_task_t*)task;
894
895 bad:
896
897 if (NULL != task) dpl_async_task_free(task);
898
899 return NULL;
900 }
901
902 /**
903 * get a resource with range
904 *
905 * @param ctx the droplet context
906 * @param bucket the optional bucket
907 * @param resource the mandat resource
908 * @param option DPL_OPTION_HTTP_COMPAT use if possible the HTTP compat mode
909 * @param object_type DPL_FTYPE_ANY get any type of resource
910 * @param condition the optional condition
911 * @param range the optional range
912 *
913 * @return DPL_SUCCESS
914 * @return DPL_FAILURE
915 * @return DPL_ENOENT resource does not exist
916 */
dpl_get_id_async_prepare(dpl_ctx_t * ctx,const char * bucket,const char * resource,const dpl_option_t * option,dpl_ftype_t object_type,const dpl_condition_t * condition,const dpl_range_t * range)917 dpl_task_t* dpl_get_id_async_prepare(dpl_ctx_t* ctx,
918 const char* bucket,
919 const char* resource,
920 const dpl_option_t* option,
921 dpl_ftype_t object_type,
922 const dpl_condition_t* condition,
923 const dpl_range_t* range)
924 {
925 dpl_async_task_t* task = NULL;
926
927 task = calloc(1, sizeof(*task));
928 if (NULL == task) goto bad;
929
930 task->ctx = ctx;
931 task->type = DPL_TASK_GET_ID;
932 task->task.func = async_do;
933 DUP_IF_NOT_NULL(task->u.get, bucket);
934 DUP_IF_NOT_NULL(task->u.get, resource);
935 if (NULL != option) task->u.get.option = dpl_option_dup(option);
936 task->u.get.object_type = object_type;
937 if (NULL != condition) task->u.get.condition = dpl_condition_dup(condition);
938 if (NULL != range) task->u.get.range = dpl_range_dup(range);
939
940 return (dpl_task_t*)task;
941
942 bad:
943
944 if (NULL != task) dpl_async_task_free(task);
945
946 return NULL;
947 }
948
949 /**
950 * get user and system metadata
951 *
952 * @param ctx the droplet context
953 * @param bucket the optional bucket
954 * @param resource the mandat resource
955 * @param option DPL_OPTION_HTTP_COMPAT use if possible the HTTP compat mode
956 * @param object_type DPL_FTYPE_ANY get any type of resource
957 * @param condition the optional condition
958 * @param metadatap the returned user metadata client shall free
959 * @param sysmdp the returned system metadata passed through stack
960 *
961 * @return DPL_SUCCESS
962 * @return DPL_FAILURE
963 * @return DPL_ENOENT resource does not exist
964 */
dpl_head_id_async_prepare(dpl_ctx_t * ctx,const char * bucket,const char * resource,const dpl_option_t * option,dpl_ftype_t object_type,const dpl_condition_t * condition)965 dpl_task_t* dpl_head_id_async_prepare(dpl_ctx_t* ctx,
966 const char* bucket,
967 const char* resource,
968 const dpl_option_t* option,
969 dpl_ftype_t object_type,
970 const dpl_condition_t* condition)
971 {
972 dpl_async_task_t* task = NULL;
973
974 task = calloc(1, sizeof(*task));
975 if (NULL == task) goto bad;
976
977 task->ctx = ctx;
978 task->type = DPL_TASK_HEAD_ID;
979 task->task.func = async_do;
980 DUP_IF_NOT_NULL(task->u.head, bucket);
981 DUP_IF_NOT_NULL(task->u.head, resource);
982 if (NULL != option) task->u.head.option = dpl_option_dup(option);
983 task->u.head.object_type = object_type;
984 if (NULL != condition) task->u.head.condition = dpl_condition_dup(condition);
985
986 return (dpl_task_t*)task;
987
988 bad:
989
990 if (NULL != task) dpl_async_task_free(task);
991
992 return NULL;
993 }
994
995 /**
996 * delete a resource
997 *
998 * @param ctx the droplet context
999 * @param bucket the optional bucket
1000 * @param resource the mandat resource
1001 * @param option DPL_OPTION_HTTP_COMPAT use if possible the HTTP compat mode
1002 * @param condition the optional condition
1003 *
1004 * @return DPL_SUCCESS
1005 * @return DPL_FAILURE
1006 * @return DPL_ENOENT resource does not exist
1007 */
dpl_delete_id_async_prepare(dpl_ctx_t * ctx,const char * bucket,const char * resource,const dpl_option_t * option,dpl_ftype_t object_type,const dpl_condition_t * condition)1008 dpl_task_t* dpl_delete_id_async_prepare(dpl_ctx_t* ctx,
1009 const char* bucket,
1010 const char* resource,
1011 const dpl_option_t* option,
1012 dpl_ftype_t object_type,
1013 const dpl_condition_t* condition)
1014 {
1015 dpl_async_task_t* task = NULL;
1016
1017 task = calloc(1, sizeof(*task));
1018 if (NULL == task) goto bad;
1019
1020 task->ctx = ctx;
1021 task->type = DPL_TASK_DELETE_ID;
1022 task->task.func = async_do;
1023 DUP_IF_NOT_NULL(task->u.delete, bucket);
1024 DUP_IF_NOT_NULL(task->u.delete, resource);
1025 if (NULL != option) task->u.delete.option = dpl_option_dup(option);
1026 task->u.delete.object_type = object_type;
1027 if (NULL != condition)
1028 task->u.delete.condition = dpl_condition_dup(condition);
1029
1030 return (dpl_task_t*)task;
1031
1032 bad:
1033
1034 if (NULL != task) dpl_async_task_free(task);
1035
1036 return NULL;
1037 }
1038
1039 /**
1040 * perform various flavors of server side copies
1041 *
1042 * @param ctx the droplet context
1043 * @param src_bucket the optional source bucket
1044 * @param src_resource the mandat source resource
1045 * @param dst_bucket the optional destination bucket
1046 * @param dst_resource the optional destination resource (if dst equals src)
1047 * @param option unused
1048 * @param object_type unused
1049 * @param copy_directive DPL_COPY_DIRECTIVE_COPY server side copy
1050 * @param copy_directive DPL_COPY_DIRECTIVE_METADATA_REPLACE setattr
1051 * @param copy_directive DPL_COPY_DIRECTIVE_LINK hard link
1052 * @param copy_directive DPL_COPY_DIRECTIVE_SYMLINK reference
1053 * @param copy_directive DPL_COPY_DIRECTIVE_MOVE rename
1054 * @param copy_directive DPL_COPY_DIRECTIVE_MKDENT create a directory entry
1055 * @param metadata the optional user metadata
1056 * @param sysmd the optional system metadata
1057 * @param condition the optional condition
1058 *
1059 * @return DPL_SUCCESS
1060 * @return DPL_FAILURE
1061 */
dpl_copy_id_async_prepare(dpl_ctx_t * ctx,const char * src_bucket,const char * src_resource,const char * dst_bucket,const char * dst_resource,const dpl_option_t * option,dpl_ftype_t object_type,dpl_copy_directive_t copy_directive,const dpl_dict_t * metadata,const dpl_sysmd_t * sysmd,const dpl_condition_t * condition)1062 dpl_task_t* dpl_copy_id_async_prepare(dpl_ctx_t* ctx,
1063 const char* src_bucket,
1064 const char* src_resource,
1065 const char* dst_bucket,
1066 const char* dst_resource,
1067 const dpl_option_t* option,
1068 dpl_ftype_t object_type,
1069 dpl_copy_directive_t copy_directive,
1070 const dpl_dict_t* metadata,
1071 const dpl_sysmd_t* sysmd,
1072 const dpl_condition_t* condition)
1073 {
1074 dpl_async_task_t* task = NULL;
1075
1076 task = calloc(1, sizeof(*task));
1077 if (NULL == task) goto bad;
1078
1079 task->ctx = ctx;
1080 task->type = DPL_TASK_COPY_ID;
1081 task->task.func = async_do;
1082 DUP_IF_NOT_NULL(task->u.copy, src_bucket);
1083 DUP_IF_NOT_NULL(task->u.copy, src_resource);
1084 DUP_IF_NOT_NULL(task->u.copy, dst_bucket);
1085 DUP_IF_NOT_NULL(task->u.copy, dst_resource);
1086 if (NULL != option) task->u.copy.option = dpl_option_dup(option);
1087 task->u.copy.object_type = object_type;
1088 task->u.copy.copy_directive = copy_directive;
1089 if (NULL != metadata) task->u.copy.metadata = dpl_dict_dup(metadata);
1090 if (NULL != sysmd) task->u.copy.sysmd = dpl_sysmd_dup(sysmd);
1091 if (NULL != condition) task->u.copy.condition = dpl_condition_dup(condition);
1092
1093 return (dpl_task_t*)task;
1094
1095 bad:
1096
1097 if (NULL != task) dpl_async_task_free(task);
1098
1099 return NULL;
1100 }
1101
1102 /* @} */
1103