source: trunk/third/rpm/db/os_win32/os_open.c @ 19079

Revision 19079, 5.9 KB checked in by ghudson, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r19078, which included commits to RCS files with non-trunk default branches.
Line 
1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1997-2002
5 *      Sleepycat Software.  All rights reserved.
6 */
7
8#include "db_config.h"
9
10#ifndef lint
11static const char revid[] = "Id: os_open.c,v 11.21 2002/07/12 18:56:55 bostic Exp ";
12#endif /* not lint */
13
14#ifndef NO_SYSTEM_INCLUDES
15#include <sys/types.h>
16
17#include <fcntl.h>
18#include <signal.h>
19#include <string.h>
20#include <unistd.h>
21#endif
22
23#include "db_int.h"
24
25/*
26 * __os_open --
27 *      Open a file descriptor.
28 */
29int
30__os_open(dbenv, name, flags, mode, fhp)
31        DB_ENV *dbenv;
32        const char *name;
33        u_int32_t flags;
34        int mode;
35        DB_FH *fhp;
36{
37        DWORD bytesWritten;
38        u_int32_t log_size, pagesize, sectorsize;
39        int access, attr, oflags, share, createflag;
40        int ret, nrepeat;
41        char *drive, dbuf[4]; /* <letter><colon><slosh><nul> */
42
43#ifdef DIAGNOSTIC
44#define OKFLAGS                                                         \
45        (DB_OSO_CREATE | DB_OSO_DIRECT | DB_OSO_EXCL | DB_OSO_LOG |     \
46         DB_OSO_RDONLY | DB_OSO_REGION | DB_OSO_SEQ | DB_OSO_TEMP |     \
47         DB_OSO_TRUNC)
48        if ((ret = __db_fchk(dbenv, "__os_open", flags, OKFLAGS)) != 0)
49                return (ret);
50#endif
51
52        /*
53         * The "public" interface to the __os_open routine passes around POSIX
54         * 1003.1 flags, not DB flags.  If the user has defined their own open
55         * interface, use the POSIX flags.
56         */
57        if (DB_GLOBAL(j_open) != NULL) {
58                oflags = O_BINARY | O_NOINHERIT;
59
60                if (LF_ISSET(DB_OSO_CREATE))
61                        oflags |= O_CREAT;
62
63                if (LF_ISSET(DB_OSO_EXCL))
64                        oflags |= O_EXCL;
65
66                if (LF_ISSET(DB_OSO_RDONLY))
67                        oflags |= O_RDONLY;
68                else
69                        oflags |= O_RDWR;
70
71                if (LF_ISSET(DB_OSO_SEQ))
72                        oflags |= _O_SEQUENTIAL;
73                else
74                        oflags |= _O_RANDOM;
75
76                if (LF_ISSET(DB_OSO_TEMP))
77                        oflags |= _O_TEMPORARY;
78
79                if (LF_ISSET(DB_OSO_TRUNC))
80                        oflags |= O_TRUNC;
81
82                return (__os_openhandle(dbenv, name, oflags, mode, fhp));
83        }
84
85        ret = 0;
86
87        if (LF_ISSET(DB_OSO_LOG))
88                log_size = fhp->log_size;                       /* XXX: Gag. */
89
90        pagesize = fhp->pagesize;
91
92        memset(fhp, 0, sizeof(*fhp));
93        fhp->fd = -1;
94
95        /*
96         * Otherwise, use the Windows/32 CreateFile interface so that we can
97         * play magic games with log files to get data flush effects similar
98         * to the POSIX O_DSYNC flag.
99         *
100         * !!!
101         * We currently ignore the 'mode' argument.  It would be possible
102         * to construct a set of security attributes that we could pass to
103         * CreateFile that would accurately represents the mode.  In worst
104         * case, this would require looking up user and all group names and
105         * creating an entry for each.  Alternatively, we could call the
106         * _chmod (partial emulation) function after file creation, although
107         * this leaves us with an obvious race.  However, these efforts are
108         * largely meaningless on FAT, the most common file system, which
109         * only has a "readable" and "writeable" flag, applying to all users.
110         */
111        access = GENERIC_READ;
112        if (!LF_ISSET(DB_OSO_RDONLY))
113                access |= GENERIC_WRITE;
114
115        share = FILE_SHARE_READ | FILE_SHARE_WRITE;
116        attr = FILE_ATTRIBUTE_NORMAL;
117
118        /*
119         * Reproduce POSIX 1003.1 semantics: if O_CREATE and O_EXCL are both
120         * specified, fail, returning EEXIST, unless we create the file.
121         */
122        if (LF_ISSET(DB_OSO_CREATE) && LF_ISSET(DB_OSO_EXCL))
123                createflag = CREATE_NEW;        /* create only if !exist*/
124        else if (!LF_ISSET(DB_OSO_CREATE) && LF_ISSET(DB_OSO_TRUNC))
125                createflag = TRUNCATE_EXISTING; /* truncate, fail if !exist */
126        else if (LF_ISSET(DB_OSO_TRUNC))
127                createflag = CREATE_ALWAYS;     /* create and truncate */
128        else if (LF_ISSET(DB_OSO_CREATE))
129                createflag = OPEN_ALWAYS;       /* open or create */
130        else
131                createflag = OPEN_EXISTING;     /* open only if existing */
132
133        if (LF_ISSET(DB_OSO_LOG)) {
134                F_SET(fhp, DB_FH_NOSYNC);
135                attr |= FILE_FLAG_WRITE_THROUGH;
136        }
137
138        if (LF_ISSET(DB_OSO_SEQ))
139                attr |= FILE_FLAG_SEQUENTIAL_SCAN;
140        else
141                attr |= FILE_FLAG_RANDOM_ACCESS;
142
143        if (LF_ISSET(DB_OSO_TEMP))
144                attr |= FILE_FLAG_DELETE_ON_CLOSE;
145
146        /*
147         * We can turn filesystem buffering off if the page size is a
148         * multiple of the disk's sector size. To find the sector size,
149         * we call GetDiskFreeSpace, which expects a drive name like "d:\\"
150         * or NULL for the current disk (i.e., a relative path)
151         */
152        if (LF_ISSET(DB_OSO_DIRECT) && pagesize != 0 && name[0] != '\0') {
153                if (name[1] == ':') {
154                        drive = dbuf;
155                        snprintf(dbuf, sizeof(dbuf), "%c:\\", name[0]);
156                } else
157                        drive = NULL;
158
159                if (GetDiskFreeSpace(drive, NULL, &sectorsize, NULL, NULL) &&
160                    pagesize % sectorsize == 0)
161                        attr |= FILE_FLAG_NO_BUFFERING;
162        }
163
164        for (nrepeat = 1;; ++nrepeat) {
165                fhp->handle =
166                    CreateFile(name, access, share, NULL, createflag, attr, 0);
167                if (fhp->handle == INVALID_HANDLE_VALUE) {
168                        /*
169                         * If it's a "temporary" error, we retry up to 3 times,
170                         * waiting up to 12 seconds.  While it's not a problem
171                         * if we can't open a database, an inability to open a
172                         * log file is cause for serious dismay.
173                         */
174                        ret = __os_win32_errno();
175                        if ((ret != ENFILE && ret != EMFILE && ret != ENOSPC) ||
176                            nrepeat > 3)
177                                goto err;
178
179                        (void)__os_sleep(dbenv, nrepeat * 2, 0);
180                } else
181                        break;
182        }
183
184        /*
185         * Special handling needed for log files.  To get Windows to not update
186         * the MFT metadata on each write, extend the file to its maximum size.
187         * Windows will allocate all the data blocks and store them in the MFT
188         * (inode) area.  In addition, flush the MFT area to disk.
189         * This strategy only works for Win/NT; Win/9X does not
190         * guarantee that the logs will be zero filled.
191         */
192        if (LF_ISSET(DB_OSO_LOG) && log_size != 0 && __os_is_winnt()) {
193                if (SetFilePointer(fhp->handle,
194                    log_size - 1, NULL, FILE_BEGIN) == (DWORD)-1)
195                        goto err;
196                if (WriteFile(fhp->handle, "\x00", 1, &bytesWritten, NULL) == 0)
197                        goto err;
198                if (bytesWritten != 1)
199                        goto err;
200                if (SetEndOfFile(fhp->handle) == 0)
201                        goto err;
202                if (SetFilePointer(
203                    fhp->handle, 0, NULL, FILE_BEGIN) == (DWORD)-1)
204                        goto err;
205                if (FlushFileBuffers(fhp->handle) == 0)
206                        goto err;
207        }
208
209        F_SET(fhp, DB_FH_VALID);
210        return (0);
211
212err:    if (ret == 0)
213                ret = __os_win32_errno();
214        if (fhp->handle != INVALID_HANDLE_VALUE)
215                (void)CloseHandle(fhp->handle);
216        return (ret);
217}
Note: See TracBrowser for help on using the repository browser.