From ae42bbc55a9e05976269026ddabcfb917f6e922f Mon Sep 17 00:00:00 2001 From: Siddhesh Poyarekar Date: Mon, 17 Mar 2014 18:42:53 +0530 Subject: [PATCH] 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. --- ChangeLog | 5 ++++ libio/iofdopen.c | 15 ++++++++--- libio/tst-ftell-active-handler.c | 55 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index eea2ef6..da6a230 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2014-03-17 Siddhesh Poyarekar + * 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. diff --git a/libio/iofdopen.c b/libio/iofdopen.c index 843a4fa..b36d21d 100644 --- a/libio/iofdopen.c +++ b/libio/iofdopen.c @@ -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) diff --git a/libio/tst-ftell-active-handler.c b/libio/tst-ftell-active-handler.c index 40ca58c..e9dc7b3 100644 --- a/libio/tst-ftell-active-handler.c +++ b/libio/tst-ftell-active-handler.c @@ -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; } -- 2.7.4