1251875Speter/* Licensed to the Apache Software Foundation (ASF) under one or more 2251875Speter * contributor license agreements. See the NOTICE file distributed with 3251875Speter * this work for additional information regarding copyright ownership. 4251875Speter * The ASF licenses this file to You under the Apache License, Version 2.0 5251875Speter * (the "License"); you may not use this file except in compliance with 6251875Speter * the License. You may obtain a copy of the License at 7251875Speter * 8251875Speter * http://www.apache.org/licenses/LICENSE-2.0 9251875Speter * 10251875Speter * Unless required by applicable law or agreed to in writing, software 11251875Speter * distributed under the License is distributed on an "AS IS" BASIS, 12251875Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13251875Speter * See the License for the specific language governing permissions and 14251875Speter * limitations under the License. 15251875Speter */ 16251875Speter 17251875Speter#include "apr_arch_file_io.h" 18251875Speter#include "apr_file_io.h" 19251875Speter#include "apr_general.h" 20251875Speter#include "apr_strings.h" 21251875Speter#include "apr_errno.h" 22251875Speter 23251875Speter#ifdef HAVE_UTIME 24251875Speter#include <utime.h> 25251875Speter#endif 26251875Speter 27251875Speterstatic apr_filetype_e filetype_from_mode(mode_t mode) 28251875Speter{ 29251875Speter apr_filetype_e type; 30251875Speter 31251875Speter switch (mode & S_IFMT) { 32251875Speter case S_IFREG: 33251875Speter type = APR_REG; break; 34251875Speter case S_IFDIR: 35251875Speter type = APR_DIR; break; 36251875Speter case S_IFLNK: 37251875Speter type = APR_LNK; break; 38251875Speter case S_IFCHR: 39251875Speter type = APR_CHR; break; 40251875Speter case S_IFBLK: 41251875Speter type = APR_BLK; break; 42251875Speter#if defined(S_IFFIFO) 43251875Speter case S_IFFIFO: 44251875Speter type = APR_PIPE; break; 45251875Speter#endif 46251875Speter#if !defined(BEOS) && defined(S_IFSOCK) 47251875Speter case S_IFSOCK: 48251875Speter type = APR_SOCK; break; 49251875Speter#endif 50251875Speter 51251875Speter default: 52251875Speter /* Work around missing S_IFxxx values above 53251875Speter * for Linux et al. 54251875Speter */ 55251875Speter#if !defined(S_IFFIFO) && defined(S_ISFIFO) 56251875Speter if (S_ISFIFO(mode)) { 57251875Speter type = APR_PIPE; 58251875Speter } else 59251875Speter#endif 60251875Speter#if !defined(BEOS) && !defined(S_IFSOCK) && defined(S_ISSOCK) 61251875Speter if (S_ISSOCK(mode)) { 62251875Speter type = APR_SOCK; 63251875Speter } else 64251875Speter#endif 65251875Speter type = APR_UNKFILE; 66251875Speter } 67251875Speter return type; 68251875Speter} 69251875Speter 70251875Speterstatic void fill_out_finfo(apr_finfo_t *finfo, struct_stat *info, 71251875Speter apr_int32_t wanted) 72251875Speter{ 73251875Speter finfo->valid = APR_FINFO_MIN | APR_FINFO_IDENT | APR_FINFO_NLINK 74251875Speter | APR_FINFO_OWNER | APR_FINFO_PROT; 75251875Speter finfo->protection = apr_unix_mode2perms(info->st_mode); 76251875Speter finfo->filetype = filetype_from_mode(info->st_mode); 77251875Speter finfo->user = info->st_uid; 78251875Speter finfo->group = info->st_gid; 79251875Speter finfo->size = info->st_size; 80251875Speter finfo->device = info->st_dev; 81251875Speter finfo->nlink = info->st_nlink; 82251875Speter 83251875Speter /* Check for overflow if storing a 64-bit st_ino in a 32-bit 84251875Speter * apr_ino_t for LFS builds: */ 85251875Speter if (sizeof(apr_ino_t) >= sizeof(info->st_ino) 86251875Speter || (apr_ino_t)info->st_ino == info->st_ino) { 87251875Speter finfo->inode = info->st_ino; 88251875Speter } else { 89251875Speter finfo->valid &= ~APR_FINFO_INODE; 90251875Speter } 91251875Speter 92251875Speter apr_time_ansi_put(&finfo->atime, info->st_atime); 93251875Speter#ifdef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC 94251875Speter finfo->atime += info->st_atim.tv_nsec / APR_TIME_C(1000); 95251875Speter#elif defined(HAVE_STRUCT_STAT_ST_ATIMENSEC) 96251875Speter finfo->atime += info->st_atimensec / APR_TIME_C(1000); 97251875Speter#elif defined(HAVE_STRUCT_STAT_ST_ATIME_N) 98269847Speter finfo->atime += info->st_atime_n / APR_TIME_C(1000); 99251875Speter#endif 100251875Speter 101251875Speter apr_time_ansi_put(&finfo->mtime, info->st_mtime); 102251875Speter#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 103251875Speter finfo->mtime += info->st_mtim.tv_nsec / APR_TIME_C(1000); 104251875Speter#elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC) 105251875Speter finfo->mtime += info->st_mtimensec / APR_TIME_C(1000); 106251875Speter#elif defined(HAVE_STRUCT_STAT_ST_MTIME_N) 107269847Speter finfo->mtime += info->st_mtime_n / APR_TIME_C(1000); 108251875Speter#endif 109251875Speter 110251875Speter apr_time_ansi_put(&finfo->ctime, info->st_ctime); 111251875Speter#ifdef HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC 112251875Speter finfo->ctime += info->st_ctim.tv_nsec / APR_TIME_C(1000); 113251875Speter#elif defined(HAVE_STRUCT_STAT_ST_CTIMENSEC) 114251875Speter finfo->ctime += info->st_ctimensec / APR_TIME_C(1000); 115251875Speter#elif defined(HAVE_STRUCT_STAT_ST_CTIME_N) 116251875Speter finfo->ctime += info->st_ctime_n / APR_TIME_C(1000); 117251875Speter#endif 118251875Speter 119251875Speter#ifdef HAVE_STRUCT_STAT_ST_BLOCKS 120251875Speter#ifdef DEV_BSIZE 121251875Speter finfo->csize = (apr_off_t)info->st_blocks * (apr_off_t)DEV_BSIZE; 122251875Speter#else 123251875Speter finfo->csize = (apr_off_t)info->st_blocks * (apr_off_t)512; 124251875Speter#endif 125251875Speter finfo->valid |= APR_FINFO_CSIZE; 126251875Speter#endif 127251875Speter} 128251875Speter 129251875Speterapr_status_t apr_file_info_get_locked(apr_finfo_t *finfo, apr_int32_t wanted, 130251875Speter apr_file_t *thefile) 131251875Speter{ 132251875Speter struct_stat info; 133251875Speter 134251875Speter if (thefile->buffered) { 135251875Speter apr_status_t rv = apr_file_flush_locked(thefile); 136251875Speter if (rv != APR_SUCCESS) 137251875Speter return rv; 138251875Speter } 139251875Speter 140251875Speter if (fstat(thefile->filedes, &info) == 0) { 141251875Speter finfo->pool = thefile->pool; 142251875Speter finfo->fname = thefile->fname; 143251875Speter fill_out_finfo(finfo, &info, wanted); 144251875Speter return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS; 145251875Speter } 146251875Speter else { 147251875Speter return errno; 148251875Speter } 149251875Speter} 150251875Speter 151251875SpeterAPR_DECLARE(apr_status_t) apr_file_info_get(apr_finfo_t *finfo, 152251875Speter apr_int32_t wanted, 153251875Speter apr_file_t *thefile) 154251875Speter{ 155251875Speter struct_stat info; 156251875Speter 157251875Speter if (thefile->buffered) { 158251875Speter apr_status_t rv = apr_file_flush(thefile); 159251875Speter if (rv != APR_SUCCESS) 160251875Speter return rv; 161251875Speter } 162251875Speter 163251875Speter if (fstat(thefile->filedes, &info) == 0) { 164251875Speter finfo->pool = thefile->pool; 165251875Speter finfo->fname = thefile->fname; 166251875Speter fill_out_finfo(finfo, &info, wanted); 167251875Speter return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS; 168251875Speter } 169251875Speter else { 170251875Speter return errno; 171251875Speter } 172251875Speter} 173251875Speter 174251875SpeterAPR_DECLARE(apr_status_t) apr_file_perms_set(const char *fname, 175251875Speter apr_fileperms_t perms) 176251875Speter{ 177251875Speter mode_t mode = apr_unix_perms2mode(perms); 178251875Speter 179251875Speter if (chmod(fname, mode) == -1) 180251875Speter return errno; 181251875Speter return APR_SUCCESS; 182251875Speter} 183251875Speter 184251875SpeterAPR_DECLARE(apr_status_t) apr_file_attrs_set(const char *fname, 185251875Speter apr_fileattrs_t attributes, 186251875Speter apr_fileattrs_t attr_mask, 187251875Speter apr_pool_t *pool) 188251875Speter{ 189251875Speter apr_status_t status; 190251875Speter apr_finfo_t finfo; 191251875Speter 192251875Speter /* Don't do anything if we can't handle the requested attributes */ 193251875Speter if (!(attr_mask & (APR_FILE_ATTR_READONLY 194251875Speter | APR_FILE_ATTR_EXECUTABLE))) 195251875Speter return APR_SUCCESS; 196251875Speter 197251875Speter status = apr_stat(&finfo, fname, APR_FINFO_PROT, pool); 198251875Speter if (status) 199251875Speter return status; 200251875Speter 201251875Speter /* ### TODO: should added bits be umask'd? */ 202251875Speter if (attr_mask & APR_FILE_ATTR_READONLY) 203251875Speter { 204251875Speter if (attributes & APR_FILE_ATTR_READONLY) 205251875Speter { 206251875Speter finfo.protection &= ~APR_UWRITE; 207251875Speter finfo.protection &= ~APR_GWRITE; 208251875Speter finfo.protection &= ~APR_WWRITE; 209251875Speter } 210251875Speter else 211251875Speter { 212251875Speter /* ### umask this! */ 213251875Speter finfo.protection |= APR_UWRITE; 214251875Speter finfo.protection |= APR_GWRITE; 215251875Speter finfo.protection |= APR_WWRITE; 216251875Speter } 217251875Speter } 218251875Speter 219251875Speter if (attr_mask & APR_FILE_ATTR_EXECUTABLE) 220251875Speter { 221251875Speter if (attributes & APR_FILE_ATTR_EXECUTABLE) 222251875Speter { 223251875Speter /* ### umask this! */ 224251875Speter finfo.protection |= APR_UEXECUTE; 225251875Speter finfo.protection |= APR_GEXECUTE; 226251875Speter finfo.protection |= APR_WEXECUTE; 227251875Speter } 228251875Speter else 229251875Speter { 230251875Speter finfo.protection &= ~APR_UEXECUTE; 231251875Speter finfo.protection &= ~APR_GEXECUTE; 232251875Speter finfo.protection &= ~APR_WEXECUTE; 233251875Speter } 234251875Speter } 235251875Speter 236251875Speter return apr_file_perms_set(fname, finfo.protection); 237251875Speter} 238251875Speter 239251875Speter 240251875SpeterAPR_DECLARE(apr_status_t) apr_file_mtime_set(const char *fname, 241251875Speter apr_time_t mtime, 242251875Speter apr_pool_t *pool) 243251875Speter{ 244251875Speter apr_status_t status; 245251875Speter apr_finfo_t finfo; 246251875Speter 247251875Speter status = apr_stat(&finfo, fname, APR_FINFO_ATIME, pool); 248251875Speter if (status) { 249251875Speter return status; 250251875Speter } 251251875Speter 252251875Speter#ifdef HAVE_UTIMES 253251875Speter { 254251875Speter struct timeval tvp[2]; 255251875Speter 256251875Speter tvp[0].tv_sec = apr_time_sec(finfo.atime); 257251875Speter tvp[0].tv_usec = apr_time_usec(finfo.atime); 258251875Speter tvp[1].tv_sec = apr_time_sec(mtime); 259251875Speter tvp[1].tv_usec = apr_time_usec(mtime); 260251875Speter 261251875Speter if (utimes(fname, tvp) == -1) { 262251875Speter return errno; 263251875Speter } 264251875Speter } 265251875Speter#elif defined(HAVE_UTIME) 266251875Speter { 267251875Speter struct utimbuf buf; 268251875Speter 269251875Speter buf.actime = (time_t) (finfo.atime / APR_USEC_PER_SEC); 270251875Speter buf.modtime = (time_t) (mtime / APR_USEC_PER_SEC); 271251875Speter 272251875Speter if (utime(fname, &buf) == -1) { 273251875Speter return errno; 274251875Speter } 275251875Speter } 276251875Speter#else 277251875Speter return APR_ENOTIMPL; 278251875Speter#endif 279251875Speter 280251875Speter return APR_SUCCESS; 281251875Speter} 282251875Speter 283251875Speter 284251875SpeterAPR_DECLARE(apr_status_t) apr_stat(apr_finfo_t *finfo, 285251875Speter const char *fname, 286251875Speter apr_int32_t wanted, apr_pool_t *pool) 287251875Speter{ 288251875Speter struct_stat info; 289251875Speter int srv; 290251875Speter 291251875Speter if (wanted & APR_FINFO_LINK) 292251875Speter srv = lstat(fname, &info); 293251875Speter else 294251875Speter srv = stat(fname, &info); 295251875Speter 296251875Speter if (srv == 0) { 297251875Speter finfo->pool = pool; 298251875Speter finfo->fname = fname; 299251875Speter fill_out_finfo(finfo, &info, wanted); 300251875Speter if (wanted & APR_FINFO_LINK) 301251875Speter wanted &= ~APR_FINFO_LINK; 302251875Speter return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS; 303251875Speter } 304251875Speter else { 305251875Speter#if !defined(ENOENT) || !defined(ENOTDIR) 306251875Speter#error ENOENT || ENOTDIR not defined; please see the 307251875Speter#error comments at this line in the source for a workaround. 308251875Speter /* 309251875Speter * If ENOENT || ENOTDIR is not defined in one of the your OS's 310251875Speter * include files, APR cannot report a good reason why the stat() 311251875Speter * of the file failed; there are cases where it can fail even though 312251875Speter * the file exists. This opens holes in Apache, for example, because 313251875Speter * it becomes possible for someone to get a directory listing of a 314251875Speter * directory even though there is an index (eg. index.html) file in 315251875Speter * it. If you do not have a problem with this, delete the above 316251875Speter * #error lines and start the compile again. If you need to do this, 317251875Speter * please submit a bug report to http://www.apache.org/bug_report.html 318251875Speter * letting us know that you needed to do this. Please be sure to 319251875Speter * include the operating system you are using. 320251875Speter */ 321251875Speter /* WARNING: All errors will be handled as not found 322251875Speter */ 323251875Speter#if !defined(ENOENT) 324251875Speter return APR_ENOENT; 325251875Speter#else 326251875Speter /* WARNING: All errors but not found will be handled as not directory 327251875Speter */ 328251875Speter if (errno != ENOENT) 329251875Speter return APR_ENOENT; 330251875Speter else 331251875Speter return errno; 332251875Speter#endif 333251875Speter#else /* All was defined well, report the usual: */ 334251875Speter return errno; 335251875Speter#endif 336251875Speter } 337251875Speter} 338251875Speter 339251875Speter 340