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