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