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.7 2005/10/31 02:22:32 bostic Exp $
00008  */
00009 
00010 #include "db_config.h"
00011 
00012 #ifndef NO_SYSTEM_INCLUDES
00013 #include <sys/types.h>
00014 #include <sys/stat.h>
00015 
00016 #ifdef HAVE_SYS_FCNTL_H
00017 #include <sys/fcntl.h>
00018 #endif
00019 
00020 #include <fcntl.h>
00021 #include <string.h>
00022 #endif
00023 
00024 #include "db_int.h"
00025 
00026 static int __os_intermediate_dir __P((DB_ENV *, const char *));
00027 #ifdef HAVE_QNX
00028 static int __os_region_open __P((DB_ENV *, const char *, int, int, DB_FH **));
00029 #endif
00030 
00031 /*
00032  * __os_have_direct --
00033  *      Check to see if we support direct I/O.
00034  *
00035  * PUBLIC: int __os_have_direct __P((void));
00036  */
00037 int
00038 __os_have_direct()
00039 {
00040         int ret;
00041 
00042         ret = 0;
00043 
00044 #ifdef HAVE_O_DIRECT
00045         ret = 1;
00046 #endif
00047 #if defined(HAVE_DIRECTIO) && defined(DIRECTIO_ON)
00048         ret = 1;
00049 #endif
00050         return (ret);
00051 }
00052 
00053 /*
00054  * __os_open --
00055  *      Open a file.
00056  *
00057  * PUBLIC: int __os_open
00058  * PUBLIC:     __P((DB_ENV *, const char *, u_int32_t, int, DB_FH **));
00059  */
00060 int
00061 __os_open(dbenv, name, flags, mode, fhpp)
00062         DB_ENV *dbenv;
00063         const char *name;
00064         u_int32_t flags;
00065         int mode;
00066         DB_FH **fhpp;
00067 {
00068         return (__os_open_extend(dbenv, name, 0, flags, mode, fhpp));
00069 }
00070 
00071 /*
00072  * __os_open_extend --
00073  *      Open a file descriptor (including page size and log size information).
00074  *
00075  * PUBLIC: int __os_open_extend __P((DB_ENV *,
00076  * PUBLIC:     const char *, u_int32_t, u_int32_t, int, DB_FH **));
00077  */
00078 int
00079 __os_open_extend(dbenv, name, page_size, flags, mode, fhpp)
00080         DB_ENV *dbenv;
00081         const char *name;
00082         u_int32_t page_size, flags;
00083         int mode;
00084         DB_FH **fhpp;
00085 {
00086         DB_FH *fhp;
00087         int oflags, ret;
00088 
00089         COMPQUIET(page_size, 0);
00090 
00091         *fhpp = NULL;
00092         oflags = 0;
00093 
00094 #define OKFLAGS                                                         \
00095         (DB_OSO_ABSMODE | DB_OSO_CREATE | DB_OSO_DIRECT | DB_OSO_DSYNC |\
00096         DB_OSO_EXCL | DB_OSO_RDONLY | DB_OSO_REGION | DB_OSO_SEQ |      \
00097         DB_OSO_TEMP | DB_OSO_TRUNC)
00098         if ((ret = __db_fchk(dbenv, "__os_open", flags, OKFLAGS)) != 0)
00099                 return (ret);
00100 
00101 #if defined(O_BINARY)
00102         /*
00103          * If there's a binary-mode open flag, set it, we never want any
00104          * kind of translation.  Some systems do translations by default,
00105          * e.g., with Cygwin, the default mode for an open() is set by the
00106          * mode of the mount that underlies the file.
00107          */
00108         oflags |= O_BINARY;
00109 #endif
00110 
00111         /*
00112          * DB requires the POSIX 1003.1 semantic that two files opened at the
00113          * same time with DB_OSO_CREATE/O_CREAT and DB_OSO_EXCL/O_EXCL flags
00114          * set return an EEXIST failure in at least one.
00115          */
00116         if (LF_ISSET(DB_OSO_CREATE))
00117                 oflags |= O_CREAT;
00118 
00119         if (LF_ISSET(DB_OSO_EXCL))
00120                 oflags |= O_EXCL;
00121 
00122 #ifdef HAVE_O_DIRECT
00123         if (LF_ISSET(DB_OSO_DIRECT))
00124                 oflags |= O_DIRECT;
00125 #endif
00126 #ifdef O_DSYNC
00127         if (LF_ISSET(DB_OSO_DSYNC))
00128                 oflags |= O_DSYNC;
00129 #endif
00130 
00131         if (LF_ISSET(DB_OSO_RDONLY))
00132                 oflags |= O_RDONLY;
00133         else
00134                 oflags |= O_RDWR;
00135 
00136         if (LF_ISSET(DB_OSO_TRUNC))
00137                 oflags |= O_TRUNC;
00138 
00139         /*
00140          * Undocumented feature: allow applications to create intermediate
00141          * directories whenever a file is opened.
00142          */
00143         if (dbenv != NULL &&
00144             dbenv->dir_mode != 0 && LF_ISSET(DB_OSO_CREATE) &&
00145             (ret = __os_intermediate_dir(dbenv, name)) != 0)
00146                 return (ret);
00147 
00148 #ifdef HAVE_QNX
00149         if (LF_ISSET(DB_OSO_REGION))
00150                 return (__os_qnx_region_open(dbenv, name, oflags, mode, fhpp));
00151 #endif
00152         /* Open the file. */
00153         if ((ret = __os_openhandle(dbenv, name, oflags, mode, &fhp)) != 0)
00154                 return (ret);
00155 
00156 #ifdef HAVE_FCHMOD
00157         /*
00158          * If the code using Berkeley DB is a library, that code may not be able
00159          * to control the application's umask value.  Allow applications to set
00160          * absolute file modes.  We can't fix the race between file creation and
00161          * the fchmod call -- we can't modify the process' umask here since the
00162          * process may be multi-threaded and the umask value is per-process, not
00163          * per-thread.
00164          */
00165         if (LF_ISSET(DB_OSO_CREATE) && LF_ISSET(DB_OSO_ABSMODE))
00166                 (void)fchmod(fhp->fd, mode);
00167 #endif
00168 
00169 #ifdef O_DSYNC
00170         /*
00171          * If we can configure the file descriptor to flush on write, the
00172          * file descriptor does not need to be explicitly sync'd.
00173          */
00174         if (LF_ISSET(DB_OSO_DSYNC))
00175                 F_SET(fhp, DB_FH_NOSYNC);
00176 #endif
00177 
00178 #if defined(HAVE_DIRECTIO) && defined(DIRECTIO_ON)
00179         /*
00180          * The Solaris C library includes directio, but you have to set special
00181          * compile flags to #define DIRECTIO_ON.  Require both in order to call
00182          * directio.
00183          */
00184         if (LF_ISSET(DB_OSO_DIRECT))
00185                 (void)directio(fhp->fd, DIRECTIO_ON);
00186 #endif
00187 
00188         /*
00189          * Delete any temporary file.
00190          *
00191          * !!!
00192          * There's a race here, where we've created a file and we crash before
00193          * we can unlink it.  Temporary files aren't common in DB, regardless,
00194          * it's not a security problem because the file is empty.  There's no
00195          * reasonable way to avoid the race (playing signal games isn't worth
00196          * the portability nightmare), so we just live with it.
00197          */
00198         if (LF_ISSET(DB_OSO_TEMP)) {
00199 #if defined(HAVE_UNLINK_WITH_OPEN_FAILURE) || defined(CONFIG_TEST)
00200                 if ((ret = __os_strdup(dbenv, name, &fhp->name)) != 0) {
00201                         (void)__os_closehandle(dbenv, fhp);
00202                         (void)__os_unlink(dbenv, name);
00203                         return (ret);
00204                 }
00205                 F_SET(fhp, DB_FH_UNLINK);
00206 #else
00207                 (void)__os_unlink(dbenv, name);
00208 #endif
00209         }
00210 
00211         *fhpp = fhp;
00212         return (0);
00213 }
00214 
00215 #ifdef HAVE_QNX
00216 /*
00217  * __os_qnx_region_open --
00218  *      Open a shared memory region file using POSIX shm_open.
00219  */
00220 static int
00221 __os_qnx_region_open(dbenv, name, oflags, mode, fhpp)
00222         DB_ENV *dbenv;
00223         const char *name;
00224         int oflags;
00225         int mode;
00226         DB_FH **fhpp;
00227 {
00228         DB_FH *fhp;
00229         int ret;
00230         char *newname;
00231 
00232         if ((ret = __os_calloc(dbenv, 1, sizeof(DB_FH), fhpp)) != 0)
00233                 return (ret);
00234         fhp = *fhpp;
00235 
00236         if ((ret = __os_shmname(dbenv, name, &newname)) != 0)
00237                 goto err;
00238 
00239         /*
00240          * Once we have created the object, we don't need the name
00241          * anymore.  Other callers of this will convert themselves.
00242          */
00243         fhp->fd = shm_open(newname, oflags, mode);
00244         __os_free(dbenv, newname);
00245 
00246         if (fhp->fd == -1) {
00247                 ret = __os_get_errno();
00248                 goto err;
00249         }
00250 
00251         F_SET(fhp, DB_FH_OPENED);
00252 
00253 #ifdef HAVE_FCNTL_F_SETFD
00254         /* Deny file descriptor access to any child process. */
00255         if (fcntl(fhp->fd, F_SETFD, 1) == -1) {
00256                 ret = __os_get_errno();
00257                 __db_err(dbenv, "fcntl(F_SETFD): %s", strerror(ret));
00258                 goto err;
00259         }
00260 #endif
00261 
00262 err:    if (ret != 0) {
00263                 (void)__os_closehandle(dbenv, fhp);
00264                 *fhpp = NULL;
00265         }
00266 
00267         return (ret);
00268 }
00269 
00270 /*
00271  * __os_shmname --
00272  *      Translate a pathname into a shm_open memory object name.
00273  *
00274  * PUBLIC: #ifdef HAVE_QNX
00275  * PUBLIC: int __os_shmname __P((DB_ENV *, const char *, char **));
00276  * PUBLIC: #endif
00277  */
00278 int
00279 __os_shmname(dbenv, name, newnamep)
00280         DB_ENV *dbenv;
00281         const char *name;
00282         char **newnamep;
00283 {
00284         int ret;
00285         size_t size;
00286         char *p, *q, *tmpname;
00287 
00288         *newnamep = NULL;
00289 
00290         /*
00291          * POSIX states that the name for a shared memory object
00292          * may begin with a slash '/' and support for subsequent
00293          * slashes is implementation-dependent.  The one implementation
00294          * we know of right now, QNX, forbids subsequent slashes.
00295          * We don't want to be parsing pathnames for '.' and '..' in
00296          * the middle.  In order to allow easy conversion, just take
00297          * the last component as the shared memory name.  This limits
00298          * the namespace a bit, but makes our job a lot easier.
00299          *
00300          * We should not be modifying user memory, so we use our own.
00301          * Caller is responsible for freeing the memory we give them.
00302          */
00303         if ((ret = __os_strdup(dbenv, name, &tmpname)) != 0)
00304                 return (ret);
00305         /*
00306          * Skip over filename component.
00307          * We set that separator to '\0' so that we can do another
00308          * __db_rpath.  However, we immediately set it then to ':'
00309          * so that we end up with the tailing directory:filename.
00310          * We require a home directory component.  Return an error
00311          * if there isn't one.
00312          */
00313         p = __db_rpath(tmpname);
00314         if (p == NULL)
00315                 return (EINVAL);
00316         if (p != tmpname) {
00317                 *p = '\0';
00318                 q = p;
00319                 p = __db_rpath(tmpname);
00320                 *q = ':';
00321         }
00322         if (p != NULL) {
00323                 /*
00324                  * If we have a path component, copy and return it.
00325                  */
00326                 ret = __os_strdup(dbenv, p, newnamep);
00327                 __os_free(dbenv, tmpname);
00328                 return (ret);
00329         }
00330 
00331         /*
00332          * We were given just a directory name with no path components.
00333          * Add a leading slash, and copy the remainder.
00334          */
00335         size = strlen(tmpname) + 2;
00336         if ((ret = __os_malloc(dbenv, size, &p)) != 0)
00337                 return (ret);
00338         p[0] = '/';
00339         memcpy(&p[1], tmpname, size-1);
00340         __os_free(dbenv, tmpname);
00341         *newnamep = p;
00342         return (0);
00343 }
00344 #endif
00345 
00346 /*
00347  * __os_intermediate_dir --
00348  *      Create intermediate directories.
00349  */
00350 static int
00351 __os_intermediate_dir(dbenv, name)
00352         DB_ENV *dbenv;
00353         const char *name;
00354 {
00355         size_t len;
00356         int ret;
00357         char savech, *p, *t, buf[128];
00358 
00359         ret = 0;
00360 
00361         /*
00362          * Get a copy so we can modify the string.
00363          *
00364          * Allocate memory if temporary space is too small.
00365          */
00366         if ((len = strlen(name)) > sizeof(buf) - 1) {
00367                 if ((ret = __os_umalloc(dbenv, len + 1, &t)) != 0)
00368                         return (ret);
00369         } else
00370                 t = buf;
00371         (void)strcpy(t, name);
00372 
00373         /*
00374          * Cycle through the path, creating intermediate directories.
00375          *
00376          * Skip the first byte if it's a path separator, it's the start of an
00377          * absolute pathname.
00378          */
00379         if (PATH_SEPARATOR[1] == '\0') {
00380                 for (p = t + 1; p[0] != '\0'; ++p)
00381                         if (p[0] == PATH_SEPARATOR[0]) {
00382                                 savech = *p;
00383                                 *p = '\0';
00384                                 if (__os_exists(t, NULL) &&
00385                                     (ret = __os_mkdir(
00386                                         dbenv, t, dbenv->dir_mode)) != 0)
00387                                         break;
00388                                 *p = savech;
00389                         }
00390         } else
00391                 for (p = t + 1; p[0] != '\0'; ++p)
00392                         if (strchr(PATH_SEPARATOR, p[0]) != NULL) {
00393                                 savech = *p;
00394                                 *p = '\0';
00395                                 if (__os_exists(t, NULL) &&
00396                                     (ret = __os_mkdir(
00397                                         dbenv, t, dbenv->dir_mode)) != 0)
00398                                         break;
00399                                 *p = savech;
00400                         }
00401         if (t != buf)
00402                 __os_free(dbenv, t);
00403         return (ret);
00404 }

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