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