mirror of
git://git.sv.gnu.org/coreutils.git
synced 2026-04-19 18:26:32 +02:00
cat: don’t trust st_size on /proc files
* src/cat.c (main): Improve test for when copying will exhaust the output device. Do not rely on st_size, which is unreliable in /proc. Use lseek instead; this is good enough here. * tests/cat/cat-self.sh: Test the relaxation of the heuristic for self-copying.
This commit is contained in:
31
src/cat.c
31
src/cat.c
@@ -645,9 +645,10 @@ main (int argc, char **argv)
|
||||
/* 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;
|
||||
@@ -701,17 +702,27 @@ main (int argc, char **argv)
|
||||
|
||||
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. */
|
||||
|
||||
@@ -30,4 +30,24 @@ echo y >doc.end || framework_failure_
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user