1 /* check-sources:disable-copyright-check */
2 /*
3 * simple example which operates into a folder (creation of a folder, atomic
4 * file creation + get/set data/metadata + listing of a folder + getattr +
5 * deletion)
6 */
7
8 #include <droplet.h>
9 #include <droplet/async.h>
10 #include <assert.h>
11 #include <sys/param.h>
12
13 #define DATA_LEN 10000
14
15 dpl_ctx_t* ctx = NULL;
16 dpl_task_pool_t* pool = NULL;
17 char* folder = NULL;
18 int folder_len;
19 dpl_dict_t* metadata = NULL;
20 char new_path[MAXPATHLEN];
21
22 pthread_mutex_t prog_lock;
23 pthread_cond_t prog_cond;
24
25 pthread_mutex_t list_lock;
26 pthread_cond_t list_cond;
27 int n_ok = 0;
28
free_all()29 void free_all()
30 {
31 fprintf(stderr, "finished\n");
32
33 if (NULL != metadata) dpl_dict_free(metadata);
34
35 if (NULL != pool) {
36 // dpl_task_pool_cancel(pool);
37 // dpl_task_pool_destroy(pool);
38 }
39
40 dpl_ctx_free(ctx); // free context
41
42 dpl_free(); // free droplet library
43
44 pthread_cond_signal(&prog_cond);
45 }
46
cb_delete_object(void * handle)47 void cb_delete_object(void* handle)
48 {
49 dpl_async_task_t* atask = (dpl_async_task_t*)handle;
50
51 dpl_async_task_free(atask);
52
53 free_all();
54 }
55
delete_object()56 void delete_object()
57 {
58 dpl_async_task_t* atask = NULL;
59 dpl_buf_t* buf = NULL;
60
61 fprintf(stderr, "delete object+MD\n");
62
63 atask = (dpl_async_task_t*)dpl_delete_async_prepare(
64 ctx, // the context
65 NULL, // no bucket
66 new_path, // the key
67 NULL, // no option
68 DPL_FTYPE_UNDEF, // no matter the file type
69 NULL); // no condition
70
71 if (NULL == atask) {
72 fprintf(stderr, "error preparing task\n");
73 exit(1);
74 }
75
76 atask->cb_func = cb_delete_object;
77 atask->cb_arg = atask;
78
79 dpl_task_pool_put(pool, (dpl_task_t*)atask);
80 }
81
cb_head_object(void * handle)82 void cb_head_object(void* handle)
83 {
84 dpl_async_task_t* atask = (dpl_async_task_t*)handle;
85
86 if (DPL_SUCCESS != atask->ret) {
87 fprintf(stderr, "getattr error on %s: %s (%d)\n", atask->u.head.resource,
88 dpl_status_str(atask->ret), atask->ret);
89 exit(1);
90 }
91
92 fprintf(stderr, "file %s: size=%ld mtime=%lu\n", atask->u.head.resource,
93 atask->u.head.sysmd.size, atask->u.head.sysmd.mtime);
94 // dpl_dict_print(atask->u.head.metadata, stderr, 5);
95
96 dpl_async_task_free(atask);
97
98 pthread_mutex_lock(&list_lock);
99 n_ok++;
100 pthread_cond_signal(&list_cond);
101 pthread_mutex_unlock(&list_lock);
102 }
103
cb_list_bucket(void * handle)104 void cb_list_bucket(void* handle)
105 {
106 dpl_async_task_t* atask = (dpl_async_task_t*)handle;
107 int i;
108
109 if (DPL_SUCCESS != atask->ret) {
110 fprintf(stderr, "error listing folder: %s (%d)\n",
111 dpl_status_str(atask->ret), atask->ret);
112 exit(1);
113 }
114
115 pthread_mutex_init(&list_lock, NULL);
116 pthread_cond_init(&list_cond, NULL);
117
118 for (i = 0; i < atask->u.list_bucket.objects->n_items; i++) {
119 dpl_object_t* obj
120 = (dpl_object_t*)dpl_vec_get(atask->u.list_bucket.objects, i);
121 dpl_sysmd_t obj_sysmd;
122 dpl_dict_t* obj_md = NULL;
123 dpl_async_task_t* sub_atask = NULL;
124
125 fprintf(stderr, "getting md\n");
126
127 sub_atask = (dpl_async_task_t*)dpl_head_async_prepare(
128 ctx,
129 NULL, // no bucket
130 obj->path,
131 NULL, // option
132 DPL_FTYPE_UNDEF, // no matter the file type
133 NULL); // condition
134
135 if (NULL == sub_atask) {
136 fprintf(stderr, "error preparing task\n");
137 exit(1);
138 }
139
140 sub_atask->cb_func = cb_head_object;
141 sub_atask->cb_arg = sub_atask;
142
143 dpl_task_pool_put(pool, (dpl_task_t*)sub_atask);
144 }
145
146 for (i = 0; i < atask->u.list_bucket.common_prefixes->n_items; i++) {
147 dpl_common_prefix_t* dir = (dpl_common_prefix_t*)dpl_vec_get(
148 atask->u.list_bucket.common_prefixes, i);
149
150 fprintf(stderr, "dir %s\n", dir->prefix);
151 }
152
153 again:
154
155 pthread_cond_wait(&list_cond, &list_lock);
156
157 // printf("n_ok=%d\n", n_ok);
158
159 if (n_ok != atask->u.list_bucket.objects->n_items) goto again;
160
161 dpl_async_task_free(atask);
162
163 delete_object();
164 }
165
list_bucket()166 void list_bucket()
167 {
168 dpl_async_task_t* atask = NULL;
169 dpl_buf_t* buf = NULL;
170 int i;
171
172 fprintf(stderr, "listing of folder\n");
173
174 atask = (dpl_async_task_t*)dpl_list_bucket_async_prepare(ctx, NULL, folder,
175 "/");
176
177 if (NULL == atask) {
178 fprintf(stderr, "error preparing task\n");
179 exit(1);
180 }
181
182 atask->cb_func = cb_list_bucket;
183 atask->cb_arg = atask;
184
185 dpl_task_pool_put(pool, (dpl_task_t*)atask);
186 }
187
cb_get_metadata(void * handle)188 void cb_get_metadata(void* handle)
189 {
190 dpl_async_task_t* atask = (dpl_async_task_t*)handle;
191 dpl_dict_var_t* metadatum = NULL;
192
193 if (DPL_SUCCESS != atask->ret) {
194 fprintf(stderr, "error getting metadata: %s (%d)\n",
195 dpl_status_str(atask->ret), atask->ret);
196 exit(1);
197 }
198
199 fprintf(stderr, "checking metadata\n");
200
201 metadatum = dpl_dict_get(atask->u.head.metadata, "foo");
202 if (NULL == metadatum) {
203 fprintf(stderr, "missing metadatum\n");
204 exit(1);
205 }
206
207 assert(metadatum->val->type == DPL_VALUE_STRING);
208 if (strcmp(dpl_sbuf_get_str(metadatum->val->string), "bar2")) {
209 fprintf(stderr, "bad value in metadatum\n");
210 exit(1);
211 }
212
213 metadatum = dpl_dict_get(atask->u.head.metadata, "foo2");
214 if (NULL == metadatum) {
215 fprintf(stderr, "missing metadatum\n");
216 exit(1);
217 }
218
219 assert(metadatum->val->type == DPL_VALUE_STRING);
220 if (strcmp(dpl_sbuf_get_str(metadatum->val->string), "qux")) {
221 fprintf(stderr, "bad value in metadatum\n");
222 exit(1);
223 }
224
225 dpl_async_task_free(atask);
226
227 list_bucket();
228 }
229
get_metadata()230 void get_metadata()
231 {
232 dpl_async_task_t* atask = NULL;
233
234 fprintf(stderr, "getting MD only\n");
235
236 atask = (dpl_async_task_t*)dpl_head_async_prepare(
237 ctx, // the context
238 NULL, // no bucket,
239 new_path, // the key
240 NULL, // no option
241 DPL_FTYPE_UNDEF, // no matter the file type
242 NULL); // no condition,
243
244 if (NULL == atask) {
245 fprintf(stderr, "error preparing task\n");
246 exit(1);
247 }
248
249 atask->cb_func = cb_get_metadata;
250 atask->cb_arg = atask;
251
252 dpl_task_pool_put(pool, (dpl_task_t*)atask);
253 }
254
cb_update_metadata(void * handle)255 void cb_update_metadata(void* handle)
256 {
257 dpl_async_task_t* atask = (dpl_async_task_t*)handle;
258
259 dpl_async_task_free(atask);
260
261 get_metadata();
262 }
263
update_metadata()264 void update_metadata()
265 {
266 dpl_async_task_t* atask = NULL;
267 dpl_buf_t* buf = NULL;
268 dpl_status_t ret;
269
270 fprintf(stderr, "setting MD only\n");
271
272 ret = dpl_dict_add(metadata, "foo", "bar2", 0);
273 if (DPL_SUCCESS != ret) {
274 fprintf(stderr, "error updating metadatum: %s (%d)\n", dpl_status_str(ret),
275 ret);
276 exit(1);
277 }
278
279 atask = (dpl_async_task_t*)dpl_copy_async_prepare(
280 ctx, // the context
281 NULL, // no src bucket
282 new_path, // the key
283 NULL, // no dst bucket
284 new_path, // the same key
285 NULL, // no option
286 DPL_FTYPE_REG, // object type
287 DPL_COPY_DIRECTIVE_METADATA_REPLACE, // tell server to replace metadata
288 metadata, // the updated metadata
289 NULL, // no sysmd
290 NULL); // no condition
291
292 if (NULL == atask) {
293 fprintf(stderr, "error preparing task\n");
294 exit(1);
295 }
296
297 atask->cb_func = cb_update_metadata;
298 atask->cb_arg = atask;
299
300 dpl_task_pool_put(pool, (dpl_task_t*)atask);
301 }
302
cb_get_object(void * handle)303 void cb_get_object(void* handle)
304 {
305 dpl_async_task_t* atask = (dpl_async_task_t*)handle;
306 int i;
307 dpl_dict_var_t* metadatum = NULL;
308
309 if (DPL_SUCCESS != atask->ret) {
310 fprintf(stderr, "dpl_get failed: %s (%d)\n", dpl_status_str(atask->ret),
311 atask->ret);
312 exit(1);
313 }
314
315 fprintf(stderr, "checking object\n");
316
317 if (DATA_LEN != atask->u.get.buf->size) {
318 fprintf(stderr, "data lengths mismatch\n");
319 exit(1);
320 }
321
322 for (i = 0; i < DATA_LEN; i++)
323 if (atask->u.get.buf->ptr[i] != 'z') {
324 fprintf(stderr, "data content mismatch\n");
325 exit(1);
326 }
327
328 fprintf(stderr, "checking metadata\n");
329
330 metadatum = dpl_dict_get(atask->u.get.metadata, "foo");
331 if (NULL == metadatum) {
332 fprintf(stderr, "missing metadatum\n");
333 exit(1);
334 }
335
336 assert(metadatum->val->type == DPL_VALUE_STRING);
337 if (strcmp(dpl_sbuf_get_str(metadatum->val->string), "bar")) {
338 fprintf(stderr, "bad value in metadatum\n");
339 exit(1);
340 }
341
342 metadatum = dpl_dict_get(atask->u.get.metadata, "foo2");
343 if (NULL == metadatum) {
344 fprintf(stderr, "missing metadatum\n");
345 exit(1);
346 }
347
348 assert(metadatum->val->type == DPL_VALUE_STRING);
349 if (strcmp(dpl_sbuf_get_str(metadatum->val->string), "qux")) {
350 fprintf(stderr, "bad value in metadatum\n");
351 exit(1);
352 }
353
354 dpl_async_task_free(atask);
355
356 update_metadata();
357 }
358
get_object()359 void get_object()
360 {
361 dpl_async_task_t* atask = NULL;
362 dpl_buf_t* buf = NULL;
363 dpl_status_t ret;
364
365 fprintf(stderr, "getting object+MD\n");
366
367 atask
368 = (dpl_async_task_t*)dpl_get_async_prepare(ctx, // the context
369 NULL, // no bucket
370 new_path, // the key
371 NULL, // no opion
372 DPL_FTYPE_REG, // object type
373 NULL, // no condition
374 NULL); // no range
375
376 if (NULL == atask) {
377 fprintf(stderr, "error preparing task\n");
378 exit(1);
379 }
380
381 atask->cb_func = cb_get_object;
382 atask->cb_arg = atask;
383
384 dpl_task_pool_put(pool, (dpl_task_t*)atask);
385 }
386
cb_rename_object(void * handle)387 void cb_rename_object(void* handle)
388 {
389 dpl_async_task_t* atask = (dpl_async_task_t*)handle;
390
391 if (DPL_SUCCESS != atask->ret) {
392 fprintf(stderr, "rename object failed: %s (%d)\n",
393 dpl_status_str(atask->ret), atask->ret);
394 exit(1);
395 }
396
397 dpl_async_task_free(atask);
398
399 get_object();
400 }
401
rename_object(char * resource_path)402 void rename_object(char* resource_path)
403 {
404 dpl_async_task_t* atask = NULL;
405 dpl_buf_t* buf = NULL;
406 dpl_status_t ret;
407
408 snprintf(new_path, sizeof(new_path), "%su.1", folder);
409
410 atask = (dpl_async_task_t*)dpl_copy_async_prepare(
411 ctx,
412 NULL, // no src bucket
413 resource_path, // the src resource
414 NULL, // no dst bucket
415 new_path, // dst resource
416 NULL, // no option
417 DPL_FTYPE_REG, // regular file
418 DPL_COPY_DIRECTIVE_MOVE, // rename
419 NULL, // no metadata
420 NULL, // no sysmd
421 NULL); // no server side condition
422
423 if (NULL == atask) {
424 fprintf(stderr, "error preparing task\n");
425 exit(1);
426 }
427
428 atask->cb_func = cb_rename_object;
429 atask->cb_arg = atask;
430
431 dpl_task_pool_put(pool, (dpl_task_t*)atask);
432 }
433
cb_create_object(void * handle)434 void cb_create_object(void* handle)
435 {
436 dpl_async_task_t* atask = (dpl_async_task_t*)handle;
437
438 if (DPL_SUCCESS != atask->ret) {
439 fprintf(stderr, "create object failed: %s (%d)\n",
440 dpl_status_str(atask->ret), atask->ret);
441 exit(1);
442 }
443
444 if (!(atask->u.post.sysmd_returned.mask & DPL_SYSMD_MASK_PATH)) {
445 fprintf(stderr, "path is missing from sysmd\n");
446 exit(1);
447 }
448
449 fprintf(stderr, "resource path %s\n", atask->u.post.sysmd_returned.path);
450
451 rename_object(atask->u.post.sysmd_returned.path);
452
453 dpl_async_task_free(atask);
454 }
455
create_object()456 void create_object()
457 {
458 dpl_async_task_t* atask = NULL;
459 dpl_buf_t* buf = NULL;
460 dpl_status_t ret;
461
462 buf = dpl_buf_new();
463 if (NULL == buf) exit(1);
464
465 buf->size = DATA_LEN;
466 buf->ptr = malloc(DATA_LEN);
467 if (NULL == buf->ptr) {
468 fprintf(stderr, "alloc data failed\n");
469 exit(1);
470 }
471
472 memset(buf->ptr, 'z', buf->size);
473
474 metadata = dpl_dict_new(13);
475 if (NULL == metadata) {
476 fprintf(stderr, "dpl_dict_new failed\n");
477 exit(1);
478 }
479
480 ret = dpl_dict_add(metadata, "foo", "bar", 0);
481 if (DPL_SUCCESS != ret) {
482 fprintf(stderr, "dpl_dict_add failed\n");
483 exit(1);
484 }
485
486 ret = dpl_dict_add(metadata, "foo2", "qux", 0);
487 if (DPL_SUCCESS != ret) {
488 fprintf(stderr, "dpl_dict_add failed\n");
489 exit(1);
490 }
491
492 fprintf(stderr, "atomic creation of an object+MD\n");
493
494 atask = (dpl_async_task_t*)dpl_post_async_prepare(
495 ctx, // the context
496 NULL, // no bucket
497 folder, // the folder
498 NULL, // no option
499 DPL_FTYPE_REG, // regular object
500 NULL, // condition
501 NULL, // range
502 metadata, // the metadata
503 NULL, // no sysmd
504 buf, // object body
505 NULL); // no query params
506 if (NULL == atask) {
507 fprintf(stderr, "error preparing task\n");
508 exit(1);
509 }
510
511 atask->cb_func = cb_create_object;
512 atask->cb_arg = atask;
513
514 dpl_task_pool_put(pool, (dpl_task_t*)atask);
515 }
516
cb_make_folder(void * handle)517 void cb_make_folder(void* handle)
518 {
519 dpl_async_task_t* atask = (dpl_async_task_t*)handle;
520
521 if (DPL_SUCCESS != atask->ret) {
522 fprintf(stderr, "make dir failed: %s (%d)\n", dpl_status_str(atask->ret),
523 atask->ret);
524 exit(1);
525 }
526
527 dpl_async_task_free(atask);
528
529 create_object();
530 }
531
make_folder()532 void make_folder()
533 {
534 dpl_status_t ret, ret2;
535 dpl_async_task_t* atask = NULL;
536 dpl_buf_t* buf = NULL;
537
538 fprintf(stderr, "creating folder\n");
539
540 buf = dpl_buf_new();
541 if (NULL == buf) exit(1);
542
543 atask = (dpl_async_task_t*)dpl_put_async_prepare(ctx, // the context
544 NULL, // no bucket
545 folder, // the folder
546 NULL, // no option
547 DPL_FTYPE_DIR, // directory
548 NULL, // no condition
549 NULL, // no range
550 NULL, // no metadata
551 NULL, // no sysmd
552 buf); // object body
553 if (NULL == atask) {
554 fprintf(stderr, "error preparing task\n");
555 exit(1);
556 }
557
558 atask->cb_func = cb_make_folder;
559 atask->cb_arg = atask;
560
561 dpl_task_pool_put(pool, (dpl_task_t*)atask);
562 }
563
main(int argc,char ** argv)564 int main(int argc, char** argv)
565 {
566 int ret;
567
568 if (2 != argc) {
569 fprintf(stderr, "usage: restrest folder\n");
570 exit(1);
571 }
572
573 folder = argv[1];
574 folder_len = strlen(folder);
575 if (folder_len < 1) {
576 fprintf(stderr, "bad folder\n");
577 exit(1);
578 }
579 if (folder[folder_len - 1] != '/') {
580 fprintf(stderr, "folder name must end with a slash\n");
581 exit(1);
582 }
583
584 ret = dpl_init(); // init droplet library
585 if (DPL_SUCCESS != ret) {
586 fprintf(stderr, "dpl_init failed\n");
587 exit(1);
588 }
589
590 // open default profile
591 ctx = dpl_ctx_new(NULL, // droplet directory, default: "~/.droplet"
592 NULL); // droplet profile, default: "default"
593 if (NULL == ctx) {
594 fprintf(stderr, "dpl_ctx_new failed\n");
595 ret = 1;
596 }
597
598 // ctx->trace_level = ~0;
599 // ctx->trace_buffers = 1;
600
601 pool = dpl_task_pool_create(ctx, "resttest", 10);
602 if (NULL == pool) {
603 fprintf(stderr, "error creating pool\n");
604 exit(1);
605 }
606
607 /**/
608
609 pthread_mutex_init(&prog_lock, NULL);
610 pthread_cond_init(&prog_cond, NULL);
611
612 make_folder();
613
614 pthread_cond_wait(&prog_cond, &prog_lock);
615
616 return 0;
617 }
618