feat:replace boost library with C++11 std library
This commit is contained in:
+60
@@ -0,0 +1,60 @@
|
||||
/* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "apr_arch_file_io.h"
|
||||
#include "apr_pools.h"
|
||||
#include "apr_thread_mutex.h"
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_buffer_set(apr_file_t *file,
|
||||
char * buffer,
|
||||
apr_size_t bufsize)
|
||||
{
|
||||
apr_status_t rv;
|
||||
|
||||
file_lock(file);
|
||||
|
||||
if(file->buffered) {
|
||||
/* Flush the existing buffer */
|
||||
rv = apr_file_flush_locked(file);
|
||||
if (rv != APR_SUCCESS) {
|
||||
file_unlock(file);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
file->buffer = buffer;
|
||||
file->bufsize = bufsize;
|
||||
file->buffered = 1;
|
||||
file->bufpos = 0;
|
||||
file->direction = 0;
|
||||
file->dataRead = 0;
|
||||
|
||||
if (file->bufsize == 0) {
|
||||
/* Setting the buffer size to zero is equivalent to turning
|
||||
* buffering off.
|
||||
*/
|
||||
file->buffered = 0;
|
||||
}
|
||||
|
||||
file_unlock(file);
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_size_t) apr_file_buffer_size_get(apr_file_t *file)
|
||||
{
|
||||
return file->bufsize;
|
||||
}
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
/* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "apr_arch_file_io.h"
|
||||
#include "apr_file_io.h"
|
||||
|
||||
static apr_status_t apr_file_transfer_contents(const char *from_path,
|
||||
const char *to_path,
|
||||
apr_int32_t flags,
|
||||
apr_fileperms_t to_perms,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
apr_file_t *s, *d;
|
||||
apr_status_t status;
|
||||
apr_finfo_t finfo;
|
||||
apr_fileperms_t perms;
|
||||
|
||||
/* Open source file. */
|
||||
status = apr_file_open(&s, from_path, APR_FOPEN_READ, APR_OS_DEFAULT, pool);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
/* Maybe get its permissions. */
|
||||
if (to_perms == APR_FILE_SOURCE_PERMS) {
|
||||
status = apr_file_info_get(&finfo, APR_FINFO_PROT, s);
|
||||
if (status != APR_SUCCESS && status != APR_INCOMPLETE) {
|
||||
apr_file_close(s); /* toss any error */
|
||||
return status;
|
||||
}
|
||||
perms = finfo.protection;
|
||||
apr_file_perms_set(to_path, perms); /* ignore any failure */
|
||||
}
|
||||
else
|
||||
perms = to_perms;
|
||||
|
||||
/* Open dest file. */
|
||||
status = apr_file_open(&d, to_path, flags, perms, pool);
|
||||
if (status) {
|
||||
apr_file_close(s); /* toss any error */
|
||||
return status;
|
||||
}
|
||||
|
||||
#if BUFSIZ > APR_FILE_DEFAULT_BUFSIZE
|
||||
#define COPY_BUFSIZ BUFSIZ
|
||||
#else
|
||||
#define COPY_BUFSIZ APR_FILE_DEFAULT_BUFSIZE
|
||||
#endif
|
||||
|
||||
/* Copy bytes till the cows come home. */
|
||||
while (1) {
|
||||
char buf[COPY_BUFSIZ];
|
||||
apr_size_t bytes_this_time = sizeof(buf);
|
||||
apr_status_t read_err;
|
||||
apr_status_t write_err;
|
||||
|
||||
/* Read 'em. */
|
||||
read_err = apr_file_read(s, buf, &bytes_this_time);
|
||||
if (read_err && !APR_STATUS_IS_EOF(read_err)) {
|
||||
apr_file_close(s); /* toss any error */
|
||||
apr_file_close(d); /* toss any error */
|
||||
return read_err;
|
||||
}
|
||||
|
||||
/* Write 'em. */
|
||||
write_err = apr_file_write_full(d, buf, bytes_this_time, NULL);
|
||||
if (write_err) {
|
||||
apr_file_close(s); /* toss any error */
|
||||
apr_file_close(d); /* toss any error */
|
||||
return write_err;
|
||||
}
|
||||
|
||||
if (read_err && APR_STATUS_IS_EOF(read_err)) {
|
||||
status = apr_file_close(s);
|
||||
if (status) {
|
||||
apr_file_close(d); /* toss any error */
|
||||
return status;
|
||||
}
|
||||
|
||||
/* return the results of this close: an error, or success */
|
||||
return apr_file_close(d);
|
||||
}
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_copy(const char *from_path,
|
||||
const char *to_path,
|
||||
apr_fileperms_t perms,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
return apr_file_transfer_contents(from_path, to_path,
|
||||
(APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_TRUNCATE),
|
||||
perms,
|
||||
pool);
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_append(const char *from_path,
|
||||
const char *to_path,
|
||||
apr_fileperms_t perms,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
return apr_file_transfer_contents(from_path, to_path,
|
||||
(APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_APPEND),
|
||||
perms,
|
||||
pool);
|
||||
}
|
||||
+364
@@ -0,0 +1,364 @@
|
||||
/* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "apr_arch_file_io.h"
|
||||
#include "apr_strings.h"
|
||||
#include "apr_portable.h"
|
||||
#if APR_HAVE_SYS_SYSLIMITS_H
|
||||
#include <sys/syslimits.h>
|
||||
#endif
|
||||
#if APR_HAVE_LIMITS_H
|
||||
#include <limits.h>
|
||||
#endif
|
||||
|
||||
static apr_status_t dir_cleanup(void *thedir)
|
||||
{
|
||||
apr_dir_t *dir = thedir;
|
||||
if (closedir(dir->dirstruct) == 0) {
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
else {
|
||||
return errno;
|
||||
}
|
||||
}
|
||||
|
||||
#define PATH_SEPARATOR '/'
|
||||
|
||||
/* Remove trailing separators that don't affect the meaning of PATH. */
|
||||
static const char *path_canonicalize (const char *path, apr_pool_t *pool)
|
||||
{
|
||||
/* At some point this could eliminate redundant components. For
|
||||
* now, it just makes sure there is no trailing slash. */
|
||||
apr_size_t len = strlen (path);
|
||||
apr_size_t orig_len = len;
|
||||
|
||||
while ((len > 0) && (path[len - 1] == PATH_SEPARATOR))
|
||||
len--;
|
||||
|
||||
if (len != orig_len)
|
||||
return apr_pstrndup (pool, path, len);
|
||||
else
|
||||
return path;
|
||||
}
|
||||
|
||||
/* Remove one component off the end of PATH. */
|
||||
static char *path_remove_last_component (const char *path, apr_pool_t *pool)
|
||||
{
|
||||
const char *newpath = path_canonicalize (path, pool);
|
||||
int i;
|
||||
|
||||
for (i = (strlen(newpath) - 1); i >= 0; i--) {
|
||||
if (path[i] == PATH_SEPARATOR)
|
||||
break;
|
||||
}
|
||||
|
||||
return apr_pstrndup (pool, path, (i < 0) ? 0 : i);
|
||||
}
|
||||
|
||||
apr_status_t apr_dir_open(apr_dir_t **new, const char *dirname,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
/* On some platforms (e.g., Linux+GNU libc), d_name[] in struct
|
||||
* dirent is declared with enough storage for the name. On other
|
||||
* platforms (e.g., Solaris 8 for Intel), d_name is declared as a
|
||||
* one-byte array. Note: gcc evaluates this at compile time.
|
||||
*/
|
||||
apr_size_t dirent_size =
|
||||
sizeof(*(*new)->entry) +
|
||||
(sizeof((*new)->entry->d_name) > 1 ? 0 : 255);
|
||||
DIR *dir = opendir(dirname);
|
||||
|
||||
if (!dir) {
|
||||
return errno;
|
||||
}
|
||||
|
||||
(*new) = (apr_dir_t *)apr_palloc(pool, sizeof(apr_dir_t));
|
||||
|
||||
(*new)->pool = pool;
|
||||
(*new)->dirname = apr_pstrdup(pool, dirname);
|
||||
(*new)->dirstruct = dir;
|
||||
(*new)->entry = apr_pcalloc(pool, dirent_size);
|
||||
|
||||
apr_pool_cleanup_register((*new)->pool, *new, dir_cleanup,
|
||||
apr_pool_cleanup_null);
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
apr_status_t apr_dir_close(apr_dir_t *thedir)
|
||||
{
|
||||
return apr_pool_cleanup_run(thedir->pool, thedir, dir_cleanup);
|
||||
}
|
||||
|
||||
#ifdef DIRENT_TYPE
|
||||
static apr_filetype_e filetype_from_dirent_type(int type)
|
||||
{
|
||||
switch (type) {
|
||||
case DT_REG:
|
||||
return APR_REG;
|
||||
case DT_DIR:
|
||||
return APR_DIR;
|
||||
case DT_LNK:
|
||||
return APR_LNK;
|
||||
case DT_CHR:
|
||||
return APR_CHR;
|
||||
case DT_BLK:
|
||||
return APR_BLK;
|
||||
#if defined(DT_FIFO)
|
||||
case DT_FIFO:
|
||||
return APR_PIPE;
|
||||
#endif
|
||||
#if !defined(BEOS) && defined(DT_SOCK)
|
||||
case DT_SOCK:
|
||||
return APR_SOCK;
|
||||
#endif
|
||||
default:
|
||||
return APR_UNKFILE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
apr_status_t apr_dir_read(apr_finfo_t *finfo, apr_int32_t wanted,
|
||||
apr_dir_t *thedir)
|
||||
{
|
||||
apr_status_t ret = 0;
|
||||
#ifdef DIRENT_TYPE
|
||||
apr_filetype_e type;
|
||||
#endif
|
||||
#if APR_HAS_THREADS && defined(_POSIX_THREAD_SAFE_FUNCTIONS) \
|
||||
&& !defined(READDIR_IS_THREAD_SAFE)
|
||||
#ifdef APR_USE_READDIR64_R
|
||||
struct dirent64 *retent;
|
||||
|
||||
/* If LFS is enabled and readdir64_r is available, readdir64_r is
|
||||
* used in preference to readdir_r. This allows directories to be
|
||||
* read which contain a (64-bit) inode number which doesn't fit
|
||||
* into the 32-bit apr_ino_t, iff the caller doesn't actually care
|
||||
* about the inode number (i.e. wanted & APR_FINFO_INODE == 0).
|
||||
* (such inodes may be seen in some wonky NFS environments)
|
||||
*
|
||||
* Similarly, if the d_off field cannot be reprented in a 32-bit
|
||||
* offset, the libc readdir_r() would barf; using readdir64_r
|
||||
* bypasses that case entirely since APR does not care about
|
||||
* d_off. */
|
||||
|
||||
ret = readdir64_r(thedir->dirstruct, thedir->entry, &retent);
|
||||
#else
|
||||
|
||||
struct dirent *retent;
|
||||
|
||||
ret = readdir_r(thedir->dirstruct, thedir->entry, &retent);
|
||||
#endif
|
||||
|
||||
/* POSIX treats "end of directory" as a non-error case, so ret
|
||||
* will be zero and retent will be set to NULL in that case. */
|
||||
if (!ret && retent == NULL) {
|
||||
ret = APR_ENOENT;
|
||||
}
|
||||
|
||||
/* Solaris is a bit strange, if there are no more entries in the
|
||||
* directory, it returns EINVAL. Since this is against POSIX, we
|
||||
* hack around the problem here. EINVAL is possible from other
|
||||
* readdir implementations, but only if the result buffer is too small.
|
||||
* since we control the size of that buffer, we should never have
|
||||
* that problem.
|
||||
*/
|
||||
if (ret == EINVAL) {
|
||||
ret = APR_ENOENT;
|
||||
}
|
||||
#else
|
||||
/* We're about to call a non-thread-safe readdir() that may
|
||||
possibly set `errno', and the logic below actually cares about
|
||||
errno after the call. Therefore we need to clear errno first. */
|
||||
errno = 0;
|
||||
thedir->entry = readdir(thedir->dirstruct);
|
||||
if (thedir->entry == NULL) {
|
||||
/* If NULL was returned, this can NEVER be a success. Can it?! */
|
||||
if (errno == APR_SUCCESS) {
|
||||
ret = APR_ENOENT;
|
||||
}
|
||||
else
|
||||
ret = errno;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* No valid bit flag to test here - do we want one? */
|
||||
finfo->fname = NULL;
|
||||
|
||||
if (ret) {
|
||||
finfo->valid = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef DIRENT_TYPE
|
||||
type = filetype_from_dirent_type(thedir->entry->DIRENT_TYPE);
|
||||
if (type != APR_UNKFILE) {
|
||||
wanted &= ~APR_FINFO_TYPE;
|
||||
}
|
||||
#endif
|
||||
#ifdef DIRENT_INODE
|
||||
if (thedir->entry->DIRENT_INODE && thedir->entry->DIRENT_INODE != -1) {
|
||||
#ifdef APR_USE_READDIR64_R
|
||||
/* If readdir64_r is used, check for the overflow case of trying
|
||||
* to fit a 64-bit integer into a 32-bit integer. */
|
||||
if (sizeof(apr_ino_t) >= sizeof(retent->DIRENT_INODE)
|
||||
|| (apr_ino_t)retent->DIRENT_INODE == retent->DIRENT_INODE) {
|
||||
wanted &= ~APR_FINFO_INODE;
|
||||
} else {
|
||||
/* Prevent the fallback code below from filling in the
|
||||
* inode if the stat call fails. */
|
||||
retent->DIRENT_INODE = 0;
|
||||
}
|
||||
#else
|
||||
wanted &= ~APR_FINFO_INODE;
|
||||
#endif /* APR_USE_READDIR64_R */
|
||||
}
|
||||
#endif /* DIRENT_INODE */
|
||||
|
||||
wanted &= ~APR_FINFO_NAME;
|
||||
|
||||
if (wanted)
|
||||
{
|
||||
char fspec[APR_PATH_MAX];
|
||||
char *end;
|
||||
|
||||
end = apr_cpystrn(fspec, thedir->dirname, sizeof fspec);
|
||||
|
||||
if (end > fspec && end[-1] != '/' && (end < fspec + APR_PATH_MAX))
|
||||
*end++ = '/';
|
||||
|
||||
apr_cpystrn(end, thedir->entry->d_name,
|
||||
sizeof fspec - (end - fspec));
|
||||
|
||||
ret = apr_stat(finfo, fspec, APR_FINFO_LINK | wanted, thedir->pool);
|
||||
/* We passed a stack name that will disappear */
|
||||
finfo->fname = NULL;
|
||||
}
|
||||
|
||||
if (wanted && (ret == APR_SUCCESS || ret == APR_INCOMPLETE)) {
|
||||
wanted &= ~finfo->valid;
|
||||
}
|
||||
else {
|
||||
/* We don't bail because we fail to stat, when we are only -required-
|
||||
* to readdir... but the result will be APR_INCOMPLETE
|
||||
*/
|
||||
finfo->pool = thedir->pool;
|
||||
finfo->valid = 0;
|
||||
#ifdef DIRENT_TYPE
|
||||
if (type != APR_UNKFILE) {
|
||||
finfo->filetype = type;
|
||||
finfo->valid |= APR_FINFO_TYPE;
|
||||
}
|
||||
#endif
|
||||
#ifdef DIRENT_INODE
|
||||
if (thedir->entry->DIRENT_INODE && thedir->entry->DIRENT_INODE != -1) {
|
||||
finfo->inode = thedir->entry->DIRENT_INODE;
|
||||
finfo->valid |= APR_FINFO_INODE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
finfo->name = apr_pstrdup(thedir->pool, thedir->entry->d_name);
|
||||
finfo->valid |= APR_FINFO_NAME;
|
||||
|
||||
if (wanted)
|
||||
return APR_INCOMPLETE;
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
apr_status_t apr_dir_rewind(apr_dir_t *thedir)
|
||||
{
|
||||
rewinddir(thedir->dirstruct);
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
apr_status_t apr_dir_make(const char *path, apr_fileperms_t perm,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
mode_t mode = apr_unix_perms2mode(perm);
|
||||
|
||||
if (mkdir(path, mode) == 0) {
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
else {
|
||||
return errno;
|
||||
}
|
||||
}
|
||||
|
||||
apr_status_t apr_dir_make_recursive(const char *path, apr_fileperms_t perm,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
apr_status_t apr_err = 0;
|
||||
|
||||
apr_err = apr_dir_make (path, perm, pool); /* Try to make PATH right out */
|
||||
|
||||
if (apr_err == ENOENT) { /* Missing an intermediate dir */
|
||||
char *dir;
|
||||
|
||||
dir = path_remove_last_component(path, pool);
|
||||
/* If there is no path left, give up. */
|
||||
if (dir[0] == '\0') {
|
||||
return apr_err;
|
||||
}
|
||||
|
||||
apr_err = apr_dir_make_recursive(dir, perm, pool);
|
||||
|
||||
if (!apr_err)
|
||||
apr_err = apr_dir_make (path, perm, pool);
|
||||
}
|
||||
|
||||
/*
|
||||
* It's OK if PATH exists. Timing issues can lead to the second
|
||||
* apr_dir_make being called on existing dir, therefore this check
|
||||
* has to come last.
|
||||
*/
|
||||
if (APR_STATUS_IS_EEXIST(apr_err))
|
||||
return APR_SUCCESS;
|
||||
|
||||
return apr_err;
|
||||
}
|
||||
|
||||
apr_status_t apr_dir_remove(const char *path, apr_pool_t *pool)
|
||||
{
|
||||
if (rmdir(path) == 0) {
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
else {
|
||||
return errno;
|
||||
}
|
||||
}
|
||||
|
||||
apr_status_t apr_os_dir_get(apr_os_dir_t **thedir, apr_dir_t *dir)
|
||||
{
|
||||
if (dir == NULL) {
|
||||
return APR_ENODIR;
|
||||
}
|
||||
*thedir = dir->dirstruct;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
apr_status_t apr_os_dir_put(apr_dir_t **dir, apr_os_dir_t *thedir,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
if ((*dir) == NULL) {
|
||||
(*dir) = (apr_dir_t *)apr_pcalloc(pool, sizeof(apr_dir_t));
|
||||
(*dir)->pool = pool;
|
||||
}
|
||||
(*dir)->dirstruct = thedir;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
/* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "apr_strings.h"
|
||||
#include "apr_arch_file_io.h"
|
||||
|
||||
/* A file to put ALL of the accessor functions for apr_file_t types. */
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_name_get(const char **fname,
|
||||
apr_file_t *thefile)
|
||||
{
|
||||
*fname = thefile->fname;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_int32_t) apr_file_flags_get(apr_file_t *f)
|
||||
{
|
||||
return f->flags;
|
||||
}
|
||||
|
||||
#if !defined(OS2) && !defined(WIN32)
|
||||
mode_t apr_unix_perms2mode(apr_fileperms_t perms)
|
||||
{
|
||||
mode_t mode = 0;
|
||||
|
||||
if (perms & APR_USETID)
|
||||
mode |= S_ISUID;
|
||||
if (perms & APR_UREAD)
|
||||
mode |= S_IRUSR;
|
||||
if (perms & APR_UWRITE)
|
||||
mode |= S_IWUSR;
|
||||
if (perms & APR_UEXECUTE)
|
||||
mode |= S_IXUSR;
|
||||
|
||||
if (perms & APR_GSETID)
|
||||
mode |= S_ISGID;
|
||||
if (perms & APR_GREAD)
|
||||
mode |= S_IRGRP;
|
||||
if (perms & APR_GWRITE)
|
||||
mode |= S_IWGRP;
|
||||
if (perms & APR_GEXECUTE)
|
||||
mode |= S_IXGRP;
|
||||
|
||||
#ifdef S_ISVTX
|
||||
if (perms & APR_WSTICKY)
|
||||
mode |= S_ISVTX;
|
||||
#endif
|
||||
if (perms & APR_WREAD)
|
||||
mode |= S_IROTH;
|
||||
if (perms & APR_WWRITE)
|
||||
mode |= S_IWOTH;
|
||||
if (perms & APR_WEXECUTE)
|
||||
mode |= S_IXOTH;
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
apr_fileperms_t apr_unix_mode2perms(mode_t mode)
|
||||
{
|
||||
apr_fileperms_t perms = 0;
|
||||
|
||||
if (mode & S_ISUID)
|
||||
perms |= APR_USETID;
|
||||
if (mode & S_IRUSR)
|
||||
perms |= APR_UREAD;
|
||||
if (mode & S_IWUSR)
|
||||
perms |= APR_UWRITE;
|
||||
if (mode & S_IXUSR)
|
||||
perms |= APR_UEXECUTE;
|
||||
|
||||
if (mode & S_ISGID)
|
||||
perms |= APR_GSETID;
|
||||
if (mode & S_IRGRP)
|
||||
perms |= APR_GREAD;
|
||||
if (mode & S_IWGRP)
|
||||
perms |= APR_GWRITE;
|
||||
if (mode & S_IXGRP)
|
||||
perms |= APR_GEXECUTE;
|
||||
|
||||
#ifdef S_ISVTX
|
||||
if (mode & S_ISVTX)
|
||||
perms |= APR_WSTICKY;
|
||||
#endif
|
||||
if (mode & S_IROTH)
|
||||
perms |= APR_WREAD;
|
||||
if (mode & S_IWOTH)
|
||||
perms |= APR_WWRITE;
|
||||
if (mode & S_IXOTH)
|
||||
perms |= APR_WEXECUTE;
|
||||
|
||||
return perms;
|
||||
}
|
||||
#endif
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_data_get(void **data, const char *key,
|
||||
apr_file_t *file)
|
||||
{
|
||||
return apr_pool_userdata_get(data, key, file->pool);
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_data_set(apr_file_t *file, void *data,
|
||||
const char *key,
|
||||
apr_status_t (*cleanup)(void *))
|
||||
{
|
||||
return apr_pool_userdata_set(data, key, cleanup, file->pool);
|
||||
}
|
||||
+181
@@ -0,0 +1,181 @@
|
||||
/* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#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) {
|
||||
/* We can't dup2 unless we have a valid new_file */
|
||||
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 the existing socket in a dup2 is already buffered, we
|
||||
* have an existing and valid (hopefully) mutex, so we don't
|
||||
* want to create it again as we could leak!
|
||||
*/
|
||||
#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
|
||||
/* As above, only create the buffer if we haven't already
|
||||
* got one.
|
||||
*/
|
||||
if ((*new_file)->buffered && !(*new_file)->buffer) {
|
||||
(*new_file)->buffer = apr_palloc(p, old_file->bufsize);
|
||||
(*new_file)->bufsize = old_file->bufsize;
|
||||
}
|
||||
|
||||
/* this is the way dup() works */
|
||||
(*new_file)->blocking = old_file->blocking;
|
||||
|
||||
/* make sure unget behavior is consistent */
|
||||
(*new_file)->ungetchar = old_file->ungetchar;
|
||||
|
||||
/* apr_file_dup2() retains the original cleanup, reflecting
|
||||
* the existing inherit and nocleanup flags. This means,
|
||||
* that apr_file_dup2() cannot be called against an apr_file_t
|
||||
* already closed with apr_file_close, because the expected
|
||||
* cleanup was already killed.
|
||||
*/
|
||||
if (which_dup == 2) {
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
/* apr_file_dup() retains all old_file flags with the exceptions
|
||||
* of APR_INHERIT and APR_FOPEN_NOCLEANUP.
|
||||
* The user must call apr_file_inherit_set() on the dupped
|
||||
* apr_file_t when desired.
|
||||
*/
|
||||
(*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
|
||||
/* Start out with no pollset. apr_wait_for_io_or_timeout() will
|
||||
* initialize the pollset if needed.
|
||||
*/
|
||||
(*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_pmemdup(p, 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 /* APR_HAS_THREADS */
|
||||
}
|
||||
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;
|
||||
}
|
||||
+314
@@ -0,0 +1,314 @@
|
||||
/* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "apr.h"
|
||||
#include "apr_private.h"
|
||||
#include "apr_arch_file_io.h"
|
||||
#include "apr_file_io.h"
|
||||
#include "apr_strings.h"
|
||||
#define APR_WANT_STRFUNC
|
||||
#include "apr_want.h"
|
||||
#if APR_HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
/* Win32 malpropism that can go away once everyone believes this
|
||||
* code is golden, and I'm not testing it anymore :-)
|
||||
*/
|
||||
#if APR_HAVE_DIRENT_H
|
||||
#include <dirent.h>
|
||||
#endif
|
||||
|
||||
/* Any OS that requires/refuses trailing slashes should be dealt with here.
|
||||
*/
|
||||
APR_DECLARE(apr_status_t) apr_filepath_get(char **defpath, apr_int32_t flags,
|
||||
apr_pool_t *p)
|
||||
{
|
||||
char path[APR_PATH_MAX];
|
||||
|
||||
if (!getcwd(path, sizeof(path))) {
|
||||
if (errno == ERANGE)
|
||||
return APR_ENAMETOOLONG;
|
||||
else
|
||||
return errno;
|
||||
}
|
||||
*defpath = apr_pstrdup(p, path);
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* Any OS that requires/refuses trailing slashes should be dealt with here
|
||||
*/
|
||||
APR_DECLARE(apr_status_t) apr_filepath_set(const char *path, apr_pool_t *p)
|
||||
{
|
||||
if (chdir(path) != 0)
|
||||
return errno;
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_filepath_root(const char **rootpath,
|
||||
const char **inpath,
|
||||
apr_int32_t flags,
|
||||
apr_pool_t *p)
|
||||
{
|
||||
if (**inpath == '/') {
|
||||
*rootpath = apr_pstrdup(p, "/");
|
||||
do {
|
||||
++(*inpath);
|
||||
} while (**inpath == '/');
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
return APR_ERELATIVE;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_filepath_merge(char **newpath,
|
||||
const char *rootpath,
|
||||
const char *addpath,
|
||||
apr_int32_t flags,
|
||||
apr_pool_t *p)
|
||||
{
|
||||
char *path;
|
||||
apr_size_t rootlen; /* is the length of the src rootpath */
|
||||
apr_size_t maxlen; /* maximum total path length */
|
||||
apr_size_t keptlen; /* is the length of the retained rootpath */
|
||||
apr_size_t pathlen; /* is the length of the result path */
|
||||
apr_size_t seglen; /* is the end of the current segment */
|
||||
apr_status_t rv;
|
||||
|
||||
/* Treat null as an empty path.
|
||||
*/
|
||||
if (!addpath)
|
||||
addpath = "";
|
||||
|
||||
if (addpath[0] == '/') {
|
||||
/* If addpath is rooted, then rootpath is unused.
|
||||
* Ths violates any APR_FILEPATH_SECUREROOTTEST and
|
||||
* APR_FILEPATH_NOTABSOLUTE flags specified.
|
||||
*/
|
||||
if (flags & APR_FILEPATH_SECUREROOTTEST)
|
||||
return APR_EABOVEROOT;
|
||||
if (flags & APR_FILEPATH_NOTABSOLUTE)
|
||||
return APR_EABSOLUTE;
|
||||
|
||||
/* If APR_FILEPATH_NOTABOVEROOT wasn't specified,
|
||||
* we won't test the root again, it's ignored.
|
||||
* Waste no CPU retrieving the working path.
|
||||
*/
|
||||
if (!rootpath && !(flags & APR_FILEPATH_NOTABOVEROOT))
|
||||
rootpath = "";
|
||||
}
|
||||
else {
|
||||
/* If APR_FILEPATH_NOTABSOLUTE is specified, the caller
|
||||
* requires a relative result. If the rootpath is
|
||||
* ommitted, we do not retrieve the working path,
|
||||
* if rootpath was supplied as absolute then fail.
|
||||
*/
|
||||
if (flags & APR_FILEPATH_NOTABSOLUTE) {
|
||||
if (!rootpath)
|
||||
rootpath = "";
|
||||
else if (rootpath[0] == '/')
|
||||
return APR_EABSOLUTE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!rootpath) {
|
||||
/* Start with the current working path. This is bass akwards,
|
||||
* but required since the compiler (at least vc) doesn't like
|
||||
* passing the address of a char const* for a char** arg.
|
||||
*/
|
||||
char *getpath;
|
||||
rv = apr_filepath_get(&getpath, flags, p);
|
||||
rootpath = getpath;
|
||||
if (rv != APR_SUCCESS)
|
||||
return errno;
|
||||
|
||||
/* XXX: Any kernel subject to goofy, uncanonical results
|
||||
* must run the rootpath against the user's given flags.
|
||||
* Simplest would be a recursive call to apr_filepath_merge
|
||||
* with an empty (not null) rootpath and addpath of the cwd.
|
||||
*/
|
||||
}
|
||||
|
||||
rootlen = strlen(rootpath);
|
||||
maxlen = rootlen + strlen(addpath) + 4; /* 4 for slashes at start, after
|
||||
* root, and at end, plus trailing
|
||||
* null */
|
||||
if (maxlen > APR_PATH_MAX) {
|
||||
return APR_ENAMETOOLONG;
|
||||
}
|
||||
path = (char *)apr_palloc(p, maxlen);
|
||||
|
||||
if (addpath[0] == '/') {
|
||||
/* Ignore the given root path, strip off leading
|
||||
* '/'s to a single leading '/' from the addpath,
|
||||
* and leave addpath at the first non-'/' character.
|
||||
*/
|
||||
keptlen = 0;
|
||||
while (addpath[0] == '/')
|
||||
++addpath;
|
||||
path[0] = '/';
|
||||
pathlen = 1;
|
||||
}
|
||||
else {
|
||||
/* If both paths are relative, fail early
|
||||
*/
|
||||
if (rootpath[0] != '/' && (flags & APR_FILEPATH_NOTRELATIVE))
|
||||
return APR_ERELATIVE;
|
||||
|
||||
/* Base the result path on the rootpath
|
||||
*/
|
||||
keptlen = rootlen;
|
||||
memcpy(path, rootpath, rootlen);
|
||||
|
||||
/* Always '/' terminate the given root path
|
||||
*/
|
||||
if (keptlen && path[keptlen - 1] != '/') {
|
||||
path[keptlen++] = '/';
|
||||
}
|
||||
pathlen = keptlen;
|
||||
}
|
||||
|
||||
while (*addpath) {
|
||||
/* Parse each segment, find the closing '/'
|
||||
*/
|
||||
const char *next = addpath;
|
||||
while (*next && (*next != '/')) {
|
||||
++next;
|
||||
}
|
||||
seglen = next - addpath;
|
||||
|
||||
if (seglen == 0 || (seglen == 1 && addpath[0] == '.')) {
|
||||
/* noop segment (/ or ./) so skip it
|
||||
*/
|
||||
}
|
||||
else if (seglen == 2 && addpath[0] == '.' && addpath[1] == '.') {
|
||||
/* backpath (../) */
|
||||
if (pathlen == 1 && path[0] == '/') {
|
||||
/* Attempt to move above root. Always die if the
|
||||
* APR_FILEPATH_SECUREROOTTEST flag is specified.
|
||||
*/
|
||||
if (flags & APR_FILEPATH_SECUREROOTTEST) {
|
||||
return APR_EABOVEROOT;
|
||||
}
|
||||
|
||||
/* Otherwise this is simply a noop, above root is root.
|
||||
* Flag that rootpath was entirely replaced.
|
||||
*/
|
||||
keptlen = 0;
|
||||
}
|
||||
else if (pathlen == 0
|
||||
|| (pathlen == 3
|
||||
&& !memcmp(path + pathlen - 3, "../", 3))
|
||||
|| (pathlen > 3
|
||||
&& !memcmp(path + pathlen - 4, "/../", 4))) {
|
||||
/* Path is already backpathed or empty, if the
|
||||
* APR_FILEPATH_SECUREROOTTEST.was given die now.
|
||||
*/
|
||||
if (flags & APR_FILEPATH_SECUREROOTTEST) {
|
||||
return APR_EABOVEROOT;
|
||||
}
|
||||
|
||||
/* Otherwise append another backpath, including
|
||||
* trailing slash if present.
|
||||
*/
|
||||
memcpy(path + pathlen, "../", *next ? 3 : 2);
|
||||
pathlen += *next ? 3 : 2;
|
||||
}
|
||||
else {
|
||||
/* otherwise crop the prior segment
|
||||
*/
|
||||
do {
|
||||
--pathlen;
|
||||
} while (pathlen && path[pathlen - 1] != '/');
|
||||
}
|
||||
|
||||
/* Now test if we are above where we started and back up
|
||||
* the keptlen offset to reflect the added/altered path.
|
||||
*/
|
||||
if (pathlen < keptlen) {
|
||||
if (flags & APR_FILEPATH_SECUREROOTTEST) {
|
||||
return APR_EABOVEROOT;
|
||||
}
|
||||
keptlen = pathlen;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* An actual segment, append it to the destination path
|
||||
*/
|
||||
if (*next) {
|
||||
seglen++;
|
||||
}
|
||||
memcpy(path + pathlen, addpath, seglen);
|
||||
pathlen += seglen;
|
||||
}
|
||||
|
||||
/* Skip over trailing slash to the next segment
|
||||
*/
|
||||
if (*next) {
|
||||
++next;
|
||||
}
|
||||
|
||||
addpath = next;
|
||||
}
|
||||
path[pathlen] = '\0';
|
||||
|
||||
/* keptlen will be the rootlen unless the addpath contained
|
||||
* backpath elements. If so, and APR_FILEPATH_NOTABOVEROOT
|
||||
* is specified (APR_FILEPATH_SECUREROOTTEST was caught above),
|
||||
* compare the original root to assure the result path is
|
||||
* still within given root path.
|
||||
*/
|
||||
if ((flags & APR_FILEPATH_NOTABOVEROOT) && keptlen < rootlen) {
|
||||
if (strncmp(rootpath, path, rootlen)) {
|
||||
return APR_EABOVEROOT;
|
||||
}
|
||||
if (rootpath[rootlen - 1] != '/'
|
||||
&& path[rootlen] && path[rootlen] != '/') {
|
||||
return APR_EABOVEROOT;
|
||||
}
|
||||
}
|
||||
|
||||
*newpath = path;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_filepath_list_split(apr_array_header_t **pathelts,
|
||||
const char *liststr,
|
||||
apr_pool_t *p)
|
||||
{
|
||||
return apr_filepath_list_split_impl(pathelts, liststr, ':', p);
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_filepath_list_merge(char **liststr,
|
||||
apr_array_header_t *pathelts,
|
||||
apr_pool_t *p)
|
||||
{
|
||||
return apr_filepath_list_merge_impl(liststr, pathelts, ':', p);
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_filepath_encoding(int *style, apr_pool_t *p)
|
||||
{
|
||||
#if defined(DARWIN)
|
||||
*style = APR_FILEPATH_ENCODING_UTF8;
|
||||
#else
|
||||
*style = APR_FILEPATH_ENCODING_LOCALE;
|
||||
#endif
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#define APR_WANT_STRFUNC
|
||||
#define APR_WANT_MEMFUNC
|
||||
#include "apr_want.h"
|
||||
|
||||
#include "apr_errno.h"
|
||||
#include "apr_pools.h"
|
||||
#include "apr_strings.h"
|
||||
#include "apr_tables.h"
|
||||
|
||||
#include "apr_private.h"
|
||||
|
||||
apr_status_t apr_filepath_list_split_impl(apr_array_header_t **pathelts,
|
||||
const char *liststr,
|
||||
char separator,
|
||||
apr_pool_t *p)
|
||||
{
|
||||
char *path, *part, *ptr;
|
||||
char separator_string[2] = { '\0', '\0' };
|
||||
apr_array_header_t *elts;
|
||||
int nelts;
|
||||
|
||||
separator_string[0] = separator;
|
||||
/* Count the number of path elements. We know there'll be at least
|
||||
one even if path is an empty string. */
|
||||
path = apr_pstrdup(p, liststr);
|
||||
for (nelts = 0, ptr = path; ptr != NULL; ++nelts)
|
||||
{
|
||||
ptr = strchr(ptr, separator);
|
||||
if (ptr)
|
||||
++ptr;
|
||||
}
|
||||
|
||||
/* Split the path into the array. */
|
||||
elts = apr_array_make(p, nelts, sizeof(char*));
|
||||
while ((part = apr_strtok(path, separator_string, &ptr)) != NULL)
|
||||
{
|
||||
if (*part == '\0') /* Ignore empty path components. */
|
||||
continue;
|
||||
|
||||
*(char**)apr_array_push(elts) = part;
|
||||
path = NULL; /* For the next call to apr_strtok */
|
||||
}
|
||||
|
||||
*pathelts = elts;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
apr_status_t apr_filepath_list_merge_impl(char **liststr,
|
||||
apr_array_header_t *pathelts,
|
||||
char separator,
|
||||
apr_pool_t *p)
|
||||
{
|
||||
apr_size_t path_size = 0;
|
||||
char *path;
|
||||
int i;
|
||||
|
||||
/* This test isn't 100% certain, but it'll catch at least some
|
||||
invalid uses... */
|
||||
if (pathelts->elt_size != sizeof(char*))
|
||||
return APR_EINVAL;
|
||||
|
||||
/* Calculate the size of the merged path */
|
||||
for (i = 0; i < pathelts->nelts; ++i)
|
||||
path_size += strlen(((char**)pathelts->elts)[i]);
|
||||
|
||||
if (path_size == 0)
|
||||
{
|
||||
*liststr = NULL;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
if (i > 0) /* Add space for the separators */
|
||||
path_size += (i - 1);
|
||||
|
||||
/* Merge the path components */
|
||||
path = *liststr = apr_palloc(p, path_size + 1);
|
||||
for (i = 0; i < pathelts->nelts; ++i)
|
||||
{
|
||||
/* ### Hmmmm. Calling strlen twice on the same string. Yuck.
|
||||
But is is better than reallocation in apr_pstrcat? */
|
||||
const char *part = ((char**)pathelts->elts)[i];
|
||||
apr_size_t part_size = strlen(part);
|
||||
if (part_size == 0) /* Ignore empty path components. */
|
||||
continue;
|
||||
|
||||
if (i > 0)
|
||||
*path++ = separator;
|
||||
memcpy(path, part, part_size);
|
||||
path += part_size;
|
||||
}
|
||||
*path = '\0';
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
+339
@@ -0,0 +1,339 @@
|
||||
/* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "apr_arch_file_io.h"
|
||||
#include "apr_file_io.h"
|
||||
#include "apr_general.h"
|
||||
#include "apr_strings.h"
|
||||
#include "apr_errno.h"
|
||||
|
||||
#ifdef HAVE_UTIME
|
||||
#include <utime.h>
|
||||
#endif
|
||||
|
||||
static apr_filetype_e filetype_from_mode(mode_t mode)
|
||||
{
|
||||
apr_filetype_e type;
|
||||
|
||||
switch (mode & S_IFMT) {
|
||||
case S_IFREG:
|
||||
type = APR_REG; break;
|
||||
case S_IFDIR:
|
||||
type = APR_DIR; break;
|
||||
case S_IFLNK:
|
||||
type = APR_LNK; break;
|
||||
case S_IFCHR:
|
||||
type = APR_CHR; break;
|
||||
case S_IFBLK:
|
||||
type = APR_BLK; break;
|
||||
#if defined(S_IFFIFO)
|
||||
case S_IFFIFO:
|
||||
type = APR_PIPE; break;
|
||||
#endif
|
||||
#if !defined(BEOS) && defined(S_IFSOCK)
|
||||
case S_IFSOCK:
|
||||
type = APR_SOCK; break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
/* Work around missing S_IFxxx values above
|
||||
* for Linux et al.
|
||||
*/
|
||||
#if !defined(S_IFFIFO) && defined(S_ISFIFO)
|
||||
if (S_ISFIFO(mode)) {
|
||||
type = APR_PIPE;
|
||||
} else
|
||||
#endif
|
||||
#if !defined(BEOS) && !defined(S_IFSOCK) && defined(S_ISSOCK)
|
||||
if (S_ISSOCK(mode)) {
|
||||
type = APR_SOCK;
|
||||
} else
|
||||
#endif
|
||||
type = APR_UNKFILE;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
static void fill_out_finfo(apr_finfo_t *finfo, struct_stat *info,
|
||||
apr_int32_t wanted)
|
||||
{
|
||||
finfo->valid = APR_FINFO_MIN | APR_FINFO_IDENT | APR_FINFO_NLINK
|
||||
| APR_FINFO_OWNER | APR_FINFO_PROT;
|
||||
finfo->protection = apr_unix_mode2perms(info->st_mode);
|
||||
finfo->filetype = filetype_from_mode(info->st_mode);
|
||||
finfo->user = info->st_uid;
|
||||
finfo->group = info->st_gid;
|
||||
finfo->size = info->st_size;
|
||||
finfo->device = info->st_dev;
|
||||
finfo->nlink = info->st_nlink;
|
||||
|
||||
/* Check for overflow if storing a 64-bit st_ino in a 32-bit
|
||||
* apr_ino_t for LFS builds: */
|
||||
if (sizeof(apr_ino_t) >= sizeof(info->st_ino)
|
||||
|| (apr_ino_t)info->st_ino == info->st_ino) {
|
||||
finfo->inode = info->st_ino;
|
||||
} else {
|
||||
finfo->valid &= ~APR_FINFO_INODE;
|
||||
}
|
||||
|
||||
apr_time_ansi_put(&finfo->atime, info->st_atime);
|
||||
#ifdef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC
|
||||
finfo->atime += info->st_atim.tv_nsec / APR_TIME_C(1000);
|
||||
#elif defined(HAVE_STRUCT_STAT_ST_ATIMENSEC)
|
||||
finfo->atime += info->st_atimensec / APR_TIME_C(1000);
|
||||
#elif defined(HAVE_STRUCT_STAT_ST_ATIME_N)
|
||||
finfo->atime += info->st_atime_n / APR_TIME_C(1000);
|
||||
#endif
|
||||
|
||||
apr_time_ansi_put(&finfo->mtime, info->st_mtime);
|
||||
#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
|
||||
finfo->mtime += info->st_mtim.tv_nsec / APR_TIME_C(1000);
|
||||
#elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
|
||||
finfo->mtime += info->st_mtimensec / APR_TIME_C(1000);
|
||||
#elif defined(HAVE_STRUCT_STAT_ST_MTIME_N)
|
||||
finfo->mtime += info->st_mtime_n / APR_TIME_C(1000);
|
||||
#endif
|
||||
|
||||
apr_time_ansi_put(&finfo->ctime, info->st_ctime);
|
||||
#ifdef HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC
|
||||
finfo->ctime += info->st_ctim.tv_nsec / APR_TIME_C(1000);
|
||||
#elif defined(HAVE_STRUCT_STAT_ST_CTIMENSEC)
|
||||
finfo->ctime += info->st_ctimensec / APR_TIME_C(1000);
|
||||
#elif defined(HAVE_STRUCT_STAT_ST_CTIME_N)
|
||||
finfo->ctime += info->st_ctime_n / APR_TIME_C(1000);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STRUCT_STAT_ST_BLOCKS
|
||||
#ifdef DEV_BSIZE
|
||||
finfo->csize = (apr_off_t)info->st_blocks * (apr_off_t)DEV_BSIZE;
|
||||
#else
|
||||
finfo->csize = (apr_off_t)info->st_blocks * (apr_off_t)512;
|
||||
#endif
|
||||
finfo->valid |= APR_FINFO_CSIZE;
|
||||
#endif
|
||||
}
|
||||
|
||||
apr_status_t apr_file_info_get_locked(apr_finfo_t *finfo, apr_int32_t wanted,
|
||||
apr_file_t *thefile)
|
||||
{
|
||||
struct_stat info;
|
||||
|
||||
if (thefile->buffered) {
|
||||
apr_status_t rv = apr_file_flush_locked(thefile);
|
||||
if (rv != APR_SUCCESS)
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (fstat(thefile->filedes, &info) == 0) {
|
||||
finfo->pool = thefile->pool;
|
||||
finfo->fname = thefile->fname;
|
||||
fill_out_finfo(finfo, &info, wanted);
|
||||
return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS;
|
||||
}
|
||||
else {
|
||||
return errno;
|
||||
}
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_info_get(apr_finfo_t *finfo,
|
||||
apr_int32_t wanted,
|
||||
apr_file_t *thefile)
|
||||
{
|
||||
struct_stat info;
|
||||
|
||||
if (thefile->buffered) {
|
||||
apr_status_t rv = apr_file_flush(thefile);
|
||||
if (rv != APR_SUCCESS)
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (fstat(thefile->filedes, &info) == 0) {
|
||||
finfo->pool = thefile->pool;
|
||||
finfo->fname = thefile->fname;
|
||||
fill_out_finfo(finfo, &info, wanted);
|
||||
return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS;
|
||||
}
|
||||
else {
|
||||
return errno;
|
||||
}
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_perms_set(const char *fname,
|
||||
apr_fileperms_t perms)
|
||||
{
|
||||
mode_t mode = apr_unix_perms2mode(perms);
|
||||
|
||||
if (chmod(fname, mode) == -1)
|
||||
return errno;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_attrs_set(const char *fname,
|
||||
apr_fileattrs_t attributes,
|
||||
apr_fileattrs_t attr_mask,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
apr_status_t status;
|
||||
apr_finfo_t finfo;
|
||||
|
||||
/* Don't do anything if we can't handle the requested attributes */
|
||||
if (!(attr_mask & (APR_FILE_ATTR_READONLY
|
||||
| APR_FILE_ATTR_EXECUTABLE)))
|
||||
return APR_SUCCESS;
|
||||
|
||||
status = apr_stat(&finfo, fname, APR_FINFO_PROT, pool);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
/* ### TODO: should added bits be umask'd? */
|
||||
if (attr_mask & APR_FILE_ATTR_READONLY)
|
||||
{
|
||||
if (attributes & APR_FILE_ATTR_READONLY)
|
||||
{
|
||||
finfo.protection &= ~APR_UWRITE;
|
||||
finfo.protection &= ~APR_GWRITE;
|
||||
finfo.protection &= ~APR_WWRITE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* ### umask this! */
|
||||
finfo.protection |= APR_UWRITE;
|
||||
finfo.protection |= APR_GWRITE;
|
||||
finfo.protection |= APR_WWRITE;
|
||||
}
|
||||
}
|
||||
|
||||
if (attr_mask & APR_FILE_ATTR_EXECUTABLE)
|
||||
{
|
||||
if (attributes & APR_FILE_ATTR_EXECUTABLE)
|
||||
{
|
||||
/* ### umask this! */
|
||||
finfo.protection |= APR_UEXECUTE;
|
||||
finfo.protection |= APR_GEXECUTE;
|
||||
finfo.protection |= APR_WEXECUTE;
|
||||
}
|
||||
else
|
||||
{
|
||||
finfo.protection &= ~APR_UEXECUTE;
|
||||
finfo.protection &= ~APR_GEXECUTE;
|
||||
finfo.protection &= ~APR_WEXECUTE;
|
||||
}
|
||||
}
|
||||
|
||||
return apr_file_perms_set(fname, finfo.protection);
|
||||
}
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_mtime_set(const char *fname,
|
||||
apr_time_t mtime,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
apr_status_t status;
|
||||
apr_finfo_t finfo;
|
||||
|
||||
status = apr_stat(&finfo, fname, APR_FINFO_ATIME, pool);
|
||||
if (status) {
|
||||
return status;
|
||||
}
|
||||
|
||||
#ifdef HAVE_UTIMES
|
||||
{
|
||||
struct timeval tvp[2];
|
||||
|
||||
tvp[0].tv_sec = apr_time_sec(finfo.atime);
|
||||
tvp[0].tv_usec = apr_time_usec(finfo.atime);
|
||||
tvp[1].tv_sec = apr_time_sec(mtime);
|
||||
tvp[1].tv_usec = apr_time_usec(mtime);
|
||||
|
||||
if (utimes(fname, tvp) == -1) {
|
||||
return errno;
|
||||
}
|
||||
}
|
||||
#elif defined(HAVE_UTIME)
|
||||
{
|
||||
struct utimbuf buf;
|
||||
|
||||
buf.actime = (time_t) (finfo.atime / APR_USEC_PER_SEC);
|
||||
buf.modtime = (time_t) (mtime / APR_USEC_PER_SEC);
|
||||
|
||||
if (utime(fname, &buf) == -1) {
|
||||
return errno;
|
||||
}
|
||||
}
|
||||
#else
|
||||
return APR_ENOTIMPL;
|
||||
#endif
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_stat(apr_finfo_t *finfo,
|
||||
const char *fname,
|
||||
apr_int32_t wanted, apr_pool_t *pool)
|
||||
{
|
||||
struct_stat info;
|
||||
int srv;
|
||||
|
||||
if (wanted & APR_FINFO_LINK)
|
||||
srv = lstat(fname, &info);
|
||||
else
|
||||
srv = stat(fname, &info);
|
||||
|
||||
if (srv == 0) {
|
||||
finfo->pool = pool;
|
||||
finfo->fname = fname;
|
||||
fill_out_finfo(finfo, &info, wanted);
|
||||
if (wanted & APR_FINFO_LINK)
|
||||
wanted &= ~APR_FINFO_LINK;
|
||||
return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS;
|
||||
}
|
||||
else {
|
||||
#if !defined(ENOENT) || !defined(ENOTDIR)
|
||||
#error ENOENT || ENOTDIR not defined; please see the
|
||||
#error comments at this line in the source for a workaround.
|
||||
/*
|
||||
* If ENOENT || ENOTDIR is not defined in one of the your OS's
|
||||
* include files, APR cannot report a good reason why the stat()
|
||||
* of the file failed; there are cases where it can fail even though
|
||||
* the file exists. This opens holes in Apache, for example, because
|
||||
* it becomes possible for someone to get a directory listing of a
|
||||
* directory even though there is an index (eg. index.html) file in
|
||||
* it. If you do not have a problem with this, delete the above
|
||||
* #error lines and start the compile again. If you need to do this,
|
||||
* please submit a bug report to http://www.apache.org/bug_report.html
|
||||
* letting us know that you needed to do this. Please be sure to
|
||||
* include the operating system you are using.
|
||||
*/
|
||||
/* WARNING: All errors will be handled as not found
|
||||
*/
|
||||
#if !defined(ENOENT)
|
||||
return APR_ENOENT;
|
||||
#else
|
||||
/* WARNING: All errors but not found will be handled as not directory
|
||||
*/
|
||||
if (errno != ENOENT)
|
||||
return APR_ENOENT;
|
||||
else
|
||||
return errno;
|
||||
#endif
|
||||
#else /* All was defined well, report the usual: */
|
||||
return errno;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
/* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "apr_arch_file_io.h"
|
||||
|
||||
#if APR_HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_FILE_H
|
||||
#include <sys/file.h>
|
||||
#endif
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_lock(apr_file_t *thefile, int type)
|
||||
{
|
||||
int rc;
|
||||
|
||||
#if defined(HAVE_FCNTL_H)
|
||||
{
|
||||
struct flock l = { 0 };
|
||||
int fc;
|
||||
|
||||
l.l_whence = SEEK_SET; /* count l_start from start of file */
|
||||
l.l_start = 0; /* lock from start of file */
|
||||
l.l_len = 0; /* lock to end of file */
|
||||
if ((type & APR_FLOCK_TYPEMASK) == APR_FLOCK_SHARED)
|
||||
l.l_type = F_RDLCK;
|
||||
else
|
||||
l.l_type = F_WRLCK;
|
||||
|
||||
fc = (type & APR_FLOCK_NONBLOCK) ? F_SETLK : F_SETLKW;
|
||||
|
||||
/* keep trying if fcntl() gets interrupted (by a signal) */
|
||||
while ((rc = fcntl(thefile->filedes, fc, &l)) < 0 && errno == EINTR)
|
||||
continue;
|
||||
|
||||
if (rc == -1) {
|
||||
/* on some Unix boxes (e.g., Tru64), we get EACCES instead
|
||||
* of EAGAIN; we don't want APR_STATUS_IS_EAGAIN() matching EACCES
|
||||
* since that breaks other things, so fix up the retcode here
|
||||
*/
|
||||
if (errno == EACCES) {
|
||||
return EAGAIN;
|
||||
}
|
||||
return errno;
|
||||
}
|
||||
}
|
||||
#elif defined(HAVE_SYS_FILE_H)
|
||||
{
|
||||
int ltype;
|
||||
|
||||
if ((type & APR_FLOCK_TYPEMASK) == APR_FLOCK_SHARED)
|
||||
ltype = LOCK_SH;
|
||||
else
|
||||
ltype = LOCK_EX;
|
||||
if ((type & APR_FLOCK_NONBLOCK) != 0)
|
||||
ltype |= LOCK_NB;
|
||||
|
||||
/* keep trying if flock() gets interrupted (by a signal) */
|
||||
while ((rc = flock(thefile->filedes, ltype)) < 0 && errno == EINTR)
|
||||
continue;
|
||||
|
||||
if (rc == -1)
|
||||
return errno;
|
||||
}
|
||||
#else
|
||||
#error No file locking mechanism is available.
|
||||
#endif
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_unlock(apr_file_t *thefile)
|
||||
{
|
||||
int rc;
|
||||
|
||||
#if defined(HAVE_FCNTL_H)
|
||||
{
|
||||
struct flock l = { 0 };
|
||||
|
||||
l.l_whence = SEEK_SET; /* count l_start from start of file */
|
||||
l.l_start = 0; /* lock from start of file */
|
||||
l.l_len = 0; /* lock to end of file */
|
||||
l.l_type = F_UNLCK;
|
||||
|
||||
/* keep trying if fcntl() gets interrupted (by a signal) */
|
||||
while ((rc = fcntl(thefile->filedes, F_SETLKW, &l)) < 0
|
||||
&& errno == EINTR)
|
||||
continue;
|
||||
|
||||
if (rc == -1)
|
||||
return errno;
|
||||
}
|
||||
#elif defined(HAVE_SYS_FILE_H)
|
||||
{
|
||||
/* keep trying if flock() gets interrupted (by a signal) */
|
||||
while ((rc = flock(thefile->filedes, LOCK_UN)) < 0 && errno == EINTR)
|
||||
continue;
|
||||
|
||||
if (rc == -1)
|
||||
return errno;
|
||||
}
|
||||
#else
|
||||
#error No file locking mechanism is available.
|
||||
#endif
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
/* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "apr_file_io.h"
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_read_full(apr_file_t *thefile, void *buf,
|
||||
apr_size_t nbytes,
|
||||
apr_size_t *bytes_read)
|
||||
{
|
||||
apr_status_t status;
|
||||
apr_size_t total_read = 0;
|
||||
|
||||
do {
|
||||
apr_size_t amt = nbytes;
|
||||
|
||||
status = apr_file_read(thefile, buf, &amt);
|
||||
buf = (char *)buf + amt;
|
||||
nbytes -= amt;
|
||||
total_read += amt;
|
||||
} while (status == APR_SUCCESS && nbytes > 0);
|
||||
|
||||
if (bytes_read != NULL)
|
||||
*bytes_read = total_read;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_write_full(apr_file_t *thefile,
|
||||
const void *buf,
|
||||
apr_size_t nbytes,
|
||||
apr_size_t *bytes_written)
|
||||
{
|
||||
apr_status_t status;
|
||||
apr_size_t total_written = 0;
|
||||
|
||||
do {
|
||||
apr_size_t amt = nbytes;
|
||||
|
||||
status = apr_file_write(thefile, buf, &amt);
|
||||
buf = (char *)buf + amt;
|
||||
nbytes -= amt;
|
||||
total_written += amt;
|
||||
} while (status == APR_SUCCESS && nbytes > 0);
|
||||
|
||||
if (bytes_written != NULL)
|
||||
*bytes_written = total_written;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_writev_full(apr_file_t *thefile,
|
||||
const struct iovec *vec,
|
||||
apr_size_t nvec,
|
||||
apr_size_t *bytes_written)
|
||||
{
|
||||
apr_status_t rv = APR_SUCCESS;
|
||||
apr_size_t i;
|
||||
apr_size_t amt = 0;
|
||||
apr_size_t total = 0;
|
||||
|
||||
for (i = 0; i < nvec; i++) {
|
||||
total += vec[i].iov_len;
|
||||
}
|
||||
|
||||
rv = apr_file_writev(thefile, vec, nvec, &amt);
|
||||
|
||||
if (bytes_written != NULL)
|
||||
*bytes_written = amt;
|
||||
|
||||
if (rv != APR_SUCCESS || (amt == total)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
for (i = 0; i < nvec && amt; i++) {
|
||||
if (amt >= vec[i].iov_len) {
|
||||
amt -= vec[i].iov_len;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (amt) {
|
||||
rv = apr_file_write_full(thefile, (const char *)vec[i].iov_base + amt,
|
||||
vec[i].iov_len - amt, NULL);
|
||||
}
|
||||
|
||||
for (; i < nvec && rv == APR_SUCCESS; i++) {
|
||||
rv = apr_file_write_full(thefile, vec[i].iov_base,
|
||||
vec[i].iov_len, &amt);
|
||||
}
|
||||
|
||||
if (bytes_written != NULL)
|
||||
*bytes_written = total;
|
||||
|
||||
return rv;
|
||||
}
|
||||
+223
@@ -0,0 +1,223 @@
|
||||
/* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 1987, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "apr_private.h"
|
||||
#include "apr_file_io.h" /* prototype of apr_mkstemp() */
|
||||
#include "apr_strings.h" /* prototype of apr_mkstemp() */
|
||||
#include "apr_arch_file_io.h" /* prototype of apr_mkstemp() */
|
||||
#include "apr_portable.h" /* for apr_os_file_put() */
|
||||
#include "apr_arch_inherit.h"
|
||||
|
||||
#ifndef HAVE_MKSTEMP
|
||||
|
||||
#if defined(SVR4) || defined(WIN32) || defined(NETWARE)
|
||||
#ifdef SVR4
|
||||
#if HAVE_INTTYPES_H
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
#endif
|
||||
#define arc4random() rand()
|
||||
#define seedrandom(a) srand(a)
|
||||
#else
|
||||
#if APR_HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
#define arc4random() random()
|
||||
#define seedrandom(a) srandom(a)
|
||||
#endif
|
||||
|
||||
#if APR_HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#if APR_HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#ifdef HAVE_TIME_H
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
static const unsigned char padchar[] =
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
static apr_uint32_t randseed=0;
|
||||
|
||||
static int gettemp(char *path, apr_file_t **doopen, apr_int32_t flags, apr_pool_t *p)
|
||||
{
|
||||
register char *start, *trv, *suffp;
|
||||
char *pad;
|
||||
apr_finfo_t sbuf;
|
||||
apr_status_t rv;
|
||||
apr_uint32_t randnum;
|
||||
|
||||
if (randseed==0) {
|
||||
randseed = (int)apr_time_now();
|
||||
seedrandom(randseed);
|
||||
}
|
||||
|
||||
for (trv = path; *trv; ++trv)
|
||||
;
|
||||
suffp = trv;
|
||||
--trv;
|
||||
if (trv < path) {
|
||||
return APR_EINVAL;
|
||||
}
|
||||
|
||||
/* Fill space with random characters */
|
||||
while (*trv == 'X') {
|
||||
randnum = arc4random() % (sizeof(padchar) - 1);
|
||||
*trv-- = padchar[randnum];
|
||||
}
|
||||
start = trv + 1;
|
||||
|
||||
/*
|
||||
* check the target directory.
|
||||
*/
|
||||
for (;; --trv) {
|
||||
if (trv <= path)
|
||||
break;
|
||||
if (*trv == '/') {
|
||||
*trv = '\0';
|
||||
rv = apr_stat(&sbuf, path, APR_FINFO_TYPE, p);
|
||||
*trv = '/';
|
||||
if (rv != APR_SUCCESS)
|
||||
return rv;
|
||||
if (sbuf.filetype != APR_DIR) {
|
||||
return APR_ENOTDIR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if ((rv = apr_file_open(doopen, path, flags,
|
||||
APR_UREAD | APR_UWRITE, p)) == APR_SUCCESS)
|
||||
return APR_SUCCESS;
|
||||
if (!APR_STATUS_IS_EEXIST(rv))
|
||||
return rv;
|
||||
|
||||
/* If we have a collision, cycle through the space of filenames */
|
||||
for (trv = start;;) {
|
||||
if (*trv == '\0' || trv == suffp)
|
||||
return APR_EINVAL; /* XXX: is this the correct return code? */
|
||||
pad = strchr((char *)padchar, *trv);
|
||||
if (pad == NULL || !*++pad) {
|
||||
*trv++ = padchar[0];
|
||||
}
|
||||
else {
|
||||
*trv++ = *pad;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#if APR_HAVE_STDLIB_H
|
||||
#include <stdlib.h> /* for mkstemp() - Single Unix */
|
||||
#endif
|
||||
#if APR_HAVE_UNISTD_H
|
||||
#include <unistd.h> /* for mkstemp() - FreeBSD */
|
||||
#endif
|
||||
#endif /* !defined(HAVE_MKSTEMP) */
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_mktemp(apr_file_t **fp, char *template, apr_int32_t flags, apr_pool_t *p)
|
||||
{
|
||||
#ifdef HAVE_MKSTEMP
|
||||
int fd;
|
||||
#endif
|
||||
flags = (!flags) ? APR_FOPEN_CREATE | APR_FOPEN_READ | APR_FOPEN_WRITE | APR_FOPEN_EXCL |
|
||||
APR_FOPEN_DELONCLOSE : flags;
|
||||
#ifndef HAVE_MKSTEMP
|
||||
return gettemp(template, fp, flags, p);
|
||||
#else
|
||||
|
||||
#ifdef HAVE_MKSTEMP64
|
||||
fd = mkstemp64(template);
|
||||
#else
|
||||
fd = mkstemp(template);
|
||||
#endif
|
||||
|
||||
if (fd == -1) {
|
||||
return errno;
|
||||
}
|
||||
/* XXX: We must reset several flags values as passed-in, since
|
||||
* mkstemp didn't subscribe to our preference flags.
|
||||
*
|
||||
* We either have to unset the flags, or fix up the fd and other
|
||||
* xthread and inherit bits appropriately. Since gettemp() above
|
||||
* calls apr_file_open, our flags are respected in that code path.
|
||||
*/
|
||||
apr_os_file_put(fp, &fd, flags, p);
|
||||
(*fp)->fname = apr_pstrdup(p, template);
|
||||
|
||||
if (!(flags & APR_FOPEN_NOCLEANUP)) {
|
||||
int flags;
|
||||
|
||||
if ((flags = fcntl(fd, F_GETFD)) == -1)
|
||||
return errno;
|
||||
|
||||
flags |= FD_CLOEXEC;
|
||||
if (fcntl(fd, F_SETFD, flags) == -1)
|
||||
return errno;
|
||||
|
||||
apr_pool_cleanup_register((*fp)->pool, (void *)(*fp),
|
||||
apr_unix_file_cleanup,
|
||||
apr_unix_child_file_cleanup);
|
||||
}
|
||||
#endif
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
+417
@@ -0,0 +1,417 @@
|
||||
/* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "apr_arch_file_io.h"
|
||||
#include "apr_strings.h"
|
||||
#include "apr_portable.h"
|
||||
#include "apr_thread_mutex.h"
|
||||
#include "apr_arch_inherit.h"
|
||||
|
||||
#ifdef NETWARE
|
||||
#include "nks/dirio.h"
|
||||
#include "apr_hash.h"
|
||||
#include "fsio.h"
|
||||
#endif
|
||||
|
||||
static apr_status_t file_cleanup(apr_file_t *file, int is_child)
|
||||
{
|
||||
apr_status_t rv = APR_SUCCESS;
|
||||
int fd = file->filedes;
|
||||
|
||||
/* Set file descriptor to -1 before close(), so that there is no
|
||||
* chance of returning an already closed FD from apr_os_file_get().
|
||||
*/
|
||||
file->filedes = -1;
|
||||
|
||||
if (close(fd) == 0) {
|
||||
/* Only the parent process should delete the file! */
|
||||
if (!is_child && (file->flags & APR_FOPEN_DELONCLOSE)) {
|
||||
unlink(file->fname);
|
||||
}
|
||||
#if APR_HAS_THREADS
|
||||
if (file->thlock) {
|
||||
rv = apr_thread_mutex_destroy(file->thlock);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
/* Restore, close() was not successful. */
|
||||
file->filedes = fd;
|
||||
|
||||
/* Are there any error conditions other than EINTR or EBADF? */
|
||||
rv = errno;
|
||||
}
|
||||
#ifndef WAITIO_USES_POLL
|
||||
if (file->pollset != NULL) {
|
||||
apr_status_t pollset_rv = apr_pollset_destroy(file->pollset);
|
||||
/* If the file close failed, return its error value,
|
||||
* not apr_pollset_destroy()'s.
|
||||
*/
|
||||
if (rv == APR_SUCCESS) {
|
||||
rv = pollset_rv;
|
||||
}
|
||||
}
|
||||
#endif /* !WAITIO_USES_POLL */
|
||||
return rv;
|
||||
}
|
||||
|
||||
apr_status_t apr_unix_file_cleanup(void *thefile)
|
||||
{
|
||||
apr_file_t *file = thefile;
|
||||
apr_status_t flush_rv = APR_SUCCESS, rv = APR_SUCCESS;
|
||||
|
||||
if (file->buffered) {
|
||||
flush_rv = apr_file_flush(file);
|
||||
}
|
||||
|
||||
rv = file_cleanup(file, 0);
|
||||
|
||||
return rv != APR_SUCCESS ? rv : flush_rv;
|
||||
}
|
||||
|
||||
apr_status_t apr_unix_child_file_cleanup(void *thefile)
|
||||
{
|
||||
return file_cleanup(thefile, 1);
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_open(apr_file_t **new,
|
||||
const char *fname,
|
||||
apr_int32_t flag,
|
||||
apr_fileperms_t perm,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
apr_os_file_t fd;
|
||||
int oflags = 0;
|
||||
#if APR_HAS_THREADS
|
||||
apr_thread_mutex_t *thlock;
|
||||
apr_status_t rv;
|
||||
#endif
|
||||
|
||||
if ((flag & APR_FOPEN_READ) && (flag & APR_FOPEN_WRITE)) {
|
||||
oflags = O_RDWR;
|
||||
}
|
||||
else if (flag & APR_FOPEN_READ) {
|
||||
oflags = O_RDONLY;
|
||||
}
|
||||
else if (flag & APR_FOPEN_WRITE) {
|
||||
oflags = O_WRONLY;
|
||||
}
|
||||
else {
|
||||
return APR_EACCES;
|
||||
}
|
||||
|
||||
if (flag & APR_FOPEN_CREATE) {
|
||||
oflags |= O_CREAT;
|
||||
if (flag & APR_FOPEN_EXCL) {
|
||||
oflags |= O_EXCL;
|
||||
}
|
||||
}
|
||||
if ((flag & APR_FOPEN_EXCL) && !(flag & APR_FOPEN_CREATE)) {
|
||||
return APR_EACCES;
|
||||
}
|
||||
|
||||
if (flag & APR_FOPEN_APPEND) {
|
||||
oflags |= O_APPEND;
|
||||
}
|
||||
if (flag & APR_FOPEN_TRUNCATE) {
|
||||
oflags |= O_TRUNC;
|
||||
}
|
||||
#ifdef O_BINARY
|
||||
if (flag & APR_FOPEN_BINARY) {
|
||||
oflags |= O_BINARY;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (flag & APR_FOPEN_NONBLOCK) {
|
||||
#ifdef O_NONBLOCK
|
||||
oflags |= O_NONBLOCK;
|
||||
#else
|
||||
return APR_ENOTIMPL;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef O_CLOEXEC
|
||||
/* Introduced in Linux 2.6.23. Silently ignored on earlier Linux kernels.
|
||||
*/
|
||||
if (!(flag & APR_FOPEN_NOCLEANUP)) {
|
||||
oflags |= O_CLOEXEC;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if APR_HAS_LARGE_FILES && defined(_LARGEFILE64_SOURCE)
|
||||
oflags |= O_LARGEFILE;
|
||||
#elif defined(O_LARGEFILE)
|
||||
if (flag & APR_FOPEN_LARGEFILE) {
|
||||
oflags |= O_LARGEFILE;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if APR_HAS_THREADS
|
||||
if ((flag & APR_FOPEN_BUFFERED) && (flag & APR_FOPEN_XTHREAD)) {
|
||||
rv = apr_thread_mutex_create(&thlock,
|
||||
APR_THREAD_MUTEX_DEFAULT, pool);
|
||||
if (rv) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (perm == APR_OS_DEFAULT) {
|
||||
fd = open(fname, oflags, 0666);
|
||||
}
|
||||
else {
|
||||
fd = open(fname, oflags, apr_unix_perms2mode(perm));
|
||||
}
|
||||
if (fd < 0) {
|
||||
return errno;
|
||||
}
|
||||
if (!(flag & APR_FOPEN_NOCLEANUP)) {
|
||||
#ifdef O_CLOEXEC
|
||||
static int has_o_cloexec = 0;
|
||||
if (!has_o_cloexec)
|
||||
#endif
|
||||
{
|
||||
int flags;
|
||||
|
||||
if ((flags = fcntl(fd, F_GETFD)) == -1) {
|
||||
close(fd);
|
||||
return errno;
|
||||
}
|
||||
if ((flags & FD_CLOEXEC) == 0) {
|
||||
flags |= FD_CLOEXEC;
|
||||
if (fcntl(fd, F_SETFD, flags) == -1) {
|
||||
close(fd);
|
||||
return errno;
|
||||
}
|
||||
}
|
||||
#ifdef O_CLOEXEC
|
||||
else {
|
||||
has_o_cloexec = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
(*new) = (apr_file_t *)apr_pcalloc(pool, sizeof(apr_file_t));
|
||||
(*new)->pool = pool;
|
||||
(*new)->flags = flag;
|
||||
(*new)->filedes = fd;
|
||||
|
||||
(*new)->fname = apr_pstrdup(pool, fname);
|
||||
|
||||
(*new)->blocking = BLK_ON;
|
||||
(*new)->buffered = (flag & APR_FOPEN_BUFFERED) > 0;
|
||||
|
||||
if ((*new)->buffered) {
|
||||
(*new)->buffer = apr_palloc(pool, APR_FILE_DEFAULT_BUFSIZE);
|
||||
(*new)->bufsize = APR_FILE_DEFAULT_BUFSIZE;
|
||||
#if APR_HAS_THREADS
|
||||
if ((*new)->flags & APR_FOPEN_XTHREAD) {
|
||||
(*new)->thlock = thlock;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
(*new)->buffer = NULL;
|
||||
}
|
||||
|
||||
(*new)->is_pipe = 0;
|
||||
(*new)->timeout = -1;
|
||||
(*new)->ungetchar = -1;
|
||||
(*new)->eof_hit = 0;
|
||||
(*new)->filePtr = 0;
|
||||
(*new)->bufpos = 0;
|
||||
(*new)->dataRead = 0;
|
||||
(*new)->direction = 0;
|
||||
#ifndef WAITIO_USES_POLL
|
||||
/* Start out with no pollset. apr_wait_for_io_or_timeout() will
|
||||
* initialize the pollset if needed.
|
||||
*/
|
||||
(*new)->pollset = NULL;
|
||||
#endif
|
||||
if (!(flag & APR_FOPEN_NOCLEANUP)) {
|
||||
apr_pool_cleanup_register((*new)->pool, (void *)(*new),
|
||||
apr_unix_file_cleanup,
|
||||
apr_unix_child_file_cleanup);
|
||||
}
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_close(apr_file_t *file)
|
||||
{
|
||||
return apr_pool_cleanup_run(file->pool, file, apr_unix_file_cleanup);
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_remove(const char *path, apr_pool_t *pool)
|
||||
{
|
||||
if (unlink(path) == 0) {
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
else {
|
||||
return errno;
|
||||
}
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_rename(const char *from_path,
|
||||
const char *to_path,
|
||||
apr_pool_t *p)
|
||||
{
|
||||
if (rename(from_path, to_path) != 0) {
|
||||
return errno;
|
||||
}
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_os_file_get(apr_os_file_t *thefile,
|
||||
apr_file_t *file)
|
||||
{
|
||||
*thefile = file->filedes;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_os_file_put(apr_file_t **file,
|
||||
apr_os_file_t *thefile,
|
||||
apr_int32_t flags, apr_pool_t *pool)
|
||||
{
|
||||
int *dafile = thefile;
|
||||
|
||||
(*file) = apr_pcalloc(pool, sizeof(apr_file_t));
|
||||
(*file)->pool = pool;
|
||||
(*file)->eof_hit = 0;
|
||||
(*file)->blocking = BLK_UNKNOWN; /* in case it is a pipe */
|
||||
(*file)->timeout = -1;
|
||||
(*file)->ungetchar = -1; /* no char avail */
|
||||
(*file)->filedes = *dafile;
|
||||
(*file)->flags = flags | APR_FOPEN_NOCLEANUP;
|
||||
(*file)->buffered = (flags & APR_FOPEN_BUFFERED) > 0;
|
||||
|
||||
#ifndef WAITIO_USES_POLL
|
||||
/* Start out with no pollset. apr_wait_for_io_or_timeout() will
|
||||
* initialize the pollset if needed.
|
||||
*/
|
||||
(*file)->pollset = NULL;
|
||||
#endif
|
||||
|
||||
if ((*file)->buffered) {
|
||||
(*file)->buffer = apr_palloc(pool, APR_FILE_DEFAULT_BUFSIZE);
|
||||
(*file)->bufsize = APR_FILE_DEFAULT_BUFSIZE;
|
||||
#if APR_HAS_THREADS
|
||||
if ((*file)->flags & APR_FOPEN_XTHREAD) {
|
||||
apr_status_t rv;
|
||||
rv = apr_thread_mutex_create(&((*file)->thlock),
|
||||
APR_THREAD_MUTEX_DEFAULT, pool);
|
||||
if (rv) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_eof(apr_file_t *fptr)
|
||||
{
|
||||
if (fptr->eof_hit == 1) {
|
||||
return APR_EOF;
|
||||
}
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_open_flags_stderr(apr_file_t **thefile,
|
||||
apr_int32_t flags,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
int fd = STDERR_FILENO;
|
||||
|
||||
return apr_os_file_put(thefile, &fd, flags | APR_FOPEN_WRITE, pool);
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_open_flags_stdout(apr_file_t **thefile,
|
||||
apr_int32_t flags,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
int fd = STDOUT_FILENO;
|
||||
|
||||
return apr_os_file_put(thefile, &fd, flags | APR_FOPEN_WRITE, pool);
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_open_flags_stdin(apr_file_t **thefile,
|
||||
apr_int32_t flags,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
int fd = STDIN_FILENO;
|
||||
|
||||
return apr_os_file_put(thefile, &fd, flags | APR_FOPEN_READ, pool);
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_open_stderr(apr_file_t **thefile,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
return apr_file_open_flags_stderr(thefile, 0, pool);
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_open_stdout(apr_file_t **thefile,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
return apr_file_open_flags_stdout(thefile, 0, pool);
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_open_stdin(apr_file_t **thefile,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
return apr_file_open_flags_stdin(thefile, 0, pool);
|
||||
}
|
||||
|
||||
APR_IMPLEMENT_INHERIT_SET(file, flags, pool, apr_unix_file_cleanup)
|
||||
|
||||
/* We need to do this by hand instead of using APR_IMPLEMENT_INHERIT_UNSET
|
||||
* because the macro sets both cleanups to the same function, which is not
|
||||
* suitable on Unix (see PR 41119). */
|
||||
APR_DECLARE(apr_status_t) apr_file_inherit_unset(apr_file_t *thefile)
|
||||
{
|
||||
if (thefile->flags & APR_FOPEN_NOCLEANUP) {
|
||||
return APR_EINVAL;
|
||||
}
|
||||
if (thefile->flags & APR_INHERIT) {
|
||||
int flags;
|
||||
|
||||
if ((flags = fcntl(thefile->filedes, F_GETFD)) == -1)
|
||||
return errno;
|
||||
|
||||
flags |= FD_CLOEXEC;
|
||||
if (fcntl(thefile->filedes, F_SETFD, flags) == -1)
|
||||
return errno;
|
||||
|
||||
thefile->flags &= ~APR_INHERIT;
|
||||
apr_pool_child_cleanup_set(thefile->pool,
|
||||
(void *)thefile,
|
||||
apr_unix_file_cleanup,
|
||||
apr_unix_child_file_cleanup);
|
||||
}
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
APR_POOL_IMPLEMENT_ACCESSOR(file)
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_link(const char *from_path,
|
||||
const char *to_path)
|
||||
{
|
||||
if (link(from_path, to_path) == -1) {
|
||||
return errno;
|
||||
}
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
+292
@@ -0,0 +1,292 @@
|
||||
/* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "apr_arch_file_io.h"
|
||||
#include "apr_strings.h"
|
||||
#include "apr_portable.h"
|
||||
|
||||
#include "apr_arch_inherit.h"
|
||||
|
||||
/* Figure out how to get pipe block/nonblock on BeOS...
|
||||
* Basically, BONE7 changed things again so that ioctl didn't work,
|
||||
* but now fcntl does, hence we need to do this extra checking.
|
||||
* The joys of beta programs. :-)
|
||||
*/
|
||||
#if defined(BEOS)
|
||||
#if !defined(BONE7)
|
||||
# define BEOS_BLOCKING 1
|
||||
#else
|
||||
# define BEOS_BLOCKING 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static apr_status_t pipeblock(apr_file_t *thepipe)
|
||||
{
|
||||
#if !defined(BEOS) || !BEOS_BLOCKING
|
||||
int fd_flags;
|
||||
|
||||
fd_flags = fcntl(thepipe->filedes, F_GETFL, 0);
|
||||
# if defined(O_NONBLOCK)
|
||||
fd_flags &= ~O_NONBLOCK;
|
||||
# elif defined(O_NDELAY)
|
||||
fd_flags &= ~O_NDELAY;
|
||||
# elif defined(O_FNDELAY)
|
||||
fd_flags &= ~O_FNDELAY;
|
||||
# else
|
||||
/* XXXX: this breaks things, but an alternative isn't obvious...*/
|
||||
return APR_ENOTIMPL;
|
||||
# endif
|
||||
if (fcntl(thepipe->filedes, F_SETFL, fd_flags) == -1) {
|
||||
return errno;
|
||||
}
|
||||
#else /* BEOS_BLOCKING */
|
||||
|
||||
# if BEOS_BONE /* This only works on BONE 0-6 */
|
||||
int on = 0;
|
||||
if (ioctl(thepipe->filedes, FIONBIO, &on, sizeof(on)) < 0) {
|
||||
return errno;
|
||||
}
|
||||
# else /* "classic" BeOS doesn't support this at all */
|
||||
return APR_ENOTIMPL;
|
||||
# endif
|
||||
|
||||
#endif /* !BEOS_BLOCKING */
|
||||
|
||||
thepipe->blocking = BLK_ON;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
static apr_status_t pipenonblock(apr_file_t *thepipe)
|
||||
{
|
||||
#if !defined(BEOS) || !BEOS_BLOCKING
|
||||
int fd_flags = fcntl(thepipe->filedes, F_GETFL, 0);
|
||||
|
||||
# if defined(O_NONBLOCK)
|
||||
fd_flags |= O_NONBLOCK;
|
||||
# elif defined(O_NDELAY)
|
||||
fd_flags |= O_NDELAY;
|
||||
# elif defined(O_FNDELAY)
|
||||
fd_flags |= O_FNDELAY;
|
||||
# else
|
||||
/* XXXX: this breaks things, but an alternative isn't obvious...*/
|
||||
return APR_ENOTIMPL;
|
||||
# endif
|
||||
if (fcntl(thepipe->filedes, F_SETFL, fd_flags) == -1) {
|
||||
return errno;
|
||||
}
|
||||
|
||||
#else /* BEOS_BLOCKING */
|
||||
|
||||
# if BEOS_BONE /* This only works on BONE 0-6 */
|
||||
int on = 1;
|
||||
if (ioctl(thepipe->filedes, FIONBIO, &on, sizeof(on)) < 0) {
|
||||
return errno;
|
||||
}
|
||||
# else /* "classic" BeOS doesn't support this at all */
|
||||
return APR_ENOTIMPL;
|
||||
# endif
|
||||
|
||||
#endif /* !BEOS_BLOCKING */
|
||||
|
||||
thepipe->blocking = BLK_OFF;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_pipe_timeout_set(apr_file_t *thepipe, apr_interval_time_t timeout)
|
||||
{
|
||||
if (thepipe->is_pipe == 1) {
|
||||
thepipe->timeout = timeout;
|
||||
if (timeout >= 0) {
|
||||
if (thepipe->blocking != BLK_OFF) { /* blocking or unknown state */
|
||||
return pipenonblock(thepipe);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (thepipe->blocking != BLK_ON) { /* non-blocking or unknown state */
|
||||
return pipeblock(thepipe);
|
||||
}
|
||||
}
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
return APR_EINVAL;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_pipe_timeout_get(apr_file_t *thepipe, apr_interval_time_t *timeout)
|
||||
{
|
||||
if (thepipe->is_pipe == 1) {
|
||||
*timeout = thepipe->timeout;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
return APR_EINVAL;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_os_pipe_put_ex(apr_file_t **file,
|
||||
apr_os_file_t *thefile,
|
||||
int register_cleanup,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
int *dafile = thefile;
|
||||
|
||||
(*file) = apr_pcalloc(pool, sizeof(apr_file_t));
|
||||
(*file)->pool = pool;
|
||||
(*file)->eof_hit = 0;
|
||||
(*file)->is_pipe = 1;
|
||||
(*file)->blocking = BLK_UNKNOWN; /* app needs to make a timeout call */
|
||||
(*file)->timeout = -1;
|
||||
(*file)->ungetchar = -1; /* no char avail */
|
||||
(*file)->filedes = *dafile;
|
||||
if (!register_cleanup) {
|
||||
(*file)->flags = APR_FOPEN_NOCLEANUP;
|
||||
}
|
||||
(*file)->buffered = 0;
|
||||
#if APR_HAS_THREADS
|
||||
(*file)->thlock = NULL;
|
||||
#endif
|
||||
if (register_cleanup) {
|
||||
apr_pool_cleanup_register((*file)->pool, (void *)(*file),
|
||||
apr_unix_file_cleanup,
|
||||
apr_pool_cleanup_null);
|
||||
}
|
||||
#ifndef WAITIO_USES_POLL
|
||||
/* Start out with no pollset. apr_wait_for_io_or_timeout() will
|
||||
* initialize the pollset if needed.
|
||||
*/
|
||||
(*file)->pollset = NULL;
|
||||
#endif
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_os_pipe_put(apr_file_t **file,
|
||||
apr_os_file_t *thefile,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
return apr_os_pipe_put_ex(file, thefile, 0, pool);
|
||||
}
|
||||
|
||||
static apr_status_t file_pipe_create(apr_file_t **in, apr_file_t **out,
|
||||
apr_pool_t *pool_in, apr_pool_t *pool_out)
|
||||
{
|
||||
int filedes[2];
|
||||
|
||||
if (pipe(filedes) == -1) {
|
||||
return errno;
|
||||
}
|
||||
|
||||
(*in) = (apr_file_t *)apr_pcalloc(pool_in, sizeof(apr_file_t));
|
||||
(*in)->pool = pool_in;
|
||||
(*in)->filedes = filedes[0];
|
||||
(*in)->is_pipe = 1;
|
||||
(*in)->fname = NULL;
|
||||
(*in)->buffered = 0;
|
||||
(*in)->blocking = BLK_ON;
|
||||
(*in)->timeout = -1;
|
||||
(*in)->ungetchar = -1;
|
||||
(*in)->flags = APR_INHERIT;
|
||||
#if APR_HAS_THREADS
|
||||
(*in)->thlock = NULL;
|
||||
#endif
|
||||
#ifndef WAITIO_USES_POLL
|
||||
(*in)->pollset = NULL;
|
||||
#endif
|
||||
(*out) = (apr_file_t *)apr_pcalloc(pool_out, sizeof(apr_file_t));
|
||||
(*out)->pool = pool_out;
|
||||
(*out)->filedes = filedes[1];
|
||||
(*out)->is_pipe = 1;
|
||||
(*out)->fname = NULL;
|
||||
(*out)->buffered = 0;
|
||||
(*out)->blocking = BLK_ON;
|
||||
(*out)->flags = APR_INHERIT;
|
||||
(*out)->timeout = -1;
|
||||
#if APR_HAS_THREADS
|
||||
(*out)->thlock = NULL;
|
||||
#endif
|
||||
#ifndef WAITIO_USES_POLL
|
||||
(*out)->pollset = NULL;
|
||||
#endif
|
||||
apr_pool_cleanup_register((*in)->pool, (void *)(*in), apr_unix_file_cleanup,
|
||||
apr_pool_cleanup_null);
|
||||
apr_pool_cleanup_register((*out)->pool, (void *)(*out), apr_unix_file_cleanup,
|
||||
apr_pool_cleanup_null);
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
static void file_pipe_block(apr_file_t **in, apr_file_t **out, apr_int32_t blocking)
|
||||
{
|
||||
switch (blocking) {
|
||||
case APR_FULL_BLOCK:
|
||||
break;
|
||||
case APR_READ_BLOCK:
|
||||
apr_file_pipe_timeout_set(*out, 0);
|
||||
break;
|
||||
case APR_WRITE_BLOCK:
|
||||
apr_file_pipe_timeout_set(*in, 0);
|
||||
break;
|
||||
default:
|
||||
apr_file_pipe_timeout_set(*out, 0);
|
||||
apr_file_pipe_timeout_set(*in, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_pipe_create(apr_file_t **in,
|
||||
apr_file_t **out, apr_pool_t *pool)
|
||||
{
|
||||
return file_pipe_create(in, out, pool, pool);
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_pipe_create_ex(apr_file_t **in,
|
||||
apr_file_t **out,
|
||||
apr_int32_t blocking,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
apr_status_t status;
|
||||
|
||||
if ((status = file_pipe_create(in, out, pool, pool)) != APR_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
file_pipe_block(in, out, blocking);
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_pipe_create_pools(apr_file_t **in,
|
||||
apr_file_t **out, apr_int32_t blocking, apr_pool_t *pool_in, apr_pool_t *pool_out)
|
||||
{
|
||||
apr_status_t status;
|
||||
|
||||
if ((status = file_pipe_create(in, out, pool_in, pool_out)) != APR_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
file_pipe_block(in, out, blocking);
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_namedpipe_create(const char *filename,
|
||||
apr_fileperms_t perm, apr_pool_t *pool)
|
||||
{
|
||||
mode_t mode = apr_unix_perms2mode(perm);
|
||||
|
||||
if (mkfifo(filename, mode) == -1) {
|
||||
return errno;
|
||||
}
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+528
@@ -0,0 +1,528 @@
|
||||
/* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "apr_arch_file_io.h"
|
||||
#include "apr_strings.h"
|
||||
#include "apr_thread_mutex.h"
|
||||
#include "apr_support.h"
|
||||
|
||||
/* The only case where we don't use wait_for_io_or_timeout is on
|
||||
* pre-BONE BeOS, so this check should be sufficient and simpler */
|
||||
#if !defined(BEOS_R5)
|
||||
#define USE_WAIT_FOR_IO
|
||||
#endif
|
||||
|
||||
static apr_status_t file_read_buffered(apr_file_t *thefile, void *buf,
|
||||
apr_size_t *nbytes)
|
||||
{
|
||||
apr_ssize_t rv;
|
||||
char *pos = (char *)buf;
|
||||
apr_uint64_t blocksize;
|
||||
apr_uint64_t size = *nbytes;
|
||||
|
||||
if (thefile->direction == 1) {
|
||||
rv = apr_file_flush_locked(thefile);
|
||||
if (rv) {
|
||||
return rv;
|
||||
}
|
||||
thefile->bufpos = 0;
|
||||
thefile->direction = 0;
|
||||
thefile->dataRead = 0;
|
||||
}
|
||||
|
||||
rv = 0;
|
||||
if (thefile->ungetchar != -1) {
|
||||
*pos = (char)thefile->ungetchar;
|
||||
++pos;
|
||||
--size;
|
||||
thefile->ungetchar = -1;
|
||||
}
|
||||
while (rv == 0 && size > 0) {
|
||||
if (thefile->bufpos >= thefile->dataRead) {
|
||||
int bytesread = read(thefile->filedes, thefile->buffer,
|
||||
thefile->bufsize);
|
||||
if (bytesread == 0) {
|
||||
thefile->eof_hit = TRUE;
|
||||
rv = APR_EOF;
|
||||
break;
|
||||
}
|
||||
else if (bytesread == -1) {
|
||||
rv = errno;
|
||||
break;
|
||||
}
|
||||
thefile->dataRead = bytesread;
|
||||
thefile->filePtr += thefile->dataRead;
|
||||
thefile->bufpos = 0;
|
||||
}
|
||||
|
||||
blocksize = size > thefile->dataRead - thefile->bufpos ? thefile->dataRead - thefile->bufpos : size;
|
||||
memcpy(pos, thefile->buffer + thefile->bufpos, blocksize);
|
||||
thefile->bufpos += blocksize;
|
||||
pos += blocksize;
|
||||
size -= blocksize;
|
||||
}
|
||||
|
||||
*nbytes = pos - (char *)buf;
|
||||
if (*nbytes) {
|
||||
rv = 0;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_read(apr_file_t *thefile, void *buf, apr_size_t *nbytes)
|
||||
{
|
||||
apr_ssize_t rv;
|
||||
apr_size_t bytes_read;
|
||||
|
||||
if (*nbytes <= 0) {
|
||||
*nbytes = 0;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
if (thefile->buffered) {
|
||||
file_lock(thefile);
|
||||
rv = file_read_buffered(thefile, buf, nbytes);
|
||||
file_unlock(thefile);
|
||||
return rv;
|
||||
}
|
||||
else {
|
||||
bytes_read = 0;
|
||||
if (thefile->ungetchar != -1) {
|
||||
bytes_read = 1;
|
||||
*(char *)buf = (char)thefile->ungetchar;
|
||||
buf = (char *)buf + 1;
|
||||
(*nbytes)--;
|
||||
thefile->ungetchar = -1;
|
||||
if (*nbytes == 0) {
|
||||
*nbytes = bytes_read;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
rv = read(thefile->filedes, buf, *nbytes);
|
||||
} while (rv == -1 && errno == EINTR);
|
||||
#ifdef USE_WAIT_FOR_IO
|
||||
if (rv == -1 &&
|
||||
(errno == EAGAIN || errno == EWOULDBLOCK) &&
|
||||
thefile->timeout != 0) {
|
||||
apr_status_t arv = apr_wait_for_io_or_timeout(thefile, NULL, 1);
|
||||
if (arv != APR_SUCCESS) {
|
||||
*nbytes = bytes_read;
|
||||
return arv;
|
||||
}
|
||||
else {
|
||||
do {
|
||||
rv = read(thefile->filedes, buf, *nbytes);
|
||||
} while (rv == -1 && errno == EINTR);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
*nbytes = bytes_read;
|
||||
if (rv == 0) {
|
||||
thefile->eof_hit = TRUE;
|
||||
return APR_EOF;
|
||||
}
|
||||
if (rv > 0) {
|
||||
*nbytes += rv;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
return errno;
|
||||
}
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_write(apr_file_t *thefile, const void *buf, apr_size_t *nbytes)
|
||||
{
|
||||
apr_size_t rv;
|
||||
|
||||
if (thefile->buffered) {
|
||||
char *pos = (char *)buf;
|
||||
int blocksize;
|
||||
int size = *nbytes;
|
||||
|
||||
file_lock(thefile);
|
||||
|
||||
if ( thefile->direction == 0 ) {
|
||||
/* Position file pointer for writing at the offset we are
|
||||
* logically reading from
|
||||
*/
|
||||
apr_int64_t offset = thefile->filePtr - thefile->dataRead + thefile->bufpos;
|
||||
if (offset != thefile->filePtr)
|
||||
lseek(thefile->filedes, offset, SEEK_SET);
|
||||
thefile->bufpos = thefile->dataRead = 0;
|
||||
thefile->direction = 1;
|
||||
}
|
||||
|
||||
rv = 0;
|
||||
while (rv == 0 && size > 0) {
|
||||
if (thefile->bufpos == thefile->bufsize) /* write buffer is full*/
|
||||
rv = apr_file_flush_locked(thefile);
|
||||
|
||||
blocksize = size > thefile->bufsize - thefile->bufpos ?
|
||||
thefile->bufsize - thefile->bufpos : size;
|
||||
memcpy(thefile->buffer + thefile->bufpos, pos, blocksize);
|
||||
thefile->bufpos += blocksize;
|
||||
pos += blocksize;
|
||||
size -= blocksize;
|
||||
}
|
||||
|
||||
file_unlock(thefile);
|
||||
|
||||
return rv;
|
||||
}
|
||||
else {
|
||||
do {
|
||||
rv = write(thefile->filedes, buf, *nbytes);
|
||||
} while (rv == (apr_size_t)-1 && errno == EINTR);
|
||||
#ifdef USE_WAIT_FOR_IO
|
||||
if (rv == (apr_size_t)-1 &&
|
||||
(errno == EAGAIN || errno == EWOULDBLOCK) &&
|
||||
thefile->timeout != 0) {
|
||||
apr_status_t arv = apr_wait_for_io_or_timeout(thefile, NULL, 0);
|
||||
if (arv != APR_SUCCESS) {
|
||||
*nbytes = 0;
|
||||
return arv;
|
||||
}
|
||||
else {
|
||||
do {
|
||||
do {
|
||||
rv = write(thefile->filedes, buf, *nbytes);
|
||||
} while (rv == (apr_size_t)-1 && errno == EINTR);
|
||||
if (rv == (apr_size_t)-1 &&
|
||||
(errno == EAGAIN || errno == EWOULDBLOCK)) {
|
||||
*nbytes /= 2; /* yes, we'll loop if kernel lied
|
||||
* and we can't even write 1 byte
|
||||
*/
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
} while (1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (rv == (apr_size_t)-1) {
|
||||
(*nbytes) = 0;
|
||||
return errno;
|
||||
}
|
||||
*nbytes = rv;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_writev(apr_file_t *thefile, const struct iovec *vec,
|
||||
apr_size_t nvec, apr_size_t *nbytes)
|
||||
{
|
||||
#ifdef HAVE_WRITEV
|
||||
apr_status_t rv;
|
||||
apr_ssize_t bytes;
|
||||
|
||||
if (thefile->buffered) {
|
||||
file_lock(thefile);
|
||||
|
||||
rv = apr_file_flush_locked(thefile);
|
||||
if (rv != APR_SUCCESS) {
|
||||
file_unlock(thefile);
|
||||
return rv;
|
||||
}
|
||||
if (thefile->direction == 0) {
|
||||
/* Position file pointer for writing at the offset we are
|
||||
* logically reading from
|
||||
*/
|
||||
apr_int64_t offset = thefile->filePtr - thefile->dataRead +
|
||||
thefile->bufpos;
|
||||
if (offset != thefile->filePtr)
|
||||
lseek(thefile->filedes, offset, SEEK_SET);
|
||||
thefile->bufpos = thefile->dataRead = 0;
|
||||
}
|
||||
|
||||
file_unlock(thefile);
|
||||
}
|
||||
|
||||
if ((bytes = writev(thefile->filedes, vec, nvec)) < 0) {
|
||||
*nbytes = 0;
|
||||
rv = errno;
|
||||
}
|
||||
else {
|
||||
*nbytes = bytes;
|
||||
rv = APR_SUCCESS;
|
||||
}
|
||||
return rv;
|
||||
#else
|
||||
/**
|
||||
* The problem with trying to output the entire iovec is that we cannot
|
||||
* maintain the behaviour that a real writev would have. If we iterate
|
||||
* over the iovec one at a time, we lose the atomic properties of
|
||||
* writev(). The other option is to combine the entire iovec into one
|
||||
* buffer that we could then send in one call to write(). This is not
|
||||
* reasonable since we do not know how much data an iovec could contain.
|
||||
*
|
||||
* The only reasonable option, that maintains the semantics of a real
|
||||
* writev(), is to only write the first iovec. Callers of file_writev()
|
||||
* must deal with partial writes as they normally would. If you want to
|
||||
* ensure an entire iovec is written, use apr_file_writev_full().
|
||||
*/
|
||||
|
||||
*nbytes = vec[0].iov_len;
|
||||
return apr_file_write(thefile, vec[0].iov_base, nbytes);
|
||||
#endif
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_putc(char ch, apr_file_t *thefile)
|
||||
{
|
||||
apr_size_t nbytes = 1;
|
||||
|
||||
return apr_file_write(thefile, &ch, &nbytes);
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_ungetc(char ch, apr_file_t *thefile)
|
||||
{
|
||||
thefile->ungetchar = (unsigned char)ch;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_getc(char *ch, apr_file_t *thefile)
|
||||
{
|
||||
apr_size_t nbytes = 1;
|
||||
|
||||
return apr_file_read(thefile, ch, &nbytes);
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_puts(const char *str, apr_file_t *thefile)
|
||||
{
|
||||
return apr_file_write_full(thefile, str, strlen(str), NULL);
|
||||
}
|
||||
|
||||
apr_status_t apr_file_flush_locked(apr_file_t *thefile)
|
||||
{
|
||||
apr_status_t rv = APR_SUCCESS;
|
||||
|
||||
if (thefile->direction == 1 && thefile->bufpos) {
|
||||
apr_ssize_t written = 0, ret;
|
||||
|
||||
do {
|
||||
ret = write(thefile->filedes, thefile->buffer + written,
|
||||
thefile->bufpos - written);
|
||||
if (ret > 0)
|
||||
written += ret;
|
||||
} while (written < thefile->bufpos &&
|
||||
(ret > 0 || (ret == -1 && errno == EINTR)));
|
||||
if (ret == -1) {
|
||||
rv = errno;
|
||||
} else {
|
||||
thefile->filePtr += written;
|
||||
thefile->bufpos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_flush(apr_file_t *thefile)
|
||||
{
|
||||
apr_status_t rv = APR_SUCCESS;
|
||||
|
||||
if (thefile->buffered) {
|
||||
file_lock(thefile);
|
||||
rv = apr_file_flush_locked(thefile);
|
||||
file_unlock(thefile);
|
||||
}
|
||||
/* There isn't anything to do if we aren't buffering the output
|
||||
* so just return success.
|
||||
*/
|
||||
return rv;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_sync(apr_file_t *thefile)
|
||||
{
|
||||
apr_status_t rv = APR_SUCCESS;
|
||||
|
||||
file_lock(thefile);
|
||||
|
||||
if (thefile->buffered) {
|
||||
rv = apr_file_flush_locked(thefile);
|
||||
|
||||
if (rv != APR_SUCCESS) {
|
||||
file_unlock(thefile);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
if (fsync(thefile->filedes)) {
|
||||
rv = apr_get_os_error();
|
||||
}
|
||||
|
||||
file_unlock(thefile);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_datasync(apr_file_t *thefile)
|
||||
{
|
||||
apr_status_t rv = APR_SUCCESS;
|
||||
|
||||
file_lock(thefile);
|
||||
|
||||
if (thefile->buffered) {
|
||||
rv = apr_file_flush_locked(thefile);
|
||||
|
||||
if (rv != APR_SUCCESS) {
|
||||
file_unlock(thefile);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_FDATASYNC
|
||||
if (fdatasync(thefile->filedes)) {
|
||||
#elif defined(F_FULLFSYNC)
|
||||
if (fcntl(thefile->filedes, F_FULLFSYNC)) {
|
||||
#else
|
||||
if (fsync(thefile->filedes)) {
|
||||
#endif
|
||||
rv = apr_get_os_error();
|
||||
}
|
||||
|
||||
file_unlock(thefile);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_gets(char *str, int len, apr_file_t *thefile)
|
||||
{
|
||||
apr_status_t rv = APR_SUCCESS; /* get rid of gcc warning */
|
||||
apr_size_t nbytes;
|
||||
const char *str_start = str;
|
||||
char *final = str + len - 1;
|
||||
|
||||
if (len <= 1) {
|
||||
/* sort of like fgets(), which returns NULL and stores no bytes
|
||||
*/
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
/* If we have an underlying buffer, we can be *much* more efficient
|
||||
* and skip over the apr_file_read calls.
|
||||
*/
|
||||
if (thefile->buffered) {
|
||||
file_lock(thefile);
|
||||
|
||||
if (thefile->direction == 1) {
|
||||
rv = apr_file_flush_locked(thefile);
|
||||
if (rv) {
|
||||
file_unlock(thefile);
|
||||
return rv;
|
||||
}
|
||||
|
||||
thefile->direction = 0;
|
||||
thefile->bufpos = 0;
|
||||
thefile->dataRead = 0;
|
||||
}
|
||||
|
||||
while (str < final) { /* leave room for trailing '\0' */
|
||||
/* Force ungetc leftover to call apr_file_read. */
|
||||
if (thefile->bufpos < thefile->dataRead &&
|
||||
thefile->ungetchar == -1) {
|
||||
*str = thefile->buffer[thefile->bufpos++];
|
||||
}
|
||||
else {
|
||||
nbytes = 1;
|
||||
rv = file_read_buffered(thefile, str, &nbytes);
|
||||
if (rv != APR_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (*str == '\n') {
|
||||
++str;
|
||||
break;
|
||||
}
|
||||
++str;
|
||||
}
|
||||
file_unlock(thefile);
|
||||
}
|
||||
else {
|
||||
while (str < final) { /* leave room for trailing '\0' */
|
||||
nbytes = 1;
|
||||
rv = apr_file_read(thefile, str, &nbytes);
|
||||
if (rv != APR_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
if (*str == '\n') {
|
||||
++str;
|
||||
break;
|
||||
}
|
||||
++str;
|
||||
}
|
||||
}
|
||||
|
||||
/* We must store a terminating '\0' if we've stored any chars. We can
|
||||
* get away with storing it if we hit an error first.
|
||||
*/
|
||||
*str = '\0';
|
||||
if (str > str_start) {
|
||||
/* we stored chars; don't report EOF or any other errors;
|
||||
* the app will find out about that on the next call
|
||||
*/
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
struct apr_file_printf_data {
|
||||
apr_vformatter_buff_t vbuff;
|
||||
apr_file_t *fptr;
|
||||
char *buf;
|
||||
};
|
||||
|
||||
static int file_printf_flush(apr_vformatter_buff_t *buff)
|
||||
{
|
||||
struct apr_file_printf_data *data = (struct apr_file_printf_data *)buff;
|
||||
|
||||
if (apr_file_write_full(data->fptr, data->buf,
|
||||
data->vbuff.curpos - data->buf, NULL)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
data->vbuff.curpos = data->buf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
APR_DECLARE_NONSTD(int) apr_file_printf(apr_file_t *fptr,
|
||||
const char *format, ...)
|
||||
{
|
||||
struct apr_file_printf_data data;
|
||||
va_list ap;
|
||||
int count;
|
||||
|
||||
/* don't really need a HUGE_STRING_LEN anymore */
|
||||
data.buf = malloc(HUGE_STRING_LEN);
|
||||
if (data.buf == NULL) {
|
||||
return -1;
|
||||
}
|
||||
data.vbuff.curpos = data.buf;
|
||||
data.vbuff.endpos = data.buf + HUGE_STRING_LEN;
|
||||
data.fptr = fptr;
|
||||
va_start(ap, format);
|
||||
count = apr_vformatter(file_printf_flush,
|
||||
(apr_vformatter_buff_t *)&data, format, ap);
|
||||
/* apr_vformatter does not call flush for the last bits */
|
||||
if (count >= 0) file_printf_flush((apr_vformatter_buff_t *)&data);
|
||||
|
||||
va_end(ap);
|
||||
|
||||
free(data.buf);
|
||||
|
||||
return count;
|
||||
}
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
/* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "apr_arch_file_io.h"
|
||||
|
||||
static apr_status_t setptr(apr_file_t *thefile, apr_off_t pos )
|
||||
{
|
||||
apr_off_t newbufpos;
|
||||
apr_status_t rv;
|
||||
|
||||
if (thefile->direction == 1) {
|
||||
rv = apr_file_flush_locked(thefile);
|
||||
if (rv) {
|
||||
return rv;
|
||||
}
|
||||
thefile->bufpos = thefile->direction = thefile->dataRead = 0;
|
||||
}
|
||||
|
||||
newbufpos = pos - (thefile->filePtr - thefile->dataRead);
|
||||
if (newbufpos >= 0 && newbufpos <= thefile->dataRead) {
|
||||
thefile->bufpos = newbufpos;
|
||||
rv = APR_SUCCESS;
|
||||
}
|
||||
else {
|
||||
if (lseek(thefile->filedes, pos, SEEK_SET) != -1) {
|
||||
thefile->bufpos = thefile->dataRead = 0;
|
||||
thefile->filePtr = pos;
|
||||
rv = APR_SUCCESS;
|
||||
}
|
||||
else {
|
||||
rv = errno;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_seek(apr_file_t *thefile, apr_seek_where_t where, apr_off_t *offset)
|
||||
{
|
||||
apr_off_t rv;
|
||||
|
||||
thefile->eof_hit = 0;
|
||||
|
||||
if (thefile->buffered) {
|
||||
int rc = EINVAL;
|
||||
apr_finfo_t finfo;
|
||||
|
||||
file_lock(thefile);
|
||||
|
||||
switch (where) {
|
||||
case APR_SET:
|
||||
rc = setptr(thefile, *offset);
|
||||
break;
|
||||
|
||||
case APR_CUR:
|
||||
rc = setptr(thefile, thefile->filePtr - thefile->dataRead + thefile->bufpos + *offset);
|
||||
break;
|
||||
|
||||
case APR_END:
|
||||
rc = apr_file_info_get_locked(&finfo, APR_FINFO_SIZE, thefile);
|
||||
if (rc == APR_SUCCESS)
|
||||
rc = setptr(thefile, finfo.size + *offset);
|
||||
break;
|
||||
}
|
||||
|
||||
*offset = thefile->filePtr - thefile->dataRead + thefile->bufpos;
|
||||
|
||||
file_unlock(thefile);
|
||||
|
||||
return rc;
|
||||
}
|
||||
else {
|
||||
rv = lseek(thefile->filedes, *offset, where);
|
||||
if (rv == -1) {
|
||||
*offset = -1;
|
||||
return errno;
|
||||
}
|
||||
else {
|
||||
*offset = rv;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
apr_status_t apr_file_trunc(apr_file_t *fp, apr_off_t offset)
|
||||
{
|
||||
if (fp->buffered) {
|
||||
int rc = 0;
|
||||
file_lock(fp);
|
||||
if (fp->direction == 1 && fp->bufpos != 0) {
|
||||
apr_off_t len = fp->filePtr + fp->bufpos;
|
||||
if (offset < len) {
|
||||
/* New file end fall below our write buffer limit.
|
||||
* Figure out if and what needs to be flushed.
|
||||
*/
|
||||
apr_off_t off = len - offset;
|
||||
if (off >= 0 && off <= fp->bufpos)
|
||||
fp->bufpos = fp->bufpos - (size_t)off;
|
||||
else
|
||||
fp->bufpos = 0;
|
||||
}
|
||||
rc = apr_file_flush_locked(fp);
|
||||
/* Reset buffer positions for write mode */
|
||||
fp->bufpos = fp->direction = fp->dataRead = 0;
|
||||
}
|
||||
else if (fp->direction == 0) {
|
||||
/* Discard the read buffer, as we are about to reposition
|
||||
* ourselves to the end of file.
|
||||
*/
|
||||
fp->bufpos = 0;
|
||||
fp->dataRead = 0;
|
||||
}
|
||||
file_unlock(fp);
|
||||
if (rc) {
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
if (ftruncate(fp->filedes, offset) == -1) {
|
||||
return errno;
|
||||
}
|
||||
return apr_file_seek(fp, APR_SET, &offset);
|
||||
}
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
/* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include "apr_private.h"
|
||||
#include "apr_file_io.h"
|
||||
#include "apr_strings.h"
|
||||
#include "apr_env.h"
|
||||
|
||||
|
||||
/* Try to open a temporary file in the temporary dir, write to it,
|
||||
and then close it. */
|
||||
static int test_tempdir(const char *temp_dir, apr_pool_t *p)
|
||||
{
|
||||
apr_file_t *dummy_file;
|
||||
char *path = apr_pstrcat(p, temp_dir, "/apr-tmp.XXXXXX", NULL);
|
||||
|
||||
if (apr_file_mktemp(&dummy_file, path, 0, p) == APR_SUCCESS) {
|
||||
if (apr_file_putc('!', dummy_file) == APR_SUCCESS) {
|
||||
if (apr_file_close(dummy_file) == APR_SUCCESS) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_temp_dir_get(const char **temp_dir,
|
||||
apr_pool_t *p)
|
||||
{
|
||||
apr_status_t apr_err;
|
||||
const char *try_dirs[] = { "/tmp", "/usr/tmp", "/var/tmp" };
|
||||
const char *try_envs[] = { "TMPDIR", "TMP", "TEMP"};
|
||||
const char *dir;
|
||||
char *cwd;
|
||||
int i;
|
||||
|
||||
/* Our goal is to find a temporary directory suitable for writing
|
||||
into.
|
||||
Here's the order in which we'll try various paths:
|
||||
|
||||
$TMPDIR
|
||||
$TMP
|
||||
$TEMP
|
||||
"C:\TEMP" (windows only)
|
||||
"SYS:\TMP" (netware only)
|
||||
"/tmp"
|
||||
"/var/tmp"
|
||||
"/usr/tmp"
|
||||
P_tmpdir (POSIX define)
|
||||
`pwd`
|
||||
|
||||
NOTE: This algorithm is basically the same one used by Python
|
||||
2.2's tempfile.py module. */
|
||||
|
||||
/* Try the environment first. */
|
||||
for (i = 0; i < (sizeof(try_envs) / sizeof(const char *)); i++) {
|
||||
char *value;
|
||||
apr_err = apr_env_get(&value, try_envs[i], p);
|
||||
if ((apr_err == APR_SUCCESS) && value) {
|
||||
apr_size_t len = strlen(value);
|
||||
if (len && (len < APR_PATH_MAX) && test_tempdir(value, p)) {
|
||||
dir = value;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
/* Next, on Win32, try the C:\TEMP directory. */
|
||||
if (test_tempdir("C:\\TEMP", p)) {
|
||||
dir = "C:\\TEMP";
|
||||
goto end;
|
||||
}
|
||||
#endif
|
||||
#ifdef NETWARE
|
||||
/* Next, on NetWare, try the SYS:/TMP directory. */
|
||||
if (test_tempdir("SYS:/TMP", p)) {
|
||||
dir = "SYS:/TMP";
|
||||
goto end;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Next, try a set of hard-coded paths. */
|
||||
for (i = 0; i < (sizeof(try_dirs) / sizeof(const char *)); i++) {
|
||||
if (test_tempdir(try_dirs[i], p)) {
|
||||
dir = try_dirs[i];
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef P_tmpdir
|
||||
/*
|
||||
* If we have it, use the POSIX definition of where
|
||||
* the tmpdir should be
|
||||
*/
|
||||
if (test_tempdir(P_tmpdir, p)) {
|
||||
dir = P_tmpdir;
|
||||
goto end;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Finally, try the current working directory. */
|
||||
if (APR_SUCCESS == apr_filepath_get(&cwd, APR_FILEPATH_NATIVE, p)) {
|
||||
if (test_tempdir(cwd, p)) {
|
||||
dir = cwd;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
/* We didn't find a suitable temp dir anywhere */
|
||||
return APR_EGENERAL;
|
||||
|
||||
end:
|
||||
*temp_dir = apr_pstrdup(p, dir);
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
Reference in New Issue
Block a user