mirror of
https://github.com/sqlite/sqlite.git
synced 2026-01-06 08:01:16 +03:00
Add support for parsing options in non-traditional tar form to the ".ar"
command. Have writefile() attempt to create any missing path components. And not to throw an exception if it is called to create a directory that already exists. FossilOrigin-Name: 38dbeb1e777aa7ec742aa27002ad4dcee28af520dc43de96e5c56c39f16574ff
This commit is contained in:
@@ -40,6 +40,7 @@ SQLITE_EXTENSION_INIT1
|
||||
#include <dirent.h>
|
||||
#include <time.h>
|
||||
#include <utime.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
#define FSDIR_SCHEMA "(name,mode,mtime,data,path HIDDEN,dir HIDDEN)"
|
||||
@@ -90,6 +91,103 @@ static void ctxErrorMsg(sqlite3_context *ctx, const char *zFmt, ...){
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/*
|
||||
** Argument zFile is the name of a file that will be created and/or written
|
||||
** by SQL function writefile(). This function ensures that the directory
|
||||
** zFile will be written to exists, creating it if required. The permissions
|
||||
** for any path components created by this function are set to (mode&0777).
|
||||
**
|
||||
** If an OOM condition is encountered, SQLITE_NOMEM is returned. Otherwise,
|
||||
** SQLITE_OK is returned if the directory is successfully created, or
|
||||
** SQLITE_ERROR otherwise.
|
||||
*/
|
||||
static int makeDirectory(
|
||||
const char *zFile,
|
||||
mode_t mode
|
||||
){
|
||||
char *zCopy = sqlite3_mprintf("%s", zFile);
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
if( zCopy==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
int nCopy = strlen(zCopy);
|
||||
int i = 1;
|
||||
|
||||
while( rc==SQLITE_OK ){
|
||||
struct stat sStat;
|
||||
int rc;
|
||||
|
||||
for(; zCopy[i]!='/' && i<nCopy; i++);
|
||||
if( i==nCopy ) break;
|
||||
zCopy[i] = '\0';
|
||||
|
||||
rc = stat(zCopy, &sStat);
|
||||
if( rc!=0 ){
|
||||
if( mkdir(zCopy, mode & 0777) ) rc = SQLITE_ERROR;
|
||||
}else{
|
||||
if( !S_ISDIR(sStat.st_mode) ) rc = SQLITE_ERROR;
|
||||
}
|
||||
zCopy[i] = '/';
|
||||
i++;
|
||||
}
|
||||
|
||||
sqlite3_free(zCopy);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int writeFile(
|
||||
sqlite3_context *pCtx,
|
||||
const char *zFile,
|
||||
mode_t mode,
|
||||
sqlite3_value *pData
|
||||
){
|
||||
if( S_ISLNK(mode) ){
|
||||
const char *zTo = (const char*)sqlite3_value_text(pData);
|
||||
if( symlink(zTo, zFile)<0 ) return 1;
|
||||
}else{
|
||||
if( S_ISDIR(mode) ){
|
||||
if( mkdir(zFile, mode) ){
|
||||
/* The mkdir() call to create the directory failed. This might not
|
||||
** be an error though - if there is already a directory at the same
|
||||
** path and either the permissions already match or can be changed
|
||||
** to do so using chmod(), it is not an error. */
|
||||
struct stat sStat;
|
||||
if( errno!=EEXIST
|
||||
|| 0!=stat(zFile, &sStat)
|
||||
|| !S_ISDIR(sStat.st_mode)
|
||||
|| ((sStat.st_mode&0777)!=(mode&0777) && 0!=chmod(zFile, mode&0777))
|
||||
){
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
sqlite3_int64 nWrite = 0;
|
||||
const char *z;
|
||||
int rc = 0;
|
||||
FILE *out = fopen(zFile, "wb");
|
||||
if( out==0 ) return 1;
|
||||
z = (const char*)sqlite3_value_blob(pData);
|
||||
if( z ){
|
||||
sqlite3_int64 n = fwrite(z, 1, sqlite3_value_bytes(pData), out);
|
||||
nWrite = sqlite3_value_bytes(pData);
|
||||
if( nWrite!=n ){
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
fclose(out);
|
||||
if( rc==0 && chmod(zFile, mode & 0777) ){
|
||||
rc = 1;
|
||||
}
|
||||
if( rc ) return 2;
|
||||
sqlite3_result_int64(pCtx, nWrite);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the "writefile(W,X[,Y]])" SQL function.
|
||||
**
|
||||
@@ -104,6 +202,7 @@ static void writefileFunc(
|
||||
){
|
||||
const char *zFile;
|
||||
mode_t mode = 0;
|
||||
int res;
|
||||
|
||||
if( argc<2 || argc>3 ){
|
||||
sqlite3_result_error(context,
|
||||
@@ -119,46 +218,20 @@ static void writefileFunc(
|
||||
mode = sqlite3_value_int(argv[2]);
|
||||
}
|
||||
|
||||
if( S_ISLNK(mode) ){
|
||||
const char *zTo = (const char*)sqlite3_value_text(argv[1]);
|
||||
if( symlink(zTo, zFile)<0 ){
|
||||
ctxErrorMsg(context, "failed to create symlink: %s", zFile);
|
||||
return;
|
||||
}
|
||||
}else{
|
||||
if( S_ISDIR(mode) ){
|
||||
if( mkdir(zFile, mode) ){
|
||||
ctxErrorMsg(context, "failed to create directory: %s", zFile);
|
||||
return;
|
||||
}
|
||||
}else{
|
||||
sqlite3_int64 nWrite = 0;
|
||||
const char *z;
|
||||
int rc = 0;
|
||||
FILE *out = fopen(zFile, "wb");
|
||||
if( out==0 ){
|
||||
if( argc>2 ){
|
||||
ctxErrorMsg(context, "failed to open file for writing: %s", zFile);
|
||||
}
|
||||
return;
|
||||
}
|
||||
z = (const char*)sqlite3_value_blob(argv[1]);
|
||||
if( z ){
|
||||
sqlite3_int64 n = fwrite(z, 1, sqlite3_value_bytes(argv[1]), out);
|
||||
nWrite = sqlite3_value_bytes(argv[1]);
|
||||
if( nWrite!=n ){
|
||||
ctxErrorMsg(context, "failed to write file: %s", zFile);
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
fclose(out);
|
||||
if( rc ) return;
|
||||
sqlite3_result_int64(context, nWrite);
|
||||
res = writeFile(context, zFile, mode, argv[1]);
|
||||
if( res==1 && errno==ENOENT ){
|
||||
if( makeDirectory(zFile, mode)==SQLITE_OK ){
|
||||
res = writeFile(context, zFile, mode, argv[1]);
|
||||
}
|
||||
}
|
||||
|
||||
if( argc>2 && chmod(zFile, mode & 0777) ){
|
||||
ctxErrorMsg(context, "failed to chmod file: %s", zFile);
|
||||
return;
|
||||
if( res!=0 ){
|
||||
if( S_ISLNK(mode) ){
|
||||
ctxErrorMsg(context, "failed to create symlink: %s", zFile);
|
||||
}else if( S_ISDIR(mode) ){
|
||||
ctxErrorMsg(context, "failed to create directory: %s", zFile);
|
||||
}else{
|
||||
ctxErrorMsg(context, "failed to write file: %s", zFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
16
manifest
16
manifest
@@ -1,5 +1,5 @@
|
||||
C Enhance\svirtual\stable\s"fsdir"\sin\sext/misc/fileio.c.\sAdd\ssupport\sfor\s"-C"\sto\nthe\sshell\scommand's\s".ar\sc"\scommand.
|
||||
D 2017-12-11T20:22:02.045
|
||||
C Add\ssupport\sfor\sparsing\soptions\sin\snon-traditional\star\sform\sto\sthe\s".ar"\ncommand.\sHave\swritefile()\sattempt\sto\screate\sany\smissing\spath\scomponents.\sAnd\nnot\sto\sthrow\san\sexception\sif\sit\sis\scalled\sto\screate\sa\sdirectory\sthat\salready\nexists.
|
||||
D 2017-12-12T20:04:59.331
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F Makefile.in 6a879cbf01e37f9eac131414955f71774b566502d9a57ded1b8585b507503cb8
|
||||
@@ -269,7 +269,7 @@ F ext/misc/compress.c 122faa92d25033d6c3f07c39231de074ab3d2e83
|
||||
F ext/misc/csv.c 1a009b93650732e22334edc92459c4630b9fa703397cbb3c8ca279921a36ca11
|
||||
F ext/misc/dbdump.c 3509fa6b8932d04e932d6b6b827b6a82ca362781b8e8f3c77336f416793e215e
|
||||
F ext/misc/eval.c f971962e92ebb8b0a4e6b62949463ee454d88fa2
|
||||
F ext/misc/fileio.c 238d0c65a14bda99748285527543273e0248bc428c01c3955ec45acb8738db3b
|
||||
F ext/misc/fileio.c 29b7fc94752fff6245cf4a81455f98cf6778ec1102ca7e67bf693d41a7db4307
|
||||
F ext/misc/fuzzer.c 7c64b8197bb77b7d64eff7cac7848870235d4c25
|
||||
F ext/misc/ieee754.c f190d0cc5182529acb15babd177781be1ac1718c
|
||||
F ext/misc/json1.c dbe086615b9546c156bf32b9378fc09383b58bd17513b866cfd24c1e15281984
|
||||
@@ -474,7 +474,7 @@ F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
|
||||
F src/resolve.c bbee7e31d369a18a2f4836644769882e9c5d40ef4a3af911db06410b65cb3730
|
||||
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
|
||||
F src/select.c 17e220191860a64a18c084141e1a8b7309e166a6f2d42c02021af27ea080d157
|
||||
F src/shell.c.in 4c7a2c1226216dfad7978642c958143f0fdfee4f09aef2add1e73e3601dd7d33
|
||||
F src/shell.c.in 0ab6e3c1fa09e420e643628d55929422867ca053f05df67a4cae4a67e2a6cfc5
|
||||
F src/sqlite.h.in 8fd97993d48b50b9bade38c52f12d175942c9497c960905610c7b03a3e4b5818
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h c02d628cca67f3889c689d82d25c3eb45e2c155db08e4c6089b5840d64687d34
|
||||
@@ -1214,7 +1214,7 @@ F test/shell4.test 89ad573879a745974ff2df20ff97c5d6ffffbd5d
|
||||
F test/shell5.test 23939a4c51f0421330ea61dbd3c74f9c215f5f8d3d1a94846da6ffc777a35458
|
||||
F test/shell6.test 1ceb51b2678c472ba6cf1e5da96679ce8347889fe2c3bf93a0e0fa73f00b00d3
|
||||
F test/shell7.test 115132f66d0463417f408562cc2cf534f6bbc6d83a6d50f0072a9eb171bae97f
|
||||
F test/shell8.test d04773f4e8cdad62d42a1b13bf4c1182109880441689a2f5d5001e190ec04831
|
||||
F test/shell8.test 5c5a9d100d34b125e0f46d259ea76cf074ac60719b722b2a2c63d759c63fc113
|
||||
F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
|
||||
F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5
|
||||
F test/shrink.test 1b4330b1fd9e818c04726d45cb28db73087535ce
|
||||
@@ -1682,7 +1682,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 8cd70960c5ddf0d0b2c40b8b6af4ce6b0277ffdaf04f33fcb33227d2b99ad515
|
||||
R ddf59f7efc51e054de53889e9f879e48
|
||||
P 0394889afed2479773af594e2d9659cf58b8959004ebcdeaff8e08e5dae684ef
|
||||
R e0d6dbcefc8608142fe03f9ef6d2dee7
|
||||
U dan
|
||||
Z c8a2667de38f55deb8cffcf1545f4d0c
|
||||
Z 5813e7d404a813775aab77275468b917
|
||||
|
||||
@@ -1 +1 @@
|
||||
0394889afed2479773af594e2d9659cf58b8959004ebcdeaff8e08e5dae684ef
|
||||
38dbeb1e777aa7ec742aa27002ad4dcee28af520dc43de96e5c56c39f16574ff
|
||||
244
src/shell.c.in
244
src/shell.c.in
@@ -4075,17 +4075,17 @@ static int lintDotCommand(
|
||||
}
|
||||
|
||||
static void shellPrepare(
|
||||
ShellState *p,
|
||||
sqlite3 *db,
|
||||
int *pRc,
|
||||
const char *zSql,
|
||||
sqlite3_stmt **ppStmt
|
||||
){
|
||||
*ppStmt = 0;
|
||||
if( *pRc==SQLITE_OK ){
|
||||
int rc = sqlite3_prepare_v2(p->db, zSql, -1, ppStmt, 0);
|
||||
int rc = sqlite3_prepare_v2(db, zSql, -1, ppStmt, 0);
|
||||
if( rc!=SQLITE_OK ){
|
||||
raw_printf(stderr, "sql error: %s (%d)\n",
|
||||
sqlite3_errmsg(p->db), sqlite3_errcode(p->db)
|
||||
sqlite3_errmsg(db), sqlite3_errcode(db)
|
||||
);
|
||||
*pRc = rc;
|
||||
}
|
||||
@@ -4141,10 +4141,42 @@ static int arUsage(void){
|
||||
/*
|
||||
** Values for ArCommand.eCmd.
|
||||
*/
|
||||
#define AR_CMD_CREATE 1
|
||||
#define AR_CMD_EXTRACT 2
|
||||
#define AR_CMD_LIST 3
|
||||
#define AR_CMD_UPDATE 4
|
||||
#define AR_CMD_CREATE 1
|
||||
#define AR_CMD_EXTRACT 2
|
||||
#define AR_CMD_LIST 3
|
||||
#define AR_CMD_UPDATE 4
|
||||
|
||||
/*
|
||||
** Other (non-command) switches.
|
||||
*/
|
||||
#define AR_SWITCH_VERBOSE 5
|
||||
#define AR_SWITCH_FILE 6
|
||||
#define AR_SWITCH_DIRECTORY 7
|
||||
|
||||
static int arProcessSwitch(ArCommand *pAr, int eSwitch, const char *zArg){
|
||||
switch( eSwitch ){
|
||||
case AR_CMD_CREATE:
|
||||
case AR_CMD_EXTRACT:
|
||||
case AR_CMD_LIST:
|
||||
case AR_CMD_UPDATE:
|
||||
if( pAr->eCmd ) return arUsage();
|
||||
pAr->eCmd = eSwitch;
|
||||
break;
|
||||
|
||||
case AR_SWITCH_VERBOSE:
|
||||
pAr->bVerbose = 1;
|
||||
break;
|
||||
|
||||
case AR_SWITCH_FILE:
|
||||
pAr->zFile = zArg;
|
||||
break;
|
||||
case AR_SWITCH_DIRECTORY:
|
||||
pAr->zDir = zArg;
|
||||
break;
|
||||
}
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Parse the command line for an ".ar" command. The results are written into
|
||||
@@ -4157,6 +4189,23 @@ static int arParseCommand(
|
||||
int nArg, /* Number of entries in azArg[] */
|
||||
ArCommand *pAr /* Populate this object */
|
||||
){
|
||||
struct ArSwitch {
|
||||
char cShort;
|
||||
const char *zLong;
|
||||
int eSwitch;
|
||||
int bArg;
|
||||
} aSwitch[] = {
|
||||
{ 'c', "create", AR_CMD_CREATE, 0 },
|
||||
{ 'x', "extract", AR_CMD_EXTRACT, 0 },
|
||||
{ 't', "list", AR_CMD_LIST, 0 },
|
||||
{ 'u', "update", AR_CMD_UPDATE, 0 },
|
||||
{ 'v', "verbose", AR_SWITCH_VERBOSE, 0 },
|
||||
{ 'f', "file", AR_SWITCH_FILE, 1 },
|
||||
{ 'C', "directory", AR_SWITCH_DIRECTORY, 1 }
|
||||
};
|
||||
int nSwitch = sizeof(aSwitch) / sizeof(struct ArSwitch);
|
||||
struct ArSwitch *pEnd = &aSwitch[nSwitch];
|
||||
|
||||
if( nArg<=1 ){
|
||||
return arUsage();
|
||||
}else{
|
||||
@@ -4168,45 +4217,91 @@ static int arParseCommand(
|
||||
int i;
|
||||
int iArg = 2;
|
||||
for(i=0; z[i]; i++){
|
||||
switch( z[i] ){
|
||||
case 'c':
|
||||
if( pAr->eCmd ) return arUsage();
|
||||
pAr->eCmd = AR_CMD_CREATE;
|
||||
break;
|
||||
case 'x':
|
||||
if( pAr->eCmd ) return arUsage();
|
||||
pAr->eCmd = AR_CMD_EXTRACT;
|
||||
break;
|
||||
case 't':
|
||||
if( pAr->eCmd ) return arUsage();
|
||||
pAr->eCmd = AR_CMD_LIST;
|
||||
break;
|
||||
case 'u':
|
||||
if( pAr->eCmd ) return arUsage();
|
||||
pAr->eCmd = AR_CMD_UPDATE;
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
pAr->bVerbose = 1;
|
||||
break;
|
||||
case 'f':
|
||||
if( iArg>=nArg ) return arUsage();
|
||||
pAr->zFile = azArg[iArg++];
|
||||
break;
|
||||
case 'C':
|
||||
if( iArg>=nArg ) return arUsage();
|
||||
pAr->zDir = azArg[iArg++];
|
||||
break;
|
||||
|
||||
default:
|
||||
return arUsage();
|
||||
const char *zArg = 0;
|
||||
struct ArSwitch *pOpt;
|
||||
for(pOpt=&aSwitch[0]; pOpt<pEnd; pOpt++){
|
||||
if( z[i]==pOpt->cShort ) break;
|
||||
}
|
||||
if( pOpt==pEnd ) return arUsage();
|
||||
if( pOpt->bArg ){
|
||||
if( iArg>=nArg ) return arUsage();
|
||||
zArg = azArg[iArg++];
|
||||
}
|
||||
if( arProcessSwitch(pAr, pOpt->eSwitch, zArg) ) return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
pAr->nArg = nArg-iArg;
|
||||
if( pAr->nArg>0 ){
|
||||
pAr->azArg = &azArg[iArg];
|
||||
}
|
||||
}else{
|
||||
/* Non-traditional invocation */
|
||||
int iArg;
|
||||
for(iArg=1; iArg<nArg; iArg++){
|
||||
int n;
|
||||
z = azArg[iArg];
|
||||
if( z[0]!='-' ){
|
||||
/* All remaining command line words are command arguments. */
|
||||
pAr->azArg = &azArg[iArg];
|
||||
pAr->nArg = nArg-iArg;
|
||||
break;
|
||||
}
|
||||
n = strlen(z);
|
||||
|
||||
if( z[1]!='-' ){
|
||||
int i;
|
||||
/* One or more short options */
|
||||
for(i=1; i<n; i++){
|
||||
const char *zArg = 0;
|
||||
struct ArSwitch *pOpt;
|
||||
for(pOpt=&aSwitch[0]; pOpt<pEnd; pOpt++){
|
||||
if( z[i]==pOpt->cShort ) break;
|
||||
}
|
||||
if( pOpt==pEnd ) return arUsage();
|
||||
if( pOpt->bArg ){
|
||||
if( i<(n-1) ){
|
||||
zArg = &z[i+1];
|
||||
i = n;
|
||||
}else{
|
||||
if( iArg>=(nArg-1) ) return arUsage();
|
||||
zArg = azArg[++iArg];
|
||||
}
|
||||
}
|
||||
if( arProcessSwitch(pAr, pOpt->eSwitch, zArg) ) return SQLITE_ERROR;
|
||||
}
|
||||
}else if( z[2]=='\0' ){
|
||||
/* A -- option, indicating that all remaining command line words
|
||||
** are command arguments. */
|
||||
pAr->azArg = &azArg[iArg+1];
|
||||
pAr->nArg = nArg-iArg-1;
|
||||
break;
|
||||
}else{
|
||||
/* A long option */
|
||||
const char *zArg = 0; /* Argument for option, if any */
|
||||
struct ArSwitch *pMatch = 0; /* Matching option */
|
||||
struct ArSwitch *pOpt; /* Iterator */
|
||||
for(pOpt=&aSwitch[0]; pOpt<pEnd; pOpt++){
|
||||
const char *zLong = pOpt->zLong;
|
||||
if( (n-2)<=strlen(zLong) && 0==memcmp(&z[2], zLong, n-2) ){
|
||||
if( pMatch ){
|
||||
/* ambiguous option */
|
||||
return arUsage();
|
||||
}else{
|
||||
pMatch = pOpt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( pMatch==0 ){
|
||||
/* no such option. */
|
||||
return arUsage();
|
||||
}
|
||||
if( pMatch->bArg ){
|
||||
if( iArg>=(nArg-1) ) return arUsage();
|
||||
zArg = azArg[++iArg];
|
||||
}
|
||||
if( arProcessSwitch(pAr, pMatch->eSwitch, zArg) ) return SQLITE_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4216,7 +4311,7 @@ static int arParseCommand(
|
||||
/*
|
||||
** Implementation of .ar "Update" command.
|
||||
*/
|
||||
static int arUpdateCmd(ShellState *p, ArCommand *pAr){
|
||||
static int arUpdateCmd(ShellState *p, sqlite3 *db, ArCommand *pAr){
|
||||
raw_printf(stderr, "todo...\n");
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -4224,7 +4319,7 @@ static int arUpdateCmd(ShellState *p, ArCommand *pAr){
|
||||
/*
|
||||
** Implementation of .ar "lisT" command.
|
||||
*/
|
||||
static int arListCommand(ShellState *p, ArCommand *pAr){
|
||||
static int arListCommand(ShellState *p, sqlite3 *db, ArCommand *pAr){
|
||||
raw_printf(stderr, "todo...\n");
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -4233,7 +4328,7 @@ static int arListCommand(ShellState *p, ArCommand *pAr){
|
||||
/*
|
||||
** Implementation of .ar "eXtract" command.
|
||||
*/
|
||||
static int arExtractCommand(ShellState *p, ArCommand *pAr){
|
||||
static int arExtractCommand(ShellState *p, sqlite3 *db, ArCommand *pAr){
|
||||
const char *zSql1 =
|
||||
"SELECT :1 || name, writefile(:1 || name, "
|
||||
"CASE WHEN (data AND sz>=0 AND sz!=length(data)) THEN uncompress(data) "
|
||||
@@ -4255,7 +4350,7 @@ static int arExtractCommand(ShellState *p, ArCommand *pAr){
|
||||
memset(times, 0, sizeof(times));
|
||||
times[0].tv_sec = time(0);
|
||||
|
||||
shellPrepare(p, &rc, zSql1, &pSql);
|
||||
shellPrepare(db, &rc, zSql1, &pSql);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_bind_text(pSql, 1, zDir, -1, SQLITE_STATIC);
|
||||
}
|
||||
@@ -4266,7 +4361,7 @@ static int arExtractCommand(ShellState *p, ArCommand *pAr){
|
||||
}
|
||||
shellFinalize(&rc, pSql);
|
||||
|
||||
shellPrepare(p, &rc, zSql2, &pSql);
|
||||
shellPrepare(db, &rc, zSql2, &pSql);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_bind_text(pSql, 1, zDir, -1, SQLITE_STATIC);
|
||||
}
|
||||
@@ -4296,20 +4391,19 @@ static int arExtractCommand(ShellState *p, ArCommand *pAr){
|
||||
*/
|
||||
static int arCreateCommand(
|
||||
ShellState *p, /* Shell state pointer */
|
||||
sqlite3 *db,
|
||||
ArCommand *pAr /* Command arguments and options */
|
||||
){
|
||||
const char *zSql =
|
||||
"SELECT name, mode, mtime, data FROM fsdir(?, ?)";
|
||||
|
||||
const char *zSqlar =
|
||||
const char *zSql = "SELECT name, mode, mtime, data FROM fsdir(?, ?)";
|
||||
const char *zCreate =
|
||||
"CREATE TABLE IF NOT EXISTS sqlar("
|
||||
"name TEXT PRIMARY KEY, -- name of the file\n"
|
||||
"mode INT, -- access permissions\n"
|
||||
"mtime INT, -- last modification time\n"
|
||||
"sz INT, -- original file size\n"
|
||||
"data BLOB -- compressed content\n"
|
||||
")";
|
||||
|
||||
")";
|
||||
const char *zDrop = "DROP TABLE IF EXISTS sqlar";
|
||||
const char *zInsert = "REPLACE INTO sqlar VALUES(?, ?, ?, ?, ?)";
|
||||
|
||||
sqlite3_stmt *pStmt = 0; /* Directory traverser */
|
||||
@@ -4320,12 +4414,15 @@ static int arCreateCommand(
|
||||
Bytef *aCompress = 0; /* Compression buffer */
|
||||
int nCompress = 0; /* Size of compression buffer */
|
||||
|
||||
rc = sqlite3_exec(p->db, "SAVEPOINT ar;", 0, 0, 0);
|
||||
rc = sqlite3_exec(db, "SAVEPOINT ar;", 0, 0, 0);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
rc = sqlite3_exec(p->db, zSqlar, 0, 0, 0);
|
||||
shellPrepare(p, &rc, zInsert, &pInsert);
|
||||
shellPrepare(p, &rc, zSql, &pStmt);
|
||||
rc = sqlite3_exec(db, zDrop, 0, 0, 0);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
rc = sqlite3_exec(db, zCreate, 0, 0, 0);
|
||||
shellPrepare(db, &rc, zInsert, &pInsert);
|
||||
shellPrepare(db, &rc, zSql, &pStmt);
|
||||
sqlite3_bind_text(pStmt, 2, pAr->zDir, -1, SQLITE_STATIC);
|
||||
|
||||
for(i=0; i<pAr->nArg && rc==SQLITE_OK; i++){
|
||||
@@ -4385,9 +4482,9 @@ static int arCreateCommand(
|
||||
}
|
||||
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3_exec(p->db, "ROLLBACK TO ar; RELEASE ar;", 0, 0, 0);
|
||||
sqlite3_exec(db, "ROLLBACK TO ar; RELEASE ar;", 0, 0, 0);
|
||||
}else{
|
||||
rc = sqlite3_exec(p->db, "RELEASE ar;", 0, 0, 0);
|
||||
rc = sqlite3_exec(db, "RELEASE ar;", 0, 0, 0);
|
||||
}
|
||||
shellFinalize(&rc, pStmt);
|
||||
shellFinalize(&rc, pInsert);
|
||||
@@ -4407,24 +4504,49 @@ static int arDotCommand(
|
||||
int rc;
|
||||
rc = arParseCommand(azArg, nArg, &cmd);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3 *db = 0; /* Database handle to use as archive */
|
||||
|
||||
if( cmd.zFile ){
|
||||
int flags;
|
||||
if( cmd.eCmd==AR_CMD_CREATE || cmd.eCmd==AR_CMD_UPDATE ){
|
||||
flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE;
|
||||
}else{
|
||||
flags = SQLITE_OPEN_READONLY;
|
||||
}
|
||||
rc = sqlite3_open_v2(cmd.zFile, &db, flags, 0);
|
||||
if( rc!=SQLITE_OK ){
|
||||
raw_printf(stderr, "cannot open file: %s (%s)\n",
|
||||
cmd.zFile, sqlite3_errmsg(db)
|
||||
);
|
||||
sqlite3_close(db);
|
||||
return rc;
|
||||
}
|
||||
}else{
|
||||
db = pState->db;
|
||||
}
|
||||
|
||||
switch( cmd.eCmd ){
|
||||
case AR_CMD_CREATE:
|
||||
rc = arCreateCommand(pState, &cmd);
|
||||
rc = arCreateCommand(pState, db, &cmd);
|
||||
break;
|
||||
|
||||
case AR_CMD_EXTRACT:
|
||||
rc = arExtractCommand(pState, &cmd);
|
||||
rc = arExtractCommand(pState, db, &cmd);
|
||||
break;
|
||||
|
||||
case AR_CMD_LIST:
|
||||
rc = arListCommand(pState, &cmd);
|
||||
rc = arListCommand(pState, db, &cmd);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert( cmd.eCmd==AR_CMD_UPDATE );
|
||||
rc = arUpdateCmd(pState, &cmd);
|
||||
rc = arUpdateCmd(pState, db, &cmd);
|
||||
break;
|
||||
}
|
||||
|
||||
if( cmd.zFile ){
|
||||
sqlite3_close(db);
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
||||
@@ -62,41 +62,68 @@ proc dir_compare {d1 d2} {
|
||||
string compare $l1 $l2
|
||||
}
|
||||
|
||||
populate_dir ar1 {
|
||||
file1 "abcd"
|
||||
file2 "efgh"
|
||||
dir1/file3 "ijkl"
|
||||
foreach {tn tcl} {
|
||||
1 {
|
||||
set c1 ".ar c ar1"
|
||||
set x1 ".ar x"
|
||||
|
||||
set c2 ".ar cC ar1 ."
|
||||
set x2 ".ar Cx ar3"
|
||||
}
|
||||
|
||||
2 {
|
||||
set c1 ".ar -c ar1"
|
||||
set x1 ".ar -x"
|
||||
|
||||
set c2 ".ar -cC ar1 ."
|
||||
set x2 ".ar -xC ar3"
|
||||
}
|
||||
|
||||
3 {
|
||||
set c1 ".ar --create ar1"
|
||||
set x1 ".ar --extract"
|
||||
|
||||
set c2 ".ar --directory ar1 --create ."
|
||||
set x2 ".ar --extract --dir ar3"
|
||||
}
|
||||
|
||||
4 {
|
||||
set c1 ".ar --cr ar1"
|
||||
set x1 ".ar --e"
|
||||
|
||||
set c2 ".ar -C ar1 -c ."
|
||||
set x2 ".ar -x -C ar3"
|
||||
}
|
||||
} {
|
||||
eval $tcl
|
||||
|
||||
# Populate directory "ar1" with some files.
|
||||
#
|
||||
populate_dir ar1 {
|
||||
file1 "abcd"
|
||||
file2 "efgh"
|
||||
dir1/file3 "ijkl"
|
||||
}
|
||||
set expected [dir_to_list ar1]
|
||||
|
||||
do_test 1.$tn.1 {
|
||||
catchcmd test_ar.db $c1
|
||||
file delete -force ar1
|
||||
catchcmd test_ar.db $x1
|
||||
dir_to_list ar1
|
||||
} $expected
|
||||
|
||||
do_test 1.$tn.2 {
|
||||
file delete -force ar3
|
||||
catchcmd test_ar.db $c2
|
||||
catchcmd test_ar.db $x2
|
||||
dir_to_list ar3
|
||||
} $expected
|
||||
}
|
||||
|
||||
set expected [dir_to_list ar1]
|
||||
# puts "# $expected"
|
||||
do_test 1.1 {
|
||||
forcedelete test_ar.db
|
||||
|
||||
catchcmd test_ar.db ".ar c ar1"
|
||||
file delete -force ar1
|
||||
catchcmd test_ar.db ".ar x"
|
||||
|
||||
dir_to_list ar1
|
||||
} $expected
|
||||
|
||||
do_test 1.2 {
|
||||
file delete -force ar3
|
||||
file mkdir ar3
|
||||
catchcmd test_ar.db ".ar xvC ar3"
|
||||
dir_to_list ar3/ar1
|
||||
} $expected
|
||||
|
||||
do_test 1.3 {
|
||||
file delete -force ar3
|
||||
file mkdir ar3
|
||||
|
||||
forcedelete test_ar.db
|
||||
catchcmd test_ar.db ".ar cC ar1 file1 file2 dir1"
|
||||
catchcmd test_ar.db ".ar xC ar3"
|
||||
dir_to_list ar3
|
||||
} $expected
|
||||
finish_test
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
Reference in New Issue
Block a user