1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1997,2008 Oracle.  All rights reserved.
5 *
6 * $Id: os_open.c,v 12.29 2008/03/26 04:11:35 david Exp $
7 */
8
9#include "db_config.h"
10
11#include "db_int.h"
12
13/*
14 * __os_open --
15 *	Open a file descriptor (including page size and log size information).
16 *
17 * PUBLIC: int __os_open __P((ENV *,
18 * PUBLIC:     const char *, u_int32_t, u_int32_t, int, DB_FH **));
19 */
20int
21__os_open(env, name, page_size, flags, mode, fhpp)
22	ENV *env;
23	const char *name;
24	u_int32_t page_size, flags;
25	int mode;
26	DB_FH **fhpp;
27{
28	DB_ENV *dbenv;
29	DB_FH *fhp;
30	int oflags, ret;
31
32	COMPQUIET(page_size, 0);
33
34	dbenv = env == NULL ? NULL : env->dbenv;
35	*fhpp = NULL;
36	oflags = 0;
37
38	if (dbenv != NULL &&
39	    FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS | DB_VERB_FILEOPS_ALL))
40		__db_msg(env, "fileops: open %s", name);
41
42#define	OKFLAGS								\
43	(DB_OSO_ABSMODE | DB_OSO_CREATE | DB_OSO_DIRECT | DB_OSO_DSYNC |\
44	DB_OSO_EXCL | DB_OSO_RDONLY | DB_OSO_REGION | DB_OSO_SEQ |	\
45	DB_OSO_TEMP | DB_OSO_TRUNC)
46	if ((ret = __db_fchk(env, "__os_open", flags, OKFLAGS)) != 0)
47		return (ret);
48
49#if defined(O_BINARY)
50	/*
51	 * If there's a binary-mode open flag, set it, we never want any
52	 * kind of translation.  Some systems do translations by default,
53	 * e.g., with Cygwin, the default mode for an open() is set by the
54	 * mode of the mount that underlies the file.
55	 */
56	oflags |= O_BINARY;
57#endif
58
59	/*
60	 * DB requires the POSIX 1003.1 semantic that two files opened at the
61	 * same time with DB_OSO_CREATE/O_CREAT and DB_OSO_EXCL/O_EXCL flags
62	 * set return an EEXIST failure in at least one.
63	 */
64	if (LF_ISSET(DB_OSO_CREATE))
65		oflags |= O_CREAT;
66
67	if (LF_ISSET(DB_OSO_EXCL))
68		oflags |= O_EXCL;
69
70#ifdef HAVE_O_DIRECT
71	if (LF_ISSET(DB_OSO_DIRECT))
72		oflags |= O_DIRECT;
73#endif
74#ifdef O_DSYNC
75	if (LF_ISSET(DB_OSO_DSYNC))
76		oflags |= O_DSYNC;
77#endif
78
79	if (LF_ISSET(DB_OSO_RDONLY))
80		oflags |= O_RDONLY;
81	else
82		oflags |= O_RDWR;
83
84	if (LF_ISSET(DB_OSO_TRUNC))
85		oflags |= O_TRUNC;
86
87	/*
88	 * Undocumented feature: allow applications to create intermediate
89	 * directories whenever a file is opened.
90	 */
91	if (dbenv != NULL &&
92	    env->dir_mode != 0 && LF_ISSET(DB_OSO_CREATE) &&
93	    (ret = __db_mkpath(env, name)) != 0)
94		return (ret);
95
96	/* Open the file. */
97#ifdef HAVE_QNX
98	if (LF_ISSET(DB_OSO_REGION))
99		ret = __os_qnx_region_open(env, name, oflags, mode, &fhp);
100	else
101#endif
102	ret = __os_openhandle(env, name, oflags, mode, &fhp);
103	if (ret != 0)
104		return (ret);
105
106	if (LF_ISSET(DB_OSO_REGION))
107		F_SET(fhp, DB_FH_REGION);
108#ifdef HAVE_FCHMOD
109	/*
110	 * If the code using Berkeley DB is a library, that code may not be able
111	 * to control the application's umask value.  Allow applications to set
112	 * absolute file modes.  We can't fix the race between file creation and
113	 * the fchmod call -- we can't modify the process' umask here since the
114	 * process may be multi-threaded and the umask value is per-process, not
115	 * per-thread.
116	 */
117	if (LF_ISSET(DB_OSO_CREATE) && LF_ISSET(DB_OSO_ABSMODE))
118		(void)fchmod(fhp->fd, mode);
119#endif
120
121#ifdef O_DSYNC
122	/*
123	 * If we can configure the file descriptor to flush on write, the
124	 * file descriptor does not need to be explicitly sync'd.
125	 */
126	if (LF_ISSET(DB_OSO_DSYNC))
127		F_SET(fhp, DB_FH_NOSYNC);
128#endif
129
130#if defined(HAVE_DIRECTIO) && defined(DIRECTIO_ON)
131	/*
132	 * The Solaris C library includes directio, but you have to set special
133	 * compile flags to #define DIRECTIO_ON.  Require both in order to call
134	 * directio.
135	 */
136	if (LF_ISSET(DB_OSO_DIRECT))
137		(void)directio(fhp->fd, DIRECTIO_ON);
138#endif
139
140	/*
141	 * Delete any temporary file.
142	 *
143	 * !!!
144	 * There's a race here, where we've created a file and we crash before
145	 * we can unlink it.  Temporary files aren't common in DB, regardless,
146	 * it's not a security problem because the file is empty.  There's no
147	 * reasonable way to avoid the race (playing signal games isn't worth
148	 * the portability nightmare), so we just live with it.
149	 */
150	if (LF_ISSET(DB_OSO_TEMP)) {
151#if defined(HAVE_UNLINK_WITH_OPEN_FAILURE) || defined(CONFIG_TEST)
152		F_SET(fhp, DB_FH_UNLINK);
153#else
154		(void)__os_unlink(env, name, 0);
155#endif
156	}
157
158	*fhpp = fhp;
159	return (0);
160}
161