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)