/ Check-in [7b6e30e6]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Log all error from close() in os_unix.c to sqlite3_log() but do not attempt to report errors back up to the application. Update the unix error logging to put the most important information earlier in the message.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:7b6e30e6a712311d4ef275253b085b85e6e17116
User & Date: drh 2011-03-02 02:08:13
References
2011-03-02
17:54
Fix bugs in [7b6e30e6a7] that only show up on Mac. check-in: ec55e8c6 user: drh tags: trunk
Context
2011-03-02
15:44
Make sure the rtreenode() testing and analysis routine in the RTREE extension can handle 64-bit rowids. This fix is in response to a message on the mailing list. check-in: 24602557 user: drh tags: trunk
15:09
Proof-of-concept prototype for the proposed xSetSystemCall extension method on the VFS. check-in: 92b5a76a user: drh tags: syscall-override
02:08
Log all error from close() in os_unix.c to sqlite3_log() but do not attempt to report errors back up to the application. Update the unix error logging to put the most important information earlier in the message. check-in: 7b6e30e6 user: drh tags: trunk
2011-02-25
03:25
Comment out some code in os_unix.c that only runs on MacOSX with SQLITE_ENABLE_LOCKING_STYLE. check-in: 4e50b036 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/os_unix.c.

763
764
765
766
767
768
769
770
771
772
773
774
775
776
777

778
779
780
781
782
783
784
...
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813

814
815
816

817
818
819
820
821

















822


823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
....
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
....
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507

1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
....
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
....
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
....
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
....
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
....
3435
3436
3437
3438
3439
3440
3441
3442



3443
3444
3445
3446
3447
3448
3449
....
4246
4247
4248
4249
4250
4251
4252
4253
4254
4255
4256
4257
4258
4259
4260
....
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284
4285
4286
....
4323
4324
4325
4326
4327
4328
4329
4330
4331
4332
4333
4334
4335
4336
4337
4338
4339
4340
4341
4342
4343
4344
4345
4346
....
4744
4745
4746
4747
4748
4749
4750
4751
4752
4753
4754
4755
4756
4757
4758
....
4760
4761
4762
4763
4764
4765
4766
4767
4768
4769
4770
4771
4772
4773
4774
4775
....
4793
4794
4795
4796
4797
4798
4799
4800
4801
4802
4803
4804
4805
4806
4807
4808
4809
....
4856
4857
4858
4859
4860
4861
4862
4863
4864
4865
4866
4867
4868
4869
4870
4871
4872
....
5046
5047
5048
5049
5050
5051
5052
5053
5054
5055
5056
5057
5058
5059
5060
....
5489
5490
5491
5492
5493
5494
5495
5496
5497
5498
5499
5500
5501
5502
5503
....
5589
5590
5591
5592
5593
5594
5595
5596
5597
5598
5599
5600
5601
5602
5603
5604
5605
5606
5607
5608
5609
5610
5611
....
5847
5848
5849
5850
5851
5852
5853
5854
5855
5856
5857
5858
5859
5860
5861
5862
5863
5864
5865
5866
5867
5868
**
** The first argument passed to the macro should be the error code that
** will be returned to SQLite (e.g. SQLITE_IOERR_DELETE, SQLITE_CANTOPEN). 
** The two subsequent arguments should be the name of the OS function that
** failed (e.g. "unlink", "open") and the the associated file-system path,
** if any.
*/
#define unixLogError(a,b,c)     unixLogError_x(a,b,c,__LINE__)
static int unixLogError_x(
  int errcode,                    /* SQLite error code */
  const char *zFunc,              /* Name of OS function that failed */
  const char *zPath,              /* File path associated with error */
  int iLine                       /* Source line number where error occurred */
){
  char *zErr;                     /* Message from strerror() or equivalent */


  /* If this is not a threadsafe build (SQLITE_THREADSAFE==0), then use
  ** the strerror() function to obtain the human-readable error message
  ** equivalent to errno. Otherwise, use strerror_r().
  */ 
#if SQLITE_THREADSAFE && defined(HAVE_STRERROR_R)
  char aErr[80];
................................................................................
  ** available, the error message will often be an empty string. Not a
  ** huge problem. Incorrectly concluding that the GNU version is available 
  ** could lead to a segfault though.
  */
#if defined(STRERROR_R_CHAR_P) || defined(__USE_GNU)
  zErr = 
# endif
  strerror_r(errno, aErr, sizeof(aErr)-1);

#elif SQLITE_THREADSAFE
  /* This is a threadsafe build, but strerror_r() is not available. */
  zErr = "";
#else
  /* Non-threadsafe build, use strerror(). */
  zErr = strerror(errno);
#endif

  assert( errcode!=SQLITE_OK );

  sqlite3_log(errcode,
      "os_unix.c: %s() at line %d - \"%s\" errno=%d path=%s",
      zFunc, iLine, zErr, errno, (zPath ? zPath : "n/a")

  );

  return errcode;
}





















/*
** Close all file descriptors accumuated in the unixInodeInfo->pUnused list.
** If all such file descriptors are closed without error, the list is
** cleared and SQLITE_OK returned.
**
** Otherwise, if an error occurs, then successfully closed file descriptor
** entries are removed from the list, and SQLITE_IOERR_CLOSE returned. 
** not deleted and SQLITE_IOERR_CLOSE returned.
*/ 
static int closePendingFds(unixFile *pFile){
  int rc = SQLITE_OK;
  unixInodeInfo *pInode = pFile->pInode;
  UnixUnusedFd *pError = 0;
  UnixUnusedFd *p;
  UnixUnusedFd *pNext;
  for(p=pInode->pUnused; p; p=pNext){
    pNext = p->pNext;
    if( close(p->fd) ){
      pFile->lastErrno = errno;
      rc = unixLogError(SQLITE_IOERR_CLOSE, "close", pFile->zPath);
      p->pNext = pError;
      pError = p;
    }else{
      sqlite3_free(p);
    }
  }
  pInode->pUnused = pError;
  return rc;
}

/*
** Release a unixInodeInfo structure previously allocated by findInodeInfo().
**
** The mutex entered using the unixEnterMutex() function must be held
** when this function is called.
................................................................................
    /* Decrement the count of locks against this same file.  When the
    ** count reaches zero, close any other file descriptors whose close
    ** was deferred because of outstanding locks.
    */
    pInode->nLock--;
    assert( pInode->nLock>=0 );
    if( pInode->nLock==0 ){
      int rc2 = closePendingFds(pFile);
      if( rc==SQLITE_OK ){
        rc = rc2;
      }
    }
  }
	
end_unlock:
  unixLeaveMutex();
  if( rc==SQLITE_OK ) pFile->eFileLock = eFileLock;
  return rc;
................................................................................
** even on VxWorks.  A mutex will be acquired on VxWorks by the
** vxworksReleaseFileId() routine.
*/
static int closeUnixFile(sqlite3_file *id){
  unixFile *pFile = (unixFile*)id;
  if( pFile ){
    if( pFile->dirfd>=0 ){
      int err = close(pFile->dirfd);
      if( err ){
        pFile->lastErrno = errno;
        return unixLogError(SQLITE_IOERR_DIR_CLOSE, "close", pFile->zPath);
      }else{
        pFile->dirfd=-1;
      }
    }
    if( pFile->h>=0 ){

      int err = close(pFile->h);
      if( err ){
        pFile->lastErrno = errno;
        return unixLogError(SQLITE_IOERR_CLOSE, "close", pFile->zPath);
      }
    }
#if OS_VXWORKS
    if( pFile->pId ){
      if( pFile->isDelete ){
        unlink(pFile->pId->zCanonicalName);
      }
      vxworksReleaseFileId(pFile->pId);
................................................................................
      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
      if( IS_LOCK_ERROR(rc) ){
        pFile->lastErrno = tErrno;
      }
    }
    return rc;
  } 
  if( close(fd) ){
    pFile->lastErrno = errno;
    rc = SQLITE_IOERR_CLOSE;
  }
  
  /* got it, set the type and return ok */
  pFile->eFileLock = eFileLock;
  return rc;
}

/*
................................................................................
        pFile->eFileLock = NO_LOCK;
      }
    }
    if( rc==SQLITE_OK ){
      pInode->nLock--;
      assert( pInode->nLock>=0 );
      if( pInode->nLock==0 ){
        rc = closePendingFds(pFile);
      }
    }
  }
  
  unixLeaveMutex();
  if( rc==SQLITE_OK ) pFile->eFileLock = eFileLock;
  return rc;
................................................................................
  rc = full_fsync(pFile->h, isFullsync, isDataOnly);
  SimulateIOError( rc=1 );
  if( rc ){
    pFile->lastErrno = errno;
    return unixLogError(SQLITE_IOERR_FSYNC, "full_fsync", pFile->zPath);
  }
  if( pFile->dirfd>=0 ){
    int err;
    OSTRACE(("DIRSYNC %-3d (have_fullfsync=%d fullsync=%d)\n", pFile->dirfd,
            HAVE_FULLFSYNC, isFullsync));
#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.
    */
................................................................................
       ** A failed directory sync is not a big deal.  So it seems
       ** better to ignore the error.  Ticket #1657
       */
       /* pFile->lastErrno = errno; */
       /* return SQLITE_IOERR; */
    }
#endif
    err = close(pFile->dirfd); /* Only need to sync once, so close the */
    if( err==0 ){              /* directory when we are done */
      pFile->dirfd = -1;
    }else{
      pFile->lastErrno = errno;
      rc = unixLogError(SQLITE_IOERR_DIR_CLOSE, "close", pFile->zPath);
    }
  }
  return rc;
}

/*
** Truncate an open file to a specified size
*/
................................................................................
    int i;
    assert( p->pInode==pFd->pInode );
    if( p->mutex ) sqlite3_mutex_free(p->mutex);
    for(i=0; i<p->nRegion; i++){
      munmap(p->apRegion[i], p->szRegion);
    }
    sqlite3_free(p->apRegion);
    if( p->h>=0 ) close(p->h);



    p->pInode->pShmNode = 0;
    sqlite3_free(p);
  }
}

/*
** Open a shared-memory area associated with open database file pDbFd.  
................................................................................
      ** handle h - as it is guaranteed that no posix locks will be released
      ** by doing so.
      **
      ** If scenario (a) caused the error then things are not so safe. The
      ** implicit assumption here is that if fstat() fails, things are in
      ** such bad shape that dropping a lock or two doesn't matter much.
      */
      close(h);
      h = -1;
    }
    unixLeaveMutex();
  }

#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
  else if( pLockingStyle == &afpIoMethods ){
................................................................................
      pCtx->dbPath = zFilename;
      pCtx->reserved = 0;
      srandomdev();
      unixEnterMutex();
      rc = findInodeInfo(pNew, &pNew->pInode);
      if( rc!=SQLITE_OK ){
        sqlite3_free(pNew->lockingContext);
        close(h);
        h = -1;
      }
      unixLeaveMutex();        
    }
  }
#endif

................................................................................
    unixLeaveMutex();
  }
#endif
  
  pNew->lastErrno = 0;
#if OS_VXWORKS
  if( rc!=SQLITE_OK ){
    if( h>=0 ) close(h);
    h = -1;
    unlink(zFilename);
    isDelete = 0;
  }
  pNew->isDelete = isDelete;
#endif
  if( rc!=SQLITE_OK ){
    if( dirfd>=0 ) close(dirfd); /* silent leak if fail, already in error */
    if( h>=0 ) close(h);
  }else{
    pNew->pMethod = pLockingStyle;
    OpenCounter(+1);
  }
  return rc;
}

................................................................................
    rc = openDirectory(zPath, &dirfd);
    if( rc!=SQLITE_OK ){
      /* It is safe to close fd at this point, because it is guaranteed not
      ** to be open on a database file. If it were open on a database file,
      ** it would not be safe to close as this would release any locks held
      ** on the file by this process.  */
      assert( eType!=SQLITE_OPEN_MAIN_DB );
      close(fd);             /* silently leak if fail, already in error */
      goto open_finished;
    }
  }

#ifdef FD_CLOEXEC
  fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
#endif
................................................................................
  noLock = eType!=SQLITE_OPEN_MAIN_DB;

  
#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE
  struct statfs fsInfo;
  if( fstatfs(fd, &fsInfo) == -1 ){
    ((unixFile*)pFile)->lastErrno = errno;
    if( dirfd>=0 ) close(dirfd); /* silently leak if fail, in error */
    close(fd); /* silently leak if fail, in error */
    return SQLITE_IOERR_ACCESS;
  }
  if (0 == strncmp("msdos", fsInfo.f_fstypename, 5)) {
    ((unixFile*)pFile)->fsFlags |= SQLITE_FSFLAGS_IS_MSDOS;
  }
#endif
  
................................................................................
        ** on that file that are currently holding advisory locks on it,
        ** then the call to close() will cancel those locks. In practice,
        ** we're assuming that statfs() doesn't fail very often. At least
        ** not while other file descriptors opened by the same process on
        ** the same file are working.  */
        p->lastErrno = errno;
        if( dirfd>=0 ){
          close(dirfd); /* silently leak if fail, in error */
        }
        close(fd); /* silently leak if fail, in error */
        rc = SQLITE_IOERR_ACCESS;
        goto open_finished;
      }
      useProxy = !(fsInfo.f_flags&MNT_LOCAL);
    }
    if( useProxy ){
      rc = fillInUnixFile(pVfs, fd, dirfd, pFile, zPath, noLock, isDelete);
................................................................................
      if( fsync(fd)==-1 )
#else
      if( fsync(fd) )
#endif
      {
        rc = unixLogError(SQLITE_IOERR_DIR_FSYNC, "fsync", zPath);
      }
      if( close(fd)&&!rc ){
        rc = unixLogError(SQLITE_IOERR_DIR_CLOSE, "close", zPath);
      }
    }
  }
#endif
  return rc;
}

/*
................................................................................
      memcpy(zBuf, &t, sizeof(t));
      pid = getpid();
      memcpy(&zBuf[sizeof(t)], &pid, sizeof(pid));
      assert( sizeof(t)+sizeof(pid)<=(size_t)nBuf );
      nBuf = sizeof(t) + sizeof(pid);
    }else{
      do{ nBuf = read(fd, zBuf, nBuf); }while( nBuf<0 && errno==EINTR );
      close(fd);
    }
  }
#endif
  return nBuf;
}


................................................................................
  
  rc = fillInUnixFile(&dummyVfs, fd, dirfd, (sqlite3_file*)pNew, path, 0, 0);
  if( rc==SQLITE_OK ){
    *ppFile = pNew;
    return SQLITE_OK;
  }
end_create_proxy:    
  close(fd); /* silently leak fd if error, we're already in error */
  sqlite3_free(pNew);
  sqlite3_free(pUnused);
  return rc;
}

#ifdef SQLITE_TEST
/* simulate multiple hosts by creating unique hostid file paths */
................................................................................
  }
  if( rename(tPath, cPath) ){
    sqlite3_snprintf(sizeof(errmsg), errmsg, "rename failed (%d)", errno);
    goto end_breaklock;
  }
  rc = 0;
  fprintf(stderr, "broke stale lock on %s\n", cPath);
  close(conchFile->h);
  conchFile->h = fd;
  conchFile->openFlags = O_RDWR | O_CREAT;

end_breaklock:
  if( rc ){
    if( fd>=0 ){
      unlink(tPath);
      close(fd);
    }
    fprintf(stderr, "failed to break stale lock on %s, %s\n", cPath, errmsg);
  }
  return rc;
}

/* Take the requested lock on the conch file and break a stale lock if the 
................................................................................
      }
      conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, SHARED_LOCK);
      
    end_takeconch:
      OSTRACE(("TRANSPROXY: CLOSE  %d\n", pFile->h));
      if( rc==SQLITE_OK && pFile->openFlags ){
        if( pFile->h>=0 ){
#ifdef STRICT_CLOSE_ERROR
          if( close(pFile->h) ){
            pFile->lastErrno = errno;
            return SQLITE_IOERR_CLOSE;
          }
#else
          close(pFile->h); /* silently leak fd if fail */
#endif
        }
        pFile->h = -1;
        int fd = open(pCtx->dbPath, pFile->openFlags,
                      SQLITE_DEFAULT_FILE_PERMISSIONS);
        OSTRACE(("TRANSPROXY: OPEN  %d\n", fd));
        if( fd>=0 ){
          pFile->h = fd;







|
|






>







 







|






|



>

<
|
>





>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>


<
<
<
<
<
<

|
<

<




|
<
<
<
<
<
|
|
<
|
<







 







|
<
<
<







 







|
<
<
<
<
|
|
<

>
|
<
<
<
<







 







|
<
<
<







 







|







 







<







 







|
|
|
<
<
<
<







 







|
>
>
>







 







|







 







|







 







|







|
|







 







|







 







|
|







 







|

|







 







|
<
<







 







|







 







|







 







|







|







 







|
<
<
<
<
<
<
<







763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
...
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816

817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845






846
847

848

849
850
851
852
853





854
855

856

857
858
859
860
861
862
863
....
1460
1461
1462
1463
1464
1465
1466
1467



1468
1469
1470
1471
1472
1473
1474
....
1495
1496
1497
1498
1499
1500
1501
1502




1503
1504

1505
1506
1507




1508
1509
1510
1511
1512
1513
1514
....
1710
1711
1712
1713
1714
1715
1716
1717



1718
1719
1720
1721
1722
1723
1724
....
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
....
3035
3036
3037
3038
3039
3040
3041

3042
3043
3044
3045
3046
3047
3048
....
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062




3063
3064
3065
3066
3067
3068
3069
....
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
....
4236
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
....
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
4275
4276
....
4313
4314
4315
4316
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330
4331
4332
4333
4334
4335
4336
....
4734
4735
4736
4737
4738
4739
4740
4741
4742
4743
4744
4745
4746
4747
4748
....
4750
4751
4752
4753
4754
4755
4756
4757
4758
4759
4760
4761
4762
4763
4764
4765
....
4783
4784
4785
4786
4787
4788
4789
4790
4791
4792
4793
4794
4795
4796
4797
4798
4799
....
4846
4847
4848
4849
4850
4851
4852
4853


4854
4855
4856
4857
4858
4859
4860
....
5034
5035
5036
5037
5038
5039
5040
5041
5042
5043
5044
5045
5046
5047
5048
....
5477
5478
5479
5480
5481
5482
5483
5484
5485
5486
5487
5488
5489
5490
5491
....
5577
5578
5579
5580
5581
5582
5583
5584
5585
5586
5587
5588
5589
5590
5591
5592
5593
5594
5595
5596
5597
5598
5599
....
5835
5836
5837
5838
5839
5840
5841
5842







5843
5844
5845
5846
5847
5848
5849
**
** The first argument passed to the macro should be the error code that
** will be returned to SQLite (e.g. SQLITE_IOERR_DELETE, SQLITE_CANTOPEN). 
** The two subsequent arguments should be the name of the OS function that
** failed (e.g. "unlink", "open") and the the associated file-system path,
** if any.
*/
#define unixLogError(a,b,c)     unixLogErrorAtLine(a,b,c,__LINE__)
static int unixLogErrorAtLine(
  int errcode,                    /* SQLite error code */
  const char *zFunc,              /* Name of OS function that failed */
  const char *zPath,              /* File path associated with error */
  int iLine                       /* Source line number where error occurred */
){
  char *zErr;                     /* Message from strerror() or equivalent */
  int iErrno = errno;             /* Saved syscall error number */

  /* If this is not a threadsafe build (SQLITE_THREADSAFE==0), then use
  ** the strerror() function to obtain the human-readable error message
  ** equivalent to errno. Otherwise, use strerror_r().
  */ 
#if SQLITE_THREADSAFE && defined(HAVE_STRERROR_R)
  char aErr[80];
................................................................................
  ** available, the error message will often be an empty string. Not a
  ** huge problem. Incorrectly concluding that the GNU version is available 
  ** could lead to a segfault though.
  */
#if defined(STRERROR_R_CHAR_P) || defined(__USE_GNU)
  zErr = 
# endif
  strerror_r(iErrno, aErr, sizeof(aErr)-1);

#elif SQLITE_THREADSAFE
  /* This is a threadsafe build, but strerror_r() is not available. */
  zErr = "";
#else
  /* Non-threadsafe build, use strerror(). */
  zErr = strerror(iErrno);
#endif

  assert( errcode!=SQLITE_OK );
  if( zPath==0 ) zPath = "";
  sqlite3_log(errcode,

      "os_unix.c:%d: (%d) %s(%s) - %s",
      iLine, iErrno, zFunc, zPath, zErr
  );

  return errcode;
}

/*
** Close a file descriptor.
**
** We assume that close() almost always works, since it is only in a
** very sick application or on a very sick platform that it might fail.
** If it does fail, simply leak the file descriptor, but do log the
** error.
**
** Note that it is not safe to retry close() after EINTR since the
** file descriptor might have already been reused by another thread.
** So we don't even try to recover from an EINTR.  Just log the error
** and move on.
*/
static void robust_close(unixFile *pFile, int h, int lineno){
  if( close(h) ){
    unixLogErrorAtLine(SQLITE_IOERR_CLOSE, "close",
                       pFile ? pFile->zPath : 0, lineno);
  }
}

/*
** Close all file descriptors accumuated in the unixInodeInfo->pUnused list.






*/ 
static void closePendingFds(unixFile *pFile){

  unixInodeInfo *pInode = pFile->pInode;

  UnixUnusedFd *p;
  UnixUnusedFd *pNext;
  for(p=pInode->pUnused; p; p=pNext){
    pNext = p->pNext;
    robust_close(pFile, p->fd, __LINE__);





    sqlite3_free(p);
  }

  pInode->pUnused = 0;

}

/*
** Release a unixInodeInfo structure previously allocated by findInodeInfo().
**
** The mutex entered using the unixEnterMutex() function must be held
** when this function is called.
................................................................................
    /* Decrement the count of locks against this same file.  When the
    ** count reaches zero, close any other file descriptors whose close
    ** was deferred because of outstanding locks.
    */
    pInode->nLock--;
    assert( pInode->nLock>=0 );
    if( pInode->nLock==0 ){
      closePendingFds(pFile);



    }
  }
	
