📄 os_win.c
字号:
** 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(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 pFile->locktype to this value before exiting */ int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */ winFile *pFile = (winFile*)id; assert( pFile!=0 ); OSTRACE5("LOCK %d %d was %d(%d)\n", pFile->h, locktype, pFile->locktype, pFile->sharedLockByte); /* If there is already a lock of this type or more restrictive on the ** OsFile, do nothing. Don't use the end_lock: exit path, as ** sqlite3OsEnterMutex() hasn't been called yet. */ if( pFile->locktype>=locktype ){ return SQLITE_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. */ OSTRACE2("could not get a PENDING lock. cnt=%d\n", cnt); Sleep(1); } gotPendingLock = res; } /* Acquire a shared lock */ if( locktype==SHARED_LOCK && res ){ assert( pFile->locktype==NO_LOCK ); res = getReadLock(pFile); if( res ){ newLocktype = SHARED_LOCK; } } /* 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; } } /* 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); OSTRACE2("unreadlock = %d\n", res); res = LockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); if( res ){ newLocktype = EXCLUSIVE_LOCK; }else{ OSTRACE2("error-code = %d\n", 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 = SQLITE_OK; }else{ OSTRACE4("LOCK FAILED %d trying for %d but got %d\n", pFile->h, locktype, newLocktype); rc = SQLITE_BUSY; } pFile->locktype = 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(sqlite3_file *id, int *pResOut){ int rc; winFile *pFile = (winFile*)id; assert( pFile!=0 ); if( pFile->locktype>=RESERVED_LOCK ){ rc = 1; OSTRACE3("TEST WR-LOCK %d %d (local)\n", pFile->h, rc); }else{ rc = LockFile(pFile->h, RESERVED_BYTE, 0, 1, 0); if( rc ){ UnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0); } rc = !rc; OSTRACE3("TEST WR-LOCK %d %d (remote)\n", pFile->h, rc); } *pResOut = rc; return SQLITE_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 SQLITE_IOERR;*/static int winUnlock(sqlite3_file *id, int locktype){ int type; winFile *pFile = (winFile*)id; int rc = SQLITE_OK; assert( pFile!=0 ); assert( locktype<=SHARED_LOCK ); OSTRACE5("UNLOCK %d to %d was %d(%d)\n", pFile->h, locktype, pFile->locktype, pFile->sharedLockByte); type = pFile->locktype; if( type>=EXCLUSIVE_LOCK ){ UnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); if( locktype==SHARED_LOCK && !getReadLock(pFile) ){ /* This should never happen. We should always be able to ** reacquire the read lock */ rc = SQLITE_IOERR_UNLOCK; } } if( type>=RESERVED_LOCK ){ UnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0); } if( locktype==NO_LOCK && type>=SHARED_LOCK ){ unlockReadLock(pFile); } if( type>=PENDING_LOCK ){ UnlockFile(pFile->h, PENDING_BYTE, 0, 1, 0); } pFile->locktype = locktype; return rc;}/*** Control and query of the open file handle.*/static int winFileControl(sqlite3_file *id, int op, void *pArg){ switch( op ){ case SQLITE_FCNTL_LOCKSTATE: { *(int*)pArg = ((winFile*)id)->locktype; return SQLITE_OK; } } return SQLITE_ERROR;}/*** 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.**** SQLite code assumes this function cannot fail. It also assumes that** if two files are created in the same file-system directory (i.e.** a database and its journal file) that the sector size will be the** same for both.*/static int winSectorSize(sqlite3_file *id){ return SQLITE_DEFAULT_SECTOR_SIZE;}/*** Return a vector of device characteristics.*/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, winRead, winWrite, winTruncate, winSync, winFileSize, winLock, winUnlock, winCheckReservedLock, winFileControl, winSectorSize, winDeviceCharacteristics};/***************************************************************************** Here ends the I/O methods that form the sqlite3_io_methods object.**** The next block of code implements the 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 = 0; if( isNT() ){ zConverted = utf8ToUnicode(zFilename); }else{ zConverted = utf8ToMbcs(zFilename); } /* caller will handle out of memory */ return zConverted;}/*** Create a temporary file name in zBuf. zBuf must be big enough to** hold at pVfs->mxPathname characters.*/static int getTempname(int nBuf, char *zBuf){ static char zChars[] = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789"; size_t 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, "%s", zMulti); free(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, "%s", zUtf8); free(zUtf8); }else{ return SQLITE_NOMEM; } } for(i=strlen(zTempPath); i>0 && zTempPath[i-1]=='\\'; i--){} zTempPath[i] = 0; sqlite3_snprintf(nBuf-30, zBuf, "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPath); j = strlen(zBuf); sqlite3_randomness(20, &zBuf[j]); for(i=0; i<20; i++, j++){ zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; } zBuf[j] = 0; OSTRACE2("TEMP FILENAME: %s\n", zBuf); return SQLITE_OK; }/*** The return value of getLastErrorMsg** is zero if the error message fits in the buffer, or non-zero** otherwise (if the message was truncated).*/static int getLastErrorMsg(int nBuf, char *zBuf){ DWORD error = GetLastError();#if SQLITE_OS_WINCE sqlite3_snprintf(nBuf, zBuf, "OsError 0x%x (%u)", error, error);#else /* FormatMessage returns 0 on failure. Otherwise it ** returns the number of TCHARs written to the output ** buffer, excluding the terminating null char. */ if (!FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, zBuf, nBuf-1, 0)) { sqlite3_snprintf(nBuf, zBuf, "OsError 0x%x (%u)", error, error); }#endif return 0;}/*** 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; int isTemp; winFile *pFile = (winFile*)id; void *zConverted; /* Filename in OS encoding */ const char *zUtf8Name = zName; /* Filename in UTF-8 encoding */ char zTmpname[MAX_PATH+1]; /* Buffer used to create temp filename */ /* If the second argument to this function is NULL, generate a ** temporary file name to use */ if( !zUtf8Name ){ int rc = getTempname(MAX_PATH+1, zTmpname); if( rc!=SQLITE_OK ){ return rc; } zUtf8Name = zTmpname; } /* Convert the filename to the system encoding. */ zConverted = convertUtf8Filename(zUtf8Name); 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_DELETEONCLOSE ){#if SQLITE_OS_WINCE dwFlagsAndAttributes = FILE_ATTRIBUTE_HIDDEN;#else dwFlagsAndAttributes = FILE_ATTRIBUTE_TEMPORARY | FILE_ATTRIBUTE_HIDDEN | FILE_FLAG_DELETE_ON_CLOSE;#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -