From: dan Date: Wed, 13 Dec 2017 20:04:53 +0000 (+0000) Subject: Add support for the "--list" command. And for arguments to the "--extract" X-Git-Tag: version-3.22.0~108^2~27 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=3f67ddf8f22cae016c577dff9295b2fe523031c9;p=thirdparty%2Fsqlite.git Add support for the "--list" command. And for arguments to the "--extract" command. FossilOrigin-Name: 32c4fa2552bb0fa7d7d143108457efae7a756d6cb14b1d59312e56efac3b2656 --- diff --git a/manifest b/manifest index 61046afc09..8be2f2242c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\stests\sand\sfixes\sfor\sthe\sshell\s".ar"\scommand\s-f\soption. -D 2017-12-12T20:28:36.588 +C Add\ssupport\sfor\sthe\s"--list"\scommand.\sAnd\sfor\sarguments\sto\sthe\s"--extract"\ncommand. +D 2017-12-13T20:04:53.034 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 6a879cbf01e37f9eac131414955f71774b566502d9a57ded1b8585b507503cb8 @@ -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 a09773c80a647f6ba4ef8dd9ce88840d52dbede5a9fa318333843deb8c8548b7 +F src/shell.c.in b53eddcb293a9d35c0673c1d3bf2cf120b55e6660b436f65d689776a56391562 F src/sqlite.h.in 8fd97993d48b50b9bade38c52f12d175942c9497c960905610c7b03a3e4b5818 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h c02d628cca67f3889c689d82d25c3eb45e2c155db08e4c6089b5840d64687d34 @@ -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 38dbeb1e777aa7ec742aa27002ad4dcee28af520dc43de96e5c56c39f16574ff -R e6fcdae437270c2329ef751955f65f0e +P 1a9867973c9d6675fa5254fdd74f36004707a98a91593a188033cf5a49cc7a0b +R c505f9c0d154ac54b6761fcc5d07e027 U dan -Z 1b5cf819c180e1535b22a7c0cf2ece4d +Z dcb23b384070f4f2014f2150f41e157a diff --git a/manifest.uuid b/manifest.uuid index 7640d02900..71ba76fdc3 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1a9867973c9d6675fa5254fdd74f36004707a98a91593a188033cf5a49cc7a0b \ No newline at end of file +32c4fa2552bb0fa7d7d143108457efae7a756d6cb14b1d59312e56efac3b2656 \ No newline at end of file diff --git a/src/shell.c.in b/src/shell.c.in index ee9ccd6e76..0230e5f4d7 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -4092,6 +4092,26 @@ static void shellPrepare( } } +static void shellPrepare2( + sqlite3 *db, + int *pRc, + const char *zSql, + const char *zTail, + sqlite3_stmt **ppStmt +){ + if( *pRc==SQLITE_OK && zTail ){ + char *z = sqlite3_mprintf("%s %s", zSql, zTail); + if( z==0 ){ + *pRc = SQLITE_NOMEM; + }else{ + shellPrepare(db, pRc, z, ppStmt); + sqlite3_free(z); + } + }else{ + shellPrepare(db, pRc, zSql, ppStmt); + } +} + static void shellFinalize( int *pRc, sqlite3_stmt *pStmt @@ -4316,12 +4336,96 @@ static int arUpdateCmd(ShellState *p, sqlite3 *db, ArCommand *pAr){ return SQLITE_OK; } +/* +** This function assumes that all arguments within the ArCommand.azArg[] +** array refer to archive members, as for the --extract or --list commands. +** It checks that each of them are present. If any specified file is not +** present in the archive, an error is printed to stderr and an error +** code returned. Otherwise, if all specified arguments are present in +** the archive, SQLITE_OK is returned. +** +** This function strips any trailing '/' characters from each argument. +** This is consistent with the way the [tar] command seems to work on +** Linux. +*/ +static int arCheckEntries(sqlite3 *db, ArCommand *pAr){ + int rc = SQLITE_OK; + if( pAr->nArg ){ + int i; + sqlite3_stmt *pTest = 0; + + shellPrepare(db, &rc, "SELECT name FROM sqlar WHERE name=?", &pTest); + for(i=0; inArg && rc==SQLITE_OK; i++){ + char *z = pAr->azArg[i]; + int n = strlen(z); + int bOk = 0; + while( n>0 && z[n-1]=='/' ) n--; + z[n] = '\0'; + sqlite3_bind_text(pTest, 1, z, -1, SQLITE_STATIC); + if( SQLITE_ROW==sqlite3_step(pTest) ){ + bOk = 1; + } + shellReset(&rc, pTest); + if( rc==SQLITE_OK && bOk==0 ){ + raw_printf(stderr, "not found in archive: %s\n", z); + rc = SQLITE_ERROR; + } + } + shellFinalize(&rc, pTest); + } + + return rc; +} + +/* +** Format a WHERE clause that can be used against the "sqlar" table to +** identify all archive members that match the command arguments held +** in (*pAr). Leave this WHERE clause in (*pzWhere) before returning. +** The caller is responsible for eventually calling sqlite3_free() on +** any non-NULL (*pzWhere) value. +*/ +static void arWhereClause( + int *pRc, + ArCommand *pAr, + char **pzWhere /* OUT: New WHERE clause (or NULL) */ +){ + char *zWhere = 0; + if( *pRc==SQLITE_OK ){ + int i; + const char *zSep = "WHERE "; + for(i=0; inArg; i++){ + const char *z = pAr->azArg[i]; + zWhere = sqlite3_mprintf( + "%z%s name = '%q' OR name BETWEEN '%q/' AND '%q0'", + zWhere, zSep, z, z, z + ); + if( zWhere==0 ){ + *pRc = SQLITE_NOMEM; + break; + } + zSep = " OR "; + } + } + *pzWhere = zWhere; +} + /* ** Implementation of .ar "lisT" command. */ static int arListCommand(ShellState *p, sqlite3 *db, ArCommand *pAr){ - raw_printf(stderr, "todo...\n"); - return SQLITE_OK; + const char *zSql = "SELECT name FROM sqlar"; + char *zWhere = 0; + sqlite3_stmt *pSql = 0; + int rc; + + rc = arCheckEntries(db, pAr); + arWhereClause(&rc, pAr, &zWhere); + + shellPrepare2(db, &rc, zSql, zWhere, &pSql); + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){ + raw_printf(p->out, "%s\n", sqlite3_column_text(pSql, 0)); + } + return rc; } @@ -4331,8 +4435,11 @@ static int arListCommand(ShellState *p, sqlite3 *db, 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) " - " ELSE data END, " + "CASE WHEN (data AND sz>=0 AND sz!=length(data)) THEN " + " uncompress(data) " + "ELSE" + " data " + "END, " "mode) FROM sqlar"; const char *zSql2 = "SELECT :1 || name, mtime FROM sqlar"; @@ -4340,17 +4447,27 @@ static int arExtractCommand(ShellState *p, sqlite3 *db, ArCommand *pAr){ sqlite3_stmt *pSql = 0; int rc = SQLITE_OK; char *zDir = 0; + char *zWhere = 0; - if( pAr->zDir ){ - zDir = sqlite3_mprintf("%s/", pAr->zDir); - }else{ - zDir = sqlite3_mprintf(""); + /* If arguments are specified, check that they actually exist within + ** the archive before proceeding. And formulate a WHERE clause to + ** match them. */ + rc = arCheckEntries(db, pAr); + arWhereClause(&rc, pAr, &zWhere); + + if( rc==SQLITE_OK ){ + if( pAr->zDir ){ + zDir = sqlite3_mprintf("%s/", pAr->zDir); + }else{ + zDir = sqlite3_mprintf(""); + } + if( zDir==0 ) rc = SQLITE_NOMEM; } memset(times, 0, sizeof(times)); times[0].tv_sec = time(0); - shellPrepare(db, &rc, zSql1, &pSql); + shellPrepare2(db, &rc, zSql1, zWhere, &pSql); if( rc==SQLITE_OK ){ sqlite3_bind_text(pSql, 1, zDir, -1, SQLITE_STATIC); } @@ -4361,7 +4478,7 @@ static int arExtractCommand(ShellState *p, sqlite3 *db, ArCommand *pAr){ } shellFinalize(&rc, pSql); - shellPrepare(db, &rc, zSql2, &pSql); + shellPrepare2(db, &rc, zSql2, zWhere, &pSql); if( rc==SQLITE_OK ){ sqlite3_bind_text(pSql, 1, zDir, -1, SQLITE_STATIC); } @@ -4377,6 +4494,7 @@ static int arExtractCommand(ShellState *p, sqlite3 *db, ArCommand *pAr){ shellFinalize(&rc, pSql); sqlite3_free(zDir); + sqlite3_free(zWhere); return rc; }