📄 os_unix.c
字号:
if( errno==EISDIR ){ return SQLITE_CANTOPEN; }#endif id->h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY); if( id->h<0 ){ return SQLITE_CANTOPEN; } *pReadonly = 1; }else{ *pReadonly = 0; } sqlite3OsEnterMutex(); rc = findLockInfo(id->h, &id->pLock, &id->pOpen); sqlite3OsLeaveMutex(); if( rc ){ close(id->h); return SQLITE_NOMEM; } id->locktype = 0; id->isOpen = 1; TRACE3("OPEN %-3d %s\n", id->h, zFilename); OpenCounter(+1); return SQLITE_OK;}/*** 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 sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){ int rc; assert( !id->isOpen ); if( access(zFilename, 0)==0 ){ return SQLITE_CANTOPEN; } id->dirfd = -1; id->h = open(zFilename, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW|O_LARGEFILE|O_BINARY, 0600); if( id->h<0 ){ return SQLITE_CANTOPEN; } sqlite3OsEnterMutex(); rc = findLockInfo(id->h, &id->pLock, &id->pOpen); sqlite3OsLeaveMutex(); if( rc ){ close(id->h); unlink(zFilename); return SQLITE_NOMEM; } id->locktype = 0; id->isOpen = 1; if( delFlag ){ unlink(zFilename); } TRACE3("OPEN-EX %-3d %s\n", id->h, zFilename); OpenCounter(+1); return SQLITE_OK;}/*** 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 sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){ int rc; assert( !id->isOpen ); id->dirfd = -1; id->h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY); if( id->h<0 ){ return SQLITE_CANTOPEN; } sqlite3OsEnterMutex(); rc = findLockInfo(id->h, &id->pLock, &id->pOpen); sqlite3OsLeaveMutex(); if( rc ){ close(id->h); return SQLITE_NOMEM; } id->locktype = 0; id->isOpen = 1; TRACE3("OPEN-RO %-3d %s\n", id->h, zFilename); OpenCounter(+1); return SQLITE_OK;}/*** 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 sqlite3OsOpenDirectory( const char *zDirname, OsFile *id){ if( !id->isOpen ){ /* 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); 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.*/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 sqlite3OsTempFileName(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; }#ifndef SQLITE_OMIT_PAGER_PRAGMAS/*** Check that a given pathname is a directory and is writable ***/int sqlite3OsIsDirWritable(char *zBuf){ 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; return 1;}#endif /* SQLITE_OMIT_PAGER_PRAGMAS *//*** 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 sqlite3OsRead(OsFile *id, void *pBuf, int amt){ int got; assert( id->isOpen ); SimulateIOError(SQLITE_IOERR); TIMER_START; got = read(id->h, pBuf, amt); TIMER_END; TRACE4("READ %-3d %7d %d\n", id->h, last_page, TIMER_ELAPSED); SEEK(0); /* if( got<0 ) got = 0; */ if( got==amt ){ return SQLITE_OK; }else{ return SQLITE_IOERR; }}/*** Write data from a buffer into a file. Return SQLITE_OK on success** or some other error code on failure.*/int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){ int wrote = 0; assert( id->isOpen ); assert( amt>0 ); SimulateIOError(SQLITE_IOERR); SimulateDiskfullError; TIMER_START; while( amt>0 && (wrote = write(id->h, pBuf, amt))>0 ){ amt -= wrote; pBuf = &((char*)pBuf)[wrote]; } TIMER_END; TRACE4("WRITE %-3d %7d %d\n", id->h, last_page, TIMER_ELAPSED); SEEK(0); if( amt>0 ){ return SQLITE_FULL; } return SQLITE_OK;}/*** Move the read/write pointer in a file.*/int sqlite3OsSeek(OsFile *id, i64 offset){ assert( id->isOpen ); SEEK(offset/1024 + 1); lseek(id->h, offset, SEEK_SET); return SQLITE_OK;}/*** 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){#ifdef SQLITE_NO_SYNC return SQLITE_OK;#else int rc;#ifdef F_FULLFSYNC rc = fcntl(fd, F_FULLFSYNC, 0); if( rc ) rc = fsync(fd);#else rc = fsync(fd);#endif return rc;#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 sqlite3OsSync(OsFile *id){ assert( id->isOpen ); SimulateIOError(SQLITE_IOERR); TRACE2("SYNC %-3d\n", id->h); if( full_fsync(id->h) ){ return SQLITE_IOERR; } if( id->dirfd>=0 ){ TRACE2("DIRSYNC %-3d\n", id->dirfd); full_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;}/*** Sync the directory zDirname. This is a no-op on operating systems other** than UNIX.*/int sqlite3OsSyncDirectory(const char *zDirname){ int fd; int r; SimulateIOError(SQLITE_IOERR); fd = open(zDirname, O_RDONLY|O_BINARY, 0644); TRACE3("DIRSYNC %-3d (%s)\n", fd, zDirname); if( fd<0 ){ return SQLITE_CANTOPEN; } r = fsync(fd); close(fd); return ((r==0)?SQLITE_OK:SQLITE_IOERR);}/*** Truncate an open file to a specified size*/int sqlite3OsTruncate(OsFile *id, i64 nByte){ assert( id->isOpen ); SimulateIOError(SQLITE_IOERR); return ftruncate(id->h, nByte)==0 ? SQLITE_OK : SQLITE_IOERR;}/*** Determine the current size of a file in bytes*/int sqlite3OsFileSize(OsFile *id, i64 *pSize){ struct stat buf; assert( id->isOpen ); SimulateIOError(SQLITE_IOERR); if( fstat(id->h, &buf)!=0 ){ return SQLITE_IOERR; } *pSize = buf.st_size; return SQLITE_OK;}/*** 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. If the file is unlocked or holds only SHARED locks, then** return zero.*/int sqlite3OsCheckReservedLock(OsFile *id){ int r = 0; assert( id->isOpen ); sqlite3OsEnterMutex(); /* Needed because id->pLock is shared across threads */ /* Check if a thread in this process holds such a lock */ if( id->pLock->locktype>SHARED_LOCK ){ r = 1; } /* Otherwise see if some other process holds it. */ if( !r ){ struct flock lock; lock.l_whence = SEEK_SET; lock.l_start = RESERVED_BYTE; lock.l_len = 1; lock.l_type = F_WRLCK; fcntl(id->h, F_GETLK, &lock); if( lock.l_type!=F_UNLCK ){ r = 1; } } sqlite3OsLeaveMutex(); TRACE3("TEST WR-LOCK %d %d\n", id->h, r); return r;}#ifdef SQLITE_DEBUG/*** Helper function for printing out trace information from debugging** binaries. This returns the string represetation of the supplied** integer lock-type.*/static const char * locktypeName(int locktype){ switch( locktype ){ case NO_LOCK: return "NONE"; case SHARED_LOCK: return "SHARED"; case RESERVED_LOCK: return "RESERVED"; case PENDING_LOCK: return "PENDING"; case EXCLUSIVE_LOCK: return "EXCLUSIVE"; } return "ERROR";}#endif/*** Lock the file with the lock specified by parameter locktype - one** of the following:**** (1) SHARED_LOCK** (2) RESERVED_LOCK** (3) PENDING_LOCK** (4) EXCLUSIVE_LOCK**** Sometimes when requesting one lock state, additional lock states** are inserted in between. The locking might fail on one of the later** 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. Use the sqlite3OsUnlock()** routine to lower a locking level.*/int sqlite3OsLock(OsFile *id, int locktype){ /* The following describes the implementation of the various locks and ** lock transitions in terms of the POSIX advisory shared and exclusive ** lock primitives (called read-locks and write-locks below, to avoid ** confusion with SQLite lock names). The algorithms are complicated ** slightly in order to be compatible with windows systems simultaneously ** accessing the same database file, in case that is ever required. ** ** Symbols defined in os.h indentify the 'pending byte' and the 'reserved ** byte', each single bytes at well known offsets, and the 'shared byte ** range', a range of 510 bytes at a well known offset.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -