📄 os.c
字号:
return SQLITE_CANTOPEN; } sqliteOsEnterMutex(); id->pLock = findLockInfo(id->fd); sqliteOsLeaveMutex(); if( id->pLock==0 ){ close(id->fd); return SQLITE_NOMEM; } id->locked = 0; TRACE3("OPEN-RO %-3d %s\n", id->fd, zFilename); OpenCounter(+1); return SQLITE_OK;#endif#if OS_WIN HANDLE h = CreateFile(zFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL ); if( h==INVALID_HANDLE_VALUE ){ return SQLITE_CANTOPEN; } id->h = h; id->locked = 0; OpenCounter(+1); return SQLITE_OK;#endif#if OS_MAC FSSpec fsSpec;# ifdef _LARGE_FILE HFSUniStr255 dfName; FSRef fsRef; if( __path2fss(zFilename, &fsSpec) != noErr ) return SQLITE_CANTOPEN; if( FSpMakeFSRef(&fsSpec, &fsRef) != noErr ) return SQLITE_CANTOPEN; FSGetDataForkName(&dfName); if( FSOpenFork(&fsRef, dfName.length, dfName.unicode, fsRdPerm, &(id->refNum)) != noErr ) return SQLITE_CANTOPEN;# else __path2fss(zFilename, &fsSpec); if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdPerm, &(id->refNum)) != noErr ) return SQLITE_CANTOPEN;# endif if( HOpenRF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrShPerm, &(id->refNumRF)) != noErr){ id->refNumRF = -1; } id->locked = 0; id->delOnClose = 0; OpenCounter(+1); return SQLITE_OK;#endif}/*** Attempt to open a file descriptor for the directory that contains a** file. This file descriptor can be used to fsync() the directory** in order to make sure the creation of a new file is actually written** to disk.**** This routine is only meaningful for Unix. It is a no-op under** windows since windows does not support hard links.**** On success, a handle for a previously open file is at *id is** updated with the new directory file descriptor and SQLITE_OK is** returned.**** On failure, the function returns SQLITE_CANTOPEN and leaves** *id unchanged.*/int sqliteOsOpenDirectory( const char *zDirname, OsFile *id){#if OS_UNIX if( id->fd<0 ){ /* Do not open the directory if the corresponding file is not already ** open. */ return SQLITE_CANTOPEN; } assert( id->dirfd<0 ); id->dirfd = open(zDirname, O_RDONLY|O_BINARY, 0644); if( id->dirfd<0 ){ return SQLITE_CANTOPEN; } TRACE3("OPENDIR %-3d %s\n", id->dirfd, zDirname);#endif return SQLITE_OK;}/*** Create a temporary file name in zBuf. zBuf must be big enough to** hold at least SQLITE_TEMPNAME_SIZE characters.*/int sqliteOsTempFileName(char *zBuf){#if OS_UNIX static const char *azDirs[] = { "/var/tmp", "/usr/tmp", "/tmp", ".", }; static char zChars[] = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789"; int i, j; struct stat buf; const char *zDir = "."; for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); i++){ if( stat(azDirs[i], &buf) ) continue; if( !S_ISDIR(buf.st_mode) ) continue; if( access(azDirs[i], 07) ) continue; zDir = azDirs[i]; break; } do{ sprintf(zBuf, "%s/"TEMP_FILE_PREFIX, zDir); j = strlen(zBuf); for(i=0; i<15; i++){ int n = sqliteRandomByte() % (sizeof(zChars)-1); zBuf[j++] = zChars[n]; } zBuf[j] = 0; }while( access(zBuf,0)==0 );#endif#if OS_WIN static char zChars[] = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789"; int i, j; char zTempPath[SQLITE_TEMPNAME_SIZE]; GetTempPath(SQLITE_TEMPNAME_SIZE-30, zTempPath); for(i=strlen(zTempPath); i>0 && zTempPath[i-1]=='\\'; i--){} zTempPath[i] = 0; for(;;){ sprintf(zBuf, "%s\\"TEMP_FILE_PREFIX, zTempPath); j = strlen(zBuf); for(i=0; i<15; i++){ int n = sqliteRandomByte() % (sizeof(zChars) - 1); zBuf[j++] = zChars[n]; } zBuf[j] = 0; if( !sqliteOsFileExists(zBuf) ) break; }#endif#if OS_MAC static char zChars[] = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789"; int i, j; char zTempPath[SQLITE_TEMPNAME_SIZE]; char zdirName[32]; CInfoPBRec infoRec; Str31 dirName; memset(&infoRec, 0, sizeof(infoRec)); memset(zTempPath, 0, SQLITE_TEMPNAME_SIZE); if( FindFolder(kOnSystemDisk, kTemporaryFolderType, kCreateFolder, &(infoRec.dirInfo.ioVRefNum), &(infoRec.dirInfo.ioDrParID)) == noErr ){ infoRec.dirInfo.ioNamePtr = dirName; do{ infoRec.dirInfo.ioFDirIndex = -1; infoRec.dirInfo.ioDrDirID = infoRec.dirInfo.ioDrParID; if( PBGetCatInfoSync(&infoRec) == noErr ){ CopyPascalStringToC(dirName, zdirName); i = strlen(zdirName); memmove(&(zTempPath[i+1]), zTempPath, strlen(zTempPath)); strcpy(zTempPath, zdirName); zTempPath[i] = ':'; }else{ *zTempPath = 0; break; } } while( infoRec.dirInfo.ioDrDirID != fsRtDirID ); } if( *zTempPath == 0 ) getcwd(zTempPath, SQLITE_TEMPNAME_SIZE-24); for(;;){ sprintf(zBuf, "%s"TEMP_FILE_PREFIX, zTempPath); j = strlen(zBuf); for(i=0; i<15; i++){ int n = sqliteRandomByte() % sizeof(zChars); zBuf[j++] = zChars[n]; } zBuf[j] = 0; if( !sqliteOsFileExists(zBuf) ) break; }#endif return SQLITE_OK; }/*** Close a file*/int sqliteOsClose(OsFile *id){#if OS_UNIX close(id->fd); if( id->dirfd>=0 ) close(id->dirfd); id->dirfd = -1; sqliteOsEnterMutex(); releaseLockInfo(id->pLock); 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 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.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -