diff options
Diffstat (limited to 'src/os/os_open.c')
-rw-r--r-- | src/os/os_open.c | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/src/os/os_open.c b/src/os/os_open.c new file mode 100644 index 00000000..5090c8e1 --- /dev/null +++ b/src/os/os_open.c @@ -0,0 +1,162 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 2012 Oracle and/or its affiliates. All rights reserved. + * + * $Id$ + */ + +#include "db_config.h" + +#include "db_int.h" + +/* + * __os_open -- + * Open a file descriptor (including page size and log size information). + * + * PUBLIC: int __os_open __P((ENV *, + * PUBLIC: const char *, u_int32_t, u_int32_t, int, DB_FH **)); + */ +int +__os_open(env, name, page_size, flags, mode, fhpp) + ENV *env; + const char *name; + u_int32_t page_size, flags; + int mode; + DB_FH **fhpp; +{ + DB_ENV *dbenv; + DB_FH *fhp; + int oflags, ret; + + COMPQUIET(page_size, 0); + + dbenv = env == NULL ? NULL : env->dbenv; + *fhpp = NULL; + oflags = 0; + + if (dbenv != NULL && + FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS | DB_VERB_FILEOPS_ALL)) + __db_msg(env, DB_STR_A("0152", + "fileops: open %s", "%s"), name); + +#undef OKFLAGS +#define OKFLAGS \ + (DB_OSO_ABSMODE | DB_OSO_CREATE | DB_OSO_DIRECT | DB_OSO_DSYNC |\ + DB_OSO_EXCL | DB_OSO_RDONLY | DB_OSO_REGION | DB_OSO_SEQ | \ + DB_OSO_TEMP | DB_OSO_TRUNC) + if ((ret = __db_fchk(env, "__os_open", flags, OKFLAGS)) != 0) + return (ret); + +#if defined(O_BINARY) + /* + * If there's a binary-mode open flag, set it, we never want any + * kind of translation. Some systems do translations by default, + * e.g., with Cygwin, the default mode for an open() is set by the + * mode of the mount that underlies the file. + */ + oflags |= O_BINARY; +#endif + + /* + * DB requires the POSIX 1003.1 semantic that two files opened at the + * same time with DB_OSO_CREATE/O_CREAT and DB_OSO_EXCL/O_EXCL flags + * set return an EEXIST failure in at least one. + */ + if (LF_ISSET(DB_OSO_CREATE)) + oflags |= O_CREAT; + + if (LF_ISSET(DB_OSO_EXCL)) + oflags |= O_EXCL; + +#ifdef HAVE_O_DIRECT + if (LF_ISSET(DB_OSO_DIRECT)) + oflags |= O_DIRECT; +#endif +#ifdef O_DSYNC + if (LF_ISSET(DB_OSO_DSYNC)) + oflags |= O_DSYNC; +#endif + + if (LF_ISSET(DB_OSO_RDONLY)) + oflags |= O_RDONLY; + else + oflags |= O_RDWR; + + if (LF_ISSET(DB_OSO_TRUNC)) + oflags |= O_TRUNC; + + /* + * Undocumented feature: allow applications to create intermediate + * directories whenever a file is opened. + */ + if (dbenv != NULL && + env->dir_mode != 0 && LF_ISSET(DB_OSO_CREATE) && + (ret = __db_mkpath(env, name)) != 0) + return (ret); + + /* Open the file. */ +#ifdef HAVE_QNX + if (LF_ISSET(DB_OSO_REGION)) + ret = __os_qnx_region_open(env, name, oflags, mode, &fhp); + else +#endif + ret = __os_openhandle(env, name, oflags, mode, &fhp); + if (ret != 0) + return (ret); + + if (LF_ISSET(DB_OSO_REGION)) + F_SET(fhp, DB_FH_REGION); +#ifdef HAVE_FCHMOD + /* + * If the code using Berkeley DB is a library, that code may not be able + * to control the application's umask value. Allow applications to set + * absolute file modes. We can't fix the race between file creation and + * the fchmod call -- we can't modify the process' umask here since the + * process may be multi-threaded and the umask value is per-process, not + * per-thread. + */ + if (LF_ISSET(DB_OSO_CREATE) && LF_ISSET(DB_OSO_ABSMODE)) + (void)fchmod(fhp->fd, mode); +#endif + +#ifdef O_DSYNC + /* + * If we can configure the file descriptor to flush on write, the + * file descriptor does not need to be explicitly sync'd. + */ + if (LF_ISSET(DB_OSO_DSYNC)) + F_SET(fhp, DB_FH_NOSYNC); +#endif + +#if defined(HAVE_DIRECTIO) && defined(DIRECTIO_ON) + /* + * The Solaris C library includes directio, but you have to set special + * compile flags to #define DIRECTIO_ON. Require both in order to call + * directio. + */ + if (LF_ISSET(DB_OSO_DIRECT)) + (void)directio(fhp->fd, DIRECTIO_ON); +#endif + + /* + * Delete any temporary file. + * + * !!! + * There's a race here, where we've created a file and we crash before + * we can unlink it. Temporary files aren't common in DB, regardless, + * it's not a security problem because the file is empty. There's no + * reasonable way to avoid the race (playing signal games isn't worth + * the portability nightmare), so we just live with it. + */ + if (LF_ISSET(DB_OSO_TEMP)) { +#if defined(HAVE_UNLINK_WITH_OPEN_FAILURE) || defined(CONFIG_TEST) + F_SET(fhp, DB_FH_UNLINK); +#else + (void)__os_unlink(env, name, 0); +#endif + } + + *fhpp = fhp; + return (0); +} |