1/* Licensed to the Apache Software Foundation (ASF) under one or more 2 * contributor license agreements. See the NOTICE file distributed with 3 * this work for additional information regarding copyright ownership. 4 * The ASF licenses this file to You under the Apache License, Version 2.0 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "apr_arch_file_io.h" 18#include "apr_file_io.h" 19#include "apr_general.h" 20#include "apr_strings.h" 21#include "apr_errno.h" 22 23#ifdef HAVE_UTIME 24#include <utime.h> 25#endif 26 27#ifdef __DARWIN_APR_BUILDING_32_BIT_INODE 28__private_extern__ apr_filetype_e filetype_from_mode(mode_t mode); 29#else /* !__DARWIN_APR_BUILDING_32_BIT_INODE */ 30__private_extern__ apr_filetype_e filetype_from_mode(mode_t mode) 31{ 32 apr_filetype_e type; 33 34 switch (mode & S_IFMT) { 35 case S_IFREG: 36 type = APR_REG; break; 37 case S_IFDIR: 38 type = APR_DIR; break; 39 case S_IFLNK: 40 type = APR_LNK; break; 41 case S_IFCHR: 42 type = APR_CHR; break; 43 case S_IFBLK: 44 type = APR_BLK; break; 45#if defined(S_IFFIFO) 46 case S_IFFIFO: 47 type = APR_PIPE; break; 48#endif 49#if !defined(BEOS) && defined(S_IFSOCK) 50 case S_IFSOCK: 51 type = APR_SOCK; break; 52#endif 53 54 default: 55 /* Work around missing S_IFxxx values above 56 * for Linux et al. 57 */ 58#if !defined(S_IFFIFO) && defined(S_ISFIFO) 59 if (S_ISFIFO(mode)) { 60 type = APR_PIPE; 61 } else 62#endif 63#if !defined(BEOS) && !defined(S_IFSOCK) && defined(S_ISSOCK) 64 if (S_ISSOCK(mode)) { 65 type = APR_SOCK; 66 } else 67#endif 68 type = APR_UNKFILE; 69 } 70 return type; 71} 72#endif /* __DARWIN_APR_BUILDING_32_BIT_INODE */ 73 74static void fill_out_finfo(apr_finfo_t *finfo, struct_stat *info, 75 apr_int32_t wanted) 76{ 77 finfo->valid = APR_FINFO_MIN | APR_FINFO_IDENT | APR_FINFO_NLINK 78 | APR_FINFO_OWNER | APR_FINFO_PROT; 79 finfo->protection = apr_unix_mode2perms(info->st_mode); 80 finfo->filetype = filetype_from_mode(info->st_mode); 81 finfo->user = info->st_uid; 82 finfo->group = info->st_gid; 83 finfo->size = info->st_size; 84 finfo->device = info->st_dev; 85 finfo->nlink = info->st_nlink; 86 87 /* Check for overflow if storing a 64-bit st_ino in a 32-bit 88 * apr_ino_t for LFS builds: */ 89 if (sizeof(apr_ino_t) >= sizeof(info->st_ino) 90 || (apr_ino_t)info->st_ino == info->st_ino) { 91 finfo->inode = info->st_ino; 92 } else { 93 finfo->valid &= ~APR_FINFO_INODE; 94 } 95 96 apr_time_ansi_put(&finfo->atime, info->st_atime); 97#ifdef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC 98 finfo->atime += info->st_atim.tv_nsec / APR_TIME_C(1000); 99#elif defined(HAVE_STRUCT_STAT_ST_ATIMENSEC) 100 finfo->atime += info->st_atimensec / APR_TIME_C(1000); 101#elif defined(HAVE_STRUCT_STAT_ST_ATIME_N) 102 finfo->ctime += info->st_atime_n / APR_TIME_C(1000); 103#endif 104 105 apr_time_ansi_put(&finfo->mtime, info->st_mtime); 106#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 107 finfo->mtime += info->st_mtim.tv_nsec / APR_TIME_C(1000); 108#elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC) 109 finfo->mtime += info->st_mtimensec / APR_TIME_C(1000); 110#elif defined(HAVE_STRUCT_STAT_ST_MTIME_N) 111 finfo->ctime += info->st_mtime_n / APR_TIME_C(1000); 112#endif 113 114 apr_time_ansi_put(&finfo->ctime, info->st_ctime); 115#ifdef HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC 116 finfo->ctime += info->st_ctim.tv_nsec / APR_TIME_C(1000); 117#elif defined(HAVE_STRUCT_STAT_ST_CTIMENSEC) 118 finfo->ctime += info->st_ctimensec / APR_TIME_C(1000); 119#elif defined(HAVE_STRUCT_STAT_ST_CTIME_N) 120 finfo->ctime += info->st_ctime_n / APR_TIME_C(1000); 121#endif 122 123#ifdef HAVE_STRUCT_STAT_ST_BLOCKS 124#ifdef DEV_BSIZE 125 finfo->csize = (apr_off_t)info->st_blocks * (apr_off_t)DEV_BSIZE; 126#else 127 finfo->csize = (apr_off_t)info->st_blocks * (apr_off_t)512; 128#endif 129 finfo->valid |= APR_FINFO_CSIZE; 130#endif 131} 132 133apr_status_t apr_file_info_get_locked(apr_finfo_t *finfo, apr_int32_t wanted, 134 apr_file_t *thefile) 135{ 136 struct_stat info; 137 138 if (thefile->buffered) { 139 apr_status_t rv = apr_file_flush_locked(thefile); 140 if (rv != APR_SUCCESS) 141 return rv; 142 } 143 144 if (fstat(thefile->filedes, &info) == 0) { 145 finfo->pool = thefile->pool; 146 finfo->fname = thefile->fname; 147 fill_out_finfo(finfo, &info, wanted); 148 return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS; 149 } 150 else { 151 return errno; 152 } 153} 154 155APR_DECLARE(apr_status_t) apr_file_info_get(apr_finfo_t *finfo, 156 apr_int32_t wanted, 157 apr_file_t *thefile) 158{ 159 struct_stat info; 160 161 if (thefile->buffered) { 162 apr_status_t rv = apr_file_flush(thefile); 163 if (rv != APR_SUCCESS) 164 return rv; 165 } 166 167 if (fstat(thefile->filedes, &info) == 0) { 168 finfo->pool = thefile->pool; 169 finfo->fname = thefile->fname; 170 fill_out_finfo(finfo, &info, wanted); 171 return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS; 172 } 173 else { 174 return errno; 175 } 176} 177 178#ifndef __DARWIN_APR_BUILDING_32_BIT_INODE 179APR_DECLARE(apr_status_t) apr_file_perms_set(const char *fname, 180 apr_fileperms_t perms) 181{ 182 mode_t mode = apr_unix_perms2mode(perms); 183 184 if (chmod(fname, mode) == -1) 185 return errno; 186 return APR_SUCCESS; 187} 188 189APR_DECLARE(apr_status_t) apr_file_attrs_set(const char *fname, 190 apr_fileattrs_t attributes, 191 apr_fileattrs_t attr_mask, 192 apr_pool_t *pool) 193{ 194 apr_status_t status; 195 apr_finfo_t finfo; 196 197 /* Don't do anything if we can't handle the requested attributes */ 198 if (!(attr_mask & (APR_FILE_ATTR_READONLY 199 | APR_FILE_ATTR_EXECUTABLE))) 200 return APR_SUCCESS; 201 202 status = apr_stat(&finfo, fname, APR_FINFO_PROT, pool); 203 if (status) 204 return status; 205 206 /* ### TODO: should added bits be umask'd? */ 207 if (attr_mask & APR_FILE_ATTR_READONLY) 208 { 209 if (attributes & APR_FILE_ATTR_READONLY) 210 { 211 finfo.protection &= ~APR_UWRITE; 212 finfo.protection &= ~APR_GWRITE; 213 finfo.protection &= ~APR_WWRITE; 214 } 215 else 216 { 217 /* ### umask this! */ 218 finfo.protection |= APR_UWRITE; 219 finfo.protection |= APR_GWRITE; 220 finfo.protection |= APR_WWRITE; 221 } 222 } 223 224 if (attr_mask & APR_FILE_ATTR_EXECUTABLE) 225 { 226 if (attributes & APR_FILE_ATTR_EXECUTABLE) 227 { 228 /* ### umask this! */ 229 finfo.protection |= APR_UEXECUTE; 230 finfo.protection |= APR_GEXECUTE; 231 finfo.protection |= APR_WEXECUTE; 232 } 233 else 234 { 235 finfo.protection &= ~APR_UEXECUTE; 236 finfo.protection &= ~APR_GEXECUTE; 237 finfo.protection &= ~APR_WEXECUTE; 238 } 239 } 240 241 return apr_file_perms_set(fname, finfo.protection); 242} 243 244 245APR_DECLARE(apr_status_t) apr_file_mtime_set(const char *fname, 246 apr_time_t mtime, 247 apr_pool_t *pool) 248{ 249 apr_status_t status; 250 apr_finfo_t finfo; 251 252 status = apr_stat(&finfo, fname, APR_FINFO_ATIME, pool); 253 if (status) { 254 return status; 255 } 256 257#ifdef HAVE_UTIMES 258 { 259 struct timeval tvp[2]; 260 261 tvp[0].tv_sec = apr_time_sec(finfo.atime); 262 tvp[0].tv_usec = apr_time_usec(finfo.atime); 263 tvp[1].tv_sec = apr_time_sec(mtime); 264 tvp[1].tv_usec = apr_time_usec(mtime); 265 266 if (utimes(fname, tvp) == -1) { 267 return errno; 268 } 269 } 270#elif defined(HAVE_UTIME) 271 { 272 struct utimbuf buf; 273 274 buf.actime = (time_t) (finfo.atime / APR_USEC_PER_SEC); 275 buf.modtime = (time_t) (mtime / APR_USEC_PER_SEC); 276 277 if (utime(fname, &buf) == -1) { 278 return errno; 279 } 280 } 281#else 282 return APR_ENOTIMPL; 283#endif 284 285 return APR_SUCCESS; 286} 287#endif /* !__DARWIN_APR_BUILDING_32_BIT_INODE */ 288 289 290APR_DECLARE(apr_status_t) apr_stat(apr_finfo_t *finfo, 291 const char *fname, 292 apr_int32_t wanted, apr_pool_t *pool) 293{ 294 struct_stat info; 295 int srv; 296 297 if (wanted & APR_FINFO_LINK) 298 srv = lstat(fname, &info); 299 else 300 srv = stat(fname, &info); 301 302 if (srv == 0) { 303 finfo->pool = pool; 304 finfo->fname = fname; 305 fill_out_finfo(finfo, &info, wanted); 306 if (wanted & APR_FINFO_LINK) 307 wanted &= ~APR_FINFO_LINK; 308 return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS; 309 } 310 else { 311#if !defined(ENOENT) || !defined(ENOTDIR) 312#error ENOENT || ENOTDIR not defined; please see the 313#error comments at this line in the source for a workaround. 314 /* 315 * If ENOENT || ENOTDIR is not defined in one of the your OS's 316 * include files, APR cannot report a good reason why the stat() 317 * of the file failed; there are cases where it can fail even though 318 * the file exists. This opens holes in Apache, for example, because 319 * it becomes possible for someone to get a directory listing of a 320 * directory even though there is an index (eg. index.html) file in 321 * it. If you do not have a problem with this, delete the above 322 * #error lines and start the compile again. If you need to do this, 323 * please submit a bug report to http://www.apache.org/bug_report.html 324 * letting us know that you needed to do this. Please be sure to 325 * include the operating system you are using. 326 */ 327 /* WARNING: All errors will be handled as not found 328 */ 329#if !defined(ENOENT) 330 return APR_ENOENT; 331#else 332 /* WARNING: All errors but not found will be handled as not directory 333 */ 334 if (errno != ENOENT) 335 return APR_ENOENT; 336 else 337 return errno; 338#endif 339#else /* All was defined well, report the usual: */ 340 return errno; 341#endif 342 } 343} 344 345 346