This source file includes following definitions.
- isNT
- utf8ToUnicode
- unicodeToUtf8
- mbcsToUnicode
- unicodeToMbcs
- sqlite3_win32_mbcs_to_utf8
- utf8ToMbcs
- localtime
- winceMutexAcquire
- winceCreateLock
- winceDestroyLock
- winceLockFile
- winceUnlockFile
- winceLockFileEx
- seekWinFile
- winClose
- winRead
- winWrite
- winTruncate
- winSync
- winFileSize
- getReadLock
- unlockReadLock
- winLock
- winCheckReservedLock
- winUnlock
- winFileControl
- winSectorSize
- winDeviceCharacteristics
- winShmEnterMutex
- winShmLeaveMutex
- winShmMutexHeld
- winShmSystemLock
- winShmPurge
- winOpenSharedMemory
- winShmUnmap
- winShmLock
- winShmBarrier
- winShmMap
- convertUtf8Filename
- getTempname
- getLastErrorMsg
- winOpen
- winDelete
- winAccess
- winFullPathname
- getSectorSize
- winDlOpen
- winDlError
- winDlSym
- winDlClose
- winRandomness
- winSleep
- winCurrentTimeInt64
- winCurrentTime
- winGetLastError
- sqlite3_os_init
- sqlite3_os_end
- chromium_sqlite3_initialize_win_sqlite3_file
#include "sqliteInt.h"
#if SQLITE_OS_WIN
#include <winbase.h>
#ifdef __CYGWIN__
# include <sys/cygwin.h>
#endif
#if defined(THREADSAFE) && THREADSAFE
# define SQLITE_W32_THREADS 1
#endif
#include "os_common.h"
#ifndef INVALID_FILE_ATTRIBUTES
# define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
#endif
#if SQLITE_OS_WINCE
# define AreFileApisANSI() 1
# define FormatMessageW(a,b,c,d,e,f,g) 0
#endif
typedef struct winShm winShm;
typedef struct winShmNode winShmNode;
#if SQLITE_OS_WINCE
typedef struct winceLock {
int nReaders;
BOOL bPending;
BOOL bReserved;
BOOL bExclusive;
} winceLock;
#endif
typedef struct winFile winFile;
struct winFile {
const sqlite3_io_methods *pMethod;
sqlite3_vfs *pVfs;
HANDLE h;
unsigned char locktype;
short sharedLockByte;
DWORD lastErrno;
DWORD sectorSize;
winShm *pShm;
const char *zPath;
int szChunk;
#if SQLITE_OS_WINCE
WCHAR *zDeleteOnClose;
HANDLE hMutex;
HANDLE hShared;
winceLock local;
winceLock *shared;
#endif
};
static int getSectorSize(
sqlite3_vfs *pVfs,
const char *zRelative
);
#ifdef SQLITE_TEST
int sqlite3_os_type = 0;
#else
static int sqlite3_os_type = 0;
#endif
#if SQLITE_OS_WINCE
# define isNT() (1)
#else
static int isNT(void){
if( sqlite3_os_type==0 ){
OSVERSIONINFO sInfo;
sInfo.dwOSVersionInfoSize = sizeof(sInfo);
GetVersionEx(&sInfo);
sqlite3_os_type = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1;
}
return sqlite3_os_type==2;
}
#endif
static WCHAR *utf8ToUnicode(const char *zFilename){
int nChar;
WCHAR *zWideFilename;
nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0);
zWideFilename = malloc( nChar*sizeof(zWideFilename[0]) );
if( zWideFilename==0 ){
return 0;
}
nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename, nChar);
if( nChar==0 ){
free(zWideFilename);
zWideFilename = 0;
}
return zWideFilename;
}
static char *unicodeToUtf8(const WCHAR *zWideFilename){
int nByte;
char *zFilename;
nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, 0, 0, 0, 0);
zFilename = malloc( nByte );
if( zFilename==0 ){
return 0;
}
nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, zFilename, nByte,
0, 0);
if( nByte == 0 ){
free(zFilename);
zFilename = 0;
}
return zFilename;
}
static WCHAR *mbcsToUnicode(const char *zFilename){
int nByte;
WCHAR *zMbcsFilename;
int codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
nByte = MultiByteToWideChar(codepage, 0, zFilename, -1, NULL,0)*sizeof(WCHAR);
zMbcsFilename = malloc( nByte*sizeof(zMbcsFilename[0]) );
if( zMbcsFilename==0 ){
return 0;
}
nByte = MultiByteToWideChar(codepage, 0, zFilename, -1, zMbcsFilename, nByte);
if( nByte==0 ){
free(zMbcsFilename);
zMbcsFilename = 0;
}
return zMbcsFilename;
}
static char *unicodeToMbcs(const WCHAR *zWideFilename){
int nByte;
char *zFilename;
int codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
nByte = WideCharToMultiByte(codepage, 0, zWideFilename, -1, 0, 0, 0, 0);
zFilename = malloc( nByte );
if( zFilename==0 ){
return 0;
}
nByte = WideCharToMultiByte(codepage, 0, zWideFilename, -1, zFilename, nByte,
0, 0);
if( nByte == 0 ){
free(zFilename);
zFilename = 0;
}
return zFilename;
}
char *sqlite3_win32_mbcs_to_utf8(const char *zFilename){
char *zFilenameUtf8;
WCHAR *zTmpWide;
zTmpWide = mbcsToUnicode(zFilename);
if( zTmpWide==0 ){
return 0;
}
zFilenameUtf8 = unicodeToUtf8(zTmpWide);
free(zTmpWide);
return zFilenameUtf8;
}
static char *utf8ToMbcs(const char *zFilename){
char *zFilenameMbcs;
WCHAR *zTmpWide;
zTmpWide = utf8ToUnicode(zFilename);
if( zTmpWide==0 ){
return 0;
}
zFilenameMbcs = unicodeToMbcs(zTmpWide);
free(zTmpWide);
return zFilenameMbcs;
}
#if SQLITE_OS_WINCE
#include <time.h>
struct tm *__cdecl localtime(const time_t *t)
{
static struct tm y;
FILETIME uTm, lTm;
SYSTEMTIME pTm;
sqlite3_int64 t64;
t64 = *t;
t64 = (t64 + 11644473600)*10000000;
uTm.dwLowDateTime = (DWORD)(t64 & 0xFFFFFFFF);
uTm.dwHighDateTime= (DWORD)(t64 >> 32);
FileTimeToLocalFileTime(&uTm,&lTm);
FileTimeToSystemTime(&lTm,&pTm);
y.tm_year = pTm.wYear - 1900;
y.tm_mon = pTm.wMonth - 1;
y.tm_wday = pTm.wDayOfWeek;
y.tm_mday = pTm.wDay;
y.tm_hour = pTm.wHour;
y.tm_min = pTm.wMinute;
y.tm_sec = pTm.wSecond;
return &y;
}
#define GetTempPathA(a,b)
#define LockFile(a,b,c,d,e) winceLockFile(&a, b, c, d, e)
#define UnlockFile(a,b,c,d,e) winceUnlockFile(&a, b, c, d, e)
#define LockFileEx(a,b,c,d,e,f) winceLockFileEx(&a, b, c, d, e, f)
#define HANDLE_TO_WINFILE(a) (winFile*)&((char*)a)[-(int)offsetof(winFile,h)]
static void winceMutexAcquire(HANDLE h){
DWORD dwErr;
do {
dwErr = WaitForSingleObject(h, INFINITE);
} while (dwErr != WAIT_OBJECT_0 && dwErr != WAIT_ABANDONED);
}
#define winceMutexRelease(h) ReleaseMutex(h)
static BOOL winceCreateLock(const char *zFilename, winFile *pFile){
WCHAR *zTok;
WCHAR *zName = utf8ToUnicode(zFilename);
BOOL bInit = TRUE;
ZeroMemory(&pFile->local, sizeof(pFile->local));
zTok = CharLowerW(zName);
for (;*zTok;zTok++){
if (*zTok == '\\') *zTok = '_';
}
pFile->hMutex = CreateMutexW(NULL, FALSE, zName);
if (!pFile->hMutex){
pFile->lastErrno = GetLastError();
free(zName);
return FALSE;
}
winceMutexAcquire(pFile->hMutex);
CharUpperW(zName);
pFile->hShared = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL,
PAGE_READWRITE, 0, sizeof(winceLock),
zName);
if (GetLastError() == ERROR_ALREADY_EXISTS){
bInit = FALSE;
}
free(zName);
if (pFile->hShared){
pFile->shared = (winceLock*)MapViewOfFile(pFile->hShared,
FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, sizeof(winceLock));
if (!pFile->shared){
pFile->lastErrno = GetLastError();
CloseHandle(pFile->hShared);
pFile->hShared = NULL;
}
}
if (pFile->hShared == NULL){
winceMutexRelease(pFile->hMutex);
CloseHandle(pFile->hMutex);
pFile->hMutex = NULL;
return FALSE;
}
if (bInit) {
ZeroMemory(pFile->shared, sizeof(winceLock));
}
winceMutexRelease(pFile->hMutex);
return TRUE;
}
static void winceDestroyLock(winFile *pFile){
if (pFile->hMutex){
winceMutexAcquire(pFile->hMutex);
if (pFile->local.nReaders){
pFile->shared->nReaders --;
}
if (pFile->local.bReserved){
pFile->shared->bReserved = FALSE;
}
if (pFile->local.bPending){
pFile->shared->bPending = FALSE;
}
if (pFile->local.bExclusive){
pFile->shared->bExclusive = FALSE;
}
UnmapViewOfFile(pFile->shared);
CloseHandle(pFile->hShared);
winceMutexRelease(pFile->hMutex);
CloseHandle(pFile->hMutex);
pFile->hMutex = NULL;
}
}
static BOOL winceLockFile(
HANDLE *phFile,
DWORD dwFileOffsetLow,
DWORD dwFileOffsetHigh,
DWORD nNumberOfBytesToLockLow,
DWORD nNumberOfBytesToLockHigh
){
winFile *pFile = HANDLE_TO_WINFILE(phFile);
BOOL bReturn = FALSE;
UNUSED_PARAMETER(dwFileOffsetHigh);
UNUSED_PARAMETER(nNumberOfBytesToLockHigh);
if (!pFile->hMutex) return TRUE;
winceMutexAcquire(pFile->hMutex);
if (dwFileOffsetLow == (DWORD)SHARED_FIRST
&& nNumberOfBytesToLockLow == (DWORD)SHARED_SIZE){
if (pFile->shared->nReaders == 0 && pFile->shared->bExclusive == 0){
pFile->shared->bExclusive = TRUE;
pFile->local.bExclusive = TRUE;
bReturn = TRUE;
}
}
else if (dwFileOffsetLow == (DWORD)SHARED_FIRST &&
nNumberOfBytesToLockLow == 1){
if (pFile->shared->bExclusive == 0){
pFile->local.nReaders ++;
if (pFile->local.nReaders == 1){
pFile->shared->nReaders ++;
}
bReturn = TRUE;
}
}
else if (dwFileOffsetLow == (DWORD)PENDING_BYTE && nNumberOfBytesToLockLow == 1){
if (pFile->shared->bPending == 0) {
pFile->shared->bPending = TRUE;
pFile->local.bPending = TRUE;
bReturn = TRUE;
}
}
else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE && nNumberOfBytesToLockLow == 1){
if (pFile->shared->bReserved == 0) {
pFile->shared->bReserved = TRUE;
pFile->local.bReserved = TRUE;
bReturn = TRUE;
}
}
winceMutexRelease(pFile->hMutex);
return bReturn;
}
static BOOL winceUnlockFile(
HANDLE *phFile,
DWORD dwFileOffsetLow,
DWORD dwFileOffsetHigh,
DWORD nNumberOfBytesToUnlockLow,
DWORD nNumberOfBytesToUnlockHigh
){
winFile *pFile = HANDLE_TO_WINFILE(phFile);
BOOL bReturn = FALSE;
UNUSED_PARAMETER(dwFileOffsetHigh);
UNUSED_PARAMETER(nNumberOfBytesToUnlockHigh);
if (!pFile->hMutex) return TRUE;
winceMutexAcquire(pFile->hMutex);
if (dwFileOffsetLow == (DWORD)SHARED_FIRST){
if (pFile->local.bExclusive){
assert(nNumberOfBytesToUnlockLow == (DWORD)SHARED_SIZE);
pFile->local.bExclusive = FALSE;
pFile->shared->bExclusive = FALSE;
bReturn = TRUE;
}
else if (pFile->local.nReaders){
assert(nNumberOfBytesToUnlockLow == (DWORD)SHARED_SIZE || nNumberOfBytesToUnlockLow == 1);
pFile->local.nReaders --;
if (pFile->local.nReaders == 0)
{
pFile->shared->nReaders --;
}
bReturn = TRUE;
}
}
else if (dwFileOffsetLow == (DWORD)PENDING_BYTE && nNumberOfBytesToUnlockLow == 1){
if (pFile->local.bPending){
pFile->local.bPending = FALSE;
pFile->shared->bPending = FALSE;
bReturn = TRUE;
}
}
else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE && nNumberOfBytesToUnlockLow == 1){
if (pFile->local.bReserved) {
pFile->local.bReserved = FALSE;
pFile->shared->bReserved = FALSE;
bReturn = TRUE;
}
}
winceMutexRelease(pFile->hMutex);
return bReturn;
}
static BOOL winceLockFileEx(
HANDLE *phFile,
DWORD dwFlags,
DWORD dwReserved,
DWORD nNumberOfBytesToLockLow,
DWORD nNumberOfBytesToLockHigh,
LPOVERLAPPED lpOverlapped
){
UNUSED_PARAMETER(dwReserved);
UNUSED_PARAMETER(nNumberOfBytesToLockHigh);
if (lpOverlapped->Offset == (DWORD)SHARED_FIRST &&
dwFlags == 1 &&
nNumberOfBytesToLockLow == (DWORD)SHARED_SIZE){
return winceLockFile(phFile, SHARED_FIRST, 0, 1, 0);
}
return FALSE;
}
#endif
#ifndef INVALID_SET_FILE_POINTER
# define INVALID_SET_FILE_POINTER ((DWORD)-1)
#endif
static int seekWinFile(winFile *pFile, sqlite3_int64 iOffset){
LONG upperBits;
LONG lowerBits;
DWORD dwRet;
upperBits = (LONG)((iOffset>>32) & 0x7fffffff);
lowerBits = (LONG)(iOffset & 0xffffffff);
dwRet = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
if( (dwRet==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR) ){
pFile->lastErrno = GetLastError();
return 1;
}
return 0;
}
#define MX_CLOSE_ATTEMPT 3
static int winClose(sqlite3_file *id){
int rc, cnt = 0;
winFile *pFile = (winFile*)id;
assert( id!=0 );
assert( pFile->pShm==0 );
OSTRACE(("CLOSE %d\n", pFile->h));
do{
rc = CloseHandle(pFile->h);
}while( rc==0 && ++cnt < MX_CLOSE_ATTEMPT && (Sleep(100), 1) );
#if SQLITE_OS_WINCE
#define WINCE_DELETION_ATTEMPTS 3
winceDestroyLock(pFile);
if( pFile->zDeleteOnClose ){
int cnt = 0;
while(
DeleteFileW(pFile->zDeleteOnClose)==0
&& GetFileAttributesW(pFile->zDeleteOnClose)!=0xffffffff
&& cnt++ < WINCE_DELETION_ATTEMPTS
){
Sleep(100);
}
free(pFile->zDeleteOnClose);
}
#endif
OSTRACE(("CLOSE %d %s\n", pFile->h, rc ? "ok" : "failed"));
OpenCounter(-1);
return rc ? SQLITE_OK : SQLITE_IOERR;
}
static int winRead(
sqlite3_file *id,
void *pBuf,
int amt,
sqlite3_int64 offset
){
winFile *pFile = (winFile*)id;
DWORD nRead;
assert( id!=0 );
SimulateIOError(return SQLITE_IOERR_READ);
OSTRACE(("READ %d lock=%d\n", pFile->h, pFile->locktype));
if( seekWinFile(pFile, offset) ){
return SQLITE_FULL;
}
if( !ReadFile(pFile->h, pBuf, amt, &nRead, 0) ){
pFile->lastErrno = GetLastError();
return SQLITE_IOERR_READ;
}
if( nRead<(DWORD)amt ){
memset(&((char*)pBuf)[nRead], 0, amt-nRead);
return SQLITE_IOERR_SHORT_READ;
}
return SQLITE_OK;
}
static int winWrite(
sqlite3_file *id,
const void *pBuf,
int amt,
sqlite3_int64 offset
){
int rc;
winFile *pFile = (winFile*)id;
assert( amt>0 );
assert( pFile );
SimulateIOError(return SQLITE_IOERR_WRITE);
SimulateDiskfullError(return SQLITE_FULL);
OSTRACE(("WRITE %d lock=%d\n", pFile->h, pFile->locktype));
rc = seekWinFile(pFile, offset);
if( rc==0 ){
u8 *aRem = (u8 *)pBuf;
int nRem = amt;
DWORD nWrite;
while( nRem>0 && WriteFile(pFile->h, aRem, nRem, &nWrite, 0) && nWrite>0 ){
aRem += nWrite;
nRem -= nWrite;
}
if( nRem>0 ){
pFile->lastErrno = GetLastError();
rc = 1;
}
}
if( rc ){
if( pFile->lastErrno==ERROR_HANDLE_DISK_FULL ){
return SQLITE_FULL;
}
return SQLITE_IOERR_WRITE;
}
return SQLITE_OK;
}
static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
winFile *pFile = (winFile*)id;
int rc = SQLITE_OK;
assert( pFile );
OSTRACE(("TRUNCATE %d %lld\n", pFile->h, nByte));
SimulateIOError(return SQLITE_IOERR_TRUNCATE);
if( pFile->szChunk ){
nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk;
}
if( seekWinFile(pFile, nByte) ){
rc = SQLITE_IOERR_TRUNCATE;
}else if( 0==SetEndOfFile(pFile->h) ){
pFile->lastErrno = GetLastError();
rc = SQLITE_IOERR_TRUNCATE;
}
OSTRACE(("TRUNCATE %d %lld %s\n", pFile->h, nByte, rc ? "failed" : "ok"));
return rc;
}
#ifdef SQLITE_TEST
int sqlite3_sync_count = 0;
int sqlite3_fullsync_count = 0;
#endif
static int winSync(sqlite3_file *id, int flags){
#if !defined(NDEBUG) || !defined(SQLITE_NO_SYNC) || defined(SQLITE_DEBUG)
winFile *pFile = (winFile*)id;
#else
UNUSED_PARAMETER(id);
#endif
assert( pFile );
assert((flags&0x0F)==SQLITE_SYNC_NORMAL
|| (flags&0x0F)==SQLITE_SYNC_FULL
);
OSTRACE(("SYNC %d lock=%d\n", pFile->h, pFile->locktype));
#ifndef SQLITE_TEST
UNUSED_PARAMETER(flags);
#else
if( flags & SQLITE_SYNC_FULL ){
sqlite3_fullsync_count++;
}
sqlite3_sync_count++;
#endif
SimulateDiskfullError( return SQLITE_FULL );
SimulateIOError( return SQLITE_IOERR; );
#ifdef SQLITE_NO_SYNC
return SQLITE_OK;
#else
if( FlushFileBuffers(pFile->h) ){
return SQLITE_OK;
}else{
pFile->lastErrno = GetLastError();
return SQLITE_IOERR;
}
#endif
}
static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){
DWORD upperBits;
DWORD lowerBits;
winFile *pFile = (winFile*)id;
DWORD error;
assert( id!=0 );
SimulateIOError(return SQLITE_IOERR_FSTAT);
lowerBits = GetFileSize(pFile->h, &upperBits);
if( (lowerBits == INVALID_FILE_SIZE)
&& ((error = GetLastError()) != NO_ERROR) )
{
pFile->lastErrno = error;
return SQLITE_IOERR_FSTAT;
}
*pSize = (((sqlite3_int64)upperBits)<<32) + lowerBits;
return SQLITE_OK;
}
#ifndef LOCKFILE_FAIL_IMMEDIATELY
# define LOCKFILE_FAIL_IMMEDIATELY 1
#endif
static int getReadLock(winFile *pFile){
int res;
if( isNT() ){
OVERLAPPED ovlp;
ovlp.Offset = SHARED_FIRST;
ovlp.OffsetHigh = 0;
ovlp.hEvent = 0;
res = LockFileEx(pFile->h, LOCKFILE_FAIL_IMMEDIATELY,
0, SHARED_SIZE, 0, &ovlp);
#if SQLITE_OS_WINCE==0
}else{
int lk;
sqlite3_randomness(sizeof(lk), &lk);
pFile->sharedLockByte = (short)((lk & 0x7fffffff)%(SHARED_SIZE - 1));
res = LockFile(pFile->h, SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0);
#endif
}
if( res == 0 ){
pFile->lastErrno = GetLastError();
}
return res;
}
static int unlockReadLock(winFile *pFile){
int res;
if( isNT() ){
res = UnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
#if SQLITE_OS_WINCE==0
}else{
res = UnlockFile(pFile->h, SHARED_FIRST + pFile->sharedLockByte, 0, 1, 0);
#endif
}
if( res == 0 ){
pFile->lastErrno = GetLastError();
}
return res;
}
static int winLock(sqlite3_file *id, int locktype){
int rc = SQLITE_OK;
int res = 1;
int newLocktype;
int gotPendingLock = 0;
winFile *pFile = (winFile*)id;
DWORD error = NO_ERROR;
assert( id!=0 );
OSTRACE(("LOCK %d %d was %d(%d)\n",
pFile->h, locktype, pFile->locktype, pFile->sharedLockByte));
if( pFile->locktype>=locktype ){
return SQLITE_OK;
}
assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK );
assert( locktype!=PENDING_LOCK );
assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK );
newLocktype = pFile->locktype;
if( (pFile->locktype==NO_LOCK)
|| ( (locktype==EXCLUSIVE_LOCK)
&& (pFile->locktype==RESERVED_LOCK))
){
int cnt = 3;
while( cnt-->0 && (res = LockFile(pFile->h, PENDING_BYTE, 0, 1, 0))==0 ){
OSTRACE(("could not get a PENDING lock. cnt=%d\n", cnt));
Sleep(1);
}
gotPendingLock = res;
if( !res ){
error = GetLastError();
}
}
if( locktype==SHARED_LOCK && res ){
assert( pFile->locktype==NO_LOCK );
res = getReadLock(pFile);
if( res ){
newLocktype = SHARED_LOCK;
}else{
error = GetLastError();
}
}
if( locktype==RESERVED_LOCK && res ){
assert( pFile->locktype==SHARED_LOCK );
res = LockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
if( res ){
newLocktype = RESERVED_LOCK;
}else{
error = GetLastError();
}
}
if( locktype==EXCLUSIVE_LOCK && res ){
newLocktype = PENDING_LOCK;
gotPendingLock = 0;
}
if( locktype==EXCLUSIVE_LOCK && res ){
assert( pFile->locktype>=SHARED_LOCK );
res = unlockReadLock(pFile);
OSTRACE(("unreadlock = %d\n", res));
res = LockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
if( res ){
newLocktype = EXCLUSIVE_LOCK;
}else{
error = GetLastError();
OSTRACE(("error-code = %d\n", error));
getReadLock(pFile);
}
}
if( gotPendingLock && locktype==SHARED_LOCK ){
UnlockFile(pFile->h, PENDING_BYTE, 0, 1, 0);
}
if( res ){
rc = SQLITE_OK;
}else{
OSTRACE(("LOCK FAILED %d trying for %d but got %d\n", pFile->h,
locktype, newLocktype));
pFile->lastErrno = error;
rc = SQLITE_BUSY;
}
pFile->locktype = (u8)newLocktype;
return rc;
}
static int winCheckReservedLock(sqlite3_file *id, int *pResOut){
int rc;
winFile *pFile = (winFile*)id;
SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
assert( id!=0 );
if( pFile->locktype>=RESERVED_LOCK ){
rc = 1;
OSTRACE(("TEST WR-LOCK %d %d (local)\n", pFile->h, rc));
}else{
rc = LockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
if( rc ){
UnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
}
rc = !rc;
OSTRACE(("TEST WR-LOCK %d %d (remote)\n", pFile->h, rc));
}
*pResOut = rc;
return SQLITE_OK;
}
static int winUnlock(sqlite3_file *id, int locktype){
int type;
winFile *pFile = (winFile*)id;
int rc = SQLITE_OK;
assert( pFile!=0 );
assert( locktype<=SHARED_LOCK );
OSTRACE(("UNLOCK %d to %d was %d(%d)\n", pFile->h, locktype,
pFile->locktype, pFile->sharedLockByte));
type = pFile->locktype;
if( type>=EXCLUSIVE_LOCK ){
UnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
if( locktype==SHARED_LOCK && !getReadLock(pFile) ){
rc = SQLITE_IOERR_UNLOCK;
}
}
if( type>=RESERVED_LOCK ){
UnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
}
if( locktype==NO_LOCK && type>=SHARED_LOCK ){
unlockReadLock(pFile);
}
if( type>=PENDING_LOCK ){
UnlockFile(pFile->h, PENDING_BYTE, 0, 1, 0);
}
pFile->locktype = (u8)locktype;
return rc;
}
static int winFileControl(sqlite3_file *id, int op, void *pArg){
switch( op ){
case SQLITE_FCNTL_LOCKSTATE: {
*(int*)pArg = ((winFile*)id)->locktype;
return SQLITE_OK;
}
case SQLITE_LAST_ERRNO: {
*(int*)pArg = (int)((winFile*)id)->lastErrno;
return SQLITE_OK;
}
case SQLITE_FCNTL_CHUNK_SIZE: {
((winFile*)id)->szChunk = *(int *)pArg;
return SQLITE_OK;
}
case SQLITE_FCNTL_SIZE_HINT: {
sqlite3_int64 sz = *(sqlite3_int64*)pArg;
SimulateIOErrorBenign(1);
winTruncate(id, sz);
SimulateIOErrorBenign(0);
return SQLITE_OK;
}
case SQLITE_FCNTL_SYNC_OMITTED: {
return SQLITE_OK;
}
}
return SQLITE_NOTFOUND;
}
static int winSectorSize(sqlite3_file *id){
assert( id!=0 );
return (int)(((winFile*)id)->sectorSize);
}
static int winDeviceCharacteristics(sqlite3_file *id){
UNUSED_PARAMETER(id);
return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN;
}
#ifndef SQLITE_OMIT_WAL
SYSTEM_INFO winSysInfo;
static void winShmEnterMutex(void){
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
}
static void winShmLeaveMutex(void){
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
}
#ifdef SQLITE_DEBUG
static int winShmMutexHeld(void) {
return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
}
#endif
struct winShmNode {
sqlite3_mutex *mutex;
char *zFilename;
winFile hFile;
int szRegion;
int nRegion;
struct ShmRegion {
HANDLE hMap;
void *pMap;
} *aRegion;
DWORD lastErrno;
int nRef;
winShm *pFirst;
winShmNode *pNext;
#ifdef SQLITE_DEBUG
u8 nextShmId;
#endif
};
static winShmNode *winShmNodeList = 0;
struct winShm {
winShmNode *pShmNode;
winShm *pNext;
u8 hasMutex;
u16 sharedMask;
u16 exclMask;
#ifdef SQLITE_DEBUG
u8 id;
#endif
};
#define WIN_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4)
#define WIN_SHM_DMS (WIN_SHM_BASE+SQLITE_SHM_NLOCK)
#define _SHM_UNLCK 1
#define _SHM_RDLCK 2
#define _SHM_WRLCK 3
static int winShmSystemLock(
winShmNode *pFile,
int lockType,
int ofst,
int nByte
){
OVERLAPPED ovlp;
DWORD dwFlags;
int rc = 0;
assert( sqlite3_mutex_held(pFile->mutex) || pFile->nRef==0 );
dwFlags = LOCKFILE_FAIL_IMMEDIATELY;
if( lockType == _SHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
memset(&ovlp, 0, sizeof(OVERLAPPED));
ovlp.Offset = ofst;
if( lockType==_SHM_UNLCK ){
rc = UnlockFileEx(pFile->hFile.h, 0, nByte, 0, &ovlp);
}else{
rc = LockFileEx(pFile->hFile.h, dwFlags, 0, nByte, 0, &ovlp);
}
if( rc!= 0 ){
rc = SQLITE_OK;
}else{
pFile->lastErrno = GetLastError();
rc = SQLITE_BUSY;
}
OSTRACE(("SHM-LOCK %d %s %s 0x%08lx\n",
pFile->hFile.h,
rc==SQLITE_OK ? "ok" : "failed",
lockType==_SHM_UNLCK ? "UnlockFileEx" : "LockFileEx",
pFile->lastErrno));
return rc;
}
static int winOpen(sqlite3_vfs*,const char*,sqlite3_file*,int,int*);
static int winDelete(sqlite3_vfs *,const char*,int);
static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){
winShmNode **pp;
winShmNode *p;
BOOL bRc;
assert( winShmMutexHeld() );
pp = &winShmNodeList;
while( (p = *pp)!=0 ){
if( p->nRef==0 ){
int i;
if( p->mutex ) sqlite3_mutex_free(p->mutex);
for(i=0; i<p->nRegion; i++){
bRc = UnmapViewOfFile(p->aRegion[i].pMap);
OSTRACE(("SHM-PURGE pid-%d unmap region=%d %s\n",
(int)GetCurrentProcessId(), i,
bRc ? "ok" : "failed"));
bRc = CloseHandle(p->aRegion[i].hMap);
OSTRACE(("SHM-PURGE pid-%d close region=%d %s\n",
(int)GetCurrentProcessId(), i,
bRc ? "ok" : "failed"));
}
if( p->hFile.h != INVALID_HANDLE_VALUE ){
SimulateIOErrorBenign(1);
winClose((sqlite3_file *)&p->hFile);
SimulateIOErrorBenign(0);
}
if( deleteFlag ){
SimulateIOErrorBenign(1);
winDelete(pVfs, p->zFilename, 0);
SimulateIOErrorBenign(0);
}
*pp = p->pNext;
sqlite3_free(p->aRegion);
sqlite3_free(p);
}else{
pp = &p->pNext;
}
}
}
static int winOpenSharedMemory(winFile *pDbFd){
struct winShm *p;
struct winShmNode *pShmNode = 0;
int rc;
struct winShmNode *pNew;
int nName;
assert( pDbFd->pShm==0 );
p = sqlite3_malloc( sizeof(*p) );
if( p==0 ) return SQLITE_NOMEM;
memset(p, 0, sizeof(*p));
nName = sqlite3Strlen30(pDbFd->zPath);
pNew = sqlite3_malloc( sizeof(*pShmNode) + nName + 15 );
if( pNew==0 ){
sqlite3_free(p);
return SQLITE_NOMEM;
}
memset(pNew, 0, sizeof(*pNew));
pNew->zFilename = (char*)&pNew[1];
sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath);
winShmEnterMutex();
for(pShmNode = winShmNodeList; pShmNode; pShmNode=pShmNode->pNext){
if( sqlite3StrICmp(pShmNode->zFilename, pNew->zFilename)==0 ) break;
}
if( pShmNode ){
sqlite3_free(pNew);
}else{
pShmNode = pNew;
pNew = 0;
((winFile*)(&pShmNode->hFile))->h = INVALID_HANDLE_VALUE;
pShmNode->pNext = winShmNodeList;
winShmNodeList = pShmNode;
pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
if( pShmNode->mutex==0 ){
rc = SQLITE_NOMEM;
goto shm_open_err;
}
rc = winOpen(pDbFd->pVfs,
pShmNode->zFilename,
(sqlite3_file*)&pShmNode->hFile,
SQLITE_OPEN_WAL | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
0);
if( SQLITE_OK!=rc ){
rc = SQLITE_CANTOPEN_BKPT;
goto shm_open_err;
}
if( winShmSystemLock(pShmNode, _SHM_WRLCK, WIN_SHM_DMS, 1)==SQLITE_OK ){
rc = winTruncate((sqlite3_file *)&pShmNode->hFile, 0);
if( rc!=SQLITE_OK ){
rc = SQLITE_IOERR_SHMOPEN;
}
}
if( rc==SQLITE_OK ){
winShmSystemLock(pShmNode, _SHM_UNLCK, WIN_SHM_DMS, 1);
rc = winShmSystemLock(pShmNode, _SHM_RDLCK, WIN_SHM_DMS, 1);
}
if( rc ) goto shm_open_err;
}
p->pShmNode = pShmNode;
#ifdef SQLITE_DEBUG
p->id = pShmNode->nextShmId++;
#endif
pShmNode->nRef++;
pDbFd->pShm = p;
winShmLeaveMutex();
sqlite3_mutex_enter(pShmNode->mutex);
p->pNext = pShmNode->pFirst;
pShmNode->pFirst = p;
sqlite3_mutex_leave(pShmNode->mutex);
return SQLITE_OK;
shm_open_err:
winShmSystemLock(pShmNode, _SHM_UNLCK, WIN_SHM_DMS, 1);
winShmPurge(pDbFd->pVfs, 0);
sqlite3_free(p);
sqlite3_free(pNew);
winShmLeaveMutex();
return rc;
}
static int winShmUnmap(
sqlite3_file *fd,
int deleteFlag
){
winFile *pDbFd;
winShm *p;
winShmNode *pShmNode;
winShm **pp;
pDbFd = (winFile*)fd;
p = pDbFd->pShm;
if( p==0 ) return SQLITE_OK;
pShmNode = p->pShmNode;
sqlite3_mutex_enter(pShmNode->mutex);
for(pp=&pShmNode->pFirst; (*pp)!=p; pp = &(*pp)->pNext){}
*pp = p->pNext;
sqlite3_free(p);
pDbFd->pShm = 0;
sqlite3_mutex_leave(pShmNode->mutex);
winShmEnterMutex();
assert( pShmNode->nRef>0 );
pShmNode->nRef--;
if( pShmNode->nRef==0 ){
winShmPurge(pDbFd->pVfs, deleteFlag);
}
winShmLeaveMutex();
return SQLITE_OK;
}
static int winShmLock(
sqlite3_file *fd,
int ofst,
int n,
int flags
){
winFile *pDbFd = (winFile*)fd;
winShm *p = pDbFd->pShm;
winShm *pX;
winShmNode *pShmNode = p->pShmNode;
int rc = SQLITE_OK;
u16 mask;
assert( ofst>=0 && ofst+n<=SQLITE_SHM_NLOCK );
assert( n>=1 );
assert( flags==(SQLITE_SHM_LOCK | SQLITE_SHM_SHARED)
|| flags==(SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE)
|| flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED)
|| flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) );
assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 );
mask = (u16)((1U<<(ofst+n)) - (1U<<ofst));
assert( n>1 || mask==(1<<ofst) );
sqlite3_mutex_enter(pShmNode->mutex);
if( flags & SQLITE_SHM_UNLOCK ){
u16 allMask = 0;
for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
if( pX==p ) continue;
assert( (pX->exclMask & (p->exclMask|p->sharedMask))==0 );
allMask |= pX->sharedMask;
}
if( (mask & allMask)==0 ){
rc = winShmSystemLock(pShmNode, _SHM_UNLCK, ofst+WIN_SHM_BASE, n);
}else{
rc = SQLITE_OK;
}
if( rc==SQLITE_OK ){
p->exclMask &= ~mask;
p->sharedMask &= ~mask;
}
}else if( flags & SQLITE_SHM_SHARED ){
u16 allShared = 0;
for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
if( (pX->exclMask & mask)!=0 ){
rc = SQLITE_BUSY;
break;
}
allShared |= pX->sharedMask;
}
if( rc==SQLITE_OK ){
if( (allShared & mask)==0 ){
rc = winShmSystemLock(pShmNode, _SHM_RDLCK, ofst+WIN_SHM_BASE, n);
}else{
rc = SQLITE_OK;
}
}
if( rc==SQLITE_OK ){
p->sharedMask |= mask;
}
}else{
for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
if( (pX->exclMask & mask)!=0 || (pX->sharedMask & mask)!=0 ){
rc = SQLITE_BUSY;
break;
}
}
if( rc==SQLITE_OK ){
rc = winShmSystemLock(pShmNode, _SHM_WRLCK, ofst+WIN_SHM_BASE, n);
if( rc==SQLITE_OK ){
assert( (p->sharedMask & mask)==0 );
p->exclMask |= mask;
}
}
}
sqlite3_mutex_leave(pShmNode->mutex);
OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x %s\n",
p->id, (int)GetCurrentProcessId(), p->sharedMask, p->exclMask,
rc ? "failed" : "ok"));
return rc;
}
static void winShmBarrier(
sqlite3_file *fd
){
UNUSED_PARAMETER(fd);
winShmEnterMutex();
winShmLeaveMutex();
}
static int winShmMap(
sqlite3_file *fd,
int iRegion,
int szRegion,
int isWrite,
void volatile **pp
){
winFile *pDbFd = (winFile*)fd;
winShm *p = pDbFd->pShm;
winShmNode *pShmNode;
int rc = SQLITE_OK;
if( !p ){
rc = winOpenSharedMemory(pDbFd);
if( rc!=SQLITE_OK ) return rc;
p = pDbFd->pShm;
}
pShmNode = p->pShmNode;
sqlite3_mutex_enter(pShmNode->mutex);
assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
if( pShmNode->nRegion<=iRegion ){
struct ShmRegion *apNew;
int nByte = (iRegion+1)*szRegion;
sqlite3_int64 sz;
pShmNode->szRegion = szRegion;
rc = winFileSize((sqlite3_file *)&pShmNode->hFile, &sz);
if( rc!=SQLITE_OK ){
rc = SQLITE_IOERR_SHMSIZE;
goto shmpage_out;
}
if( sz<nByte ){
if( !isWrite ) goto shmpage_out;
rc = winTruncate((sqlite3_file *)&pShmNode->hFile, nByte);
if( rc!=SQLITE_OK ){
rc = SQLITE_IOERR_SHMSIZE;
goto shmpage_out;
}
}
apNew = (struct ShmRegion *)sqlite3_realloc(
pShmNode->aRegion, (iRegion+1)*sizeof(apNew[0])
);
if( !apNew ){
rc = SQLITE_IOERR_NOMEM;
goto shmpage_out;
}
pShmNode->aRegion = apNew;
while( pShmNode->nRegion<=iRegion ){
HANDLE hMap;
void *pMap = 0;
hMap = CreateFileMapping(pShmNode->hFile.h,
NULL, PAGE_READWRITE, 0, nByte, NULL
);
OSTRACE(("SHM-MAP pid-%d create region=%d nbyte=%d %s\n",
(int)GetCurrentProcessId(), pShmNode->nRegion, nByte,
hMap ? "ok" : "failed"));
if( hMap ){
int iOffset = pShmNode->nRegion*szRegion;
int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity;
pMap = MapViewOfFile(hMap, FILE_MAP_WRITE | FILE_MAP_READ,
0, iOffset - iOffsetShift, szRegion + iOffsetShift
);
OSTRACE(("SHM-MAP pid-%d map region=%d offset=%d size=%d %s\n",
(int)GetCurrentProcessId(), pShmNode->nRegion, iOffset, szRegion,
pMap ? "ok" : "failed"));
}
if( !pMap ){
pShmNode->lastErrno = GetLastError();
rc = SQLITE_IOERR;
if( hMap ) CloseHandle(hMap);
goto shmpage_out;
}
pShmNode->aRegion[pShmNode->nRegion].pMap = pMap;
pShmNode->aRegion[pShmNode->nRegion].hMap = hMap;
pShmNode->nRegion++;
}
}
shmpage_out:
if( pShmNode->nRegion>iRegion ){
int iOffset = iRegion*szRegion;
int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity;
char *p = (char *)pShmNode->aRegion[iRegion].pMap;
*pp = (void *)&p[iOffsetShift];
}else{
*pp = 0;
}
sqlite3_mutex_leave(pShmNode->mutex);
return rc;
}
#else
# define winShmMap 0
# define winShmLock 0
# define winShmBarrier 0
# define winShmUnmap 0
#endif
static const sqlite3_io_methods winIoMethod = {
2,
winClose,
winRead,
winWrite,
winTruncate,
winSync,
winFileSize,
winLock,
winUnlock,
winCheckReservedLock,
winFileControl,
winSectorSize,
winDeviceCharacteristics,
winShmMap,
winShmLock,
winShmBarrier,
winShmUnmap
};
static void *convertUtf8Filename(const char *zFilename){
void *zConverted = 0;
if( isNT() ){
zConverted = utf8ToUnicode(zFilename);
#if SQLITE_OS_WINCE==0
}else{
zConverted = utf8ToMbcs(zFilename);
#endif
}
return zConverted;
}
static int getTempname(int nBuf, char *zBuf){
static char zChars[] =
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789";
size_t i, j;
char zTempPath[MAX_PATH+1];
SimulateIOError( return SQLITE_IOERR );
if( sqlite3_temp_directory ){
sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", sqlite3_temp_directory);
}else if( isNT() ){
char *zMulti;
WCHAR zWidePath[MAX_PATH];
GetTempPathW(MAX_PATH-30, zWidePath);
zMulti = unicodeToUtf8(zWidePath);
if( zMulti ){
sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zMulti);
free(zMulti);
}else{
return SQLITE_NOMEM;
}
#if SQLITE_OS_WINCE==0
}else{
char *zUtf8;
char zMbcsPath[MAX_PATH];
GetTempPathA(MAX_PATH-30, zMbcsPath);
zUtf8 = sqlite3_win32_mbcs_to_utf8(zMbcsPath);
if( zUtf8 ){
sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zUtf8);
free(zUtf8);
}else{
return SQLITE_NOMEM;
}
#endif
}
if( (sqlite3Strlen30(zTempPath) + sqlite3Strlen30(SQLITE_TEMP_FILE_PREFIX) + 17) >= nBuf ){
return SQLITE_ERROR;
}
for(i=sqlite3Strlen30(zTempPath); i>0 && zTempPath[i-1]=='\\'; i--){}
zTempPath[i] = 0;
sqlite3_snprintf(nBuf-17, zBuf,
"%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPath);
j = sqlite3Strlen30(zBuf);
sqlite3_randomness(15, &zBuf[j]);
for(i=0; i<15; i++, j++){
zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
}
zBuf[j] = 0;
OSTRACE(("TEMP FILENAME: %s\n", zBuf));
return SQLITE_OK;
}
static int getLastErrorMsg(int nBuf, char *zBuf){
DWORD error = GetLastError();
DWORD dwLen = 0;
char *zOut = 0;
if( isNT() ){
WCHAR *zTempWide = NULL;
dwLen = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
error,
0,
(LPWSTR) &zTempWide,
0,
0);
if( dwLen > 0 ){
zOut = unicodeToUtf8(zTempWide);
LocalFree(zTempWide);
}
#if SQLITE_OS_WINCE==0
}else{
char *zTemp = NULL;
dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
error,
0,
(LPSTR) &zTemp,
0,
0);
if( dwLen > 0 ){
zOut = sqlite3_win32_mbcs_to_utf8(zTemp);
LocalFree(zTemp);
}
#endif
}
if( 0 == dwLen ){
sqlite3_snprintf(nBuf, zBuf, "OsError 0x%x (%u)", error, error);
}else{
sqlite3_snprintf(nBuf, zBuf, "%s", zOut);
free(zOut);
}
return 0;
}
static int winOpen(
sqlite3_vfs *pVfs,
const char *zName,
sqlite3_file *id,
int flags,
int *pOutFlags
){
HANDLE h;
DWORD dwDesiredAccess;
DWORD dwShareMode;
DWORD dwCreationDisposition;
DWORD dwFlagsAndAttributes = 0;
#if SQLITE_OS_WINCE
int isTemp = 0;
#endif
winFile *pFile = (winFile*)id;
void *zConverted;
const char *zUtf8Name = zName;
char zTmpname[MAX_PATH+1];
int rc = SQLITE_OK;
#if !defined(NDEBUG) || SQLITE_OS_WINCE
int eType = flags&0xFFFFFF00;
#endif
int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE);
int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE);
int isCreate = (flags & SQLITE_OPEN_CREATE);
#ifndef NDEBUG
int isReadonly = (flags & SQLITE_OPEN_READONLY);
#endif
int isReadWrite = (flags & SQLITE_OPEN_READWRITE);
#ifndef NDEBUG
int isOpenJournal = (isCreate && (
eType==SQLITE_OPEN_MASTER_JOURNAL
|| eType==SQLITE_OPEN_MAIN_JOURNAL
|| eType==SQLITE_OPEN_WAL
));
#endif
assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly));
assert(isCreate==0 || isReadWrite);
assert(isExclusive==0 || isCreate);
assert(isDelete==0 || isCreate);
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB );
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL );
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MASTER_JOURNAL );
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL );
assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB
|| eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL
|| eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL
|| eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL
);
assert( id!=0 );
UNUSED_PARAMETER(pVfs);
pFile->h = INVALID_HANDLE_VALUE;
if( !zUtf8Name ){
assert(isDelete && !isOpenJournal);
rc = getTempname(MAX_PATH+1, zTmpname);
if( rc!=SQLITE_OK ){
return rc;
}
zUtf8Name = zTmpname;
}
zConverted = convertUtf8Filename(zUtf8Name);
if( zConverted==0 ){
return SQLITE_NOMEM;
}
if( isReadWrite ){
dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
}else{
dwDesiredAccess = GENERIC_READ;
}
if( isExclusive ){
dwCreationDisposition = CREATE_NEW;
}else if( isCreate ){
dwCreationDisposition = OPEN_ALWAYS;
}else{
dwCreationDisposition = OPEN_EXISTING;
}
dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
if( isDelete ){
#if SQLITE_OS_WINCE
dwFlagsAndAttributes = FILE_ATTRIBUTE_HIDDEN;
isTemp = 1;
#else
dwFlagsAndAttributes = FILE_ATTRIBUTE_TEMPORARY
| FILE_ATTRIBUTE_HIDDEN
| FILE_FLAG_DELETE_ON_CLOSE;
#endif
}else{
dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
}
#if SQLITE_OS_WINCE
dwFlagsAndAttributes |= FILE_FLAG_RANDOM_ACCESS;
#endif
if( isNT() ){
h = CreateFileW((WCHAR*)zConverted,
dwDesiredAccess,
dwShareMode,
NULL,
dwCreationDisposition,
dwFlagsAndAttributes,
NULL
);
#if SQLITE_OS_WINCE==0
}else{
h = CreateFileA((char*)zConverted,
dwDesiredAccess,
dwShareMode,
NULL,
dwCreationDisposition,
dwFlagsAndAttributes,
NULL
);
#endif
}
OSTRACE(("OPEN %d %s 0x%lx %s\n",
h, zName, dwDesiredAccess,
h==INVALID_HANDLE_VALUE ? "failed" : "ok"));
if( h==INVALID_HANDLE_VALUE ){
pFile->lastErrno = GetLastError();
free(zConverted);
if( isReadWrite ){
return winOpen(pVfs, zName, id,
((flags|SQLITE_OPEN_READONLY)&~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)), pOutFlags);
}else{
return SQLITE_CANTOPEN_BKPT;
}
}
if( pOutFlags ){
if( isReadWrite ){
*pOutFlags = SQLITE_OPEN_READWRITE;
}else{
*pOutFlags = SQLITE_OPEN_READONLY;
}
}
memset(pFile, 0, sizeof(*pFile));
pFile->pMethod = &winIoMethod;
pFile->h = h;
pFile->lastErrno = NO_ERROR;
pFile->pVfs = pVfs;
pFile->pShm = 0;
pFile->zPath = zName;
pFile->sectorSize = getSectorSize(pVfs, zUtf8Name);
#if SQLITE_OS_WINCE
if( isReadWrite && eType==SQLITE_OPEN_MAIN_DB
&& !winceCreateLock(zName, pFile)
){
CloseHandle(h);
free(zConverted);
return SQLITE_CANTOPEN_BKPT;
}
if( isTemp ){
pFile->zDeleteOnClose = zConverted;
}else
#endif
{
free(zConverted);
}
OpenCounter(+1);
return rc;
}
#define MX_DELETION_ATTEMPTS 5
static int winDelete(
sqlite3_vfs *pVfs,
const char *zFilename,
int syncDir
){
int cnt = 0;
DWORD rc;
DWORD error = 0;
void *zConverted;
UNUSED_PARAMETER(pVfs);
UNUSED_PARAMETER(syncDir);
SimulateIOError(return SQLITE_IOERR_DELETE);
zConverted = convertUtf8Filename(zFilename);
if( zConverted==0 ){
return SQLITE_NOMEM;
}
if( isNT() ){
do{
DeleteFileW(zConverted);
}while( ( ((rc = GetFileAttributesW(zConverted)) != INVALID_FILE_ATTRIBUTES)
|| ((error = GetLastError()) == ERROR_ACCESS_DENIED))
&& (++cnt < MX_DELETION_ATTEMPTS)
&& (Sleep(100), 1) );
#if SQLITE_OS_WINCE==0
}else{
do{
DeleteFileA(zConverted);
}while( ( ((rc = GetFileAttributesA(zConverted)) != INVALID_FILE_ATTRIBUTES)
|| ((error = GetLastError()) == ERROR_ACCESS_DENIED))
&& (++cnt < MX_DELETION_ATTEMPTS)
&& (Sleep(100), 1) );
#endif
}
free(zConverted);
OSTRACE(("DELETE \"%s\" %s\n", zFilename,
( (rc==INVALID_FILE_ATTRIBUTES) && (error==ERROR_FILE_NOT_FOUND)) ?
"ok" : "failed" ));
return ( (rc == INVALID_FILE_ATTRIBUTES)
&& (error == ERROR_FILE_NOT_FOUND)) ? SQLITE_OK : SQLITE_IOERR_DELETE;
}
static int winAccess(
sqlite3_vfs *pVfs,
const char *zFilename,
int flags,
int *pResOut
){
DWORD attr;
int rc = 0;
void *zConverted;
UNUSED_PARAMETER(pVfs);
SimulateIOError( return SQLITE_IOERR_ACCESS; );
zConverted = convertUtf8Filename(zFilename);
if( zConverted==0 ){
return SQLITE_NOMEM;
}
if( isNT() ){
WIN32_FILE_ATTRIBUTE_DATA sAttrData;
memset(&sAttrData, 0, sizeof(sAttrData));
if( GetFileAttributesExW((WCHAR*)zConverted,
GetFileExInfoStandard,
&sAttrData) ){
if( flags==SQLITE_ACCESS_EXISTS
&& sAttrData.nFileSizeHigh==0
&& sAttrData.nFileSizeLow==0 ){
attr = INVALID_FILE_ATTRIBUTES;
}else{
attr = sAttrData.dwFileAttributes;
}
}else{
if( GetLastError()!=ERROR_FILE_NOT_FOUND ){
free(zConverted);
return SQLITE_IOERR_ACCESS;
}else{
attr = INVALID_FILE_ATTRIBUTES;
}
}
#if SQLITE_OS_WINCE==0
}else{
attr = GetFileAttributesA((char*)zConverted);
#endif
}
free(zConverted);
switch( flags ){
case SQLITE_ACCESS_READ:
case SQLITE_ACCESS_EXISTS:
rc = attr!=INVALID_FILE_ATTRIBUTES;
break;
case SQLITE_ACCESS_READWRITE:
rc = (attr & FILE_ATTRIBUTE_READONLY)==0;
break;
default:
assert(!"Invalid flags argument");
}
*pResOut = rc;
return SQLITE_OK;
}
static int winFullPathname(
sqlite3_vfs *pVfs,
const char *zRelative,
int nFull,
char *zFull
){
#if defined(__CYGWIN__)
SimulateIOError( return SQLITE_ERROR );
UNUSED_PARAMETER(nFull);
cygwin_conv_to_full_win32_path(zRelative, zFull);
return SQLITE_OK;
#endif
#if SQLITE_OS_WINCE
SimulateIOError( return SQLITE_ERROR );
UNUSED_PARAMETER(nFull);
sqlite3_snprintf(pVfs->mxPathname, zFull, "%s", zRelative);
return SQLITE_OK;
#endif
#if !SQLITE_OS_WINCE && !defined(__CYGWIN__)
int nByte;
void *zConverted;
char *zOut;
SimulateIOError( return SQLITE_ERROR );
UNUSED_PARAMETER(nFull);
zConverted = convertUtf8Filename(zRelative);
if( isNT() ){
WCHAR *zTemp;
nByte = GetFullPathNameW((WCHAR*)zConverted, 0, 0, 0) + 3;
zTemp = malloc( nByte*sizeof(zTemp[0]) );
if( zTemp==0 ){
free(zConverted);
return SQLITE_NOMEM;
}
GetFullPathNameW((WCHAR*)zConverted, nByte, zTemp, 0);
free(zConverted);
zOut = unicodeToUtf8(zTemp);
free(zTemp);
#if SQLITE_OS_WINCE==0
}else{
char *zTemp;
nByte = GetFullPathNameA((char*)zConverted, 0, 0, 0) + 3;
zTemp = malloc( nByte*sizeof(zTemp[0]) );
if( zTemp==0 ){
free(zConverted);
return SQLITE_NOMEM;
}
GetFullPathNameA((char*)zConverted, nByte, zTemp, 0);
free(zConverted);
zOut = sqlite3_win32_mbcs_to_utf8(zTemp);
free(zTemp);
#endif
}
if( zOut ){
sqlite3_snprintf(pVfs->mxPathname, zFull, "%s", zOut);
free(zOut);
return SQLITE_OK;
}else{
return SQLITE_NOMEM;
}
#endif
}
static int getSectorSize(
sqlite3_vfs *pVfs,
const char *zRelative
){
DWORD bytesPerSector = SQLITE_DEFAULT_SECTOR_SIZE;
#if SQLITE_OS_WINCE
UNUSED_PARAMETER(pVfs);
UNUSED_PARAMETER(zRelative);
#else
char zFullpath[MAX_PATH+1];
int rc;
DWORD dwRet = 0;
DWORD dwDummy;
SimulateIOErrorBenign(1);
rc = winFullPathname(pVfs, zRelative, MAX_PATH, zFullpath);
SimulateIOErrorBenign(0);
if( rc == SQLITE_OK )
{
void *zConverted = convertUtf8Filename(zFullpath);
if( zConverted ){
if( isNT() ){
WCHAR *p = zConverted;
for(;*p;p++){
if( *p == '\\' ){
*p = '\0';
break;
}
}
dwRet = GetDiskFreeSpaceW((WCHAR*)zConverted,
&dwDummy,
&bytesPerSector,
&dwDummy,
&dwDummy);
}else{
char *p = (char *)zConverted;
for(;*p;p++){
if( *p == '\\' ){
*p = '\0';
break;
}
}
dwRet = GetDiskFreeSpaceA((char*)zConverted,
&dwDummy,
&bytesPerSector,
&dwDummy,
&dwDummy);
}
free(zConverted);
}
if( !dwRet ){
bytesPerSector = SQLITE_DEFAULT_SECTOR_SIZE;
}
}
#endif
return (int) bytesPerSector;
}
#ifndef SQLITE_OMIT_LOAD_EXTENSION
static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){
HANDLE h;
void *zConverted = convertUtf8Filename(zFilename);
UNUSED_PARAMETER(pVfs);
if( zConverted==0 ){
return 0;
}
if( isNT() ){
h = LoadLibraryW((WCHAR*)zConverted);
#if SQLITE_OS_WINCE==0
}else{
h = LoadLibraryA((char*)zConverted);
#endif
}
free(zConverted);
return (void*)h;
}
static void winDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){
UNUSED_PARAMETER(pVfs);
getLastErrorMsg(nBuf, zBufOut);
}
void (*winDlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol))(void){
UNUSED_PARAMETER(pVfs);
#if SQLITE_OS_WINCE
return (void(*)(void))GetProcAddressA((HANDLE)pHandle, zSymbol);
#else
return (void(*)(void))GetProcAddress((HANDLE)pHandle, zSymbol);
#endif
}
void winDlClose(sqlite3_vfs *pVfs, void *pHandle){
UNUSED_PARAMETER(pVfs);
FreeLibrary((HANDLE)pHandle);
}
#else
#define winDlOpen 0
#define winDlError 0
#define winDlSym 0
#define winDlClose 0
#endif
static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
int n = 0;
UNUSED_PARAMETER(pVfs);
#if defined(SQLITE_TEST)
n = nBuf;
memset(zBuf, 0, nBuf);
#else
if( sizeof(SYSTEMTIME)<=nBuf-n ){
SYSTEMTIME x;
GetSystemTime(&x);
memcpy(&zBuf[n], &x, sizeof(x));
n += sizeof(x);
}
if( sizeof(DWORD)<=nBuf-n ){
DWORD pid = GetCurrentProcessId();
memcpy(&zBuf[n], &pid, sizeof(pid));
n += sizeof(pid);
}
if( sizeof(DWORD)<=nBuf-n ){
DWORD cnt = GetTickCount();
memcpy(&zBuf[n], &cnt, sizeof(cnt));
n += sizeof(cnt);
}
if( sizeof(LARGE_INTEGER)<=nBuf-n ){
LARGE_INTEGER i;
QueryPerformanceCounter(&i);
memcpy(&zBuf[n], &i, sizeof(i));
n += sizeof(i);
}
#endif
return n;
}
static int winSleep(sqlite3_vfs *pVfs, int microsec){
Sleep((microsec+999)/1000);
UNUSED_PARAMETER(pVfs);
return ((microsec+999)/1000)*1000;
}
#ifdef SQLITE_TEST
int sqlite3_current_time = 0;
#endif
static int winCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){
FILETIME ft;
static const sqlite3_int64 winFiletimeEpoch = 23058135*(sqlite3_int64)8640000;
#ifdef SQLITE_TEST
static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
#endif
static const sqlite3_int64 max32BitValue =
(sqlite3_int64)2000000000 + (sqlite3_int64)2000000000 + (sqlite3_int64)294967296;
#if SQLITE_OS_WINCE
SYSTEMTIME time;
GetSystemTime(&time);
if (!SystemTimeToFileTime(&time,&ft)){
return 1;
}
#else
GetSystemTimeAsFileTime( &ft );
#endif
*piNow = winFiletimeEpoch +
((((sqlite3_int64)ft.dwHighDateTime)*max32BitValue) +
(sqlite3_int64)ft.dwLowDateTime)/(sqlite3_int64)10000;
#ifdef SQLITE_TEST
if( sqlite3_current_time ){
*piNow = 1000*(sqlite3_int64)sqlite3_current_time + unixEpoch;
}
#endif
UNUSED_PARAMETER(pVfs);
return 0;
}
int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){
int rc;
sqlite3_int64 i;
rc = winCurrentTimeInt64(pVfs, &i);
if( !rc ){
*prNow = i/86400000.0;
}
return rc;
}
static int winGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
UNUSED_PARAMETER(pVfs);
return getLastErrorMsg(nBuf, zBuf);
}
int sqlite3_os_init(void){
static sqlite3_vfs winVfs = {
3,
sizeof(winFile),
MAX_PATH,
0,
"win32",
0,
winOpen,
winDelete,
winAccess,
winFullPathname,
winDlOpen,
winDlError,
winDlSym,
winDlClose,
winRandomness,
winSleep,
winCurrentTime,
winGetLastError,
winCurrentTimeInt64,
0,
0,
0,
};
#ifndef SQLITE_OMIT_WAL
memset(&winSysInfo, 0, sizeof(SYSTEM_INFO));
GetSystemInfo(&winSysInfo);
assert(winSysInfo.dwAllocationGranularity > 0);
#endif
sqlite3_vfs_register(&winVfs, 1);
return SQLITE_OK;
}
int sqlite3_os_end(void){
return SQLITE_OK;
}
void chromium_sqlite3_initialize_win_sqlite3_file(sqlite3_file* file, HANDLE handle) {
winFile* winSQLite3File = (winFile*)file;
memset(file, 0, sizeof(*file));
winSQLite3File->pMethod = &winIoMethod;
winSQLite3File->h = handle;
}
#endif