| /* | |
| ** 2005 November 29 | |
| ** | |
| ** The author disclaims copyright to this source code. In place of | |
| ** a legal notice, here is a blessing: | |
| ** | |
| ** May you do good and not evil. | |
| ** May you find forgiveness for yourself and forgive others. | |
| ** May you share freely, never taking more than you give. | |
| ** | |
| ****************************************************************************** | |
| ** | |
| ** This file contains OS interface code that is common to all | |
| ** architectures. | |
| */ | |
| #define _SQLITE_OS_C_ 1 | |
| #include "sqliteInt.h" | |
| #undef _SQLITE_OS_C_ | |
| /* | |
| ** The default SQLite sqlite3_vfs implementations do not allocate | |
| ** memory (actually, os_unix.c allocates a small amount of memory | |
| ** from within OsOpen()), but some third-party implementations may. | |
| ** So we test the effects of a malloc() failing and the sqlite3OsXXX() | |
| ** function returning SQLITE_IOERR_NOMEM using the DO_OS_MALLOC_TEST macro. | |
| ** | |
| ** The following functions are instrumented for malloc() failure | |
| ** testing: | |
| ** | |
| ** sqlite3OsRead() | |
| ** sqlite3OsWrite() | |
| ** sqlite3OsSync() | |
| ** sqlite3OsFileSize() | |
| ** sqlite3OsLock() | |
| ** sqlite3OsCheckReservedLock() | |
| ** sqlite3OsFileControl() | |
| ** sqlite3OsShmMap() | |
| ** sqlite3OsOpen() | |
| ** sqlite3OsDelete() | |
| ** sqlite3OsAccess() | |
| ** sqlite3OsFullPathname() | |
| ** | |
| */ | |
| #if defined(SQLITE_TEST) | |
| int sqlite3_memdebug_vfs_oom_test = 1; | |
| #define DO_OS_MALLOC_TEST(x) \ | |
| if (sqlite3_memdebug_vfs_oom_test && (!x || !sqlite3IsMemJournal(x))) { \ | |
| void *pTstAlloc = sqlite3Malloc(10); \ | |
| if (!pTstAlloc) return SQLITE_IOERR_NOMEM; \ | |
| sqlite3_free(pTstAlloc); \ | |
| } | |
| #else | |
| #define DO_OS_MALLOC_TEST(x) | |
| #endif | |
| /* | |
| ** The following routines are convenience wrappers around methods | |
| ** of the sqlite3_file object. This is mostly just syntactic sugar. All | |
| ** of this would be completely automatic if SQLite were coded using | |
| ** C++ instead of plain old C. | |
| */ | |
| int sqlite3OsClose(sqlite3_file *pId){ | |
| int rc = SQLITE_OK; | |
| if( pId->pMethods ){ | |
| rc = pId->pMethods->xClose(pId); | |
| pId->pMethods = 0; | |
| } | |
| return rc; | |
| } | |
| int sqlite3OsRead(sqlite3_file *id, void *pBuf, int amt, i64 offset){ | |
| DO_OS_MALLOC_TEST(id); | |
| return id->pMethods->xRead(id, pBuf, amt, offset); | |
| } | |
| int sqlite3OsWrite(sqlite3_file *id, const void *pBuf, int amt, i64 offset){ | |
| DO_OS_MALLOC_TEST(id); | |
| return id->pMethods->xWrite(id, pBuf, amt, offset); | |
| } | |
| int sqlite3OsTruncate(sqlite3_file *id, i64 size){ | |
| return id->pMethods->xTruncate(id, size); | |
| } | |
| int sqlite3OsSync(sqlite3_file *id, int flags){ | |
| DO_OS_MALLOC_TEST(id); | |
| return id->pMethods->xSync(id, flags); | |
| } | |
| int sqlite3OsFileSize(sqlite3_file *id, i64 *pSize){ | |
| DO_OS_MALLOC_TEST(id); | |
| return id->pMethods->xFileSize(id, pSize); | |
| } | |
| int sqlite3OsLock(sqlite3_file *id, int lockType){ | |
| DO_OS_MALLOC_TEST(id); | |
| return id->pMethods->xLock(id, lockType); | |
| } | |
| int sqlite3OsUnlock(sqlite3_file *id, int lockType){ | |
| return id->pMethods->xUnlock(id, lockType); | |
| } | |
| int sqlite3OsCheckReservedLock(sqlite3_file *id, int *pResOut){ | |
| DO_OS_MALLOC_TEST(id); | |
| return id->pMethods->xCheckReservedLock(id, pResOut); | |
| } | |
| /* | |
| ** Use sqlite3OsFileControl() when we are doing something that might fail | |
| ** and we need to know about the failures. Use sqlite3OsFileControlHint() | |
| ** when simply tossing information over the wall to the VFS and we do not | |
| ** really care if the VFS receives and understands the information since it | |
| ** is only a hint and can be safely ignored. The sqlite3OsFileControlHint() | |
| ** routine has no return value since the return value would be meaningless. | |
| */ | |
| int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){ | |
| #ifdef SQLITE_TEST | |
| if( op!=SQLITE_FCNTL_COMMIT_PHASETWO ){ | |
| /* Faults are not injected into COMMIT_PHASETWO because, assuming SQLite | |
| ** is using a regular VFS, it is called after the corresponding | |
| ** transaction has been committed. Injecting a fault at this point | |
| ** confuses the test scripts - the COMMIT comand returns SQLITE_NOMEM | |
| ** but the transaction is committed anyway. | |
| ** | |
| ** The core must call OsFileControl() though, not OsFileControlHint(), | |
| ** as if a custom VFS (e.g. zipvfs) returns an error here, it probably | |
| ** means the commit really has failed and an error should be returned | |
| ** to the user. */ | |
| DO_OS_MALLOC_TEST(id); | |
| } | |
| #endif | |
| return id->pMethods->xFileControl(id, op, pArg); | |
| } | |
| void sqlite3OsFileControlHint(sqlite3_file *id, int op, void *pArg){ | |
| (void)id->pMethods->xFileControl(id, op, pArg); | |
| } | |
| int sqlite3OsSectorSize(sqlite3_file *id){ | |
| int (*xSectorSize)(sqlite3_file*) = id->pMethods->xSectorSize; | |
| return (xSectorSize ? xSectorSize(id) : SQLITE_DEFAULT_SECTOR_SIZE); | |
| } | |
| int sqlite3OsDeviceCharacteristics(sqlite3_file *id){ | |
| return id->pMethods->xDeviceCharacteristics(id); | |
| } | |
| int sqlite3OsShmLock(sqlite3_file *id, int offset, int n, int flags){ | |
| return id->pMethods->xShmLock(id, offset, n, flags); | |
| } | |
| void sqlite3OsShmBarrier(sqlite3_file *id){ | |
| id->pMethods->xShmBarrier(id); | |
| } | |
| int sqlite3OsShmUnmap(sqlite3_file *id, int deleteFlag){ | |
| return id->pMethods->xShmUnmap(id, deleteFlag); | |
| } | |
| int sqlite3OsShmMap( | |
| sqlite3_file *id, /* Database file handle */ | |
| int iPage, | |
| int pgsz, | |
| int bExtend, /* True to extend file if necessary */ | |
| void volatile **pp /* OUT: Pointer to mapping */ | |
| ){ | |
| DO_OS_MALLOC_TEST(id); | |
| return id->pMethods->xShmMap(id, iPage, pgsz, bExtend, pp); | |
| } | |
| #if SQLITE_MAX_MMAP_SIZE>0 | |
| /* The real implementation of xFetch and xUnfetch */ | |
| int sqlite3OsFetch(sqlite3_file *id, i64 iOff, int iAmt, void **pp){ | |
| DO_OS_MALLOC_TEST(id); | |
| return id->pMethods->xFetch(id, iOff, iAmt, pp); | |
| } | |
| int sqlite3OsUnfetch(sqlite3_file *id, i64 iOff, void *p){ | |
| return id->pMethods->xUnfetch(id, iOff, p); | |
| } | |
| #else | |
| /* No-op stubs to use when memory-mapped I/O is disabled */ | |
| int sqlite3OsFetch(sqlite3_file *id, i64 iOff, int iAmt, void **pp){ | |
| *pp = 0; | |
| return SQLITE_OK; | |
| } | |
| int sqlite3OsUnfetch(sqlite3_file *id, i64 iOff, void *p){ | |
| return SQLITE_OK; | |
| } | |
| #endif | |
| /* | |
| ** The next group of routines are convenience wrappers around the | |
| ** VFS methods. | |
| */ | |
| int sqlite3OsOpen( | |
| sqlite3_vfs *pVfs, | |
| const char *zPath, | |
| sqlite3_file *pFile, | |
| int flags, | |
| int *pFlagsOut | |
| ){ | |
| int rc; | |
| DO_OS_MALLOC_TEST(0); | |
| /* 0x87f7f is a mask of SQLITE_OPEN_ flags that are valid to be passed | |
| ** down into the VFS layer. Some SQLITE_OPEN_ flags (for example, | |
| ** SQLITE_OPEN_FULLMUTEX or SQLITE_OPEN_SHAREDCACHE) are blocked before | |
| ** reaching the VFS. */ | |
| rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x87f7f, pFlagsOut); | |
| assert( rc==SQLITE_OK || pFile->pMethods==0 ); | |
| return rc; | |
| } | |
| int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ | |
| DO_OS_MALLOC_TEST(0); | |
| assert( dirSync==0 || dirSync==1 ); | |
| return pVfs->xDelete(pVfs, zPath, dirSync); | |
| } | |
| int sqlite3OsAccess( | |
| sqlite3_vfs *pVfs, | |
| const char *zPath, | |
| int flags, | |
| int *pResOut | |
| ){ | |
| DO_OS_MALLOC_TEST(0); | |
| return pVfs->xAccess(pVfs, zPath, flags, pResOut); | |
| } | |
| int sqlite3OsFullPathname( | |
| sqlite3_vfs *pVfs, | |
| const char *zPath, | |
| int nPathOut, | |
| char *zPathOut | |
| ){ | |
| DO_OS_MALLOC_TEST(0); | |
| zPathOut[0] = 0; | |
| return pVfs->xFullPathname(pVfs, zPath, nPathOut, zPathOut); | |
| } | |
| #ifndef SQLITE_OMIT_LOAD_EXTENSION | |
| void *sqlite3OsDlOpen(sqlite3_vfs *pVfs, const char *zPath){ | |
| return pVfs->xDlOpen(pVfs, zPath); | |
| } | |
| void sqlite3OsDlError(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ | |
| pVfs->xDlError(pVfs, nByte, zBufOut); | |
| } | |
| void (*sqlite3OsDlSym(sqlite3_vfs *pVfs, void *pHdle, const char *zSym))(void){ | |
| return pVfs->xDlSym(pVfs, pHdle, zSym); | |
| } | |
| void sqlite3OsDlClose(sqlite3_vfs *pVfs, void *pHandle){ | |
| pVfs->xDlClose(pVfs, pHandle); | |
| } | |
| #endif /* SQLITE_OMIT_LOAD_EXTENSION */ | |
| int sqlite3OsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ | |
| return pVfs->xRandomness(pVfs, nByte, zBufOut); | |
| } | |
| int sqlite3OsSleep(sqlite3_vfs *pVfs, int nMicro){ | |
| return pVfs->xSleep(pVfs, nMicro); | |
| } | |
| int sqlite3OsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){ | |
| int rc; | |
| /* IMPLEMENTATION-OF: R-49045-42493 SQLite will use the xCurrentTimeInt64() | |
| ** method to get the current date and time if that method is available | |
| ** (if iVersion is 2 or greater and the function pointer is not NULL) and | |
| ** will fall back to xCurrentTime() if xCurrentTimeInt64() is | |
| ** unavailable. | |
| */ | |
| if( pVfs->iVersion>=2 && pVfs->xCurrentTimeInt64 ){ | |
| rc = pVfs->xCurrentTimeInt64(pVfs, pTimeOut); | |
| }else{ | |
| double r; | |
| rc = pVfs->xCurrentTime(pVfs, &r); | |
| *pTimeOut = (sqlite3_int64)(r*86400000.0); | |
| } | |
| return rc; | |
| } | |
| int sqlite3OsOpenMalloc( | |
| sqlite3_vfs *pVfs, | |
| const char *zFile, | |
| sqlite3_file **ppFile, | |
| int flags, | |
| int *pOutFlags | |
| ){ | |
| int rc = SQLITE_NOMEM; | |
| sqlite3_file *pFile; | |
| pFile = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile); | |
| if( pFile ){ | |
| rc = sqlite3OsOpen(pVfs, zFile, pFile, flags, pOutFlags); | |
| if( rc!=SQLITE_OK ){ | |
| sqlite3_free(pFile); | |
| }else{ | |
| *ppFile = pFile; | |
| } | |
| } | |
| return rc; | |
| } | |
| int sqlite3OsCloseFree(sqlite3_file *pFile){ | |
| int rc = SQLITE_OK; | |
| assert( pFile ); | |
| rc = sqlite3OsClose(pFile); | |
| sqlite3_free(pFile); | |
| return rc; | |
| } | |
| /* | |
| ** This function is a wrapper around the OS specific implementation of | |
| ** sqlite3_os_init(). The purpose of the wrapper is to provide the | |
| ** ability to simulate a malloc failure, so that the handling of an | |
| ** error in sqlite3_os_init() by the upper layers can be tested. | |
| */ | |
| int sqlite3OsInit(void){ | |
| void *p = sqlite3_malloc(10); | |
| if( p==0 ) return SQLITE_NOMEM; | |
| sqlite3_free(p); | |
| return sqlite3_os_init(); | |
| } | |
| /* | |
| ** The list of all registered VFS implementations. | |
| */ | |
| static sqlite3_vfs * SQLITE_WSD vfsList = 0; | |
| #define vfsList GLOBAL(sqlite3_vfs *, vfsList) | |
| /* | |
| ** Locate a VFS by name. If no name is given, simply return the | |
| ** first VFS on the list. | |
| */ | |
| sqlite3_vfs *sqlite3_vfs_find(const char *zVfs){ | |
| sqlite3_vfs *pVfs = 0; | |
| #if SQLITE_THREADSAFE | |
| sqlite3_mutex *mutex; | |
| #endif | |
| #ifndef SQLITE_OMIT_AUTOINIT | |
| int rc = sqlite3_initialize(); | |
| if( rc ) return 0; | |
| #endif | |
| #if SQLITE_THREADSAFE | |
| mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); | |
| #endif | |
| sqlite3_mutex_enter(mutex); | |
| for(pVfs = vfsList; pVfs; pVfs=pVfs->pNext){ | |
| if( zVfs==0 ) break; | |
| if( strcmp(zVfs, pVfs->zName)==0 ) break; | |
| } | |
| sqlite3_mutex_leave(mutex); | |
| return pVfs; | |
| } | |
| /* | |
| ** Unlink a VFS from the linked list | |
| */ | |
| static void vfsUnlink(sqlite3_vfs *pVfs){ | |
| assert( sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)) ); | |
| if( pVfs==0 ){ | |
| /* No-op */ | |
| }else if( vfsList==pVfs ){ | |
| vfsList = pVfs->pNext; | |
| }else if( vfsList ){ | |
| sqlite3_vfs *p = vfsList; | |
| while( p->pNext && p->pNext!=pVfs ){ | |
| p = p->pNext; | |
| } | |
| if( p->pNext==pVfs ){ | |
| p->pNext = pVfs->pNext; | |
| } | |
| } | |
| } | |
| /* | |
| ** Register a VFS with the system. It is harmless to register the same | |
| ** VFS multiple times. The new VFS becomes the default if makeDflt is | |
| ** true. | |
| */ | |
| int sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){ | |
| MUTEX_LOGIC(sqlite3_mutex *mutex;) | |
| #ifndef SQLITE_OMIT_AUTOINIT | |
| int rc = sqlite3_initialize(); | |
| if( rc ) return rc; | |
| #endif | |
| #ifdef SQLITE_ENABLE_API_ARMOR | |
| if( pVfs==0 ) return SQLITE_MISUSE_BKPT; | |
| #endif | |
| MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); ) | |
| sqlite3_mutex_enter(mutex); | |
| vfsUnlink(pVfs); | |
| if( makeDflt || vfsList==0 ){ | |
| pVfs->pNext = vfsList; | |
| vfsList = pVfs; | |
| }else{ | |
| pVfs->pNext = vfsList->pNext; | |
| vfsList->pNext = pVfs; | |
| } | |
| assert(vfsList); | |
| sqlite3_mutex_leave(mutex); | |
| return SQLITE_OK; | |
| } | |
| /* | |
| ** Unregister a VFS so that it is no longer accessible. | |
| */ | |
| int sqlite3_vfs_unregister(sqlite3_vfs *pVfs){ | |
| #if SQLITE_THREADSAFE | |
| sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); | |
| #endif | |
| sqlite3_mutex_enter(mutex); | |
| vfsUnlink(pVfs); | |
| sqlite3_mutex_leave(mutex); | |
| return SQLITE_OK; | |
| } |