summaryrefslogtreecommitdiff
path: root/bdb/os/os_handle.c
blob: d85b13a6602fcecbefc44d5b5490f6c18bde79c4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/*-
 * See the file LICENSE for redistribution information.
 *
 * Copyright (c) 1998, 1999, 2000
 *	Sleepycat Software.  All rights reserved.
 */

#include "db_config.h"

#ifndef lint
static const char revid[] = "$Id: os_handle.c,v 11.19 2000/11/30 00:58:42 ubell Exp $";
#endif /* not lint */

#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>

#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#endif

#include "db_int.h"
#include "os_jump.h"

/*
 * __os_openhandle --
 *	Open a file, using POSIX 1003.1 open flags.
 *
 * PUBLIC: int __os_openhandle __P((DB_ENV *, const char *, int, int, DB_FH *));
 */
int
__os_openhandle(dbenv, name, flags, mode, fhp)
	DB_ENV *dbenv;
	const char *name;
	int flags, mode;
	DB_FH *fhp;
{
	int ret, nrepeat;
#ifdef HAVE_VXWORKS
	int newflags;
#endif

	memset(fhp, 0, sizeof(*fhp));

	/* If the application specified an interface, use it. */
	if (__db_jump.j_open != NULL) {
		if ((fhp->fd = __db_jump.j_open(name, flags, mode)) == -1)
			return (__os_get_errno());
		F_SET(fhp, DB_FH_VALID);
		return (0);
	}

	for (ret = 0, nrepeat = 1; nrepeat < 4; ++nrepeat) {
#ifdef	HAVE_VXWORKS
		/*
		 * VxWorks does not support O_CREAT on open, you have to use
		 * creat() instead.  (It does not support O_EXCL or O_TRUNC
		 * either, even though they are defined "for future support".)
		 * If O_EXCL is specified, single thread and try to open the
		 * file.  If successful, return EEXIST.  Otherwise, call creat
		 * and then end single threading.
		 */
		if (LF_ISSET(O_CREAT)) {
			DB_BEGIN_SINGLE_THREAD;
			newflags = flags & ~(O_CREAT | O_EXCL);
			if (LF_ISSET(O_EXCL)) {
				if ((fhp->fd =
				    open(name, newflags, mode)) != -1) {
					/*
					 * If we get here, we want O_EXCL
					 * create, and it exists.  Close and
					 * return EEXISTS.
					 */
					(void)close(fhp->fd);
					DB_END_SINGLE_THREAD;
					return (EEXIST);
				}
				/*
				 * XXX
				 * Assume any error means non-existence.
				 * Unfortunately return values (even for
				 * non-existence) are driver specific so
				 * there is no single error we can use to
				 * verify we truly got the equivalent of
				 * ENOENT.
				 */
			}
			fhp->fd = creat(name, newflags);
			DB_END_SINGLE_THREAD;
		} else

		/* FALLTHROUGH */
#endif
#ifdef __VMS
		/*
		 * !!!
		 * Open with full sharing on VMS.
		 *
		 * We use these flags because they are the ones set by the VMS
		 * CRTL mmap() call when it opens a file, and we have to be
		 * able to open files that mmap() has previously opened, e.g.,
		 * when we're joining already existing DB regions.
		 */
		fhp->fd = open(name, flags, mode, "shr=get,put,upd,del,upi");
#else
		fhp->fd = open(name, flags, mode);
#endif

		if (fhp->fd == -1) {
			/*
			 * If it's a "temporary" error, we retry up to 3 times,
			 * waiting up to 12 seconds.  While it's not a problem
			 * if we can't open a database, an inability to open a
			 * log file is cause for serious dismay.
			 */
			ret = __os_get_errno();
			if (ret == ENFILE || ret == EMFILE || ret == ENOSPC) {
				(void)__os_sleep(dbenv, nrepeat * 2, 0);
				continue;
			}
		} else {
#if defined(HAVE_FCNTL_F_SETFD)
			/* Deny file descriptor access to any child process. */
			if (fcntl(fhp->fd, F_SETFD, FD_CLOEXEC) == -1) {
				ret = __os_get_errno();
				__db_err(dbenv, "fcntl(F_SETFD): %s",
				    strerror(ret));
				(void)__os_closehandle(fhp);
			} else
#endif
				F_SET(fhp, DB_FH_VALID);
		}
		break;
	}

	return (ret);
}

/*
 * __os_closehandle --
 *	Close a file.
 *
 * PUBLIC: int __os_closehandle __P((DB_FH *));
 */
int
__os_closehandle(fhp)
	DB_FH *fhp;
{
	int ret;

	/* Don't close file descriptors that were never opened. */
	DB_ASSERT(F_ISSET(fhp, DB_FH_VALID) && fhp->fd != -1);

	ret = __db_jump.j_close != NULL ?
	    __db_jump.j_close(fhp->fd) : close(fhp->fd);

	/*
	 * Smash the POSIX file descriptor -- it's never tested, but we want
	 * to catch any mistakes.
	 */
	fhp->fd = -1;
	F_CLR(fhp, DB_FH_VALID);

	return (ret == 0 ? 0 : __os_get_errno());
}