diff options
Diffstat (limited to 'file_io/netware/filestat.c')
-rw-r--r-- | file_io/netware/filestat.c | 417 |
1 files changed, 417 insertions, 0 deletions
diff --git a/file_io/netware/filestat.c b/file_io/netware/filestat.c new file mode 100644 index 0000000..6627951 --- /dev/null +++ b/file_io/netware/filestat.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; +} |