From 16cfe2d3bad524f7d33fe54518fcff3fdc78c31c Mon Sep 17 00:00:00 2001
From: Rob Swindell <rob@synchro.net>
Date: Mon, 3 Jan 2022 17:39:55 -0800
Subject: [PATCH] Add overwrite argument to extract_file_from_archive and
 Archive.extract

Previously, extracted files were always overwritten (so that is the "default" for Archive.extract() and mostly what I'm specifying in the C/C++ code by default now), but this caused a problem with DIZ extraction: archives that contained multiple DIZ files (e.g in sub-directories), the last to be extracted would be used. A maximum of 3 DIZs can be extracted, so it would usually be the 3rd DIZ in the archive if there were that many.

Another solution would be to *only* extract DIZ files from the root of the archive and I should look into that as well, but the always-overwrite behavior also seemed to be wrong, so that *also* needed fixing (allow caller to control behavior).

This fixes issue #317, at least for archives where the root DIZ exists *before* any nested DIZ files. I'll have to try and create a purposeful archive to test the other conditions (where the root DIZ would appear *after* the nested DIZ(s)).
---
 src/sbbs3/filedat.c    | 5 ++++-
 src/sbbs3/filedat.h    | 2 +-
 src/sbbs3/js_archive.c | 9 +++++++--
 src/sbbs3/pack_qwk.cpp | 1 +
 src/sbbs3/pack_rep.cpp | 1 +
 src/sbbs3/sbbsecho.c   | 2 +-
 src/sbbs3/un_qwk.cpp   | 1 +
 src/sbbs3/un_rep.cpp   | 1 +
 8 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/src/sbbs3/filedat.c b/src/sbbs3/filedat.c
index 074114f2a0..51679e5346 100644
--- a/src/sbbs3/filedat.c
+++ b/src/sbbs3/filedat.c
@@ -809,7 +809,7 @@ long create_archive(const char* archive, const char* format
 }
 
 long extract_files_from_archive(const char* archive, const char* outdir, const char* allowed_filename_chars
-	,bool with_path, long max_files, str_list_t file_list, char* error, size_t maxerrlen)
+	,bool with_path, bool overwrite, long max_files, str_list_t file_list, char* error, size_t maxerrlen)
 {
 	int result;
 	struct archive *ar;
@@ -884,6 +884,8 @@ long extract_files_from_archive(const char* archive, const char* outdir, const c
 		SAFECOPY(fpath, outdir);
 		backslash(fpath);
 		SAFECAT(fpath, pathname);
+		if(!overwrite && fexist(fpath))
+			continue;
 		FILE* fp = fopen(fpath, "wb");
 		if(fp == NULL) {
 			char err[256];
@@ -945,6 +947,7 @@ bool extract_diz(scfg_t* cfg, file_t* f, str_list_t diz_fnames, char* path, size
 		,/* outdir: */cfg->temp_dir
 		,/* allowed_filename_chars: */NULL /* any */
 		,/* with_path: */false
+		,/* overwrite: */false
 		,/* max_files: */strListCount(diz_fnames)
 		,/* file_list: */diz_fnames
 		,/* error: */NULL, 0) >= 0) {
diff --git a/src/sbbs3/filedat.h b/src/sbbs3/filedat.h
index b598014706..de68269df5 100644
--- a/src/sbbs3/filedat.h
+++ b/src/sbbs3/filedat.h
@@ -72,7 +72,7 @@ DLLEXPORT long			create_archive(const char* archive, const char* format
 						               ,bool with_path, str_list_t file_list, char* error, size_t maxerrlen);
 DLLEXPORT char*			cmdstr(scfg_t*, user_t*, const char* instr, const char* fpath, const char* fspec, char* cmd, size_t);
 DLLEXPORT long			extract_files_from_archive(const char* archive, const char* outdir, const char* allowed_filename_chars
-						                           ,bool with_path, long max_files, str_list_t file_list, char* error, size_t);
+						                           ,bool with_path, bool overwrite, long max_files, str_list_t file_list, char* error, size_t);
 DLLEXPORT int			archive_type(const char* archive, char* str, size_t size);
 extern const char*		supported_archive_formats[];
 
diff --git a/src/sbbs3/js_archive.c b/src/sbbs3/js_archive.c
index 608da5a3ae..34e754f8e6 100644
--- a/src/sbbs3/js_archive.c
+++ b/src/sbbs3/js_archive.c
@@ -109,6 +109,7 @@ js_extract(JSContext *cx, uintN argc, jsval *arglist)
 	char*		allowed_filename_chars = SAFEST_FILENAME_CHARS;
 	str_list_t	file_list = NULL;
 	bool		with_path = false;
+	bool		overwrite = true;
 	int32		max_files = 0;
 	char		error[256] = "";
 	jsrefcount	rc;
@@ -136,6 +137,10 @@ js_extract(JSContext *cx, uintN argc, jsval *arglist)
 			allowed_filename_chars = NULL;	// We trust this archive
 		argn++;
 	}
+	if(argc > argn && JSVAL_IS_BOOLEAN(argv[argn])) {
+		overwrite = JSVAL_TO_BOOLEAN(argv[argn]);
+		argn++;
+	}
 	if(argc > argn && JSVAL_IS_NUMBER(argv[argn])) {
 		if(!JS_ValueToInt32(cx, argv[argn], &max_files)) {
 			free(outdir);
@@ -154,7 +159,7 @@ js_extract(JSContext *cx, uintN argc, jsval *arglist)
 
 	rc = JS_SUSPENDREQUEST(cx);
 	long extracted = extract_files_from_archive(filename, outdir, allowed_filename_chars
-		,with_path, (ulong)max_files, file_list, error, sizeof(error));
+		,with_path, overwrite, (ulong)max_files, file_list, error, sizeof(error));
 	strListFree(&file_list);
 	free(outdir);
 	JS_RESUMEREQUEST(cx, rc);
@@ -538,7 +543,7 @@ static jsSyncMethodSpec js_archive_functions[] = {
 		,31900
 	},
 	{ "extract",	js_extract,		1,	JSTYPE_NUMBER
-		,JSDOCSTR("output_directory [,boolean with_path = false] [,number max_files = 0] [,string file/pattern [...]]")
+		,JSDOCSTR("output_directory [,boolean with_path = false] [,boolean overwrite = true] [,number max_files = 0] [,string file/pattern [...]]")
 		,JSDOCSTR("Extract files from an archive to specified output directory.<br>"
 			"Returns the number of files extracted.<br>"
 			"Will throw exception upon error.")
diff --git a/src/sbbs3/pack_qwk.cpp b/src/sbbs3/pack_qwk.cpp
index f680480fa2..0727e71969 100644
--- a/src/sbbs3/pack_qwk.cpp
+++ b/src/sbbs3/pack_qwk.cpp
@@ -73,6 +73,7 @@ bool sbbs_t::pack_qwk(char *packet, ulong *msgcnt, bool prepack)
 			,/* outdir: */cfg.temp_dir
 			,/* allowed_filename_chars: */NULL /* any */
 			,/* with_path: */false
+			,/* overwrite: */true
 			,/* max_files: */0 /* unlimited */
 			,/* file_list: */NULL /* all files */
 			,error, sizeof(error));
diff --git a/src/sbbs3/pack_rep.cpp b/src/sbbs3/pack_rep.cpp
index 190bba9ebb..8f70d9069e 100644
--- a/src/sbbs3/pack_rep.cpp
+++ b/src/sbbs3/pack_rep.cpp
@@ -67,6 +67,7 @@ bool sbbs_t::pack_rep(uint hubnum)
 			,/* outdir: */cfg.temp_dir
 			,/* allowed_filename_chars: */NULL /* any */
 			,/* with_path: */false
+			,/* overwrite: */true
 			,/* max_files: */0 /* unlimited */
 			,/* file_list: */NULL /* all files */
 			,error, sizeof(error));
diff --git a/src/sbbs3/sbbsecho.c b/src/sbbs3/sbbsecho.c
index 982e328aa3..fcb4a24123 100644
--- a/src/sbbs3/sbbsecho.c
+++ b/src/sbbs3/sbbsecho.c
@@ -2266,7 +2266,7 @@ int unpack(const char *infile, const char* outdir)
 	long file_count;
 
 	file_count = extract_files_from_archive(infile, outdir
-		,/* allowed_filename_chars: */SAFEST_FILENAME_CHARS, /* with_path */false
+		,/* allowed_filename_chars: */SAFEST_FILENAME_CHARS, /* with_path */false, /* overwrite: */true
 		,/* max_files: */0, /* file_list = ALL */NULL, error, sizeof(error));
 	if(file_count > 0) {
 		lprintf(LOG_DEBUG, "libarchive extracted %lu files from %s", file_count, infile);
diff --git a/src/sbbs3/un_qwk.cpp b/src/sbbs3/un_qwk.cpp
index ac05baf2f7..6f4096015c 100644
--- a/src/sbbs3/un_qwk.cpp
+++ b/src/sbbs3/un_qwk.cpp
@@ -80,6 +80,7 @@ bool sbbs_t::unpack_qwk(char *packet,uint hubnum)
 		,/* outdir: */cfg.temp_dir
 		,/* allowed_filename_chars: */NULL /* any */
 		,/* with_path: */false
+		,/* overwrite: */true
 		,/* max_files: */0 /* unlimited */
 		,/* file_list: */NULL /* all files */
 		,error, sizeof(error));
diff --git a/src/sbbs3/un_rep.cpp b/src/sbbs3/un_rep.cpp
index 7db302217e..918949d01c 100644
--- a/src/sbbs3/un_rep.cpp
+++ b/src/sbbs3/un_rep.cpp
@@ -76,6 +76,7 @@ bool sbbs_t::unpack_rep(char* repfile)
 		,/* outdir: */cfg.temp_dir
 		,/* allowed_filename_chars: */SAFEST_FILENAME_CHARS
 		,/* with_path: */false
+		,/* overwrite: */true
 		,/* max_files */1000
 		,/* file_list: */NULL /* all files */
 		,error, sizeof(error));
-- 
GitLab