diff --git a/include/fmt/os.h b/include/fmt/os.h index 39c7473c..f404faaf 100644 --- a/include/fmt/os.h +++ b/include/fmt/os.h @@ -377,10 +377,14 @@ class ostream : private detail::buffer { inline void flush() { size_t n = size(); - if (n == 0) return; // Clear before writing to not write the data again if the write fails. clear(); - file_.write(data(), n); + // Write in a loop because write may write fewer bytes than requested. + for (const char* p = data(); n != 0;) { + size_t written = file_.write(p, n); + p += written; + n -= written; + } } template diff --git a/test/posix-mock-test.cc b/test/posix-mock-test.cc index 15b173a0..059f5461 100644 --- a/test/posix-mock-test.cc +++ b/test/posix-mock-test.cc @@ -54,6 +54,7 @@ int fclose_count; int fileno_count; size_t read_nbyte; size_t write_nbyte; +size_t write_max; // Maximum number of bytes written per call if nonzero. bool sysconf_error; enum { none, max_size, error } fstat_sim; @@ -142,6 +143,7 @@ test::ssize_t test::read(int fildes, void* buf, test::size_t nbyte) { test::ssize_t test::write(int fildes, const void* buf, test::size_t nbyte) { write_nbyte = nbyte; EMULATE_EINTR(write, -1); + if (write_max != 0 && nbyte > write_max) nbyte = write_max; return ::FMT_POSIX(write(fildes, buf, nbyte)); } @@ -308,6 +310,17 @@ TEST(file_test, write_retry) { # endif } +TEST(ostream_test, short_write) { + write_max = 1; + { + auto out = fmt::output_file("temp"); + out.print("abc"); + } + write_max = 0; + file f("temp", file::RDONLY); + EXPECT_READ(f, "abc"); +} + # ifdef _WIN32 TEST(file_test, convert_read_count) { auto pipe = fmt::pipe();