Repository: microsoft/terminal
File: src/cascadia/TerminalSettingsModel/FileUtils.cpp (C++)

Code before:
        {
            if (exception.GetErrorCode() == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
            {
                return {};
            }

            throw;
        }
    }

    void WriteUTF8File(const std::filesystem::path& path, const std::string_view content)
    {
        wil::unique_hfile file{ CreateFileW(path.c_str(), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr) };
        THROW_LAST_ERROR_IF(!file);

        const auto fileSize = gsl::narrow<DWORD>(content.size());
        DWORD bytesWritten = 0;
        THROW_IF_WIN32_BOOL_FALSE(WriteFile(file.get(), content.data(), fileSize, &bytesWritten, nullptr));

        if (bytesWritten != fileSize)
        {
            THROW_WIN32_MSG(ERROR_WRITE_FAULT, "failed to write whole file");
        }
    }

    void WriteUTF8FileAtomic(const std::filesystem::path& path, const std::string_view content)
    {
        // GH#10787: In the case of symbolic link, ensure that we modify the target rather than the link itself.
        // We append the paths manually rather than using "canonical" method to support scenario in which link target doesn't exist
        auto resolvedPath = path;
        while (std::filesystem::is_symlink(resolvedPath))
        {
            resolvedPath = resolvedPath.parent_path() / std::filesystem::read_symlink(resolvedPath);
        }

        auto tmpPath = resolvedPath;
        tmpPath += L".tmp";

        // Writing to a file isn't atomic, but...
        WriteUTF8File(tmpPath, content);

        // renaming one is (supposed to be) atomic.
        // Wait... "supposed to be"!? Well it's technically not always atomic,
        // but it's pretty darn close to it, so... better than nothing.
        std::filesystem::rename(tmpPath, resolvedPath);
    }
}


Review comment (suggestion):
nit: You could modify this function to take `path` as a by-value argument.
That way you don't have to create the local `resolvedPath` copy.

Code after:
        {
            if (exception.GetErrorCode() == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
            {
                return {};
            }

            throw;
        }
    }

    void WriteUTF8File(const std::filesystem::path& path, const std::string_view content)
    {
        wil::unique_hfile file{ CreateFileW(path.c_str(), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr) };
        THROW_LAST_ERROR_IF(!file);

        const auto fileSize = gsl::narrow<DWORD>(content.size());
        DWORD bytesWritten = 0;
        THROW_IF_WIN32_BOOL_FALSE(WriteFile(file.get(), content.data(), fileSize, &bytesWritten, nullptr));

        if (bytesWritten != fileSize)
        {
            THROW_WIN32_MSG(ERROR_WRITE_FAULT, "failed to write whole file");
        }
    }

    void WriteUTF8FileAtomic(const std::filesystem::path& path, const std::string_view content)
    {
        // GH#10787: rename() will replace symbolic links themselves and not the path they point at.
        // It's thus important that we first resolve them before generating temporary path.
        std::error_code ec;
        const auto resolvedPath = std::filesystem::is_symlink(path) ? std::filesystem::canonical(path, ec) : path;
        if (ec)
        {
            if (ec.value() != ERROR_FILE_NOT_FOUND)
            {
                THROW_WIN32_MSG(ec.value(), "failed to compute canonical path");
            }

            // The original file is a symbolic link, but the target doesn't exist.
            // Consider two fall-backs:
            //   * resolve the link manually, which might be less accurate and more prone to race conditions
            //   * write to the file directly, which lets the system resolve the symbolic link but leaves the write non-atomic
            // The latter is chosen, as this is an edge case and our 'atomic' writes are only best-effort.
            WriteUTF8File(path, content);
            return;
        }

        auto tmpPath = resolvedPath;
        tmpPath += L".tmp";

        // Writing to a file isn't atomic, but...