|  | This is a backport of the following sqlite changes: | 
|  |  | 
|  | 1. http://sqlite.org/src/ci/9109128cb5 | 
|  | 2. http://sqlite.org/src/ci/713b1b7dc1 | 
|  | 3. http://sqlite.org/src/ci/8d1b5c3ac0 | 
|  | 4. http://sqlite.org/src/ci/6b236069e1 | 
|  | 5. http://sqlite.org/src/ci/880b51150a | 
|  |  | 
|  | which are needed for experiments with using unpatched sqlite. | 
|  | If you hit a merge conflict on this file it is most likely | 
|  | that you've upgraded to version of sqlite that includes those patches. | 
|  | diff --git a/third_party/sqlite/amalgamation/sqlite3.c b/third_party/sqlite/amalgamation/sqlite3.c | 
|  | index 3e794a9..73ff15f 100644 | 
|  | --- a/third_party/sqlite/amalgamation/sqlite3.c | 
|  | +++ b/third_party/sqlite/amalgamation/sqlite3.c | 
|  | @@ -24144,7 +24144,6 @@ struct unixFile { | 
|  | sqlite3_io_methods const *pMethod;  /* Always the first entry */ | 
|  | unixInodeInfo *pInode;              /* Info about locks on this inode */ | 
|  | int h;                              /* The file descriptor */ | 
|  | -  int dirfd;                          /* File descriptor for the directory */ | 
|  | unsigned char eFileLock;            /* The type of lock held on this fd */ | 
|  | unsigned char ctrlFlags;            /* Behavioral bits.  UNIXFILE_* flags */ | 
|  | int lastErrno;                      /* The unix errno from last I/O error */ | 
|  | @@ -24188,6 +24187,7 @@ struct unixFile { | 
|  | */ | 
|  | #define UNIXFILE_EXCL   0x01     /* Connections from one process only */ | 
|  | #define UNIXFILE_RDONLY 0x02     /* Connection is read only */ | 
|  | +#define UNIXFILE_DIRSYNC 0x04    /* Directory sync needed */ | 
|  |  | 
|  | /* | 
|  | ** Include code that is common to all os_*.c files | 
|  | @@ -24426,6 +24426,9 @@ SQLITE_API int sqlite3_open_file_count = 0; | 
|  | #define threadid 0 | 
|  | #endif | 
|  |  | 
|  | +/* Forward reference */ | 
|  | +static int openDirectory(const char*, int*); | 
|  | + | 
|  | /* | 
|  | ** Many system calls are accessed through pointer-to-functions so that | 
|  | ** they may be overridden at runtime to facilitate fault injection during | 
|  | @@ -24522,6 +24525,12 @@ static struct unix_syscall { | 
|  | #endif | 
|  | #define osFallocate ((int(*)(int,off_t,off_t))aSyscall[15].pCurrent) | 
|  |  | 
|  | +  { "unlink",       (sqlite3_syscall_ptr)unlink,           0 }, | 
|  | +#define osUnlink    ((int(*)(const char*))aSyscall[16].pCurrent) | 
|  | + | 
|  | +  { "openDirectory",    (sqlite3_syscall_ptr)openDirectory,      0 }, | 
|  | +#define osOpenDirectory ((int(*)(const char*,int*))aSyscall[17].pCurrent) | 
|  | + | 
|  | }; /* End of the overrideable system calls */ | 
|  |  | 
|  | /* | 
|  | @@ -25876,10 +25885,6 @@ static int unixUnlock(sqlite3_file *id, int eFileLock){ | 
|  | */ | 
|  | static int closeUnixFile(sqlite3_file *id){ | 
|  | unixFile *pFile = (unixFile*)id; | 
|  | -  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; | 
|  | @@ -25887,7 +25892,7 @@ static int closeUnixFile(sqlite3_file *id){ | 
|  | #if OS_VXWORKS | 
|  | if( pFile->pId ){ | 
|  | if( pFile->isDelete ){ | 
|  | -      unlink(pFile->pId->zCanonicalName); | 
|  | +      osUnlink(pFile->pId->zCanonicalName); | 
|  | } | 
|  | vxworksReleaseFileId(pFile->pId); | 
|  | pFile->pId = 0; | 
|  | @@ -26134,7 +26139,7 @@ static int dotlockUnlock(sqlite3_file *id, int eFileLock) { | 
|  |  | 
|  | /* To fully unlock the database, delete the lock file */ | 
|  | assert( eFileLock==NO_LOCK ); | 
|  | -  if( unlink(zLockFile) ){ | 
|  | +  if( osUnlink(zLockFile) ){ | 
|  | int rc = 0; | 
|  | int tErrno = errno; | 
|  | if( ENOENT != tErrno ){ | 
|  | @@ -27371,6 +27376,50 @@ static int full_fsync(int fd, int fullSync, int dataOnly){ | 
|  | } | 
|  |  | 
|  | /* | 
|  | +** Open a file descriptor to the directory containing file zFilename. | 
|  | +** If successful, *pFd is set to the opened file descriptor and | 
|  | +** SQLITE_OK is returned. If an error occurs, either SQLITE_NOMEM | 
|  | +** or SQLITE_CANTOPEN is returned and *pFd is set to an undefined | 
|  | +** value. | 
|  | +** | 
|  | +** The directory file descriptor is used for only one thing - to | 
|  | +** fsync() a directory to make sure file creation and deletion events | 
|  | +** are flushed to disk.  Such fsyncs are not needed on newer | 
|  | +** journaling filesystems, but are required on older filesystems. | 
|  | +** | 
|  | +** This routine can be overridden using the xSetSysCall interface. | 
|  | +** The ability to override this routine was added in support of the | 
|  | +** chromium sandbox.  Opening a directory is a security risk (we are | 
|  | +** told) so making it overrideable allows the chromium sandbox to | 
|  | +** replace this routine with a harmless no-op.  To make this routine | 
|  | +** a no-op, replace it with a stub that returns SQLITE_OK but leaves | 
|  | +** *pFd set to a negative number. | 
|  | +** | 
|  | +** If SQLITE_OK is returned, the caller is responsible for closing | 
|  | +** the file descriptor *pFd using close(). | 
|  | +*/ | 
|  | +static int openDirectory(const char *zFilename, int *pFd){ | 
|  | +  int ii; | 
|  | +  int fd = -1; | 
|  | +  char zDirname[MAX_PATHNAME+1]; | 
|  | + | 
|  | +  sqlite3_snprintf(MAX_PATHNAME, zDirname, "%s", zFilename); | 
|  | +  for(ii=(int)strlen(zDirname); ii>1 && zDirname[ii]!='/'; ii--); | 
|  | +  if( ii>0 ){ | 
|  | +    zDirname[ii] = '\0'; | 
|  | +    fd = robust_open(zDirname, O_RDONLY|O_BINARY, 0); | 
|  | +    if( fd>=0 ){ | 
|  | +#ifdef FD_CLOEXEC | 
|  | +      osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC); | 
|  | +#endif | 
|  | +      OSTRACE(("OPENDIR %-3d %s\n", fd, zDirname)); | 
|  | +    } | 
|  | +  } | 
|  | +  *pFd = fd; | 
|  | +  return (fd>=0?SQLITE_OK:unixLogError(SQLITE_CANTOPEN_BKPT, "open", zDirname)); | 
|  | +} | 
|  | + | 
|  | +/* | 
|  | ** Make sure all writes to a particular file are committed to disk. | 
|  | ** | 
|  | ** If dataOnly==0 then both the file itself and its metadata (file | 
|  | @@ -27410,28 +27459,21 @@ static int unixSync(sqlite3_file *id, int flags){ | 
|  | 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, | 
|  | + | 
|  | +  /* Also fsync the directory containing the file if the DIRSYNC flag | 
|  | +  ** is set.  This is a one-time occurrance.  Many systems (examples: AIX) | 
|  | +  ** are unable to fsync a directory, so ignore errors on the fsync. | 
|  | +  */ | 
|  | +  if( pFile->ctrlFlags & UNIXFILE_DIRSYNC ){ | 
|  | +    int dirfd; | 
|  | +    OSTRACE(("DIRSYNC %s (have_fullfsync=%d fullsync=%d)\n", pFile->zPath, | 
|  | 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. | 
|  | -    */ | 
|  | -    if( (!HAVE_FULLFSYNC || !isFullsync) && 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 | 
|  | -       */ | 
|  | -       /* pFile->lastErrno = errno; */ | 
|  | -       /* return SQLITE_IOERR; */ | 
|  | +    rc = osOpenDirectory(pFile->zPath, &dirfd); | 
|  | +    if( rc==SQLITE_OK && dirfd>=0 ){ | 
|  | +      full_fsync(dirfd, 0, 0); | 
|  | +      robust_close(pFile, dirfd, __LINE__); | 
|  | } | 
|  | -#endif | 
|  | -    /* Only need to sync once, so close the  directory when we are done */ | 
|  | -    robust_close(pFile, pFile->dirfd, __LINE__); | 
|  | -    pFile->dirfd = -1; | 
|  | +    pFile->ctrlFlags &= ~UNIXFILE_DIRSYNC; | 
|  | } | 
|  | return rc; | 
|  | } | 
|  | @@ -28255,7 +28297,7 @@ static int unixShmUnmap( | 
|  | assert( pShmNode->nRef>0 ); | 
|  | pShmNode->nRef--; | 
|  | if( pShmNode->nRef==0 ){ | 
|  | -    if( deleteFlag && pShmNode->h>=0 ) unlink(pShmNode->zFilename); | 
|  | +    if( deleteFlag && pShmNode->h>=0 ) osUnlink(pShmNode->zFilename); | 
|  | unixShmPurge(pDbFd); | 
|  | } | 
|  | unixLeaveMutex(); | 
|  | @@ -28575,7 +28617,7 @@ void initUnixFile(sqlite3_file* file) { | 
|  | int fillInUnixFile( | 
|  | sqlite3_vfs *pVfs,      /* Pointer to vfs object */ | 
|  | int h,                  /* Open file descriptor of file being opened */ | 
|  | -  int dirfd,              /* Directory file descriptor */ | 
|  | +  int syncDir,            /* True to sync directory on first sync */ | 
|  | sqlite3_file *pId,      /* Write to the unixFile structure here */ | 
|  | const char *zFilename,  /* Name of the file being opened */ | 
|  | int noLock,             /* Omit locking if true */ | 
|  | @@ -28606,7 +28648,6 @@ int fillInUnixFile( | 
|  |  | 
|  | OSTRACE(("OPEN    %-3d %s\n", h, zFilename)); | 
|  | pNew->h = h; | 
|  | -  pNew->dirfd = dirfd; | 
|  | pNew->zPath = zFilename; | 
|  | if( memcmp(pVfs->zName,"unix-excl",10)==0 ){ | 
|  | pNew->ctrlFlags = UNIXFILE_EXCL; | 
|  | @@ -28616,6 +28657,9 @@ int fillInUnixFile( | 
|  | if( isReadOnly ){ | 
|  | pNew->ctrlFlags |= UNIXFILE_RDONLY; | 
|  | } | 
|  | +  if( syncDir ){ | 
|  | +    pNew->ctrlFlags |= UNIXFILE_DIRSYNC; | 
|  | +  } | 
|  |  | 
|  | #if OS_VXWORKS | 
|  | pNew->pId = vxworksFindFileId(zFilename); | 
|  | @@ -28742,13 +28786,12 @@ int fillInUnixFile( | 
|  | if( rc!=SQLITE_OK ){ | 
|  | if( h>=0 ) robust_close(pNew, h, __LINE__); | 
|  | h = -1; | 
|  | -    unlink(zFilename); | 
|  | +    osUnlink(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; | 
|  | @@ -28758,37 +28801,6 @@ int fillInUnixFile( | 
|  | } | 
|  |  | 
|  | /* | 
|  | -** Open a file descriptor to the directory containing file zFilename. | 
|  | -** If successful, *pFd is set to the opened file descriptor and | 
|  | -** SQLITE_OK is returned. If an error occurs, either SQLITE_NOMEM | 
|  | -** or SQLITE_CANTOPEN is returned and *pFd is set to an undefined | 
|  | -** value. | 
|  | -** | 
|  | -** If SQLITE_OK is returned, the caller is responsible for closing | 
|  | -** the file descriptor *pFd using close(). | 
|  | -*/ | 
|  | -static int openDirectory(const char *zFilename, int *pFd){ | 
|  | -  int ii; | 
|  | -  int fd = -1; | 
|  | -  char zDirname[MAX_PATHNAME+1]; | 
|  | - | 
|  | -  sqlite3_snprintf(MAX_PATHNAME, zDirname, "%s", zFilename); | 
|  | -  for(ii=(int)strlen(zDirname); ii>1 && zDirname[ii]!='/'; ii--); | 
|  | -  if( ii>0 ){ | 
|  | -    zDirname[ii] = '\0'; | 
|  | -    fd = robust_open(zDirname, O_RDONLY|O_BINARY, 0); | 
|  | -    if( fd>=0 ){ | 
|  | -#ifdef FD_CLOEXEC | 
|  | -      osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC); | 
|  | -#endif | 
|  | -      OSTRACE(("OPENDIR %-3d %s\n", fd, zDirname)); | 
|  | -    } | 
|  | -  } | 
|  | -  *pFd = fd; | 
|  | -  return (fd>=0?SQLITE_OK:unixLogError(SQLITE_CANTOPEN_BKPT, "open", zDirname)); | 
|  | -} | 
|  | - | 
|  | -/* | 
|  | ** Return the name of a directory in which to put temporary files. | 
|  | ** If no suitable temporary file directory can be found, return NULL. | 
|  | */ | 
|  | @@ -29083,7 +29095,6 @@ static int unixOpen( | 
|  | ){ | 
|  | unixFile *p = (unixFile *)pFile; | 
|  | int fd = -1;                   /* File descriptor returned by open() */ | 
|  | -  int dirfd = -1;                /* Directory file descriptor */ | 
|  | int openFlags = 0;             /* Flags to pass to open() */ | 
|  | int eType = flags&0xFFFFFF00;  /* Type of file to open */ | 
|  | int noLock;                    /* True to omit locking primitives */ | 
|  | @@ -29102,7 +29113,7 @@ static int unixOpen( | 
|  | ** a file-descriptor on the directory too. The first time unixSync() | 
|  | ** is called the directory file descriptor will be fsync()ed and close()d. | 
|  | */ | 
|  | -  int isOpenDirectory = (isCreate && ( | 
|  | +  int syncDir = (isCreate && ( | 
|  | eType==SQLITE_OPEN_MASTER_JOURNAL | 
|  | || eType==SQLITE_OPEN_MAIN_JOURNAL | 
|  | || eType==SQLITE_OPEN_WAL | 
|  | @@ -29149,7 +29160,7 @@ static int unixOpen( | 
|  | } | 
|  | }else if( !zName ){ | 
|  | /* If zName is NULL, the upper layer is requesting a temp file. */ | 
|  | -    assert(isDelete && !isOpenDirectory); | 
|  | +    assert(isDelete && !syncDir); | 
|  | rc = unixGetTempname(MAX_PATHNAME+1, zTmpname); | 
|  | if( rc!=SQLITE_OK ){ | 
|  | return rc; | 
|  | @@ -29202,7 +29213,7 @@ static int unixOpen( | 
|  | #if OS_VXWORKS | 
|  | zPath = zName; | 
|  | #else | 
|  | -    unlink(zName); | 
|  | +    osUnlink(zName); | 
|  | #endif | 
|  | } | 
|  | #if SQLITE_ENABLE_LOCKING_STYLE | 
|  | @@ -29211,19 +29222,6 @@ static int unixOpen( | 
|  | } | 
|  | #endif | 
|  |  | 
|  | -  if( isOpenDirectory ){ | 
|  | -    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 | 
|  | osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC); | 
|  | #endif | 
|  | @@ -29235,7 +29233,6 @@ static int unixOpen( | 
|  | 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; | 
|  | } | 
|  | @@ -29267,9 +29264,6 @@ static int unixOpen( | 
|  | ** 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; | 
|  | @@ -29277,7 +29271,7 @@ static int unixOpen( | 
|  | useProxy = !(fsInfo.f_flags&MNT_LOCAL); | 
|  | } | 
|  | if( useProxy ){ | 
|  | -      rc = fillInUnixFile(pVfs, fd, dirfd, pFile, zPath, noLock, | 
|  | +      rc = fillInUnixFile(pVfs, fd, syncDir, pFile, zPath, noLock, | 
|  | isDelete, isReadonly); | 
|  | if( rc==SQLITE_OK ){ | 
|  | rc = proxyTransformUnixFile((unixFile*)pFile, ":auto:"); | 
|  | @@ -29295,7 +29289,7 @@ static int unixOpen( | 
|  | } | 
|  | #endif | 
|  |  | 
|  | -  rc = fillInUnixFile(pVfs, fd, dirfd, pFile, zPath, noLock, | 
|  | +  rc = fillInUnixFile(pVfs, fd, syncDir, pFile, zPath, noLock, | 
|  | isDelete, isReadonly); | 
|  | open_finished: | 
|  | if( rc!=SQLITE_OK ){ | 
|  | @@ -29317,13 +29311,13 @@ static int unixDelete( | 
|  | int rc = SQLITE_OK; | 
|  | UNUSED_PARAMETER(NotUsed); | 
|  | SimulateIOError(return SQLITE_IOERR_DELETE); | 
|  | -  if( unlink(zPath)==(-1) && errno!=ENOENT ){ | 
|  | +  if( osUnlink(zPath)==(-1) && errno!=ENOENT ){ | 
|  | return unixLogError(SQLITE_IOERR_DELETE, "unlink", zPath); | 
|  | } | 
|  | #ifndef SQLITE_DISABLE_DIRSYNC | 
|  | if( dirSync ){ | 
|  | int fd; | 
|  | -    rc = openDirectory(zPath, &fd); | 
|  | +    rc = osOpenDirectory(zPath, &fd); | 
|  | if( rc==SQLITE_OK ){ | 
|  | #if OS_VXWORKS | 
|  | if( fsync(fd)==-1 ) | 
|  | @@ -29895,7 +29889,6 @@ static int proxyCreateUnixFile( | 
|  | int islockfile           /* if non zero missing dirs will be created */ | 
|  | ) { | 
|  | int fd = -1; | 
|  | -  int dirfd = -1; | 
|  | unixFile *pNew; | 
|  | int rc = SQLITE_OK; | 
|  | int openFlags = O_RDWR | O_CREAT; | 
|  | @@ -29960,7 +29953,7 @@ static int proxyCreateUnixFile( | 
|  | pUnused->flags = openFlags; | 
|  | pNew->pUnused = pUnused; | 
|  |  | 
|  | -  rc = fillInUnixFile(&dummyVfs, fd, dirfd, (sqlite3_file*)pNew, path, 0, 0, 0); | 
|  | +  rc = fillInUnixFile(&dummyVfs, fd, 0, (sqlite3_file*)pNew, path, 0, 0, 0); | 
|  | if( rc==SQLITE_OK ){ | 
|  | *ppFile = pNew; | 
|  | return SQLITE_OK; | 
|  | @@ -30074,7 +30067,7 @@ static int proxyBreakConchLock(unixFile *pFile, uuid_t myHostID){ | 
|  | end_breaklock: | 
|  | if( rc ){ | 
|  | if( fd>=0 ){ | 
|  | -      unlink(tPath); | 
|  | +      osUnlink(tPath); | 
|  | robust_close(pFile, fd, __LINE__); | 
|  | } | 
|  | fprintf(stderr, "failed to break stale lock on %s, %s\n", cPath, errmsg); | 
|  | @@ -30897,7 +30890,7 @@ SQLITE_API int sqlite3_os_init(void){ | 
|  |  | 
|  | /* Double-check that the aSyscall[] array has been constructed | 
|  | ** correctly.  See ticket [bb3a86e890c8e96ab] */ | 
|  | -  assert( ArraySize(aSyscall)==16 ); | 
|  | +  assert( ArraySize(aSyscall)==18 ); | 
|  |  | 
|  | /* Register all VFSes defined in the aVfs[] array */ | 
|  | for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){ | 
|  | diff --git a/third_party/sqlite/src/src/os_unix.c b/third_party/sqlite/src/src/os_unix.c | 
|  | index e5b2540..804c588 100644 | 
|  | --- a/third_party/sqlite/src/src/os_unix.c | 
|  | +++ b/third_party/sqlite/src/src/os_unix.c | 
|  | @@ -204,7 +204,6 @@ struct unixFile { | 
|  | sqlite3_io_methods const *pMethod;  /* Always the first entry */ | 
|  | unixInodeInfo *pInode;              /* Info about locks on this inode */ | 
|  | int h;                              /* The file descriptor */ | 
|  | -  int dirfd;                          /* File descriptor for the directory */ | 
|  | unsigned char eFileLock;            /* The type of lock held on this fd */ | 
|  | unsigned char ctrlFlags;            /* Behavioral bits.  UNIXFILE_* flags */ | 
|  | int lastErrno;                      /* The unix errno from last I/O error */ | 
|  | @@ -248,6 +247,7 @@ struct unixFile { | 
|  | */ | 
|  | #define UNIXFILE_EXCL   0x01     /* Connections from one process only */ | 
|  | #define UNIXFILE_RDONLY 0x02     /* Connection is read only */ | 
|  | +#define UNIXFILE_DIRSYNC 0x04    /* Directory sync needed */ | 
|  |  | 
|  | /* | 
|  | ** Include code that is common to all os_*.c files | 
|  | @@ -281,6 +281,9 @@ struct unixFile { | 
|  | #define threadid 0 | 
|  | #endif | 
|  |  | 
|  | +/* Forward reference */ | 
|  | +static int openDirectory(const char*, int*); | 
|  | + | 
|  | /* | 
|  | ** Many system calls are accessed through pointer-to-functions so that | 
|  | ** they may be overridden at runtime to facilitate fault injection during | 
|  | @@ -377,6 +380,12 @@ static struct unix_syscall { | 
|  | #endif | 
|  | #define osFallocate ((int(*)(int,off_t,off_t))aSyscall[15].pCurrent) | 
|  |  | 
|  | +  { "unlink",       (sqlite3_syscall_ptr)unlink,           0 }, | 
|  | +#define osUnlink    ((int(*)(const char*))aSyscall[16].pCurrent) | 
|  | + | 
|  | +  { "openDirectory",    (sqlite3_syscall_ptr)openDirectory,      0 }, | 
|  | +#define osOpenDirectory ((int(*)(const char*,int*))aSyscall[17].pCurrent) | 
|  | + | 
|  | }; /* End of the overrideable system calls */ | 
|  |  | 
|  | /* | 
|  | @@ -1731,10 +1740,6 @@ static int unixUnlock(sqlite3_file *id, int eFileLock){ | 
|  | */ | 
|  | static int closeUnixFile(sqlite3_file *id){ | 
|  | unixFile *pFile = (unixFile*)id; | 
|  | -  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; | 
|  | @@ -1742,7 +1747,7 @@ static int closeUnixFile(sqlite3_file *id){ | 
|  | #if OS_VXWORKS | 
|  | if( pFile->pId ){ | 
|  | if( pFile->isDelete ){ | 
|  | -      unlink(pFile->pId->zCanonicalName); | 
|  | +      osUnlink(pFile->pId->zCanonicalName); | 
|  | } | 
|  | vxworksReleaseFileId(pFile->pId); | 
|  | pFile->pId = 0; | 
|  | @@ -1989,7 +1994,7 @@ static int dotlockUnlock(sqlite3_file *id, int eFileLock) { | 
|  |  | 
|  | /* To fully unlock the database, delete the lock file */ | 
|  | assert( eFileLock==NO_LOCK ); | 
|  | -  if( unlink(zLockFile) ){ | 
|  | +  if( osUnlink(zLockFile) ){ | 
|  | int rc = 0; | 
|  | int tErrno = errno; | 
|  | if( ENOENT != tErrno ){ | 
|  | @@ -3226,6 +3231,50 @@ static int full_fsync(int fd, int fullSync, int dataOnly){ | 
|  | } | 
|  |  | 
|  | /* | 
|  | +** Open a file descriptor to the directory containing file zFilename. | 
|  | +** If successful, *pFd is set to the opened file descriptor and | 
|  | +** SQLITE_OK is returned. If an error occurs, either SQLITE_NOMEM | 
|  | +** or SQLITE_CANTOPEN is returned and *pFd is set to an undefined | 
|  | +** value. | 
|  | +** | 
|  | +** The directory file descriptor is used for only one thing - to | 
|  | +** fsync() a directory to make sure file creation and deletion events | 
|  | +** are flushed to disk.  Such fsyncs are not needed on newer | 
|  | +** journaling filesystems, but are required on older filesystems. | 
|  | +** | 
|  | +** This routine can be overridden using the xSetSysCall interface. | 
|  | +** The ability to override this routine was added in support of the | 
|  | +** chromium sandbox.  Opening a directory is a security risk (we are | 
|  | +** told) so making it overrideable allows the chromium sandbox to | 
|  | +** replace this routine with a harmless no-op.  To make this routine | 
|  | +** a no-op, replace it with a stub that returns SQLITE_OK but leaves | 
|  | +** *pFd set to a negative number. | 
|  | +** | 
|  | +** If SQLITE_OK is returned, the caller is responsible for closing | 
|  | +** the file descriptor *pFd using close(). | 
|  | +*/ | 
|  | +static int openDirectory(const char *zFilename, int *pFd){ | 
|  | +  int ii; | 
|  | +  int fd = -1; | 
|  | +  char zDirname[MAX_PATHNAME+1]; | 
|  | + | 
|  | +  sqlite3_snprintf(MAX_PATHNAME, zDirname, "%s", zFilename); | 
|  | +  for(ii=(int)strlen(zDirname); ii>1 && zDirname[ii]!='/'; ii--); | 
|  | +  if( ii>0 ){ | 
|  | +    zDirname[ii] = '\0'; | 
|  | +    fd = robust_open(zDirname, O_RDONLY|O_BINARY, 0); | 
|  | +    if( fd>=0 ){ | 
|  | +#ifdef FD_CLOEXEC | 
|  | +      osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC); | 
|  | +#endif | 
|  | +      OSTRACE(("OPENDIR %-3d %s\n", fd, zDirname)); | 
|  | +    } | 
|  | +  } | 
|  | +  *pFd = fd; | 
|  | +  return (fd>=0?SQLITE_OK:unixLogError(SQLITE_CANTOPEN_BKPT, "open", zDirname)); | 
|  | +} | 
|  | + | 
|  | +/* | 
|  | ** Make sure all writes to a particular file are committed to disk. | 
|  | ** | 
|  | ** If dataOnly==0 then both the file itself and its metadata (file | 
|  | @@ -3265,28 +3314,23 @@ static int unixSync(sqlite3_file *id, int flags){ | 
|  | 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, | 
|  | + | 
|  | +  /* Also fsync the directory containing the file if the DIRSYNC flag | 
|  | +  ** is set.  This is a one-time occurrance.  Many systems (examples: AIX) | 
|  | +  ** are unable to fsync a directory, so ignore errors on the fsync. | 
|  | +  */ | 
|  | +  if( pFile->ctrlFlags & UNIXFILE_DIRSYNC ){ | 
|  | +    int dirfd; | 
|  | +    OSTRACE(("DIRSYNC %s (have_fullfsync=%d fullsync=%d)\n", pFile->zPath, | 
|  | 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. | 
|  | -    */ | 
|  | -    if( (!HAVE_FULLFSYNC || !isFullsync) && 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 | 
|  | -       */ | 
|  | -       /* pFile->lastErrno = errno; */ | 
|  | -       /* return SQLITE_IOERR; */ | 
|  | +    rc = osOpenDirectory(pFile->zPath, &dirfd); | 
|  | +    if( rc==SQLITE_OK && dirfd>=0 ){ | 
|  | +      full_fsync(dirfd, 0, 0); | 
|  | +      robust_close(pFile, dirfd, __LINE__); | 
|  | +    }else if( rc==SQLITE_CANTOPEN ){ | 
|  | +      rc = SQLITE_OK; | 
|  | } | 
|  | -#endif | 
|  | -    /* Only need to sync once, so close the  directory when we are done */ | 
|  | -    robust_close(pFile, pFile->dirfd, __LINE__); | 
|  | -    pFile->dirfd = -1; | 
|  | +    pFile->ctrlFlags &= ~UNIXFILE_DIRSYNC; | 
|  | } | 
|  | return rc; | 
|  | } | 
|  | @@ -4110,7 +4154,7 @@ static int unixShmUnmap( | 
|  | assert( pShmNode->nRef>0 ); | 
|  | pShmNode->nRef--; | 
|  | if( pShmNode->nRef==0 ){ | 
|  | -    if( deleteFlag && pShmNode->h>=0 ) unlink(pShmNode->zFilename); | 
|  | +    if( deleteFlag && pShmNode->h>=0 ) osUnlink(pShmNode->zFilename); | 
|  | unixShmPurge(pDbFd); | 
|  | } | 
|  | unixLeaveMutex(); | 
|  | @@ -4430,7 +4474,7 @@ void initUnixFile(sqlite3_file* file) { | 
|  | int fillInUnixFile( | 
|  | sqlite3_vfs *pVfs,      /* Pointer to vfs object */ | 
|  | int h,                  /* Open file descriptor of file being opened */ | 
|  | -  int dirfd,              /* Directory file descriptor */ | 
|  | +  int syncDir,            /* True to sync directory on first sync */ | 
|  | sqlite3_file *pId,      /* Write to the unixFile structure here */ | 
|  | const char *zFilename,  /* Name of the file being opened */ | 
|  | int noLock,             /* Omit locking if true */ | 
|  | @@ -4461,7 +4505,6 @@ int fillInUnixFile( | 
|  |  | 
|  | OSTRACE(("OPEN    %-3d %s\n", h, zFilename)); | 
|  | pNew->h = h; | 
|  | -  pNew->dirfd = dirfd; | 
|  | pNew->zPath = zFilename; | 
|  | if( memcmp(pVfs->zName,"unix-excl",10)==0 ){ | 
|  | pNew->ctrlFlags = UNIXFILE_EXCL; | 
|  | @@ -4471,6 +4514,9 @@ int fillInUnixFile( | 
|  | if( isReadOnly ){ | 
|  | pNew->ctrlFlags |= UNIXFILE_RDONLY; | 
|  | } | 
|  | +  if( syncDir ){ | 
|  | +    pNew->ctrlFlags |= UNIXFILE_DIRSYNC; | 
|  | +  } | 
|  |  | 
|  | #if OS_VXWORKS | 
|  | pNew->pId = vxworksFindFileId(zFilename); | 
|  | @@ -4597,13 +4643,12 @@ int fillInUnixFile( | 
|  | if( rc!=SQLITE_OK ){ | 
|  | if( h>=0 ) robust_close(pNew, h, __LINE__); | 
|  | h = -1; | 
|  | -    unlink(zFilename); | 
|  | +    osUnlink(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; | 
|  | @@ -4613,37 +4658,6 @@ int fillInUnixFile( | 
|  | } | 
|  |  | 
|  | /* | 
|  | -** Open a file descriptor to the directory containing file zFilename. | 
|  | -** If successful, *pFd is set to the opened file descriptor and | 
|  | -** SQLITE_OK is returned. If an error occurs, either SQLITE_NOMEM | 
|  | -** or SQLITE_CANTOPEN is returned and *pFd is set to an undefined | 
|  | -** value. | 
|  | -** | 
|  | -** If SQLITE_OK is returned, the caller is responsible for closing | 
|  | -** the file descriptor *pFd using close(). | 
|  | -*/ | 
|  | -static int openDirectory(const char *zFilename, int *pFd){ | 
|  | -  int ii; | 
|  | -  int fd = -1; | 
|  | -  char zDirname[MAX_PATHNAME+1]; | 
|  | - | 
|  | -  sqlite3_snprintf(MAX_PATHNAME, zDirname, "%s", zFilename); | 
|  | -  for(ii=(int)strlen(zDirname); ii>1 && zDirname[ii]!='/'; ii--); | 
|  | -  if( ii>0 ){ | 
|  | -    zDirname[ii] = '\0'; | 
|  | -    fd = robust_open(zDirname, O_RDONLY|O_BINARY, 0); | 
|  | -    if( fd>=0 ){ | 
|  | -#ifdef FD_CLOEXEC | 
|  | -      osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC); | 
|  | -#endif | 
|  | -      OSTRACE(("OPENDIR %-3d %s\n", fd, zDirname)); | 
|  | -    } | 
|  | -  } | 
|  | -  *pFd = fd; | 
|  | -  return (fd>=0?SQLITE_OK:unixLogError(SQLITE_CANTOPEN_BKPT, "open", zDirname)); | 
|  | -} | 
|  | - | 
|  | -/* | 
|  | ** Return the name of a directory in which to put temporary files. | 
|  | ** If no suitable temporary file directory can be found, return NULL. | 
|  | */ | 
|  | @@ -4938,7 +4952,6 @@ static int unixOpen( | 
|  | ){ | 
|  | unixFile *p = (unixFile *)pFile; | 
|  | int fd = -1;                   /* File descriptor returned by open() */ | 
|  | -  int dirfd = -1;                /* Directory file descriptor */ | 
|  | int openFlags = 0;             /* Flags to pass to open() */ | 
|  | int eType = flags&0xFFFFFF00;  /* Type of file to open */ | 
|  | int noLock;                    /* True to omit locking primitives */ | 
|  | @@ -4957,7 +4970,7 @@ static int unixOpen( | 
|  | ** a file-descriptor on the directory too. The first time unixSync() | 
|  | ** is called the directory file descriptor will be fsync()ed and close()d. | 
|  | */ | 
|  | -  int isOpenDirectory = (isCreate && ( | 
|  | +  int syncDir = (isCreate && ( | 
|  | eType==SQLITE_OPEN_MASTER_JOURNAL | 
|  | || eType==SQLITE_OPEN_MAIN_JOURNAL | 
|  | || eType==SQLITE_OPEN_WAL | 
|  | @@ -5004,7 +5017,7 @@ static int unixOpen( | 
|  | } | 
|  | }else if( !zName ){ | 
|  | /* If zName is NULL, the upper layer is requesting a temp file. */ | 
|  | -    assert(isDelete && !isOpenDirectory); | 
|  | +    assert(isDelete && !syncDir); | 
|  | rc = unixGetTempname(MAX_PATHNAME+1, zTmpname); | 
|  | if( rc!=SQLITE_OK ){ | 
|  | return rc; | 
|  | @@ -5057,7 +5070,7 @@ static int unixOpen( | 
|  | #if OS_VXWORKS | 
|  | zPath = zName; | 
|  | #else | 
|  | -    unlink(zName); | 
|  | +    osUnlink(zName); | 
|  | #endif | 
|  | } | 
|  | #if SQLITE_ENABLE_LOCKING_STYLE | 
|  | @@ -5066,19 +5079,6 @@ static int unixOpen( | 
|  | } | 
|  | #endif | 
|  |  | 
|  | -  if( isOpenDirectory ){ | 
|  | -    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 | 
|  | osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC); | 
|  | #endif | 
|  | @@ -5090,7 +5090,6 @@ static int unixOpen( | 
|  | 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; | 
|  | } | 
|  | @@ -5122,9 +5121,6 @@ static int unixOpen( | 
|  | ** 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; | 
|  | @@ -5132,7 +5128,7 @@ static int unixOpen( | 
|  | useProxy = !(fsInfo.f_flags&MNT_LOCAL); | 
|  | } | 
|  | if( useProxy ){ | 
|  | -      rc = fillInUnixFile(pVfs, fd, dirfd, pFile, zPath, noLock, | 
|  | +      rc = fillInUnixFile(pVfs, fd, syncDir, pFile, zPath, noLock, | 
|  | isDelete, isReadonly); | 
|  | if( rc==SQLITE_OK ){ | 
|  | rc = proxyTransformUnixFile((unixFile*)pFile, ":auto:"); | 
|  | @@ -5150,7 +5146,7 @@ static int unixOpen( | 
|  | } | 
|  | #endif | 
|  |  | 
|  | -  rc = fillInUnixFile(pVfs, fd, dirfd, pFile, zPath, noLock, | 
|  | +  rc = fillInUnixFile(pVfs, fd, syncDir, pFile, zPath, noLock, | 
|  | isDelete, isReadonly); | 
|  | open_finished: | 
|  | if( rc!=SQLITE_OK ){ | 
|  | @@ -5172,13 +5168,13 @@ static int unixDelete( | 
|  | int rc = SQLITE_OK; | 
|  | UNUSED_PARAMETER(NotUsed); | 
|  | SimulateIOError(return SQLITE_IOERR_DELETE); | 
|  | -  if( unlink(zPath)==(-1) && errno!=ENOENT ){ | 
|  | +  if( osUnlink(zPath)==(-1) && errno!=ENOENT ){ | 
|  | return unixLogError(SQLITE_IOERR_DELETE, "unlink", zPath); | 
|  | } | 
|  | #ifndef SQLITE_DISABLE_DIRSYNC | 
|  | if( dirSync ){ | 
|  | int fd; | 
|  | -    rc = openDirectory(zPath, &fd); | 
|  | +    rc = osOpenDirectory(zPath, &fd); | 
|  | if( rc==SQLITE_OK ){ | 
|  | #if OS_VXWORKS | 
|  | if( fsync(fd)==-1 ) | 
|  | @@ -5189,6 +5185,8 @@ static int unixDelete( | 
|  | rc = unixLogError(SQLITE_IOERR_DIR_FSYNC, "fsync", zPath); | 
|  | } | 
|  | robust_close(0, fd, __LINE__); | 
|  | +    }else if( rc==SQLITE_CANTOPEN ){ | 
|  | +      rc = SQLITE_OK; | 
|  | } | 
|  | } | 
|  | #endif | 
|  | @@ -5750,7 +5748,6 @@ static int proxyCreateUnixFile( | 
|  | int islockfile           /* if non zero missing dirs will be created */ | 
|  | ) { | 
|  | int fd = -1; | 
|  | -  int dirfd = -1; | 
|  | unixFile *pNew; | 
|  | int rc = SQLITE_OK; | 
|  | int openFlags = O_RDWR | O_CREAT; | 
|  | @@ -5815,7 +5812,7 @@ static int proxyCreateUnixFile( | 
|  | pUnused->flags = openFlags; | 
|  | pNew->pUnused = pUnused; | 
|  |  | 
|  | -  rc = fillInUnixFile(&dummyVfs, fd, dirfd, (sqlite3_file*)pNew, path, 0, 0, 0); | 
|  | +  rc = fillInUnixFile(&dummyVfs, fd, 0, (sqlite3_file*)pNew, path, 0, 0, 0); | 
|  | if( rc==SQLITE_OK ){ | 
|  | *ppFile = pNew; | 
|  | return SQLITE_OK; | 
|  | @@ -5929,7 +5926,7 @@ static int proxyBreakConchLock(unixFile *pFile, uuid_t myHostID){ | 
|  | end_breaklock: | 
|  | if( rc ){ | 
|  | if( fd>=0 ){ | 
|  | -      unlink(tPath); | 
|  | +      osUnlink(tPath); | 
|  | robust_close(pFile, fd, __LINE__); | 
|  | } | 
|  | fprintf(stderr, "failed to break stale lock on %s, %s\n", cPath, errmsg); | 
|  | @@ -6752,7 +6749,7 @@ int sqlite3_os_init(void){ | 
|  |  | 
|  | /* Double-check that the aSyscall[] array has been constructed | 
|  | ** correctly.  See ticket [bb3a86e890c8e96ab] */ | 
|  | -  assert( ArraySize(aSyscall)==16 ); | 
|  | +  assert( ArraySize(aSyscall)==18 ); | 
|  |  | 
|  | /* Register all VFSes defined in the aVfs[] array */ | 
|  | for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){ | 
|  | diff --git a/third_party/sqlite/src/test/syscall.test b/third_party/sqlite/src/test/syscall.test | 
|  | index 4442612..201bd63 100644 | 
|  | --- a/third_party/sqlite/src/test/syscall.test | 
|  | +++ b/third_party/sqlite/src/test/syscall.test | 
|  | @@ -59,7 +59,7 @@ do_test 2.1.2 { test_syscall exists nosuchcall } 0 | 
|  | foreach s { | 
|  | open close access getcwd stat fstat ftruncate | 
|  | fcntl read pread write pwrite fchmod fallocate | 
|  | -    pread64 pwrite64 | 
|  | +    pread64 pwrite64 unlink openDirectory | 
|  | } { | 
|  | if {[test_syscall exists $s]} {lappend syscall_list $s} | 
|  | } | 
|  | diff --git a/third_party/sqlite/system-sqlite.patch b/third_party/sqlite/system-sqlite.patch | 
|  | index f61f019..31d6b00 100644 | 
|  | --- a/third_party/sqlite/system-sqlite.patch | 
|  | +++ b/third_party/sqlite/system-sqlite.patch | 
|  | @@ -1,48 +0,0 @@ | 
|  | -This is a backport of http://sqlite.org/src/ci/9109128cb5, | 
|  | -which is needed for experiments with using unpatched sqlite. | 
|  | -If you hit a merge conflict on this file it is most likely | 
|  | -that you've upgraded to version of sqlite that includes this patch. | 
|  | -Index: src/os_unix.c | 
|  | -=================================================================== | 
|  | ---- src/os_unix.c | 
|  | -+++ src/os_unix.c | 
|  | -@@ -4787,11 +4787,11 @@ | 
|  | -   ** ignored and -1 is returned. The caller will try to open a new file | 
|  | -   ** descriptor on the same path, fail, and return an error to SQLite. | 
|  | -   ** | 
|  | -   ** Even if a subsequent open() call does succeed, the consequences of | 
|  | -   ** not searching for a resusable file descriptor are not dire.  */ | 
|  | --  if( 0==stat(zPath, &sStat) ){ | 
|  | -+  if( 0==osStat(zPath, &sStat) ){ | 
|  | -     unixInodeInfo *pInode; | 
|  | - | 
|  | -     unixEnterMutex(); | 
|  | -     pInode = inodeList; | 
|  | -     while( pInode && (pInode->fileId.dev!=sStat.st_dev | 
|  | -@@ -4863,11 +4863,11 @@ | 
|  | -     while( nDb>0 && zPath[nDb]!='-' ) nDb--; | 
|  | -     if( nDb==0 ) return SQLITE_OK; | 
|  | -     memcpy(zDb, zPath, nDb); | 
|  | -     zDb[nDb] = '\0'; | 
|  | - | 
|  | --    if( 0==stat(zDb, &sStat) ){ | 
|  | -+    if( 0==osStat(zDb, &sStat) ){ | 
|  | -       *pMode = sStat.st_mode & 0777; | 
|  | -     }else{ | 
|  | -       rc = SQLITE_IOERR_FSTAT; | 
|  | -     } | 
|  | -   }else if( flags & SQLITE_OPEN_DELETEONCLOSE ){ | 
|  | -@@ -5208,11 +5208,11 @@ | 
|  | -       assert(!"Invalid flags argument"); | 
|  | -   } | 
|  | -   *pResOut = (osAccess(zPath, amode)==0); | 
|  | -   if( flags==SQLITE_ACCESS_EXISTS && *pResOut ){ | 
|  | -     struct stat buf; | 
|  | --    if( 0==stat(zPath, &buf) && buf.st_size==0 ){ | 
|  | -+    if( 0==osStat(zPath, &buf) && buf.st_size==0 ){ | 
|  | -       *pResOut = 0; | 
|  | -     } | 
|  | -   } | 
|  | -   return SQLITE_OK; | 
|  | - } | 
|  | - |