Main Page | Class Hierarchy | Data Structures | Directories | File List | Data Fields | Related Pages

os_open.c

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1997-2005
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * $Id: os_open.c,v 12.6 2005/10/31 11:21:01 mjc Exp $
00008  */
00009 
00010 #include "db_config.h"
00011 
00012 #ifndef NO_SYSTEM_INCLUDES
00013 #include <sys/types.h>
00014 
00015 #include <fcntl.h>
00016 #include <signal.h>
00017 #include <string.h>
00018 #endif
00019 
00020 #include "db_int.h"
00021 
00022 /*
00023  * __os_have_direct --
00024  *      Check to see if we support direct I/O.
00025  *
00026  * PUBLIC: int __os_have_direct __P((void));
00027  */
00028 int
00029 __os_have_direct()
00030 {
00031         return (1);
00032 }
00033 
00034 /*
00035  * __os_open --
00036  *      Open a file descriptor.
00037  */
00038 __os_open(dbenv, name, flags, mode, fhpp)
00039         DB_ENV *dbenv;
00040         const char *name;
00041         u_int32_t flags;
00042         int mode;
00043         DB_FH **fhpp;
00044 {
00045         return (__os_open_extend(dbenv, name, 0, flags, mode, fhpp));
00046 }
00047 
00048 /*
00049  * __os_open_extend --
00050  *      Open a file descriptor (including page size and log size information).
00051  */
00052 int
00053 __os_open_extend(dbenv, name, page_size, flags, mode, fhpp)
00054         DB_ENV *dbenv;
00055         const char *name;
00056         u_int32_t page_size, flags;
00057         int mode;
00058         DB_FH **fhpp;
00059 {
00060         DB_FH *fhp;
00061         DWORD cluster_size, sector_size, free_clusters, total_clusters;
00062         int access, attr, createflag, nrepeat, oflags, ret, share;
00063         _TCHAR *drive, *tname;
00064         _TCHAR dbuf[4]; /* <letter><colon><slash><nul> */
00065 
00066         fhp = NULL;
00067         tname = NULL;
00068 
00069 #define OKFLAGS                                                         \
00070         (DB_OSO_ABSMODE | DB_OSO_CREATE | DB_OSO_DIRECT | DB_OSO_DSYNC |\
00071         DB_OSO_EXCL | DB_OSO_RDONLY | DB_OSO_REGION |   DB_OSO_SEQ |    \
00072         DB_OSO_TEMP | DB_OSO_TRUNC)
00073         if ((ret = __db_fchk(dbenv, "__os_open", flags, OKFLAGS)) != 0)
00074                 return (ret);
00075 
00076         /*
00077          * The "public" interface to the __os_open routine passes around POSIX
00078          * 1003.1 flags, not DB flags.  If the user has defined their own open
00079          * interface, use the POSIX flags.
00080          */
00081         if (DB_GLOBAL(j_open) != NULL) {
00082                 oflags = O_BINARY | O_NOINHERIT;
00083 
00084                 if (LF_ISSET(DB_OSO_CREATE))
00085                         oflags |= O_CREAT;
00086 #ifdef O_DSYNC
00087                 if (LF_ISSET(DB_OSO_DSYNC))
00088                         oflags |= O_DSYNC;
00089 #endif
00090 
00091                 if (LF_ISSET(DB_OSO_EXCL))
00092                         oflags |= O_EXCL;
00093 
00094                 if (LF_ISSET(DB_OSO_RDONLY))
00095                         oflags |= O_RDONLY;
00096                 else
00097                         oflags |= O_RDWR;
00098 
00099                 if (LF_ISSET(DB_OSO_SEQ))
00100                         oflags |= _O_SEQUENTIAL;
00101                 else
00102                         oflags |= _O_RANDOM;
00103 
00104                 if (LF_ISSET(DB_OSO_TEMP))
00105                         oflags |= _O_TEMPORARY;
00106 
00107                 if (LF_ISSET(DB_OSO_TRUNC))
00108                         oflags |= O_TRUNC;
00109 
00110                 return (__os_openhandle(dbenv, name, oflags, mode, fhpp));
00111         }
00112 
00113         TO_TSTRING(dbenv, name, tname, ret);
00114         if (ret != 0)
00115                 goto err;
00116 
00117         if ((ret = __os_calloc(dbenv, 1, sizeof(DB_FH), &fhp)) != 0)
00118                 goto err;
00119 
00120         /*
00121          * Otherwise, use the Windows/32 CreateFile interface so that we can
00122          * play magic games with files to get data flush effects similar to
00123          * the POSIX O_DSYNC flag.
00124          *
00125          * !!!
00126          * We currently ignore the 'mode' argument.  It would be possible
00127          * to construct a set of security attributes that we could pass to
00128          * CreateFile that would accurately represents the mode.  In worst
00129          * case, this would require looking up user and all group names and
00130          * creating an entry for each.  Alternatively, we could call the
00131          * _chmod (partial emulation) function after file creation, although
00132          * this leaves us with an obvious race.  However, these efforts are
00133          * largely meaningless on FAT, the most common file system, which
00134          * only has a "readable" and "writeable" flag, applying to all users.
00135          */
00136         access = GENERIC_READ;
00137         if (!LF_ISSET(DB_OSO_RDONLY))
00138                 access |= GENERIC_WRITE;
00139 
00140         share = FILE_SHARE_READ | FILE_SHARE_WRITE;
00141         if (__os_is_winnt())
00142                 share |= FILE_SHARE_DELETE;
00143         attr = FILE_ATTRIBUTE_NORMAL;
00144 
00145         /*
00146          * Reproduce POSIX 1003.1 semantics: if O_CREATE and O_EXCL are both
00147          * specified, fail, returning EEXIST, unless we create the file.
00148          */
00149         if (LF_ISSET(DB_OSO_CREATE) && LF_ISSET(DB_OSO_EXCL))
00150                 createflag = CREATE_NEW;        /* create only if !exist*/
00151         else if (!LF_ISSET(DB_OSO_CREATE) && LF_ISSET(DB_OSO_TRUNC))
00152                 createflag = TRUNCATE_EXISTING; /* truncate, fail if !exist */
00153         else if (LF_ISSET(DB_OSO_TRUNC))
00154                 createflag = CREATE_ALWAYS;     /* create and truncate */
00155         else if (LF_ISSET(DB_OSO_CREATE))
00156                 createflag = OPEN_ALWAYS;       /* open or create */
00157         else
00158                 createflag = OPEN_EXISTING;     /* open only if existing */
00159 
00160         if (LF_ISSET(DB_OSO_DSYNC)) {
00161                 F_SET(fhp, DB_FH_NOSYNC);
00162                 attr |= FILE_FLAG_WRITE_THROUGH;
00163         }
00164 
00165         if (LF_ISSET(DB_OSO_SEQ))
00166                 attr |= FILE_FLAG_SEQUENTIAL_SCAN;
00167         else
00168                 attr |= FILE_FLAG_RANDOM_ACCESS;
00169 
00170         if (LF_ISSET(DB_OSO_TEMP))
00171                 attr |= FILE_FLAG_DELETE_ON_CLOSE;
00172 
00173         /*
00174          * We can turn filesystem buffering off if the page size is a
00175          * multiple of the disk's sector size. To find the sector size,
00176          * we call GetDiskFreeSpace, which expects a drive name like "d:\\"
00177          * or NULL for the current disk (i.e., a relative path)
00178          */
00179         if (LF_ISSET(DB_OSO_DIRECT) && page_size != 0 && name[0] != '\0') {
00180                 if (name[1] == ':') {
00181                         drive = dbuf;
00182                         _sntprintf(dbuf, sizeof(dbuf), _T("%c:\\"), tname[0]);
00183                 } else
00184                         drive = NULL;
00185 
00186                 /*
00187                  * We ignore all results except sectorsize, but some versions
00188                  * of Windows require that the parameters are non-NULL.
00189                  */
00190                 if (GetDiskFreeSpace(drive, &cluster_size,
00191                     &sector_size, &free_clusters, &total_clusters) &&
00192                     page_size % sector_size == 0)
00193                         attr |= FILE_FLAG_NO_BUFFERING;
00194         }
00195 
00196         for (nrepeat = 1;; ++nrepeat) {
00197                 fhp->handle =
00198                     CreateFile(tname, access, share, NULL, createflag, attr, 0);
00199                 if (fhp->handle == INVALID_HANDLE_VALUE) {
00200                         /*
00201                          * If it's a "temporary" error, we retry up to 3 times,
00202                          * waiting up to 12 seconds.  While it's not a problem
00203                          * if we can't open a database, an inability to open a
00204                          * log file is cause for serious dismay.
00205                          */
00206                         ret = __os_get_errno();
00207                         if ((ret != ENFILE && ret != EMFILE && ret != ENOSPC) ||
00208                             nrepeat > 3)
00209                                 goto err;
00210 
00211                         __os_sleep(dbenv, nrepeat * 2, 0);
00212                 } else
00213                         break;
00214         }
00215 
00216         FREE_STRING(dbenv, tname);
00217 
00218         F_SET(fhp, DB_FH_OPENED);
00219         *fhpp = fhp;
00220         return (0);
00221 
00222 err:    if (ret == 0)
00223                 ret = __os_get_errno();
00224 
00225         FREE_STRING(dbenv, tname);
00226         if (fhp != NULL)
00227                 (void)__os_closehandle(dbenv, fhp);
00228         return (ret);
00229 }

Generated on Sun Dec 25 12:14:42 2005 for Berkeley DB 4.4.16 by  doxygen 1.4.2