]> git.tuebingen.mpg.de Git - paraslash.git/blob - blob.c
Merge the new afs code.
[paraslash.git] / blob.c
1 #include "para.h"
2 #include "error.h"
3 #include "afs.h"
4 #include "string.h"
5
6 /** \file blob.c Macros and functions for blob handling. */
7
8 static struct osl_column_description blob_cols[] = {
9         [BLOBCOL_ID] = {
10                 .storage_type = OSL_MAPPED_STORAGE,
11                 .storage_flags = OSL_RBTREE | OSL_UNIQUE | OSL_FIXED_SIZE,
12                 .name = "id",
13                 .data_size = 4,
14                 .compare_function = uint32_compare
15         },
16         [BLOBCOL_NAME] = {
17                 .storage_type = OSL_MAPPED_STORAGE,
18                 .storage_flags = OSL_RBTREE | OSL_UNIQUE,
19                 .name = "name",
20                 .compare_function = string_compare
21         },
22         [BLOBCOL_DEF] = {
23                 .storage_type = OSL_DISK_STORAGE,
24                 .storage_flags = 0,
25                 .name = "definition"
26         }
27 };
28
29 /** \cond doxygen isn't smart enough to recognize these */
30 INIT_BLOB_TABLE(lyrics);
31 INIT_BLOB_TABLE(images);
32 INIT_BLOB_TABLE(moods);
33 INIT_BLOB_TABLE(playlists);
34 /** \endcond */
35
36 /** Flags that may be passed to the \p ls functions of each blob  type. */
37 enum blob_ls_flags {
38         /** List both id and name. */
39         BLOB_LS_FLAG_LONG = 1,
40         /** Reverse sort order. */
41         BLOB_LS_FLAG_REVERSE = 2,
42         /** Sort by id instead of name. */
43         BLOB_LS_FLAG_SORT_BY_ID = 4,
44 };
45
46 /** Data passed to \p com_lsbob_callback(). */
47 struct com_lsblob_options {
48         /** Given flags for the ls command. */
49         uint32_t flags;
50 };
51
52 /** Structure passed to the \p print_blob loop function. */
53 struct lsblob_loop_data {
54         struct com_lsblob_options *opts;
55         struct para_buffer *pb;
56         struct osl_table *table;
57 };
58
59 static int print_blob(struct osl_row *row, void *loop_data)
60 {
61         struct osl_object obj;
62         char *name;
63         uint32_t id;
64         int ret;
65         struct lsblob_loop_data *lld = loop_data;
66
67         ret = osl_get_object(lld->table, row, BLOBCOL_NAME, &obj);
68         if (ret < 0)
69                 return ret;
70         name = obj.data;
71         if (!*name) /* ignore dummy row */
72                 return 1;
73         ret = osl_get_object(lld->table, row, BLOBCOL_ID, &obj);
74         if (ret < 0)
75                 return ret;
76         id = *(uint32_t *)obj.data;
77         if (lld->opts->flags & BLOB_LS_FLAG_LONG)
78                 para_printf(lld->pb, "%u\t%s\n", id, name);
79         else
80                 para_printf(lld->pb, "%s\n", name);
81         return 1;
82 }
83
84 int com_lsblob_callback(struct osl_table *table,
85                 const struct osl_object *query, struct osl_object *ls_output)
86 {
87         struct para_buffer pb = {.buf = NULL};
88         struct lsblob_loop_data lld = {.opts = query->data, .pb = &pb, .table = table};
89         int ret;
90
91         if (lld.opts->flags & BLOB_LS_FLAG_REVERSE) {
92                 if (lld.opts->flags & BLOB_LS_FLAG_SORT_BY_ID)
93                         ret = osl_rbtree_loop(lld.table, BLOBCOL_ID, &lld, print_blob);
94                 else
95                         ret = osl_rbtree_loop_reverse(lld.table, BLOBCOL_NAME, &lld, print_blob);
96         } else {
97                 if (lld.opts->flags & BLOB_LS_FLAG_SORT_BY_ID)
98                         ret = osl_rbtree_loop_reverse(lld.table, BLOBCOL_ID, &lld, print_blob);
99                 else
100                         ret = osl_rbtree_loop(lld.table, BLOBCOL_NAME, &lld, print_blob);
101         }
102         ls_output->data = pb.buf;
103         ls_output->size = pb.size;
104         return ret;
105 }
106
107 static int com_lsblob(callback_function *f, __a_unused int fd, int argc, const char **argv)
108 {
109         struct com_lsblob_options clbo = {.flags = 0};
110         struct osl_object query = {.data = &clbo, .size = sizeof(clbo)},
111                 ls_output;
112         int i, ret;
113
114         for (i = 1; i < argc; i++) {
115                 const char *arg = argv[i];
116                 if (arg[0] != '-')
117                         break;
118                 if (!strcmp(arg, "--")) {
119                         i++;
120                         break;
121                 }
122                 if (!strcmp(arg, "-l")) {
123                         clbo.flags |= BLOB_LS_FLAG_LONG;
124                         continue;
125                 }
126                 if (!strcmp(arg, "-i")) {
127                         clbo.flags |= BLOB_LS_FLAG_SORT_BY_ID;
128                         continue;
129                 }
130                 if (!strcmp(arg, "-r")) {
131                         clbo.flags |= BLOB_LS_FLAG_REVERSE;
132                         continue;
133                 }
134         }
135         if (argc > i)
136                 return -E_BLOB_SYNTAX;
137         ret = send_option_arg_callback_request(&query, argc - i,
138                 argv + i, f, &ls_output);
139         if (ret >= 0 && ls_output.data)
140                 printf("%s\n", (char *)ls_output.data);
141         free(ls_output.data);
142         return ret;
143 }
144
145 static int com_catblob_callback(struct osl_table *table,
146                 const struct osl_object *query, struct osl_object *output)
147 {
148         struct osl_object obj;
149         int ret;
150         struct osl_row *row;
151
152         ret = osl_get_row(table, BLOBCOL_NAME, query, &row);
153         if (ret < 0)
154                 return ret;
155         ret = osl_open_disk_object(table, row, BLOBCOL_DEF, &obj);
156         if (ret < 0)
157                 return ret;
158         output->data = para_malloc(obj.size);
159         output->size = obj.size;
160         memcpy(output->data, obj.data, obj.size);
161         return osl_close_disk_object(&obj);
162 }
163 static int com_catblob(callback_function *f, __a_unused int fd, int argc,
164                 const char **argv)
165 {
166         struct osl_object cat_output = {.data = NULL};
167         int ret;
168
169         if (argc != 2)
170                 return -E_BLOB_SYNTAX;
171         if (!*argv[1]) /* empty name is reserved of the dummy row */
172                 return -E_BLOB_SYNTAX;
173         ret = send_standard_callback_request(1, argv + 1, f, &cat_output);
174         if (ret >= 0 && cat_output.data)
175                 printf("%s\n", (char *)cat_output.data);
176         free(cat_output.data);
177         return ret;
178
179 }
180
181 static int com_addblob_callback(struct osl_table *table,
182                 const struct osl_object *query,
183                 __a_unused struct osl_object *result)
184 {
185         struct osl_object objs[NUM_BLOB_COLUMNS];
186         char *name = query->data;
187         size_t name_len = strlen(name) + 1;
188         uint32_t id;
189         unsigned num_rows;
190         int ret;
191
192         ret = osl_get_num_rows(table, &num_rows);
193         if (ret < 0)
194                 return ret;
195         if (!num_rows) { /* this is the first entry ever added */
196                 /* insert dummy row containing the id */
197                 id = 2; /* this entry will be entry #1, so 2 is the next */
198                 objs[BLOBCOL_ID].data = &id;
199                 objs[BLOBCOL_ID].size = sizeof(id);
200                 objs[BLOBCOL_NAME].data = "";
201                 objs[BLOBCOL_NAME].size = 1;
202                 objs[BLOBCOL_DEF].data = "";
203                 objs[BLOBCOL_DEF].size = 1;
204                 ret = osl_add_row(table, objs);
205                 if (ret < 0)
206                         return ret;
207         } else { /* get id of the dummy row and increment it */
208                 struct osl_row *row;
209                 struct osl_object obj = {.data = "", .size = 1};
210                 ret = osl_get_row(table, BLOBCOL_NAME, &obj, &row);
211                 if (ret < 0)
212                         return ret;
213                 ret = osl_get_object(table, row, BLOBCOL_ID, &obj);
214                 if (ret < 0)
215                         return ret;
216                 id = *(uint32_t *)obj.data + 1;
217                 obj.data = &id;
218                 ret = osl_update_object(table, row, BLOBCOL_ID, &obj);
219                 if (ret < 0)
220                         return ret;
221         }
222         id--;
223         objs[BLOBCOL_ID].data = &id;
224         objs[BLOBCOL_ID].size = sizeof(id);
225         objs[BLOBCOL_NAME].data = name;
226         objs[BLOBCOL_NAME].size = name_len;
227         objs[BLOBCOL_DEF].data = name + name_len;
228         objs[BLOBCOL_DEF].size = query->size - name_len;
229         return osl_add_row(table, objs);
230 }
231
232 static int com_addblob(callback_function *f, __a_unused int fd, int argc,
233                 const char **argv)
234 {
235         struct osl_object arg_obj;
236
237         if (argc != 2)
238                 return -E_BLOB_SYNTAX;
239         if (!*argv[1]) /* empty name is reserved for the dummy row */
240                 return -E_BLOB_SYNTAX;
241         PARA_NOTICE_LOG("argv[1]: %s\n", argv[1]);
242         arg_obj.size = strlen(argv[1]) + 1;
243         arg_obj.data = (char *)argv[1];
244         return stdin_command(&arg_obj, f, 10 * 1024 * 1024, NULL);
245 }
246
247 static int com_rmblob_callback(struct osl_table *table,
248                 const struct osl_object *query,
249                 __a_unused struct osl_object *result)
250 {
251         char *p = query->data;
252         size_t len;
253         int ret;
254
255         for (; p < (char *)query->data + query->size; p += len + 1) {
256                 struct osl_row *row;
257                 struct osl_object obj;
258
259                 len = strlen(p);
260                 obj.data = p;
261                 obj.size = len + 1;
262                 ret = osl_get_row(table, BLOBCOL_NAME, &obj, &row);
263                 if (ret < 0)
264                         return ret;
265                 ret = osl_del_row(table, row);
266                 if (ret < 0)
267                         return ret;
268         }
269         return 1;
270 }
271
272 static int com_rmblob(callback_function *f, __a_unused int fd, int argc,
273                 const char **argv)
274 {
275         if (argc < 2)
276                 return -E_MOOD_SYNTAX;
277         return send_option_arg_callback_request(NULL, argc - 1, argv + 1, f,
278                 NULL);
279 }
280
281 static int com_mvblob_callback(struct osl_table *table,
282                 const struct osl_object *query,
283                 __a_unused struct osl_object *result)
284 {
285         char *src = (char *) query->data;
286         struct osl_object obj = {.data = src, .size = strlen(src) + 1};
287         char *dest = src + obj.size;
288         struct osl_row *row;
289         int ret = osl_get_row(table, BLOBCOL_NAME, &obj, &row);
290
291         if (ret < 0)
292                 return ret;
293         obj.data = dest;
294         obj.size = strlen(dest) + 1;
295         return osl_update_object(table, row, BLOBCOL_NAME, &obj);
296 }
297
298 static int com_mvblob(callback_function *f,  __a_unused int fd,
299                 int argc, const char **argv)
300 {
301         if (argc != 3)
302                 return -E_MOOD_SYNTAX;
303         return send_option_arg_callback_request(NULL, argc - 1, argv + 1, f,
304                 NULL);
305 }
306
307 #define DEFINE_BLOB_COMMAND(cmd_name, table_name, cmd_prefix) \
308         static int com_ ## cmd_name ## cmd_prefix ## _callback(const struct osl_object *query, \
309                         struct osl_object *output) \
310         { \
311                 return com_ ## cmd_name ## blob_callback(table_name ## _table, query, output); \
312         } \
313         int com_ ## cmd_name ## cmd_prefix(__a_unused int fd, int argc, const char **argv) \
314         { \
315                 return com_ ## cmd_name ## blob(com_ ## cmd_name ## cmd_prefix ## _callback, fd, argc, argv); \
316         }
317
318 static int blob_get_name_by_id(struct osl_table *table, uint32_t id,
319                 char **name)
320 {
321         struct osl_row *row;
322         struct osl_object obj = {.data = &id, .size = sizeof(id)};
323         int ret;
324
325         *name = NULL;
326         if (!id)
327                 return 1;
328         ret = osl_get_row(table, BLOBCOL_ID, &obj, &row);
329         if (ret < 0)
330                 return ret;
331         ret = osl_get_object(table, row, BLOBCOL_NAME, &obj);
332         if (ret < 0)
333                 return ret;
334         *name = (char *)obj.data;
335         return 1;
336 }
337 /** Define the \p get_name_by_id function for this blob type. */
338 #define DEFINE_GET_NAME_BY_ID(table_name, cmd_prefix) \
339         int cmd_prefix ## _get_name_by_id(uint32_t id, char **name) \
340         { \
341                 return blob_get_name_by_id(table_name ## _table, id, name); \
342         }
343
344 /** Define the \p shutdown function for this blob type. */
345 #define DEFINE_BLOB_SHUTDOWN(table_name) \
346         void table_name ## _shutdown(enum osl_close_flags flags) \
347         { \
348                 osl_close_table(table_name ## _table, flags); \
349                 table_name ## _table = NULL; \
350         }
351
352 static int blob_init(struct osl_table **table,
353                 const struct osl_table_description *desc,
354                 struct table_info *ti)
355 {
356         int ret;
357
358         ti->desc = desc;
359         ret = osl_open_table(ti->desc, &ti->table);
360         if (ret >= 0) {
361                 *table = ti->table;
362                 return ret;
363         }
364         *table = NULL;
365         return ret == -E_NOENT? 1 : ret;
366 }
367
368 /** Define the \p init function for this blob type. */
369 #define DEFINE_BLOB_INIT(table_name) \
370         int table_name ## _init(struct table_info *ti) \
371         { \
372                 return blob_init(&table_name ## _table, \
373                         &table_name ## _table_desc, ti); \
374         }
375
376
377 /** Define all functions for this blob type. */
378 #define DEFINE_BLOB_FUNCTIONS(table_name, cmd_prefix) \
379         DEFINE_BLOB_COMMAND(ls, table_name, cmd_prefix) \
380         DEFINE_BLOB_COMMAND(cat, table_name, cmd_prefix) \
381         DEFINE_BLOB_COMMAND(add, table_name, cmd_prefix) \
382         DEFINE_BLOB_COMMAND(rm, table_name, cmd_prefix) \
383         DEFINE_BLOB_COMMAND(mv, table_name, cmd_prefix) \
384         DEFINE_GET_NAME_BY_ID(table_name, cmd_prefix); \
385         DEFINE_BLOB_SHUTDOWN(table_name); \
386         DEFINE_BLOB_INIT(table_name);
387
388 /** \cond doxygen isn't smart enough to recognize these */
389 DEFINE_BLOB_FUNCTIONS(lyrics, lyr);
390 DEFINE_BLOB_FUNCTIONS(images, img);
391 DEFINE_BLOB_FUNCTIONS(moods, mood);
392 DEFINE_BLOB_FUNCTIONS(playlists, pl);
393 /** \endcond */