filestat.c revision 251886
11541Srgrimes/* Licensed to the Apache Software Foundation (ASF) under one or more 21541Srgrimes * contributor license agreements. See the NOTICE file distributed with 31541Srgrimes * this work for additional information regarding copyright ownership. 41541Srgrimes * The ASF licenses this file to You under the Apache License, Version 2.0 51541Srgrimes * (the "License"); you may not use this file except in compliance with 61541Srgrimes * the License. You may obtain a copy of the License at 71541Srgrimes * 81541Srgrimes * http://www.apache.org/licenses/LICENSE-2.0 91541Srgrimes * 101541Srgrimes * Unless required by applicable law or agreed to in writing, software 111541Srgrimes * distributed under the License is distributed on an "AS IS" BASIS, 121541Srgrimes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131541Srgrimes * See the License for the specific language governing permissions and 141541Srgrimes * limitations under the License. 151541Srgrimes */ 161541Srgrimes 171541Srgrimes#include "apr_arch_file_io.h" 181541Srgrimes#include "apr_file_io.h" 191541Srgrimes#include "apr_general.h" 201541Srgrimes#include "apr_strings.h" 211541Srgrimes#include "apr_errno.h" 221541Srgrimes 231541Srgrimes#ifdef HAVE_UTIME 241541Srgrimes#include <utime.h> 251541Srgrimes#endif 261541Srgrimes 271541Srgrimesstatic apr_filetype_e filetype_from_mode(mode_t mode) 281541Srgrimes{ 291541Srgrimes apr_filetype_e type; 301541Srgrimes 311541Srgrimes switch (mode & S_IFMT) { 321541Srgrimes case S_IFREG: 331541Srgrimes type = APR_REG; break; 3450477Speter case S_IFDIR: 351541Srgrimes type = APR_DIR; break; 361541Srgrimes case S_IFLNK: 372169Spaul type = APR_LNK; break; 382169Spaul case S_IFCHR: 392169Spaul type = APR_CHR; break; 40104343Smike case S_IFBLK: 41104343Smike type = APR_BLK; break; 42104342Smike#if defined(S_IFFIFO) 43104342Smike case S_IFFIFO: 4437622Sbde type = APR_PIPE; break; 4537622Sbde#endif 466247Swollman#if !defined(BEOS) && defined(S_IFSOCK) 4755679Sshin case S_IFSOCK: 4855679Sshin type = APR_SOCK; break; 4955679Sshin#endif 501541Srgrimes 511541Srgrimes default: 521541Srgrimes /* Work around missing S_IFxxx values above 531541Srgrimes * for Linux et al. 541541Srgrimes */ 551541Srgrimes#if !defined(S_IFFIFO) && defined(S_ISFIFO) 561541Srgrimes if (S_ISFIFO(mode)) { 571541Srgrimes type = APR_PIPE; 581541Srgrimes } else 598876Srgrimes#endif 6036767Sbde#if !defined(BEOS) && !defined(S_IFSOCK) && defined(S_ISSOCK) 611541Srgrimes if (S_ISSOCK(mode)) { 621541Srgrimes type = APR_SOCK; 638876Srgrimes } else 6436767Sbde#endif 651541Srgrimes type = APR_UNKFILE; 661541Srgrimes } 671541Srgrimes return type; 681541Srgrimes} 691541Srgrimes 701541Srgrimesstatic void fill_out_finfo(apr_finfo_t *finfo, struct_stat *info, 711541Srgrimes apr_int32_t wanted) 721541Srgrimes{ 731541Srgrimes finfo->valid = APR_FINFO_MIN | APR_FINFO_IDENT | APR_FINFO_NLINK 7470826Srwatson | APR_FINFO_OWNER | APR_FINFO_PROT; 7570826Srwatson finfo->protection = apr_unix_mode2perms(info->st_mode); 7670854Srwatson finfo->filetype = filetype_from_mode(info->st_mode); 776348Swollman finfo->user = info->st_uid; 781541Srgrimes finfo->group = info->st_gid; 791541Srgrimes finfo->size = info->st_size; 801541Srgrimes finfo->device = info->st_dev; 811541Srgrimes finfo->nlink = info->st_nlink; 821541Srgrimes 831541Srgrimes /* Check for overflow if storing a 64-bit st_ino in a 32-bit 841541Srgrimes * apr_ino_t for LFS builds: */ 851541Srgrimes if (sizeof(apr_ino_t) >= sizeof(info->st_ino) 861541Srgrimes || (apr_ino_t)info->st_ino == info->st_ino) { 871541Srgrimes finfo->inode = info->st_ino; 881541Srgrimes } else { 891541Srgrimes finfo->valid &= ~APR_FINFO_INODE; 901541Srgrimes } 911541Srgrimes 921541Srgrimes apr_time_ansi_put(&finfo->atime, info->st_atime); 931541Srgrimes#ifdef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC 941541Srgrimes finfo->atime += info->st_atim.tv_nsec / APR_TIME_C(1000); 956247Swollman#elif defined(HAVE_STRUCT_STAT_ST_ATIMENSEC) 961541Srgrimes finfo->atime += info->st_atimensec / APR_TIME_C(1000); 971541Srgrimes#elif defined(HAVE_STRUCT_STAT_ST_ATIME_N) 986247Swollman finfo->ctime += info->st_atime_n / APR_TIME_C(1000); 996247Swollman#endif 1006247Swollman 1016247Swollman apr_time_ansi_put(&finfo->mtime, info->st_mtime); 1026247Swollman#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 1036247Swollman finfo->mtime += info->st_mtim.tv_nsec / APR_TIME_C(1000); 1046247Swollman#elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC) 1056247Swollman finfo->mtime += info->st_mtimensec / APR_TIME_C(1000); 1061541Srgrimes#elif defined(HAVE_STRUCT_STAT_ST_MTIME_N) 1071541Srgrimes finfo->ctime += info->st_mtime_n / APR_TIME_C(1000); 108124258Sandre#endif 1091541Srgrimes 1101541Srgrimes apr_time_ansi_put(&finfo->ctime, info->st_ctime); 1111541Srgrimes#ifdef HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC 1121541Srgrimes finfo->ctime += info->st_ctim.tv_nsec / APR_TIME_C(1000); 113124258Sandre#elif defined(HAVE_STRUCT_STAT_ST_CTIMENSEC) 114124290Sandre finfo->ctime += info->st_ctimensec / APR_TIME_C(1000); 115124290Sandre#elif defined(HAVE_STRUCT_STAT_ST_CTIME_N) 116124258Sandre finfo->ctime += info->st_ctime_n / APR_TIME_C(1000); 117124258Sandre#endif 118124258Sandre 119124258Sandre#ifdef HAVE_STRUCT_STAT_ST_BLOCKS 120124258Sandre#ifdef DEV_BSIZE 121124290Sandre finfo->csize = (apr_off_t)info->st_blocks * (apr_off_t)DEV_BSIZE; 122124258Sandre#else 123124258Sandre finfo->csize = (apr_off_t)info->st_blocks * (apr_off_t)512; 124124258Sandre#endif 125124258Sandre finfo->valid |= APR_FINFO_CSIZE; 126124258Sandre#endif 127124258Sandre} 128124258Sandre 129124437Sandreapr_status_t apr_file_info_get_locked(apr_finfo_t *finfo, apr_int32_t wanted, 1301541Srgrimes apr_file_t *thefile) 13152904Sshin{ 13252904Sshin struct_stat info; 13352904Sshin 13452904Sshin if (thefile->buffered) { 13552904Sshin apr_status_t rv = apr_file_flush_locked(thefile); 13652904Sshin if (rv != APR_SUCCESS) 13752904Sshin return rv; 13852904Sshin } 1391541Srgrimes 1406247Swollman if (fstat(thefile->filedes, &info) == 0) { 1411541Srgrimes finfo->pool = thefile->pool; 1421541Srgrimes finfo->fname = thefile->fname; 1431541Srgrimes fill_out_finfo(finfo, &info, wanted); 14460067Sjlemon return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS; 14560067Sjlemon } 1466247Swollman else { 1476247Swollman return errno; 1486247Swollman } 149104342Smike} 1506247Swollman 1511541SrgrimesAPR_DECLARE(apr_status_t) apr_file_info_get(apr_finfo_t *finfo, 1521541Srgrimes apr_int32_t wanted, 1531541Srgrimes apr_file_t *thefile) 1541541Srgrimes{ 155104342Smike struct_stat info; 1561541Srgrimes 1576247Swollman if (thefile->buffered) { 1586247Swollman apr_status_t rv = apr_file_flush(thefile); 159104342Smike if (rv != APR_SUCCESS) 1602169Spaul return rv; 161104342Smike } 162 163 if (fstat(thefile->filedes, &info) == 0) { 164 finfo->pool = thefile->pool; 165 finfo->fname = thefile->fname; 166 fill_out_finfo(finfo, &info, wanted); 167 return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS; 168 } 169 else { 170 return errno; 171 } 172} 173 174APR_DECLARE(apr_status_t) apr_file_perms_set(const char *fname, 175 apr_fileperms_t perms) 176{ 177 mode_t mode = apr_unix_perms2mode(perms); 178 179 if (chmod(fname, mode) == -1) 180 return errno; 181 return APR_SUCCESS; 182} 183 184APR_DECLARE(apr_status_t) apr_file_attrs_set(const char *fname, 185 apr_fileattrs_t attributes, 186 apr_fileattrs_t attr_mask, 187 apr_pool_t *pool) 188{ 189 apr_status_t status; 190 apr_finfo_t finfo; 191 192 /* Don't do anything if we can't handle the requested attributes */ 193 if (!(attr_mask & (APR_FILE_ATTR_READONLY 194 | APR_FILE_ATTR_EXECUTABLE))) 195 return APR_SUCCESS; 196 197 status = apr_stat(&finfo, fname, APR_FINFO_PROT, pool); 198 if (status) 199 return status; 200 201 /* ### TODO: should added bits be umask'd? */ 202 if (attr_mask & APR_FILE_ATTR_READONLY) 203 { 204 if (attributes & APR_FILE_ATTR_READONLY) 205 { 206 finfo.protection &= ~APR_UWRITE; 207 finfo.protection &= ~APR_GWRITE; 208 finfo.protection &= ~APR_WWRITE; 209 } 210 else 211 { 212 /* ### umask this! */ 213 finfo.protection |= APR_UWRITE; 214 finfo.protection |= APR_GWRITE; 215 finfo.protection |= APR_WWRITE; 216 } 217 } 218 219 if (attr_mask & APR_FILE_ATTR_EXECUTABLE) 220 { 221 if (attributes & APR_FILE_ATTR_EXECUTABLE) 222 { 223 /* ### umask this! */ 224 finfo.protection |= APR_UEXECUTE; 225 finfo.protection |= APR_GEXECUTE; 226 finfo.protection |= APR_WEXECUTE; 227 } 228 else 229 { 230 finfo.protection &= ~APR_UEXECUTE; 231 finfo.protection &= ~APR_GEXECUTE; 232 finfo.protection &= ~APR_WEXECUTE; 233 } 234 } 235 236 return apr_file_perms_set(fname, finfo.protection); 237} 238 239 240APR_DECLARE(apr_status_t) apr_file_mtime_set(const char *fname, 241 apr_time_t mtime, 242 apr_pool_t *pool) 243{ 244 apr_status_t status; 245 apr_finfo_t finfo; 246 247 status = apr_stat(&finfo, fname, APR_FINFO_ATIME, pool); 248 if (status) { 249 return status; 250 } 251 252#ifdef HAVE_UTIMES 253 { 254 struct timeval tvp[2]; 255 256 tvp[0].tv_sec = apr_time_sec(finfo.atime); 257 tvp[0].tv_usec = apr_time_usec(finfo.atime); 258 tvp[1].tv_sec = apr_time_sec(mtime); 259 tvp[1].tv_usec = apr_time_usec(mtime); 260 261 if (utimes(fname, tvp) == -1) { 262 return errno; 263 } 264 } 265#elif defined(HAVE_UTIME) 266 { 267 struct utimbuf buf; 268 269 buf.actime = (time_t) (finfo.atime / APR_USEC_PER_SEC); 270 buf.modtime = (time_t) (mtime / APR_USEC_PER_SEC); 271 272 if (utime(fname, &buf) == -1) { 273 return errno; 274 } 275 } 276#else 277 return APR_ENOTIMPL; 278#endif 279 280 return APR_SUCCESS; 281} 282 283 284APR_DECLARE(apr_status_t) apr_stat(apr_finfo_t *finfo, 285 const char *fname, 286 apr_int32_t wanted, apr_pool_t *pool) 287{ 288 struct_stat info; 289 int srv; 290 291 if (wanted & APR_FINFO_LINK) 292 srv = lstat(fname, &info); 293 else 294 srv = stat(fname, &info); 295 296 if (srv == 0) { 297 finfo->pool = pool; 298 finfo->fname = fname; 299 fill_out_finfo(finfo, &info, wanted); 300 if (wanted & APR_FINFO_LINK) 301 wanted &= ~APR_FINFO_LINK; 302 return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS; 303 } 304 else { 305#if !defined(ENOENT) || !defined(ENOTDIR) 306#error ENOENT || ENOTDIR not defined; please see the 307#error comments at this line in the source for a workaround. 308 /* 309 * If ENOENT || ENOTDIR is not defined in one of the your OS's 310 * include files, APR cannot report a good reason why the stat() 311 * of the file failed; there are cases where it can fail even though 312 * the file exists. This opens holes in Apache, for example, because 313 * it becomes possible for someone to get a directory listing of a 314 * directory even though there is an index (eg. index.html) file in 315 * it. If you do not have a problem with this, delete the above 316 * #error lines and start the compile again. If you need to do this, 317 * please submit a bug report to http://www.apache.org/bug_report.html 318 * letting us know that you needed to do this. Please be sure to 319 * include the operating system you are using. 320 */ 321 /* WARNING: All errors will be handled as not found 322 */ 323#if !defined(ENOENT) 324 return APR_ENOENT; 325#else 326 /* WARNING: All errors but not found will be handled as not directory 327 */ 328 if (errno != ENOENT) 329 return APR_ENOENT; 330 else 331 return errno; 332#endif 333#else /* All was defined well, report the usual: */ 334 return errno; 335#endif 336 } 337} 338 339 340