Fix issues on unix with opening database files via symlinks that are not in the current working directory. And with nested symlinks.
FossilOrigin-Name: 4003db4a49c6b623750e56f626fa492c8402067f
This commit is contained in:
commit
8770677c1e
26
manifest
26
manifest
@ -1,5 +1,5 @@
|
||||
C Add\sthe\sability\sto\sdo\sWindows\sbuilds\sto\sthe\samalgamation\starball.
|
||||
D 2016-01-25T23:24:38.805
|
||||
C Fix\sissues\son\sunix\swith\sopening\sdatabase\sfiles\svia\ssymlinks\sthat\sare\snot\sin\sthe\scurrent\sworking\sdirectory.\sAnd\swith\snested\ssymlinks.
|
||||
D 2016-01-26T14:48:02.511
|
||||
F Makefile.in 027c1603f255390c43a426671055a31c0a65fdb4
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc 6fca5455aaecbd14479f33f091aa19df2d3d2969
|
||||
@ -13,7 +13,7 @@ F autoconf/INSTALL 83e4a25da9fd053c7b3665eaaaf7919707915903
|
||||
F autoconf/Makefile.am 1c1657650775960804945dc392e14d9e43c5ed84
|
||||
F autoconf/Makefile.msc 68ed752a809b611d97b95d8572a34fe6fd1196f1
|
||||
F autoconf/README.first 6c4f34fe115ff55d4e8dbfa3cecf04a0188292f7
|
||||
F autoconf/README.txt e9757a381e5ce2553dbaa6247bb8ad00eb8d87aa w autoconf/README
|
||||
F autoconf/README.txt e9757a381e5ce2553dbaa6247bb8ad00eb8d87aa
|
||||
F autoconf/configure.ac 7b1ea0dcaf49fafba262ce4b0ee8cb3281b555d1
|
||||
F autoconf/tea/Makefile.in b438a7020446c8a8156e8d97c8914a04833da6fd
|
||||
F autoconf/tea/README 3e9a3c060f29a44344ab50aec506f4db903fb873
|
||||
@ -330,7 +330,7 @@ F src/os.c 8fd25588eeba74068d41102d26810e216999b6c8
|
||||
F src/os.h 3e57a24e2794a94d3cf2342c6d9a884888cd96bf
|
||||
F src/os_common.h abdb9a191a367793268fe553d25bab894e986a0e
|
||||
F src/os_setup.h c9d4553b5aaa6f73391448b265b89bed0b890faa
|
||||
F src/os_unix.c 0eb7f469fcd4e1fbedf30060438e26b839ec5486
|
||||
F src/os_unix.c 5bb20172d0c9a6afcfa829a88c406970593c848d
|
||||
F src/os_win.c 386fba30419e8458b13209781c2af5590eab2811
|
||||
F src/os_win.h eb7a47aa17b26b77eb97e4823f20a00b8bda12ca
|
||||
F src/pager.c 2916c66aee50f69d9ec56a7619b62d9c6a3bee61
|
||||
@ -421,7 +421,7 @@ F src/vdbemem.c b9181e77eca2a095929d46250daf85c8d2621fc0
|
||||
F src/vdbesort.c 3bb1f1f03162e6d223da623714d8e93fcaeac658
|
||||
F src/vdbetrace.c 8befe829faff6d9e6f6e4dee5a7d3f85cc85f1a0
|
||||
F src/vtab.c 320682cca733115b4cbe71320b5c5eeb1074ebde
|
||||
F src/vxworks.h 974e7d9a98f602d6310d563e1dc4e08f9fc48e47
|
||||
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c d21b99fd1458159d0b1ecdccc8ee6ada4fdc4c54
|
||||
F src/wal.h 2f7c831cf3b071fa548bf2d5cac640846a7ff19c
|
||||
F src/walker.c 0f142b5bd3ed2041fc52d773880748b212e63354
|
||||
@ -925,7 +925,7 @@ F test/orderby6.test 8b38138ab0972588240b3fca0985d2e400432859
|
||||
F test/orderby7.test 3d1383d52ade5b9eb3a173b3147fdd296f0202da
|
||||
F test/orderby8.test 23ef1a5d72bd3adcc2f65561c654295d1b8047bd
|
||||
F test/orderby9.test 87fb9548debcc2cd141c5299002dd94672fa76a3
|
||||
F test/oserror.test 361346396ae18462c7393c1ac5c3f17237bd89b2
|
||||
F test/oserror.test b32dc34f2363ef18532e3a0a7358e3e7e321974f
|
||||
F test/ovfl.test 4f7ca651cba5c059a12d8c67dddd49bec5747799
|
||||
F test/pager1.test 1acbdb14c5952a72dd43129cabdbf69aaa3ed1fa
|
||||
F test/pager2.test 67b8f40ae98112bcdba1f2b2d03ea83266418c71
|
||||
@ -1062,9 +1062,9 @@ F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4
|
||||
F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a
|
||||
F test/subtype1.test 7fe09496352f97053af1437150751be2d0a0cae8
|
||||
F test/superlock.test 1cde669f68d2dd37d6c9bd35eee1d95491ae3fc2
|
||||
F test/symlink.test cbf6cb8c6c4b63a39e9f0f6b0d5c99e249dbc102
|
||||
F test/symlink.test c9ebe7330d228249e447038276bfc8a7b22f4849
|
||||
F test/sync.test a34cd43e98b7fb84eabbf38f7ed8f7349b3f3d85
|
||||
F test/syscall.test 2aa9e111b79fb385681ff8940124def6f8faab87
|
||||
F test/syscall.test f59ba4e25f7ba4a4c031026cc2ef8b6e4b4c639c
|
||||
F test/sysfault.test c9f2b0d8d677558f74de750c75e12a5454719d04
|
||||
F test/tabfunc01.test cc33684f9480fcf1fd5ce287ac28d22971cad1cc
|
||||
F test/table.test b708f3e5fa2542fa51dfab21fc07b36ea445cb2f
|
||||
@ -1421,8 +1421,8 @@ F tool/vdbe_profile.tcl 246d0da094856d72d2c12efec03250d71639d19f
|
||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
P 7c49a9478bd36564e81d33458ca1f4063ddaca83 6df8a9c00a9d067f67d492da7a4617908070c6c0
|
||||
R c1478777421253ac0125637ca661aa71
|
||||
T +closed 6df8a9c00a9d067f67d492da7a4617908070c6c0
|
||||
U drh
|
||||
Z 730cfb6cf754e8e26f747fb36fc92bb4
|
||||
P abd2b357c55fdcdbc8e66a81a3fbb7f822ea0a4f 4a4385564dd3887a7953820b60c99d6ce289f96a
|
||||
R 1d2d15b294b146d0b5d200f0cf62495d
|
||||
T +closed 4a4385564dd3887a7953820b60c99d6ce289f96a
|
||||
U dan
|
||||
Z 7fd087e8bb59761ded2cdf6adb6cd578
|
||||
|
@ -1 +1 @@
|
||||
abd2b357c55fdcdbc8e66a81a3fbb7f822ea0a4f
|
||||
4003db4a49c6b623750e56f626fa492c8402067f
|
149
src/os_unix.c
149
src/os_unix.c
@ -149,6 +149,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()
|
||||
@ -475,6 +480,12 @@ static struct unix_syscall {
|
||||
#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 */
|
||||
|
||||
@ -5927,6 +5938,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
|
||||
@ -5943,7 +5980,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
|
||||
@ -5952,60 +5999,62 @@ static int unixFullPathname(
|
||||
*/
|
||||
SimulateIOError( return SQLITE_ERROR );
|
||||
|
||||
assert( pVfs->mxPathname==MAX_PATHNAME );
|
||||
UNUSED_PARAMETER(pVfs);
|
||||
do {
|
||||
|
||||
#if defined(HAVE_READLINK)
|
||||
/* 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);
|
||||
/* 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);
|
||||
}
|
||||
sqlite3_snprintf(nOut, zOut, "%s", zPath);
|
||||
nByte = sqlite3Strlen30(zOut);
|
||||
}else{
|
||||
zOut[nByte] = '\0';
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 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;
|
||||
}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 */
|
||||
}
|
||||
|
||||
|
||||
@ -7504,7 +7553,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++){
|
||||
|
@ -28,4 +28,5 @@
|
||||
#define OS_VXWORKS 0
|
||||
#define HAVE_FCHOWN 1
|
||||
#define HAVE_READLINK 1
|
||||
#define HAVE_LSTAT 1
|
||||
#endif /* defined(_WRS_KERNEL) */
|
||||
|
@ -95,7 +95,7 @@ do_test 1.4.1 {
|
||||
|
||||
do_re_test 1.4.2 {
|
||||
lindex $::log 0
|
||||
} {^os_unix.c:\d*: \(\d+\) (open|readlink)\(.*test.db\) - }
|
||||
} {^os_unix.c:\d*: \(\d+\) (open|readlink|lstat)\(.*test.db\) - }
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# Tests oserror-1.* test failures in the unlink() system call.
|
||||
|
@ -83,38 +83,49 @@ do_test 1.5 {
|
||||
do_test 2.0 {
|
||||
catch { db close }
|
||||
catch { db2 close }
|
||||
forcedelete test.db test.db2
|
||||
forcedelete test.db test.db2 test.db3
|
||||
sqlite3 db test.db
|
||||
execsql { CREATE TABLE t1(x) }
|
||||
file link test.db2 test.db
|
||||
sqlite3 db2 test.db2
|
||||
file exists test.db-journal
|
||||
} 0
|
||||
file link test.db3 test.db2
|
||||
set {} {}
|
||||
} {}
|
||||
|
||||
do_test 2.1 {
|
||||
execsql {
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(1);
|
||||
} db2
|
||||
file exists test.db-journal
|
||||
} 1
|
||||
do_test 2.2 {
|
||||
file exists test.db2-journal
|
||||
} 0
|
||||
do_test 2.3 {
|
||||
execsql {
|
||||
COMMIT;
|
||||
PRAGMA journal_mode = wal;
|
||||
INSERT INTO t1 VALUES(2);
|
||||
} db2
|
||||
file exists test.db-wal
|
||||
} 1
|
||||
do_test 2.4 {
|
||||
file exists test.db2-wal
|
||||
} 0
|
||||
do_execsql_test 2.5 {
|
||||
SELECT * FROM t1;
|
||||
} {1 2}
|
||||
foreach {tn f} {1 test.db2 2 test.db3} {
|
||||
do_test 2.$tn.1 {
|
||||
sqlite3 db2 $f
|
||||
file exists test.db-journal
|
||||
} 0
|
||||
do_test 2.$tn.2 {
|
||||
execsql {
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(1);
|
||||
} db2
|
||||
file exists test.db-journal
|
||||
} 1
|
||||
do_test 2.$tn.3 {
|
||||
list [file exists test2.db-journal] [file exists test3.db-journal]
|
||||
} {0 0}
|
||||
do_test 2.$tn.4 {
|
||||
execsql {
|
||||
COMMIT;
|
||||
PRAGMA journal_mode = wal;
|
||||
INSERT INTO t1 VALUES(2);
|
||||
} db2
|
||||
file exists test.db-wal
|
||||
} 1
|
||||
do_test 2.$tn.5 {
|
||||
list [file exists test2.db-wal] [file exists test3.db-wal]
|
||||
} {0 0}
|
||||
do_execsql_test 2.$tn.6 {
|
||||
SELECT * FROM t1;
|
||||
} {1 2}
|
||||
db2 close
|
||||
do_execsql_test 2.$tn.7 {
|
||||
DELETE FROM t1;
|
||||
PRAGMA journal_mode = delete;
|
||||
} delete
|
||||
}
|
||||
|
||||
# Try to open a ridiculously long pathname. Bug found by
|
||||
# Kostya Serebryany using libFuzzer on 2015-11-30.
|
||||
@ -125,5 +136,56 @@ do_test 3.1 {
|
||||
set res
|
||||
} {unable to open database file}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that relative symlinks that are not located in the cwd work.
|
||||
#
|
||||
do_test 4.1 {
|
||||
forcedelete x y z
|
||||
file mkdir x
|
||||
file mkdir y
|
||||
file mkdir z
|
||||
sqlite3 db x/test.db
|
||||
file link y/test.db ../x/test.db
|
||||
file link z/test.db ../y/test.db
|
||||
execsql {
|
||||
PRAGMA journal_mode = wal;
|
||||
CREATE TABLE t1(x, y);
|
||||
INSERT INTO t1 VALUES('hello', 'world');
|
||||
}
|
||||
} {wal}
|
||||
|
||||
do_test 4.2.1 {
|
||||
db close
|
||||
sqlite3 db y/test.db
|
||||
db eval { SELECT * FROM t1 }
|
||||
} {hello world}
|
||||
do_test 4.2.2 {
|
||||
list [file exists x/test.db-wal] [file exists y/test.db-wal]
|
||||
} {1 0}
|
||||
|
||||
do_test 4.3.1 {
|
||||
db close
|
||||
sqlite3 db z/test.db
|
||||
db eval { SELECT * FROM t1 }
|
||||
} {hello world}
|
||||
do_test 4.3.2 {
|
||||
list [file exists x/test.db-wal] [file exists y/test.db-wal] \
|
||||
[file exists z/test.db-wal]
|
||||
} {1 0 0}
|
||||
|
||||
do_test 4.4.0 {
|
||||
forcedelete w
|
||||
file mkdir w
|
||||
file link w/test.db [file join [pwd] x/test.db]
|
||||
set {} {}
|
||||
} {}
|
||||
do_test 4.4.1 {
|
||||
db close
|
||||
sqlite3 db w/test.db
|
||||
db eval { SELECT * FROM t1 }
|
||||
} {hello world}
|
||||
do_test 4.4.2 {
|
||||
list [file exists x/test.db-wal] [file exists w/test.db-wal]
|
||||
} {1 0}
|
||||
|
||||
finish_test
|
||||
|
@ -61,7 +61,7 @@ foreach s {
|
||||
fcntl read pread write pwrite fchmod fallocate
|
||||
pread64 pwrite64 unlink openDirectory mkdir rmdir
|
||||
statvfs fchown geteuid umask mmap munmap mremap
|
||||
getpagesize readlink
|
||||
getpagesize readlink lstat
|
||||
} {
|
||||
if {[test_syscall exists $s]} {lappend syscall_list $s}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user