]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Further tests for os_unix.c.
authordan <dan@noemail.net>
Wed, 30 Mar 2011 19:08:03 +0000 (19:08 +0000)
committerdan <dan@noemail.net>
Wed, 30 Mar 2011 19:08:03 +0000 (19:08 +0000)
FossilOrigin-Name: a84f7711949ea3885b0e36e48118d2c76a8a5b82

manifest
manifest.uuid
src/os_unix.c
src/test1.c
src/test_syscall.c
test/syscall.test
test/sysfault.test
test/unixexcl.test [new file with mode: 0644]

index 71c1fddc9a91e35dcd086d6196d08823af9b3b57..cb8d6273aac6282a60abac31e44754dd688955dc 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Do\snot\sgenerate\ssqlite_stat1\sentries\sfor\sempty\stables\swhen\srunning\nANALYZE.\s\sTicket\s[83ea97620bd31016451]
-D 2011-03-30T14:54:05.390
+C Further\stests\sfor\sos_unix.c.
+D 2011-03-30T19:08:03.321
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 27701a1653595a1f2187dc61c8117e00a6c1d50f
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -162,7 +162,7 @@ F src/os.c 22ac61d06e72a0dac900400147333b07b13d8e1d
 F src/os.h 9dbed8c2b9c1f2f2ebabc09e49829d4777c26bf9
 F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f
 F src/os_os2.c 2596fd2d5d0976c6c0c628d0c3c7c4e7a724f4cf
-F src/os_unix.c 0b37759312e8adb58c0c7dab1ab8ca16957bf299
+F src/os_unix.c be9f9d3383a7b556a1f3805442e0061e436eb7ac
 F src/os_win.c 24d72407a90551969744cf9bcbb1b4c72c5fa845
 F src/pager.c 6aa906b60a59664ba58d3f746164bb010d407ce1
 F src/pager.h 3f8c783de1d4706b40b1ac15b64f5f896bcc78d1
@@ -185,7 +185,7 @@ F src/sqliteLimit.h a17dcd3fb775d63b64a43a55c54cb282f9726f44
 F src/status.c 4997380fbb915426fef9e500b4872e79c99267fc
 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
 F src/tclsqlite.c b020ebf3b4af58cae7875e217efd7ac22f485713
-F src/test1.c 9020310c7617234b33fd1c3064f89524db25f290
+F src/test1.c 9ca440e80e16e53920904a0a5ac7feffb9b2c9a1
 F src/test2.c 80d323d11e909cf0eb1b6fbb4ac22276483bcf31
 F src/test3.c 056093cfef69ff4227a6bdb9108564dc7f45e4bc
 F src/test4.c 0528360b5025688002a5feb6be906ddce52eaaee
@@ -220,7 +220,7 @@ F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0
 F src/test_server.c bbba05c144b5fc4b52ff650a4328027b3fa5fcc6
 F src/test_stat.c f682704b5d1ba8e1d4e7e882a6d7922e2dcf066c
 F src/test_superlock.c 2b97936ca127d13962c3605dbc9a4ef269c424cd
-F src/test_syscall.c d12e8cd163cd33b66d0a3d1b8daaf136d09d65c2
+F src/test_syscall.c 349a2b913e82b029f01527f58f65d66a02a09a84
 F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
 F src/test_thread.c bedd05cad673dba53326f3aa468cc803038896c0
 F src/test_vfs.c 2ed8853c1e51ac6f9ea091f7ce4e0d618bba8b86
@@ -672,8 +672,8 @@ F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4
 F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a
 F test/superlock.test 5d7a4954b0059c903f82c7b67867bc5451a7c082
 F test/sync.test ded6b39d8d8ca3c0c5518516c6371b3316d3e3a3
