]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add the ".ar x" command to the shell. For extracting the contents of sqlar
authordan <dan@noemail.net>
Thu, 7 Dec 2017 21:03:33 +0000 (21:03 +0000)
committerdan <dan@noemail.net>
Thu, 7 Dec 2017 21:03:33 +0000 (21:03 +0000)
archives.

FossilOrigin-Name: 0cc699d14adfe8c7b7be50c180186562861806c47425c80c935bce43ee5c5c12

ext/misc/fileio.c
manifest
manifest.uuid
src/shell.c.in

index 475f3713ce8c6103397f577e91daa61dabcefead..db69357008e7d6439a8379cc44119c6c76b9a606 100644 (file)
 #include "sqlite3ext.h"
 SQLITE_EXTENSION_INIT1
 #include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <time.h>
+#include <utime.h>
+
 
 #define FSDIR_SCHEMA "CREATE TABLE x(name,mode,mtime,data,dir HIDDEN)"
 
@@ -69,44 +80,91 @@ static void readfileFunc(
   readFileContents(context, zName);
 }
 
+static void ctxErrorMsg(sqlite3_context *ctx, const char *zFmt, ...){
+  char *zMsg = 0;
+  va_list ap;
+  va_start(ap, zFmt);
+  zMsg = sqlite3_vmprintf(zFmt, ap);
+  sqlite3_result_error(ctx, zMsg, -1);
+  sqlite3_free(zMsg);
+  va_end(ap);
+}
+
 /*
-** Implementation of the "writefile(X,Y)" SQL function.  The argument Y
-** is written into file X.  The number of bytes written is returned.  Or
-** NULL is returned if something goes wrong, such as being unable to open
-** file X for writing.
+** Implementation of the "writefile(W,X[,Y]])" SQL function.  
+**
+** The argument X is written into file W.  The number of bytes written is
+** returned. Or NULL is returned if something goes wrong, such as being unable
+** to open file X for writing.
 */
 static void writefileFunc(
   sqlite3_context *context,
   int argc,
   sqlite3_value **argv
 ){
-  FILE *out;
-  const char *z;
-  sqlite3_int64 rc;
   const char *zFile;
+  mode_t mode = 0;
+
+  if( argc<2 || argc>3 ){
+    sqlite3_result_error(context, 
+        "wrong number of arguments to function writefile()", -1
+    );
+    return;
+  }
 
-  (void)(argc);  /* Unused parameter */
   zFile = (const char*)sqlite3_value_text(argv[0]);
   if( zFile==0 ) return;
-  out = fopen(zFile, "wb");
-  if( out==0 ) return;
-  z = (const char*)sqlite3_value_blob(argv[1]);
-  if( z==0 ){
-    rc = 0;
+  if( argc>=3 ){
+    sqlite3_result_int(context, 0);
+    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{
-    rc = fwrite(z, 1, sqlite3_value_bytes(argv[1]), out);
+    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);
+    }
+
+    if( argc>2 && chmod(zFile, mode & 0777) ){
+      ctxErrorMsg(context, "failed to chmod file: %s", zFile);
+      return;
+    }
   }
-  fclose(out);
-  sqlite3_result_int64(context, rc);
 }
 
 #ifndef SQLITE_OMIT_VIRTUALTABLE
 
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <dirent.h>
-
 /* 
 */
 typedef struct fsdir_cursor fsdir_cursor;