end_unlock:
  unixLeaveMutex();
  if( rc==SQLITE_OK ) pFile->eFileLock = eFileLock;
  return rc;
................................................................................
** even on VxWorks.  A mutex will be acquired on VxWorks by the
** vxworksReleaseFileId() routine.
*/
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 OS_VXWORKS
    if( pFile->pId ){
      if( pFile->isDelete ){
        unlink(pFile->pId->zCanonicalName);
      }
      vxworksReleaseFileId(pFile->pId);
................................................................................
      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
      if( IS_LOCK_ERROR(rc) ){
        pFile->lastErrno = tErrno;
      }
    }
    return rc;
  } 
  robust_close(pFile, fd, __LINE__);



  
  /* got it, set the type and return ok */
  pFile->eFileLock = eFileLock;
  return rc;
}

/*
................................................................................
        pFile->eFileLock = NO_LOCK;
      }
    }
    if( rc==SQLITE_OK ){
      pInode->nLock--;
      assert( pInode->nLock>=0 );
      if( pInode->nLock==0 ){
        closePendingFds(pFile);
      }
    }
  }
  
  unixLeaveMutex();
  if( rc==SQLITE_OK ) pFile->eFileLock = eFileLock;
  return rc;
................................................................................
  rc = full_fsync(pFile->h, isFullsync, isDataOnly);
  SimulateIOError( rc=1 );
  if( rc ){
    pFile->lastErrno = errno;
    return unixLogError(SQLITE_IOERR_FSYNC, "full_fsync", pFile->zPath);
  }
  if( pFile->dirfd>=0 ){

    OSTRACE(("DIRSYNC %-3d (have_fullfsync=%d fullsync=%d)\n", pFile->dirfd,
            HAVE_FULLFSYNC, isFullsync));
#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.
    */
................................................................................
       ** A failed directory sync is not a big deal.  So it seems
       ** better to ignore the error.  Ticket #1657
       */
       /* pFile->lastErrno = errno; */
       /* return SQLITE_IOERR; */
    }
#endif
    /* Only need to sync once, so close the  directory when we are done */
    robust_close(pFile, pFile->dirfd, __LINE__);
    pFile->dirfd = -1;




  }
  return rc;
}

/*
** Truncate an open file to a specified size
*/
................................................................................
    int i;
    assert( p->pInode==pFd->pInode );
    if( p->mutex ) sqlite3_mutex_free(p->mutex);
    for(i=0; i<p->nRegion; i++){
      munmap(p->apRegion[i], p->szRegion);
    }
    sqlite3_free(p->apRegion);
    if( p->h>=0 ){
      robust_close(pFd, p->h, __LINE__);
      p->h = -1;
    }
    p->pInode->pShmNode = 0;
    sqlite3_free(p);
  }
}

/*
** Open a shared-memory area associated with open database file pDbFd.  
................................................................................
      ** handle h - as it is guaranteed that no posix locks will be released
      ** by doing so.
      **
      ** If scenario (a) caused the error then things are not so safe. The
      ** implicit assumption here is that if fstat() fails, things are in
      ** such bad shape that dropping a lock or two doesn't matter much.
      */
      robust_close(pNew, h, __LINE__);
      h = -1;
    }
    unixLeaveMutex();
  }

#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
  else if( pLockingStyle == &afpIoMethods ){
................................................................................
      pCtx->dbPath = zFilename;
      pCtx->reserved = 0;
      srandomdev();
      unixEnterMutex();
      rc = findInodeInfo(pNew, &pNew->pInode);
      if( rc!=SQLITE_OK ){
        sqlite3_free(pNew->lockingContext);
        robust_close(pNew, h, __LINE__);
        h = -1;
      }
      unixLeaveMutex();        
    }
  }
#endif

................................................................................
    unixLeaveMutex();
  }
#endif
  
  pNew->lastErrno = 0;
#if OS_VXWORKS
  if( rc!=SQLITE_OK ){
    if( h>=0 ) robust_close(pNew, h, __LINE__);
    h = -1;
    unlink(zFilename);
    isDelete = 0;
  }
  pNew->isDelete = isDelete;
#endif
  if( rc!=SQLITE_OK ){
    if( dirfd>=0 ) robust_close(pNew, dirfd, __LINE__);
    if( h>=0 ) robust_close(pNew, h, __LINE__);
  }else{
    pNew->pMethod = pLockingStyle;
    OpenCounter(+1);
  }
  return rc;
}

