diff options
author | Jesse Morgan <jesse@jesterpm.net> | 2016-12-17 21:28:53 -0800 |
---|---|---|
committer | Jesse Morgan <jesse@jesterpm.net> | 2016-12-17 21:28:53 -0800 |
commit | 54df2afaa61c6a03cbb4a33c9b90fa572b6d07b8 (patch) | |
tree | 18147b92b969d25ffbe61935fb63035cac820dd0 /db-4.8.30/os |
Berkeley DB 4.8 with rust build script for linux.
Diffstat (limited to 'db-4.8.30/os')
31 files changed, 3681 insertions, 0 deletions
diff --git a/db-4.8.30/os/os_abort.c b/db-4.8.30/os/os_abort.c new file mode 100644 index 0000000..a119000 --- /dev/null +++ b/db-4.8.30/os/os_abort.c @@ -0,0 +1,33 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2005-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "db_config.h" + +#include "db_int.h" + +/* + * __os_abort -- + * + * PUBLIC: void __os_abort __P((ENV *)); + */ +void +__os_abort(env) + ENV *env; +{ + __os_stack(env); /* Try and get a stack trace. */ + +#ifdef HAVE_ABORT + abort(); /* Try and drop core. */ + /* NOTREACHED */ +#endif +#ifdef SIGABRT + (void)raise(SIGABRT); /* Try and drop core. */ +#endif + exit(1); /* Quit anyway. */ + /* NOTREACHED */ +} diff --git a/db-4.8.30/os/os_abs.c b/db-4.8.30/os/os_abs.c new file mode 100644 index 0000000..59b167c --- /dev/null +++ b/db-4.8.30/os/os_abs.c @@ -0,0 +1,24 @@ +/*- + * 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. + * + * PUBLIC: int __os_abspath __P((const char *)); + */ +int +__os_abspath(path) + const char *path; +{ + return (path[0] == '/'); +} diff --git a/db-4.8.30/os/os_addrinfo.c b/db-4.8.30/os/os_addrinfo.c new file mode 100644 index 0000000..57554f8 --- /dev/null +++ b/db-4.8.30/os/os_addrinfo.c @@ -0,0 +1,176 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2006-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "db_config.h" + +#define __INCLUDE_NETWORKING 1 +#include "db_int.h" + +/* + * __os_getaddrinfo and __os_freeaddrinfo wrap the getaddrinfo and freeaddrinfo + * calls, as well as the associated platform dependent error handling, mapping + * the error return to a ANSI C/POSIX error return. + */ + +/* + * __os_getaddrinfo -- + * + * PUBLIC: #if defined(HAVE_REPLICATION_THREADS) + * PUBLIC: int __os_getaddrinfo __P((ENV *, const char *, u_int, + * PUBLIC: const char *, const ADDRINFO *, ADDRINFO **)); + * PUBLIC: #endif + */ +int +__os_getaddrinfo(env, nodename, port, servname, hints, res) + ENV *env; + const char *nodename, *servname; + u_int port; + const ADDRINFO *hints; + ADDRINFO **res; +{ +#ifdef HAVE_GETADDRINFO + int ret; + + if ((ret = getaddrinfo(nodename, servname, hints, res)) == 0) + return (0); + + __db_errx(env, "%s(%u): host lookup failed: %s", + nodename == NULL ? "" : nodename, port, +#ifdef DB_WIN32 + gai_strerrorA(ret)); +#else + gai_strerror(ret)); +#endif + return (__os_posix_err(ret)); +#else + ADDRINFO *answer; + struct hostent *hostaddr; + struct sockaddr_in sin; + u_int32_t tmpaddr; + int ret; + + COMPQUIET(hints, NULL); + COMPQUIET(servname, NULL); + + /* INADDR_NONE is not defined on Solaris 2.6, 2.7 or 2.8. */ +#ifndef INADDR_NONE +#define INADDR_NONE ((u_long)0xffffffff) +#endif + + /* + * Basic implementation of IPv4 component of getaddrinfo. + * Limited to the functionality used by repmgr. + */ + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + if (nodename) { + if (nodename[0] == '\0') + sin.sin_addr.s_addr = htonl(INADDR_ANY); + else if ((tmpaddr = inet_addr(nodename)) != INADDR_NONE) { + sin.sin_addr.s_addr = tmpaddr; + } else { + hostaddr = gethostbyname(nodename); + if (hostaddr == NULL) { +#ifdef DB_WIN32 + ret = __os_get_neterr(); + __db_syserr(env, ret, + "%s(%u): host lookup failed", + nodename == NULL ? "" : nodename, port); + return (__os_posix_err(ret)); +#else + /* + * Historic UNIX systems used the h_errno + * global variable to return gethostbyname + * errors. The only function we currently + * use that needs h_errno is gethostbyname, + * so we deal with it here. + * + * hstrerror is not available on Solaris 2.6 + * (it is in libresolv but is a private, + * unexported symbol). + */ +#ifdef HAVE_HSTRERROR + __db_errx(env, + "%s(%u): host lookup failed: %s", + nodename == NULL ? "" : nodename, port, + hstrerror(h_errno)); +#else + __db_errx(env, + "%s(%u): host lookup failed: %d", + nodename == NULL ? "" : nodename, port, + h_errno); +#endif + switch (h_errno) { + case HOST_NOT_FOUND: + case NO_DATA: + return (EHOSTUNREACH); + case TRY_AGAIN: + return (EAGAIN); + case NO_RECOVERY: + default: + return (EFAULT); + } + /* NOTREACHED */ +#endif + } + memcpy(&(sin.sin_addr), + hostaddr->h_addr, (size_t)hostaddr->h_length); + } + } else /* No host specified. */ + sin.sin_addr.s_addr = htonl(INADDR_ANY); + sin.sin_port = htons((u_int16_t)port); + + if ((ret = __os_calloc(env, 1, sizeof(ADDRINFO), &answer)) != 0) + return (ret); + if ((ret = __os_malloc(env, sizeof(sin), &answer->ai_addr)) != 0) { + __os_free(env, answer); + return (ret); + } + + answer->ai_family = AF_INET; + answer->ai_protocol = IPPROTO_TCP; + answer->ai_socktype = SOCK_STREAM; + answer->ai_addrlen = sizeof(sin); + memcpy(answer->ai_addr, &sin, sizeof(sin)); + *res = answer; + + return (0); +#endif /* HAVE_GETADDRINFO */ +} + +/* + * __os_freeaddrinfo -- + * + * PUBLIC: #if defined(HAVE_REPLICATION_THREADS) + * PUBLIC: void __os_freeaddrinfo __P((ENV *, ADDRINFO *)); + * PUBLIC: #endif + */ +void +__os_freeaddrinfo(env, ai) + ENV *env; + ADDRINFO *ai; +{ +#ifdef HAVE_GETADDRINFO + COMPQUIET(env, NULL); + + freeaddrinfo(ai); +#else + ADDRINFO *next, *tmpaddr; + + for (next = ai; next != NULL; next = tmpaddr) { + if (next->ai_canonname != NULL) + __os_free(env, next->ai_canonname); + + if (next->ai_addr != NULL) + __os_free(env, next->ai_addr); + + tmpaddr = next->ai_next; + __os_free(env, next); + } +#endif +} diff --git a/db-4.8.30/os/os_alloc.c b/db-4.8.30/os/os_alloc.c new file mode 100644 index 0000000..70af8a5 --- /dev/null +++ b/db-4.8.30/os/os_alloc.c @@ -0,0 +1,459 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "db_config.h" + +#include "db_int.h" + +#ifdef DIAGNOSTIC +static void __os_guard __P((ENV *)); + +typedef union { + size_t size; + uintmax_t align; +} db_allocinfo_t; +#endif + +/* + * !!! + * Correct for systems that return NULL when you allocate 0 bytes of memory. + * There are several places in DB where we allocate the number of bytes held + * by the key/data item, and it can be 0. Correct here so that malloc never + * returns a NULL for that reason (which behavior is permitted by ANSI). We + * could make these calls macros on non-Alpha architectures (that's where we + * saw the problem), but it's probably not worth the autoconf complexity. + * + * !!! + * Correct for systems that don't set errno when malloc and friends fail. + * + * Out of memory. + * We wish to hold the whole sky, + * But we never will. + */ + +/* + * __os_umalloc -- + * Allocate memory to be used by the application. + * + * Use, in order of preference, the allocation function specified to the + * ENV handle, the allocation function specified as a replacement for + * the library malloc, or the library malloc(). + * + * PUBLIC: int __os_umalloc __P((ENV *, size_t, void *)); + */ +int +__os_umalloc(env, size, storep) + ENV *env; + size_t size; + void *storep; +{ + DB_ENV *dbenv; + int ret; + + dbenv = env == NULL ? NULL : env->dbenv; + + /* Never allocate 0 bytes -- some C libraries don't like it. */ + if (size == 0) + ++size; + + if (dbenv == NULL || dbenv->db_malloc == NULL) { + if (DB_GLOBAL(j_malloc) != NULL) + *(void **)storep = DB_GLOBAL(j_malloc)(size); + else + *(void **)storep = malloc(size); + if (*(void **)storep == NULL) { + /* + * Correct error return, see __os_malloc. + */ + if ((ret = __os_get_errno_ret_zero()) == 0) { + ret = ENOMEM; + __os_set_errno(ENOMEM); + } + __db_err(env, ret, "malloc: %lu", (u_long)size); + return (ret); + } + return (0); + } + + if ((*(void **)storep = dbenv->db_malloc(size)) == NULL) { + __db_errx(env, + "user-specified malloc function returned NULL"); + return (ENOMEM); + } + + return (0); +} + +/* + * __os_urealloc -- + * Allocate memory to be used by the application. + * + * A realloc(3) counterpart to __os_umalloc's malloc(3). + * + * PUBLIC: int __os_urealloc __P((ENV *, size_t, void *)); + */ +int +__os_urealloc(env, size, storep) + ENV *env; + size_t size; + void *storep; +{ + DB_ENV *dbenv; + int ret; + void *ptr; + + dbenv = env == NULL ? NULL : env->dbenv; + ptr = *(void **)storep; + + /* Never allocate 0 bytes -- some C libraries don't like it. */ + if (size == 0) + ++size; + + if (dbenv == NULL || dbenv->db_realloc == NULL) { + if (ptr == NULL) + return (__os_umalloc(env, size, storep)); + + if (DB_GLOBAL(j_realloc) != NULL) + *(void **)storep = DB_GLOBAL(j_realloc)(ptr, size); + else + *(void **)storep = realloc(ptr, size); + if (*(void **)storep == NULL) { + /* + * Correct errno, see __os_realloc. + */ + if ((ret = __os_get_errno_ret_zero()) == 0) { + ret = ENOMEM; + __os_set_errno(ENOMEM); + } + __db_err(env, ret, "realloc: %lu", (u_long)size); + return (ret); + } + return (0); + } + + if ((*(void **)storep = dbenv->db_realloc(ptr, size)) == NULL) { + __db_errx(env, + "User-specified realloc function returned NULL"); + return (ENOMEM); + } + + return (0); +} + +/* + * __os_ufree -- + * Free memory used by the application. + * + * A free(3) counterpart to __os_umalloc's malloc(3). + * + * PUBLIC: void __os_ufree __P((ENV *, void *)); + */ +void +__os_ufree(env, ptr) + ENV *env; + void *ptr; +{ + DB_ENV *dbenv; + + dbenv = env == NULL ? NULL : env->dbenv; + + if (dbenv != NULL && dbenv->db_free != NULL) + dbenv->db_free(ptr); + else if (DB_GLOBAL(j_free) != NULL) + DB_GLOBAL(j_free)(ptr); + else + free(ptr); +} + +/* + * __os_strdup -- + * The strdup(3) function for DB. + * + * PUBLIC: int __os_strdup __P((ENV *, const char *, void *)); + */ +int +__os_strdup(env, str, storep) + ENV *env; + const char *str; + void *storep; +{ + size_t size; + int ret; + void *p; + + *(void **)storep = NULL; + + size = strlen(str) + 1; + if ((ret = __os_malloc(env, size, &p)) != 0) + return (ret); + + memcpy(p, str, size); + + *(void **)storep = p; + return (0); +} + +/* + * __os_calloc -- + * The calloc(3) function for DB. + * + * PUBLIC: int __os_calloc __P((ENV *, size_t, size_t, void *)); + */ +int +__os_calloc(env, num, size, storep) + ENV *env; + size_t num, size; + void *storep; +{ + int ret; + + size *= num; + if ((ret = __os_malloc(env, size, storep)) != 0) + return (ret); + + memset(*(void **)storep, 0, size); + + return (0); +} + +/* + * __os_malloc -- + * The malloc(3) function for DB. + * + * PUBLIC: int __os_malloc __P((ENV *, size_t, void *)); + */ +int +__os_malloc(env, size, storep) + ENV *env; + size_t size; + void *storep; +{ + int ret; + void *p; + + *(void **)storep = NULL; + + /* Never allocate 0 bytes -- some C libraries don't like it. */ + if (size == 0) + ++size; + +#ifdef DIAGNOSTIC + /* Add room for size and a guard byte. */ + size += sizeof(db_allocinfo_t) + 1; +#endif + + if (DB_GLOBAL(j_malloc) != NULL) + p = DB_GLOBAL(j_malloc)(size); + else + p = malloc(size); + if (p == NULL) { + /* + * Some C libraries don't correctly set errno when malloc(3) + * fails. We'd like to 0 out errno before calling malloc, + * but it turns out that setting errno is quite expensive on + * Windows/NT in an MT environment. + */ + if ((ret = __os_get_errno_ret_zero()) == 0) { + ret = ENOMEM; + __os_set_errno(ENOMEM); + } + __db_err(env, ret, "malloc: %lu", (u_long)size); + return (ret); + } + +#ifdef DIAGNOSTIC + /* Overwrite memory. */ + memset(p, CLEAR_BYTE, size); + + /* + * Guard bytes: if #DIAGNOSTIC is defined, we allocate an additional + * byte after the memory and set it to a special value that we check + * for when the memory is free'd. + */ + ((u_int8_t *)p)[size - 1] = CLEAR_BYTE; + + ((db_allocinfo_t *)p)->size = size; + p = &((db_allocinfo_t *)p)[1]; +#endif + *(void **)storep = p; + + return (0); +} + +/* + * __os_realloc -- + * The realloc(3) function for DB. + * + * PUBLIC: int __os_realloc __P((ENV *, size_t, void *)); + */ +int +__os_realloc(env, size, storep) + ENV *env; + size_t size; + void *storep; +{ + int ret; + void *p, *ptr; + + ptr = *(void **)storep; + + /* Never allocate 0 bytes -- some C libraries don't like it. */ + if (size == 0) + ++size; + + /* If we haven't yet allocated anything yet, simply call malloc. */ + if (ptr == NULL) + return (__os_malloc(env, size, storep)); + +#ifdef DIAGNOSTIC + /* Add room for size and a guard byte. */ + size += sizeof(db_allocinfo_t) + 1; + + /* Back up to the real beginning */ + ptr = &((db_allocinfo_t *)ptr)[-1]; + + { + size_t s; + + s = ((db_allocinfo_t *)ptr)->size; + if (((u_int8_t *)ptr)[s - 1] != CLEAR_BYTE) + __os_guard(env); + } +#endif + + /* + * Don't overwrite the original pointer, there are places in DB we + * try to continue after realloc fails. + */ + if (DB_GLOBAL(j_realloc) != NULL) + p = DB_GLOBAL(j_realloc)(ptr, size); + else + p = realloc(ptr, size); + if (p == NULL) { + /* + * Some C libraries don't correctly set errno when malloc(3) + * fails. We'd like to 0 out errno before calling malloc, + * but it turns out that setting errno is quite expensive on + * Windows/NT in an MT environment. + */ + if ((ret = __os_get_errno_ret_zero()) == 0) { + ret = ENOMEM; + __os_set_errno(ENOMEM); + } + __db_err(env, ret, "realloc: %lu", (u_long)size); + return (ret); + } +#ifdef DIAGNOSTIC + ((u_int8_t *)p)[size - 1] = CLEAR_BYTE; /* Initialize guard byte. */ + + ((db_allocinfo_t *)p)->size = size; + p = &((db_allocinfo_t *)p)[1]; +#endif + + *(void **)storep = p; + + return (0); +} + +/* + * __os_free -- + * The free(3) function for DB. + * + * PUBLIC: void __os_free __P((ENV *, void *)); + */ +void +__os_free(env, ptr) + ENV *env; + void *ptr; +{ +#ifdef DIAGNOSTIC + size_t size; +#endif + + /* + * ANSI C requires free(NULL) work. Don't depend on the underlying + * library. + */ + if (ptr == NULL) + return; + +#ifdef DIAGNOSTIC + /* + * Check that the guard byte (one past the end of the memory) is + * still CLEAR_BYTE. + */ + ptr = &((db_allocinfo_t *)ptr)[-1]; + size = ((db_allocinfo_t *)ptr)->size; + if (((u_int8_t *)ptr)[size - 1] != CLEAR_BYTE) + __os_guard(env); + + /* Overwrite memory. */ + if (size != 0) + memset(ptr, CLEAR_BYTE, size); +#else + COMPQUIET(env, NULL); +#endif + + if (DB_GLOBAL(j_free) != NULL) + DB_GLOBAL(j_free)(ptr); + else + free(ptr); +} + +#ifdef DIAGNOSTIC +/* + * __os_guard -- + * Complain and abort. + */ +static void +__os_guard(env) + ENV *env; +{ + __db_errx(env, "Guard byte incorrect during free"); + __os_abort(env); + /* NOTREACHED */ +} +#endif + +/* + * __ua_memcpy -- + * Copy memory to memory without relying on any kind of alignment. + * + * There are places in DB that we have unaligned data, for example, + * when we've stored a structure in a log record as a DBT, and now + * we want to look at it. Unfortunately, if you have code like: + * + * struct a { + * int x; + * } *p; + * + * void *func_argument; + * int local; + * + * p = (struct a *)func_argument; + * memcpy(&local, p->x, sizeof(local)); + * + * compilers optimize to use inline instructions requiring alignment, + * and records in the log don't have any particular alignment. (This + * isn't a compiler bug, because it's a structure they're allowed to + * assume alignment.) + * + * Casting the memcpy arguments to (u_int8_t *) appears to work most + * of the time, but we've seen examples where it wasn't sufficient + * and there's nothing in ANSI C that requires that work. + * + * PUBLIC: void *__ua_memcpy __P((void *, const void *, size_t)); + */ +void * +__ua_memcpy(dst, src, len) + void *dst; + const void *src; + size_t len; +{ + return ((void *)memcpy(dst, src, len)); +} diff --git a/db-4.8.30/os/os_clock.c b/db-4.8.30/os/os_clock.c new file mode 100644 index 0000000..d4c822e --- /dev/null +++ b/db-4.8.30/os/os_clock.c @@ -0,0 +1,73 @@ +/*- + * 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. + * + * PUBLIC: void __os_gettime __P((ENV *, db_timespec *, int)); + */ +void +__os_gettime(env, tp, monotonic) + ENV *env; + db_timespec *tp; + int monotonic; +{ + const char *sc; + int ret; + +#if defined(HAVE_CLOCK_GETTIME) +#if defined(HAVE_CLOCK_MONOTONIC) + if (monotonic) + RETRY_CHK((clock_gettime( + CLOCK_MONOTONIC, (struct timespec *)tp)), ret); + else +#endif + RETRY_CHK((clock_gettime( + CLOCK_REALTIME, (struct timespec *)tp)), ret); + + RETRY_CHK((clock_gettime(CLOCK_REALTIME, (struct timespec *)tp)), ret); + if (ret != 0) { + sc = "clock_gettime"; + goto err; + } +#elif defined(HAVE_GETTIMEOFDAY) + struct timeval v; + + RETRY_CHK((gettimeofday(&v, NULL)), ret); + if (ret != 0) { + sc = "gettimeofday"; + goto err; + } + + tp->tv_sec = v.tv_sec; + tp->tv_nsec = v.tv_usec * NS_PER_US; +#elif defined(HAVE_TIME) + time_t now; + + RETRY_CHK((time(&now) == (time_t)-1 ? 1 : 0), ret); + if (ret != 0) { + sc = "time"; + goto err; + } + + tp->tv_sec = now; + tp->tv_nsec = 0; +#else + NO AVAILABLE CLOCK IMPLEMENTATION +#endif + COMPQUIET(monotonic, 0); + return; + +err: __db_syserr(env, ret, "%s", sc); + (void)__env_panic(env, __os_posix_err(ret)); +} diff --git a/db-4.8.30/os/os_config.c b/db-4.8.30/os/os_config.c new file mode 100644 index 0000000..4e94291 --- /dev/null +++ b/db-4.8.30/os/os_config.c @@ -0,0 +1,70 @@ +/*- + * 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_fs_notzero -- + * Return 1 if allocated filesystem blocks are not zeroed. + * + * PUBLIC: int __os_fs_notzero __P((void)); + */ +int +__os_fs_notzero() +{ + /* Most filesystems zero out implicitly created pages. */ + return (0); +} + +/* + * __os_support_direct_io -- + * Return 1 if we support direct I/O. + * + * PUBLIC: int __os_support_direct_io __P((void)); + */ +int +__os_support_direct_io() +{ + int ret; + + ret = 0; + +#ifdef HAVE_O_DIRECT + ret = 1; +#endif +#if defined(HAVE_DIRECTIO) && defined(DIRECTIO_ON) + ret = 1; +#endif + return (ret); +} + +/* + * __os_support_db_register -- + * Return 1 if the system supports DB_REGISTER. + * + * PUBLIC: int __os_support_db_register __P((void)); + */ +int +__os_support_db_register() +{ + return (1); +} + +/* + * __os_support_replication -- + * Return 1 if the system supports replication. + * + * PUBLIC: int __os_support_replication __P((void)); + */ +int +__os_support_replication() +{ + return (1); +} diff --git a/db-4.8.30/os/os_cpu.c b/db-4.8.30/os/os_cpu.c new file mode 100644 index 0000000..71387b0 --- /dev/null +++ b/db-4.8.30/os/os_cpu.c @@ -0,0 +1,47 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "db_config.h" + +#include "db_int.h" + +#ifdef HAVE_SYSTEM_INCLUDE_FILES +#if defined(HAVE_PSTAT_GETDYNAMIC) +#include <sys/pstat.h> +#endif +#endif + +/* + * __os_cpu_count -- + * Return the number of CPUs. + * + * PUBLIC: u_int32_t __os_cpu_count __P((void)); + */ +u_int32_t +__os_cpu_count() +{ +#if defined(HAVE_PSTAT_GETDYNAMIC) + /* + * HP/UX. + */ + struct pst_dynamic psd; + + return ((u_int32_t)pstat_getdynamic(&psd, + sizeof(psd), (size_t)1, 0) == -1 ? 1 : psd.psd_proc_cnt); +#elif defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN) + /* + * Solaris, Linux. + */ + long nproc; + + nproc = sysconf(_SC_NPROCESSORS_ONLN); + return ((u_int32_t)(nproc > 1 ? nproc : 1)); +#else + return (1); +#endif +} diff --git a/db-4.8.30/os/os_ctime.c b/db-4.8.30/os/os_ctime.c new file mode 100644 index 0000000..843ae60 --- /dev/null +++ b/db-4.8.30/os/os_ctime.c @@ -0,0 +1,47 @@ +/*- + * 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_ctime -- + * Format a time-stamp. + * + * PUBLIC: char *__os_ctime __P((const time_t *, char *)); + */ +char * +__os_ctime(tod, time_buf) + const time_t *tod; + char *time_buf; +{ + time_buf[CTIME_BUFLEN - 1] = '\0'; + + /* + * The ctime_r interface is the POSIX standard, thread-safe version of + * ctime. However, it was implemented in three different ways (with + * and without a buffer length argument, and where the buffer length + * argument was an int vs. a size_t *). Also, you can't depend on a + * return of (char *) from ctime_r, HP-UX 10.XX's version returned an + * int. + */ +#if defined(HAVE_VXWORKS) + { + size_t buflen = CTIME_BUFLEN; + (void)ctime_r(tod, time_buf, &buflen); + } +#elif defined(HAVE_CTIME_R_3ARG) + (void)ctime_r(tod, time_buf, CTIME_BUFLEN); +#elif defined(HAVE_CTIME_R) + (void)ctime_r(tod, time_buf); +#else + (void)strncpy(time_buf, ctime(tod), CTIME_BUFLEN - 1); +#endif + return (time_buf); +} diff --git a/db-4.8.30/os/os_dir.c b/db-4.8.30/os/os_dir.c new file mode 100644 index 0000000..6e7cb5a --- /dev/null +++ b/db-4.8.30/os/os_dir.c @@ -0,0 +1,119 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "db_config.h" + +#define __INCLUDE_DIRECTORY 1 +#include "db_int.h" + +/* + * __os_dirlist -- + * Return a list of the files in a directory. + * + * PUBLIC: int __os_dirlist __P((ENV *, const char *, int, char ***, int *)); + */ +int +__os_dirlist(env, dir, returndir, namesp, cntp) + ENV *env; + const char *dir; + int returndir, *cntp; + char ***namesp; +{ + DB_ENV *dbenv; + struct dirent *dp; + DIR *dirp; + struct stat sb; + int arraysz, cnt, ret; + char **names, buf[DB_MAXPATHLEN]; + + *namesp = NULL; + *cntp = 0; + + dbenv = env == NULL ? NULL : env->dbenv; + + if (dbenv != NULL && + FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS | DB_VERB_FILEOPS_ALL)) + __db_msg(env, "fileops: directory list %s", dir); + + if (DB_GLOBAL(j_dirlist) != NULL) + return (DB_GLOBAL(j_dirlist)(dir, namesp, cntp)); + + if ((dirp = opendir(CHAR_STAR_CAST dir)) == NULL) + return (__os_get_errno()); + names = NULL; + for (arraysz = cnt = 0; (dp = readdir(dirp)) != NULL;) { + snprintf(buf, sizeof(buf), "%s/%s", dir, dp->d_name); + + RETRY_CHK(stat(buf, &sb), ret); + if (ret != 0) { + ret = __os_posix_err(ret); + goto err; + } + + /* + * We return regular files, and optionally return directories + * (except for dot and dot-dot). + * + * Shared memory files are of a different type on QNX, and we + * return those as well. + */ +#ifdef HAVE_QNX + if (!S_ISREG(sb.st_mode) && !S_TYPEISSHM(&sb)) { +#else + if (!S_ISREG(sb.st_mode)) { +#endif + if (!returndir || !S_ISDIR(sb.st_mode)) + continue; + if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || + (dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) + continue; + } + + if (cnt >= arraysz) { + arraysz += 100; + if ((ret = __os_realloc(env, + (u_int)arraysz * sizeof(names[0]), &names)) != 0) + goto err; + } + if ((ret = __os_strdup(env, dp->d_name, &names[cnt])) != 0) + goto err; + cnt++; + } + (void)closedir(dirp); + + *namesp = names; + *cntp = cnt; + return (0); + +err: if (names != NULL) + __os_dirfree(env, names, cnt); + if (dirp != NULL) + (void)closedir(dirp); + return (ret); +} + +/* + * __os_dirfree -- + * Free the list of files. + * + * PUBLIC: void __os_dirfree __P((ENV *, char **, int)); + */ +void +__os_dirfree(env, names, cnt) + ENV *env; + char **names; + int cnt; +{ + if (DB_GLOBAL(j_dirfree) != NULL) + DB_GLOBAL(j_dirfree)(names, cnt); + else { + while (cnt > 0) + __os_free(env, names[--cnt]); + __os_free(env, names); + } +} diff --git a/db-4.8.30/os/os_errno.c b/db-4.8.30/os/os_errno.c new file mode 100644 index 0000000..d74d1d9 --- /dev/null +++ b/db-4.8.30/os/os_errno.c @@ -0,0 +1,129 @@ +/*- + * 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. + * + * PUBLIC: int __os_get_errno_ret_zero __P((void)); + */ +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. + * + * PUBLIC: int __os_get_errno __P((void)); + */ +int +__os_get_errno() +{ + /* This routine must be able to return the same value repeatedly. */ + return (__os_get_syserr()); +} + +#if 0 +/* + * __os_get_neterr -- + * Return the last network-related error or EAGAIN if the last + * error is zero. + * + * PUBLIC: int __os_get_neterr __P((void)); + */ +int +__os_get_neterr() +{ + /* This routine must be able to return the same value repeatedly. */ + return (__os_get_syserr()); +} +#endif + +/* + * __os_get_syserr -- + * Return the last system error or EAGAIN if the last error is zero. + * + * PUBLIC: int __os_get_syserr __P((void)); + */ +int +__os_get_syserr() +{ + /* This routine must be able to return the same value repeatedly. */ + if (errno == 0) + __os_set_errno(EAGAIN); + return (errno); +} + +/* + * __os_set_errno -- + * Set the value of errno. + * + * PUBLIC: void __os_set_errno __P((int)); + */ +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. + * + * PUBLIC: char *__os_strerror __P((int, char *, size_t)); + */ +char * +__os_strerror(error, buf, len) + int error; + char *buf; + size_t len; +{ + /* No translation is needed in the POSIX layer. */ + (void)strncpy(buf, strerror(error), len - 1); + buf[len - 1] = '\0'; + + return (buf); +} + +/* + * __os_posix_err + * Convert a system error to a POSIX error. + * + * PUBLIC: int __os_posix_err __P((int)); + */ +int +__os_posix_err(error) + int error; +{ + return (error); +} diff --git a/db-4.8.30/os/os_fid.c b/db-4.8.30/os/os_fid.c new file mode 100644 index 0000000..59cb8dd --- /dev/null +++ b/db-4.8.30/os/os_fid.c @@ -0,0 +1,134 @@ +/*- + * 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. + * + * PUBLIC: int __os_fileid __P((ENV *, const char *, int, u_int8_t *)); + */ +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; + +#ifdef HAVE_STAT + struct stat sb; + int ret; + + /* + * The structure of a fileid on a POSIX/UNIX system is: + * + * ino[4] dev[4] unique-ID[4] serial-counter[4] empty[4]. + * + * For real files, which have a backing inode and device, the first + * 8 bytes are filled in and the following bytes are left 0. For + * temporary files, the following 12 bytes are filled in. + * + * Clear the buffer. + */ + memset(fidp, 0, DB_FILE_ID_LEN); + RETRY_CHK((stat(CHAR_STAR_CAST fname, &sb)), ret); + if (ret != 0) { + __db_syserr(env, ret, "stat: %s", fname); + return (__os_posix_err(ret)); + } + + /* + * !!! + * Nothing is ever big enough -- on Sparc V9, st_ino, st_dev and the + * time_t types are all 8 bytes. As DB_FILE_ID_LEN is only 20 bytes, + * we convert to a (potentially) smaller fixed-size type and use it. + * + * 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. When we're called from the mpool layer, though, + * we need to be careful not to include anything that isn't + * reproducible for a given file, such as the timestamp or serial + * number. + */ + tmp = (u_int32_t)sb.st_ino; + for (p = (u_int8_t *)&tmp, i = sizeof(u_int32_t); i > 0; --i) + *fidp++ = *p++; + + tmp = (u_int32_t)sb.st_dev; + for (p = (u_int8_t *)&tmp, i = sizeof(u_int32_t); i > 0; --i) + *fidp++ = *p++; +#else + /* + * Use the file name. + * + * XXX + * Cast the first argument, the BREW ARM compiler is unhappy if + * we don't. + */ + (void)strncpy((char *)fidp, fname, DB_FILE_ID_LEN); +#endif /* HAVE_STAT */ + + 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; + + for (p = (u_int8_t *) + &DB_GLOBAL(fid_serial), i = sizeof(u_int32_t); i > 0; --i) + *fidp++ = *p++; + } + + return (0); +} diff --git a/db-4.8.30/os/os_flock.c b/db-4.8.30/os/os_flock.c new file mode 100644 index 0000000..6997719 --- /dev/null +++ b/db-4.8.30/os/os_flock.c @@ -0,0 +1,62 @@ +/*- + * 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. + * + * PUBLIC: int __os_fdlock __P((ENV *, DB_FH *, off_t, int, int)); + */ +int +__os_fdlock(env, fhp, offset, acquire, nowait) + ENV *env; + DB_FH *fhp; + int acquire, nowait; + off_t offset; +{ +#ifdef HAVE_FCNTL + DB_ENV *dbenv; + struct flock fl; + int ret, t_ret; + + dbenv = env == NULL ? NULL : env->dbenv; + + DB_ASSERT(env, F_ISSET(fhp, DB_FH_OPENED) && fhp->fd != -1); + + 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); + + fl.l_start = offset; + fl.l_len = 1; + fl.l_type = acquire ? F_WRLCK : F_UNLCK; + fl.l_whence = SEEK_SET; + + RETRY_CHK_EINTR_ONLY( + (fcntl(fhp->fd, nowait ? F_SETLK : F_SETLKW, &fl)), ret); + + if (ret == 0) + return (0); + + if ((t_ret = __os_posix_err(ret)) != EACCES && t_ret != EAGAIN) + __db_syserr(env, ret, "fcntl"); + return (t_ret); +#else + COMPQUIET(fhp, NULL); + COMPQUIET(acquire, 0); + COMPQUIET(nowait, 0); + COMPQUIET(offset, 0); + __db_syserr(env, DB_OPNOTSUP, "advisory file locking unavailable"); + return (DB_OPNOTSUP); +#endif +} diff --git a/db-4.8.30/os/os_fsync.c b/db-4.8.30/os/os_fsync.c new file mode 100644 index 0000000..35e244c --- /dev/null +++ b/db-4.8.30/os/os_fsync.c @@ -0,0 +1,103 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "db_config.h" + +#include "db_int.h" + +#ifdef HAVE_VXWORKS +#include "ioLib.h" + +#define fsync(fd) __vx_fsync(fd) + +int +__vx_fsync(fd) + int fd; +{ + int ret; + + /* + * The results of ioctl are driver dependent. Some will return the + * number of bytes sync'ed. Only if it returns 'ERROR' should we + * flag it. + */ + if ((ret = ioctl(fd, FIOSYNC, 0)) != ERROR) + return (0); + return (ret); +} +#endif + +#ifdef __hp3000s900 +#define fsync(fd) __mpe_fsync(fd) + +int +__mpe_fsync(fd) + int fd; +{ + extern FCONTROL(short, short, void *); + + FCONTROL(_MPE_FILENO(fd), 2, NULL); /* Flush the buffers */ + FCONTROL(_MPE_FILENO(fd), 6, NULL); /* Write the EOF */ + return (0); +} +#endif + +/* + * __os_fsync -- + * Flush a file descriptor. + * + * PUBLIC: int __os_fsync __P((ENV *, DB_FH *)); + */ +int +__os_fsync(env, fhp) + ENV *env; + DB_FH *fhp; +{ + DB_ENV *dbenv; + int ret; + + dbenv = env == NULL ? NULL : env->dbenv; + + DB_ASSERT(env, F_ISSET(fhp, DB_FH_OPENED) && fhp->fd != -1); + + /* + * 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); + + if (DB_GLOBAL(j_fsync) != NULL) + ret = DB_GLOBAL(j_fsync)(fhp->fd); + else { +#if defined(F_FULLFSYNC) + RETRY_CHK((fcntl(fhp->fd, F_FULLFSYNC, 0)), ret); + /* + * On OS X, F_FULLSYNC only works on HFS+, so we need to fall + * back to regular fsync on other filesystems. + */ + if (ret == ENOTSUP) + RETRY_CHK((fsync(fhp->fd)), ret); +#elif defined(HAVE_QNX) + ret = __qnx_fsync(fhp); +#elif defined(HAVE_FDATASYNC) + RETRY_CHK((fdatasync(fhp->fd)), ret); +#else + RETRY_CHK((fsync(fhp->fd)), ret); +#endif + } + + if (ret != 0) { + __db_syserr(env, ret, "fsync"); + ret = __os_posix_err(ret); + } + return (ret); +} diff --git a/db-4.8.30/os/os_getenv.c b/db-4.8.30/os/os_getenv.c new file mode 100644 index 0000000..581f412 --- /dev/null +++ b/db-4.8.30/os/os_getenv.c @@ -0,0 +1,58 @@ +/*- + * 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. + * + * PUBLIC: int __os_getenv __P((ENV *, const char *, char **, size_t)); + */ +int +__os_getenv(env, name, bpp, buflen) + ENV *env; + const char *name; + char **bpp; + size_t buflen; +{ + /* + * If we have getenv, there's a value and the buffer is large enough: + * copy value into the pointer, return 0 + * If we have getenv, there's a value and the buffer is too short: + * set pointer to NULL, return EINVAL + * If we have getenv and there's no value: + * set pointer to NULL, return 0 + * If we don't have getenv: + * set pointer to NULL, return 0 + */ +#ifdef HAVE_GETENV + char *p; + + if ((p = getenv(name)) != NULL) { + if (strlen(p) < buflen) { + (void)strcpy(*bpp, p); + return (0); + } + + *bpp = NULL; + __db_errx(env, + "%s: buffer too small to hold environment variable %s", + name, p); + return (EINVAL); + } +#else + COMPQUIET(env, NULL); + COMPQUIET(name, NULL); + COMPQUIET(buflen, 0); +#endif + *bpp = NULL; + return (0); +} diff --git a/db-4.8.30/os/os_handle.c b/db-4.8.30/os/os_handle.c new file mode 100644 index 0000000..e833aa1 --- /dev/null +++ b/db-4.8.30/os/os_handle.c @@ -0,0 +1,241 @@ +/*- + * 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. + * + * PUBLIC: int __os_openhandle + * PUBLIC: __P((ENV *, const char *, int, int, DB_FH **)); + */ +int +__os_openhandle(env, name, flags, mode, fhpp) + ENV *env; + const char *name; + int flags, mode; + DB_FH **fhpp; +{ + DB_FH *fhp; + u_int nrepeat, retries; + int fcntl_flags, ret; +#ifdef HAVE_VXWORKS + int newflags; +#endif + /* + * 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); + } + + /* If the application specified an interface, use it. */ + if (DB_GLOBAL(j_open) != NULL) { + if ((fhp->fd = DB_GLOBAL(j_open)(name, flags, mode)) == -1) { + ret = __os_posix_err(__os_get_syserr()); + goto err; + } + goto done; + } + + retries = 0; + for (nrepeat = 1; nrepeat < 4; ++nrepeat) { + ret = 0; +#ifdef HAVE_VXWORKS + /* + * VxWorks does not support O_CREAT on open, you have to use + * creat() instead. (It does not support O_EXCL or O_TRUNC + * either, even though they are defined "for future support".) + * We really want the POSIX behavior that if O_CREAT is set, + * we open if it exists, or create it if it doesn't exist. + * If O_CREAT is specified, single thread and try to open the + * file. If successful, and O_EXCL return EEXIST. If + * unsuccessful call creat and then end single threading. + */ + if (LF_ISSET(O_CREAT)) { + DB_BEGIN_SINGLE_THREAD; + newflags = flags & ~(O_CREAT | O_EXCL); + if ((fhp->fd = open(name, newflags, mode)) != -1) { + /* + * We need to mark the file opened at this + * point so that if we get any error below + * we will properly close the fd we just + * opened on the error path. + */ + F_SET(fhp, DB_FH_OPENED); + if (LF_ISSET(O_EXCL)) { + /* + * If we get here, want O_EXCL create, + * and the file exists. Close and + * return EEXISTS. + */ + DB_END_SINGLE_THREAD; + ret = EEXIST; + goto err; + } + /* + * XXX + * Assume any error means non-existence. + * Unfortunately return values (even for + * non-existence) are driver specific so + * there is no single error we can use to + * verify we truly got the equivalent of + * ENOENT. + */ + } else + fhp->fd = creat(name, newflags); + DB_END_SINGLE_THREAD; + } else + /* FALLTHROUGH */ +#endif +#ifdef __VMS + /* + * !!! + * Open with full sharing on VMS. + * + * We use these flags because they are the ones set by the VMS + * CRTL mmap() call when it opens a file, and we have to be + * able to open files that mmap() has previously opened, e.g., + * when we're joining already existing DB regions. + */ + fhp->fd = open(name, flags, mode, "shr=get,put,upd,del,upi"); +#else + fhp->fd = open(name, flags, mode); +#endif + if (fhp->fd != -1) { + 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) { +#if defined(HAVE_FCNTL_F_SETFD) + /* Deny file descriptor access to any child process. */ + if ((fcntl_flags = fcntl(fhp->fd, F_GETFD)) == -1 || + fcntl(fhp->fd, F_SETFD, fcntl_flags | FD_CLOEXEC) == -1) { + ret = __os_get_syserr(); + __db_syserr(env, ret, "fcntl(F_SETFD)"); + ret = __os_posix_err(ret); + goto err; + } +#else + COMPQUIET(fcntl_flags, 0); +#endif + +done: F_SET(fhp, DB_FH_OPENED); + *fhpp = fhp; + return (0); + } + +err: (void)__os_closehandle(env, fhp); + return (ret); +} + +/* + * __os_closehandle -- + * Close a file. + * + * PUBLIC: int __os_closehandle __P((ENV *, DB_FH *)); + */ +int +__os_closehandle(env, fhp) + ENV *env; + DB_FH *fhp; +{ + DB_ENV *dbenv; + int ret; + + ret = 0; + + /* + * If we linked the DB_FH handle into the ENV, it needs to be + * unlinked. + */ + DB_ASSERT(env, env != NULL || !F_ISSET(fhp, DB_FH_ENVLINK)); + + 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: close %s", 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 (DB_GLOBAL(j_close) != NULL) + ret = DB_GLOBAL(j_close)(fhp->fd); + else + RETRY_CHK((close(fhp->fd)), ret); + if (ret != 0) { + __db_syserr(env, ret, "close"); + 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/os_map.c b/db-4.8.30/os/os_map.c new file mode 100644 index 0000000..b5de0ed --- /dev/null +++ b/db-4.8.30/os/os_map.c @@ -0,0 +1,594 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "db_config.h" + +#include "db_int.h" + +#ifdef HAVE_SYSTEM_INCLUDE_FILES +#ifdef HAVE_MMAP +#include <sys/mman.h> +#endif + +#ifdef HAVE_SHMGET +#include <sys/ipc.h> +#include <sys/shm.h> +#endif +#endif + +#ifdef HAVE_MMAP +static int __os_map __P((ENV *, char *, DB_FH *, size_t, int, int, void **)); +#endif +#ifdef HAVE_SHMGET +static int __shm_mode __P((ENV *)); +#else +static int __no_system_mem __P((ENV *)); +#endif + +/* + * __os_attach -- + * Create/join a shared memory region. + * + * PUBLIC: int __os_attach __P((ENV *, REGINFO *, REGION *)); + */ +int +__os_attach(env, infop, rp) + ENV *env; + REGINFO *infop; + REGION *rp; +{ + DB_ENV *dbenv; + int create_ok, ret; + + /* + * We pass a DB_ENV handle to the user's replacement map function, + * so there must be a valid handle. + */ + DB_ASSERT(env, env != NULL && env->dbenv != NULL); + dbenv = env->dbenv; + + if (DB_GLOBAL(j_region_map) != NULL) { + /* + * We have to find out if the region is being created. Ask + * the underlying map function, and use the REGINFO structure + * to pass that information back to our caller. + */ + create_ok = F_ISSET(infop, REGION_CREATE) ? 1 : 0; + ret = DB_GLOBAL(j_region_map) + (dbenv, infop->name, rp->size, &create_ok, &infop->addr); + if (create_ok) + F_SET(infop, REGION_CREATE); + else + F_CLR(infop, REGION_CREATE); + return (ret); + } + + if (F_ISSET(env, ENV_SYSTEM_MEM)) { + /* + * If the region is in system memory on UNIX, we use shmget(2). + * + * !!! + * There exist spinlocks that don't work in shmget memory, e.g., + * the HP/UX msemaphore interface. If we don't have locks that + * will work in shmget memory, we better be private and not be + * threaded. If we reach this point, we know we're public, so + * it's an error. + */ +#if defined(HAVE_MUTEX_HPPA_MSEM_INIT) + __db_errx(env, + "architecture does not support locks inside system shared memory"); + return (EINVAL); +#endif +#if defined(HAVE_SHMGET) + { + key_t segid; + int id, mode; + + /* + * We could potentially create based on REGION_CREATE_OK, but + * that's dangerous -- we might get crammed in sideways if + * some of the expected regions exist but others do not. Also, + * if the requested size differs from an existing region's + * actual size, then all sorts of nasty things can happen. + * Basing create solely on REGION_CREATE is much safer -- a + * recovery will get us straightened out. + */ + if (F_ISSET(infop, REGION_CREATE)) { + /* + * The application must give us a base System V IPC key + * value. Adjust that value based on the region's ID, + * and correct so the user's original value appears in + * the ipcs output. + */ + if (dbenv->shm_key == INVALID_REGION_SEGID) { + __db_errx(env, + "no base system shared memory ID specified"); + return (EINVAL); + } + + /* + * !!! + * The BDB API takes a "long" as the base segment ID, + * then adds an unsigned 32-bit value and stores it + * in a key_t. Wrong, admittedly, but not worth an + * API change to fix. + */ + segid = (key_t) + ((u_long)dbenv->shm_key + (infop->id - 1)); + + /* + * If map to an existing region, assume the application + * crashed and we're restarting. Delete the old region + * and re-try. If that fails, return an error, the + * application will have to select a different segment + * ID or clean up some other way. + */ + if ((id = shmget(segid, 0, 0)) != -1) { + (void)shmctl(id, IPC_RMID, NULL); + if ((id = shmget(segid, 0, 0)) != -1) { + __db_errx(env, + "shmget: key: %ld: shared system memory region already exists", + (long)segid); + return (EAGAIN); + } + } + + /* + * Map the DbEnv::open method file mode permissions to + * shmget call permissions. + */ + mode = IPC_CREAT | __shm_mode(env); + if ((id = shmget(segid, rp->size, mode)) == -1) { + ret = __os_get_syserr(); + __db_syserr(env, ret, + "shmget: key: %ld: unable to create shared system memory region", + (long)segid); + return (__os_posix_err(ret)); + } + rp->segid = id; + } else + id = rp->segid; + + if ((infop->addr = shmat(id, NULL, 0)) == (void *)-1) { + infop->addr = NULL; + ret = __os_get_syserr(); + __db_syserr(env, ret, + "shmat: id %d: unable to attach to shared system memory region", id); + return (__os_posix_err(ret)); + } + + /* Optionally lock the memory down. */ + if (F_ISSET(env, ENV_LOCKDOWN)) { +#ifdef HAVE_SHMCTL_SHM_LOCK + ret = shmctl( + id, SHM_LOCK, NULL) == 0 ? 0 : __os_get_syserr(); +#else + ret = DB_OPNOTSUP; +#endif + if (ret != 0) { + __db_syserr(env, ret, + "shmctl/SHM_LOCK: id %d: unable to lock down shared memory region", id); + return (__os_posix_err(ret)); + } + } + + return (0); + } +#else + return (__no_system_mem(env)); +#endif + } + +#ifdef HAVE_MMAP + { + DB_FH *fhp; + + fhp = NULL; + + /* + * Try to open/create the shared region 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); + + /* + * If we created the file, grow it to its full size before mapping + * it in. We really want to avoid touching the buffer cache after + * mmap(2) is called, doing anything else confuses the hell out of + * systems without merged VM/buffer cache systems, or, more to the + * point, *badly* merged VM/buffer cache systems. + */ + if (ret == 0 && F_ISSET(infop, REGION_CREATE)) { + if (F_ISSET(dbenv, DB_ENV_REGION_INIT)) + ret = __db_file_write(env, fhp, + rp->size / MEGABYTE, rp->size % MEGABYTE, 0x00); + else + ret = __db_file_extend(env, fhp, rp->size); + } + + /* Map the file in. */ + if (ret == 0) + ret = __os_map(env, + infop->name, fhp, rp->size, 1, 0, &infop->addr); + + if (fhp != NULL) + (void)__os_closehandle(env, fhp); + + return (ret); + } +#else + COMPQUIET(infop, NULL); + COMPQUIET(rp, NULL); + __db_errx(env, + "architecture lacks mmap(2), shared environments not possible"); + return (DB_OPNOTSUP); +#endif +} + +/* + * __os_detach -- + * Detach from a shared memory region. + * + * PUBLIC: int __os_detach __P((ENV *, REGINFO *, int)); + */ +int +__os_detach(env, infop, destroy) + ENV *env; + REGINFO *infop; + int destroy; +{ + DB_ENV *dbenv; + REGION *rp; + int ret; + + /* + * We pass a DB_ENV handle to the user's replacement unmap function, + * so there must be a valid handle. + */ + DB_ASSERT(env, env != NULL && env->dbenv != NULL); + dbenv = env->dbenv; + + rp = infop->rp; + + /* If the user replaced the unmap call, call through their interface. */ + if (DB_GLOBAL(j_region_unmap) != NULL) + return (DB_GLOBAL(j_region_unmap)(dbenv, infop->addr)); + + if (F_ISSET(env, ENV_SYSTEM_MEM)) { +#ifdef HAVE_SHMGET + int segid; + + /* + * We may be about to remove the memory referenced by rp, + * save the segment ID, and (optionally) wipe the original. + */ + segid = rp->segid; + if (destroy) + rp->segid = INVALID_REGION_SEGID; + + if (shmdt(infop->addr) != 0) { + ret = __os_get_syserr(); + __db_syserr(env, ret, "shmdt"); + return (__os_posix_err(ret)); + } + + if (destroy && shmctl(segid, IPC_RMID, + NULL) != 0 && (ret = __os_get_syserr()) != EINVAL) { + __db_syserr(env, ret, + "shmctl: id %d: unable to delete system shared memory region", + segid); + return (__os_posix_err(ret)); + } + + return (0); +#else + return (__no_system_mem(env)); +#endif + } + +#ifdef HAVE_MMAP +#ifdef HAVE_MUNLOCK + if (F_ISSET(env, ENV_LOCKDOWN)) + (void)munlock(infop->addr, rp->size); +#endif + if (munmap(infop->addr, rp->size) != 0) { + ret = __os_get_syserr(); + __db_syserr(env, ret, "munmap"); + return (__os_posix_err(ret)); + } + + if (destroy && (ret = __os_unlink(env, infop->name, 1)) != 0) + return (ret); + + return (0); +#else + COMPQUIET(destroy, 0); + COMPQUIET(ret, 0); + return (EINVAL); +#endif +} + +/* + * __os_mapfile -- + * Map in a shared memory file. + * + * PUBLIC: int __os_mapfile __P((ENV *, char *, DB_FH *, size_t, int, void **)); + */ +int +__os_mapfile(env, path, fhp, len, is_rdonly, addrp) + ENV *env; + char *path; + DB_FH *fhp; + int is_rdonly; + size_t len; + void **addrp; +{ +#if defined(HAVE_MMAP) && !defined(HAVE_QNX) + DB_ENV *dbenv; + + /* If the user replaced the map call, call through their interface. */ + if (DB_GLOBAL(j_file_map) != NULL) { + /* + * We pass a DB_ENV handle to the user's replacement map + * function, so there must be a valid handle. + */ + DB_ASSERT(env, env != NULL && env->dbenv != NULL); + dbenv = env->dbenv; + + return ( + DB_GLOBAL(j_file_map)(dbenv, path, len, is_rdonly, addrp)); + } + + return (__os_map(env, path, fhp, len, 0, is_rdonly, addrp)); +#else + COMPQUIET(env, NULL); + COMPQUIET(path, NULL); + COMPQUIET(fhp, NULL); + COMPQUIET(is_rdonly, 0); + COMPQUIET(len, 0); + COMPQUIET(addrp, NULL); + return (DB_OPNOTSUP); +#endif +} + +/* + * __os_unmapfile -- + * Unmap the shared memory file. + * + * PUBLIC: int __os_unmapfile __P((ENV *, void *, size_t)); + */ +int +__os_unmapfile(env, addr, len) + ENV *env; + void *addr; + size_t len; +{ + DB_ENV *dbenv; + int ret; + + /* + * We pass a DB_ENV handle to the user's replacement unmap function, + * so there must be a valid handle. + */ + DB_ASSERT(env, env != NULL && env->dbenv != NULL); + dbenv = env->dbenv; + + if (FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS | DB_VERB_FILEOPS_ALL)) + __db_msg(env, "fileops: munmap"); + + /* If the user replaced the map call, call through their interface. */ + if (DB_GLOBAL(j_file_unmap) != NULL) + return (DB_GLOBAL(j_file_unmap)(dbenv, addr)); + +#ifdef HAVE_MMAP +#ifdef HAVE_MUNLOCK + if (F_ISSET(env, ENV_LOCKDOWN)) + RETRY_CHK((munlock(addr, len)), ret); + /* + * !!! + * The return value is ignored. + */ +#else + COMPQUIET(env, NULL); +#endif + RETRY_CHK((munmap(addr, len)), ret); + ret = __os_posix_err(ret); +#else + COMPQUIET(env, NULL); + ret = EINVAL; +#endif + return (ret); +} + +#ifdef HAVE_MMAP +/* + * __os_map -- + * Call the mmap(2) function. + */ +static int +__os_map(env, path, fhp, len, is_region, is_rdonly, addrp) + ENV *env; + char *path; + DB_FH *fhp; + int is_region, is_rdonly; + size_t len; + void **addrp; +{ + DB_ENV *dbenv; + int flags, prot, ret; + void *p; + + /* + * We pass a DB_ENV handle to the user's replacement map function, + * so there must be a valid handle. + */ + DB_ASSERT(env, env != NULL && env->dbenv != NULL); + dbenv = env->dbenv; + + if (FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS | DB_VERB_FILEOPS_ALL)) + __db_msg(env, "fileops: mmap %s", path); + + DB_ASSERT(env, F_ISSET(fhp, DB_FH_OPENED) && fhp->fd != -1); + + /* + * If it's read-only, it's private, and if it's not, it's shared. + * Don't bother with an additional parameter. + */ + flags = is_rdonly ? MAP_PRIVATE : MAP_SHARED; + +#ifdef MAP_FILE + /* + * Historically, MAP_FILE was required for mapping regular files, + * even though it was the default. Some systems have it, some + * don't, some that have it set it to 0. + */ + flags |= MAP_FILE; +#endif + + /* + * I know of no systems that implement the flag to tell the system + * that the region contains semaphores, but it's not an unreasonable + * thing to do, and has been part of the design since forever. I + * don't think anyone will object, but don't set it for read-only + * files, it doesn't make sense. + */ +#ifdef MAP_HASSEMAPHORE + if (is_region && !is_rdonly) + flags |= MAP_HASSEMAPHORE; +#else + COMPQUIET(is_region, 0); +#endif + + /* + * FreeBSD: + * Causes data dirtied via this VM map to be flushed to physical media + * only when necessary (usually by the pager) rather then gratuitously. + * Typically this prevents the update daemons from flushing pages + * dirtied through such maps and thus allows efficient sharing of + * memory across unassociated processes using a file-backed shared + * memory map. + */ +#ifdef MAP_NOSYNC + flags |= MAP_NOSYNC; +#endif + + prot = PROT_READ | (is_rdonly ? 0 : PROT_WRITE); + + /* + * XXX + * Work around a bug in the VMS V7.1 mmap() implementation. To map + * a file into memory on VMS it needs to be opened in a certain way, + * originally. To get the file opened in that certain way, the VMS + * mmap() closes the file and re-opens it. When it does this, it + * doesn't flush any caches out to disk before closing. The problem + * this causes us is that when the memory cache doesn't get written + * out, the file isn't big enough to match the memory chunk and the + * mmap() call fails. This call to fsync() fixes the problem. DEC + * thinks this isn't a bug because of language in XPG5 discussing user + * responsibility for on-disk and in-memory synchronization. + */ +#ifdef VMS + if (__os_fsync(env, fhp) == -1) + return (__os_posix_err(__os_get_syserr())); +#endif + + /* MAP_FAILED was not defined in early mmap implementations. */ +#ifndef MAP_FAILED +#define MAP_FAILED -1 +#endif + if ((p = mmap(NULL, + len, prot, flags, fhp->fd, (off_t)0)) == (void *)MAP_FAILED) { + ret = __os_get_syserr(); + __db_syserr(env, ret, "mmap"); + return (__os_posix_err(ret)); + } + + /* + * If it's a region, we want to make sure that the memory isn't paged. + * For example, Solaris will page large mpools because it thinks that + * I/O buffer memory is more important than we are. The mlock system + * call may or may not succeed (mlock is restricted to the super-user + * on some systems). Currently, the only other use of mmap in DB is + * to map read-only databases -- we don't want them paged, either, so + * the call isn't conditional. + */ + if (F_ISSET(env, ENV_LOCKDOWN)) { +#ifdef HAVE_MLOCK + ret = mlock(p, len) == 0 ? 0 : __os_get_syserr(); +#else + ret = DB_OPNOTSUP; +#endif + if (ret != 0) { + __db_syserr(env, ret, "mlock"); + return (__os_posix_err(ret)); + } + } + + *addrp = p; + return (0); +} +#endif + +#ifdef HAVE_SHMGET +#ifndef SHM_R +#define SHM_R 0400 +#endif +#ifndef SHM_W +#define SHM_W 0200 +#endif + +/* + * __shm_mode -- + * Map the DbEnv::open method file mode permissions to shmget call + * permissions. + */ +static int +__shm_mode(env) + ENV *env; +{ + int mode; + + /* Default to r/w owner, r/w group. */ + if (env->db_mode == 0) + return (SHM_R | SHM_W | SHM_R >> 3 | SHM_W >> 3); + + mode = 0; + if (env->db_mode & S_IRUSR) + mode |= SHM_R; + if (env->db_mode & S_IWUSR) + mode |= SHM_W; + if (env->db_mode & S_IRGRP) + mode |= SHM_R >> 3; + if (env->db_mode & S_IWGRP) + mode |= SHM_W >> 3; + if (env->db_mode & S_IROTH) + mode |= SHM_R >> 6; + if (env->db_mode & S_IWOTH) + mode |= SHM_W >> 6; + return (mode); +} +#else +/* + * __no_system_mem -- + * No system memory environments error message. + */ +static int +__no_system_mem(env) + ENV *env; +{ + __db_errx(env, + "architecture doesn't support environments in system memory"); + return (DB_OPNOTSUP); +} +#endif /* HAVE_SHMGET */ diff --git a/db-4.8.30/os/os_mkdir.c b/db-4.8.30/os/os_mkdir.c new file mode 100644 index 0000000..238be1a --- /dev/null +++ b/db-4.8.30/os/os_mkdir.c @@ -0,0 +1,51 @@ +/*- + * 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. + * + * PUBLIC: int __os_mkdir __P((ENV *, const char *, int)); + */ +int +__os_mkdir(env, name, mode) + ENV *env; + const char *name; + int mode; +{ + DB_ENV *dbenv; + 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. */ +#if defined(HAVE_VXWORKS) + RETRY_CHK((mkdir(CHAR_STAR_CAST name)), ret); +#else + RETRY_CHK((mkdir(name, DB_MODE_700)), ret); +#endif + if (ret != 0) + return (__os_posix_err(ret)); + + /* Set the absolute permissions, if specified. */ +#if !defined(HAVE_VXWORKS) + if (mode != 0) { + RETRY_CHK((chmod(name, mode)), ret); + if (ret != 0) + ret = __os_posix_err(ret); + } +#endif + return (ret); +} diff --git a/db-4.8.30/os/os_open.c b/db-4.8.30/os/os_open.c new file mode 100644 index 0000000..a9eeef3 --- /dev/null +++ b/db-4.8.30/os/os_open.c @@ -0,0 +1,160 @@ +/*- + * 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). + * + * PUBLIC: int __os_open __P((ENV *, + * PUBLIC: const char *, u_int32_t, u_int32_t, int, DB_FH **)); + */ +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; + int oflags, ret; + + COMPQUIET(page_size, 0); + + dbenv = env == NULL ? NULL : env->dbenv; + *fhpp = NULL; + oflags = 0; + + 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); + +#if defined(O_BINARY) + /* + * If there's a binary-mode open flag, set it, we never want any + * kind of translation. Some systems do translations by default, + * e.g., with Cygwin, the default mode for an open() is set by the + * mode of the mount that underlies the file. + */ + oflags |= O_BINARY; +#endif + + /* + * DB requires the POSIX 1003.1 semantic that two files opened at the + * same time with DB_OSO_CREATE/O_CREAT and DB_OSO_EXCL/O_EXCL flags + * set return an EEXIST failure in at least one. + */ + if (LF_ISSET(DB_OSO_CREATE)) + oflags |= O_CREAT; + + if (LF_ISSET(DB_OSO_EXCL)) + oflags |= O_EXCL; + +#ifdef HAVE_O_DIRECT + if (LF_ISSET(DB_OSO_DIRECT)) + oflags |= O_DIRECT; +#endif +#ifdef O_DSYNC + if (LF_ISSET(DB_OSO_DSYNC)) + oflags |= O_DSYNC; +#endif + + if (LF_ISSET(DB_OSO_RDONLY)) + oflags |= O_RDONLY; + else + oflags |= O_RDWR; + + if (LF_ISSET(DB_OSO_TRUNC)) + oflags |= O_TRUNC; + + /* + * Undocumented feature: allow applications to create intermediate + * directories whenever a file is opened. + */ + if (dbenv != NULL && + env->dir_mode != 0 && LF_ISSET(DB_OSO_CREATE) && + (ret = __db_mkpath(env, name)) != 0) + return (ret); + + /* Open the file. */ +#ifdef HAVE_QNX + if (LF_ISSET(DB_OSO_REGION)) + ret = __os_qnx_region_open(env, name, oflags, mode, &fhp); + else +#endif + ret = __os_openhandle(env, name, oflags, mode, &fhp); + if (ret != 0) + return (ret); + + if (LF_ISSET(DB_OSO_REGION)) + F_SET(fhp, DB_FH_REGION); +#ifdef HAVE_FCHMOD + /* + * If the code using Berkeley DB is a library, that code may not be able + * to control the application's umask value. Allow applications to set + * absolute file modes. We can't fix the race between file creation and + * the fchmod call -- we can't modify the process' umask here since the + * process may be multi-threaded and the umask value is per-process, not + * per-thread. + */ + if (LF_ISSET(DB_OSO_CREATE) && LF_ISSET(DB_OSO_ABSMODE)) + (void)fchmod(fhp->fd, mode); +#endif + +#ifdef O_DSYNC + /* + * If we can configure the file descriptor to flush on write, the + * file descriptor does not need to be explicitly sync'd. + */ + if (LF_ISSET(DB_OSO_DSYNC)) + F_SET(fhp, DB_FH_NOSYNC); +#endif + +#if defined(HAVE_DIRECTIO) && defined(DIRECTIO_ON) + /* + * The Solaris C library includes directio, but you have to set special + * compile flags to #define DIRECTIO_ON. Require both in order to call + * directio. + */ + if (LF_ISSET(DB_OSO_DIRECT)) + (void)directio(fhp->fd, DIRECTIO_ON); +#endif + + /* + * Delete any temporary file. + * + * !!! + * There's a race here, where we've created a file and we crash before + * we can unlink it. Temporary files aren't common in DB, regardless, + * it's not a security problem because the file is empty. There's no + * reasonable way to avoid the race (playing signal games isn't worth + * the portability nightmare), so we just live with it. + */ + if (LF_ISSET(DB_OSO_TEMP)) { +#if defined(HAVE_UNLINK_WITH_OPEN_FAILURE) || defined(CONFIG_TEST) + F_SET(fhp, DB_FH_UNLINK); +#else + (void)__os_unlink(env, name, 0); +#endif + } + + *fhpp = fhp; + return (0); +} diff --git a/db-4.8.30/os/os_pid.c b/db-4.8.30/os/os_pid.c new file mode 100644 index 0000000..4eb74f2 --- /dev/null +++ b/db-4.8.30/os/os_pid.c @@ -0,0 +1,57 @@ +/*- + * 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_id -- + * Return the current process ID. + * + * PUBLIC: void __os_id __P((DB_ENV *, pid_t *, db_threadid_t*)); + */ +void +__os_id(dbenv, pidp, tidp) + DB_ENV *dbenv; + pid_t *pidp; + db_threadid_t *tidp; +{ + /* + * We can't depend on dbenv not being NULL, this routine is called + * from places where there's no DB_ENV handle. + * + * We cache the pid in the ENV handle, getting the process ID is a + * fairly slow call on lots of systems. + */ + if (pidp != NULL) { + if (dbenv == NULL) { +#if defined(HAVE_VXWORKS) + *pidp = taskIdSelf(); +#else + *pidp = getpid(); +#endif + } else + *pidp = dbenv->env->pid_cache; + } + + if (tidp != NULL) { +#if defined(DB_WIN32) + *tidp = GetCurrentThreadId(); +#elif defined(HAVE_MUTEX_UI_THREADS) + *tidp = thr_self(); +#elif defined(HAVE_PTHREAD_SELF) + *tidp = pthread_self(); +#else + /* + * Default to just getpid. + */ + *tidp = 0; +#endif + } +} diff --git a/db-4.8.30/os/os_rename.c b/db-4.8.30/os/os_rename.c new file mode 100644 index 0000000..4245b98 --- /dev/null +++ b/db-4.8.30/os/os_rename.c @@ -0,0 +1,52 @@ +/*- + * 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. + * + * PUBLIC: int __os_rename __P((ENV *, + * PUBLIC: const char *, const char *, u_int32_t)); + */ +int +__os_rename(env, oldname, newname, silent) + ENV *env; + const char *oldname, *newname; + u_int32_t silent; +{ + DB_ENV *dbenv; + 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); + + LAST_PANIC_CHECK_BEFORE_IO(env); + + if (DB_GLOBAL(j_rename) != NULL) + ret = DB_GLOBAL(j_rename)(oldname, newname); + else + RETRY_CHK((rename(oldname, newname)), ret); + + /* + * If "silent" is not set, then errors are OK and we should not output + * an error message. + */ + if (ret != 0) { + if (!silent) + __db_syserr( + env, ret, "rename %s %s", oldname, newname); + ret = __os_posix_err(ret); + } + return (ret); +} diff --git a/db-4.8.30/os/os_root.c b/db-4.8.30/os/os_root.c new file mode 100644 index 0000000..79fe398 --- /dev/null +++ b/db-4.8.30/os/os_root.c @@ -0,0 +1,27 @@ +/*- + * 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_isroot -- + * Return if user has special permissions. + * + * PUBLIC: int __os_isroot __P((void)); + */ +int +__os_isroot() +{ +#ifdef HAVE_GETUID + return (getuid() == 0); +#else + return (0); +#endif +} diff --git a/db-4.8.30/os/os_rpath.c b/db-4.8.30/os/os_rpath.c new file mode 100644 index 0000000..c59855b --- /dev/null +++ b/db-4.8.30/os/os_rpath.c @@ -0,0 +1,36 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "db_config.h" + +#include "db_int.h" + +/* + * __db_rpath -- + * Return the last path separator in the path or NULL if none found. + * + * PUBLIC: char *__db_rpath __P((const char *)); + */ +char * +__db_rpath(path) + const char *path; +{ + const char *s, *last; + + s = path; + last = NULL; + if (PATH_SEPARATOR[1] != '\0') { + for (; s[0] != '\0'; ++s) + if (strchr(PATH_SEPARATOR, s[0]) != NULL) + last = s; + } else + for (; s[0] != '\0'; ++s) + if (s[0] == PATH_SEPARATOR[0]) + last = s; + return ((char *)last); +} diff --git a/db-4.8.30/os/os_rw.c b/db-4.8.30/os/os_rw.c new file mode 100644 index 0000000..235f993 --- /dev/null +++ b/db-4.8.30/os/os_rw.c @@ -0,0 +1,285 @@ +/*- + * 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. + * + * PUBLIC: int __os_io __P((ENV *, int, DB_FH *, db_pgno_t, + * PUBLIC: u_int32_t, u_int32_t, u_int32_t, u_int8_t *, size_t *)); + */ +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; +{ +#if defined(HAVE_PREAD) && defined(HAVE_PWRITE) + DB_ENV *dbenv; + off_t offset; + ssize_t nio; +#endif + int ret; + + /* + * Check for illegal usage. + * + * This routine is used in one of two ways: reading bytes from an + * absolute offset and reading a specific database page. All of + * our absolute offsets are known to fit into a u_int32_t, while + * our database pages might be at offsets larger than a u_int32_t. + * We don't want to specify an absolute offset in our caller as we + * aren't exactly sure what size an off_t might be. + */ + DB_ASSERT(env, F_ISSET(fhp, DB_FH_OPENED) && fhp->fd != -1); + DB_ASSERT(env, (pgno == 0 && pgsize == 0) || relative == 0); + +#if defined(HAVE_PREAD) && defined(HAVE_PWRITE) + dbenv = env == NULL ? NULL : env->dbenv; + + if ((offset = relative) == 0) + offset = (off_t)pgno * pgsize; + switch (op) { + case DB_IO_READ: + if (DB_GLOBAL(j_read) != NULL) + goto slow; +#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 at offset %lu", + fhp->name, (u_long)io_len, (u_long)offset); + + LAST_PANIC_CHECK_BEFORE_IO(env); + nio = DB_GLOBAL(j_pread) != NULL ? + DB_GLOBAL(j_pread)(fhp->fd, buf, io_len, offset) : + pread(fhp->fd, buf, io_len, offset); + break; + case DB_IO_WRITE: + if (DB_GLOBAL(j_write) != NULL) + goto slow; +#ifdef HAVE_FILESYSTEM_NOTZERO + if (__os_fs_notzero()) + goto slow; +#endif +#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 at offset %lu", + fhp->name, (u_long)io_len, (u_long)offset); + + LAST_PANIC_CHECK_BEFORE_IO(env); + nio = DB_GLOBAL(j_pwrite) != NULL ? + DB_GLOBAL(j_pwrite)(fhp->fd, buf, io_len, offset) : + pwrite(fhp->fd, buf, io_len, offset); + break; + default: + return (EINVAL); + } + if (nio == (ssize_t)io_len) { + *niop = io_len; + 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; + default: + ret = EINVAL; + break; + } + +err: MUTEX_UNLOCK(env, fhp->mtx_fh); + + return (ret); + +} + +/* + * __os_read -- + * Read from a file handle. + * + * PUBLIC: int __os_read __P((ENV *, DB_FH *, void *, size_t, size_t *)); + */ +int +__os_read(env, fhp, addr, len, nrp) + ENV *env; + DB_FH *fhp; + void *addr; + size_t len; + size_t *nrp; +{ + DB_ENV *dbenv; + size_t offset; + ssize_t nr; + int ret; + u_int8_t *taddr; + + dbenv = env == NULL ? NULL : env->dbenv; + ret = 0; + + DB_ASSERT(env, F_ISSET(fhp, DB_FH_OPENED) && fhp->fd != -1); + +#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); + + if (DB_GLOBAL(j_read) != NULL) { + *nrp = len; + LAST_PANIC_CHECK_BEFORE_IO(env); + if (DB_GLOBAL(j_read)(fhp->fd, addr, len) != (ssize_t)len) { + ret = __os_get_syserr(); + __db_syserr(env, ret, "read: %#lx, %lu", + P_TO_ULONG(addr), (u_long)len); + ret = __os_posix_err(ret); + } + return (ret); + } + + for (taddr = addr, offset = 0; + offset < len; taddr += nr, offset += (u_int32_t)nr) { + LAST_PANIC_CHECK_BEFORE_IO(env); + RETRY_CHK(((nr = read(fhp->fd, + CHAR_STAR_CAST taddr, len - offset)) < 0 ? 1 : 0), ret); + if (nr == 0 || ret != 0) + break; + } + *nrp = (size_t)(taddr - (u_int8_t *)addr); + if (ret != 0) { + __db_syserr(env, ret, "read: %#lx, %lu", + P_TO_ULONG(taddr), (u_long)len - offset); + ret = __os_posix_err(ret); + } + return (ret); +} + +/* + * __os_write -- + * Write to a file handle. + * + * PUBLIC: int __os_write __P((ENV *, DB_FH *, void *, size_t, size_t *)); + */ +int +__os_write(env, fhp, addr, len, nwp) + ENV *env; + DB_FH *fhp; + void *addr; + size_t len; + size_t *nwp; +{ + DB_ASSERT(env, F_ISSET(fhp, DB_FH_OPENED) && fhp->fd != -1); + +#ifdef HAVE_FILESYSTEM_NOTZERO + /* Zero-fill as necessary. */ + if (__os_fs_notzero()) { + int ret; + if ((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. + * + * PUBLIC: int __os_physwrite + * PUBLIC: __P((ENV *, DB_FH *, void *, size_t, size_t *)); + */ +int +__os_physwrite(env, fhp, addr, len, nwp) + ENV *env; + DB_FH *fhp; + void *addr; + size_t len; + size_t *nwp; +{ + DB_ENV *dbenv; + size_t offset; + ssize_t nw; + int ret; + u_int8_t *taddr; + + 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); + +#if defined(HAVE_FILESYSTEM_NOTZERO) && defined(DIAGNOSTIC) + if (__os_fs_notzero()) { + struct stat sb; + off_t cur_off; + + DB_ASSERT(env, fstat(fhp->fd, &sb) != -1 && + (cur_off = lseek(fhp->fd, (off_t)0, SEEK_CUR)) != -1 && + cur_off <= sb.st_size); + } +#endif + if (DB_GLOBAL(j_write) != NULL) { + *nwp = len; + LAST_PANIC_CHECK_BEFORE_IO(env); + if (DB_GLOBAL(j_write)(fhp->fd, addr, len) != (ssize_t)len) { + ret = __os_get_syserr(); + __db_syserr(env, ret, "write: %#lx, %lu", + P_TO_ULONG(addr), (u_long)len); + ret = __os_posix_err(ret); + + DB_EVENT(env, DB_EVENT_WRITE_FAILED, NULL); + } + return (ret); + } + + for (taddr = addr, offset = 0; + offset < len; taddr += nw, offset += (u_int32_t)nw) { + LAST_PANIC_CHECK_BEFORE_IO(env); + RETRY_CHK(((nw = write(fhp->fd, + CHAR_STAR_CAST taddr, len - offset)) < 0 ? 1 : 0), ret); + if (ret != 0) + break; + } + *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/os_seek.c b/db-4.8.30/os/os_seek.c new file mode 100644 index 0000000..7c9c9e9 --- /dev/null +++ b/db-4.8.30/os/os_seek.c @@ -0,0 +1,64 @@ +/*- + * 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. + * + * PUBLIC: int __os_seek __P((ENV *, + * PUBLIC: DB_FH *, db_pgno_t, u_int32_t, u_int32_t)); + */ +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; +{ + DB_ENV *dbenv; + off_t offset; + int ret; + + dbenv = env == NULL ? NULL : env->dbenv; + + DB_ASSERT(env, F_ISSET(fhp, DB_FH_OPENED) && fhp->fd != -1); + +#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); + + if (DB_GLOBAL(j_seek) != NULL) + ret = DB_GLOBAL(j_seek)(fhp->fd, offset, SEEK_SET); + else + RETRY_CHK((lseek( + fhp->fd, offset, SEEK_SET) == -1 ? 1 : 0), ret); + + 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/os_stack.c b/db-4.8.30/os/os_stack.c new file mode 100644 index 0000000..ee859b7 --- /dev/null +++ b/db-4.8.30/os/os_stack.c @@ -0,0 +1,45 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2001-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "db_config.h" + +#include "db_int.h" +#if defined(HAVE_SYSTEM_INCLUDE_FILES) && defined(HAVE_BACKTRACE) && \ + defined(HAVE_BACKTRACE_SYMBOLS) && defined(HAVE_EXECINFO_H) +#include <execinfo.h> +#endif + +/* + * __os_stack -- + * Output a stack trace to the message file handle. + * + * PUBLIC: void __os_stack __P((ENV *)); + */ +void +__os_stack(env) + ENV *env; +{ +#if defined(HAVE_BACKTRACE) && defined(HAVE_BACKTRACE_SYMBOLS) + void *array[200]; + size_t i, size; + char **strings; + + /* + * Solaris and the GNU C library support this interface. Solaris + * has additional interfaces (printstack and walkcontext), I don't + * know if they offer any additional value or not. + */ + size = backtrace(array, sizeof(array) / sizeof(array[0])); + strings = backtrace_symbols(array, size); + + for (i = 0; i < size; ++i) + __db_errx(env, "%s", strings[i]); + free(strings); +#endif + COMPQUIET(env, NULL); +} diff --git a/db-4.8.30/os/os_stat.c b/db-4.8.30/os/os_stat.c new file mode 100644 index 0000000..1c3b44a --- /dev/null +++ b/db-4.8.30/os/os_stat.c @@ -0,0 +1,107 @@ +/*- + * 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. + * + * PUBLIC: int __os_exists __P((ENV *, const char *, int *)); + */ +int +__os_exists(env, path, isdirp) + ENV *env; + const char *path; + int *isdirp; +{ + DB_ENV *dbenv; + struct stat sb; + 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: stat %s", path); + + if (DB_GLOBAL(j_exists) != NULL) + return (DB_GLOBAL(j_exists)(path, isdirp)); + + RETRY_CHK((stat(CHAR_STAR_CAST path, &sb)), ret); + if (ret != 0) + return (__os_posix_err(ret)); + +#if !defined(S_ISDIR) || defined(STAT_MACROS_BROKEN) +#undef S_ISDIR +#ifdef _S_IFDIR +#define S_ISDIR(m) (_S_IFDIR & (m)) +#else +#define S_ISDIR(m) (((m) & 0170000) == 0040000) +#endif +#endif + if (isdirp != NULL) + *isdirp = S_ISDIR(sb.st_mode); + + return (0); +} + +/* + * __os_ioinfo -- + * Return file size and I/O size; abstracted to make it easier + * to replace. + * + * PUBLIC: int __os_ioinfo __P((ENV *, const char *, + * PUBLIC: DB_FH *, u_int32_t *, u_int32_t *, u_int32_t *)); + */ +int +__os_ioinfo(env, path, fhp, mbytesp, bytesp, iosizep) + ENV *env; + const char *path; + DB_FH *fhp; + u_int32_t *mbytesp, *bytesp, *iosizep; +{ + struct stat sb; + int ret; + + if (DB_GLOBAL(j_ioinfo) != NULL) + return (DB_GLOBAL(j_ioinfo)(path, + fhp->fd, mbytesp, bytesp, iosizep)); + + DB_ASSERT(env, F_ISSET(fhp, DB_FH_OPENED) && fhp->fd != -1); + + RETRY_CHK((fstat(fhp->fd, &sb)), ret); + if (ret != 0) { + __db_syserr(env, ret, "fstat"); + return (__os_posix_err(ret)); + } + + /* Return the size of the file. */ + if (mbytesp != NULL) + *mbytesp = (u_int32_t)(sb.st_size / MEGABYTE); + if (bytesp != NULL) + *bytesp = (u_int32_t)(sb.st_size % MEGABYTE); + + /* + * Return the underlying filesystem I/O size, if available. + * + * XXX + * Check for a 0 size -- the HP MPE/iX architecture has st_blksize, + * but it's always 0. + */ +#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE + if (iosizep != NULL && (*iosizep = sb.st_blksize) == 0) + *iosizep = DB_DEF_IOSIZE; +#else + if (iosizep != NULL) + *iosizep = DB_DEF_IOSIZE; +#endif + return (0); +} diff --git a/db-4.8.30/os/os_tmpdir.c b/db-4.8.30/os/os_tmpdir.c new file mode 100644 index 0000000..c5369eb --- /dev/null +++ b/db-4.8.30/os/os_tmpdir.c @@ -0,0 +1,138 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1998-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "db_config.h" + +#include "db_int.h" + +#ifdef HAVE_SYSTEM_INCLUDE_FILES +#ifdef macintosh +#include <TFileSpec.h> +#endif +#endif + +/* + * __os_tmpdir -- + * Set the temporary directory path. + * + * The order of items in the list structure and the order of checks in + * the environment are documented. + * + * PUBLIC: int __os_tmpdir __P((ENV *, u_int32_t)); + */ +int +__os_tmpdir(env, flags) + ENV *env; + u_int32_t flags; +{ + DB_ENV *dbenv; + int isdir, ret; + char *tdir, tdir_buf[DB_MAXPATHLEN]; + + dbenv = env->dbenv; + + /* Use the environment if it's permitted and initialized. */ + if (LF_ISSET(DB_USE_ENVIRON) || + (LF_ISSET(DB_USE_ENVIRON_ROOT) && __os_isroot())) { + /* POSIX: TMPDIR */ + tdir = tdir_buf; + if ((ret = __os_getenv( + env, "TMPDIR", &tdir, sizeof(tdir_buf))) != 0) + return (ret); + if (tdir != NULL && tdir[0] != '\0') + goto found; + + /* + * Windows: TEMP, TMP + */ + tdir = tdir_buf; + if ((ret = __os_getenv( + env, "TEMP", &tdir, sizeof(tdir_buf))) != 0) + return (ret); + if (tdir != NULL && tdir[0] != '\0') + goto found; + + tdir = tdir_buf; + if ((ret = __os_getenv( + env, "TMP", &tdir, sizeof(tdir_buf))) != 0) + return (ret); + if (tdir != NULL && tdir[0] != '\0') + goto found; + + /* Macintosh */ + tdir = tdir_buf; + if ((ret = __os_getenv( + env, "TempFolder", &tdir, sizeof(tdir_buf))) != 0) + return (ret); + + if (tdir != NULL && tdir[0] != '\0') +found: return (__os_strdup(env, tdir, &dbenv->db_tmp_dir)); + } + +#ifdef macintosh + /* Get the path to the temporary folder. */ + {FSSpec spec; + + if (!Special2FSSpec(kTemporaryFolderType, + kOnSystemDisk, 0, &spec)) + return (__os_strdup(env, + FSp2FullPath(&spec), &dbenv->db_tmp_dir)); + } +#endif +#ifdef DB_WIN32 + /* Get the path to the temporary directory. */ + { + _TCHAR tpath[DB_MAXPATHLEN + 1]; + char *path, *eos; + + if (GetTempPath(DB_MAXPATHLEN, tpath) > 2) { + FROM_TSTRING(env, tpath, path, ret); + if (ret != 0) + return (ret); + + eos = path + strlen(path) - 1; + if (*eos == '\\' || *eos == '/') + *eos = '\0'; + if (__os_exists(env, path, &isdir) == 0 && isdir) { + ret = __os_strdup(env, + path, &dbenv->db_tmp_dir); + FREE_STRING(env, path); + return (ret); + } + FREE_STRING(env, path); + } + } +#endif + + /* + * Step through the static list looking for a possibility. + * + * We don't use the obvious data structure because some C compilers + * (and I use the phrase loosely) don't like static data arrays. + */ +#define DB_TEMP_DIRECTORY(n) { \ + char *__p = n; \ + if (__os_exists(env, __p, &isdir) == 0 && isdir != 0) \ + return (__os_strdup(env, __p, &dbenv->db_tmp_dir)); \ + } +#ifdef DB_WIN32 + DB_TEMP_DIRECTORY("/temp"); + DB_TEMP_DIRECTORY("C:/temp"); + DB_TEMP_DIRECTORY("C:/tmp"); +#else + DB_TEMP_DIRECTORY("/var/tmp"); + DB_TEMP_DIRECTORY("/usr/tmp"); + DB_TEMP_DIRECTORY("/tmp"); +#endif + + /* + * If we don't have any other place to store temporary files, store + * them in the current directory. + */ + return (__os_strdup(env, "", &dbenv->db_tmp_dir)); +} diff --git a/db-4.8.30/os/os_truncate.c b/db-4.8.30/os/os_truncate.c new file mode 100644 index 0000000..1e01bfc --- /dev/null +++ b/db-4.8.30/os/os_truncate.c @@ -0,0 +1,61 @@ +/*- + * 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. + * + * PUBLIC: int __os_truncate __P((ENV *, DB_FH *, db_pgno_t, u_int32_t)); + */ +int +__os_truncate(env, fhp, pgno, pgsize) + ENV *env; + DB_FH *fhp; + db_pgno_t pgno; + u_int32_t pgsize; +{ + DB_ENV *dbenv; + off_t offset; + int ret; + + dbenv = env == NULL ? NULL : env->dbenv; + + /* + * Truncate a file so that "pgno" is discarded from the end of the + * file. + */ + offset = (off_t)pgsize * pgno; + + 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); + + LAST_PANIC_CHECK_BEFORE_IO(env); + + if (DB_GLOBAL(j_ftruncate) != NULL) + ret = DB_GLOBAL(j_ftruncate)(fhp->fd, offset); + else { +#ifdef HAVE_FTRUNCATE + RETRY_CHK((ftruncate(fhp->fd, offset)), ret); +#else + ret = DB_OPNOTSUP; +#endif + } + + if (ret != 0) { + __db_syserr(env, ret, "ftruncate: %lu", (u_long)offset); + ret = __os_posix_err(ret); + } + + return (ret); +} diff --git a/db-4.8.30/os/os_uid.c b/db-4.8.30/os/os_uid.c new file mode 100644 index 0000000..0575077 --- /dev/null +++ b/db-4.8.30/os/os_uid.c @@ -0,0 +1,55 @@ +/*- + * 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_unique_id -- + * Return a unique 32-bit value. + * + * PUBLIC: void __os_unique_id __P((ENV *, u_int32_t *)); + */ +void +__os_unique_id(env, idp) + ENV *env; + u_int32_t *idp; +{ + DB_ENV *dbenv; + db_timespec v; + pid_t pid; + u_int32_t id; + + *idp = 0; + + dbenv = env == NULL ? NULL : env->dbenv; + + /* + * Our randomized value is comprised of our process ID, the current + * time of day and a stack address, all XOR'd together. + */ + __os_id(dbenv, &pid, NULL); + __os_gettime(env, &v, 1); + + id = (u_int32_t)pid ^ + (u_int32_t)v.tv_sec ^ (u_int32_t)v.tv_nsec ^ P_TO_UINT32(&pid); + + /* + * We could try and find a reasonable random-number generator, but + * that's not all that easy to do. Seed and use srand()/rand(), if + * we can find them. + */ + if (DB_GLOBAL(uid_init) == 0) { + DB_GLOBAL(uid_init) = 1; + srand((u_int)id); + } + id ^= (u_int)rand(); + + *idp = id; +} diff --git a/db-4.8.30/os/os_unlink.c b/db-4.8.30/os/os_unlink.c new file mode 100644 index 0000000..bdbcb98 --- /dev/null +++ b/db-4.8.30/os/os_unlink.c @@ -0,0 +1,78 @@ +/*- + * 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. + * + * PUBLIC: int __os_unlink __P((ENV *, const char *, int)); + */ +int +__os_unlink(env, path, overwrite_test) + ENV *env; + const char *path; + int overwrite_test; +{ + DB_ENV *dbenv; + 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); + + LAST_PANIC_CHECK_BEFORE_IO(env); + + if (DB_GLOBAL(j_unlink) != NULL) + ret = DB_GLOBAL(j_unlink)(path); + else { + RETRY_CHK((unlink(CHAR_STAR_CAST path)), ret); +#ifdef HAVE_QNX + /* + * The file may be a region file created by shm_open, not a + * regular file. Try and delete using unlink, and if that + * fails for an unexpected reason, try a shared memory unlink. + */ + if (ret != 0 && __os_posix_err(ret) != ENOENT) + RETRY_CHK((shm_unlink(path)), ret); +#endif + } + + /* + * !!! + * The results of unlink are file system driver specific on VxWorks. + * In the case of removing a file that did not exist, some, at least, + * return an error, but with an errno of 0, not ENOENT. We do not + * have to test for that explicitly, the RETRY_CHK macro resets "ret" + * to be the errno, and so we'll just slide right on through. + * + * 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) { + t_ret = __os_posix_err(ret); + if (t_ret != ENOENT) + __db_syserr(env, ret, "unlink: %s", path); + ret = t_ret; + } + + return (ret); +} diff --git a/db-4.8.30/os/os_yield.c b/db-4.8.30/os/os_yield.c new file mode 100644 index 0000000..4a6107e --- /dev/null +++ b/db-4.8.30/os/os_yield.c @@ -0,0 +1,96 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "db_config.h" + +#define __INCLUDE_SELECT_H 1 +#include "db_int.h" + +#if defined(HAVE_SYSTEM_INCLUDE_FILES) && defined(HAVE_SCHED_YIELD) +#include <sched.h> +#endif + +static void __os_sleep __P((ENV *, u_long, u_long)); + +/* + * __os_yield -- + * Yield the processor, optionally pausing until running again. + * + * PUBLIC: void __os_yield __P((ENV *, u_long, u_long)); + */ +void +__os_yield(env, secs, usecs) + ENV *env; + u_long secs, usecs; /* Seconds and microseconds. */ +{ + /* + * Don't require the values be normalized (some operating systems + * return an error if the usecs argument to select is too large). + */ + for (; usecs >= US_PER_SEC; usecs -= US_PER_SEC) + ++secs; + + if (DB_GLOBAL(j_yield) != NULL) { + (void)DB_GLOBAL(j_yield)(secs, usecs); + return; + } + + /* + * Yield the processor so other processes or threads can run. Use + * the local yield call if not pausing, otherwise call the select + * function. + */ + if (secs != 0 || usecs != 0) + __os_sleep(env, secs, usecs); + else { +#if defined(HAVE_MUTEX_UI_THREADS) + thr_yield(); +#elif defined(HAVE_PTHREAD_YIELD) + pthread_yield(); +#elif defined(HAVE_SCHED_YIELD) + (void)sched_yield(); +#elif defined(HAVE_YIELD) + yield(); +#else + __os_sleep(env, 0, 0); +#endif + } +} + +/* + * __os_sleep -- + * Pause the thread of control. + */ +static void +__os_sleep(env, secs, usecs) + ENV *env; + u_long secs, usecs; /* Seconds and microseconds. */ +{ + struct timeval t; + int ret; + + /* + * Sheer raving paranoia -- don't select for 0 time, in case some + * implementation doesn't yield the processor in that case. + */ + t.tv_sec = (long)secs; + t.tv_usec = (long)usecs + 1; + + /* + * We don't catch interrupts and restart the system call here, unlike + * other Berkeley DB system calls. This may be a user attempting to + * interrupt a sleeping DB utility (for example, db_checkpoint), and + * we want the utility to see the signal and quit. This assumes it's + * always OK for DB to sleep for less time than originally scheduled. + */ + if (select(0, NULL, NULL, NULL, &t) == -1) { + ret = __os_get_syserr(); + if (__os_posix_err(ret) != EINTR) + __db_syserr(env, ret, "select"); + } +} |