1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 1998,2008 Oracle. All rights reserved. 5 * 6 * $Id: os_handle.c,v 12.22 2008/01/31 18:40:47 bostic Exp $ 7 */ 8 9#include "db_config.h" 10 11#include "db_int.h" 12 13/* 14 * __os_openhandle -- 15 * Open a file, using POSIX 1003.1 open flags. 16 */ 17int 18__os_openhandle(env, name, flags, mode, fhpp) 19 ENV *env; 20 const char *name; 21 int flags, mode; 22 DB_FH **fhpp; 23{ 24#ifdef DB_WINCE 25 /* 26 * __os_openhandle API is not implemented on WinCE. 27 * It is not currently called from within the Berkeley DB library, 28 * so don't log the failure via the __db_err mechanism. 29 */ 30 return (EFAULT); 31#else 32 DB_FH *fhp; 33 int ret, nrepeat, retries; 34 35 /* 36 * Allocate the file handle and copy the file name. We generally only 37 * use the name for verbose or error messages, but on systems where we 38 * can't unlink temporary files immediately, we use the name to unlink 39 * the temporary file when the file handle is closed. 40 * 41 * Lock the ENV handle and insert the new file handle on the list. 42 */ 43 if ((ret = __os_calloc(env, 1, sizeof(DB_FH), &fhp)) != 0) 44 return (ret); 45 if ((ret = __os_strdup(env, name, &fhp->name)) != 0) 46 goto err; 47 if (env != NULL) { 48 MUTEX_LOCK(env, env->mtx_env); 49 TAILQ_INSERT_TAIL(&env->fdlist, fhp, q); 50 MUTEX_UNLOCK(env, env->mtx_env); 51 F_SET(fhp, DB_FH_ENVLINK); 52 } 53 54 retries = 0; 55 for (nrepeat = 1; nrepeat < 4; ++nrepeat) { 56 fhp->fd = _open(name, flags, mode); 57 58 if (fhp->fd != -1) { 59 ret = 0; 60 break; 61 } 62 63 switch (ret = __os_posix_err(__os_get_syserr())) { 64 case EMFILE: 65 case ENFILE: 66 case ENOSPC: 67 /* 68 * If it's a "temporary" error, we retry up to 3 times, 69 * waiting up to 12 seconds. While it's not a problem 70 * if we can't open a database, an inability to open a 71 * log file is cause for serious dismay. 72 */ 73 __os_yield(env, nrepeat * 2, 0); 74 break; 75 case EAGAIN: 76 case EBUSY: 77 case EINTR: 78 /* 79 * If an EAGAIN, EBUSY or EINTR, retry immediately for 80 * DB_RETRY times. 81 */ 82 if (++retries < DB_RETRY) 83 --nrepeat; 84 break; 85 default: 86 /* Open is silent on error. */ 87 goto err; 88 } 89 } 90 91 if (ret == 0) { 92 F_SET(fhp, DB_FH_OPENED); 93 *fhpp = fhp; 94 return (0); 95 } 96 97err: (void)__os_closehandle(env, fhp); 98 return (ret); 99#endif 100} 101 102/* 103 * __os_closehandle -- 104 * Close a file. 105 */ 106int 107__os_closehandle(env, fhp) 108 ENV *env; 109 DB_FH *fhp; 110{ 111 DB_ENV *dbenv; 112 int ret, t_ret; 113 114 ret = 0; 115 116 if (env != NULL) { 117 dbenv = env->dbenv; 118 if (fhp->name != NULL && FLD_ISSET( 119 dbenv->verbose, DB_VERB_FILEOPS | DB_VERB_FILEOPS_ALL)) 120 __db_msg(env, "fileops: %s: close", fhp->name); 121 122 if (F_ISSET(fhp, DB_FH_ENVLINK)) { 123 /* 124 * Lock the ENV handle and remove this file 125 * handle from the list. 126 */ 127 MUTEX_LOCK(env, env->mtx_env); 128 TAILQ_REMOVE(&env->fdlist, fhp, q); 129 MUTEX_UNLOCK(env, env->mtx_env); 130 } 131 } 132 133 /* Discard any underlying system file reference. */ 134 if (F_ISSET(fhp, DB_FH_OPENED)) { 135 if (fhp->handle != INVALID_HANDLE_VALUE) 136 RETRY_CHK((!CloseHandle(fhp->handle)), ret); 137 else 138#ifdef DB_WINCE 139 ret = EFAULT; 140#else 141 RETRY_CHK((_close(fhp->fd)), ret); 142#endif 143 144 if (fhp->trunc_handle != INVALID_HANDLE_VALUE) { 145 RETRY_CHK((!CloseHandle(fhp->trunc_handle)), t_ret); 146 if (t_ret != 0 && ret == 0) 147 ret = t_ret; 148 } 149 150 if (ret != 0) { 151 __db_syserr(env, ret, "CloseHandle"); 152 ret = __os_posix_err(ret); 153 } 154 } 155 156 /* Unlink the file if we haven't already done so. */ 157 if (F_ISSET(fhp, DB_FH_UNLINK)) 158 (void)__os_unlink(env, fhp->name, 0); 159 160 if (fhp->name != NULL) 161 __os_free(env, fhp->name); 162 __os_free(env, fhp); 163 164 return (ret); 165} 166