@@ -463,7 +521,7 @@ int sqlite3_fileio_init(
   rc = sqlite3_create_function(db, "readfile", 1, SQLITE_UTF8, 0,
                                readfileFunc, 0, 0);
   if( rc==SQLITE_OK ){
-    rc = sqlite3_create_function(db, "writefile", 2, SQLITE_UTF8, 0,
+    rc = sqlite3_create_function(db, "writefile", -1, SQLITE_UTF8, 0,
                                  writefileFunc, 0, 0);
   }
   if( rc==SQLITE_OK ){
index dc93367667d02ed6e8be49e2a9cb0ff92a8f8047..ab01f7195cc28cd3889532a7c5e4ef12c1f6d862 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Begin\sadding\ssupport\sfor\sthe\ssqlar\sarchive\sformat\sto\sshell.c.\sThere\sis\sno\n"extract"\scommand\sso\sfar,\sonly\s"create".
-D 2017-12-07T15:44:29.604
+C Add\sthe\s".ar\sx"\scommand\sto\sthe\sshell.\sFor\sextracting\sthe\scontents\sof\ssqlar\narchives.
+D 2017-12-07T21:03:33.903
 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 bd2dd9bd22a509f972a4658be18bbfef80aec3cbc3e18948c5e8c5e29ece9939
+F ext/misc/fileio.c c84ec9c399657bd95914e7c4e9aefcc148cb86fe3ab7f2102e9557c861dd0d51
 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 56c4c091c74af2c7858f2d8af962caa632889596435b17bffbc308058fb305cc
+F src/shell.c.in 2f9ae0bee09bdd35922ab7ed264d88e1d7fb34d39d37fc633e6a3a1af60036be
 F src/sqlite.h.in 8fd97993d48b50b9bade38c52f12d175942c9497c960905610c7b03a3e4b5818
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
 F src/sqlite3ext.h c02d628cca67f3889c689d82d25c3eb45e2c155db08e4c6089b5840d64687d34
@@ -1681,7 +1681,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 8155b5ac850327ea76aba2adf624132f3e05024c973afd218b12f186fc7630e8
-R 1ffe38726fc0bf4dcb6cd1bf88405c9b
+P c9827a01a6e107f38f85c2b2c1c7a599e443067b106217e965b6936441ca619d
+R 4b2bb930e9456062f8914cba7a04cf63
 U dan
-Z f98960131c8a51264c03e5b1a40bd1b7
+Z 4726613d4458219c808274490c55a044
index 3b745e1dd52978281177502c23172d4d8c17864d..245ee49a8fa3fa341cae7b6f0f151734f7779554 100644 (file)
@@ -1 +1 @@
-c9827a01a6e107f38f85c2b2c1c7a599e443067b106217e965b6936441ca619d
\ No newline at end of file
+0cc699d14adfe8c7b7be50c180186562861806c47425c80c935bce43ee5c5c12
\ No newline at end of file
index 9015a4330ac75f35d565f467a937a8ae20e16887..fe58460fe19637e19ccc8ba5934dcd4decc81391 100644 (file)
@@ -4096,8 +4096,16 @@ static void shellFinalize(
   int *pRc, 
   sqlite3_stmt *pStmt
 ){
-  int rc = sqlite3_finalize(pStmt);
-  if( *pRc==SQLITE_OK ) *pRc = rc;
+  if( pStmt ){
+    sqlite3 *db = sqlite3_db_handle(pStmt);
+    int rc = sqlite3_finalize(pStmt);
+    if( *pRc==SQLITE_OK ){
+      if( rc!=SQLITE_OK ){
+        raw_printf(stderr, "SQL error: %s\n", sqlite3_errmsg(db));
+      }
+      *pRc = rc;
+    }
+  }
 }
 
 static void shellReset(
@@ -4112,16 +4120,40 @@ static void shellReset(
 ** Implementation of .ar "eXtract" command. 
 */
 static int arExtractCommand(ShellState *p, int bVerbose){
-  const char *zSql = 
-    "SELECT name, mode, mtime, sz, data FROM sqlar";
+  const char *zSql1 = 
+    "SELECT name, writefile(name, "
+    "CASE WHEN (data AND sz>=0 AND sz!=length(data)) THEN uncompress(data) "
+    "   ELSE data END, "
+    "mode) FROM sqlar";
+  const char *zSql2 = "SELECT name, mtime FROM sqlar"; 
+
+  struct timespec times[2];
   sqlite3_stmt *pSql = 0;
   int rc = SQLITE_OK;
 
-  shellPrepare(p, &rc, zSql, &pSql);
+  memset(times, 0, sizeof(times));
+  times[0].tv_sec = time(0);
+
+  shellPrepare(p, &rc, zSql1, &pSql);
   while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
+    if( bVerbose ){
+      raw_printf(stdout, "%s\n", sqlite3_column_text(pSql, 0));
+    }
   }
+  shellFinalize(&rc, pSql);
 
+  shellPrepare(p, &rc, zSql2, &pSql);
+  while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
+    const char *zPath = (const char*)sqlite3_column_text(pSql, 0);
+    times[1].tv_sec = (time_t)sqlite3_column_int64(pSql, 1);
+    if( utimensat(AT_FDCWD, zPath, times, AT_SYMLINK_NOFOLLOW) ){
+      raw_printf(stderr, "failed to set timestamp for %s\n", zPath);
+      rc = SQLITE_ERROR;
+      break;
+    }
+  }
   shellFinalize(&rc, pSql);
+
   return rc;
 }