From 54df2afaa61c6a03cbb4a33c9b90fa572b6d07b8 Mon Sep 17 00:00:00 2001 From: Jesse Morgan Date: Sat, 17 Dec 2016 21:28:53 -0800 Subject: Berkeley DB 4.8 with rust build script for linux. --- db-4.8.30/os_windows/ce_ctime.c | 87 ++++++++ db-4.8.30/os_windows/os_abs.c | 30 +++ db-4.8.30/os_windows/os_clock.c | 79 +++++++ db-4.8.30/os_windows/os_config.c | 133 ++++++++++++ db-4.8.30/os_windows/os_cpu.c | 27 +++ db-4.8.30/os_windows/os_dir.c | 122 +++++++++++ db-4.8.30/os_windows/os_errno.c | 427 +++++++++++++++++++++++++++++++++++++ db-4.8.30/os_windows/os_fid.c | 129 +++++++++++ db-4.8.30/os_windows/os_flock.c | 88 ++++++++ db-4.8.30/os_windows/os_fsync.c | 43 ++++ db-4.8.30/os_windows/os_getenv.c | 102 +++++++++ db-4.8.30/os_windows/os_handle.c | 165 ++++++++++++++ db-4.8.30/os_windows/os_map.c | 362 +++++++++++++++++++++++++++++++ db-4.8.30/os_windows/os_mkdir.c | 43 ++++ db-4.8.30/os_windows/os_open.c | 255 ++++++++++++++++++++++ db-4.8.30/os_windows/os_rename.c | 81 +++++++ db-4.8.30/os_windows/os_rw.c | 215 +++++++++++++++++++ db-4.8.30/os_windows/os_seek.c | 65 ++++++ db-4.8.30/os_windows/os_stat.c | 90 ++++++++ db-4.8.30/os_windows/os_truncate.c | 98 +++++++++ db-4.8.30/os_windows/os_unlink.c | 108 ++++++++++ db-4.8.30/os_windows/os_yield.c | 35 +++ 22 files changed, 2784 insertions(+) create mode 100644 db-4.8.30/os_windows/ce_ctime.c create mode 100644 db-4.8.30/os_windows/os_abs.c create mode 100644 db-4.8.30/os_windows/os_clock.c create mode 100644 db-4.8.30/os_windows/os_config.c create mode 100644 db-4.8.30/os_windows/os_cpu.c create mode 100644 db-4.8.30/os_windows/os_dir.c create mode 100644 db-4.8.30/os_windows/os_errno.c create mode 100644 db-4.8.30/os_windows/os_fid.c create mode 100644 db-4.8.30/os_windows/os_flock.c create mode 100644 db-4.8.30/os_windows/os_fsync.c create mode 100644 db-4.8.30/os_windows/os_getenv.c create mode 100644 db-4.8.30/os_windows/os_handle.c create mode 100644 db-4.8.30/os_windows/os_map.c create mode 100644 db-4.8.30/os_windows/os_mkdir.c create mode 100644 db-4.8.30/os_windows/os_open.c create mode 100644 db-4.8.30/os_windows/os_rename.c create mode 100644 db-4.8.30/os_windows/os_rw.c create mode 100644 db-4.8.30/os_windows/os_seek.c create mode 100644 db-4.8.30/os_windows/os_stat.c create mode 100644 db-4.8.30/os_windows/os_truncate.c create mode 100644 db-4.8.30/os_windows/os_unlink.c create mode 100644 db-4.8.30/os_windows/os_yield.c (limited to 'db-4.8.30/os_windows') diff --git a/db-4.8.30/os_windows/ce_ctime.c b/db-4.8.30/os_windows/ce_ctime.c new file mode 100644 index 0000000..1937c0a --- /dev/null +++ b/db-4.8.30/os_windows/ce_ctime.c @@ -0,0 +1,87 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2001-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "db_config.h" + +#include "db_int.h" + +static void __os_windows_ct_numb __P((char *, int)); + +/* + * __os_ctime -- + * Format a time-stamp. + */ +char * +__os_ctime(tod, time_buf) + const time_t *tod; + char *time_buf; +{ + char *ncp; + __int64 i64_tod; + struct _FILETIME file_tod, file_loc; + struct _SYSTEMTIME sys_loc; +static const __int64 SECS_BETWEEN_EPOCHS = 11644473600; +static const __int64 SECS_TO_100NS = 10000000; /* 10^7 */ + + strcpy(time_buf, "Thu Jan 01 00:00:00 1970"); + time_buf[CTIME_BUFLEN - 1] = '\0'; + + /* Convert the tod to a SYSTEM_TIME struct */ + i64_tod = *tod; + i64_tod = (i64_tod + SECS_BETWEEN_EPOCHS)*SECS_TO_100NS; + memcpy(&file_tod, &i64_tod, sizeof(file_tod)); + FileTimeToLocalFileTime(&file_tod, &file_loc); + FileTimeToSystemTime(&file_loc, &sys_loc); + + /* + * Convert the _SYSTEMTIME to the correct format in time_buf. + * Based closely on the os_brew/ctime.c implementation. + * + * wWeekDay : Day of the week 0-6 (0=Monday, 6=Sunday) + */ + ncp = &"MonTueWedThuFriSatSun"[sys_loc.wDayOfWeek*3]; + time_buf[0] = *ncp++; + time_buf[1] = *ncp++; + time_buf[2] = *ncp; + ncp = &"JanFebMarAprMayJunJulAugSepOctNovDec"[(sys_loc.wMonth - 1) * 3]; + time_buf[4] = *ncp++; + time_buf[5] = *ncp++; + time_buf[6] = *ncp; + + __os_windows_ct_numb(time_buf + 8, sys_loc.wDay); + /* Add 100 to keep the leading zero. */ + __os_windows_ct_numb(time_buf + 11, sys_loc.wHour + 100); + __os_windows_ct_numb(time_buf + 14, sys_loc.wMinute + 100); + __os_windows_ct_numb(time_buf + 17, sys_loc.wSecond + 100); + + if (sys_loc.wYear < 100) { /* 9 99 */ + time_buf[20] = ' '; + time_buf[21] = ' '; + __os_windows_ct_numb(time_buf + 22, sys_loc.wYear); + } else { /* 99 1999 */ + __os_windows_ct_numb(time_buf + 20, sys_loc.wYear / 100); + __os_windows_ct_numb(time_buf + 22, sys_loc.wYear % 100 + 100); + } + + return (time_buf); +} + +/* + * __os_windows_ct_numb -- + * Append ASCII representations for two digits to a string. + */ +static void +__os_windows_ct_numb(cp, n) + char *cp; + int n; +{ + cp[0] = ' '; + if (n >= 10) + cp[0] = (n / 10) % 10 + '0'; + cp[1] = n % 10 + '0'; +} diff --git a/db-4.8.30/os_windows/os_abs.c b/db-4.8.30/os_windows/os_abs.c new file mode 100644 index 0000000..4ab39f5 --- /dev/null +++ b/db-4.8.30/os_windows/os_abs.c @@ -0,0 +1,30 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "db_config.h" + +#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-4.8.30/os_windows/os_clock.c b/db-4.8.30/os_windows/os_clock.c new file mode 100644 index 0000000..66c1ece --- /dev/null +++ b/db-4.8.30/os_windows/os_clock.c @@ -0,0 +1,79 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2001-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "db_config.h" + +#include "db_int.h" + +/* + * __os_gettime -- + * Return the current time-of-day clock in seconds and nanoseconds. + */ +void +__os_gettime(env, tp, monotonic) + ENV *env; + db_timespec *tp; + int monotonic; +{ + if (monotonic) { + /* + * The elapsed time is stored as a DWORD value, so time wraps + * around to zero if the system runs for 49.7 days. Initialize + * a base value with 50 days worth of seconds, and add 50 more + * days every time the counter wraps. That ensures we always + * move forward. + * + * It's possible this code could race, but the danger is we + * would increment base_seconds more than once per wrap and + * eventually overflow, which is a pretty remote possibility. + */ +#define TIMER_WRAP_SECONDS (50 * 24 * 60 * 60) + static DWORD last_ticks; + static time_t base_seconds; + DWORD ticks; + + ticks = GetTickCount(); + if (ticks < last_ticks) + base_seconds += TIMER_WRAP_SECONDS; + last_ticks = ticks; + tp->tv_sec = base_seconds + (u_int32_t)(ticks / 1000); + tp->tv_nsec = (u_int32_t)((ticks % 1000) * NS_PER_MS); + } else { +#ifdef DB_WINCE + FILETIME ft; + LARGE_INTEGER large_int; + LONGLONG ns_since_epoch, utc1970; + SYSTEMTIME st; + + (void)GetSystemTime(&st); + (void)SystemTimeToFileTime(&st, &ft); + + /* + * A FILETIME expresses time as 100 nanosecond chunks from + * Jan 1, 1601; convert to a timespec where the time is + * is expressed in seconds and nanoseconds from Jan 1, 1970. + * + * UTC_1970 is the number of 100-nano-second chunks from + * 1601 to 1970. + */ +#define NS100_PER_SEC (NS_PER_SEC / 100) +#define UTC_1970 (((LONGLONG)27111902 << 32) + (LONGLONG)3577643008) + memcpy(&large_int, &ft, sizeof(large_int)); + utc1970 = UTC_1970; + ns_since_epoch = (large_int.QuadPart - utc1970); + tp->tv_sec = (time_t)(ns_since_epoch / NS100_PER_SEC); + tp->tv_nsec = (long)(ns_since_epoch % NS100_PER_SEC); +#else + struct _timeb now; + + _ftime(&now); + tp->tv_sec = now.time; + tp->tv_nsec = now.millitm * NS_PER_MS; +#endif + } +} diff --git a/db-4.8.30/os_windows/os_config.c b/db-4.8.30/os_windows/os_config.c new file mode 100644 index 0000000..5833d58 --- /dev/null +++ b/db-4.8.30/os_windows/os_config.c @@ -0,0 +1,133 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "db_config.h" + +#include "db_int.h" + +/* + * __os_is_winnt -- + * Return 1 if Windows/NT, otherwise 0. + * + * PUBLIC: int __os_is_winnt __P((void)); + */ +int +__os_is_winnt() +{ +#ifdef DB_WINCE + return (1); +#else + 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); +#endif +} + +/* + * __os_fs_notzero -- + * Return 1 if allocated filesystem blocks are not zeroed. + */ +int +__os_fs_notzero() +{ +#ifdef DB_WINCE + return (1); +#else + static int __os_notzero = -1; + OSVERSIONINFO osvi; + + /* + * Windows/NT zero-fills pages that were never explicitly written to + * the file. Note however that this is *NOT* documented. In fact, the + * Win32 documentation makes it clear that there are no guarantees that + * uninitialized bytes will be zeroed: + * + * If the file is extended, the contents of the file between the old + * EOF position and the new position are not defined. + * + * Experiments confirm that NT/2K/XP all zero fill for both NTFS and + * FAT32. Cygwin also relies on this behavior. This is the relevant + * comment from Cygwin: + * + * Oops, this is the bug case - Win95 uses whatever is on the disk + * instead of some known (safe) value, so we must seek back and fill + * in the gap with zeros. - DJ + * Note: this bug doesn't happen on NT4, even though the + * documentation for WriteFile() says that it *may* happen on any OS. + * + * We're making a bet, here, but we made it a long time ago and haven't + * yet seen any evidence that it was wrong. + * + * Windows 95/98 and On-Time give random garbage, and that breaks + * Berkeley DB. + * + * The value of __os_notzero is computed only once, and cached to + * avoid the overhead of repeated calls to GetVersion(). + */ + if (__os_notzero == -1) { + if (__os_is_winnt()) { + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&osvi); + if (_tcscmp(osvi.szCSDVersion, _T("RTTarget-32")) == 0) + __os_notzero = 1; /* On-Time */ + else + __os_notzero = 0; /* Windows/NT */ + } else + __os_notzero = 1; /* Not Windows/NT */ + } + return (__os_notzero); +#endif +} + +/* + * __os_support_direct_io -- + * Check to see if we support direct I/O. + */ +int +__os_support_direct_io() +{ + return (1); +} + +/* + * __os_support_db_register -- + * Return 1 if the system supports DB_REGISTER. + */ +int +__os_support_db_register() +{ +#ifdef DB_WINCE + return (0); +#else + return (__os_is_winnt()); +#endif +} + +/* + * __os_support_replication -- + * Return 1 if the system supports replication. + */ +int +__os_support_replication() +{ +#ifdef DB_WINCE + return (0); +#else + return (__os_is_winnt()); +#endif +} diff --git a/db-4.8.30/os_windows/os_cpu.c b/db-4.8.30/os_windows/os_cpu.c new file mode 100644 index 0000000..5238904 --- /dev/null +++ b/db-4.8.30/os_windows/os_cpu.c @@ -0,0 +1,27 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "db_config.h" + +#include "db_int.h" + +/* + * __os_cpu_count -- + * Return the number of CPUs. + * + * PUBLIC: u_int32_t __os_cpu_count __P((void)); + */ +u_int32_t +__os_cpu_count() +{ + SYSTEM_INFO SystemInfo; + + GetSystemInfo(&SystemInfo); + + return ((u_int32_t)SystemInfo.dwNumberOfProcessors); +} diff --git a/db-4.8.30/os_windows/os_dir.c b/db-4.8.30/os_windows/os_dir.c new file mode 100644 index 0000000..acb646d --- /dev/null +++ b/db-4.8.30/os_windows/os_dir.c @@ -0,0 +1,122 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "db_config.h" + +#include "db_int.h" + +/* + * __os_dirlist -- + * Return a list of the files in a directory. + */ +int +__os_dirlist(env, dir, returndir, namesp, cntp) + ENV *env; + const char *dir; + int returndir, *cntp; + char ***namesp; +{ + HANDLE dirhandle; + WIN32_FIND_DATA fdata; + int arraysz, cnt, ret; + char **names, *onename; + _TCHAR tfilespec[DB_MAXPATHLEN + 1]; + _TCHAR *tdir; + + *namesp = NULL; + *cntp = 0; + + TO_TSTRING(env, dir, tdir, ret); + if (ret != 0) + return (ret); + + (void)_sntprintf(tfilespec, DB_MAXPATHLEN, + _T("%s%hc*"), tdir, PATH_SEPARATOR[0]); + + /* + * On WinCE, FindFirstFile will return INVALID_HANDLE_VALUE when + * the searched directory is empty, and set last error to + * ERROR_NO_MORE_FILES, on Windows it will return "." instead. + */ + if ((dirhandle = + FindFirstFile(tfilespec, &fdata)) == INVALID_HANDLE_VALUE) { + if (GetLastError() == ERROR_NO_MORE_FILES) + return (0); + return (__os_posix_err(__os_get_syserr())); + } + + names = NULL; + arraysz = cnt = ret = 0; + for (;;) { + if (returndir || + (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { + if (fdata.cFileName[0] == _T('.') && + (fdata.cFileName[1] == _T('\0') || + (fdata.cFileName[1] == _T('.') && + fdata.cFileName[2] == _T('\0')))) + goto next; + if (cnt >= arraysz) { + arraysz += 100; + if ((ret = __os_realloc(env, + arraysz * sizeof(names[0]), &names)) != 0) + goto err; + } + /* + * FROM_TSTRING doesn't necessarily allocate new + * memory, so we must do that explicitly. + * Unfortunately, when compiled with UNICODE, we'll + * copy twice. + */ + FROM_TSTRING(env, fdata.cFileName, onename, ret); + if (ret != 0) + goto err; + ret = __os_strdup(env, onename, &names[cnt]); + FREE_STRING(env, onename); + if (ret != 0) + goto err; + cnt++; + } +next: + if (!FindNextFile(dirhandle, &fdata)) { + if (GetLastError() == ERROR_NO_MORE_FILES) + break; + else { + ret = __os_posix_err(__os_get_syserr()); + goto err; + } + } + } + +err: if (!FindClose(dirhandle) && ret == 0) + ret = __os_posix_err(__os_get_syserr()); + + if (ret == 0) { + *namesp = names; + *cntp = cnt; + } else if (names != NULL) + __os_dirfree(env, names, cnt); + + FREE_STRING(env, tdir); + + return (ret); +} + +/* + * __os_dirfree -- + * Free the list of files. + */ +void +__os_dirfree(env, names, cnt) + ENV *env; + char **names; + int cnt; +{ + while (cnt > 0) + __os_free(env, names[--cnt]); + __os_free(env, names); +} diff --git a/db-4.8.30/os_windows/os_errno.c b/db-4.8.30/os_windows/os_errno.c new file mode 100644 index 0000000..35b540b --- /dev/null +++ b/db-4.8.30/os_windows/os_errno.c @@ -0,0 +1,427 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "db_config.h" + +#include "db_int.h" + +/* + * __os_get_errno_ret_zero -- + * Return the last system error, including an error of zero. + */ +int +__os_get_errno_ret_zero() +{ + /* This routine must be able to return the same value repeatedly. */ + return (errno); +} + +/* + * We've seen cases where system calls failed but errno was never set. For + * that reason, __os_get_errno() and __os_get_syserr set errno to EAGAIN if + * it's not already set, to work around the problem. For obvious reasons, + * we can only call this function if we know an error has occurred, that + * is, we can't test the return for a non-zero value after the get call. + * + * __os_get_errno -- + * Return the last ANSI C "errno" value or EAGAIN if the last error + * is zero. + */ +int +__os_get_errno() +{ + /* This routine must be able to return the same value repeatedly. */ + if (errno == 0) + __os_set_errno(EAGAIN); + return (errno); +} + +#ifdef HAVE_REPLICATION_THREADS +/* + * __os_get_neterr -- + * Return the last networking error or EAGAIN if the last error is zero. + * + * PUBLIC: #ifdef HAVE_REPLICATION_THREADS + * PUBLIC: int __os_get_neterr __P((void)); + * PUBLIC: #endif + */ +int +__os_get_neterr() +{ + int err; + + /* This routine must be able to return the same value repeatedly. */ + err = WSAGetLastError(); + if (err == 0) + WSASetLastError(err = ERROR_RETRY); + return (err); +} +#endif + +/* + * __os_get_syserr -- + * Return the last system error or EAGAIN if the last error is zero. + */ +int +__os_get_syserr() +{ + int err; + + /* This routine must be able to return the same value repeatedly. */ + err = GetLastError(); + if (err == 0) + SetLastError(err = ERROR_RETRY); + return (err); +} + +/* + * __os_set_errno -- + * Set the value of errno. + */ +void +__os_set_errno(evalue) + int evalue; +{ + /* + * This routine is called by the compatibility interfaces (DB 1.85, + * dbm and hsearch). Force values > 0, that is, not one of DB 2.X + * and later's public error returns. If something bad has happened, + * default to EFAULT -- a nasty return. Otherwise, default to EINVAL. + * As the compatibility APIs aren't included on Windows, the Windows + * version of this routine doesn't need this behavior. + */ + errno = + evalue >= 0 ? evalue : (evalue == DB_RUNRECOVERY ? EFAULT : EINVAL); +} + +/* + * __os_strerror -- + * Return a string associated with the system error. + */ +char * +__os_strerror(error, buf, len) + int error; + char *buf; + size_t len; +{ +#ifdef DB_WINCE +#define MAX_TMPBUF_LEN 512 + _TCHAR tbuf[MAX_TMPBUF_LEN]; + size_t maxlen; + + DB_ASSERT(NULL, error != 0); + + memset(tbuf, 0, sizeof(_TCHAR)*MAX_TMPBUF_LEN); + maxlen = (len > MAX_TMPBUF_LEN ? MAX_TMPBUF_LEN : len); + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, (DWORD)error, + 0, tbuf, maxlen-1, NULL); + + if (WideCharToMultiByte(CP_UTF8, 0, tbuf, -1, + buf, len, 0, NULL) == 0) + strncpy(buf, "Error message translation failed.", len); +#else + DB_ASSERT(NULL, error != 0); + /* + * Explicitly call FormatMessageA, since we want to receive a char + * string back, not a tchar string. + */ + FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, + 0, (DWORD)error, 0, buf, (DWORD)(len - 1), NULL); + buf[len - 1] = '\0'; +#endif + + return (buf); +} + +/* + * __os_posix_err -- + * Convert a system error to a POSIX error. + */ +int +__os_posix_err(error) + int error; +{ + /* Handle calls on successful returns. */ + if (error == 0) + return (0); + + /* + * Translate the Windows error codes we care about. + */ + switch (error) { + case ERROR_INVALID_PARAMETER: + return (EINVAL); + + case ERROR_FILE_NOT_FOUND: + case ERROR_INVALID_DRIVE: + case ERROR_PATH_NOT_FOUND: + return (ENOENT); + + case ERROR_NO_MORE_FILES: + case ERROR_TOO_MANY_OPEN_FILES: + return (EMFILE); + + case ERROR_ACCESS_DENIED: + return (EPERM); + + case ERROR_INVALID_HANDLE: + return (EBADF); + + case ERROR_NOT_ENOUGH_MEMORY: + return (ENOMEM); + + case ERROR_DISK_FULL: + return (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: + return (EFAULT); + + case ERROR_ALREADY_EXISTS: + case ERROR_FILE_EXISTS: + return (EEXIST); + + case ERROR_NOT_SAME_DEVICE: + return (EXDEV); + + case ERROR_WRITE_PROTECT: + return (EACCES); + + case ERROR_LOCK_FAILED: + case ERROR_LOCK_VIOLATION: + case ERROR_NOT_READY: + case ERROR_SHARING_VIOLATION: + return (EBUSY); + + case ERROR_RETRY: + return (EINTR); + } + + /* + * Translate the Windows socket error codes. + */ + switch (error) { + case WSAEADDRINUSE: +#ifdef EADDRINUSE + return (EADDRINUSE); +#else + break; +#endif + case WSAEADDRNOTAVAIL: +#ifdef EADDRNOTAVAIL + return (EADDRNOTAVAIL); +#else + break; +#endif + case WSAEAFNOSUPPORT: +#ifdef EAFNOSUPPORT + return (EAFNOSUPPORT); +#else + break; +#endif + case WSAEALREADY: +#ifdef EALREADY + return (EALREADY); +#else + break; +#endif + case WSAEBADF: + return (EBADF); + case WSAECONNABORTED: +#ifdef ECONNABORTED + return (ECONNABORTED); +#else + break; +#endif + case WSAECONNREFUSED: +#ifdef ECONNREFUSED + return (ECONNREFUSED); +#else + break; +#endif + case WSAECONNRESET: +#ifdef ECONNRESET + return (ECONNRESET); +#else + break; +#endif + case WSAEDESTADDRREQ: +#ifdef EDESTADDRREQ + return (EDESTADDRREQ); +#else + break; +#endif + case WSAEFAULT: + return (EFAULT); + case WSAEHOSTDOWN: +#ifdef EHOSTDOWN + return (EHOSTDOWN); +#else + break; +#endif + case WSAEHOSTUNREACH: +#ifdef EHOSTUNREACH + return (EHOSTUNREACH); +#else + break; +#endif + case WSAEINPROGRESS: +#ifdef EINPROGRESS + return (EINPROGRESS); +#else + break; +#endif + case WSAEINTR: + return (EINTR); + case WSAEINVAL: + return (EINVAL); + case WSAEISCONN: +#ifdef EISCONN + return (EISCONN); +#else + break; +#endif + case WSAELOOP: +#ifdef ELOOP + return (ELOOP); +#else + break; +#endif + case WSAEMFILE: + return (EMFILE); + case WSAEMSGSIZE: +#ifdef EMSGSIZE + return (EMSGSIZE); +#else + break; +#endif + case WSAENAMETOOLONG: + return (ENAMETOOLONG); + case WSAENETDOWN: +#ifdef ENETDOWN + return (ENETDOWN); +#else + break; +#endif + case WSAENETRESET: +#ifdef ENETRESET + return (ENETRESET); +#else + break; +#endif + case WSAENETUNREACH: +#ifdef ENETUNREACH + return (ENETUNREACH); +#else + break; +#endif + case WSAENOBUFS: +#ifdef ENOBUFS + return (ENOBUFS); +#else + break; +#endif + case WSAENOPROTOOPT: +#ifdef ENOPROTOOPT + return (ENOPROTOOPT); +#else + break; +#endif + case WSAENOTCONN: +#ifdef ENOTCONN + return (ENOTCONN); +#else + break; +#endif + case WSANOTINITIALISED: + return (EAGAIN); + case WSAENOTSOCK: +#ifdef ENOTSOCK + return (ENOTSOCK); +#else + break; +#endif + case WSAEOPNOTSUPP: + return (DB_OPNOTSUP); + case WSAEPFNOSUPPORT: +#ifdef EPFNOSUPPORT + return (EPFNOSUPPORT); +#else + break; +#endif + case WSAEPROTONOSUPPORT: +#ifdef EPROTONOSUPPORT + return (EPROTONOSUPPORT); +#else + break; +#endif + case WSAEPROTOTYPE: +#ifdef EPROTOTYPE + return (EPROTOTYPE); +#else + break; +#endif + case WSAESHUTDOWN: +#ifdef ESHUTDOWN + return (ESHUTDOWN); +#else + break; +#endif + case WSAESOCKTNOSUPPORT: +#ifdef ESOCKTNOSUPPORT + return (ESOCKTNOSUPPORT); +#else + break; +#endif + case WSAETIMEDOUT: +#ifdef ETIMEDOUT + return (ETIMEDOUT); +#else + break; +#endif + case WSAETOOMANYREFS: +#ifdef ETOOMANYREFS + return (ETOOMANYREFS); +#else + break; +#endif + case WSAEWOULDBLOCK: +#ifdef EWOULDBLOCK + return (EWOULDBLOCK); +#else + return (EAGAIN); +#endif + case WSAHOST_NOT_FOUND: +#ifdef EHOSTUNREACH + return (EHOSTUNREACH); +#else + break; +#endif + case WSASYSNOTREADY: + return (EAGAIN); + case WSATRY_AGAIN: + return (EAGAIN); + case WSAVERNOTSUPPORTED: + return (DB_OPNOTSUP); + case WSAEACCES: + return (EACCES); + } + + /* + * EFAULT is the default if we don't have a translation. + */ + return (EFAULT); +} diff --git a/db-4.8.30/os_windows/os_fid.c b/db-4.8.30/os_windows/os_fid.c new file mode 100644 index 0000000..3283ea5 --- /dev/null +++ b/db-4.8.30/os_windows/os_fid.c @@ -0,0 +1,129 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "db_config.h" + +#include "db_int.h" + +/* + * __os_fileid -- + * Return a unique identifier for a file. + */ +int +__os_fileid(env, fname, unique_okay, fidp) + ENV *env; + const char *fname; + int unique_okay; + u_int8_t *fidp; +{ + pid_t pid; + 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 *fhp; + BY_HANDLE_FILE_INFORMATION fi; + BOOL retval = FALSE; + + DB_ASSERT(env, fname != NULL); + + /* Clear the buffer. */ + memset(fidp, 0, DB_FILE_ID_LEN); + + /* + * 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(env, fname, 0, + DB_OSO_RDONLY, DB_MODE_400, &fhp)) != 0) + return (ret); + + /* File open, get its info */ + if ((retval = GetFileInformationByHandle(fhp->handle, &fi)) == FALSE) + ret = __os_get_syserr(); + (void)__os_closehandle(env, fhp); + + if (retval == FALSE) + return (__os_posix_err(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) { + /* Add in 32-bits of (hopefully) unique number. */ + __os_unique_id(env, &tmp); + for (p = (u_int8_t *)&tmp, i = sizeof(u_int32_t); i > 0; --i) + *fidp++ = *p++; + + /* + * Initialize/increment the serial number we use to help + * avoid fileid collisions. Note 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 use the bottom 32-bits of the process ID, hoping they + * are more random than the top 32-bits (should we be on a + * machine with 64-bit process IDs). + * + * 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 + * 32-bit platforms, and has few interesting properties in + * base 2. + */ + if (DB_GLOBAL(fid_serial) == 0) { + __os_id(env->dbenv, &pid, NULL); + DB_GLOBAL(fid_serial) = (u_int32_t)pid; + } else + DB_GLOBAL(fid_serial) += 100000; + + } 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-4.8.30/os_windows/os_flock.c b/db-4.8.30/os_windows/os_flock.c new file mode 100644 index 0000000..df2492f --- /dev/null +++ b/db-4.8.30/os_windows/os_flock.c @@ -0,0 +1,88 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "db_config.h" + +#include "db_int.h" + +/* + * __os_fdlock -- + * Acquire/release a lock on a byte in a file. + */ +int +__os_fdlock(env, fhp, offset, acquire, nowait) + ENV *env; + DB_FH *fhp; + int acquire, nowait; + off_t offset; +{ +#ifdef DB_WINCE + /* + * This functionality is not supported by WinCE, so just fail. + * + * Should only happen if an app attempts to open an environment + * with the DB_REGISTER flag. + */ + __db_errx(env, "fdlock API not implemented for WinCE, DB_REGISTER " + "environment flag not supported."); + return (EFAULT); +#else + DWORD low, high; + DB_ENV *dbenv; + OVERLAPPED over; + int ret; + + dbenv = env == NULL ? NULL : env->dbenv; + + DB_ASSERT(env, + F_ISSET(fhp, DB_FH_OPENED) && fhp->handle != INVALID_HANDLE_VALUE); + + if (dbenv != NULL && FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS_ALL)) + __db_msg(env, + "fileops: flock %s %s offset %lu", + fhp->name, acquire ? "acquire": "release", (u_long)offset); + + /* + * Windows file locking interferes with read/write operations, so we + * map the ranges to an area past the end of the file. + */ + DB_ASSERT(env, offset < (u_int64_t)INT64_MAX); + offset = UINT64_MAX - offset; + low = (DWORD)offset; + high = (DWORD)(offset >> 32); + + if (acquire) { + if (nowait) + RETRY_CHK_EINTR_ONLY( + !LockFile(fhp->handle, low, high, 1, 0), ret); + else if (__os_is_winnt()) { + memset(&over, 0, sizeof(over)); + over.Offset = low; + over.OffsetHigh = high; + RETRY_CHK_EINTR_ONLY( + !LockFileEx(fhp->handle, LOCKFILE_EXCLUSIVE_LOCK, + 0, 1, 0, &over), + ret); + } else { + /* Windows 9x/ME doesn't support a blocking call. */ + for (;;) { + RETRY_CHK_EINTR_ONLY( + !LockFile(fhp->handle, low, high, 1, 0), + ret); + if (__os_posix_err(ret) != EAGAIN) + break; + __os_yield(env, 1, 0); + } + } + } else + RETRY_CHK_EINTR_ONLY( + !UnlockFile(fhp->handle, low, high, 1, 0), ret); + + return (__os_posix_err(ret)); +#endif +} diff --git a/db-4.8.30/os_windows/os_fsync.c b/db-4.8.30/os_windows/os_fsync.c new file mode 100644 index 0000000..0e57cb4 --- /dev/null +++ b/db-4.8.30/os_windows/os_fsync.c @@ -0,0 +1,43 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "db_config.h" + +#include "db_int.h" + +/* + * __os_fsync -- + * Flush a file descriptor. + */ +int +__os_fsync(env, fhp) + ENV *env; + DB_FH *fhp; +{ + DB_ENV *dbenv; + int ret; + + dbenv = env == NULL ? NULL : env->dbenv; + + /* + * Do nothing if the file descriptor has been marked as not requiring + * any sync to disk. + */ + if (F_ISSET(fhp, DB_FH_NOSYNC)) + return (0); + + if (dbenv != NULL && FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS_ALL)) + __db_msg(env, "fileops: flush %s", fhp->name); + + RETRY_CHK((!FlushFileBuffers(fhp->handle)), ret); + if (ret != 0) { + __db_syserr(env, ret, "FlushFileBuffers"); + ret = __os_posix_err(ret); + } + return (ret); +} diff --git a/db-4.8.30/os_windows/os_getenv.c b/db-4.8.30/os_windows/os_getenv.c new file mode 100644 index 0000000..0f4cb12 --- /dev/null +++ b/db-4.8.30/os_windows/os_getenv.c @@ -0,0 +1,102 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "db_config.h" + +#include "db_int.h" + +/* + * __os_getenv -- + * Retrieve an environment variable. + */ +int +__os_getenv(env, name, bpp, buflen) + ENV *env; + const char *name; + char **bpp; + size_t buflen; +{ +#ifdef DB_WINCE + COMPQUIET(name, NULL); + /* WinCE does not have a getenv implementation. */ + return (0); +#else + _TCHAR *tname, tbuf[1024]; + int ret; + char *p; + + /* + * If there's a value and the buffer is large enough: + * copy value into the pointer, return 0 + * If there's a value and the buffer is too short: + * set pointer to NULL, return EINVAL + * If there's no value: + * set pointer to NULL, return 0 + */ + if ((p = getenv(name)) != NULL) { + if (strlen(p) < buflen) { + (void)strcpy(*bpp, p); + return (0); + } + goto small_buf; + } + + TO_TSTRING(env, name, tname, ret); + if (ret != 0) + return (ret); + /* + * The declared size of the tbuf buffer limits the maximum environment + * variable size in Berkeley DB on Windows. If that's too small, or if + * we need to get rid of large allocations on the BDB stack, we should + * malloc the tbuf memory. + */ + ret = GetEnvironmentVariable(tname, tbuf, sizeof(tbuf)); + FREE_STRING(env, tname); + + /* + * If GetEnvironmentVariable succeeds, the return value is the number + * of characters stored in the buffer pointed to by lpBuffer, not + * including the terminating null character. If the buffer is not + * large enough to hold the data, the return value is the buffer size, + * in characters, required to hold the string and its terminating null + * character. If GetEnvironmentVariable fails, the return value is + * zero. If the specified environment variable was not found in the + * environment block, GetLastError returns ERROR_ENVVAR_NOT_FOUND. + */ + if (ret == 0) { + if ((ret = __os_get_syserr()) == ERROR_ENVVAR_NOT_FOUND) { + *bpp = NULL; + return (0); + } + __db_syserr(env, ret, "GetEnvironmentVariable"); + return (__os_posix_err(ret)); + } + if (ret > (int)sizeof(tbuf)) + goto small_buf; + + FROM_TSTRING(env, tbuf, p, ret); + if (ret != 0) + return (ret); + if (strlen(p) < buflen) + (void)strcpy(*bpp, p); + else + *bpp = NULL; + FREE_STRING(env, p); + if (*bpp == NULL) + goto small_buf; + + return (0); + +small_buf: + *bpp = NULL; + __db_errx(env, + "%s: buffer too small to hold environment variable %s", + name, p); + return (EINVAL); +#endif +} diff --git a/db-4.8.30/os_windows/os_handle.c b/db-4.8.30/os_windows/os_handle.c new file mode 100644 index 0000000..74681e3 --- /dev/null +++ b/db-4.8.30/os_windows/os_handle.c @@ -0,0 +1,165 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1998-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "db_config.h" + +#include "db_int.h" + +/* + * __os_openhandle -- + * Open a file, using POSIX 1003.1 open flags. + */ +int +__os_openhandle(env, name, flags, mode, fhpp) + ENV *env; + const char *name; + int flags, mode; + DB_FH **fhpp; +{ +#ifdef DB_WINCE + /* + * __os_openhandle API is not implemented on WinCE. + * It is not currently called from within the Berkeley DB library, + * so don't log the failure via the __db_err mechanism. + */ + return (EFAULT); +#else + DB_FH *fhp; + int ret, nrepeat, retries; + + /* + * Allocate the file handle and copy the file name. We generally only + * use the name for verbose or error messages, but on systems where we + * can't unlink temporary files immediately, we use the name to unlink + * the temporary file when the file handle is closed. + * + * Lock the ENV handle and insert the new file handle on the list. + */ + if ((ret = __os_calloc(env, 1, sizeof(DB_FH), &fhp)) != 0) + return (ret); + if ((ret = __os_strdup(env, name, &fhp->name)) != 0) + goto err; + if (env != NULL) { + MUTEX_LOCK(env, env->mtx_env); + TAILQ_INSERT_TAIL(&env->fdlist, fhp, q); + MUTEX_UNLOCK(env, env->mtx_env); + F_SET(fhp, DB_FH_ENVLINK); + } + + retries = 0; + for (nrepeat = 1; nrepeat < 4; ++nrepeat) { + fhp->fd = _open(name, flags, mode); + + if (fhp->fd != -1) { + ret = 0; + break; + } + + switch (ret = __os_posix_err(__os_get_syserr())) { + case EMFILE: + case ENFILE: + case ENOSPC: + /* + * 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. + */ + __os_yield(env, nrepeat * 2, 0); + break; + case EAGAIN: + case EBUSY: + case EINTR: + /* + * If an EAGAIN, EBUSY or EINTR, retry immediately for + * DB_RETRY times. + */ + if (++retries < DB_RETRY) + --nrepeat; + break; + default: + /* Open is silent on error. */ + goto err; + } + } + + if (ret == 0) { + F_SET(fhp, DB_FH_OPENED); + *fhpp = fhp; + return (0); + } + +err: (void)__os_closehandle(env, fhp); + return (ret); +#endif +} + +/* + * __os_closehandle -- + * Close a file. + */ +int +__os_closehandle(env, fhp) + ENV *env; + DB_FH *fhp; +{ + DB_ENV *dbenv; + int ret, t_ret; + + ret = 0; + + if (env != NULL) { + dbenv = env->dbenv; + if (fhp->name != NULL && FLD_ISSET( + dbenv->verbose, DB_VERB_FILEOPS | DB_VERB_FILEOPS_ALL)) + __db_msg(env, "fileops: %s: close", fhp->name); + + if (F_ISSET(fhp, DB_FH_ENVLINK)) { + /* + * Lock the ENV handle and remove this file + * handle from the list. + */ + MUTEX_LOCK(env, env->mtx_env); + TAILQ_REMOVE(&env->fdlist, fhp, q); + MUTEX_UNLOCK(env, env->mtx_env); + } + } + + /* Discard any underlying system file reference. */ + if (F_ISSET(fhp, DB_FH_OPENED)) { + if (fhp->handle != INVALID_HANDLE_VALUE) + RETRY_CHK((!CloseHandle(fhp->handle)), ret); + else +#ifdef DB_WINCE + ret = EFAULT; +#else + RETRY_CHK((_close(fhp->fd)), ret); +#endif + + if (fhp->trunc_handle != INVALID_HANDLE_VALUE) { + RETRY_CHK((!CloseHandle(fhp->trunc_handle)), t_ret); + if (t_ret != 0 && ret == 0) + ret = t_ret; + } + + if (ret != 0) { + __db_syserr(env, ret, "CloseHandle"); + ret = __os_posix_err(ret); + } + } + + /* Unlink the file if we haven't already done so. */ + if (F_ISSET(fhp, DB_FH_UNLINK)) + (void)__os_unlink(env, fhp->name, 0); + + if (fhp->name != NULL) + __os_free(env, fhp->name); + __os_free(env, fhp); + + return (ret); +} diff --git a/db-4.8.30/os_windows/os_map.c b/db-4.8.30/os_windows/os_map.c new file mode 100644 index 0000000..0889969 --- /dev/null +++ b/db-4.8.30/os_windows/os_map.c @@ -0,0 +1,362 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "db_config.h" + +#include "db_int.h" + +static int __os_map + __P((ENV *, char *, REGINFO *, DB_FH *, size_t, int, int, int, void **)); +static int __os_unique_name __P((_TCHAR *, HANDLE, _TCHAR *, size_t)); + +/* + * __os_attach -- + * Create/join a shared memory region. + */ +int +__os_attach(env, infop, rp) + ENV *env; + REGINFO *infop; + REGION *rp; +{ + DB_FH *fhp; + int ret; + + /* + * On Windows/9X, files that are opened by multiple processes do not + * share data correctly. For this reason, we require that DB_PRIVATE + * be specified on that platform. + */ + if (!F_ISSET(env, ENV_PRIVATE) && __os_is_winnt() == 0) { + __db_err(env, + EINVAL, "Windows 9X systems must specify DB_PRIVATE"); + return (EINVAL); + } + + /* + * 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(env, infop->name, 0, DB_OSO_REGION | + (F_ISSET(infop, REGION_CREATE_OK) ? DB_OSO_CREATE : 0), + env->db_mode, &fhp)) != 0) { + __db_err(env, ret, "%s", infop->name); + return (ret); + } + + /* + * 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(env, infop->name, infop, fhp, rp->size, + 1, F_ISSET(env, ENV_SYSTEM_MEM), 0, &infop->addr); + if (ret == 0 && F_ISSET(env, ENV_SYSTEM_MEM)) + rp->segid = 1; + + (void)__os_closehandle(env, fhp); + + return (ret); +} + +/* + * __os_detach -- + * Detach from a shared memory region. + */ +int +__os_detach(env, infop, destroy) + ENV *env; + REGINFO *infop; + int destroy; +{ + DB_ENV *dbenv; + int ret, t_ret; + + dbenv = env->dbenv; + + if (infop->wnt_handle != NULL) { + (void)CloseHandle(infop->wnt_handle); + infop->wnt_handle = NULL; + } + + ret = !UnmapViewOfFile(infop->addr) ? __os_get_syserr() : 0; + if (ret != 0) { + __db_syserr(env, ret, "UnmapViewOfFile"); + ret = __os_posix_err(ret); + } + + if (!F_ISSET(env, ENV_SYSTEM_MEM) && destroy && + (t_ret = __os_unlink(env, infop->name, 1)) != 0 && ret == 0) + ret = t_ret; + + return (ret); +} + +/* + * __os_mapfile -- + * Map in a shared memory file. + */ +int +__os_mapfile(env, path, fhp, len, is_rdonly, addr) + ENV *env; + char *path; + DB_FH *fhp; + int is_rdonly; + size_t len; + void **addr; +{ +#ifdef DB_WINCE + /* + * Windows CE has special requirements for file mapping to work. + * * The input handle needs to be opened using CreateFileForMapping + * * Concurrent access via a non mapped file is not supported. + * So we disable support for memory mapping files on Windows CE. It is + * currently only used as an optimization in mpool for small read only + * databases. + */ + return (EFAULT); +#else + DB_ENV *dbenv; + + dbenv = env == NULL ? NULL : env->dbenv; + + if (dbenv != NULL && + FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS | DB_VERB_FILEOPS_ALL)) + __db_msg(env, "fileops: mmap %s", path); + return (__os_map(env, path, NULL, fhp, len, 0, 0, is_rdonly, addr)); +#endif +} + +/* + * __os_unmapfile -- + * Unmap the shared memory file. + */ +int +__os_unmapfile(env, addr, len) + ENV *env; + void *addr; + size_t len; +{ + DB_ENV *dbenv; + + dbenv = env == NULL ? NULL : env->dbenv; + + if (dbenv != NULL && + FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS | DB_VERB_FILEOPS_ALL)) + __db_msg(env, "fileops: munmap"); + + return (!UnmapViewOfFile(addr) ? __os_posix_err(__os_get_syserr()) : 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 file index, found in the file + * information structure (similar to UNIX inode #). + * + * When a file is deleted, its file index may be reused, + * but if the unique name has not gone from its namespace, + * we may get a conflict. So to ensure some tie in to the + * original pathname, we also use the creation time and the + * file basename. This is not a perfect system, but it + * should work for all but anamolous test cases. + * + */ +static int +__os_unique_name(orig_path, hfile, result_path, result_path_len) + _TCHAR *orig_path, *result_path; + HANDLE hfile; + size_t result_path_len; +{ + BY_HANDLE_FILE_INFORMATION fileinfo; + _TCHAR *basename, *p; + + /* + * In Windows, pathname components are delimited by '/' or '\', and + * if neither is present, we need to strip off leading drive letter + * (e.g. c:foo.txt). + */ + basename = _tcsrchr(orig_path, '/'); + p = _tcsrchr(orig_path, '\\'); + if (basename == NULL || (p != NULL && p > basename)) + basename = p; + if (basename == NULL) + basename = _tcsrchr(orig_path, ':'); + + if (basename == NULL) + basename = orig_path; + else + basename++; + + if (!GetFileInformationByHandle(hfile, &fileinfo)) + return (__os_posix_err(__os_get_syserr())); + + (void)_sntprintf(result_path, result_path_len, + _T("__db_shmem.%8.8lx.%8.8lx.%8.8lx.%8.8lx.%8.8lx.%s"), + fileinfo.dwVolumeSerialNumber, + fileinfo.nFileIndexHigh, + fileinfo.nFileIndexLow, + fileinfo.ftCreationTime.dwHighDateTime, + fileinfo.ftCreationTime.dwHighDateTime, + basename); + + return (0); +} + +/* + * __os_map -- + * The mmap(2) function for Windows. + */ +static int +__os_map(env, path, infop, fhp, len, is_region, is_system, is_rdonly, addr) + ENV *env; + REGINFO *infop; + char *path; + DB_FH *fhp; + int is_region, is_system, is_rdonly; + size_t len; + void **addr; +{ + HANDLE hMemory; + int ret, use_pagefile; + _TCHAR *tpath, shmem_name[DB_MAXPATHLEN]; + void *pMemory; + unsigned __int64 len64; + + ret = 0; + if (infop != NULL) + infop->wnt_handle = NULL; + + /* + * On 64 bit systems, len is already a 64 bit value. + * On 32 bit systems len is a 32 bit value. + * Always convert to a 64 bit value, so that the high order + * DWORD can be simply extracted on 64 bit platforms. + */ + len64 = len; + + 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) { +#ifdef DB_WINCE + __db_errx(env, "Unable to memory map regions using system " + "memory on WinCE."); + return (EFAULT); +#endif + TO_TSTRING(env, path, tpath, ret); + if (ret != 0) + return (ret); + ret = __os_unique_name(tpath, fhp->handle, + shmem_name, sizeof(shmem_name)); + FREE_STRING(env, tpath); + if (ret != 0) + return (ret); + } + + /* + * XXX + * DB: We have not implemented copy-on-write here. + * + * If this is an region in system memory, we try to open it using the + * OpenFileMapping() first, and only call CreateFileMapping() if we're + * really creating the section. There are two reasons: + * + * 1) We only create the mapping if we have newly created the region. + * This avoids a long-running problem caused by Windows reference + * counting, where regions that are closed by all processes are + * deleted. It turns out that just checking for a zeroed region + * is not good enough. See [#4882] and [#7127] for the details. + * + * 2) CreateFileMapping 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. + */ + hMemory = NULL; + if (use_pagefile) { +#ifndef DB_WINCE + hMemory = OpenFileMapping( + is_rdonly ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS, + 0, shmem_name); + + if (hMemory == NULL && F_ISSET(infop, REGION_CREATE_OK)) + hMemory = CreateFileMapping((HANDLE)-1, 0, + is_rdonly ? PAGE_READONLY : PAGE_READWRITE, + (DWORD)(len64 >> 32), (DWORD)len64, shmem_name); +#endif + } else { + hMemory = CreateFileMapping(fhp->handle, 0, + is_rdonly ? PAGE_READONLY : PAGE_READWRITE, + (DWORD)(len64 >> 32), (DWORD)len64, NULL); +#ifdef DB_WINCE + /* + * WinCE automatically closes the handle passed in. + * Ensure DB does not attempt to close the handle again. + */ + fhp->handle = INVALID_HANDLE_VALUE; + F_CLR(fhp, DB_FH_OPENED); +#endif + } + + if (hMemory == NULL) { + ret = __os_get_syserr(); + __db_syserr(env, ret, "OpenFileMapping"); + return (__env_panic(env, __os_posix_err(ret))); + } + + pMemory = MapViewOfFile(hMemory, + (is_rdonly ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS), 0, 0, len); + if (pMemory == NULL) { + ret = __os_get_syserr(); + __db_syserr(env, ret, "MapViewOfFile"); + return (__env_panic(env, __os_posix_err(ret))); + } + + /* + * 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. + */ + if (use_pagefile && infop != NULL) + infop->wnt_handle = hMemory; + else + CloseHandle(hMemory); + + *addr = pMemory; + return (ret); +} diff --git a/db-4.8.30/os_windows/os_mkdir.c b/db-4.8.30/os_windows/os_mkdir.c new file mode 100644 index 0000000..b739986 --- /dev/null +++ b/db-4.8.30/os_windows/os_mkdir.c @@ -0,0 +1,43 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "db_config.h" + +#include "db_int.h" + +/* + * __os_mkdir -- + * Create a directory. + */ +int +__os_mkdir(env, name, mode) + ENV *env; + const char *name; + int mode; +{ + DB_ENV *dbenv; + _TCHAR *tname; + int ret; + + dbenv = env == NULL ? NULL : env->dbenv; + + if (dbenv != NULL && + FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS | DB_VERB_FILEOPS_ALL)) + __db_msg(env, "fileops: mkdir %s", name); + + /* Make the directory, with paranoid permissions. */ + TO_TSTRING(env, name, tname, ret); + if (ret != 0) + return (ret); + RETRY_CHK(!CreateDirectory(tname, NULL), ret); + FREE_STRING(env, tname); + if (ret != 0) + return (__os_posix_err(ret)); + + return (ret); +} diff --git a/db-4.8.30/os_windows/os_open.c b/db-4.8.30/os_windows/os_open.c new file mode 100644 index 0000000..e15222f --- /dev/null +++ b/db-4.8.30/os_windows/os_open.c @@ -0,0 +1,255 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "db_config.h" + +#include "db_int.h" + +/* + * __os_open -- + * Open a file descriptor (including page size and log size information). + */ +int +__os_open(env, name, page_size, flags, mode, fhpp) + ENV *env; + const char *name; + u_int32_t page_size, flags; + int mode; + DB_FH **fhpp; +{ + DB_ENV *dbenv; + DB_FH *fhp; +#ifndef DB_WINCE + DWORD cluster_size, sector_size, free_clusters, total_clusters; + _TCHAR *drive, dbuf[4]; /* */ +#endif + int access, attr, createflag, nrepeat, ret, share; + _TCHAR *tname; + + dbenv = env == NULL ? NULL : env->dbenv; + *fhpp = NULL; + tname = NULL; + + if (dbenv != NULL && + FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS | DB_VERB_FILEOPS_ALL)) + __db_msg(env, "fileops: open %s", name); + +#define OKFLAGS \ + (DB_OSO_ABSMODE | DB_OSO_CREATE | DB_OSO_DIRECT | DB_OSO_DSYNC |\ + DB_OSO_EXCL | DB_OSO_RDONLY | DB_OSO_REGION | DB_OSO_SEQ | \ + DB_OSO_TEMP | DB_OSO_TRUNC) + if ((ret = __db_fchk(env, "__os_open", flags, OKFLAGS)) != 0) + return (ret); + + TO_TSTRING(env, name, tname, ret); + if (ret != 0) + goto err; + + /* + * Allocate the file handle and copy the file name. We generally only + * use the name for verbose or error messages, but on systems where we + * can't unlink temporary files immediately, we use the name to unlink + * the temporary file when the file handle is closed. + * + * Lock the ENV handle and insert the new file handle on the list. + */ + if ((ret = __os_calloc(env, 1, sizeof(DB_FH), &fhp)) != 0) + return (ret); + if ((ret = __os_strdup(env, name, &fhp->name)) != 0) + goto err; + if (env != NULL) { + MUTEX_LOCK(env, env->mtx_env); + TAILQ_INSERT_TAIL(&env->fdlist, fhp, q); + MUTEX_UNLOCK(env, env->mtx_env); + F_SET(fhp, DB_FH_ENVLINK); + } + + /* + * Otherwise, use the Windows/32 CreateFile interface so that we can + * play magic games with 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. + */ + access = GENERIC_READ; + if (!LF_ISSET(DB_OSO_RDONLY)) + access |= GENERIC_WRITE; + +#ifdef DB_WINCE + /* + * WinCE translates these flags into share flags for + * CreateFileForMapping. + * Also WinCE does not support the FILE_SHARE_DELETE flag. + */ + if (LF_ISSET(DB_OSO_REGION)) + share = GENERIC_READ | GENERIC_WRITE; + else + share = FILE_SHARE_READ | FILE_SHARE_WRITE; +#else + share = FILE_SHARE_READ | FILE_SHARE_WRITE; + if (__os_is_winnt()) + share |= FILE_SHARE_DELETE; +#endif + 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_DSYNC)) { + F_SET(fhp, DB_FH_NOSYNC); + attr |= FILE_FLAG_WRITE_THROUGH; + } + +#ifndef DB_WINCE + if (LF_ISSET(DB_OSO_SEQ)) + attr |= FILE_FLAG_SEQUENTIAL_SCAN; + else + attr |= FILE_FLAG_RANDOM_ACCESS; +#endif + + if (LF_ISSET(DB_OSO_TEMP)) + attr |= FILE_FLAG_DELETE_ON_CLOSE; + + /* + * We can turn filesystem buffering off if the page size is a + * multiple of the disk's sector size. To find the sector size, + * we call GetDiskFreeSpace, which expects a drive name like "d:\\" + * or NULL for the current disk (i.e., a relative path). + * + * WinCE only has GetDiskFreeSpaceEx which does not + * return the sector size. + */ +#ifndef DB_WINCE + if (LF_ISSET(DB_OSO_DIRECT) && page_size != 0 && name[0] != '\0') { + if (name[1] == ':') { + drive = dbuf; + _sntprintf(dbuf, sizeof(dbuf), _T("%c:\\"), tname[0]); + } else + drive = NULL; + + /* + * We ignore all results except sectorsize, but some versions + * of Windows require that the parameters are non-NULL. + */ + if (GetDiskFreeSpace(drive, &cluster_size, + §or_size, &free_clusters, &total_clusters) && + page_size % sector_size == 0) + attr |= FILE_FLAG_NO_BUFFERING; + } +#endif + + fhp->handle = fhp->trunc_handle = INVALID_HANDLE_VALUE; + for (nrepeat = 1;; ++nrepeat) { + if (fhp->handle == INVALID_HANDLE_VALUE) { +#ifdef DB_WINCE + if (LF_ISSET(DB_OSO_REGION)) + fhp->handle = CreateFileForMapping(tname, + access, share, NULL, createflag, attr, 0); + else +#endif + fhp->handle = CreateFile(tname, + access, share, NULL, createflag, attr, 0); + } + +#ifdef HAVE_FTRUNCATE + /* + * Older versions of WinCE may not support truncate, if so, the + * HAVE_FTRUNCATE macro should be #undef'ed, and we + * don't need to open this second handle. + * + * WinCE dose not support opening a second handle on the same + * file via CreateFileForMapping, but this dose not matter + * since we are not truncating region files but database files. + * + * But some older versions of WinCE even + * dose not allow a second handle opened via CreateFile. If + * this is the case, users will need to #undef the + * HAVE_FTRUNCATE macro in build_wince/db_config.h. + */ + + /* + * Windows does not provide truncate directly. There is no + * safe way to use a handle for truncate concurrently with + * reads or writes. To deal with this, we open a second handle + * used just for truncating. + */ + if (fhp->handle != INVALID_HANDLE_VALUE && + !LF_ISSET(DB_OSO_RDONLY | DB_OSO_TEMP) && + fhp->trunc_handle == INVALID_HANDLE_VALUE +#ifdef DB_WINCE + /* Do not open trunc handle for region files. */ + && (!LF_ISSET(DB_OSO_REGION)) +#endif + ) + fhp->trunc_handle = CreateFile( + tname, access, share, NULL, OPEN_EXISTING, attr, 0); +#endif + +#ifndef HAVE_FTRUNCATE + if (fhp->handle == INVALID_HANDLE_VALUE) +#else + if (fhp->handle == INVALID_HANDLE_VALUE || + (!LF_ISSET(DB_OSO_RDONLY | DB_OSO_TEMP) && + fhp->trunc_handle == INVALID_HANDLE_VALUE +#ifdef DB_WINCE + /* Do not open trunc handle for region files. */ + && (!LF_ISSET(DB_OSO_REGION)) +#endif + )) +#endif + { + /* + * 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_posix_err(__os_get_syserr()); + if ((ret != ENFILE && ret != EMFILE && ret != ENOSPC) || + nrepeat > 3) + goto err; + + __os_yield(env, nrepeat * 2, 0); + } else + break; + } + + FREE_STRING(env, tname); + + if (LF_ISSET(DB_OSO_REGION)) + F_SET(fhp, DB_FH_REGION); + F_SET(fhp, DB_FH_OPENED); + *fhpp = fhp; + return (0); + +err: FREE_STRING(env, tname); + if (fhp != NULL) + (void)__os_closehandle(env, fhp); + return (ret); +} diff --git a/db-4.8.30/os_windows/os_rename.c b/db-4.8.30/os_windows/os_rename.c new file mode 100644 index 0000000..9312d8a --- /dev/null +++ b/db-4.8.30/os_windows/os_rename.c @@ -0,0 +1,81 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "db_config.h" + +#include "db_int.h" + +/* + * __os_rename -- + * Rename a file. + */ +int +__os_rename(env, oldname, newname, silent) + ENV *env; + const char *oldname, *newname; + u_int32_t silent; +{ + DB_ENV *dbenv; + _TCHAR *toldname, *tnewname; + int ret; + + dbenv = env == NULL ? NULL : env->dbenv; + + if (dbenv != NULL && + FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS | DB_VERB_FILEOPS_ALL)) + __db_msg(env, "fileops: rename %s to %s", oldname, newname); + + TO_TSTRING(env, oldname, toldname, ret); + if (ret != 0) + return (ret); + TO_TSTRING(env, newname, tnewname, ret); + if (ret != 0) { + FREE_STRING(env, toldname); + return (ret); + } + + LAST_PANIC_CHECK_BEFORE_IO(env); + + if (!MoveFile(toldname, tnewname)) + ret = __os_get_syserr(); + + if (__os_posix_err(ret) == EEXIST) { + ret = 0; +#ifndef DB_WINCE + if (__os_is_winnt()) { + if (!MoveFileEx( + toldname, tnewname, MOVEFILE_REPLACE_EXISTING)) + ret = __os_get_syserr(); + } else +#endif + { + /* + * There is no MoveFileEx for Win9x/Me/CE, so we have to + * do the best we can. Note that the MoveFile call + * above would have succeeded if oldname and newname + * refer to the same file, so we don't need to check + * that here. + */ + (void)DeleteFile(tnewname); + if (!MoveFile(toldname, tnewname)) + ret = __os_get_syserr(); + } + } + + FREE_STRING(env, tnewname); + FREE_STRING(env, toldname); + + if (ret != 0) { + if (silent == 0) + __db_syserr( + env, ret, "MoveFileEx %s %s", oldname, newname); + ret = __os_posix_err(ret); + } + + return (ret); +} diff --git a/db-4.8.30/os_windows/os_rw.c b/db-4.8.30/os_windows/os_rw.c new file mode 100644 index 0000000..5e46e03 --- /dev/null +++ b/db-4.8.30/os_windows/os_rw.c @@ -0,0 +1,215 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "db_config.h" + +#include "db_int.h" + +/* + * __os_io -- + * Do an I/O. + */ +int +__os_io(env, op, fhp, pgno, pgsize, relative, io_len, buf, niop) + ENV *env; + int op; + DB_FH *fhp; + db_pgno_t pgno; + u_int32_t pgsize, relative, io_len; + u_int8_t *buf; + size_t *niop; +{ + int ret; + +#ifndef DB_WINCE + if (__os_is_winnt()) { + DB_ENV *dbenv; + DWORD nbytes; + OVERLAPPED over; + ULONG64 off; + dbenv = env == NULL ? NULL : env->dbenv; + if ((off = relative) == 0) + off = (ULONG64)pgsize * pgno; + over.Offset = (DWORD)(off & 0xffffffff); + over.OffsetHigh = (DWORD)(off >> 32); + over.hEvent = 0; /* we don't want asynchronous notifications */ + + if (dbenv != NULL && + FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS_ALL)) + __db_msg(env, + "fileops: %s %s: %lu bytes at offset %lu", + op == DB_IO_READ ? "read" : "write", + fhp->name, (u_long)io_len, (u_long)off); + + LAST_PANIC_CHECK_BEFORE_IO(env); + + switch (op) { + case DB_IO_READ: +#if defined(HAVE_STATISTICS) + ++fhp->read_count; +#endif + if (!ReadFile(fhp->handle, + buf, (DWORD)io_len, &nbytes, &over)) + goto slow; + break; + case DB_IO_WRITE: +#ifdef HAVE_FILESYSTEM_NOTZERO + if (__os_fs_notzero()) + goto slow; +#endif +#if defined(HAVE_STATISTICS) + ++fhp->write_count; +#endif + if (!WriteFile(fhp->handle, + buf, (DWORD)io_len, &nbytes, &over)) + goto slow; + break; + } + if (nbytes == io_len) { + *niop = (size_t)nbytes; + return (0); + } + } + +slow: +#endif + MUTEX_LOCK(env, fhp->mtx_fh); + + if ((ret = __os_seek(env, fhp, pgno, pgsize, relative)) != 0) + goto err; + + switch (op) { + case DB_IO_READ: + ret = __os_read(env, fhp, buf, io_len, niop); + break; + case DB_IO_WRITE: + ret = __os_write(env, fhp, buf, io_len, niop); + break; + } + +err: MUTEX_UNLOCK(env, fhp->mtx_fh); + + return (ret); +} + +/* + * __os_read -- + * Read from a file handle. + */ +int +__os_read(env, fhp, addr, len, nrp) + ENV *env; + DB_FH *fhp; + void *addr; + size_t len; + size_t *nrp; +{ + DB_ENV *dbenv; + DWORD count; + size_t offset, nr; + u_int8_t *taddr; + int ret; + + dbenv = env == NULL ? NULL : env->dbenv; + ret = 0; + +#if defined(HAVE_STATISTICS) + ++fhp->read_count; +#endif + if (dbenv != NULL && FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS_ALL)) + __db_msg(env, + "fileops: read %s: %lu bytes", fhp->name, (u_long)len); + + for (taddr = addr, + offset = 0; offset < len; taddr += nr, offset += nr) { + LAST_PANIC_CHECK_BEFORE_IO(env); + RETRY_CHK((!ReadFile(fhp->handle, + taddr, (DWORD)(len - offset), &count, NULL)), ret); + if (count == 0 || ret != 0) + break; + nr = (size_t)count; + } + *nrp = taddr - (u_int8_t *)addr; + if (ret != 0) { + __db_syserr(env, ret, "read: 0x%lx, %lu", + P_TO_ULONG(taddr), (u_long)len - offset); + ret = __os_posix_err(ret); + } + return (ret); +} + +/* + * __os_write -- + * Write to a file handle. + */ +int +__os_write(env, fhp, addr, len, nwp) + ENV *env; + DB_FH *fhp; + void *addr; + size_t len; + size_t *nwp; +{ + int ret; + +#ifdef HAVE_FILESYSTEM_NOTZERO + /* Zero-fill as necessary. */ + if (__os_fs_notzero() && + (ret = __db_zero_fill(env, fhp)) != 0) + return (ret); +#endif + return (__os_physwrite(env, fhp, addr, len, nwp)); +} + +/* + * __os_physwrite -- + * Physical write to a file handle. + */ +int +__os_physwrite(env, fhp, addr, len, nwp) + ENV *env; + DB_FH *fhp; + void *addr; + size_t len; + size_t *nwp; +{ + DB_ENV *dbenv; + DWORD count; + size_t offset, nw; + u_int8_t *taddr; + int ret; + + dbenv = env == NULL ? NULL : env->dbenv; + ret = 0; + +#if defined(HAVE_STATISTICS) + ++fhp->write_count; +#endif + if (dbenv != NULL && FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS_ALL)) + __db_msg(env, + "fileops: write %s: %lu bytes", fhp->name, (u_long)len); + + for (taddr = addr, + offset = 0; offset < len; taddr += nw, offset += nw) { + LAST_PANIC_CHECK_BEFORE_IO(env); + RETRY_CHK((!WriteFile(fhp->handle, + taddr, (DWORD)(len - offset), &count, NULL)), ret); + if (ret != 0) + break; + nw = (size_t)count; + } + *nwp = len; + if (ret != 0) { + __db_syserr(env, ret, "write: %#lx, %lu", + P_TO_ULONG(taddr), (u_long)len - offset); + ret = __os_posix_err(ret); + + DB_EVENT(env, DB_EVENT_WRITE_FAILED, NULL); + } + return (ret); +} diff --git a/db-4.8.30/os_windows/os_seek.c b/db-4.8.30/os_windows/os_seek.c new file mode 100644 index 0000000..be689b9 --- /dev/null +++ b/db-4.8.30/os_windows/os_seek.c @@ -0,0 +1,65 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "db_config.h" + +#include "db_int.h" + +/* + * __os_seek -- + * Seek to a page/byte offset in the file. + */ +int +__os_seek(env, fhp, pgno, pgsize, relative) + ENV *env; + DB_FH *fhp; + db_pgno_t pgno; + u_int32_t pgsize; + u_int32_t relative; +{ + /* Yes, this really is how Microsoft designed their API. */ + union { + __int64 bigint; + struct { + unsigned long low; + long high; + }; + } offbytes; + DB_ENV *dbenv; + off_t offset; + int ret; + + dbenv = env == NULL ? NULL : env->dbenv; + +#if defined(HAVE_STATISTICS) + ++fhp->seek_count; +#endif + + offset = (off_t)pgsize * pgno + relative; + + if (dbenv != NULL && FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS_ALL)) + __db_msg(env, + "fileops: seek %s to %lu", fhp->name, (u_long)offset); + + offbytes.bigint = offset; + ret = (SetFilePointer(fhp->handle, offbytes.low, + &offbytes.high, FILE_BEGIN) == (DWORD)-1) ? __os_get_syserr() : 0; + + if (ret == 0) { + fhp->pgsize = pgsize; + fhp->pgno = pgno; + fhp->offset = relative; + } else { + __db_syserr(env, ret, + "seek: %lu: (%lu * %lu) + %lu", (u_long)offset, + (u_long)pgno, (u_long)pgsize, (u_long)relative); + ret = __os_posix_err(ret); + } + + return (ret); +} diff --git a/db-4.8.30/os_windows/os_stat.c b/db-4.8.30/os_windows/os_stat.c new file mode 100644 index 0000000..0f40a05 --- /dev/null +++ b/db-4.8.30/os_windows/os_stat.c @@ -0,0 +1,90 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "db_config.h" + +#include "db_int.h" + +/* + * __os_exists -- + * Return if the file exists. + */ +int +__os_exists(env, path, isdirp) + ENV *env; + const char *path; + int *isdirp; +{ + DB_ENV *dbenv; + DWORD attrs; + _TCHAR *tpath; + int ret; + + dbenv = env == NULL ? NULL : env->dbenv; + + TO_TSTRING(env, path, tpath, ret); + if (ret != 0) + return (ret); + + if (dbenv != NULL && + FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS | DB_VERB_FILEOPS_ALL)) + __db_msg(env, "fileops: stat %s", path); + + RETRY_CHK( + ((attrs = GetFileAttributes(tpath)) == (DWORD)-1 ? 1 : 0), ret); + if (ret == 0) { + if (isdirp != NULL) + *isdirp = (attrs & FILE_ATTRIBUTE_DIRECTORY); + } else + ret = __os_posix_err(ret); + + FREE_STRING(env, tpath); + return (ret); +} + +/* + * __os_ioinfo -- + * Return file size and I/O size; abstracted to make it easier + * to replace. + */ +int +__os_ioinfo(env, path, fhp, mbytesp, bytesp, iosizep) + ENV *env; + const char *path; + DB_FH *fhp; + u_int32_t *mbytesp, *bytesp, *iosizep; +{ + int ret; + BY_HANDLE_FILE_INFORMATION bhfi; + unsigned __int64 filesize; + + RETRY_CHK((!GetFileInformationByHandle(fhp->handle, &bhfi)), ret); + if (ret != 0) { + __db_syserr(env, ret, "GetFileInformationByHandle"); + return (__os_posix_err(ret)); + } + + filesize = ((unsigned __int64)bhfi.nFileSizeHigh << 32) + + bhfi.nFileSizeLow; + + /* Return the size of the file. */ + if (mbytesp != NULL) + *mbytesp = (u_int32_t)(filesize / MEGABYTE); + if (bytesp != NULL) + *bytesp = (u_int32_t)(filesize % MEGABYTE); + + /* + * The filesystem I/O size is not easily available. In particular, + * the values returned by GetDiskFreeSpace() are not very helpful + * (NTFS volumes often report 512B clusters, which are too small to + * be a useful default). + */ + if (iosizep != NULL) + *iosizep = DB_DEF_IOSIZE; + return (0); +} diff --git a/db-4.8.30/os_windows/os_truncate.c b/db-4.8.30/os_windows/os_truncate.c new file mode 100644 index 0000000..b35233b --- /dev/null +++ b/db-4.8.30/os_windows/os_truncate.c @@ -0,0 +1,98 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2004-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "db_config.h" + +#include "db_int.h" + +/* + * __os_truncate -- + * Truncate the file. + */ +int +__os_truncate(env, fhp, pgno, pgsize) + ENV *env; + DB_FH *fhp; + db_pgno_t pgno; + u_int32_t pgsize; +{ + /* Yes, this really is how Microsoft have designed their API */ + union { + __int64 bigint; + struct { + unsigned long low; + long high; + }; + } off; + DB_ENV *dbenv; + off_t offset; + int ret; + + dbenv = env == NULL ? NULL : env->dbenv; + offset = (off_t)pgsize * pgno; + ret = 0; + + if (dbenv != NULL && + FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS | DB_VERB_FILEOPS_ALL)) + __db_msg(env, + "fileops: truncate %s to %lu", fhp->name, (u_long)offset); + +#ifdef HAVE_FILESYSTEM_NOTZERO + /* + * If the filesystem doesn't zero fill, it isn't safe to extend the + * file, or we end up with junk blocks. Just return in that case. + */ + if (__os_fs_notzero()) { + off_t stat_offset; + u_int32_t mbytes, bytes; + + /* Stat the file. */ + if ((ret = + __os_ioinfo(env, NULL, fhp, &mbytes, &bytes, NULL)) != 0) + return (ret); + stat_offset = (off_t)mbytes * MEGABYTE + bytes; + + if (offset > stat_offset) + return (0); + } +#endif + + LAST_PANIC_CHECK_BEFORE_IO(env); + + /* + * Windows doesn't provide truncate directly. Instead, it has + * SetEndOfFile, which truncates to the current position. To + * deal with that, we open a duplicate file handle for truncating. + * + * We want to retry the truncate call, which involves a SetFilePointer + * and a SetEndOfFile, but there are several complications: + * + * 1) since the Windows API deals in 32-bit values, it's possible that + * the return from SetFilePointer (the low 32-bits) is + * INVALID_SET_FILE_POINTER even when the call has succeeded. So we + * have to also check whether GetLastError() returns NO_ERROR. + * + * 2) when it returns, SetFilePointer overwrites the high bits of the + * offset, so if we need to retry, we have to reset the offset each + * time. + * + * We can't switch to SetFilePointerEx, which knows about 64-bit + * offsets, because it isn't supported on Win9x/ME. + */ + RETRY_CHK((off.bigint = (__int64)pgsize * pgno, + (SetFilePointer(fhp->trunc_handle, off.low, &off.high, FILE_BEGIN) + == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) || + !SetEndOfFile(fhp->trunc_handle)), ret); + + if (ret != 0) { + __db_syserr(env, ret, "SetFilePointer: %lu", pgno * pgsize); + ret = __os_posix_err(ret); + } + + return (ret); +} diff --git a/db-4.8.30/os_windows/os_unlink.c b/db-4.8.30/os_windows/os_unlink.c new file mode 100644 index 0000000..7b5544c --- /dev/null +++ b/db-4.8.30/os_windows/os_unlink.c @@ -0,0 +1,108 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "db_config.h" + +#include "db_int.h" + +/* + * __os_unlink -- + * Remove a file. + */ +int +__os_unlink(env, path, overwrite_test) + ENV *env; + const char *path; + int overwrite_test; +{ + DB_ENV *dbenv; + HANDLE h; + _TCHAR *tpath, *orig_tpath, buf[DB_MAXPATHLEN]; + u_int32_t id; + int ret, t_ret; + + dbenv = env == NULL ? NULL : env->dbenv; + + if (dbenv != NULL && + FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS | DB_VERB_FILEOPS_ALL)) + __db_msg(env, "fileops: unlink %s", path); + + /* Optionally overwrite the contents of the file to enhance security. */ + if (dbenv != NULL && overwrite_test && F_ISSET(dbenv, DB_ENV_OVERWRITE)) + (void)__db_file_multi_write(env, path); + + TO_TSTRING(env, path, tpath, ret); + if (ret != 0) + return (ret); + orig_tpath = tpath; + + LAST_PANIC_CHECK_BEFORE_IO(env); + + /* + * Windows NT and its descendants allow removal of open files, but the + * DeleteFile Win32 system call isn't equivalent to a POSIX unlink. + * Firstly, it only succeeds if FILE_SHARE_DELETE is set when the file + * is opened. Secondly, it leaves the file in a "zombie" state, where + * it can't be opened again, but a new file with the same name can't be + * created either. + * + * Since we depend on being able to recreate files (during recovery, + * say), we have to first rename the file, and then delete it. It + * still hangs around, but with a name we don't care about. The rename + * will fail if the file doesn't exist, which isn't a problem, but if + * it fails for some other reason, we need to know about it or a + * subsequent open may fail for no apparent reason. + */ + if (__os_is_winnt()) { + __os_unique_id(env, &id); + _sntprintf(buf, DB_MAXPATHLEN, _T("%s.del.%010u"), tpath, id); + if (MoveFile(tpath, buf)) + tpath = buf; + else { + ret = __os_get_syserr(); + if (__os_posix_err(ret) != ENOENT) + __db_err(env, ret, + "MoveFile: rename %s to temporary file", + path); + } + + /* + * Try removing the file using the delete-on-close flag. This + * plays nicer with files that are still open than DeleteFile. + */ + h = CreateFile(tpath, 0, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, 0); + if (h != INVALID_HANDLE_VALUE) { + (void)CloseHandle (h); + if (GetFileAttributes(tpath) == INVALID_FILE_ATTRIBUTES) + goto skipdel; + } + } + + RETRY_CHK((!DeleteFile(tpath)), ret); + +skipdel: + FREE_STRING(env, orig_tpath); + + /* + * XXX + * We shouldn't be testing for an errno of ENOENT here, but ENOENT + * signals that a file is missing, and we attempt to unlink things + * (such as v. 2.x environment regions, in ENV->remove) that we + * are expecting not to be there. Reporting errors in these cases + * is annoying. + */ + if (ret != 0) { + if ((t_ret = __os_posix_err(ret)) != ENOENT) + __db_syserr(env, ret, "DeleteFile: %s", path); + ret = t_ret; + } + + return (ret); +} diff --git a/db-4.8.30/os_windows/os_yield.c b/db-4.8.30/os_windows/os_yield.c new file mode 100644 index 0000000..3d07386 --- /dev/null +++ b/db-4.8.30/os_windows/os_yield.c @@ -0,0 +1,35 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "db_config.h" + +#include "db_int.h" + +/* + * __os_yield -- + * Yield the processor, optionally pausing until running again. + */ +void +__os_yield(env, secs, usecs) + ENV *env; + u_long secs, usecs; /* Seconds and microseconds. */ +{ + COMPQUIET(env, NULL); + + /* Don't require the values be normalized. */ + for (; usecs >= US_PER_SEC; usecs -= US_PER_SEC) + ++secs; + + /* + * Yield the processor so other processes or threads can run. + * + * Sheer raving paranoia -- don't sleep for 0 time, in case some + * implementation doesn't yield the processor in that case. + */ + Sleep(secs * MS_PER_SEC + (usecs / US_PER_MS) + 1); +} -- cgit v1.2.3