#endif
/*
-** The winFile structure is a subclass of OsFile specific to the win32
+** The winFile structure is a subclass of sqlite3_file* specific to the win32
** portability layer.
*/
typedef struct winFile winFile;
struct winFile {
- IoMethod const *pMethod;/* Must be first */
+ const sqlite3_io_methods *pMethod;/* Must be first */
HANDLE h; /* Handle for accessing the file */
unsigned char locktype; /* Type of lock currently held on this file */
short sharedLockByte; /* Randomly chosen byte used as a shared lock */
};
-/*
-** Do not include any of the File I/O interface procedures if the
-** SQLITE_OMIT_DISKIO macro is defined (indicating that there database
-** will be in-memory only)
-*/
-#ifndef SQLITE_OMIT_DISKIO
-
/*
** The following variable is (normally) set once and never changes
** thereafter. It records whether the operating system is Win95
** In order to facilitate testing on a WinNT system, the test fixture
** can manually set this value to 1 to emulate Win98 behavior.
*/
+#ifdef SQLITE_TEST
int sqlite3_os_type = 0;
+#else
+static int sqlite3_os_type = 0;
+#endif
/*
** Return true (non-zero) if we are running under WinNT, Win2K, WinXP,
/*
** Convert a UTF-8 string to microsoft unicode (UTF-16?).
**
-** Space to hold the returned string is obtained from sqliteMalloc.
+** Space to hold the returned string is obtained from sqlite3_malloc.
*/
static WCHAR *utf8ToUnicode(const char *zFilename){
int nChar;
WCHAR *zWideFilename;
nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0);
- zWideFilename = sqliteMalloc( nChar*sizeof(zWideFilename[0]) );
+ zWideFilename = sqlite3_malloc( nChar*sizeof(zWideFilename[0]) );
if( zWideFilename==0 ){
return 0;
}
nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename, nChar);
if( nChar==0 ){
- sqliteFree(zWideFilename);
+ sqlite3_free(zWideFilename);
zWideFilename = 0;
}
return zWideFilename;
/*
** Convert microsoft unicode to UTF-8. Space to hold the returned string is
-** obtained from sqliteMalloc().
+** obtained from sqlite3_malloc().
*/
static char *unicodeToUtf8(const WCHAR *zWideFilename){
int nByte;
char *zFilename;
nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, 0, 0, 0, 0);
- zFilename = sqliteMalloc( nByte );
+ zFilename = sqlite3_malloc( nByte );
if( zFilename==0 ){
return 0;
}
nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, zFilename, nByte,
0, 0);
if( nByte == 0 ){
- sqliteFree(zFilename);
+ sqlite3_free(zFilename);
zFilename = 0;
}
return zFilename;
** current codepage settings for file apis.
**
** Space to hold the returned string is obtained
-** from sqliteMalloc.
+** from sqlite3_malloc.
*/
static WCHAR *mbcsToUnicode(const char *zFilename){
int nByte;
int codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
nByte = MultiByteToWideChar(codepage, 0, zFilename, -1, NULL,0)*sizeof(WCHAR);
- zMbcsFilename = sqliteMalloc( nByte*sizeof(zMbcsFilename[0]) );
+ zMbcsFilename = sqlite3_malloc( nByte*sizeof(zMbcsFilename[0]) );
if( zMbcsFilename==0 ){
return 0;
}
nByte = MultiByteToWideChar(codepage, 0, zFilename, -1, zMbcsFilename, nByte);
if( nByte==0 ){
- sqliteFree(zMbcsFilename);
+ sqlite3_free(zMbcsFilename);
zMbcsFilename = 0;
}
return zMbcsFilename;
** user's Ansi codepage.
**
** Space to hold the returned string is obtained from
-** sqliteMalloc().
+** sqlite3_malloc().
*/
static char *unicodeToMbcs(const WCHAR *zWideFilename){
int nByte;
int codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
nByte = WideCharToMultiByte(codepage, 0, zWideFilename, -1, 0, 0, 0, 0);
- zFilename = sqliteMalloc( nByte );
+ zFilename = sqlite3_malloc( nByte );
if( zFilename==0 ){
return 0;
}
nByte = WideCharToMultiByte(codepage, 0, zWideFilename, -1, zFilename, nByte,
0, 0);
if( nByte == 0 ){
- sqliteFree(zFilename);
+ sqlite3_free(zFilename);
zFilename = 0;
}
return zFilename;
/*
** Convert multibyte character string to UTF-8. Space to hold the
-** returned string is obtained from sqliteMalloc().
+** returned string is obtained from sqlite3_malloc().
*/
static char *mbcsToUtf8(const char *zFilename){
char *zFilenameUtf8;
return 0;
}
zFilenameUtf8 = unicodeToUtf8(zTmpWide);
- sqliteFree(zTmpWide);
+ sqlite3_free(zTmpWide);
return zFilenameUtf8;
}
/*
** Convert UTF-8 to multibyte character string. Space to hold the
-** returned string is obtained from sqliteMalloc().
+** returned string is obtained from sqlite3_malloc().
*/
static char *utf8ToMbcs(const char *zFilename){
char *zFilenameMbcs;
return 0;
}
zFilenameMbcs = unicodeToMbcs(zTmpWide);
- sqliteFree(zTmpWide);
+ sqlite3_free(zTmpWide);
return zFilenameMbcs;
}
/* Create/open the named mutex */
pFile->hMutex = CreateMutexW(NULL, FALSE, zName);
if (!pFile->hMutex){
- sqliteFree(zName);
+ sqlite3_free(zName);
return FALSE;
}
bInit = FALSE;
}
- sqliteFree(zName);
+ sqlite3_free(zName);
/* If we succeeded in making the shared memory handle, map it. */
if (pFile->hShared){
if( pFile->zDeleteOnClose ){
DeleteFileW(pFile->zDeleteOnClose);
- sqliteFree(pFile->zDeleteOnClose);
+ sqlite3_free(pFile->zDeleteOnClose);
pFile->zDeleteOnClose = 0;
}
*****************************************************************************/
#endif /* OS_WINCE */
-/*
-** Convert a UTF-8 filename into whatever form the underlying
-** operating system wants filenames in. Space to hold the result
-** is obtained from sqliteMalloc and must be freed by the calling
-** function.
-*/
-static void *convertUtf8Filename(const char *zFilename){
- void *zConverted = 0;
- if( isNT() ){
- zConverted = utf8ToUnicode(zFilename);
- }else{
- zConverted = utf8ToMbcs(zFilename);
- }
- /* caller will handle out of memory */
- return zConverted;
-}
-
-/*
-** Delete the named file.
-**
-** Note that windows does not allow a file to be deleted if some other
-** process has it open. Sometimes a virus scanner or indexing program
-** will open a journal file shortly after it is created in order to do
-** whatever it is it does. While this other process is holding the
-** file open, we will be unable to delete it. To work around this
-** problem, we delay 100 milliseconds and try to delete again. Up
-** to MX_DELETION_ATTEMPTs deletion attempts are run before giving
-** up and returning an error.
-*/
-#define MX_DELETION_ATTEMPTS 3
-int sqlite3WinDelete(const char *zFilename){
- int cnt = 0;
- int rc;
- void *zConverted = convertUtf8Filename(zFilename);
- if( zConverted==0 ){
- return SQLITE_NOMEM;
- }
- SimulateIOError(return SQLITE_IOERR_DELETE);
- if( isNT() ){
- do{
- rc = DeleteFileW(zConverted);
- }while( rc==0 && GetFileAttributesW(zConverted)!=0xffffffff
- && cnt++ < MX_DELETION_ATTEMPTS && (Sleep(100), 1) );
- }else{
-#if OS_WINCE
- return SQLITE_NOMEM;
-#else
- do{
- rc = DeleteFileA(zConverted);
- }while( rc==0 && GetFileAttributesA(zConverted)!=0xffffffff
- && cnt++ < MX_DELETION_ATTEMPTS && (Sleep(100), 1) );
-#endif
- }
- sqliteFree(zConverted);
- OSTRACE2("DELETE \"%s\"\n", zFilename);
- return rc!=0 ? SQLITE_OK : SQLITE_IOERR;
-}
-
-/*
-** Return TRUE if the named file exists.
-*/
-int sqlite3WinFileExists(const char *zFilename){
- int exists = 0;
- void *zConverted = convertUtf8Filename(zFilename);
- if( zConverted==0 ){
- return SQLITE_NOMEM;
- }
- if( isNT() ){
- exists = GetFileAttributesW((WCHAR*)zConverted) != 0xffffffff;
- }else{
-#if OS_WINCE
- return SQLITE_NOMEM;
-#else
- exists = GetFileAttributesA((char*)zConverted) != 0xffffffff;
-#endif
- }
- sqliteFree(zConverted);
- return exists;
-}
-
-/* Forward declaration */
-static int allocateWinFile(winFile *pInit, OsFile **pId);
-
-/*
-** Attempt to open a file for both reading and writing. If that
-** fails, try opening it read-only. If the file does not exist,
-** try to create it.
-**
-** On success, a handle for the open file is written to *id
-** and *pReadonly is set to 0 if the file was opened for reading and
-** writing or 1 if the file was opened read-only. The function returns
-** SQLITE_OK.
-**
-** On failure, the function returns SQLITE_CANTOPEN and leaves
-** *id and *pReadonly unchanged.
-*/
-int sqlite3WinOpenReadWrite(
- const char *zFilename,
- OsFile **pId,
- int *pReadonly
-){
- winFile f;
- HANDLE h;
- void *zConverted = convertUtf8Filename(zFilename);
- if( zConverted==0 ){
- return SQLITE_NOMEM;
- }
- assert( *pId==0 );
-
- if( isNT() ){
- h = CreateFileW((WCHAR*)zConverted,
- GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL,
- OPEN_ALWAYS,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
- NULL
- );
- if( h==INVALID_HANDLE_VALUE ){
- h = CreateFileW((WCHAR*)zConverted,
- GENERIC_READ,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL,
- OPEN_ALWAYS,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
- NULL
- );
- if( h==INVALID_HANDLE_VALUE ){
- sqliteFree(zConverted);
- return SQLITE_CANTOPEN;
- }
- *pReadonly = 1;
- }else{
- *pReadonly = 0;
- }
-#if OS_WINCE
- if (!winceCreateLock(zFilename, &f)){
- CloseHandle(h);
- sqliteFree(zConverted);
- return SQLITE_CANTOPEN;
- }
-#endif
- }else{
-#if OS_WINCE
- return SQLITE_NOMEM;
-#else
- h = CreateFileA((char*)zConverted,
- GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL,
- OPEN_ALWAYS,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
- NULL
- );
- if( h==INVALID_HANDLE_VALUE ){
- h = CreateFileA((char*)zConverted,
- GENERIC_READ,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL,
- OPEN_ALWAYS,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
- NULL
- );
- if( h==INVALID_HANDLE_VALUE ){
- sqliteFree(zConverted);
- return SQLITE_CANTOPEN;
- }
- *pReadonly = 1;
- }else{
- *pReadonly = 0;
- }
-#endif /* OS_WINCE */
- }
-
- sqliteFree(zConverted);
-
- f.h = h;
-#if OS_WINCE
- f.zDeleteOnClose = 0;
-#endif
- OSTRACE3("OPEN R/W %d \"%s\"\n", h, zFilename);
- return allocateWinFile(&f, pId);
-}
-
-
-/*
-** Attempt to open a new file for exclusive access by this process.
-** The file will be opened for both reading and writing. To avoid
-** a potential security problem, we do not allow the file to have
-** previously existed. Nor do we allow the file to be a symbolic
-** link.
-**
-** If delFlag is true, then make arrangements to automatically delete
-** the file when it is closed.
-**
-** On success, write the file handle into *id and return SQLITE_OK.
-**
-** On failure, return SQLITE_CANTOPEN.
-**
-** Sometimes if we have just deleted a prior journal file, windows
-** will fail to open a new one because there is a "pending delete".
-** To work around this bug, we pause for 100 milliseconds and attempt
-** a second open after the first one fails. The whole operation only
-** fails if both open attempts are unsuccessful.
-*/
-int sqlite3WinOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){
- winFile f;
- HANDLE h;
- DWORD fileflags;
- void *zConverted = convertUtf8Filename(zFilename);
- if( zConverted==0 ){
- return SQLITE_NOMEM;
- }
- assert( *pId == 0 );
- fileflags = FILE_FLAG_RANDOM_ACCESS;
-#if !OS_WINCE
- if( delFlag ){
- fileflags |= FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE;
- }
-#endif
- if( isNT() ){
- int cnt = 0;
- do{
- h = CreateFileW((WCHAR*)zConverted,
- GENERIC_READ | GENERIC_WRITE,
- 0,
- NULL,
- CREATE_ALWAYS,
- fileflags,
- NULL
- );
- }while( h==INVALID_HANDLE_VALUE && cnt++ < 2 && (Sleep(100), 1) );
- }else{
-#if OS_WINCE
- return SQLITE_NOMEM;
-#else
- int cnt = 0;
- do{
- h = CreateFileA((char*)zConverted,
- GENERIC_READ | GENERIC_WRITE,
- 0,
- NULL,
- CREATE_ALWAYS,
- fileflags,
- NULL
- );
- }while( h==INVALID_HANDLE_VALUE && cnt++ < 2 && (Sleep(100), 1) );
-#endif /* OS_WINCE */
- }
-#if OS_WINCE
- if( delFlag && h!=INVALID_HANDLE_VALUE ){
- f.zDeleteOnClose = zConverted;
- zConverted = 0;
- }
- f.hMutex = NULL;
-#endif
- sqliteFree(zConverted);
- if( h==INVALID_HANDLE_VALUE ){
- return SQLITE_CANTOPEN;
- }
- f.h = h;
- OSTRACE3("OPEN EX %d \"%s\"\n", h, zFilename);
- return allocateWinFile(&f, pId);
-}
-
-/*
-** Attempt to open a new file for read-only access.
-**
-** On success, write the file handle into *id and return SQLITE_OK.
-**
-** On failure, return SQLITE_CANTOPEN.
-*/
-int sqlite3WinOpenReadOnly(const char *zFilename, OsFile **pId){
- winFile f;
- HANDLE h;
- void *zConverted = convertUtf8Filename(zFilename);
- if( zConverted==0 ){
- return SQLITE_NOMEM;
- }
- assert( *pId==0 );
- if( isNT() ){
- h = CreateFileW((WCHAR*)zConverted,
- GENERIC_READ,
- 0,
- NULL,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
- NULL
- );
- }else{
-#if OS_WINCE
- return SQLITE_NOMEM;
-#else
- h = CreateFileA((char*)zConverted,
- GENERIC_READ,
- 0,
- NULL,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
- NULL
- );
-#endif
- }
- sqliteFree(zConverted);
- if( h==INVALID_HANDLE_VALUE ){
- return SQLITE_CANTOPEN;
- }
- f.h = h;
-#if OS_WINCE
- f.zDeleteOnClose = 0;
- f.hMutex = NULL;
-#endif
- OSTRACE3("OPEN RO %d \"%s\"\n", h, zFilename);
- return allocateWinFile(&f, pId);
-}
-
-/*
-** Attempt to open a file descriptor for the directory that contains a
-** file. This file descriptor can be used to fsync() the directory
-** in order to make sure the creation of a new file is actually written
-** to disk.
-**
-** This routine is only meaningful for Unix. It is a no-op under
-** windows since windows does not support hard links.
-**
-** On success, a handle for a previously open file is at *id is
-** updated with the new directory file descriptor and SQLITE_OK is
-** returned.
-**
-** On failure, the function returns SQLITE_CANTOPEN and leaves
-** *id unchanged.
-*/
-static int winOpenDirectory(
- OsFile *id,
- const char *zDirname
-){
- return SQLITE_OK;
-}
-
-/*
-** Create a temporary file name in zBuf. zBuf must be big enough to
-** hold at least SQLITE_TEMPNAME_SIZE characters.
-*/
-int sqlite3WinTempFileName(char *zBuf){
- static char zChars[] =
- "abcdefghijklmnopqrstuvwxyz"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "0123456789";
- int i, j;
- char zTempPath[SQLITE_TEMPNAME_SIZE];
- if( sqlite3_temp_directory ){
- strncpy(zTempPath, sqlite3_temp_directory, SQLITE_TEMPNAME_SIZE-30);
- zTempPath[SQLITE_TEMPNAME_SIZE-30] = 0;
- }else if( isNT() ){
- char *zMulti;
- WCHAR zWidePath[SQLITE_TEMPNAME_SIZE];
- GetTempPathW(SQLITE_TEMPNAME_SIZE-30, zWidePath);
- zMulti = unicodeToUtf8(zWidePath);
- if( zMulti ){
- strncpy(zTempPath, zMulti, SQLITE_TEMPNAME_SIZE-30);
- zTempPath[SQLITE_TEMPNAME_SIZE-30] = 0;
- sqliteFree(zMulti);
- }else{
- return SQLITE_NOMEM;
- }
- }else{
- char *zUtf8;
- char zMbcsPath[SQLITE_TEMPNAME_SIZE];
- GetTempPathA(SQLITE_TEMPNAME_SIZE-30, zMbcsPath);
- zUtf8 = mbcsToUtf8(zMbcsPath);
- if( zUtf8 ){
- strncpy(zTempPath, zUtf8, SQLITE_TEMPNAME_SIZE-30);
- zTempPath[SQLITE_TEMPNAME_SIZE-30] = 0;
- sqliteFree(zUtf8);
- }else{
- return SQLITE_NOMEM;
- }
- }
- for(i=strlen(zTempPath); i>0 && zTempPath[i-1]=='\\'; i--){}
- zTempPath[i] = 0;
- for(;;){
- sqlite3_snprintf(SQLITE_TEMPNAME_SIZE, zBuf,
- "%s\\"TEMP_FILE_PREFIX, zTempPath);
- j = strlen(zBuf);
- sqlite3Randomness(15, &zBuf[j]);
- for(i=0; i<15; i++, j++){
- zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
- }
- zBuf[j] = 0;
- if( !sqlite3OsFileExists(zBuf) ) break;
- }
- OSTRACE2("TEMP FILENAME: %s\n", zBuf);
- return SQLITE_OK;
-}
+/*****************************************************************************
+** The next group of routines implement the I/O methods specified
+** by the sqlite3_io_methods object.
+******************************************************************************/
/*
** Close a file.
** giving up and returning an error.
*/
#define MX_CLOSE_ATTEMPT 3
-static int winClose(OsFile **pId){
- winFile *pFile;
- int rc = 1;
- if( pId && (pFile = (winFile*)*pId)!=0 ){
- int rc, cnt = 0;
- OSTRACE2("CLOSE %d\n", pFile->h);
- do{
- rc = CloseHandle(pFile->h);
- }while( rc==0 && cnt++ < MX_CLOSE_ATTEMPT && (Sleep(100), 1) );
+static int winClose(sqlite3_file *id){
+ int rc, cnt = 0;
+ winFile *pFile = (winFile*)id;
+ OSTRACE2("CLOSE %d\n", pFile->h);
+ do{
+ rc = CloseHandle(pFile->h);
+ }while( rc==0 && cnt++ < MX_CLOSE_ATTEMPT && (Sleep(100), 1) );
#if OS_WINCE
- winceDestroyLock(pFile);
+ winceDestroyLock(pFile);
#endif
- OpenCounter(-1);
- sqliteFree(pFile);
- *pId = 0;
- }
+ OpenCounter(-1);
return rc ? SQLITE_OK : SQLITE_IOERR;
}
+/*
+** Some microsoft compilers lack this definition.
+*/
+#ifndef INVALID_SET_FILE_POINTER
+# define INVALID_SET_FILE_POINTER ((DWORD)-1)
+#endif
+
/*
** Read data from a file into a buffer. Return SQLITE_OK if all
** bytes were read successfully and SQLITE_IOERR if anything goes
** wrong.
*/
-static int winRead(OsFile *id, void *pBuf, int amt){
+static int winRead(
+ sqlite3_file *id, /* File to read from */
+ void *pBuf, /* Write content into this buffer */
+ int amt, /* Number of bytes to read */
+ sqlite3_int64 offset /* Begin reading at this offset */
+){
+ LONG upperBits = (offset>>32) & 0x7fffffff;
+ LONG lowerBits = offset & 0xffffffff;
+ DWORD rc;
DWORD got;
+ winFile *pFile = (winFile*)id;
assert( id!=0 );
SimulateIOError(return SQLITE_IOERR_READ);
- OSTRACE3("READ %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype);
- if( !ReadFile(((winFile*)id)->h, pBuf, amt, &got, 0) ){
+ OSTRACE3("READ %d lock=%d\n", pFile->h, pFile->locktype);
+ rc = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
+ if( rc==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR ){
+ return SQLITE_FULL;
+ }
+ if( !ReadFile(pFile->h, pBuf, amt, &got, 0) ){
return SQLITE_IOERR_READ;
}
if( got==(DWORD)amt ){
** Write data from a buffer into a file. Return SQLITE_OK on success
** or some other error code on failure.
*/
-static int winWrite(OsFile *id, const void *pBuf, int amt){
- int rc = 0;
+static int winWrite(
+ sqlite3_file *id, /* File to write into */
+ const void *pBuf, /* The bytes to be written */
+ int amt, /* Number of bytes to write */
+ sqlite3_int64 offset /* Offset into the file to begin writing at */
+){
+ LONG upperBits = (offset>>32) & 0x7fffffff;
+ LONG lowerBits = offset & 0xffffffff;
+ DWORD rc;
DWORD wrote;
+ winFile *pFile = (winFile*)id;
assert( id!=0 );
- SimulateIOError(return SQLITE_IOERR_READ);
+ SimulateIOError(return SQLITE_IOERR_WRITE);
SimulateDiskfullError(return SQLITE_FULL);
- OSTRACE3("WRITE %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype);
+ OSTRACE3("WRITE %d lock=%d\n", pFile->h, pFile->locktype);
+ rc = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
+ if( rc==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR ){
+ return SQLITE_FULL;
+ }
assert( amt>0 );
- while( amt>0 && (rc = WriteFile(((winFile*)id)->h, pBuf, amt, &wrote, 0))!=0
- && wrote>0 ){
+ while(
+ amt>0
+ && (rc = WriteFile(pFile->h, pBuf, amt, &wrote, 0))!=0
+ && wrote>0
+ ){
amt -= wrote;
pBuf = &((char*)pBuf)[wrote];
}
}
/*
-** Some microsoft compilers lack this definition.
+** Truncate an open file to a specified size
*/
-#ifndef INVALID_SET_FILE_POINTER
-# define INVALID_SET_FILE_POINTER ((DWORD)-1)
-#endif
-
-/*
-** Move the read/write pointer in a file.
-*/
-static int winSeek(OsFile *id, i64 offset){
- LONG upperBits = offset>>32;
- LONG lowerBits = offset & 0xffffffff;
- DWORD rc;
- assert( id!=0 );
-#ifdef SQLITE_TEST
- if( offset ) SimulateDiskfullError(return SQLITE_FULL);
-#endif
- rc = SetFilePointer(((winFile*)id)->h, lowerBits, &upperBits, FILE_BEGIN);
- OSTRACE3("SEEK %d %lld\n", ((winFile*)id)->h, offset);
- if( rc==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR ){
- return SQLITE_FULL;
- }
+static int winTruncate(sqlite3_file *id, i64 nByte){
+ LONG upperBits = (nByte>>32) & 0x7fffffff;
+ LONG lowerBits = nByte & 0xffffffff;
+ winFile *pFile = (winFile*)id;
+ OSTRACE3("TRUNCATE %d %lld\n", pFile->h, nByte);
+ SimulateIOError(return SQLITE_IOERR_TRUNCATE);
+ SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
+ SetEndOfFile(pFile->h);
return SQLITE_OK;
}
/*
** Make sure all writes to a particular file are committed to disk.
*/
-static int winSync(OsFile *id, int dataOnly){
- assert( id!=0 );
- OSTRACE3("SYNC %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype);
- if( FlushFileBuffers(((winFile*)id)->h) ){
+static int winSync(sqlite3_file *id, int flags){
+ winFile *pFile = (winFile*)id;
+ OSTRACE3("SYNC %d lock=%d\n", pFile->h, pFile->locktype);
+ if( FlushFileBuffers(pFile->h) ){
return SQLITE_OK;
}else{
return SQLITE_IOERR;
}
}
-/*
-** Sync the directory zDirname. This is a no-op on operating systems other
-** than UNIX.
-*/
-int sqlite3WinSyncDirectory(const char *zDirname){
- SimulateIOError(return SQLITE_IOERR_READ);
- return SQLITE_OK;
-}
-
-/*
-** Truncate an open file to a specified size
-*/
-static int winTruncate(OsFile *id, i64 nByte){
- LONG upperBits = nByte>>32;
- assert( id!=0 );
- OSTRACE3("TRUNCATE %d %lld\n", ((winFile*)id)->h, nByte);
- SimulateIOError(return SQLITE_IOERR_TRUNCATE);
- SetFilePointer(((winFile*)id)->h, nByte, &upperBits, FILE_BEGIN);
- SetEndOfFile(((winFile*)id)->h);
- return SQLITE_OK;
-}
-
/*
** Determine the current size of a file in bytes
*/
-static int winFileSize(OsFile *id, i64 *pSize){
+static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){
+ winFile *pFile = (winFile*)id;
DWORD upperBits, lowerBits;
- assert( id!=0 );
SimulateIOError(return SQLITE_IOERR_FSTAT);
- lowerBits = GetFileSize(((winFile*)id)->h, &upperBits);
- *pSize = (((i64)upperBits)<<32) + lowerBits;
+ lowerBits = GetFileSize(pFile->h, &upperBits);
+ *pSize = (((sqlite3_int64)upperBits)<<32) + lowerBits;
return SQLITE_OK;
}
** Different API routines are called depending on whether or not this
** is Win95 or WinNT.
*/
-static int getReadLock(winFile *id){
+static int getReadLock(winFile *pFile){
int res;
if( isNT() ){
OVERLAPPED ovlp;
ovlp.Offset = SHARED_FIRST;
ovlp.OffsetHigh = 0;
ovlp.hEvent = 0;
- res = LockFileEx(id->h, LOCKFILE_FAIL_IMMEDIATELY, 0, SHARED_SIZE,0,&ovlp);
+ res = LockFileEx(pFile->h, LOCKFILE_FAIL_IMMEDIATELY,
+ 0, SHARED_SIZE, 0, &ovlp);
}else{
int lk;
sqlite3Randomness(sizeof(lk), &lk);
- id->sharedLockByte = (lk & 0x7fffffff)%(SHARED_SIZE - 1);
- res = LockFile(id->h, SHARED_FIRST+id->sharedLockByte, 0, 1, 0);
+ pFile->sharedLockByte = (lk & 0x7fffffff)%(SHARED_SIZE - 1);
+ res = LockFile(pFile->h, SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0);
}
return res;
}
return res;
}
-#ifndef SQLITE_OMIT_PAGER_PRAGMAS
-/*
-** Check that a given pathname is a directory and is writable
-**
-*/
-int sqlite3WinIsDirWritable(char *zDirname){
- int fileAttr;
- void *zConverted;
- if( zDirname==0 ) return 0;
- if( !isNT() && strlen(zDirname)>MAX_PATH ) return 0;
-
- zConverted = convertUtf8Filename(zDirname);
- if( zConverted==0 ){
- return SQLITE_NOMEM;
- }
- if( isNT() ){
- fileAttr = GetFileAttributesW((WCHAR*)zConverted);
- }else{
-#if OS_WINCE
- return 0;
-#else
- fileAttr = GetFileAttributesA((char*)zConverted);
-#endif
- }
- sqliteFree(zConverted);
- if( fileAttr == 0xffffffff ) return 0;
- if( (fileAttr & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY ){
- return 0;
- }
- return 1;
-}
-#endif /* SQLITE_OMIT_PAGER_PRAGMAS */
-
/*
** Lock the file with the lock specified by parameter locktype - one
** of the following:
** It is not possible to lower the locking level one step at a time. You
** must go straight to locking level 0.
*/
-static int winLock(OsFile *id, int locktype){
+static int winLock(sqlite3_file *id, int locktype){
int rc = SQLITE_OK; /* Return code from subroutines */
int res = 1; /* Result of a windows lock call */
- int newLocktype; /* Set id->locktype to this value before exiting */
+ int newLocktype; /* Set pFile->locktype to this value before exiting */
int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */
winFile *pFile = (winFile*)id;
** file by this or any other process. If such a lock is held, return
** non-zero, otherwise zero.
*/
-static int winCheckReservedLock(OsFile *id){
+static int winCheckReservedLock(sqlite3_file *id){
int rc;
winFile *pFile = (winFile*)id;
assert( pFile!=0 );
** is NO_LOCK. If the second argument is SHARED_LOCK then this routine
** might return SQLITE_IOERR;
*/
-static int winUnlock(OsFile *id, int locktype){
+static int winUnlock(sqlite3_file *id, int locktype){
int type;
- int rc = SQLITE_OK;
winFile *pFile = (winFile*)id;
+ int rc = SQLITE_OK;
assert( pFile!=0 );
assert( locktype<=SHARED_LOCK );
OSTRACE5("UNLOCK %d to %d was %d(%d)\n", pFile->h, locktype,
}
/*
-** Turn a relative pathname into a full pathname. Return a pointer
-** to the full pathname stored in space obtained from sqliteMalloc().
-** The calling function is responsible for freeing this space once it
-** is no longer needed.
+** Currently unimplemented
*/
-char *sqlite3WinFullPathname(const char *zRelative){
- char *zFull;
-#if defined(__CYGWIN__)
- int nByte;
- nByte = strlen(zRelative) + MAX_PATH + 1001;
- zFull = sqliteMalloc( nByte );
- if( zFull==0 ) return 0;
- if( cygwin_conv_to_full_win32_path(zRelative, zFull) ) return 0;
-#elif OS_WINCE
- /* WinCE has no concept of a relative pathname, or so I am told. */
- zFull = sqliteStrDup(zRelative);
-#else
- int nByte;
- void *zConverted;
- zConverted = convertUtf8Filename(zRelative);
- if( isNT() ){
- WCHAR *zTemp;
- nByte = GetFullPathNameW((WCHAR*)zConverted, 0, 0, 0) + 3;
- zTemp = sqliteMalloc( nByte*sizeof(zTemp[0]) );
- if( zTemp==0 ){
- sqliteFree(zConverted);
- return 0;
- }
- GetFullPathNameW((WCHAR*)zConverted, nByte, zTemp, 0);
- sqliteFree(zConverted);
- zFull = unicodeToUtf8(zTemp);
- sqliteFree(zTemp);
- }else{
- char *zTemp;
- nByte = GetFullPathNameA((char*)zConverted, 0, 0, 0) + 3;
- zTemp = sqliteMalloc( nByte*sizeof(zTemp[0]) );
- if( zTemp==0 ){
- sqliteFree(zConverted);
- return 0;
- }
- GetFullPathNameA((char*)zConverted, nByte, zTemp, 0);
- sqliteFree(zConverted);
- zFull = mbcsToUtf8(zTemp);
- sqliteFree(zTemp);
- }
-#endif
- return zFull;
-}
-
-/*
-** The fullSync option is meaningless on windows. This is a no-op.
-*/
-static void winSetFullSync(OsFile *id, int v){
- return;
-}
-
-/*
-** Return the underlying file handle for an OsFile
-*/
-static int winFileHandle(OsFile *id){
- return (int)((winFile*)id)->h;
+static int winBreakLock(sqlite3_file *id){
+ return SQLITE_ERROR;
}
/*
** Return an integer that indices the type of lock currently held
** by this handle. (Used for testing and analysis only.)
*/
-static int winLockState(OsFile *id){
- return ((winFile*)id)->locktype;
+static int winLockState(sqlite3_file *id){
+ winFile *pFile = (winFile*)id;
+ return pFile->locktype;
}
/*
** a database and it's journal file) that the sector size will be the
** same for both.
*/
-static int winSectorSize(OsFile *id){
+static int winSectorSize(sqlite3_file *id){
return SQLITE_DEFAULT_SECTOR_SIZE;
}
/*
-** This vector defines all the methods that can operate on an OsFile
-** for win32.
+** Return a vector of device characteristics.
*/
-static const IoMethod sqlite3WinIoMethod = {
+static int winDeviceCharacteristics(sqlite3_file *id){
+ return 0;
+}
+
+/*
+** This vector defines all the methods that can operate on an
+** sqlite3_file for win32.
+*/
+static const sqlite3_io_methods winIoMethod = {
+ 1, /* iVersion */
winClose,
- winOpenDirectory,
winRead,
winWrite,
- winSeek,
winTruncate,
winSync,
- winSetFullSync,
- winFileHandle,
winFileSize,
winLock,
winUnlock,
- winLockState,
winCheckReservedLock,
+ winBreakLock,
+ winLockState,
winSectorSize,
+ winDeviceCharacteristics
};
+/***************************************************************************
+** Here ends the I/O methods that form the sqlite3_io_methods object.
+**
+** The next block of code implements the VFS methods.
+****************************************************************************/
+
/*
-** Allocate memory for an OsFile. Initialize the new OsFile
-** to the value given in pInit and return a pointer to the new
-** OsFile. If we run out of memory, close the file and return NULL.
+** Convert a UTF-8 filename into whatever form the underlying
+** operating system wants filenames in. Space to hold the result
+** is obtained from sqlite3_malloc and must be freed by the calling
+** function.
*/
-static int allocateWinFile(winFile *pInit, OsFile **pId){
- winFile *pNew;
- pNew = sqliteMalloc( sizeof(*pNew) );
- if( pNew==0 ){
- CloseHandle(pInit->h);
+static void *convertUtf8Filename(const char *zFilename){
+ void *zConverted = 0;
+ if( isNT() ){
+ zConverted = utf8ToUnicode(zFilename);
+ }else{
+ zConverted = utf8ToMbcs(zFilename);
+ }
+ /* caller will handle out of memory */
+ return zConverted;
+}
+
+/*
+** Open a file.
+*/
+static int winOpen(
+ sqlite3_vfs *pVfs, /* Not used */
+ const char *zName, /* Name of the file (UTF-8) */
+ sqlite3_file *id, /* Write the SQLite file handle here */
+ int flags, /* Open mode flags */
+ int *pOutFlags /* Status return flags */
+){
+ HANDLE h;
+ DWORD dwDesiredAccess;
+ DWORD dwShareMode;
+ DWORD dwCreationDisposition;
+ DWORD dwFlagsAndAttributes = 0;
+ winFile *pFile = (winFile*)id;
+ void *zConverted = convertUtf8Filename(zName);
+ if( zConverted==0 ){
+ return SQLITE_NOMEM;
+ }
+
+ if( flags & SQLITE_OPEN_READWRITE ){
+ dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
+ }else{
+ dwDesiredAccess = GENERIC_READ;
+ }
+ if( flags & SQLITE_OPEN_CREATE ){
+ dwCreationDisposition = OPEN_ALWAYS;
+ }else{
+ dwCreationDisposition = OPEN_EXISTING;
+ }
+ if( flags & SQLITE_OPEN_MAIN_DB ){
+ dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+ }else{
+ dwShareMode = 0;
+ }
+ if( flags & (SQLITE_OPEN_TEMP_DB | SQLITE_OPEN_TEMP_JOURNAL
+ | SQLITE_OPEN_SUBJOURNAL) ){
+ dwFlagsAndAttributes = FILE_ATTRIBUTE_TEMPORARY
+ | FILE_ATTRIBUTE_HIDDEN
+ | FILE_FLAG_DELETE_ON_CLOSE;
+ }else{
+ dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
+ }
+ if( flags & (SQLITE_OPEN_MAIN_DB | SQLITE_OPEN_TEMP_DB) ){
+ dwFlagsAndAttributes |= FILE_FLAG_RANDOM_ACCESS;
+ }else{
+ dwFlagsAndAttributes |= FILE_FLAG_SEQUENTIAL_SCAN;
+ }
+ if( isNT() ){
+ h = CreateFileW((WCHAR*)zConverted,
+ dwDesiredAccess,
+ dwShareMode,
+ NULL,
+ dwCreationDisposition,
+ dwFlagsAndAttributes,
+ NULL
+ );
+ }else{
+#if OS_WINCE
+ return SQLITE_NOMEM;
+#else
+ h = CreateFileA((char*)zConverted,
+ dwDesiredAccess,
+ dwShareMode,
+ NULL,
+ dwCreationDisposition,
+ dwFlagsAndAttributes,
+ NULL
+ );
+#endif
+ }
+ if( h==INVALID_HANDLE_VALUE ){
+ if( flags & SQLITE_OPEN_READWRITE ){
+ sqlite3_free(zConverted);
+ return winOpen(0, zName, id,
+ ((flags|SQLITE_OPEN_READONLY)&~SQLITE_OPEN_READWRITE), pOutFlags);
+ }else{
+ return SQLITE_CANTOPEN;
+ }
+ }
+ if( pOutFlags ){
+ if( flags & SQLITE_OPEN_READWRITE ){
+ *pOutFlags = SQLITE_OPEN_READWRITE;
+ }else{
+ *pOutFlags = SQLITE_OPEN_READONLY;
+ }
+ }
+ memset(pFile, 0, sizeof(*pFile));
+ pFile->pMethod = &winIoMethod;
+ pFile->h = h;
#if OS_WINCE
- sqliteFree(pInit->zDeleteOnClose);
+ if( (flags & (SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB)) ==
+ (SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB)
+ && !winceCreateLock(zFilename, &f)
+ ){
+ CloseHandle(h);
+ sqlite3_free(zConverted);
+ return SQLITE_CANTOPEN;
+ }
+ if( dwFlagsAndAttributes & FILE_FLAG_DELETEONCLOSE ){
+ pFile->zDeleteOnClose = zConverted;
+ }else
#endif
- *pId = 0;
+ {
+ sqlite3_free(zConverted);
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Delete the named file.
+**
+** Note that windows does not allow a file to be deleted if some other
+** process has it open. Sometimes a virus scanner or indexing program
+** will open a journal file shortly after it is created in order to do
+** whatever it is it does. While this other process is holding the
+** file open, we will be unable to delete it. To work around this
+** problem, we delay 100 milliseconds and try to delete again. Up
+** to MX_DELETION_ATTEMPTs deletion attempts are run before giving
+** up and returning an error.
+*/
+#define MX_DELETION_ATTEMPTS 3
+static int winDelete(
+ sqlite3_vfs *pVfs, /* Not used on win32 */
+ const char *zFilename, /* Name of file to delete */
+ int syncDir /* Not used on win32 */
+){
+ int cnt = 0;
+ int rc;
+ void *zConverted = convertUtf8Filename(zFilename);
+ if( zConverted==0 ){
return SQLITE_NOMEM;
+ }
+ SimulateIOError(return SQLITE_IOERR_DELETE);
+ if( isNT() ){
+ do{
+ rc = DeleteFileW(zConverted);
+ }while( rc==0 && GetFileAttributesW(zConverted)!=0xffffffff
+ && cnt++ < MX_DELETION_ATTEMPTS && (Sleep(100), 1) );
}else{
- *pNew = *pInit;
- pNew->pMethod = &sqlite3WinIoMethod;
- pNew->locktype = NO_LOCK;
- pNew->sharedLockByte = 0;
- *pId = (OsFile*)pNew;
- OpenCounter(+1);
- return SQLITE_OK;
+#if OS_WINCE
+ return SQLITE_NOMEM;
+#else
+ do{
+ rc = DeleteFileA(zConverted);
+ }while( rc==0 && GetFileAttributesA(zConverted)!=0xffffffff
+ && cnt++ < MX_DELETION_ATTEMPTS && (Sleep(100), 1) );
+#endif
}
+ sqlite3_free(zConverted);
+ OSTRACE2("DELETE \"%s\"\n", zFilename);
+ return rc!=0 ? SQLITE_OK : SQLITE_IOERR;
}
+/*
+** Check the existance and status of a file.
+*/
+static int winAccess(
+ sqlite3_vfs *pVfs, /* Not used on win32 */
+ const char *zFilename, /* Name of file to check */
+ int flags /* Type of test to make on this file */
+){
+ DWORD attr;
+ int rc;
+ void *zConverted = convertUtf8Filename(zFilename);
+ if( zConverted==0 ){
+ return SQLITE_NOMEM;
+ }
+ if( isNT() ){
+ attr = GetFileAttributesW((WCHAR*)zConverted);
+ }else{
+#if OS_WINCE
+ return SQLITE_NOMEM;
+#else
+ attr = GetFileAttributesA((char*)zConverted);
+#endif
+ }
+ sqlite3_free(zConverted);
+ switch( flags ){
+ case SQLITE_ACCESS_EXISTS:
+ rc = attr!=0xffffffff;
+ break;
+ case SQLITE_ACCESS_READWRITE:
+ rc = (attr & FILE_ATTRIBUTE_READONLY)==0;
+ break;
+ case SQLITE_ACCESS_READONLY:
+ rc = (attr!=0xffffffff) && ((attr & FILE_ATTRIBUTE_READONLY)==1);
+ break;
+ default:
+ assert(!"Invalid flags argument");
+ }
+ return rc;
+}
-#endif /* SQLITE_OMIT_DISKIO */
-/***************************************************************************
-** Everything above deals with file I/O. Everything that follows deals
-** with other miscellanous aspects of the operating system interface
-****************************************************************************/
-#if !defined(SQLITE_OMIT_LOAD_EXTENSION)
+/*
+** Create a temporary file name in zBuf. zBuf must be big enough to
+** hold at pVfs->mxPathname characters.
+*/
+static int winGetTempName(sqlite3_vfs *pVfs, char *zBuf){
+ static char zChars[] =
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "0123456789";
+ int i, j;
+ char zTempPath[MAX_PATH+1];
+ 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, "%z", zMulti);
+ }else{
+ return SQLITE_NOMEM;
+ }
+ }else{
+ char *zUtf8;
+ char zMbcsPath[MAX_PATH];
+ GetTempPathA(MAX_PATH-30, zMbcsPath);
+ zUtf8 = mbcsToUtf8(zMbcsPath);
+ if( zUtf8 ){
+ sqlite3_snprintf(MAX_PATH-30, zTempPath, "%z", zUtf8);
+ }else{
+ return SQLITE_NOMEM;
+ }
+ }
+ for(i=strlen(zTempPath); i>0 && zTempPath[i-1]=='\\'; i--){}
+ zTempPath[i] = 0;
+ for(;;){
+ sqlite3_snprintf(pVfs->mxPathname-30, zBuf,
+ "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPath);
+ j = strlen(zBuf);
+ sqlite3Randomness(15, &zBuf[j]);
+ for(i=0; i<15; i++, j++){
+ zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
+ }
+ zBuf[j] = 0;
+ if( !sqlite3OsAccess(pVfs, zBuf, SQLITE_ACCESS_EXISTS) ) break;
+ }
+ OSTRACE2("TEMP FILENAME: %s\n", zBuf);
+ return SQLITE_OK;
+}
+
+/*
+** Turn a relative pathname into a full pathname. Write the full
+** pathname into zOut[]. zOut[] will be at least pVfs->mxPathname
+** bytes in size.
+*/
+static int winFullPathname(
+ sqlite3_vfs *pVfs,
+ const char *zRelative,
+ char *zFull
+){
+
+#if defined(__CYGWIN__)
+ cygwin_conv_to_full_win32_path(zRelative, zFull);
+ return SQLITE_OK
+#endif
+
+#if OS_WINCE
+ /* WinCE has no concept of a relative pathname, or so I am told. */
+ sqlite3_snprintf(pVfs->mxPathname, zFull, "%s", zRelative);
+#endif
+
+#if !OS_WINCE && !defined(__CYGWIN__)
+ int nByte;
+ void *zConverted;
+ char *zOut;
+ zConverted = convertUtf8Filename(zRelative);
+ if( isNT() ){
+ WCHAR *zTemp;
+ nByte = GetFullPathNameW((WCHAR*)zConverted, 0, 0, 0) + 3;
+ zTemp = sqlite3_malloc( nByte*sizeof(zTemp[0]) );
+ if( zTemp==0 ){
+ sqlite3_free(zConverted);
+ return SQLITE_NOMEM;
+ }
+ GetFullPathNameW((WCHAR*)zConverted, nByte, zTemp, 0);
+ sqlite3_free(zConverted);
+ zOut = unicodeToUtf8(zTemp);
+ sqlite3_free(zTemp);
+ }else{
+ char *zTemp;
+ nByte = GetFullPathNameA((char*)zConverted, 0, 0, 0) + 3;
+ zTemp = sqlite3_malloc( nByte*sizeof(zTemp[0]) );
+ if( zTemp==0 ){
+ sqlite3_free(zConverted);
+ return SQLITE_NOMEM;
+ }
+ GetFullPathNameA((char*)zConverted, nByte, zTemp, 0);
+ sqlite3_free(zConverted);
+ zOut = mbcsToUtf8(zTemp);
+ sqlite3_free(zTemp);
+ }
+ if( zOut ){
+ sqlite3_snprintf(pVfs->mxPathname, zFull, "%z", zOut);
+ return SQLITE_OK;
+ }else{
+ return SQLITE_NOMEM;
+ }
+#endif
+}
+
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
/*
** Interfaces for opening a shared library, finding entry points
** within the shared library, and closing the shared library.
*/
-void *sqlite3WinDlopen(const char *zFilename){
+/*
+** Interfaces for opening a shared library, finding entry points
+** within the shared library, and closing the shared library.
+*/
+static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){
HANDLE h;
void *zConverted = convertUtf8Filename(zFilename);
if( zConverted==0 ){
h = LoadLibraryA((char*)zConverted);
#endif
}
- sqliteFree(zConverted);
+ sqlite3_free(zConverted);
return (void*)h;
-
}
-void *sqlite3WinDlsym(void *pHandle, const char *zSymbol){
+static void winDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){
+ FormatMessage(
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ GetLastError(),
+ 0,
+ zBufOut,
+ nBuf-1,
+ 0
+ );
+}
+void *winDlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol){
#if OS_WINCE
/* The GetProcAddressA() routine is only available on wince. */
return GetProcAddressA((HANDLE)pHandle, zSymbol);
return GetProcAddress((HANDLE)pHandle, zSymbol);
#endif
}
-int sqlite3WinDlclose(void *pHandle){
- return FreeLibrary((HANDLE)pHandle);
-}
-#endif /* !SQLITE_OMIT_LOAD_EXTENSION */
-
-/*
-** Get information to seed the random number generator. The seed
-** is written into the buffer zBuf[256]. The calling function must
-** supply a sufficiently large buffer.
-*/
-int sqlite3WinRandomSeed(char *zBuf){
- /* We have to initialize zBuf to prevent valgrind from reporting
- ** errors. The reports issued by valgrind are incorrect - we would
- ** prefer that the randomness be increased by making use of the
- ** uninitialized space in zBuf - but valgrind errors tend to worry
- ** some users. Rather than argue, it seems easier just to initialize
- ** the whole array and silence valgrind, even if that means less randomness
- ** in the random seed.
- **
- ** When testing, initializing zBuf[] to zero is all we do. That means
- ** that we always use the same random number sequence.* This makes the
- ** tests repeatable.
- */
- memset(zBuf, 0, 256);
- GetSystemTime((LPSYSTEMTIME)zBuf);
- return SQLITE_OK;
+void winDlClose(sqlite3_vfs *pVfs, void *pHandle){
+ FreeLibrary((HANDLE)pHandle);
}
+#else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */
+ #define winDlOpen 0
+ #define winDlError 0
+ #define winDlSym 0
+ #define winDlClose 0
+#endif
-/*
-** Sleep for a little while. Return the amount of time slept.
-*/
-int sqlite3WinSleep(int ms){
- Sleep(ms);
- return ms;
-}
/*
-** Static variables used for thread synchronization
+** Write up to nBuf bytes of randomness into zBuf.
*/
-static int inMutex = 0;
-#ifdef SQLITE_W32_THREADS
- static DWORD mutexOwner;
- static CRITICAL_SECTION cs;
-#endif
-
-/*
-** The following pair of routines implement mutual exclusion for
-** multi-threaded processes. Only a single thread is allowed to
-** executed code that is surrounded by EnterMutex() and LeaveMutex().
-**
-** SQLite uses only a single Mutex. There is not much critical
-** code and what little there is executes quickly and without blocking.
-**
-** Version 3.3.1 and earlier used a simple mutex. Beginning with
-** version 3.3.2, a recursive mutex is required.
-*/
-void sqlite3WinEnterMutex(){
-#ifdef SQLITE_W32_THREADS
- static int isInit = 0;
- while( !isInit ){
- static long lock = 0;
- if( InterlockedIncrement(&lock)==1 ){
- InitializeCriticalSection(&cs);
- isInit = 1;
- }else{
- Sleep(1);
- }
+static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
+ if( sizeof(LPSYSTEMTIME)>=nBuf ){
+ GetSystemTime((LPSYSTEMTIME)zBuf);
+ return sizeof(LPSYSTEMTIME);
+ }else{
+ return 0;
}
- EnterCriticalSection(&cs);
- mutexOwner = GetCurrentThreadId();
-#endif
- inMutex++;
-}
-void sqlite3WinLeaveMutex(){
- assert( inMutex );
- inMutex--;
-#ifdef SQLITE_W32_THREADS
- assert( mutexOwner==GetCurrentThreadId() );
- LeaveCriticalSection(&cs);
-#endif
}
+
/*
-** Return TRUE if the mutex is currently held.
-**
-** If the thisThreadOnly parameter is true, return true if and only if the
-** calling thread holds the mutex. If the parameter is false, return
-** true if any thread holds the mutex.
+** Sleep for a little while. Return the amount of time slept.
*/
-int sqlite3WinInMutex(int thisThreadOnly){
-#ifdef SQLITE_W32_THREADS
- return inMutex>0 && (thisThreadOnly==0 || mutexOwner==GetCurrentThreadId());
-#else
- return inMutex>0;
-#endif
+static int winSleep(sqlite3_vfs *pVfs, int microsec){
+ Sleep((microsec+999)/1000);
+ return ((microsec+999)/1000)*1000;
}
-
/*
** The following variable, if set to a non-zero value, becomes the result
** returned from sqlite3OsCurrentTime(). This is used for testing.
** current time and date as a Julian Day number into *prNow and
** return 0. Return 1 if the time and date cannot be found.
*/
-int sqlite3WinCurrentTime(double *prNow){
+int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){
FILETIME ft;
/* FILETIME structure is a 64-bit value representing the number of
100-nanosecond intervals since January 1, 1601 (= JD 2305813.5).
return 0;
}
-/*
-** Remember the number of thread-specific-data blocks allocated.
-** Use this to verify that we are not leaking thread-specific-data.
-** Ticket #1601
-*/
-#ifdef SQLITE_TEST
-int sqlite3_tsd_count = 0;
-# define TSD_COUNTER_INCR InterlockedIncrement(&sqlite3_tsd_count)
-# define TSD_COUNTER_DECR InterlockedDecrement(&sqlite3_tsd_count)
-#else
-# define TSD_COUNTER_INCR /* no-op */
-# define TSD_COUNTER_DECR /* no-op */
-#endif
-
-
/*
-** If called with allocateFlag>1, then return a pointer to thread
-** specific data for the current thread. Allocate and zero the
-** thread-specific data if it does not already exist necessary.
-**
-** If called with allocateFlag==0, then check the current thread
-** specific data. Return it if it exists. If it does not exist,
-** then return NULL.
-**
-** If called with allocateFlag<0, check to see if the thread specific
-** data is allocated and is all zero. If it is then deallocate it.
-** Return a pointer to the thread specific data or NULL if it is
-** unallocated or gets deallocated.
+** Return a pointer to the sqlite3DefaultVfs structure. We use
+** a function rather than give the structure global scope because
+** some compilers (MSVC) do not allow forward declarations of
+** initialized structures.
*/
-ThreadData *sqlite3WinThreadSpecificData(int allocateFlag){
- static int key;
- static int keyInit = 0;
- static const ThreadData zeroData = {0};
- ThreadData *pTsd;
-
- if( !keyInit ){
- sqlite3OsEnterMutex();
- if( !keyInit ){
- key = TlsAlloc();
- if( key==0xffffffff ){
- sqlite3OsLeaveMutex();
- return 0;
- }
- keyInit = 1;
- }
- sqlite3OsLeaveMutex();
- }
- pTsd = TlsGetValue(key);
- if( allocateFlag>0 ){
- if( !pTsd ){
- pTsd = sqlite3OsMalloc( sizeof(zeroData) );
- if( pTsd ){
- *pTsd = zeroData;
- TlsSetValue(key, pTsd);
- TSD_COUNTER_INCR;
- }
- }
- }else if( pTsd!=0 && allocateFlag<0
- && memcmp(pTsd, &zeroData, sizeof(ThreadData))==0 ){
- sqlite3OsFree(pTsd);
- TlsSetValue(key, 0);
- TSD_COUNTER_DECR;
- pTsd = 0;
- }
- return pTsd;
+sqlite3_vfs *sqlite3OsDefaultVfs(void){
+ static sqlite3_vfs winVfs = {
+ 1, /* iVersion */
+ sizeof(winFile), /* szOsFile */
+ MAX_PATH, /* mxPathname */
+ 0, /* nRef */
+ 0, /* vfsMutex */
+ 0, /* pNext */
+ "win32", /* zName */
+ 0, /* pAppData */
+
+ winOpen, /* xOpen */
+ winDelete, /* xDelete */
+ winAccess, /* xAccess */
+ winGetTempName, /* xGetTempName */
+ winFullPathname, /* xFullPathname */
+ winDlOpen, /* xDlOpen */
+ winDlError, /* xDlError */
+ winDlSym, /* xDlSym */
+ winDlClose, /* xDlClose */
+ winRandomness, /* xRandomness */
+ winSleep, /* xSleep */
+ winCurrentTime /* xCurrentTime */
+ };
+
+ return &winVfs;
}
+
#endif /* OS_WIN */