SQLite Archiver

Check-in [b45aa9345e]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add the -d option to delete content from the SQLAR. Accept GLOB patterns as filenames for -l, -e, and -d.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: b45aa9345e29efc715ec213f12ef4d614ff615fb
User & Date: drh 2016-08-22 17:23:50
Context
2016-09-19
12:10
Update the built-in SQLite to the latest 3.15.0 alpha version. check-in: 72b6147da3 user: drh tags: trunk
2016-08-22
17:23
Add the -d option to delete content from the SQLAR. Accept GLOB patterns as filenames for -l, -e, and -d. check-in: b45aa9345e user: drh tags: trunk
2016-07-11
19:22
Update to the version 3.13.0 of SQLite. check-in: 52199b0fb4 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to sqlar.c.

    31     31   /*
    32     32   ** Show a help message and quit.
    33     33   */
    34     34   static void showHelp(const char *argv0){
    35     35     fprintf(stderr, "Usage: %s [options] archive [files...]\n", argv0);
    36     36     fprintf(stderr,
    37     37        "Options:\n"
           38  +     "   -d      Delete files from the archive\n"
    38     39        "   -e      Prompt for passphrase.  -ee to scramble the prompt\n"
    39     40        "   -l      List files in archive\n"
    40     41        "   -n      Do not compress files\n"
    41     42        "   -x      Extract files from archive\n"
    42     43        "   -v      Verbose output\n"
    43     44     );
    44     45     exit(1);
    45     46   }
    46     47   
    47     48   /*
    48     49   ** The database schema:
    49     50   */
    50         -static const char zSchema[] = 
           51  +static const char zSchema[] =
    51     52     "CREATE TABLE IF NOT EXISTS sqlar(\n"
    52     53     "  name TEXT PRIMARY KEY,\n"
    53     54     "  mode INT,\n"
    54     55     "  mtime INT,\n"
    55     56     "  sz INT,\n"
    56     57     "  data BLOB\n"
    57     58     ");"
