📄 os.c
字号:
if( aNew==0 ){ /* If a malloc fails, just leak the file descriptor */ }else{ pOpen->aPending = aNew; pOpen->aPending[pOpen->nPending-1] = id->fd; } }else{ /* There are no outstanding locks so we can close the file immediately */ close(id->fd); } releaseLockInfo(id->pLock); releaseOpenCnt(id->pOpen); sqliteOsLeaveMutex(); TRACE2("CLOSE %-3d\n", id->fd); OpenCounter(-1); return SQLITE_OK;#endif#if OS_WIN CloseHandle(id->h); OpenCounter(-1); return SQLITE_OK;#endif#if OS_MAC if( id->refNumRF!=-1 ) FSClose(id->refNumRF);# ifdef _LARGE_FILE FSCloseFork(id->refNum);# else FSClose(id->refNum);# endif if( id->delOnClose ){ unlink(id->pathToDel); sqliteFree(id->pathToDel); } OpenCounter(-1); return SQLITE_OK;#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.*/int sqliteOsRead(OsFile *id, void *pBuf, int amt){#if OS_UNIX int got; SimulateIOError(SQLITE_IOERR); TIMER_START; got = read(id->fd, pBuf, amt); TIMER_END; TRACE4("READ %-3d %7d %d\n", id->fd, last_page, elapse); SEEK(0); /* if( got<0 ) got = 0; */ if( got==amt ){ return SQLITE_OK; }else{ return SQLITE_IOERR; }#endif#if OS_WIN DWORD got; SimulateIOError(SQLITE_IOERR); TRACE2("READ %d\n", last_page); if( !ReadFile(id->h, pBuf, amt, &got, 0) ){ got = 0; } if( got==(DWORD)amt ){ return SQLITE_OK; }else{ return SQLITE_IOERR; }#endif#if OS_MAC int got; SimulateIOError(SQLITE_IOERR); TRACE2("READ %d\n", last_page);# ifdef _LARGE_FILE FSReadFork(id->refNum, fsAtMark, 0, (ByteCount)amt, pBuf, (ByteCount*)&got);# else got = amt; FSRead(id->refNum, &got, pBuf);# endif if( got==amt ){ return SQLITE_OK; }else{ return SQLITE_IOERR; }#endif}/*** Write data from a buffer into a file. Return SQLITE_OK on success** or some other error code on failure.*/int sqliteOsWrite(OsFile *id, const void *pBuf, int amt){#if OS_UNIX int wrote = 0; SimulateIOError(SQLITE_IOERR); TIMER_START; while( amt>0 && (wrote = write(id->fd, pBuf, amt))>0 ){ amt -= wrote; pBuf = &((char*)pBuf)[wrote]; } TIMER_END; TRACE4("WRITE %-3d %7d %d\n", id->fd, last_page, elapse); SEEK(0); if( amt>0 ){ return SQLITE_FULL; } return SQLITE_OK;#endif#if OS_WIN int rc; DWORD wrote; SimulateIOError(SQLITE_IOERR); TRACE2("WRITE %d\n", last_page); while( amt>0 && (rc = WriteFile(id->h, pBuf, amt, &wrote, 0))!=0 && wrote>0 ){ amt -= wrote; pBuf = &((char*)pBuf)[wrote]; } if( !rc || amt>(int)wrote ){ return SQLITE_FULL; } return SQLITE_OK;#endif#if OS_MAC OSErr oserr; int wrote = 0; SimulateIOError(SQLITE_IOERR); TRACE2("WRITE %d\n", last_page); while( amt>0 ){# ifdef _LARGE_FILE oserr = FSWriteFork(id->refNum, fsAtMark, 0, (ByteCount)amt, pBuf, (ByteCount*)&wrote);# else wrote = amt; oserr = FSWrite(id->refNum, &wrote, pBuf);# endif if( wrote == 0 || oserr != noErr) break; amt -= wrote; pBuf = &((char*)pBuf)[wrote]; } if( oserr != noErr || amt>wrote ){ return SQLITE_FULL; } return SQLITE_OK;#endif}/*** Move the read/write pointer in a file.*/int sqliteOsSeek(OsFile *id, off_t offset){ SEEK(offset/1024 + 1);#if OS_UNIX lseek(id->fd, offset, SEEK_SET); return SQLITE_OK;#endif#if OS_WIN { LONG upperBits = offset>>32; LONG lowerBits = offset & 0xffffffff; DWORD rc; rc = SetFilePointer(id->h, lowerBits, &upperBits, FILE_BEGIN); /* TRACE3("SEEK rc=0x%x upper=0x%x\n", rc, upperBits); */ } return SQLITE_OK;#endif#if OS_MAC { off_t curSize; if( sqliteOsFileSize(id, &curSize) != SQLITE_OK ){ return SQLITE_IOERR; } if( offset >= curSize ){ if( sqliteOsTruncate(id, offset+1) != SQLITE_OK ){ return SQLITE_IOERR; } }# ifdef _LARGE_FILE if( FSSetForkPosition(id->refNum, fsFromStart, offset) != noErr ){# else if( SetFPos(id->refNum, fsFromStart, offset) != noErr ){# endif return SQLITE_IOERR; }else{ return SQLITE_OK; } }#endif}/*** Make sure all writes to a particular file are committed to disk.**** Under Unix, also make sure that the directory entry for the file** has been created by fsync-ing the directory that contains the file.** If we do not do this and we encounter a power failure, the directory** entry for the journal might not exist after we reboot. The next** SQLite to access the file will not know that the journal exists (because** the directory entry for the journal was never created) and the transaction** will not roll back - possibly leading to database corruption.*/int sqliteOsSync(OsFile *id){#if OS_UNIX SimulateIOError(SQLITE_IOERR); TRACE2("SYNC %-3d\n", id->fd); if( fsync(id->fd) ){ return SQLITE_IOERR; }else{ if( id->dirfd>=0 ){ TRACE2("DIRSYNC %-3d\n", id->dirfd); fsync(id->dirfd); close(id->dirfd); /* Only need to sync once, so close the directory */ id->dirfd = -1; /* when we are done. */ } return SQLITE_OK; }#endif#if OS_WIN if( FlushFileBuffers(id->h) ){ return SQLITE_OK; }else{ return SQLITE_IOERR; }#endif#if OS_MAC# ifdef _LARGE_FILE if( FSFlushFork(id->refNum) != noErr ){# else ParamBlockRec params; memset(¶ms, 0, sizeof(ParamBlockRec)); params.ioParam.ioRefNum = id->refNum; if( PBFlushFileSync(¶ms) != noErr ){# endif return SQLITE_IOERR; }else{ return SQLITE_OK; }#endif}/*** Truncate an open file to a specified size*/int sqliteOsTruncate(OsFile *id, off_t nByte){ SimulateIOError(SQLITE_IOERR);#if OS_UNIX return ftruncate(id->fd, nByte)==0 ? SQLITE_OK : SQLITE_IOERR;#endif#if OS_WIN { LONG upperBits = nByte>>32; SetFilePointer(id->h, nByte, &upperBits, FILE_BEGIN); SetEndOfFile(id->h); } return SQLITE_OK;#endif#if OS_MAC# ifdef _LARGE_FILE if( FSSetForkSize(id->refNum, fsFromStart, nByte) != noErr){# else if( SetEOF(id->refNum, nByte) != noErr ){# endif return SQLITE_IOERR; }else{ return SQLITE_OK; }#endif}/*** Determine the current size of a file in bytes*/int sqliteOsFileSize(OsFile *id, off_t *pSize){#if OS_UNIX struct stat buf; SimulateIOError(SQLITE_IOERR); if( fstat(id->fd, &buf)!=0 ){ return SQLITE_IOERR; } *pSize = buf.st_size; return SQLITE_OK;#endif#if OS_WIN DWORD upperBits, lowerBits; SimulateIOError(SQLITE_IOERR); lowerBits = GetFileSize(id->h, &upperBits); *pSize = (((off_t)upperBits)<<32) + lowerBits; return SQLITE_OK;#endif#if OS_MAC# ifdef _LARGE_FILE if( FSGetForkSize(id->refNum, pSize) != noErr){# else if( GetEOF(id->refNum, pSize) != noErr ){# endif return SQLITE_IOERR; }else{ return SQLITE_OK; }#endif}#if OS_WIN/*** Return true (non-zero) if we are running under WinNT, Win2K or WinXP.** Return false (zero) for Win95, Win98, or WinME.**** Here is an interesting observation: Win95, Win98, and WinME lack** the LockFileEx() API. But we can still statically link against that** API as long as we don't call it win running Win95/98/ME. A call to** this routine is used to determine if the host is Win95/98/ME or** WinNT/2K/XP so that we will know whether or not we can safely call** the LockFileEx() API.*/int isNT(void){ static int osType = 0; /* 0=unknown 1=win95 2=winNT */ if( osType==0 ){ OSVERSIONINFO sInfo; sInfo.dwOSVersionInfoSize = sizeof(sInfo); GetVersionEx(&sInfo); osType = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1; } return osType==2;}#endif/*** Windows file locking notes: [similar issues apply to MacOS]**** We cannot use LockFileEx() or UnlockFileEx() on Win95/98/ME because** those functions are not available. So we use only LockFile() and** UnlockFile().**** LockFile() prevents not just writing but also reading by other processes.** (This is a design error on the part of Windows, but there is nothing** we can do about that.) So the region used for locking is at the** end of the file where it is unlikely to ever interfere with an** actual read attempt.**** A database read lock is obtained by locking a single randomly-chosen ** byte out of a specific range of bytes. The lock byte is obtained at ** random so two separate readers can probably access the file at the ** same time, unless they are unlucky and choose the same lock byte.** A database write lock is obtained by locking all bytes in the range.** There can only be one writer.**** A lock is obtained on the first byte of the lock range before acquiring** either a read lock or a write lock. This prevents two processes from** attempting to get a lock at a same time. The semantics of ** sqliteOsReadLock() require that if there is already a write lock, that** lock is converted into a read lock atomically. The lock on the first** byte allows us to drop the old write lock and get the read lock without** another process jumping into the middle and messing us up. The same** argument applies to sqliteOsWriteLock().**** On WinNT/2K/XP systems, LockFileEx() and UnlockFileEx() are available,** which means we can use reader/writer locks. When reader writer locks** are used, the lock is placed on the same range of bytes that is used** for probabilistic locking in Win95/98/ME. Hence, the locking scheme** will support two or more Win95 readers or two or more WinNT readers.** But a single Win95 reader will lock out all WinNT readers and a single** WinNT reader will lock out all other Win95 readers.**** Note: On MacOS we use the resource fork for locking.**** The following #defines specify the range of bytes used for locking.** N_LOCKBYTE is the number of bytes available for doing the locking.** The first byte used to hold the lock while the lock is changing does** not count toward this number. FIRST_LOCKBYTE is the address of** the first byte in the range of bytes used for locking.*/#define N_LOCKBYTE 10239#if OS_MAC# define FIRST_LOCKBYTE (0x000fffff - N_LOCKBYTE)#else# define FIRST_LOCKBYTE (0xffffffff - N_LOCKBYTE)#endif/*** Change the status of the lock on the file "id" to be a readlock.** If the file was write locked, then this reduces the lock to a read.** If the file was read locked, then this acquires a new read lock.**** Return SQLITE_OK on success and SQLITE_BUSY on failure. If this** library was compiled with large file support (LFS) but LFS is not** available on the host, then an SQLITE_NOLFS is returned.*/int sqliteOsReadLock(OsFile *id){#if OS_UNIX int rc; sqliteOsEnterMutex(); if( id->pLock->cnt>0 ){ if( !id->locked ){ id->pLock->cnt++; id->locked = 1; id->pOpen->nLock++; } rc = SQLITE_OK; }else if( id->locked || id->pLock->cnt==0 ){ struct flock lock; int s; lock.l_type = F_RDLCK; lock.l_whence = SEEK_SET; lock.l_start = lock.l_len = 0L; s = fcntl(id->fd, F_SETLK, &lock); if( s!=0 ){ rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY; }else{ rc = SQLITE_OK; if( !id->locked ){ id->pOpen->nLock++; id->locked = 1; } id->pLock->cnt = 1; } }else{ rc = SQLITE_BUSY; } sqliteOsLeaveMutex(); return rc;#endif#if OS_WIN int rc; if( id->locked>0 ){ rc = SQLITE_OK; }else{ int lk; int res; int cnt = 100; sqliteRandomness(sizeof(lk), &lk); lk = (lk & 0x7fffffff)%N_LOCKBYTE + 1; while( cnt-->0 && (res = LockFile(id->h, FIRST_LOCKBYTE, 0, 1, 0))==0 ){ Sleep(1); } if( res ){ UnlockFile(id->h, FIRST_LOCKBYTE+1, 0, N_LOCKBYTE, 0); if( isNT() ){ OVERLAPPED ovlp; ovlp.Offset = FIRST_LOCKBYTE+1; ovlp.OffsetHigh = 0; ovlp.hEvent = 0; res = LockFileEx(id->h, LOCKFILE_FAIL_IMMEDIATELY, 0, N_LOCKBYTE, 0, &ovlp); }else{ res = LockFile(id->h, FIRST_LOCKBYTE+lk, 0, 1, 0); } UnlockFile(id->h, FIRST_LOCKBYTE, 0, 1, 0); } if( res ){ id->locked = lk; rc = SQLITE_OK; }else{ rc = SQLITE_BUSY; } } return rc;#endif#if OS_MAC
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -