com_check(): Add attribute checking.
authorAndre Noll <maan@tuebingen.mpg.de>
Tue, 7 Apr 2015 21:18:34 +0000 (21:18 +0000)
committerAndre Noll <maan@tuebingen.mpg.de>
Wed, 12 Aug 2015 21:23:48 +0000 (23:23 +0200)
The afs info stored in the audio file table contains the attribute
bit mask of each audio file. If there is a bit set which does
not correspond to an attribute defined in the attribute table, we
have an inconsistency. This commit adds a check that reports such
inconsistencies.

com_check(), which is part of afs.c, calls the attribute check
callback of attribute.c via the callback mechanism. The callback
computes the logical or of all defined bits and passes this bit mask
to aft_check_attributes() of aft.c to check each audio file against
the mask. Hence two new public functions are required.

afs.c
afs.cmd
afs.h
aft.c
attribute.c

diff --git a/afs.c b/afs.c
index 67b473a..c6ecbec 100644 (file)
--- a/afs.c
+++ b/afs.c
@@ -1108,7 +1108,9 @@ enum com_check_flags {
        /** Check the mood table. */
        CHECK_MOODS = 2,
        /** Check the playlist table. */
-       CHECK_PLAYLISTS = 4
+       CHECK_PLAYLISTS = 4,
+       /** Check the attribute table against the audio file table. */
+       CHECK_ATTS = 8
 };
 
 int com_check(struct command_context *cc)
@@ -1128,6 +1130,10 @@ int com_check(struct command_context *cc)
                        flags |= CHECK_AFT;
                        continue;
                }
+               if (!strcmp(arg, "-A")) {
+                       flags |= CHECK_ATTS;
+                       continue;
+               }
                if (!strcmp(arg, "-p")) {
                        flags |= CHECK_PLAYLISTS;
                        continue;
@@ -1148,6 +1154,12 @@ int com_check(struct command_context *cc)
                if (ret < 0)
                        return ret;
        }
+       if (flags & CHECK_ATTS) {
+               ret = send_callback_request(attribute_check_callback, NULL,
+                       afs_cb_result_handler, cc);
+               if (ret < 0)
+                       return ret;
+       }
        if (flags & CHECK_PLAYLISTS) {
                ret = send_callback_request(playlist_check_callback,
                        NULL, afs_cb_result_handler, cc);
diff --git a/afs.cmd b/afs.cmd
index 9d87d18..56a7d95 100644 (file)
--- a/afs.cmd
+++ b/afs.cmd
@@ -118,9 +118,9 @@ H: Rename attribute old to new.
 N: check
 P: AFS_READ
 D: Run integrity checks against osl tables.
-U: check [-a] [-m] [-p]
-H: Check the audio file table, the mood definitions and all
-H: defined playlists and report any inconsistencies found.
+U: check [-a] [-A] [-m] [-p]
+H: Check the audio file table, the attribute table, the mood definitions
+H: and all defined playlists. Report any inconsistencies.
 H:
 H: Options:
 H:
@@ -129,12 +129,17 @@ H:        table which are not present in the file system. Moreover, it checks
 H:     whether the lyrics id and all entries in the audio file table are
 H:     valid.
 H:
+H: -A  Check the attribute table against the afs attribute bitmask of
+H:     each audio file in the audio file table. Reports audio files
+H:     whose attribute bitmask is invalid, i.e., has a bit set which
+H:     does not correspond to any attribute of the attribute table.
+H:
 H: -m  Run syntax checks on all defined moods in the mood table.
 H:
 H: -p  Check all playlists for lines that correspond to files not contained
 H:     in the audio file table.
 H:
-H: If called without arguments, all three checks are run.
+H: If called without arguments, all checks are run.
 ---
 N: rmatt
 P: AFS_READ | AFS_WRITE
diff --git a/afs.h b/afs.h
index 8fd8313..78bc50a 100644 (file)
--- a/afs.h
+++ b/afs.h
@@ -242,10 +242,12 @@ void attribute_init(struct afs_table *t);
 void get_attribute_bitmap(const uint64_t *atts, char *buf); /* needed by com_ls() */
 int get_attribute_bitnum_by_name(const char *att_name, unsigned char *bitnum);
 int get_attribute_text(uint64_t *atts, const char *delim, char **text);
+int attribute_check_callback(int fd, __a_unused const struct osl_object *query);
 
 /* aft */
 void aft_init(struct afs_table *t);
 int aft_get_row_of_path(const char *path, struct osl_row **row);
+int aft_check_attributes(uint64_t att_mask, struct para_buffer *pb);
 int open_and_update_audio_file(struct audio_file_data *afd);
 int load_afd(int shmid, struct audio_file_data *afd);
 int get_afsi_of_row(const struct osl_row *row, struct afs_info *afsi);
diff --git a/aft.c b/aft.c
index 9f6c4e2..3d5170c 100644 (file)
--- a/aft.c
+++ b/aft.c
@@ -2574,6 +2574,62 @@ int aft_check_callback(int fd, __a_unused const struct osl_object *query)
        return ret;
 }
 
