I ran into this problem when using Texinfo 5.2 to install GNU Emacs into a destination directory whose file name contained spaces. The shell command:

install-info --info-dir="/d/a b/info" "/d/a b/info/emacs.info.gz"

failed with the diagnostic "sh: /d/a: No such file or directory".

I'm attaching a proposed patch.
Index: ChangeLog
===================================================================
--- ChangeLog   (revision 5412)
+++ ChangeLog   (working copy)
@@ -1,3 +1,13 @@
+2014-02-14  Paul Eggert  <[email protected]>
+
+       * install-info/install-info.c (open_possibly_compressed_file):
+       Work even if the file name contains arbitrary shell
+       metacharacters.  Do this by running the decompressor on standard
+       input, rather than by having the shell open the file.
+       Return either stdin or a pipe.
+       Don't bother with IS_PIPE arg; no longer needed.
+       All callers changed.  Check for freopen failure.
+
 2014-02-09  Karl Berry  <[email protected]>
 
        * doc/texinfo.tex (\cartouche): do not do \nonarrowing at all;
Index: install-info/install-info.c
===================================================================
--- install-info/install-info.c (revision 5412)
+++ install-info/install-info.c (working copy)
@@ -667,13 +667,15 @@
    If we do open it, return the actual name of the file opened in
    OPENED_FILENAME and the compress program to use to (de)compress it in
    COMPRESSION_PROGRAM.  The compression program is determined by the
+   magic number, not the filename.
    
-   MAGIC number, not the filename.  */
+   Return either stdin reading the file, or a non-stdin pipe reading
+   the output of the compression program.  */
 
 FILE *
 open_possibly_compressed_file (char *filename,
     void (*create_callback) (char *),
-    char **opened_filename, char **compression_program, int *is_pipe)
+    char **opened_filename, char **compression_program)
 {
   char *local_opened_filename, *local_compression_program;
   int nread;
@@ -686,35 +688,35 @@
     opened_filename = &local_opened_filename;
 
   *opened_filename = filename;
-  f = fopen (*opened_filename, FOPEN_RBIN);
+  f = freopen (*opened_filename, FOPEN_RBIN, stdin);
   if (!f)
     {
       *opened_filename = concat (filename, ".gz", "");
-      f = fopen (*opened_filename, FOPEN_RBIN);
+      f = freopen (*opened_filename, FOPEN_RBIN, stdin);
     }
   if (!f)
     {
       free (*opened_filename);
       *opened_filename = concat (filename, ".xz", "");
-      f = fopen (*opened_filename, FOPEN_RBIN);
+      f = freopen (*opened_filename, FOPEN_RBIN, stdin);
     }
   if (!f)
     {
       free (*opened_filename);
       *opened_filename = concat (filename, ".bz2", "");
-      f = fopen (*opened_filename, FOPEN_RBIN);
+      f = freopen (*opened_filename, FOPEN_RBIN, stdin);
     }
   if (!f)
     {
       free (*opened_filename);
       *opened_filename = concat (filename, ".lz", "");
-      f = fopen (*opened_filename, FOPEN_RBIN);
+      f = freopen (*opened_filename, FOPEN_RBIN, stdin);
     }
   if (!f)
     {
      free (*opened_filename);
      *opened_filename = concat (filename, ".lzma", "");
-     f = fopen (*opened_filename, FOPEN_RBIN);
+     f = freopen (*opened_filename, FOPEN_RBIN, stdin);
     }
 #ifdef __MSDOS__
   if (!f)
@@ -721,13 +723,13 @@
     {
       free (*opened_filename);
       *opened_filename = concat (filename, ".igz", "");
-      f = fopen (*opened_filename, FOPEN_RBIN);
+      f = freopen (*opened_filename, FOPEN_RBIN, stdin);
     }
   if (!f)
     {
       free (*opened_filename);
       *opened_filename = concat (filename, ".inz", "");
-      f = fopen (*opened_filename, FOPEN_RBIN);
+      f = freopen (*opened_filename, FOPEN_RBIN, stdin);
     }
 #endif /* __MSDOS__ */
    if (!f)
@@ -739,7 +741,7 @@
            /* And try opening it again.  */
            free (*opened_filename);
            *opened_filename = filename;
-           f = fopen (*opened_filename, FOPEN_RBIN);
+           f = freopen (*opened_filename, FOPEN_RBIN, stdin);
            if (!f)
              pfatal_with_name (filename);
          }
@@ -819,27 +821,26 @@
   else
     *compression_program = NULL;
 
+  /* Seek back over the magic bytes.  */
+  if (fseek (f, 0, 0) < 0)
+    pfatal_with_name (*opened_filename);
+
   if (*compression_program)
-    { /* It's compressed, so fclose the file and then open a pipe.  */
-      char *command = concat (*compression_program," -cd <", *opened_filename);
-      if (fclose (f) < 0)
-        pfatal_with_name (*opened_filename);
+    { /* It's compressed, so open a pipe.  */
+      char *command = concat (*compression_program, " -d", "");
       f = popen (command, "r");
-      if (f)
-        *is_pipe = 1;
-      else
+      if (! f)
         pfatal_with_name (command);
     }
   else
-    { /* It's a plain file, seek back over the magic bytes.  */
-      if (fseek (f, 0, 0) < 0)
-        pfatal_with_name (*opened_filename);
+    {
 #if O_BINARY
       /* Since this is a text file, and we opened it in binary mode,
          switch back to text mode.  */
       f = freopen (*opened_filename, "r", f);
+      if (! f)
+       pfatal_with_name (*opened_filename);
 #endif
-      *is_pipe = 0;
     }
 
   return f;
@@ -860,7 +861,6 @@
 {
   char *real_name;
   FILE *f;
-  int pipe_p;
   int filled = 0;
   int data_size = 8192;
   char *data = xmalloc (data_size);
@@ -869,7 +869,7 @@
   f = open_possibly_compressed_file (filename, create_callback,
                                      opened_filename ? opened_filename
                                                      : &real_name,
-                                     compression_program, &pipe_p);
+                                     compression_program);
 
   for (;;)
     {
@@ -892,10 +892,8 @@
   /* We need to close the stream, since on some systems the pipe created
      by popen is simulated by a temporary file which only gets removed
      inside pclose.  */
-  if (pipe_p)
+  if (f != stdin)
     pclose (f);
-  else
-    fclose (f);
 
   *sizep = filled;
   return data;
@@ -1906,6 +1904,12 @@
   bindtextdomain (PACKAGE, LOCALEDIR);
   textdomain (PACKAGE);
 
+  /* Make sure standard input can be freopened at will.  Otherwise,
+     when stdin starts off closed, bad things could happen if a plain fopen
+     returns stdin before open_possibly_compressed_file freopens it.  */
+  if (! freopen (NULL_DEVICE, "r", stdin))
+    pfatal_with_name (NULL_DEVICE);
+
   munge_old_style_debian_options (argc, argv, &argc, &argv);
 
   while (1)

Reply via email to