From 91601deb844848dc02959679fd41e1441a76aff4 Mon Sep 17 00:00:00 2001 From: Aaron Seigo Date: Sun, 14 Dec 2014 12:30:27 +0100 Subject: the all-in-one-file version of unqlite --- common/unqlite/os_win.c | 940 ------------------------------------------------ 1 file changed, 940 deletions(-) delete mode 100644 common/unqlite/os_win.c (limited to 'common/unqlite/os_win.c') diff --git a/common/unqlite/os_win.c b/common/unqlite/os_win.c deleted file mode 100644 index c1e0821..0000000 --- a/common/unqlite/os_win.c +++ /dev/null @@ -1,940 +0,0 @@ -/* - * Symisc unQLite: An Embeddable NoSQL (Post Modern) Database Engine. - * Copyright (C) 2012-2013, Symisc Systems http://unqlite.org/ - * Version 1.1.6 - * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES - * please contact Symisc Systems via: - * legal@symisc.net - * licensing@symisc.net - * contact@symisc.net - * or visit: - * http://unqlite.org/licensing.html - */ - /* $SymiscID: os_win.c v1.2 Win7 2012-11-10 12:10 devel $ */ -#ifndef UNQLITE_AMALGAMATION -#include "unqliteInt.h" -#endif -/* Omit the whole layer from the build if compiling for platforms other than Windows */ -#ifdef __WINNT__ -/* This file contains code that is specific to windows. (Mostly SQLite3 source tree) */ -#include -/* -** Some microsoft compilers lack this definition. -*/ -#ifndef INVALID_FILE_ATTRIBUTES -# define INVALID_FILE_ATTRIBUTES ((DWORD)-1) -#endif -/* -** WinCE lacks native support for file locking so we have to fake it -** with some code of our own. -*/ -#ifdef __WIN_CE__ -typedef struct winceLock { - int nReaders; /* Number of reader locks obtained */ - BOOL bPending; /* Indicates a pending lock has been obtained */ - BOOL bReserved; /* Indicates a reserved lock has been obtained */ - BOOL bExclusive; /* Indicates an exclusive lock has been obtained */ -} winceLock; -#define AreFileApisANSI() 1 -#define FormatMessageW(a,b,c,d,e,f,g) 0 -#endif - -/* -** The winFile structure is a subclass of unqlite_file* specific to the win32 -** portability layer. -*/ -typedef struct winFile winFile; -struct winFile { - const unqlite_io_methods *pMethod; /*** Must be first ***/ - unqlite_vfs *pVfs; /* The VFS used to open this file */ - HANDLE h; /* Handle for accessing the file */ - sxu8 locktype; /* Type of lock currently held on this file */ - short sharedLockByte; /* Randomly chosen byte used as a shared lock */ - DWORD lastErrno; /* The Windows errno from the last I/O error */ - DWORD sectorSize; /* Sector size of the device file is on */ - int szChunk; /* Chunk size */ -#ifdef __WIN_CE__ - WCHAR *zDeleteOnClose; /* Name of file to delete when closing */ - HANDLE hMutex; /* Mutex used to control access to shared lock */ - HANDLE hShared; /* Shared memory segment used for locking */ - winceLock local; /* Locks obtained by this instance of winFile */ - winceLock *shared; /* Global shared lock memory for the file */ -#endif -}; -/* -** Convert a UTF-8 string to microsoft unicode (UTF-16?). -** -** Space to hold the returned string is obtained from HeapAlloc(). -*/ -static WCHAR *utf8ToUnicode(const char *zFilename){ - int nChar; - WCHAR *zWideFilename; - - nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, 0, 0); - zWideFilename = (WCHAR *)HeapAlloc(GetProcessHeap(),0,nChar*sizeof(zWideFilename[0]) ); - if( zWideFilename==0 ){ - return 0; - } - nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename, nChar); - if( nChar==0 ){ - HeapFree(GetProcessHeap(),0,zWideFilename); - zWideFilename = 0; - } - return zWideFilename; -} - -/* -** Convert microsoft unicode to UTF-8. Space to hold the returned string is -** obtained from malloc(). -*/ -static char *unicodeToUtf8(const WCHAR *zWideFilename){ - int nByte; - char *zFilename; - - nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, 0, 0, 0, 0); - zFilename = (char *)HeapAlloc(GetProcessHeap(),0,nByte ); - if( zFilename==0 ){ - return 0; - } - nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, zFilename, nByte, - 0, 0); - if( nByte == 0 ){ - HeapFree(GetProcessHeap(),0,zFilename); - zFilename = 0; - } - return zFilename; -} - -/* -** Convert an ansi string to microsoft unicode, based on the -** current codepage settings for file apis. -** -** Space to hold the returned string is obtained -** from malloc. -*/ -static WCHAR *mbcsToUnicode(const char *zFilename){ - int nByte; - WCHAR *zMbcsFilename; - int codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP; - - nByte = MultiByteToWideChar(codepage, 0, zFilename, -1, 0,0)*sizeof(WCHAR); - zMbcsFilename = (WCHAR *)HeapAlloc(GetProcessHeap(),0,nByte*sizeof(zMbcsFilename[0]) ); - if( zMbcsFilename==0 ){ - return 0; - } - nByte = MultiByteToWideChar(codepage, 0, zFilename, -1, zMbcsFilename, nByte); - if( nByte==0 ){ - HeapFree(GetProcessHeap(),0,zMbcsFilename); - zMbcsFilename = 0; - } - return zMbcsFilename; -} -/* -** Convert multibyte character string to UTF-8. Space to hold the -** returned string is obtained from malloc(). -*/ -char *unqlite_win32_mbcs_to_utf8(const char *zFilename){ - char *zFilenameUtf8; - WCHAR *zTmpWide; - - zTmpWide = mbcsToUnicode(zFilename); - if( zTmpWide==0 ){ - return 0; - } - zFilenameUtf8 = unicodeToUtf8(zTmpWide); - HeapFree(GetProcessHeap(),0,zTmpWide); - return zFilenameUtf8; -} -/* -** Some microsoft compilers lack this definition. -*/ -#ifndef INVALID_SET_FILE_POINTER -# define INVALID_SET_FILE_POINTER ((DWORD)-1) -#endif - -/* -** Move the current position of the file handle passed as the first -** argument to offset iOffset within the file. If successful, return 0. -** Otherwise, set pFile->lastErrno and return non-zero. -*/ -static int seekWinFile(winFile *pFile, unqlite_int64 iOffset){ - LONG upperBits; /* Most sig. 32 bits of new offset */ - LONG lowerBits; /* Least sig. 32 bits of new offset */ - DWORD dwRet; /* Value returned by SetFilePointer() */ - - upperBits = (LONG)((iOffset>>32) & 0x7fffffff); - lowerBits = (LONG)(iOffset & 0xffffffff); - - /* API oddity: If successful, SetFilePointer() returns a dword - ** containing the lower 32-bits of the new file-offset. Or, if it fails, - ** it returns INVALID_SET_FILE_POINTER. However according to MSDN, - ** INVALID_SET_FILE_POINTER may also be a valid new offset. So to determine - ** whether an error has actually occured, it is also necessary to call - ** GetLastError(). - */ - dwRet = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN); - if( (dwRet==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR) ){ - pFile->lastErrno = GetLastError(); - return 1; - } - return 0; -} -/* -** Close a file. -** -** It is reported that an attempt to close a handle might sometimes -** fail. This is a very unreasonable result, but windows is notorious -** for being unreasonable so I do not doubt that it might happen. If -** the close fails, we pause for 100 milliseconds and try again. As -** many as MX_CLOSE_ATTEMPT attempts to close the handle are made before -** giving up and returning an error. -*/ -#define MX_CLOSE_ATTEMPT 3 -static int winClose(unqlite_file *id) -{ - int rc, cnt = 0; - winFile *pFile = (winFile*)id; - do{ - rc = CloseHandle(pFile->h); - }while( rc==0 && ++cnt < MX_CLOSE_ATTEMPT && (Sleep(100), 1) ); - - return rc ? UNQLITE_OK : UNQLITE_IOERR; -} -/* -** Read data from a file into a buffer. Return UNQLITE_OK if all -** bytes were read successfully and UNQLITE_IOERR if anything goes -** wrong. -*/ -static int winRead( - unqlite_file *id, /* File to read from */ - void *pBuf, /* Write content into this buffer */ - unqlite_int64 amt, /* Number of bytes to read */ - unqlite_int64 offset /* Begin reading at this offset */ -){ - winFile *pFile = (winFile*)id; /* file handle */ - DWORD nRead; /* Number of bytes actually read from file */ - - if( seekWinFile(pFile, offset) ){ - return UNQLITE_FULL; - } - if( !ReadFile(pFile->h, pBuf, (DWORD)amt, &nRead, 0) ){ - pFile->lastErrno = GetLastError(); - return UNQLITE_IOERR; - } - if( nRead<(DWORD)amt ){ - /* Unread parts of the buffer must be zero-filled */ - SyZero(&((char*)pBuf)[nRead],(sxu32)(amt-nRead)); - return UNQLITE_IOERR; - } - - return UNQLITE_OK; -} - -/* -** Write data from a buffer into a file. Return UNQLITE_OK on success -** or some other error code on failure. -*/ -static int winWrite( - unqlite_file *id, /* File to write into */ - const void *pBuf, /* The bytes to be written */ - unqlite_int64 amt, /* Number of bytes to write */ - unqlite_int64 offset /* Offset into the file to begin writing at */ -){ - int rc; /* True if error has occured, else false */ - winFile *pFile = (winFile*)id; /* File handle */ - - rc = seekWinFile(pFile, offset); - if( rc==0 ){ - sxu8 *aRem = (sxu8 *)pBuf; /* Data yet to be written */ - unqlite_int64 nRem = amt; /* Number of bytes yet to be written */ - DWORD nWrite; /* Bytes written by each WriteFile() call */ - - while( nRem>0 && WriteFile(pFile->h, aRem, (DWORD)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 UNQLITE_FULL; - } - return UNQLITE_IOERR; - } - return UNQLITE_OK; -} - -/* -** Truncate an open file to a specified size -*/ -static int winTruncate(unqlite_file *id, unqlite_int64 nByte){ - winFile *pFile = (winFile*)id; /* File handle object */ - int rc = UNQLITE_OK; /* Return code for this function */ - - - /* If the user has configured a chunk-size for this file, truncate the - ** file so that it consists of an integer number of chunks (i.e. the - ** actual file size after the operation may be larger than the requested - ** size). - */ - if( pFile->szChunk ){ - nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk; - } - - /* SetEndOfFile() returns non-zero when successful, or zero when it fails. */ - if( seekWinFile(pFile, nByte) ){ - rc = UNQLITE_IOERR; - }else if( 0==SetEndOfFile(pFile->h) ){ - pFile->lastErrno = GetLastError(); - rc = UNQLITE_IOERR; - } - return rc; -} -/* -** Make sure all writes to a particular file are committed to disk. -*/ -static int winSync(unqlite_file *id, int flags){ - winFile *pFile = (winFile*)id; - SXUNUSED(flags); /* MSVC warning */ - if( FlushFileBuffers(pFile->h) ){ - return UNQLITE_OK; - }else{ - pFile->lastErrno = GetLastError(); - return UNQLITE_IOERR; - } -} -/* -** Determine the current size of a file in bytes -*/ -static int winFileSize(unqlite_file *id, unqlite_int64 *pSize){ - DWORD upperBits; - DWORD lowerBits; - winFile *pFile = (winFile*)id; - DWORD error; - lowerBits = GetFileSize(pFile->h, &upperBits); - if( (lowerBits == INVALID_FILE_SIZE) - && ((error = GetLastError()) != NO_ERROR) ) - { - pFile->lastErrno = error; - return UNQLITE_IOERR; - } - *pSize = (((unqlite_int64)upperBits)<<32) + lowerBits; - return UNQLITE_OK; -} -/* -** LOCKFILE_FAIL_IMMEDIATELY is undefined on some Windows systems. -*/ -#ifndef LOCKFILE_FAIL_IMMEDIATELY -# define LOCKFILE_FAIL_IMMEDIATELY 1 -#endif - -/* -** Acquire a reader lock. -*/ -static int getReadLock(winFile *pFile){ - int res; - 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( res == 0 ){ - pFile->lastErrno = GetLastError(); - } - return res; -} -/* -** Undo a readlock -*/ -static int unlockReadLock(winFile *pFile){ - int res; - res = UnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); - if( res == 0 ){ - pFile->lastErrno = GetLastError(); - } - return res; -} -/* -** Lock the file with the lock specified by parameter locktype - one -** of the following: -** -** (1) SHARED_LOCK -** (2) RESERVED_LOCK -** (3) PENDING_LOCK -** (4) EXCLUSIVE_LOCK -** -** Sometimes when requesting one lock state, additional lock states -** are inserted in between. The locking might fail on one of the later -** transitions leaving the lock state different from what it started but -** still short of its goal. The following chart shows the allowed -** transitions and the inserted intermediate states: -** -** UNLOCKED -> SHARED -** SHARED -> RESERVED -** SHARED -> (PENDING) -> EXCLUSIVE -** RESERVED -> (PENDING) -> EXCLUSIVE -** PENDING -> EXCLUSIVE -** -** This routine will only increase a lock. The winUnlock() routine -** erases all locks at once and returns us immediately to locking level 0. -** 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(unqlite_file *id, int locktype){ - int rc = UNQLITE_OK; /* Return code from subroutines */ - int res = 1; /* Result of a windows lock call */ - 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; - DWORD error = NO_ERROR; - - /* If there is already a lock of this type or more restrictive on the - ** OsFile, do nothing. - */ - if( pFile->locktype>=locktype ){ - return UNQLITE_OK; - } - - /* Make sure the locking sequence is correct - assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK ); - assert( locktype!=PENDING_LOCK ); - assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK ); - */ - /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or - ** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of - ** the PENDING_LOCK byte is temporary. - */ - 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 ){ - /* Try 3 times to get the pending lock. The pending lock might be - ** held by another reader process who will release it momentarily. - */ - Sleep(1); - } - gotPendingLock = res; - if( !res ){ - error = GetLastError(); - } - } - - /* Acquire a shared lock - */ - if( locktype==SHARED_LOCK && res ){ - /* assert( pFile->locktype==NO_LOCK ); */ - res = getReadLock(pFile); - if( res ){ - newLocktype = SHARED_LOCK; - }else{ - error = GetLastError(); - } - } - - /* Acquire a RESERVED lock - */ - 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(); - } - } - - /* Acquire a PENDING lock - */ - if( locktype==EXCLUSIVE_LOCK && res ){ - newLocktype = PENDING_LOCK; - gotPendingLock = 0; - } - - /* Acquire an EXCLUSIVE lock - */ - if( locktype==EXCLUSIVE_LOCK && res ){ - /* assert( pFile->locktype>=SHARED_LOCK ); */ - res = unlockReadLock(pFile); - res = LockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); - if( res ){ - newLocktype = EXCLUSIVE_LOCK; - }else{ - error = GetLastError(); - getReadLock(pFile); - } - } - - /* If we are holding a PENDING lock that ought to be released, then - ** release it now. - */ - if( gotPendingLock && locktype==SHARED_LOCK ){ - UnlockFile(pFile->h, PENDING_BYTE, 0, 1, 0); - } - - /* Update the state of the lock has held in the file descriptor then - ** return the appropriate result code. - */ - if( res ){ - rc = UNQLITE_OK; - }else{ - pFile->lastErrno = error; - rc = UNQLITE_BUSY; - } - pFile->locktype = (sxu8)newLocktype; - return rc; -} -/* -** This routine checks if there is a RESERVED lock held on the specified -** file by this or any other process. If such a lock is held, return -** non-zero, otherwise zero. -*/ -static int winCheckReservedLock(unqlite_file *id, int *pResOut){ - int rc; - winFile *pFile = (winFile*)id; - if( pFile->locktype>=RESERVED_LOCK ){ - rc = 1; - }else{ - rc = LockFile(pFile->h, RESERVED_BYTE, 0, 1, 0); - if( rc ){ - UnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0); - } - rc = !rc; - } - *pResOut = rc; - return UNQLITE_OK; -} -/* -** Lower the locking level on file descriptor id to locktype. locktype -** must be either NO_LOCK or SHARED_LOCK. -** -** If the locking level of the file descriptor is already at or below -** the requested locking level, this routine is a no-op. -** -** It is not possible for this routine to fail if the second argument -** is NO_LOCK. If the second argument is SHARED_LOCK then this routine -** might return UNQLITE_IOERR; -*/ -static int winUnlock(unqlite_file *id, int locktype){ - int type; - winFile *pFile = (winFile*)id; - int rc = UNQLITE_OK; - - type = pFile->locktype; - if( type>=EXCLUSIVE_LOCK ){ - UnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); - if( locktype==SHARED_LOCK && !getReadLock(pFile) ){ - /* This should never happen. We should always be able to - ** reacquire the read lock */ - rc = UNQLITE_IOERR; - } - } - 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 = (sxu8)locktype; - return rc; -} -/* -** Return the sector size in bytes of the underlying block device for -** the specified file. This is almost always 512 bytes, but may be -** larger for some devices. -** -*/ -static int winSectorSize(unqlite_file *id){ - return (int)(((winFile*)id)->sectorSize); -} -/* -** This vector defines all the methods that can operate on an -** unqlite_file for Windows systems. -*/ -static const unqlite_io_methods winIoMethod = { - 1, /* iVersion */ - winClose, /* xClose */ - winRead, /* xRead */ - winWrite, /* xWrite */ - winTruncate, /* xTruncate */ - winSync, /* xSync */ - winFileSize, /* xFileSize */ - winLock, /* xLock */ - winUnlock, /* xUnlock */ - winCheckReservedLock, /* xCheckReservedLock */ - winSectorSize, /* xSectorSize */ -}; -/* - * Windows VFS Methods. - */ -/* -** Convert a UTF-8 filename into whatever form the underlying -** operating system wants filenames in. Space to hold the result -** is obtained from malloc and must be freed by the calling -** function. -*/ -static void *convertUtf8Filename(const char *zFilename) -{ - void *zConverted; - zConverted = utf8ToUnicode(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 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 5 -static int winDelete( - unqlite_vfs *pVfs, /* Not used on win32 */ - const char *zFilename, /* Name of file to delete */ - int syncDir /* Not used on win32 */ -){ - int cnt = 0; - DWORD rc; - DWORD error = 0; - void *zConverted; - zConverted = convertUtf8Filename(zFilename); - if( zConverted==0 ){ - SXUNUSED(pVfs); - SXUNUSED(syncDir); - return UNQLITE_NOMEM; - } - do{ - DeleteFileW((LPCWSTR)zConverted); - }while( ( ((rc = GetFileAttributesW((LPCWSTR)zConverted)) != INVALID_FILE_ATTRIBUTES) - || ((error = GetLastError()) == ERROR_ACCESS_DENIED)) - && (++cnt < MX_DELETION_ATTEMPTS) - && (Sleep(100), 1) - ); - HeapFree(GetProcessHeap(),0,zConverted); - - return ( (rc == INVALID_FILE_ATTRIBUTES) - && (error == ERROR_FILE_NOT_FOUND)) ? UNQLITE_OK : UNQLITE_IOERR; -} -/* -** Check the existance and status of a file. -*/ -static int winAccess( - unqlite_vfs *pVfs, /* Not used */ - const char *zFilename, /* Name of file to check */ - int flags, /* Type of test to make on this file */ - int *pResOut /* OUT: Result */ -){ - WIN32_FILE_ATTRIBUTE_DATA sAttrData; - DWORD attr; - int rc = 0; - void *zConverted; - SXUNUSED(pVfs); - - zConverted = convertUtf8Filename(zFilename); - if( zConverted==0 ){ - return UNQLITE_NOMEM; - } - SyZero(&sAttrData,sizeof(sAttrData)); - if( GetFileAttributesExW((WCHAR*)zConverted, - GetFileExInfoStandard, - &sAttrData) ){ - /* For an UNQLITE_ACCESS_EXISTS query, treat a zero-length file - ** as if it does not exist. - */ - if( flags==UNQLITE_ACCESS_EXISTS - && sAttrData.nFileSizeHigh==0 - && sAttrData.nFileSizeLow==0 ){ - attr = INVALID_FILE_ATTRIBUTES; - }else{ - attr = sAttrData.dwFileAttributes; - } - }else{ - if( GetLastError()!=ERROR_FILE_NOT_FOUND ){ - HeapFree(GetProcessHeap(),0,zConverted); - return UNQLITE_IOERR; - }else{ - attr = INVALID_FILE_ATTRIBUTES; - } - } - HeapFree(GetProcessHeap(),0,zConverted); - switch( flags ){ - case UNQLITE_ACCESS_READWRITE: - rc = (attr & FILE_ATTRIBUTE_READONLY)==0; - break; - case UNQLITE_ACCESS_READ: - case UNQLITE_ACCESS_EXISTS: - default: - rc = attr!=INVALID_FILE_ATTRIBUTES; - break; - } - *pResOut = rc; - return UNQLITE_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( - unqlite_vfs *pVfs, /* Pointer to vfs object */ - const char *zRelative, /* Possibly relative input path */ - int nFull, /* Size of output buffer in bytes */ - char *zFull /* Output buffer */ -){ - int nByte; - void *zConverted; - WCHAR *zTemp; - char *zOut; - SXUNUSED(nFull); - zConverted = convertUtf8Filename(zRelative); - if( zConverted == 0 ){ - return UNQLITE_NOMEM; - } - nByte = GetFullPathNameW((WCHAR*)zConverted, 0, 0, 0) + 3; - zTemp = (WCHAR *)HeapAlloc(GetProcessHeap(),0,nByte*sizeof(zTemp[0]) ); - if( zTemp==0 ){ - HeapFree(GetProcessHeap(),0,zConverted); - return UNQLITE_NOMEM; - } - GetFullPathNameW((WCHAR*)zConverted, nByte, zTemp, 0); - HeapFree(GetProcessHeap(),0,zConverted); - zOut = unicodeToUtf8(zTemp); - HeapFree(GetProcessHeap(),0,zTemp); - if( zOut == 0 ){ - return UNQLITE_NOMEM; - } - Systrcpy(zFull,(sxu32)pVfs->mxPathname,zOut,0); - HeapFree(GetProcessHeap(),0,zOut); - return UNQLITE_OK; -} -/* -** Get the sector size of the device used to store -** file. -*/ -static int getSectorSize( - unqlite_vfs *pVfs, - const char *zRelative /* UTF-8 file name */ -){ - DWORD bytesPerSector = UNQLITE_DEFAULT_SECTOR_SIZE; - char zFullpath[MAX_PATH+1]; - int rc; - DWORD dwRet = 0; - DWORD dwDummy; - /* - ** We need to get the full path name of the file - ** to get the drive letter to look up the sector - ** size. - */ - rc = winFullPathname(pVfs, zRelative, MAX_PATH, zFullpath); - if( rc == UNQLITE_OK ) - { - void *zConverted = convertUtf8Filename(zFullpath); - if( zConverted ){ - /* trim path to just drive reference */ - WCHAR *p = (WCHAR *)zConverted; - for(;*p;p++){ - if( *p == '\\' ){ - *p = '\0'; - break; - } - } - dwRet = GetDiskFreeSpaceW((WCHAR*)zConverted, - &dwDummy, - &bytesPerSector, - &dwDummy, - &dwDummy); - HeapFree(GetProcessHeap(),0,zConverted); - } - if( !dwRet ){ - bytesPerSector = UNQLITE_DEFAULT_SECTOR_SIZE; - } - } - return (int) bytesPerSector; -} -/* -** Sleep for a little while. Return the amount of time slept. -*/ -static int winSleep(unqlite_vfs *pVfs, int microsec){ - Sleep((microsec+999)/1000); - SXUNUSED(pVfs); - return ((microsec+999)/1000)*1000; -} -/* - * Export the current system time. - */ -static int winCurrentTime(unqlite_vfs *pVfs,Sytm *pOut) -{ - SYSTEMTIME sSys; - SXUNUSED(pVfs); - GetSystemTime(&sSys); - SYSTEMTIME_TO_SYTM(&sSys,pOut); - return UNQLITE_OK; -} -/* -** The idea is that this function works like a combination of -** GetLastError() and FormatMessage() on windows (or errno and -** strerror_r() on unix). After an error is returned by an OS -** function, UnQLite calls this function with zBuf pointing to -** a buffer of nBuf bytes. The OS layer should populate the -** buffer with a nul-terminated UTF-8 encoded error message -** describing the last IO error to have occurred within the calling -** thread. -** -** If the error message is too large for the supplied buffer, -** it should be truncated. The return value of xGetLastError -** is zero if the error message fits in the buffer, or non-zero -** otherwise (if the message was truncated). If non-zero is returned, -** then it is not necessary to include the nul-terminator character -** in the output buffer. -*/ -static int winGetLastError(unqlite_vfs *pVfs, 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. - */ - DWORD error = GetLastError(); - WCHAR *zTempWide = 0; - DWORD dwLen; - char *zOut = 0; - - SXUNUSED(pVfs); - dwLen = FormatMessageW( - FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - 0, - error, - 0, - (LPWSTR) &zTempWide, - 0, - 0 - ); - if( dwLen > 0 ){ - /* allocate a buffer and convert to UTF8 */ - zOut = unicodeToUtf8(zTempWide); - /* free the system buffer allocated by FormatMessage */ - LocalFree(zTempWide); - } - if( 0 == dwLen ){ - Systrcpy(zBuf,(sxu32)nBuf,"OS Error",sizeof("OS Error")-1); - }else{ - /* copy a maximum of nBuf chars to output buffer */ - Systrcpy(zBuf,(sxu32)nBuf,zOut,0 /* Compute input length automatically */); - /* free the UTF8 buffer */ - HeapFree(GetProcessHeap(),0,zOut); - } - return 0; -} -/* -** Open a file. -*/ -static int winOpen( - unqlite_vfs *pVfs, /* Not used */ - const char *zName, /* Name of the file (UTF-8) */ - unqlite_file *id, /* Write the UnQLite file handle here */ - unsigned int flags /* Open mode flags */ -){ - HANDLE h; - DWORD dwDesiredAccess; - DWORD dwShareMode; - DWORD dwCreationDisposition; - DWORD dwFlagsAndAttributes = 0; - winFile *pFile = (winFile*)id; - void *zConverted; /* Filename in OS encoding */ - const char *zUtf8Name = zName; /* Filename in UTF-8 encoding */ - int isExclusive = (flags & UNQLITE_OPEN_EXCLUSIVE); - int isDelete = (flags & UNQLITE_OPEN_TEMP_DB); - int isCreate = (flags & UNQLITE_OPEN_CREATE); - int isReadWrite = (flags & UNQLITE_OPEN_READWRITE); - - pFile->h = INVALID_HANDLE_VALUE; - /* Convert the filename to the system encoding. */ - zConverted = convertUtf8Filename(zUtf8Name); - if( zConverted==0 ){ - return UNQLITE_NOMEM; - } - if( isReadWrite ){ - dwDesiredAccess = GENERIC_READ | GENERIC_WRITE; - }else{ - dwDesiredAccess = GENERIC_READ; - } - /* UNQLITE_OPEN_EXCLUSIVE is used to make sure that a new file is - ** created. - */ - if( isExclusive ){ - /* Creates a new file, only if it does not already exist. */ - /* If the file exists, it fails. */ - dwCreationDisposition = CREATE_NEW; - }else if( isCreate ){ - /* Open existing file, or create if it doesn't exist */ - dwCreationDisposition = OPEN_ALWAYS; - }else{ - /* Opens a file, only if it exists. */ - dwCreationDisposition = OPEN_EXISTING; - } - - dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; - - if( isDelete ){ - dwFlagsAndAttributes = FILE_ATTRIBUTE_TEMPORARY - | FILE_ATTRIBUTE_HIDDEN - | FILE_FLAG_DELETE_ON_CLOSE; - }else{ - dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL; - } - h = CreateFileW((WCHAR*)zConverted, - dwDesiredAccess, - dwShareMode, - NULL, - dwCreationDisposition, - dwFlagsAndAttributes, - NULL - ); - if( h==INVALID_HANDLE_VALUE ){ - pFile->lastErrno = GetLastError(); - HeapFree(GetProcessHeap(),0,zConverted); - return UNQLITE_IOERR; - } - SyZero(pFile,sizeof(*pFile)); - pFile->pMethod = &winIoMethod; - pFile->h = h; - pFile->lastErrno = NO_ERROR; - pFile->pVfs = pVfs; - pFile->sectorSize = getSectorSize(pVfs, zUtf8Name); - HeapFree(GetProcessHeap(),0,zConverted); - return UNQLITE_OK; -} -/* - * Export the Windows Vfs. - */ -UNQLITE_PRIVATE const unqlite_vfs * unqliteExportBuiltinVfs(void) -{ - static const unqlite_vfs sWinvfs = { - "Windows", /* Vfs name */ - 1, /* Vfs structure version */ - sizeof(winFile), /* szOsFile */ - MAX_PATH, /* mxPathName */ - winOpen, /* xOpen */ - winDelete, /* xDelete */ - winAccess, /* xAccess */ - winFullPathname, /* xFullPathname */ - 0, /* xTmp */ - winSleep, /* xSleep */ - winCurrentTime, /* xCurrentTime */ - winGetLastError, /* xGetLastError */ - }; - return &sWinvfs; -} -#endif /* __WINNT__ */ -- cgit v1.2.3