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++){ |