diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/os_unix.c | 174 | ||||
-rw-r--r-- | src/test1.c | 39 | ||||
-rw-r--r-- | src/test_syscall.c | 30 |
3 files changed, 151 insertions, 92 deletions
diff --git a/src/os_unix.c b/src/os_unix.c index d958b6fc9..bf11e678a 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -593,9 +593,22 @@ static int robust_ftruncate(int h, sqlite3_int64 sz){ */ static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) { switch (posixError) { +#if 0 + /* At one point this code was not commented out. In theory, this branch + ** should never be hit, as this function should only be called after + ** a locking-related function (i.e. fcntl()) has returned non-zero with + ** the value of errno as the first argument. Since a system call has failed, + ** errno should be non-zero. + ** + ** Despite this, if errno really is zero, we still don't want to return + ** SQLITE_OK. The system call failed, and *some* SQLite error should be + ** propagated back to the caller. Commenting this branch out means errno==0 + ** will be handled by the "default:" case below. + */ case 0: return SQLITE_OK; - +#endif + case EAGAIN: case ETIMEDOUT: case EBUSY: @@ -1037,7 +1050,7 @@ static void closePendingFds(unixFile *pFile){ static void releaseInodeInfo(unixFile *pFile){ unixInodeInfo *pInode = pFile->pInode; assert( unixMutexHeld() ); - if( pInode ){ + if( ALWAYS(pInode) ){ pInode->nRef--; if( pInode->nRef==0 ){ assert( pInode->pShmNode==0 ); @@ -1211,6 +1224,9 @@ static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){ ** This function is a pass-through to fcntl(F_SETLK) if pFile is using ** any VFS other than "unix-excl" or if pFile is opened on "unix-excl" ** and is read-only. +** +** Zero is returned if the call completes successfully, or -1 if a call +** to fcntl() fails. In this case, errno is set appropriately (by fcntl()). */ static int unixFileLock(unixFile *pFile, struct flock *pLock){ int rc; @@ -1307,7 +1323,6 @@ static int unixLock(sqlite3_file *id, int eFileLock){ unixFile *pFile = (unixFile*)id; unixInodeInfo *pInode = pFile->pInode; struct flock lock; - int s = 0; int tErrno = 0; assert( pFile ); @@ -1376,11 +1391,10 @@ static int unixLock(sqlite3_file *id, int eFileLock){ ){ lock.l_type = (eFileLock==SHARED_LOCK?F_RDLCK:F_WRLCK); lock.l_start = PENDING_BYTE; - s = unixFileLock(pFile, &lock); - if( s==(-1) ){ + if( unixFileLock(pFile, &lock) ){ tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); - if( IS_LOCK_ERROR(rc) ){ + if( rc!=SQLITE_BUSY ){ pFile->lastErrno = tErrno; } goto end_lock; @@ -1394,33 +1408,31 @@ static int unixLock(sqlite3_file *id, int eFileLock){ if( eFileLock==SHARED_LOCK ){ assert( pInode->nShared==0 ); assert( pInode->eFileLock==0 ); + assert( rc==SQLITE_OK ); /* Now get the read-lock */ lock.l_start = SHARED_FIRST; lock.l_len = SHARED_SIZE; - if( (s = unixFileLock(pFile, &lock))==(-1) ){ + if( unixFileLock(pFile, &lock) ){ tErrno = errno; + rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); } + /* Drop the temporary PENDING lock */ lock.l_start = PENDING_BYTE; lock.l_len = 1L; lock.l_type = F_UNLCK; - if( unixFileLock(pFile, &lock)!=0 ){ - if( s != -1 ){ - /* This could happen with a network mount */ - tErrno = errno; - rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); - if( IS_LOCK_ERROR(rc) ){ - pFile->lastErrno = tErrno; - } - goto end_lock; - } + if( unixFileLock(pFile, &lock) && rc==SQLITE_OK ){ + /* This could happen with a network mount */ + tErrno = errno; + rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); } - if( s==(-1) ){ - rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); - if( IS_LOCK_ERROR(rc) ){ + + if( rc ){ + if( rc!=SQLITE_BUSY ){ pFile->lastErrno = tErrno; } + goto end_lock; }else{ pFile->eFileLock = SHARED_LOCK; pInode->nLock++; @@ -1437,22 +1449,20 @@ static int unixLock(sqlite3_file *id, int eFileLock){ */ assert( 0!=pFile->eFileLock ); lock.l_type = F_WRLCK; - switch( eFileLock ){ - case RESERVED_LOCK: - lock.l_start = RESERVED_BYTE; - break; - case EXCLUSIVE_LOCK: - lock.l_start = SHARED_FIRST; - lock.l_len = SHARED_SIZE; - break; - default: - assert(0); + + assert( eFileLock==RESERVED_LOCK || eFileLock==EXCLUSIVE_LOCK ); + if( eFileLock==RESERVED_LOCK ){ + lock.l_start = RESERVED_BYTE; + lock.l_len = 1L; + }else{ + lock.l_start = SHARED_FIRST; + lock.l_len = SHARED_SIZE; } - s = unixFileLock(pFile, &lock); - if( s==(-1) ){ + + if( unixFileLock(pFile, &lock) ){ tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); - if( IS_LOCK_ERROR(rc) ){ + if( rc!=SQLITE_BUSY ){ pFile->lastErrno = tErrno; } } @@ -1623,10 +1633,10 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ lock.l_whence = SEEK_SET; lock.l_start = SHARED_FIRST; lock.l_len = SHARED_SIZE; - if( unixFileLock(pFile, &lock)==(-1) ){ + if( unixFileLock(pFile, &lock) ){ tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK); - if( IS_LOCK_ERROR(rc) ){ + if( rc!=SQLITE_BUSY ){ pFile->lastErrno = tErrno; } goto end_unlock; @@ -1637,12 +1647,12 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ lock.l_whence = SEEK_SET; lock.l_start = PENDING_BYTE; lock.l_len = 2L; assert( PENDING_BYTE+1==RESERVED_BYTE ); - if( unixFileLock(pFile, &lock)!=(-1) ){ + if( unixFileLock(pFile, &lock)==0 ){ pInode->eFileLock = SHARED_LOCK; }else{ tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); - if( IS_LOCK_ERROR(rc) ){ + if( rc!=SQLITE_BUSY ){ pFile->lastErrno = tErrno; } goto end_unlock; @@ -1661,12 +1671,12 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ SimulateIOErrorBenign(1); SimulateIOError( h=(-1) ) SimulateIOErrorBenign(0); - if( unixFileLock(pFile, &lock)!=(-1) ){ + if( unixFileLock(pFile, &lock)==0 ){ pInode->eFileLock = NO_LOCK; }else{ tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); - if( IS_LOCK_ERROR(rc) ){ + if( rc!=SQLITE_BUSY ){ pFile->lastErrno = tErrno; } pInode->eFileLock = NO_LOCK; @@ -1714,29 +1724,27 @@ static int unixUnlock(sqlite3_file *id, int eFileLock){ */ static int closeUnixFile(sqlite3_file *id){ unixFile *pFile = (unixFile*)id; - if( pFile ){ - if( pFile->dirfd>=0 ){ - robust_close(pFile, pFile->dirfd, __LINE__); - pFile->dirfd=-1; - } - if( pFile->h>=0 ){ - robust_close(pFile, pFile->h, __LINE__); - pFile->h = -1; - } + if( pFile->dirfd>=0 ){ + robust_close(pFile, pFile->dirfd, __LINE__); + pFile->dirfd=-1; + } + if( pFile->h>=0 ){ + robust_close(pFile, pFile->h, __LINE__); + pFile->h = -1; + } #if OS_VXWORKS - if( pFile->pId ){ - if( pFile->isDelete ){ - unlink(pFile->pId->zCanonicalName); - } - vxworksReleaseFileId(pFile->pId); - pFile->pId = 0; + if( pFile->pId ){ + if( pFile->isDelete ){ + unlink(pFile->pId->zCanonicalName); } -#endif - OSTRACE(("CLOSE %-3d\n", pFile->h)); - OpenCounter(-1); - sqlite3_free(pFile->pUnused); - memset(pFile, 0, sizeof(unixFile)); + vxworksReleaseFileId(pFile->pId); + pFile->pId = 0; } +#endif + OSTRACE(("CLOSE %-3d\n", pFile->h)); + OpenCounter(-1); + sqlite3_free(pFile->pUnused); + memset(pFile, 0, sizeof(unixFile)); return SQLITE_OK; } @@ -1745,24 +1753,25 @@ static int closeUnixFile(sqlite3_file *id){ */ static int unixClose(sqlite3_file *id){ int rc = SQLITE_OK; - if( id ){ - unixFile *pFile = (unixFile *)id; - unixUnlock(id, NO_LOCK); - unixEnterMutex(); - assert( pFile->pInode==0 || pFile->pInode->nLock>0 - || pFile->pInode->bProcessLock==0 ); - if( pFile->pInode && pFile->pInode->nLock ){ - /* If there are outstanding locks, do not actually close the file just - ** yet because that would clear those locks. Instead, add the file - ** descriptor to pInode->pUnused list. It will be automatically closed - ** when the last lock is cleared. - */ - setPendingFd(pFile); - } - releaseInodeInfo(pFile); - rc = closeUnixFile(id); - unixLeaveMutex(); + unixFile *pFile = (unixFile *)id; + unixUnlock(id, NO_LOCK); + unixEnterMutex(); + + /* unixFile.pInode is always valid here. Otherwise, a different close + ** routine (e.g. nolockClose()) would be called instead. + */ + assert( pFile->pInode->nLock>0 || pFile->pInode->bProcessLock==0 ); + if( ALWAYS(pFile->pInode) && pFile->pInode->nLock ){ + /* If there are outstanding locks, do not actually close the file just + ** yet because that would clear those locks. Instead, add the file + ** descriptor to pInode->pUnused list. It will be automatically closed + ** when the last lock is cleared. + */ + setPendingFd(pFile); } + releaseInodeInfo(pFile); + rc = closeUnixFile(id); + unixLeaveMutex(); return rc; } @@ -3007,6 +3016,7 @@ static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){ do{ got = osPwrite64(id->h, pBuf, cnt, offset);}while( got<0 && errno==EINTR); #else newOffset = lseek(id->h, offset, SEEK_SET); + SimulateIOError( newOffset-- ); if( newOffset!=offset ){ if( newOffset == -1 ){ ((unixFile*)id)->lastErrno = errno; @@ -3375,12 +3385,16 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){ nSize = ((nByte+pFile->szChunk-1) / pFile->szChunk) * pFile->szChunk; if( nSize>(i64)buf.st_size ){ + #if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE - int rc; + /* The code below is handling the return value of osFallocate() + ** correctly. posix_fallocate() is defined to "returns zero on success, + ** or an error number on failure". See the manpage for details. */ + int err; do{ - rc = osFallocate(pFile->h, buf.st_size, nSize-buf.st_size); - }while( rc<0 && errno==EINTR ); - if( rc ) return SQLITE_IOERR_WRITE; + err = osFallocate(pFile->h, buf.st_size, nSize-buf.st_size); + }while( err==EINTR ); + if( err ) return SQLITE_IOERR_WRITE; #else /* If the OS does not have posix_fallocate(), fake it. First use ** ftruncate() to set the file size, then write a single byte to diff --git a/src/test1.c b/src/test1.c index 852ecdecc..8a0d09a71 100644 --- a/src/test1.c +++ b/src/test1.c @@ -4889,6 +4889,44 @@ static int file_control_chunksize_test( } /* +** tclcmd: file_control_sizehint_test DB DBNAME SIZE +** +** This TCL command runs the sqlite3_file_control interface and +** verifies correct operation of the SQLITE_GET_LOCKPROXYFILE and +** SQLITE_SET_LOCKPROXYFILE verbs. +*/ +static int file_control_sizehint_test( + ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int objc, /* Number of arguments */ + Tcl_Obj *CONST objv[] /* Command arguments */ +){ + sqlite3_int64 nSize; /* Hinted size */ + char *zDb; /* Db name ("main", "temp" etc.) */ + sqlite3 *db; /* Database handle */ + int rc; /* file_control() return code */ + + if( objc!=4 ){ + Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME SIZE"); + return TCL_ERROR; + } + if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) + || Tcl_GetWideIntFromObj(interp, objv[3], &nSize) + ){ + return TCL_ERROR; + } + zDb = Tcl_GetString(objv[2]); + if( zDb[0]=='\0' ) zDb = NULL; + + rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_SIZE_HINT, (void *)&nSize); + if( rc ){ + Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_STATIC); + return TCL_ERROR; + } + return TCL_OK; +} + +/* ** tclcmd: file_control_lockproxy_test DB PWD ** ** This TCL command runs the sqlite3_file_control interface and @@ -5608,6 +5646,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ { "file_control_lasterrno_test", file_control_lasterrno_test, 0 }, { "file_control_lockproxy_test", file_control_lockproxy_test, 0 }, { "file_control_chunksize_test", file_control_chunksize_test, 0 }, + { "file_control_sizehint_test", file_control_sizehint_test, 0 }, { "sqlite3_vfs_list", vfs_list, 0 }, { "sqlite3_create_function_v2", test_create_function_v2, 0 }, diff --git a/src/test_syscall.c b/src/test_syscall.c index 61508ec45..dbac01d69 100644 --- a/src/test_syscall.c +++ b/src/test_syscall.c @@ -121,7 +121,7 @@ struct TestSyscallArray { /* 4 */ { "stat", (sqlite3_syscall_ptr)ts_stat, 0, 0, 0 }, /* 5 */ { "fstat", (sqlite3_syscall_ptr)ts_fstat, 0, 0, 0 }, /* 6 */ { "ftruncate", (sqlite3_syscall_ptr)ts_ftruncate, 0, EIO, 0 }, - /* 7 */ { "fcntl", (sqlite3_syscall_ptr)ts_fcntl, 0, 0, 0 }, + /* 7 */ { "fcntl", (sqlite3_syscall_ptr)ts_fcntl, 0, EACCES, 0 }, /* 8 */ { "read", (sqlite3_syscall_ptr)ts_read, 0, 0, 0 }, /* 9 */ { "pread", (sqlite3_syscall_ptr)ts_pread, 0, 0, 0 }, /* 10 */ { "pread64", (sqlite3_syscall_ptr)ts_pread64, 0, 0, 0 }, @@ -275,7 +275,7 @@ static int ts_ftruncate(int fd, off_t n){ static int ts_fcntl(int fd, int cmd, ... ){ va_list ap; void *pArg; - if( tsIsFail() ){ + if( tsIsFailErrno("fcntl") ){ return -1; } va_start(ap, cmd); @@ -287,7 +287,7 @@ static int ts_fcntl(int fd, int cmd, ... ){ ** A wrapper around read(). */ static int ts_read(int fd, void *aBuf, size_t nBuf){ - if( tsIsFail() ){ + if( tsIsFailErrno("read") ){ return -1; } return orig_read(fd, aBuf, nBuf); @@ -297,7 +297,7 @@ static int ts_read(int fd, void *aBuf, size_t nBuf){ ** A wrapper around pread(). */ static int ts_pread(int fd, void *aBuf, size_t nBuf, off_t off){ - if( tsIsFail() ){ + if( tsIsFailErrno("pread") ){ return -1; } return orig_pread(fd, aBuf, nBuf, off); @@ -307,7 +307,7 @@ static int ts_pread(int fd, void *aBuf, size_t nBuf, off_t off){ ** A wrapper around pread64(). */ static int ts_pread64(int fd, void *aBuf, size_t nBuf, off_t off){ - if( tsIsFail() ){ + if( tsIsFailErrno("pread64") ){ return -1; } return orig_pread64(fd, aBuf, nBuf, off); @@ -317,7 +317,7 @@ static int ts_pread64(int fd, void *aBuf, size_t nBuf, off_t off){ ** A wrapper around write(). */ static int ts_write(int fd, const void *aBuf, size_t nBuf){ - if( tsIsFail() ){ + if( tsIsFailErrno("write") ){ return -1; } return orig_write(fd, aBuf, nBuf); @@ -327,7 +327,7 @@ static int ts_write(int fd, const void *aBuf, size_t nBuf){ ** A wrapper around pwrite(). */ static int ts_pwrite(int fd, const void *aBuf, size_t nBuf, off_t off){ - if( tsIsFail() ){ + if( tsIsFailErrno("pwrite") ){ return -1; } return orig_pwrite(fd, aBuf, nBuf, off); @@ -337,7 +337,7 @@ static int ts_pwrite(int fd, const void *aBuf, size_t nBuf, off_t off){ ** A wrapper around pwrite64(). */ static int ts_pwrite64(int fd, const void *aBuf, size_t nBuf, off_t off){ - if( tsIsFail() ){ + if( tsIsFailErrno("pwrite64") ){ return -1; } return orig_pwrite64(fd, aBuf, nBuf, off); @@ -531,11 +531,17 @@ static int test_syscall_errno( const char *z; int i; } aErrno[] = { - { "EACCES", EACCES }, - { "EINTR", EINTR }, - { "EIO", EIO }, + { "EACCES", EACCES }, + { "EINTR", EINTR }, + { "EIO", EIO }, { "EOVERFLOW", EOVERFLOW }, - { "ENOMEM", ENOMEM }, + { "ENOMEM", ENOMEM }, + { "EAGAIN", EAGAIN }, + { "ETIMEDOUT", ETIMEDOUT }, + { "EBUSY", EBUSY }, + { "EPERM", EPERM }, + { "EDEADLK", EDEADLK }, + { "ENOLCK", ENOLCK }, { 0, 0 } }; |