summaryrefslogtreecommitdiff
path: root/src/os_posix/os_open.c
blob: 971fe47f11bfc0599e2086557b563b5d52ce0e5d (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
/*-
 * See the file LICENSE for redistribution information.
 *
 * Copyright (c) 2008-2011 WiredTiger, Inc.
 *	All rights reserved.
 *
 * $Id$
 */

#include "wt_internal.h"

/*
 * __wt_open --
 *	Open a file handle.
 */
int
__wt_open(ENV *env, const char *name, mode_t mode, int ok_create, WT_FH **fhp)
{
	IDB *idb;
	IENV *ienv;
	WT_FH *fh;
	int f, fd, ret;

	fh = NULL;
	ienv = env->ienv;

	 WT_VERBOSE(env, WT_VERB_FILEOPS, (env, "fileops: %s: open", name));

	/* Increment the reference count if we already have the file open. */
	__wt_lock(env, ienv->mtx);
	TAILQ_FOREACH(idb, &ienv->dbqh, q) {
		if ((fh = idb->fh) == NULL)
			continue;
		if (strcmp(name, idb->name) == 0) {
			++fh->refcnt;
			*fhp = fh;
			break;
		}
	}
	__wt_unlock(env, ienv->mtx);
	if (fh != NULL)
		return (0);

	f = O_RDWR;
#ifdef O_BINARY
	/* Windows clones: we always want to treat the file as a binary. */
	f |= O_BINARY;
#endif
	if (ok_create)
		f |= O_CREAT;

	if ((fd = open(name, f, mode)) == -1) {
		__wt_api_env_err(env, errno, "%s", name);
		return (WT_ERROR);
	}

	WT_RET(__wt_calloc(env, 1, sizeof(WT_FH), &fh));
	WT_ERR(__wt_stat_alloc_fh_stats(env, &fh->stats));
	WT_ERR(__wt_strdup(env, name, &fh->name));

#if defined(HAVE_FCNTL) && defined(FD_CLOEXEC)
	/*
	 * Security:
	 * The application may spawn a new process, and we don't want another
	 * process to have access to our file handles.  There's an obvious
	 * race here...
	 */
	if ((f = fcntl(fd, F_GETFD)) == -1 ||
	    fcntl(fd, F_SETFD, f | FD_CLOEXEC) == -1) {
		__wt_api_env_err(env, errno, "%s: fcntl", name);
		goto err;
	}
#endif

	fh->fd = fd;
	fh->refcnt = 1;
	*fhp = fh;

	/* Set the file's size. */
	WT_ERR(__wt_filesize(env, fh, &fh->file_size));

	/* Link onto the environment's list of files. */
	__wt_lock(env, ienv->mtx);
	TAILQ_INSERT_TAIL(&ienv->fhqh, fh, q);
	__wt_unlock(env, ienv->mtx);

	return (0);

err:	if (fh != NULL) {
		if (fh->name != NULL)
			__wt_free(env, fh->name, 0);
		__wt_free(env, fh, sizeof(WT_FH));
	}
	(void)close(fd);
	return (ret);
}

/*
 * __wt_close --
 *	Close a file handle.
 */
int
__wt_close(ENV *env, WT_FH *fh)
{
	IENV *ienv;
	int ret;

	ienv = env->ienv;
	ret = 0;

	if (fh == NULL || fh->refcnt == 0 || --fh->refcnt > 0)
		return (0);

	/* Remove from the list and discard the memory. */
	__wt_lock(env, ienv->mtx);
	TAILQ_REMOVE(&ienv->fhqh, fh, q);
	__wt_unlock(env, ienv->mtx);

	if (close(fh->fd) != 0) {
		__wt_api_env_err(env, errno, "%s", fh->name);
		ret = WT_ERROR;
	}

	__wt_free(env, fh->name, 0);
	__wt_free(env, fh->stats, 0);
	__wt_free(env, fh, sizeof(WT_FH));
	return (ret);
}