}
}
- /* Now deallocate the data. The effect of ftruncate on
- non-regular files is unspecified, so don't worry about any
- errors reported for them. */
+ /* Now deallocate the data. The effect of ftruncate is specified
+ on regular files and shared memory objects (also directories, but
+ they are not possible here); don't worry about errors reported
+ for other file types. */
+
if (flags->remove_file && ftruncate (fd, 0) != 0
- && S_ISREG (st.st_mode))
+ && (S_ISREG (st.st_mode) || S_TYPEISSHM (&st)))
{
error (0, errno, _("%s: error truncating"), qname);
ok = false;
return node;
}
-/* Return a stream for FILE, opened with mode HOW. A null FILE means
- standard output; HOW should be "w". When opening for input, "-"
+/* Return a pointer to stdout status, or NULL on failure. */
+
+static struct stat *
+get_outstatus (void)
+{
+ static int outstat_errno;
+ static struct stat outstat;
+ if (outstat_errno == 0)
+ outstat_errno = fstat (STDOUT_FILENO, &outstat) == 0 ? -1 : errno;
+ return outstat_errno < 0 ? &outstat : NULL;
+}
+
+/* Return a stream for FILE, opened with mode HOW. If HOW is "w",
+ the file is already open on standard output, and needs to be
+ truncated unless FILE is null. When opening for input, "-"
means standard input. To avoid confusion, do not return file
descriptors STDIN_FILENO, STDOUT_FILENO, or STDERR_FILENO when
opening an ordinary FILE. Return NULL if unsuccessful.
else if (*how == 'w')
{
if (file && ftruncate (STDOUT_FILENO, 0) != 0)
- die (SORT_FAILURE, errno, _("%s: error truncating"),
- quotef (file));
+ {
+ int ftruncate_errno = errno;
+ struct stat *outst = get_outstatus ();
+ if (!outst || S_ISREG (outst->st_mode) || S_TYPEISSHM (outst))
+ die (SORT_FAILURE, ftruncate_errno, _("%s: error truncating"),
+ quotef (file));
+ }
fp = stdout;
}
else
avoid_trashing_input (struct sortfile *files, size_t ntemps,
size_t nfiles, char const *outfile)
{
- bool got_outstat = false;
- struct stat outstat;
struct tempnode *tempcopy = NULL;
for (size_t i = ntemps; i < nfiles; i++)
same = true;
else
{
- if (! got_outstat)
- {
- if (fstat (STDOUT_FILENO, &outstat) != 0)
- break;
- got_outstat = true;
- }
+ struct stat *outst = get_outstatus ();
+ if (!outst)
+ break;
same = (((is_stdin
? fstat (STDIN_FILENO, &instat)
: stat (files[i].name, &instat))
== 0)
- && SAME_INODE (instat, outstat));
+ && SAME_INODE (instat, *outst));
}
if (same)
if (SAME_INODE (in_stat_buf, out_stat_buf))
die (EXIT_FAILURE, 0, _("%s would overwrite input; aborting"),
quoteaf (name));
- if (ftruncate (fd, 0) != 0)
+ if (ftruncate (fd, 0) != 0
+ && (S_ISREG (out_stat_buf.st_mode) || S_TYPEISSHM (&out_stat_buf)))
die (EXIT_FAILURE, errno, _("%s: error truncating"), quotef (name));
return fd;