@@ -6665,11 +6665,14 @@ static int arRemoveCommand(ArCommand *pAr){
66656665*/
66666666static int arExtractCommand(ArCommand *pAr){
66676667 const char *zSql1 =
6668- "SELECT "
6669- " ($dir || name),"
6670- " writefile(($dir || name), %s, mode, mtime) "
6671- "FROM %s WHERE (%s) AND (data IS NULL OR $dirOnly = 0)"
6672- " AND name NOT GLOB '*..[/\\]*'";
6668+ "SELECT ($dir || name),\n"
6669+ " writefile(($dir || name), %s, mode, mtime)\n"
6670+ " FROM %s\n"
6671+ " WHERE (%s)\n"
6672+ " AND NOT ((mode&0xf000)==0x8000 AND $pass>0)\n" /* Files on pass 0 */
6673+ " AND NOT (data IS NULL AND $pass==1)\n" /* Dirs on passes 0,2 */
6674+ " AND NOT ((mode&0xf000)==0xa000 AND $pass<>1)\n" /* Symlink on pass 1 */
6675+ " AND name NOT GLOB '*..[/\\]*'\n";
66736676
66746677 const char *azExtraArg[] = {
66756678 "sqlar_uncompress(data, sz)",
@@ -6705,16 +6708,21 @@ static int arExtractCommand(ArCommand *pAr){
67056708 j = sqlite3_bind_parameter_index(pSql, "$dir");
67066709 sqlite3_bind_text(pSql, j, zDir, -1, SQLITE_STATIC);
67076710
6708- /* Run the SELECT statement twice. The first time, writefile() is called
6709- ** for all archive members that should be extracted. The second time,
6710- ** only for the directories. This is because the timestamps for
6711- ** extracted directories must be reset after they are populated (as
6712- ** populating them changes the timestamp). */
6713- for(i=0; i<2; i++){
6714- j = sqlite3_bind_parameter_index(pSql, "$dirOnly");
6711+ /* Run the SELECT statement thrice:
6712+ ** (1) writefile() all files and directories, but not symlinks
6713+ ** (2) writefile() for symlinks
6714+ ** (3) writefile() for directory again
6715+ ** Symlinks are created after everything else to prevent writing content
6716+ ** through a symlink that was created by the extraction.
6717+ ** The third pass is so that the timestamps for extracted directories
6718+ ** will be reset to the value in the archive, since populating them
6719+ ** in the previous passes will have changed the timestamp. */
6720+ for(i=0; i<3; i++){
6721+ j = sqlite3_bind_parameter_index(pSql, "$pass");
67156722 sqlite3_bind_int(pSql, j, i);
67166723 if( pAr->bDryRun ){
67176724 cli_printf(pAr->out, "%s\n", sqlite3_sql(pSql));
6725+ break;
67186726 }else{
67196727 while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
67206728 if( i==0 && pAr->bVerbose ){
0 commit comments