summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/sort.c82
1 files changed, 52 insertions, 30 deletions
diff --git a/src/sort.c b/src/sort.c
index 0ae7c9938..c6ffbc4d3 100644
--- a/src/sort.c
+++ b/src/sort.c
@@ -225,8 +225,17 @@ static int const linelength = 30;
/* Maximum number of elements for the array(s) of struct line's, in bytes. */
#define LINEALLOC (SORTALLOC / 2)
-/* Directory in which any temporary files are to be created. */
-static char *temp_dir;
+/* Array of directory names in which any temporary files are to be created. */
+static char const **temp_dirs;
+
+/* Number of temporary directory names used. */
+static size_t temp_dir_count;
+
+/* Number of allocated slots in temp_dirs. */
+static size_t temp_dir_alloc;
+
+/* Our process ID. */
+static pid_t process_id;
/* Flag to reverse the order of all comparisons. */
static int reverse;
@@ -286,6 +295,7 @@ Write sorted concatenation of all FILE(s) to standard output.\n\
-s stabilize sort by disabling last resort comparison\n\
-t SEP use SEParator instead of non- to whitespace transition\n\
-T DIRECTORY use DIRECTORY for temporary files, not $TMPDIR or %s\n\
+ multiple -T options specify multiple directories\n\
-u with -c, check for strict ordering;\n\
with -m, only output the first of an equal sequence\n\
-z end lines with 0 byte, not newline, for find -print0\n\
@@ -412,37 +422,46 @@ write_bytes (const char *buf, size_t n_bytes, FILE *fp, const char *output_file)
}
}
+/* Append DIR to the array of temporary directory names. */
+static void
+add_temp_dir (char const *dir)
+{
+ if (temp_dir_count == temp_dir_alloc)
+ {
+ temp_dir_alloc = temp_dir_alloc ? temp_dir_alloc * 2 : 16;
+ temp_dirs = xrealloc (temp_dirs, sizeof (temp_dirs) * temp_dir_alloc);
+ }
+
+ temp_dirs[temp_dir_count++] = dir;
+}
+
/* Return a name for a temporary file. */
static char *
tempname (void)
{
- static unsigned int seq;
- int len = strlen (temp_dir);
- char *name = xmalloc (len + 1 + sizeof ("sort") - 1 + 5 + 5 + 1);
+ static unsigned long sequence_number;
+
+ unsigned long seq = sequence_number++;
+ unsigned long pid = process_id;
+ char const *temp_dir = temp_dirs[seq % temp_dir_count];
+ size_t len = strlen (temp_dir);
+ char const *slash = "/" + (len == 0 || temp_dir[len - 1] == '/');
+ char *name = xmalloc (len + 1 + sizeof "sort" - 1
+ + sizeof pid * CHAR_BIT / 3 + 1
+ + sizeof seq * CHAR_BIT / 3 + 1);
int long_file_names = NAME_MAX_IN_DIR (temp_dir) > 12;
struct tempnode *node;
- /* If long filenames aren't supported, we cannot use filenames
- longer than 8+3 and still assume they are unique. */
if (long_file_names)
- sprintf (name,
- "%s%ssort%5.5d%5.5d",
- temp_dir,
- (len && temp_dir[len - 1] != '/') ? "/" : "",
- (unsigned int) getpid () & 0xffff, seq);
+ sprintf (name, "%s%ssort%lu.%.5lu", temp_dir, slash, pid, seq);
else
- sprintf (name, "%s%ss%5.5d%2.2d.%3.3d",
- temp_dir,
- (len && temp_dir[len - 1] != '/') ? "/" : "",
- (unsigned int) getpid () & 0xffff, seq / 1000, seq % 1000);
-
- ++seq;
-
- /* Make sure that SEQ's value fits in 5 digits if temp_dir is on
- an 8.3 filesystem. */
- if (!long_file_names && seq >= 100000)
- seq = 0;
+ {
+ /* Make sure the file name is safe for an 8.3 filesystem. */
+ sprintf (name, "%s%ss%.5d%.2d.%.3d", temp_dir, slash,
+ (int) (pid % 100000), (int) (seq / 1000 % 100),
+ (int) (seq % 1000));
+ }
node = (struct tempnode *) xmalloc (sizeof (struct tempnode));
node->name = name;
@@ -1779,7 +1798,7 @@ sighandler (int sig)
signal (sig, SIG_DFL);
#endif
cleanup ();
- kill (getpid (), sig);
+ kill (process_id, sig);
}
/* Set the ordering options for KEY specified in S.
@@ -1851,6 +1870,7 @@ main (int argc, char **argv)
#endif
program_name = argv[0];
+ process_id = getpid ();
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
@@ -1890,10 +1910,6 @@ main (int argc, char **argv)
have_read_stdin = 0;
inittables ();
- temp_dir = getenv ("TMPDIR");
- if (temp_dir == NULL)
- temp_dir = DEFAULT_TMPDIR;
-
/* Change the way xmalloc and xrealloc fail. */
xalloc_exit_failure = SORT_FAILURE;
xalloc_fail_func = cleanup;
@@ -2146,11 +2162,11 @@ but lacks following character offset"));
break;
case 'T':
if (s[1])
- temp_dir = ++s;
+ add_temp_dir (++s);
else
{
if (i < argc - 1)
- temp_dir = argv[++i];
+ add_temp_dir (argv[++i]);
else
error (SORT_FAILURE, 0,
_("option `-T' requires an argument"));
@@ -2208,6 +2224,12 @@ but lacks following character offset"));
insertkey (&gkey);
reverse = gkey.reverse;
+ if (temp_dir_count == 0)
+ {
+ char const *t = getenv ("TMPDIR");
+ add_temp_dir (t ? t : DEFAULT_TMPDIR);
+ }
+
if (nfiles == 0)
{
nfiles = 1;