From: Andre Noll Date: Mon, 22 Jul 2013 20:10:40 +0000 (+0200) Subject: com_setatt(): Allow to specify a file name pattern. X-Git-Tag: v0.5.0~7^2^2 X-Git-Url: http://git.tue.mpg.de/?a=commitdiff_plain;h=73299ebf;p=paraslash.git com_setatt(): Allow to specify a file name pattern. The help text of the setatt command claims that file name patterns may be specified as arguments. The text also contains an example which involves a wildcard pattern. However, this never worked as advertised since the command actually accepts only full paths. This commit teaches the command to process the given arguments as patterns by employing the same pattern matching loop that is also used by other commands. In addition we now also send a "no matches" message to the client in case there was no match. Previously the command stayed silent and terminated successfully in this case. --- diff --git a/aft.c b/aft.c index 412d19aa..1d2d6d8d 100644 --- a/aft.c +++ b/aft.c @@ -2502,13 +2502,60 @@ int com_cpsi(struct command_context *cc) return ret; } -static void com_setatt_callback(__a_unused int fd, const struct osl_object *query) +struct change_atts_data { + uint64_t add_mask, del_mask; + struct para_buffer pb; +}; + +static int change_atts(__a_unused struct osl_table *table, + struct osl_row *row, __a_unused const char *name, void *data) +{ + int ret; + struct osl_object obj; + struct afs_info old_afsi, new_afsi; + struct afsi_change_event_data aced = { + .aft_row = row, + .old_afsi = &old_afsi + }; + struct change_atts_data *cad = data; + + ret = get_afsi_object_of_row(row, &obj); + if (ret < 0) + return ret; + ret = load_afsi(&old_afsi, &obj); + if (ret < 0) + return ret; + new_afsi = old_afsi; + new_afsi.attributes |= cad->add_mask; + new_afsi.attributes &= ~cad->del_mask; + save_afsi(&new_afsi, &obj); /* in-place update */ + afs_event(AFSI_CHANGE, &cad->pb, &aced); + return 1; +} + +static void com_setatt_callback(int fd, const struct osl_object *query) { char *p; - uint64_t add_mask = 0, del_mask = 0; int ret; size_t len; - struct osl_object obj; + struct change_atts_data cad = { + .pb = { + .max_size = shm_get_shmmax(), + .max_size_handler = afs_max_size_handler, + .private_data = &(struct afs_max_size_handler_data) { + .fd = fd, + .band = SBD_OUTPUT + } + } + }; + struct pattern_match_data pmd = { + .table = audio_file_table, + .loop_col_num = AFTCOL_HASH, + .match_col_num = AFTCOL_PATH, + .pm_flags = PM_SKIP_EMPTY_NAME, + .data = &cad, + .action = change_atts + }; for (p = query->data; p < (char *)query->data + query->size; p += len + 1) { char c; @@ -2516,7 +2563,7 @@ static void com_setatt_callback(__a_unused int fd, const struct osl_object *quer len = strlen(p); ret = -E_ATTR_SYNTAX; - if (!*p) + if (len == 0) goto out; c = p[len - 1]; if (c != '+' && c != '-') @@ -2526,38 +2573,27 @@ static void com_setatt_callback(__a_unused int fd, const struct osl_object *quer if (ret < 0) goto out; if (c == '+') - add_mask |= (1UL << bitnum); + cad.add_mask |= (1UL << bitnum); else - del_mask |= (1UL << bitnum); + cad.del_mask |= (1UL << bitnum); } ret = -E_ATTR_SYNTAX; - if (!add_mask && !del_mask) + if (!cad.add_mask && !cad.del_mask) goto out; - PARA_DEBUG_LOG("masks: %llx:%llx\n",(long long unsigned)add_mask, - (long long unsigned)del_mask); - for (; p < (char *)query->data + query->size; p += len + 1) { /* TODO: fnmatch */ - struct afs_info old_afsi, new_afsi; - struct afsi_change_event_data aced = {.old_afsi = &old_afsi}; - - len = strlen(p); - ret = aft_get_row_of_path(p, &aced.aft_row); - if (ret < 0) - goto out; - ret = get_afsi_object_of_row(aced.aft_row, &obj); - if (ret < 0) - goto out; - ret = load_afsi(&old_afsi, &obj); - if (ret < 0) - goto out; - new_afsi = old_afsi; - new_afsi.attributes |= add_mask; - new_afsi.attributes &= ~del_mask; - save_afsi(&new_afsi, &obj); /* in-place update */ - afs_event(AFSI_CHANGE, NULL, &aced); - } + pmd.patterns.data = p; + assert(p < (char *)query->data + query->size); + pmd.patterns.size = (char *)query->data + query->size - p; + ret = for_each_matching_row(&pmd); + if (ret < 0) + goto out; + if (pmd.num_matches == 0) + para_printf(&cad.pb, "no matches\n"); out: if (ret < 0) - PARA_NOTICE_LOG("%s\n", para_strerror(-ret)); + para_printf(&cad.pb, "%s\n", para_strerror(-ret)); + if (cad.pb.offset) + pass_buffer_as_shm(fd, SBD_OUTPUT, cad.pb.buf, cad.pb.offset); + free(cad.pb.buf); } int com_setatt(struct command_context *cc) @@ -2565,7 +2601,7 @@ int com_setatt(struct command_context *cc) if (cc->argc < 3) return -E_ATTR_SYNTAX; return send_standard_callback_request(cc->argc - 1, cc->argv + 1, - com_setatt_callback, NULL, NULL); + com_setatt_callback, afs_cb_result_handler, cc); } static void afs_stat_callback(int fd, const struct osl_object *query)