................................................................................
   192    193     while( isspace(z[0]) ) z++;
   193    194     for(i=0; i<MX_PASSPHRASE-1; i++){
   194    195       zPassphrase[i] = z[i];
   195    196     }
   196    197     while( i>0 && isspace(z[i-1]) ){ i--; }
   197    198     zPassphrase[i] = 0;
   198    199   }
          200  +
          201  +/*
          202  +** List of command-line arguments
          203  +*/
          204  +typedef struct NameList NameList;
          205  +struct NameList {
          206  +  const char **azName;   /* List of names */
          207  +  int nName;             /* Number of names on the list */
          208  +};
          209  +
          210  +/*
          211  +** Inplementation of SQL function "name_on_list(X)".  Return
          212  +** true if X is on the list of GLOB patterns given on the command-line.
          213  +*/
          214  +static void name_on_list(
          215  +  sqlite3_context *context,
          216  +  int argc,
          217  +  sqlite3_value **argv
          218  +){
          219  +  NameList *pList = (NameList*)sqlite3_user_data(context);
          220  +  int i;
          221  +  int rc = 0;
          222  +  const char *z = (const char*)sqlite3_value_text(argv[0]);
          223  +  if( z!=0 ){
          224  +    for(i=0; i<pList->nName; i++){
          225  +      if( sqlite3_strglob(pList->azName[i], z)==0 ){
          226  +        rc = 1;
          227  +        break;
          228  +      }
          229  +    }
          230  +  }
          231  +  sqlite3_result_int(context, rc);
          232  +}
          233  +
          234  +/*
          235  +** SQL functions that always true.  This is used in place of
          236  +** name_on_list() when no command-line arguments are given.
          237  +*/
          238  +static void alwaysTrue(sqlite3_context *ctx, int n, sqlite3_value **v){
          239  +  sqlite3_result_int(ctx, 1);
          240  +}
          241  +
   199    242   
   200    243   /*
   201    244   ** Open the database.
   202    245   */
   203         -static void db_open(const char *zArchive, int writeFlag, int seeFlag){
          246  +static void db_open(
          247  +  const char *zArchive,
          248  +  int writeFlag,
          249  +  int seeFlag,
          250  +  const char **azFiles,
          251  +  int nFiles
          252  +){
   204    253     int rc;
   205    254     int fg;
          255  +  NameList *x = 0;
   206    256     if( writeFlag ){
   207    257       fg = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
   208    258     }else{
   209    259       fg = SQLITE_OPEN_READONLY;
   210    260     }
   211    261     rc = sqlite3_open_v2(zArchive, &db, fg, 0);
   212    262     if( rc ) errorMsg("Cannot open archive [%s]: %s\n", zArchive,
   213    263                       sqlite3_errmsg(db));
          264  +  if( azFiles!=0 && nFiles>0 ){
          265  +    x = sqlite3_malloc( sizeof(NameList) );
          266  +    if( x==0 ) errorMsg("Out of memory");
          267  +    x->azName = azFiles;
          268  +    x->nName = nFiles;
          269  +    sqlite3_create_function(db, "name_on_list", 1, SQLITE_UTF8,
          270  +                           (char*)x, name_on_list, 0, 0);
          271  +  }else{
          272  +    sqlite3_create_function(db, "name_on_list", 1, SQLITE_UTF8,
          273  +                            0, alwaysTrue, 0, 0);
          274  +  }
   214    275     if( seeFlag ){
   215    276       char *zSql;
   216    277       char zPassPhrase[MX_PASSPHRASE+1];
   217    278   #ifndef SQLITE_HAS_CODEC
   218    279       printf("WARNING:  The passphrase is a no-op because this build of\n"
   219    280              "sqlar is compiled without encryption capabilities.\n");
   220    281   #endif
................................................................................
   414    475       if( verboseFlag ){
   415    476         if( szCompr<szOrig ){
   416    477           int pct = szOrig ? (100*(sqlite3_int64)szCompr)/szOrig : 0;
   417    478           printf("  added: %s (deflate %d%%)\n", zFilename, 100-pct);
   418    479         }else{
   419    480           printf("  added: %s\n", zFilename);
   420    481         }
   421         -    } 
          482  +    }
   422    483     }else{
   423    484       sqlite3_bind_int(pStmt, 4, 0);
   424    485       sqlite3_bind_null(pStmt, 5);
   425    486       if( verboseFlag ) printf("  added: %s\n", zFilename);
   426    487     }
   427    488     rc = sqlite3_step(pStmt);
   428    489     if( rc!=SQLITE_DONE ){
................................................................................
   444    505           sqlite3_free(zSubpath);
   445    506         }
   446    507         closedir(d);
   447    508       }
   448    509     }
   449    510   }
   450    511   
   451         -/*
   452         -** List of command-line arguments
   453         -*/
   454         -typedef struct NameList NameList;
   455         -struct NameList {
   456         -  char **azName;   /* List of names */
   457         -  int nName;       /* Number of names on the list */
   458         -};
   459         -
   460         -/*
   461         -** Inplementation of SQL function "name_on_list(X)".  Return
   462         -** true if X is on the list of names given on the command-line.
   463         -*/
   464         -static void name_on_list(
   465         -  sqlite3_context *context,
   466         -  int argc,
   467         -  sqlite3_value **argv
   468         -){
   469         -  NameList *pList = (NameList*)sqlite3_user_data(context);
   470         -  int i;
   471         -  int rc = 0;
   472         -  const char *z = (const char*)sqlite3_value_text(argv[0]);
   473         -  if( z!=0 ){
   474         -    for(i=0; i<pList->nName; i++){
   475         -      if( strcmp(pList->azName[i], z)==0 ){
   476         -        rc = 1;
   477         -        break;
   478         -      }
   479         -    }
   480         -  }
   481         -  sqlite3_result_int(context, rc);
   482         -}
   483         -
   484    512   int main(int argc, char **argv){
   485    513     const char *zArchive = 0;
   486         -  char **azFiles = 0;
          514  +  const char **azFiles = 0;
   487    515     int nFiles = 0;
   488    516     int listFlag = 0;
   489    517     int extractFlag = 0;
   490    518     int verboseFlag = 0;
   491    519     int noCompress = 0;
   492    520     int seeFlag = 0;
          521  +  int deleteFlag = 0;
   493    522     int i, j;
   494    523   
   495    524     if( sqlite3_strglob("*/unsqlar", argv[0])==0 ){
   496    525       extractFlag = 1;
   497    526     }
   498    527     for(i=1; i<argc; i++){
   499    528       if( argv[i][0]=='-' ){
................................................................................
   500    529         for(j=1; argv[i][j]; j++){
   501    530           switch( argv[i][j] ){
   502    531             case 'l':   listFlag = 1;    break;
   503    532             case 'n':   noCompress = 1;  break;
   504    533             case 'v':   verboseFlag = 1; break;
   505    534             case 'x':   extractFlag = 1; break;
   506    535             case 'e':   seeFlag++;       break;
          536  +          case 'd':   deleteFlag = 1;  break;
   507    537             case '-':   break;
   508    538             default:    showHelp(argv[0]);
   509    539           }
   510    540         }
   511    541       }else if( zArchive==0 ){
   512    542         zArchive = argv[i];
   513    543       }else{
   514         -      azFiles = &argv[i];
          544  +      azFiles = (const char**)&argv[i];
   515    545         nFiles = argc - i;
   516    546         break;
   517    547       }
   518    548     }
   519    549     if( zArchive==0 ) showHelp(argv[0]);
   520         -  if( listFlag ){
   521         -    db_open(zArchive, 0, seeFlag);
          550  +  if( listFlag || deleteFlag ){
          551  +    if( deleteFlag && nFiles==0 ){
          552  +      errorMsg("Specify one or more files to delete on the command-line");
          553  +    }
          554  +    db_open(zArchive, deleteFlag, seeFlag, azFiles, nFiles);
   522    555       if( verboseFlag ){
   523    556         db_prepare(
   524    557             "SELECT name, sz, length(data), mode, datetime(mtime,'unixepoch')"
   525         -          " FROM sqlar ORDER BY name"
          558  +          " FROM sqlar WHERE name_on_list(name) ORDER BY name"
   526    559         );
   527    560         while( sqlite3_step(pStmt)==SQLITE_ROW ){
          561  +        if( deleteFlag ) printf("DELETE ");
   528    562           printf("%10d %10d %03o %s %s\n", 
   529    563                  sqlite3_column_int(pStmt, 1),
   530    564                  sqlite3_column_int(pStmt, 2),
   531    565                  sqlite3_column_int(pStmt, 3)&0777,
   532    566                  sqlite3_column_text(pStmt, 4),
   533    567                  sqlite3_column_text(pStmt, 0));
   534    568         }
   535    569       }else{
   536    570         db_prepare(
   537         -          "SELECT name FROM sqlar ORDER BY name"
          571  +          "SELECT name FROM sqlar WHERE name_on_list(name) ORDER BY name"
   538    572         );
   539    573         while( sqlite3_step(pStmt)==SQLITE_ROW ){
          574  +        if( deleteFlag ) printf("DELETE ");
   540    575           printf("%s\n", sqlite3_column_text(pStmt,0));
   541    576         }
   542    577       }
          578  +    if( deleteFlag ){
          579  +      sqlite3_exec(db, "DELETE FROM sqlar WHERE name_on_list(name)", 0, 0, 0);
          580  +    }
   543    581       db_close(1);
   544    582     }else if( extractFlag ){
   545    583       const char *zSql;
   546         -    db_open(zArchive, 0, seeFlag);
   547         -    if( nFiles ){
   548         -      NameList x;
   549         -      x.azName = azFiles;
   550         -      x.nName = nFiles;
   551         -      sqlite3_create_function(db, "name_on_list", 1, SQLITE_UTF8,
   552         -                              (char*)&x, name_on_list, 0, 0);
   553         -      zSql = "SELECT name, mode, mtime, sz, data FROM sqlar"
   554         -             " WHERE name_on_list(filename)";
   555         -    }else{
   556         -      zSql = "SELECT name, mode, mtime, sz, data FROM sqlar";
   557         -    }
          584  +    db_open(zArchive, 0, seeFlag, azFiles, nFiles);
          585  +    zSql = "SELECT name, mode, mtime, sz, data FROM sqlar"
          586  +           " WHERE name_on_list(filename)";
   558    587       db_prepare(zSql);
   559    588       while( sqlite3_step(pStmt)==SQLITE_ROW ){
   560    589         const char *zFN = (const char*)sqlite3_column_text(pStmt, 0);
   561    590         check_filename(zFN);
   562    591         if( zFN[0]=='/' ){
   563    592           errorMsg("absolute pathname: %s\n", zFN);
   564    593         }
................................................................................
   570    599                    sqlite3_column_int64(pStmt,2),
   571    600                    sqlite3_column_int(pStmt,3),
   572    601                    sqlite3_column_blob(pStmt,4),
   573    602                    sqlite3_column_bytes(pStmt,4));
   574    603       }
   575    604       db_close(1);
   576    605     }else{
   577         -    if( azFiles==0 ) showHelp(argv[0]);
   578         -    db_open(zArchive, 1, seeFlag);
          606  +    if( azFiles==0 ){
          607  +      errorMsg("Specify one or more files to add on the command-line");
          608  +    }
          609  +    db_open(zArchive, 1, seeFlag, 0, 0);
   579    610       for(i=0; i<nFiles; i++){
   580    611         add_file(azFiles[i], verboseFlag, noCompress);
   581    612       }
   582    613       db_close(1);
   583    614     }
   584    615     return 0;
   585    616   }