aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2019-11-18 17:46:38 +0000
committerdrh <drh@noemail.net>2019-11-18 17:46:38 +0000
commit0933aad72c5ac1a763891c03b231ce72b1d19b03 (patch)
treeace29f58dd8b9c2ac613cc8dad3c8fc4d47cc5a8 /src
parent804725a6b9ea8ba9ef507866b1d8d2628d1e4356 (diff)
downloadsqlite-0933aad72c5ac1a763891c03b231ce72b1d19b03.tar.gz
sqlite-0933aad72c5ac1a763891c03b231ce72b1d19b03.zip
Add support for SQLITE_OPEN_NOFOLLOW.
FossilOrigin-Name: cb79c828496a703f1410f61458ebc1e15a92a63412b36f51945b2b5a32ec6e88
Diffstat (limited to 'src')
-rw-r--r--src/os_unix.c18
-rw-r--r--src/os_win.c3
-rw-r--r--src/pager.c8
-rw-r--r--src/shell.c.in18
-rw-r--r--src/sqlite.h.in3
-rw-r--r--src/tclsqlite.c10
-rw-r--r--src/test_demovfs.c6
-rw-r--r--src/test_vfs.c1
8 files changed, 60 insertions, 7 deletions
diff --git a/src/os_unix.c b/src/os_unix.c
index f2ac89f2c..7217a5d5f 100644
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -6251,15 +6251,25 @@ static int unixAccess(
SimulateIOError( return SQLITE_IOERR_ACCESS; );
assert( pResOut!=0 );
- /* The spec says there are three possible values for flags. But only
- ** two of them are actually used */
- assert( flags==SQLITE_ACCESS_EXISTS || flags==SQLITE_ACCESS_READWRITE );
+ /* The spec says there are four possible values for flags. But the
+ ** SQLITE_ACCESS_READ flag is never used */
+ assert( flags==SQLITE_ACCESS_EXISTS
+ || flags==SQLITE_ACCESS_READWRITE
+ || flags==SQLITE_ACCESS_SYMLINK );
if( flags==SQLITE_ACCESS_EXISTS ){
struct stat buf;
*pResOut = (0==osStat(zPath, &buf) && buf.st_size>0);
- }else{
+ }else if( flags==SQLITE_ACCESS_READWRITE ){
*pResOut = osAccess(zPath, W_OK|R_OK)==0;
+ }else{
+#if !defined(HAVE_LSTAT)
+ *pResOut = 0;
+#else
+ struct stat buf;
+ *pResOut = (0==osLstat(zPath, &buf) && S_ISLNK(buf.st_mode));
+#endif
+ assert( flags==SQLITE_ACCESS_SYMLINK );
}
return SQLITE_OK;
}
diff --git a/src/os_win.c b/src/os_win.c
index 32758ab76..2b492d6fa 100644
--- a/src/os_win.c
+++ b/src/os_win.c
@@ -5472,6 +5472,9 @@ static int winAccess(
rc = attr!=INVALID_FILE_ATTRIBUTES &&
(attr & FILE_ATTRIBUTE_READONLY)==0;
break;
+ case SQLITE_ACCESS_SYMLINK:
+ rc = 0; /* No symlinks on windows */
+ break;
default:
assert(!"Invalid flags argument");
}
diff --git a/src/pager.c b/src/pager.c
index 9ec8f58df..095e3f5ac 100644
--- a/src/pager.c
+++ b/src/pager.c
@@ -4788,6 +4788,14 @@ int sqlite3PagerOpen(
*/
if( zFilename && zFilename[0] ){
const char *z;
+ if( (vfsFlags & SQLITE_OPEN_NOFOLLOW)!=0 ){
+ int isLink = 0;
+ if( sqlite3OsAccess(pVfs, zFilename, SQLITE_ACCESS_SYMLINK, &isLink)==0
+ && isLink
+ ){
+ return SQLITE_CANTOPEN_SYMLINK;
+ }
+ }
nPathname = pVfs->mxPathname+1;
zPathname = sqlite3DbMallocRaw(0, nPathname*2);
if( zPathname==0 ){
diff --git a/src/shell.c.in b/src/shell.c.in
index 105cab6e5..e6b6f1a1b 100644
--- a/src/shell.c.in
+++ b/src/shell.c.in
@@ -1021,6 +1021,7 @@ struct ShellState {
int outCount; /* Revert to stdout when reaching zero */
int cnt; /* Number of records displayed so far */
int lineno; /* Line number of last line read from in */
+ int openFlags; /* Additional flags to open. (SQLITE_OPEN_NOFOLLOW) */
FILE *in; /* Read commands from this stream */
FILE *out; /* Write results here */
FILE *traceOut; /* Output for sqlite3_trace() */
@@ -3562,6 +3563,7 @@ static const char *(azHelp[]) = {
" --maxsize N Maximum size for --hexdb or --deserialized database",
#endif
" --new Initialize FILE to an empty database",
+ " --nofollow Do not follow symbolic links",
" --readonly Open FILE readonly",
" --zip FILE is a ZIP archive",
".output ?FILE? Send output to FILE or stdout if FILE is omitted",
@@ -4126,7 +4128,7 @@ static void open_db(ShellState *p, int openFlags){
switch( p->openMode ){
case SHELL_OPEN_APPENDVFS: {
sqlite3_open_v2(p->zDbFilename, &p->db,
- SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, "apndvfs");
+ SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|p->openFlags, "apndvfs");
break;
}
case SHELL_OPEN_HEXDB:
@@ -4139,12 +4141,14 @@ static void open_db(ShellState *p, int openFlags){
break;
}
case SHELL_OPEN_READONLY: {
- sqlite3_open_v2(p->zDbFilename, &p->db, SQLITE_OPEN_READONLY, 0);
+ sqlite3_open_v2(p->zDbFilename, &p->db,
+ SQLITE_OPEN_READONLY|p->openFlags, 0);
break;
}
case SHELL_OPEN_UNSPEC:
case SHELL_OPEN_NORMAL: {
- sqlite3_open(p->zDbFilename, &p->db);
+ sqlite3_open_v2(p->zDbFilename, &p->db,
+ SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|p->openFlags, 0);
break;
}
}
@@ -8042,6 +8046,7 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3_free(p->zFreeOnClose);
p->zFreeOnClose = 0;
p->openMode = SHELL_OPEN_UNSPEC;
+ p->openFlags = 0;
p->szMax = 0;
/* Check for command-line arguments */
for(iName=1; iName<nArg && azArg[iName][0]=='-'; iName++){
@@ -8056,6 +8061,8 @@ static int do_meta_command(char *zLine, ShellState *p){
p->openMode = SHELL_OPEN_APPENDVFS;
}else if( optionMatch(z, "readonly") ){
p->openMode = SHELL_OPEN_READONLY;
+ }else if( optionMatch(z, "nofollow") ){
+ p->openFlags |= SQLITE_OPEN_NOFOLLOW;
#ifdef SQLITE_ENABLE_DESERIALIZE
}else if( optionMatch(z, "deserialize") ){
p->openMode = SHELL_OPEN_DESERIALIZE;
@@ -9976,6 +9983,7 @@ static const char zOptions[] =
" -multiplex enable the multiplexor VFS\n"
#endif
" -newline SEP set output row separator. Default: '\\n'\n"
+ " -nofollow refuse to open symbolic links to database files\n"
" -nullvalue TEXT set text string for NULL values. Default ''\n"
" -pagecache SIZE N use N slots of SZ bytes each for page cache memory\n"
" -quote set output mode to 'quote'\n"
@@ -10286,6 +10294,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
#endif
}else if( strcmp(z,"-readonly")==0 ){
data.openMode = SHELL_OPEN_READONLY;
+ }else if( strcmp(z,"-nofollow")==0 ){
+ data.openFlags = SQLITE_OPEN_NOFOLLOW;
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
}else if( strncmp(z, "-A",2)==0 ){
/* All remaining command-line arguments are passed to the ".archive"
@@ -10389,6 +10399,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
#endif
}else if( strcmp(z,"-readonly")==0 ){
data.openMode = SHELL_OPEN_READONLY;
+ }else if( strcmp(z,"-nofollow")==0 ){
+ data.openFlags |= SQLITE_OPEN_NOFOLLOW;
}else if( strcmp(z,"-ascii")==0 ){
data.mode = MODE_Ascii;
sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index 91d3158ee..8373f5c7f 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -516,6 +516,7 @@ int sqlite3_exec(
#define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8))
#define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4<<8))
#define SQLITE_CANTOPEN_DIRTYWAL (SQLITE_CANTOPEN | (5<<8)) /* Not Used */
+#define SQLITE_CANTOPEN_SYMLINK (SQLITE_CANTOPEN | (6<<8))
#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8))
#define SQLITE_CORRUPT_SEQUENCE (SQLITE_CORRUPT | (2<<8))
#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
@@ -568,6 +569,7 @@ int sqlite3_exec(
#define SQLITE_OPEN_SHAREDCACHE 0x00020000 /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_PRIVATECACHE 0x00040000 /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_WAL 0x00080000 /* VFS only */
+#define SQLITE_OPEN_NOFOLLOW 0x01000000 /* Ok for sqlite3_open_v2() */
/* Reserved: 0x00F00000 */
@@ -1406,6 +1408,7 @@ struct sqlite3_vfs {
#define SQLITE_ACCESS_EXISTS 0
#define SQLITE_ACCESS_READWRITE 1 /* Used by PRAGMA temp_store_directory */
#define SQLITE_ACCESS_READ 2 /* Unused */
+#define SQLITE_ACCESS_SYMLINK 3 /* Test if file is symbolic link */
/*
** CAPI3REF: Flags for the xShmLock VFS method
diff --git a/src/tclsqlite.c b/src/tclsqlite.c
index 80a057262..a691898dc 100644
--- a/src/tclsqlite.c
+++ b/src/tclsqlite.c
@@ -3670,6 +3670,7 @@ static int sqliteCmdUsage(
){
Tcl_WrongNumArgs(interp, 1, objv,
"HANDLE ?FILENAME? ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN?"
+ " ?-nofollow BOOLEAN?"
" ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?"
#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
" ?-key CODECKEY?"
@@ -3681,6 +3682,7 @@ static int sqliteCmdUsage(
/*
** sqlite3 DBNAME FILENAME ?-vfs VFSNAME? ?-key KEY? ?-readonly BOOLEAN?
** ?-create BOOLEAN? ?-nomutex BOOLEAN?
+** ?-nofollow BOOLEAN?
**
** This is the main Tcl command. When the "sqlite" Tcl command is
** invoked, this routine runs to process that command.
@@ -3779,6 +3781,14 @@ static int SQLITE_TCLAPI DbMain(
}else{
flags &= ~SQLITE_OPEN_CREATE;
}
+ }else if( strcmp(zArg, "-nofollow")==0 ){
+ int b;
+ if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR;
+ if( b ){
+ flags |= SQLITE_OPEN_NOFOLLOW;
+ }else{
+ flags &= ~SQLITE_OPEN_NOFOLLOW;
+ }
}else if( strcmp(zArg, "-nomutex")==0 ){
int b;
if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR;
diff --git a/src/test_demovfs.c b/src/test_demovfs.c
index eaba20873..baf14b10b 100644
--- a/src/test_demovfs.c
+++ b/src/test_demovfs.c
@@ -508,8 +508,14 @@ static int demoAccess(
assert( flags==SQLITE_ACCESS_EXISTS /* access(zPath, F_OK) */
|| flags==SQLITE_ACCESS_READ /* access(zPath, R_OK) */
|| flags==SQLITE_ACCESS_READWRITE /* access(zPath, R_OK|W_OK) */
+ || flags==SQLITE_ACCESS_SYMLINK /* Always false */
);
+ if( flags==SQLITE_ACCESS_SYMLINK ){
+ /* For this demo implementation, assume that symlinks do not exist. */
+ *pResOut = 0;
+ return SQLITE_OK;
+ }
if( flags==SQLITE_ACCESS_READWRITE ) eAccess = R_OK|W_OK;
if( flags==SQLITE_ACCESS_READ ) eAccess = R_OK;
diff --git a/src/test_vfs.c b/src/test_vfs.c
index 3357a0a27..84baeb943 100644
--- a/src/test_vfs.c
+++ b/src/test_vfs.c
@@ -732,6 +732,7 @@ static int tvfsAccess(
if( flags==SQLITE_ACCESS_EXISTS ) zArg = "SQLITE_ACCESS_EXISTS";
if( flags==SQLITE_ACCESS_READWRITE ) zArg = "SQLITE_ACCESS_READWRITE";
if( flags==SQLITE_ACCESS_READ ) zArg = "SQLITE_ACCESS_READ";
+ if( flags==SQLITE_ACCESS_SYMLINK ) zArg = "SQLITE_ACCESS_SYMLINK";
tvfsExecTcl(p, "xAccess",
Tcl_NewStringObj(zPath, -1), Tcl_NewStringObj(zArg, -1), 0, 0
);