1
2 static const char cright_years_z[] =
3
4 /* Handle so called `shell archives'.
5 Copyright (C) */ "1994-2015";
6
7 /* Free Software Foundation, Inc.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3, or (at your option)
12 any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License along
20 with this program. If not, see <http://www.gnu.org/licenses/>.
21
22 --copyright-mark "(copyright \\(c\\)[ \t]+[*]/ *\")([12][90][0-9][0-9])"
23 */
24
25 /*
26 A note about translated strings:
27
28 There are several categories of English text that get emitted by this
29 program:
30
31 1) Error messages by this program. These should all be literals
32 in this program text and should be surrounded by _() macro calls.
33
34 2) Error messages emitted by the shell script emitted by this
35 program. These messages *MUST ALL BE DEFINED* in the 'shar-msg'
36 table defined in scripts.def. The emitted script will try to
37 translate them before echoing them out to the user.
38
39 3) Shell script comments that are inserted into the output.
40 These English comments are *NEVER* translated. They appear both
41 as literal text in this program, and as literal script text in
42 the 'text' table in "scripts.def". Localization of "shar" has
43 no effect on these comment strings.
44 */
45 #define SHAR_C 1
46 #include "shar-opts.h"
47
48 #include <ctype.h>
49 #ifdef HAVE_LIMITS_H
50 # include <limits.h>
51 #endif
52 #include <time.h>
53
54 #include "inttostr.h"
55 #include "liballoca.h"
56 #include "md5.c"
57 #include "md5.h"
58 #include "quotearg.h"
59 #include "xalloc.h"
60 #include "xgetcwd.h"
61 #include "scribble.h"
62
63 #if HAVE_LOCALE_H
64 #else
65 # define setlocale(Category, Locale)
66 #endif
67
68 #ifndef NUL
69 # define NUL '\0'
70 #endif
71
72 #include "scripts.x"
73
74 /* Character which goes in front of each line. */
75 #define DEFAULT_LINE_PREFIX_1 'X'
76
77 /* Character which goes in front of each line if here_delimiter[0] ==
78 DEFAULT_LINE_PREFIX_1. */
79 #define DEFAULT_LINE_PREFIX_2 'Y'
80
81 /* Maximum length for a text line before it is considered binary. */
82 #define MAXIMUM_NON_BINARY_LINE 200
83
84 #define LOG10_MAX_INT 11
85
86 char const * const program_name = "shar";
87
88 /* System related declarations. */
89
90 /* Convert a possibly-signed character to an unsigned character. This is
91 a bit safer than casting to unsigned char, since it catches some type
92 errors that the cast doesn't. */
to_uchar(char ch)93 static inline unsigned char to_uchar (char ch) { return ch; }
94
95 #if STDC_HEADERS
96 # define ISASCII(_c) 1
97 #else
98 # ifdef isascii
99 # define ISASCII(_c) isascii (to_uchar (_c))
100 # else
101 # if HAVE_ISASCII
102 # define ISASCII(_c) isascii (to_uchar (_c))
103 # else
104 # define ISASCII(_c) ((_c) & 0x7f == (unsigned char) (_c))
105 # endif
106 # endif
107 #endif
108
109 #ifdef isgraph
110 #define IS_GRAPH(_c) isgraph (to_uchar (_c))
111 #else
112 #define IS_GRAPH(_c) (isprint (to_uchar (_c)) && !isspace (to_uchar (_c)))
113 #endif
114
115 struct tm *localtime ();
116
117 #if MSDOS
118 /* 1 extra for CR. */
119 # define CRLF_STRLEN(_s) (strlen (_s) + 1)
120 #else
121 # define CRLF_STRLEN(_s) (strlen (_s))
122 #endif
123
124 #if !NO_WALKTREE
125
126 /* Declare directory reading routines and structures. */
127
128 # ifdef __MSDOS__
129 # include "msd_dir.h"
130 # else
131 # include DIRENT_HEADER
132 # endif
133
134 # if HAVE_DIRENT_H
135 # define NAMLEN(dirent) (strlen((dirent)->d_name))
136 # else
137 # define NAMLEN(dirent) ((dirent)->d_namlen)
138 # ifndef __MSDOS__
139 # define dirent direct
140 # endif
141 # endif
142
143 #endif /* !NO_WALKTREE */
144
145 /* Option variables. */
146
147 /* Determine whether an integer type is signed, and its bounds.
148 This code assumes two's (or one's!) complement with no holes. */
149
150 /* The extra casts work around common compiler bugs,
151 e.g. Cray C 5.0.3.0 when t == time_t. */
152 #ifndef TYPE_SIGNED
153 # define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
154 #endif
155 #ifndef TYPE_MINIMUM
156 # define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) \
157 ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) \
158 : (t) 0))
159 #endif
160 #ifndef TYPE_MAXIMUM
161 # define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t)))
162 #endif
163
164 static char explain_text_fmt[sizeof(explain_fmt_fmt_z)];
165 static int const explain_1_len = sizeof(explain_1_z) - 1;
166 static int const explain_2_len = sizeof(explain_2_z) - 1;
167
168 typedef enum {
169 QUOT_ID_LNAME,
170 QUOT_ID_RNAME,
171 QUOT_ID_PATH
172 } quot_id_t;
173
174 typedef struct {
175 char const * cmpr_name;
176 char const * cmpr_cmd_fmt;
177 char const * cmpr_title;
178 char const * cmpr_mode; /* this must match text after ${lock_dir}/ */
179 char const * cmpr_unpack;
180 char const * cmpr_unnote;
181 unsigned long cmpr_level;
182 } compact_state_t;
183
184 compact_state_t gzip_compaction = {
185 .cmpr_name = "gzip",
186 .cmpr_cmd_fmt = "gzip -c -%u %s",
187 .cmpr_title = "gzipped",
188 .cmpr_mode = "gzi",
189 .cmpr_unpack = "gzip -dc ${lock_dir}/gzi > %s && \\\n",
190 .cmpr_unnote = "gunzipping file %s"
191 };
192
193 compact_state_t xz_compaction = {
194 .cmpr_name = "xz",
195 .cmpr_cmd_fmt = "xz -zc -%u %s",
196 .cmpr_title = "xz-compressed",
197 .cmpr_mode = "xzi",
198 .cmpr_unpack = "xz -dc ${lock_dir}/xzi > %s && \\\n",
199 .cmpr_unnote = "xz-decompressing file %s"
200 };
201
202 compact_state_t bzip2_compaction = {
203 .cmpr_name = "bzip2",
204 .cmpr_cmd_fmt = "bzip2 -zkc -%u %s",
205 .cmpr_title = "bzipped",
206 .cmpr_mode = "bzi",
207 .cmpr_unpack = "bzip2 -dkc ${lock_dir}/bzi > %s && \\\n",
208 .cmpr_unnote = "bunzipping file %s"
209 };
210
211 #ifdef HAVE_COMPRESS
212 compact_state_t compress_compaction = {
213 .cmpr_name = "compress",
214 .cmpr_cmd_fmt = "compress -b%u < %s",
215 .cmpr_title = "compressed",
216 .cmpr_mode = "cmp",
217 .cmpr_unpack = "compress -d < ${lock_dir}/cmp > %s && \\\n",
218 .cmpr_unnote = "uncompressing file %s"
219 };
220 #endif
221
222 compact_state_t * const compaction[] = {
223 &gzip_compaction,
224 &xz_compaction,
225 #ifdef HAVE_COMPRESS
226 &compress_compaction,
227 #endif
228 &bzip2_compaction
229 };
230 compact_state_t * cmpr_state = NULL;
231
232 static int const compact_ct = sizeof(compaction)/sizeof(compaction[0]);
233
234 /* Character to get at the beginning of each line. */
235 static int line_prefix = '\0';
236
237 /* Value of strlen (here_delimiter). */
238 static size_t here_delimiter_length = 0;
239
240 /* Switch for debugging on. */
241 #if DEBUG
242 static int debugging_mode = 0;
243 #endif
244
245 /* Other global variables. */
246
247 typedef enum {
248 fail = ~1, // disambiguate, in case "true" is -1.
249 doue_true = true,
250 doue_false = false
251 } do_uue_t;
252
253 do_uue_t uuencode_file = fail;
254 int opt_idx = 0;
255
256 /* File onto which the shar script is being written. */
257 static FILE *output = NULL;
258
259 /* Position for archive type message. */
260 static off_t archive_type_position = 0;
261
262 /* Position for first file in the shar file. */
263 static off_t first_file_position = 0;
264
265 /* Actual output filename. */
266 static char *output_filename = NULL;
267
268 /* Output file ordinal. FIXME: also flag for -o. */
269 static int part_number = 0;
270
271 /* Table saying whether each character is binary or not. */
272 static unsigned char byte_is_binary[256];
273
274 /* For checking file type and access modes. */
275 static struct stat struct_stat;
276
277 /* The number used to make the intermediate files unique. */
278 static int sharpid = 0;
279
280 static int translate_script = 0;
281
282 static int mkdir_alloc_ct = 0;
283 static int mkdir_already_ct = 0;
284 static char** mkdir_already;
285
286 #if DEBUG
287 # define DEBUG_PRINT(Format, Value) \
288 if (debugging_mode) \
289 { \
290 static char const _f[] = Format; \
291 char buf[INT_BUFSIZE_BOUND (off_t)]; \
292 printf (_f, offtostr (Value, buf)); \
293 }
294 #else
295 # define DEBUG_PRINT(Format, Value)
296 #endif
297
298 static void open_output (void);
299 static void close_output (int next_part_no);
300
301 /* Walking tree routines. */
302
303 /* Define a type just for easing ansi2knr's life. */
304 typedef int (*walker_t) (const char *, const char *);
305
306 static void
init_shar_msg(void)307 init_shar_msg(void)
308 {
309 int ix;
310 struct quoting_options * alwaysq, * doubleq;
311
312 if (translate_script)
313 {
314 for (ix = 0; ix < SHAR_MSG_CT; ix++)
315 shar_msg_table[ix] = gettext (shar_msg_table[ix]);
316 }
317
318 alwaysq = clone_quoting_options (NULL);
319 set_quoting_style (alwaysq, shell_always_quoting_style);
320
321 doubleq = clone_quoting_options (NULL);
322 set_quoting_style (doubleq, c_quoting_style);
323 set_char_quoting (doubleq, '"', 1); // ");
324
325 for (ix = 0; ix < SHAR_MSG_CT; ix++)
326 {
327 char const * pz = shar_msg_table[ix];
328
329 switch (shar_msg_xform[ix])
330 {
331 case XFORM_PLAIN: continue;
332
333 case XFORM_APOSTROPHE:
334 pz = quotearg_alloc (pz, shar_msg_size[ix], alwaysq);
335 break;
336
337 case XFORM_DBL_QUOTE:
338 pz = quotearg_alloc (pz, shar_msg_size[ix], doubleq);
339 break;
340 }
341
342 shar_msg_table[ix] = pz;
343 }
344
345 free (alwaysq);
346 free (doubleq);
347 }
348
349 static char const *
format_report(char const * fmt,char const * what)350 format_report(char const * fmt, char const * what)
351 {
352 if (fmt == NULL)
353 return NULL;
354
355 {
356 size_t sz = strlen (fmt) + strlen (what) + 2;
357 char * res = scribble_get(sz);
358 int len = snprintf (res, sz, fmt, what);
359 if ((unsigned)len < sz)
360 return res;
361 if (len < 0)
362 die (SHAR_EXIT_BUG, _("printf formatting error: %s\n"), fmt);
363
364 res = scribble_get(len + 1);
365 return res;
366 }
367 }
368
369 static void
echo_status(const char * test,const char * ok_fmt,const char * bad_fmt,const char * what,int die_on_failure)370 echo_status (const char* test,
371 const char* ok_fmt,
372 const char* bad_fmt,
373 const char* what,
374 int die_on_failure )
375 {
376 char const * good_quot;
377 char const * bad_quot;
378 char const * die_str;
379
380 /*
381 NOTE TO DEVELOPERS: The two format arguments "ok_fmt" and "bad_fmt" are
382 expected to be correctly quoted for use by the shell command, "echo".
383 That is to say, the status strings contain an unadorned:
384 echo %s
385 and the input has to work correctly.
386
387 These formatting strings will normally have a "%s" in them somewhere to
388 fill in the value from "what". Those strings are then used in the real
389 output formatting with show_all_status_z or show_good_status_z or
390 show_bad_status_z. Not all do, so "what" can sometimes be NULL.
391 */
392 good_quot = format_report (ok_fmt, what);
393 bad_quot = format_report (bad_fmt, what);
394 die_str = die_on_failure ? show_status_dies_z : "";
395
396 if (good_quot != NULL)
397 {
398 if (bad_quot != NULL)
399 fprintf (output, show_all_status_z, test, good_quot,
400 bad_quot, die_str);
401 else
402 fprintf (output, show_good_status_z, test, good_quot);
403 }
404
405 else if (bad_quot != NULL)
406 fprintf (output, show_bad_status_z, test, bad_quot, die_str);
407
408 else
409 die (SHAR_EXIT_BUG, _("sharutils bug - no status"));
410 }
411
412 static void
echo_text(const char * format_pz,const char * arg_pz,bool cascade)413 echo_text (const char* format_pz, const char* arg_pz, bool cascade)
414 {
415 static char const continue_z[] = " &&\n";
416 size_t sz = strlen (format_pz) + strlen (arg_pz) + sizeof (continue_z);
417 char * bf = scribble_get (sz);
418 unsigned int len = (unsigned)snprintf (bf, sz, format_pz, arg_pz);
419
420 if (cascade)
421 memcpy (bf + len, continue_z, sizeof (continue_z));
422 fprintf (output, echo_string_z, bf);
423 }
424
425 #if !NO_WALKTREE
426
427 /*--------------------------------------------------------------------------.
428 | Recursively call ROUTINE on each entry, down the directory tree. NAME |
429 | is the path to explore. RESTORE_NAME is the name that will be later |
430 | relative to the unsharing directory. ROUTINE may also assume |
431 | struct_stat is set, it accepts updated values for NAME and RESTORE_NAME. |
432 `--------------------------------------------------------------------------*/
433
434 static int
walkdown(walker_t routine,const char * local_name,const char * restore_name)435 walkdown (
436 walker_t routine,
437 const char *local_name,
438 const char *restore_name)
439 {
440 DIR *directory; /* directory being scanned */
441 int status; /* status to return */
442
443 char *local_name_copy; /* writeable copy of local_name */
444 size_t local_name_length; /* number of characters in local_name_copy */
445 size_t sizeof_local_name; /* allocated size of local_name_copy */
446
447 char *restore_name_copy; /* writeable copy of restore_name */
448 int restore_offset; /* passdown copy of restore_name */
449 size_t restore_name_length; /* number of characters in restore_name_copy */
450 size_t sizeof_restore_name; /* allocated size of restore_name_copy */
451
452 if (stat (local_name, &struct_stat))
453 {
454 error (0, errno, "%s", local_name);
455 return SHAR_EXIT_FILE_NOT_FOUND;
456 }
457
458 if (!S_ISDIR (struct_stat.st_mode & S_IFMT))
459 return (*routine) (local_name, restore_name);
460
461 if (directory = opendir (local_name), !directory)
462 {
463 error (0, errno, "%s", local_name);
464 return SHAR_EXIT_CANNOT_OPENDIR;
465 }
466
467 status = 0;
468
469 /* include trailing '/' in length */
470
471 local_name_length = strlen (local_name) + 1;
472 sizeof_local_name = local_name_length + 32;
473 local_name_copy = xmalloc (sizeof_local_name);
474 memcpy (local_name_copy, local_name, local_name_length-1);
475 local_name_copy[ local_name_length-1 ] = '/';
476 local_name_copy[ local_name_length ] = NUL;
477
478 restore_name_length = strlen (restore_name) + 1;
479 sizeof_restore_name = restore_name_length + 32;
480 restore_name_copy = xmalloc (sizeof_restore_name);
481 memcpy (restore_name_copy, restore_name, restore_name_length-1);
482 restore_name_copy[ restore_name_length-1 ] = '/';
483 restore_name_copy[ restore_name_length ] = NUL;
484
485 if ((restore_name_copy[0] == '.') && (restore_name_copy[1] == '/'))
486 restore_offset = 2;
487 else
488 restore_offset = 0;
489
490 for (;;)
491 {
492 struct dirent *entry = readdir (directory);
493 const char* pzN;
494 int space_need;
495
496 if (entry == NULL)
497 break;
498
499 /* append the new file name after the trailing '/' char.
500 If we need more space, add in a buffer so we needn't
501 allocate over and over. */
502
503 pzN = entry->d_name;
504 if (*pzN == '.')
505 {
506 if (pzN[1] == NUL)
507 continue;
508 if ((pzN[1] == '.') && (pzN[2] == NUL))
509 continue;
510 }
511
512 space_need = 1 + NAMLEN (entry);
513 if (local_name_length + space_need > sizeof_local_name)
514 {
515 sizeof_local_name = local_name_length + space_need + 16;
516 local_name_copy = (char *)
517 xrealloc (local_name_copy, sizeof_local_name);
518 }
519 strcpy (local_name_copy + local_name_length, pzN);
520
521 if (restore_name_length + space_need > sizeof_restore_name)
522 {
523 sizeof_restore_name = restore_name_length + space_need + 16;
524 restore_name_copy = (char *)
525 xrealloc (restore_name_copy, sizeof_restore_name);
526 }
527 strcpy (restore_name_copy + restore_name_length, pzN);
528
529 status = walkdown (routine, local_name_copy,
530 restore_name_copy + restore_offset);
531 if (status != 0)
532 break;
533 }
534
535 /* Clean up. */
536
537 free (local_name_copy);
538 free (restore_name_copy);
539
540 #if CLOSEDIR_VOID
541 closedir (directory);
542 #else
543 if (closedir (directory))
544 {
545 error (0, errno, "%s", local_name);
546 return SHAR_EXIT_CANNOT_OPENDIR;
547 }
548 #endif
549
550 return status;
551 }
552
553 #endif /* !NO_WALKTREE */
554
555 /*------------------------------------------------------------------.
556 | Walk through the directory tree, calling ROUTINE for each entry. |
557 | ROUTINE may also assume struct_stat is set. |
558 `------------------------------------------------------------------*/
559
560 static int
walktree(walker_t routine,const char * local_name)561 walktree (walker_t routine, const char *local_name)
562 {
563 const char *restore_name;
564 char *local_name_copy;
565
566 /* Remove crumb at end. */
567 {
568 int len = strlen (local_name);
569 char *cursor;
570
571 local_name_copy = (char *) alloca (len + 1);
572 memcpy (local_name_copy, local_name, len + 1);
573 cursor = local_name_copy + len - 1;
574
575 while (*cursor == '/' && cursor > local_name_copy)
576 *(cursor--) = NUL;
577 }
578
579 /* Remove crumb at beginning. */
580
581 if (HAVE_OPT(BASENAME))
582 restore_name = base_name (local_name_copy);
583 else if (!strncmp (local_name_copy, "./", 2))
584 restore_name = local_name_copy + 2;
585 else
586 restore_name = local_name_copy;
587
588 #if NO_WALKTREE
589
590 /* Just act on current entry. */
591
592 {
593 int status = stat (local_name_copy, &struct_stat);
594
595 if (status != 0)
596 {
597 error (0, errno, "%s", local_name_copy);
598 status = SHAR_EXIT_FILE_NOT_FOUND;
599 }
600 else
601 status = (*routine) (local_name_copy, restore_name);
602
603 return status;
604 }
605
606 #else
607
608 /* Walk recursively. */
609
610 return walkdown (routine, local_name_copy, restore_name);
611
612 #endif
613 }
614
615 /* Generating parts of shar file. */
616
617 /*---------------------------------------------------------------------.
618 | Build a `drwxrwxrwx' string corresponding to MODE into MODE_STRING. |
619 `---------------------------------------------------------------------*/
620
621 static char *
mode_string(unsigned mode)622 mode_string (unsigned mode)
623 {
624 static char const modes[] = "-rwxrwxrwx";
625 static char result[12];
626 int ix = 1;
627 int msk = 0400;
628
629 strcpy (result, "----------");
630
631 do {
632 if (mode & msk)
633 result[ix] = modes[ix];
634 ix++;
635 msk >>= 1;
636 } while (msk != 0);
637
638 if (mode & 04000)
639 result[3] = 's';
640
641 if (mode & 02000)
642 result[6] = 's';
643
644 return result;
645 }
646
647 /*-----------------------------------------------------------------------.
648 | Generate shell code which, at *unshar* time, will study the properties |
649 | of the unpacking system and set some variables accordingly. |
650 `-----------------------------------------------------------------------*/
651
652 static void
generate_configure(void)653 generate_configure (void)
654 {
655 if (! HAVE_OPT(NO_MD5_DIGEST))
656 fprintf (output, md5check_z, SM_not_verifying_sums);
657
658 fputs (clobber_check_z, output);
659
660 if (! HAVE_OPT(NO_I18N))
661 {
662 fputs (i18n_z, output);
663 /* Above the name of the program of the package which supports the
664 --print-text-domain-dir option has to be given. */
665 }
666
667 if (! HAVE_OPT(QUIET_UNSHAR))
668 {
669 if (HAVE_OPT(VANILLA_OPERATION))
670 fputs (dev_tty_nocheck_z, output);
671 else
672 {
673 if (HAVE_OPT(QUERY_USER))
674 /* Check if /dev/tty exists. If yes, define shar_tty to
675 '/dev/tty', else, leave it empty. */
676
677 fputs (dev_tty_check_z, output);
678
679 /* Try to find a way to echo a message without newline. Set
680 shar_n to '-n' or nothing for an echo option, and shar_c
681 to '\c' or nothing for a string terminator. */
682
683 fputs (echo_checks_z, output);
684 }
685 }
686
687 if (! HAVE_OPT(NO_TIMESTAMP))
688 {
689 fprintf (output, timestamp_z, SM_time_not_set);
690 }
691
692 if ((! HAVE_OPT(WHOLE_SIZE_LIMIT)) || (part_number == 1))
693 {
694 echo_status (ck_lockdir_z, NULL, SM_lock_dir_exists, lock_dir_z, 1);
695
696 /* Create locking directory. */
697 if (HAVE_OPT(VANILLA_OPERATION))
698 echo_status (make_lock_dir_z, NULL, SM_no_lock_dir, lock_dir_z, 1);
699 else
700 echo_status (make_lock_dir_z, SM_x_lock_dir_created,
701 SM_x_no_lock_dir, lock_dir_z, 1);
702 }
703 else
704 {
705 fprintf (output, seq_check_z,
706 SM_unpack_part_1, part_number,
707 SM_unpack_next_part);
708 }
709
710 if (HAVE_OPT(QUERY_USER))
711 {
712 fprintf (output, query_answers_z,
713 SM_ans_yes, SM_yes_means,
714 SM_ans_no, SM_no_means,
715 SM_ans_all, SM_all_means,
716 SM_ans_none, SM_none_means,
717 SM_ans_help, SM_help_means,
718 SM_ans_quit, SM_quit_means);
719 }
720 }
721
722 /*----------------------------------------------.
723 | generate_mkdir |
724 | Make sure it is done only once for each dir |
725 `----------------------------------------------*/
726
727 static void
generate_mkdir(const char * path)728 generate_mkdir (const char *path)
729 {
730 const char *quoted_path;
731
732 /* If already generated code for this dir creation, don't do again. */
733
734 {
735 int ct = mkdir_already_ct;
736 char** pp = mkdir_already;
737
738 while (--ct > 0)
739 {
740 if (strcmp (*(pp++), path) == 0)
741 return;
742 }
743 }
744
745 /* Haven't done this one. */
746
747 if (++mkdir_already_ct > mkdir_alloc_ct)
748 {
749 /*
750 * We need more name space. Get larger and larger chunks of space.
751 * The bound is when integers go negative. Too many directories. :)
752 *
753 * 16, 40, 76, 130, 211, 332, 514, 787, 1196, 1810, 2731, 4112, ...
754 */
755 mkdir_alloc_ct += 16 + (mkdir_alloc_ct/2);
756 if (mkdir_alloc_ct < 0)
757 die (SHAR_EXIT_FAILED,
758 _("Too many directories for mkdir generation"));
759
760 if (mkdir_already != NULL)
761 mkdir_already =
762 xrealloc (mkdir_already, mkdir_alloc_ct * sizeof (char*));
763 else
764 mkdir_already = xmalloc (mkdir_alloc_ct * sizeof (char*));
765 }
766
767 /* Add the directory into our "we've done this already" table */
768
769 mkdir_already[ mkdir_already_ct-1 ] = xstrdup (path);
770
771 /* Generate the text. */
772
773 quoted_path = quotearg_n_style (
774 QUOT_ID_PATH, shell_always_quoting_style, path);
775 fprintf (output, dir_check_z, quoted_path);
776 if (! HAVE_OPT(QUIET_UNSHAR))
777 {
778 fprintf (output, dir_create_z, quoted_path);
779 echo_status (aok_check_z, SM_x_dir_created, SM_x_no_dir, path, 1);
780 }
781 else
782 fprintf (output, " mkdir %s || exit 1\n", quoted_path);
783 fputs ("fi\n", output);
784 }
785
786 static void
clear_mkdir_already(void)787 clear_mkdir_already (void)
788 {
789 char** pp = mkdir_already;
790 int ct = mkdir_already_ct;
791
792 mkdir_already_ct = 0;
793 while (--ct >= 0)
794 {
795 free (*pp);
796 *(pp++) = NULL;
797 }
798 }
799
800 /*---.
801 | ? |
802 `---*/
803
804 static void
generate_mkdir_script(const char * path)805 generate_mkdir_script (const char * path)
806 {
807 char *cursor;
808
809 for (cursor = strchr (path, '/'); cursor; cursor = strchr (cursor + 1, '/'))
810 {
811
812 /* Avoid empty string if leading or double '/'. */
813
814 if (cursor == path || *(cursor - 1) == '/')
815 continue;
816
817 /* Omit '.'. */
818
819 if (cursor[-1] == '.' && (cursor == path + 1 || cursor[-2] == '/'))
820 continue;
821
822 /* Temporarily terminate string. FIXME! */
823
824 *cursor = 0;
825 generate_mkdir (path);
826 *cursor = '/';
827 }
828 }
829
830 /* Walking routines. */
831
832 /*---.
833 | ? |
834 `---*/
835
836 static int
check_accessibility(const char * local_name,const char * restore_name)837 check_accessibility (const char *local_name, const char *restore_name)
838 {
839 if (access (local_name, 4))
840 {
841 error (0, errno, _("Cannot access %s"), local_name);
842 return SHAR_EXIT_FILE_NOT_FOUND;
843 }
844
845 return SHAR_EXIT_SUCCESS;
846 }
847
848 /*---.
849 | ? |
850 `---*/
851
852 static int
generate_one_header_line(const char * local_name,const char * restore_name)853 generate_one_header_line (const char *local_name, const char *restore_name)
854 {
855 char buf[INT_BUFSIZE_BOUND (off_t)];
856 fprintf (output, "# %6s %s %s\n", offtostr (struct_stat.st_size, buf),
857 mode_string (struct_stat.st_mode), restore_name);
858 return 0;
859 }
860
861 static void
print_caution_notes(FILE * fp)862 print_caution_notes (FILE * fp)
863 {
864 {
865 char const * msg;
866
867 if (! HAVE_OPT(NO_CHECK_EXISTING))
868 msg = exist_keep_z;
869 else if (HAVE_OPT(QUERY_USER))
870 msg = exist_ask_z;
871 else
872 msg = exist_kill_z;
873
874 fprintf (fp, exist_note_z, msg);
875 }
876
877 if (HAVE_OPT(WHOLE_SIZE_LIMIT))
878 {
879 int len = snprintf (explain_text_fmt, sizeof (explain_text_fmt),
880 explain_fmt_fmt_z, explain_1_len, explain_2_len);
881 if ((unsigned)len >= sizeof (explain_text_fmt))
882 strcpy (explain_text_fmt, "#%-256s\n#%-256s\n");
883
884 /* May be split, provide for white space for an explanation. */
885
886 fputs ("#\n", output);
887 archive_type_position = ftello (output);
888 fprintf (fp, explain_text_fmt, "", "");
889 }
890 }
891
892 static void
print_header_stamp(FILE * fp)893 print_header_stamp (FILE * fp)
894 {
895 {
896 char const * pz = HAVE_OPT(ARCHIVE_NAME) ? OPT_ARG(ARCHIVE_NAME) : "";
897 char const * ch = HAVE_OPT(ARCHIVE_NAME) ? ", a shell" : "a shell";
898
899 fprintf (fp, file_leader_z, pz, ch, PACKAGE, VERSION, sharpid);
900 }
901
902 {
903 static char ftime_fmt[] = "%Y-%m-%d %H:%M %Z";
904
905 /*
906 * All fields are two characters, except %Y is four and
907 * %Z may be up to 30 (?!?!). Anyway, if that still fails,
908 * we'll drop back to "%z". We'll give up if that fails.
909 */
910 char buffer[sizeof (ftime_fmt) + 64];
911 time_t now;
912 struct tm * local_time;
913 time (&now);
914 local_time = localtime (&now);
915 {
916 size_t l =
917 strftime (buffer, sizeof (buffer) - 1, ftime_fmt, local_time);
918 if (l == 0)
919 {
920 ftime_fmt[sizeof(ftime_fmt) - 2] = 'z';
921 l = strftime (buffer, sizeof (buffer) - 1, ftime_fmt, local_time);
922 }
923 if (l > 0)
924 fprintf (fp, made_on_comment_z, buffer, OPT_ARG(SUBMITTER));
925 }
926 }
927
928 {
929 char * c_dir = xgetcwd ();
930 if (c_dir != NULL)
931 {
932 fprintf (fp, source_dir_comment_z, c_dir);
933 free (c_dir);
934 }
935 else
936 error (0, errno, _("Cannot get current directory name"));
937 }
938 }
939
940 /*---.
941 | ? |
942 `---*/
943
944 static void
generate_full_header(int argc,char * const * argv)945 generate_full_header (int argc, char * const * argv)
946 {
947 int counter;
948
949 for (counter = 0; counter < argc; counter++)
950 {
951 struct stat sb;
952 /* If we cannot stat it, it is either a valid option or we have
953 already errored out. */
954 if (stat (argv[counter], &sb) != 0)
955 continue;
956
957 if (walktree (check_accessibility, argv[counter]))
958 exit (SHAR_EXIT_FAILED);
959 }
960
961 if (HAVE_OPT(NET_HEADERS))
962 {
963 static char const by[] =
964 "Submitted-by: %s\nArchive-name: %s%s%02d\n\n";
965 bool has_slash = (strchr (OPT_ARG(ARCHIVE_NAME), '/') != NULL);
966 int part = (part_number > 0) ? part_number : 1;
967
968 fprintf (output, by, OPT_ARG(SUBMITTER), OPT_ARG(ARCHIVE_NAME),
969 has_slash ? "" : "/part", part);
970 }
971
972 if (HAVE_OPT(CUT_MARK))
973 fputs (cut_mark_line_z, output);
974
975 print_header_stamp (output);
976 print_caution_notes (output);
977 fputs (contents_z, output);
978
979 for (counter = 0; counter < argc; counter++)
980 {
981 struct stat sb;
982 /* If we cannot stat it, it is either a valid option or we have
983 already errored out. */
984 if (stat (argv[counter], &sb) != 0)
985 continue;
986
987 (void) walktree (generate_one_header_line, argv[counter]);
988 }
989 fputs ("#\n", output);
990
991 generate_configure ();
992 }
993
994 void
change_files(const char * restore_name,off_t * remaining_size)995 change_files (const char * restore_name, off_t * remaining_size)
996 {
997 /* Change to another file. */
998
999 DEBUG_PRINT ("New file, remaining %s, ", *remaining_size);
1000 DEBUG_PRINT ("Limit still %s\n", OPT_VALUE_WHOLE_SIZE_LIMIT);
1001
1002 /* Close the "&&" and report an error if any of the above
1003 failed. */
1004
1005 fputs (" :\n", output);
1006 echo_status ("test $? -ne 0", SM_restore_failed, NULL, restore_name, 0);
1007
1008 {
1009 size_t sz = strlen (SM_end_of_part) + 2 * LOG10_MAX_INT;
1010 char * bf = scribble_get (sz);
1011 snprintf (bf, sz, SM_end_of_part, part_number, part_number+1);
1012 fprintf (output, echo_string_z, bf);
1013 }
1014
1015 close_output (part_number + 1);
1016
1017 /* Clear mkdir_already in case the user unshars out of order. */
1018
1019 clear_mkdir_already ();
1020
1021 /* Form the next filename. */
1022
1023 open_output ();
1024 if (! HAVE_OPT(QUIET))
1025 fprintf (stderr, _("Starting file %s\n"), output_filename);
1026
1027 if (HAVE_OPT(NET_HEADERS))
1028 {
1029 fprintf (output, "Submitted-by: %s\n", OPT_ARG(SUBMITTER));
1030 fprintf (output, "Archive-name: %s%s%02d\n\n", OPT_ARG(ARCHIVE_NAME),
1031 strchr (OPT_ARG(ARCHIVE_NAME), '/') ? "" : "/part",
1032 part_number ? part_number : 1);
1033 }
1034
1035 if (HAVE_OPT(CUT_MARK))
1036 fputs (cut_mark_line_z, output);
1037
1038 {
1039 static const char part_z[] = "part %02d of %s ";
1040 char const * nm = HAVE_OPT(ARCHIVE_NAME) ? OPT_ARG(ARCHIVE_NAME) :
1041 "a multipart";
1042 off_t len = sizeof(part_z) + strlen(nm) + LOG10_MAX_INT;
1043 char * bf = scribble_get (len);
1044 snprintf (bf, len, part_z, part_number, nm);
1045 fprintf (output, file_leader_z, bf, "", PACKAGE, VERSION, sharpid);
1046 }
1047
1048 generate_configure ();
1049
1050 first_file_position = ftello (output);
1051 }
1052
1053 static void
read_byte_size(char * wc,size_t wc_sz,FILE * pfp)1054 read_byte_size (char * wc, size_t wc_sz, FILE * pfp)
1055 {
1056 char * pz = wc;
1057
1058 /* Read to the first digit or EOF */
1059 for (;;)
1060 {
1061 int ch = getc (pfp);
1062 if (ch == EOF)
1063 goto bogus_number; /* no digits were found */
1064
1065 if (isdigit (ch))
1066 {
1067 *(pz++) = ch;
1068 break;
1069 }
1070 }
1071
1072 for (;;)
1073 {
1074 int ch = getc (pfp);
1075 if (! isdigit (ch))
1076 break;
1077 *(pz++) = ch;
1078 if (pz >= wc + wc_sz)
1079 goto bogus_number; /* number is waaay too large */
1080 }
1081
1082 *pz = NUL;
1083 return;
1084
1085 bogus_number:
1086 wc[0] = '0'; /* assume zero length */
1087 wc[1] = NUL;
1088 }
1089
1090 /* Emit shell script text to validate the restored file size
1091 Validate the transferred file using simple 'wc' command. */
1092 static void
emit_char_ct_validation(char const * local_name,char const * quoted_name,char const * restore_name,int did_md5)1093 emit_char_ct_validation (
1094 char const * local_name,
1095 char const * quoted_name,
1096 char const * restore_name,
1097 int did_md5)
1098 {
1099 /* Shell command able to count characters from its standard input.
1100 We have to take care for the locale setting because wc in multi-byte
1101 character environments gets different results. */
1102
1103 char wc[1 + LOG10_MAX_INT * 2]; // enough for 64 bit size
1104 char * command;
1105
1106 #ifndef __MINGW32__
1107 static char const cct_cmd[] = "LC_ALL=C wc -c < %s";
1108 #else
1109 static char const cct_cmd[] = "set LC_ALL=C & wc -c \"%s\"";
1110 quoted_name = local_name;
1111 #endif
1112
1113 command = alloca (sizeof(cct_cmd) + strlen (quoted_name));
1114 sprintf (command, cct_cmd, quoted_name);
1115
1116 {
1117 FILE * pfp = popen (command, "r");
1118 if (pfp == NULL)
1119 die (SHAR_EXIT_FAILED, _("Could not popen command"), command);
1120
1121 /* Read from stdin white space followed by digits. That ought to be
1122 followed by a newline or a NUL. */
1123 read_byte_size (wc, sizeof(wc), pfp);
1124 pclose (pfp);
1125 }
1126
1127 if (did_md5)
1128 fputs (otherwise_z, output);
1129
1130 {
1131 size_t sz = strlen (SM_bad_size) + strlen (restore_name) + LOG10_MAX_INT;
1132 char * bf = scribble_get (sz);
1133 snprintf (bf, sz, SM_bad_size, restore_name, wc);
1134 fprintf (output, ck_chct_z, restore_name, wc, bf);
1135 }
1136 }
1137
1138 /**
1139 * Determine if file needs encoding. A file needs encoding if any byte
1140 * falls outside the range of 0x20 through 0x7E, plus tabs and newlines.
1141 * Also encode files that have lines that start with "From " because
1142 * mail handlers will often insert spurious ">" characters when found.
1143 * This function also pays attention of the --text-files and --uuencode
1144 * options, forcing the result to be 0 and 1 respectively.
1145 *
1146 * @param[in] fname input file name
1147 * @returns 0 if the file is a simple text file -- no encoding needed.
1148 * @returns 1 when the file must be encoded.
1149 */
1150 static do_uue_t
file_needs_encoding(char const * fname)1151 file_needs_encoding (char const * fname)
1152 {
1153 #ifdef __CHAR_UNSIGNED__
1154 # define BYTE_IS_BINARY(_ch) (byte_is_binary[_ch])
1155 #else
1156 # define BYTE_IS_BINARY(_ch) (byte_is_binary[(_ch) & 0xFF])
1157 #endif
1158
1159 FILE * infp;
1160 int line_length;
1161
1162 if (cmpr_state != NULL)
1163 return true; // compression always implies encoding
1164
1165 switch (WHICH_OPT_MIXED_UUENCODE) {
1166 case VALUE_OPT_TEXT_FILES: return false;
1167 case VALUE_OPT_UUENCODE: return true;
1168 default: break;
1169 }
1170
1171 /* Read the input file, seeking for one non-ASCII character. Considering the
1172 average file size, even reading the whole file (if it is text) would
1173 usually be faster than invoking 'file'. */
1174
1175 infp = fopen (fname, "r" FOPEN_BINARY);
1176
1177 if (infp == NULL)
1178 {
1179 error (0, errno, _("Cannot open file %s"), fname);
1180 return fail;
1181 }
1182
1183 /* Assume initially that the input file is text. Then try to prove
1184 it is binary by looking for binary characters or long lines. */
1185
1186 line_length = 0;
1187
1188 for (;;)
1189 {
1190 int ch = getc (infp);
1191
1192 retest_char:
1193 switch (ch) {
1194 case EOF: goto loop_done;
1195 case '\n': line_length = 0; break;
1196 case 'F':
1197 case 'f':
1198 if (line_length > 0)
1199 {
1200 line_length++;
1201 break;
1202 }
1203
1204 {
1205 /*
1206 * Mail handlers like to mutilate lines beginning with "from ".
1207 * Therefore, if a line starts with "From " or "from ", deem
1208 * the file to need encoding.
1209 */
1210 static char const from[] = "rom ";
1211 char const * p = from;
1212 for (;;)
1213 {
1214 line_length++;
1215 ch = getc (infp);
1216 if (ch != *p)
1217 goto retest_char;
1218 if (*++p == NUL)
1219 {
1220 line_length = MAXIMUM_NON_BINARY_LINE;
1221 goto loop_done;
1222 }
1223 }
1224 /* NOTREACHED */
1225 }
1226
1227 default:
1228 if (BYTE_IS_BINARY(ch))
1229 {
1230 line_length = MAXIMUM_NON_BINARY_LINE;
1231 goto loop_done;
1232 }
1233
1234 line_length++;
1235 } /* switch (ch) */
1236
1237 if (line_length >= MAXIMUM_NON_BINARY_LINE)
1238 break;
1239 } loop_done:;
1240
1241 fclose (infp);
1242
1243 /* Text files should terminate with an end of line. */
1244
1245 return (line_length != 0) ? true : false;
1246 #undef BYTE_IS_BINARY
1247 }
1248
1249 #ifdef HAVE_WORKING_FORK
1250
1251 static void
encode_file_to_pipe(int out_fd,const char * local_name,const char * q_local_name,const char * restore_name)1252 encode_file_to_pipe (
1253 int out_fd,
1254 const char * local_name,
1255 const char * q_local_name,
1256 const char * restore_name)
1257 {
1258 /* Start writing the pipe with encodes. */
1259
1260 FILE * in_fp;
1261 FILE * out_fp;
1262 char * cmdline = alloca (strlen (q_local_name) + 64);
1263 char const * open_txt = cmdline;
1264 char const * open_fmt = "popen";
1265
1266 if (cmpr_state != NULL)
1267 {
1268 sprintf (cmdline, cmpr_state->cmpr_cmd_fmt,
1269 cmpr_state->cmpr_level, q_local_name);
1270 in_fp = popen (cmdline, "r" FOPEN_BINARY);
1271 }
1272 else
1273 {
1274 in_fp = fopen (local_name, "r" FOPEN_BINARY);
1275 open_fmt = "fopen";
1276 open_txt = local_name;
1277 }
1278
1279 if (in_fp == NULL)
1280 fserr (SHAR_EXIT_FAILED, open_fmt, open_txt);
1281
1282 out_fp = fdopen (out_fd, "w" FOPEN_BINARY);
1283
1284 fprintf (out_fp, mode_fmt_z, restore_name);
1285
1286 copy_file_encoded (in_fp, out_fp);
1287 fprintf (out_fp, "end\n");
1288 if (cmpr_state != NULL)
1289 pclose (in_fp);
1290 else
1291 fclose (in_fp);
1292
1293 exit (EXIT_SUCCESS);
1294 }
1295
1296 static FILE *
open_encoded_file(char const * local_name,char const * q_local_name,const char * restore_name)1297 open_encoded_file (char const * local_name, char const * q_local_name,
1298 const char * restore_name)
1299 {
1300 int pipex[2];
1301
1302 /* Fork a uuencode process. */
1303
1304 if (pipe (pipex) < 0)
1305 fserr (SHAR_EXIT_FAILED, _("call"), "pipe(2)");
1306 fflush (output);
1307
1308 switch (fork ())
1309 {
1310 case 0:
1311 close (pipex[0]);
1312 encode_file_to_pipe (pipex[1], local_name, q_local_name, restore_name);
1313 /* NOTREACHED */
1314
1315 case -1:
1316 fserr (SHAR_EXIT_FAILED, _("call"), "fork");
1317 return NULL;
1318
1319 default:
1320 /* Parent, create a file to read. */
1321 break;
1322 }
1323 close (pipex[1]);
1324
1325 {
1326 FILE * fp = fdopen (pipex[0], "r" FOPEN_BINARY);
1327 if (fp == NULL)
1328 fserr (SHAR_EXIT_FAILED, "fdopen", _("pipe fd"));
1329 return fp;
1330 }
1331 }
1332
1333 #else /* ! HAVE_WORKING_FORK */
1334
1335 #ifdef __MINGW32__
1336 static char *
win_cmd_quote(char const * fname)1337 win_cmd_quote (char const * fname)
1338 {
1339 static size_t blen = 0;
1340 static char *buf = NULL;
1341 size_t nlen = strlen (fname);
1342 if (nlen + 3 > blen)
1343 {
1344 blen = nlen + 3;
1345 buf = buf ? malloc (blen) : realloc (buf, blen);
1346 if (buf == NULL)
1347 fserr (SHAR_EXIT_FAILED, "malloc", fname);
1348 }
1349 *buf = '"';
1350 memcpy (buf+1, fname, nlen);
1351 buf[nlen + 1] = '"';
1352 buf[nlen + 2] = NUL;
1353 }
1354
1355 static int
isatty(int fd)1356 isatty (int fd)
1357 {
1358 return (_isatty (fd) && _lseek (fd, SEEK_CUR, 0L) == -1);
1359 }
1360 #endif
1361
1362 static FILE *
open_encoded_file(char const * local_name,char const * q_local_name,char const * restore_name)1363 open_encoded_file (char const * local_name,
1364 char const * q_local_name,
1365 char const * restore_name)
1366 {
1367 char * cmdline, * p;
1368 static char uu_cmd_fmt[] = "uuencode %s";
1369 size_t sz = sizeof (uu_cmd_fmt);
1370 /* A command to use for encoding an uncompressed text file. */
1371 #ifdef __MINGW32__
1372 /* Windows needs a different style of quoting. */
1373 q_local_name = win_cmd_quote (local_name);
1374 restore_name = win_cmd_quote (restore_name);
1375 #else
1376 restore_name = quotearg_n_style (QUOT_ID_RNAME, shell_always_quoting_style,
1377 restore_name);
1378 #endif
1379
1380 sz += strlen (q_local_name) + strlen (restore_name);
1381
1382 if (cmpr_state == NULL)
1383 {
1384 p = cmdline = alloca (sz);
1385
1386 /* Insert the uuencode command. It will be reading from the
1387 original file, so append the name of the remote file. */
1388 sprintf (p, uu_cmd_fmt, q_local_name);
1389 strcat (strcat (p, " "), restore_name);
1390 }
1391 else
1392 {
1393 /* Before uuencoding the file, we compress it. The compressed output
1394 is piped into uuencode. */
1395 sz += strlen (cmpr_state->cmpr_cmd_fmt) + LOG10_MAX_INT;
1396
1397 p = cmdline = alloca (sz);
1398 sprintf (p, cmpr_state->cmpr_cmd_fmt, cmpr_state->cmpr_level,
1399 q_local_name);
1400 p += strlen (p);
1401 /* Append a pipe into uuencode. */
1402 strcat (p, " | ");
1403 p += strlen (p);
1404 sprintf (p, uu_cmd_fmt, restore_name);
1405 }
1406
1407 /* Don't use "r" FOPEN_BINARY mode because it might be "rb", while we need
1408 text-mode read here, because we will be reading pure text from
1409 uuencode, and we want to drop any CR characters from the CRLF
1410 line endings, when we write the result into the shar. */
1411 {
1412 FILE * in_fp = popen (cmdline, "r" FOPEN_TEXT);
1413
1414 if (in_fp == NULL)
1415 fserr (SHAR_EXIT_FAILED, "popen", cmdline);
1416
1417 return in_fp;
1418 }
1419 }
1420
1421 #endif /* HAVE_WORKING_FORK */
1422
1423 static FILE *
open_shar_input(const char * local_name,const char * q_local_name,const char * restore_name,const char * q_restore_name,const char ** file_type_p,const char ** file_type_remote_p,int * pipe_p)1424 open_shar_input (
1425 const char * local_name,
1426 const char * q_local_name,
1427 const char * restore_name,
1428 const char * q_restore_name,
1429 const char ** file_type_p,
1430 const char ** file_type_remote_p,
1431 int *pipe_p)
1432 {
1433 FILE * infp;
1434
1435 uuencode_file = file_needs_encoding (local_name);
1436 if (uuencode_file == fail)
1437 return NULL;
1438
1439 /* If mixed, determine the file type. */
1440
1441 if (! uuencode_file)
1442 {
1443 *file_type_p = _("text");
1444 *file_type_remote_p = SM_type_text;
1445
1446 infp = fopen (local_name, "r" FOPEN_BINARY);
1447 if (infp == NULL)
1448 fserr (SHAR_EXIT_FAILED, "fopen", local_name);
1449 *pipe_p = 0;
1450 }
1451 else
1452 {
1453 if (cmpr_state != NULL)
1454 *file_type_p = *file_type_remote_p = cmpr_state->cmpr_title;
1455 else
1456 {
1457 *file_type_p = _("text");
1458 *file_type_remote_p = _("(text)");
1459 }
1460
1461 infp = open_encoded_file (local_name, q_local_name, restore_name);
1462 *pipe_p = 1;
1463 }
1464
1465 return infp;
1466 }
1467
1468 /**
1469 * Change to another file.
1470 */
1471 static void
split_shar_ed_file(char const * restore,off_t * size_left,int * split_flag)1472 split_shar_ed_file (char const * restore, off_t * size_left, int * split_flag)
1473 {
1474 DEBUG_PRINT ("New file, remaining %s, ", (*size_left));
1475 DEBUG_PRINT ("Limit still %s\n", OPT_VALUE_WHOLE_SIZE_LIMIT);
1476
1477 fprintf (output, "%s\n", OPT_ARG(HERE_DELIMITER));
1478
1479 /* Close the "&&" and report an error if any of the above
1480 failed. */
1481
1482 fputs (" :\n", output);
1483 echo_status ("test $? -ne 0", SM_restore_failed, NULL, restore, 0);
1484
1485 if (! HAVE_OPT(NO_CHECK_EXISTING))
1486 fputs ("fi\n", output);
1487
1488 if (HAVE_OPT(QUIET_UNSHAR))
1489 {
1490 size_t sz = strlen (SM_end_of_part) + 2 * LOG10_MAX_INT;
1491 char * bf = scribble_get (sz);
1492 snprintf (bf, sz, SM_end_of_part, part_number, part_number + 1);
1493 fprintf (output, echo_string_z, bf);
1494 }
1495 else
1496 {
1497 char const * nm =
1498 HAVE_OPT(ARCHIVE_NAME) ? OPT_ARG(ARCHIVE_NAME) : SM_word_archive;
1499 size_t sz1 = strlen (SM_s_end_of_part) + strlen (nm) + LOG10_MAX_INT;
1500 size_t sz2 = strlen (SM_contin_in_part) + strlen (restore)
1501 + LOG10_MAX_INT;
1502 char * bf;
1503 if (sz1 < sz2)
1504 sz1 = sz2;
1505 bf = scribble_get (sz1);
1506 snprintf (bf, sz1, SM_s_end_of_part, nm, part_number);
1507 fprintf (output, echo_string_z, bf);
1508 snprintf (bf, sz1, SM_contin_in_part, restore, (long)part_number + 1);
1509 fprintf (output, echo_string_z, bf);
1510 }
1511
1512 fwrite (split_file_z, sizeof (split_file_z) - 1, 1, output);
1513
1514 if (part_number == 1)
1515 {
1516 /* Rewrite the info lines on the first header. */
1517
1518 fseeko (output, archive_type_position, SEEK_SET);
1519 fprintf (output, explain_text_fmt, explain_1_z, explain_2_z);
1520 fseeko (output, 0, SEEK_END);
1521 }
1522 close_output (part_number + 1);
1523
1524 /* Next! */
1525
1526 open_output ();
1527
1528 if (HAVE_OPT(NET_HEADERS))
1529 {
1530 fprintf (output, "Submitted-by: %s\n", OPT_ARG(SUBMITTER));
1531 fprintf (output, "Archive-name: %s%s%02d\n\n",
1532 OPT_ARG(ARCHIVE_NAME),
1533 strchr (OPT_ARG(ARCHIVE_NAME), '/') ? "" : "/part",
1534 part_number ? part_number : 1);
1535 }
1536
1537 if (HAVE_OPT(CUT_MARK))
1538 fputs (cut_mark_line_z, output);
1539
1540 fprintf (output, continue_archive_z,
1541 base_name (output_filename), part_number,
1542 HAVE_OPT(ARCHIVE_NAME)
1543 ? OPT_ARG(ARCHIVE_NAME) : "a multipart archive",
1544 restore, sharpid);
1545
1546 generate_configure ();
1547
1548 if (! HAVE_OPT(NO_CHECK_EXISTING))
1549 {
1550 if (HAVE_OPT(QUIET_UNSHAR))
1551 fputs (split_continue_quietly_z, output);
1552 else
1553 {
1554 fputs (split_continue_z, output);
1555 fprintf (output, SM_still_skipping, restore);
1556 fputs (otherwise_z, output);
1557 }
1558 }
1559
1560 if (! HAVE_OPT(QUIET))
1561 fprintf (stderr, _("Continuing file %s\n"), output_filename);
1562 if (! HAVE_OPT(QUIET_UNSHAR))
1563 echo_text (SM_continuing, restore, false);
1564
1565 fprintf (output, split_resume_z,
1566 line_prefix, OPT_ARG(HERE_DELIMITER),
1567 uuencode_file ? "${lock_dir}/uue" : restore);
1568
1569 (*size_left) = OPT_VALUE_WHOLE_SIZE_LIMIT - ftello (output);
1570 *split_flag = 1;
1571 }
1572
1573 static void
process_shar_input(FILE * input,off_t * size_left,int * split_flag,char const * restore,char const * q_restore)1574 process_shar_input (FILE * input, off_t * size_left, int * split_flag,
1575 char const * restore, char const * q_restore)
1576 {
1577 char * inbf = scribble_get (BUFSIZ);
1578
1579 if (uuencode_file && (cmpr_state != NULL))
1580 {
1581 char * p = fgets (inbf, BUFSIZ, input);
1582 char * e;
1583 if ((p == NULL) || (strncmp (p, mode_fmt_z, 6) != 0))
1584 return;
1585 /*
1586 * Find the start of the last token
1587 */
1588 e = p + strlen(p);
1589 while ( isspace (to_uchar (e[-1])) && (e > p)) e--;
1590 while (! isspace (to_uchar (e[-1])) && (e > p)) e--;
1591 fwrite (p, e - p, 1, output);
1592 fprintf (output, "_sh%05d/%s\n", (int)sharpid, cmpr_state->cmpr_mode);
1593 }
1594
1595 while (fgets (inbf, BUFSIZ, input))
1596 {
1597 /* Output a line and test the length. */
1598
1599 if (!HAVE_OPT(FORCE_PREFIX)
1600 && ISASCII (inbf[0])
1601 && IS_GRAPH (inbf[0])
1602
1603 /* Protect lines already starting with the prefix. */
1604 && inbf[0] != line_prefix
1605
1606 /* Old mail programs interpret ~ directives. */
1607 && inbf[0] != '~'
1608
1609 /* Avoid mailing lines which are just '.'. */
1610 && inbf[0] != '.'
1611
1612 #if STRNCMP_IS_FAST
1613 && strncmp (inbf, OPT_ARG(HERE_DELIMITER), here_delimiter_length)
1614
1615 /* unshar -e: avoid 'exit 0'. */
1616 && strncmp (inbf, "exit 0", 6)
1617
1618 /* Don't let mail prepend a '>'. */
1619 && strncmp (inbf, "From", 4)
1620 #else
1621 && (inbf[0] != OPT_ARG(HERE_DELIMITER)[0]
1622 || strncmp (inbf, OPT_ARG(HERE_DELIMITER),
1623 here_delimiter_length))
1624
1625 /* unshar -e: avoid 'exit 0'. */
1626 && (inbf[0] != 'e' || strncmp (inbf, "exit 0", 6))
1627
1628 /* Don't let mail prepend a '>'. */
1629 && (inbf[0] != 'F' || strncmp (inbf, "From", 4))
1630 #endif
1631 )
1632 fputs (inbf, output);
1633 else
1634 {
1635 fprintf (output, "%c%s", line_prefix, inbf);
1636 (*size_left)--;
1637 }
1638
1639 /* Try completing an incomplete line, but not if the incomplete
1640 line contains no character. This might occur with -T for
1641 incomplete files, or sometimes when switching to a new file. */
1642
1643 if (*inbf && inbf[strlen (inbf) - 1] != '\n')
1644 {
1645 putc ('\n', output);
1646 (*size_left)--;
1647 }
1648
1649 (*size_left) -= CRLF_STRLEN (inbf);
1650 if (WHICH_OPT_WHOLE_SIZE_LIMIT != VALUE_OPT_SPLIT_SIZE_LIMIT)
1651 continue;
1652
1653 if ((int)(*size_left) >= 0)
1654 continue;
1655 split_shar_ed_file (restore, size_left, split_flag);
1656 }
1657 }
1658
1659 static void
print_query_user(char const * rname)1660 print_query_user (char const * rname)
1661 {
1662 size_t rname_len = strlen (rname);
1663 size_t sz = strlen (SM_overwriting) + rname_len;
1664 char * str_a, * str_b;
1665
1666 str_a = scribble_get (sz);
1667 snprintf (str_a, sz, SM_overwriting, rname);
1668
1669 sz = strlen (SM_overwrite) + rname_len;
1670 str_b = scribble_get (sz);
1671 snprintf (str_b, sz, SM_overwrite, rname);
1672
1673 fprintf (output, query_user_z, str_a, str_b);
1674
1675 sz = strlen (SM_skipping) + rname_len;
1676 str_b = scribble_get (sz);
1677 snprintf (str_b, sz, SM_skipping, rname);
1678 fprintf (output, query_check_z, SM_extract_aborted, str_b, str_b);
1679 }
1680
1681 /* Prepare a shar script. */
1682
1683 static int
start_sharing_file(char const ** lnameq_p,char const ** rnameq_p,FILE ** fpp,off_t * size_left_p,int * pipe_p)1684 start_sharing_file (char const ** lnameq_p, char const ** rnameq_p,
1685 FILE ** fpp, off_t * size_left_p, int *pipe_p)
1686 {
1687 char const * lname = *lnameq_p;
1688 char const * rname = *rnameq_p;
1689 char const * file_type; /* text or binary */
1690 char const * file_type_remote; /* text or binary, avoiding locale */
1691
1692 /* Check to see that this is still a regular file and readable. */
1693
1694 if (!S_ISREG (struct_stat.st_mode & S_IFMT))
1695 {
1696 error (0, 0, _("%s: Not a regular file"), lname);
1697 return 0;
1698 }
1699 if (access (lname, R_OK))
1700 {
1701 error (0, 0, _("Cannot access %s"), lname);
1702 return 0;
1703 }
1704
1705 *lnameq_p =
1706 quotearg_n_style (QUOT_ID_LNAME, shell_always_quoting_style, lname);
1707 *rnameq_p =
1708 quotearg_n_style (QUOT_ID_RNAME, shell_always_quoting_style, rname);
1709
1710 /*
1711 * If file size is limited, either splitting files or not,
1712 * get the current output length. Switch files if we split on file
1713 * boundaries and there may not be enough space.
1714 */
1715 if (HAVE_OPT(WHOLE_SIZE_LIMIT))
1716 {
1717 off_t current_size = ftello (output);
1718 off_t encoded_size = 1024 + (uuencode_file
1719 ? (struct_stat.st_size + struct_stat.st_size / 3)
1720 : struct_stat.st_size);
1721
1722 *size_left_p = OPT_VALUE_WHOLE_SIZE_LIMIT - current_size;
1723 DEBUG_PRINT ("In shar: remaining size %s\n", *size_left_p);
1724
1725 if ( (WHICH_OPT_WHOLE_SIZE_LIMIT != VALUE_OPT_SPLIT_SIZE_LIMIT)
1726 && (current_size > first_file_position)
1727 && (encoded_size > *size_left_p))
1728 {
1729 change_files (*rnameq_p, size_left_p);
1730 current_size = ftello (output);
1731 *size_left_p = OPT_VALUE_WHOLE_SIZE_LIMIT - current_size;
1732 }
1733 }
1734
1735 else
1736 *size_left_p = ~0; /* give some value to the variable */
1737
1738 fprintf (output, break_line_z, rname);
1739
1740 generate_mkdir_script (rname);
1741
1742 if (struct_stat.st_size == 0)
1743 {
1744 file_type = _("empty");
1745 file_type_remote = SM_is_empty;
1746 *fpp = NULL; /* give some value to the variable */
1747 }
1748 else
1749 {
1750 *fpp = open_shar_input (lname, *lnameq_p, rname, *rnameq_p,
1751 &file_type, &file_type_remote, pipe_p);
1752 if (*fpp == NULL)
1753 return 0;
1754 }
1755
1756 /* Protect existing files. */
1757
1758 if (! HAVE_OPT(NO_CHECK_EXISTING))
1759 {
1760 fprintf (output, pre_exist_z, *rnameq_p);
1761
1762 if (HAVE_OPT(QUERY_USER))
1763 print_query_user (rname);
1764 else
1765 echo_text (SM_skip_exist, rname, false);
1766
1767 fputs (otherwise_z, output);
1768 }
1769
1770 if (! HAVE_OPT(QUIET))
1771 error (0, 0, _("Saving %s (%s)"), lname, file_type);
1772
1773 if (! HAVE_OPT(QUIET_UNSHAR))
1774 {
1775 size_t sz = strlen (SM_x_extracting)
1776 + strlen (rname) + strlen (file_type_remote);
1777 char * bf = scribble_get(sz);
1778 snprintf (bf, sz, SM_x_extracting, rname, file_type_remote);
1779 fprintf (output, echo_string_z, bf);
1780 }
1781
1782 return 1;
1783 }
1784
1785 static void
finish_sharing_file(const char * lname,const char * lname_q,const char * rname,const char * rname_q)1786 finish_sharing_file (const char * lname, const char * lname_q,
1787 const char * rname, const char * rname_q)
1788 {
1789 if (! HAVE_OPT(NO_TIMESTAMP))
1790 {
1791 struct tm * restore_time;
1792 /* Set the dates as they were. */
1793
1794 restore_time = localtime (&struct_stat.st_mtime);
1795 fprintf (output, shar_touch_z,
1796 (restore_time->tm_year + 1900) / 100,
1797 (restore_time->tm_year + 1900) % 100,
1798 restore_time->tm_mon + 1, restore_time->tm_mday,
1799 restore_time->tm_hour, restore_time->tm_min,
1800 restore_time->tm_sec, rname_q);
1801 }
1802
1803 if (HAVE_OPT(VANILLA_OPERATION))
1804 {
1805 /* Close the "&&" and report an error if any of the above
1806 failed. */
1807 fputs (":\n", output);
1808 echo_status ("test $? -ne 0", SM_restore_failed, NULL, rname, 0);
1809 }
1810
1811 else
1812 {
1813 unsigned char md5buffer[16];
1814 FILE *fp = NULL;
1815 int did_md5 = 0;
1816
1817 /* Set the permissions as they were. */
1818
1819 fprintf (output, SM_restore_mode,
1820 (unsigned) (struct_stat.st_mode & 0777), rname_q);
1821
1822 /* Report an error if any of the above failed. */
1823
1824 echo_status ("test $? -ne 0", SM_restore_failed, NULL, rname, 0);
1825
1826 if ( ! HAVE_OPT(NO_MD5_DIGEST)
1827 && (fp = fopen (lname, "r" FOPEN_BINARY)) != NULL
1828 && md5_stream (fp, md5buffer) == 0)
1829 {
1830 /* Validate the transferred file using 'md5sum' command. */
1831 size_t cnt;
1832 did_md5 = 1;
1833
1834 fprintf (output, md5test_z, rname_q,
1835 SM_md5_check_failed, OPT_ARG(HERE_DELIMITER));
1836
1837 for (cnt = 0; cnt < 16; ++cnt)
1838 fprintf (output, "%02x", md5buffer[cnt]);
1839
1840 fprintf (output, " %c%s\n%s\n",
1841 ' ', rname, OPT_ARG(HERE_DELIMITER));
1842 /* This ^^^ space is not necessarily a parameter now. But it
1843 is a flag for binary/text mode and will perhaps be used later. */
1844 }
1845
1846 if (fp != NULL)
1847 fclose (fp);
1848
1849 if (! HAVE_OPT(NO_CHARACTER_COUNT))
1850 emit_char_ct_validation (lname, lname_q, rname_q, did_md5);
1851
1852 if (did_md5)
1853 fputs (" fi\n", output);
1854 }
1855
1856 /* If the exists option is in place close the if. */
1857
1858 if (! HAVE_OPT(NO_CHECK_EXISTING))
1859 fputs ("fi\n", output);
1860 }
1861
1862 /*---.
1863 | ? |
1864 `---*/
1865
1866 static int
shar(const char * lname,const char * rname)1867 shar (const char * lname, const char * rname)
1868 {
1869 FILE * input;
1870 off_t size_left;
1871 int split_flag = 0; /* file split flag */
1872 char const * lname_q = lname;
1873 char const * rname_q = rname;
1874 int pipe_p;
1875
1876 scribble_free ();
1877
1878 if (! start_sharing_file (&lname_q, &rname_q, &input, &size_left, &pipe_p))
1879 return SHAR_EXIT_FAILED;
1880
1881 if (struct_stat.st_size == 0)
1882 {
1883 /* Just touch the file, or empty it if it exists. */
1884
1885 fprintf (output, " > %s &&\n", rname_q);
1886 }
1887
1888 else
1889 {
1890 /* Run sed for non-empty files. */
1891
1892 if (uuencode_file)
1893 {
1894
1895 /* Run sed through uudecode (via temp file if might get split). */
1896
1897 fprintf (output, " sed 's/^%c//' << '%s' ",
1898 line_prefix, OPT_ARG(HERE_DELIMITER));
1899 if (HAVE_OPT(NO_PIPING))
1900 fprintf (output, "> ${lock_dir}/uue &&\n");
1901 else
1902 fputs ("| uudecode &&\n", output);
1903 }
1904
1905 else
1906 {
1907 /* Just run it into the file. */
1908
1909 fprintf (output, " sed 's/^%c//' << '%s' > %s &&\n",
1910 line_prefix, OPT_ARG(HERE_DELIMITER), rname_q);
1911 }
1912
1913 process_shar_input (input, &size_left, &split_flag, rname, rname_q);
1914
1915 if (!pipe_p)
1916 fclose (input);
1917 else
1918 {
1919 #if HAVE_WORKING_FORK
1920 fclose (input);
1921 while (wait (NULL) >= 0)
1922 ;
1923 #else
1924 if (pclose (input))
1925 fserr (SHAR_EXIT_FAILED, _("call"), "pclose");
1926 #endif
1927 }
1928
1929 fprintf (output, "%s\n", OPT_ARG(HERE_DELIMITER));
1930 if (split_flag && ! HAVE_OPT(QUIET_UNSHAR))
1931 echo_text (SM_file_complete, rname, true);
1932
1933 /* If this file was uuencoded w/Split, decode it and drop the temp. */
1934
1935 if (uuencode_file && HAVE_OPT(NO_PIPING))
1936 {
1937 if (! HAVE_OPT(QUIET_UNSHAR))
1938 echo_text (SM_uudec_file, rname, true);
1939
1940 fwrite (shar_decode_z, sizeof (shar_decode_z) - 1, 1, output);
1941 }
1942
1943 /* If this file was compressed, uncompress it and drop the temp. */
1944 if (cmpr_state != NULL)
1945 {
1946 if (! HAVE_OPT(QUIET_UNSHAR))
1947 echo_text (cmpr_state->cmpr_unnote, rname, true);
1948 fprintf (output, cmpr_state->cmpr_unpack, rname_q);
1949 }
1950 }
1951
1952 finish_sharing_file (lname, lname_q, rname, rname_q);
1953
1954 return EXIT_SUCCESS;
1955 }
1956
1957 /**
1958 * Look over the base name for our output files. If it has a formatting
1959 * element in it, ensure that it is an integer format ("diouxX") and that
1960 * there is only one formatting element. Allow that element to consume
1961 * 128 bytes and allow all the remaining characters to consume 1 byte of
1962 * output. Allocate a buffer that large and set the global
1963 * output_filename to point to that buffer.
1964 *
1965 * Finally, if no formatting element was found in this base name string,
1966 * then append ".%02d" to the base name and point the --output-prefix
1967 * option argument to this new string.
1968 */
1969 static void
parse_output_base_name(char const * arg)1970 parse_output_base_name (char const * arg)
1971 {
1972 char * bad_fmt = _("Invalid format for output file names (%s): %s");
1973 int c;
1974 int hadarg = 0;
1975 char const *p;
1976 int base_name_len = 128;
1977
1978 for (p = arg ; (c = *p++) != 0; )
1979 {
1980 base_name_len++;
1981 if (c != '%')
1982 continue;
1983 c = *p++;
1984 if (c == '%')
1985 continue;
1986 if (hadarg)
1987 usage_message(bad_fmt, _("more than one format element"), arg);
1988
1989 while (c != 0 && strchr("#0+- 'I", c) != 0)
1990 c = *p++;
1991 if (c == 0)
1992 usage_message(bad_fmt, _("no conversion character"), arg);
1993
1994 if (c >= '0' && c <= '9')
1995 {
1996 long v;
1997 char const * skp;
1998 errno = 0;
1999 v = strtol((void *)(p-1), (void *)&skp, 10);
2000 if ((v == 0) || (v > 16) || (errno != 0))
2001 usage_message(bad_fmt, _("format is too wide"), arg);
2002 p = skp;
2003 c = *p++;
2004 base_name_len += v;
2005 }
2006 if (c == '.')
2007 {
2008 c = *p++;
2009 while (c != 0 && c >= '0' && c <= '9')
2010 c = *p++;
2011 }
2012 if (c == 0 || strchr("diouxX", c) == 0)
2013 usage_message(bad_fmt, _("invalid conversion character"), arg);
2014 hadarg = 1;
2015 }
2016 output_filename = xmalloc(base_name_len);
2017 if (! hadarg)
2018 {
2019 static char const sfx[] = ".%02d";
2020 size_t len = strlen (arg);
2021 char * fmt = xmalloc(len + sizeof (sfx));
2022 bool svd = initialization_done;
2023 memcpy (fmt, arg, len);
2024 memcpy (fmt + len, sfx, sizeof (sfx));
2025
2026 /* this is allowed to happen after initialization. */
2027 initialization_done = false;
2028 SET_OPT_OUTPUT_PREFIX(fmt);
2029 initialization_done = svd;
2030 }
2031 }
2032
2033 /**
2034 * Open the next output file, or die trying. The output-prefix argument
2035 * must have been specified and has been parsed to ensure it has exactly
2036 * one printf integer argument in it. (We append it, if necessary.)
2037 * "output_filename" is a buffer allocated by parse_output_base_name()
2038 * that is guaranteed large enough to format 100,000 output files.
2039 */
2040 static void
open_output(void)2041 open_output (void)
2042 {
2043 if (! HAVE_OPT(OUTPUT_PREFIX))
2044 {
2045 output = stdout;
2046 #ifdef __MINGW32__
2047 _setmode (fileno (stdout) , _O_BINARY);
2048 #endif
2049 return;
2050 }
2051
2052 if (output_filename == NULL)
2053 parse_output_base_name (OPT_ARG(OUTPUT_PREFIX));
2054 sprintf (output_filename, OPT_ARG(OUTPUT_PREFIX), ++part_number);
2055 output = fopen (output_filename, "w" FOPEN_BINARY);
2056
2057 if (output == NULL)
2058 fserr (SHAR_EXIT_FAILED, _("Opening"), output_filename);
2059 }
2060
2061 /**
2062 * Close the current output file, or die trying.
2063 */
2064 static void
close_output(int part)2065 close_output (int part)
2066 {
2067 if (part > 0)
2068 fprintf (output, "echo %d > ${lock_dir}/seq\n", part);
2069
2070 fputs ("exit 0\n", output);
2071
2072 if (fclose (output) != 0)
2073 fserr (SHAR_EXIT_FAILED, _("Closing"), output_filename);
2074 }
2075
2076 /**
2077 * Trim an input line. Remove trailing white space and return the first
2078 * non-whitespace character. Blank lines or lines starting with the hash
2079 * character ("#") cause NULL to be returned and are ignored.
2080 *
2081 * @param[in,out] pz string to trim
2082 * @returns the first non-blank character in "pz".
2083 */
2084 static char *
trim(char * pz)2085 trim (char * pz)
2086 {
2087 char * res;
2088 while (isspace (to_uchar (*pz))) pz++;
2089 switch (*pz)
2090 {
2091 case NUL:
2092 case '#':
2093 return NULL;
2094 }
2095 res = pz;
2096 pz += strlen (pz);
2097 while (isspace (to_uchar (pz[-1]))) pz--;
2098 *pz = NUL;
2099 return res;
2100 }
2101
2102 /**
2103 * Guess at a submitter email address. Get the current login name and
2104 * current host name and hope that that is reasonable.
2105 *
2106 * @returns an allocated string containing "login@thishostname".
2107 */
2108 static void
set_submitter(void)2109 set_submitter (void)
2110 {
2111 char * buffer;
2112 char * uname = getuser (getuid ());
2113 size_t len = strlen (uname);
2114 if (uname == NULL)
2115 fserr (SHAR_EXIT_FAILED, "getpwuid", "getuid()");
2116 buffer = xmalloc (len + 2 + HOST_NAME_MAX);
2117 memcpy (buffer, uname, len);
2118 buffer[len++] = '@';
2119 gethostname (buffer + len, HOST_NAME_MAX);
2120 SET_OPT_SUBMITTER(buffer);
2121 }
2122
2123 /**
2124 * post-option processing configuring. Verifies global state,
2125 * sets up reference tables and reads up the input list, as required.
2126 *
2127 * @param[in,out] argcp pointer to argument count
2128 * @param[in,out] argvp pointer to arg vector pointer
2129 */
2130 static void
configure_shar(int * argc_p,char *** argv_p)2131 configure_shar (int * argc_p, char *** argv_p)
2132 {
2133 line_prefix = (OPT_ARG(HERE_DELIMITER)[0] == DEFAULT_LINE_PREFIX_1
2134 ? DEFAULT_LINE_PREFIX_2
2135 : DEFAULT_LINE_PREFIX_1);
2136
2137 here_delimiter_length = strlen (OPT_ARG(HERE_DELIMITER));
2138 gzip_compaction.cmpr_level =
2139 xz_compaction.cmpr_level =
2140 bzip2_compaction.cmpr_level = DESC(LEVEL_OF_COMPRESSION).optArg.argInt;
2141 #ifdef HAVE_COMPRESS
2142 compress_compaction.cmpr_level = DESC(BITS_PER_CODE).optArg.argInt;
2143 #endif
2144
2145 /* Set defaults for unset options. */
2146 if (! HAVE_OPT(SUBMITTER))
2147 set_submitter ();
2148
2149 open_output ();
2150 if (isatty (fileno (output)) && isatty (STDERR_FILENO))
2151 {
2152 /*
2153 * Output is going to a TTY device, and so is stderr.
2154 * Redirect stderr to /dev/null in that case so that
2155 * the results are not cluttered with chatter.
2156 */
2157 FILE * fp = freopen ("/dev/null", "w" FOPEN_BINARY, stderr);
2158 if (fp != stderr)
2159 error (SHAR_EXIT_FAILED, errno,
2160 _("reopening stderr to /dev/null"));
2161 }
2162
2163 memset ((char *) byte_is_binary, 1, sizeof (byte_is_binary));
2164 /* \n ends an input line, and \v and \r disrupt the output */
2165 byte_is_binary['\b'] = 0; /* BS back space */
2166 byte_is_binary['\t'] = 0; /* HT horiz. tab */
2167 byte_is_binary['\f'] = 0; /* FF form feed */
2168 /* bytes 0x20 through and including 0x7E --> 0x7E - 0x20 + 1 */
2169 memset ((char *) byte_is_binary + 0x20, 0, 0x7F - 0x20);
2170
2171 /* Maybe read file list from standard input. */
2172
2173 if (HAVE_OPT(INPUT_FILE_LIST))
2174 {
2175 char ** list;
2176 int max_argc = 32;
2177 char * get_buf = scribble_get (BUFSIZ);
2178
2179 *argc_p = 0;
2180
2181 list = (char **) xmalloc (max_argc * sizeof (char *));
2182
2183 #ifdef __MINGW32__
2184 _setmode (fileno (stdin), _O_BINARY);
2185 #endif
2186
2187 for (;;)
2188 {
2189 char * pz = fgets (get_buf, BUFSIZ, stdin);
2190 if (pz == NULL)
2191 break;
2192
2193 pz = trim (pz);
2194 if (pz == NULL)
2195 continue;
2196
2197 if (*argc_p == max_argc)
2198 {
2199 max_argc += max_argc / 2;
2200 list = (char **) xrealloc (list, max_argc * sizeof (*list));
2201 }
2202
2203 list[(*argc_p)++] = xstrdup (pz);
2204 }
2205 *argv_p = list;
2206 opt_idx = 0;
2207 }
2208
2209 scribble_free ();
2210 /* Diagnose various usage errors. */
2211
2212 if (opt_idx >= *argc_p)
2213 usage_message (_("No input files"));
2214
2215 if (HAVE_OPT(WHOLE_SIZE_LIMIT))
2216 {
2217 if (OPT_VALUE_WHOLE_SIZE_LIMIT < 4096)
2218 OPT_VALUE_WHOLE_SIZE_LIMIT *= 1024;
2219 if (WHICH_OPT_WHOLE_SIZE_LIMIT == VALUE_OPT_SPLIT_SIZE_LIMIT)
2220 SET_OPT_NO_PIPING;
2221 }
2222
2223 /* Start making the archive file. */
2224
2225 generate_full_header (*argc_p - opt_idx, &(*argv_p)[opt_idx]);
2226
2227 if (HAVE_OPT(QUERY_USER))
2228 {
2229 if (HAVE_OPT(NET_HEADERS))
2230 error (0, 0, _("PLEASE avoid -X shars on Usenet or public networks"));
2231
2232 fputs ("shar_wish=\n", output);
2233 }
2234
2235 first_file_position = ftello (output);
2236 }
2237
2238 /**
2239 * Ensure intermixing is okay. Called for options that may be intermixed.
2240 * Verify that either we are still initializing or that intermixing has been
2241 * enabled.
2242 *
2243 * @param opts unused
2244 * @param od unused
2245 */
2246 void
check_intermixing(tOptions * opts,tOptDesc * od)2247 check_intermixing (tOptions * opts, tOptDesc * od)
2248 {
2249 (void)opts;
2250 (void)od;
2251
2252 if (initialization_done && ! HAVE_OPT(INTERMIX_TYPE))
2253 usage_message (
2254 _("The '%s' option may not be intermixed with file names\n\
2255 unless the --intermix-type option has been specified."), od->pz_Name);
2256 }
2257
2258 /**
2259 * Ensure we are initializing. Called for options that may not be
2260 * intermixed with input names.
2261 *
2262 * @param opts unused
2263 * @param od unused
2264 */
2265 void
validate_opt_context(tOptions * opts,tOptDesc * od)2266 validate_opt_context (tOptions * opts, tOptDesc * od)
2267 {
2268 (void)opts;
2269 (void)od;
2270
2271 if (initialization_done)
2272 usage_message(_("The '%s' option must appear before any file names"),
2273 od->pz_Name);
2274 }
2275
2276 /**
2277 * Some form of compaction has been requested.
2278 * Check for either "none" or one of the known compression types.
2279 * Sets the global variable \a cmpr_state to either NULL or
2280 * the correct element from the array of compactors.
2281 *
2282 * @param[in] opts program option descriptor
2283 * @param[in] od compaction option descriptor
2284 */
2285 void
set_compaction(tOptions * opts,tOptDesc * od)2286 set_compaction (tOptions * opts, tOptDesc * od)
2287 {
2288 char const * c_type = od->optArg.argString;
2289 int ix = 0;
2290
2291 (void)opts;
2292 (void)od;
2293
2294 check_intermixing (opts, od);
2295
2296 if (strcmp (c_type, "none") == 0)
2297 {
2298 cmpr_state = NULL;
2299 return;
2300 }
2301
2302 for (;;) {
2303 if (strcmp (c_type, compaction[ix]->cmpr_name) == 0)
2304 break;
2305 if (++ix >= compact_ct)
2306 {
2307 fprintf (stderr,
2308 _("invalid compaction type: %s\nthe known types are:\n"),
2309 c_type);
2310 for (ix = 0; ix < compact_ct; ix++)
2311 fprintf (stderr, "\t%s\n", compaction[ix]->cmpr_name);
2312 USAGE (SHAR_EXIT_OPTION_ERROR);
2313 }
2314 }
2315 cmpr_state = compaction[ix];
2316 }
2317
2318 /**
2319 * Do all configuring to be done. After this runs, only compaction and
2320 * encoding options may be intermixes with input names. And then only if
2321 * the --intermix-type option has been specified.
2322 *
2323 * @param[in,out] argcp pointer to argument count
2324 * @param[in,out] argvp pointer to arg vector pointer
2325 */
2326 static void
initialize(int * argcp,char *** argvp)2327 initialize(int * argcp, char *** argvp)
2328 {
2329 sharpid = (int) getpid ();
2330 setlocale (LC_ALL, "");
2331
2332 /* Set the text message domain. */
2333 bindtextdomain (PACKAGE, LOCALEDIR);
2334 textdomain (PACKAGE);
2335 scribble_init ();
2336
2337 opt_idx = optionProcess (&sharOptions, *argcp, *argvp);
2338 if (opt_idx == *argcp)
2339 {
2340 if (! HAVE_OPT(INPUT_FILE_LIST))
2341 SET_OPT_INPUT_FILE_LIST("-");
2342 }
2343 else
2344 {
2345 if (HAVE_OPT(INPUT_FILE_LIST) && (opt_idx != *argcp))
2346 usage_message(
2347 _("files on command line and --input-file-list specified"));
2348 }
2349
2350 init_shar_msg ();
2351 configure_shar (argcp, argvp);
2352 initialization_done = true;
2353 }
2354
2355 /**
2356 * Process a file hierarchy into a shell archive.
2357 */
2358
2359 int
main(int argc,char ** argv)2360 main (int argc, char ** argv)
2361 {
2362 shar_exit_code_t status = SHAR_EXIT_SUCCESS;
2363 initialize (&argc, &argv);
2364
2365 /* Process positional parameters and files. */
2366
2367 while (opt_idx < argc)
2368 {
2369 char * arg = argv[opt_idx++];
2370 struct stat sb;
2371 if (stat (arg, &sb) != 0)
2372 {
2373 if (HAVE_OPT(INTERMIX_TYPE) && (*arg == '-'))
2374 {
2375 while (*++arg == '-') ;
2376 optionLoadLine (&sharOptions, arg);
2377 }
2378 else
2379 error (0, errno, "%s", arg);
2380 continue;
2381 }
2382
2383 {
2384 shar_exit_code_t s = walktree (shar, arg);
2385 if (status == SHAR_EXIT_SUCCESS)
2386 status = s;
2387 }
2388 }
2389
2390 /* Delete the sequence file, if any. */
2391
2392 if (HAVE_OPT(WHOLE_SIZE_LIMIT) && part_number > 1)
2393 {
2394 fprintf (output, echo_string_z, SM_you_are_done);
2395 if (HAVE_OPT(QUIET))
2396 fprintf (stderr, _("Created %d files\n"), part_number);
2397 }
2398
2399 echo_status ("rm -fr ${lock_dir}", SM_x_rem_lock_dir, SM_x_no_rem_lock_dir,
2400 "${lock_dir}", 1);
2401
2402 close_output (0);
2403 scribble_deinit ();
2404 exit (status);
2405 }
2406 /*
2407 * Local Variables:
2408 * mode: C
2409 * c-file-style: "gnu"
2410 * indent-tabs-mode: nil
2411 * End:
2412 * end of shar.c */
2413