diff options
-rw-r--r-- | src/sort.c | 83 | ||||
-rw-r--r-- | src/tr.c | 5 |
2 files changed, 56 insertions, 32 deletions
diff --git a/src/sort.c b/src/sort.c index eb34c32d5..ae28518b3 100644 --- a/src/sort.c +++ b/src/sort.c @@ -19,16 +19,7 @@ The author may be reached (Email) at the address mike@gnu.ai.mit.edu, or (US mail) as Mike Haertel c/o Free Software Foundation. */ -#ifdef HAVE_CONFIG_H -#if defined (CONFIG_BROKETS) -/* We use <config.h> instead of "config.h" so that a compilation - using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h - (which it would do because it found this file in $srcdir). */ #include <config.h> -#else -#include "config.h" -#endif -#endif /* Get isblank from GNU libc. */ #define _GNU_SOURCE @@ -38,6 +29,7 @@ #include <stdio.h> #include "system.h" #include "long-options.h" +#include "safe-stat.h" #ifdef _POSIX_VERSION #include <limits.h> @@ -1732,32 +1724,61 @@ main (argc, argv) if (strcmp (outfile, "-")) { - for (i = 0; i < nfiles; ++i) - if (!strcmp (outfile, files[i])) - break; - if (i == nfiles) - ofp = xfopen (outfile, "w"); - else + struct stat outstat; + if (SAFE_STAT (outfile, &outstat) == 0) { - char buf[8192]; - FILE *fp = xfopen (outfile, "r"); - int cc; - - tmp = tempname (); - ofp = xfopen (tmp, "w"); - while ((cc = fread (buf, 1, sizeof buf, fp)) > 0) - xfwrite (buf, 1, cc, ofp); - if (ferror (fp)) + /* The following code prevents a race condition when + people use the brain dead shell programming idiom: + cat file | sort -o file + This feature is provided for historical compatibility, + but we strongly discourage ever relying on this in + new shell programs. */ + + /* Temporarily copy each input file that might be another name + for the output file. When in doubt (e.g. a pipe), copy. */ + for (i = 0; i < nfiles; ++i) { - error (0, errno, "%s", outfile); - cleanup (); - exit (2); + char buf[8192]; + FILE *fp; + int cc; + + if (S_ISREG (outstat.st_mode) && strcmp (outfile, files[i])) + { + struct stat instat; + if ((strcmp (files[i], "-") + ? SAFE_STAT (files[i], &instat) + : fstat (fileno (stdin), &instat)) != 0) + { + error (0, errno, "%s", files[i]); + cleanup (); + exit (2); + } + if (S_ISREG (instat.st_mode) + && (instat.st_ino != outstat.st_ino + || instat.st_dev != outstat.st_dev)) + { + /* We know the files are distinct. */ + continue; + } + } + + fp = xfopen (files[i], "r"); + tmp = tempname (); + ofp = xfopen (tmp, "w"); + while ((cc = fread (buf, 1, sizeof buf, fp)) > 0) + xfwrite (buf, 1, cc, ofp); + if (ferror (fp)) + { + error (0, errno, "%s", files[i]); + cleanup (); + exit (2); + } + xfclose (ofp); + xfclose (fp); + files[i] = tmp; } - xfclose (ofp); - xfclose (fp); - files[i] = tmp; - ofp = xfopen (outfile, "w"); } + ofp = xfopen (outfile, "w"); } else ofp = stdout; @@ -343,7 +343,7 @@ Usage: %s [OPTION]... SET1 [SET2]\n\ SETs are specified as strings of characters. Most represent\n\ themselves. Here are the special writings:\n\ \n\ - \\NNN character with octal value NNN (1 to 3 digits)\n\ + \\NNN character with octal value NNN (1 to 3 octal digits)\n\ \\\\ backslash\n\ \\a audible BEL\n\ \\b backspace\n\ @@ -1798,6 +1798,9 @@ deleting and squeezing repeats"); without squeezing repeats"); } + if (squeeze_repeats && non_option_args == 0) + error (1, 0, "at least one string must be given when squeezing repeats"); + spec_init (s1); if (parse_str ((unsigned char *) argv[optind], s1)) exit (1); |