Merge branch 'refs/heads/t/si_update'
authorAndre Noll <maan@tuebingen.mpg.de>
Sun, 20 Aug 2017 13:54:25 +0000 (15:54 +0200)
committerAndre Noll <maan@tuebingen.mpg.de>
Sun, 20 Aug 2017 13:55:47 +0000 (15:55 +0200)
A single patch which teaches the afs event handler to trigger a status
item update when the image or lyrics table changes. This patch had a
bug which was only noticed after the branch had been merged to next.
Therefore the series contains a fixup commit.

Cooking for almost two months.

* refs/heads/t/si_update:
  server: Avoid NULL pointer dereference in make_status_items().
  Update status items on blob events.

1  2 
NEWS.md
aft.c

diff --combined NEWS.md
+++ b/NEWS.md
@@@ -1,21 -1,5 +1,24 @@@
  NEWS
  ====
 +---------------------
 +current master branch
 +---------------------
 +
 +- New sort order for the ls command: -s=h sorts the ls output by hash
 +  value of the audio file.
 +- autogen.sh now runs the test suite after a successful build.
 +- The contents of overview.pdf have been integrated into the user
 +  manual.
 +- The doxygen source browser has been disabled temporarily. The
 +  API reference is still online, though.
 +- Overhaul of the source code documentation.
 +- The deprecated --full-path option of the ls command has been
 +  removed. It was a no-op since 0.6.0.
 +- The wma decoder has been cleaned up and its bitstream API made
 +  more robust.
++- The image/lyrics ID status items of the current audio file are now
++  updated on changes. This affects para_gui, which used to report the
++  old value until EOF.
  
  -------------------------------
  0.6.0 (2017-04-28) "fuzzy flux"
