Change offset in fdopen only if setting O_APPEND

fdopen should only be allowed to change the offset in the file it
attaches to if it is setting O_APPEND.  If O_APPEND is already set, it
should not change the state of the handle.
This commit is contained in:
Siddhesh Poyarekar 2014-03-17 18:42:53 +05:30
parent ea33158c96
commit ae42bbc55a
3 changed files with 71 additions and 4 deletions

View File

@ -1,5 +1,10 @@
2014-03-17 Siddhesh Poyarekar <siddhesh@redhat.com>
* libio/iofdopen.c (_IO_new_fdopen): Seek to end only if
setting O_APPEND.
* libio/tst-ftell-active-handler.c (do_append_test): Add a
test case.
[BZ #16680]
* libio/fileops.c (_IO_file_open): Seek to end of file but
don't cache the offset.

View File

@ -59,6 +59,11 @@ _IO_new_fdopen (fd, mode)
int i;
int use_mmap = 0;
/* Decide whether we modify the offset of the file we attach to and seek to
the end of file. We only do this if the mode is 'a' and if the file
descriptor did not have O_APPEND in its flags already. */
bool do_seek = false;
switch (*mode)
{
case 'r':
@ -128,6 +133,7 @@ _IO_new_fdopen (fd, mode)
*/
if ((posix_mode & O_APPEND) && !(fd_flags & O_APPEND))
{
do_seek = true;
#ifdef F_SETFL
if (_IO_fcntl (fd, F_SETFL, fd_flags | O_APPEND) == -1)
#endif
@ -167,10 +173,11 @@ _IO_new_fdopen (fd, mode)
_IO_mask_flags (&new_f->fp.file, read_write,
_IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING);
/* For append mode, set the file offset to the end of the file. Don't
update the offset cache though, since the file handle is not active. */
if ((read_write & (_IO_IS_APPENDING | _IO_NO_READS))
== (_IO_IS_APPENDING | _IO_NO_READS))
/* For append mode, set the file offset to the end of the file if we added
O_APPEND to the file descriptor flags. Don't update the offset cache
though, since the file handle is not active. */
if (do_seek && ((read_write & (_IO_IS_APPENDING | _IO_NO_READS))
== (_IO_IS_APPENDING | _IO_NO_READS)))
{
_IO_off64_t new_pos = _IO_SYSSEEK (&new_f->fp.file, 0, _IO_seek_end);
if (new_pos == _IO_pos_BAD && errno != ESPIPE)

View File

@ -414,6 +414,61 @@ do_append_test (const char *filename)
}
}
/* For fdopen in 'a' mode, the file descriptor should not change if the file
is already open with the O_APPEND flag set. */
fd = open (filename, O_WRONLY | O_APPEND, 0);
if (fd == -1)
{
printf ("open(O_APPEND) failed: %m\n");
return 1;
}
off_t seek_ret = lseek (fd, file_len - 1, SEEK_SET);
if (seek_ret == -1)
{
printf ("lseek[O_APPEND][0] failed: %m\n");
ret |= 1;
}
fp = fdopen (fd, "a");
if (fp == NULL)
{
printf ("fdopen(O_APPEND) failed: %m\n");
close (fd);
return 1;
}
off_t new_seek_ret = lseek (fd, 0, SEEK_CUR);
if (seek_ret == -1)
{
printf ("lseek[O_APPEND][1] failed: %m\n");
ret |= 1;
}
printf ("\tappend: fdopen (file, \"a\"): O_APPEND: ");
if (seek_ret != new_seek_ret)
{
printf ("incorrectly modified file offset to %ld, should be %ld",
new_seek_ret, seek_ret);
ret |= 1;
}
else
printf ("retained current file offset %ld", seek_ret);
new_seek_ret = ftello (fp);
if (seek_ret != new_seek_ret)
{
printf (", ftello reported incorrect offset %ld, should be %ld\n",
new_seek_ret, seek_ret);
ret |= 1;
}
else
printf (", ftello reported correct offset %ld\n", seek_ret);
fclose (fp);
return ret;
}