Repository: bitcoin/bitcoin
File: src/streams.h (C/C++)

Code before:

public:
    explicit AutoFile(std::FILE* file, std::vector<std::byte> data_xor={});

    ~AutoFile() { fclose(); }

    // Disallow copies
    AutoFile(const AutoFile&) = delete;
    AutoFile& operator=(const AutoFile&) = delete;

    bool feof() const { return std::feof(m_file); }

    int fclose()
    {
        if (auto rel{release()}) return std::fclose(rel);
        return 0;
    }

    /** Get wrapped FILE* with transfer of ownership.
     * @note This will invalidate the AutoFile object, and makes it the responsibility of the caller
     * of this function to clean up the returned FILE*.
     */
    std::FILE* release()
    {
        std::FILE* ret{m_file};
        m_file = nullptr;
        return ret;
    }

    /** Return true if the wrapped FILE* is nullptr, false otherwise.
     */
    bool IsNull() const { return m_file == nullptr; }

    /** Continue with a different XOR key */
    void SetXor(std::vector<std::byte> data_xor) { m_xor = data_xor; }

    /** Implementation detail, only used internally. */
    std::size_t detail_fread(std::span<std::byte> dst);

    /** Wrapper around fseek(). Will throw if seeking is not possible. */
    void seek(int64_t offset, int origin);

    /** Find position within the file. Will throw if unknown. */
    int64_t tell();

    /** Wrapper around FileCommit(). */
    bool Commit();

    /** Wrapper around TruncateFile(). */
    bool Truncate(unsigned size);


Review comment (bug):
```suggestion
            LogError("Failed to close file: %s", SysErrorString(errno));
```

Code after:
 * file corrupt.
 */
class AutoFile
{
protected:
    std::FILE* m_file;
    std::vector<std::byte> m_xor;
    std::optional<int64_t> m_position;
    bool m_was_written{false};

public:
    explicit AutoFile(std::FILE* file, std::vector<std::byte> data_xor={});

    ~AutoFile()
    {
        if (m_was_written) {
            // Callers that wrote to the file must have closed it explicitly
            // with the fclose() method and checked that the close succeeded.
            // This is because here in the destructor we have no way to signal
            // errors from fclose() which, after write, could mean the file is
            // corrupted and must be handled properly at the call site.
            // Destructors in C++ cannot signal an error to the callers because
            // they do not return a value and are not allowed to throw exceptions.
            Assume(IsNull());
        }

        if (fclose() != 0) {
            LogError("Failed to close file: %s", SysErrorString(errno));
        }
    }

    // Disallow copies
    AutoFile(const AutoFile&) = delete;
    AutoFile& operator=(const AutoFile&) = delete;

    bool feof() const { return std::feof(m_file); }

    [[nodiscard]] int fclose()
    {
        if (auto rel{release()}) return std::fclose(rel);
        return 0;
    }

    /** Get wrapped FILE* with transfer of ownership.
     * @note This will invalidate the AutoFile object, and makes it the responsibility of the caller
     * of this function to clean up the returned FILE*.
     */
    std::FILE* release()
    {
        std::FILE* ret{m_file};
        m_file = nullptr;