Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch follow-symlinks Excluding Merge-Ins
This is equivalent to a diff from 7ac017a4 to 4a438556
2016-01-26
| ||
14:48 | Fix issues on unix with opening database files via symlinks that are not in the current working directory. And with nested symlinks. (check-in: 4003db4a user: dan tags: trunk) | |
13:56 | Ensure that unixFullpathname() always nul-terminates its output buffer, even when returning an error. (Closed-Leaf check-in: 4a438556 user: dan tags: follow-symlinks) | |
00:12 | Remove an unused variable. (check-in: 1c2656c1 user: drh tags: follow-symlinks) | |
2016-01-25
| ||
22:08 | Fix a compiler warning about doing pointer arithmetic involving a NULL pointer even though the result of computation is never used. (check-in: 7c49a947 user: drh tags: trunk) | |
17:04 | Fix issues on unix with opening database files via symlinks that are not in the current working directory. And with nested symlinks. (check-in: 80398fd4 user: dan tags: follow-symlinks) | |
15:57 | Replace the OP_SetIfNotPos operator with OP_OffsetLimit in the VDBE, for simpler and smaller code. (check-in: 7ac017a4 user: drh tags: trunk) | |
13:55 | Add the SQLITE_EXTRA_DURABLE compile-time option. (check-in: 30671345 user: drh tags: trunk) | |
Changes to src/os_unix.c.
︙ | ︙ | |||
145 146 147 148 149 150 151 152 153 154 155 156 157 158 | #endif /* ** Maximum supported path-length. */ #define MAX_PATHNAME 512 /* Always cast the getpid() return type for compatibility with ** kernel modules in VxWorks. */ #define osGetpid(X) (pid_t)getpid() /* ** Only set the lastErrno if the error code is a real error and not ** a normal expected return code of SQLITE_BUSY or SQLITE_OK | > > > > > | 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | #endif /* ** Maximum supported path-length. */ #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() /* ** Only set the lastErrno if the error code is a real error and not ** a normal expected return code of SQLITE_BUSY or SQLITE_OK |
︙ | ︙ | |||
471 472 473 474 475 476 477 478 479 480 481 482 483 484 | #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) }; /* End of the overrideable system calls */ /* ** On some systems, calls to fchown() will trigger a message in a security ** log if they come from non-root processes. So avoid calling fchown() if | > > > > > > | 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 | #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 */ /* ** On some systems, calls to fchown() will trigger a message in a security ** log if they come from non-root processes. So avoid calling fchown() if |
︙ | ︙ | |||
5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 | *pResOut = (0==osStat(zPath, &buf) && buf.st_size>0); }else{ *pResOut = osAccess(zPath, W_OK|R_OK)==0; } return SQLITE_OK; } /* ** Turn a relative pathname into a full pathname. The relative path ** is stored as a nul-terminated string in the buffer pointed to by ** zPath. ** ** zOut points to a buffer of at least sqlite3_vfs.mxPathname bytes ** (in this case, MAX_PATHNAME bytes). The full-path is written to ** this buffer before returning. */ static int unixFullPathname( sqlite3_vfs *pVfs, /* Pointer to vfs object */ const char *zPath, /* Possibly relative input path */ 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 ** function failing. This function could fail if, for example, the ** current working directory has been unlinked. */ SimulateIOError( return SQLITE_ERROR ); | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < < | | < < < | > | | | | < < | | | | > > > > > > | | | < < | < < < < < < < < < < < | > | | | > | > > | > > > > | > > | < > | | | < > | > > > > | > | 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043 6044 6045 6046 6047 6048 6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 6060 6061 6062 6063 6064 | *pResOut = (0==osStat(zPath, &buf) && buf.st_size>0); }else{ *pResOut = osAccess(zPath, W_OK|R_OK)==0; } 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 ** is stored as a nul-terminated string in the buffer pointed to by ** zPath. ** ** zOut points to a buffer of at least sqlite3_vfs.mxPathname bytes ** (in this case, MAX_PATHNAME bytes). The full-path is written to ** this buffer before returning. */ static int unixFullPathname( sqlite3_vfs *pVfs, /* Pointer to vfs object */ const char *zPath, /* Possibly relative input path */ 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 ** function failing. This function could fail if, for example, the ** current working directory has been unlinked. */ SimulateIOError( return SQLITE_ERROR ); do { /* 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( 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; } 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 */ } #ifndef SQLITE_OMIT_LOAD_EXTENSION /* ** Interfaces for opening a shared library, finding entry points ** within the shared library, and closing the shared library. |
︙ | ︙ | |||
7500 7501 7502 7503 7504 7505 7506 | UNIXVFS("unix-proxy", proxyIoFinder ), #endif }; unsigned int i; /* Loop counter */ /* Double-check that the aSyscall[] array has been constructed ** correctly. See ticket [bb3a86e890c8e96ab] */ | | | 7549 7550 7551 7552 7553 7554 7555 7556 7557 7558 7559 7560 7561 7562 7563 | UNIXVFS("unix-proxy", proxyIoFinder ), #endif }; unsigned int i; /* Loop counter */ /* Double-check that the aSyscall[] array has been constructed ** correctly. See ticket [bb3a86e890c8e96ab] */ assert( ArraySize(aSyscall)==28 ); /* Register all VFSes defined in the aVfs[] array */ for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){ sqlite3_vfs_register(&aVfs[i], i==0); } return SQLITE_OK; } |
︙ | ︙ |
Changes to src/vxworks.h.
︙ | ︙ | |||
24 25 26 27 28 29 30 31 | #define SQLITE_ENABLE_LOCKING_STYLE 0 #define HAVE_UTIME 1 #else /* This is not VxWorks. */ #define OS_VXWORKS 0 #define HAVE_FCHOWN 1 #define HAVE_READLINK 1 #endif /* defined(_WRS_KERNEL) */ | > | 24 25 26 27 28 29 30 31 32 | #define SQLITE_ENABLE_LOCKING_STYLE 0 #define HAVE_UTIME 1 #else /* This is not VxWorks. */ #define OS_VXWORKS 0 #define HAVE_FCHOWN 1 #define HAVE_READLINK 1 #define HAVE_LSTAT 1 #endif /* defined(_WRS_KERNEL) */ |
Changes to test/oserror.test.
︙ | ︙ | |||
91 92 93 94 95 96 97 | do_test 1.4.1 { set ::log [list] list [catch { sqlite3 dbh /root/test.db } msg] $msg } {1 {unable to open database file}} do_re_test 1.4.2 { lindex $::log 0 | | | 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | do_test 1.4.1 { set ::log [list] 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|readlink|lstat)\(.*test.db\) - } #-------------------------------------------------------------------------- # Tests oserror-1.* test failures in the unlink() system call. # ifcapable wal { do_test 2.1.1 { set ::log [list] |
︙ | ︙ |
Changes to test/symlink.test.
︙ | ︙ | |||
79 80 81 82 83 84 85 | #------------------------------------------------------------------------- # 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 } | | > > > > > > | | | < | | | | | | | | | | | | | | | | | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 | #------------------------------------------------------------------------- # 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 test.db3 sqlite3 db test.db execsql { CREATE TABLE t1(x) } file link test.db2 test.db file link test.db3 test.db2 set {} {} } {} 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. # do_test 3.1 { db close catch {sqlite3 db [string repeat [string repeat x 100]/ 6]} res 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 |
Changes to test/syscall.test.
︙ | ︙ | |||
57 58 59 60 61 62 63 | # Tests for the xNextSystemCall method. # foreach s { open close access getcwd stat fstat ftruncate fcntl read pread write pwrite fchmod fallocate pread64 pwrite64 unlink openDirectory mkdir rmdir statvfs fchown geteuid umask mmap munmap mremap | | | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | # Tests for the xNextSystemCall method. # foreach s { open close access getcwd stat fstat ftruncate fcntl read pread write pwrite fchmod fallocate pread64 pwrite64 unlink openDirectory mkdir rmdir statvfs fchown geteuid umask mmap munmap mremap getpagesize readlink lstat } { if {[test_syscall exists $s]} {lappend syscall_list $s} } do_test 3.1 { lsort [test_syscall list] } [lsort $syscall_list] #------------------------------------------------------------------------- # This test verifies that if a call to open() fails and errno is set to |
︙ | ︙ |