Import BSDDB 4.7.25 (as of svn r89086)

This commit is contained in:
Zachary Ware
2017-09-04 13:40:25 -05:00
parent 4b29e0458f
commit 8f590873d0
4781 changed files with 2241032 additions and 6 deletions

33
os/os_abort.c Normal file
View File

@@ -0,0 +1,33 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2005,2008 Oracle. All rights reserved.
*
* $Id: os_abort.c 63573 2008-05-23 21:43:21Z trent.nelson $
*/
#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 */
}

24
os/os_abs.c Normal file
View File

@@ -0,0 +1,24 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997,2008 Oracle. All rights reserved.
*
* $Id: os_abs.c 63573 2008-05-23 21:43:21Z trent.nelson $
*/
#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] == '/');
}

176
os/os_addrinfo.c Normal file
View File

@@ -0,0 +1,176 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2006,2008 Oracle. All rights reserved.
*
* $Id: os_addrinfo.c 63573 2008-05-23 21:43:21Z trent.nelson $
*/
#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
}

459
os/os_alloc.c Normal file
View File

@@ -0,0 +1,459 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997,2008 Oracle. All rights reserved.
*
* $Id: os_alloc.c 63573 2008-05-23 21:43:21Z trent.nelson $
*/
#include "db_config.h"
#include "db_int.h"
#ifdef DIAGNOSTIC
static void __os_guard __P((ENV *));
typedef union {
size_t size;
double 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));
}

73
os/os_clock.c Normal file
View File

@@ -0,0 +1,73 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2001,2008 Oracle. All rights reserved.
*
* $Id: os_clock.c 63573 2008-05-23 21:43:21Z trent.nelson $
*/
#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));
}

70
os/os_config.c Normal file
View File

@@ -0,0 +1,70 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1998,2008 Oracle. All rights reserved.
*
* $Id: os_config.c 63573 2008-05-23 21:43:21Z trent.nelson $
*/
#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);
}

47
os/os_cpu.c Normal file
View File

@@ -0,0 +1,47 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997,2008 Oracle. All rights reserved.
*
* $Id: os_cpu.c 63573 2008-05-23 21:43:21Z trent.nelson $
*/
#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
}

47
os/os_ctime.c Normal file
View File

@@ -0,0 +1,47 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2001,2008 Oracle. All rights reserved.
*
* $Id: os_ctime.c 63573 2008-05-23 21:43:21Z trent.nelson $
*/
#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);
}

119
os/os_dir.c Normal file
View File

@@ -0,0 +1,119 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997,2008 Oracle. All rights reserved.
*
* $Id: os_dir.c 63573 2008-05-23 21:43:21Z trent.nelson $
*/
#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);
}
}

129
os/os_errno.c Normal file
View File

@@ -0,0 +1,129 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1999,2008 Oracle. All rights reserved.
*
* $Id: os_errno.c 63573 2008-05-23 21:43:21Z trent.nelson $
*/
#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);
}

134
os/os_fid.c Normal file
View File

@@ -0,0 +1,134 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996,2008 Oracle. All rights reserved.
*
* $Id: os_fid.c 63573 2008-05-23 21:43:21Z trent.nelson $
*/
#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);
}

62
os/os_flock.c Normal file
View File

@@ -0,0 +1,62 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997,2008 Oracle. All rights reserved.
*
* $Id: os_flock.c 63573 2008-05-23 21:43:21Z trent.nelson $
*/
#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
}

103
os/os_fsync.c Normal file
View File

@@ -0,0 +1,103 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997,2008 Oracle. All rights reserved.
*
* $Id: os_fsync.c 63573 2008-05-23 21:43:21Z trent.nelson $
*/
#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);
}

58
os/os_getenv.c Normal file
View File

@@ -0,0 +1,58 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997,2008 Oracle. All rights reserved.
*
* $Id: os_getenv.c 63573 2008-05-23 21:43:21Z trent.nelson $
*/
#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);
}

241
os/os_handle.c Normal file
View File

@@ -0,0 +1,241 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1998,2008 Oracle. All rights reserved.
*
* $Id: os_handle.c 63573 2008-05-23 21:43:21Z trent.nelson $
*/
#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);
}

594
os/os_map.c Normal file
View File

@@ -0,0 +1,594 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996,2008 Oracle. All rights reserved.
*
* $Id: os_map.c 63573 2008-05-23 21:43:21Z trent.nelson $
*/
#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 */

51
os/os_mkdir.c Normal file
View File

