diff options
Diffstat (limited to 'src/os_win.c')
-rw-r--r-- | src/os_win.c | 421 |
1 files changed, 271 insertions, 150 deletions
diff --git a/src/os_win.c b/src/os_win.c index 10c431644..89e64aa43 100644 --- a/src/os_win.c +++ b/src/os_win.c @@ -30,7 +30,7 @@ ** available in Windows platforms based on the NT kernel. */ #if !SQLITE_OS_WINNT && !defined(SQLITE_OMIT_WAL) -# error "WAL mode requires support from the Windows NT kernel, compile\ +# error "WAL mode requires support from the Windows NT kernel, compile\ with SQLITE_OMIT_WAL." #endif @@ -51,6 +51,66 @@ #endif /* +** Maximum pathname length (in chars) for Win32. This should normally be +** MAX_PATH. +*/ +#ifndef SQLITE_WIN32_MAX_PATH_CHARS +# define SQLITE_WIN32_MAX_PATH_CHARS (MAX_PATH) +#endif + +/* +** Maximum pathname length (in chars) for WinNT. This should normally be +** 32767. +*/ +#ifndef SQLITE_WINNT_MAX_PATH_CHARS +# define SQLITE_WINNT_MAX_PATH_CHARS (32767) +#endif + +/* +** Maximum pathname length (in bytes) for Win32. The MAX_PATH macro is in +** characters, so we allocate 3 bytes per character assuming worst-case of +** 4-bytes-per-character for UTF8. +*/ +#ifndef SQLITE_WIN32_MAX_PATH_BYTES +# define SQLITE_WIN32_MAX_PATH_BYTES (SQLITE_WIN32_MAX_PATH_CHARS*4) +#endif + +/* +** Maximum pathname length (in bytes) for WinNT. This should normally be +** 32767 * sizeof(WCHAR). +*/ +#ifndef SQLITE_WINNT_MAX_PATH_BYTES +# define SQLITE_WINNT_MAX_PATH_BYTES \ + (sizeof(WCHAR) * SQLITE_WINNT_MAX_PATH_CHARS) +#endif + +/* +** Maximum error message length (in chars) for WinRT. +*/ +#ifndef SQLITE_WIN32_MAX_ERRMSG_CHARS +# define SQLITE_WIN32_MAX_ERRMSG_CHARS (1024) +#endif + +/* +** Returns non-zero if the character should be treated as a directory +** separator. +*/ +#ifndef winIsDirSep +# define winIsDirSep(a) (((a) == '/') || ((a) == '\\')) +#endif + +/* +** Returns the string that should be used as the directory separator. +*/ +#ifndef winGetDirDep +# ifdef __CYGWIN__ +# define winGetDirDep() "/" +# else +# define winGetDirDep() "\\" +# endif +#endif + +/* ** Do we need to manually define the Win32 file mapping APIs for use with WAL ** mode (e.g. these APIs are available in the Windows CE SDK; however, they ** are not present in the header file)? @@ -1057,11 +1117,11 @@ void sqlite3_win32_sleep(DWORD milliseconds){ ** the LockFileEx() API. */ #if SQLITE_OS_WINCE || SQLITE_OS_WINRT -# define isNT() (1) +# define osIsNT() (1) #elif !defined(SQLITE_WIN32_HAS_WIDE) -# define isNT() (0) +# define osIsNT() (0) #else - static int isNT(void){ + static int osIsNT(void){ if( sqlite3_os_type==0 ){ OSVERSIONINFOA sInfo; sInfo.dwOSVersionInfoSize = sizeof(sInfo); @@ -1272,7 +1332,7 @@ void sqlite3MemSetDefault(void){ ** ** Space to hold the returned string is obtained from malloc. */ -static LPWSTR utf8ToUnicode(const char *zFilename){ +static LPWSTR winUtf8ToUnicode(const char *zFilename){ int nChar; LPWSTR zWideFilename; @@ -1297,7 +1357,7 @@ static LPWSTR utf8ToUnicode(const char *zFilename){ ** Convert Microsoft Unicode to UTF-8. Space to hold the returned string is ** obtained from sqlite3_malloc(). */ -static char *unicodeToUtf8(LPCWSTR zWideFilename){ +static char *winUnicodeToUtf8(LPCWSTR zWideFilename){ int nByte; char *zFilename; @@ -1325,7 +1385,7 @@ static char *unicodeToUtf8(LPCWSTR zWideFilename){ ** Space to hold the returned string is obtained ** from sqlite3_malloc. */ -static LPWSTR mbcsToUnicode(const char *zFilename){ +static LPWSTR winMbcsToUnicode(const char *zFilename){ int nByte; LPWSTR zMbcsFilename; int codepage = osAreFileApisANSI() ? CP_ACP : CP_OEMCP; @@ -1355,7 +1415,7 @@ static LPWSTR mbcsToUnicode(const char *zFilename){ ** Space to hold the returned string is obtained from ** sqlite3_malloc(). */ -static char *unicodeToMbcs(LPCWSTR zWideFilename){ +static char *winUnicodeToMbcs(LPCWSTR zWideFilename){ int nByte; char *zFilename; int codepage = osAreFileApisANSI() ? CP_ACP : CP_OEMCP; @@ -1385,11 +1445,11 @@ char *sqlite3_win32_mbcs_to_utf8(const char *zFilename){ char *zFilenameUtf8; LPWSTR zTmpWide; - zTmpWide = mbcsToUnicode(zFilename); + zTmpWide = winMbcsToUnicode(zFilename); if( zTmpWide==0 ){ return 0; } - zFilenameUtf8 = unicodeToUtf8(zTmpWide); + zFilenameUtf8 = winUnicodeToUtf8(zTmpWide); sqlite3_free(zTmpWide); return zFilenameUtf8; } @@ -1402,11 +1462,11 @@ char *sqlite3_win32_utf8_to_mbcs(const char *zFilename){ char *zFilenameMbcs; LPWSTR zTmpWide; - zTmpWide = utf8ToUnicode(zFilename); + zTmpWide = winUtf8ToUnicode(zFilename); if( zTmpWide==0 ){ return 0; } - zFilenameMbcs = unicodeToMbcs(zTmpWide); + zFilenameMbcs = winUnicodeToMbcs(zTmpWide); sqlite3_free(zTmpWide); return zFilenameMbcs; } @@ -1436,7 +1496,7 @@ int sqlite3_win32_set_directory(DWORD type, LPCWSTR zValue){ if( ppDirectory ){ char *zValueUtf8 = 0; if( zValue && zValue[0] ){ - zValueUtf8 = unicodeToUtf8(zValue); + zValueUtf8 = winUnicodeToUtf8(zValue); if ( zValueUtf8==0 ){ return SQLITE_NOMEM; } @@ -1449,11 +1509,11 @@ int sqlite3_win32_set_directory(DWORD type, LPCWSTR zValue){ } /* -** The return value of getLastErrorMsg +** The return value of winGetLastErrorMsg ** is zero if the error message fits in the buffer, or non-zero ** otherwise (if the message was truncated). */ -static int getLastErrorMsg(DWORD lastErrno, int nBuf, char *zBuf){ +static int winGetLastErrorMsg(DWORD lastErrno, int nBuf, char *zBuf){ /* FormatMessage returns 0 on failure. Otherwise it ** returns the number of TCHARs written to the output ** buffer, excluding the terminating null char. @@ -1461,16 +1521,16 @@ static int getLastErrorMsg(DWORD lastErrno, int nBuf, char *zBuf){ DWORD dwLen = 0; char *zOut = 0; - if( isNT() ){ + if( osIsNT() ){ #if SQLITE_OS_WINRT - WCHAR zTempWide[MAX_PATH+1]; /* NOTE: Somewhat arbitrary. */ + WCHAR zTempWide[SQLITE_WIN32_MAX_ERRMSG_CHARS+1]; dwLen = osFormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, lastErrno, 0, zTempWide, - MAX_PATH, + SQLITE_WIN32_MAX_ERRMSG_CHARS, 0); #else LPWSTR zTempWide = NULL; @@ -1487,7 +1547,7 @@ static int getLastErrorMsg(DWORD lastErrno, int nBuf, char *zBuf){ if( dwLen > 0 ){ /* allocate a buffer and convert to UTF8 */ sqlite3BeginBenignMalloc(); - zOut = unicodeToUtf8(zTempWide); + zOut = winUnicodeToUtf8(zTempWide); sqlite3EndBenignMalloc(); #if !SQLITE_OS_WINRT /* free the system buffer allocated by FormatMessage */ @@ -1555,7 +1615,7 @@ static int winLogErrorAtLine( int i; /* Loop counter */ zMsg[0] = 0; - getLastErrorMsg(lastErrno, sizeof(zMsg), zMsg); + winGetLastErrorMsg(lastErrno, sizeof(zMsg), zMsg); assert( errcode!=SQLITE_OK ); if( zPath==0 ) zPath = ""; for(i=0; zMsg[i] && zMsg[i]!='\r' && zMsg[i]!='\n'; i++){} @@ -1580,17 +1640,17 @@ static int winLogErrorAtLine( #ifndef SQLITE_WIN32_IOERR_RETRY_DELAY # define SQLITE_WIN32_IOERR_RETRY_DELAY 25 #endif -static int win32IoerrRetry = SQLITE_WIN32_IOERR_RETRY; -static int win32IoerrRetryDelay = SQLITE_WIN32_IOERR_RETRY_DELAY; +static int winIoerrRetry = SQLITE_WIN32_IOERR_RETRY; +static int winIoerrRetryDelay = SQLITE_WIN32_IOERR_RETRY_DELAY; /* ** If a ReadFile() or WriteFile() error occurs, invoke this routine ** to see if it should be retried. Return TRUE to retry. Return FALSE ** to give up with an error. */ -static int retryIoerr(int *pnRetry, DWORD *pError){ +static int winRetryIoerr(int *pnRetry, DWORD *pError){ DWORD e = osGetLastError(); - if( *pnRetry>=win32IoerrRetry ){ + if( *pnRetry>=winIoerrRetry ){ if( pError ){ *pError = e; } @@ -1599,7 +1659,7 @@ static int retryIoerr(int *pnRetry, DWORD *pError){ if( e==ERROR_ACCESS_DENIED || e==ERROR_LOCK_VIOLATION || e==ERROR_SHARING_VIOLATION ){ - sqlite3_win32_sleep(win32IoerrRetryDelay*(1+*pnRetry)); + sqlite3_win32_sleep(winIoerrRetryDelay*(1+*pnRetry)); ++*pnRetry; return 1; } @@ -1612,11 +1672,11 @@ static int retryIoerr(int *pnRetry, DWORD *pError){ /* ** Log a I/O error retry episode. */ -static void logIoerr(int nRetry){ +static void winLogIoerr(int nRetry){ if( nRetry ){ sqlite3_log(SQLITE_IOERR, "delayed %dms for lock/sharing conflict", - win32IoerrRetryDelay*nRetry*(nRetry+1)/2 + winIoerrRetryDelay*nRetry*(nRetry+1)/2 ); } } @@ -1681,7 +1741,7 @@ static int winceCreateLock(const char *zFilename, winFile *pFile){ BOOL bLogged = FALSE; BOOL bInit = TRUE; - zName = utf8ToUnicode(zFilename); + zName = winUtf8ToUnicode(zFilename); if( zName==0 ){ /* out of memory */ return SQLITE_IOERR_NOMEM; @@ -1954,7 +2014,7 @@ static BOOL winLockFile( return winceLockFile(phFile, offsetLow, offsetHigh, numBytesLow, numBytesHigh); #else - if( isNT() ){ + if( osIsNT() ){ OVERLAPPED ovlp; memset(&ovlp, 0, sizeof(OVERLAPPED)); ovlp.Offset = offsetLow; @@ -1985,7 +2045,7 @@ static BOOL winUnlockFile( return winceUnlockFile(phFile, offsetLow, offsetHigh, numBytesLow, numBytesHigh); #else - if( isNT() ){ + if( osIsNT() ){ OVERLAPPED ovlp; memset(&ovlp, 0, sizeof(OVERLAPPED)); ovlp.Offset = offsetLow; @@ -2015,7 +2075,7 @@ static BOOL winUnlockFile( ** argument to offset iOffset within the file. If successful, return 0. ** Otherwise, set pFile->lastErrno and return non-zero. */ -static int seekWinFile(winFile *pFile, sqlite3_int64 iOffset){ +static int winSeekFile(winFile *pFile, sqlite3_int64 iOffset){ #if !SQLITE_OS_WINRT LONG upperBits; /* Most sig. 32 bits of new offset */ LONG lowerBits; /* Least sig. 32 bits of new offset */ @@ -2040,7 +2100,7 @@ static int seekWinFile(winFile *pFile, sqlite3_int64 iOffset){ && ((lastErrno = osGetLastError())!=NO_ERROR)) ){ pFile->lastErrno = lastErrno; winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno, - "seekWinFile", pFile->zPath); + "winSeekFile", pFile->zPath); OSTRACE(("SEEK file=%p, rc=SQLITE_IOERR_SEEK\n", pFile->h)); return 1; } @@ -2061,7 +2121,7 @@ static int seekWinFile(winFile *pFile, sqlite3_int64 iOffset){ if(!bRet){ pFile->lastErrno = osGetLastError(); winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno, - "seekWinFile", pFile->zPath); + "winSeekFile", pFile->zPath); OSTRACE(("SEEK file=%p, rc=SQLITE_IOERR_SEEK\n", pFile->h)); return 1; } @@ -2176,7 +2236,7 @@ static int winRead( #endif #if SQLITE_OS_WINCE - if( seekWinFile(pFile, offset) ){ + if( winSeekFile(pFile, offset) ){ OSTRACE(("READ file=%p, rc=SQLITE_FULL\n", pFile->h)); return SQLITE_FULL; } @@ -2189,13 +2249,13 @@ static int winRead( osGetLastError()!=ERROR_HANDLE_EOF ){ #endif DWORD lastErrno; - if( retryIoerr(&nRetry, &lastErrno) ) continue; + if( winRetryIoerr(&nRetry, &lastErrno) ) continue; pFile->lastErrno = lastErrno; OSTRACE(("READ file=%p, rc=SQLITE_IOERR_READ\n", pFile->h)); return winLogError(SQLITE_IOERR_READ, pFile->lastErrno, "winRead", pFile->zPath); } - logIoerr(nRetry); + winLogIoerr(nRetry); if( nRead<(DWORD)amt ){ /* Unread parts of the buffer must be zero-filled */ memset(&((char*)pBuf)[nRead], 0, amt-nRead); @@ -2248,7 +2308,7 @@ static int winWrite( #endif #if SQLITE_OS_WINCE - rc = seekWinFile(pFile, offset); + rc = winSeekFile(pFile, offset); if( rc==0 ){ #else { @@ -2273,7 +2333,7 @@ static int winWrite( #else if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, &overlapped) ){ #endif - if( retryIoerr(&nRetry, &lastErrno) ) continue; + if( winRetryIoerr(&nRetry, &lastErrno) ) continue; break; } assert( nWrite==0 || nWrite<=(DWORD)nRem ); @@ -2305,7 +2365,7 @@ static int winWrite( return winLogError(SQLITE_IOERR_WRITE, pFile->lastErrno, "winWrite", pFile->zPath); }else{ - logIoerr(nRetry); + winLogIoerr(nRetry); } OSTRACE(("WRITE file=%p, rc=SQLITE_OK\n", pFile->h)); return SQLITE_OK; @@ -2334,7 +2394,7 @@ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){ } /* SetEndOfFile() returns non-zero when successful, or zero when it fails. */ - if( seekWinFile(pFile, nByte) ){ + if( winSeekFile(pFile, nByte) ){ rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno, "winTruncate1", pFile->zPath); }else if( 0==osSetEndOfFile(pFile->h) && @@ -2415,6 +2475,7 @@ static int winSync(sqlite3_file *id, int flags){ ** no-op */ #ifdef SQLITE_NO_SYNC + OSTRACE(("SYNC-NOP file=%p, rc=SQLITE_OK\n", pFile->h)); return SQLITE_OK; #else rc = osFlushFileBuffers(pFile->h); @@ -2512,10 +2573,10 @@ static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){ ** Different API routines are called depending on whether or not this ** is Win9x or WinNT. */ -static int getReadLock(winFile *pFile){ +static int winGetReadLock(winFile *pFile){ int res; OSTRACE(("READ-LOCK file=%p, lock=%d\n", pFile->h, pFile->locktype)); - if( isNT() ){ + if( osIsNT() ){ #if SQLITE_OS_WINCE /* ** NOTE: Windows CE is handled differently here due its lack of the Win32 @@ -2547,11 +2608,11 @@ static int getReadLock(winFile *pFile){ /* ** Undo a readlock */ -static int unlockReadLock(winFile *pFile){ +static int winUnlockReadLock(winFile *pFile){ int res; DWORD lastErrno; OSTRACE(("READ-UNLOCK file=%p, lock=%d\n", pFile->h, pFile->locktype)); - if( isNT() ){ + if( osIsNT() ){ res = winUnlockFile(&pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); } #ifdef SQLITE_WIN32_HAS_ANSI @@ -2562,7 +2623,7 @@ static int unlockReadLock(winFile *pFile){ if( res==0 && ((lastErrno = osGetLastError())!=ERROR_NOT_LOCKED) ){ pFile->lastErrno = lastErrno; winLogError(SQLITE_IOERR_UNLOCK, pFile->lastErrno, - "unlockReadLock", pFile->zPath); + "winUnlockReadLock", pFile->zPath); } OSTRACE(("READ-UNLOCK file=%p, rc=%s\n", pFile->h, sqlite3ErrName(res))); return res; @@ -2653,7 +2714,7 @@ static int winLock(sqlite3_file *id, int locktype){ */ if( locktype==SHARED_LOCK && res ){ assert( pFile->locktype==NO_LOCK ); - res = getReadLock(pFile); + res = winGetReadLock(pFile); if( res ){ newLocktype = SHARED_LOCK; }else{ @@ -2684,14 +2745,14 @@ static int winLock(sqlite3_file *id, int locktype){ */ if( locktype==EXCLUSIVE_LOCK && res ){ assert( pFile->locktype>=SHARED_LOCK ); - res = unlockReadLock(pFile); + res = winUnlockReadLock(pFile); res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, SHARED_FIRST, 0, SHARED_SIZE, 0); if( res ){ newLocktype = EXCLUSIVE_LOCK; }else{ lastErrno = osGetLastError(); - getReadLock(pFile); + winGetReadLock(pFile); } } @@ -2708,10 +2769,10 @@ static int winLock(sqlite3_file *id, int locktype){ if( res ){ rc = SQLITE_OK; }else{ - OSTRACE(("LOCK-FAIL file=%p, wanted=%d, got=%d\n", - pFile->h, locktype, newLocktype)); pFile->lastErrno = lastErrno; rc = SQLITE_BUSY; + OSTRACE(("LOCK-FAIL file=%p, wanted=%d, got=%d\n", + pFile->h, locktype, newLocktype)); } pFile->locktype = (u8)newLocktype; OSTRACE(("LOCK file=%p, lock=%d, rc=%s\n", @@ -2771,7 +2832,7 @@ static int winUnlock(sqlite3_file *id, int locktype){ type = pFile->locktype; if( type>=EXCLUSIVE_LOCK ){ winUnlockFile(&pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); - if( locktype==SHARED_LOCK && !getReadLock(pFile) ){ + if( locktype==SHARED_LOCK && !winGetReadLock(pFile) ){ /* This should never happen. We should always be able to ** reacquire the read lock */ rc = winLogError(SQLITE_IOERR_UNLOCK, osGetLastError(), @@ -2782,7 +2843,7 @@ static int winUnlock(sqlite3_file *id, int locktype){ winUnlockFile(&pFile->h, RESERVED_BYTE, 0, 1, 0); } if( locktype==NO_LOCK && type>=SHARED_LOCK ){ - unlockReadLock(pFile); + winUnlockReadLock(pFile); } if( type>=PENDING_LOCK ){ winUnlockFile(&pFile->h, PENDING_BYTE, 0, 1, 0); @@ -2810,7 +2871,7 @@ static void winModeBit(winFile *pFile, unsigned char mask, int *pArg){ } /* Forward declaration */ -static int getTempname(int nBuf, char *zBuf); +static int winGetTempname(sqlite3_vfs *, char **); #if SQLITE_MAX_MMAP_SIZE>0 static int winMapfile(winFile*, sqlite3_int64); #endif @@ -2873,26 +2934,26 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){ case SQLITE_FCNTL_WIN32_AV_RETRY: { int *a = (int*)pArg; if( a[0]>0 ){ - win32IoerrRetry = a[0]; + winIoerrRetry = a[0]; }else{ - a[0] = win32IoerrRetry; + a[0] = winIoerrRetry; } if( a[1]>0 ){ - win32IoerrRetryDelay = a[1]; + winIoerrRetryDelay = a[1]; }else{ - a[1] = win32IoerrRetryDelay; + a[1] = winIoerrRetryDelay; } OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); return SQLITE_OK; } case SQLITE_FCNTL_TEMPFILENAME: { - char *zTFile = sqlite3MallocZero( pFile->pVfs->mxPathname ); - if( zTFile ){ - getTempname(pFile->pVfs->mxPathname, zTFile); + char *zTFile = 0; + int rc = winGetTempname(pFile->pVfs, &zTFile); + if( rc==SQLITE_OK ){ *(char**)pArg = zTFile; } - OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); - return SQLITE_OK; + OSTRACE(("FCNTL file=%p, rc=%d\n", pFile->h, rc)); + return rc; } #if SQLITE_MAX_MMAP_SIZE>0 case SQLITE_FCNTL_MMAP_SIZE: { @@ -3854,10 +3915,10 @@ static const sqlite3_io_methods winIoMethod = { ** is obtained from malloc and must be freed by the calling ** function. */ -static void *convertUtf8Filename(const char *zFilename){ +static void *winConvertUtf8Filename(const char *zFilename){ void *zConverted = 0; - if( isNT() ){ - zConverted = utf8ToUnicode(zFilename); + if( osIsNT() ){ + zConverted = winUtf8ToUnicode(zFilename); } #ifdef SQLITE_WIN32_HAS_ANSI else{ @@ -3869,26 +3930,29 @@ static void *convertUtf8Filename(const char *zFilename){ } /* -** Maximum pathname length (in bytes) for windows. The MAX_PATH macro is -** in characters, so we allocate 3 bytes per character assuming worst-case -** 3-bytes-per-character UTF8. +** This function returns non-zero if the specified UTF-8 string buffer +** ends with a directory separator character. */ -#ifndef SQLITE_WIN32_MAX_PATH -# define SQLITE_WIN32_MAX_PATH (MAX_PATH*3) -#endif +static int winEndsInDirSep(char *zBuf){ + if( zBuf ){ + int nLen = sqlite3Strlen30(zBuf); + return nLen>0 && winIsDirSep(zBuf[nLen-1]); + } + return 0; +} /* -** Create a temporary file name in zBuf. zBuf must be big enough to -** hold at pVfs->mxPathname characters. +** Create a temporary file name and store the resulting pointer into pzBuf. +** The pointer returned in pzBuf must be freed via sqlite3_free(). */ -static int getTempname(int nBuf, char *zBuf){ +static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){ static char zChars[] = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789"; size_t i, j; - int nTempPath; - char zTempPath[SQLITE_WIN32_MAX_PATH+2]; + int nBuf, nLen; + char *zBuf; /* It's odd to simulate an io-error here, but really this is just ** using the io-error infrastructure to test that SQLite handles this @@ -3896,23 +3960,49 @@ static int getTempname(int nBuf, char *zBuf){ */ SimulateIOError( return SQLITE_IOERR ); + /* Allocate a temporary buffer to store the fully qualified file + ** name for the temporary file. If this fails, we cannot continue. + */ + nBuf = pVfs->mxPathname; + zBuf = sqlite3MallocZero( nBuf+2 ); + if( !zBuf ){ + OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n")); + return SQLITE_IOERR_NOMEM; + } + + /* Figure out the effective temporary directory. First, check if one + ** has been explicitly set by the application; otherwise, use the one + ** configured by the operating system. + */ + assert( nBuf>30 ); if( sqlite3_temp_directory ){ - sqlite3_snprintf(SQLITE_WIN32_MAX_PATH-30, zTempPath, "%s", - sqlite3_temp_directory); + sqlite3_snprintf(nBuf-30, zBuf, "%s%s", sqlite3_temp_directory, + winEndsInDirSep(sqlite3_temp_directory) ? "" : + winGetDirDep()); } #if !SQLITE_OS_WINRT - else if( isNT() ){ + else if( osIsNT() ){ char *zMulti; - WCHAR zWidePath[MAX_PATH]; - if( osGetTempPathW(MAX_PATH-30, zWidePath)==0 ){ + LPWSTR zWidePath = sqlite3MallocZero( nBuf*sizeof(WCHAR) ); + if( !zWidePath ){ + sqlite3_free(zBuf); + OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n")); + return SQLITE_IOERR_NOMEM; + } + if( osGetTempPathW(nBuf, zWidePath)==0 ){ + sqlite3_free(zWidePath); + sqlite3_free(zBuf); OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_GETTEMPPATH\n")); return SQLITE_IOERR_GETTEMPPATH; } - zMulti = unicodeToUtf8(zWidePath); + zMulti = winUnicodeToUtf8(zWidePath); if( zMulti ){ - sqlite3_snprintf(SQLITE_WIN32_MAX_PATH-30, zTempPath, "%s", zMulti); + sqlite3_snprintf(nBuf-30, zBuf, "%s", zMulti); sqlite3_free(zMulti); + sqlite3_free(zWidePath); }else{ + sqlite3_free(zWidePath); + sqlite3_free(zBuf); OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n")); return SQLITE_IOERR_NOMEM; } @@ -3920,55 +4010,43 @@ static int getTempname(int nBuf, char *zBuf){ #ifdef SQLITE_WIN32_HAS_ANSI else{ char *zUtf8; - char zMbcsPath[SQLITE_WIN32_MAX_PATH]; - if( osGetTempPathA(SQLITE_WIN32_MAX_PATH-30, zMbcsPath)==0 ){ + char *zMbcsPath = sqlite3MallocZero( nBuf ); + if( !zMbcsPath ){ + sqlite3_free(zBuf); + OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n")); + return SQLITE_IOERR_NOMEM; + } + if( osGetTempPathA(nBuf, zMbcsPath)==0 ){ + sqlite3_free(zBuf); OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_GETTEMPPATH\n")); return SQLITE_IOERR_GETTEMPPATH; } zUtf8 = sqlite3_win32_mbcs_to_utf8(zMbcsPath); if( zUtf8 ){ - sqlite3_snprintf(SQLITE_WIN32_MAX_PATH-30, zTempPath, "%s", zUtf8); + sqlite3_snprintf(nBuf-30, zBuf, "%s", zUtf8); sqlite3_free(zUtf8); }else{ + sqlite3_free(zBuf); OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n")); return SQLITE_IOERR_NOMEM; } } -#else - else{ - /* - ** Compiled without ANSI support and the current operating system - ** is not Windows NT; therefore, just zero the temporary buffer. - */ - memset(zTempPath, 0, SQLITE_WIN32_MAX_PATH+2); - } #endif /* SQLITE_WIN32_HAS_ANSI */ -#else - else{ - /* - ** Compiled for WinRT and the sqlite3_temp_directory is not set; - ** therefore, just zero the temporary buffer. - */ - memset(zTempPath, 0, SQLITE_WIN32_MAX_PATH+2); - } #endif /* !SQLITE_OS_WINRT */ /* Check that the output buffer is large enough for the temporary file ** name. If it is not, return SQLITE_ERROR. */ - nTempPath = sqlite3Strlen30(zTempPath); + nLen = sqlite3Strlen30(zBuf); - if( (nTempPath + sqlite3Strlen30(SQLITE_TEMP_FILE_PREFIX) + 18) >= nBuf ){ + if( (nLen + sqlite3Strlen30(SQLITE_TEMP_FILE_PREFIX) + 18) >= nBuf ){ + sqlite3_free(zBuf); OSTRACE(("TEMP-FILENAME rc=SQLITE_ERROR\n")); return SQLITE_ERROR; } - for(i=nTempPath; i>0 && zTempPath[i-1]=='\\'; i--){} - zTempPath[i] = 0; + sqlite3_snprintf(nBuf-18-nLen, zBuf+nLen, SQLITE_TEMP_FILE_PREFIX); - sqlite3_snprintf(nBuf-18, zBuf, (nTempPath > 0) ? - "%s\\"SQLITE_TEMP_FILE_PREFIX : SQLITE_TEMP_FILE_PREFIX, - zTempPath); j = sqlite3Strlen30(zBuf); sqlite3_randomness(15, &zBuf[j]); for(i=0; i<15; i++, j++){ @@ -3976,6 +4054,7 @@ static int getTempname(int nBuf, char *zBuf){ } zBuf[j] = 0; zBuf[j+1] = 0; + *pzBuf = zBuf; OSTRACE(("TEMP-FILENAME name=%s, rc=SQLITE_OK\n", zBuf)); return SQLITE_OK; @@ -3991,13 +4070,13 @@ static int winIsDir(const void *zConverted){ int rc = 0; DWORD lastErrno; - if( isNT() ){ + if( osIsNT() ){ int cnt = 0; WIN32_FILE_ATTRIBUTE_DATA sAttrData; memset(&sAttrData, 0, sizeof(sAttrData)); while( !(rc = osGetFileAttributesExW((LPCWSTR)zConverted, GetFileExInfoStandard, - &sAttrData)) && retryIoerr(&cnt, &lastErrno) ){} + &sAttrData)) && winRetryIoerr(&cnt, &lastErrno) ){} if( !rc ){ return 0; /* Invalid name? */ } @@ -4014,7 +4093,7 @@ static int winIsDir(const void *zConverted){ ** Open a file. */ static int winOpen( - sqlite3_vfs *pVfs, /* Not used */ + sqlite3_vfs *pVfs, /* Used to get maximum path name length */ const char *zName, /* Name of the file (UTF-8) */ sqlite3_file *id, /* Write the SQLite file handle here */ int flags, /* Open mode flags */ @@ -4037,7 +4116,7 @@ static int winOpen( /* If argument zPath is a NULL pointer, this function is required to open ** a temporary file. Use this buffer to store the file name in. */ - char zTmpname[SQLITE_WIN32_MAX_PATH+2]; /* Buffer used to create temp filename */ + char *zTmpname = 0; /* For temporary filename, if necessary. */ int rc = SQLITE_OK; /* Function Return Code */ #if !defined(NDEBUG) || SQLITE_OS_WINCE @@ -4092,7 +4171,7 @@ static int winOpen( pFile->h = INVALID_HANDLE_VALUE; #if SQLITE_OS_WINRT - if( !sqlite3_temp_directory ){ + if( !zUtf8Name && !sqlite3_temp_directory ){ sqlite3_log(SQLITE_ERROR, "sqlite3_temp_directory variable should be set for WinRT"); } @@ -4102,8 +4181,8 @@ static int winOpen( ** temporary file name to use */ if( !zUtf8Name ){ - assert(isDelete && !isOpenJournal); - rc = getTempname(SQLITE_WIN32_MAX_PATH+2, zTmpname); + assert( isDelete && !isOpenJournal ); + rc = winGetTempname(pVfs, &zTmpname); if( rc!=SQLITE_OK ){ OSTRACE(("OPEN name=%s, rc=%s", zUtf8Name, sqlite3ErrName(rc))); return rc; @@ -4116,17 +4195,19 @@ static int winOpen( ** sqlite3_uri_parameter(). */ assert( (eType!=SQLITE_OPEN_MAIN_DB) || (flags & SQLITE_OPEN_URI) || - zUtf8Name[strlen(zUtf8Name)+1]==0 ); + zUtf8Name[sqlite3Strlen30(zUtf8Name)+1]==0 ); /* Convert the filename to the system encoding. */ - zConverted = convertUtf8Filename(zUtf8Name); + zConverted = winConvertUtf8Filename(zUtf8Name); if( zConverted==0 ){ + sqlite3_free(zTmpname); OSTRACE(("OPEN name=%s, rc=SQLITE_IOERR_NOMEM", zUtf8Name)); return SQLITE_IOERR_NOMEM; } if( winIsDir(zConverted) ){ sqlite3_free(zConverted); + sqlite3_free(zTmpname); OSTRACE(("OPEN name=%s, rc=SQLITE_CANTOPEN_ISDIR", zUtf8Name)); return SQLITE_CANTOPEN_ISDIR; } @@ -4173,7 +4254,7 @@ static int winOpen( dwFlagsAndAttributes |= FILE_FLAG_RANDOM_ACCESS; #endif - if( isNT() ){ + if( osIsNT() ){ #if SQLITE_OS_WINRT CREATEFILE2_EXTENDED_PARAMETERS extendedParameters; extendedParameters.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS); @@ -4188,7 +4269,7 @@ static int winOpen( dwShareMode, dwCreationDisposition, &extendedParameters))==INVALID_HANDLE_VALUE && - retryIoerr(&cnt, &lastErrno) ){ + winRetryIoerr(&cnt, &lastErrno) ){ /* Noop */ } #else @@ -4198,7 +4279,7 @@ static int winOpen( dwCreationDisposition, dwFlagsAndAttributes, NULL))==INVALID_HANDLE_VALUE && - retryIoerr(&cnt, &lastErrno) ){ + winRetryIoerr(&cnt, &lastErrno) ){ /* Noop */ } #endif @@ -4211,12 +4292,12 @@ static int winOpen( dwCreationDisposition, dwFlagsAndAttributes, NULL))==INVALID_HANDLE_VALUE && - retryIoerr(&cnt, &lastErrno) ){ + winRetryIoerr(&cnt, &lastErrno) ){ /* Noop */ } } #endif - logIoerr(cnt); + winLogIoerr(cnt); OSTRACE(("OPEN file=%p, name=%s, access=%lx, rc=%s\n", h, zUtf8Name, dwDesiredAccess, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok")); @@ -4225,6 +4306,7 @@ static int winOpen( pFile->lastErrno = lastErrno; winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name); sqlite3_free(zConverted); + sqlite3_free(zTmpname); if( isReadWrite && !isExclusive ){ return winOpen(pVfs, zName, id, ((flags|SQLITE_OPEN_READONLY) & @@ -4253,6 +4335,7 @@ static int winOpen( ){ osCloseHandle(h); sqlite3_free(zConverted); + sqlite3_free(zTmpname); OSTRACE(("OPEN-CE-LOCK name=%s, rc=%s\n", zName, sqlite3ErrName(rc))); return rc; } @@ -4262,6 +4345,7 @@ static int winOpen( #endif { sqlite3_free(zConverted); + sqlite3_free(zTmpname); } pFile->pMethod = &winIoMethod; @@ -4315,11 +4399,12 @@ static int winDelete( SimulateIOError(return SQLITE_IOERR_DELETE); OSTRACE(("DELETE name=%s, syncDir=%d\n", zFilename, syncDir)); - zConverted = convertUtf8Filename(zFilename); + zConverted = winConvertUtf8Filename(zFilename); if( zConverted==0 ){ + OSTRACE(("DELETE name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename)); return SQLITE_IOERR_NOMEM; } - if( isNT() ){ + if( osIsNT() ){ do { #if SQLITE_OS_WINRT WIN32_FILE_ATTRIBUTE_DATA sAttrData; @@ -4358,7 +4443,7 @@ static int winDelete( rc = SQLITE_OK; /* Deleted OK. */ break; } - if ( !retryIoerr(&cnt, &lastErrno) ){ + if ( !winRetryIoerr(&cnt, &lastErrno) ){ rc = SQLITE_ERROR; /* No more retries. */ break; } @@ -4386,7 +4471,7 @@ static int winDelete( rc = SQLITE_OK; /* Deleted OK. */ break; } - if ( !retryIoerr(&cnt, &lastErrno) ){ + if ( !winRetryIoerr(&cnt, &lastErrno) ){ rc = SQLITE_ERROR; /* No more retries. */ break; } @@ -4397,7 +4482,7 @@ static int winDelete( rc = winLogError(SQLITE_IOERR_DELETE, lastErrno, "winDelete", zFilename); }else{ - logIoerr(cnt); + winLogIoerr(cnt); } sqlite3_free(zConverted); OSTRACE(("DELETE name=%s, rc=%s\n", zFilename, sqlite3ErrName(rc))); @@ -4423,18 +4508,18 @@ static int winAccess( OSTRACE(("ACCESS name=%s, flags=%x, pResOut=%p\n", zFilename, flags, pResOut)); - zConverted = convertUtf8Filename(zFilename); + zConverted = winConvertUtf8Filename(zFilename); if( zConverted==0 ){ OSTRACE(("ACCESS name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename)); return SQLITE_IOERR_NOMEM; } - if( isNT() ){ + if( osIsNT() ){ int cnt = 0; WIN32_FILE_ATTRIBUTE_DATA sAttrData; memset(&sAttrData, 0, sizeof(sAttrData)); while( !(rc = osGetFileAttributesExW((LPCWSTR)zConverted, GetFileExInfoStandard, - &sAttrData)) && retryIoerr(&cnt, &lastErrno) ){} + &sAttrData)) && winRetryIoerr(&cnt, &lastErrno) ){} if( rc ){ /* For an SQLITE_ACCESS_EXISTS query, treat a zero-length file ** as if it does not exist. @@ -4447,7 +4532,7 @@ static int winAccess( attr = sAttrData.dwFileAttributes; } }else{ - logIoerr(cnt); + winLogIoerr(cnt); if( lastErrno!=ERROR_FILE_NOT_FOUND && lastErrno!=ERROR_PATH_NOT_FOUND ){ winLogError(SQLITE_IOERR_ACCESS, lastErrno, "winAccess", zFilename); sqlite3_free(zConverted); @@ -4498,7 +4583,7 @@ static BOOL winIsVerbatimPathname( ** the final two cases; therefore, we return the safer return value of TRUE ** so that callers of this function will simply use it verbatim. */ - if ( zPathname[0]=='/' || zPathname[0]=='\\' ){ + if ( winIsDirSep(zPathname[0]) ){ return TRUE; } @@ -4534,7 +4619,6 @@ static int winFullPathname( #if defined(__CYGWIN__) SimulateIOError( return SQLITE_ERROR ); UNUSED_PARAMETER(nFull); - assert( pVfs->mxPathname>=SQLITE_WIN32_MAX_PATH ); assert( nFull>=pVfs->mxPathname ); if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){ /* @@ -4543,15 +4627,21 @@ static int winFullPathname( ** for converting the relative path name to an absolute ** one by prepending the data directory and a slash. */ - char zOut[SQLITE_WIN32_MAX_PATH+1]; + char *zOut = sqlite3MallocZero( pVfs->mxPathname+1 ); + if( !zOut ){ + winLogError(SQLITE_IOERR_NOMEM, 0, "winFullPathname", zRelative); + return SQLITE_IOERR_NOMEM; + } if( cygwin_conv_path(CCP_POSIX_TO_WIN_A|CCP_RELATIVE, zRelative, zOut, - SQLITE_WIN32_MAX_PATH+1)<0 ){ + pVfs->mxPathname+1)<0 ){ winLogError(SQLITE_CANTOPEN_FULLPATH, (DWORD)errno, "cygwin_conv_path", zRelative); + sqlite3_free(zOut); return SQLITE_CANTOPEN_FULLPATH; } - sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s\\%s", - sqlite3_data_directory, zOut); + sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s%s%s", + sqlite3_data_directory, winGetDirDep(), zOut); + sqlite3_free(zOut); }else{ if( cygwin_conv_path(CCP_POSIX_TO_WIN_A, zRelative, zFull, nFull)<0 ){ winLogError(SQLITE_CANTOPEN_FULLPATH, (DWORD)errno, "cygwin_conv_path", @@ -4573,8 +4663,8 @@ static int winFullPathname( ** for converting the relative path name to an absolute ** one by prepending the data directory and a backslash. */ - sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s\\%s", - sqlite3_data_directory, zRelative); + sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s%s%s", + sqlite3_data_directory, winGetDirDep(), zRelative); }else{ sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zRelative); } @@ -4606,15 +4696,15 @@ static int winFullPathname( ** for converting the relative path name to an absolute ** one by prepending the data directory and a backslash. */ - sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s\\%s", - sqlite3_data_directory, zRelative); + sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s%s%s", + sqlite3_data_directory, winGetDirDep(), zRelative); return SQLITE_OK; } - zConverted = convertUtf8Filename(zRelative); + zConverted = winConvertUtf8Filename(zRelative); if( zConverted==0 ){ return SQLITE_IOERR_NOMEM; } - if( isNT() ){ + if( osIsNT() ){ LPWSTR zTemp; nByte = osGetFullPathNameW((LPCWSTR)zConverted, 0, 0, 0); if( nByte==0 ){ @@ -4638,7 +4728,7 @@ static int winFullPathname( return SQLITE_CANTOPEN_FULLPATH; } sqlite3_free(zConverted); - zOut = unicodeToUtf8(zTemp); + zOut = winUnicodeToUtf8(zTemp); sqlite3_free(zTemp); } #ifdef SQLITE_WIN32_HAS_ANSI @@ -4691,12 +4781,12 @@ static int winFullPathname( */ static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){ HANDLE h; - void *zConverted = convertUtf8Filename(zFilename); + void *zConverted = winConvertUtf8Filename(zFilename); UNUSED_PARAMETER(pVfs); if( zConverted==0 ){ return 0; } - if( isNT() ){ + if( osIsNT() ){ #if SQLITE_OS_WINRT h = osLoadPackagedLibrary((LPCWSTR)zConverted, 0); #else @@ -4713,7 +4803,7 @@ static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){ } static void winDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){ UNUSED_PARAMETER(pVfs); - getLastErrorMsg(osGetLastError(), nBuf, zBufOut); + winGetLastErrorMsg(osGetLastError(), nBuf, zBufOut); } static void (*winDlSym(sqlite3_vfs *pVfs,void *pH,const char *zSym))(void){ UNUSED_PARAMETER(pVfs); @@ -4889,7 +4979,7 @@ static int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){ */ static int winGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ UNUSED_PARAMETER(pVfs); - return getLastErrorMsg(osGetLastError(), nBuf, zBuf); + return winGetLastErrorMsg(osGetLastError(), nBuf, zBuf); } /* @@ -4899,7 +4989,7 @@ int sqlite3_os_init(void){ static sqlite3_vfs winVfs = { 3, /* iVersion */ sizeof(winFile), /* szOsFile */ - SQLITE_WIN32_MAX_PATH, /* mxPathname */ + SQLITE_WIN32_MAX_PATH_BYTES, /* mxPathname */ 0, /* pNext */ "win32", /* zName */ 0, /* pAppData */ @@ -4920,6 +5010,32 @@ int sqlite3_os_init(void){ winGetSystemCall, /* xGetSystemCall */ winNextSystemCall, /* xNextSystemCall */ }; +#if defined(SQLITE_WIN32_HAS_WIDE) + static sqlite3_vfs winLongPathVfs = { + 3, /* iVersion */ + sizeof(winFile), /* szOsFile */ + SQLITE_WINNT_MAX_PATH_BYTES, /* mxPathname */ + 0, /* pNext */ + "win32-longpath", /* zName */ + 0, /* pAppData */ + winOpen, /* xOpen */ + winDelete, /* xDelete */ + winAccess, /* xAccess */ + winFullPathname, /* xFullPathname */ + winDlOpen, /* xDlOpen */ + winDlError, /* xDlError */ + winDlSym, /* xDlSym */ + winDlClose, /* xDlClose */ + winRandomness, /* xRandomness */ + winSleep, /* xSleep */ + winCurrentTime, /* xCurrentTime */ + winGetLastError, /* xGetLastError */ + winCurrentTimeInt64, /* xCurrentTimeInt64 */ + winSetSystemCall, /* xSetSystemCall */ + winGetSystemCall, /* xGetSystemCall */ + winNextSystemCall, /* xNextSystemCall */ + }; +#endif /* Double-check that the aSyscall[] array has been constructed ** correctly. See ticket [bb3a86e890c8e96ab] */ @@ -4936,6 +5052,11 @@ int sqlite3_os_init(void){ assert( winSysInfo.dwPageSize>0 ); sqlite3_vfs_register(&winVfs, 1); + +#if defined(SQLITE_WIN32_HAS_WIDE) + sqlite3_vfs_register(&winLongPathVfs, 0); +#endif + return SQLITE_OK; } |