1 /*
2  *  gretl -- Gnu Regression, Econometrics and Time-series Library
3  *  Copyright (C) 2001 Allin Cottrell and Riccardo "Jack" Lucchetti
4  *
5  *  This program is free software: you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation, either version 3 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  *
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
23 
24 #include "libgretl.h"
25 #include "gretl_zip.h"
26 
handle_zip_error(const char * fname,GError * gerr,int err,const char * action)27 static int handle_zip_error (const char *fname,
28 			     GError *gerr, int err,
29 			     const char *action)
30 {
31     if (gerr != NULL) {
32 	fprintf(stderr, "handle_zip_error: '%s'\n", gerr->message);
33 	gretl_errmsg_sprintf("%s: %s", fname, gerr->message);
34 	g_error_free(gerr);
35     } else if (err) {
36 	gretl_errmsg_sprintf("%s: error %s", fname, action);
37     }
38 
39     return err;
40 }
41 
42 #ifdef USE_GSF /* libgsf-1 >= 1.14.31 */
43 
44 #include <gsf/gsf.h>
45 
46 #define ZDEBUG 0
47 #define CHUNK 32768
48 
49 #define gsf_is_dir(i) (GSF_IS_INFILE(i) && \
50 		       gsf_infile_num_children(GSF_INFILE(i)) >= 0)
51 
ensure_gsf_init(void)52 static void ensure_gsf_init (void)
53 {
54     static int initted;
55 
56     if (!initted) {
57 	gsf_init();
58 	initted = 1;
59     }
60 }
61 
transcribe_gsf_data(GsfInput * input,GsfOutput * output)62 static int transcribe_gsf_data (GsfInput *input, GsfOutput *output)
63 {
64     guint8 const *data;
65     size_t len;
66 
67     while ((len = gsf_input_remaining(input)) > 0) {
68 	if (len > CHUNK) {
69 	    len = CHUNK;
70 	}
71 	if ((data = gsf_input_read(input, len, NULL)) == NULL) {
72 	    return 1;
73 	}
74 	if (!gsf_output_write(output, len, data)) {
75 	    return 1;
76 	}
77     }
78 
79     return 0;
80 }
81 
clone_gsf_tree(GsfInput * input,GsfOutput * output)82 static int clone_gsf_tree (GsfInput *input, GsfOutput *output)
83 {
84     int err = 0;
85 
86     if (gsf_input_size(input) > 0) {
87 	err = transcribe_gsf_data(input, output);
88     }
89 
90     if (GSF_IS_INFILE(input) && gsf_infile_num_children(GSF_INFILE(input)) > 0) {
91 	GsfInfile *in = GSF_INFILE(input);
92 	GsfOutfile *out = GSF_OUTFILE(output);
93 	int i, n = gsf_infile_num_children(in);
94 	char const *name;
95 	GsfInput *src;
96 	GsfOutput *dest;
97 	gboolean is_dir;
98 	GDateTime *modtime;
99 
100 	for (i=0; i<n && !err; i++) {
101 	    src = gsf_infile_child_by_index(in, i);
102 	    if (src == NULL) {
103 		err = 1;
104 		break;
105 	    }
106 
107 	    name = gsf_infile_name_by_index(in, i);
108 	    is_dir = gsf_is_dir(src);
109 #if ZDEBUG
110 	    fprintf(stderr, "clone_gsf_tree: i = %d (%s, %s)\n", i, name,
111 		    is_dir ? "directory" : "file");
112 #endif
113 	    modtime = gsf_input_get_modtime(src);
114 	    dest = gsf_outfile_new_child_full(out, name, is_dir,
115 					      "modtime", modtime,
116 					      NULL);
117 	    if (dest == NULL) {
118 		err = 1;
119 	    } else {
120 		err = clone_gsf_tree(src, dest);
121 	    }
122 	}
123     }
124 
125     gsf_output_close(output);
126     g_object_unref(G_OBJECT(output));
127     g_object_unref(G_OBJECT(input));
128 
129     return err;
130 }
131 
gretl_gsf_make_zipfile(const char * fname,const char * path)132 static int gretl_gsf_make_zipfile (const char *fname,
133 				   const char *path)
134 {
135     GsfInfile *infile;
136     GsfOutput *output, *ziproot;
137     GsfOutfile *outfile = NULL;
138     GError *gerr = NULL;
139     int err = 0;
140 
141     ensure_gsf_init();
142 
143 #if ZDEBUG
144     fprintf(stderr, "gretl_make_zipfile (gsf):\n fname='%s'\n path='%s'\n",
145 	    fname, path);
146 #endif
147 
148     infile = gsf_infile_stdio_new(path, &gerr);
149 
150     if (infile == NULL) {
151 	err = 1;
152     } else {
153 	output = gsf_output_stdio_new(fname, &gerr);
154 	if (output == NULL) {
155 	    err = 1;
156 	}
157     }
158 
159     if (!err) {
160 	outfile = gsf_outfile_zip_new(output, &gerr);
161 	g_object_unref(G_OBJECT(output));
162 	if (outfile == NULL) {
163 	    err = 1;
164 	}
165     }
166 
167     if (!err) {
168 	ziproot = gsf_outfile_new_child(outfile, path, 1);
169 	if (ziproot == NULL) {
170 	    fprintf(stderr, "failed to create ziproot for '%s'\n", path);
171 	    err = 1;
172 	} else {
173 	    err = clone_gsf_tree(GSF_INPUT(infile), ziproot);
174 	}
175     }
176 
177     if (outfile != NULL) {
178 	gsf_output_close(GSF_OUTPUT(outfile));
179 	g_object_unref(G_OBJECT(outfile));
180     }
181 
182 #if ZDEBUG
183     fprintf(stderr, "*** gretl_make_zipfile: returning %d\n", err);
184 #endif
185 
186     return handle_zip_error(fname, gerr, err, "zipping");
187 }
188 
gretl_gsf_zip_datafile(const char * fname,const char * path,int level)189 static int gretl_gsf_zip_datafile (const char *fname,
190 				   const char *path,
191 				   int level)
192 {
193     GsfOutput *output;
194     GsfOutfile *outfile = NULL;
195     GError *gerr = NULL;
196     int err = 0;
197 
198     ensure_gsf_init();
199 
200 #if ZDEBUG
201     fprintf(stderr, "gretl_zip_datafile (gsf):\n fname='%s'\n", fname);
202 #endif
203 
204     output = gsf_output_stdio_new(fname, &gerr);
205     if (output == NULL) {
206 	err = 1;
207     }
208 
209     if (!err) {
210 	outfile = gsf_outfile_zip_new(output, &gerr);
211 	g_object_unref(G_OBJECT(output));
212 	if (outfile == NULL) {
213 	    err = 1;
214 	}
215     }
216 
217     if (!err) {
218 	const char *names[] = { "data.xml", "data.bin" };
219 	char fullname[FILENAME_MAX];
220 	GsfInput *zinp;
221 	GsfOutput *zout;
222 	int i;
223 
224 	for (i=0; i<2 && !err; i++) {
225 	    gretl_build_path(fullname, path, names[i], NULL);
226 	    zinp = gsf_input_stdio_new(fullname, &gerr);
227 	    if (zinp == NULL) {
228 		err = 1;
229 	    } else {
230 		/* note: property not present in libgsf <= 1.14.30 */
231 		zout = gsf_outfile_new_child_full(outfile, names[i], 0,
232 						  "deflate-level", level,
233 						  NULL);
234 		err = transcribe_gsf_data(zinp, zout);
235 		gsf_output_close(zout);
236 		g_object_unref(G_OBJECT(zout));
237 		g_object_unref(G_OBJECT(zinp));
238 	    }
239 	}
240     }
241 
242     if (outfile != NULL) {
243 	gsf_output_close(GSF_OUTPUT(outfile));
244 	g_object_unref(G_OBJECT(outfile));
245     }
246 
247 #if ZDEBUG
248     fprintf(stderr, "*** gretl_gsf_zip_datafile: returning %d\n", err);
249 #endif
250 
251     return handle_zip_error(fname, gerr, err, "zipping");
252 }
253 
254 /* @fname: the name of the file to be unzipped.
255    @path: if non-NULL, the location into which the unzipping
256    should be done (if NULL, use pwd).
257    @zdirname: if non-NULL, set its content to the name of
258    the top-level directory within the zipfile (via g_strdup).
259 */
260 
gretl_gsf_unzip(const char * fname,const char * path,gchar ** zdirname)261 static int gretl_gsf_unzip (const char *fname,
262 			    const char *path,
263 			    gchar **zdirname)
264 {
265     GsfInput *input;
266     GsfInfile *infile;
267     GsfOutfile *outfile;
268     GError *gerr = NULL;
269     int err = 0;
270 
271 #if ZDEBUG
272     fprintf(stderr, "*** gretl_gsf_unzip_file:\n fname='%s'\n", fname);
273     fprintf(stderr, "path='%s', zdirname=%p\n", path, (void *) zdirname);
274 #endif
275 
276     ensure_gsf_init();
277     input = gsf_input_stdio_new(fname, &gerr);
278 
279     if (input == NULL) {
280 	err = 1;
281     } else {
282 	infile = gsf_infile_zip_new(input, &gerr);
283 	g_object_unref(G_OBJECT(input));
284 	if (infile == NULL) {
285 	    err = 1;
286 	} else {
287 	    if (zdirname != NULL) {
288 		*zdirname = g_strdup(gsf_infile_name_by_index(infile, 0));
289 	    }
290 	    if (path != NULL) {
291 		outfile = gsf_outfile_stdio_new(path, &gerr);
292 	    } else {
293 		outfile = gsf_outfile_stdio_new(".", &gerr);
294 	    }
295 	    if (outfile == NULL) {
296 		err = 1;
297 	    } else {
298 		err = clone_gsf_tree(GSF_INPUT(infile), GSF_OUTPUT(outfile));
299 	    }
300 	}
301     }
302 
303 #if ZDEBUG
304     fprintf(stderr, "*** gretl_gsf_unzip_file: returning %d\n", err);
305 #endif
306 
307     return handle_zip_error(fname, gerr, err, "unzipping");
308 }
309 
310 #else /* native, using gretlzip plugin, not libgsf */
311 
312 #include "plugins.h"
313 
gretl_plugin_unzip(const char * fname,const char * path,gchar ** zdirname)314 static int gretl_plugin_unzip (const char *fname,
315 			       const char *path,
316 			       gchar **zdirname)
317 {
318     int (*zfunc) (const char *, const char *, gchar **, GError **);
319     GError *gerr = NULL;
320     int err = 0;
321 
322     zfunc = get_plugin_function("gretl_native_unzip");
323     if (zfunc == NULL) {
324 	/* error message handled by get_plugin_function() */
325         return 1;
326     }
327 
328 #if ZDEBUG
329     fprintf(stderr, "gretl_plugin_unzip: fname='%s,\npath='%s'\nzdirname=%p\n",
330 	    fname, path, (void *) zdirname);
331 #endif
332 
333     err = (*zfunc)(fname, path, zdirname, &gerr);
334 
335     return handle_zip_error(fname, gerr, err, "unzipping");
336 }
337 
338 /*
339  * @fname: full path to zipfile to be created.
340  * @path: path relative to workdir for files to be picked up
341  * and zipped.
342  */
343 
gretl_plugin_make_zipfile(const char * fname,const char * path)344 static int gretl_plugin_make_zipfile (const char *fname,
345 				      const char *path)
346 {
347     int (*zfunc) (const char *, const char *, GError **);
348     GError *gerr = NULL;
349     int err = 0;
350 
351     zfunc = get_plugin_function("gretl_native_make_zipfile");
352     if (zfunc == NULL) {
353         return 1;
354     }
355 
356     err = (*zfunc)(fname, path, &gerr);
357 #if ZDEBUG
358     fprintf(stderr, "gretl_plugin_make_zipfile: err = %d\n", err);
359 #endif
360 
361     return handle_zip_error(fname, gerr, err, "zipping");
362 }
363 
gretl_plugin_zip_datafile(const char * fname,const char * path,int level)364 static int gretl_plugin_zip_datafile (const char *fname,
365 				      const char *path,
366 				      int level)
367 {
368     int (*zfunc) (const char *, const char *, int, GError **);
369     GError *gerr = NULL;
370     int err = 0;
371 
372     zfunc = get_plugin_function("gretl_native_zip_datafile");
373     if (zfunc == NULL) {
374         return 1;
375     }
376 
377     err = (*zfunc)(fname, path, level, &gerr);
378 
379     return handle_zip_error(fname, gerr, err, "zipping");
380 }
381 
382 #endif /* zip/unzip variants */
383 
384 /**
385  * gretl_unzip:
386  * @fname: name of the file to unzip.
387  *
388  * Unzips @fname in the current directory, preserving any
389  * internal directory structure.
390  *
391  * Returns: 0 on success, non-zero code on error.
392  */
393 
gretl_unzip(const char * fname)394 int gretl_unzip (const char *fname)
395 {
396 #if USE_GSF
397     return gretl_gsf_unzip(fname, NULL, NULL);
398 #else
399     return gretl_plugin_unzip(fname, NULL, NULL);
400 #endif
401 }
402 
403 /**
404  * gretl_unzip_into:
405  * @fname: name of the file to unzip.
406  * @dirname: the name of the directory in which unzipping
407  * should take place.
408  *
409  * Unzips @fname in the specified directory, preserving any
410  * internal directory structure.
411  *
412  * Returns: 0 on success, non-zero code on error.
413  */
414 
gretl_unzip_into(const char * fname,const char * dirname)415 int gretl_unzip_into (const char *fname, const char *dirname)
416 {
417 #if USE_GSF
418     return gretl_gsf_unzip(fname, dirname, NULL);
419 #else
420     return gretl_plugin_unzip(fname, dirname, NULL);
421 #endif
422 }
423 
424 /**
425  * gretl_make zipfile:
426  * @fname: name of the zip file to create.
427  * @path: the path to the content which should be zipped.
428  *
429  * Creates a zip file of the specified name, whose content
430  * is determined (recursively) by @path.
431  *
432  * Returns: 0 on success, non-zero code on error.
433  */
434 
gretl_make_zipfile(const char * fname,const char * path)435 int gretl_make_zipfile (const char *fname, const char *path)
436 {
437 #if USE_GSF
438     return gretl_gsf_make_zipfile(fname, path);
439 #else
440     return gretl_plugin_make_zipfile(fname, path);
441 #endif
442 }
443 
444 /**
445  * gretl_unzip_session_file:
446  * @fname: name of the file to unzip.
447  * @zdirname: location to receive the name of the top-level
448  * directory within the zip archive.
449  *
450  * Specialized (slightly) unzipper for gretl session files.
451  *
452  * Returns: 0 on success, non-zero code on error.
453  */
454 
gretl_unzip_session_file(const char * fname,gchar ** zdirname)455 int gretl_unzip_session_file (const char *fname, gchar **zdirname)
456 {
457 #if USE_GSF
458     return gretl_gsf_unzip(fname, NULL, zdirname);
459 #else
460     return gretl_plugin_unzip(fname, NULL, zdirname);
461 #endif
462 }
463 
464 /**
465  * gretl_zip_datafile:
466  * @fname: name of the zip file to create.
467  * @path: the path to the content which should be zipped.
468  * @level: the zlib compression level to apply.
469  *
470  * Creates a zip file of the specified name, with content
471  * given by @path, using the specified compression level.
472  *
473  * Returns: 0 on success, non-zero code on error.
474  */
475 
gretl_zip_datafile(const char * fname,const char * path,int level)476 int gretl_zip_datafile (const char *fname, const char *path,
477 			int level)
478 {
479 #if USE_GSF
480     return gretl_gsf_zip_datafile(fname, path, level);
481 #else
482     return gretl_plugin_zip_datafile(fname, path, level);
483 #endif
484 }
485 
486 /* below: apparatus for making a zipfile for a function
487    package
488 */
489 
zip_report(int err,int nf,gretlopt opt,PRN * prn)490 static void zip_report (int err, int nf, gretlopt opt, PRN *prn)
491 {
492     if (opt & OPT_G) {
493 	/* GUI use */
494 	if (err && nf) {
495 	    pprintf(prn, "<@fail> (%s)\n", _("not found"));
496 	} else if (err) {
497 	    pputs(prn, "<@fail>\n");
498 	} else {
499 	    pputs(prn, "<@ok>\n");
500 	}
501     } else {
502 	if (err && nf) {
503 	    pprintf(prn, "failed (%s)\n", _("not found"));
504 	} else if (err) {
505 	    pputs(prn, "failed\n");
506 	} else {
507 	    pputs(prn, "OK\n");
508 	}
509     }
510 }
511 
pkg_zipfile_add(const char * fname,const char * dotpath,gretlopt opt,PRN * prn)512 static int pkg_zipfile_add (const char *fname,
513 			    const char *dotpath,
514 			    gretlopt opt,
515 			    PRN *prn)
516 {
517     gchar *dest = NULL;
518     struct stat sbuf;
519     int nf = 0;
520     int err = 0;
521 
522     pprintf(prn, "Copying %s... ", fname);
523 
524     if (stat(fname, &sbuf) != 0) {
525 	nf = err = E_DATA;
526     } else if (sbuf.st_mode & S_IFDIR) {
527 	/* aha, we've got a subdir */
528 	gchar *ziptmp;
529 
530 	ziptmp = g_strdup_printf("%s%cpkgtmp.zip", dotpath, SLASH);
531 	err = gretl_make_zipfile(ziptmp, fname);
532 	if (!err) {
533 	    err = gretl_unzip_into(ziptmp, dotpath);
534 	    gretl_remove(ziptmp);
535 	}
536 	g_free(ziptmp);
537     } else {
538 	/* a regular file, we hope; but if this is the PDF file
539 	   for a package we'll allow that it may be found in a
540 	   subdirectory (probably "doc")
541 	*/
542 	const char *p = strrslash(fname);
543 
544 	if (p != NULL && has_suffix(fname, ".pdf")) {
545 	    dest = g_strdup_printf("%s%c%s", dotpath, SLASH, p + 1);
546 	} else {
547 	    dest = g_strdup_printf("%s%c%s", dotpath, SLASH, fname);
548 	}
549 	err = gretl_copy_file(fname, dest);
550     }
551 
552     zip_report(err, nf, opt, prn);
553     g_free(dest);
554 
555     return err;
556 }
557 
558 /**
559  * package_make_zipfile:
560  * @gfnname: name of the gfn file to be zip-packaged.
561  * @pdfdoc: package has PDF documentation? (0/1).
562  * @datafiles: names of any data files to include (or NULL).
563  * @n_datafiles: the number of strings in @datafiles.
564  * @pzipname: location to receive "dotdir" zipname, or NULL.
565  * @dest: specific path for output zipfile, or NULL.
566  * @opt: use OPT_G for GUI use (only);
567  * @prn: gretl printer for progress.
568  *
569  * Collects the specified gfn file plus any additional files
570  * it references (PDF doc and/or data files) and makes a
571  * zip archive, using the user's "dotdir" as workspace.
572  * If @pzipname is non-NULL this is taken as signal to
573  * leave the zipfile where it has been created, and to
574  * "return" its full path via this pointer. Otherwise, if
575  * @dest is non-NULL it is taken to stipulate a path to
576  * which the zipfile should be moved/renamed.
577  *
578  * Errors are flagged if both @pzipname and @dest are NULL,
579  * if @gfnname does not have the ".gfn" extension, or if
580  * the basename of the gfn file (minus extension) is over
581  * 32 bytes long.
582  *
583  * Returns: 0 on success, non-zero code on error.
584  */
585 
package_make_zipfile(const char * gfnname,int pdfdoc,char ** datafiles,int n_datafiles,gchar ** pzipname,const char * dest,gretlopt opt,PRN * prn)586 int package_make_zipfile (const char *gfnname,
587 			  int pdfdoc,
588 			  char **datafiles,
589 			  int n_datafiles,
590 			  gchar **pzipname,
591 			  const char *dest,
592 			  gretlopt opt,
593 			  PRN *prn)
594 {
595     char pkgbase[FILENAME_MAX];
596     gchar *pkgname = NULL;
597     gchar *origdir = NULL;
598     gchar *tmp, *dotpath = NULL;
599     int len, dir_made = 0;
600     int err = 0;
601 
602     if (pzipname == NULL && dest == NULL) {
603 	/* we need one or the other of these */
604 	return E_DATA;
605     }
606 
607     if (!has_suffix(gfnname, ".gfn")) {
608 	gretl_errmsg_set("Input must have extension \".gfn\"");
609 	return E_DATA;
610     }
611 
612     /* determine the common path to files for packaging,
613        and also the name of the package
614     */
615     strcpy(pkgbase, gfnname);
616     tmp = strrslash(pkgbase);
617     if (tmp != NULL) {
618 	/* got some path component */
619 	*tmp = '\0';
620 	tmp++;
621     } else {
622 	/* using current working directory */
623 	*pkgbase = '\0';
624 	tmp = (gchar *) gfnname;
625     }
626 
627     len = strlen(tmp) - 4; /* minus 4 for ".gfn" */
628     if (len < 0 || len > 31) {
629 	gretl_errmsg_set("Invalid package name (31 bytes max)");
630 	return E_DATA;
631     }
632 
633     pkgname = g_strndup(tmp, len);
634 
635     /* record where we are now */
636     origdir = g_get_current_dir();
637 
638 #if 0
639     fprintf(stderr, "origdir: '%s'\n", origdir);
640     fprintf(stderr, "pkgbase: '%s'\n", pkgbase);
641     fprintf(stderr, "pkgname: '%s'\n", pkgname);
642 #endif
643 
644     if (*pkgbase != '\0') {
645 	/* get into place for copying */
646 	pputs(prn, "Getting in place... ");
647 	err = gretl_chdir(pkgbase);
648 	zip_report(err, 0, opt, prn);
649     }
650 
651     if (!err) {
652 	/* path to temporary dir for zipping */
653 	dotpath = g_strdup_printf("%s%s", gretl_dotdir(), pkgname);
654 	pputs(prn, "Making temporary directory... ");
655 	err = gretl_mkdir(dotpath);
656 	zip_report(err, 0, opt, prn);
657     }
658 
659     if (!err) {
660 	dir_made = 1;
661     }
662 
663     if (!err) {
664 	/* copy the gfn file into place */
665 	tmp = g_strdup_printf("%s.gfn", pkgname);
666 	err = pkg_zipfile_add(tmp, dotpath, opt, prn);
667 	g_free(tmp);
668     }
669 
670     if (!err && pdfdoc) {
671 	/* copy PDF file into place */
672 	struct stat sbuf;
673 
674 	tmp = g_strdup_printf("%s.pdf", pkgname);
675 	if (stat(tmp, &sbuf) != 0) {
676 	    g_free(tmp);
677 	    tmp = g_strdup_printf("doc/%s.pdf", pkgname);
678 	}
679 	err = pkg_zipfile_add(tmp, dotpath, opt, prn);
680 	g_free(tmp);
681     }
682 
683     if (!err && datafiles != NULL) {
684 	/* copy data files into place, if any */
685 	int i;
686 
687 	for (i=0; i<n_datafiles && !err; i++) {
688 	    err = pkg_zipfile_add(datafiles[i],
689 				  dotpath, opt, prn);
690 	}
691     }
692 
693     if (!err) {
694 	/* get into place for making zipfile */
695 	err = gretl_chdir(gretl_dotdir());
696 	if (!err) {
697 	    tmp = g_strdup_printf("%s.zip", pkgname);
698 	    pprintf(prn, "Making %s... ", tmp);
699 	    err = gretl_make_zipfile(tmp, pkgname);
700 	    zip_report(err, 0, opt, prn);
701 	    if (!err) {
702 		if (pzipname != NULL) {
703 		    /* Signals that we should leave the zipfile in
704 		       the user's dotdir and return its name via
705 		       this pointer.
706 		    */
707 		    *pzipname = g_strdup_printf("%s%s.zip", gretl_dotdir(),
708 						pkgname);
709 		} else {
710 		    /* If we get here dest must be non-NULL,
711 		       but it may be a relative path, in which
712 		       case we need to prepend @origdir for the
713 		       zipfile copying operation.
714 		    */
715 		    const char *realdest = dest;
716 		    gchar *zipname = NULL;
717 
718 		    pprintf(prn, "Copying %s... ", tmp);
719 
720 		    if (origdir != NULL && !g_path_is_absolute(dest)) {
721 			zipname = g_build_filename(origdir, dest, NULL);
722 			realdest = zipname;
723 		    }
724 		    err = gretl_copy_file(tmp, realdest);
725 		    zip_report(err, 0, opt, prn);
726 		    if (strcmp(tmp, realdest)) {
727 			gretl_remove(tmp);
728 		    }
729 		    g_free(zipname);
730 		}
731 	    }
732 	    g_free(tmp);
733 	}
734     }
735 
736     if (origdir != NULL) {
737 	/* get back to where we came from */
738 	gretl_chdir(origdir);
739 	g_free(origdir);
740     }
741 
742     if (dir_made) {
743 	/* delete the temporary zip directory */
744 	gretl_deltree(dotpath);
745     }
746 
747     g_free(dotpath);
748     g_free(pkgname);
749 
750     return err;
751 }
752