@@ -0,0 +1,51 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997,2008 Oracle. All rights reserved.
*
* $Id: os_mkdir.c 63573 2008-05-23 21:43:21Z trent.nelson $
*/
#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);
}

160
os/os_open.c Normal file
View File

@@ -0,0 +1,160 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997,2008 Oracle. All rights reserved.
*
* $Id: os_open.c 63573 2008-05-23 21:43:21Z trent.nelson $
*/
#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);
}

63
os/os_pid.c Normal file
View File

@@ -0,0 +1,63 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2001,2008 Oracle. All rights reserved.
*
* $Id: os_pid.c 63573 2008-05-23 21:43:21Z trent.nelson $
*/
#include "db_config.h"
#include "db_int.h"
#ifdef HAVE_MUTEX_SUPPORT
#include "dbinc/mutex_int.h" /* Required to load appropriate
header files for thread functions. */
#endif
/*
* __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_MUTEX_SOLARIS_LWP) || \
defined(HAVE_MUTEX_PTHREADS) || defined(HAVE_PTHREAD_API)
*tidp = pthread_self();
#else
/*
* Default to just getpid.
*/
*tidp = 0;
#endif
}
}

52
os/os_rename.c Normal file
View File

@@ -0,0 +1,52 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997,2008 Oracle. All rights reserved.
*
* $Id: os_rename.c 63573 2008-05-23 21:43:21Z trent.nelson $
*/
#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);
}

27
os/os_root.c Normal file
View File

@@ -0,0 +1,27 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1999,2008 Oracle. All rights reserved.
*
* $Id: os_root.c 63573 2008-05-23 21:43:21Z trent.nelson $
*/
#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
}

36
os/os_rpath.c Normal file
View File

@@ -0,0 +1,36 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997,2008 Oracle. All rights reserved.
*
* $Id: os_rpath.c 63573 2008-05-23 21:43:21Z trent.nelson $
*/
#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);
}

285
os/os_rw.c Normal file
View File

@@ -0,0 +1,285 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997,2008 Oracle. All rights reserved.
*
* $Id: os_rw.c 63573 2008-05-23 21:43:21Z trent.nelson $
*/
#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);
}

64
os/os_seek.c Normal file
View File

@@ -0,0 +1,64 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997,2008 Oracle. All rights reserved.
*
* $Id: os_seek.c 63573 2008-05-23 21:43:21Z trent.nelson $
*/
#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);
}

45
os/os_stack.c Normal file
View File

@@ -0,0 +1,45 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2001,2008 Oracle. All rights reserved.
*
* $Id: os_stack.c 63573 2008-05-23 21:43:21Z trent.nelson $
*/
#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);
}

107
os/os_stat.c Normal file
View File

@@ -0,0 +1,107 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997,2008 Oracle. All rights reserved.
*
* $Id: os_stat.c 63573 2008-05-23 21:43:21Z trent.nelson $
*/
#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);
}

138
os/os_tmpdir.c Normal file
View File

@@ -0,0 +1,138 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1998,2008 Oracle. All rights reserved.
*
* $Id: os_tmpdir.c 63573 2008-05-23 21:43:21Z trent.nelson $
*/
#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));
}

61
os/os_truncate.c Normal file
View File

@@ -0,0 +1,61 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2004,2008 Oracle. All rights reserved.
*
* $Id: os_truncate.c 63573 2008-05-23 21:43:21Z trent.nelson $
*/
#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);
}

55
os/os_uid.c Normal file
View File

@@ -0,0 +1,55 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2001,2008 Oracle. All rights reserved.
*
* $Id: os_uid.c 63573 2008-05-23 21:43:21Z trent.nelson $
*/
#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;
}

78
os/os_unlink.c Normal file
View File

@@ -0,0 +1,78 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997,2008 Oracle. All rights reserved.
*
* $Id: os_unlink.c 63573 2008-05-23 21:43:21Z trent.nelson $
*/
#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);
}

97
os/os_yield.c Normal file
View File

@@ -0,0 +1,97 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997,2008 Oracle. All rights reserved.
*
* $Id: os_yield.c 63573 2008-05-23 21:43:21Z trent.nelson $
*/
#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) && \
(defined(HAVE_MUTEX_PTHREADS) || defined(HAVE_PTHREAD_API))
pthread_yield();
#elif defined(HAVE_SCHED_YIELD)
(void)sched_yield();
#elif defined(HAVE_YIELD)
yield();
#else
__os_sleep(dbenv, 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");
}
}