summaryrefslogtreecommitdiff
path: root/libc
diff options
context:
space:
mode:
authorManuel Novoa III <mjn3@codepoet.org>2003-01-22 19:08:38 +0000
committerManuel Novoa III <mjn3@codepoet.org>2003-01-22 19:08:38 +0000
commitc5a9df36d2317c036858086715459dc4f4a5472f (patch)
tree36dbabdd05371891cee0d5f8e871e8e68b06a31c /libc
parent9febc84ad3517e6226418ca6b9280ab1f069209f (diff)
Fixed a bug related file position in append mode. _stdio_fwrite now
seeks to the end of the stream when append mode is set and we are transitioning to write mode, so that subsequent ftell() return values are correct. Also fix _stdio_fopen to support fdopen() with append specified when the underlying file didn't have O_APPEND set. It now sets the O_APPEND flag as recommended by SUSv3 and is done by glibc.
Diffstat (limited to 'libc')
-rw-r--r--libc/stdio/stdio.c63
1 files changed, 52 insertions, 11 deletions
diff --git a/libc/stdio/stdio.c b/libc/stdio/stdio.c
index 7db727c76..4cd330a9b 100644
--- a/libc/stdio/stdio.c
+++ b/libc/stdio/stdio.c
@@ -50,6 +50,15 @@
* Added internal function _wstdio_fwrite.
* Jan 3, 2003
* Fixed a bug in _wstdio_fwrite.
+ *
+ * Jan 22, 2003
+ * Fixed a bug related file position in append mode. _stdio_fwrite now
+ * seeks to the end of the stream when append mode is set and we are
+ * transitioning to write mode, so that subsequent ftell() return
+ * values are correct.
+ * Also fix _stdio_fopen to support fdopen() with append specified when
+ * the underlying file didn't have O_APPEND set. It now sets the
+ * O_APPEND flag as recommended by SUSv3 and is done by glibc.
*/
/* Before we include anything, convert L_ctermid to L_ctermid_function
@@ -1507,8 +1516,8 @@ size_t _stdio_fread(unsigned char *buffer, size_t bytes, register FILE *stream)
* error flag before/after the write process, but it doesn't seem worth
* the trouble. */
-/* Like standard write, but always does a full write unless error plus
- *deals correctly with bufsize > SSIZE_MAX... not much on an issue on linux
+/* Like standard write, but always does a full write unless error, plus
+ * deals correctly with bufsize > SSIZE_MAX... not much on an issue on linux
* but definitly could be on Elks. Also on Elks, always loops for EINTR..
* Returns number of bytes written, so a short write indicates an error */
static size_t _stdio_WRITE(register FILE *stream,
@@ -1592,8 +1601,18 @@ size_t _stdio_fwrite(const unsigned char *buffer, size_t bytes,
stream->bufgetc =
#endif /* __STDIO_GETC_MACRO */
stream->bufpos = stream->bufread = stream->bufstart;
+ } else
+#endif
+ if ((stream->modeflags & (__FLAG_WRITING|__FLAG_APPEND)) == __FLAG_APPEND) {
+ /* Append mode, but not currently writing. Need to seek to end for proper
+ * ftell() return values. Don't worry if the stream isn't seekable. */
+ __offmax_t pos[1];
+ *pos = 0;
+ if (_stdio_lseek(stream, pos, SEEK_END) && (errno != EPIPE)) { /* Too big? */
+ stream->modeflags |= __FLAG_ERROR;
+ return 0;
+ }
}
-#endif
#ifdef __STDIO_PUTC_MACRO
/* We need to disable putc macro in case of error */
@@ -1716,6 +1735,19 @@ size_t _stdio_fwrite(const unsigned char *buffer, size_t bytes,
/* We always clear the reading flag in case at EOF. */
stream->modeflags &= ~(__FLAG_READING);
+
+ if ((stream->modeflags & (__FLAG_WRITING|__FLAG_APPEND)) == __FLAG_APPEND) {
+ /* Append mode, but not currently writing. Need to seek to end for proper
+ * ftell() return values. Don't worry if the stream isn't seekable. */
+ __offmax_t pos[1];
+ *pos = 0;
+ if (_stdio_lseek(stream, pos, SEEK_END) && (errno != EPIPE)) { /* Too big? */
+ stream->modeflags |= __FLAG_ERROR;
+ return 0;
+ }
+ }
+
+
/* Unlike the buffered case, we set the writing flag now since we don't
* need to do anything here for fflush(). */
stream->modeflags |= __FLAG_WRITING;
@@ -2322,17 +2354,26 @@ FILE *_stdio_fopen(const char * __restrict filename,
}
if (filedes >= 0) { /* Handle fdopen trickery. */
- /*
- * NOTE: it is insufficient to just check R/W/RW agreement.
- * We must also check for append mode agreement, as well as
- * largefile agreement if applicable.
- */
- int i = (open_mode & (O_ACCMODE|O_APPEND|O_LARGEFILE)) + 1;
-
- if ((i & (((int) filename) + 1)) != i) {
+ /* NOTE: it is insufficient to just check R/W/RW agreement.
+ * We must also check largefile compatibility if applicable.
+ * Also, if append mode is desired for fdopen but O_APPEND isn't
+ * currently set, then set it as recommended by SUSv3. However,
+ * if append mode is not specified for fdopen but O_APPEND is set,
+ * leave it set (glibc compat). */
+ int i = (open_mode & (O_ACCMODE|O_LARGEFILE)) + 1;
+
+ if (((i & (((int) filename) + 1)) != i) /* Check basic agreement. */
+ || (((open_mode & O_APPEND)
+ && !(((int) filename) & O_APPEND)
+ && fcntl(filedes, F_SETFL, O_APPEND))) /* Need O_APPEND. */
+ ) {
__set_errno(EINVAL);
filedes = -1;
}
+#ifdef __STDIO_LARGE_FILES
+ /* For later... to reflect largefile setting in stream flags. */
+ open_mode |= (((int) filename) & O_LARGEFILE);
+#endif /* __STDIO_LARGE_FILES */
stream->filedes = filedes;
} else {
#ifdef __STDIO_LARGE_FILES