Skip to content

Commit

Permalink
Fix error handling in xml_document::save_file
Browse files Browse the repository at this point in the history
There were two conditions under which xml_document::save_file could
previously return true even though the saving failed:

- The last write to the file was buffered in stdio buffer, and it's that
  last write that would fail due to lack of disk space
- The data has been written correctly but fclose failed to update file
  metadata, which can result in truncated size / missing inode updates.

This change fixes both by adjusting save_file to fflush before the check,
and also checking fclose results. Note that while fflush here is
technically redundant, because it's implied by fclose, we must check
ferror explicitly anyway, and so it feels a little cleaner to do most of
the error handling in save_file_impl, so that the changes of fclose()
failing are very slim.

Of course, neither change guarantees that the contents of the file are
going to be safe on disk following a power failure.
  • Loading branch information
zeux committed Oct 8, 2022
1 parent 0cb4f02 commit 444963e
Showing 1 changed file with 3 additions and 3 deletions.
6 changes: 3 additions & 3 deletions src/pugixml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5070,7 +5070,7 @@ PUGI__NS_BEGIN
xml_writer_file writer(file);
doc.save(writer, indent, flags, encoding);

return ferror(file) == 0;
return fflush(file) == 0 && ferror(file) == 0;
}

struct name_null_sentry
Expand Down Expand Up @@ -7423,15 +7423,15 @@ namespace pugi
using impl::auto_deleter; // MSVC7 workaround
auto_deleter<FILE> file(impl::open_file(path_, (flags & format_save_file_text) ? "w" : "wb"), impl::close_file);

return impl::save_file_impl(*this, file.data, indent, flags, encoding);
return impl::save_file_impl(*this, file.data, indent, flags, encoding) && fclose(file.release()) == 0;
}

PUGI__FN bool xml_document::save_file(const wchar_t* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const
{
using impl::auto_deleter; // MSVC7 workaround
auto_deleter<FILE> file(impl::open_file_wide(path_, (flags & format_save_file_text) ? L"w" : L"wb"), impl::close_file);

return impl::save_file_impl(*this, file.data, indent, flags, encoding);
return impl::save_file_impl(*this, file.data, indent, flags, encoding) && fclose(file.release()) == 0;
}

PUGI__FN xml_node xml_document::document_element() const
Expand Down

0 comments on commit 444963e

Please sign in to comment.