| Index: third_party/sqlite/src/src/os_unix.c
|
| diff --git a/third_party/sqlite/src/src/os_unix.c b/third_party/sqlite/src/src/os_unix.c
|
| index e1228e3e5590d5b39b012209a72e2a8488f0e39b..60981af7e738e70bc6d827683c4ef0ae41e2e091 100644
|
| --- a/third_party/sqlite/src/src/os_unix.c
|
| +++ b/third_party/sqlite/src/src/os_unix.c
|
| @@ -71,6 +71,19 @@
|
| # endif
|
| #endif
|
|
|
| +/* Use pread() and pwrite() if they are available */
|
| +#if defined(__APPLE__)
|
| +# define HAVE_PREAD 1
|
| +# define HAVE_PWRITE 1
|
| +#endif
|
| +#if defined(HAVE_PREAD64) && defined(HAVE_PWRITE64)
|
| +# undef USE_PREAD
|
| +# define USE_PREAD64 1
|
| +#elif defined(HAVE_PREAD) && defined(HAVE_PWRITE)
|
| +# undef USE_PREAD64
|
| +# define USE_PREAD 1
|
| +#endif
|
| +
|
| /*
|
| ** standard include files.
|
| */
|
| @@ -149,6 +162,11 @@
|
| */
|
| #define MAX_PATHNAME 512
|
|
|
| +/*
|
| +** Maximum supported symbolic links
|
| +*/
|
| +#define SQLITE_MAX_SYMLINKS 100
|
| +
|
| /* Always cast the getpid() return type for compatibility with
|
| ** kernel modules in VxWorks. */
|
| #define osGetpid(X) (pid_t)getpid()
|
| @@ -387,7 +405,7 @@ static struct unix_syscall {
|
| #else
|
| { "pread64", (sqlite3_syscall_ptr)0, 0 },
|
| #endif
|
| -#define osPread64 ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[10].pCurrent)
|
| +#define osPread64 ((ssize_t(*)(int,void*,size_t,off64_t))aSyscall[10].pCurrent)
|
|
|
| { "write", (sqlite3_syscall_ptr)write, 0 },
|
| #define osWrite ((ssize_t(*)(int,const void*,size_t))aSyscall[11].pCurrent)
|
| @@ -405,7 +423,7 @@ static struct unix_syscall {
|
| #else
|
| { "pwrite64", (sqlite3_syscall_ptr)0, 0 },
|
| #endif
|
| -#define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off_t))\
|
| +#define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off64_t))\
|
| aSyscall[13].pCurrent)
|
|
|
| { "fchmod", (sqlite3_syscall_ptr)fchmod, 0 },
|
| @@ -430,33 +448,57 @@ static struct unix_syscall {
|
| { "rmdir", (sqlite3_syscall_ptr)rmdir, 0 },
|
| #define osRmdir ((int(*)(const char*))aSyscall[19].pCurrent)
|
|
|
| +#if defined(HAVE_FCHOWN)
|
| { "fchown", (sqlite3_syscall_ptr)fchown, 0 },
|
| +#else
|
| + { "fchown", (sqlite3_syscall_ptr)0, 0 },
|
| +#endif
|
| #define osFchown ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent)
|
|
|
| { "geteuid", (sqlite3_syscall_ptr)geteuid, 0 },
|
| #define osGeteuid ((uid_t(*)(void))aSyscall[21].pCurrent)
|
|
|
| #if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
|
| - { "mmap", (sqlite3_syscall_ptr)mmap, 0 },
|
| + { "mmap", (sqlite3_syscall_ptr)mmap, 0 },
|
| +#else
|
| + { "mmap", (sqlite3_syscall_ptr)0, 0 },
|
| +#endif
|
| #define osMmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[22].pCurrent)
|
|
|
| +#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
|
| { "munmap", (sqlite3_syscall_ptr)munmap, 0 },
|
| +#else
|
| + { "munmap", (sqlite3_syscall_ptr)0, 0 },
|
| +#endif
|
| #define osMunmap ((void*(*)(void*,size_t))aSyscall[23].pCurrent)
|
|
|
| -#if HAVE_MREMAP
|
| +#if HAVE_MREMAP && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)
|
| { "mremap", (sqlite3_syscall_ptr)mremap, 0 },
|
| #else
|
| { "mremap", (sqlite3_syscall_ptr)0, 0 },
|
| #endif
|
| #define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[24].pCurrent)
|
|
|
| +#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
|
| { "getpagesize", (sqlite3_syscall_ptr)unixGetpagesize, 0 },
|
| +#else
|
| + { "getpagesize", (sqlite3_syscall_ptr)0, 0 },
|
| +#endif
|
| #define osGetpagesize ((int(*)(void))aSyscall[25].pCurrent)
|
|
|
| +#if defined(HAVE_READLINK)
|
| { "readlink", (sqlite3_syscall_ptr)readlink, 0 },
|
| +#else
|
| + { "readlink", (sqlite3_syscall_ptr)0, 0 },
|
| +#endif
|
| #define osReadlink ((ssize_t(*)(const char*,char*,size_t))aSyscall[26].pCurrent)
|
|
|
| +#if defined(HAVE_LSTAT)
|
| + { "lstat", (sqlite3_syscall_ptr)lstat, 0 },
|
| +#else
|
| + { "lstat", (sqlite3_syscall_ptr)0, 0 },
|
| #endif
|
| +#define osLstat ((int(*)(const char*,struct stat*))aSyscall[27].pCurrent)
|
|
|
| }; /* End of the overrideable system calls */
|
|
|
| @@ -467,10 +509,10 @@ static struct unix_syscall {
|
| ** we are not running as root.
|
| */
|
| static int robustFchown(int fd, uid_t uid, gid_t gid){
|
| -#if OS_VXWORKS
|
| - return 0;
|
| -#else
|
| +#if defined(HAVE_FCHOWN)
|
| return osGeteuid() ? 0 : osFchown(fd,uid,gid);
|
| +#else
|
| + return 0;
|
| #endif
|
| }
|
|
|
| @@ -1019,7 +1061,14 @@ struct unixFileId {
|
| #if OS_VXWORKS
|
| struct vxworksFileId *pId; /* Unique file ID for vxworks. */
|
| #else
|
| - ino_t ino; /* Inode number */
|
| + /* We are told that some versions of Android contain a bug that
|
| + ** sizes ino_t at only 32-bits instead of 64-bits. (See
|
| + ** https://android-review.googlesource.com/#/c/115351/3/dist/sqlite3.c)
|
| + ** To work around this, always allocate 64-bits for the inode number.
|
| + ** On small machines that only have 32-bit inodes, this wastes 4 bytes,
|
| + ** but that should not be a big deal. */
|
| + /* WAS: ino_t ino; */
|
| + u64 ino; /* Inode number */
|
| #endif
|
| };
|
|
|
| @@ -1264,7 +1313,7 @@ static int findInodeInfo(
|
| #if OS_VXWORKS
|
| fileId.pId = pFile->pId;
|
| #else
|
| - fileId.ino = statbuf.st_ino;
|
| + fileId.ino = (u64)statbuf.st_ino;
|
| #endif
|
| pInode = inodeList;
|
| while( pInode && memcmp(&fileId, &pInode->fileId, sizeof(fileId)) ){
|
| @@ -1273,7 +1322,7 @@ static int findInodeInfo(
|
| if( pInode==0 ){
|
| pInode = sqlite3_malloc64( sizeof(*pInode) );
|
| if( pInode==0 ){
|
| - return SQLITE_NOMEM;
|
| + return SQLITE_NOMEM_BKPT;
|
| }
|
| memset(pInode, 0, sizeof(*pInode));
|
| memcpy(&pInode->fileId, &fileId, sizeof(fileId));
|
| @@ -1304,7 +1353,8 @@ static int fileHasMoved(unixFile *pFile){
|
| return 0;
|
|
|
| return pFile->pInode!=0 &&
|
| - (osStat(pFile->zPath, &buf)!=0 || buf.st_ino!=pFile->pInode->fileId.ino);
|
| + (osStat(pFile->zPath, &buf)!=0
|
| + || (u64)buf.st_ino!=pFile->pInode->fileId.ino);
|
| #endif
|
| }
|
|
|
| @@ -1321,12 +1371,16 @@ static int fileHasMoved(unixFile *pFile){
|
| static void verifyDbFile(unixFile *pFile){
|
| struct stat buf;
|
| int rc;
|
| +
|
| + /* These verifications occurs for the main database only */
|
| + if( pFile->ctrlFlags & UNIXFILE_NOLOCK ) return;
|
| +
|
| rc = osFstat(pFile->h, &buf);
|
| if( rc!=0 ){
|
| sqlite3_log(SQLITE_WARNING, "cannot fstat db file %s", pFile->zPath);
|
| return;
|
| }
|
| - if( buf.st_nlink==0 && (pFile->ctrlFlags & UNIXFILE_DELETE)==0 ){
|
| + if( buf.st_nlink==0 ){
|
| sqlite3_log(SQLITE_WARNING, "file unlinked while open: %s", pFile->zPath);
|
| return;
|
| }
|
| @@ -1462,7 +1516,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
|
| ** lock transitions in terms of the POSIX advisory shared and exclusive
|
| ** lock primitives (called read-locks and write-locks below, to avoid
|
| ** confusion with SQLite lock names). The algorithms are complicated
|
| - ** slightly in order to be compatible with windows systems simultaneously
|
| + ** slightly in order to be compatible with Windows95 systems simultaneously
|
| ** accessing the same database file, in case that is ever required.
|
| **
|
| ** Symbols defined in os.h indentify the 'pending byte' and the 'reserved
|
| @@ -1470,8 +1524,14 @@ static int unixLock(sqlite3_file *id, int eFileLock){
|
| ** range', a range of 510 bytes at a well known offset.
|
| **
|
| ** To obtain a SHARED lock, a read-lock is obtained on the 'pending
|
| - ** byte'. If this is successful, a random byte from the 'shared byte
|
| - ** range' is read-locked and the lock on the 'pending byte' released.
|
| + ** byte'. If this is successful, 'shared byte range' is read-locked
|
| + ** and the lock on the 'pending byte' released. (Legacy note: When
|
| + ** SQLite was first developed, Windows95 systems were still very common,
|
| + ** and Widnows95 lacks a shared-lock capability. So on Windows95, a
|
| + ** single randomly selected by from the 'shared byte range' is locked.
|
| + ** Windows95 is now pretty much extinct, but this work-around for the
|
| + ** lack of shared-locks on Windows95 lives on, for backwards
|
| + ** compatibility.)
|
| **
|
| ** A process may only obtain a RESERVED lock after it has a SHARED lock.
|
| ** A RESERVED lock is implemented by grabbing a write-lock on the
|
| @@ -1490,11 +1550,6 @@ static int unixLock(sqlite3_file *id, int eFileLock){
|
| ** range'. Since all other locks require a read-lock on one of the bytes
|
| ** within this range, this ensures that no other locks are held on the
|
| ** database.
|
| - **
|
| - ** The reason a single byte cannot be used instead of the 'shared byte
|
| - ** range' is that some versions of windows do not support read-locks. By
|
| - ** locking a random byte from a range, concurrent SHARED locks may exist
|
| - ** even if the locking primitive used is always a write-lock.
|
| */
|
| int rc = SQLITE_OK;
|
| unixFile *pFile = (unixFile*)id;
|
| @@ -3141,7 +3196,7 @@ static int unixRead(
|
| );
|
| #endif
|
|
|
| -#if defined(SQLITE_MMAP_READWRITE) && SQLITE_MAX_MMAP_SIZE>0
|
| +#if SQLITE_MAX_MMAP_SIZE>0
|
| /* Deal with as much of this read request as possible by transfering
|
| ** data from the memory mapping using memcpy(). */
|
| if( offset<pFile->mmapSize ){
|
| @@ -4199,7 +4254,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
|
|
|
| /* Allocate space for the new unixShm object. */
|
| p = sqlite3_malloc64( sizeof(*p) );
|
| - if( p==0 ) return SQLITE_NOMEM;
|
| + if( p==0 ) return SQLITE_NOMEM_BKPT;
|
| memset(p, 0, sizeof(*p));
|
| assert( pDbFd->pShm==0 );
|
|
|
| @@ -4231,7 +4286,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
|
| #endif
|
| pShmNode = sqlite3_malloc64( sizeof(*pShmNode) + nShmFilename );
|
| if( pShmNode==0 ){
|
| - rc = SQLITE_NOMEM;
|
| + rc = SQLITE_NOMEM_BKPT;
|
| goto shm_open_err;
|
| }
|
| memset(pShmNode, 0, sizeof(*pShmNode)+nShmFilename);
|
| @@ -4247,10 +4302,12 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
|
| pShmNode->h = -1;
|
| pDbFd->pInode->pShmNode = pShmNode;
|
| pShmNode->pInode = pDbFd->pInode;
|
| - pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
|
| - if( pShmNode->mutex==0 ){
|
| - rc = SQLITE_NOMEM;
|
| - goto shm_open_err;
|
| + if( sqlite3GlobalConfig.bCoreMutex ){
|
| + pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
|
| + if( pShmNode->mutex==0 ){
|
| + rc = SQLITE_NOMEM_BKPT;
|
| + goto shm_open_err;
|
| + }
|
| }
|
|
|
| if( pInode->bProcessLock==0 ){
|
| @@ -4422,7 +4479,7 @@ static int unixShmMap(
|
| pShmNode->apRegion, nReqRegion*sizeof(char *)
|
| );
|
| if( !apNew ){
|
| - rc = SQLITE_IOERR_NOMEM;
|
| + rc = SQLITE_IOERR_NOMEM_BKPT;
|
| goto shmpage_out;
|
| }
|
| pShmNode->apRegion = apNew;
|
| @@ -4442,7 +4499,7 @@ static int unixShmMap(
|
| }else{
|
| pMem = sqlite3_malloc64(szRegion);
|
| if( pMem==0 ){
|
| - rc = SQLITE_NOMEM;
|
| + rc = SQLITE_NOMEM_BKPT;
|
| goto shmpage_out;
|
| }
|
| memset(pMem, 0, szRegion);
|
| @@ -5220,7 +5277,7 @@ static int fillInUnixFile(
|
| pNew->pId = vxworksFindFileId(zFilename);
|
| if( pNew->pId==0 ){
|
| ctrlFlags |= UNIXFILE_NOLOCK;
|
| - rc = SQLITE_NOMEM;
|
| + rc = SQLITE_NOMEM_BKPT;
|
| }
|
| #endif
|
|
|
| @@ -5276,7 +5333,7 @@ static int fillInUnixFile(
|
| afpLockingContext *pCtx;
|
| pNew->lockingContext = pCtx = sqlite3_malloc64( sizeof(*pCtx) );
|
| if( pCtx==0 ){
|
| - rc = SQLITE_NOMEM;
|
| + rc = SQLITE_NOMEM_BKPT;
|
| }else{
|
| /* NB: zFilename exists and remains valid until the file is closed
|
| ** according to requirement F11141. So we do not need to make a
|
| @@ -5306,7 +5363,7 @@ static int fillInUnixFile(
|
| nFilename = (int)strlen(zFilename) + 6;
|
| zLockFile = (char *)sqlite3_malloc64(nFilename);
|
| if( zLockFile==0 ){
|
| - rc = SQLITE_NOMEM;
|
| + rc = SQLITE_NOMEM_BKPT;
|
| }else{
|
| sqlite3_snprintf(nFilename, zLockFile, "%s" DOTLOCK_SUFFIX, zFilename);
|
| }
|
| @@ -5329,7 +5386,7 @@ static int fillInUnixFile(
|
| if( zSemName[n]=='/' ) zSemName[n] = '_';
|
| pNew->pInode->pSem = sem_open(zSemName, O_CREAT, 0666, 1);
|
| if( pNew->pInode->pSem == SEM_FAILED ){
|
| - rc = SQLITE_NOMEM;
|
| + rc = SQLITE_NOMEM_BKPT;
|
| pNew->pInode->aSemName[0] = '\0';
|
| }
|
| }
|
| @@ -5369,20 +5426,24 @@ static const char *unixTempFileDir(void){
|
| "/tmp",
|
| "."
|
| };
|
| - unsigned int i;
|
| + unsigned int i = 0;
|
| struct stat buf;
|
| const char *zDir = sqlite3_temp_directory;
|
|
|
| if( !azDirs[0] ) azDirs[0] = getenv("SQLITE_TMPDIR");
|
| if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR");
|
| - for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); zDir=azDirs[i++]){
|
| - if( zDir==0 ) continue;
|
| - if( osStat(zDir, &buf) ) continue;
|
| - if( !S_ISDIR(buf.st_mode) ) continue;
|
| - if( osAccess(zDir, 07) ) continue;
|
| - break;
|
| - }
|
| - return zDir;
|
| + while(1){
|
| + if( zDir!=0
|
| + && osStat(zDir, &buf)==0
|
| + && S_ISDIR(buf.st_mode)
|
| + && osAccess(zDir, 03)==0
|
| + ){
|
| + return zDir;
|
| + }
|
| + if( i>=sizeof(azDirs)/sizeof(azDirs[0]) ) break;
|
| + zDir = azDirs[i++];
|
| + }
|
| + return 0;
|
| }
|
|
|
| /*
|
| @@ -5398,9 +5459,11 @@ static int unixGetTempname(int nBuf, char *zBuf){
|
| ** using the io-error infrastructure to test that SQLite handles this
|
| ** function failing.
|
| */
|
| + zBuf[0] = 0;
|
| SimulateIOError( return SQLITE_IOERR );
|
|
|
| zDir = unixTempFileDir();
|
| + if( zDir==0 ) return SQLITE_IOERR_GETTEMPPATH;
|
| do{
|
| u64 r;
|
| sqlite3_randomness(sizeof(r), &r);
|
| @@ -5463,7 +5526,7 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
|
| unixEnterMutex();
|
| pInode = inodeList;
|
| while( pInode && (pInode->fileId.dev!=sStat.st_dev
|
| - || pInode->fileId.ino!=sStat.st_ino) ){
|
| + || pInode->fileId.ino!=(u64)sStat.st_ino) ){
|
| pInode = pInode->pNext;
|
| }
|
| if( pInode ){
|
| @@ -5481,6 +5544,27 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
|
| }
|
|
|
| /*
|
| +** Find the mode, uid and gid of file zFile.
|
| +*/
|
| +static int getFileMode(
|
| + const char *zFile, /* File name */
|
| + mode_t *pMode, /* OUT: Permissions of zFile */
|
| + uid_t *pUid, /* OUT: uid of zFile. */
|
| + gid_t *pGid /* OUT: gid of zFile. */
|
| +){
|
| + struct stat sStat; /* Output of stat() on database file */
|
| + int rc = SQLITE_OK;
|
| + if( 0==osStat(zFile, &sStat) ){
|
| + *pMode = sStat.st_mode & 0777;
|
| + *pUid = sStat.st_uid;
|
| + *pGid = sStat.st_gid;
|
| + }else{
|
| + rc = SQLITE_IOERR_FSTAT;
|
| + }
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| ** This function is called by unixOpen() to determine the unix permissions
|
| ** to create new files with. If no error occurs, then SQLITE_OK is returned
|
| ** and a value suitable for passing as the third argument to open(2) is
|
| @@ -5515,7 +5599,6 @@ static int findCreateFileMode(
|
| if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){
|
| char zDb[MAX_PATHNAME+1]; /* Database file path */
|
| int nDb; /* Number of valid bytes in zDb */
|
| - struct stat sStat; /* Output of stat() on database file */
|
|
|
| /* zPath is a path to a WAL or journal file. The following block derives
|
| ** the path to the associated database file from zPath. This block handles
|
| @@ -5546,15 +5629,18 @@ static int findCreateFileMode(
|
| memcpy(zDb, zPath, nDb);
|
| zDb[nDb] = '\0';
|
|
|
| - if( 0==osStat(zDb, &sStat) ){
|
| - *pMode = sStat.st_mode & 0777;
|
| - *pUid = sStat.st_uid;
|
| - *pGid = sStat.st_gid;
|
| - }else{
|
| - rc = SQLITE_IOERR_FSTAT;
|
| - }
|
| + rc = getFileMode(zDb, pMode, pUid, pGid);
|
| }else if( flags & SQLITE_OPEN_DELETEONCLOSE ){
|
| *pMode = 0600;
|
| + }else if( flags & SQLITE_OPEN_URI ){
|
| + /* If this is a main database file and the file was opened using a URI
|
| + ** filename, check for the "modeof" parameter. If present, interpret
|
| + ** its value as a filename and try to copy the mode, uid and gid from
|
| + ** that file. */
|
| + const char *z = sqlite3_uri_parameter(zPath, "modeof");
|
| + if( z ){
|
| + rc = getFileMode(z, pMode, pUid, pGid);
|
| + }
|
| }
|
| return rc;
|
| }
|
| @@ -5584,7 +5670,7 @@ int chromium_sqlite3_fill_in_unix_sqlite3_file(sqlite3_vfs* pVfs,
|
| if( eType==SQLITE_OPEN_MAIN_DB ){
|
| p->pUnused = sqlite3_malloc(sizeof(*p->pUnused));
|
| if (!p->pUnused) {
|
| - return SQLITE_NOMEM;
|
| + return SQLITE_NOMEM_BKPT;
|
| }
|
| p->pUnused->fd = fd;
|
| p->pUnused->flags = flags;
|
| @@ -5710,7 +5796,7 @@ static int unixOpen(
|
| /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
|
| pUnused = sqlite3_malloc64(sizeof(*pUnused));
|
| if( !pUnused ){
|
| - return SQLITE_NOMEM;
|
| + return SQLITE_NOMEM_BKPT;
|
| }
|
| }
|
| p->pUnused = pUnused;
|
| @@ -5797,7 +5883,7 @@ static int unixOpen(
|
| zPath = sqlite3_mprintf("%s", zName);
|
| if( zPath==0 ){
|
| robust_close(p, fd, __LINE__);
|
| - return SQLITE_NOMEM;
|
| + return SQLITE_NOMEM_BKPT;
|
| }
|
| #else
|
| osUnlink(zName);
|
| @@ -5808,9 +5894,6 @@ static int unixOpen(
|
| p->openFlags = openFlags;
|
| }
|
| #endif
|
| -
|
| - noLock = eType!=SQLITE_OPEN_MAIN_DB;
|
| -
|
|
|
| #if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE
|
| if( fstatfs(fd, &fsInfo) == -1 ){
|
| @@ -5829,6 +5912,7 @@ static int unixOpen(
|
| /* Set up appropriate ctrlFlags */
|
| if( isDelete ) ctrlFlags |= UNIXFILE_DELETE;
|
| if( isReadonly ) ctrlFlags |= UNIXFILE_RDONLY;
|
| + noLock = eType!=SQLITE_OPEN_MAIN_DB;
|
| if( noLock ) ctrlFlags |= UNIXFILE_NOLOCK;
|
| if( syncDir ) ctrlFlags |= UNIXFILE_DIRSYNC;
|
| if( flags & SQLITE_OPEN_URI ) ctrlFlags |= UNIXFILE_URI;
|
| @@ -5907,12 +5991,7 @@ static int unixDelete(
|
| int fd;
|
| rc = osOpenDirectory(zPath, &fd);
|
| if( rc==SQLITE_OK ){
|
| -#if OS_VXWORKS
|
| - if( fsync(fd)==-1 )
|
| -#else
|
| - if( fsync(fd) )
|
| -#endif
|
| - {
|
| + if( full_fsync(fd,0,0) ){
|
| rc = unixLogError(SQLITE_IOERR_DIR_FSYNC, "fsync", zPath);
|
| }
|
| robust_close(0, fd, __LINE__);
|
| @@ -5958,6 +6037,32 @@ static int unixAccess(
|
| return SQLITE_OK;
|
| }
|
|
|
| +/*
|
| +**
|
| +*/
|
| +static int mkFullPathname(
|
| + const char *zPath, /* Input path */
|
| + char *zOut, /* Output buffer */
|
| + int nOut /* Allocated size of buffer zOut */
|
| +){
|
| + int nPath = sqlite3Strlen30(zPath);
|
| + int iOff = 0;
|
| + if( zPath[0]!='/' ){
|
| + if( osGetcwd(zOut, nOut-2)==0 ){
|
| + return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath);
|
| + }
|
| + iOff = sqlite3Strlen30(zOut);
|
| + zOut[iOff++] = '/';
|
| + }
|
| + if( (iOff+nPath+1)>nOut ){
|
| + /* SQLite assumes that xFullPathname() nul-terminates the output buffer
|
| + ** even if it returns an error. */
|
| + zOut[iOff] = '\0';
|
| + return SQLITE_CANTOPEN_BKPT;
|
| + }
|
| + sqlite3_snprintf(nOut-iOff, &zOut[iOff], "%s", zPath);
|
| + return SQLITE_OK;
|
| +}
|
|
|
| /*
|
| ** Turn a relative pathname into a full pathname. The relative path
|
| @@ -5974,7 +6079,17 @@ static int unixFullPathname(
|
| int nOut, /* Size of output buffer in bytes */
|
| char *zOut /* Output buffer */
|
| ){
|
| +#if !defined(HAVE_READLINK) || !defined(HAVE_LSTAT)
|
| + return mkFullPathname(zPath, zOut, nOut);
|
| +#else
|
| + int rc = SQLITE_OK;
|
| int nByte;
|
| + int nLink = 1; /* Number of symbolic links followed so far */
|
| + const char *zIn = zPath; /* Input path for each iteration of loop */
|
| + char *zDel = 0;
|
| +
|
| + assert( pVfs->mxPathname==MAX_PATHNAME );
|
| + UNUSED_PARAMETER(pVfs);
|
|
|
| /* It's odd to simulate an io-error here, but really this is just
|
| ** using the io-error infrastructure to test that SQLite handles this
|
| @@ -5983,58 +6098,62 @@ static int unixFullPathname(
|
| */
|
| SimulateIOError( return SQLITE_ERROR );
|
|
|
| - assert( pVfs->mxPathname==MAX_PATHNAME );
|
| - UNUSED_PARAMETER(pVfs);
|
| + do {
|
|
|
| - /* Attempt to resolve the path as if it were a symbolic link. If it is
|
| - ** a symbolic link, the resolved path is stored in buffer zOut[]. Or, if
|
| - ** the identified file is not a symbolic link or does not exist, then
|
| - ** zPath is copied directly into zOut. Either way, nByte is left set to
|
| - ** the size of the string copied into zOut[] in bytes. */
|
| - nByte = osReadlink(zPath, zOut, nOut-1);
|
| - if( nByte<0 ){
|
| - if( errno!=EINVAL && errno!=ENOENT ){
|
| - return unixLogError(SQLITE_CANTOPEN_BKPT, "readlink", zPath);
|
| - }
|
| - sqlite3_snprintf(nOut, zOut, "%s", zPath);
|
| - nByte = sqlite3Strlen30(zOut);
|
| - }else{
|
| - zOut[nByte] = '\0';
|
| - }
|
| + /* Call stat() on path zIn. Set bLink to true if the path is a symbolic
|
| + ** link, or false otherwise. */
|
| + int bLink = 0;
|
| + struct stat buf;
|
| + if( osLstat(zIn, &buf)!=0 ){
|
| + if( errno!=ENOENT ){
|
| + rc = unixLogError(SQLITE_CANTOPEN_BKPT, "lstat", zIn);
|
| + }
|
| + }else{
|
| + bLink = S_ISLNK(buf.st_mode);
|
| + }
|
|
|
| - /* If buffer zOut[] now contains an absolute path there is nothing more
|
| - ** to do. If it contains a relative path, do the following:
|
| - **
|
| - ** * move the relative path string so that it is at the end of th
|
| - ** zOut[] buffer.
|
| - ** * Call getcwd() to read the path of the current working directory
|
| - ** into the start of the zOut[] buffer.
|
| - ** * Append a '/' character to the cwd string and move the
|
| - ** relative path back within the buffer so that it immediately
|
| - ** follows the '/'.
|
| - **
|
| - ** This code is written so that if the combination of the CWD and relative
|
| - ** path are larger than the allocated size of zOut[] the CWD is silently
|
| - ** truncated to make it fit. This is Ok, as SQLite refuses to open any
|
| - ** file for which this function returns a full path larger than (nOut-8)
|
| - ** bytes in size. */
|
| - testcase( nByte==nOut-5 );
|
| - testcase( nByte==nOut-4 );
|
| - if( zOut[0]!='/' && nByte<nOut-4 ){
|
| - int nCwd;
|
| - int nRem = nOut-nByte-1;
|
| - memmove(&zOut[nRem], zOut, nByte+1);
|
| - zOut[nRem-1] = '\0';
|
| - if( osGetcwd(zOut, nRem-1)==0 ){
|
| - return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath);
|
| + if( bLink ){
|
| + if( zDel==0 ){
|
| + zDel = sqlite3_malloc(nOut);
|
| + if( zDel==0 ) rc = SQLITE_NOMEM_BKPT;
|
| + }else if( ++nLink>SQLITE_MAX_SYMLINKS ){
|
| + rc = SQLITE_CANTOPEN_BKPT;
|
| + }
|
| +
|
| + if( rc==SQLITE_OK ){
|
| + nByte = osReadlink(zIn, zDel, nOut-1);
|
| + if( nByte<0 ){
|
| + rc = unixLogError(SQLITE_CANTOPEN_BKPT, "readlink", zIn);
|
| + }else{
|
| + if( zDel[0]!='/' ){
|
| + int n;
|
| + for(n = sqlite3Strlen30(zIn); n>0 && zIn[n-1]!='/'; n--);
|
| + if( nByte+n+1>nOut ){
|
| + rc = SQLITE_CANTOPEN_BKPT;
|
| + }else{
|
| + memmove(&zDel[n], zDel, nByte+1);
|
| + memcpy(zDel, zIn, n);
|
| + nByte += n;
|
| + }
|
| + }
|
| + zDel[nByte] = '\0';
|
| + }
|
| + }
|
| +
|
| + zIn = zDel;
|
| }
|
| - nCwd = sqlite3Strlen30(zOut);
|
| - assert( nCwd<=nRem-1 );
|
| - zOut[nCwd] = '/';
|
| - memmove(&zOut[nCwd+1], &zOut[nRem], nByte+1);
|
| - }
|
|
|
| - return SQLITE_OK;
|
| + assert( rc!=SQLITE_OK || zIn!=zOut || zIn[0]=='/' );
|
| + if( rc==SQLITE_OK && zIn!=zOut ){
|
| + rc = mkFullPathname(zIn, zOut, nOut);
|
| + }
|
| + if( bLink==0 ) break;
|
| + zIn = zOut;
|
| + }while( rc==SQLITE_OK );
|
| +
|
| + sqlite3_free(zDel);
|
| + return rc;
|
| +#endif /* HAVE_READLINK && HAVE_LSTAT */
|
| }
|
|
|
|
|
| @@ -6234,23 +6353,18 @@ static int unixCurrentTime(sqlite3_vfs *NotUsed, double *prNow){
|
| # define unixCurrentTime 0
|
| #endif
|
|
|
| -#ifndef SQLITE_OMIT_DEPRECATED
|
| /*
|
| -** We added the xGetLastError() method with the intention of providing
|
| -** better low-level error messages when operating-system problems come up
|
| -** during SQLite operation. But so far, none of that has been implemented
|
| -** in the core. So this routine is never called. For now, it is merely
|
| -** a place-holder.
|
| +** The xGetLastError() method is designed to return a better
|
| +** low-level error message when operating-system problems come up
|
| +** during SQLite operation. Only the integer return code is currently
|
| +** used.
|
| */
|
| static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
|
| UNUSED_PARAMETER(NotUsed);
|
| UNUSED_PARAMETER(NotUsed2);
|
| UNUSED_PARAMETER(NotUsed3);
|
| - return 0;
|
| + return errno;
|
| }
|
| -#else
|
| -# define unixGetLastError 0
|
| -#endif
|
|
|
|
|
| /*
|
| @@ -6540,7 +6654,7 @@ static int proxyCreateUnixFile(
|
| }else{
|
| pUnused = sqlite3_malloc64(sizeof(*pUnused));
|
| if( !pUnused ){
|
| - return SQLITE_NOMEM;
|
| + return SQLITE_NOMEM_BKPT;
|
| }
|
| }
|
| if( fd<0 ){
|
| @@ -6573,7 +6687,7 @@ static int proxyCreateUnixFile(
|
|
|
| pNew = (unixFile *)sqlite3_malloc64(sizeof(*pNew));
|
| if( pNew==NULL ){
|
| - rc = SQLITE_NOMEM;
|
| + rc = SQLITE_NOMEM_BKPT;
|
| goto end_create_proxy;
|
| }
|
| memset(pNew, 0, sizeof(unixFile));
|
| @@ -6916,7 +7030,7 @@ static int proxyTakeConch(unixFile *pFile){
|
| writeSize = PROXY_PATHINDEX + strlen(&writeBuffer[PROXY_PATHINDEX]);
|
| robust_ftruncate(conchFile->h, writeSize);
|
| rc = unixWrite((sqlite3_file *)conchFile, writeBuffer, writeSize, 0);
|
| - fsync(conchFile->h);
|
| + full_fsync(conchFile->h,0,0);
|
| /* If we created a new conch file (not just updated the contents of a
|
| ** valid conch file), try to match the permissions of the database
|
| */
|
| @@ -6986,7 +7100,7 @@ static int proxyTakeConch(unixFile *pFile){
|
| if( tempLockPath ){
|
| pCtx->lockProxyPath = sqlite3DbStrDup(0, tempLockPath);
|
| if( !pCtx->lockProxyPath ){
|
| - rc = SQLITE_NOMEM;
|
| + rc = SQLITE_NOMEM_BKPT;
|
| }
|
| }
|
| }
|
| @@ -7051,7 +7165,7 @@ static int proxyCreateConchPathname(char *dbPath, char **pConchPath){
|
| ** the name of the original database file. */
|
| *pConchPath = conchPath = (char *)sqlite3_malloc64(len + 8);
|
| if( conchPath==0 ){
|
| - return SQLITE_NOMEM;
|
| + return SQLITE_NOMEM_BKPT;
|
| }
|
| memcpy(conchPath, dbPath, len+1);
|
|
|
| @@ -7167,7 +7281,7 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) {
|
|
|
| pCtx = sqlite3_malloc64( sizeof(*pCtx) );
|
| if( pCtx==0 ){
|
| - return SQLITE_NOMEM;
|
| + return SQLITE_NOMEM_BKPT;
|
| }
|
| memset(pCtx, 0, sizeof(*pCtx));
|
|
|
| @@ -7203,7 +7317,7 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) {
|
| if( rc==SQLITE_OK ){
|
| pCtx->dbPath = sqlite3DbStrDup(0, dbPath);
|
| if( pCtx->dbPath==NULL ){
|
| - rc = SQLITE_NOMEM;
|
| + rc = SQLITE_NOMEM_BKPT;
|
| }
|
| }
|
| if( rc==SQLITE_OK ){
|
| @@ -7533,7 +7647,7 @@ int sqlite3_os_init(void){
|
|
|
| /* Double-check that the aSyscall[] array has been constructed
|
| ** correctly. See ticket [bb3a86e890c8e96ab] */
|
| - assert( ArraySize(aSyscall)==27 );
|
| + assert( ArraySize(aSyscall)==28 );
|
|
|
| /* Register all VFSes defined in the aVfs[] array */
|
| for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
|
|
|