diff options
Diffstat (limited to 'libio')
| -rw-r--r-- | libio/bits/types/struct_FILE.h | 9 | ||||
| -rw-r--r-- | libio/fileops.c | 2 | ||||
| -rw-r--r-- | libio/iofwrite.c | 39 |
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; |
