From: Andre Noll Date: Mon, 24 Sep 2007 16:10:36 +0000 (+0200) Subject: blob.c: Implement pattern matching. X-Git-Tag: v0.3.0~361 X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=commitdiff_plain;h=60f9b7e82c73870d0fd3c09b5fe1fb61aa38dfd7 blob.c: Implement pattern matching. Most of the blob functions now take a pattern list as arguments, and the function does the job for all blobs that match any given pattern in the list. The only exceptions are addblob and mvblob where a pattern list does not make sense. --- diff --git a/blob.c b/blob.c index 20151241..0980aad5 100644 --- a/blob.c +++ b/blob.c @@ -1,3 +1,12 @@ +/* + * Copyright (C) 2007 Andre Noll + * + * Licensed under the GPL v2. For licencing details see COPYING. + */ + +/** \file blob.c Macros and functions for blob handling. */ + +#include #include "para.h" #include "error.h" #include "afh.h" @@ -5,8 +14,6 @@ #include "string.h" #include "net.h" -/** \file blob.c Macros and functions for blob handling. */ - static struct osl_column_description blob_cols[] = { [BLOBCOL_ID] = { .storage_type = OSL_MAPPED_STORAGE, @@ -45,72 +52,117 @@ enum blob_ls_flags { BLOB_LS_FLAG_SORT_BY_ID = 4, }; -/** Data passed to \p com_lsbob_callback(). */ -struct com_lsblob_options { - /** Given flags for the ls command. */ +/** Structure passed to the \p print_blob function. */ +struct lsblob_data { uint32_t flags; + struct para_buffer pb; }; -/** Structure passed to the \p print_blob loop function. */ -struct lsblob_loop_data { - struct com_lsblob_options *opts; - struct para_buffer *pb; - struct osl_table *table; -}; - -static int print_blob(struct osl_row *row, void *loop_data) +static int print_blob(struct osl_table *table, struct osl_row *row, const char *name, void *data) { struct osl_object obj; - char *name; uint32_t id; int ret; - struct lsblob_loop_data *lld = loop_data; + struct lsblob_data *lbd = data; - ret = osl_get_object(lld->table, row, BLOBCOL_NAME, &obj); - if (ret < 0) - return ret; - name = obj.data; - if (!*name) /* ignore dummy row */ + if (!(lbd->flags & BLOB_LS_FLAG_LONG)) { + para_printf(&lbd->pb, "%s\n", name); return 1; - ret = osl_get_object(lld->table, row, BLOBCOL_ID, &obj); + } + ret = osl_get_object(table, row, BLOBCOL_ID, &obj); if (ret < 0) return ret; id = *(uint32_t *)obj.data; - if (lld->opts->flags & BLOB_LS_FLAG_LONG) - para_printf(lld->pb, "%u\t%s\n", id, name); - else - para_printf(lld->pb, "%s\n", name); + para_printf(&lbd->pb, "%u\t%s\n", id, name); return 1; } +enum blob_match_loop_flags { + BM_NAME_LOOP = 1, + BM_REVERSE_LOOP = 2 +}; + +struct blob_match_data { + struct osl_table *table; + const char *patterns; + size_t patterns_size; + int fnmatch_flags; + unsigned loop_flags; + void *data; + int (*action)(struct osl_table *table, struct osl_row *row, const char *name, void *data); +}; + +static int action_if_blob_matches(struct osl_row *row, void *data) +{ + struct blob_match_data *bmd = data; + struct osl_object name_obj; + const char *p, *name; + int ret = osl_get_object(bmd->table, row, BLOBCOL_NAME, &name_obj); + + if (ret < 0) { + PARA_ERROR_LOG("%s\n", PARA_STRERROR(-ret)); + return ret; + } + name = (char *)name_obj.data; + if (!*name) /* ignore dummy row */ + return 1; + if (!bmd->patterns_size) /* match everything if no pattern was given */ + return bmd->action(bmd->table, row, name, bmd->data); + for (p = bmd->patterns; p < bmd->patterns + bmd->patterns_size; + p += strlen(p) + 1) { + ret = fnmatch(p, name, bmd->fnmatch_flags); + if (ret == FNM_NOMATCH) + continue; + if (ret) + return -E_FNMATCH; + return bmd->action(bmd->table, row, name, bmd->data); + } + return 1; +} + +static int for_each_matching_blob(struct blob_match_data *bmd) +{ + unsigned col = (bmd->loop_flags & BM_NAME_LOOP)? + BLOBCOL_NAME : BLOBCOL_ID; + + if (bmd->loop_flags & BM_REVERSE_LOOP) + return osl_rbtree_loop_reverse(bmd->table, col, bmd, action_if_blob_matches); + return osl_rbtree_loop(bmd->table, col, bmd, action_if_blob_matches); +} + int com_lsblob_callback(struct osl_table *table, const struct osl_object *query, struct osl_object *ls_output) { - struct para_buffer pb = {.buf = NULL}; - struct lsblob_loop_data lld = {.opts = query->data, .pb = &pb, .table = table}; + struct lsblob_data lbd = {.flags = *(uint32_t *)query}; + struct blob_match_data bmd = { + .table = table, + .patterns = (char *)query->data + sizeof(uint32_t), + .patterns_size = query->size - sizeof(uint32_t), + .data = &lbd, + .action = print_blob + }; int ret; - if (lld.opts->flags & BLOB_LS_FLAG_REVERSE) { - if (lld.opts->flags & BLOB_LS_FLAG_SORT_BY_ID) - ret = osl_rbtree_loop(lld.table, BLOBCOL_ID, &lld, print_blob); - else - ret = osl_rbtree_loop_reverse(lld.table, BLOBCOL_NAME, &lld, print_blob); - } else { - if (lld.opts->flags & BLOB_LS_FLAG_SORT_BY_ID) - ret = osl_rbtree_loop_reverse(lld.table, BLOBCOL_ID, &lld, print_blob); - else - ret = osl_rbtree_loop(lld.table, BLOBCOL_NAME, &lld, print_blob); + if (lbd.flags & BLOB_LS_FLAG_REVERSE) + bmd.loop_flags |= BM_REVERSE_LOOP; + if (!(lbd.flags & BLOB_LS_FLAG_SORT_BY_ID)) + bmd.loop_flags |= BM_NAME_LOOP; + ret = for_each_matching_blob(&bmd); + if (lbd.pb.buf) { + ls_output->data = lbd.pb.buf; + ls_output->size = lbd.pb.size; + return 1; } - ls_output->data = pb.buf; - ls_output->size = pb.size; + if (ret > 0) + ret = 0; return ret; } static int com_lsblob(callback_function *f, int fd, int argc, char * const * const argv) { - struct com_lsblob_options clbo = {.flags = 0}; - struct osl_object query = {.data = &clbo, .size = sizeof(clbo)}, - ls_output; + uint32_t flags = 0; + struct osl_object options = {.data = &flags, .size = sizeof(flags)}, + result; int i, ret; for (i = 1; i < argc; i++) { @@ -122,64 +174,140 @@ static int com_lsblob(callback_function *f, int fd, int argc, char * const * con break; } if (!strcmp(arg, "-l")) { - clbo.flags |= BLOB_LS_FLAG_LONG; + flags |= BLOB_LS_FLAG_LONG; continue; } if (!strcmp(arg, "-i")) { - clbo.flags |= BLOB_LS_FLAG_SORT_BY_ID; + flags |= BLOB_LS_FLAG_SORT_BY_ID; continue; } if (!strcmp(arg, "-r")) { - clbo.flags |= BLOB_LS_FLAG_REVERSE; + flags |= BLOB_LS_FLAG_REVERSE; continue; } } - if (argc > i) - return -E_BLOB_SYNTAX; - ret = send_option_arg_callback_request(&query, argc - i, - argv + i, f, &ls_output); +// if (argc > i) +// return -E_BLOB_SYNTAX; + ret = send_option_arg_callback_request(&options, argc - i, + argv + i, f, &result); if (ret > 0) { - send_buffer(fd, (char *)ls_output.data); - free(ls_output.data); + send_buffer(fd, (char *)result.data); + free(result.data); } return ret; } -static int com_catblob_callback(struct osl_table *table, - const struct osl_object *query, struct osl_object *output) +static int cat_blob(struct osl_table *table, struct osl_row *row, + __a_unused const char *name, void *data) { - struct osl_object obj; int ret; - struct osl_row *row; + struct osl_object *blobs = data; + struct osl_object obj; - ret = osl_get_row(table, BLOBCOL_NAME, query, &row); - if (ret < 0) - return ret; ret = osl_open_disk_object(table, row, BLOBCOL_DEF, &obj); if (ret < 0) return ret; - output->data = para_malloc(obj.size); - output->size = obj.size; - memcpy(output->data, obj.data, obj.size); + if (obj.size) { + blobs->data = para_realloc(blobs->data, blobs->size + obj.size); + memcpy(blobs->data + blobs->size, obj.data, obj.size); + blobs->size += obj.size; + } return osl_close_disk_object(&obj); } +static int com_catblob_callback(struct osl_table *table, + const struct osl_object *query, struct osl_object *result) +{ + int ret; + struct blob_match_data bmd = { + .table = table, + .patterns = (char *)query->data, + .patterns_size = query->size, + .data = result, + .action = cat_blob + }; + result->data = NULL; + ret = for_each_matching_blob(&bmd); + if (result->data) + return 1; + return (ret > 0)? 0 : ret; +} + static int com_catblob(callback_function *f, int fd, int argc, char * const * const argv) { - struct osl_object cat_output = {.data = NULL}; + struct osl_object result; int ret; - if (argc != 2) - return -E_BLOB_SYNTAX; - if (!*argv[1]) /* empty name is reserved of the dummy row */ + if (argc < 2) return -E_BLOB_SYNTAX; - ret = send_standard_callback_request(1, argv + 1, f, &cat_output); - if (ret > 0) - ret = send_bin_buffer(fd, (char *)cat_output.data, cat_output.size); - free(cat_output.data); + ret = send_standard_callback_request(argc - 1, argv + 1, f, &result); + if (ret > 0) { + ret = send_bin_buffer(fd, (char *)result.data, result.size); + free(result.data); + } return ret; +} + +struct rmblob_data { + struct para_buffer pb; + unsigned num_removed; +}; + +static int remove_blob(struct osl_table *table, struct osl_row *row, + const char *name, void *data) +{ + struct rmblob_data *rmbd = data; + int ret = osl_del_row(table, row); + if (ret < 0) { + para_printf(&rmbd->pb, "%s: %s\n", name, PARA_STRERROR(-ret)); + return ret; + } + rmbd->num_removed++; + return 1; /* return success to remove other matching blobs. */ +} +static int com_rmblob_callback(struct osl_table *table, + const struct osl_object *query, + __a_unused struct osl_object *result) +{ + int ret; + struct rmblob_data rmbd = {.num_removed = 0}; + struct blob_match_data bmd = { + .table = table, + .patterns = (char *)query->data, + .patterns_size = query->size, + .data = &rmbd, + .action = remove_blob + }; + result->data = NULL; + ret = for_each_matching_blob(&bmd); + if (ret < 0) + para_printf(&rmbd.pb, "%s\n", PARA_STRERROR(-ret)); + if (!rmbd.num_removed) + para_printf(&rmbd.pb, "no matches, nothing removed\n"); + else + para_printf(&rmbd.pb, "removed %d blobs\n", rmbd.num_removed); + result->data = rmbd.pb.buf; + result->size = rmbd.pb.size; + return 1; +} + +static int com_rmblob(callback_function *f, __a_unused int fd, int argc, + char * const * const argv) +{ + int ret; + struct osl_object result; + + if (argc < 2) + return -E_MOOD_SYNTAX; + ret = send_option_arg_callback_request(NULL, argc - 1, argv + 1, f, + &result); + if (ret > 0) { + send_buffer(fd, (char *)result.data); + free(result.data); + } + return ret; } static int com_addblob_callback(struct osl_table *table, @@ -248,40 +376,6 @@ static int com_addblob(callback_function *f, int fd, int argc, return stdin_command(fd, &arg_obj, f, 10 * 1024 * 1024, NULL); } -static int com_rmblob_callback(struct osl_table *table, - const struct osl_object *query, - __a_unused struct osl_object *result) -{ - char *p = query->data; - size_t len; - int ret; - - for (; p < (char *)query->data + query->size; p += len + 1) { - struct osl_row *row; - struct osl_object obj; - - len = strlen(p); - obj.data = p; - obj.size = len + 1; - ret = osl_get_row(table, BLOBCOL_NAME, &obj, &row); - if (ret < 0) - return ret; - ret = osl_del_row(table, row); - if (ret < 0) - return ret; - } - return 1; -} - -static int com_rmblob(callback_function *f, __a_unused int fd, int argc, - char * const * const argv) -{ - if (argc < 2) - return -E_MOOD_SYNTAX; - return send_option_arg_callback_request(NULL, argc - 1, argv + 1, f, - NULL); -} - static int com_mvblob_callback(struct osl_table *table, const struct osl_object *query, __a_unused struct osl_object *result)