]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
On unix, if a file is opened via a symlink, create, read and write journal and wal...
authordan <dan@noemail.net>
Sat, 31 Oct 2015 17:58:33 +0000 (17:58 +0000)
committerdan <dan@noemail.net>
Sat, 31 Oct 2015 17:58:33 +0000 (17:58 +0000)
FossilOrigin-Name: c7c8105099c0412ac6c605f98987092c10bde57c

manifest
manifest.uuid
src/os_unix.c
test/oserror.test
test/symlink.test [new file with mode: 0644]
test/syscall.test

index b9fdab8d24b8b0364c43144b6d86c3def9979e22..683c05afd8576d115b83d47653d9148ab019ee92 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\smutex\soperations\sto\stest\scode\sin\stest3.c\sto\savoid\striggering\sassert()\sfailures\sin\scertain\sconfigurations.
-D 2015-10-30T20:54:25.598
+C On\sunix,\sif\sa\sfile\sis\sopened\svia\sa\ssymlink,\screate,\sread\sand\swrite\sjournal\sand\swal\sfiles\sbased\son\sthe\sname\sof\sthe\sactual\sdb\sfile,\snot\sthe\ssymlink.
+D 2015-10-31T17:58:33.378
 F Makefile.in 4469ed8b02a9934fea9503d791165367d19db2f7
 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
 F Makefile.msc 702d3e98f3afc6587a78481257f3c4c900efc3a4
@@ -324,7 +324,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 fc93d55f96bb978f0b0168c6ea7d6fc60b0e172c
+F src/os_unix.c cf72e06e15839ebe7121e01d3eebf256c039b0ca
 F src/os_win.c 1716291e5ec2dbfc5a1fe0b32182030f1f7d8acf
 F src/os_win.h eb7a47aa17b26b77eb97e4823f20a00b8bda12ca
 F src/pager.c 9c1eec0d88133484b165fa0b5284a411c24b964c
@@ -913,7 +913,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 14fec2796c2b6fe431c7823750e8a18a761176d7
+F test/oserror.test 361346396ae18462c7393c1ac5c3f17237bd89b2
 F test/ovfl.test 4f7ca651cba5c059a12d8c67dddd49bec5747799
 F test/pager1.test 1acbdb14c5952a72dd43129cabdbf69aaa3ed1fa
 F test/pager2.test 67b8f40ae98112bcdba1f2b2d03ea83266418c71
@@ -1046,8 +1046,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 2513f7c030df0f435c6415687ba8b739f3d312df
 F test/sync.test a34cd43e98b7fb84eabbf38f7ed8f7349b3f3d85
-F test/syscall.test d2fdaad713f103ac611fe7ef9b724c7b69f8149c
+F test/syscall.test fba9ebdc6905d05bba6a835e691f20ed9ea2cc88
 F test/sysfault.test fa776e60bf46bdd3ae69f0b73e46ee3977a58ae6
 F test/tabfunc01.test 03c4ad422c6ab596cff6dcaf86dd061a9f039525
 F test/table.test b708f3e5fa2542fa51dfab21fc07b36ea445cb2f
@@ -1397,7 +1398,10 @@ F tool/vdbe_profile.tcl 246d0da094856d72d2c12efec03250d71639d19f
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 7565b046ff939e8310631397a4526fbd98b99aaf
-R 614298574df997c982bceb820bb362b3
+P 9f19420b0a79dff65fc3a9d548f4b3fc4955f9f9
+R 6c3cb8b317a5bfe5a7c51bf7e4e6022e
+T *branch * follow-symlinks
+T *sym-follow-symlinks *
+T -sym-trunk *
 U dan
-Z ee268c45e17adbdf740dc7b91893f898
+Z 9a079ec9742e185ced0424071f7f7c65
index 4eeefb872e9844ff8d06c54ec1bf5075de27d076..9abe98cb17c2b8ad5c9c30d32b29f1a0a1b76d59 100644 (file)
@@ -1 +1 @@
-9f19420b0a79dff65fc3a9d548f4b3fc4955f9f9
\ No newline at end of file
+c7c8105099c0412ac6c605f98987092c10bde57c
\ No newline at end of file
index fb2a8ca916e6141df99d49cb565e58d942b1d6c9..b322d238e89bc3bd48a653897b0a88c51d7c157a 100644 (file)
@@ -464,6 +464,9 @@ static struct unix_syscall {
   { "getpagesize",  (sqlite3_syscall_ptr)unixGetpagesize, 0 },
 #define osGetpagesize ((int(*)(void))aSyscall[24].pCurrent)
 
+  { "readlink",     (sqlite3_syscall_ptr)readlink,        0 },
+#define osReadlink ((ssize_t(*)(const char*,char*,size_t))aSyscall[25].pCurrent)
+
 #endif
 
 }; /* End of the overrideable system calls */