+struct aft_check_atts_data {
+       uint64_t att_mask;
+       struct para_buffer *pb;
+};
+
+static int check_atts_of_audio_file(struct osl_row *row, void *data)
+{
+       struct aft_check_atts_data *acad = data;
+       int ret;
+       struct afs_info afsi;
+       char *path;
+       uint64_t bad_bits;
+
+       ret = get_afsi_of_row(row, &afsi);
+       if (ret < 0) {
+               para_printf(acad->pb, "cannot get afsi\n");
+               return ret;
+       }
+       bad_bits = afsi.attributes & ~acad->att_mask;
+       if (bad_bits == 0) /* OK */
+               return 0;
+       ret = get_audio_file_path_of_row(row, &path);
+       if (ret < 0) {
+               para_printf(acad->pb, "cannot get path\n");
+               return ret;
+       }
+       para_printf(acad->pb, "invalid attribute bits (%" PRIu64 "): %s\n",
+               bad_bits, path);
+       /* return success to keep looping */
+       return 1;
+}
+
+/**
+ * Iterate over all audio files and check the attribute bit mask.
+ *
+ * \param att_mask The mask of all valid attributes.
+ * \param pb Used for reporting inconsistencies.
+ *
+ * This reads the attribute bit mask of each audio file from the afs info
+ * structure stored in the audio file table and verifies that all set bits are
+ * also turned on in \a att_mask, i.e., correspond to an attribute of the
+ * attribute table. Audio files for which this is not the case are reported via
+ * \a pb.
+ *
+ * \return Standard. Inconsistencies are not regarded as errors.
+ *
+ * \sa \ref attribute_check_callback().
+ */
+int aft_check_attributes(uint64_t att_mask, struct para_buffer *pb)
+{
+       struct aft_check_atts_data acad = {.att_mask = att_mask, .pb = pb};
+
+       para_printf(pb, "checking attributes, mask: %" PRIx64 "\n", att_mask);
+       return audio_file_loop(&acad, check_atts_of_audio_file);
+}
+
 /**
  * Close the audio file table.
  *
index 5bb14ed..f31da53 100644 (file)
@@ -476,6 +476,58 @@ err:
        return ret;
 }
 
+static int att_logical_or(struct osl_row *row, void *data)
+{
+       uint64_t *att_mask = data;
+       struct osl_object bitnum_obj;
+       int ret = osl_get_object(attribute_table, row, ATTCOL_BITNUM, &bitnum_obj);
+
+       if (ret < 0)
+               return ret;
+       *att_mask |= 1 << *(unsigned char *)bitnum_obj.data;
+       return 0;
+}
+
+/**
+ * Compute the attribute bit mask and check each afs info bitmap.
+ *
+ * \param fd Needed for the para buffer.
+ * \param query Unused.
+ *
+ * This iterates over all attributes in the attribute table and computes the
+ * logical or of 1 << b where b is the bit number of the attribute. The
+ * resulting bit mask is passed to aft_check_attributes() which performs the
+ * actual check.
+ *
+ * \return Standard.
+ *
+ * \sa \ref aft_check_attributes().
+ */
+int attribute_check_callback(int fd, __a_unused const struct osl_object *query)
+{
+       int ret;
+       uint64_t att_mask = 0; /* bits corresponding to a attributes */
+       struct para_buffer pb = {
+               .max_size = shm_get_shmmax(),
+               .private_data = &(struct afs_max_size_handler_data) {
+                       .fd = fd,
+                       .band = SBD_OUTPUT
+               },
+               .max_size_handler = afs_max_size_handler,
+       };
+
+       ret = osl_rbtree_loop(attribute_table, ATTCOL_BITNUM, &att_mask,
+               att_logical_or);
+       if (ret < 0) {
+               PARA_ERROR_LOG("attribute table loop failed: %s\n",
+                       para_strerror(-ret));
+               return ret;
+       }
+       ret = aft_check_attributes(att_mask, &pb);
+       flush_and_free_pb(&pb);
+       return ret;
+}
+
 /**
  * Close the attribute table.
  *