From: Andre Noll Date: Sun, 26 Apr 2015 12:11:56 +0000 (+0200) Subject: Merge branch 'refs/heads/t/immediate-si-update' X-Git-Tag: v0.5.5~40 X-Git-Url: http://git.tuebingen.mpg.de/?a=commitdiff_plain;h=1a8e3628040a94a8c06027335962a6cb2f827a63;hp=-c;p=paraslash.git Merge branch 'refs/heads/t/immediate-si-update' Cooking in next for four weeks. * aft: Store resolved paths when adding files. * aft: Update mtime and file size on afhi changes. * aft: Update status items on afs events. * aft.c: Pass struct ls_data pointer to make_status_items(). * afs: Simplify open_next_audio_file(). Conflicts: aft.c --- 1a8e3628040a94a8c06027335962a6cb2f827a63 diff --combined NEWS index c0ba3b28,b29d4b82..22e16ebe --- a/NEWS +++ b/NEWS @@@ -7,10 -7,8 +7,12 @@@ current master branch "magnetic momentu - On Linux systems, local sockets are now created in the abstract name space by default. This allows to get rid of the socket specials in /var/paraslash. + - New autoconf macros to avoid duplication in configure.ac. - ++ - Status items (as shown by para_gui) are updated correctly ++ when the meta information of the current audio changes. Download: ./releases/paraslash-git.tar.bz2 (tarball) ++ ------------------------------------------ 0.5.4 (2015-01-23) "exponential alignment" ------------------------------------------ diff --combined afs.c index b74cb45c,a16252cd..ea0a9f9f --- a/afs.c +++ b/afs.c @@@ -195,7 -195,7 +195,7 @@@ static int dispatch_result(int result_s * copied. It then notifies the afs process that the callback function \a f * should be executed by sending the shared memory identifier (shmid) to the * socket. - + * * If the callback produces a result, it sends any number of shared memory * identifiers back via the socket. For each such identifier received, \a * result_handler is called. The contents of the sma identified by the received @@@ -236,8 -236,8 +236,8 @@@ int send_callback_request(callback_func if (ret < 0) goto out; - *(uint32_t *) buf = afs_socket_cookie; - *(int *) (buf + sizeof(afs_socket_cookie)) = query_shmid; + *(uint32_t *)buf = afs_socket_cookie; + *(int *)(buf + sizeof(afs_socket_cookie)) = query_shmid; ret = connect_local_socket(conf.afs_socket_arg); if (ret < 0) @@@ -455,7 -455,7 +455,7 @@@ static int pass_afd(int fd, char *buf, } /** - * Open the audio file with highest score. + * Pass the fd of the next audio file to the server process. * * This stores all information for streaming the "best" audio file in a shared * memory area. The id of that area and an open file descriptor for the next @@@ -467,27 -467,15 +467,15 @@@ */ static int open_next_audio_file(void) { - struct osl_row *aft_row; struct audio_file_data afd; int ret, shmid; char buf[8]; - long score; - again: - PARA_NOTICE_LOG("getting next audio file\n"); - ret = score_get_best(&aft_row, &score); + + ret = open_and_update_audio_file(&afd); if (ret < 0) { PARA_ERROR_LOG("%s\n", para_strerror(-ret)); goto no_admissible_files; } - ret = open_and_update_audio_file(aft_row, score, &afd); - if (ret < 0) { - ret = score_delete(aft_row); - if (ret < 0) { - PARA_ERROR_LOG("%s\n", para_strerror(-ret)); - goto no_admissible_files; - } - goto again; - } shmid = ret; if (!write_ok(server_socket)) { ret = -E_AFS_SOCKET; @@@ -607,9 -595,8 +595,9 @@@ static void com_select_callback(int fd activate_mood_or_playlist(NULL, &num_admissible); } } else - ret2 = para_printf(&pb, "activated %s (%d admissible files)\n", current_mop? - current_mop : "dummy mood", num_admissible); + ret2 = para_printf(&pb, "activated %s (%d admissible files)\n", + current_mop? current_mop : "dummy mood", + num_admissible); out: if (ret2 >= 0 && pb.offset) pass_buffer_as_shm(fd, SBD_OUTPUT, pb.buf, pb.offset); @@@ -1011,13 -998,7 +999,13 @@@ static void create_tables_callback(int { uint32_t table_mask = *(uint32_t *)query->data; int i, ret; - struct para_buffer pb = {.buf = NULL}; + struct para_buffer pb = { + .max_size = shm_get_shmmax(), + .private_data = &(struct afs_max_size_handler_data) { + .fd = fd, + .band = SBD_OUTPUT + } + }; close_afs_tables(); for (i = 0; i < NUM_AFS_TABLES; i++) { diff --combined aft.c index 826fc28b,fb0d4fd2..acf75156 --- a/aft.c +++ b/aft.c @@@ -293,60 -293,36 +293,36 @@@ static struct osl_table_description aud .column_descriptions = aft_cols }; - /* We don't want dot or dot-dot anywhere. */ - static int verify_dotfile(const char *rest) - { - /* - * The first character was '.', but that has already been discarded, we - * now test the rest. - */ - switch (*rest) { - case '\0': case '/': /* /foo/. and /foo/./bar are not ok */ - return -1; - case '.': /* path start with /foo/.. */ - if (rest[1] == '\0' || rest[1] == '/') - return -1; /* /foo/.. or /foo/../bar are not ok */ - /* /foo/..bar is ok */ - } - return 1; - } - /* - * We fundamentally don't like some paths: We don't want double slashes or - * slashes at the end that can make pathnames ambiguous. + * Produce a canonicalized absolute pathname. + * + * Returns one if the resolved path a directory, zero if it is a regular file, + * negative on errors. */ static int verify_path(const char *orig_path, char **resolved_path) { - char c; - size_t len; - char *path; + int ret; + char *path = NULL; + struct stat statbuf; if (*orig_path != '/') /* we only accept absolute paths */ - return -E_BAD_PATH; - len = strlen(orig_path); - *resolved_path = para_strdup(orig_path); - path = *resolved_path; - while (len > 1 && path[--len] == '/') - path[len] = '\0'; /* remove slash at the end */ - c = *path++; - while (c) { - if (c == '/') { - c = *path++; - switch (c) { - case '/': /* double slash */ - goto bad_path; - case '.': - if (verify_dotfile(path) < 0) - goto bad_path; - default: - continue; - } - } - c = *path++; - } - return 1; - bad_path: - free(*resolved_path); + goto fail; + path = realpath(orig_path, NULL); + if (!path) + goto fail; + if (stat(path, &statbuf) < 0) + goto fail; + if (S_ISREG(statbuf.st_mode)) + ret = 0; + else if (S_ISDIR(statbuf.st_mode)) + ret = 1; + else + goto fail; + *resolved_path = path; + return ret; + fail: + *resolved_path = NULL; + free(path); return -E_BAD_PATH; } @@@ -693,13 -669,16 +669,13 @@@ err int load_afd(int shmid, struct audio_file_data *afd) { void *shm_afd; - char *buf; int ret; ret = shm_attach(shmid, ATTACH_RO, &shm_afd); if (ret < 0) return ret; *afd = *(struct audio_file_data *)shm_afd; - buf = shm_afd; - buf += sizeof(*afd); - load_chunk_table(&afd->afhi, buf); + load_chunk_table(&afd->afhi, shm_afd + sizeof(*afd)); shm_detach(shm_afd); return 1; } @@@ -1037,17 -1016,33 +1013,33 @@@ out return ret; } - static int make_status_items(struct audio_file_data *afd, - struct afs_info *afsi, char *path, long score, - unsigned char *hash) + static struct ls_data status_item_ls_data; + static struct osl_row *current_aft_row; + + static void make_inode_status_items(struct para_buffer *pb) + { + struct stat statbuf = {.st_size = 0}; + char *path, mtime_str[30] = "\0"; + struct tm mtime_tm; + int ret; + + ret = get_audio_file_path_of_row(current_aft_row, &path); + if (ret < 0) + goto out; + ret = stat(path, &statbuf); + if (ret < 0) + goto out; + localtime_r(&statbuf.st_mtime, &mtime_tm); + ret = strftime(mtime_str, 29, "%b %d %Y", &mtime_tm); + assert(ret > 0); /* number of bytes placed in mtime_str */ + out: + /* We don't care too much about errors here */ + (void)WRITE_STATUS_ITEM(pb, SI_MTIME, "%s\n", mtime_str); + (void)WRITE_STATUS_ITEM(pb, SI_FILE_SIZE, "%ld\n", statbuf.st_size / 1024); + } + + static int make_status_items(void) { - struct ls_data d = { - .afhi = afd->afhi, - .afsi = *afsi, - .path = path, - .score = score, - .hash = hash - }; struct ls_options opts = { .flags = LS_FLAG_FULL_PATH | LS_FLAG_ADMISSIBLE_ONLY, .mode = LS_MODE_VERBOSE, @@@ -1057,30 -1052,30 +1049,30 @@@ int ret; time(¤t_time); - ret = print_list_item(&d, &opts, &pb, current_time); + ret = print_list_item(&status_item_ls_data, &opts, &pb, current_time); if (ret < 0) return ret; + make_inode_status_items(&pb); free(status_items); status_items = pb.buf; memset(&pb, 0, sizeof(pb)); pb.max_size = shm_get_shmmax() - 1; pb.flags = PBF_SIZE_PREFIX; - ret = print_list_item(&d, &opts, &pb, current_time); + ret = print_list_item(&status_item_ls_data, &opts, &pb, current_time); if (ret < 0) { free(status_items); status_items = NULL; return ret; } + make_inode_status_items(&pb); free(parser_friendly_status_items); parser_friendly_status_items = pb.buf; return 1; } /** - * Mmap the given audio file and update statistics. + * Open the audio file with highest score and set up an afd structure. * - * \param aft_row Determines the audio file to be opened and updated. - * \param score The score of the audio file. * \param afd Result pointer. * * On success, the numplayed field of the audio file selector info is increased @@@ -1089,66 -1084,75 +1081,75 @@@ * * \return Positive shmid on success, negative on errors. */ - int open_and_update_audio_file(struct osl_row *aft_row, long score, - struct audio_file_data *afd) + int open_and_update_audio_file(struct audio_file_data *afd) { - unsigned char *aft_hash, file_hash[HASH_SIZE]; + unsigned char file_hash[HASH_SIZE]; struct osl_object afsi_obj; - struct afs_info old_afsi, new_afsi; - int ret = get_hash_of_row(aft_row, &aft_hash); + struct afs_info new_afsi; + int ret; struct afsi_change_event_data aced; struct osl_object map, chunk_table_obj; - char *path; - + struct ls_data *d = &status_item_ls_data; + again: + ret = score_get_best(¤t_aft_row, &d->score); if (ret < 0) return ret; - ret = get_audio_file_path_of_row(aft_row, &path); + ret = get_hash_of_row(current_aft_row, &d->hash); if (ret < 0) return ret; - PARA_NOTICE_LOG("%s\n", path); - ret = get_afsi_object_of_row(aft_row, &afsi_obj); + ret = get_audio_file_path_of_row(current_aft_row, &d->path); if (ret < 0) return ret; - ret = load_afsi(&old_afsi, &afsi_obj); + PARA_NOTICE_LOG("%s\n", d->path); + ret = get_afsi_object_of_row(current_aft_row, &afsi_obj); if (ret < 0) return ret; - ret = get_afhi_of_row(aft_row, &afd->afhi); + ret = load_afsi(&d->afsi, &afsi_obj); if (ret < 0) return ret; - afd->afhi.chunk_table = NULL; - ret = osl(osl_open_disk_object(audio_file_table, aft_row, + ret = get_afhi_of_row(current_aft_row, &afd->afhi); + if (ret < 0) + return ret; + d->afhi = afd->afhi; + d->afhi.chunk_table = afd->afhi.chunk_table = NULL; + ret = osl(osl_open_disk_object(audio_file_table, current_aft_row, AFTCOL_CHUNKS, &chunk_table_obj)); if (ret < 0) return ret; - ret = mmap_full_file(path, O_RDONLY, &map.data, &map.size, &afd->fd); + ret = mmap_full_file(d->path, O_RDONLY, &map.data, &map.size, &afd->fd); if (ret < 0) - goto err; + goto out; hash_function(map.data, map.size, file_hash); - ret = hash_compare(file_hash, aft_hash); + ret = hash_compare(file_hash, d->hash); para_munmap(map.data, map.size); if (ret) { ret = -E_HASH_MISMATCH; - goto err; + goto out; } - new_afsi = old_afsi; + new_afsi = d->afsi; new_afsi.num_played++; new_afsi.last_played = time(NULL); save_afsi(&new_afsi, &afsi_obj); /* in-place update */ - afd->audio_format_id = old_afsi.audio_format_id; + afd->audio_format_id = d->afsi.audio_format_id; load_chunk_table(&afd->afhi, chunk_table_obj.data); - ret = make_status_items(afd, &old_afsi, path, score, file_hash); - if (ret < 0) - goto out; - aced.aft_row = aft_row; - aced.old_afsi = &old_afsi; + aced.aft_row = current_aft_row; + aced.old_afsi = &d->afsi; + /* + * No need to update the status items as the AFSI_CHANGE event will + * recreate them. + */ afs_event(AFSI_CHANGE, NULL, &aced); ret = save_afd(afd); -err: +out: free(afd->afhi.chunk_table); osl_close_disk_object(&chunk_table_obj); - if (ret < 0) - PARA_ERROR_LOG("%s: %s\n", path, para_strerror(-ret)); + if (ret < 0) { + PARA_ERROR_LOG("%s: %s\n", d->path, para_strerror(-ret)); + ret = score_delete(current_aft_row); + if (ret >= 0) + goto again; + } return ret; } @@@ -1953,7 -1957,6 +1954,6 @@@ int com_add(struct command_context *cc { int i, ret; struct private_add_data pad = {.cc = cc, .flags = 0}; - struct stat statbuf; for (i = 1; i < cc->argc; i++) { const char *arg = cc->argv[i]; @@@ -1992,20 -1995,10 +1992,10 @@@ return ret; continue; } - ret = stat(path, &statbuf); - if (ret < 0) { - ret = send_sb_va(&cc->scc, SBD_ERROR_LOG, - "failed to stat %s (%s)\n", path, - strerror(errno)); - free(path); - if (ret < 0) - return ret; - continue; - } - if (S_ISDIR(statbuf.st_mode)) + if (ret == 1) /* directory */ ret = for_each_file_in_dir(path, add_one_audio_file, &pad); - else + else /* regular file */ ret = add_one_audio_file(path, &pad); if (ret < 0) { send_sb_va(&cc->scc, SBD_OUTPUT, "%s: %s\n", path, @@@ -2110,10 -2103,7 +2100,10 @@@ static void com_touch_callback(int fd, struct touch_action_data tad = {.cto = query->data, .pb = { .max_size = shm_get_shmmax(), - .private_data = &fd, + .private_data = &(struct afs_max_size_handler_data) { + .fd = fd, + .band = SBD_OUTPUT + }, .max_size_handler = afs_max_size_handler } }; @@@ -2254,10 -2244,7 +2244,10 @@@ static void com_rm_callback(int fd, con struct com_rm_action_data crd = {.flags = *(uint32_t *)query->data, .pb = { .max_size = shm_get_shmmax(), - .private_data = &fd, + .private_data = &(struct afs_max_size_handler_data) { + .fd = fd, + .band = SBD_OUTPUT + }, .max_size_handler = afs_max_size_handler } }; @@@ -2399,10 -2386,7 +2389,10 @@@ static void com_cpsi_callback(int fd, c .flags = *(unsigned *)query->data, .pb = { .max_size = shm_get_shmmax(), - .private_data = &fd, + .private_data = &(struct afs_max_size_handler_data) { + .fd = fd, + .band = SBD_OUTPUT + }, .max_size_handler = afs_max_size_handler } }; @@@ -2773,9 -2757,27 +2763,27 @@@ static int aft_event_handler(enum afs_e if (ret < 0) return ret; return audio_file_loop(data, clear_attribute); - } - default: + } case AFSI_CHANGE: { + struct afsi_change_event_data *aced = data; + uint64_t old_last_played = status_item_ls_data.afsi.last_played; + if (aced->aft_row != current_aft_row) + return 0; + ret = get_afsi_of_row(aced->aft_row, &status_item_ls_data.afsi); + if (ret < 0) + return ret; + status_item_ls_data.afsi.last_played = old_last_played; + make_status_items(); return 1; + } case AFHI_CHANGE: { + if (data != current_aft_row) + return 0; + ret = get_afhi_of_row(data, &status_item_ls_data.afhi); + if (ret < 0) + return ret; + make_status_items(); + return 1; + } default: + return 0; } } diff --combined command.c index cb5cce16,0baad5dc..175b496c --- a/command.c +++ b/command.c @@@ -112,21 -112,15 +112,15 @@@ static char *vss_get_status_flags(unsig static unsigned get_status(struct misc_meta_data *nmmd, int parser_friendly, char **result) { - char mtime[30] = ""; char *status, *flags; /* vss status info */ /* nobody updates our version of "now" */ long offset = (nmmd->offset + 500) / 1000; struct timeval current_time; - struct tm mtime_tm; struct para_buffer b = {.flags = parser_friendly? PBF_SIZE_PREFIX : 0}; /* report real status */ status = vss_status_tohuman(nmmd->vss_status_flags); flags = vss_get_status_flags(nmmd->vss_status_flags); - if (nmmd->size) { /* parent currently has an audio file open */ - localtime_r(&nmmd->mtime, &mtime_tm); - strftime(mtime, 29, "%b %d %Y", &mtime_tm); - } clock_get_realtime(¤t_time); /* * The calls to WRITE_STATUS_ITEM() below never fail because @@@ -134,8 -128,6 +128,6 @@@ * is not smart enough to prove this and complains nevertheless. * Casting the return value to void silences clang. */ - (void)WRITE_STATUS_ITEM(&b, SI_FILE_SIZE, "%zu\n", nmmd->size / 1024); - (void)WRITE_STATUS_ITEM(&b, SI_MTIME, "%s\n", mtime); (void)WRITE_STATUS_ITEM(&b, SI_STATUS, "%s\n", status); (void)WRITE_STATUS_ITEM(&b, SI_STATUS_FLAGS, "%s\n", flags); (void)WRITE_STATUS_ITEM(&b, SI_OFFSET, "%li\n", offset); @@@ -780,7 -772,7 +772,7 @@@ static int com_tasks(struct command_con * check if perms are sufficient to exec a command having perms cmd_perms. * Returns 0 if perms are sufficient, -E_PERM otherwise. */ -static int check_perms(unsigned int perms, struct server_command *cmd_ptr) +static int check_perms(unsigned int perms, const struct server_command *cmd_ptr) { PARA_DEBUG_LOG("checking permissions\n"); return (cmd_ptr->perms & perms) < cmd_ptr->perms ? -E_PERM : 0; diff --combined server.h index baefceee,287614c8..93fd558c --- a/server.h +++ b/server.h @@@ -10,12 -10,12 +10,12 @@@ #define MMD_INFO_SIZE 16384 /** The maximum length of the host component in an URL */ -#define MAX_HOSTLEN 256 +#define MAX_HOSTLEN 256 -/** Holds the arguments for the para_server's sender command. */ -struct sender_command_data{ - /** Greater than 0 indicates that a sender cmd is already queued. */ +/** Arguments for the sender command. */ +struct sender_command_data { + /** Greater than zero indicates that a sender cmd is already queued. */ int cmd_num; /** The number of the sender in question. */ int sender_num; @@@ -52,8 -52,6 +52,6 @@@ struct misc_meta_data { /** The size of the current audio file in bytes. */ size_t size; - /** The last modification time of the current audio file. */ - time_t mtime; /** The "old" status flags -- commands may only read them. */ unsigned int vss_status_flags; /** The new status flags -- commands may set them. */