aboutsummaryrefslogtreecommitdiff
path: root/libio
diff options
context:
space:
mode:
Diffstat (limited to 'libio')
-rw-r--r--libio/bits/types/struct_FILE.h9
-rw-r--r--libio/fileops.c2
-rw-r--r--libio/iofwrite.c39
3 files changed, 44 insertions, 6 deletions
diff --git a/libio/bits/types/struct_FILE.h b/libio/bits/types/struct_FILE.h
index 0e8ac64e36..2012d70681 100644
--- a/libio/bits/types/struct_FILE.h
+++ b/libio/bits/types/struct_FILE.h
@@ -97,8 +97,15 @@ struct _IO_FILE_complete
void *_freeres_buf;
struct _IO_FILE **_prevchain;
int _mode;
+#ifdef __LP64__
+ int _unused3;
+#endif
+ __uint64_t _total_written;
+#ifndef __LP64__
+ int _unused3;
+#endif
/* Make sure we don't get into trouble again. */
- char _unused2[15 * sizeof (int) - 5 * sizeof (void *)];
+ char _unused2[12 * sizeof (int) - 5 * sizeof (void *)];
};
/* These macros are used by bits/stdio.h and internal headers. */
diff --git a/libio/fileops.c b/libio/fileops.c
index 775999deb3..12b440b09d 100644
--- a/libio/fileops.c
+++ b/libio/fileops.c
@@ -113,6 +113,7 @@ _IO_new_file_init_internal (struct _IO_FILE_plus *fp)
_IO_link_in (fp);
fp->file._fileno = -1;
+ fp->file._total_written = 0;
}
/* External version of _IO_new_file_init_internal which switches off
@@ -1185,6 +1186,7 @@ _IO_new_file_write (FILE *f, const void *data, ssize_t n)
f->_flags |= _IO_ERR_SEEN;
break;
}
+ f->_total_written += count;
to_do -= count;
data = (void *) ((char *) data + count);
}
diff --git a/libio/iofwrite.c b/libio/iofwrite.c
index f94493c6ba..7897c4afaf 100644
--- a/libio/iofwrite.c
+++ b/libio/iofwrite.c
@@ -36,13 +36,42 @@ _IO_fwrite (const void *buf, size_t size, size_t count, FILE *fp)
return 0;
_IO_acquire_lock (fp);
if (_IO_vtable_offset (fp) != 0 || _IO_fwide (fp, -1) == -1)
- written = _IO_sputn (fp, (const char *) buf, request);
+ {
+ /* Compute actually written bytes plus pending buffer
+ contents. */
+ uint64_t original_total_written
+ = fp->_total_written + (fp->_IO_write_ptr - fp->_IO_write_base);
+ written = _IO_sputn (fp, (const char *) buf, request);
+ if (written == EOF)
+ {
+ /* An error happened and we need to find the appropriate return
+ value. There 3 possible scenarios:
+ 1. If the number of bytes written is between 0..[buffer content],
+ we need to return 0 because none of the bytes from this
+ request have been written;
+ 2. If the number of bytes written is between
+ [buffer content]+1..request-1, that means we managed to write
+ data requested in this fwrite call;
+ 3. We might have written all the requested data and got an error
+ anyway. We can't return success, which means we still have to
+ return less than request. */
+ if (fp->_total_written > original_total_written)
+ {
+ written = fp->_total_written - original_total_written;
+ /* If everything was reported as written and somehow an
+ error occurred afterwards, avoid reporting success. */
+ if (written == request)
+ --written;
+ }
+ else
+ /* Only already-pending buffer contents was written. */
+ written = 0;
+ }
+ }
_IO_release_lock (fp);
/* We have written all of the input in case the return value indicates
- this or EOF is returned. The latter is a special case where we
- simply did not manage to flush the buffer. But the data is in the
- buffer and therefore written as far as fwrite is concerned. */
- if (written == request || written == EOF)
+ this. */
+ if (written == request)
return count;
else
return written / size;