Add the "modeof=<filename>" URI parameter to os_unix.c - used to specify a file to copy permissions from when a new database is created. Also allow passing NULL as the second parameter to sqlite3rbu_vacuum().

FossilOrigin-Name: ed406d31ff54ee3de8db91690a966e5c561f8f94
This commit is contained in:
dan 2016-08-11 18:05:47 +00:00
parent 6ff4627d5d
commit 1bf4ca7c42
8 changed files with 126 additions and 35 deletions

View File

@ -361,6 +361,8 @@ foreach {bReopen} { 0 1 } {
}
} {
if {$tn=="vtab"} { ifcapable !fts5 break }
foreach {tn2 rbusql r1 r2} {
1 {
CREATE TABLE data0_t1(a, b, c, rbu_rowid, rbu_control);

View File

@ -156,7 +156,49 @@ foreach step {0 1} {
trigger tr1 t1 0 {CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN SELECT 1; END}
}
}
}
#-------------------------------------------------------------------------
# Test that passing a NULL value as the second argument to
# sqlite3rbu_vacuum() causes it to:
#
# * Use <database>-vacuum as the state db, and
# * Set the state db permissions to the same as those on the db file.
#
db close
if {$::tcl_platform(platform)=="unix"} {
forcedelete test.db
sqlite3 db test.db
do_execsql_test 5.0 {
CREATE TABLE t1(a, b);
INSERT INTO t1 VALUES(1, 2);
INSERT INTO t1 VALUES(3, 4);
INSERT INTO t1 VALUES(5, 6);
INSERT INTO t1 VALUES(7, 8);
}
db close
foreach {tn perm} {
1 00755
2 00666
3 00644
4 00444
} {
forcedelete test.db-vacuum
do_test 5.$tn.1 {
file attributes test.db -permissions $perm
sqlite3rbu_vacuum rbu test.db
rbu step
} {SQLITE_OK}
do_test 5.$tn.2 { file exists test.db-vacuum } 1
do_test 5.$tn.3 { file attributes test.db-vacuum -permissions} $perm
rbu close
}
}
finish_test

View File

@ -2334,15 +2334,18 @@ static RbuState *rbuLoadState(sqlite3rbu *p){
** error occurs, leave an error code and message in the RBU handle.
*/
static void rbuOpenDatabase(sqlite3rbu *p){
assert( p->rc==SQLITE_OK );
assert( p->dbMain==0 && p->dbRbu==0 );
assert( rbuIsVacuum(p) || p->zTarget!=0 );
assert( p->rc || (p->dbMain==0 && p->dbRbu==0) );
assert( p->rc || rbuIsVacuum(p) || p->zTarget!=0 );
/* Open the RBU database */
p->dbRbu = rbuOpenDbhandle(p, p->zRbu, 1);
if( p->rc==SQLITE_OK && rbuIsVacuum(p) ){
sqlite3_file_control(p->dbRbu, "main", SQLITE_FCNTL_RBUCNT, (void*)p);
if( p->zState==0 ){
const char *zFile = sqlite3_db_filename(p->dbRbu, "main");
p->zState = rbuMPrintf(p, "file://%s-vacuum?modeof=%s", zFile, zFile);
}
}
/* If using separate RBU and state databases, attach the state database to
@ -3477,8 +3480,7 @@ static sqlite3rbu *openRbuHandle(
sqlite3rbu *p;
size_t nTarget = zTarget ? strlen(zTarget) : 0;
size_t nRbu = strlen(zRbu);
size_t nState = zState ? strlen(zState) : 0;
size_t nByte = sizeof(sqlite3rbu) + nTarget+1 + nRbu+1+ nState+1;
size_t nByte = sizeof(sqlite3rbu) + nTarget+1 + nRbu+1;
p = (sqlite3rbu*)sqlite3_malloc64(nByte);
if( p ){
@ -3500,8 +3502,7 @@ static sqlite3rbu *openRbuHandle(
memcpy(p->zRbu, zRbu, nRbu+1);
pCsr += nRbu+1;
if( zState ){
p->zState = pCsr;
memcpy(p->zState, zState, nState+1);
p->zState = rbuMPrintf(p, "%s", zState);
}
rbuOpenDatabase(p);
}
@ -3611,6 +3612,20 @@ static sqlite3rbu *openRbuHandle(
return p;
}
/*
** Allocate and return an RBU handle with all fields zeroed except for the
** error code, which is set to SQLITE_MISUSE.
*/
static sqlite3rbu *rbuMisuseError(void){
sqlite3rbu *pRet;
pRet = sqlite3_malloc64(sizeof(sqlite3rbu));
if( pRet ){
memset(pRet, 0, sizeof(sqlite3rbu));
pRet->rc = SQLITE_MISUSE;
}
return pRet;
}
/*
** Open and return a new RBU handle.
*/
@ -3619,6 +3634,7 @@ sqlite3rbu *sqlite3rbu_open(
const char *zRbu,
const char *zState
){
if( zTarget==0 || zRbu==0 ){ return rbuMisuseError(); }
/* TODO: Check that zTarget and zRbu are non-NULL */
return openRbuHandle(zTarget, zRbu, zState);
}
@ -3630,6 +3646,7 @@ sqlite3rbu *sqlite3rbu_vacuum(
const char *zTarget,
const char *zState
){
if( zTarget==0 ){ return rbuMisuseError(); }
/* TODO: Check that both arguments are non-NULL */
return openRbuHandle(0, zTarget, zState);
}
@ -3707,6 +3724,7 @@ int sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){
rbuEditErrmsg(p);
rc = p->rc;
*pzErrmsg = p->zErrmsg;
sqlite3_free(p->zState);
sqlite3_free(p);
}else{
rc = SQLITE_NOMEM;

View File

@ -319,16 +319,22 @@ sqlite3rbu *sqlite3rbu_open(
** An RBU vacuum is similar to SQLite's built-in VACUUM command, except
** that it can be suspended and resumed like an RBU update.
**
** The second argument to this function, which may not be NULL, identifies
** a database in which to store the state of the RBU vacuum operation if
** it is suspended. The first time sqlite3rbu_vacuum() is called, to start
** an RBU vacuum operation, the state database should either not exist or
** be empty (contain no tables). If an RBU vacuum is suspended by calling
** The second argument to this function identifies a database in which
** to store the state of the RBU vacuum operation if it is suspended. The
** first time sqlite3rbu_vacuum() is called, to start an RBU vacuum
** operation, the state database should either not exist or be empty
** (contain no tables). If an RBU vacuum is suspended by calling
** sqlite3rbu_close() on the RBU handle before sqlite3rbu_step() has
** returned SQLITE_DONE, the vacuum state is stored in the state database.
** The vacuum can be resumed by calling this function to open a new RBU
** handle specifying the same target and state databases.
**
** If the second argument passed to this function is NULL, then the
** name of the state database is "<database>-vacuum", where <database>
** is the name of the target database file. In this case, on UNIX, if the
** state database is not already present in the file-system, it is created
** with the same permissions as the target db is made.
**
** This function does not delete the state database after an RBU vacuum
** is completed, even if it created it. However, if the call to
** sqlite3rbu_close() returns any value other than SQLITE_OK, the contents

View File

@ -240,13 +240,13 @@ static int SQLITE_TCLAPI test_sqlite3rbu_vacuum(
const char *zTarget;
const char *zStateDb = 0;
if( objc!=4 ){
Tcl_WrongNumArgs(interp, 1, objv, "NAME TARGET-DB STATE-DB");
if( objc!=3 && objc!=4 ){
Tcl_WrongNumArgs(interp, 1, objv, "NAME TARGET-DB ?STATE-DB?");
return TCL_ERROR;
}
zCmd = Tcl_GetString(objv[1]);
zTarget = Tcl_GetString(objv[2]);
zStateDb = Tcl_GetString(objv[3]);
if( objc==4 ) zStateDb = Tcl_GetString(objv[3]);
pRbu = sqlite3rbu_vacuum(zTarget, zStateDb);
Tcl_CreateObjCommand(interp, zCmd, test_sqlite3rbu_cmd, (ClientData)pRbu, 0);

View File

@ -1,5 +1,5 @@
C Fix\sa\s1\sbyte\sbuffer\soverwrite\sin\sthe\s"sqldiff\s--rbu"\scommand.
D 2016-08-11T09:55:55.485
C Add\sthe\s"modeof=<filename>"\sURI\sparameter\sto\sos_unix.c\s-\sused\sto\sspecify\sa\sfile\sto\scopy\spermissions\sfrom\swhen\sa\snew\sdatabase\sis\screated.\sAlso\sallow\spassing\sNULL\sas\sthe\ssecond\sparameter\sto\ssqlite3rbu_vacuum().
D 2016-08-11T18:05:47.763
F Makefile.in cfd8fb987cd7a6af046daa87daa146d5aad0e088
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc d66d0395c38571aab3804f8db0fa20707ae4609a
@ -250,13 +250,13 @@ F ext/rbu/rbufault.test cc0be8d5d392d98b0c2d6a51be377ea989250a89
F ext/rbu/rbufault2.test 9a7f19edd6ea35c4c9f807d8a3db0a03a5670c06
F ext/rbu/rbufault3.test 54a399888ac4af44c68f9f58afbed23149428bca
F ext/rbu/rbufts.test 828cd689da825f0a7b7c53ffc1f6f7fdb6fa5bda
F ext/rbu/rbuprogress.test 2023a7df2c523e3df1cb532eff811cda385a789a
F ext/rbu/rbuprogress.test e3e25fb7622641b8f2df7c6b7a7eb6fddfc46a4b
F ext/rbu/rbusave.test 0f43b6686084f426ddd040b878426452fd2c2f48
F ext/rbu/rbuvacuum.test 4a977447c15c2581ab668781d9ef4294382530e0
F ext/rbu/rbuvacuum2.test 45009e127c3fb385e5c0fd5a8a63fb922a79d0ab
F ext/rbu/sqlite3rbu.c 948677ee0ec57da51148e6c5f64ac68afcf36ab2
F ext/rbu/sqlite3rbu.h db8858120c9be14b60c9225f9da28221f5f6b945
F ext/rbu/test_rbu.c 1a6bbc6982e32485a48df111d0bb1934d537eabd
F ext/rbu/rbuvacuum2.test 2569205b74ff40fbf3bda2fce33a58eb40eebdcc
F ext/rbu/sqlite3rbu.c e074c38798b90591f7f0cf0032d62f152ce5a95e
F ext/rbu/sqlite3rbu.h 1d91c5b7d066645bd1ff8e4b85c2b9b5dd29fb05
F ext/rbu/test_rbu.c 5aa22616afac6f71ebd3d9bc9bf1006cfabcca88
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
F ext/rtree/rtree.c d26a815b0df1c412a6881dae8d7fd3c9c08cce68
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
@ -368,7 +368,7 @@ F src/os.c add02933b1dce7a39a005b00a2f5364b763e9a24
F src/os.h 8e976e59eb4ca1c0fca6d35ee803e38951cb0343
F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85
F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
F src/os_unix.c a9443cdab41d7f3cdf0df3a5aab62fd6e1c9b234
F src/os_unix.c be9ca0f901a2b6c1bc93dc338f4863675180c189
F src/os_win.c 520f23475f1de530c435d30b67b7b15fe90874b0
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
F src/pager.c 40928c450320da78bb4bd3ae82818f4239e19b7e
@ -1510,7 +1510,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 2ea0c8b46eefd4874f021f8dfd344be751f2034f
R 26e854b22e510a9651c111418b0d5f03
P ab83d7077da80ddbcf399d0797d79e964dc64f0e
R 753cf0ce0fc5b95ce832a2f13995ee3e
U dan
Z 78ea492cf13c3fac64589b27f22aa44b
Z 87571942a0f33f54e925f9d7f08d0ded

View File

@ -1 +1 @@
ab83d7077da80ddbcf399d0797d79e964dc64f0e
ed406d31ff54ee3de8db91690a966e5c561f8f94

View File

@ -5529,6 +5529,27 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
return pUnused;
}
/*
** Find the mode, uid and gid of file zFile.
*/
static int getFileMode(
const char *zFile, /* File name */
mode_t *pMode, /* OUT: Permissions of zFile */
uid_t *pUid, /* OUT: uid of zFile. */
gid_t *pGid /* OUT: gid of zFile. */
){
struct stat sStat; /* Output of stat() on database file */
int rc = SQLITE_OK;
if( 0==osStat(zFile, &sStat) ){
*pMode = sStat.st_mode & 0777;
*pUid = sStat.st_uid;
*pGid = sStat.st_gid;
}else{
rc = SQLITE_IOERR_FSTAT;
}
return rc;
}
/*
** This function is called by unixOpen() to determine the unix permissions
** to create new files with. If no error occurs, then SQLITE_OK is returned
@ -5564,7 +5585,6 @@ static int findCreateFileMode(
if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){
char zDb[MAX_PATHNAME+1]; /* Database file path */
int nDb; /* Number of valid bytes in zDb */
struct stat sStat; /* Output of stat() on database file */
/* zPath is a path to a WAL or journal file. The following block derives
** the path to the associated database file from zPath. This block handles
@ -5595,15 +5615,18 @@ static int findCreateFileMode(
memcpy(zDb, zPath, nDb);
zDb[nDb] = '\0';
if( 0==osStat(zDb, &sStat) ){
*pMode = sStat.st_mode & 0777;
*pUid = sStat.st_uid;
*pGid = sStat.st_gid;
}else{
rc = SQLITE_IOERR_FSTAT;
}
rc = getFileMode(zDb, pMode, pUid, pGid);
}else if( flags & SQLITE_OPEN_DELETEONCLOSE ){
*pMode = 0600;
}else if( flags & SQLITE_OPEN_URI ){
/* If this is a main database file and the file was opened using a URI
** filename, check for the "modeof" parameter. If present, interpret
** its value as a filename and try to copy the mode, uid and gid from
** that file. */
const char *z = sqlite3_uri_parameter(zPath, "modeof");
if( z ){
rc = getFileMode(z, pMode, pUid, pGid);
}
}
return rc;
}