diff options
author | drh <drh@noemail.net> | 2019-11-18 17:46:38 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2019-11-18 17:46:38 +0000 |
commit | 0933aad72c5ac1a763891c03b231ce72b1d19b03 (patch) | |
tree | ace29f58dd8b9c2ac613cc8dad3c8fc4d47cc5a8 /src | |
parent | 804725a6b9ea8ba9ef507866b1d8d2628d1e4356 (diff) | |
download | sqlite-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.c | 18 | ||||
-rw-r--r-- | src/os_win.c | 3 | ||||
-rw-r--r-- | src/pager.c | 8 | ||||
-rw-r--r-- | src/shell.c.in | 18 | ||||
-rw-r--r-- | src/sqlite.h.in | 3 | ||||
-rw-r--r-- | src/tclsqlite.c | 10 | ||||
-rw-r--r-- | src/test_demovfs.c | 6 | ||||
-rw-r--r-- | src/test_vfs.c | 1 |
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 ); |