................................................................................
    rc = openDirectory(zPath, &dirfd);
    if( rc!=SQLITE_OK ){
      /* It is safe to close fd at this point, because it is guaranteed not
      ** to be open on a database file. If it were open on a database file,
      ** it would not be safe to close as this would release any locks held
      ** on the file by this process.  */
      assert( eType!=SQLITE_OPEN_MAIN_DB );
      robust_close(p, fd, __LINE__);
      goto open_finished;
    }
  }

#ifdef FD_CLOEXEC
  fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
#endif
................................................................................
  noLock = eType!=SQLITE_OPEN_MAIN_DB;

  
#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE
  struct statfs fsInfo;
  if( fstatfs(fd, &fsInfo) == -1 ){
    ((unixFile*)pFile)->lastErrno = errno;
    if( dirfd>=0 ) robust_close(p, dirfd, __LINE__);
    robust_close(p, fd, __LINE__);
    return SQLITE_IOERR_ACCESS;
  }
  if (0 == strncmp("msdos", fsInfo.f_fstypename, 5)) {
    ((unixFile*)pFile)->fsFlags |= SQLITE_FSFLAGS_IS_MSDOS;
  }
#endif
  
................................................................................
        ** on that file that are currently holding advisory locks on it,
        ** then the call to close() will cancel those locks. In practice,
        ** we're assuming that statfs() doesn't fail very often. At least
        ** not while other file descriptors opened by the same process on
        ** the same file are working.  */
        p->lastErrno = errno;
        if( dirfd>=0 ){
          robust_close(p, dirfd, __LINE__);
        }
        robust_close(p, fd, __LINE__);
        rc = SQLITE_IOERR_ACCESS;
        goto open_finished;
      }
      useProxy = !(fsInfo.f_flags&MNT_LOCAL);
    }
    if( useProxy ){
      rc = fillInUnixFile(pVfs, fd, dirfd, pFile, zPath, noLock, isDelete);
................................................................................
      if( fsync(fd)==-1 )
#else
      if( fsync(fd) )
#endif
      {
        rc = unixLogError(SQLITE_IOERR_DIR_FSYNC, "fsync", zPath);
      }
      robust_close(0, fd, __LINE__);


    }
  }
#endif
  return rc;
}

/*
................................................................................
      memcpy(zBuf, &t, sizeof(t));
      pid = getpid();
      memcpy(&zBuf[sizeof(t)], &pid, sizeof(pid));
      assert( sizeof(t)+sizeof(pid)<=(size_t)nBuf );
      nBuf = sizeof(t) + sizeof(pid);
    }else{
      do{ nBuf = read(fd, zBuf, nBuf); }while( nBuf<0 && errno==EINTR );
      robust_close(0, fd, __LINE__);
    }
  }
#endif
  return nBuf;
}


................................................................................
  
  rc = fillInUnixFile(&dummyVfs, fd, dirfd, (sqlite3_file*)pNew, path, 0, 0);
  if( rc==SQLITE_OK ){
    *ppFile = pNew;
    return SQLITE_OK;
  }
end_create_proxy:    
  robust_close(pNew, fd, __LINE__);
  sqlite3_free(pNew);
  sqlite3_free(pUnused);
  return rc;
}

#ifdef SQLITE_TEST
/* simulate multiple hosts by creating unique hostid file paths */
................................................................................
  }
  if( rename(tPath, cPath) ){
    sqlite3_snprintf(sizeof(errmsg), errmsg, "rename failed (%d)", errno);
    goto end_breaklock;
  }
  rc = 0;
  fprintf(stderr, "broke stale lock on %s\n", cPath);
  robust_close(pFile, conchFile->h, __LINE__);
  conchFile->h = fd;
  conchFile->openFlags = O_RDWR | O_CREAT;

end_breaklock:
  if( rc ){
    if( fd>=0 ){
      unlink(tPath);
      robust_close(pFile, fd, __LINE__);
    }
    fprintf(stderr, "failed to break stale lock on %s, %s\n", cPath, errmsg);
  }
  return rc;
}