-F test/syscall.test 125d9781d914c408e8629053b5f914dc920ab3eb
-F test/sysfault.test be42aa42f89a82305cf3807047d419595e430480
+F test/syscall.test d1dae1fee88613cf763d97ad0038d867509e0c42
+F test/sysfault.test a2c3ca66d82f3b4ac7d29f1aeaba8962f4f5a22a
 F test/table.test 04ba066432430657712d167ebf28080fe878d305
 F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126
 F test/tclsqlite.test 8c154101e704170c2be10f137a5499ac2c6da8d3
@@ -828,6 +828,7 @@ F test/types.test bf816ce73c7dfcfe26b700c19f97ef4050d194ff
 F test/types2.test 3555aacf8ed8dc883356e59efc314707e6247a84
 F test/types3.test a0f66bf12f80fad89493535474f7a6d16fa58150
 F test/unique.test 083c7fff74695bcc27a71d75699deba3595bc9c2
+F test/unixexcl.test 9d80a54d86d2261f660758928959368ffc36151e
 F test/update.test 8bc86fd7ef1a00014f76dc6a6a7c974df4aef172
 F test/utf16align.test 54cd35a27c005a9b6e7815d887718780b6a462ae
 F test/vacuum.test 29b60e8cc9e573b39676df6c4a75fe9e02d04a09
@@ -919,7 +920,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P 3d2de011814002e2e25b7645f94ff8fc7aab9cdd
-R 0216cf925df143bd6cbc69301b702732
-U drh
-Z ebdb63d4898403f81a888e3e3a66ac94
+P 3a27af5b3c688c651ba1fae261026ef77b7ff5e3
+R 8aec69201b7794049bf0ef28fa4da45f
+U dan
+Z 9b217166a2b3bec7df70dcbc250ff848
index 4c1fb6bb6a64f5003b25db8c4a122cc439180051..d8ae4421575a658cf57c6aec283184d752b83805 100644 (file)
@@ -1 +1 @@
-3a27af5b3c688c651ba1fae261026ef77b7ff5e3
\ No newline at end of file
+a84f7711949ea3885b0e36e48118d2c76a8a5b82
\ No newline at end of file
index d958b6fc93cc0da5b0b4e9279f203cf0050f683c..bf11e678afc4e06d0ad65db0c36b2483591fefb7 100644 (file)
@@ -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
index 852ecdecc728d3eaf8e86671df97cfbe01e9d38a..8a0d09a7164752018c497f0e957345118593260a 100644 (file)
@@ -4888,6 +4888,44 @@ static int file_control_chunksize_test(
   return TCL_OK;
 }
 