@@ -6026,6 +6029,7 @@ static int unixFullPathname(
   int nOut,                     /* Size of output buffer in bytes */
   char *zOut                    /* Output buffer */
 ){
+  int nByte;
 
   /* 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
@@ -6037,17 +6041,53 @@ static int unixFullPathname(
   assert( pVfs->mxPathname==MAX_PATHNAME );
   UNUSED_PARAMETER(pVfs);
 
-  zOut[nOut-1] = '\0';
-  if( zPath[0]=='/' ){
-    sqlite3_snprintf(nOut, zOut, "%s", zPath);
+  /* 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);
+    }
+    zOut[nOut-1] = '\0';
+    sqlite3_snprintf(nOut-1, zOut, "%s", zPath);
+    nByte = sqlite3Strlen30(zOut);
   }else{
+    zOut[nByte] = '\0';
+  }
+
+  /* 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.  */
+  if( zOut[0]!='/' ){
     int nCwd;
-    if( osGetcwd(zOut, nOut-1)==0 ){
+    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);
     }
-    nCwd = (int)strlen(zOut);
-    sqlite3_snprintf(nOut-nCwd, &zOut[nCwd], "/%s", zPath);
+    nCwd = sqlite3Strlen30(zOut);
+    assert( nCwd<=nRem-1 );
+    zOut[nCwd] = '/';
+    memmove(&zOut[nCwd+1], &zOut[nRem], nByte+1);
   }
+
   return SQLITE_OK;
 }
 
@@ -7542,7 +7582,7 @@ int sqlite3_os_init(void){
 
   /* Double-check that the aSyscall[] array has been constructed
   ** correctly.  See ticket [bb3a86e890c8e96ab] */
-  assert( ArraySize(aSyscall)==25 );
+  assert( ArraySize(aSyscall)==26 );
 
   /* Register all VFSes defined in the aVfs[] array */
   for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
index 1bfa37cd6c34e6099c69f0bd8bc810c4857f9f0d..5fa7f98eb5681f3277c4da1cd04e9cce5b0bfcb8 100644 (file)
@@ -93,7 +93,9 @@ do_test 1.4.1 {
   list [catch { sqlite3 dbh /root/test.db } msg] $msg
 } {1 {unable to open database file}}
 
-do_re_test 1.4.2 { lindex $::log 0 } {^os_unix.c:\d*: \(\d+\) open\(.*test.db\) - }
+do_re_test 1.4.2 { 
+  lindex $::log 0
+} {^os_unix.c:\d*: \(\d+\) (open|readlink)\(.*test.db\) - }
 
 #--------------------------------------------------------------------------
 # Tests oserror-1.* test failures in the unlink() system call.
diff --git a/test/symlink.test b/test/symlink.test
new file mode 100644 (file)
index 0000000..af7ec2a
--- /dev/null
@@ -0,0 +1,119 @@
+# 2015 October 31
+#
+# The author disclaims copyright to this source code.  In place of
+# a legal notice, here is a blessing:
+#
+#    May you do good and not evil.
+#    May you find forgiveness for yourself and forgive others.
+#    May you share freely, never taking more than you give.
+#
+#***********************************************************************
+# This file implements regression tests for SQLite library.  The
+# focus of this file is testing that SQLite can follow symbolic links.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix symlink
+
+# This only runs on unix.
+if {$::tcl_platform(platform)!="unix"} {
+  finish_test
+  return
+}
+
+# Ensure that test.db has been created.
+#
+do_execsql_test 1.0 {
+  CREATE TABLE t1(x, y);
+}
+
+# Test that SQLite follows symlinks when opening files.
+#
+forcedelete test.db2
+do_test 1.1 {
+  file link test.db2 test.db
+  sqlite3 db2 test.db2
+  sqlite3_db_filename db2 main
+} [file join [pwd] test.db]
+
+# Test that if the symlink points to a file that does not exists, it is
+# created when it is opened.
+#
+do_test 1.2.1 {
+  db2 close
+  db close
+  forcedelete test.db
+  file exists test.db
+} 0
+do_test 1.2.2 {
+  sqlite3 db2 test.db2
+  file exists test.db
+} 1
+do_test 1.2.3 {
+  sqlite3_db_filename db2 main
+} [file join [pwd] test.db]
+db2 close
+
+# Test that a loop of symlinks cannot be opened.
+#
+do_test 1.3 {
+  forcedelete test.db
+  # Note: Tcl [file link] command is too smart to create loops of symlinks.
+  exec ln -s test.db2 test.db
+  list [catch { sqlite3 db test.db } msg] $msg
+} {1 {unable to open database file}}
+
+# Test that overly large paths cannot be opened.
+#
+do_test 1.4 {
+  set name "test.db[string repeat x 502]"
+  list [catch { sqlite3 db $name } msg] $msg
+} {1 {unable to open database file}}
+do_test 1.5 {
+  set r [expr 510 - [string length test.db] - [string length [pwd]]]
+  set name "test.db[string repeat x $r]"
+  list [catch { sqlite3 db $name } msg] $msg
+} {1 {unable to open database file}}
+
+#-------------------------------------------------------------------------
+# Test that journal and wal files are created next to the real file,
+# not the symlink.
+#
+do_test 2.0 {
+  catch { db close }
+  catch { db2 close }
+  forcedelete test.db test.db2
+  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
+
+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}
+
+finish_test
index c2d9979031ff61b827e783472328526017902503..83b8b8b40fdf7f1723fd8aacb39b5dc9339487aa 100644 (file)
@@ -61,7 +61,7 @@ foreach s {
     fcntl read pread write pwrite fchmod fallocate
     pread64 pwrite64 unlink openDirectory mkdir rmdir 
     statvfs fchown umask mmap munmap mremap
-    getpagesize
+    getpagesize readlink
 } {
   if {[test_syscall exists $s]} {lappend syscall_list $s}
 }