161 lines
4.1 KiB
C
161 lines
4.1 KiB
C
/*-
|
|
* See the file LICENSE for redistribution information.
|
|
*
|
|
* Copyright (c) 1997,2008 Oracle. All rights reserved.
|
|
*
|
|
* $Id: os_open.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
|
*/
|
|
|
|
#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, "fileops: open %s", name);
|
|
|
|
#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);
|
|
}
|