com_setatt(): Allow to specify a file name pattern.
[paraslash.git] / aft.c
diff --git a/aft.c b/aft.c
index 412d19a..1d2d6d8 100644 (file)
--- 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)