		/* Copyright 2000-2004 The Apache Software Foundation
		 *
		 * Licensed 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)
          36    {
          36        apr_filetype_e type;
		
          36        switch (mode & S_IFMT) {
		    case S_IFREG:
          30            type = APR_REG;  break;
		    case S_IFDIR:
           6            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;
		    }
          36        return type;
		}
		
		static void fill_out_finfo(apr_finfo_t *finfo, struct stat *info,
		                           apr_int32_t wanted)
          36    { 
          36        finfo->valid = APR_FINFO_MIN | APR_FINFO_IDENT | APR_FINFO_NLINK
		                 | APR_FINFO_OWNER | APR_FINFO_PROT;
          36        finfo->protection = apr_unix_mode2perms(info->st_mode);
          36        finfo->filetype = filetype_from_mode(info->st_mode);
          36        finfo->user = info->st_uid;
          36        finfo->group = info->st_gid;
          36        finfo->size = info->st_size;
          36        finfo->inode = info->st_ino;
          36        finfo->device = info->st_dev;
          36        finfo->nlink = info->st_nlink;
          36        apr_time_ansi_put(&finfo->atime, info->st_atime);
          36        apr_time_ansi_put(&finfo->mtime, info->st_mtime);
          36        apr_time_ansi_put(&finfo->ctime, info->st_ctime);
		    /* ### needs to be revisited  
		     * if (wanted & APR_FINFO_CSIZE) {
		     *   finfo->csize = info->st_blocks * 512;
		     *   finfo->valid |= APR_FINFO_CSIZE;
		     * }
		     */
		}
		
		APR_DECLARE(apr_status_t) apr_file_info_get(apr_finfo_t *finfo, 
		                                            apr_int32_t wanted,
		                                            apr_file_t *thefile)
          10    {
          10        struct stat info;
		
          10        if (thefile->buffered) {
           1            apr_status_t rv = apr_file_flush(thefile);
           1            if (rv != APR_SUCCESS)
      ######                return rv;
		    }
		
          10        if (fstat(thefile->filedes, &info) == 0) {
          10            finfo->pool = thefile->pool;
          10            finfo->fname = thefile->fname;
          10            fill_out_finfo(finfo, &info, wanted);
          10            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);
		}
		
		
		APR_DECLARE(apr_status_t) apr_file_mtime_set(const char *fname,
		                                              apr_time_t mtime,
		                                              apr_pool_t *pool)
           1    {
           1        apr_status_t status;
           1        apr_finfo_t finfo;
		
           1        status = apr_stat(&finfo, fname, APR_FINFO_ATIME, pool);
           1        if (!APR_STATUS_IS_SUCCESS(status)) {
      ######            return status;
		    }
		
		#ifdef HAVE_UTIMES
		    {
           1          struct timeval tvp[2];
		    
           1          tvp[0].tv_sec = apr_time_sec(finfo.atime);
           1          tvp[0].tv_usec = apr_time_usec(finfo.atime);
           1          tvp[1].tv_sec = apr_time_sec(mtime);
           1          tvp[1].tv_usec = apr_time_usec(mtime);
		      
           1          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
		
           1        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)
          33    {
          33        struct stat info;
          33        int srv;
		
          33        if (wanted & APR_FINFO_LINK)
           2            srv = lstat(fname, &info);
		    else
          31            srv = stat(fname, &info);
		
          33        if (srv == 0) {
          26            finfo->pool = pool;
          26            finfo->fname = fname;
          26            fill_out_finfo(finfo, &info, wanted);
          26            if (wanted & APR_FINFO_LINK)
           2                wanted &= ~APR_FINFO_LINK;
          26            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: */
           7            return errno;
		#endif
		    }
		}
		
		
