chromium/chrome/installer/mini_installer/write_to_disk.cc

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include "chrome/installer/mini_installer/write_to_disk.h"

#include <windows.h>

#include <stddef.h>

#include <algorithm>

#include "chrome/installer/mini_installer/memory_range.h"
#include "chrome/installer/mini_installer/mini_file.h"

namespace mini_installer {

bool WriteToDisk(const MemoryRange& data, const wchar_t* full_path) {
  MiniFile file;
  if (!file.Create(full_path)) {
    return false;
  }

  // Don't write all of the data at once because this can lead to kernel
  // address-space exhaustion on 32-bit Windows (see https://crbug.com/1001022
  // for details).
  constexpr size_t kMaxWriteAmount = 8 * 1024 * 1024;
  for (size_t total_written = 0; total_written < data.size; /**/) {
    const size_t write_amount =
        std::min(kMaxWriteAmount, data.size - total_written);
    DWORD written = 0;
    if (!::WriteFile(file.GetHandleUnsafe(), data.data + total_written,
                     static_cast<DWORD>(write_amount), &written, nullptr)) {
      const auto write_error = ::GetLastError();

      // Delete the file since the write failed.
      file.DeleteOnClose();
      file.Close();

      ::SetLastError(write_error);
      return false;
    }
    total_written += write_amount;
  }
  return true;
}

}  // namespace mini_installer