/* Optimal size of i/o operations of output. */
idx_t outsize = io_blksize (&stat_buf);
- /* Device and I-node number of the output. */
+ /* Device, I-node number and lazily-acquired flags of the output. */
dev_t out_dev = stat_buf.st_dev;
ino_t out_ino = stat_buf.st_ino;
+ int out_flags = -2;
/* True if the output is a regular file. */
bool out_isreg = S_ISREG (stat_buf.st_mode) != 0;
fdadvise (input_desc, 0, 0, FADVISE_SEQUENTIAL);
- /* Don't copy a nonempty regular file to itself, as that would
- merely exhaust the output device. It's better to catch this
- error earlier rather than later. */
+ /* Don't copy a file to itself if that would merely exhaust the
+ output device. It's better to catch this error earlier
+ rather than later. */
- if (out_isreg
- && stat_buf.st_dev == out_dev && stat_buf.st_ino == out_ino
- && lseek (input_desc, 0, SEEK_CUR) < stat_buf.st_size)
+ if (stat_buf.st_dev == out_dev && stat_buf.st_ino == out_ino)
{
- error (0, 0, _("%s: input file is output file"), quotef (infile));
- ok = false;
- goto contin;
+ if (out_flags < -1)
+ out_flags = fcntl (STDOUT_FILENO, F_GETFL);
+ bool exhausting = 0 <= out_flags && out_flags & O_APPEND;
+ if (!exhausting)
+ {
+ off_t in_pos = lseek (input_desc, 0, SEEK_CUR);
+ if (0 <= in_pos)
+ exhausting = in_pos < lseek (STDOUT_FILENO, 0, SEEK_CUR);
+ }
+ if (exhausting)
+ {
+ error (0, 0, _("%s: input file is output file"), quotef (infile));
+ ok = false;
+ goto contin;
+ }
}
/* Pointer to the input buffer. */
cat doc doc.end >doc || fail=1
compare doc doc.end || fail=1
+# This terminates even though it copies a file to itself.
+# Coreutils 9.5 and earlier rejected this.
+echo x >fx || framework_failure_
+echo y >fy || framework_failure_
+cat fx fy >fxy || fail=1
+for i in 1 2; do
+ cat fx >fxy$i || fail=1
+done
+for i in 3 4 5 6; do
+ cat fx >fx$i || fail=1
+done
+cat - fy <fxy1 1<>fxy1 || fail=1
+compare fxy fxy1 || fail=1
+cat fxy2 fy 1<>fxy2 || fail=1
+compare fxy fxy2 || fail=1
+returns_ 1 cat fx fx3 1<>fx3 || fail=1
+returns_ 1 cat - fx4 <fx 1<>fx4 || fail=1
+returns_ 1 cat fx5 >>fx5 || fail=1
+returns_ 1 cat <fx6 >>fx6 || fail=1
+
Exit $fail