/** \file fd.c Helper functions for file descriptor handling. */
+#include <regex.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/mman.h>
#include "para.h"
#include "error.h"
+#include "string.h"
/**
* Write a buffer to a file descriptor, re-write on short writes.
int para_select(int n, fd_set *readfds, fd_set *writefds,
struct timeval *timeout_tv)
{
- int ret, err;
- do {
+ int ret;
+ do
ret = select(n, readfds, writefds, NULL, timeout_tv);
- err = errno;
- } while (ret < 0 && err == EINTR);
+ while (ret < 0 && errno == EINTR);
if (ret < 0)
return -ERRNO_TO_PARA_ERROR(errno);
return ret;
* \param start The start address of the memory mapping.
* \param length The size of the mapping.
*
- * \return Positive on success, \p -E_MUNMAP on errors.
+ * \return Standard.
*
* \sa munmap(2), mmap_full_file().
*/
int write_ok(int fd)
{
- struct timeval tv = {0, 0};
+ struct timeval tv;
fd_set wfds;
- int ret;
-again:
+
FD_ZERO(&wfds);
FD_SET(fd, &wfds);
tv.tv_sec = 0;
tv.tv_usec = 0;
- ret = select(fd + 1, NULL, &wfds, NULL, &tv);
- if (ret < 0 && errno == EINTR)
- goto again;
- return ret;
+ return para_select(fd + 1, NULL, &wfds, &tv);
}
/**
}
}
}
+
+/**
+ * Traverse the given directory recursively.
+ *
+ * \param dirname The directory to traverse.
+ * \param func The function to call for each entry.
+ * \param private_data Pointer to an arbitrary data structure.
+ *
+ * For each regular file under \a dirname, the supplied function \a func is
+ * called. The full path of the regular file and the \a private_data pointer
+ * are passed to \a func. Directories for which the calling process has no
+ * permissions to change to are silently ignored.
+ *
+ * \return Standard.
+ */
+int for_each_file_in_dir(const char *dirname,
+ int (*func)(const char *, void *), void *private_data)
+{
+ DIR *dir;
+ struct dirent *entry;
+ int cwd_fd, ret2, ret = para_opendir(dirname, &dir, &cwd_fd);
+
+ if (ret < 0)
+ return ret == -ERRNO_TO_PARA_ERROR(EACCES)? 1 : ret;
+ /* scan cwd recursively */
+ while ((entry = readdir(dir))) {
+ mode_t m;
+ char *tmp;
+ struct stat s;
+
+ if (!strcmp(entry->d_name, "."))
+ continue;
+ if (!strcmp(entry->d_name, ".."))
+ continue;
+ if (lstat(entry->d_name, &s) == -1)
+ continue;
+ m = s.st_mode;
+ if (!S_ISREG(m) && !S_ISDIR(m))
+ continue;
+ tmp = make_message("%s/%s", dirname, entry->d_name);
+ if (!S_ISDIR(m)) {
+ ret = func(tmp, private_data);
+ free(tmp);
+ if (ret < 0)
+ goto out;
+ continue;
+ }
+ /* directory */
+ ret = for_each_file_in_dir(tmp, func, private_data);
+ free(tmp);
+ if (ret < 0)
+ goto out;
+ }
+ ret = 1;
+out:
+ closedir(dir);
+ ret2 = para_fchdir(cwd_fd);
+ if (ret2 < 0 && ret >= 0)
+ ret = ret2;
+ close(cwd_fd);
+ return ret;
+}
* senders.
*/
+#include <regex.h>
#include <dirent.h>
+#include <osl.h>
#include "para.h"
#include "error.h"
return 1;
}
+ static void set_slice_duration(struct fec_client *fc, struct fec_group *g)
+ {
+ struct timeval group_duration, *chunk_tv = vss_chunk_time();
+
+ tv_scale(g->num_chunks, chunk_tv, &group_duration);
+ tv_divide(fc->fcp->slices_per_group + fc->num_extra_slices,
+ &group_duration, &g->slice_duration);
+ PARA_DEBUG_LOG("durations (group/chunk/slice): %lu/%lu/%lu\n",
+ tv2ms(&group_duration), tv2ms(chunk_tv), tv2ms(&g->slice_duration));
+ }
+
static int setup_next_fec_group(struct fec_client *fc, struct vss_task *vsst)
{
int ret, i, k, data_slices;
g->first_chunk = mmd->current_chunk;
g->num = 0;
} else {
+ /* use duration of the previous group for the timing of this group */
+ set_slice_duration(fc, g);
g->first_chunk += g->num_chunks;
g->num++;
}
g->num_chunks = i - g->first_chunk;
assert(g->num_chunks);
fc->current_slice_num = 0;
+ if (g->num == 0)
+ set_slice_duration(fc, g);
/* setup header slices */
buf = vsst->header_buf;
for (; i < k; i++)
fc->src_data[i] = (const unsigned char *)buf;
}
-
- /* setup group timing */
- tv_scale(g->first_chunk - fc->first_stream_chunk, chunk_tv, &tmp);
- tv_add(&fc->stream_start, &tmp, &g->start);
- tv_scale(g->num_chunks, chunk_tv, &tmp); /* group duration */
- tv_divide(fc->fcp->slices_per_group + fc->num_extra_slices,
- &tmp, &g->slice_duration);
-
- PARA_DEBUG_LOG("FEC group %d: %d chunks (%d - %d), %d header slices, %d data slices\n",
+ PARA_DEBUG_LOG("FEC group %d: %d chunks (%d - %d), "
+ "%d header slices, %d data slices\n",
g->num, g->num_chunks, g->first_chunk,
g->first_chunk + g->num_chunks - 1,
g->num_header_slices, data_slices
);
- PARA_DEBUG_LOG("durations (group/chunk/slice): %lu/%lu/%lu\n",
- tv2ms(&tmp), tv2ms(chunk_tv), tv2ms(&g->slice_duration));
+ /* set group start */
+ tv_scale(g->first_chunk - fc->first_stream_chunk, chunk_tv, &tmp);
+ tv_add(&fc->stream_start, &tmp, &g->start);
return 1;
}
static void set_eof_barrier(struct vss_task *vsst)
{
struct fec_client *fc;
- struct timeval timeout = mmd->afd.afhi.eof_tv,
- *chunk_tv = vss_chunk_time();
+ struct timeval timeout = {1, 0}, *chunk_tv = vss_chunk_time();
if (!chunk_tv)
goto out;
mmd->afd.afhi.chunk_tv.tv_usec = 0;
free(mmd->afd.afhi.chunk_table);
mmd->afd.afhi.chunk_table = NULL;
- free(mmd->afd.afhi.info_string);
- mmd->afd.afhi.info_string = make_message("%s:\n%s:\n%s:\n", status_item_list[SI_AUDIO_FILE_INFO],
- status_item_list[SI_TAGINFO1], status_item_list[SI_TAGINFO2]);
- make_empty_status_items(mmd->afd.verbose_ls_output);
mmd->mtime = 0;
mmd->size = 0;
mmd->events++;
if (passed_fd < 0)
goto err;
shmid = afs_data;
- free(mmd->afd.afhi.info_string);
ret = load_afd(shmid, &mmd->afd);
if (ret < 0)
goto err;
*/
static void vss_send(struct vss_task *vsst)
{
- int i, sent_something = 0;
+ int i, fec_active = 0;
struct timeval due;
struct fec_client *fc, *tmp_fc;
list_for_each_entry_safe(fc, tmp_fc, &fec_client_list, node) {
if (fc->error < 0)
continue;
- if (!next_slice_is_due(fc, NULL))
+ if (!next_slice_is_due(fc, NULL)) {
+ fec_active = 1;
continue;
+ }
if (compute_next_fec_slice(fc, vsst) <= 0)
continue;
PARA_DEBUG_LOG("sending %d:%d (%u bytes)\n", fc->group.num,
fc->fcp->max_slice_bytes,
fc->fcp->private_data);
fc->current_slice_num++;
- sent_something = 1;
+ fec_active = 1;
}
if (mmd->current_chunk >= mmd->afd.afhi.chunks_total) { /* eof */
- if (!sent_something)
+ if (!fec_active)
mmd->new_vss_status_flags |= VSS_NEXT;
return;
}
free(hn);
free(home);
mmd->sender_cmd_data.cmd_num = -1;
- make_empty_status_items(mmd->afd.verbose_ls_output);
if (conf.autoplay_given) {
struct timeval tmp;
mmd->vss_status_flags |= VSS_PLAYING;