+/*
+** 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
 **
@@ -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 },
 
index 61508ec45059888641aa1a5cdb3b3f3cb1c479b3..dbac01d69bcc72f66a68247348d1e8a16ac3ba09 100644 (file)
@@ -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 }
   };
 
index 610c529866c59e2a052149ee91c36d59656e7ce0..21295a59cfa7d6db0eafcb63ca92bc4b242b7ea4 100644 (file)
@@ -194,6 +194,57 @@ do_test 6.2 {
   db close
 } {}
 
+#-------------------------------------------------------------------------
+# Test that a database file a single byte in size is treated as an empty
+# file. Whereas a file 2 bytes or larger might be considered corrupt.
+#
+catch { db close }
+forcedelete test.db test.db2
+
+proc create_db_file {nByte} {
+  set fd [open test.db w]
+  fconfigure $fd -translation binary -encoding binary
+  puts -nonewline $fd [string range "xSQLite" 1 $nByte]
+  close $fd
+}
+
+foreach {nByte res} {
+  1      {0 {}}
+  2      {1 {file is encrypted or is not a database}}
+  3      {1 {file is encrypted or is not a database}}
+} {
+  do_test 7.$nByte {
+    create_db_file $nByte
+    sqlite3 db test.db
+    catchsql { CREATE TABLE t1(a, b) }
+  } $res
+  catch { db close }
+}
+
+#-------------------------------------------------------------------------
+# 
+catch { db close }
+forcedelete test.db test.db2
+
+do_test 8.1 {
+  sqlite3 db test.db
+  file_control_chunksize_test db main 4096
+  file size test.db
+} {0}
+
+foreach {tn hint size} {
+  1  1000    4096 
+  2  1000    4096 
+  3  3000    4096 
+  4  4096    4096 
+  5  4197    8192 
+} {
+  do_test 8.2.$tn {
+    file_control_sizehint_test db main $hint
+    file size test.db
+  } $size
+}
+
 
 
 finish_test
index f6d1eabbc17198e56d25f8c1487b1e06a2031cc1..c8c6f512f1370815fd3b9085baff8175fc904cff 100644 (file)
@@ -66,7 +66,11 @@ do_faultsim_test 1 -faults vfsfault-* -prep {
     {1 {attempt to write a readonly database}}
 }
 
-# Errors in the fstat() function when opening and writing a file.
+#-------------------------------------------------------------------------
+# Errors in the fstat() function when opening and writing a file. Cases
+# where fstat() fails and sets errno to ENOMEM and EOVERFLOW are both
+# tested. EOVERFLOW is interpreted as meaning that a file on disk is
+# too large to be opened by the OS.
 #
 foreach {tn errno errlist} {
   1 ENOMEM       {{disk I/O error}}
@@ -85,12 +89,57 @@ foreach {tn errno errlist} {
   "
 }
 
+#-------------------------------------------------------------------------
+# Various errors in locking functions. 
+#
+foreach vfs {unix unix-excl} {
+  foreach {tn errno errlist} {
+    1 EAGAIN       {{database is locked}}
+    2 ETIMEDOUT    {{database is locked}}
+    3 EBUSY        {{database is locked}}
+    4 EINTR        {{database is locked}}
+    5 ENOLCK       {{database is locked}}
+    6 EACCES       {{database is locked}}
+    7 EPERM        {{access permission denied}}
+    8 EDEADLK      {{disk I/O error}}
+    9 ENOMEM       {{disk I/O error}}
+  } {
+    proc vfsfault_install {} { test_syscall install fcntl }
+    set errs [list]
+    foreach e $errlist { lappend errs [list 1 $e] }
+  
+    set body [string map [list %VFS% $vfs] {
+      sqlite3 db test.db
+      db eval {
+        CREATE TABLE t1(a, b);
+        INSERT INTO t1 VALUES(1, 2);
+      }
+      set fd [open test.db-journal w]
+      puts $fd "hello world"
+      close $fd
+      sqlite3 db test.db -vfs %VFS%
+      db eval {
+        SELECT * FROM t1;
+      }
+    }]
+  
+    do_faultsim_test 1.3.$vfs.$tn -faults vfsfault-* -prep {
+      faultsim_restore
+    } -body "
+      test_syscall errno fcntl $errno
+      $body
+    " -test "
+      faultsim_test_result {0 {1 2}} $errs
+    "
+  }
+}
+
 #-------------------------------------------------------------------------
 # Check that a single EINTR error does not affect processing.
 #
 proc vfsfault_install {} { 
   test_syscall reset
-  test_syscall install {open ftruncate close}
+  test_syscall install {open ftruncate close read pread pread64 write fallocate}
 }
 
 forcedelete test.db test.db2
@@ -113,16 +162,25 @@ do_faultsim_test 2.1 -faults vfsfault-transient -prep {
   test_syscall errno open      EINTR
   test_syscall errno ftruncate EINTR
   test_syscall errno close     EINTR
+  test_syscall errno read      EINTR
+  test_syscall errno pread     EINTR
+  test_syscall errno pread64   EINTR
+  test_syscall errno write     EINTR
+  test_syscall errno fallocate EINTR
 
   sqlite3 db test.db
+  file_control_chunksize_test db main 8192
+
   set res [db eval {
     ATTACH 'test.db2' AS 'aux';
     SELECT * FROM t1;
     PRAGMA journal_mode = truncate;
     BEGIN;
       INSERT INTO t1 VALUES('jkl', 'mno', 'pqr');
+      INSERT INTO t1 VALUES(randomblob(10000), 0, 0);
       UPDATE t2 SET x = 2;
     COMMIT;
+    DELETE FROM t1 WHERE length(a)>3;
     SELECT * FROM t1;
     SELECT * FROM t2;
   }]
@@ -159,8 +217,31 @@ do_faultsim_test 2.2 -faults vfsfault-* -prep {
 }
 
 #-------------------------------------------------------------------------
-# 
 
+proc vfsfault_install {} { 
+  test_syscall reset
+  test_syscall install {fstat fallocate}
+}
+do_faultsim_test 3 -faults vfsfault-* -prep {
+  faultsim_delete_and_reopen
+  file_control_chunksize_test db main 8192
+  execsql {
+    CREATE TABLE t1(a, b);
+    BEGIN;
+      SELECT * FROM t1;
+  }
+} -body {
+  test_syscall errno fstat     EIO
+  test_syscall errno fallocate EIO
+
+  execsql {
+    INSERT INTO t1 VALUES(randomblob(10000), randomblob(10000));
+    SELECT length(a) + length(b) FROM t1;
+    COMMIT;
+  }
+} -test {
+  faultsim_test_result {0 20000}
+}
 
 finish_test
 
diff --git a/test/unixexcl.test b/test/unixexcl.test
new file mode 100644 (file)
index 0000000..057ae0a
--- /dev/null
@@ -0,0 +1,83 @@
+# 2011 March 30
+#
+# The author disclaims copyright to this source code.  In place of
+# a legal notice, here is a blessing:
+#
+#    May you do good and not evil.
+#    May you find forgiveness for yourself and forgive others.
+#    May you share freely, never taking more than you give.
+#
+#***********************************************************************
+#
+# This file contains tests for the "unix-excl" VFS module (part of 
+# os_unix.c).
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+source $testdir/lock_common.tcl
+source $testdir/malloc_common.tcl
+
+if {$::tcl_platform(platform)!="unix" || [info commands test_syscall]==""} {
+  finish_test
+  return
+} 
+set testprefix unixexcl
+
+
+
+# Test that when using VFS "unix-excl", the first time the database is read
+# a process-wide exclusive lock is taken on it. This means other connections
+# within the process may still access the db normally, but connections from
+# outside the process cannot.
+#
+do_multiclient_test tn {
+  do_test unixexcl-1.$tn.1 {
+    sql1 {
+      CREATE TABLE t1(a, b);
+      INSERT INTO t1 VALUES('hello', 'world');
+    }
+  } {}
+  do_test unixexcl-1.$tn.2 { sql2 { SELECT * FROM t1 } } {hello world}
+  do_test unixexcl-1.$tn.3 {
+    code1 {
+      db close
+      sqlite3 db test.db -vfs unix-excl
+      db eval { SELECT * FROM t1 }
+    }
+  } {hello world}
+  if {$tn==1} {
+    do_test unixexcl-1.$tn.4.multiproc { 
+      csql2 { SELECT * FROM t1 } 
+    } {1 {database is locked}}
+  } else {
+    do_test unixexcl-1.$tn.4.singleproc { 
+      csql2 { SELECT * FROM t1 } 
+    } {0 {hello world}}
+  }
+}
+
+# Test that when using VFS "unix-excl", if a file is opened in read-only mode
+# the behaviour is the same as if VFS "unix" were used.
+#
+do_multiclient_test tn {
+  do_test unixexcl-2.$tn.1 {
+    sql1 {
+      CREATE TABLE t1(a, b);
+      INSERT INTO t1 VALUES('hello', 'world');
+    }
+  } {}
+  do_test unixexcl-2.$tn.2 { sql2 { SELECT * FROM t1 } } {hello world}
+  do_test unixexcl-2.$tn.3 {
+    code1 {
+      db close
+      sqlite3 db test.db -readonly yes -vfs unix-excl
+      db eval { SELECT * FROM t1 }
+    }
+  } {hello world}
+  do_test unixexcl-2.$tn.4 { 
+    csql2 { SELECT * FROM t1 } 
+  } {0 {hello world}}
+}
+
+finish_test