#include "apr_arch_file_io.h"
#include "apr_strings.h"
#include "apr_portable.h"
#include "apr_thread_mutex.h"
#include "apr_arch_inherit.h"
static apr_status_t file_dup(apr_file_t **new_file,
apr_file_t *old_file, apr_pool_t *p,
int which_dup)
{
int rv;
#ifdef HAVE_DUP3
int flags = 0;
#endif
if (which_dup == 2) {
if ((*new_file) == NULL) {
return APR_EINVAL;
}
#ifdef HAVE_DUP3
if (!((*new_file)->flags & (APR_FOPEN_NOCLEANUP|APR_INHERIT)))
flags |= O_CLOEXEC;
rv = dup3(old_file->filedes, (*new_file)->filedes, flags);
#else
rv = dup2(old_file->filedes, (*new_file)->filedes);
if (!((*new_file)->flags & (APR_FOPEN_NOCLEANUP|APR_INHERIT))) {
int flags;
if (rv == -1)
return errno;
if ((flags = fcntl((*new_file)->filedes, F_GETFD)) == -1)
return errno;
flags |= FD_CLOEXEC;
if (fcntl((*new_file)->filedes, F_SETFD, flags) == -1)
return errno;
}
#endif
} else {
rv = dup(old_file->filedes);
}
if (rv == -1)
return errno;
if (which_dup == 1) {
(*new_file) = (apr_file_t *)apr_pcalloc(p, sizeof(apr_file_t));
(*new_file)->pool = p;
(*new_file)->filedes = rv;
}
(*new_file)->fname = apr_pstrdup(p, old_file->fname);
(*new_file)->buffered = old_file->buffered;
#if APR_HAS_THREADS
if ((*new_file)->buffered && !(*new_file)->thlock && old_file->thlock) {
apr_thread_mutex_create(&((*new_file)->thlock),
APR_THREAD_MUTEX_DEFAULT, p);
}
#endif
if ((*new_file)->buffered && !(*new_file)->buffer) {
(*new_file)->buffer = apr_palloc(p, old_file->bufsize);
(*new_file)->bufsize = old_file->bufsize;
}
(*new_file)->blocking = old_file->blocking;
(*new_file)->ungetchar = old_file->ungetchar;
if (which_dup == 2) {
return APR_SUCCESS;
}
(*new_file)->flags = old_file->flags
& ~(APR_INHERIT | APR_FOPEN_NOCLEANUP);
apr_pool_cleanup_register((*new_file)->pool, (void *)(*new_file),
apr_unix_file_cleanup,
apr_unix_child_file_cleanup);
#ifndef WAITIO_USES_POLL
(*new_file)->pollset = NULL;
#endif
return APR_SUCCESS;
}
APR_DECLARE(apr_status_t) apr_file_dup(apr_file_t **new_file,
apr_file_t *old_file, apr_pool_t *p)
{
return file_dup(new_file, old_file, p, 1);
}
APR_DECLARE(apr_status_t) apr_file_dup2(apr_file_t *new_file,
apr_file_t *old_file, apr_pool_t *p)
{
return file_dup(&new_file, old_file, p, 2);
}
APR_DECLARE(apr_status_t) apr_file_setaside(apr_file_t **new_file,
apr_file_t *old_file,
apr_pool_t *p)
{
*new_file = (apr_file_t *)apr_palloc(p, sizeof(apr_file_t));
memcpy(*new_file, old_file, sizeof(apr_file_t));
(*new_file)->pool = p;
if (old_file->buffered) {
(*new_file)->buffer = apr_palloc(p, old_file->bufsize);
(*new_file)->bufsize = old_file->bufsize;
if (old_file->direction == 1) {
memcpy((*new_file)->buffer, old_file->buffer, old_file->bufpos);
}
else {
memcpy((*new_file)->buffer, old_file->buffer, old_file->dataRead);
}
#if APR_HAS_THREADS
if (old_file->thlock) {
apr_thread_mutex_create(&((*new_file)->thlock),
APR_THREAD_MUTEX_DEFAULT, p);
apr_thread_mutex_destroy(old_file->thlock);
}
#endif
}
if (old_file->fname) {
(*new_file)->fname = apr_pstrdup(p, old_file->fname);
}
if (!(old_file->flags & APR_FOPEN_NOCLEANUP)) {
apr_pool_cleanup_register(p, (void *)(*new_file),
apr_unix_file_cleanup,
((*new_file)->flags & APR_INHERIT)
? apr_pool_cleanup_null
: apr_unix_child_file_cleanup);
}
old_file->filedes = -1;
apr_pool_cleanup_kill(old_file->pool, (void *)old_file,
apr_unix_file_cleanup);
#ifndef WAITIO_USES_POLL
(*new_file)->pollset = NULL;
#endif
return APR_SUCCESS;
}