Merge branch 'refs/heads/t/si_update'
[paraslash.git] / aft.c
diff --git a/aft.c b/aft.c
index d58f9daf014c0237148db3e0837f11f003bd0230..6c07bcc2a13deb72985f7b87fb98c689c1c38a96 100644 (file)
--- a/aft.c
+++ b/aft.c
@@ -377,6 +377,7 @@ static void save_afhi(struct afh_info *afhi, char *buf)
        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);
@@ -541,10 +542,12 @@ int get_audio_file_path_of_row(const struct osl_row *row, char **path)
        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;
 }
 
 /**
@@ -592,6 +595,10 @@ static int get_hash_of_row(const struct osl_row *row, unsigned char **hash)
  * \param afhi Result pointer.
  *
  * \return The return value of the underlying call to osl_get_object().
+ *
+ * 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)
 {
@@ -984,6 +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);
@@ -1105,6 +1114,12 @@ out:
        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;
@@ -1222,6 +1237,8 @@ static int sort_matching_paths(struct ls_options *options)
                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;
        }
@@ -1370,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);
@@ -1436,6 +1452,8 @@ static int com_ls(struct command_context *cc, struct lls_parse_result *lpr)
                        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;
@@ -2553,6 +2571,16 @@ static int aft_event_handler(enum afs_events event, struct para_buffer *pb,
                        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;
        }