📄 os_unix.c
字号:
}/*** 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, 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; if( pFile==0 ){ /* Do not open the directory if the corresponding file is not already ** open. */ return SQLITE_CANTOPEN; } SET_THREADID(pFile); assert( pFile->dirfd<0 ); pFile->dirfd = open(zDirname, O_RDONLY|O_BINARY, 0); if( pFile->dirfd<0 ){ return SQLITE_CANTOPEN; } TRACE3("OPENDIR %-3d %s\n", pFile->dirfd, zDirname); return SQLITE_OK;}/*** If the following global variable points to a string which is the** name of a directory, then that directory will be used to store** temporary files.**** See also the "PRAGMA temp_store_directory" SQL command.*/char *sqlite3_temp_directory = 0;/*** 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;#ifdef USE_PREAD got = pread(id->h, pBuf, cnt, id->offset);#else lseek(id->h, id->offset, SEEK_SET); got = read(id->h, pBuf, cnt);#endif 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 ); TIMER_START; got = seekAndRead((unixFile*)id, pBuf, amt); TIMER_END; TRACE5("READ %-3d %5d %7d %d\n", ((unixFile*)id)->h, got, last_page, TIMER_ELAPSED); SEEK(0); SimulateIOError( got = -1 ); 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;#ifdef USE_PREAD got = pwrite(id->h, pBuf, cnt, id->offset);#else lseek(id->h, id->offset, SEEK_SET); got = write(id->h, pBuf, cnt);#endif 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 ); TIMER_START; while( amt>0 && (wrote = seekAndWrite((unixFile*)id, pBuf, amt))>0 ){ amt -= wrote; pBuf = &((char*)pBuf)[wrote]; } TIMER_END; TRACE5("WRITE %-3d %5d %7d %d\n", ((unixFile*)id)->h, wrote, last_page, TIMER_ELAPSED); SEEK(0); 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 ); SEEK(offset/1024 + 1);#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#endif /* HAVE_FULLFSYNC */ if( dataOnly ){ rc = fdatasync(fd); }else{ rc = fsync(fd); }#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 ); TRACE2("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 ){ TRACE4("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); TRACE3("DIRSYNC %-3d (%s)\n", fd, zDirname); if( fd<0 ){ return SQLITE_CANTOPEN; } r = fsync(fd); close(fd); SimulateIOError( r=1 ); if( r ){ return SQLITE_IOERR_DIR_FSYNC; }else{ return SQLITE_OK; }#endif}/*** Truncate an open file to a specified size*/static int unixTruncate(OsFile *id, i64 nByte){ int rc; assert( id ); rc = ftruncate(((unixFile*)id)->h, nByte); SimulateIOError( rc=1 ); if( rc ){ return SQLITE_IOERR_TRUNCATE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -