feat:replace boost library with C++11 std library
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
/* NetWare & Win32 have much in common with regards to file names (both are
|
||||
* DOSish) so it makes sense to share some code
|
||||
*/
|
||||
#include "../win32/filepath.c"
|
||||
@@ -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 "fsio.h"
|
||||
#include "nks/dirio.h"
|
||||
#include "apr_file_io.h"
|
||||
#include "apr_general.h"
|
||||
#include "apr_strings.h"
|
||||
#include "apr_errno.h"
|
||||
#include "apr_hash.h"
|
||||
#include "apr_thread_rwlock.h"
|
||||
|
||||
#ifdef HAVE_UTIME_H
|
||||
#include <utime.h>
|
||||
#endif
|
||||
|
||||
#define APR_HAS_PSA
|
||||
|
||||
static apr_filetype_e filetype_from_mode(mode_t mode)
|
||||
{
|
||||
apr_filetype_e type = APR_NOFILE;
|
||||
|
||||
if (S_ISREG(mode))
|
||||
type = APR_REG;
|
||||
else if (S_ISDIR(mode))
|
||||
type = APR_DIR;
|
||||
else if (S_ISCHR(mode))
|
||||
type = APR_CHR;
|
||||
else if (S_ISBLK(mode))
|
||||
type = APR_BLK;
|
||||
else if (S_ISFIFO(mode))
|
||||
type = APR_PIPE;
|
||||
else if (S_ISLNK(mode))
|
||||
type = APR_LNK;
|
||||
else if (S_ISSOCK(mode))
|
||||
type = APR_SOCK;
|
||||
else
|
||||
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->inode = info->st_ino;
|
||||
finfo->device = info->st_dev;
|
||||
finfo->nlink = info->st_nlink;
|
||||
|
||||
apr_time_ansi_put(&finfo->atime, info->st_atime.tv_sec);
|
||||
apr_time_ansi_put(&finfo->mtime, info->st_mtime.tv_sec);
|
||||
apr_time_ansi_put(&finfo->ctime, info->st_ctime.tv_sec);
|
||||
|
||||
#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) {
|
||||
/* XXX: flush here is not mutex protected */
|
||||
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);
|
||||
}
|
||||
|
||||
#ifndef APR_HAS_PSA
|
||||
static apr_status_t stat_cache_cleanup(void *data)
|
||||
{
|
||||
apr_pool_t *p = (apr_pool_t *)getGlobalPool();
|
||||
apr_hash_index_t *hi;
|
||||
apr_hash_t *statCache = (apr_hash_t*)data;
|
||||
char *key;
|
||||
apr_ssize_t keylen;
|
||||
NXPathCtx_t pathctx;
|
||||
|
||||
for (hi = apr_hash_first(p, statCache); hi; hi = apr_hash_next(hi)) {
|
||||
apr_hash_this(hi, (const void**)&key, &keylen, (void**)&pathctx);
|
||||
|
||||
if (pathctx) {
|
||||
NXFreePathContext(pathctx);
|
||||
}
|
||||
}
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
int cstat (NXPathCtx_t ctx, char *path, struct stat *buf, unsigned long requestmap, apr_pool_t *p)
|
||||
{
|
||||
apr_pool_t *gPool = (apr_pool_t *)getGlobalPool();
|
||||
apr_hash_t *statCache = NULL;
|
||||
apr_thread_rwlock_t *rwlock = NULL;
|
||||
|
||||
NXPathCtx_t pathctx = 0;
|
||||
char *ptr = NULL, *tr;
|
||||
int len = 0, x;
|
||||
char *ppath;
|
||||
char *pinfo;
|
||||
|
||||
if (ctx == 1) {
|
||||
|
||||
/* If there isn't a global pool then just stat the file
|
||||
and return */
|
||||
if (!gPool) {
|
||||
char poolname[50];
|
||||
|
||||
if (apr_pool_create(&gPool, NULL) != APR_SUCCESS) {
|
||||
return getstat(ctx, path, buf, requestmap);
|
||||
}
|
||||
|
||||
setGlobalPool(gPool);
|
||||
apr_pool_tag(gPool, apr_pstrdup(gPool, "cstat_mem_pool"));
|
||||
|
||||
statCache = apr_hash_make(gPool);
|
||||
apr_pool_userdata_set ((void*)statCache, "STAT_CACHE", stat_cache_cleanup, gPool);
|
||||
|
||||
apr_thread_rwlock_create(&rwlock, gPool);
|
||||
apr_pool_userdata_set ((void*)rwlock, "STAT_CACHE_LOCK", apr_pool_cleanup_null, gPool);
|
||||
}
|
||||
else {
|
||||
apr_pool_userdata_get((void**)&statCache, "STAT_CACHE", gPool);
|
||||
apr_pool_userdata_get((void**)&rwlock, "STAT_CACHE_LOCK", gPool);
|
||||
}
|
||||
|
||||
if (!gPool || !statCache || !rwlock) {
|
||||
return getstat(ctx, path, buf, requestmap);
|
||||
}
|
||||
|
||||
for (x = 0,tr = path;*tr != '\0';tr++,x++) {
|
||||
if (*tr == '\\' || *tr == '/') {
|
||||
ptr = tr;
|
||||
len = x;
|
||||
}
|
||||
if (*tr == ':') {
|
||||
ptr = "\\";
|
||||
len = x;
|
||||
}
|
||||
}
|
||||
|
||||
if (ptr) {
|
||||
ppath = apr_pstrndup (p, path, len);
|
||||
strlwr(ppath);
|
||||
if (ptr[1] != '\0') {
|
||||
ptr++;
|
||||
}
|
||||
/* If the path ended in a trailing slash then our result path
|
||||
will be a single slash. To avoid stat'ing the root with a
|
||||
slash, we need to make sure we stat the current directory
|
||||
with a dot */
|
||||
if (((*ptr == '/') || (*ptr == '\\')) && (*(ptr+1) == '\0')) {
|
||||
pinfo = apr_pstrdup (p, ".");
|
||||
}
|
||||
else {
|
||||
pinfo = apr_pstrdup (p, ptr);
|
||||
}
|
||||
}
|
||||
|
||||
/* If we have a statCache then try to pull the information
|
||||
from the cache. Otherwise just stat the file and return.*/
|
||||
if (statCache) {
|
||||
apr_thread_rwlock_rdlock(rwlock);
|
||||
pathctx = (NXPathCtx_t) apr_hash_get(statCache, ppath, APR_HASH_KEY_STRING);
|
||||
apr_thread_rwlock_unlock(rwlock);
|
||||
if (pathctx) {
|
||||
return getstat(pathctx, pinfo, buf, requestmap);
|
||||
}
|
||||
else {
|
||||
int err;
|
||||
|
||||
err = NXCreatePathContext(0, ppath, 0, NULL, &pathctx);
|
||||
if (!err) {
|
||||
apr_thread_rwlock_wrlock(rwlock);
|
||||
apr_hash_set(statCache, apr_pstrdup(gPool,ppath) , APR_HASH_KEY_STRING, (void*)pathctx);
|
||||
apr_thread_rwlock_unlock(rwlock);
|
||||
return getstat(pathctx, pinfo, buf, requestmap);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return getstat(ctx, path, buf, requestmap);
|
||||
}
|
||||
#endif
|
||||
|
||||
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;
|
||||
NXPathCtx_t pathCtx = 0;
|
||||
|
||||
getcwdpath(NULL, &pathCtx, CTX_ACTUAL_CWD);
|
||||
#ifdef APR_HAS_PSA
|
||||
srv = getstat(pathCtx, (char*)fname, &info, ST_STAT_BITS|ST_NAME_BIT);
|
||||
#else
|
||||
srv = cstat(pathCtx, (char*)fname, &info, ST_STAT_BITS|ST_NAME_BIT, pool);
|
||||
#endif
|
||||
errno = srv;
|
||||
|
||||
if (srv == 0) {
|
||||
finfo->pool = pool;
|
||||
finfo->fname = fname;
|
||||
fill_out_finfo(finfo, &info, wanted);
|
||||
if (wanted & APR_FINFO_LINK)
|
||||
wanted &= ~APR_FINFO_LINK;
|
||||
if (wanted & APR_FINFO_NAME) {
|
||||
finfo->name = apr_pstrdup(pool, info.st_name);
|
||||
finfo->valid |= APR_FINFO_NAME;
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
/* 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_arch_file_io.h"
|
||||
#include "apr_strings.h"
|
||||
|
||||
apr_status_t filepath_root_case(char **rootpath, char *root, apr_pool_t *p)
|
||||
{
|
||||
/* See the Windows code to figure out what to do here.
|
||||
It probably checks to make sure that the root exists
|
||||
and case it correctly according to the file system.
|
||||
*/
|
||||
*rootpath = apr_pstrdup(p, root);
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
apr_status_t filepath_has_drive(const char *rootpath, int only, apr_pool_t *p)
|
||||
{
|
||||
char *s;
|
||||
|
||||
if (rootpath) {
|
||||
s = strchr (rootpath, ':');
|
||||
if (only)
|
||||
/* Test if the path only has a drive/volume and nothing else
|
||||
*/
|
||||
return (s && (s != rootpath) && !s[1]);
|
||||
else
|
||||
/* Test if the path includes a drive/volume
|
||||
*/
|
||||
return (s && (s != rootpath));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
apr_status_t filepath_compare_drive(const char *path1, const char *path2, apr_pool_t *p)
|
||||
{
|
||||
char *s1, *s2;
|
||||
|
||||
if (path1 && path2) {
|
||||
s1 = strchr (path1, ':');
|
||||
s2 = strchr (path2, ':');
|
||||
|
||||
/* Make sure that they both have a drive/volume delimiter
|
||||
and are the same size. Then see if they match.
|
||||
*/
|
||||
if (s1 && s2 && ((s1-path1) == (s2-path2))) {
|
||||
return strnicmp (s1, s2, s1-path1);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_filepath_get(char **rootpath, apr_int32_t flags,
|
||||
apr_pool_t *p)
|
||||
{
|
||||
char path[APR_PATH_MAX];
|
||||
char *ptr;
|
||||
|
||||
/* use getcwdpath to make sure that we get the volume name*/
|
||||
if (!getcwdpath(path, NULL, 0)) {
|
||||
if (errno == ERANGE)
|
||||
return APR_ENAMETOOLONG;
|
||||
else
|
||||
return errno;
|
||||
}
|
||||
/* Strip off the server name if there is one*/
|
||||
ptr = strpbrk(path, "\\/:");
|
||||
if (!ptr) {
|
||||
return APR_ENOENT;
|
||||
}
|
||||
if (*ptr == ':') {
|
||||
ptr = path;
|
||||
}
|
||||
*rootpath = apr_pstrdup(p, ptr);
|
||||
if (!(flags & APR_FILEPATH_NATIVE)) {
|
||||
for (ptr = *rootpath; *ptr; ++ptr) {
|
||||
if (*ptr == '\\')
|
||||
*ptr = '/';
|
||||
}
|
||||
}
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_filepath_set(const char *rootpath,
|
||||
apr_pool_t *p)
|
||||
{
|
||||
if (chdir2(rootpath) != 0)
|
||||
return errno;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/* 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 <nks/fsio.h>
|
||||
#include "apr_arch_file_io.h"
|
||||
|
||||
|
||||
apr_status_t apr_file_lock(apr_file_t *thefile, int type)
|
||||
{
|
||||
int fc;
|
||||
|
||||
fc = (type & APR_FLOCK_NONBLOCK) ? NX_RANGE_LOCK_TRYLOCK : NX_RANGE_LOCK_CHECK;
|
||||
|
||||
if(NXFileRangeLock(thefile->filedes,fc, 0, 0) == -1)
|
||||
return errno;
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
apr_status_t apr_file_unlock(apr_file_t *thefile)
|
||||
{
|
||||
if(NXFileRangeUnlock(thefile->filedes,NX_RANGE_LOCK_CANCEL,0 , 0) == -1)
|
||||
return errno;
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/* 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" /* 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"
|
||||
|
||||
#include <stdlib.h> /* for mkstemp() - Single Unix */
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_mktemp(apr_file_t **fp, char *template, apr_int32_t flags, apr_pool_t *p)
|
||||
{
|
||||
int fd;
|
||||
apr_status_t rv;
|
||||
|
||||
flags = (!flags) ? APR_FOPEN_CREATE | APR_FOPEN_READ | APR_FOPEN_WRITE |
|
||||
APR_FOPEN_DELONCLOSE : flags & ~APR_FOPEN_EXCL;
|
||||
|
||||
fd = mkstemp(template);
|
||||
if (fd == -1) {
|
||||
return errno;
|
||||
}
|
||||
/* We need to reopen the file to get rid of the o_excl flag.
|
||||
* Otherwise file locking will not allow the file to be shared.
|
||||
*/
|
||||
close(fd);
|
||||
if ((rv = apr_file_open(fp, template, flags|APR_FOPEN_NOCLEANUP,
|
||||
APR_UREAD | APR_UWRITE, p)) == APR_SUCCESS) {
|
||||
|
||||
|
||||
if (!(flags & APR_FOPEN_NOCLEANUP)) {
|
||||
int flags;
|
||||
|
||||
if ((flags = fcntl((*fp)->filedes, F_GETFD)) == -1)
|
||||
return errno;
|
||||
|
||||
flags |= FD_CLOEXEC;
|
||||
if (fcntl((*fp)->filedes, F_SETFD, flags) == -1)
|
||||
return errno;
|
||||
|
||||
apr_pool_cleanup_register((*fp)->pool, (void *)(*fp),
|
||||
apr_unix_file_cleanup,
|
||||
apr_unix_child_file_cleanup);
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
+239
@@ -0,0 +1,239 @@
|
||||
/* 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 <stdio.h>
|
||||
#include <nks/fsio.h>
|
||||
#include <nks/errno.h>
|
||||
|
||||
#include "apr_arch_file_io.h"
|
||||
#include "apr_strings.h"
|
||||
#include "apr_portable.h"
|
||||
#include "apr_arch_inherit.h"
|
||||
|
||||
static apr_status_t pipeblock(apr_file_t *thepipe)
|
||||
{
|
||||
#ifdef USE_FLAGS
|
||||
unsigned long flags;
|
||||
|
||||
if (fcntl(thepipe->filedes, F_GETFL, &flags) != -1)
|
||||
{
|
||||
flags &= ~FNDELAY;
|
||||
fcntl(thepipe->filedes, F_SETFL, flags);
|
||||
}
|
||||
#else
|
||||
errno = 0;
|
||||
fcntl(thepipe->filedes, F_SETFL, 0);
|
||||
#endif
|
||||
|
||||
if (errno)
|
||||
return errno;
|
||||
|
||||
thepipe->blocking = BLK_ON;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
static apr_status_t pipenonblock(apr_file_t *thepipe)
|
||||
{
|
||||
#ifdef USE_FLAGS
|
||||
unsigned long flags;
|
||||
|
||||
errno = 0;
|
||||
if (fcntl(thepipe->filedes, F_GETFL, &flags) != -1)
|
||||
{
|
||||
flags |= FNDELAY;
|
||||
fcntl(thepipe->filedes, F_SETFL, flags);
|
||||
}
|
||||
#else
|
||||
errno = 0;
|
||||
fcntl(thepipe->filedes, F_SETFL, FNDELAY);
|
||||
#endif
|
||||
|
||||
if (errno)
|
||||
return errno;
|
||||
|
||||
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);
|
||||
}
|
||||
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));
|
||||
(*out) = (apr_file_t *)apr_pcalloc(pool_out, sizeof(apr_file_t));
|
||||
|
||||
(*in)->pool = pool_in;
|
||||
(*out)->pool = pool_out;
|
||||
(*in)->filedes = filedes[0];
|
||||
(*out)->filedes = filedes[1];
|
||||
(*in)->flags = APR_INHERIT;
|
||||
(*out)->flags = APR_INHERIT;
|
||||
(*in)->is_pipe =
|
||||
(*out)->is_pipe = 1;
|
||||
(*out)->fname =
|
||||
(*in)->fname = NULL;
|
||||
(*in)->buffered =
|
||||
(*out)->buffered = 0;
|
||||
(*in)->blocking =
|
||||
(*out)->blocking = BLK_ON;
|
||||
(*in)->timeout =
|
||||
(*out)->timeout = -1;
|
||||
(*in)->ungetchar = -1;
|
||||
(*in)->thlock =
|
||||
(*out)->thlock = NULL;
|
||||
(void) apr_pollset_create(&(*in)->pollset, 1, pool_in, 0);
|
||||
(void) apr_pollset_create(&(*out)->pollset, 1, pool_out, 0);
|
||||
|
||||
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)
|
||||
{
|
||||
return APR_ENOTIMPL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/* 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_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;
|
||||
|
||||
apr_thread_mutex_lock(file->mutex);
|
||||
|
||||
if(file->buffered) {
|
||||
/* Flush the existing buffer */
|
||||
rv = apr_file_flush(file);
|
||||
if (rv != APR_SUCCESS) {
|
||||
apr_thread_mutex_unlock(file->mutex);
|
||||
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;
|
||||
}
|
||||
|
||||
apr_thread_mutex_unlock(file->mutex);
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_size_t) apr_file_buffer_size_get(apr_file_t *file)
|
||||
{
|
||||
return file->bufsize;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
#include "../unix/copy.c"
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
/* 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_lib.h"
|
||||
#include "apr_strings.h"
|
||||
#include "apr_portable.h"
|
||||
#include <string.h>
|
||||
|
||||
static apr_status_t dir_cleanup(void *thedir)
|
||||
{
|
||||
apr_dir_t *dir = thedir;
|
||||
return apr_dir_close(dir);
|
||||
}
|
||||
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_dir_open(apr_dir_t **new, const char *dirname, apr_pool_t *pool)
|
||||
{
|
||||
apr_dir_t *thedir = (apr_dir_t *)apr_palloc(pool, sizeof(apr_dir_t));
|
||||
|
||||
if (thedir == NULL)
|
||||
return APR_ENOMEM;
|
||||
|
||||
thedir->pool = pool;
|
||||
thedir->dirname = apr_pstrdup(pool, dirname);
|
||||
|
||||
if (thedir->dirname == NULL)
|
||||
return APR_ENOMEM;
|
||||
|
||||
thedir->handle = 0;
|
||||
thedir->validentry = FALSE;
|
||||
*new = thedir;
|
||||
apr_pool_cleanup_register(pool, thedir, dir_cleanup, apr_pool_cleanup_null);
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_dir_close(apr_dir_t *thedir)
|
||||
{
|
||||
int rv = 0;
|
||||
|
||||
if (thedir->handle) {
|
||||
rv = DosFindClose(thedir->handle);
|
||||
|
||||
if (rv == 0) {
|
||||
thedir->handle = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return APR_FROM_OS_ERROR(rv);
|
||||
}
|
||||
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_dir_read(apr_finfo_t *finfo, apr_int32_t wanted,
|
||||
apr_dir_t *thedir)
|
||||
{
|
||||
int rv;
|
||||
ULONG entries = 1;
|
||||
|
||||
if (thedir->handle == 0) {
|
||||
thedir->handle = HDIR_CREATE;
|
||||
rv = DosFindFirst(apr_pstrcat(thedir->pool, thedir->dirname, "/*", NULL), &thedir->handle,
|
||||
FILE_ARCHIVED|FILE_DIRECTORY|FILE_SYSTEM|FILE_HIDDEN|FILE_READONLY,
|
||||
&thedir->entry, sizeof(thedir->entry), &entries, FIL_STANDARD);
|
||||
} else {
|
||||
rv = DosFindNext(thedir->handle, &thedir->entry, sizeof(thedir->entry), &entries);
|
||||
}
|
||||
|
||||
finfo->pool = thedir->pool;
|
||||
finfo->fname = NULL;
|
||||
finfo->valid = 0;
|
||||
|
||||
if (rv == 0 && entries == 1) {
|
||||
thedir->validentry = TRUE;
|
||||
|
||||
/* We passed a name off the stack that has popped */
|
||||
finfo->fname = NULL;
|
||||
finfo->size = thedir->entry.cbFile;
|
||||
finfo->csize = thedir->entry.cbFileAlloc;
|
||||
|
||||
/* Only directories & regular files show up in directory listings */
|
||||
finfo->filetype = (thedir->entry.attrFile & FILE_DIRECTORY) ? APR_DIR : APR_REG;
|
||||
|
||||
apr_os2_time_to_apr_time(&finfo->mtime, thedir->entry.fdateLastWrite,
|
||||
thedir->entry.ftimeLastWrite);
|
||||
apr_os2_time_to_apr_time(&finfo->atime, thedir->entry.fdateLastAccess,
|
||||
thedir->entry.ftimeLastAccess);
|
||||
apr_os2_time_to_apr_time(&finfo->ctime, thedir->entry.fdateCreation,
|
||||
thedir->entry.ftimeCreation);
|
||||
|
||||
finfo->name = thedir->entry.achName;
|
||||
finfo->valid = APR_FINFO_NAME | APR_FINFO_MTIME | APR_FINFO_ATIME |
|
||||
APR_FINFO_CTIME | APR_FINFO_TYPE | APR_FINFO_SIZE |
|
||||
APR_FINFO_CSIZE;
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
thedir->validentry = FALSE;
|
||||
|
||||
if (rv)
|
||||
return APR_FROM_OS_ERROR(rv);
|
||||
|
||||
return APR_ENOENT;
|
||||
}
|
||||
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_dir_rewind(apr_dir_t *thedir)
|
||||
{
|
||||
return apr_dir_close(thedir);
|
||||
}
|
||||
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_dir_make(const char *path, apr_fileperms_t perm, apr_pool_t *pool)
|
||||
{
|
||||
return APR_FROM_OS_ERROR(DosCreateDir(path, NULL));
|
||||
}
|
||||
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_dir_remove(const char *path, apr_pool_t *pool)
|
||||
{
|
||||
return APR_FROM_OS_ERROR(DosDeleteDir(path));
|
||||
}
|
||||
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_os_dir_get(apr_os_dir_t **thedir, apr_dir_t *dir)
|
||||
{
|
||||
if (dir == NULL) {
|
||||
return APR_ENODIR;
|
||||
}
|
||||
*thedir = &dir->handle;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
APR_DECLARE(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)->handle = *thedir;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/* 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"
|
||||
#include "apr_lib.h"
|
||||
#include "apr_strings.h"
|
||||
#include <string.h>
|
||||
|
||||
#define IS_SEP(c) (c == '/' || c == '\\')
|
||||
|
||||
/* 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) && IS_SEP(path[len - 1])) {
|
||||
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 (IS_SEP(path[i])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return apr_pstrndup(pool, path, (i < 0) ? 0 : i);
|
||||
}
|
||||
|
||||
|
||||
|
||||
apr_status_t apr_dir_make_recursive(const char *path, apr_fileperms_t perm,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
apr_status_t apr_err = APR_SUCCESS;
|
||||
|
||||
apr_err = apr_dir_make(path, perm, pool); /* Try to make PATH right out */
|
||||
|
||||
if (APR_STATUS_IS_ENOENT(apr_err)) { /* Missing an intermediate dir */
|
||||
char *dir;
|
||||
|
||||
dir = path_remove_last_component(path, pool);
|
||||
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;
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
/* 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 "../unix/fileacc.c"
|
||||
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
/* 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_lib.h"
|
||||
#include "apr_strings.h"
|
||||
#include <string.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 rv;
|
||||
apr_file_t *dup_file;
|
||||
|
||||
if (*new_file == NULL) {
|
||||
dup_file = (apr_file_t *)apr_palloc(p, sizeof(apr_file_t));
|
||||
|
||||
if (dup_file == NULL) {
|
||||
return APR_ENOMEM;
|
||||
}
|
||||
|
||||
dup_file->filedes = -1;
|
||||
} else {
|
||||
dup_file = *new_file;
|
||||
}
|
||||
|
||||
dup_file->pool = p;
|
||||
rv = DosDupHandle(old_file->filedes, &dup_file->filedes);
|
||||
|
||||
if (rv) {
|
||||
return APR_FROM_OS_ERROR(rv);
|
||||
}
|
||||
|
||||
dup_file->fname = apr_pstrdup(dup_file->pool, old_file->fname);
|
||||
dup_file->buffered = old_file->buffered;
|
||||
dup_file->isopen = old_file->isopen;
|
||||
dup_file->flags = old_file->flags & ~APR_INHERIT;
|
||||
/* TODO - dup pipes correctly */
|
||||
dup_file->pipe = old_file->pipe;
|
||||
|
||||
if (*new_file == NULL) {
|
||||
apr_pool_cleanup_register(dup_file->pool, dup_file, apr_file_cleanup,
|
||||
apr_pool_cleanup_null);
|
||||
*new_file = dup_file;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (*new_file) {
|
||||
apr_file_close(*new_file);
|
||||
(*new_file)->filedes = -1;
|
||||
}
|
||||
|
||||
return file_dup(new_file, old_file, p);
|
||||
}
|
||||
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
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 (old_file->mutex) {
|
||||
apr_thread_mutex_create(&((*new_file)->mutex),
|
||||
APR_THREAD_MUTEX_DEFAULT, p);
|
||||
apr_thread_mutex_destroy(old_file->mutex);
|
||||
}
|
||||
}
|
||||
|
||||
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_file_cleanup,
|
||||
apr_file_cleanup);
|
||||
}
|
||||
|
||||
old_file->filedes = -1;
|
||||
apr_pool_cleanup_kill(old_file->pool, (void *)old_file,
|
||||
apr_file_cleanup);
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
/* 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 "../win32/filepath.c"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../unix/filepath_util.c"
|
||||
+241
@@ -0,0 +1,241 @@
|
||||
/* 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 INCL_DOS
|
||||
#define INCL_DOSERRORS
|
||||
#include "apr_arch_file_io.h"
|
||||
#include "apr_file_io.h"
|
||||
#include "apr_lib.h"
|
||||
#include <sys/time.h>
|
||||
#include "apr_strings.h"
|
||||
|
||||
|
||||
static void FS3_to_finfo(apr_finfo_t *finfo, FILESTATUS3 *fstatus)
|
||||
{
|
||||
finfo->protection = (fstatus->attrFile & FILE_READONLY) ? 0x555 : 0x777;
|
||||
|
||||
if (fstatus->attrFile & FILE_DIRECTORY)
|
||||
finfo->filetype = APR_DIR;
|
||||
else
|
||||
finfo->filetype = APR_REG;
|
||||
/* XXX: No other possible types from FS3? */
|
||||
|
||||
finfo->user = 0;
|
||||
finfo->group = 0;
|
||||
finfo->inode = 0;
|
||||
finfo->device = 0;
|
||||
finfo->size = fstatus->cbFile;
|
||||
finfo->csize = fstatus->cbFileAlloc;
|
||||
apr_os2_time_to_apr_time(&finfo->atime, fstatus->fdateLastAccess,
|
||||
fstatus->ftimeLastAccess );
|
||||
apr_os2_time_to_apr_time(&finfo->mtime, fstatus->fdateLastWrite,
|
||||
fstatus->ftimeLastWrite );
|
||||
apr_os2_time_to_apr_time(&finfo->ctime, fstatus->fdateCreation,
|
||||
fstatus->ftimeCreation );
|
||||
finfo->valid = APR_FINFO_TYPE | APR_FINFO_PROT | APR_FINFO_SIZE
|
||||
| APR_FINFO_CSIZE | APR_FINFO_MTIME
|
||||
| APR_FINFO_CTIME | APR_FINFO_ATIME | APR_FINFO_LINK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static apr_status_t handle_type(apr_filetype_e *ftype, HFILE file)
|
||||
{
|
||||
ULONG filetype, fileattr, rc;
|
||||
|
||||
rc = DosQueryHType(file, &filetype, &fileattr);
|
||||
|
||||
if (rc == 0) {
|
||||
switch (filetype & 0xff) {
|
||||
case 0:
|
||||
*ftype = APR_REG;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
*ftype = APR_CHR;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
*ftype = APR_PIPE;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Brian, is this correct???
|
||||
*/
|
||||
*ftype = APR_UNKFILE;
|
||||
break;
|
||||
}
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
return APR_FROM_OS_ERROR(rc);
|
||||
}
|
||||
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_info_get(apr_finfo_t *finfo, apr_int32_t wanted,
|
||||
apr_file_t *thefile)
|
||||
{
|
||||
ULONG rc;
|
||||
FILESTATUS3 fstatus;
|
||||
|
||||
if (thefile->isopen) {
|
||||
if (thefile->buffered) {
|
||||
/* XXX: flush here is not mutex protected */
|
||||
apr_status_t rv = apr_file_flush(thefile);
|
||||
|
||||
if (rv != APR_SUCCESS) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
rc = DosQueryFileInfo(thefile->filedes, FIL_STANDARD, &fstatus, sizeof(fstatus));
|
||||
}
|
||||
else
|
||||
rc = DosQueryPathInfo(thefile->fname, FIL_STANDARD, &fstatus, sizeof(fstatus));
|
||||
|
||||
if (rc == 0) {
|
||||
FS3_to_finfo(finfo, &fstatus);
|
||||
finfo->fname = thefile->fname;
|
||||
|
||||
if (finfo->filetype == APR_REG) {
|
||||
if (thefile->isopen) {
|
||||
return handle_type(&finfo->filetype, thefile->filedes);
|
||||
}
|
||||
} else {
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
finfo->protection = 0;
|
||||
finfo->filetype = APR_NOFILE;
|
||||
return APR_FROM_OS_ERROR(rc);
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_perms_set(const char *fname, apr_fileperms_t perms)
|
||||
{
|
||||
return APR_ENOTIMPL;
|
||||
}
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_stat(apr_finfo_t *finfo, const char *fname,
|
||||
apr_int32_t wanted, apr_pool_t *cont)
|
||||
{
|
||||
ULONG rc;
|
||||
FILESTATUS3 fstatus;
|
||||
|
||||
finfo->protection = 0;
|
||||
finfo->filetype = APR_NOFILE;
|
||||
finfo->name = NULL;
|
||||
rc = DosQueryPathInfo(fname, FIL_STANDARD, &fstatus, sizeof(fstatus));
|
||||
|
||||
if (rc == 0) {
|
||||
FS3_to_finfo(finfo, &fstatus);
|
||||
finfo->fname = fname;
|
||||
|
||||
if (wanted & APR_FINFO_NAME) {
|
||||
ULONG count = 1;
|
||||
HDIR hDir = HDIR_SYSTEM;
|
||||
FILEFINDBUF3 ffb;
|
||||
rc = DosFindFirst(fname, &hDir,
|
||||
FILE_DIRECTORY|FILE_HIDDEN|FILE_SYSTEM|FILE_ARCHIVED,
|
||||
&ffb, sizeof(ffb), &count, FIL_STANDARD);
|
||||
if (rc == 0 && count == 1) {
|
||||
finfo->name = apr_pstrdup(cont, ffb.achName);
|
||||
finfo->valid |= APR_FINFO_NAME;
|
||||
}
|
||||
}
|
||||
} else if (rc == ERROR_INVALID_ACCESS) {
|
||||
memset(finfo, 0, sizeof(apr_finfo_t));
|
||||
finfo->valid = APR_FINFO_TYPE | APR_FINFO_PROT;
|
||||
finfo->protection = 0666;
|
||||
finfo->filetype = APR_CHR;
|
||||
|
||||
if (wanted & APR_FINFO_NAME) {
|
||||
finfo->name = apr_pstrdup(cont, fname);
|
||||
finfo->valid |= APR_FINFO_NAME;
|
||||
}
|
||||
} else {
|
||||
return APR_FROM_OS_ERROR(rc);
|
||||
}
|
||||
|
||||
return (wanted & ~finfo->valid) ? APR_INCOMPLETE : 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 *cont)
|
||||
{
|
||||
FILESTATUS3 fs3;
|
||||
ULONG rc;
|
||||
|
||||
/* Don't do anything if we can't handle the requested attributes */
|
||||
if (!(attr_mask & (APR_FILE_ATTR_READONLY
|
||||
| APR_FILE_ATTR_HIDDEN)))
|
||||
return APR_SUCCESS;
|
||||
|
||||
rc = DosQueryPathInfo(fname, FIL_STANDARD, &fs3, sizeof(fs3));
|
||||
if (rc == 0) {
|
||||
ULONG old_attr = fs3.attrFile;
|
||||
|
||||
if (attr_mask & APR_FILE_ATTR_READONLY)
|
||||
{
|
||||
if (attributes & APR_FILE_ATTR_READONLY) {
|
||||
fs3.attrFile |= FILE_READONLY;
|
||||
} else {
|
||||
fs3.attrFile &= ~FILE_READONLY;
|
||||
}
|
||||
}
|
||||
|
||||
if (attr_mask & APR_FILE_ATTR_HIDDEN)
|
||||
{
|
||||
if (attributes & APR_FILE_ATTR_HIDDEN) {
|
||||
fs3.attrFile |= FILE_HIDDEN;
|
||||
} else {
|
||||
fs3.attrFile &= ~FILE_HIDDEN;
|
||||
}
|
||||
}
|
||||
|
||||
if (fs3.attrFile != old_attr) {
|
||||
rc = DosSetPathInfo(fname, FIL_STANDARD, &fs3, sizeof(fs3), 0);
|
||||
}
|
||||
}
|
||||
|
||||
return APR_FROM_OS_ERROR(rc);
|
||||
}
|
||||
|
||||
|
||||
/* ### Somebody please write this! */
|
||||
APR_DECLARE(apr_status_t) apr_file_mtime_set(const char *fname,
|
||||
apr_time_t mtime,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
FILESTATUS3 fs3;
|
||||
ULONG rc;
|
||||
rc = DosQueryPathInfo(fname, FIL_STANDARD, &fs3, sizeof(fs3));
|
||||
|
||||
if (rc) {
|
||||
return APR_FROM_OS_ERROR(rc);
|
||||
}
|
||||
|
||||
apr_apr_time_to_os2_time(&fs3.fdateLastWrite, &fs3.ftimeLastWrite, mtime);
|
||||
|
||||
rc = DosSetPathInfo(fname, FIL_STANDARD, &fs3, sizeof(fs3), 0);
|
||||
return APR_FROM_OS_ERROR(rc);
|
||||
}
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
/* 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_arch_file_io.h"
|
||||
#include "apr_strings.h"
|
||||
#include "apr_lib.h"
|
||||
#include <ctype.h>
|
||||
|
||||
/* OS/2 Exceptions:
|
||||
*
|
||||
* Note that trailing spaces and trailing periods are never recorded
|
||||
* in the file system.
|
||||
*
|
||||
* Leading spaces and periods are accepted, however.
|
||||
* The * ? < > codes all have wildcard side effects
|
||||
* The " / \ : are exclusively component separator tokens
|
||||
* The system doesn't accept | for any (known) purpose
|
||||
* Oddly, \x7f _is_ acceptable ;)
|
||||
*/
|
||||
|
||||
const char c_is_fnchar[256] =
|
||||
{/* Reject all ctrl codes... */
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
/* " * / : < > ? */
|
||||
1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,0, 1,1,1,1,1,1,1,1,1,1,0,1,0,1,0,0,
|
||||
/* \ */
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,
|
||||
/* | */
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,
|
||||
/* High bit codes are accepted */
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
|
||||
};
|
||||
|
||||
|
||||
#define IS_SLASH(c) (c == '/' || c == '\\')
|
||||
|
||||
|
||||
apr_status_t filepath_root_test(char *path, apr_pool_t *p)
|
||||
{
|
||||
char drive = apr_toupper(path[0]);
|
||||
|
||||
if (drive >= 'A' && drive <= 'Z' && path[1] == ':' && IS_SLASH(path[2]))
|
||||
return APR_SUCCESS;
|
||||
|
||||
return APR_EBADPATH;
|
||||
}
|
||||
|
||||
|
||||
apr_status_t filepath_drive_get(char **rootpath, char drive,
|
||||
apr_int32_t flags, apr_pool_t *p)
|
||||
{
|
||||
char path[APR_PATH_MAX];
|
||||
char *pos;
|
||||
ULONG rc;
|
||||
ULONG bufsize = sizeof(path) - 3;
|
||||
|
||||
path[0] = drive;
|
||||
path[1] = ':';
|
||||
path[2] = '/';
|
||||
|
||||
rc = DosQueryCurrentDir(apr_toupper(drive) - 'A', path+3, &bufsize);
|
||||
|
||||
if (rc) {
|
||||
return APR_FROM_OS_ERROR(rc);
|
||||
}
|
||||
|
||||
if (!(flags & APR_FILEPATH_NATIVE)) {
|
||||
for (pos=path; *pos; pos++) {
|
||||
if (*pos == '\\')
|
||||
*pos = '/';
|
||||
}
|
||||
}
|
||||
|
||||
*rootpath = apr_pstrdup(p, path);
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
apr_status_t filepath_root_case(char **rootpath, char *root, apr_pool_t *p)
|
||||
{
|
||||
if (root[0] && apr_islower(root[0]) && root[1] == ':') {
|
||||
*rootpath = apr_pstrdup(p, root);
|
||||
(*rootpath)[0] = apr_toupper((*rootpath)[0]);
|
||||
}
|
||||
else {
|
||||
*rootpath = root;
|
||||
}
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_filepath_get(char **defpath, apr_int32_t flags,
|
||||
apr_pool_t *p)
|
||||
{
|
||||
char path[APR_PATH_MAX];
|
||||
ULONG drive;
|
||||
ULONG drivemap;
|
||||
ULONG rv, pathlen = sizeof(path) - 3;
|
||||
char *pos;
|
||||
|
||||
DosQueryCurrentDisk(&drive, &drivemap);
|
||||
path[0] = '@' + drive;
|
||||
strcpy(path+1, ":\\");
|
||||
rv = DosQueryCurrentDir(drive, path+3, &pathlen);
|
||||
|
||||
*defpath = apr_pstrdup(p, path);
|
||||
|
||||
if (!(flags & APR_FILEPATH_NATIVE)) {
|
||||
for (pos=*defpath; *pos; pos++) {
|
||||
if (*pos == '\\')
|
||||
*pos = '/';
|
||||
}
|
||||
}
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_filepath_set(const char *path, apr_pool_t *p)
|
||||
{
|
||||
ULONG rv = 0;
|
||||
|
||||
if (path[1] == ':')
|
||||
rv = DosSetDefaultDisk(apr_toupper(path[0]) - '@');
|
||||
|
||||
if (rv == 0)
|
||||
rv = DosSetCurrentDir(path);
|
||||
|
||||
return APR_FROM_OS_ERROR(rv);
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/* 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"
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_lock(apr_file_t *thefile, int type)
|
||||
{
|
||||
FILELOCK lockrange = { 0, 0x7fffffff };
|
||||
ULONG rc;
|
||||
|
||||
rc = DosSetFileLocks(thefile->filedes, NULL, &lockrange,
|
||||
(type & APR_FLOCK_NONBLOCK) ? 0 : (ULONG)-1,
|
||||
(type & APR_FLOCK_TYPEMASK) == APR_FLOCK_SHARED);
|
||||
return APR_FROM_OS_ERROR(rc);
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_unlock(apr_file_t *thefile)
|
||||
{
|
||||
FILELOCK unlockrange = { 0, 0x7fffffff };
|
||||
ULONG rc;
|
||||
|
||||
rc = DosSetFileLocks(thefile->filedes, &unlockrange, NULL, 0, 0);
|
||||
return APR_FROM_OS_ERROR(rc);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
#include "../unix/fullrw.c"
|
||||
@@ -0,0 +1,95 @@
|
||||
/* 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 INCL_DOSERRORS
|
||||
#include "apr_arch_file_io.h"
|
||||
#include "apr_file_io.h"
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "apr_errno.h"
|
||||
|
||||
static int errormap[][2] = {
|
||||
{ NO_ERROR, APR_SUCCESS },
|
||||
{ ERROR_FILE_NOT_FOUND, APR_ENOENT },
|
||||
{ ERROR_PATH_NOT_FOUND, APR_ENOENT },
|
||||
{ ERROR_TOO_MANY_OPEN_FILES, APR_EMFILE },
|
||||
{ ERROR_ACCESS_DENIED, APR_EACCES },
|
||||
{ ERROR_SHARING_VIOLATION, APR_EACCES },
|
||||
{ ERROR_INVALID_PARAMETER, APR_EINVAL },
|
||||
{ ERROR_OPEN_FAILED, APR_ENOENT },
|
||||
{ ERROR_DISK_FULL, APR_ENOSPC },
|
||||
{ ERROR_FILENAME_EXCED_RANGE, APR_ENAMETOOLONG },
|
||||
{ ERROR_INVALID_FUNCTION, APR_EINVAL },
|
||||
{ ERROR_INVALID_HANDLE, APR_EBADF },
|
||||
{ ERROR_NEGATIVE_SEEK, APR_ESPIPE },
|
||||
{ ERROR_NO_SIGNAL_SENT, ESRCH },
|
||||
{ ERROR_NO_DATA, APR_EAGAIN },
|
||||
{ SOCEINTR, EINTR },
|
||||
{ SOCEWOULDBLOCK, EWOULDBLOCK },
|
||||
{ SOCEINPROGRESS, EINPROGRESS },
|
||||
{ SOCEALREADY, EALREADY },
|
||||
{ SOCENOTSOCK, ENOTSOCK },
|
||||
{ SOCEDESTADDRREQ, EDESTADDRREQ },
|
||||
{ SOCEMSGSIZE, EMSGSIZE },
|
||||
{ SOCEPROTOTYPE, EPROTOTYPE },
|
||||
{ SOCENOPROTOOPT, ENOPROTOOPT },
|
||||
{ SOCEPROTONOSUPPORT, EPROTONOSUPPORT },
|
||||
{ SOCESOCKTNOSUPPORT, ESOCKTNOSUPPORT },
|
||||
{ SOCEOPNOTSUPP, EOPNOTSUPP },
|
||||
{ SOCEPFNOSUPPORT, EPFNOSUPPORT },
|
||||
{ SOCEAFNOSUPPORT, EAFNOSUPPORT },
|
||||
{ SOCEADDRINUSE, EADDRINUSE },
|
||||
{ SOCEADDRNOTAVAIL, EADDRNOTAVAIL },
|
||||
{ SOCENETDOWN, ENETDOWN },
|
||||
{ SOCENETUNREACH, ENETUNREACH },
|
||||
{ SOCENETRESET, ENETRESET },
|
||||
{ SOCECONNABORTED, ECONNABORTED },
|
||||
{ SOCECONNRESET, ECONNRESET },
|
||||
{ SOCENOBUFS, ENOBUFS },
|
||||
{ SOCEISCONN, EISCONN },
|
||||
{ SOCENOTCONN, ENOTCONN },
|
||||
{ SOCESHUTDOWN, ESHUTDOWN },
|
||||
{ SOCETOOMANYREFS, ETOOMANYREFS },
|
||||
{ SOCETIMEDOUT, ETIMEDOUT },
|
||||
{ SOCECONNREFUSED, ECONNREFUSED },
|
||||
{ SOCELOOP, ELOOP },
|
||||
{ SOCENAMETOOLONG, ENAMETOOLONG },
|
||||
{ SOCEHOSTDOWN, EHOSTDOWN },
|
||||
{ SOCEHOSTUNREACH, EHOSTUNREACH },
|
||||
{ SOCENOTEMPTY, ENOTEMPTY },
|
||||
{ SOCEPIPE, EPIPE }
|
||||
};
|
||||
|
||||
#define MAPSIZE (sizeof(errormap)/sizeof(errormap[0]))
|
||||
|
||||
int apr_canonical_error(apr_status_t err)
|
||||
{
|
||||
int rv = -1, index;
|
||||
|
||||
if (err < APR_OS_START_SYSERR)
|
||||
return err;
|
||||
|
||||
err -= APR_OS_START_SYSERR;
|
||||
|
||||
for (index=0; index<MAPSIZE && errormap[index][0] != err; index++);
|
||||
|
||||
if (index<MAPSIZE)
|
||||
rv = errormap[index][1];
|
||||
else
|
||||
fprintf(stderr, "apr_canonical_error: Unknown OS/2 error code %d\n", err );
|
||||
|
||||
return rv;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
#include "../unix/mktemp.c"
|
||||
+304
@@ -0,0 +1,304 @@
|
||||
/* 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_lib.h"
|
||||
#include "apr_portable.h"
|
||||
#include "apr_strings.h"
|
||||
#include "apr_arch_inherit.h"
|
||||
#include <string.h>
|
||||
|
||||
apr_status_t apr_file_cleanup(void *thefile)
|
||||
{
|
||||
apr_file_t *file = thefile;
|
||||
return apr_file_close(file);
|
||||
}
|
||||
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
int oflags = 0;
|
||||
int mflags = OPEN_FLAGS_FAIL_ON_ERROR|OPEN_SHARE_DENYNONE|OPEN_FLAGS_NOINHERIT;
|
||||
int rv;
|
||||
ULONG action;
|
||||
apr_file_t *dafile = (apr_file_t *)apr_palloc(pool, sizeof(apr_file_t));
|
||||
|
||||
if (flag & APR_FOPEN_NONBLOCK) {
|
||||
return APR_ENOTIMPL;
|
||||
}
|
||||
|
||||
dafile->pool = pool;
|
||||
dafile->isopen = FALSE;
|
||||
dafile->eof_hit = FALSE;
|
||||
dafile->buffer = NULL;
|
||||
dafile->flags = flag;
|
||||
dafile->blocking = BLK_ON;
|
||||
|
||||
if ((flag & APR_FOPEN_READ) && (flag & APR_FOPEN_WRITE)) {
|
||||
mflags |= OPEN_ACCESS_READWRITE;
|
||||
} else if (flag & APR_FOPEN_READ) {
|
||||
mflags |= OPEN_ACCESS_READONLY;
|
||||
} else if (flag & APR_FOPEN_WRITE) {
|
||||
mflags |= OPEN_ACCESS_WRITEONLY;
|
||||
} else {
|
||||
dafile->filedes = -1;
|
||||
return APR_EACCES;
|
||||
}
|
||||
|
||||
dafile->buffered = (flag & APR_FOPEN_BUFFERED) > 0;
|
||||
|
||||
if (dafile->buffered) {
|
||||
dafile->buffer = apr_palloc(pool, APR_FILE_DEFAULT_BUFSIZE);
|
||||
dafile->bufsize = APR_FILE_DEFAULT_BUFSIZE;
|
||||
rv = apr_thread_mutex_create(&dafile->mutex, 0, pool);
|
||||
|
||||
if (rv)
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (flag & APR_FOPEN_CREATE) {
|
||||
oflags |= OPEN_ACTION_CREATE_IF_NEW;
|
||||
|
||||
if (!(flag & APR_FOPEN_EXCL) && !(flag & APR_FOPEN_TRUNCATE)) {
|
||||
oflags |= OPEN_ACTION_OPEN_IF_EXISTS;
|
||||
}
|
||||
}
|
||||
|
||||
if ((flag & APR_FOPEN_EXCL) && !(flag & APR_FOPEN_CREATE))
|
||||
return APR_EACCES;
|
||||
|
||||
if (flag & APR_FOPEN_TRUNCATE) {
|
||||
oflags |= OPEN_ACTION_REPLACE_IF_EXISTS;
|
||||
} else if ((oflags & 0xFF) == 0) {
|
||||
oflags |= OPEN_ACTION_OPEN_IF_EXISTS;
|
||||
}
|
||||
|
||||
rv = DosOpen(fname, &(dafile->filedes), &action, 0, 0, oflags, mflags, NULL);
|
||||
|
||||
if (rv == 0 && (flag & APR_FOPEN_APPEND)) {
|
||||
ULONG newptr;
|
||||
rv = DosSetFilePtr(dafile->filedes, 0, FILE_END, &newptr );
|
||||
|
||||
if (rv)
|
||||
DosClose(dafile->filedes);
|
||||
}
|
||||
|
||||
if (rv != 0)
|
||||
return APR_FROM_OS_ERROR(rv);
|
||||
|
||||
dafile->isopen = TRUE;
|
||||
dafile->fname = apr_pstrdup(pool, fname);
|
||||
dafile->filePtr = 0;
|
||||
dafile->bufpos = 0;
|
||||
dafile->dataRead = 0;
|
||||
dafile->direction = 0;
|
||||
dafile->pipe = FALSE;
|
||||
|
||||
if (!(flag & APR_FOPEN_NOCLEANUP)) {
|
||||
apr_pool_cleanup_register(dafile->pool, dafile, apr_file_cleanup, apr_file_cleanup);
|
||||
}
|
||||
|
||||
*new = dafile;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_close(apr_file_t *file)
|
||||
{
|
||||
ULONG rc;
|
||||
apr_status_t status;
|
||||
|
||||
if (file && file->isopen) {
|
||||
/* XXX: flush here is not mutex protected */
|
||||
status = apr_file_flush(file);
|
||||
rc = DosClose(file->filedes);
|
||||
|
||||
if (rc == 0) {
|
||||
file->isopen = FALSE;
|
||||
|
||||
if (file->flags & APR_FOPEN_DELONCLOSE) {
|
||||
status = APR_FROM_OS_ERROR(DosDelete(file->fname));
|
||||
}
|
||||
/* else we return the status of the flush attempt
|
||||
* when all else succeeds
|
||||
*/
|
||||
} else {
|
||||
return APR_FROM_OS_ERROR(rc);
|
||||
}
|
||||
}
|
||||
|
||||
if (file->buffered)
|
||||
apr_thread_mutex_destroy(file->mutex);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_remove(const char *path, apr_pool_t *pool)
|
||||
{
|
||||
ULONG rc = DosDelete(path);
|
||||
return APR_FROM_OS_ERROR(rc);
|
||||
}
|
||||
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_rename(const char *from_path, const char *to_path,
|
||||
apr_pool_t *p)
|
||||
{
|
||||
ULONG rc = DosMove(from_path, to_path);
|
||||
|
||||
if (rc == ERROR_ACCESS_DENIED || rc == ERROR_ALREADY_EXISTS) {
|
||||
rc = DosDelete(to_path);
|
||||
|
||||
if (rc == 0 || rc == ERROR_FILE_NOT_FOUND) {
|
||||
rc = DosMove(from_path, to_path);
|
||||
}
|
||||
}
|
||||
|
||||
return APR_FROM_OS_ERROR(rc);
|
||||
}
|
||||
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
apr_os_file_t *dafile = thefile;
|
||||
|
||||
(*file) = apr_palloc(pool, sizeof(apr_file_t));
|
||||
(*file)->pool = pool;
|
||||
(*file)->filedes = *dafile;
|
||||
(*file)->isopen = TRUE;
|
||||
(*file)->eof_hit = FALSE;
|
||||
(*file)->flags = flags;
|
||||
(*file)->pipe = FALSE;
|
||||
(*file)->buffered = (flags & APR_FOPEN_BUFFERED) > 0;
|
||||
|
||||
if ((*file)->buffered) {
|
||||
apr_status_t rv;
|
||||
|
||||
(*file)->buffer = apr_palloc(pool, APR_FILE_DEFAULT_BUFSIZE);
|
||||
(*file)->bufsize = APR_FILE_DEFAULT_BUFSIZE;
|
||||
rv = apr_thread_mutex_create(&(*file)->mutex, 0, pool);
|
||||
|
||||
if (rv)
|
||||
return rv;
|
||||
}
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_eof(apr_file_t *fptr)
|
||||
{
|
||||
if (!fptr->isopen || 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)
|
||||
{
|
||||
apr_os_file_t fd = 2;
|
||||
|
||||
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)
|
||||
{
|
||||
apr_os_file_t fd = 1;
|
||||
|
||||
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)
|
||||
{
|
||||
apr_os_file_t fd = 0;
|
||||
|
||||
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_POOL_IMPLEMENT_ACCESSOR(file);
|
||||
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_inherit_set(apr_file_t *thefile)
|
||||
{
|
||||
int rv;
|
||||
ULONG state;
|
||||
|
||||
rv = DosQueryFHState(thefile->filedes, &state);
|
||||
|
||||
if (rv == 0 && (state & OPEN_FLAGS_NOINHERIT) != 0) {
|
||||
rv = DosSetFHState(thefile->filedes, state & ~OPEN_FLAGS_NOINHERIT);
|
||||
}
|
||||
|
||||
return APR_FROM_OS_ERROR(rv);
|
||||
}
|
||||
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_inherit_unset(apr_file_t *thefile)
|
||||
{
|
||||
int rv;
|
||||
ULONG state;
|
||||
|
||||
rv = DosQueryFHState(thefile->filedes, &state);
|
||||
|
||||
if (rv == 0 && (state & OPEN_FLAGS_NOINHERIT) == 0) {
|
||||
rv = DosSetFHState(thefile->filedes, state | OPEN_FLAGS_NOINHERIT);
|
||||
}
|
||||
|
||||
return APR_FROM_OS_ERROR(rv);
|
||||
}
|
||||
+236
@@ -0,0 +1,236 @@
|
||||
/* 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 INCL_DOSERRORS
|
||||
#include "apr_arch_file_io.h"
|
||||
#include "apr_file_io.h"
|
||||
#include "apr_general.h"
|
||||
#include "apr_lib.h"
|
||||
#include "apr_strings.h"
|
||||
#include "apr_portable.h"
|
||||
#include <string.h>
|
||||
#include <process.h>
|
||||
|
||||
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)
|
||||
{
|
||||
ULONG filedes[2];
|
||||
ULONG rc, action;
|
||||
static int id = 0;
|
||||
char pipename[50];
|
||||
|
||||
sprintf(pipename, "/pipe/%d.%d", getpid(), id++);
|
||||
rc = DosCreateNPipe(pipename, filedes, NP_ACCESS_INBOUND, NP_NOWAIT|1, 4096, 4096, 0);
|
||||
|
||||
if (rc)
|
||||
return APR_FROM_OS_ERROR(rc);
|
||||
|
||||
rc = DosConnectNPipe(filedes[0]);
|
||||
|
||||
if (rc && rc != ERROR_PIPE_NOT_CONNECTED) {
|
||||
DosClose(filedes[0]);
|
||||
return APR_FROM_OS_ERROR(rc);
|
||||
}
|
||||
|
||||
rc = DosOpen (pipename, filedes+1, &action, 0, FILE_NORMAL,
|
||||
OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW,
|
||||
OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYREADWRITE,
|
||||
NULL);
|
||||
|
||||
if (rc) {
|
||||
DosClose(filedes[0]);
|
||||
return APR_FROM_OS_ERROR(rc);
|
||||
}
|
||||
|
||||
(*in) = (apr_file_t *)apr_palloc(pool_in, sizeof(apr_file_t));
|
||||
rc = DosCreateEventSem(NULL, &(*in)->pipeSem, DC_SEM_SHARED, FALSE);
|
||||
|
||||
if (rc) {
|
||||
DosClose(filedes[0]);
|
||||
DosClose(filedes[1]);
|
||||
return APR_FROM_OS_ERROR(rc);
|
||||
}
|
||||
|
||||
rc = DosSetNPipeSem(filedes[0], (HSEM)(*in)->pipeSem, 1);
|
||||
|
||||
if (!rc) {
|
||||
rc = DosSetNPHState(filedes[0], NP_WAIT);
|
||||
}
|
||||
|
||||
if (rc) {
|
||||
DosClose(filedes[0]);
|
||||
DosClose(filedes[1]);
|
||||
DosCloseEventSem((*in)->pipeSem);
|
||||
return APR_FROM_OS_ERROR(rc);
|
||||
}
|
||||
|
||||
(*in)->pool = pool_in;
|
||||
(*in)->filedes = filedes[0];
|
||||
(*in)->fname = apr_pstrdup(pool_in, pipename);
|
||||
(*in)->isopen = TRUE;
|
||||
(*in)->buffered = FALSE;
|
||||
(*in)->flags = 0;
|
||||
(*in)->pipe = 1;
|
||||
(*in)->timeout = -1;
|
||||
(*in)->blocking = BLK_ON;
|
||||
apr_pool_cleanup_register(pool_in, *in, apr_file_cleanup,
|
||||
apr_pool_cleanup_null);
|
||||
|
||||
(*out) = (apr_file_t *)apr_palloc(pool_out, sizeof(apr_file_t));
|
||||
(*out)->pool = pool_out;
|
||||
(*out)->filedes = filedes[1];
|
||||
(*out)->fname = apr_pstrdup(pool_out, pipename);
|
||||
(*out)->isopen = TRUE;
|
||||
(*out)->buffered = FALSE;
|
||||
(*out)->flags = 0;
|
||||
(*out)->pipe = 1;
|
||||
(*out)->timeout = -1;
|
||||
(*out)->blocking = BLK_ON;
|
||||
apr_pool_cleanup_register(pool_out, *out, apr_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)
|
||||
{
|
||||
/* Not yet implemented, interface not suitable */
|
||||
return APR_ENOTIMPL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_pipe_timeout_set(apr_file_t *thepipe, apr_interval_time_t timeout)
|
||||
{
|
||||
if (thepipe->pipe == 1) {
|
||||
thepipe->timeout = timeout;
|
||||
|
||||
if (thepipe->timeout >= 0) {
|
||||
if (thepipe->blocking != BLK_OFF) {
|
||||
thepipe->blocking = BLK_OFF;
|
||||
return APR_FROM_OS_ERROR(DosSetNPHState(thepipe->filedes, NP_NOWAIT));
|
||||
}
|
||||
}
|
||||
else if (thepipe->timeout == -1) {
|
||||
if (thepipe->blocking != BLK_ON) {
|
||||
thepipe->blocking = BLK_ON;
|
||||
return APR_FROM_OS_ERROR(DosSetNPHState(thepipe->filedes, NP_WAIT));
|
||||
}
|
||||
}
|
||||
}
|
||||
return APR_EINVAL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_pipe_timeout_get(apr_file_t *thepipe, apr_interval_time_t *timeout)
|
||||
{
|
||||
if (thepipe->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)
|
||||
{
|
||||
(*file) = apr_pcalloc(pool, sizeof(apr_file_t));
|
||||
(*file)->pool = pool;
|
||||
(*file)->isopen = TRUE;
|
||||
(*file)->pipe = 1;
|
||||
(*file)->blocking = BLK_UNKNOWN; /* app needs to make a timeout call */
|
||||
(*file)->timeout = -1;
|
||||
(*file)->filedes = *thefile;
|
||||
|
||||
if (register_cleanup) {
|
||||
apr_pool_cleanup_register(pool, *file, apr_file_cleanup,
|
||||
apr_pool_cleanup_null);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
+388
@@ -0,0 +1,388 @@
|
||||
/* 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 INCL_DOS
|
||||
#define INCL_DOSERRORS
|
||||
|
||||
#include "apr_arch_file_io.h"
|
||||
#include "apr_file_io.h"
|
||||
#include "apr_lib.h"
|
||||
#include "apr_strings.h"
|
||||
|
||||
#include <malloc.h>
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_read(apr_file_t *thefile, void *buf, apr_size_t *nbytes)
|
||||
{
|
||||
ULONG rc = 0;
|
||||
ULONG bytesread;
|
||||
|
||||
if (!thefile->isopen) {
|
||||
*nbytes = 0;
|
||||
return APR_EBADF;
|
||||
}
|
||||
|
||||
if (thefile->buffered) {
|
||||
char *pos = (char *)buf;
|
||||
ULONG blocksize;
|
||||
ULONG size = *nbytes;
|
||||
|
||||
apr_thread_mutex_lock(thefile->mutex);
|
||||
|
||||
if (thefile->direction == 1) {
|
||||
int rv = apr_file_flush(thefile);
|
||||
|
||||
if (rv != APR_SUCCESS) {
|
||||
apr_thread_mutex_unlock(thefile->mutex);
|
||||
return rv;
|
||||
}
|
||||
|
||||
thefile->bufpos = 0;
|
||||
thefile->direction = 0;
|
||||
thefile->dataRead = 0;
|
||||
}
|
||||
|
||||
while (rc == 0 && size > 0) {
|
||||
if (thefile->bufpos >= thefile->dataRead) {
|
||||
ULONG bytesread;
|
||||
rc = DosRead(thefile->filedes, thefile->buffer,
|
||||
thefile->bufsize, &bytesread);
|
||||
|
||||
if (bytesread == 0) {
|
||||
if (rc == 0)
|
||||
thefile->eof_hit = TRUE;
|
||||
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 = rc == 0 ? pos - (char *)buf : 0;
|
||||
apr_thread_mutex_unlock(thefile->mutex);
|
||||
|
||||
if (*nbytes == 0 && rc == 0 && thefile->eof_hit) {
|
||||
return APR_EOF;
|
||||
}
|
||||
|
||||
return APR_FROM_OS_ERROR(rc);
|
||||
} else {
|
||||
if (thefile->pipe)
|
||||
DosResetEventSem(thefile->pipeSem, &rc);
|
||||
|
||||
rc = DosRead(thefile->filedes, buf, *nbytes, &bytesread);
|
||||
|
||||
if (rc == ERROR_NO_DATA && thefile->timeout != 0) {
|
||||
int rcwait = DosWaitEventSem(thefile->pipeSem, thefile->timeout >= 0 ? thefile->timeout / 1000 : SEM_INDEFINITE_WAIT);
|
||||
|
||||
if (rcwait == 0) {
|
||||
rc = DosRead(thefile->filedes, buf, *nbytes, &bytesread);
|
||||
}
|
||||
else if (rcwait == ERROR_TIMEOUT) {
|
||||
*nbytes = 0;
|
||||
return APR_TIMEUP;
|
||||
}
|
||||
}
|
||||
|
||||
if (rc) {
|
||||
*nbytes = 0;
|
||||
return APR_FROM_OS_ERROR(rc);
|
||||
}
|
||||
|
||||
*nbytes = bytesread;
|
||||
|
||||
if (bytesread == 0) {
|
||||
thefile->eof_hit = TRUE;
|
||||
return APR_EOF;
|
||||
}
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_write(apr_file_t *thefile, const void *buf, apr_size_t *nbytes)
|
||||
{
|
||||
ULONG rc = 0;
|
||||
ULONG byteswritten;
|
||||
|
||||
if (!thefile->isopen) {
|
||||
*nbytes = 0;
|
||||
return APR_EBADF;
|
||||
}
|
||||
|
||||
if (thefile->buffered) {
|
||||
char *pos = (char *)buf;
|
||||
int blocksize;
|
||||
int size = *nbytes;
|
||||
|
||||
apr_thread_mutex_lock(thefile->mutex);
|
||||
|
||||
if ( thefile->direction == 0 ) {
|
||||
/* Position file pointer for writing at the offset we are logically reading from */
|
||||
ULONG offset = thefile->filePtr - thefile->dataRead + thefile->bufpos;
|
||||
if (offset != thefile->filePtr)
|
||||
DosSetFilePtr(thefile->filedes, offset, FILE_BEGIN, &thefile->filePtr );
|
||||
thefile->bufpos = thefile->dataRead = 0;
|
||||
thefile->direction = 1;
|
||||
}
|
||||
|
||||
while (rc == 0 && size > 0) {
|
||||
if (thefile->bufpos == thefile->bufsize) /* write buffer is full */
|
||||
/* XXX bug; - rc is double-transformed os->apr below */
|
||||
rc = apr_file_flush(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;
|
||||
}
|
||||
|
||||
apr_thread_mutex_unlock(thefile->mutex);
|
||||
return APR_FROM_OS_ERROR(rc);
|
||||
} else {
|
||||
if (thefile->flags & APR_FOPEN_APPEND) {
|
||||
FILELOCK all = { 0, 0x7fffffff };
|
||||
ULONG newpos;
|
||||
rc = DosSetFileLocks(thefile->filedes, NULL, &all, -1, 0);
|
||||
|
||||
if (rc == 0) {
|
||||
rc = DosSetFilePtr(thefile->filedes, 0, FILE_END, &newpos);
|
||||
|
||||
if (rc == 0) {
|
||||
rc = DosWrite(thefile->filedes, buf, *nbytes, &byteswritten);
|
||||
}
|
||||
|
||||
DosSetFileLocks(thefile->filedes, &all, NULL, -1, 0);
|
||||
}
|
||||
} else {
|
||||
rc = DosWrite(thefile->filedes, buf, *nbytes, &byteswritten);
|
||||
}
|
||||
|
||||
if (rc) {
|
||||
*nbytes = 0;
|
||||
return APR_FROM_OS_ERROR(rc);
|
||||
}
|
||||
|
||||
*nbytes = byteswritten;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef HAVE_WRITEV
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_writev(apr_file_t *thefile, const struct iovec *vec, apr_size_t nvec, apr_size_t *nbytes)
|
||||
{
|
||||
int bytes;
|
||||
|
||||
if (thefile->buffered) {
|
||||
apr_status_t rv = apr_file_flush(thefile);
|
||||
if (rv != APR_SUCCESS) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
if ((bytes = writev(thefile->filedes, vec, nvec)) < 0) {
|
||||
*nbytes = 0;
|
||||
return errno;
|
||||
}
|
||||
else {
|
||||
*nbytes = bytes;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_putc(char ch, apr_file_t *thefile)
|
||||
{
|
||||
ULONG rc;
|
||||
ULONG byteswritten;
|
||||
|
||||
if (!thefile->isopen) {
|
||||
return APR_EBADF;
|
||||
}
|
||||
|
||||
rc = DosWrite(thefile->filedes, &ch, 1, &byteswritten);
|
||||
|
||||
if (rc) {
|
||||
return APR_FROM_OS_ERROR(rc);
|
||||
}
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_ungetc(char ch, apr_file_t *thefile)
|
||||
{
|
||||
apr_off_t offset = -1;
|
||||
return apr_file_seek(thefile, APR_CUR, &offset);
|
||||
}
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_getc(char *ch, apr_file_t *thefile)
|
||||
{
|
||||
ULONG rc;
|
||||
apr_size_t bytesread;
|
||||
|
||||
if (!thefile->isopen) {
|
||||
return APR_EBADF;
|
||||
}
|
||||
|
||||
bytesread = 1;
|
||||
rc = apr_file_read(thefile, ch, &bytesread);
|
||||
|
||||
if (rc) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (bytesread == 0) {
|
||||
thefile->eof_hit = TRUE;
|
||||
return APR_EOF;
|
||||
}
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_puts(const char *str, apr_file_t *thefile)
|
||||
{
|
||||
apr_size_t len;
|
||||
|
||||
len = strlen(str);
|
||||
return apr_file_write(thefile, str, &len);
|
||||
}
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_flush(apr_file_t *thefile)
|
||||
{
|
||||
if (thefile->buffered) {
|
||||
ULONG written = 0;
|
||||
int rc = 0;
|
||||
|
||||
if (thefile->direction == 1 && thefile->bufpos) {
|
||||
rc = DosWrite(thefile->filedes, thefile->buffer, thefile->bufpos, &written);
|
||||
thefile->filePtr += written;
|
||||
|
||||
if (rc == 0)
|
||||
thefile->bufpos = 0;
|
||||
}
|
||||
|
||||
return APR_FROM_OS_ERROR(rc);
|
||||
} else {
|
||||
/* There isn't anything to do if we aren't buffering the output
|
||||
* so just return success.
|
||||
*/
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_sync(apr_file_t *thefile)
|
||||
{
|
||||
return APR_ENOTIMPL;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_datasync(apr_file_t *thefile)
|
||||
{
|
||||
return APR_ENOTIMPL;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_gets(char *str, int len, apr_file_t *thefile)
|
||||
{
|
||||
apr_size_t readlen;
|
||||
apr_status_t rv = APR_SUCCESS;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len-1; i++) {
|
||||
readlen = 1;
|
||||
rv = apr_file_read(thefile, str+i, &readlen);
|
||||
|
||||
if (rv != APR_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (readlen != 1) {
|
||||
rv = APR_EOF;
|
||||
break;
|
||||
}
|
||||
|
||||
if (str[i] == '\n') {
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
str[i] = 0;
|
||||
if (i > 0) {
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
APR_DECLARE_NONSTD(int) apr_file_printf(apr_file_t *fptr,
|
||||
const char *format, ...)
|
||||
{
|
||||
int cc;
|
||||
va_list ap;
|
||||
char *buf;
|
||||
int len;
|
||||
|
||||
buf = malloc(HUGE_STRING_LEN);
|
||||
if (buf == NULL) {
|
||||
return 0;
|
||||
}
|
||||
va_start(ap, format);
|
||||
len = apr_vsnprintf(buf, HUGE_STRING_LEN, format, ap);
|
||||
cc = apr_file_puts(buf, fptr);
|
||||
va_end(ap);
|
||||
free(buf);
|
||||
return (cc == APR_SUCCESS) ? len : -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
apr_status_t apr_file_check_read(apr_file_t *fd)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!fd->pipe)
|
||||
return APR_SUCCESS; /* Not a pipe, assume no waiting */
|
||||
|
||||
rc = DosWaitEventSem(fd->pipeSem, SEM_IMMEDIATE_RETURN);
|
||||
|
||||
if (rc == ERROR_TIMEOUT)
|
||||
return APR_TIMEUP;
|
||||
|
||||
return APR_FROM_OS_ERROR(rc);
|
||||
}
|
||||
+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"
|
||||
#include "apr_file_io.h"
|
||||
#include "apr_lib.h"
|
||||
#include <string.h>
|
||||
#include <io.h>
|
||||
|
||||
|
||||
static apr_status_t setptr(apr_file_t *thefile, unsigned long pos )
|
||||
{
|
||||
long newbufpos;
|
||||
ULONG rc;
|
||||
|
||||
if (thefile->direction == 1) {
|
||||
/* XXX: flush here is not mutex protected */
|
||||
apr_status_t rv = apr_file_flush(thefile);
|
||||
|
||||
if (rv != APR_SUCCESS) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
thefile->bufpos = thefile->direction = thefile->dataRead = 0;
|
||||
}
|
||||
|
||||
newbufpos = pos - (thefile->filePtr - thefile->dataRead);
|
||||
if (newbufpos >= 0 && newbufpos <= thefile->dataRead) {
|
||||
thefile->bufpos = newbufpos;
|
||||
rc = 0;
|
||||
} else {
|
||||
rc = DosSetFilePtr(thefile->filedes, pos, FILE_BEGIN, &thefile->filePtr );
|
||||
|
||||
if ( !rc )
|
||||
thefile->bufpos = thefile->dataRead = 0;
|
||||
}
|
||||
|
||||
return APR_FROM_OS_ERROR(rc);
|
||||
}
|
||||
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_seek(apr_file_t *thefile, apr_seek_where_t where, apr_off_t *offset)
|
||||
{
|
||||
if (!thefile->isopen) {
|
||||
return APR_EBADF;
|
||||
}
|
||||
|
||||
thefile->eof_hit = 0;
|
||||
|
||||
if (thefile->buffered) {
|
||||
int rc = EINVAL;
|
||||
apr_finfo_t finfo;
|
||||
|
||||
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(&finfo, APR_FINFO_NORM, thefile);
|
||||
if (rc == APR_SUCCESS)
|
||||
rc = setptr(thefile, finfo.size + *offset);
|
||||
break;
|
||||
}
|
||||
|
||||
*offset = thefile->filePtr - thefile->dataRead + thefile->bufpos;
|
||||
return rc;
|
||||
} else {
|
||||
switch (where) {
|
||||
case APR_SET:
|
||||
where = FILE_BEGIN;
|
||||
break;
|
||||
|
||||
case APR_CUR:
|
||||
where = FILE_CURRENT;
|
||||
break;
|
||||
|
||||
case APR_END:
|
||||
where = FILE_END;
|
||||
break;
|
||||
}
|
||||
|
||||
return APR_FROM_OS_ERROR(DosSetFilePtr(thefile->filedes, *offset, where, (ULONG *)offset));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_trunc(apr_file_t *fp, apr_off_t offset)
|
||||
{
|
||||
int rc = DosSetFileSize(fp->filedes, offset);
|
||||
|
||||
if (rc != 0) {
|
||||
return APR_FROM_OS_ERROR(rc);
|
||||
}
|
||||
|
||||
if (fp->buffered) {
|
||||
return setptr(fp, offset);
|
||||
}
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
#include "../unix/tempdir.c"
|
||||
+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;
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/* 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_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;
|
||||
|
||||
if (file->flags & APR_FOPEN_XTHREAD) {
|
||||
apr_thread_mutex_lock(file->mutex);
|
||||
}
|
||||
|
||||
if(file->buffered) {
|
||||
/* Flush the existing buffer */
|
||||
rv = apr_file_flush(file);
|
||||
if (rv != APR_SUCCESS) {
|
||||
if (file->flags & APR_FOPEN_XTHREAD) {
|
||||
apr_thread_mutex_unlock(file->mutex);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
if (file->flags & APR_FOPEN_XTHREAD) {
|
||||
apr_thread_mutex_unlock(file->mutex);
|
||||
}
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_size_t) apr_file_buffer_size_get(apr_file_t *file)
|
||||
{
|
||||
return file->bufsize;
|
||||
}
|
||||
+408
@@ -0,0 +1,408 @@
|
||||
/* 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_arch_file_io.h"
|
||||
#include "apr_file_io.h"
|
||||
#include "apr_strings.h"
|
||||
#include "apr_portable.h"
|
||||
#include "apr_arch_atime.h"
|
||||
|
||||
#if APR_HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#if APR_HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
#if APR_HAVE_DIRENT_H
|
||||
#include <dirent.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
|
||||
static apr_status_t dir_cleanup(void *thedir)
|
||||
{
|
||||
apr_dir_t *dir = thedir;
|
||||
if (dir->dirhand != INVALID_HANDLE_VALUE && !FindClose(dir->dirhand)) {
|
||||
return apr_get_os_error();
|
||||
}
|
||||
dir->dirhand = INVALID_HANDLE_VALUE;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_dir_open(apr_dir_t **new, const char *dirname,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
apr_status_t rv;
|
||||
|
||||
apr_size_t len = strlen(dirname);
|
||||
(*new) = apr_pcalloc(pool, sizeof(apr_dir_t));
|
||||
/* Leave room here to add and pop the '*' wildcard for FindFirstFile
|
||||
* and double-null terminate so we have one character to change.
|
||||
*/
|
||||
(*new)->dirname = apr_palloc(pool, len + 3);
|
||||
memcpy((*new)->dirname, dirname, len);
|
||||
if (len && (*new)->dirname[len - 1] != '/') {
|
||||
(*new)->dirname[len++] = '/';
|
||||
}
|
||||
(*new)->dirname[len++] = '\0';
|
||||
(*new)->dirname[len] = '\0';
|
||||
|
||||
#if APR_HAS_UNICODE_FS
|
||||
IF_WIN_OS_IS_UNICODE
|
||||
{
|
||||
/* Create a buffer for the longest file name we will ever see
|
||||
*/
|
||||
(*new)->w.entry = apr_pcalloc(pool, sizeof(WIN32_FIND_DATAW));
|
||||
(*new)->name = apr_pcalloc(pool, APR_FILE_MAX * 3 + 1);
|
||||
}
|
||||
#endif
|
||||
#if APR_HAS_ANSI_FS
|
||||
ELSE_WIN_OS_IS_ANSI
|
||||
{
|
||||
/* Note that we won't open a directory that is greater than MAX_PATH,
|
||||
* counting the additional '/' '*' wildcard suffix. If a * won't fit
|
||||
* then neither will any other file name within the directory.
|
||||
* The length not including the trailing '*' is stored as rootlen, to
|
||||
* skip over all paths which are too long.
|
||||
*/
|
||||
if (len >= APR_PATH_MAX) {
|
||||
(*new) = NULL;
|
||||
return APR_ENAMETOOLONG;
|
||||
}
|
||||
(*new)->n.entry = apr_pcalloc(pool, sizeof(WIN32_FIND_DATAW));
|
||||
}
|
||||
#endif
|
||||
(*new)->rootlen = len - 1;
|
||||
(*new)->pool = pool;
|
||||
(*new)->dirhand = INVALID_HANDLE_VALUE;
|
||||
apr_pool_cleanup_register((*new)->pool, (void *)(*new), dir_cleanup,
|
||||
apr_pool_cleanup_null);
|
||||
|
||||
rv = apr_dir_read(NULL, 0, *new);
|
||||
if (rv != APR_SUCCESS) {
|
||||
dir_cleanup(*new);
|
||||
*new = NULL;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_dir_close(apr_dir_t *dir)
|
||||
{
|
||||
apr_pool_cleanup_kill(dir->pool, dir, dir_cleanup);
|
||||
return dir_cleanup(dir);
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_dir_read(apr_finfo_t *finfo, apr_int32_t wanted,
|
||||
apr_dir_t *thedir)
|
||||
{
|
||||
apr_status_t rv;
|
||||
char *fname;
|
||||
/* The while loops below allow us to skip all invalid file names, so that
|
||||
* we aren't reporting any files where their absolute paths are too long.
|
||||
*/
|
||||
#if APR_HAS_UNICODE_FS
|
||||
apr_wchar_t wdirname[APR_PATH_MAX];
|
||||
apr_wchar_t *eos = NULL;
|
||||
IF_WIN_OS_IS_UNICODE
|
||||
{
|
||||
/* This code path is always be invoked by apr_dir_open or
|
||||
* apr_dir_rewind, so return without filling out the finfo.
|
||||
*/
|
||||
if (thedir->dirhand == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
apr_status_t rv;
|
||||
if ((rv = utf8_to_unicode_path(wdirname, sizeof(wdirname)
|
||||
/ sizeof(apr_wchar_t),
|
||||
thedir->dirname))) {
|
||||
return rv;
|
||||
}
|
||||
eos = wcschr(wdirname, '\0');
|
||||
eos[0] = '*';
|
||||
eos[1] = '\0';
|
||||
thedir->dirhand = FindFirstFileW(wdirname, thedir->w.entry);
|
||||
eos[0] = '\0';
|
||||
if (thedir->dirhand == INVALID_HANDLE_VALUE) {
|
||||
return apr_get_os_error();
|
||||
}
|
||||
thedir->bof = 1;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
else if (thedir->bof) {
|
||||
/* Noop - we already called FindFirstFileW from
|
||||
* either apr_dir_open or apr_dir_rewind ... use
|
||||
* that first record.
|
||||
*/
|
||||
thedir->bof = 0;
|
||||
}
|
||||
else if (!FindNextFileW(thedir->dirhand, thedir->w.entry)) {
|
||||
return apr_get_os_error();
|
||||
}
|
||||
|
||||
while (thedir->rootlen &&
|
||||
thedir->rootlen + wcslen(thedir->w.entry->cFileName) >= APR_PATH_MAX)
|
||||
{
|
||||
if (!FindNextFileW(thedir->dirhand, thedir->w.entry)) {
|
||||
return apr_get_os_error();
|
||||
}
|
||||
}
|
||||
if ((rv = unicode_to_utf8_path(thedir->name, APR_FILE_MAX * 3 + 1,
|
||||
thedir->w.entry->cFileName)))
|
||||
return rv;
|
||||
fname = thedir->name;
|
||||
}
|
||||
#endif
|
||||
#if APR_HAS_ANSI_FS
|
||||
ELSE_WIN_OS_IS_ANSI
|
||||
{
|
||||
/* This code path is always be invoked by apr_dir_open or
|
||||
* apr_dir_rewind, so return without filling out the finfo.
|
||||
*/
|
||||
if (thedir->dirhand == INVALID_HANDLE_VALUE) {
|
||||
/* '/' terminated, so add the '*' and pop it when we finish */
|
||||
char *eop = strchr(thedir->dirname, '\0');
|
||||
eop[0] = '*';
|
||||
eop[1] = '\0';
|
||||
thedir->dirhand = FindFirstFileA(thedir->dirname,
|
||||
thedir->n.entry);
|
||||
eop[0] = '\0';
|
||||
if (thedir->dirhand == INVALID_HANDLE_VALUE) {
|
||||
return apr_get_os_error();
|
||||
}
|
||||
thedir->bof = 1;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
else if (thedir->bof) {
|
||||
/* Noop - we already called FindFirstFileW from
|
||||
* either apr_dir_open or apr_dir_rewind ... use
|
||||
* that first record.
|
||||
*/
|
||||
thedir->bof = 0;
|
||||
}
|
||||
else if (!FindNextFileA(thedir->dirhand, thedir->n.entry)) {
|
||||
return apr_get_os_error();
|
||||
}
|
||||
while (thedir->rootlen &&
|
||||
thedir->rootlen + strlen(thedir->n.entry->cFileName) >= MAX_PATH)
|
||||
{
|
||||
if (!FindNextFileA(thedir->dirhand, thedir->n.entry)) {
|
||||
return apr_get_os_error();
|
||||
}
|
||||
}
|
||||
fname = thedir->n.entry->cFileName;
|
||||
}
|
||||
#endif
|
||||
|
||||
fillin_fileinfo(finfo, (WIN32_FILE_ATTRIBUTE_DATA *) thedir->w.entry,
|
||||
0, wanted);
|
||||
finfo->pool = thedir->pool;
|
||||
|
||||
finfo->valid |= APR_FINFO_NAME;
|
||||
finfo->name = fname;
|
||||
|
||||
if (wanted &= ~finfo->valid) {
|
||||
/* Go back and get more_info if we can't answer the whole inquiry
|
||||
*/
|
||||
#if APR_HAS_UNICODE_FS
|
||||
IF_WIN_OS_IS_UNICODE
|
||||
{
|
||||
/* Almost all our work is done. Tack on the wide file name
|
||||
* to the end of the wdirname (already / delimited)
|
||||
*/
|
||||
if (!eos)
|
||||
eos = wcschr(wdirname, '\0');
|
||||
wcscpy(eos, thedir->w.entry->cFileName);
|
||||
rv = more_finfo(finfo, wdirname, wanted, MORE_OF_WFSPEC);
|
||||
eos[0] = '\0';
|
||||
return rv;
|
||||
}
|
||||
#endif
|
||||
#if APR_HAS_ANSI_FS
|
||||
ELSE_WIN_OS_IS_ANSI
|
||||
{
|
||||
#if APR_HAS_UNICODE_FS
|
||||
/* Don't waste stack space on a second buffer, the one we set
|
||||
* aside for the wide directory name is twice what we need.
|
||||
*/
|
||||
char *fspec = (char*)wdirname;
|
||||
#else
|
||||
char fspec[APR_PATH_MAX];
|
||||
#endif
|
||||
apr_size_t dirlen = strlen(thedir->dirname);
|
||||
if (dirlen >= sizeof(fspec))
|
||||
dirlen = sizeof(fspec) - 1;
|
||||
apr_cpystrn(fspec, thedir->dirname, sizeof(fspec));
|
||||
apr_cpystrn(fspec + dirlen, fname, sizeof(fspec) - dirlen);
|
||||
return more_finfo(finfo, fspec, wanted, MORE_OF_FSPEC);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_dir_rewind(apr_dir_t *dir)
|
||||
{
|
||||
apr_status_t rv;
|
||||
|
||||
/* this will mark the handle as invalid and we'll open it
|
||||
* again if apr_dir_read() is subsequently called
|
||||
*/
|
||||
rv = dir_cleanup(dir);
|
||||
|
||||
if (rv == APR_SUCCESS)
|
||||
rv = apr_dir_read(NULL, 0, dir);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_dir_make(const char *path, apr_fileperms_t perm,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
#if APR_HAS_UNICODE_FS
|
||||
IF_WIN_OS_IS_UNICODE
|
||||
{
|
||||
apr_wchar_t wpath[APR_PATH_MAX];
|
||||
apr_status_t rv;
|
||||
if ((rv = utf8_to_unicode_path(wpath,
|
||||
sizeof(wpath) / sizeof(apr_wchar_t),
|
||||
path))) {
|
||||
return rv;
|
||||
}
|
||||
if (!CreateDirectoryW(wpath, NULL)) {
|
||||
return apr_get_os_error();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if APR_HAS_ANSI_FS
|
||||
ELSE_WIN_OS_IS_ANSI
|
||||
if (!CreateDirectory(path, NULL)) {
|
||||
return apr_get_os_error();
|
||||
}
|
||||
#endif
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static apr_status_t dir_make_parent(char *path,
|
||||
apr_fileperms_t perm,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
apr_status_t rv;
|
||||
char *ch = strrchr(path, '\\');
|
||||
if (!ch) {
|
||||
return APR_ENOENT;
|
||||
}
|
||||
|
||||
*ch = '\0';
|
||||
rv = apr_dir_make (path, perm, pool); /* Try to make straight off */
|
||||
|
||||
if (APR_STATUS_IS_ENOENT(rv)) { /* Missing an intermediate dir */
|
||||
rv = dir_make_parent(path, perm, pool);
|
||||
|
||||
if (rv == APR_SUCCESS || APR_STATUS_IS_EEXIST(rv)) {
|
||||
rv = apr_dir_make(path, perm, pool); /* And complete the path */
|
||||
}
|
||||
}
|
||||
|
||||
*ch = '\\'; /* Always replace the slash before returning */
|
||||
return rv;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_dir_make_recursive(const char *path,
|
||||
apr_fileperms_t perm,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
apr_status_t rv = 0;
|
||||
|
||||
rv = apr_dir_make (path, perm, pool); /* Try to make PATH right out */
|
||||
|
||||
if (APR_STATUS_IS_ENOENT(rv)) { /* Missing an intermediate dir */
|
||||
char *dir;
|
||||
|
||||
rv = apr_filepath_merge(&dir, "", path, APR_FILEPATH_NATIVE, pool);
|
||||
|
||||
if (rv != APR_SUCCESS)
|
||||
return rv;
|
||||
|
||||
rv = dir_make_parent(dir, perm, pool); /* Make intermediate dirs */
|
||||
|
||||
if (rv == APR_SUCCESS || APR_STATUS_IS_EEXIST(rv)) {
|
||||
rv = apr_dir_make (dir, perm, pool); /* And complete the path */
|
||||
|
||||
if (APR_STATUS_IS_EEXIST(rv)) {
|
||||
rv = APR_SUCCESS; /* Timing issue; see comment below */
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (APR_STATUS_IS_EEXIST(rv)) {
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
rv = APR_SUCCESS;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_dir_remove(const char *path, apr_pool_t *pool)
|
||||
{
|
||||
#if APR_HAS_UNICODE_FS
|
||||
IF_WIN_OS_IS_UNICODE
|
||||
{
|
||||
apr_wchar_t wpath[APR_PATH_MAX];
|
||||
apr_status_t rv;
|
||||
if ((rv = utf8_to_unicode_path(wpath,
|
||||
sizeof(wpath) / sizeof(apr_wchar_t),
|
||||
path))) {
|
||||
return rv;
|
||||
}
|
||||
if (!RemoveDirectoryW(wpath)) {
|
||||
return apr_get_os_error();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if APR_HAS_ANSI_FS
|
||||
ELSE_WIN_OS_IS_ANSI
|
||||
if (!RemoveDirectory(path)) {
|
||||
return apr_get_os_error();
|
||||
}
|
||||
#endif
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_os_dir_get(apr_os_dir_t **thedir,
|
||||
apr_dir_t *dir)
|
||||
{
|
||||
if (dir == NULL) {
|
||||
return APR_ENODIR;
|
||||
}
|
||||
*thedir = dir->dirhand;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_os_dir_put(apr_dir_t **dir,
|
||||
apr_os_dir_t *thedir,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
return APR_ENOTIMPL;
|
||||
}
|
||||
+229
@@ -0,0 +1,229 @@
|
||||
/* 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 <string.h>
|
||||
#include "apr_arch_inherit.h"
|
||||
#include <io.h> /* for [_open/_get]_osfhandle */
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_dup(apr_file_t **new_file,
|
||||
apr_file_t *old_file, apr_pool_t *p)
|
||||
{
|
||||
#ifdef _WIN32_WCE
|
||||
return APR_ENOTIMPL;
|
||||
#else
|
||||
HANDLE hproc = GetCurrentProcess();
|
||||
HANDLE newhand = NULL;
|
||||
|
||||
if (!DuplicateHandle(hproc, old_file->filehand,
|
||||
hproc, &newhand, 0, FALSE,
|
||||
DUPLICATE_SAME_ACCESS)) {
|
||||
return apr_get_os_error();
|
||||
}
|
||||
|
||||
(*new_file) = (apr_file_t *) apr_pcalloc(p, sizeof(apr_file_t));
|
||||
(*new_file)->filehand = newhand;
|
||||
(*new_file)->flags = old_file->flags & ~(APR_STD_FLAGS | APR_INHERIT);
|
||||
(*new_file)->pool = p;
|
||||
(*new_file)->fname = apr_pstrdup(p, old_file->fname);
|
||||
(*new_file)->append = old_file->append;
|
||||
(*new_file)->buffered = FALSE;
|
||||
(*new_file)->ungetchar = old_file->ungetchar;
|
||||
|
||||
#if APR_HAS_THREADS
|
||||
if (old_file->mutex) {
|
||||
apr_thread_mutex_create(&((*new_file)->mutex),
|
||||
APR_THREAD_MUTEX_DEFAULT, p);
|
||||
}
|
||||
#endif
|
||||
|
||||
apr_pool_cleanup_register((*new_file)->pool, (void *)(*new_file), file_cleanup,
|
||||
apr_pool_cleanup_null);
|
||||
|
||||
#if APR_FILES_AS_SOCKETS
|
||||
/* Create a pollset with room for one descriptor. */
|
||||
/* ### check return codes */
|
||||
(void) apr_pollset_create(&(*new_file)->pollset, 1, p, 0);
|
||||
#endif
|
||||
return APR_SUCCESS;
|
||||
#endif /* !defined(_WIN32_WCE) */
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_dup2(apr_file_t *new_file,
|
||||
apr_file_t *old_file, apr_pool_t *p)
|
||||
{
|
||||
#ifdef _WIN32_WCE
|
||||
return APR_ENOTIMPL;
|
||||
#else
|
||||
HANDLE hproc = GetCurrentProcess();
|
||||
HANDLE newhand = NULL;
|
||||
apr_int32_t newflags;
|
||||
int fd;
|
||||
|
||||
if (new_file->flags & APR_STD_FLAGS)
|
||||
{
|
||||
if ((new_file->flags & APR_STD_FLAGS) == APR_STDERR_FLAG)
|
||||
{
|
||||
/* Flush stderr and unset its buffer, then commit the fd-based buffer.
|
||||
* This is typically a noop for Win2K/XP since services with NULL std
|
||||
* handles [but valid FILE *'s, oddly enough], but is required
|
||||
* for NT 4.0 and to use this code outside of services.
|
||||
*/
|
||||
fflush(stderr);
|
||||
setvbuf(stderr, NULL, _IONBF, 0);
|
||||
if (!_isatty(2)) {
|
||||
_commit(2 /* stderr */);
|
||||
}
|
||||
|
||||
/* Clone a handle can _close() without harming the source handle,
|
||||
* open an MSVCRT-based pseudo-fd for the file handle, then dup2
|
||||
* and close our temporary pseudo-fd once it's been duplicated.
|
||||
* This will incidently keep the FILE-based stderr in sync.
|
||||
* Note the apparently redundant _O_BINARY coersions are required.
|
||||
* Note the _dup2 will close the previous std Win32 handle.
|
||||
*/
|
||||
if (!DuplicateHandle(hproc, old_file->filehand, hproc, &newhand,
|
||||
0, FALSE, DUPLICATE_SAME_ACCESS)) {
|
||||
return apr_get_os_error();
|
||||
}
|
||||
fd = _open_osfhandle((INT_PTR)newhand, _O_WRONLY | _O_BINARY);
|
||||
_dup2(fd, 2);
|
||||
_close(fd);
|
||||
_setmode(2, _O_BINARY);
|
||||
|
||||
/* hPipeWrite was _close()'ed above, and _dup2()'ed
|
||||
* to fd 2 creating a new, inherited Win32 handle.
|
||||
* Recover that real handle from fd 2. Note that
|
||||
* SetStdHandle(STD_ERROR_HANDLE, _get_osfhandle(2))
|
||||
* is implicit in the dup2() call above
|
||||
*/
|
||||
newhand = (HANDLE)_get_osfhandle(2);
|
||||
}
|
||||
else if ((new_file->flags & APR_STD_FLAGS) == APR_STDOUT_FLAG) {
|
||||
/* For the process flow see the stderr case above */
|
||||
fflush(stdout);
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
if (!_isatty(1)) {
|
||||
_commit(1 /* stdout */);
|
||||
}
|
||||
|
||||
if (!DuplicateHandle(hproc, old_file->filehand, hproc, &newhand,
|
||||
0, FALSE, DUPLICATE_SAME_ACCESS)) {
|
||||
return apr_get_os_error();
|
||||
}
|
||||
fd = _open_osfhandle((INT_PTR)newhand, _O_WRONLY | _O_BINARY);
|
||||
_dup2(fd, 1);
|
||||
_close(fd);
|
||||
_setmode(1, _O_BINARY);
|
||||
newhand = (HANDLE)_get_osfhandle(1);
|
||||
}
|
||||
else if ((new_file->flags & APR_STD_FLAGS) == APR_STDIN_FLAG) {
|
||||
/* For the process flow see the stderr case above */
|
||||
fflush(stdin);
|
||||
setvbuf(stdin, NULL, _IONBF, 0);
|
||||
|
||||
if (!DuplicateHandle(hproc, old_file->filehand, hproc, &newhand,
|
||||
0, FALSE, DUPLICATE_SAME_ACCESS)) {
|
||||
return apr_get_os_error();
|
||||
}
|
||||
fd = _open_osfhandle((INT_PTR)newhand, _O_RDONLY | _O_BINARY);
|
||||
_dup2(fd, 0);
|
||||
_close(fd);
|
||||
_setmode(0, _O_BINARY);
|
||||
newhand = (HANDLE)_get_osfhandle(0);
|
||||
}
|
||||
newflags = (new_file->flags & APR_STD_FLAGS)
|
||||
| (old_file->flags & ~APR_STD_FLAGS) | APR_INHERIT;
|
||||
|
||||
/* No need to close the old file, _dup2() above did that for us */
|
||||
}
|
||||
else {
|
||||
if (!DuplicateHandle(hproc, old_file->filehand,
|
||||
hproc, &newhand, 0,
|
||||
FALSE, DUPLICATE_SAME_ACCESS)) {
|
||||
return apr_get_os_error();
|
||||
}
|
||||
newflags = old_file->flags & ~(APR_STD_FLAGS | APR_INHERIT);
|
||||
|
||||
if (new_file->filehand
|
||||
&& (new_file->filehand != INVALID_HANDLE_VALUE)) {
|
||||
CloseHandle(new_file->filehand);
|
||||
}
|
||||
}
|
||||
|
||||
new_file->flags = newflags;
|
||||
new_file->filehand = newhand;
|
||||
new_file->fname = apr_pstrdup(new_file->pool, old_file->fname);
|
||||
new_file->append = old_file->append;
|
||||
new_file->buffered = FALSE;
|
||||
new_file->ungetchar = old_file->ungetchar;
|
||||
|
||||
#if APR_HAS_THREADS
|
||||
if (old_file->mutex) {
|
||||
apr_thread_mutex_create(&(new_file->mutex),
|
||||
APR_THREAD_MUTEX_DEFAULT, p);
|
||||
}
|
||||
#endif
|
||||
|
||||
return APR_SUCCESS;
|
||||
#endif /* !defined(_WIN32_WCE) */
|
||||
}
|
||||
|
||||
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 (old_file->mutex) {
|
||||
apr_thread_mutex_create(&((*new_file)->mutex),
|
||||
APR_THREAD_MUTEX_DEFAULT, p);
|
||||
apr_thread_mutex_destroy(old_file->mutex);
|
||||
}
|
||||
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),
|
||||
file_cleanup,
|
||||
file_cleanup);
|
||||
}
|
||||
|
||||
old_file->filehand = INVALID_HANDLE_VALUE;
|
||||
apr_pool_cleanup_kill(old_file->pool, (void *)old_file,
|
||||
file_cleanup);
|
||||
|
||||
#if APR_FILES_AS_SOCKETS
|
||||
/* Create a pollset with room for one descriptor. */
|
||||
/* ### check return codes */
|
||||
(void) apr_pollset_create(&(*new_file)->pollset, 1, p, 0);
|
||||
#endif
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
+1005
File diff suppressed because it is too large
Load Diff
+825
@@ -0,0 +1,825 @@
|
||||
/* 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 <aclapi.h>
|
||||
#include "apr_private.h"
|
||||
#include "apr_arch_file_io.h"
|
||||
#include "apr_file_io.h"
|
||||
#include "apr_general.h"
|
||||
#include "apr_strings.h"
|
||||
#include "apr_errno.h"
|
||||
#include "apr_time.h"
|
||||
#include <sys/stat.h>
|
||||
#include "apr_arch_atime.h"
|
||||
#include "apr_arch_misc.h"
|
||||
|
||||
/* We have to assure that the file name contains no '*'s, or other
|
||||
* wildcards when using FindFirstFile to recover the true file name.
|
||||
*/
|
||||
static apr_status_t test_safe_name(const char *name)
|
||||
{
|
||||
/* Only accept ':' in the second position of the filename,
|
||||
* as the drive letter delimiter:
|
||||
*/
|
||||
if (apr_isalpha(*name) && (name[1] == ':')) {
|
||||
name += 2;
|
||||
}
|
||||
while (*name) {
|
||||
if (!IS_FNCHAR(*name) && (*name != '\\') && (*name != '/')) {
|
||||
if (*name == '?' || *name == '*')
|
||||
return APR_EPATHWILD;
|
||||
else
|
||||
return APR_EBADPATH;
|
||||
}
|
||||
++name;
|
||||
}
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
static apr_status_t free_localheap(void *heap) {
|
||||
LocalFree(heap);
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
static apr_gid_t worldid = NULL;
|
||||
|
||||
static void free_world(void)
|
||||
{
|
||||
if (worldid) {
|
||||
FreeSid(worldid);
|
||||
worldid = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Left bit shifts from World scope to given scope */
|
||||
typedef enum prot_scope_e {
|
||||
prot_scope_world = 0,
|
||||
prot_scope_group = 4,
|
||||
prot_scope_user = 8
|
||||
} prot_scope_e;
|
||||
|
||||
static apr_fileperms_t convert_prot(ACCESS_MASK acc, prot_scope_e scope)
|
||||
{
|
||||
/* These choices are based on the single filesystem bit that controls
|
||||
* the given behavior. They are -not- recommended for any set protection
|
||||
* function, such a function should -set- use GENERIC_READ/WRITE/EXECUTE
|
||||
*/
|
||||
apr_fileperms_t prot = 0;
|
||||
if (acc & FILE_EXECUTE)
|
||||
prot |= APR_WEXECUTE;
|
||||
if (acc & FILE_WRITE_DATA)
|
||||
prot |= APR_WWRITE;
|
||||
if (acc & FILE_READ_DATA)
|
||||
prot |= APR_WREAD;
|
||||
return (prot << scope);
|
||||
}
|
||||
|
||||
static void resolve_prot(apr_finfo_t *finfo, apr_int32_t wanted, PACL dacl)
|
||||
{
|
||||
TRUSTEE_W ident = {NULL, NO_MULTIPLE_TRUSTEE, TRUSTEE_IS_SID};
|
||||
ACCESS_MASK acc;
|
||||
/*
|
||||
* This function is only invoked for WinNT,
|
||||
* there is no reason for os_level testing here.
|
||||
*/
|
||||
if ((wanted & APR_FINFO_WPROT) && !worldid) {
|
||||
SID_IDENTIFIER_AUTHORITY SIDAuth = {SECURITY_WORLD_SID_AUTHORITY};
|
||||
if (AllocateAndInitializeSid(&SIDAuth, 1, SECURITY_WORLD_RID,
|
||||
0, 0, 0, 0, 0, 0, 0, &worldid))
|
||||
atexit(free_world);
|
||||
else
|
||||
worldid = NULL;
|
||||
}
|
||||
if ((wanted & APR_FINFO_UPROT) && (finfo->valid & APR_FINFO_USER)) {
|
||||
ident.TrusteeType = TRUSTEE_IS_USER;
|
||||
ident.ptstrName = finfo->user;
|
||||
/* GetEffectiveRightsFromAcl isn't supported under Win9x,
|
||||
* which shouldn't come as a surprize. Since we are passing
|
||||
* TRUSTEE_IS_SID, always skip the A->W layer.
|
||||
*/
|
||||
if (GetEffectiveRightsFromAclW(dacl, &ident, &acc) == ERROR_SUCCESS) {
|
||||
finfo->protection |= convert_prot(acc, prot_scope_user);
|
||||
finfo->valid |= APR_FINFO_UPROT;
|
||||
}
|
||||
}
|
||||
/* Windows NT: did not return group rights.
|
||||
* Windows 2000 returns group rights information.
|
||||
* Since WinNT kernels don't follow the unix model of
|
||||
* group associations, this all all pretty mute.
|
||||
*/
|
||||
if ((wanted & APR_FINFO_GPROT) && (finfo->valid & APR_FINFO_GROUP)) {
|
||||
ident.TrusteeType = TRUSTEE_IS_GROUP;
|
||||
ident.ptstrName = finfo->group;
|
||||
if (GetEffectiveRightsFromAclW(dacl, &ident, &acc) == ERROR_SUCCESS) {
|
||||
finfo->protection |= convert_prot(acc, prot_scope_group);
|
||||
finfo->valid |= APR_FINFO_GPROT;
|
||||
}
|
||||
}
|
||||
if ((wanted & APR_FINFO_WPROT) && (worldid)) {
|
||||
ident.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
|
||||
ident.ptstrName = worldid;
|
||||
if (GetEffectiveRightsFromAclW(dacl, &ident, &acc) == ERROR_SUCCESS) {
|
||||
finfo->protection |= convert_prot(acc, prot_scope_world);
|
||||
finfo->valid |= APR_FINFO_WPROT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static apr_status_t resolve_ident(apr_finfo_t *finfo, const char *fname,
|
||||
apr_int32_t wanted, apr_pool_t *pool)
|
||||
{
|
||||
apr_file_t *thefile = NULL;
|
||||
apr_status_t rv;
|
||||
/*
|
||||
* NT5 (W2K) only supports symlinks in the same manner as mount points.
|
||||
* This code should eventually take that into account, for now treat
|
||||
* every reparse point as a symlink...
|
||||
*
|
||||
* We must open the file with READ_CONTROL if we plan to retrieve the
|
||||
* user, group or permissions.
|
||||
*/
|
||||
|
||||
if ((rv = apr_file_open(&thefile, fname, APR_OPENINFO
|
||||
| ((wanted & APR_FINFO_LINK) ? APR_OPENLINK : 0)
|
||||
| ((wanted & (APR_FINFO_PROT | APR_FINFO_OWNER))
|
||||
? APR_READCONTROL : 0),
|
||||
APR_OS_DEFAULT, pool)) == APR_SUCCESS) {
|
||||
rv = apr_file_info_get(finfo, wanted, thefile);
|
||||
finfo->filehand = NULL;
|
||||
apr_file_close(thefile);
|
||||
}
|
||||
else if (APR_STATUS_IS_EACCES(rv) && (wanted & (APR_FINFO_PROT
|
||||
| APR_FINFO_OWNER))) {
|
||||
/* We have a backup plan. Perhaps we couldn't grab READ_CONTROL?
|
||||
* proceed without asking for that permission...
|
||||
*/
|
||||
if ((rv = apr_file_open(&thefile, fname, APR_OPENINFO
|
||||
| ((wanted & APR_FINFO_LINK) ? APR_OPENLINK : 0),
|
||||
APR_OS_DEFAULT, pool)) == APR_SUCCESS) {
|
||||
rv = apr_file_info_get(finfo, wanted & ~(APR_FINFO_PROT
|
||||
| APR_FINFO_OWNER),
|
||||
thefile);
|
||||
finfo->filehand = NULL;
|
||||
apr_file_close(thefile);
|
||||
}
|
||||
}
|
||||
|
||||
if (rv != APR_SUCCESS && rv != APR_INCOMPLETE)
|
||||
return (rv);
|
||||
|
||||
/* We picked up this case above and had opened the link's properties */
|
||||
if (wanted & APR_FINFO_LINK)
|
||||
finfo->valid |= APR_FINFO_LINK;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static apr_status_t guess_protection_bits(apr_finfo_t *finfo,
|
||||
apr_int32_t wanted)
|
||||
{
|
||||
/* Read, write execute for owner. In the Win9x environment, any
|
||||
* readable file is executable (well, not entirely 100% true, but
|
||||
* still looking for some cheap logic that would help us here.)
|
||||
* The same holds on NT if a file doesn't have a DACL (e.g., on FAT)
|
||||
*/
|
||||
if (finfo->protection & APR_FREADONLY) {
|
||||
finfo->protection |= APR_WREAD | APR_WEXECUTE;
|
||||
}
|
||||
else {
|
||||
finfo->protection |= APR_WREAD | APR_WEXECUTE | APR_WWRITE;
|
||||
}
|
||||
finfo->protection |= (finfo->protection << prot_scope_group)
|
||||
| (finfo->protection << prot_scope_user);
|
||||
|
||||
finfo->valid |= APR_FINFO_UPROT | APR_FINFO_GPROT | APR_FINFO_WPROT;
|
||||
|
||||
return ((wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS);
|
||||
}
|
||||
|
||||
apr_status_t more_finfo(apr_finfo_t *finfo, const void *ufile,
|
||||
apr_int32_t wanted, int whatfile)
|
||||
{
|
||||
PSID user = NULL, grp = NULL;
|
||||
PACL dacl = NULL;
|
||||
apr_status_t rv;
|
||||
|
||||
if (apr_os_level < APR_WIN_NT)
|
||||
return guess_protection_bits(finfo, wanted);
|
||||
|
||||
if (wanted & (APR_FINFO_PROT | APR_FINFO_OWNER))
|
||||
{
|
||||
/* On NT this request is incredibly expensive, but accurate.
|
||||
* Since the WinNT-only functions below are protected by the
|
||||
* (apr_os_level < APR_WIN_NT) case above, we need no extra
|
||||
* tests, but remember GetNamedSecurityInfo & GetSecurityInfo
|
||||
* are not supported on 9x.
|
||||
*/
|
||||
SECURITY_INFORMATION sinf = 0;
|
||||
PSECURITY_DESCRIPTOR pdesc = NULL;
|
||||
if (wanted & (APR_FINFO_USER | APR_FINFO_UPROT))
|
||||
sinf |= OWNER_SECURITY_INFORMATION;
|
||||
if (wanted & (APR_FINFO_GROUP | APR_FINFO_GPROT))
|
||||
sinf |= GROUP_SECURITY_INFORMATION;
|
||||
if (wanted & APR_FINFO_PROT)
|
||||
sinf |= DACL_SECURITY_INFORMATION;
|
||||
if (whatfile == MORE_OF_WFSPEC) {
|
||||
apr_wchar_t *wfile = (apr_wchar_t*) ufile;
|
||||
int fix = 0;
|
||||
if (wcsncmp(wfile, L"\\\\?\\", 4) == 0) {
|
||||
fix = 4;
|
||||
if (wcsncmp(wfile + fix, L"UNC\\", 4) == 0)
|
||||
wfile[6] = L'\\', fix = 6;
|
||||
}
|
||||
rv = GetNamedSecurityInfoW(wfile + fix,
|
||||
SE_FILE_OBJECT, sinf,
|
||||
((wanted & (APR_FINFO_USER | APR_FINFO_UPROT)) ? &user : NULL),
|
||||
((wanted & (APR_FINFO_GROUP | APR_FINFO_GPROT)) ? &grp : NULL),
|
||||
((wanted & APR_FINFO_PROT) ? &dacl : NULL),
|
||||
NULL, &pdesc);
|
||||
if (fix == 6)
|
||||
wfile[6] = L'C';
|
||||
}
|
||||
else if (whatfile == MORE_OF_FSPEC)
|
||||
rv = GetNamedSecurityInfoA((char*)ufile,
|
||||
SE_FILE_OBJECT, sinf,
|
||||
((wanted & (APR_FINFO_USER | APR_FINFO_UPROT)) ? &user : NULL),
|
||||
((wanted & (APR_FINFO_GROUP | APR_FINFO_GPROT)) ? &grp : NULL),
|
||||
((wanted & APR_FINFO_PROT) ? &dacl : NULL),
|
||||
NULL, &pdesc);
|
||||
else if (whatfile == MORE_OF_HANDLE)
|
||||
rv = GetSecurityInfo((HANDLE)ufile,
|
||||
SE_FILE_OBJECT, sinf,
|
||||
((wanted & (APR_FINFO_USER | APR_FINFO_UPROT)) ? &user : NULL),
|
||||
((wanted & (APR_FINFO_GROUP | APR_FINFO_GPROT)) ? &grp : NULL),
|
||||
((wanted & APR_FINFO_PROT) ? &dacl : NULL),
|
||||
NULL, &pdesc);
|
||||
else
|
||||
return APR_INCOMPLETE; /* should not occur */
|
||||
if (rv == ERROR_SUCCESS)
|
||||
apr_pool_cleanup_register(finfo->pool, pdesc, free_localheap,
|
||||
apr_pool_cleanup_null);
|
||||
else
|
||||
user = grp = dacl = NULL;
|
||||
|
||||
if (user) {
|
||||
finfo->user = user;
|
||||
finfo->valid |= APR_FINFO_USER;
|
||||
}
|
||||
|
||||
if (grp) {
|
||||
finfo->group = grp;
|
||||
finfo->valid |= APR_FINFO_GROUP;
|
||||
}
|
||||
|
||||
if (dacl) {
|
||||
/* Retrieved the discresionary access list */
|
||||
resolve_prot(finfo, wanted, dacl);
|
||||
}
|
||||
else if (wanted & APR_FINFO_PROT)
|
||||
guess_protection_bits(finfo, wanted);
|
||||
}
|
||||
|
||||
if ((apr_os_level >= APR_WIN_2000) && (wanted & APR_FINFO_CSIZE)
|
||||
&& (finfo->filetype == APR_REG))
|
||||
{
|
||||
DWORD sizelo, sizehi;
|
||||
if (whatfile == MORE_OF_HANDLE) {
|
||||
/* Not available for development and implementation under
|
||||
* a reasonable license; if you review the licensing
|
||||
* terms and conditions of;
|
||||
* http://go.microsoft.com/fwlink/?linkid=84083
|
||||
* you probably understand why APR chooses not to implement.
|
||||
*/
|
||||
IOSB sb;
|
||||
FSI fi;
|
||||
if ((ZwQueryInformationFile((HANDLE)ufile, &sb,
|
||||
&fi, sizeof(fi), 5) == 0)
|
||||
&& (sb.Status == 0)) {
|
||||
finfo->csize = fi.AllocationSize;
|
||||
finfo->valid |= APR_FINFO_CSIZE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
SetLastError(NO_ERROR);
|
||||
if (whatfile == MORE_OF_WFSPEC)
|
||||
sizelo = GetCompressedFileSizeW((apr_wchar_t*)ufile, &sizehi);
|
||||
else if (whatfile == MORE_OF_FSPEC)
|
||||
sizelo = GetCompressedFileSizeA((char*)ufile, &sizehi);
|
||||
else
|
||||
return APR_EGENERAL; /* should not occur */
|
||||
|
||||
if (sizelo != INVALID_FILE_SIZE || GetLastError() == NO_ERROR) {
|
||||
#if APR_HAS_LARGE_FILES
|
||||
finfo->csize = (apr_off_t)sizelo
|
||||
| ((apr_off_t)sizehi << 32);
|
||||
#else
|
||||
finfo->csize = (apr_off_t)sizelo;
|
||||
if (finfo->csize < 0 || sizehi)
|
||||
finfo->csize = 0x7fffffff;
|
||||
#endif
|
||||
finfo->valid |= APR_FINFO_CSIZE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ((wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
/* This generic fillin depends upon byhandle to be passed as 0 when
|
||||
* a WIN32_FILE_ATTRIBUTE_DATA or either WIN32_FIND_DATA [A or W] is
|
||||
* passed for wininfo. When the BY_HANDLE_FILE_INFORMATION structure
|
||||
* is passed for wininfo, byhandle is passed as 1 to offset the one
|
||||
* dword discrepancy in offset of the High/Low size structure members.
|
||||
*
|
||||
* The generic fillin returns 1 if the caller should further inquire
|
||||
* if this is a CHR filetype. If it's reasonably certain it can't be,
|
||||
* then the function returns 0.
|
||||
*/
|
||||
int fillin_fileinfo(apr_finfo_t *finfo,
|
||||
WIN32_FILE_ATTRIBUTE_DATA *wininfo,
|
||||
int byhandle, apr_int32_t wanted)
|
||||
{
|
||||
DWORD *sizes = &wininfo->nFileSizeHigh + byhandle;
|
||||
int warn = 0;
|
||||
|
||||
memset(finfo, '\0', sizeof(*finfo));
|
||||
|
||||
FileTimeToAprTime(&finfo->atime, &wininfo->ftLastAccessTime);
|
||||
FileTimeToAprTime(&finfo->ctime, &wininfo->ftCreationTime);
|
||||
FileTimeToAprTime(&finfo->mtime, &wininfo->ftLastWriteTime);
|
||||
|
||||
#if APR_HAS_LARGE_FILES
|
||||
finfo->size = (apr_off_t)sizes[1]
|
||||
| ((apr_off_t)sizes[0] << 32);
|
||||
#else
|
||||
finfo->size = (apr_off_t)sizes[1];
|
||||
if (finfo->size < 0 || sizes[0])
|
||||
finfo->size = 0x7fffffff;
|
||||
#endif
|
||||
|
||||
if (wanted & APR_FINFO_LINK &&
|
||||
wininfo->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
|
||||
finfo->filetype = APR_LNK;
|
||||
}
|
||||
else if (wininfo->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
finfo->filetype = APR_DIR;
|
||||
}
|
||||
else if (wininfo->dwFileAttributes & FILE_ATTRIBUTE_DEVICE) {
|
||||
/* Warning: This test only succeeds on Win9x, on NT these files
|
||||
* (con, aux, nul, lpt#, com# etc) escape early detection!
|
||||
*/
|
||||
finfo->filetype = APR_CHR;
|
||||
}
|
||||
else {
|
||||
/* Warning: Short of opening the handle to the file, the 'FileType'
|
||||
* appears to be unknowable (in any trustworthy or consistent sense)
|
||||
* on WinNT/2K as far as PIPE, CHR, etc are concerned.
|
||||
*/
|
||||
if (!wininfo->ftLastWriteTime.dwLowDateTime
|
||||
&& !wininfo->ftLastWriteTime.dwHighDateTime
|
||||
&& !finfo->size)
|
||||
warn = 1;
|
||||
finfo->filetype = APR_REG;
|
||||
}
|
||||
|
||||
/* The following flags are [for this moment] private to Win32.
|
||||
* That's the only excuse for not toggling valid bits to reflect them.
|
||||
*/
|
||||
if (wininfo->dwFileAttributes & FILE_ATTRIBUTE_READONLY)
|
||||
finfo->protection = APR_FREADONLY;
|
||||
|
||||
finfo->valid = APR_FINFO_ATIME | APR_FINFO_CTIME | APR_FINFO_MTIME
|
||||
| APR_FINFO_SIZE | APR_FINFO_TYPE; /* == APR_FINFO_MIN */
|
||||
|
||||
/* Only byhandle optionally tests link targets, so tell that caller
|
||||
* what it wants to hear, otherwise the byattributes is never
|
||||
* reporting anything but the link.
|
||||
*/
|
||||
if (!byhandle || (wanted & APR_FINFO_LINK))
|
||||
finfo->valid |= APR_FINFO_LINK;
|
||||
return warn;
|
||||
}
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_info_get(apr_finfo_t *finfo, apr_int32_t wanted,
|
||||
apr_file_t *thefile)
|
||||
{
|
||||
BY_HANDLE_FILE_INFORMATION FileInfo;
|
||||
|
||||
if (thefile->buffered) {
|
||||
/* XXX: flush here is not mutex protected */
|
||||
apr_status_t rv = apr_file_flush(thefile);
|
||||
if (rv != APR_SUCCESS)
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* GetFileInformationByHandle() is implemented via two syscalls:
|
||||
* QueryInformationVolume and QueryAllInformationFile. Use cheaper
|
||||
* GetFileSizeEx() API if we only need to get the file size. */
|
||||
if (wanted == APR_FINFO_SIZE) {
|
||||
LARGE_INTEGER size;
|
||||
|
||||
if (!GetFileSizeEx(thefile->filehand, &size)) {
|
||||
return apr_get_os_error();
|
||||
}
|
||||
|
||||
finfo->pool = thefile->pool;
|
||||
finfo->fname = thefile->fname;
|
||||
finfo->size = size.QuadPart;
|
||||
finfo->valid = APR_FINFO_SIZE;
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
if (!GetFileInformationByHandle(thefile->filehand, &FileInfo)) {
|
||||
return apr_get_os_error();
|
||||
}
|
||||
|
||||
fillin_fileinfo(finfo, (WIN32_FILE_ATTRIBUTE_DATA *) &FileInfo, 1, wanted);
|
||||
|
||||
if (finfo->filetype == APR_REG)
|
||||
{
|
||||
/* Go the extra mile to be -certain- that we have a real, regular
|
||||
* file, since the attribute bits aren't a certain thing. Even
|
||||
* though fillin should have hinted if we *must* do this, we
|
||||
* don't need to take chances while the handle is already open.
|
||||
*/
|
||||
DWORD FileType;
|
||||
if ((FileType = GetFileType(thefile->filehand))) {
|
||||
if (FileType == FILE_TYPE_CHAR) {
|
||||
finfo->filetype = APR_CHR;
|
||||
}
|
||||
else if (FileType == FILE_TYPE_PIPE) {
|
||||
finfo->filetype = APR_PIPE;
|
||||
}
|
||||
/* Otherwise leave the original conclusion alone
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
finfo->pool = thefile->pool;
|
||||
|
||||
/* ### The finfo lifetime may exceed the lifetime of thefile->pool
|
||||
* but finfo's aren't managed in pools, so where on earth would
|
||||
* we pstrdup the fname into???
|
||||
*/
|
||||
finfo->fname = thefile->fname;
|
||||
|
||||
/* Extra goodies known only by GetFileInformationByHandle() */
|
||||
finfo->inode = (apr_ino_t)FileInfo.nFileIndexLow
|
||||
| ((apr_ino_t)FileInfo.nFileIndexHigh << 32);
|
||||
finfo->device = FileInfo.dwVolumeSerialNumber;
|
||||
finfo->nlink = FileInfo.nNumberOfLinks;
|
||||
|
||||
finfo->valid |= APR_FINFO_IDENT | APR_FINFO_NLINK;
|
||||
|
||||
/* If we still want something more (besides the name) go get it!
|
||||
*/
|
||||
if ((wanted &= ~finfo->valid) & ~APR_FINFO_NAME) {
|
||||
return more_finfo(finfo, thefile->filehand, wanted, MORE_OF_HANDLE);
|
||||
}
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_perms_set(const char *fname,
|
||||
apr_fileperms_t perms)
|
||||
{
|
||||
return APR_ENOTIMPL;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_stat(apr_finfo_t *finfo, const char *fname,
|
||||
apr_int32_t wanted, apr_pool_t *pool)
|
||||
{
|
||||
/* XXX: is constant - needs testing - which requires a lighter-weight root test fn */
|
||||
int isroot = 0;
|
||||
apr_status_t ident_rv = 0;
|
||||
apr_status_t rv;
|
||||
#if APR_HAS_UNICODE_FS
|
||||
apr_wchar_t wfname[APR_PATH_MAX];
|
||||
|
||||
#endif
|
||||
char *filename = NULL;
|
||||
/* These all share a common subset of this structure */
|
||||
union {
|
||||
WIN32_FIND_DATAW w;
|
||||
WIN32_FIND_DATAA n;
|
||||
WIN32_FILE_ATTRIBUTE_DATA i;
|
||||
} FileInfo;
|
||||
|
||||
/* Catch fname length == MAX_PATH since GetFileAttributesEx fails
|
||||
* with PATH_NOT_FOUND. We would rather indicate length error than
|
||||
* 'not found'
|
||||
*/
|
||||
if (strlen(fname) >= APR_PATH_MAX) {
|
||||
return APR_ENAMETOOLONG;
|
||||
}
|
||||
|
||||
#if APR_HAS_UNICODE_FS
|
||||
IF_WIN_OS_IS_UNICODE
|
||||
{
|
||||
if ((wanted & (APR_FINFO_IDENT | APR_FINFO_NLINK))
|
||||
|| (~wanted & APR_FINFO_LINK)) {
|
||||
/* FindFirstFile and GetFileAttributesEx can't figure the inode,
|
||||
* device or number of links, so we need to resolve with an open
|
||||
* file handle. If the user has asked for these fields, fall over
|
||||
* to the get file info by handle method. If we fail, or the user
|
||||
* also asks for the file name, continue by our usual means.
|
||||
*
|
||||
* We also must use this method for a 'true' stat, that resolves
|
||||
* a symlink (NTFS Junction) target. This is because all fileinfo
|
||||
* on a Junction always returns the junction, opening the target
|
||||
* is the only way to resolve the target's attributes.
|
||||
*/
|
||||
if ((ident_rv = resolve_ident(finfo, fname, wanted, pool))
|
||||
== APR_SUCCESS)
|
||||
return ident_rv;
|
||||
else if (ident_rv == APR_INCOMPLETE)
|
||||
wanted &= ~finfo->valid;
|
||||
}
|
||||
|
||||
if ((rv = utf8_to_unicode_path(wfname, sizeof(wfname)
|
||||
/ sizeof(apr_wchar_t), fname)))
|
||||
return rv;
|
||||
if (!(wanted & APR_FINFO_NAME)) {
|
||||
if (!GetFileAttributesExW(wfname, GetFileExInfoStandard,
|
||||
&FileInfo.i))
|
||||
return apr_get_os_error();
|
||||
}
|
||||
else {
|
||||
/* Guard against bogus wildcards and retrieve by name
|
||||
* since we want the true name, and set aside a long
|
||||
* enough string to handle the longest file name.
|
||||
*/
|
||||
char tmpname[APR_FILE_MAX * 3 + 1];
|
||||
HANDLE hFind;
|
||||
if ((rv = test_safe_name(fname)) != APR_SUCCESS) {
|
||||
return rv;
|
||||
}
|
||||
hFind = FindFirstFileW(wfname, &FileInfo.w);
|
||||
if (hFind == INVALID_HANDLE_VALUE)
|
||||
return apr_get_os_error();
|
||||
FindClose(hFind);
|
||||
if (unicode_to_utf8_path(tmpname, sizeof(tmpname),
|
||||
FileInfo.w.cFileName)) {
|
||||
return APR_ENAMETOOLONG;
|
||||
}
|
||||
filename = apr_pstrdup(pool, tmpname);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if APR_HAS_ANSI_FS
|
||||
ELSE_WIN_OS_IS_ANSI
|
||||
{
|
||||
char *root = NULL;
|
||||
const char *test = fname;
|
||||
rv = apr_filepath_root(&root, &test, APR_FILEPATH_NATIVE, pool);
|
||||
isroot = (root && *root && !(*test));
|
||||
|
||||
if ((apr_os_level >= APR_WIN_98) && (!(wanted & APR_FINFO_NAME) || isroot))
|
||||
{
|
||||
/* cannot use FindFile on a Win98 root, it returns \*
|
||||
* GetFileAttributesExA is not available on Win95
|
||||
*/
|
||||
if (!GetFileAttributesExA(fname, GetFileExInfoStandard,
|
||||
&FileInfo.i)) {
|
||||
return apr_get_os_error();
|
||||
}
|
||||
}
|
||||
else if (isroot) {
|
||||
/* This is Win95 and we are trying to stat a root. Lie.
|
||||
*/
|
||||
if (GetDriveType(fname) != DRIVE_UNKNOWN)
|
||||
{
|
||||
finfo->pool = pool;
|
||||
finfo->filetype = 0;
|
||||
finfo->mtime = apr_time_now();
|
||||
finfo->protection |= APR_WREAD | APR_WEXECUTE | APR_WWRITE;
|
||||
finfo->protection |= (finfo->protection << prot_scope_group)
|
||||
| (finfo->protection << prot_scope_user);
|
||||
finfo->valid |= APR_FINFO_TYPE | APR_FINFO_PROT
|
||||
| APR_FINFO_MTIME
|
||||
| (wanted & APR_FINFO_LINK);
|
||||
return (wanted &= ~finfo->valid) ? APR_INCOMPLETE
|
||||
: APR_SUCCESS;
|
||||
}
|
||||
else
|
||||
return APR_FROM_OS_ERROR(ERROR_PATH_NOT_FOUND);
|
||||
}
|
||||
else {
|
||||
/* Guard against bogus wildcards and retrieve by name
|
||||
* since we want the true name, or are stuck in Win95,
|
||||
* or are looking for the root of a Win98 drive.
|
||||
*/
|
||||
HANDLE hFind;
|
||||
if ((rv = test_safe_name(fname)) != APR_SUCCESS) {
|
||||
return rv;
|
||||
}
|
||||
hFind = FindFirstFileA(fname, &FileInfo.n);
|
||||
if (hFind == INVALID_HANDLE_VALUE) {
|
||||
return apr_get_os_error();
|
||||
}
|
||||
FindClose(hFind);
|
||||
filename = apr_pstrdup(pool, FileInfo.n.cFileName);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ident_rv != APR_INCOMPLETE) {
|
||||
if (fillin_fileinfo(finfo, (WIN32_FILE_ATTRIBUTE_DATA *) &FileInfo,
|
||||
0, wanted))
|
||||
{
|
||||
/* Go the extra mile to assure we have a file. WinNT/2000 seems
|
||||
* to reliably translate char devices to the path '\\.\device'
|
||||
* so go ask for the full path.
|
||||
*/
|
||||
if (apr_os_level >= APR_WIN_NT)
|
||||
{
|
||||
#if APR_HAS_UNICODE_FS
|
||||
apr_wchar_t tmpname[APR_FILE_MAX];
|
||||
apr_wchar_t *tmpoff = NULL;
|
||||
if (GetFullPathNameW(wfname, sizeof(tmpname) / sizeof(apr_wchar_t),
|
||||
tmpname, &tmpoff))
|
||||
{
|
||||
if (!wcsncmp(tmpname, L"\\\\.\\", 4)) {
|
||||
#else
|
||||
/* Same initial logic as above, but
|
||||
* only for WinNT/non-UTF-8 builds of APR:
|
||||
*/
|
||||
char tmpname[APR_FILE_MAX];
|
||||
char *tmpoff;
|
||||
if (GetFullPathName(fname, sizeof(tmpname), tmpname, &tmpoff))
|
||||
{
|
||||
if (!strncmp(tmpname, "\\\\.\\", 4)) {
|
||||
#endif
|
||||
if (tmpoff == tmpname + 4) {
|
||||
finfo->filetype = APR_CHR;
|
||||
}
|
||||
/* For WHATEVER reason, CHR devices such as \\.\con
|
||||
* or \\.\lpt1 *may*not* update tmpoff; in fact the
|
||||
* resulting tmpoff is set to NULL. Guard against
|
||||
* either case.
|
||||
*
|
||||
* This code is identical for wide and narrow chars...
|
||||
*/
|
||||
else if (!tmpoff) {
|
||||
tmpoff = tmpname + 4;
|
||||
while (*tmpoff) {
|
||||
if (*tmpoff == '\\' || *tmpoff == '/') {
|
||||
break;
|
||||
}
|
||||
++tmpoff;
|
||||
}
|
||||
if (!*tmpoff) {
|
||||
finfo->filetype = APR_CHR;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
finfo->valid &= ~APR_FINFO_TYPE;
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
finfo->valid &= ~APR_FINFO_TYPE;
|
||||
}
|
||||
}
|
||||
finfo->pool = pool;
|
||||
}
|
||||
|
||||
if (filename && !isroot) {
|
||||
finfo->name = filename;
|
||||
finfo->valid |= APR_FINFO_NAME;
|
||||
}
|
||||
|
||||
if (wanted &= ~finfo->valid) {
|
||||
/* Caller wants more than APR_FINFO_MIN | APR_FINFO_NAME */
|
||||
#if APR_HAS_UNICODE_FS
|
||||
if (apr_os_level >= APR_WIN_NT)
|
||||
return more_finfo(finfo, wfname, wanted, MORE_OF_WFSPEC);
|
||||
#endif
|
||||
return more_finfo(finfo, fname, wanted, MORE_OF_FSPEC);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
DWORD flags;
|
||||
apr_status_t rv;
|
||||
#if APR_HAS_UNICODE_FS
|
||||
apr_wchar_t wfname[APR_PATH_MAX];
|
||||
#endif
|
||||
|
||||
/* Don't do anything if we can't handle the requested attributes */
|
||||
if (!(attr_mask & (APR_FILE_ATTR_READONLY
|
||||
| APR_FILE_ATTR_HIDDEN)))
|
||||
return APR_SUCCESS;
|
||||
|
||||
#if APR_HAS_UNICODE_FS
|
||||
IF_WIN_OS_IS_UNICODE
|
||||
{
|
||||
if ((rv = utf8_to_unicode_path(wfname,
|
||||
sizeof(wfname) / sizeof(wfname[0]),
|
||||
fname)))
|
||||
return rv;
|
||||
flags = GetFileAttributesW(wfname);
|
||||
}
|
||||
#endif
|
||||
#if APR_HAS_ANSI_FS
|
||||
ELSE_WIN_OS_IS_ANSI
|
||||
{
|
||||
flags = GetFileAttributesA(fname);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (flags == 0xFFFFFFFF)
|
||||
return apr_get_os_error();
|
||||
|
||||
if (attr_mask & APR_FILE_ATTR_READONLY)
|
||||
{
|
||||
if (attributes & APR_FILE_ATTR_READONLY)
|
||||
flags |= FILE_ATTRIBUTE_READONLY;
|
||||
else
|
||||
flags &= ~FILE_ATTRIBUTE_READONLY;
|
||||
}
|
||||
|
||||
if (attr_mask & APR_FILE_ATTR_HIDDEN)
|
||||
{
|
||||
if (attributes & APR_FILE_ATTR_HIDDEN)
|
||||
flags |= FILE_ATTRIBUTE_HIDDEN;
|
||||
else
|
||||
flags &= ~FILE_ATTRIBUTE_HIDDEN;
|
||||
}
|
||||
|
||||
#if APR_HAS_UNICODE_FS
|
||||
IF_WIN_OS_IS_UNICODE
|
||||
{
|
||||
rv = SetFileAttributesW(wfname, flags);
|
||||
}
|
||||
#endif
|
||||
#if APR_HAS_ANSI_FS
|
||||
ELSE_WIN_OS_IS_ANSI
|
||||
{
|
||||
rv = SetFileAttributesA(fname, flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (rv == 0)
|
||||
return apr_get_os_error();
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_mtime_set(const char *fname,
|
||||
apr_time_t mtime,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
apr_file_t *thefile;
|
||||
apr_status_t rv;
|
||||
|
||||
rv = apr_file_open(&thefile, fname,
|
||||
APR_FOPEN_READ | APR_WRITEATTRS,
|
||||
APR_OS_DEFAULT, pool);
|
||||
if (!rv)
|
||||
{
|
||||
FILETIME file_ctime;
|
||||
FILETIME file_atime;
|
||||
FILETIME file_mtime;
|
||||
|
||||
if (!GetFileTime(thefile->filehand,
|
||||
&file_ctime, &file_atime, &file_mtime))
|
||||
rv = apr_get_os_error();
|
||||
else
|
||||
{
|
||||
AprTimeToFileTime(&file_mtime, mtime);
|
||||
if (!SetFileTime(thefile->filehand,
|
||||
&file_ctime, &file_atime, &file_mtime))
|
||||
rv = apr_get_os_error();
|
||||
}
|
||||
|
||||
apr_file_close(thefile);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
+229
@@ -0,0 +1,229 @@
|
||||
/* 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_arch_file_io.h"
|
||||
#include "apr_strings.h"
|
||||
|
||||
/* Win32 Exceptions:
|
||||
*
|
||||
* Note that trailing spaces and trailing periods are never recorded
|
||||
* in the file system, except by a very obscure bug where any file
|
||||
* that is created with a trailing space or period, followed by the
|
||||
* ':' stream designator on an NTFS volume can never be accessed again.
|
||||
* In other words, don't ever accept them when designating a stream!
|
||||
*
|
||||
* An interesting side effect is that two or three periods are both
|
||||
* treated as the parent directory, although the fourth and on are
|
||||
* not [strongly suggest all trailing periods are trimmed off, or
|
||||
* down to two if there are no other characters.]
|
||||
*
|
||||
* Leading spaces and periods are accepted, however.
|
||||
* The * ? < > codes all have wildcard side effects
|
||||
* The " / \ : are exclusively component separator tokens
|
||||
* The system doesn't accept | for any (known) purpose
|
||||
* Oddly, \x7f _is_ acceptable ;)
|
||||
*/
|
||||
|
||||
/* apr_c_is_fnchar[] maps Win32's file name and shell escape symbols
|
||||
*
|
||||
* element & 1 == valid file name character [excluding delimiters]
|
||||
* element & 2 == character should be shell (caret) escaped from cmd.exe
|
||||
*
|
||||
* this must be in-sync with Apache httpd's gen_test_char.c for cgi escaping.
|
||||
*/
|
||||
|
||||
const char apr_c_is_fnchar[256] =
|
||||
{/* Reject all ctrl codes... Escape \n and \r (ascii 10 and 13) */
|
||||
0,0,0,0,0,0,0,0,0,0,2,0,0,2,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
/* ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
|
||||
1,1,2,1,3,3,3,3,3,3,2,1,1,1,1,0, 1,1,1,1,1,1,1,1,1,1,0,3,2,1,2,2,
|
||||
/* @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ */
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,3,2,3,3,1,
|
||||
/* ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ */
|
||||
3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,3,2,3,3,1,
|
||||
/* High bit codes are accepted (subject to utf-8->Unicode xlation) */
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
|
||||
};
|
||||
|
||||
|
||||
apr_status_t filepath_root_test(char *path, apr_pool_t *p)
|
||||
{
|
||||
apr_status_t rv;
|
||||
#if APR_HAS_UNICODE_FS
|
||||
if (apr_os_level >= APR_WIN_NT)
|
||||
{
|
||||
apr_wchar_t wpath[APR_PATH_MAX];
|
||||
if ((rv = utf8_to_unicode_path(wpath, sizeof(wpath)
|
||||
/ sizeof(apr_wchar_t), path)))
|
||||
return rv;
|
||||
rv = GetDriveTypeW(wpath);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
rv = GetDriveType(path);
|
||||
|
||||
if (rv == DRIVE_UNKNOWN || rv == DRIVE_NO_ROOT_DIR)
|
||||
return APR_EBADPATH;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
apr_status_t filepath_drive_get(char **rootpath, char drive,
|
||||
apr_int32_t flags, apr_pool_t *p)
|
||||
{
|
||||
char path[APR_PATH_MAX];
|
||||
#if APR_HAS_UNICODE_FS
|
||||
IF_WIN_OS_IS_UNICODE
|
||||
{
|
||||
apr_wchar_t *ignored;
|
||||
apr_wchar_t wdrive[8];
|
||||
apr_wchar_t wpath[APR_PATH_MAX];
|
||||
apr_status_t rv;
|
||||
/* ???: This needs review, apparently "\\?\d:." returns "\\?\d:"
|
||||
* as if that is useful for anything.
|
||||
*/
|
||||
wcscpy(wdrive, L"D:.");
|
||||
wdrive[0] = (apr_wchar_t)(unsigned char)drive;
|
||||
if (!GetFullPathNameW(wdrive, sizeof(wpath) / sizeof(apr_wchar_t), wpath, &ignored))
|
||||
return apr_get_os_error();
|
||||
if ((rv = unicode_to_utf8_path(path, sizeof(path), wpath)))
|
||||
return rv;
|
||||
}
|
||||
#endif
|
||||
#if APR_HAS_ANSI_FS
|
||||
ELSE_WIN_OS_IS_ANSI
|
||||
{
|
||||
char *ignored;
|
||||
char drivestr[4];
|
||||
drivestr[0] = drive;
|
||||
drivestr[1] = ':';
|
||||
drivestr[2] = '.';;
|
||||
drivestr[3] = '\0';
|
||||
if (!GetFullPathName(drivestr, sizeof(path), path, &ignored))
|
||||
return apr_get_os_error();
|
||||
}
|
||||
#endif
|
||||
if (!(flags & APR_FILEPATH_NATIVE)) {
|
||||
for (*rootpath = path; **rootpath; ++*rootpath) {
|
||||
if (**rootpath == '\\')
|
||||
**rootpath = '/';
|
||||
}
|
||||
}
|
||||
*rootpath = apr_pstrdup(p, path);
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
apr_status_t filepath_root_case(char **rootpath, char *root, apr_pool_t *p)
|
||||
{
|
||||
#if APR_HAS_UNICODE_FS
|
||||
IF_WIN_OS_IS_UNICODE
|
||||
{
|
||||
apr_wchar_t *ignored;
|
||||
apr_wchar_t wpath[APR_PATH_MAX];
|
||||
apr_status_t rv;
|
||||
apr_wchar_t wroot[APR_PATH_MAX];
|
||||
/* ???: This needs review, apparently "\\?\d:." returns "\\?\d:"
|
||||
* as if that is useful for anything.
|
||||
*/
|
||||
if ((rv = utf8_to_unicode_path(wroot, sizeof(wroot)
|
||||
/ sizeof(apr_wchar_t), root)))
|
||||
return rv;
|
||||
if (!GetFullPathNameW(wroot, sizeof(wpath) / sizeof(apr_wchar_t), wpath, &ignored))
|
||||
return apr_get_os_error();
|
||||
|
||||
/* Borrow wroot as a char buffer (twice as big as necessary)
|
||||
*/
|
||||
if ((rv = unicode_to_utf8_path((char*)wroot, sizeof(wroot), wpath)))
|
||||
return rv;
|
||||
*rootpath = apr_pstrdup(p, (char*)wroot);
|
||||
}
|
||||
#endif
|
||||
#if APR_HAS_ANSI_FS
|
||||
ELSE_WIN_OS_IS_ANSI
|
||||
{
|
||||
char path[APR_PATH_MAX];
|
||||
char *ignored;
|
||||
if (!GetFullPathName(root, sizeof(path), path, &ignored))
|
||||
return apr_get_os_error();
|
||||
*rootpath = apr_pstrdup(p, path);
|
||||
}
|
||||
#endif
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_filepath_get(char **rootpath, apr_int32_t flags,
|
||||
apr_pool_t *p)
|
||||
{
|
||||
char path[APR_PATH_MAX];
|
||||
#if APR_HAS_UNICODE_FS
|
||||
IF_WIN_OS_IS_UNICODE
|
||||
{
|
||||
apr_wchar_t wpath[APR_PATH_MAX];
|
||||
apr_status_t rv;
|
||||
if (!GetCurrentDirectoryW(sizeof(wpath) / sizeof(apr_wchar_t), wpath))
|
||||
return apr_get_os_error();
|
||||
if ((rv = unicode_to_utf8_path(path, sizeof(path), wpath)))
|
||||
return rv;
|
||||
}
|
||||
#endif
|
||||
#if APR_HAS_ANSI_FS
|
||||
ELSE_WIN_OS_IS_ANSI
|
||||
{
|
||||
if (!GetCurrentDirectory(sizeof(path), path))
|
||||
return apr_get_os_error();
|
||||
}
|
||||
#endif
|
||||
if (!(flags & APR_FILEPATH_NATIVE)) {
|
||||
for (*rootpath = path; **rootpath; ++*rootpath) {
|
||||
if (**rootpath == '\\')
|
||||
**rootpath = '/';
|
||||
}
|
||||
}
|
||||
*rootpath = apr_pstrdup(p, path);
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_filepath_set(const char *rootpath,
|
||||
apr_pool_t *p)
|
||||
{
|
||||
#if APR_HAS_UNICODE_FS
|
||||
IF_WIN_OS_IS_UNICODE
|
||||
{
|
||||
apr_wchar_t wpath[APR_PATH_MAX];
|
||||
apr_status_t rv;
|
||||
if ((rv = utf8_to_unicode_path(wpath, sizeof(wpath)
|
||||
/ sizeof(apr_wchar_t), rootpath)))
|
||||
return rv;
|
||||
if (!SetCurrentDirectoryW(wpath))
|
||||
return apr_get_os_error();
|
||||
}
|
||||
#endif
|
||||
#if APR_HAS_ANSI_FS
|
||||
ELSE_WIN_OS_IS_ANSI
|
||||
{
|
||||
if (!SetCurrentDirectory(rootpath))
|
||||
return apr_get_os_error();
|
||||
}
|
||||
#endif
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
/* 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"
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_lock(apr_file_t *thefile, int type)
|
||||
{
|
||||
#ifdef _WIN32_WCE
|
||||
/* The File locking is unsuported on WCE */
|
||||
return APR_ENOTIMPL;
|
||||
#else
|
||||
const DWORD len = 0xffffffff;
|
||||
DWORD flags;
|
||||
|
||||
flags = ((type & APR_FLOCK_NONBLOCK) ? LOCKFILE_FAIL_IMMEDIATELY : 0)
|
||||
+ (((type & APR_FLOCK_TYPEMASK) == APR_FLOCK_SHARED)
|
||||
? 0 : LOCKFILE_EXCLUSIVE_LOCK);
|
||||
if (apr_os_level >= APR_WIN_NT) {
|
||||
/* Syntax is correct, len is passed for LengthLow and LengthHigh*/
|
||||
OVERLAPPED offset;
|
||||
memset (&offset, 0, sizeof(offset));
|
||||
if (!LockFileEx(thefile->filehand, flags, 0, len, len, &offset))
|
||||
return apr_get_os_error();
|
||||
}
|
||||
else {
|
||||
/* On Win9x, LockFile() never blocks. Hack in a crufty poll.
|
||||
*
|
||||
* Note that this hack exposes threads to being unserviced forever,
|
||||
* in the situation that the given lock has low availability.
|
||||
* When implemented in the kernel, LockFile will typically use
|
||||
* FIFO or round robin distribution to ensure all threads get
|
||||
* one crack at the lock; but in this case we can't emulate that.
|
||||
*
|
||||
* However Win9x are barely maintainable anyways, if the user does
|
||||
* choose to build to them, this is the best we can do.
|
||||
*/
|
||||
while (!LockFile(thefile->filehand, 0, 0, len, 0)) {
|
||||
DWORD err = GetLastError();
|
||||
if ((err == ERROR_LOCK_VIOLATION) && !(type & APR_FLOCK_NONBLOCK))
|
||||
{
|
||||
Sleep(500); /* pause for a half second */
|
||||
continue; /* ... and then poll again */
|
||||
}
|
||||
return APR_FROM_OS_ERROR(err);
|
||||
}
|
||||
}
|
||||
|
||||
return APR_SUCCESS;
|
||||
#endif /* !defined(_WIN32_WCE) */
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_unlock(apr_file_t *thefile)
|
||||
{
|
||||
#ifdef _WIN32_WCE
|
||||
return APR_ENOTIMPL;
|
||||
#else
|
||||
DWORD len = 0xffffffff;
|
||||
|
||||
if (apr_os_level >= APR_WIN_NT) {
|
||||
/* Syntax is correct, len is passed for LengthLow and LengthHigh*/
|
||||
OVERLAPPED offset;
|
||||
memset (&offset, 0, sizeof(offset));
|
||||
if (!UnlockFileEx(thefile->filehand, 0, len, len, &offset))
|
||||
return apr_get_os_error();
|
||||
}
|
||||
else {
|
||||
if (!UnlockFile(thefile->filehand, 0, 0, len, 0))
|
||||
return apr_get_os_error();
|
||||
}
|
||||
|
||||
return APR_SUCCESS;
|
||||
#endif /* !defined(_WIN32_WCE) */
|
||||
}
|
||||
+755
@@ -0,0 +1,755 @@
|
||||
/* 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_arch_file_io.h"
|
||||
#include "apr_file_io.h"
|
||||
#include "apr_general.h"
|
||||
#include "apr_strings.h"
|
||||
#include "apr_portable.h"
|
||||
#include "apr_thread_mutex.h"
|
||||
#if APR_HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#include <winbase.h>
|
||||
#include <string.h>
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#include "apr_arch_misc.h"
|
||||
#include "apr_arch_inherit.h"
|
||||
#include <io.h>
|
||||
#include <winioctl.h>
|
||||
|
||||
#if APR_HAS_UNICODE_FS
|
||||
apr_status_t utf8_to_unicode_path(apr_wchar_t* retstr, apr_size_t retlen,
|
||||
const char* srcstr)
|
||||
{
|
||||
/* TODO: The computations could preconvert the string to determine
|
||||
* the true size of the retstr, but that's a memory over speed
|
||||
* tradeoff that isn't appropriate this early in development.
|
||||
*
|
||||
* Allocate the maximum string length based on leading 4
|
||||
* characters of \\?\ (allowing nearly unlimited path lengths)
|
||||
* plus the trailing null, then transform /'s into \\'s since
|
||||
* the \\?\ form doesn't allow '/' path seperators.
|
||||
*
|
||||
* Note that the \\?\ form only works for local drive paths, and
|
||||
* \\?\UNC\ is needed UNC paths.
|
||||
*/
|
||||
apr_size_t srcremains = strlen(srcstr) + 1;
|
||||
apr_wchar_t *t = retstr;
|
||||
apr_status_t rv;
|
||||
|
||||
/* This is correct, we don't twist the filename if it is will
|
||||
* definitely be shorter than 248 characters. It merits some
|
||||
* performance testing to see if this has any effect, but there
|
||||
* seem to be applications that get confused by the resulting
|
||||
* Unicode \\?\ style file names, especially if they use argv[0]
|
||||
* or call the Win32 API functions such as GetModuleName, etc.
|
||||
* Not every application is prepared to handle such names.
|
||||
*
|
||||
* Note also this is shorter than MAX_PATH, as directory paths
|
||||
* are actually limited to 248 characters.
|
||||
*
|
||||
* Note that a utf-8 name can never result in more wide chars
|
||||
* than the original number of utf-8 narrow chars.
|
||||
*/
|
||||
if (srcremains > 248) {
|
||||
if (srcstr[1] == ':' && (srcstr[2] == '/' || srcstr[2] == '\\')) {
|
||||
wcscpy (retstr, L"\\\\?\\");
|
||||
retlen -= 4;
|
||||
t += 4;
|
||||
}
|
||||
else if ((srcstr[0] == '/' || srcstr[0] == '\\')
|
||||
&& (srcstr[1] == '/' || srcstr[1] == '\\')
|
||||
&& (srcstr[2] != '?')) {
|
||||
/* Skip the slashes */
|
||||
srcstr += 2;
|
||||
srcremains -= 2;
|
||||
wcscpy (retstr, L"\\\\?\\UNC\\");
|
||||
retlen -= 8;
|
||||
t += 8;
|
||||
}
|
||||
}
|
||||
|
||||
if ((rv = apr_conv_utf8_to_ucs2(srcstr, &srcremains, t, &retlen))) {
|
||||
return (rv == APR_INCOMPLETE) ? APR_EINVAL : rv;
|
||||
}
|
||||
if (srcremains) {
|
||||
return APR_ENAMETOOLONG;
|
||||
}
|
||||
for (; *t; ++t)
|
||||
if (*t == L'/')
|
||||
*t = L'\\';
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
apr_status_t unicode_to_utf8_path(char* retstr, apr_size_t retlen,
|
||||
const apr_wchar_t* srcstr)
|
||||
{
|
||||
/* Skip the leading 4 characters if the path begins \\?\, or substitute
|
||||
* // for the \\?\UNC\ path prefix, allocating the maximum string
|
||||
* length based on the remaining string, plus the trailing null.
|
||||
* then transform \\'s back into /'s since the \\?\ form never
|
||||
* allows '/' path seperators, and APR always uses '/'s.
|
||||
*/
|
||||
apr_size_t srcremains = wcslen(srcstr) + 1;
|
||||
apr_status_t rv;
|
||||
char *t = retstr;
|
||||
if (srcstr[0] == L'\\' && srcstr[1] == L'\\' &&
|
||||
srcstr[2] == L'?' && srcstr[3] == L'\\') {
|
||||
if (srcstr[4] == L'U' && srcstr[5] == L'N' &&
|
||||
srcstr[6] == L'C' && srcstr[7] == L'\\') {
|
||||
srcremains -= 8;
|
||||
srcstr += 8;
|
||||
retstr[0] = '\\';
|
||||
retstr[1] = '\\';
|
||||
retlen -= 2;
|
||||
t += 2;
|
||||
}
|
||||
else {
|
||||
srcremains -= 4;
|
||||
srcstr += 4;
|
||||
}
|
||||
}
|
||||
|
||||
if ((rv = apr_conv_ucs2_to_utf8(srcstr, &srcremains, t, &retlen))) {
|
||||
return rv;
|
||||
}
|
||||
if (srcremains) {
|
||||
return APR_ENAMETOOLONG;
|
||||
}
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
void *res_name_from_filename(const char *file, int global, apr_pool_t *pool)
|
||||
{
|
||||
#if APR_HAS_UNICODE_FS
|
||||
IF_WIN_OS_IS_UNICODE
|
||||
{
|
||||
apr_wchar_t *wpre, *wfile, *ch;
|
||||
apr_size_t n = strlen(file) + 1;
|
||||
apr_size_t r, d;
|
||||
|
||||
if (apr_os_level >= APR_WIN_2000) {
|
||||
if (global)
|
||||
wpre = L"Global\\";
|
||||
else
|
||||
wpre = L"Local\\";
|
||||
}
|
||||
else
|
||||
wpre = L"";
|
||||
r = wcslen(wpre);
|
||||
|
||||
if (n > 256 - r) {
|
||||
file += n - 256 - r;
|
||||
n = 256;
|
||||
/* skip utf8 continuation bytes */
|
||||
while ((*file & 0xC0) == 0x80) {
|
||||
++file;
|
||||
--n;
|
||||
}
|
||||
}
|
||||
wfile = apr_palloc(pool, (r + n) * sizeof(apr_wchar_t));
|
||||
wcscpy(wfile, wpre);
|
||||
d = n;
|
||||
if (apr_conv_utf8_to_ucs2(file, &n, wfile + r, &d)) {
|
||||
return NULL;
|
||||
}
|
||||
for (ch = wfile + r; *ch; ++ch) {
|
||||
if (*ch == ':' || *ch == '/' || *ch == '\\')
|
||||
*ch = '_';
|
||||
}
|
||||
return wfile;
|
||||
}
|
||||
#endif
|
||||
#if APR_HAS_ANSI_FS
|
||||
ELSE_WIN_OS_IS_ANSI
|
||||
{
|
||||
char *nfile, *ch;
|
||||
apr_size_t n = strlen(file) + 1;
|
||||
|
||||
#if !APR_HAS_UNICODE_FS
|
||||
apr_size_t r, d;
|
||||
char *pre;
|
||||
|
||||
if (apr_os_level >= APR_WIN_2000) {
|
||||
if (global)
|
||||
pre = "Global\\";
|
||||
else
|
||||
pre = "Local\\";
|
||||
}
|
||||
else
|
||||
pre = "";
|
||||
r = strlen(pre);
|
||||
|
||||
if (n > 256 - r) {
|
||||
file += n - 256 - r;
|
||||
n = 256;
|
||||
}
|
||||
nfile = apr_palloc(pool, (r + n) * sizeof(apr_wchar_t));
|
||||
memcpy(nfile, pre, r);
|
||||
memcpy(nfile + r, file, n);
|
||||
#else
|
||||
const apr_size_t r = 0;
|
||||
if (n > 256) {
|
||||
file += n - 256;
|
||||
n = 256;
|
||||
}
|
||||
nfile = apr_pmemdup(pool, file, n);
|
||||
#endif
|
||||
for (ch = nfile + r; *ch; ++ch) {
|
||||
if (*ch == ':' || *ch == '/' || *ch == '\\')
|
||||
*ch = '_';
|
||||
}
|
||||
return nfile;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if APR_HAS_UNICODE_FS
|
||||
static apr_status_t make_sparse_file(apr_file_t *file)
|
||||
{
|
||||
BY_HANDLE_FILE_INFORMATION info;
|
||||
apr_status_t rv;
|
||||
DWORD bytesread = 0;
|
||||
DWORD res;
|
||||
|
||||
/* test */
|
||||
|
||||
if (GetFileInformationByHandle(file->filehand, &info)
|
||||
&& (info.dwFileAttributes & FILE_ATTRIBUTE_SPARSE_FILE))
|
||||
return APR_SUCCESS;
|
||||
|
||||
if (file->pOverlapped) {
|
||||
file->pOverlapped->Offset = 0;
|
||||
file->pOverlapped->OffsetHigh = 0;
|
||||
}
|
||||
|
||||
if (DeviceIoControl(file->filehand, FSCTL_SET_SPARSE, NULL, 0, NULL, 0,
|
||||
&bytesread, file->pOverlapped)) {
|
||||
rv = APR_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
rv = apr_get_os_error();
|
||||
|
||||
if (rv == APR_FROM_OS_ERROR(ERROR_IO_PENDING))
|
||||
{
|
||||
do {
|
||||
res = WaitForSingleObject(file->pOverlapped->hEvent,
|
||||
(file->timeout > 0)
|
||||
? (DWORD)(file->timeout/1000)
|
||||
: ((file->timeout == -1)
|
||||
? INFINITE : 0));
|
||||
} while (res == WAIT_ABANDONED);
|
||||
|
||||
if (res != WAIT_OBJECT_0) {
|
||||
CancelIo(file->filehand);
|
||||
}
|
||||
|
||||
if (GetOverlappedResult(file->filehand, file->pOverlapped,
|
||||
&bytesread, TRUE))
|
||||
rv = APR_SUCCESS;
|
||||
else
|
||||
rv = apr_get_os_error();
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
#endif
|
||||
|
||||
apr_status_t file_cleanup(void *thefile)
|
||||
{
|
||||
apr_file_t *file = thefile;
|
||||
apr_status_t flush_rv = APR_SUCCESS;
|
||||
|
||||
if (file->filehand != INVALID_HANDLE_VALUE) {
|
||||
|
||||
if (file->buffered) {
|
||||
/* XXX: flush here is not mutex protected */
|
||||
flush_rv = apr_file_flush((apr_file_t *)thefile);
|
||||
}
|
||||
|
||||
/* In order to avoid later segfaults with handle 'reuse',
|
||||
* we must protect against the case that a dup2'ed handle
|
||||
* is being closed, and invalidate the corresponding StdHandle
|
||||
* We also tell msvcrt when stdhandles are closed.
|
||||
*/
|
||||
if (file->flags & APR_STD_FLAGS)
|
||||
{
|
||||
if ((file->flags & APR_STD_FLAGS) == APR_STDERR_FLAG) {
|
||||
_close(2);
|
||||
SetStdHandle(STD_ERROR_HANDLE, INVALID_HANDLE_VALUE);
|
||||
}
|
||||
else if ((file->flags & APR_STD_FLAGS) == APR_STDOUT_FLAG) {
|
||||
_close(1);
|
||||
SetStdHandle(STD_OUTPUT_HANDLE, INVALID_HANDLE_VALUE);
|
||||
}
|
||||
else if ((file->flags & APR_STD_FLAGS) == APR_STDIN_FLAG) {
|
||||
_close(0);
|
||||
SetStdHandle(STD_INPUT_HANDLE, INVALID_HANDLE_VALUE);
|
||||
}
|
||||
}
|
||||
else
|
||||
CloseHandle(file->filehand);
|
||||
|
||||
file->filehand = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if (file->pOverlapped && file->pOverlapped->hEvent) {
|
||||
CloseHandle(file->pOverlapped->hEvent);
|
||||
file->pOverlapped = NULL;
|
||||
}
|
||||
return flush_rv;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
HANDLE handle = INVALID_HANDLE_VALUE;
|
||||
DWORD oflags = 0;
|
||||
DWORD createflags = 0;
|
||||
DWORD attributes = 0;
|
||||
DWORD sharemode = FILE_SHARE_READ | FILE_SHARE_WRITE;
|
||||
apr_status_t rv;
|
||||
|
||||
if (flag & APR_FOPEN_NONBLOCK) {
|
||||
return APR_ENOTIMPL;
|
||||
}
|
||||
if (flag & APR_FOPEN_READ) {
|
||||
oflags |= GENERIC_READ;
|
||||
}
|
||||
if (flag & APR_FOPEN_WRITE) {
|
||||
oflags |= GENERIC_WRITE;
|
||||
}
|
||||
if (flag & APR_WRITEATTRS) {
|
||||
oflags |= FILE_WRITE_ATTRIBUTES;
|
||||
}
|
||||
|
||||
if (apr_os_level >= APR_WIN_NT)
|
||||
sharemode |= FILE_SHARE_DELETE;
|
||||
|
||||
if (flag & APR_FOPEN_CREATE) {
|
||||
if (flag & APR_FOPEN_EXCL) {
|
||||
/* only create new if file does not already exist */
|
||||
createflags = CREATE_NEW;
|
||||
} else if (flag & APR_FOPEN_TRUNCATE) {
|
||||
/* truncate existing file or create new */
|
||||
createflags = CREATE_ALWAYS;
|
||||
} else {
|
||||
/* open existing but create if necessary */
|
||||
createflags = OPEN_ALWAYS;
|
||||
}
|
||||
} else if (flag & APR_FOPEN_TRUNCATE) {
|
||||
/* only truncate if file already exists */
|
||||
createflags = TRUNCATE_EXISTING;
|
||||
} else {
|
||||
/* only open if file already exists */
|
||||
createflags = OPEN_EXISTING;
|
||||
}
|
||||
|
||||
if ((flag & APR_FOPEN_EXCL) && !(flag & APR_FOPEN_CREATE)) {
|
||||
return APR_EACCES;
|
||||
}
|
||||
|
||||
if (flag & APR_FOPEN_DELONCLOSE) {
|
||||
attributes |= FILE_FLAG_DELETE_ON_CLOSE;
|
||||
}
|
||||
|
||||
if (flag & APR_OPENLINK) {
|
||||
attributes |= FILE_FLAG_OPEN_REPARSE_POINT;
|
||||
}
|
||||
|
||||
/* Without READ or WRITE, we fail unless apr called apr_file_open
|
||||
* internally with the private APR_OPENINFO flag.
|
||||
*
|
||||
* With the APR_OPENINFO flag on NT, use the option flag
|
||||
* FILE_FLAG_BACKUP_SEMANTICS to allow us to open directories.
|
||||
* See the static resolve_ident() fn in file_io/win32/filestat.c
|
||||
*/
|
||||
if (!(flag & (APR_FOPEN_READ | APR_FOPEN_WRITE))) {
|
||||
if (flag & APR_OPENINFO) {
|
||||
if (apr_os_level >= APR_WIN_NT) {
|
||||
attributes |= FILE_FLAG_BACKUP_SEMANTICS;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return APR_EACCES;
|
||||
}
|
||||
if (flag & APR_READCONTROL)
|
||||
oflags |= READ_CONTROL;
|
||||
}
|
||||
|
||||
if (flag & APR_FOPEN_XTHREAD) {
|
||||
/* This win32 specific feature is required
|
||||
* to allow multiple threads to work with the file.
|
||||
*/
|
||||
attributes |= FILE_FLAG_OVERLAPPED;
|
||||
}
|
||||
|
||||
#if APR_HAS_UNICODE_FS
|
||||
IF_WIN_OS_IS_UNICODE
|
||||
{
|
||||
apr_wchar_t wfname[APR_PATH_MAX];
|
||||
|
||||
if (flag & APR_FOPEN_SENDFILE_ENABLED) {
|
||||
/* This feature is required to enable sendfile operations
|
||||
* against the file on Win32. Also implies APR_FOPEN_XTHREAD.
|
||||
*/
|
||||
flag |= APR_FOPEN_XTHREAD;
|
||||
attributes |= FILE_FLAG_SEQUENTIAL_SCAN | FILE_FLAG_OVERLAPPED;
|
||||
}
|
||||
|
||||
if ((rv = utf8_to_unicode_path(wfname, sizeof(wfname)
|
||||
/ sizeof(apr_wchar_t), fname)))
|
||||
return rv;
|
||||
handle = CreateFileW(wfname, oflags, sharemode,
|
||||
NULL, createflags, attributes, 0);
|
||||
}
|
||||
#endif
|
||||
#if APR_HAS_ANSI_FS
|
||||
ELSE_WIN_OS_IS_ANSI {
|
||||
handle = CreateFileA(fname, oflags, sharemode,
|
||||
NULL, createflags, attributes, 0);
|
||||
/* This feature is not supported on this platform. */
|
||||
flag &= ~APR_FOPEN_SENDFILE_ENABLED;
|
||||
}
|
||||
#endif
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
return apr_get_os_error();
|
||||
}
|
||||
|
||||
(*new) = (apr_file_t *)apr_pcalloc(pool, sizeof(apr_file_t));
|
||||
(*new)->pool = pool;
|
||||
(*new)->filehand = handle;
|
||||
(*new)->fname = apr_pstrdup(pool, fname);
|
||||
(*new)->flags = flag;
|
||||
(*new)->timeout = -1;
|
||||
(*new)->ungetchar = -1;
|
||||
|
||||
if (flag & APR_FOPEN_APPEND) {
|
||||
(*new)->append = 1;
|
||||
SetFilePointer((*new)->filehand, 0, NULL, FILE_END);
|
||||
}
|
||||
if (flag & APR_FOPEN_BUFFERED) {
|
||||
(*new)->buffered = 1;
|
||||
(*new)->buffer = apr_palloc(pool, APR_FILE_DEFAULT_BUFSIZE);
|
||||
(*new)->bufsize = APR_FILE_DEFAULT_BUFSIZE;
|
||||
}
|
||||
/* Need the mutex to handled buffered and O_APPEND style file i/o */
|
||||
if ((*new)->buffered || (*new)->append) {
|
||||
rv = apr_thread_mutex_create(&(*new)->mutex,
|
||||
APR_THREAD_MUTEX_DEFAULT, pool);
|
||||
if (rv) {
|
||||
if (file_cleanup(*new) == APR_SUCCESS) {
|
||||
apr_pool_cleanup_kill(pool, *new, file_cleanup);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
#if APR_HAS_UNICODE_FS
|
||||
if ((apr_os_level >= APR_WIN_2000) && ((*new)->flags & APR_FOPEN_SPARSE)) {
|
||||
if ((rv = make_sparse_file(*new)) != APR_SUCCESS)
|
||||
/* The great mystery; do we close the file and return an error?
|
||||
* Do we add a new APR_INCOMPLETE style error saying opened, but
|
||||
* NOTSPARSE? For now let's simply mark the file as not-sparse.
|
||||
*/
|
||||
(*new)->flags &= ~APR_FOPEN_SPARSE;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
/* This feature is not supported on this platform. */
|
||||
(*new)->flags &= ~APR_FOPEN_SPARSE;
|
||||
|
||||
#if APR_FILES_AS_SOCKETS
|
||||
/* Create a pollset with room for one descriptor. */
|
||||
/* ### check return codes */
|
||||
(void) apr_pollset_create(&(*new)->pollset, 1, pool, 0);
|
||||
#endif
|
||||
if (!(flag & APR_FOPEN_NOCLEANUP)) {
|
||||
apr_pool_cleanup_register((*new)->pool, (void *)(*new), file_cleanup,
|
||||
apr_pool_cleanup_null);
|
||||
}
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_close(apr_file_t *file)
|
||||
{
|
||||
apr_status_t stat;
|
||||
if ((stat = file_cleanup(file)) == APR_SUCCESS) {
|
||||
apr_pool_cleanup_kill(file->pool, file, file_cleanup);
|
||||
|
||||
if (file->mutex) {
|
||||
apr_thread_mutex_destroy(file->mutex);
|
||||
}
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_remove(const char *path, apr_pool_t *pool)
|
||||
{
|
||||
#if APR_HAS_UNICODE_FS
|
||||
IF_WIN_OS_IS_UNICODE
|
||||
{
|
||||
apr_wchar_t wpath[APR_PATH_MAX];
|
||||
apr_status_t rv;
|
||||
if ((rv = utf8_to_unicode_path(wpath, sizeof(wpath)
|
||||
/ sizeof(apr_wchar_t), path))) {
|
||||
return rv;
|
||||
}
|
||||
if (DeleteFileW(wpath))
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
#if APR_HAS_ANSI_FS
|
||||
ELSE_WIN_OS_IS_ANSI
|
||||
if (DeleteFile(path))
|
||||
return APR_SUCCESS;
|
||||
#endif
|
||||
return apr_get_os_error();
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_rename(const char *frompath,
|
||||
const char *topath,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
IF_WIN_OS_IS_UNICODE
|
||||
{
|
||||
#if APR_HAS_UNICODE_FS
|
||||
apr_wchar_t wfrompath[APR_PATH_MAX], wtopath[APR_PATH_MAX];
|
||||
apr_status_t rv;
|
||||
if ((rv = utf8_to_unicode_path(wfrompath,
|
||||
sizeof(wfrompath) / sizeof(apr_wchar_t),
|
||||
frompath))) {
|
||||
return rv;
|
||||
}
|
||||
if ((rv = utf8_to_unicode_path(wtopath,
|
||||
sizeof(wtopath) / sizeof(apr_wchar_t),
|
||||
topath))) {
|
||||
return rv;
|
||||
}
|
||||
#ifndef _WIN32_WCE
|
||||
if (MoveFileExW(wfrompath, wtopath, MOVEFILE_REPLACE_EXISTING |
|
||||
MOVEFILE_COPY_ALLOWED))
|
||||
#else
|
||||
if (MoveFileW(wfrompath, wtopath))
|
||||
#endif
|
||||
return APR_SUCCESS;
|
||||
#else
|
||||
if (MoveFileEx(frompath, topath, MOVEFILE_REPLACE_EXISTING |
|
||||
MOVEFILE_COPY_ALLOWED))
|
||||
return APR_SUCCESS;
|
||||
#endif
|
||||
}
|
||||
#if APR_HAS_ANSI_FS
|
||||
ELSE_WIN_OS_IS_ANSI
|
||||
{
|
||||
/* Windows 95 and 98 do not support MoveFileEx, so we'll use
|
||||
* the old MoveFile function. However, MoveFile requires that
|
||||
* the new file not already exist...so we have to delete that
|
||||
* file if it does. Perhaps we should back up the to-be-deleted
|
||||
* file in case something happens?
|
||||
*/
|
||||
HANDLE handle = INVALID_HANDLE_VALUE;
|
||||
|
||||
if ((handle = CreateFile(topath, GENERIC_WRITE, 0, 0,
|
||||
OPEN_EXISTING, 0, 0 )) != INVALID_HANDLE_VALUE )
|
||||
{
|
||||
CloseHandle(handle);
|
||||
if (!DeleteFile(topath))
|
||||
return apr_get_os_error();
|
||||
}
|
||||
if (MoveFile(frompath, topath))
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
return apr_get_os_error();
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_link(const char *from_path,
|
||||
const char *to_path)
|
||||
{
|
||||
apr_status_t rv = APR_SUCCESS;
|
||||
|
||||
#if APR_HAS_UNICODE_FS
|
||||
IF_WIN_OS_IS_UNICODE
|
||||
{
|
||||
apr_wchar_t wfrom_path[APR_PATH_MAX];
|
||||
apr_wchar_t wto_path[APR_PATH_MAX];
|
||||
|
||||
if ((rv = utf8_to_unicode_path(wfrom_path,
|
||||
sizeof(wfrom_path) / sizeof(apr_wchar_t),
|
||||
from_path)))
|
||||
return rv;
|
||||
if ((rv = utf8_to_unicode_path(wto_path,
|
||||
sizeof(wto_path) / sizeof(apr_wchar_t),
|
||||
to_path)))
|
||||
return rv;
|
||||
|
||||
if (!CreateHardLinkW(wto_path, wfrom_path, NULL))
|
||||
return apr_get_os_error();
|
||||
}
|
||||
#endif
|
||||
#if APR_HAS_ANSI_FS
|
||||
ELSE_WIN_OS_IS_ANSI {
|
||||
if (!CreateHardLinkA(to_path, from_path, NULL))
|
||||
return apr_get_os_error();
|
||||
}
|
||||
#endif
|
||||
return rv;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_os_file_get(apr_os_file_t *thefile,
|
||||
apr_file_t *file)
|
||||
{
|
||||
*thefile = file->filehand;
|
||||
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)
|
||||
{
|
||||
(*file) = apr_pcalloc(pool, sizeof(apr_file_t));
|
||||
(*file)->pool = pool;
|
||||
(*file)->filehand = *thefile;
|
||||
(*file)->ungetchar = -1; /* no char avail */
|
||||
(*file)->timeout = -1;
|
||||
(*file)->flags = flags;
|
||||
|
||||
if (flags & APR_FOPEN_APPEND) {
|
||||
(*file)->append = 1;
|
||||
}
|
||||
if (flags & APR_FOPEN_BUFFERED) {
|
||||
(*file)->buffered = 1;
|
||||
(*file)->buffer = apr_palloc(pool, APR_FILE_DEFAULT_BUFSIZE);
|
||||
(*file)->bufsize = APR_FILE_DEFAULT_BUFSIZE;
|
||||
}
|
||||
|
||||
if ((*file)->append || (*file)->buffered) {
|
||||
apr_status_t rv;
|
||||
rv = apr_thread_mutex_create(&(*file)->mutex,
|
||||
APR_THREAD_MUTEX_DEFAULT, pool);
|
||||
if (rv) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
#if APR_FILES_AS_SOCKETS
|
||||
/* Create a pollset with room for one descriptor. */
|
||||
/* ### check return codes */
|
||||
(void) apr_pollset_create(&(*file)->pollset, 1, pool, 0);
|
||||
#endif
|
||||
/* Should we be testing if thefile is a handle to
|
||||
* a PIPE and set up the mechanics appropriately?
|
||||
*
|
||||
* (*file)->pipe;
|
||||
*/
|
||||
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)
|
||||
{
|
||||
#ifdef _WIN32_WCE
|
||||
return APR_ENOTIMPL;
|
||||
#else
|
||||
apr_os_file_t file_handle;
|
||||
|
||||
apr_set_os_error(APR_SUCCESS);
|
||||
file_handle = GetStdHandle(STD_ERROR_HANDLE);
|
||||
if (!file_handle)
|
||||
file_handle = INVALID_HANDLE_VALUE;
|
||||
|
||||
return apr_os_file_put(thefile, &file_handle,
|
||||
flags | APR_FOPEN_WRITE | APR_STDERR_FLAG, pool);
|
||||
#endif
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_open_flags_stdout(apr_file_t **thefile,
|
||||
apr_int32_t flags,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
#ifdef _WIN32_WCE
|
||||
return APR_ENOTIMPL;
|
||||
#else
|
||||
apr_os_file_t file_handle;
|
||||
|
||||
apr_set_os_error(APR_SUCCESS);
|
||||
file_handle = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (!file_handle)
|
||||
file_handle = INVALID_HANDLE_VALUE;
|
||||
|
||||
return apr_os_file_put(thefile, &file_handle,
|
||||
flags | APR_FOPEN_WRITE | APR_STDOUT_FLAG, pool);
|
||||
#endif
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_open_flags_stdin(apr_file_t **thefile,
|
||||
apr_int32_t flags,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
#ifdef _WIN32_WCE
|
||||
return APR_ENOTIMPL;
|
||||
#else
|
||||
apr_os_file_t file_handle;
|
||||
|
||||
apr_set_os_error(APR_SUCCESS);
|
||||
file_handle = GetStdHandle(STD_INPUT_HANDLE);
|
||||
if (!file_handle)
|
||||
file_handle = INVALID_HANDLE_VALUE;
|
||||
|
||||
return apr_os_file_put(thefile, &file_handle,
|
||||
flags | APR_FOPEN_READ | APR_STDIN_FLAG, pool);
|
||||
#endif
|
||||
}
|
||||
|
||||
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_POOL_IMPLEMENT_ACCESSOR(file);
|
||||
|
||||
APR_IMPLEMENT_INHERIT_SET(file, flags, pool, file_cleanup)
|
||||
|
||||
APR_IMPLEMENT_INHERIT_UNSET(file, flags, pool, file_cleanup)
|
||||
+486
@@ -0,0 +1,486 @@
|
||||
/* 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_escape.h"
|
||||
#if APR_HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#if APR_HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#if APR_HAVE_PROCESS_H
|
||||
#include <process.h> /* for getpid() on Win32 */
|
||||
#endif
|
||||
#include "apr_arch_misc.h"
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_pipe_timeout_set(apr_file_t *thepipe,
|
||||
apr_interval_time_t timeout)
|
||||
{
|
||||
/* Always OK to unset timeouts */
|
||||
if (timeout == -1) {
|
||||
thepipe->timeout = timeout;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
if (!thepipe->pipe) {
|
||||
return APR_ENOTIMPL;
|
||||
}
|
||||
if (timeout && !(thepipe->pOverlapped)) {
|
||||
/* Cannot be nonzero if a pipe was opened blocking
|
||||
*/
|
||||
return APR_EINVAL;
|
||||
}
|
||||
thepipe->timeout = timeout;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_pipe_timeout_get(apr_file_t *thepipe,
|
||||
apr_interval_time_t *timeout)
|
||||
{
|
||||
/* Always OK to get the timeout (even if it's unset ... -1) */
|
||||
*timeout = thepipe->timeout;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_pipe_create(apr_file_t **in,
|
||||
apr_file_t **out,
|
||||
apr_pool_t *p)
|
||||
{
|
||||
/* Unix creates full blocking pipes. */
|
||||
return apr_file_pipe_create_pools(in, out, APR_FULL_BLOCK, p, p);
|
||||
}
|
||||
|
||||
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 *p)
|
||||
{
|
||||
return apr_file_pipe_create_pools(in, out, blocking, p, p);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
#ifdef _WIN32_WCE
|
||||
return APR_ENOTIMPL;
|
||||
#else
|
||||
SECURITY_ATTRIBUTES sa;
|
||||
static unsigned long id = 0;
|
||||
DWORD dwPipeMode;
|
||||
DWORD dwOpenMode;
|
||||
|
||||
sa.nLength = sizeof(sa);
|
||||
|
||||
#if APR_HAS_UNICODE_FS
|
||||
IF_WIN_OS_IS_UNICODE
|
||||
sa.bInheritHandle = FALSE;
|
||||
#endif
|
||||
#if APR_HAS_ANSI_FS
|
||||
ELSE_WIN_OS_IS_ANSI
|
||||
sa.bInheritHandle = TRUE;
|
||||
#endif
|
||||
sa.lpSecurityDescriptor = NULL;
|
||||
|
||||
(*in) = (apr_file_t *)apr_pcalloc(pool_in, sizeof(apr_file_t));
|
||||
(*in)->pool = pool_in;
|
||||
(*in)->fname = NULL;
|
||||
(*in)->pipe = 1;
|
||||
(*in)->timeout = -1;
|
||||
(*in)->ungetchar = -1;
|
||||
(*in)->eof_hit = 0;
|
||||
(*in)->filePtr = 0;
|
||||
(*in)->bufpos = 0;
|
||||
(*in)->dataRead = 0;
|
||||
(*in)->direction = 0;
|
||||
(*in)->pOverlapped = NULL;
|
||||
#if APR_FILES_AS_SOCKETS
|
||||
(void) apr_pollset_create(&(*in)->pollset, 1, p, 0);
|
||||
#endif
|
||||
(*out) = (apr_file_t *)apr_pcalloc(pool_out, sizeof(apr_file_t));
|
||||
(*out)->pool = pool_out;
|
||||
(*out)->fname = NULL;
|
||||
(*out)->pipe = 1;
|
||||
(*out)->timeout = -1;
|
||||
(*out)->ungetchar = -1;
|
||||
(*out)->eof_hit = 0;
|
||||
(*out)->filePtr = 0;
|
||||
(*out)->bufpos = 0;
|
||||
(*out)->dataRead = 0;
|
||||
(*out)->direction = 0;
|
||||
(*out)->pOverlapped = NULL;
|
||||
#if APR_FILES_AS_SOCKETS
|
||||
(void) apr_pollset_create(&(*out)->pollset, 1, p, 0);
|
||||
#endif
|
||||
if (apr_os_level >= APR_WIN_NT) {
|
||||
char rand[8];
|
||||
int pid = getpid();
|
||||
#define FMT_PIPE_NAME "\\\\.\\pipe\\apr-pipe-%x.%lx."
|
||||
/* ^ ^ ^
|
||||
* pid | |
|
||||
* | |
|
||||
* id |
|
||||
* |
|
||||
* hex-escaped rand[8] (16 bytes)
|
||||
*/
|
||||
char name[sizeof FMT_PIPE_NAME + 2 * sizeof(pid)
|
||||
+ 2 * sizeof(id)
|
||||
+ 2 * sizeof(rand)];
|
||||
apr_size_t pos;
|
||||
|
||||
/* Create the read end of the pipe */
|
||||
dwOpenMode = PIPE_ACCESS_INBOUND;
|
||||
#ifdef FILE_FLAG_FIRST_PIPE_INSTANCE
|
||||
dwOpenMode |= FILE_FLAG_FIRST_PIPE_INSTANCE;
|
||||
#endif
|
||||
if (blocking == APR_WRITE_BLOCK /* READ_NONBLOCK */
|
||||
|| blocking == APR_FULL_NONBLOCK) {
|
||||
dwOpenMode |= FILE_FLAG_OVERLAPPED;
|
||||
(*in)->pOverlapped =
|
||||
(OVERLAPPED*) apr_pcalloc((*in)->pool, sizeof(OVERLAPPED));
|
||||
(*in)->pOverlapped->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
(*in)->timeout = 0;
|
||||
}
|
||||
dwPipeMode = 0;
|
||||
|
||||
apr_generate_random_bytes(rand, sizeof rand);
|
||||
pos = apr_snprintf(name, sizeof name, FMT_PIPE_NAME, pid, id++);
|
||||
apr_escape_hex(name + pos, rand, sizeof rand, 0, NULL);
|
||||
|
||||
(*in)->filehand = CreateNamedPipe(name,
|
||||
dwOpenMode,
|
||||
dwPipeMode,
|
||||
1, /* nMaxInstances, */
|
||||
0, /* nOutBufferSize, */
|
||||
65536, /* nInBufferSize, */
|
||||
1, /* nDefaultTimeOut, */
|
||||
&sa);
|
||||
if ((*in)->filehand == INVALID_HANDLE_VALUE) {
|
||||
apr_status_t rv = apr_get_os_error();
|
||||
file_cleanup(*in);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* Create the write end of the pipe */
|
||||
dwOpenMode = FILE_ATTRIBUTE_NORMAL;
|
||||
if (blocking == APR_READ_BLOCK /* WRITE_NONBLOCK */
|
||||
|| blocking == APR_FULL_NONBLOCK) {
|
||||
dwOpenMode |= FILE_FLAG_OVERLAPPED;
|
||||
(*out)->pOverlapped =
|
||||
(OVERLAPPED*) apr_pcalloc((*out)->pool, sizeof(OVERLAPPED));
|
||||
(*out)->pOverlapped->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
(*out)->timeout = 0;
|
||||
}
|
||||
|
||||
(*out)->filehand = CreateFile(name,
|
||||
GENERIC_WRITE, /* access mode */
|
||||
0, /* share mode */
|
||||
&sa, /* Security attributes */
|
||||
OPEN_EXISTING, /* dwCreationDisposition */
|
||||
dwOpenMode, /* Pipe attributes */
|
||||
NULL); /* handle to template file */
|
||||
if ((*out)->filehand == INVALID_HANDLE_VALUE) {
|
||||
apr_status_t rv = apr_get_os_error();
|
||||
file_cleanup(*out);
|
||||
file_cleanup(*in);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Pipes on Win9* are blocking. Live with it. */
|
||||
if (!CreatePipe(&(*in)->filehand, &(*out)->filehand, &sa, 65536)) {
|
||||
return apr_get_os_error();
|
||||
}
|
||||
}
|
||||
|
||||
apr_pool_cleanup_register((*in)->pool, (void *)(*in), file_cleanup,
|
||||
apr_pool_cleanup_null);
|
||||
apr_pool_cleanup_register((*out)->pool, (void *)(*out), file_cleanup,
|
||||
apr_pool_cleanup_null);
|
||||
return APR_SUCCESS;
|
||||
#endif /* _WIN32_WCE */
|
||||
}
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_namedpipe_create(const char *filename,
|
||||
apr_fileperms_t perm,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
/* Not yet implemented, interface not suitable.
|
||||
* Win32 requires the named pipe to be *opened* at the time it's
|
||||
* created, and to do so, blocking or non blocking must be elected.
|
||||
*/
|
||||
return APR_ENOTIMPL;
|
||||
}
|
||||
|
||||
|
||||
/* XXX: Problem; we need to choose between blocking and nonblocking based
|
||||
* on how *thefile was opened, and we don't have that information :-/
|
||||
* Hack; assume a blocking socket, since the most common use for the fn
|
||||
* would be to handle stdio-style or blocking pipes. Win32 doesn't have
|
||||
* select() blocking for pipes anyways :(
|
||||
*/
|
||||
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)
|
||||
{
|
||||
(*file) = apr_pcalloc(pool, sizeof(apr_file_t));
|
||||
(*file)->pool = pool;
|
||||
(*file)->pipe = 1;
|
||||
(*file)->timeout = -1;
|
||||
(*file)->ungetchar = -1;
|
||||
(*file)->filehand = *thefile;
|
||||
#if APR_FILES_AS_SOCKETS
|
||||
(void) apr_pollset_create(&(*file)->pollset, 1, pool, 0);
|
||||
#endif
|
||||
if (register_cleanup) {
|
||||
apr_pool_cleanup_register(pool, *file, file_cleanup,
|
||||
apr_pool_cleanup_null);
|
||||
}
|
||||
|
||||
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 create_socket_pipe(SOCKET *rd, SOCKET *wr)
|
||||
{
|
||||
static int id = 0;
|
||||
FD_SET rs;
|
||||
SOCKET ls;
|
||||
struct timeval socktm;
|
||||
struct sockaddr_in pa;
|
||||
struct sockaddr_in la;
|
||||
struct sockaddr_in ca;
|
||||
int nrd;
|
||||
apr_status_t rv = APR_SUCCESS;
|
||||
int ll = sizeof(la);
|
||||
int lc = sizeof(ca);
|
||||
unsigned long bm = 1;
|
||||
int uid[2];
|
||||
int iid[2];
|
||||
|
||||
*rd = INVALID_SOCKET;
|
||||
*wr = INVALID_SOCKET;
|
||||
|
||||
/* Create the unique socket identifier
|
||||
* so that we know the connection originated
|
||||
* from us.
|
||||
*/
|
||||
uid[0] = getpid();
|
||||
uid[1] = id++;
|
||||
if ((ls = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {
|
||||
return apr_get_netos_error();
|
||||
}
|
||||
|
||||
pa.sin_family = AF_INET;
|
||||
pa.sin_port = 0;
|
||||
pa.sin_addr.s_addr = inet_addr("127.0.0.1");
|
||||
|
||||
if (bind(ls, (SOCKADDR *)&pa, sizeof(pa)) == SOCKET_ERROR) {
|
||||
rv = apr_get_netos_error();
|
||||
goto cleanup;
|
||||
}
|
||||
if (getsockname(ls, (SOCKADDR *)&la, &ll) == SOCKET_ERROR) {
|
||||
rv = apr_get_netos_error();
|
||||
goto cleanup;
|
||||
}
|
||||
if (listen(ls, 1) == SOCKET_ERROR) {
|
||||
rv = apr_get_netos_error();
|
||||
goto cleanup;
|
||||
}
|
||||
if ((*wr = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {
|
||||
rv = apr_get_netos_error();
|
||||
goto cleanup;
|
||||
}
|
||||
if (connect(*wr, (SOCKADDR *)&la, sizeof(la)) == SOCKET_ERROR) {
|
||||
rv = apr_get_netos_error();
|
||||
goto cleanup;
|
||||
}
|
||||
if (send(*wr, (char *)uid, sizeof(uid), 0) != sizeof(uid)) {
|
||||
if ((rv = apr_get_netos_error()) == 0) {
|
||||
rv = APR_EINVAL;
|
||||
}
|
||||
goto cleanup;
|
||||
}
|
||||
if (ioctlsocket(ls, FIONBIO, &bm) == SOCKET_ERROR) {
|
||||
rv = apr_get_netos_error();
|
||||
goto cleanup;
|
||||
}
|
||||
for (;;) {
|
||||
int ns;
|
||||
int nc = 0;
|
||||
/* Listening socket is nonblocking by now.
|
||||
* The accept should create the socket
|
||||
* immediatelly because we are connected already.
|
||||
* However on buys systems this can take a while
|
||||
* until winsock gets a chance to handle the events.
|
||||
*/
|
||||
FD_ZERO(&rs);
|
||||
FD_SET(ls, &rs);
|
||||
|
||||
socktm.tv_sec = 1;
|
||||
socktm.tv_usec = 0;
|
||||
if ((ns = select(0, &rs, NULL, NULL, &socktm)) == SOCKET_ERROR) {
|
||||
/* Accept still not signaled */
|
||||
Sleep(100);
|
||||
continue;
|
||||
}
|
||||
if (ns == 0) {
|
||||
/* No connections in the last second */
|
||||
continue;
|
||||
}
|
||||
if ((*rd = accept(ls, (SOCKADDR *)&ca, &lc)) == INVALID_SOCKET) {
|
||||
rv = apr_get_netos_error();
|
||||
goto cleanup;
|
||||
}
|
||||
/* Verify the connection by reading the send identification.
|
||||
*/
|
||||
do {
|
||||
if (nc++)
|
||||
Sleep(1);
|
||||
nrd = recv(*rd, (char *)iid, sizeof(iid), 0);
|
||||
rv = nrd == SOCKET_ERROR ? apr_get_netos_error() : APR_SUCCESS;
|
||||
} while (APR_STATUS_IS_EAGAIN(rv));
|
||||
|
||||
if (nrd == sizeof(iid)) {
|
||||
if (memcmp(uid, iid, sizeof(uid)) == 0) {
|
||||
/* Wow, we recived what we send.
|
||||
* Put read side of the pipe to the blocking
|
||||
* mode and return.
|
||||
*/
|
||||
bm = 0;
|
||||
if (ioctlsocket(*rd, FIONBIO, &bm) == SOCKET_ERROR) {
|
||||
rv = apr_get_netos_error();
|
||||
goto cleanup;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (nrd == SOCKET_ERROR) {
|
||||
goto cleanup;
|
||||
}
|
||||
closesocket(*rd);
|
||||
}
|
||||
/* We don't need the listening socket any more */
|
||||
closesocket(ls);
|
||||
return 0;
|
||||
|
||||
cleanup:
|
||||
/* Don't leak resources */
|
||||
if (*rd != INVALID_SOCKET)
|
||||
closesocket(*rd);
|
||||
if (*wr != INVALID_SOCKET)
|
||||
closesocket(*wr);
|
||||
|
||||
*rd = INVALID_SOCKET;
|
||||
*wr = INVALID_SOCKET;
|
||||
closesocket(ls);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static apr_status_t socket_pipe_cleanup(void *thefile)
|
||||
{
|
||||
apr_file_t *file = thefile;
|
||||
if (file->filehand != INVALID_HANDLE_VALUE) {
|
||||
shutdown((SOCKET)file->filehand, SD_BOTH);
|
||||
closesocket((SOCKET)file->filehand);
|
||||
file->filehand = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
apr_status_t apr_file_socket_pipe_create(apr_file_t **in,
|
||||
apr_file_t **out,
|
||||
apr_pool_t *p)
|
||||
{
|
||||
apr_status_t rv;
|
||||
SOCKET rd;
|
||||
SOCKET wr;
|
||||
|
||||
if ((rv = create_socket_pipe(&rd, &wr)) != APR_SUCCESS) {
|
||||
return rv;
|
||||
}
|
||||
(*in) = (apr_file_t *)apr_pcalloc(p, sizeof(apr_file_t));
|
||||
(*in)->pool = p;
|
||||
(*in)->fname = NULL;
|
||||
(*in)->pipe = 1;
|
||||
(*in)->timeout = -1;
|
||||
(*in)->ungetchar = -1;
|
||||
(*in)->eof_hit = 0;
|
||||
(*in)->filePtr = 0;
|
||||
(*in)->bufpos = 0;
|
||||
(*in)->dataRead = 0;
|
||||
(*in)->direction = 0;
|
||||
(*in)->pOverlapped = (OVERLAPPED*)apr_pcalloc(p, sizeof(OVERLAPPED));
|
||||
(*in)->filehand = (HANDLE)rd;
|
||||
|
||||
(*out) = (apr_file_t *)apr_pcalloc(p, sizeof(apr_file_t));
|
||||
(*out)->pool = p;
|
||||
(*out)->fname = NULL;
|
||||
(*out)->pipe = 1;
|
||||
(*out)->timeout = -1;
|
||||
(*out)->ungetchar = -1;
|
||||
(*out)->eof_hit = 0;
|
||||
(*out)->filePtr = 0;
|
||||
(*out)->bufpos = 0;
|
||||
(*out)->dataRead = 0;
|
||||
(*out)->direction = 0;
|
||||
(*out)->pOverlapped = (OVERLAPPED*)apr_pcalloc(p, sizeof(OVERLAPPED));
|
||||
(*out)->filehand = (HANDLE)wr;
|
||||
|
||||
apr_pool_cleanup_register(p, (void *)(*in), socket_pipe_cleanup,
|
||||
apr_pool_cleanup_null);
|
||||
apr_pool_cleanup_register(p, (void *)(*out), socket_pipe_cleanup,
|
||||
apr_pool_cleanup_null);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
apr_status_t apr_file_socket_pipe_close(apr_file_t *file)
|
||||
{
|
||||
apr_status_t stat;
|
||||
if (!file->pipe)
|
||||
return apr_file_close(file);
|
||||
if ((stat = socket_pipe_cleanup(file)) == APR_SUCCESS) {
|
||||
apr_pool_cleanup_kill(file->pool, file, socket_pipe_cleanup);
|
||||
|
||||
if (file->mutex) {
|
||||
apr_thread_mutex_destroy(file->mutex);
|
||||
}
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
+592
@@ -0,0 +1,592 @@
|
||||
/* 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_lib.h"
|
||||
#include "apr_errno.h"
|
||||
#include <malloc.h>
|
||||
#include "apr_arch_atime.h"
|
||||
#include "apr_arch_misc.h"
|
||||
|
||||
/*
|
||||
* read_with_timeout()
|
||||
* Uses async i/o to emulate unix non-blocking i/o with timeouts.
|
||||
*/
|
||||
static apr_status_t read_with_timeout(apr_file_t *file, void *buf, apr_size_t len_in, apr_size_t *nbytes)
|
||||
{
|
||||
apr_status_t rv;
|
||||
DWORD res;
|
||||
DWORD len = (DWORD)len_in;
|
||||
DWORD bytesread = 0;
|
||||
|
||||
/* Handle the zero timeout non-blocking case */
|
||||
if (file->timeout == 0) {
|
||||
/* Peek at the pipe. If there is no data available, return APR_EAGAIN.
|
||||
* If data is available, go ahead and read it.
|
||||
*/
|
||||
if (file->pipe) {
|
||||
DWORD bytes;
|
||||
if (!PeekNamedPipe(file->filehand, NULL, 0, NULL, &bytes, NULL)) {
|
||||
rv = apr_get_os_error();
|
||||
if (rv == APR_FROM_OS_ERROR(ERROR_BROKEN_PIPE)) {
|
||||
rv = APR_EOF;
|
||||
}
|
||||
*nbytes = 0;
|
||||
return rv;
|
||||
}
|
||||
else {
|
||||
if (bytes == 0) {
|
||||
*nbytes = 0;
|
||||
return APR_EAGAIN;
|
||||
}
|
||||
if (len > bytes) {
|
||||
len = bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* ToDo: Handle zero timeout non-blocking file i/o
|
||||
* This is not needed until an APR application needs to
|
||||
* timeout file i/o (which means setting file i/o non-blocking)
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
if (file->pOverlapped && !file->pipe) {
|
||||
file->pOverlapped->Offset = (DWORD)file->filePtr;
|
||||
file->pOverlapped->OffsetHigh = (DWORD)(file->filePtr >> 32);
|
||||
}
|
||||
|
||||
if (ReadFile(file->filehand, buf, len,
|
||||
&bytesread, file->pOverlapped)) {
|
||||
rv = APR_SUCCESS;
|
||||
}
|
||||
else {
|
||||
rv = apr_get_os_error();
|
||||
if (rv == APR_FROM_OS_ERROR(ERROR_IO_PENDING)) {
|
||||
/* Wait for the pending i/o, timeout converted from us to ms
|
||||
* Note that we loop if someone gives up the event, since
|
||||
* folks suggest that WAIT_ABANDONED isn't actually a result
|
||||
* but an alert that ownership of the event has passed from
|
||||
* one owner to a new proc/thread.
|
||||
*/
|
||||
do {
|
||||
res = WaitForSingleObject(file->pOverlapped->hEvent,
|
||||
(file->timeout > 0)
|
||||
? (DWORD)(file->timeout/1000)
|
||||
: ((file->timeout == -1)
|
||||
? INFINITE : 0));
|
||||
} while (res == WAIT_ABANDONED);
|
||||
|
||||
/* There is one case that represents entirely
|
||||
* successful operations, otherwise we will cancel
|
||||
* the operation in progress.
|
||||
*/
|
||||
if (res != WAIT_OBJECT_0) {
|
||||
CancelIo(file->filehand);
|
||||
}
|
||||
|
||||
/* Ignore any failures above. Attempt to complete
|
||||
* the overlapped operation and use only _its_ result.
|
||||
* For example, CancelIo or WaitForSingleObject can
|
||||
* fail if the handle is closed, yet the read may have
|
||||
* completed before we attempted to CancelIo...
|
||||
*/
|
||||
if (GetOverlappedResult(file->filehand, file->pOverlapped,
|
||||
&bytesread, TRUE)) {
|
||||
rv = APR_SUCCESS;
|
||||
}
|
||||
else {
|
||||
rv = apr_get_os_error();
|
||||
if (((rv == APR_FROM_OS_ERROR(ERROR_IO_INCOMPLETE))
|
||||
|| (rv == APR_FROM_OS_ERROR(ERROR_OPERATION_ABORTED)))
|
||||
&& (res == WAIT_TIMEOUT))
|
||||
rv = APR_TIMEUP;
|
||||
}
|
||||
}
|
||||
if (rv == APR_FROM_OS_ERROR(ERROR_BROKEN_PIPE)) {
|
||||
/* Assume ERROR_BROKEN_PIPE signals an EOF reading from a pipe */
|
||||
rv = APR_EOF;
|
||||
} else if (rv == APR_FROM_OS_ERROR(ERROR_HANDLE_EOF)) {
|
||||
/* Did we hit EOF reading from the handle? */
|
||||
rv = APR_EOF;
|
||||
}
|
||||
}
|
||||
|
||||
/* OK and 0 bytes read ==> end of file */
|
||||
if (rv == APR_SUCCESS && bytesread == 0)
|
||||
rv = APR_EOF;
|
||||
|
||||
if (rv == APR_SUCCESS && file->pOverlapped && !file->pipe) {
|
||||
file->filePtr += bytesread;
|
||||
}
|
||||
*nbytes = bytesread;
|
||||
return rv;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_read(apr_file_t *thefile, void *buf, apr_size_t *len)
|
||||
{
|
||||
apr_status_t rv;
|
||||
DWORD bytes_read = 0;
|
||||
|
||||
if (*len <= 0) {
|
||||
*len = 0;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
/* If the file is open for xthread support, allocate and
|
||||
* initialize the overlapped and io completion event (hEvent).
|
||||
* Threads should NOT share an apr_file_t or its hEvent.
|
||||
*/
|
||||
if ((thefile->flags & APR_FOPEN_XTHREAD) && !thefile->pOverlapped ) {
|
||||
thefile->pOverlapped = (OVERLAPPED*) apr_pcalloc(thefile->pool,
|
||||
sizeof(OVERLAPPED));
|
||||
thefile->pOverlapped->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
if (!thefile->pOverlapped->hEvent) {
|
||||
rv = apr_get_os_error();
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle the ungetchar if there is one */
|
||||
if (thefile->ungetchar != -1) {
|
||||
bytes_read = 1;
|
||||
*(char *)buf = (char)thefile->ungetchar;
|
||||
buf = (char *)buf + 1;
|
||||
(*len)--;
|
||||
thefile->ungetchar = -1;
|
||||
if (*len == 0) {
|
||||
*len = bytes_read;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
}
|
||||
if (thefile->buffered) {
|
||||
char *pos = (char *)buf;
|
||||
apr_size_t blocksize;
|
||||
apr_size_t size = *len;
|
||||
|
||||
if (thefile->flags & APR_FOPEN_XTHREAD) {
|
||||
apr_thread_mutex_lock(thefile->mutex);
|
||||
}
|
||||
|
||||
if (thefile->direction == 1) {
|
||||
rv = apr_file_flush(thefile);
|
||||
if (rv != APR_SUCCESS) {
|
||||
if (thefile->flags & APR_FOPEN_XTHREAD) {
|
||||
apr_thread_mutex_unlock(thefile->mutex);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
thefile->bufpos = 0;
|
||||
thefile->direction = 0;
|
||||
thefile->dataRead = 0;
|
||||
}
|
||||
|
||||
rv = 0;
|
||||
while (rv == 0 && size > 0) {
|
||||
if (thefile->bufpos >= thefile->dataRead) {
|
||||
apr_size_t read;
|
||||
rv = read_with_timeout(thefile, thefile->buffer,
|
||||
thefile->bufsize, &read);
|
||||
if (read == 0) {
|
||||
if (rv == APR_EOF)
|
||||
thefile->eof_hit = TRUE;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
thefile->dataRead = read;
|
||||
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;
|
||||
}
|
||||
|
||||
*len = pos - (char *)buf;
|
||||
if (*len) {
|
||||
rv = APR_SUCCESS;
|
||||
}
|
||||
|
||||
if (thefile->flags & APR_FOPEN_XTHREAD) {
|
||||
apr_thread_mutex_unlock(thefile->mutex);
|
||||
}
|
||||
} else {
|
||||
/* Unbuffered i/o */
|
||||
apr_size_t nbytes;
|
||||
rv = read_with_timeout(thefile, buf, *len, &nbytes);
|
||||
if (rv == APR_EOF)
|
||||
thefile->eof_hit = TRUE;
|
||||
*len = nbytes;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_write(apr_file_t *thefile, const void *buf, apr_size_t *nbytes)
|
||||
{
|
||||
apr_status_t rv;
|
||||
DWORD bwrote;
|
||||
|
||||
/* If the file is open for xthread support, allocate and
|
||||
* initialize the overlapped and io completion event (hEvent).
|
||||
* Threads should NOT share an apr_file_t or its hEvent.
|
||||
*/
|
||||
if ((thefile->flags & APR_FOPEN_XTHREAD) && !thefile->pOverlapped ) {
|
||||
thefile->pOverlapped = (OVERLAPPED*) apr_pcalloc(thefile->pool,
|
||||
sizeof(OVERLAPPED));
|
||||
thefile->pOverlapped->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
if (!thefile->pOverlapped->hEvent) {
|
||||
rv = apr_get_os_error();
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
if (thefile->buffered) {
|
||||
char *pos = (char *)buf;
|
||||
apr_size_t blocksize;
|
||||
apr_size_t size = *nbytes;
|
||||
|
||||
if (thefile->flags & APR_FOPEN_XTHREAD) {
|
||||
apr_thread_mutex_lock(thefile->mutex);
|
||||
}
|
||||
|
||||
if (thefile->direction == 0) {
|
||||
/* Position file pointer for writing at the offset we are logically reading from */
|
||||
apr_off_t offset = thefile->filePtr - thefile->dataRead + thefile->bufpos;
|
||||
DWORD offlo = (DWORD)offset;
|
||||
LONG offhi = (LONG)(offset >> 32);
|
||||
if (offset != thefile->filePtr)
|
||||
SetFilePointer(thefile->filehand, offlo, &offhi, FILE_BEGIN);
|
||||
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(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;
|
||||
}
|
||||
|
||||
if (thefile->flags & APR_FOPEN_XTHREAD) {
|
||||
apr_thread_mutex_unlock(thefile->mutex);
|
||||
}
|
||||
return rv;
|
||||
} else {
|
||||
if (!thefile->pipe) {
|
||||
apr_off_t offset = 0;
|
||||
apr_status_t rc;
|
||||
if (thefile->append) {
|
||||
/* apr_file_lock will mutex the file across processes.
|
||||
* The call to apr_thread_mutex_lock is added to avoid
|
||||
* a race condition between LockFile and WriteFile
|
||||
* that occasionally leads to deadlocked threads.
|
||||
*/
|
||||
apr_thread_mutex_lock(thefile->mutex);
|
||||
rc = apr_file_lock(thefile, APR_FLOCK_EXCLUSIVE);
|
||||
if (rc != APR_SUCCESS) {
|
||||
apr_thread_mutex_unlock(thefile->mutex);
|
||||
return rc;
|
||||
}
|
||||
rc = apr_file_seek(thefile, APR_END, &offset);
|
||||
if (rc != APR_SUCCESS) {
|
||||
apr_thread_mutex_unlock(thefile->mutex);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
if (thefile->pOverlapped) {
|
||||
thefile->pOverlapped->Offset = (DWORD)thefile->filePtr;
|
||||
thefile->pOverlapped->OffsetHigh = (DWORD)(thefile->filePtr >> 32);
|
||||
}
|
||||
rv = WriteFile(thefile->filehand, buf, (DWORD)*nbytes, &bwrote,
|
||||
thefile->pOverlapped);
|
||||
if (thefile->append) {
|
||||
apr_file_unlock(thefile);
|
||||
apr_thread_mutex_unlock(thefile->mutex);
|
||||
}
|
||||
}
|
||||
else {
|
||||
rv = WriteFile(thefile->filehand, buf, (DWORD)*nbytes, &bwrote,
|
||||
thefile->pOverlapped);
|
||||
}
|
||||
if (rv) {
|
||||
*nbytes = bwrote;
|
||||
rv = APR_SUCCESS;
|
||||
}
|
||||
else {
|
||||
(*nbytes) = 0;
|
||||
rv = apr_get_os_error();
|
||||
|
||||
/* XXX: This must be corrected, per the apr_file_read logic!!! */
|
||||
if (rv == APR_FROM_OS_ERROR(ERROR_IO_PENDING)) {
|
||||
|
||||
DWORD timeout_ms;
|
||||
|
||||
if (thefile->timeout == 0) {
|
||||
timeout_ms = 0;
|
||||
}
|
||||
else if (thefile->timeout < 0) {
|
||||
timeout_ms = INFINITE;
|
||||
}
|
||||
else {
|
||||
timeout_ms = (DWORD)(thefile->timeout / 1000);
|
||||
}
|
||||
|
||||
rv = WaitForSingleObject(thefile->pOverlapped->hEvent, timeout_ms);
|
||||
switch (rv) {
|
||||
case WAIT_OBJECT_0:
|
||||
GetOverlappedResult(thefile->filehand, thefile->pOverlapped,
|
||||
&bwrote, TRUE);
|
||||
*nbytes = bwrote;
|
||||
rv = APR_SUCCESS;
|
||||
break;
|
||||
case WAIT_TIMEOUT:
|
||||
rv = (timeout_ms == 0) ? APR_EAGAIN : APR_TIMEUP;
|
||||
break;
|
||||
case WAIT_FAILED:
|
||||
rv = apr_get_os_error();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (rv != APR_SUCCESS) {
|
||||
if (apr_os_level >= APR_WIN_98)
|
||||
CancelIo(thefile->filehand);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (rv == APR_SUCCESS && thefile->pOverlapped && !thefile->pipe) {
|
||||
thefile->filePtr += *nbytes;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
/* ToDo: Write for it anyway and test the oslevel!
|
||||
* Too bad WriteFileGather() is not supported on 95&98 (or NT prior to SP2)
|
||||
*/
|
||||
APR_DECLARE(apr_status_t) apr_file_writev(apr_file_t *thefile,
|
||||
const struct iovec *vec,
|
||||
apr_size_t nvec,
|
||||
apr_size_t *nbytes)
|
||||
{
|
||||
apr_status_t rv = APR_SUCCESS;
|
||||
apr_size_t i;
|
||||
apr_size_t bwrote = 0;
|
||||
char *buf;
|
||||
|
||||
*nbytes = 0;
|
||||
for (i = 0; i < nvec; i++) {
|
||||
buf = vec[i].iov_base;
|
||||
bwrote = vec[i].iov_len;
|
||||
rv = apr_file_write(thefile, buf, &bwrote);
|
||||
*nbytes += bwrote;
|
||||
if (rv != APR_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_putc(char ch, apr_file_t *thefile)
|
||||
{
|
||||
apr_size_t len = 1;
|
||||
|
||||
return apr_file_write(thefile, &ch, &len);
|
||||
}
|
||||
|
||||
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_status_t rc;
|
||||
apr_size_t bread;
|
||||
|
||||
bread = 1;
|
||||
rc = apr_file_read(thefile, ch, &bread);
|
||||
|
||||
if (rc) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (bread == 0) {
|
||||
thefile->eof_hit = TRUE;
|
||||
return APR_EOF;
|
||||
}
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_puts(const char *str, apr_file_t *thefile)
|
||||
{
|
||||
apr_size_t len = strlen(str);
|
||||
|
||||
return apr_file_write(thefile, str, &len);
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_gets(char *str, int len, apr_file_t *thefile)
|
||||
{
|
||||
apr_size_t readlen;
|
||||
apr_status_t rv = APR_SUCCESS;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len-1; i++) {
|
||||
readlen = 1;
|
||||
rv = apr_file_read(thefile, str+i, &readlen);
|
||||
|
||||
if (rv != APR_SUCCESS && rv != APR_EOF)
|
||||
return rv;
|
||||
|
||||
if (readlen == 0) {
|
||||
/* If we have bytes, defer APR_EOF to the next call */
|
||||
if (i > 0)
|
||||
rv = APR_SUCCESS;
|
||||
break;
|
||||
}
|
||||
|
||||
if (str[i] == '\n') {
|
||||
i++; /* don't clobber this char below */
|
||||
break;
|
||||
}
|
||||
}
|
||||
str[i] = 0;
|
||||
return rv;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_flush(apr_file_t *thefile)
|
||||
{
|
||||
if (thefile->buffered) {
|
||||
DWORD numbytes, written = 0;
|
||||
apr_status_t rc = 0;
|
||||
char *buffer;
|
||||
apr_size_t bytesleft;
|
||||
|
||||
if (thefile->direction == 1 && thefile->bufpos) {
|
||||
buffer = thefile->buffer;
|
||||
bytesleft = thefile->bufpos;
|
||||
|
||||
do {
|
||||
if (bytesleft > APR_DWORD_MAX) {
|
||||
numbytes = APR_DWORD_MAX;
|
||||
}
|
||||
else {
|
||||
numbytes = (DWORD)bytesleft;
|
||||
}
|
||||
|
||||
if (!WriteFile(thefile->filehand, buffer, numbytes, &written, NULL)) {
|
||||
rc = apr_get_os_error();
|
||||
thefile->filePtr += written;
|
||||
break;
|
||||
}
|
||||
|
||||
thefile->filePtr += written;
|
||||
bytesleft -= written;
|
||||
buffer += written;
|
||||
|
||||
} while (bytesleft > 0);
|
||||
|
||||
if (rc == 0)
|
||||
thefile->bufpos = 0;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* There isn't anything to do if we aren't buffering the output
|
||||
* so just return success.
|
||||
*/
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_sync(apr_file_t *thefile){
|
||||
apr_status_t rv;
|
||||
|
||||
rv = apr_file_flush(thefile);
|
||||
if (rv != APR_SUCCESS) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!FlushFileBuffers(thefile->filehand)) {
|
||||
rv = apr_get_os_error();
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_datasync(apr_file_t *thefile){
|
||||
return apr_file_sync(thefile);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
data.buf = malloc(HUGE_STRING_LEN);
|
||||
if (data.buf == NULL) {
|
||||
return 0;
|
||||
}
|
||||
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;
|
||||
}
|
||||
+203
@@ -0,0 +1,203 @@
|
||||
/* 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 <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
static apr_status_t setptr(apr_file_t *thefile, apr_off_t pos )
|
||||
{
|
||||
apr_off_t newbufpos;
|
||||
apr_status_t rv;
|
||||
DWORD rc;
|
||||
|
||||
if (thefile->direction == 1) {
|
||||
/* XXX: flush here is not mutex protected */
|
||||
rv = apr_file_flush(thefile);
|
||||
if (rv != APR_SUCCESS)
|
||||
return rv;
|
||||
thefile->bufpos = thefile->dataRead = 0;
|
||||
thefile->direction = 0;
|
||||
}
|
||||
|
||||
/* We may be truncating to size here.
|
||||
* XXX: testing an 'unsigned' as >= 0 below indicates a bug
|
||||
*/
|
||||
newbufpos = pos - (thefile->filePtr - thefile->dataRead);
|
||||
|
||||
if (newbufpos >= 0 && newbufpos <= (apr_off_t)thefile->dataRead) {
|
||||
thefile->bufpos = (apr_size_t)newbufpos;
|
||||
rv = APR_SUCCESS;
|
||||
} else {
|
||||
DWORD offlo = (DWORD)pos;
|
||||
LONG offhi = (LONG)(pos >> 32);
|
||||
rc = SetFilePointer(thefile->filehand, offlo, &offhi, FILE_BEGIN);
|
||||
|
||||
if (rc == (DWORD)-1)
|
||||
/* A legal value, perhaps? MSDN implies prior SetLastError isn't
|
||||
* needed, googling for SetLastError SetFilePointer seems
|
||||
* to confirm this. INVALID_SET_FILE_POINTER is too recently
|
||||
* added for us to rely on it as a constant.
|
||||
*/
|
||||
rv = apr_get_os_error();
|
||||
else
|
||||
rv = APR_SUCCESS;
|
||||
|
||||
if (rv == APR_SUCCESS) {
|
||||
rv = APR_SUCCESS;
|
||||
thefile->eof_hit = 0;
|
||||
thefile->bufpos = thefile->dataRead = 0;
|
||||
thefile->filePtr = pos;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_seek(apr_file_t *thefile, apr_seek_where_t where, apr_off_t *offset)
|
||||
{
|
||||
apr_finfo_t finfo;
|
||||
apr_status_t rc = APR_SUCCESS;
|
||||
|
||||
thefile->eof_hit = 0;
|
||||
|
||||
if (thefile->buffered) {
|
||||
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(&finfo, APR_FINFO_SIZE, thefile);
|
||||
if (rc == APR_SUCCESS)
|
||||
rc = setptr(thefile, finfo.size + *offset);
|
||||
break;
|
||||
|
||||
default:
|
||||
return APR_EINVAL;
|
||||
}
|
||||
|
||||
*offset = thefile->filePtr - thefile->dataRead + thefile->bufpos;
|
||||
return rc;
|
||||
}
|
||||
/* A file opened with APR_FOPEN_XTHREAD has been opened for overlapped i/o.
|
||||
* APR must explicitly track the file pointer in this case.
|
||||
*/
|
||||
else if (thefile->pOverlapped || thefile->flags & APR_FOPEN_XTHREAD) {
|
||||
switch(where) {
|
||||
case APR_SET:
|
||||
thefile->filePtr = *offset;
|
||||
break;
|
||||
|
||||
case APR_CUR:
|
||||
thefile->filePtr += *offset;
|
||||
break;
|
||||
|
||||
case APR_END:
|
||||
rc = apr_file_info_get(&finfo, APR_FINFO_SIZE, thefile);
|
||||
if (rc == APR_SUCCESS && finfo.size + *offset >= 0)
|
||||
thefile->filePtr = finfo.size + *offset;
|
||||
break;
|
||||
|
||||
default:
|
||||
return APR_EINVAL;
|
||||
}
|
||||
*offset = thefile->filePtr;
|
||||
return rc;
|
||||
}
|
||||
else {
|
||||
DWORD howmove;
|
||||
DWORD offlo = (DWORD)*offset;
|
||||
DWORD offhi = (DWORD)(*offset >> 32);
|
||||
|
||||
switch(where) {
|
||||
case APR_SET:
|
||||
howmove = FILE_BEGIN; break;
|
||||
case APR_CUR:
|
||||
howmove = FILE_CURRENT; break;
|
||||
case APR_END:
|
||||
howmove = FILE_END; break;
|
||||
default:
|
||||
return APR_EINVAL;
|
||||
}
|
||||
offlo = SetFilePointer(thefile->filehand, (LONG)offlo,
|
||||
(LONG*)&offhi, howmove);
|
||||
if (offlo == 0xFFFFFFFF)
|
||||
rc = apr_get_os_error();
|
||||
else
|
||||
rc = APR_SUCCESS;
|
||||
/* Since we can land at 0xffffffff we will measure our APR_SUCCESS */
|
||||
if (rc == APR_SUCCESS)
|
||||
*offset = ((apr_off_t)offhi << 32) | offlo;
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_trunc(apr_file_t *thefile, apr_off_t offset)
|
||||
{
|
||||
apr_status_t rv;
|
||||
DWORD offlo = (DWORD)offset;
|
||||
LONG offhi = (LONG)(offset >> 32);
|
||||
DWORD rc;
|
||||
|
||||
if (thefile->buffered) {
|
||||
if (thefile->direction == 1) {
|
||||
/* Figure out what needs to be flushed. Don't flush the part
|
||||
* of the write buffer that will get truncated anyway.
|
||||
*/
|
||||
if (offset < thefile->filePtr) {
|
||||
thefile->bufpos = 0;
|
||||
}
|
||||
else if (offset < thefile->filePtr + (apr_off_t)thefile->bufpos) {
|
||||
thefile->bufpos = offset - thefile->filePtr;
|
||||
}
|
||||
|
||||
if (thefile->bufpos != 0) {
|
||||
rv = apr_file_flush(thefile);
|
||||
if (rv != APR_SUCCESS)
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
else if (thefile->direction == 0) {
|
||||
/* Discard the read buffer, as we are about to reposition
|
||||
* ourselves to the end of file.
|
||||
*/
|
||||
thefile->bufpos = 0;
|
||||
thefile->dataRead = 0;
|
||||
}
|
||||
}
|
||||
|
||||
rc = SetFilePointer(thefile->filehand, offlo, &offhi, FILE_BEGIN);
|
||||
if (rc == 0xFFFFFFFF)
|
||||
if ((rv = apr_get_os_error()) != APR_SUCCESS)
|
||||
return rv;
|
||||
thefile->filePtr = offset;
|
||||
/* Don't report EOF until the next read. */
|
||||
thefile->eof_hit = 0;
|
||||
|
||||
if (!SetEndOfFile(thefile->filehand))
|
||||
return apr_get_os_error();
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
Reference in New Issue
Block a user