📄 os_unix.c
字号:
h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY); if( h<0 ){ return SQLITE_CANTOPEN; } *pReadonly = 1; }else{ *pReadonly = 0; } return allocateUnixFile(h, pId, zFilename, 0);}/*** Attempt to open a new file for exclusive access by this process.** The file will be opened for both reading and writing. To avoid** a potential security problem, we do not allow the file to have** previously existed. Nor do we allow the file to be a symbolic** link.**** If delFlag is true, then make arrangements to automatically delete** the file when it is closed.**** On success, write the file handle into *id and return SQLITE_OK.**** On failure, return SQLITE_CANTOPEN.*/int sqlite3UnixOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){ int h; CRASH_TEST_OVERRIDE(sqlite3CrashOpenExclusive, zFilename, pId, delFlag); assert( 0==*pId ); h = open(zFilename, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW|O_LARGEFILE|O_BINARY, delFlag ? 0600 : SQLITE_DEFAULT_FILE_PERMISSIONS); if( h<0 ){ return SQLITE_CANTOPEN; } return allocateUnixFile(h, pId, zFilename, delFlag);}/*** Attempt to open a new file for read-only access.**** On success, write the file handle into *id and return SQLITE_OK.**** On failure, return SQLITE_CANTOPEN.*/int sqlite3UnixOpenReadOnly(const char *zFilename, OsFile **pId){ int h; CRASH_TEST_OVERRIDE(sqlite3CrashOpenReadOnly, zFilename, pId, 0); assert( 0==*pId ); h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY); if( h<0 ){ return SQLITE_CANTOPEN; } return allocateUnixFile(h, pId, zFilename, 0);}/*** 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.**** If FULL_FSYNC is enabled, this function is not longer useful, ** a FULL_FSYNC sync applies to all pending disk operations.**** On success, a handle for a previously open file 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.*/static int unixOpenDirectory( OsFile *id, const char *zDirname){ unixFile *pFile = (unixFile*)id; assert( pFile!=0 ); SET_THREADID(pFile); assert( pFile->dirfd<0 ); pFile->dirfd = open(zDirname, O_RDONLY|O_BINARY, 0); if( pFile->dirfd<0 ){ return SQLITE_CANTOPEN; } OSTRACE3("OPENDIR %-3d %s\n", pFile->dirfd, zDirname); return SQLITE_OK;}/*** Create a temporary file name in zBuf. zBuf must be big enough to** hold at least SQLITE_TEMPNAME_SIZE characters.*/int sqlite3UnixTempFileName(char *zBuf){ static const char *azDirs[] = { 0, "/var/tmp", "/usr/tmp", "/tmp", ".", }; static const unsigned char zChars[] = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789"; int i, j; struct stat buf; const char *zDir = "."; azDirs[0] = sqlite3_temp_directory; for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); i++){ if( azDirs[i]==0 ) continue; 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); sqlite3Randomness(15, &zBuf[j]); for(i=0; i<15; i++, j++){ zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; } zBuf[j] = 0; }while( access(zBuf,0)==0 ); return SQLITE_OK; }/*** Check that a given pathname is a directory and is writable ***/int sqlite3UnixIsDirWritable(char *zBuf){#ifndef SQLITE_OMIT_PAGER_PRAGMAS struct stat buf; if( zBuf==0 ) return 0; if( zBuf[0]==0 ) return 0; if( stat(zBuf, &buf) ) return 0; if( !S_ISDIR(buf.st_mode) ) return 0; if( access(zBuf, 07) ) return 0;#endif /* SQLITE_OMIT_PAGER_PRAGMAS */ return 1;}/*** Seek to the offset in id->offset then read cnt bytes into pBuf.** Return the number of bytes actually read. Update the offset.*/static int seekAndRead(unixFile *id, void *pBuf, int cnt){ int got; i64 newOffset; TIMER_START;#if defined(USE_PREAD) got = pread(id->h, pBuf, cnt, id->offset); SimulateIOError( got = -1 );#elif defined(USE_PREAD64) got = pread64(id->h, pBuf, cnt, id->offset); SimulateIOError( got = -1 );#else newOffset = lseek(id->h, id->offset, SEEK_SET); SimulateIOError( newOffset-- ); if( newOffset!=id->offset ){ return -1; } got = read(id->h, pBuf, cnt);#endif TIMER_END; OSTRACE5("READ %-3d %5d %7lld %d\n", id->h, got, id->offset, TIMER_ELAPSED); if( got>0 ){ id->offset += got; } return got;}/*** Read data from a file into a buffer. Return SQLITE_OK if all** bytes were read successfully and SQLITE_IOERR if anything goes** wrong.*/static int unixRead(OsFile *id, void *pBuf, int amt){ int got; assert( id ); got = seekAndRead((unixFile*)id, pBuf, amt); if( got==amt ){ return SQLITE_OK; }else if( got<0 ){ return SQLITE_IOERR_READ; }else{ memset(&((char*)pBuf)[got], 0, amt-got); return SQLITE_IOERR_SHORT_READ; }}/*** Seek to the offset in id->offset then read cnt bytes into pBuf.** Return the number of bytes actually read. Update the offset.*/static int seekAndWrite(unixFile *id, const void *pBuf, int cnt){ int got; i64 newOffset; TIMER_START;#if defined(USE_PREAD) got = pwrite(id->h, pBuf, cnt, id->offset);#elif defined(USE_PREAD64) got = pwrite64(id->h, pBuf, cnt, id->offset);#else newOffset = lseek(id->h, id->offset, SEEK_SET); if( newOffset!=id->offset ){ return -1; } got = write(id->h, pBuf, cnt);#endif TIMER_END; OSTRACE5("WRITE %-3d %5d %7lld %d\n", id->h, got, id->offset, TIMER_ELAPSED); if( got>0 ){ id->offset += got; } return got;}/*** Write data from a buffer into a file. Return SQLITE_OK on success** or some other error code on failure.*/static int unixWrite(OsFile *id, const void *pBuf, int amt){ int wrote = 0; assert( id ); assert( amt>0 ); while( amt>0 && (wrote = seekAndWrite((unixFile*)id, pBuf, amt))>0 ){ amt -= wrote; pBuf = &((char*)pBuf)[wrote]; } SimulateIOError(( wrote=(-1), amt=1 )); SimulateDiskfullError(( wrote=0, amt=1 )); if( amt>0 ){ if( wrote<0 ){ return SQLITE_IOERR_WRITE; }else{ return SQLITE_FULL; } } return SQLITE_OK;}/*** Move the read/write pointer in a file.*/static int unixSeek(OsFile *id, i64 offset){ assert( id );#ifdef SQLITE_TEST if( offset ) SimulateDiskfullError(return SQLITE_FULL);#endif ((unixFile*)id)->offset = offset; return SQLITE_OK;}#ifdef SQLITE_TEST/*** Count the number of fullsyncs and normal syncs. This is used to test** that syncs and fullsyncs are occuring at the right times.*/int sqlite3_sync_count = 0;int sqlite3_fullsync_count = 0;#endif/*** Use the fdatasync() API only if the HAVE_FDATASYNC macro is defined.** Otherwise use fsync() in its place.*/#ifndef HAVE_FDATASYNC# define fdatasync fsync#endif/*** Define HAVE_FULLFSYNC to 0 or 1 depending on whether or not** the F_FULLFSYNC macro is defined. F_FULLFSYNC is currently** only available on Mac OS X. But that could change.*/#ifdef F_FULLFSYNC# define HAVE_FULLFSYNC 1#else# define HAVE_FULLFSYNC 0#endif/*** The fsync() system call does not work as advertised on many** unix systems. The following procedure is an attempt to make** it work better.**** The SQLITE_NO_SYNC macro disables all fsync()s. This is useful** for testing when we want to run through the test suite quickly.** You are strongly advised *not* to deploy with SQLITE_NO_SYNC** enabled, however, since with SQLITE_NO_SYNC enabled, an OS crash** or power failure will likely corrupt the database file.*/static int full_fsync(int fd, int fullSync, int dataOnly){ int rc; /* Record the number of times that we do a normal fsync() and ** FULLSYNC. This is used during testing to verify that this procedure ** gets called with the correct arguments. */#ifdef SQLITE_TEST if( fullSync ) sqlite3_fullsync_count++; sqlite3_sync_count++;#endif /* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a ** no-op */#ifdef SQLITE_NO_SYNC rc = SQLITE_OK;#else#if HAVE_FULLFSYNC if( fullSync ){ rc = fcntl(fd, F_FULLFSYNC, 0); }else{ rc = 1; } /* If the FULLFSYNC failed, fall back to attempting an fsync(). * It shouldn't be possible for fullfsync to fail on the local * file system (on OSX), so failure indicates that FULLFSYNC * isn't supported for this file system. So, attempt an fsync * and (for now) ignore the overhead of a superfluous fcntl call. * It'd be better to detect fullfsync support once and avoid * the fcntl call every time sync is called. */ if( rc ) rc = fsync(fd);#else if( dataOnly ){ rc = fdatasync(fd); }else{ rc = fsync(fd); }#endif /* HAVE_FULLFSYNC */#endif /* defined(SQLITE_NO_SYNC) */ return rc;}/*** Make sure all writes to a particular file are committed to disk.**** If dataOnly==0 then both the file itself and its metadata (file** size, access time, etc) are synced. If dataOnly!=0 then only the** file data is synced.**** 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.*/static int unixSync(OsFile *id, int dataOnly){ int rc; unixFile *pFile = (unixFile*)id; assert( pFile ); OSTRACE2("SYNC %-3d\n", pFile->h); rc = full_fsync(pFile->h, pFile->fullSync, dataOnly); SimulateIOError( rc=1 ); if( rc ){ return SQLITE_IOERR_FSYNC; } if( pFile->dirfd>=0 ){ OSTRACE4("DIRSYNC %-3d (have_fullfsync=%d fullsync=%d)\n", pFile->dirfd, HAVE_FULLFSYNC, pFile->fullSync);#ifndef SQLITE_DISABLE_DIRSYNC /* The directory sync is only attempted if full_fsync is ** turned off or unavailable. If a full_fsync occurred above, ** then the directory sync is superfluous. */ if( (!HAVE_FULLFSYNC || !pFile->fullSync) && full_fsync(pFile->dirfd,0,0) ){ /* ** We have received multiple reports of fsync() returning ** errors when applied to directories on certain file systems. ** A failed directory sync is not a big deal. So it seems ** better to ignore the error. Ticket #1657 */ /* return SQLITE_IOERR; */ }#endif close(pFile->dirfd); /* Only need to sync once, so close the directory */ pFile->dirfd = -1; /* when we are done. */ } return SQLITE_OK;}/*** Sync the directory zDirname. This is a no-op on operating systems other** than UNIX.**** This is used to make sure the master journal file has truely been deleted** before making changes to individual journals on a multi-database commit.** The F_FULLFSYNC option is not needed here.*/int sqlite3UnixSyncDirectory(const char *zDirname){#ifdef SQLITE_DISABLE_DIRSYNC return SQLITE_OK;#else int fd; int r; fd = open(zDirname, O_RDONLY|O_BINARY, 0); OSTRACE3("DIRSYNC %-3d (%s)\n", fd, zDirname); if( fd<0 ){ return SQLITE_CANTOPEN; } r = fsync(fd);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -