diff options
-rw-r--r-- | dbm/include/hash.h | 13 | ||||
-rw-r--r-- | dbm/src/h_page.c | 57 | ||||
-rw-r--r-- | dbm/src/hash.c | 98 | ||||
-rw-r--r-- | dbm/src/mktemp.c | 41 |
4 files changed, 169 insertions, 40 deletions
diff --git a/dbm/include/hash.h b/dbm/include/hash.h index 70f93e938..30ca297a1 100644 --- a/dbm/include/hash.h +++ b/dbm/include/hash.h @@ -51,9 +51,9 @@ struct _bufhead { BUFHEAD *prev; /* LRU links */ BUFHEAD *next; /* LRU links */ BUFHEAD *ovfl; /* Overflow page buffer header */ - uint32 addr; /* Address of this page */ + uint32 addr; /* Address of this page */ char *page; /* Actual page data */ - char is_disk; + char is_disk; char flags; #define BUF_MOD 0x0001 #define BUF_DISK 0x0002 @@ -77,7 +77,7 @@ typedef int DBFILE_PTR; typedef struct hashhdr { /* Disk resident portion */ int32 magic; /* Magic NO for hash tables */ int32 version; /* Version ID */ - uint32 lorder; /* Byte Order */ + uint32 lorder; /* Byte Order */ int32 bsize; /* Bucket/Page Size */ int32 bshift; /* Bucket shift */ int32 dsize; /* Directory Size */ @@ -97,7 +97,7 @@ typedef struct hashhdr { /* Disk resident portion */ #define NCACHED 32 /* number of bit maps and spare * points */ int32 spares[NCACHED];/* spare pages for overflow */ - uint16 bitmaps[NCACHED]; /* address of overflow page + uint16 bitmaps[NCACHED]; /* address of overflow page * bitmaps */ } HASHHDR; @@ -123,12 +123,15 @@ typedef struct htab { /* Memory resident data structure */ int save_file; /* Indicates whether we need to flush * file at * exit */ - uint32 *mapp[NCACHED]; /* Pointers to page maps */ + uint32 *mapp[NCACHED]; /* Pointers to page maps */ int nmaps; /* Initial number of bitmaps */ int nbufs; /* Number of buffers left to * allocate */ BUFHEAD bufhead; /* Header of buffer lru list */ SEGMENT *dir; /* Hash Bucket directory */ + off_t file_size; /* in bytes */ + char is_temp; /* unlink file on close */ + char updateEOF; /* close and reopen on flush */ } HTAB; /* diff --git a/dbm/src/h_page.c b/dbm/src/h_page.c index f81298e67..8d8a484fa 100644 --- a/dbm/src/h_page.c +++ b/dbm/src/h_page.c @@ -72,6 +72,9 @@ static char sccsid[] = "@(#)hash_page.c 8.7 (Berkeley) 8/16/94"; #include <errno.h> #include <fcntl.h> +#if defined(_WIN32) || defined(_WINDOWS) +#include <io.h> +#endif #include <signal.h> #include <stdio.h> #include <stdlib.h> @@ -88,6 +91,8 @@ static char sccsid[] = "@(#)hash_page.c 8.7 (Berkeley) 8/16/94"; #include "page.h" /* #include "extern.h" */ +extern int mkstempflags(char *path, int extraFlags); + static uint32 *fetch_bitmap __P((HTAB *, uint32)); static uint32 first_free __P((uint32)); static int open_temp __P((HTAB *)); @@ -826,6 +831,7 @@ __put_page(HTAB *hashp, char *p, uint32 bucket, int is_bucket, int is_bitmap) register int fd, page; size_t size; int wsize; + off_t offset; size = hashp->BSIZE; if ((hashp->fp == -1) && open_temp(hashp)) @@ -860,7 +866,8 @@ __put_page(HTAB *hashp, char *p, uint32 bucket, int is_bucket, int is_bitmap) page = BUCKET_TO_PAGE(bucket); else page = OADDR_TO_PAGE(bucket); - if ((MY_LSEEK(fd, (off_t)page << hashp->BSHIFT, SEEK_SET) == -1) || + offset = (off_t)page << hashp->BSHIFT; + if ((MY_LSEEK(fd, offset, SEEK_SET) == -1) || ((wsize = write(fd, p, size)) == -1)) /* Errno is set */ return (-1); @@ -868,7 +875,11 @@ __put_page(HTAB *hashp, char *p, uint32 bucket, int is_bucket, int is_bitmap) errno = EFTYPE; return (-1); } - +#if defined(_WIN32) || defined(_WINDOWS) + if (offset + size > hashp->file_size) { + hashp->updateEOF = 1; + } +#endif /* put the page back the way it was so that it isn't byteswapped * if it remains in memory - LJM */ @@ -1151,7 +1162,11 @@ open_temp(HTAB *hashp) #if !defined(_WIN32) && !defined(_WINDOWS) && !defined(macintosh) && !defined(XP_OS2) sigset_t set, oset; #endif - static char namestr[] = "_hashXXXXXX"; + char * tmpdir; + int len; + static const char namestr[] = "/_hashXXXXXX"; + char filename[1024]; + char last; #if !defined(_WIN32) && !defined(_WINDOWS) && !defined(macintosh) && !defined(XP_OS2) /* Block signals; make sure file goes away at process exit. */ @@ -1159,12 +1174,42 @@ open_temp(HTAB *hashp) (void)sigprocmask(SIG_BLOCK, &set, &oset); #endif - if ((hashp->fp = mkstemp(namestr)) != -1) { - (void)unlink(namestr); -#if !defined(_WIN32) && !defined(_WINDOWS) && !defined(macintosh) && !defined(XP_OS2) + filename[0] = 0; +#if defined(macintosh) + strcat(filename, namestr + 1); +#else + tmpdir = getenv("TMP"); + if (!tmpdir) + tmpdir = getenv("TMPDIR"); + if (!tmpdir) + tmpdir = getenv("TEMP"); + if (!tmpdir) + tmpdir = "."; + len = strlen(tmpdir); + if (len && len < (sizeof filename - sizeof namestr)) { + strcpy(filename, tmpdir); + } + len = strlen(filename); + last = tmpdir[len - 1]; + strcat(filename, (last == '/' || last == '\\') ? namestr + 1 : namestr); +#endif + +#if defined(_WIN32) || defined(_WINDOWS) || defined(XP_OS2) + if ((hashp->fp = mkstempflags(filename, _O_BINARY|_O_TEMPORARY)) != -1) { + if (hashp->filename) { + free(hashp->filename); + } + hashp->filename = strdup(filename); + hashp->is_temp = 1; + } +#else + if ((hashp->fp = mkstemp(filename)) != -1) { + (void)unlink(filename); +#if !defined(macintosh) (void)fcntl(hashp->fp, F_SETFD, 1); #endif } +#endif #if !defined(_WIN32) && !defined(_WINDOWS) && !defined(macintosh) && !defined(XP_OS2) (void)sigprocmask(SIG_SETMASK, &oset, (sigset_t *)NULL); diff --git a/dbm/src/hash.c b/dbm/src/hash.c index 5aa91424b..8be75721b 100644 --- a/dbm/src/hash.c +++ b/dbm/src/hash.c @@ -65,15 +65,16 @@ static char sccsid[] = "@(#)hash.c 8.9 (Berkeley) 6/16/94"; #if !defined(_WIN32) && !defined(_WINDOWS) && !defined(macintosh) && !defined(XP_OS2_VACPP) #include <unistd.h> #endif +#if defined(_WIN32) || defined(_WINDOWS) +#include <windows.h> +#endif #ifdef XP_OS2_VACPP #include "types.h" #define EPERM SOCEPERM #endif -#ifdef DEBUG #include <assert.h> -#endif #include "mcom_db.h" #include "hash.h" @@ -117,25 +118,21 @@ int hash_accesses, hash_collisions, hash_expansions, hash_overflows; /* A new Lou (montulli@mozilla.com) routine. * - * The database is screwed. Delete it by - * making it a zero length file + * The database is screwed. * - * This zero's hashp so that the - * database can't be accessed any more + * This closes the file, flushing buffers as appropriate. */ static void __remove_database(DB *dbp) { HTAB *hashp = (HTAB *)dbp->internal; - if (!hashp) - return; - if(hashp->fp != NO_FILE) - close(hashp->fp); - if(hashp->filename) - unlink(hashp->filename); - dbp->internal = NULL; /* zero the internal stuff */ + assert(0); + if (!hashp) + return; + hdestroy(hashp); + dbp->internal = NULL; } /************************** INTERFACE ROUTINES ***************************/ @@ -189,6 +186,7 @@ __hash_open(const char *file, int flags, int mode, const HASHINFO *info, int dfl */ new_table = 1; } + hashp->file_size = statbuf.st_size; if (file) { @@ -561,8 +559,13 @@ hdestroy(HTAB *hashp) if (hashp->fp != -1) (void)close(hashp->fp); - if(hashp->filename) + if(hashp->filename) { +#if defined(_WIN32) || defined(_WINDOWS) || defined(XP_OS2) + if (hashp->is_temp) + (void)unlink(hashp->filename); +#endif free(hashp->filename); + } free(hashp); @@ -572,6 +575,65 @@ hdestroy(HTAB *hashp) } return (SUCCESS); } + +#if defined(_WIN32) || defined(_WINDOWS) +/* + * Close and reopen file to force file length update on windows. + * + * Returns: + * 0 == OK + * -1 DBM_ERROR + */ +static int +update_EOF(HTAB *hashp) +{ +#if defined(DBM_REOPEN_ON_FLUSH) + char * file = hashp->filename; + off_t file_size; + int flags; + int mode = -1; + struct stat statbuf; + + memset(&statbuf, 0, sizeof statbuf); + + /* make sure we won't lose the file by closing it. */ + if (!file || (stat(file, &statbuf) && (errno == ENOENT))) { + /* pretend we did it. */ + return 0; + } + + (void)close(hashp->fp); + + flags = hashp->flags & ~(O_TRUNC | O_CREAT | O_EXCL); + + if ((hashp->fp = DBFILE_OPEN(file, flags | O_BINARY, mode)) == -1) + return -1; + file_size = lseek(hashp->fp, (off_t)0, SEEK_END); + if (file_size == -1) + return -1; + hashp->file_size = file_size; + return 0; +#else + int fd = hashp->fp; + off_t file_size = lseek(fd, (off_t)0, SEEK_END); + HANDLE handle = (HANDLE)_get_osfhandle(fd); + BOOL cool = FlushFileBuffers(handle); +#ifdef DEBUG3 + if (!cool) { + DWORD err = GetLastError(); + (void)fprintf(stderr, + "FlushFileBuffers failed, last error = %d, 0x%08x\n", + err, err); + } +#endif + if (file_size == -1) + return -1; + hashp->file_size = file_size; + return cool ? 0 : -1; +#endif +} +#endif + /* * Write modified pages to disk * @@ -600,6 +662,14 @@ hash_sync(const DB *dbp, uint flags) return (0); if (__buf_free(hashp, 0, 1) || flush_meta(hashp)) return (DBM_ERROR); +#if defined(_WIN32) || defined(_WINDOWS) + if (hashp->updateEOF && hashp->filename && !hashp->is_temp) { + int status = update_EOF(hashp); + hashp->updateEOF = 0; + if (status) + return status; + } +#endif hashp->new_file = 0; return (0); } diff --git a/dbm/src/mktemp.c b/dbm/src/mktemp.c index ab606e30f..4da6c9497 100644 --- a/dbm/src/mktemp.c +++ b/dbm/src/mktemp.c @@ -64,28 +64,35 @@ static char sccsid[] = "@(#)mktemp.c 8.1 (Berkeley) 6/4/93"; #include "winfile.h" #endif -static int _gettemp(char *path, register int *doopen); +static int _gettemp(char *path, register int *doopen, int extraFlags); int -mkstemp(path) - char *path; +mkstemp(char *path) { int fd; - return (_gettemp(path, &fd) ? fd : -1); + return (_gettemp(path, &fd, 0) ? fd : -1); +} + +int +mkstempflags(char *path, int extraFlags) +{ + int fd; + + return (_gettemp(path, &fd, extraFlags) ? fd : -1); } char * -mktemp(path) - char *path; +mktemp(char *path) { - return(_gettemp(path, (int *)NULL) ? path : (char *)NULL); + return(_gettemp(path, (int *)NULL, 0) ? path : (char *)NULL); } -static int -_gettemp(path, doopen) - char *path; - register int *doopen; +/* NB: This routine modifies its input string, and does not always restore it. +** returns 1 on success, 0 on failure. +*/ +static int +_gettemp(char *path, register int *doopen, int extraFlags) { #if !defined(_WINDOWS) || defined(_WIN32) extern int errno; @@ -106,17 +113,21 @@ _gettemp(path, doopen) * doesn't exist this runs for a *very* long time. */ for (start = trv + 1;; --trv) { + char saved; if (trv <= path) break; - if (*trv == '/') { + saved = *trv; + if (saved == '/' || saved == '\\') { + int rv; *trv = '\0'; - if (stat(path, &sbuf)) + rv = stat(path, &sbuf); + *trv = saved; + if (rv) return(0); if (!S_ISDIR(sbuf.st_mode)) { errno = ENOTDIR; return(0); } - *trv = '/'; break; } } @@ -124,7 +135,7 @@ _gettemp(path, doopen) for (;;) { if (doopen) { if ((*doopen = - open(path, O_CREAT|O_EXCL|O_RDWR, 0600)) >= 0) + open(path, O_CREAT|O_EXCL|O_RDWR|extraFlags, 0600)) >= 0) return(1); if (errno != EEXIST) return(0); |