1
0
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:
dan
2017-12-12 20:04:59 +00:00
parent 1ad3f61b81
commit d4b56e5901
5 changed files with 362 additions and 140 deletions

View File

@@ -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);
}
}
}

View File

@@ -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

View File

@@ -1 +1 @@
0394889afed2479773af594e2d9659cf58b8959004ebcdeaff8e08e5dae684ef
38dbeb1e777aa7ec742aa27002ad4dcee28af520dc43de96e5c56c39f16574ff

View File

@@ -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;

View File

@@ -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