#include "db_config.h"
#include "db_int.h"
int
__os_open(env, name, page_size, flags, mode, fhpp)
ENV *env;
const char *name;
u_int32_t page_size, flags;
int mode;
DB_FH **fhpp;
{
DB_ENV *dbenv;
DB_FH *fhp;
#ifndef DB_WINCE
DWORD cluster_size, sector_size, free_clusters, total_clusters;
_TCHAR *drive, dbuf[4];
#endif
int access, attr, createflag, nrepeat, ret, share;
_TCHAR *tname;
dbenv = env == NULL ? NULL : env->dbenv;
*fhpp = NULL;
tname = NULL;
if (dbenv != NULL &&
FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS | DB_VERB_FILEOPS_ALL))
__db_msg(env, "fileops: open %s", name);
#define OKFLAGS \
(DB_OSO_ABSMODE | DB_OSO_CREATE | DB_OSO_DIRECT | DB_OSO_DSYNC |\
DB_OSO_EXCL | DB_OSO_RDONLY | DB_OSO_REGION | DB_OSO_SEQ | \
DB_OSO_TEMP | DB_OSO_TRUNC)
if ((ret = __db_fchk(env, "__os_open", flags, OKFLAGS)) != 0)
return (ret);
TO_TSTRING(env, name, tname, ret);
if (ret != 0)
goto err;
if ((ret = __os_calloc(env, 1, sizeof(DB_FH), &fhp)) != 0)
return (ret);
if ((ret = __os_strdup(env, name, &fhp->name)) != 0)
goto err;
if (env != NULL) {
MUTEX_LOCK(env, env->mtx_env);
TAILQ_INSERT_TAIL(&env->fdlist, fhp, q);
MUTEX_UNLOCK(env, env->mtx_env);
F_SET(fhp, DB_FH_ENVLINK);
}
access = GENERIC_READ;
if (!LF_ISSET(DB_OSO_RDONLY))
access |= GENERIC_WRITE;
#ifdef DB_WINCE
if (LF_ISSET(DB_OSO_REGION))
share = GENERIC_READ | GENERIC_WRITE;
else
share = FILE_SHARE_READ | FILE_SHARE_WRITE;
#else
share = FILE_SHARE_READ | FILE_SHARE_WRITE;
if (__os_is_winnt())
share |= FILE_SHARE_DELETE;
#endif
attr = FILE_ATTRIBUTE_NORMAL;
if (LF_ISSET(DB_OSO_CREATE) && LF_ISSET(DB_OSO_EXCL))
createflag = CREATE_NEW;
else if (!LF_ISSET(DB_OSO_CREATE) && LF_ISSET(DB_OSO_TRUNC))
createflag = TRUNCATE_EXISTING;
else if (LF_ISSET(DB_OSO_TRUNC))
createflag = CREATE_ALWAYS;
else if (LF_ISSET(DB_OSO_CREATE))
createflag = OPEN_ALWAYS;
else
createflag = OPEN_EXISTING;
if (LF_ISSET(DB_OSO_DSYNC)) {
F_SET(fhp, DB_FH_NOSYNC);
attr |= FILE_FLAG_WRITE_THROUGH;
}
#ifndef DB_WINCE
if (LF_ISSET(DB_OSO_SEQ))
attr |= FILE_FLAG_SEQUENTIAL_SCAN;
else
attr |= FILE_FLAG_RANDOM_ACCESS;
#endif
if (LF_ISSET(DB_OSO_TEMP))
attr |= FILE_FLAG_DELETE_ON_CLOSE;
#ifndef DB_WINCE
if (LF_ISSET(DB_OSO_DIRECT) && page_size != 0 && name[0] != '\0') {
if (name[1] == ':') {
drive = dbuf;
_sntprintf(dbuf, sizeof(dbuf), _T("%c:\\"), tname[0]);
} else
drive = NULL;
if (GetDiskFreeSpace(drive, &cluster_size,
§or_size, &free_clusters, &total_clusters) &&
page_size % sector_size == 0)
attr |= FILE_FLAG_NO_BUFFERING;
}
#endif
fhp->handle = fhp->trunc_handle = INVALID_HANDLE_VALUE;
for (nrepeat = 1;; ++nrepeat) {
if (fhp->handle == INVALID_HANDLE_VALUE) {
#ifdef DB_WINCE
if (LF_ISSET(DB_OSO_REGION))
fhp->handle = CreateFileForMapping(tname,
access, share, NULL, createflag, attr, 0);
else
#endif
fhp->handle = CreateFile(tname,
access, share, NULL, createflag, attr, 0);
}
#ifndef DB_WINCE
if (fhp->handle != INVALID_HANDLE_VALUE &&
!LF_ISSET(DB_OSO_RDONLY | DB_OSO_TEMP) &&
fhp->trunc_handle == INVALID_HANDLE_VALUE)
fhp->trunc_handle = CreateFile(
tname, access, share, NULL, OPEN_EXISTING, attr, 0);
if (fhp->handle == INVALID_HANDLE_VALUE ||
(!LF_ISSET(DB_OSO_RDONLY | DB_OSO_TEMP) &&
fhp->trunc_handle == INVALID_HANDLE_VALUE))
#else
if (fhp->handle == INVALID_HANDLE_VALUE)
#endif
{
ret = __os_posix_err(__os_get_syserr());
if ((ret != ENFILE && ret != EMFILE && ret != ENOSPC) ||
nrepeat > 3)
goto err;
__os_yield(env, nrepeat * 2, 0);
} else
break;
}
FREE_STRING(env, tname);
if (LF_ISSET(DB_OSO_REGION))
F_SET(fhp, DB_FH_REGION);
F_SET(fhp, DB_FH_OPENED);
*fhpp = fhp;
return (0);
err: FREE_STRING(env, tname);
if (fhp != NULL)
(void)__os_closehandle(env, fhp);
return (ret);
}