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