/* Take the requested lock on the conch file and break a stale lock if the 
................................................................................
      }
      conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, SHARED_LOCK);
      
    end_takeconch:
      OSTRACE(("TRANSPROXY: CLOSE  %d\n", pFile->h));
      if( rc==SQLITE_OK && pFile->openFlags ){
        if( pFile->h>=0 ){
          robust_close(pFile, pFile->h, __LINE__) ){







        }
        pFile->h = -1;
        int fd = open(pCtx->dbPath, pFile->openFlags,
                      SQLITE_DEFAULT_FILE_PERMISSIONS);
        OSTRACE(("TRANSPROXY: OPEN  %d\n", fd));
        if( fd>=0 ){
          pFile->h = fd;

Changes to test/oserror.test.

52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
    for {set i 0} {$i < 2000} {incr i} { sqlite3 dbh_$i test.db -readonly 1 }
  } msg] $msg
} {1 {unable to open database file}}
do_test 1.1.2 {
  catch { for {set i 0} {$i < 2000} {incr i} { dbh_$i close } }
} {1}

do_re_test 1.1.3 { lindex $::log 0 } {^os_unix.c: open.*test.db$}


# Test a failure in open() due to the path being a directory.
#
do_test 1.2.1 {
  file mkdir dir.db
  set ::log [list]
  list [catch { sqlite3 dbh dir.db } msg] $msg
} {1 {unable to open database file}}

do_re_test 1.2.2 { lindex $::log 0 } {^os_unix.c: open.*dir.db$}

# Test a failure in open() due to the path not existing.
#
do_test 1.3.1 {
  set ::log [list]
  list [catch { sqlite3 dbh /x/y/z/test.db } msg] $msg
} {1 {unable to open database file}}

do_re_test 1.3.2 { lindex $::log 0 } {^os_unix.c: open.*test.db$}

# Test a failure in open() due to the path not existing.
#
do_test 1.4.1 {
  set ::log [list]
  list [catch { sqlite3 dbh /root/test.db } msg] $msg
} {1 {unable to open database file}}

do_re_test 1.4.2 { lindex $::log 0 } {^os_unix.c: open.*test.db$}

#--------------------------------------------------------------------------
# Tests oserror-1.* test failures in the unlink() system call.
#
do_test 2.1.1 {
  set ::log [list]
  file mkdir test.db-wal
  forcedelete test.db
  sqlite3 dbh test.db
  catchsql { SELECT * FROM sqlite_master } dbh
} {1 {disk I/O error}}

do_re_test 2.1.2 { lindex $::log 0 } {^os_unix.c: unlink.*test.db-wal$}
do_test 2.1.3 { 
  dbh close
  forcedelete test.db-wal
} {}
  

sqlite3_shutdown
test_sqlite3_log 
sqlite3_initialize
finish_test
  







|










|








|








|












|










<
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111

    for {set i 0} {$i < 2000} {incr i} { sqlite3 dbh_$i test.db -readonly 1 }
  } msg] $msg
} {1 {unable to open database file}}
do_test 1.1.2 {
  catch { for {set i 0} {$i < 2000} {incr i} { dbh_$i close } }
} {1}

do_re_test 1.1.3 { lindex $::log 0 } {^os_unix.c:\d*: \(24\) open\(.*test.db\) - }


# Test a failure in open() due to the path being a directory.
#
do_test 1.2.1 {
  file mkdir dir.db
  set ::log [list]
  list [catch { sqlite3 dbh dir.db } msg] $msg
} {1 {unable to open database file}}

do_re_test 1.2.2 { lindex $::log 0 } {^os_unix.c:\d*: \(21\) open\(.*dir.db\) - }

# Test a failure in open() due to the path not existing.
#
do_test 1.3.1 {
  set ::log [list]
  list [catch { sqlite3 dbh /x/y/z/test.db } msg] $msg
} {1 {unable to open database file}}

do_re_test 1.3.2 { lindex $::log 0 } {^os_unix.c:\d*: \(2\) open\(.*test.db\) - }

# Test a failure in open() due to the path not existing.
#
do_test 1.4.1 {
  set ::log [list]
  list [catch { sqlite3 dbh /root/test.db } msg] $msg
} {1 {unable to open database file}}

do_re_test 1.4.2 { lindex $::log 0 } {^os_unix.c:\d*: \(13\) open\(.*test.db\) - }

#--------------------------------------------------------------------------
# Tests oserror-1.* test failures in the unlink() system call.
#
do_test 2.1.1 {
  set ::log [list]
  file mkdir test.db-wal
  forcedelete test.db
  sqlite3 dbh test.db
  catchsql { SELECT * FROM sqlite_master } dbh
} {1 {disk I/O error}}

do_re_test 2.1.2 { lindex $::log 0 } {^os_unix.c:\d*: \(21\) unlink\(.*test.db-wal\) - }
do_test 2.1.3 { 
  dbh close
  forcedelete test.db-wal
} {}
  

sqlite3_shutdown
test_sqlite3_log 
sqlite3_initialize
finish_test