/* 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 #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 } }