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