summaryrefslogtreecommitdiff
path: root/db/os_win32
diff options
context:
space:
mode:
authorjbj <devnull@localhost>2001-03-21 18:33:35 +0000
committerjbj <devnull@localhost>2001-03-21 18:33:35 +0000
commit731946f4b90eb1173452dd30f1296dd825155d82 (patch)
tree67535f54ecb7e5463c06e62044e4efd84ae0291d /db/os_win32
parent7ed904da030dc4640ff9bce8458ba07cc09d830d (diff)
downloadlibrpm-tizen-731946f4b90eb1173452dd30f1296dd825155d82.tar.gz
librpm-tizen-731946f4b90eb1173452dd30f1296dd825155d82.tar.bz2
librpm-tizen-731946f4b90eb1173452dd30f1296dd825155d82.zip
Initial revision
CVS patchset: 4644 CVS date: 2001/03/21 18:33:35
Diffstat (limited to 'db/os_win32')
-rw-r--r--db/os_win32/os_abs.c33
-rw-r--r--db/os_win32/os_dir.c82
-rw-r--r--db/os_win32/os_errno.c146
-rw-r--r--db/os_win32/os_fid.c145
-rw-r--r--db/os_win32/os_finit.c60
-rw-r--r--db/os_win32/os_map.c310
-rw-r--r--db/os_win32/os_open.c201
-rw-r--r--db/os_win32/os_rename.c57
-rw-r--r--db/os_win32/os_seek.c65
-rw-r--r--db/os_win32/os_sleep.c41
-rw-r--r--db/os_win32/os_spin.c59
-rw-r--r--db/os_win32/os_type.c35
12 files changed, 1234 insertions, 0 deletions
diff --git a/db/os_win32/os_abs.c b/db/os_win32/os_abs.c
new file mode 100644
index 000000000..7b1e3fd05
--- /dev/null
+++ b/db/os_win32/os_abs.c
@@ -0,0 +1,33 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1997, 1998, 1999, 2000
+ * Sleepycat Software. All rights reserved.
+ */
+
+#include "db_config.h"
+
+#ifndef lint
+static const char revid[] = "$Id: os_abs.c,v 11.3 2000/02/14 03:00:06 bostic Exp $";
+#endif /* not lint */
+
+#include "db_int.h"
+
+/*
+ * __os_abspath --
+ * Return if a path is an absolute path.
+ */
+int
+__os_abspath(path)
+ const char *path;
+{
+ /*
+ * !!!
+ * Check for drive specifications, e.g., "C:". In addition, the path
+ * separator used by the win32 DB (PATH_SEPARATOR) is \; look for both
+ * / and \ since these are user-input paths.
+ */
+ if (isalpha(path[0]) && path[1] == ':')
+ path += 2;
+ return (path[0] == '/' || path[0] == '\\');
+}
diff --git a/db/os_win32/os_dir.c b/db/os_win32/os_dir.c
new file mode 100644
index 000000000..d37b76010
--- /dev/null
+++ b/db/os_win32/os_dir.c
@@ -0,0 +1,82 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1997, 1998, 1999, 2000
+ * Sleepycat Software. All rights reserved.
+ */
+
+#include "db_config.h"
+
+#ifndef lint
+static const char revid[] = "$Id: os_dir.c,v 11.4 2000/03/28 21:50:17 ubell Exp $";
+#endif /* not lint */
+
+#include "db_int.h"
+#include "os_jump.h"
+
+/*
+ * __os_dirlist --
+ * Return a list of the files in a directory.
+ */
+int
+__os_dirlist(dbenv, dir, namesp, cntp)
+ DB_ENV *dbenv;
+ const char *dir;
+ char ***namesp;
+ int *cntp;
+{
+ struct _finddata_t fdata;
+ long dirhandle;
+ int arraysz, cnt, finished, ret;
+ char **names, filespec[MAXPATHLEN];
+
+ if (__db_jump.j_dirlist != NULL)
+ return (__db_jump.j_dirlist(dir, namesp, cntp));
+
+ (void)snprintf(filespec, sizeof(filespec), "%s/*", dir);
+ if ((dirhandle = _findfirst(filespec, &fdata)) == -1)
+ return (__os_get_errno());
+
+ names = NULL;
+ finished = 0;
+ for (arraysz = cnt = 0; finished != 1; ++cnt) {
+ if (cnt >= arraysz) {
+ arraysz += 100;
+ if ((ret = __os_realloc(dbenv,
+ arraysz * sizeof(names[0]), NULL, &names)) != 0)
+ goto nomem;
+ }
+ if ((ret = __os_strdup(dbenv, fdata.name, &names[cnt])) != 0)
+ goto nomem;
+ if (_findnext(dirhandle,&fdata) != 0)
+ finished = 1;
+ }
+ _findclose(dirhandle);
+
+ *namesp = names;
+ *cntp = cnt;
+ return (0);
+
+nomem: if (names != NULL)
+ __os_dirfree(names, cnt);
+ return (ret);
+}
+
+/*
+ * __os_dirfree --
+ * Free the list of files.
+ */
+void
+__os_dirfree(names, cnt)
+ char **names;
+ int cnt;
+{
+ if (__db_jump.j_dirfree != NULL) {
+ __db_jump.j_dirfree(names, cnt);
+ return;
+ }
+
+ while (cnt > 0)
+ __os_free(names[--cnt], 0);
+ __os_free(names, 0);
+}
diff --git a/db/os_win32/os_errno.c b/db/os_win32/os_errno.c
new file mode 100644
index 000000000..8324826b6
--- /dev/null
+++ b/db/os_win32/os_errno.c
@@ -0,0 +1,146 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1999, 2000
+ * Sleepycat Software. All rights reserved.
+ */
+
+#include "db_config.h"
+
+#ifndef lint
+static const char revid[] = "$Id: os_errno.c,v 11.5 2000/11/30 00:58:43 ubell Exp $";
+#endif /* not lint */
+
+#include "db_int.h"
+
+/*
+ * __os_get_errno --
+ * Return the value of errno.
+ */
+int
+__os_get_errno()
+{
+ /* This routine must be able to return the same value repeatedly. */
+ return (errno);
+}
+
+/*
+ * __os_set_errno --
+ * Set the value of errno.
+ */
+void
+__os_set_errno(evalue)
+ int evalue;
+{
+ errno = evalue;
+}
+
+/*
+ * __os_win32_errno --
+ * Return the last Windows error as an errno.
+ * We give generic error returns:
+ *
+ * EFAULT means Win* call failed,
+ * and GetLastError provided no extra info.
+ *
+ * EIO means error on Win* call.
+ * and we were unable to provide a meaningful errno for this Windows
+ * error. More information is only available by setting a breakpoint
+ * here.
+ *
+ * PUBLIC: #if defined(DB_WIN32)
+ * PUBLIC: int __os_win32_errno __P((void));
+ * PUBLIC: #endif
+ */
+int
+__os_win32_errno(void)
+{
+ DWORD last_error;
+ int ret;
+
+ /*
+ * It's possible that errno was set after the error.
+ * The caller must take care to set it to 0 before
+ * any system operation.
+ */
+ if (__os_get_errno() != 0)
+ return (__os_get_errno());
+
+ last_error = GetLastError();
+
+ /*
+ * Take our best guess at translating some of the Windows error
+ * codes. We really care about only a few of these.
+ */
+ switch (last_error) {
+ case ERROR_FILE_NOT_FOUND:
+ case ERROR_INVALID_DRIVE:
+ case ERROR_PATH_NOT_FOUND:
+ ret = ENOENT;
+ break;
+
+ case ERROR_NO_MORE_FILES:
+ case ERROR_TOO_MANY_OPEN_FILES:
+ ret = EMFILE;
+ break;
+
+ case ERROR_ACCESS_DENIED:
+ ret = EPERM;
+ break;
+
+ case ERROR_INVALID_HANDLE:
+ ret = EBADF;
+ break;
+
+ case ERROR_NOT_ENOUGH_MEMORY:
+ ret = ENOMEM;
+ break;
+
+ case ERROR_DISK_FULL:
+ ret = ENOSPC;
+
+ case ERROR_ARENA_TRASHED:
+ case ERROR_BAD_COMMAND:
+ case ERROR_BAD_ENVIRONMENT:
+ case ERROR_BAD_FORMAT:
+ case ERROR_GEN_FAILURE:
+ case ERROR_INVALID_ACCESS:
+ case ERROR_INVALID_BLOCK:
+ case ERROR_INVALID_DATA:
+ case ERROR_READ_FAULT:
+ case ERROR_WRITE_FAULT:
+ ret = EFAULT;
+ break;
+
+ case ERROR_FILE_EXISTS:
+ ret = EEXIST;
+ break;
+
+ case ERROR_NOT_SAME_DEVICE:
+ ret = EXDEV;
+ break;
+
+ case ERROR_WRITE_PROTECT:
+ ret = EACCES;
+ break;
+
+ case ERROR_NOT_READY:
+ ret = EBUSY;
+ break;
+
+ case ERROR_LOCK_VIOLATION:
+ case ERROR_SHARING_VIOLATION:
+ ret = EBUSY;
+ break;
+
+ case 0:
+ ret = EFAULT;
+ break;
+
+ default:
+ ret = EIO; /* Generic error. */
+ break;
+ }
+
+ return (ret);
+}
diff --git a/db/os_win32/os_fid.c b/db/os_win32/os_fid.c
new file mode 100644
index 000000000..c66ac5210
--- /dev/null
+++ b/db/os_win32/os_fid.c
@@ -0,0 +1,145 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1996, 1997, 1998, 1999, 2000
+ * Sleepycat Software. All rights reserved.
+ */
+
+#include "db_config.h"
+
+#ifndef lint
+static const char revid[] = "$Id: os_fid.c,v 11.7 2000/10/26 14:18:08 bostic Exp $";
+#endif /* not lint */
+
+#include "db_int.h"
+
+#define SERIAL_INIT 0
+static u_int32_t fid_serial = SERIAL_INIT;
+
+/*
+ * __os_fileid --
+ * Return a unique identifier for a file.
+ */
+int
+__os_fileid(dbenv, fname, unique_okay, fidp)
+ DB_ENV *dbenv;
+ const char *fname;
+ int unique_okay;
+ u_int8_t *fidp;
+{
+ size_t i;
+ u_int32_t tmp;
+ u_int8_t *p;
+ int ret;
+
+ /*
+ * The documentation for GetFileInformationByHandle() states that the
+ * inode-type numbers are not constant between processes. Actually,
+ * they are, they're the NTFS MFT indexes. So, this works on NTFS,
+ * but perhaps not on other platforms, and perhaps not over a network.
+ * Can't think of a better solution right now.
+ */
+ DB_FH fh;
+ HANDLE handle;
+ BY_HANDLE_FILE_INFORMATION fi;
+ BOOL retval = FALSE;
+
+ /* Clear the buffer. */
+ memset(fidp, 0, DB_FILE_ID_LEN);
+
+ /*
+ * Initialize/increment the serial number we use to help avoid
+ * fileid collisions. Note that we don't bother with locking;
+ * it's unpleasant to do from down in here, and if we race on
+ * this no real harm will be done, since the finished fileid
+ * has so many other components.
+ *
+ * We increment by 100000 on each call as a simple way of
+ * randomizing; simply incrementing seems potentially less useful
+ * if pids are also simply incremented, since this is process-local
+ * and we may be one of a set of processes starting up. 100000
+ * pushes us out of pid space on most platforms, and has few
+ * interesting properties in base 2.
+ */
+ if (fid_serial == SERIAL_INIT)
+ fid_serial = (u_int32_t)getpid();
+ else
+ fid_serial += 100000;
+
+ /*
+ * First we open the file, because we're not given a handle to it.
+ * If we can't open it, we're in trouble.
+ */
+ if ((ret = __os_open(dbenv, fname, DB_OSO_RDONLY, _S_IREAD, &fh)) != 0)
+ return (ret);
+
+ /* File open, get its info */
+ handle = (HANDLE)_get_osfhandle(fh.fd);
+ if (handle == INVALID_HANDLE_VALUE)
+ ret = __os_win32_errno();
+ else
+ if ((retval = GetFileInformationByHandle(handle, &fi)) == FALSE)
+ ret = __os_win32_errno();
+ __os_closehandle(&fh);
+
+ if (handle == INVALID_HANDLE_VALUE || retval == FALSE)
+ return (ret);
+
+ /*
+ * We want the three 32-bit words which tell us the volume ID and
+ * the file ID. We make a crude attempt to copy the bytes over to
+ * the callers buffer.
+ *
+ * We don't worry about byte sexing or the actual variable sizes.
+ *
+ * When this routine is called from the DB access methods, it's only
+ * called once -- whatever ID is generated when a database is created
+ * is stored in the database file's metadata, and that is what is
+ * saved in the mpool region's information to uniquely identify the
+ * file.
+ *
+ * When called from the mpool layer this routine will be called each
+ * time a new thread of control wants to share the file, which makes
+ * things tougher. As far as byte sexing goes, since the mpool region
+ * lives on a single host, there's no issue of that -- the entire
+ * region is byte sex dependent. As far as variable sizes go, we make
+ * the simplifying assumption that 32-bit and 64-bit processes will
+ * get the same 32-bit values if we truncate any returned 64-bit value
+ * to a 32-bit value.
+ */
+ tmp = (u_int32_t)fi.nFileIndexLow;
+ for (p = (u_int8_t *)&tmp, i = sizeof(u_int32_t); i > 0; --i)
+ *fidp++ = *p++;
+ tmp = (u_int32_t)fi.nFileIndexHigh;
+ for (p = (u_int8_t *)&tmp, i = sizeof(u_int32_t); i > 0; --i)
+ *fidp++ = *p++;
+ if (unique_okay) {
+ /*
+ * Use the system time to try to get a unique value
+ * within this process. A millisecond counter
+ * overflows 32 bits in about 49 days. So we use 8
+ * bytes, and don't bother with the volume ID, which
+ * is not very useful for our purposes.
+ */
+ SYSTEMTIME st;
+
+ GetSystemTime(&st);
+ tmp = (st.wYear - 1900) * 12 + (st.wMonth - 1);
+ for (p = (u_int8_t *)&tmp, i = sizeof(u_int32_t); i > 0; --i)
+ *fidp++ = *p++;
+ tmp = ((((st.wDay - 1) * 24 + st.wHour) * 60 +
+ st.wMinute) * 60 + st.wSecond) * 1000 +
+ st.wMilliseconds;
+ for (p = (u_int8_t *)&tmp, i = sizeof(u_int32_t); i > 0; --i)
+ *fidp++ = *p++;
+ for (p = (u_int8_t *)&fid_serial, i = sizeof(u_int32_t);
+ i > 0; --i)
+ *fidp++ = *p++;
+ } else {
+ tmp = (u_int32_t)fi.dwVolumeSerialNumber;
+ for (p = (u_int8_t *)&tmp, i = sizeof(u_int32_t); i > 0; --i)
+ *fidp++ = *p++;
+ }
+
+ return (0);
+}
diff --git a/db/os_win32/os_finit.c b/db/os_win32/os_finit.c
new file mode 100644
index 000000000..61d2a33c7
--- /dev/null
+++ b/db/os_win32/os_finit.c
@@ -0,0 +1,60 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1999, 2000
+ * Sleepycat Software. All rights reserved.
+ */
+
+#include "db_config.h"
+
+#ifndef lint
+static const char revid[] = "$Id: os_finit.c,v 11.9 2000/03/29 20:50:52 ubell Exp $";
+#endif /* not lint */
+
+#include "db_int.h"
+
+/*
+ * __os_fpinit --
+ * Initialize a page in a regular file.
+ *
+ * PUBLIC: int __os_fpinit __P((DB_ENV *, DB_FH *, db_pgno_t, int, int));
+ */
+int
+__os_fpinit(dbenv, fhp, pgno, pagecount, pagesize)
+ DB_ENV *dbenv;
+ DB_FH *fhp;
+ db_pgno_t pgno;
+ int pagecount, pagesize;
+{
+ size_t nw, totalbytes, curbytes;
+ int ret;
+ char buf[1024];
+
+ /*
+ * Windows/NT zero-fills pages that were never explicitly written to
+ * the file. Windows 95/98 gives you random garbage, and that breaks
+ * DB.
+ */
+ if (__os_is_winnt())
+ return (0);
+
+ if ((ret = __os_seek(dbenv,
+ fhp, pagesize, pgno, 0, 0, DB_OS_SEEK_SET)) != 0)
+ return (ret);
+
+ memset(buf, 0, sizeof(buf));
+ totalbytes = pagecount * pagesize;
+
+ while (totalbytes > 0) {
+ if (totalbytes > sizeof(buf))
+ curbytes = sizeof(buf);
+ else
+ curbytes = totalbytes;
+ if ((ret = __os_write(dbenv, fhp, buf, curbytes, &nw)) != 0)
+ return (ret);
+ if (nw != curbytes)
+ return (EIO);
+ totalbytes -= curbytes;
+ }
+ return (0);
+}
diff --git a/db/os_win32/os_map.c b/db/os_win32/os_map.c
new file mode 100644
index 000000000..d7b2839ed
--- /dev/null
+++ b/db/os_win32/os_map.c
@@ -0,0 +1,310 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1996, 1997, 1998, 1999, 2000
+ * Sleepycat Software. All rights reserved.
+ */
+
+#include "db_config.h"
+
+#ifndef lint
+static const char revid[] = "$Id: os_map.c,v 11.22 2000/10/26 14:18:08 bostic Exp $";
+#endif /* not lint */
+
+#include "db_int.h"
+#include "os_jump.h"
+
+static int __os_map
+ __P((DB_ENV *, char *, REGINFO *, DB_FH *, size_t, int, int, int, void **));
+static int __os_unique_name __P((char *, int, char *));
+
+/*
+ * __os_r_sysattach --
+ * Create/join a shared memory region.
+ */
+int
+__os_r_sysattach(dbenv, infop, rp)
+ DB_ENV *dbenv;
+ REGINFO *infop;
+ REGION *rp;
+{
+ DB_FH fh;
+ int is_system, ret;
+
+ /*
+ * Try to open/create the file. We DO NOT need to ensure that multiple
+ * threads/processes attempting to simultaneously create the region are
+ * properly ordered, our caller has already taken care of that.
+ */
+ if ((ret = __os_open(dbenv, infop->name,
+ F_ISSET(infop, REGION_CREATE_OK) ? DB_OSO_CREATE: 0,
+ infop->mode, &fh)) != 0) {
+ __db_err(dbenv, "%s: %s", infop->name, db_strerror(ret));
+ return (ret);
+ }
+
+ /*
+ * On Windows/9X, files that are opened by multiple processes do not
+ * share data correctly. For this reason, the DB_SYSTEM_MEM flag is
+ * implied for any application that does not specify the DB_PRIVATE
+ * flag.
+ */
+ is_system = F_ISSET(dbenv, DB_ENV_SYSTEM_MEM) ||
+ (!F_ISSET(dbenv, DB_ENV_PRIVATE) && __os_is_winnt() == 0);
+
+ /*
+ * Map the file in. If we're creating an in-system-memory region,
+ * specify a segment ID (which is never used again) so that the
+ * calling code writes out the REGENV_REF structure to the primary
+ * environment file.
+ */
+ ret = __os_map(dbenv, infop->name, infop, &fh, rp->size,
+ 1, is_system, 0, &infop->addr);
+ if (ret == 0 && is_system == 1)
+ rp->segid = 1;
+
+ (void)__os_closehandle(&fh);
+
+ return (ret);
+}
+
+/*
+ * __os_r_sysdetach --
+ * Detach from a shared memory region.
+ */
+int
+__os_r_sysdetach(dbenv, infop, destroy)
+ DB_ENV *dbenv;
+ REGINFO *infop;
+ int destroy;
+{
+ int ret, t_ret;
+
+ if (infop->wnt_handle != NULL) {
+ (void)CloseHandle(*((HANDLE*)(infop->wnt_handle)));
+ __os_free(infop->wnt_handle, sizeof(HANDLE));
+ }
+
+ __os_set_errno(0);
+ ret = !UnmapViewOfFile(infop->addr) ? __os_win32_errno() : 0;
+ if (ret != 0)
+ __db_err(dbenv, "UnmapViewOfFile: %s", strerror(ret));
+
+ if (F_ISSET(dbenv, DB_ENV_SYSTEM_MEM) && destroy &&
+ (t_ret = __os_unlink(dbenv, infop->name)) != 0 && ret == 0)
+ ret = t_ret;
+
+ return (ret);
+}
+
+/*
+ * __os_mapfile --
+ * Map in a shared memory file.
+ */
+int
+__os_mapfile(dbenv, path, fhp, len, is_rdonly, addr)
+ DB_ENV *dbenv;
+ char *path;
+ DB_FH *fhp;
+ int is_rdonly;
+ size_t len;
+ void **addr;
+{
+ /* If the user replaced the map call, call through their interface. */
+ if (__db_jump.j_map != NULL)
+ return (__db_jump.j_map(path, len, 0, is_rdonly, addr));
+
+ return (__os_map(dbenv, path, NULL, fhp, len, 0, 0, is_rdonly, addr));
+}
+
+/*
+ * __os_unmapfile --
+ * Unmap the shared memory file.
+ */
+int
+__os_unmapfile(dbenv, addr, len)
+ DB_ENV *dbenv;
+ void *addr;
+ size_t len;
+{
+ /* If the user replaced the map call, call through their interface. */
+ if (__db_jump.j_unmap != NULL)
+ return (__db_jump.j_unmap(addr, len));
+
+ __os_set_errno(0);
+ return (!UnmapViewOfFile(addr) ? __os_win32_errno() : 0);
+}
+
+/*
+ * __os_unique_name --
+ * Create a unique identifying name from a pathname (may be absolute or
+ * relative) and/or a file descriptor.
+ *
+ * The name returned must be unique (different files map to different
+ * names), and repeatable (same files, map to same names). It's not
+ * so easy to do by name. Should handle not only:
+ *
+ * foo.bar == ./foo.bar == c:/whatever_path/foo.bar
+ *
+ * but also understand that:
+ *
+ * foo.bar == Foo.Bar (FAT file system)
+ * foo.bar != Foo.Bar (NTFS)
+ *
+ * The best solution is to use the identifying number in the file
+ * information structure (similar to UNIX inode #).
+ */
+static int
+__os_unique_name(orig_path, fd, result_path)
+ char *orig_path, *result_path;
+ int fd;
+{
+ BY_HANDLE_FILE_INFORMATION fileinfo;
+
+ __os_set_errno(0);
+ if (!GetFileInformationByHandle(
+ (HANDLE)_get_osfhandle(fd), &fileinfo))
+ return (__os_win32_errno());
+ (void)sprintf(result_path, "%ld.%ld.%ld",
+ fileinfo.dwVolumeSerialNumber,
+ fileinfo.nFileIndexHigh, fileinfo.nFileIndexLow);
+ return (0);
+}
+
+/*
+ * __os_map --
+ * The mmap(2) function for Windows.
+ */
+static int
+__os_map(dbenv, path, infop, fhp, len, is_region, is_system, is_rdonly, addr)
+ DB_ENV *dbenv;
+ REGINFO *infop;
+ char *path;
+ DB_FH *fhp;
+ int is_region, is_system, is_rdonly;
+ size_t len;
+ void **addr;
+{
+ HANDLE hMemory;
+ REGENV *renv;
+ int ret;
+ void *pMemory;
+ char shmem_name[MAXPATHLEN];
+ int use_pagefile;
+
+ ret = 0;
+ if (infop != NULL)
+ infop->wnt_handle = NULL;
+
+ use_pagefile = is_region && is_system;
+
+ /*
+ * If creating a region in system space, get a matching name in the
+ * paging file namespace.
+ */
+ if (use_pagefile) {
+ (void)strcpy(shmem_name, "__db_shmem.");
+ if ((ret = __os_unique_name(path, fhp->fd,
+ &shmem_name[strlen(shmem_name)])) != 0)
+ return (ret);
+ }
+
+ /*
+ * XXX
+ * DB: We have not implemented copy-on-write here.
+ *
+ * XXX
+ * DB: This code will fail if the library is ever compiled on a 64-bit
+ * machine.
+ *
+ * XXX
+ * If this is an region in system memory, let's try opening using the
+ * OpenFileMapping() first. Why, oh why are we doing this?
+ *
+ * Well, we might be asking the OS for a handle to a pre-existing
+ * memory section, or we might be the first to get here and want the
+ * section created. CreateFileMapping() sounds like it will do both
+ * jobs. But, not so. It seems to mess up making the commit charge to
+ * the process. It thinks, incorrectly, that when we want to join a
+ * previously existing section, that it should make a commit charge
+ * for the whole section. In fact, there is no new committed memory
+ * whatever. The call can fail if there is insufficient memory free
+ * to handle the erroneous commit charge. So, we find that the bogus
+ * commit is not made if we call OpenFileMapping(). So we do that
+ * first, and only call CreateFileMapping() if we're really creating
+ * the section.
+ */
+ hMemory = NULL;
+ __os_set_errno(0);
+ if (use_pagefile)
+ hMemory = OpenFileMapping(
+ is_rdonly ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS,
+ 0,
+ shmem_name);
+
+ if (hMemory == NULL)
+ hMemory = CreateFileMapping(
+ use_pagefile ?
+ (HANDLE)0xFFFFFFFF : (HANDLE)_get_osfhandle(fhp->fd),
+ 0,
+ is_rdonly ? PAGE_READONLY : PAGE_READWRITE,
+ 0, len,
+ use_pagefile ? shmem_name : NULL);
+ if (hMemory == NULL) {
+ __db_err(dbenv,
+ "OpenFileMapping: %s", strerror(__os_win32_errno()));
+ return (__os_win32_errno());
+ }
+
+ pMemory = MapViewOfFile(hMemory,
+ (is_rdonly ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS), 0, 0, len);
+ if (pMemory == NULL) {
+ __db_err(dbenv,
+ "MapViewOfFile: %s", strerror(__os_win32_errno()));
+ return (__os_win32_errno());
+ }
+
+ /*
+ * XXX
+ * It turns out that the kernel object underlying the named section
+ * is reference counted, but that the call to MapViewOfFile() above
+ * does NOT increment the reference count! So, if we close the handle
+ * here, the kernel deletes the object from the kernel namespace.
+ * When a second process comes along to join the region, the kernel
+ * happily creates a new object with the same name, but completely
+ * different identity. The two processes then have distinct isolated
+ * mapped sections, not at all what was wanted. Not closing the handle
+ * here fixes this problem. We carry the handle around in the region
+ * structure so we can close it when unmap is called. Ignore malloc
+ * errors, it just means we leak the memory.
+ */
+ if (use_pagefile && infop != NULL) {
+ if (__os_malloc(NULL,
+ sizeof(HANDLE), NULL, &infop->wnt_handle) == 0)
+ memcpy(infop->wnt_handle, &hMemory, sizeof(HANDLE));
+ } else
+ CloseHandle(hMemory);
+
+ if (is_region) {
+ /*
+ * XXX
+ * Windows/95 zeroes anonymous memory regions at last close.
+ * This means that the backing file can exist and reference
+ * the region, but the region itself is no longer initialized.
+ * If the caller is capable of creating the region, update
+ * the REGINFO structure so that they do so.
+ */
+ renv = (REGENV *)pMemory;
+ if (renv->magic == 0)
+ if (F_ISSET(infop, REGION_CREATE_OK))
+ F_SET(infop, REGION_CREATE);
+ else {
+ (void)UnmapViewOfFile(pMemory);
+ pMemory = NULL;
+ ret = EAGAIN;
+ }
+ }
+
+ *addr = pMemory;
+ return (ret);
+}
diff --git a/db/os_win32/os_open.c b/db/os_win32/os_open.c
new file mode 100644
index 000000000..7ecd96126
--- /dev/null
+++ b/db/os_win32/os_open.c
@@ -0,0 +1,201 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1997, 1998, 1999, 2000
+ * Sleepycat Software. All rights reserved.
+ */
+
+#include "db_config.h"
+
+#ifndef lint
+static const char revid[] = "$Id: os_open.c,v 11.9 2000/11/30 00:58:43 ubell Exp $";
+#endif /* not lint */
+
+#ifndef NO_SYSTEM_INCLUDES
+#include <sys/types.h>
+
+#include <fcntl.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+#endif
+
+#include "db_int.h"
+#include "os_jump.h"
+
+int __os_win32_errno __P((void));
+
+/*
+ * __os_open --
+ * Open a file descriptor.
+ */
+int
+__os_open(dbenv, name, flags, mode, fhp)
+ DB_ENV *dbenv;
+ const char *name;
+ u_int32_t flags;
+ int mode;
+ DB_FH *fhp;
+{
+ DWORD bytesWritten;
+ HANDLE wh;
+ u_int32_t log_size;
+ int access, attr, oflags, share, createflag;
+ int ret, nrepeat;
+
+ /*
+ * The "public" interface to the __os_open routine passes around POSIX
+ * 1003.1 flags, not DB flags. If the user has defined their own open
+ * interface, use the POSIX flags.
+ */
+ if (__db_jump.j_open != NULL) {
+ oflags = O_BINARY | O_NOINHERIT;
+
+ if (LF_ISSET(DB_OSO_CREATE))
+ oflags |= O_CREAT;
+
+ if (LF_ISSET(DB_OSO_EXCL))
+ oflags |= O_EXCL;
+
+ if (LF_ISSET(DB_OSO_RDONLY))
+ oflags |= O_RDONLY;
+ else
+ oflags |= O_RDWR;
+
+ if (LF_ISSET(DB_OSO_SEQ))
+ oflags |= _O_SEQUENTIAL;
+ else
+ oflags |= _O_RANDOM;
+
+ if (LF_ISSET(DB_OSO_TEMP))
+ oflags |= _O_TEMPORARY;
+
+ if (LF_ISSET(DB_OSO_TRUNC))
+ oflags |= O_TRUNC;
+
+ return (__os_openhandle(dbenv, name, oflags, mode, fhp));
+ }
+
+ if (LF_ISSET(DB_OSO_LOG))
+ log_size = fhp->log_size; /* XXX: Gag. */
+
+ memset(fhp, 0, sizeof(*fhp));
+
+ /*
+ * Otherwise, use the Windows/32 CreateFile interface so that we can
+ * play magic games with log files to get data flush effects similar
+ * to the POSIX O_DSYNC flag.
+ *
+ * !!!
+ * We currently ignore the 'mode' argument. It would be possible
+ * to construct a set of security attributes that we could pass to
+ * CreateFile that would accurately represents the mode. In worst
+ * case, this would require looking up user and all group names and
+ * creating an entry for each. Alternatively, we could call the
+ * _chmod (partial emulation) function after file creation, although
+ * this leaves us with an obvious race. However, these efforts are
+ * largely meaningless on FAT, the most common file system, which
+ * only has a "readable" and "writeable" flag, applying to all users.
+ */
+ wh = INVALID_HANDLE_VALUE;
+
+ access = GENERIC_READ;
+ if (!LF_ISSET(DB_OSO_RDONLY))
+ access |= GENERIC_WRITE;
+
+ share = FILE_SHARE_READ | FILE_SHARE_WRITE;
+ attr = FILE_ATTRIBUTE_NORMAL;
+
+ /*
+ * Reproduce POSIX 1003.1 semantics: if O_CREATE and O_EXCL are both
+ * specified, fail, returning EEXIST, unless we create the file.
+ */
+ if (LF_ISSET(DB_OSO_CREATE) && LF_ISSET(DB_OSO_EXCL))
+ createflag = CREATE_NEW; /* create only if !exist*/
+ else if (!LF_ISSET(DB_OSO_CREATE) && LF_ISSET(DB_OSO_TRUNC))
+ createflag = TRUNCATE_EXISTING; /* truncate, fail if !exist */
+ else if (LF_ISSET(DB_OSO_TRUNC))
+ createflag = CREATE_ALWAYS; /* create and truncate */
+ else if (LF_ISSET(DB_OSO_CREATE))
+ createflag = OPEN_ALWAYS; /* open or create */
+ else
+ createflag = OPEN_EXISTING; /* open only if existing */
+
+ if (LF_ISSET(DB_OSO_LOG)) {
+ F_SET(fhp, DB_FH_NOSYNC);
+ attr |= FILE_FLAG_WRITE_THROUGH;
+ }
+
+ if (LF_ISSET(DB_OSO_SEQ))
+ attr |= FILE_FLAG_SEQUENTIAL_SCAN;
+ else
+ attr |= FILE_FLAG_RANDOM_ACCESS;
+
+ if (LF_ISSET(DB_OSO_TEMP))
+ attr |= FILE_FLAG_DELETE_ON_CLOSE;
+
+ for (nrepeat = 1; nrepeat < 4; ++nrepeat) {
+ ret = 0;
+ __os_set_errno(0);
+ wh = CreateFile(name, access, share, NULL, createflag, attr, 0);
+ if (wh == INVALID_HANDLE_VALUE) {
+ /*
+ * 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_win32_errno();
+ if (ret == ENFILE || ret == EMFILE || ret == ENOSPC) {
+ (void)__os_sleep(dbenv, nrepeat * 2, 0);
+ continue;
+ }
+ goto err;
+ }
+ break;
+ }
+
+ /*
+ * Special handling needed for log files. To get Windows to not update
+ * the MFT metadata on each write, extend the file to its maximum size.
+ * Windows will allocate all the data blocks and store them in the MFT
+ * (inode) area. In addition, flush the MFT area to disk.
+ * This strategy only works for Win/NT; Win/9X does not
+ * guarantee that the logs will be zero filled.
+ */
+ if (LF_ISSET(DB_OSO_LOG) && log_size != 0 &&
+ __os_is_winnt()) {
+ if (SetFilePointer(wh,
+ log_size - 1, NULL, FILE_BEGIN) == (DWORD)-1)
+ goto err;
+ if (WriteFile(wh, "\x00", 1, &bytesWritten, NULL) == 0)
+ goto err;
+ if (bytesWritten != 1)
+ goto err;
+ if (SetEndOfFile(wh) == 0)
+ goto err;
+ if (SetFilePointer(wh, 0, NULL, FILE_BEGIN) == (DWORD)-1)
+ goto err;
+ if (FlushFileBuffers(wh) == 0)
+ goto err;
+ }
+
+ /*
+ * We acquire a POSIX file descriptor as this allows us to use the
+ * general UNIX I/O routines instead of writing Windows specific
+ * ones. Closing that file descriptor is sufficient to close the
+ * Windows HANDLE.
+ */
+ fhp->fd =
+ _open_osfhandle((long)wh, LF_ISSET(DB_OSO_RDONLY) ? O_RDONLY : 0);
+ fhp->handle = wh;
+ F_SET(fhp, DB_FH_VALID);
+
+ return (0);
+
+err: if (ret == 0)
+ ret = __os_win32_errno();
+ if (wh != INVALID_HANDLE_VALUE)
+ (void)CloseHandle(wh);
+ return (ret);
+}
diff --git a/db/os_win32/os_rename.c b/db/os_win32/os_rename.c
new file mode 100644
index 000000000..c82482046
--- /dev/null
+++ b/db/os_win32/os_rename.c
@@ -0,0 +1,57 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1997, 1998, 1999, 2000
+ * Sleepycat Software. All rights reserved.
+ */
+
+#include "db_config.h"
+
+#ifndef lint
+static const char revid[] = "$Id: os_rename.c,v 1.2 2000/06/13 19:52:19 dda Exp $";
+#endif /* not lint */
+
+#include "db_int.h"
+#include "os_jump.h"
+
+/*
+ * __os_rename --
+ * Rename a file.
+ */
+int
+__os_rename(dbenv, old, new)
+ DB_ENV *dbenv;
+ const char *old, *new;
+{
+ int ret;
+
+ ret = 0;
+ if (__db_jump.j_rename != NULL) {
+ if (__db_jump.j_rename(old, new) == -1)
+ ret = __os_get_errno();
+ }
+ else {
+ /* Normally we would use a single MoveFileEx call with
+ * MOVEFILE_REPLACE_EXISTING flag to simulate Unix rename().
+ * But if the target file exists, and the two files' 8.3
+ * names are identical, a Windows bug causes the target file
+ * to be deleted, but the original file will not be renamed,
+ * and an ENOENT error will be returned. (See MSDN for a
+ * description of the bug).
+ *
+ * After the failed call, a MoveFile seems to perform
+ * the rename correctly (even another call to MoveFileEx
+ * does not)! The expense of this extra call only occurs
+ * on systems with the bug: Windows/98, for one, but
+ * apparently not Windows/NT and Windows/2000.
+ */
+ if (MoveFileEx(old, new, MOVEFILE_REPLACE_EXISTING) != TRUE)
+ ret = __os_win32_errno();
+ if (ret == ENOENT && MoveFile(old, new) == TRUE)
+ ret = 0;
+ }
+ if (ret != 0)
+ __db_err(dbenv, "Rename %s %s: %s", old, new, strerror(ret));
+
+ return (ret);
+}
diff --git a/db/os_win32/os_seek.c b/db/os_win32/os_seek.c
new file mode 100644
index 000000000..8cf3c98aa
--- /dev/null
+++ b/db/os_win32/os_seek.c
@@ -0,0 +1,65 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1997, 1998, 1999, 2000
+ * Sleepycat Software. All rights reserved.
+ */
+
+#include "db_config.h"
+
+#ifndef lint
+static const char revid[] = "$Id: os_seek.c,v 11.8 2000/05/17 19:30:19 bostic Exp $";
+#endif /* not lint */
+
+#include "db_int.h"
+#include "os_jump.h"
+
+/*
+ * __os_seek --
+ * Seek to a page/byte offset in the file.
+ */
+int
+__os_seek(dbenv, fhp, pgsize, pageno, relative, isrewind, db_whence)
+ DB_ENV *dbenv;
+ DB_FH *fhp;
+ size_t pgsize;
+ db_pgno_t pageno;
+ u_int32_t relative;
+ int isrewind;
+ DB_OS_SEEK db_whence;
+{
+ __int64 offset;
+ int ret, whence;
+
+ switch (db_whence) {
+ case DB_OS_SEEK_CUR:
+ whence = SEEK_CUR;
+ break;
+ case DB_OS_SEEK_END:
+ whence = SEEK_END;
+ break;
+ case DB_OS_SEEK_SET:
+ whence = SEEK_SET;
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ if (__db_jump.j_seek != NULL)
+ ret = __db_jump.j_seek(fhp->fd, pgsize, pageno,
+ relative, isrewind, whence);
+ else {
+ offset = (__int64)pgsize * pageno + relative;
+ if (isrewind)
+ offset = -offset;
+ ret = _lseeki64(
+ fhp->fd, offset, whence) == -1 ? __os_get_errno() : 0;
+ }
+
+ if (ret != 0)
+ __db_err(dbenv, "seek: %lu %d %d: %s",
+ (u_long)pgsize * pageno + relative,
+ isrewind, db_whence, strerror(ret));
+
+ return (ret);
+}
diff --git a/db/os_win32/os_sleep.c b/db/os_win32/os_sleep.c
new file mode 100644
index 000000000..f0248a583
--- /dev/null
+++ b/db/os_win32/os_sleep.c
@@ -0,0 +1,41 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1997, 1998, 1999, 2000
+ * Sleepycat Software. All rights reserved.
+ */
+
+#include "db_config.h"
+
+#ifndef lint
+static const char revid[] = "$Id: os_sleep.c,v 11.4 2000/03/30 01:46:43 ubell Exp $";
+#endif /* not lint */
+
+#include "db_int.h"
+#include "os_jump.h"
+
+/*
+ * __os_sleep --
+ * Yield the processor for a period of time.
+ */
+int
+__os_sleep(dbenv, secs, usecs)
+ DB_ENV *dbenv;
+ u_long secs, usecs; /* Seconds and microseconds. */
+{
+ COMPQUIET(dbenv, NULL);
+
+ /* Don't require that the values be normalized. */
+ for (; usecs >= 1000000; ++secs, usecs -= 1000000)
+ ;
+
+ if (__db_jump.j_sleep != NULL)
+ return (__db_jump.j_sleep(secs, usecs));
+
+ /*
+ * It's important that we yield the processor here so that other
+ * processes or threads are permitted to run.
+ */
+ Sleep(secs * 1000 + usecs / 1000);
+ return (0);
+}
diff --git a/db/os_win32/os_spin.c b/db/os_win32/os_spin.c
new file mode 100644
index 000000000..f250c523d
--- /dev/null
+++ b/db/os_win32/os_spin.c
@@ -0,0 +1,59 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1997, 1998, 1999, 2000
+ * Sleepycat Software. All rights reserved.
+ */
+
+#include "db_config.h"
+
+#ifndef lint
+static const char revid[] = "$Id: os_spin.c,v 11.6 2000/05/17 19:30:19 bostic Exp $";
+#endif /* not lint */
+
+#include "db_int.h"
+#include "os_jump.h"
+
+/*
+ * __os_spin --
+ * Return the number of default spins before blocking.
+ */
+int
+__os_spin()
+{
+ SYSTEM_INFO SystemInfo;
+
+ /*
+ * If the application specified a value or we've already figured it
+ * out, return it.
+ */
+ if (DB_GLOBAL(db_tas_spins) != 0)
+ return (DB_GLOBAL(db_tas_spins));
+
+ /* Get the number of processors */
+ GetSystemInfo(&SystemInfo);
+
+ /*
+ * Spin 50 times per processor -- we have anecdotal evidence that this
+ * is a reasonable value.
+ */
+ if (SystemInfo.dwNumberOfProcessors > 1)
+ DB_GLOBAL(db_tas_spins) = 50 * SystemInfo.dwNumberOfProcessors;
+ else
+ DB_GLOBAL(db_tas_spins) = 1;
+ return (DB_GLOBAL(db_tas_spins));
+}
+
+/*
+ * __os_yield --
+ * Yield the processor.
+ */
+void
+__os_yield(dbenv, usecs)
+ DB_ENV *dbenv;
+ u_long usecs;
+{
+ if (__db_jump.j_yield != NULL && __db_jump.j_yield() == 0)
+ return;
+ __os_sleep(dbenv, 0, usecs);
+}
diff --git a/db/os_win32/os_type.c b/db/os_win32/os_type.c
new file mode 100644
index 000000000..a82fc4b1d
--- /dev/null
+++ b/db/os_win32/os_type.c
@@ -0,0 +1,35 @@
+/*-
+ * 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_type.c,v 11.3 2000/02/14 03:00:07 bostic Exp $";
+#endif /* not lint */
+
+/*
+ * __os_is_winnt --
+ * Return 1 if Windows/NT, otherwise 0.
+ *
+ * PUBLIC: int __os_is_winnt __P((void));
+ */
+int
+__os_is_winnt()
+{
+ static int __os_type = -1;
+
+ /*
+ * The value of __os_type is computed only once, and cached to
+ * avoid the overhead of repeated calls to GetVersion().
+ */
+ if (__os_type == -1)
+ if ((GetVersion() & 0x80000000) == 0)
+ __os_type = 1;
+ else
+ __os_type = 0;
+ return (__os_type);
+}