open.c revision 269847
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_strings.h" 19#include "apr_portable.h" 20#include "apr_thread_mutex.h" 21#include "apr_arch_inherit.h" 22 23#ifdef NETWARE 24#include "nks/dirio.h" 25#include "apr_hash.h" 26#include "fsio.h" 27#endif 28 29static apr_status_t file_cleanup(apr_file_t *file, int is_child) 30{ 31 apr_status_t rv = APR_SUCCESS; 32 int fd = file->filedes; 33 34 /* Set file descriptor to -1 before close(), so that there is no 35 * chance of returning an already closed FD from apr_os_file_get(). 36 */ 37 file->filedes = -1; 38 39 if (close(fd) == 0) { 40 /* Only the parent process should delete the file! */ 41 if (!is_child && (file->flags & APR_FOPEN_DELONCLOSE)) { 42 unlink(file->fname); 43 } 44#if APR_HAS_THREADS 45 if (file->thlock) { 46 rv = apr_thread_mutex_destroy(file->thlock); 47 } 48#endif 49 } 50 else { 51 /* Restore, close() was not successful. */ 52 file->filedes = fd; 53 54 /* Are there any error conditions other than EINTR or EBADF? */ 55 rv = errno; 56 } 57#ifndef WAITIO_USES_POLL 58 if (file->pollset != NULL) { 59 apr_status_t pollset_rv = apr_pollset_destroy(file->pollset); 60 /* If the file close failed, return its error value, 61 * not apr_pollset_destroy()'s. 62 */ 63 if (rv == APR_SUCCESS) { 64 rv = pollset_rv; 65 } 66 } 67#endif /* !WAITIO_USES_POLL */ 68 return rv; 69} 70 71apr_status_t apr_unix_file_cleanup(void *thefile) 72{ 73 apr_file_t *file = thefile; 74 apr_status_t flush_rv = APR_SUCCESS, rv = APR_SUCCESS; 75 76 if (file->buffered) { 77 flush_rv = apr_file_flush(file); 78 } 79 80 rv = file_cleanup(file, 0); 81 82 return rv != APR_SUCCESS ? rv : flush_rv; 83} 84 85apr_status_t apr_unix_child_file_cleanup(void *thefile) 86{ 87 return file_cleanup(thefile, 1); 88} 89 90APR_DECLARE(apr_status_t) apr_file_open(apr_file_t **new, 91 const char *fname, 92 apr_int32_t flag, 93 apr_fileperms_t perm, 94 apr_pool_t *pool) 95{ 96 apr_os_file_t fd; 97 int oflags = 0; 98#if APR_HAS_THREADS 99 apr_thread_mutex_t *thlock; 100 apr_status_t rv; 101#endif 102 103 if ((flag & APR_FOPEN_READ) && (flag & APR_FOPEN_WRITE)) { 104 oflags = O_RDWR; 105 } 106 else if (flag & APR_FOPEN_READ) { 107 oflags = O_RDONLY; 108 } 109 else if (flag & APR_FOPEN_WRITE) { 110 oflags = O_WRONLY; 111 } 112 else { 113 return APR_EACCES; 114 } 115 116 if (flag & APR_FOPEN_CREATE) { 117 oflags |= O_CREAT; 118 if (flag & APR_FOPEN_EXCL) { 119 oflags |= O_EXCL; 120 } 121 } 122 if ((flag & APR_FOPEN_EXCL) && !(flag & APR_FOPEN_CREATE)) { 123 return APR_EACCES; 124 } 125 126 if (flag & APR_FOPEN_APPEND) { 127 oflags |= O_APPEND; 128 } 129 if (flag & APR_FOPEN_TRUNCATE) { 130 oflags |= O_TRUNC; 131 } 132#ifdef O_BINARY 133 if (flag & APR_FOPEN_BINARY) { 134 oflags |= O_BINARY; 135 } 136#endif 137 138 if (flag & APR_FOPEN_NONBLOCK) { 139#ifdef O_NONBLOCK 140 oflags |= O_NONBLOCK; 141#else 142 return APR_ENOTIMPL; 143#endif 144 } 145 146#ifdef O_CLOEXEC 147 /* Introduced in Linux 2.6.23. Silently ignored on earlier Linux kernels. 148 */ 149 if (!(flag & APR_FOPEN_NOCLEANUP)) { 150 oflags |= O_CLOEXEC; 151} 152#endif 153 154#if APR_HAS_LARGE_FILES && defined(_LARGEFILE64_SOURCE) 155 oflags |= O_LARGEFILE; 156#elif defined(O_LARGEFILE) 157 if (flag & APR_FOPEN_LARGEFILE) { 158 oflags |= O_LARGEFILE; 159 } 160#endif 161 162#if APR_HAS_THREADS 163 if ((flag & APR_FOPEN_BUFFERED) && (flag & APR_FOPEN_XTHREAD)) { 164 rv = apr_thread_mutex_create(&thlock, 165 APR_THREAD_MUTEX_DEFAULT, pool); 166 if (rv) { 167 return rv; 168 } 169 } 170#endif 171 172 if (perm == APR_OS_DEFAULT) { 173 fd = open(fname, oflags, 0666); 174 } 175 else { 176 fd = open(fname, oflags, apr_unix_perms2mode(perm)); 177 } 178 if (fd < 0) { 179 return errno; 180 } 181 if (!(flag & APR_FOPEN_NOCLEANUP)) { 182#ifdef O_CLOEXEC 183 static int has_o_cloexec = 0; 184 if (!has_o_cloexec) 185#endif 186 { 187 int flags; 188 189 if ((flags = fcntl(fd, F_GETFD)) == -1) { 190 close(fd); 191 return errno; 192 } 193 if ((flags & FD_CLOEXEC) == 0) { 194 flags |= FD_CLOEXEC; 195 if (fcntl(fd, F_SETFD, flags) == -1) { 196 close(fd); 197 return errno; 198 } 199 } 200#ifdef O_CLOEXEC 201 else { 202 has_o_cloexec = 1; 203 } 204#endif 205 } 206 } 207 208 (*new) = (apr_file_t *)apr_pcalloc(pool, sizeof(apr_file_t)); 209 (*new)->pool = pool; 210 (*new)->flags = flag; 211 (*new)->filedes = fd; 212 213 (*new)->fname = apr_pstrdup(pool, fname); 214 215 (*new)->blocking = BLK_ON; 216 (*new)->buffered = (flag & APR_FOPEN_BUFFERED) > 0; 217 218 if ((*new)->buffered) { 219 (*new)->buffer = apr_palloc(pool, APR_FILE_DEFAULT_BUFSIZE); 220 (*new)->bufsize = APR_FILE_DEFAULT_BUFSIZE; 221#if APR_HAS_THREADS 222 if ((*new)->flags & APR_FOPEN_XTHREAD) { 223 (*new)->thlock = thlock; 224 } 225#endif 226 } 227 else { 228 (*new)->buffer = NULL; 229 } 230 231 (*new)->is_pipe = 0; 232 (*new)->timeout = -1; 233 (*new)->ungetchar = -1; 234 (*new)->eof_hit = 0; 235 (*new)->filePtr = 0; 236 (*new)->bufpos = 0; 237 (*new)->dataRead = 0; 238 (*new)->direction = 0; 239#ifndef WAITIO_USES_POLL 240 /* Start out with no pollset. apr_wait_for_io_or_timeout() will 241 * initialize the pollset if needed. 242 */ 243 (*new)->pollset = NULL; 244#endif 245 if (!(flag & APR_FOPEN_NOCLEANUP)) { 246 apr_pool_cleanup_register((*new)->pool, (void *)(*new), 247 apr_unix_file_cleanup, 248 apr_unix_child_file_cleanup); 249 } 250 return APR_SUCCESS; 251} 252 253APR_DECLARE(apr_status_t) apr_file_close(apr_file_t *file) 254{ 255 return apr_pool_cleanup_run(file->pool, file, apr_unix_file_cleanup); 256} 257 258APR_DECLARE(apr_status_t) apr_file_remove(const char *path, apr_pool_t *pool) 259{ 260 if (unlink(path) == 0) { 261 return APR_SUCCESS; 262 } 263 else { 264 return errno; 265 } 266} 267 268APR_DECLARE(apr_status_t) apr_file_rename(const char *from_path, 269 const char *to_path, 270 apr_pool_t *p) 271{ 272 if (rename(from_path, to_path) != 0) { 273 return errno; 274 } 275 return APR_SUCCESS; 276} 277 278APR_DECLARE(apr_status_t) apr_os_file_get(apr_os_file_t *thefile, 279 apr_file_t *file) 280{ 281 *thefile = file->filedes; 282 return APR_SUCCESS; 283} 284 285APR_DECLARE(apr_status_t) apr_os_file_put(apr_file_t **file, 286 apr_os_file_t *thefile, 287 apr_int32_t flags, apr_pool_t *pool) 288{ 289 int *dafile = thefile; 290 291 (*file) = apr_pcalloc(pool, sizeof(apr_file_t)); 292 (*file)->pool = pool; 293 (*file)->eof_hit = 0; 294 (*file)->blocking = BLK_UNKNOWN; /* in case it is a pipe */ 295 (*file)->timeout = -1; 296 (*file)->ungetchar = -1; /* no char avail */ 297 (*file)->filedes = *dafile; 298 (*file)->flags = flags | APR_FOPEN_NOCLEANUP; 299 (*file)->buffered = (flags & APR_FOPEN_BUFFERED) > 0; 300 301#ifndef WAITIO_USES_POLL 302 /* Start out with no pollset. apr_wait_for_io_or_timeout() will 303 * initialize the pollset if needed. 304 */ 305 (*file)->pollset = NULL; 306#endif 307 308 if ((*file)->buffered) { 309 (*file)->buffer = apr_palloc(pool, APR_FILE_DEFAULT_BUFSIZE); 310 (*file)->bufsize = APR_FILE_DEFAULT_BUFSIZE; 311#if APR_HAS_THREADS 312 if ((*file)->flags & APR_FOPEN_XTHREAD) { 313 apr_status_t rv; 314 rv = apr_thread_mutex_create(&((*file)->thlock), 315 APR_THREAD_MUTEX_DEFAULT, pool); 316 if (rv) { 317 return rv; 318 } 319 } 320#endif 321 } 322 return APR_SUCCESS; 323} 324 325APR_DECLARE(apr_status_t) apr_file_eof(apr_file_t *fptr) 326{ 327 if (fptr->eof_hit == 1) { 328 return APR_EOF; 329 } 330 return APR_SUCCESS; 331} 332 333APR_DECLARE(apr_status_t) apr_file_open_flags_stderr(apr_file_t **thefile, 334 apr_int32_t flags, 335 apr_pool_t *pool) 336{ 337 int fd = STDERR_FILENO; 338 339 return apr_os_file_put(thefile, &fd, flags | APR_FOPEN_WRITE, pool); 340} 341 342APR_DECLARE(apr_status_t) apr_file_open_flags_stdout(apr_file_t **thefile, 343 apr_int32_t flags, 344 apr_pool_t *pool) 345{ 346 int fd = STDOUT_FILENO; 347 348 return apr_os_file_put(thefile, &fd, flags | APR_FOPEN_WRITE, pool); 349} 350 351APR_DECLARE(apr_status_t) apr_file_open_flags_stdin(apr_file_t **thefile, 352 apr_int32_t flags, 353 apr_pool_t *pool) 354{ 355 int fd = STDIN_FILENO; 356 357 return apr_os_file_put(thefile, &fd, flags | APR_FOPEN_READ, pool); 358} 359 360APR_DECLARE(apr_status_t) apr_file_open_stderr(apr_file_t **thefile, 361 apr_pool_t *pool) 362{ 363 return apr_file_open_flags_stderr(thefile, 0, pool); 364} 365 366APR_DECLARE(apr_status_t) apr_file_open_stdout(apr_file_t **thefile, 367 apr_pool_t *pool) 368{ 369 return apr_file_open_flags_stdout(thefile, 0, pool); 370} 371 372APR_DECLARE(apr_status_t) apr_file_open_stdin(apr_file_t **thefile, 373 apr_pool_t *pool) 374{ 375 return apr_file_open_flags_stdin(thefile, 0, pool); 376} 377 378APR_IMPLEMENT_INHERIT_SET(file, flags, pool, apr_unix_file_cleanup) 379 380/* We need to do this by hand instead of using APR_IMPLEMENT_INHERIT_UNSET 381 * because the macro sets both cleanups to the same function, which is not 382 * suitable on Unix (see PR 41119). */ 383APR_DECLARE(apr_status_t) apr_file_inherit_unset(apr_file_t *thefile) 384{ 385 if (thefile->flags & APR_FOPEN_NOCLEANUP) { 386 return APR_EINVAL; 387 } 388 if (thefile->flags & APR_INHERIT) { 389 int flags; 390 391 if ((flags = fcntl(thefile->filedes, F_GETFD)) == -1) 392 return errno; 393 394 flags |= FD_CLOEXEC; 395 if (fcntl(thefile->filedes, F_SETFD, flags) == -1) 396 return errno; 397 398 thefile->flags &= ~APR_INHERIT; 399 apr_pool_child_cleanup_set(thefile->pool, 400 (void *)thefile, 401 apr_unix_file_cleanup, 402 apr_unix_child_file_cleanup); 403 } 404 return APR_SUCCESS; 405} 406 407APR_POOL_IMPLEMENT_ACCESSOR(file) 408 409APR_DECLARE(apr_status_t) apr_file_link(const char *from_path, 410 const char *to_path) 411{ 412 if (link(from_path, to_path) == -1) { 413 return errno; 414 } 415 416 return APR_SUCCESS; 417} 418