Fix com_add segfault.
[paraslash.git] / aft.c
diff --git a/aft.c b/aft.c
index e682c203adb8678f0ae4db31060f6cbb3ddbe327..8473bc9b012b275518e056f2631222eaa954b462 100644 (file)
--- a/aft.c
+++ b/aft.c
@@ -6,16 +6,14 @@
 #include "afs.h"
 #include "net.h"
 #include "string.h"
-
-int mp3_get_file_info(char *map, size_t numbytes,
-               struct audio_format_info *afi); /* FXIME */
+#include "vss.h"
 
 #define AFS_AUDIO_FILE_DIR "/home/mp3"
 
-static void *audio_file_table;
+static struct osl_table *audio_file_table;
 
 /**
- * Describes the structure of the mmapped-afs info struct.
+ * Describes the layout of the mmapped-afs info struct.
  *
  * \sa struct afs_info.
  */
@@ -46,19 +44,8 @@ enum afsi_offsets {
  */
 void save_afsi(struct afs_info *afsi, struct osl_object *obj)
 {
-       struct afs_info default_afs_info = {
-               .last_played = time(NULL) - 365 * 24 * 60 * 60,
-               .attributes = 0,
-               .num_played = 0,
-               .image_id = 0,
-               .lyrics_id = 0,
-               .audio_format_id = 5, /* FIXME */
-       };
        char *buf = obj->data;
 
-       if (!afsi)
-               afsi = &default_afs_info;
-
        write_u64(buf + AFSI_LAST_PLAYED_OFFSET, afsi->last_played);
        write_u64(buf + AFSI_ATTRIBUTES_OFFSET, afsi->attributes);
        write_u32(buf + AFSI_NUM_PLAYED_OFFSET, afsi->num_played);
@@ -139,8 +126,7 @@ static struct osl_column_description aft_cols[] = {
        }
 };
 
-static const struct osl_table_description audio_file_table_desc = {
-       .dir = DATABASE_DIR,
+static struct osl_table_description audio_file_table_desc = {
        .name = "audio_files",
        .num_columns = NUM_AFT_COLUMNS,
        .flags = OSL_LARGE_TABLE,
@@ -366,6 +352,8 @@ static int load_chunk_info(struct osl_object *obj, struct audio_format_info *afh
 int aft_get_row_of_path(char *path, struct osl_row **row)
 {
        struct osl_object obj = {.data = path, .size = strlen(path) + 1};
+
+       PARA_NOTICE_LOG("audio_file_table: %p\n", audio_file_table);
        return osl_get_row(audio_file_table, AFTCOL_PATH, &obj, row);
 }
 
@@ -715,7 +703,7 @@ static int print_list_item(struct ls_data *d, struct ls_options *opts,
                        w->image_id_width, afsi->image_id,
                        w->lyrics_id_width, afsi->lyrics_id,
                        w->bitrate_width, afhi->bitrate,
-                       "mp3", /* FIXME */
+                       audio_format_name(afsi->audio_format_id),
                        w->frequency_width, afhi->frequency,
                        afhi->channels,
                        duration_buf,
@@ -756,7 +744,7 @@ static int print_list_item(struct ls_data *d, struct ls_options *opts,
                        image_line,
                        lyrics_line,
                        afhi->bitrate,
-                       "mp3", /* FIXME */
+                       audio_format_name(afsi->audio_format_id),
                        afhi->frequency,
                        afhi->channels,
                        duration_buf,
@@ -993,7 +981,7 @@ static int com_ls_callback(const struct osl_object *query,
                        prepare_ls_row);
        if (ret < 0)
                goto out;
-       ret = opts->num_patterns? -E_NO_MATCH : 1;
+       ret = opts->num_patterns? -E_NO_MATCH : 0;
        if (!opts->num_matching_paths) {
                PARA_NOTICE_LOG("no match, ret: %d\n", ret);
                goto out;
@@ -1016,6 +1004,7 @@ static int com_ls_callback(const struct osl_object *query,
        ret = 1;
 out:
        ls_output->data = b.buf;
+       PARA_NOTICE_LOG("ls_outoute.data: %p\n", ls_output->data);
        ls_output->size = b.size;
        free(opts->data);
        free(opts->data_ptr);
@@ -1030,7 +1019,7 @@ out:
  * full list: list everything, including afsi, afhi, atts as clear text
  *
  * */
-int com_afs_ls(int fd, int argc, const char **argv)
+int com_afs_ls(int fd, int argc, char * const * const argv)
 {
        int i, ret;
        unsigned flags = 0;
@@ -1135,8 +1124,8 @@ int com_afs_ls(int fd, int argc, const char **argv)
        opts.num_patterns = argc - i;
        ret = send_option_arg_callback_request(&query, opts.num_patterns,
                argv + i, com_ls_callback, &ls_output);
-       if (ret >= 0 && ls_output.data) {
-               send_buffer(fd, (char *)ls_output.data);
+       if (ret > 0) {
+               ret = send_buffer(fd, (char *)ls_output.data);
                free(ls_output.data);
        }
        return ret;
@@ -1156,7 +1145,7 @@ int audio_file_loop(void *private_data, osl_rbtree_loop_func *func)
                func);
 }
 
-static void *find_hash_sister(HASH_TYPE *hash)
+static struct osl_row *find_hash_sister(HASH_TYPE *hash)
 {
        const struct osl_object obj = {.data = hash, .size = HASH_SIZE};
        struct osl_row *row;
@@ -1165,21 +1154,20 @@ static void *find_hash_sister(HASH_TYPE *hash)
        return row;
 }
 
-#define AFTROW_HEADER_SIZE 4
-
 enum aft_row_offsets {
        AFTROW_AFHI_OFFSET_POS = 0,
        AFTROW_CHUNKS_OFFSET_POS = 2,
-       AFTROW_HASH_OFFSET = AFTROW_HEADER_SIZE,
-       AFTROW_FLAGS_OFFSET = (AFTROW_HASH_OFFSET + HASH_SIZE),
-       AFTROW_PATH_OFFSET = (AFTROW_FLAGS_OFFSET + 4)
+       AFTROW_AUDIO_FORMAT_OFFSET = 4,
+       AFTROW_FLAGS_OFFSET = 5,
+       AFTROW_HASH_OFFSET = 9,
+       AFTROW_PATH_OFFSET = (AFTROW_HASH_OFFSET + HASH_SIZE),
 };
 
 /* never save the afsi, as the server knows it too. Note that afhi might be NULL.
  * In this case, afhi won't be stored in the buffer  */
 static void save_audio_file_info(HASH_TYPE *hash, const char *path,
-               struct audio_format_info *afhi,
-               uint32_t flags, struct osl_object *obj)
+               struct audio_format_info *afhi, uint32_t flags,
+               uint8_t audio_format_num, struct osl_object *obj)
 {
        size_t path_len = strlen(path) + 1;
        size_t afhi_size = sizeof_afhi_buf(afhi);
@@ -1188,13 +1176,15 @@ static void save_audio_file_info(HASH_TYPE *hash, const char *path,
        char *buf = para_malloc(size);
        uint16_t pos;
 
-       memcpy(buf + AFTROW_HASH_OFFSET, hash, HASH_SIZE);
+       write_u8(buf + AFTROW_AUDIO_FORMAT_OFFSET, audio_format_num);
        write_u32(buf + AFTROW_FLAGS_OFFSET, flags);
+
+       memcpy(buf + AFTROW_HASH_OFFSET, hash, HASH_SIZE);
        strcpy(buf + AFTROW_PATH_OFFSET, path);
 
        pos = AFTROW_PATH_OFFSET + path_len;
        PARA_DEBUG_LOG("size: %zu, afhi starts at %d\n", size, pos);
-       PARA_DEBUG_LOG("last afhi byte: %p, pos %d\n", buf + pos + afhi_size - 1,
+       PARA_DEBUG_LOG("last afhi byte: %p, pos %zu\n", buf + pos + afhi_size - 1,
                pos + afhi_size - 1);
        write_u16(buf + AFTROW_AFHI_OFFSET_POS, pos);
        save_afhi(afhi, buf + pos);
@@ -1254,6 +1244,8 @@ afhi <=> force or no HS
 #define ADD_FLAG_FORCE 2
 #define ADD_FLAG_VERBOSE 4
 
+/* TODO: change log messages so that they get written to the result buffer */
+
 static int com_add_callback(const struct osl_object *query,
                __a_unused struct osl_object *result)
 {
@@ -1266,6 +1258,7 @@ static int com_add_callback(const struct osl_object *query,
        int ret;
        char afsi_buf[AFSI_SIZE];
        uint32_t flags = read_u32(buf + AFTROW_FLAGS_OFFSET);
+       struct afs_info default_afsi = {.last_played = 0};
 
        hash = (HASH_TYPE *)buf + AFTROW_HASH_OFFSET;
        hash_to_asc(hash, asc);;
@@ -1353,11 +1346,14 @@ static int com_add_callback(const struct osl_object *query,
                        return ret;
        }
        /* new entry, use default afsi */
+       default_afsi.last_played = time(NULL) - 365 * 24 * 60 * 60;
+       default_afsi.audio_format_id = read_u8(buf + AFTROW_AUDIO_FORMAT_OFFSET);
+
        if (flags & ADD_FLAG_VERBOSE)
                PARA_NOTICE_LOG("adding %s\n", path);
        objs[AFTCOL_AFSI].data = &afsi_buf;
        objs[AFTCOL_AFSI].size = AFSI_SIZE;
-       save_afsi(NULL, &objs[AFTCOL_AFSI]);
+       save_afsi(&default_afsi, &objs[AFTCOL_AFSI]);
        ret = osl_add_and_get_row(audio_file_table, objs, &aft_row);
        if (ret < 0)
                return ret;
@@ -1369,13 +1365,44 @@ struct private_add_data {
        uint32_t flags;
 };
 
+static int path_brother_callback(const struct osl_object *query,
+               struct osl_object *result)
+{
+       char *path = query->data;
+       struct osl_row *path_brother;
+       int ret = aft_get_row_of_path(path, &path_brother);
+       if (ret < 0)
+               return ret;
+       result->data = para_malloc(sizeof(path_brother));
+       result->size = sizeof(path_brother);
+       *(struct osl_row **)(result->data) = path_brother;
+       return 1;
+}
+
+static int hash_sister_callback(const struct osl_object *query,
+               struct osl_object *result)
+{
+       HASH_TYPE *hash = query->data;
+       struct osl_row *hash_sister;
+
+       hash_sister = find_hash_sister(hash);
+       if (!hash_sister)
+               return -E_RB_KEY_NOT_FOUND;
+       result->data = para_malloc(sizeof(hash_sister));
+       result->size = sizeof(hash_sister);
+       *(struct osl_row **)(result->data) = hash_sister;
+       return 1;
+}
+
+
 static int add_one_audio_file(const char *arg, const void *private_data)
 {
        int ret;
+       uint8_t format_num = -1;
        const struct private_add_data *pad = private_data;
        struct audio_format_info afhi, *afhi_ptr = NULL;
-       struct osl_row *pb, *hs; /* path brother/hash sister */
-       struct osl_object map, obj = {.data = NULL};
+       struct osl_row *pb = NULL, *hs = NULL; /* path brother/hash sister */
+       struct osl_object map, obj = {.data = NULL}, query, result;
        char *path;
        HASH_TYPE hash[HASH_SIZE];
 
@@ -1384,28 +1411,43 @@ static int add_one_audio_file(const char *arg, const void *private_data)
        ret = verify_path(arg, &path);
        if (ret < 0)
                return ret;
-       ret = aft_get_row_of_path(path, &pb);
+       query.data = path;
+       query.size = strlen(path) + 1;
+       ret = send_callback_request(path_brother_callback, &query, &result);
        if (ret < 0 && ret != -E_RB_KEY_NOT_FOUND)
                goto out_free;
+       if (ret >= 0) {
+               pb = *(struct osl_row **)result.data;
+               free(result.data);
+       }
        ret = 1;
        if (pb && (pad->flags & ADD_FLAG_LAZY)) { /* lazy is really cheap */
                if (pad->flags & ADD_FLAG_VERBOSE)
-                       PARA_NOTICE_LOG("lazy-ignore: %s\n", path);
+                       ret = send_va_buffer(pad->fd, "lazy-ignore: %s\n", path);
                goto out_free;
        }
-       /* we still want to add this file. Compute its hash and look it up */
+       /* We still want to add this file. Compute its hash. */
        ret = mmap_full_file(path, O_RDONLY, &map);
        if (ret < 0)
                goto out_free;
        hash_function(map.data, map.size, hash);
-       hs = find_hash_sister(hash);
-       /*
-        * return success if we're pretty sure that we already know this file
-        */
+
+       /* Check whether database contains file with the same hash. */
+       query.data = hash;
+       query.size = HASH_SIZE;
+       ret = send_callback_request(hash_sister_callback, &query, &result);
+       if (ret < 0 && ret != -E_RB_KEY_NOT_FOUND)
+               goto out_free;
+       if (ret >= 0) {
+               hs = *(struct osl_row **)result.data;
+               free(result.data);
+       }
+       /* Return success if we already know this file. */
        ret = 1;
        if (pb && hs && hs == pb && (!(pad->flags & ADD_FLAG_FORCE))) {
                if (pad->flags & ADD_FLAG_VERBOSE)
-                       PARA_NOTICE_LOG("not forcing update: %s\n", path);
+                       ret = send_va_buffer(pad->fd,
+                               "not forcing update: %s\n", path);
                goto out_unmap;
        }
        /*
@@ -1413,36 +1455,38 @@ static int add_one_audio_file(const char *arg, const void *private_data)
         * there is a hash sister unless in FORCE mode.
         */
        if (!hs || (pad->flags & ADD_FLAG_FORCE)) {
-               ret = mp3_get_file_info(map.data, map.size, &afhi);
-               if (ret < 0) {
-                       PARA_WARNING_LOG("audio format of %s not recognized, skipping\n", path);
-                       ret = 1;
+               ret = compute_afhi(path, map.data, map.size, &afhi);
+               if (ret < 0)
                        goto out_unmap;
-               }
+               format_num = ret;
                afhi_ptr = &afhi;
        }
        munmap(map.data, map.size);
-       save_audio_file_info(hash, path, afhi_ptr, pad->flags, &obj);
-       /* ask parent to consider this entry for adding */
+       save_audio_file_info(hash, path, afhi_ptr, pad->flags, format_num, &obj);
+       /* Ask afs to consider this entry for adding. */
        ret = send_callback_request(com_add_callback, &obj, NULL);
        goto out_free;
 
 out_unmap:
        munmap(map.data, map.size);
 out_free:
+       if (ret < 0)
+               send_va_buffer(pad->fd, "failed to add %s (%s)\n", path,
+                       PARA_STRERROR(-ret));
        free(obj.data);
        free(path);
        if (afhi_ptr)
                free(afhi_ptr->chunk_table);
-       return ret;
+       return 1; /* it's not an error if not all files could be added */
 }
 
-int com_add(int fd, int argc, char **argv)
+int com_add(int fd, int argc, char * const * const argv)
 {
        int i, ret;
        struct private_add_data pad = {.fd = fd, .flags = 0};
        struct stat statbuf;
 
+       PARA_NOTICE_LOG("argv[1]: %s\n", argv[1]);
        for (i = 1; i < argc; i++) {
                const char *arg = argv[i];
                if (arg[0] != '-')
@@ -1473,16 +1517,11 @@ int com_add(int fd, int argc, char **argv)
                if (S_ISDIR(statbuf.st_mode)) {
                        ret = for_each_file_in_dir(argv[i],
                                add_one_audio_file, &pad);
-                       if (ret < 0)
-                               return ret;
                        continue;
                }
                ret = add_one_audio_file(argv[i], &pad);
-               if (ret < 0)
-                       goto out;
        }
        ret = 1;
-out:
        return ret;
 
 }
@@ -1540,7 +1579,7 @@ static int com_touch_callback(const struct osl_object *query,
        return 1;
 }
 
-int com_touch(__a_unused int fd, int argc, const char **argv)
+int com_touch(__a_unused int fd, int argc, char * const * const argv)
 {
        struct com_touch_options cto = {
                .num_played = -1,
@@ -1629,7 +1668,7 @@ static int com_rm_callback(const struct osl_object *query,
  *
  * */
 
-int com_afs_rm(__a_unused int fd, int argc, const char **argv)
+int com_afs_rm(__a_unused int fd, int argc,  char * const * const argv)
 {
        struct com_rm_options cro = {.flags = 0};
        struct osl_object options = {.data = &cro, .size = sizeof(cro)};
@@ -1668,16 +1707,18 @@ void aft_shutdown(enum osl_close_flags flags)
 /**
  * Open the audio file table.
  *
- * \param ti Gets initialized by this function
+ * \param ti Gets initialized by this function.
+ * \param db The database directory.
  *
  * \return Positive on success, negative on errors.
  *
  * \sa osl_open_table().
  */
-int aft_init(struct table_info *ti)
+int aft_init(struct table_info *ti, const char *db)
 {
        int ret;
 
+       audio_file_table_desc.dir = db;
        ti->desc = &audio_file_table_desc;
        ret = osl_open_table(ti->desc, &ti->table);
        if (ret >= 0) {
@@ -1687,6 +1728,7 @@ int aft_init(struct table_info *ti)
                PARA_INFO_LOG("audio file table contains %d files\n", num);
                return ret;
        }
+       PARA_INFO_LOG("failed to open audio file table\n");
        audio_file_table = NULL;
        return ret == -E_NOENT? 1 : ret;
 }