From eb3afb241df1e8247dfd2e944032202976e73af8 Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Tue, 7 Apr 2015 21:18:34 +0000 Subject: [PATCH] com_check(): Add attribute checking. 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 | 14 +++++++++++++- afs.cmd | 13 +++++++++---- afs.h | 2 ++ aft.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++ attribute.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 132 insertions(+), 5 deletions(-) diff --git a/afs.c b/afs.c index 67b473a4..c6ecbecf 100644 --- 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 9d87d18c..56a7d952 100644 --- 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 8fd8313a..78bc50ae 100644 --- 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 9f6c4e29..3d5170cc 100644 --- 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. * diff --git a/attribute.c b/attribute.c index 5bb14ed4..f31da53a 100644 --- a/attribute.c +++ b/attribute.c @@ -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. * -- 2.39.2