upload http
[bottlenecks.git] / rubbos / app / httpd-2.0.64 / srclib / apr / file_io / netware / filestat.c
diff --git a/rubbos/app/httpd-2.0.64/srclib/apr/file_io/netware/filestat.c b/rubbos/app/httpd-2.0.64/srclib/apr/file_io/netware/filestat.c
new file mode 100644 (file)
index 0000000..def63b7
--- /dev/null
@@ -0,0 +1,421 @@
+/* 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);
+    /* ### needs to be revisited  
+     * if (wanted & APR_FINFO_CSIZE) {
+     *   finfo->csize = info->st_blocks * 512;
+     *   finfo->valid |= APR_FINFO_CSIZE;
+     * }
+     */
+}
+
+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 (!APR_STATUS_IS_SUCCESS(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
+    }
+}
+
+/* Perhaps this becomes nothing but a macro?
+ */
+APR_DECLARE(apr_status_t) apr_lstat(apr_finfo_t *finfo, const char *fname,
+                      apr_int32_t wanted, apr_pool_t *pool)
+{
+    return apr_stat(finfo, fname, wanted | APR_FINFO_LINK, pool);
+}
+
+
+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 (!APR_STATUS_IS_SUCCESS(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;
+}