diff --combined aft.c
--- 1/aft.c
--- 2/aft.c
+++ b/aft.c
@@@ -138,7 -138,7 +138,7 @@@ struct ls_options 
  /**
   * Describes the layout of the mmapped-afs info struct.
   *
 - * \sa struct afs_info.
 + * \sa struct \ref afs_info.
   */
  enum afsi_offsets {
        /** Where .last_played is stored. */
   * \param afsi Pointer to the audio file info to be converted.
   * \param obj Result pointer.
   *
 - * \sa load_afsi().
 + * \sa \ref load_afsi().
   */
  static void save_afsi(struct afs_info *afsi, struct osl_object *obj)
  {
   *
   * \return Standard.
   *
 - * \sa save_afsi().
 + * \sa \ref save_afsi().
   */
  static int load_afsi(struct afs_info *afsi, struct osl_object *obj)
  {
@@@ -365,10 -365,7 +365,10 @@@ static void save_afhi(struct afh_info *
        write_u32(buf + CHUNK_TV_TV_SEC_OFFSET, afhi->chunk_tv.tv_sec);
        write_u32(buf + CHUNK_TV_TV_USEC_OFFSET, afhi->chunk_tv.tv_usec);
        p = buf + AFHI_INFO_STRING_OFFSET;
 -      /* The sprintf's below are OK as our caller made sure that buf is large enough */
 +      /*
 +       * The below sprintf(3) calls are OK because our caller already made
 +       * sure that buf is large enough.
 +       */
        p += sprintf(p, "%s", afhi->techinfo) + 1;
        p += sprintf(p, "%s", afhi->tags.artist) + 1;
        p += sprintf(p, "%s", afhi->tags.title) + 1;
        sprintf(p, "%s", afhi->tags.comment);
  }
  
 +/* does not load the chunk table */
  static void load_afhi(const char *buf, struct afh_info *afhi)
  {
        afhi->seconds_total = read_u32(buf + AFHI_SECONDS_TOTAL_OFFSET);
@@@ -532,7 -528,7 +532,7 @@@ static int get_afsi_of_path(const char 
   * \param row Pointer to a row in the audio file table.
   * \param path Result pointer.
   *
 - * The result is a pointer to mmapped data. The caller must not attempt
 + * The result is a pointer to memory-mapped data. The caller must not attempt
   * to free it.
   *
   * \return Standard.
@@@ -542,12 -538,10 +542,12 @@@ int get_audio_file_path_of_row(const st
        struct osl_object path_obj;
        int ret = osl(osl_get_object(audio_file_table, row, AFTCOL_PATH,
                &path_obj));
 +
        if (ret < 0)
 -              return ret;
 -      *path = path_obj.data;
 -      return 1;
 +              *path = NULL;
 +      else
 +              *path = path_obj.data;
 +      return ret;
  }
  
  /**
   *
   * \return The return value of the underlying call to osl_get_object().
   *
 - * \sa get_hash_of_row().
 + * \sa \ref get_hash_of_row().
   */
  static int get_hash_object_of_aft_row(const struct osl_row *row,
                struct osl_object *obj)
@@@ -596,9 -590,7 +596,9 @@@ static int get_hash_of_row(const struc
   *
   * \return The return value of the underlying call to osl_get_object().
   *
 - * \sa get_chunk_table_of_row().
 + * After the call the members of the afhi structure point to mapped memory
 + * which is owned by the osl table, Hence the caller must not attempt to free
 + * this memory by calling \ref clear_afhi().
   */
  int get_afhi_of_row(const struct osl_row *row, struct afh_info *afhi)
  {
@@@ -702,7 -694,7 +702,7 @@@ static int get_local_time(uint64_t *sec
        /*
         * If the given time is more than six month away from the current time,
         * we print only the year. The additional space character in the format
 -       * string below makes the formated date align nicely with dates that
 +       * string below makes the formatted date align nicely with dates that
         * contain the time (those written by the above strftime() statement).
         */
        if (!strftime(buf, size, "%b %e  %Y", tm))
@@@ -991,6 -983,8 +991,8 @@@ static int make_status_items(void
        time_t current_time;
        int ret;
  
+       if (!status_item_ls_data.path) /* no audio file open */
+               return 0;
        ret = lls_parse(ARRAY_SIZE(argv), argv, cmd, &opts.lpr, NULL);
        assert(ret >= 0);
        time(&current_time);
        return ret;
  }
  
 +static int ls_hash_compare(const void *a, const void *b)
 +{
 +      struct ls_data *d1 = *(struct ls_data **)a, *d2 = *(struct ls_data **)b;
 +      return memcmp(d1->hash, d2->hash, HASH_SIZE);
 +}
 +
  static int ls_audio_format_compare(const void *a, const void *b)
  {
        struct ls_data *d1 = *(struct ls_data **)a, *d2 = *(struct ls_data **)b;
@@@ -1235,8 -1223,6 +1237,8 @@@ static int sort_matching_paths(struct l
                compar = ls_duration_compare; break;
        case LS_SORT_BY_AUDIO_FORMAT:
                compar = ls_audio_format_compare; break;
 +      case LS_SORT_BY_HASH:
 +              compar = ls_hash_compare; break;
        default:
                return -E_BAD_SORT;
        }
@@@ -1385,6 -1371,7 +1387,6 @@@ out
        return ret;
  }
  
 -/* TODO: flags -h (sort by hash) */
  static int com_ls(struct command_context *cc, struct lls_parse_result *lpr)
  {
        const struct lls_command *cmd = SERVER_CMD_CMD_PTR(LS);
                        opts->sorting = LS_SORT_BY_DURATION;
                else if (!strcmp(val, "a") || !strcmp(val, "audio-format"))
                        opts->sorting = LS_SORT_BY_AUDIO_FORMAT;
 +              else if (!strcmp(val, "h") || !strcmp(val, "hash"))
 +                      opts->sorting = LS_SORT_BY_HASH;
                else {
                        ret = -E_AFT_SYNTAX;
                        goto out;
@@@ -1924,7 -1909,11 +1926,7 @@@ out
  }
  EXPORT_SERVER_CMD_HANDLER(add);
  
 -/**
 - * Flags used by the touch command.
 - *
 - * \sa com_touch().
 - */
 +/** Flags used by the touch command. */
  enum touch_flags {
        /** Whether the \p FNM_PATHNAME flag should be passed to fnmatch(). */
        TOUCH_FLAG_FNM_PATHNAME = 1,
@@@ -2410,6 -2399,8 +2412,6 @@@ static int check_audio_file(struct osl_
   * \param aca Only ->pbout is used for diagnostics.
   *
   * \return Standard. Inconsistencies are reported but not regarded as an error.
 - *
 - * \sa com_check().
   */
  int aft_check_callback(struct afs_callback_arg *aca)
  {
@@@ -2478,7 -2469,7 +2480,7 @@@ int aft_check_attributes(uint64_t att_m
   *
   * \param flags Usual flags that are passed to osl_close_table().
   *
 - * \sa osl_close_table().
 + * \sa \ref osl_close_table().
   */
  static void aft_close(void)
  {
   *
   * \return Standard.
   *
 - * \sa osl_open_table().
 + * \sa \ref osl_open_table().
   */
  static int aft_open(const char *dir)
  {
@@@ -2569,6 -2560,16 +2571,16 @@@ static int aft_event_handler(enum afs_e
                        return ret;
                make_status_items();
                return 1;
+       }
+       case BLOB_RENAME:
+       case BLOB_REMOVE:
+       case BLOB_ADD: {
+               /*
+                * These events are rare. We don't bother to check whether the
+                * current status items are affected and simply recreate them
+                * every time.
+                */
+               make_status_items();
        } default:
                return 0;
        }