1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1997,2008 Oracle.  All rights reserved.
5 *
6 * $Id: os_flock.c,v 1.21 2008/01/08 20:58:46 bostic Exp $
7 */
8
9#include "db_config.h"
10
11#include "db_int.h"
12
13/*
14 * __os_fdlock --
15 *	Acquire/release a lock on a byte in a file.
16 */
17int
18__os_fdlock(env, fhp, offset, acquire, nowait)
19	ENV *env;
20	DB_FH *fhp;
21	int acquire, nowait;
22	off_t offset;
23{
24#ifdef DB_WINCE
25	/*
26	 * This functionality is not supported by WinCE, so just fail.
27	 *
28	 * Should only happen if an app attempts to open an environment
29	 * with the DB_REGISTER flag.
30	 */
31	 __db_errx(env, "fdlock API not implemented for WinCE, DB_REGISTER "
32	     "environment flag not supported.");
33	return (EFAULT);
34#else
35	DWORD low, high;
36	DB_ENV *dbenv;
37	OVERLAPPED over;
38	int ret;
39
40	dbenv = env == NULL ? NULL : env->dbenv;
41
42	DB_ASSERT(env,
43	    F_ISSET(fhp, DB_FH_OPENED) && fhp->handle != INVALID_HANDLE_VALUE);
44
45	if (dbenv != NULL && FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS_ALL))
46		__db_msg(env,
47		    "fileops: flock %s %s offset %lu",
48		    fhp->name, acquire ? "acquire": "release", (u_long)offset);
49
50	/*
51	 * Windows file locking interferes with read/write operations, so we
52	 * map the ranges to an area past the end of the file.
53	 */
54	DB_ASSERT(env, offset < (u_int64_t)INT64_MAX);
55	offset = UINT64_MAX - offset;
56	low = (DWORD)offset;
57	high = (DWORD)(offset >> 32);
58
59	if (acquire) {
60		if (nowait)
61			RETRY_CHK_EINTR_ONLY(
62			    !LockFile(fhp->handle, low, high, 1, 0), ret);
63		else if (__os_is_winnt()) {
64			memset(&over, 0, sizeof(over));
65			over.Offset = low;
66			over.OffsetHigh = high;
67			RETRY_CHK_EINTR_ONLY(
68			    !LockFileEx(fhp->handle, LOCKFILE_EXCLUSIVE_LOCK,
69			    0, 1, 0, &over),
70			    ret);
71		} else {
72			/* Windows 9x/ME doesn't support a blocking call. */
73			for (;;) {
74				RETRY_CHK_EINTR_ONLY(
75				    !LockFile(fhp->handle, low, high, 1, 0),
76				    ret);
77				if (__os_posix_err(ret) != EAGAIN)
78					break;
79				__os_yield(env, 1, 0);
80			}
81		}
82	} else
83		RETRY_CHK_EINTR_ONLY(
84		    !UnlockFile(fhp->handle, low, high, 1, 0), ret);
85
86	return (__os_posix_err(ret));
87#endif
88}
89