Skip to content

Commit 414c5d4

Browse files
Create empty Windows files with native API
1 parent 79d5f91 commit 414c5d4

1 file changed

Lines changed: 30 additions & 13 deletions

File tree

native/filter_database.cc

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,27 +12,46 @@
1212
#include <fstream>
1313
#include <iostream>
1414
#include <string>
15+
#include <system_error>
1516
#include <thread>
1617

18+
#ifdef _WIN32
19+
#include <windows.h>
20+
#endif
21+
1722
#include "binary_version.hh"
1823
#include "mmap_file.hh"
1924
#include "pdqsort.h"
2025

2126
namespace {
2227

23-
// Creates an empty file portably. On Windows, opening a new file without
24-
// writing did not reliably create it, while resize_file could briefly retain
25-
// an exclusive handle. Copying first and explicitly truncating and closing the
26-
// stream avoids both behaviors.
27-
void copy_as_empty(const std::filesystem::path& source_path,
28-
const std::filesystem::path& destination_path) {
29-
std::filesystem::copy_file(source_path, destination_path);
30-
31-
std::ofstream destination(destination_path,
28+
// Creates an empty file and closes it before returning. The Windows standard
29+
// library did not reliably materialize an empty output file, so use the native
30+
// file API there.
31+
void create_empty_file(const std::filesystem::path& path) {
32+
#ifdef _WIN32
33+
HANDLE file = CreateFileW(path.c_str(), GENERIC_WRITE,
34+
FILE_SHARE_READ | FILE_SHARE_WRITE |
35+
FILE_SHARE_DELETE,
36+
nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
37+
nullptr);
38+
if (file == INVALID_HANDLE_VALUE) {
39+
throw std::system_error(GetLastError(), std::system_category(),
40+
"Could not create empty file " +
41+
path.string());
42+
}
43+
if (!CloseHandle(file)) {
44+
throw std::system_error(GetLastError(), std::system_category(),
45+
"Could not close empty file " +
46+
path.string());
47+
}
48+
#else
49+
std::ofstream destination(path,
3250
std::ios_base::out | std::ios_base::binary |
3351
std::ios_base::trunc);
3452
destination.exceptions(std::ofstream::badbit | std::ofstream::failbit);
3553
destination.close();
54+
#endif
3655
}
3756

3857
// Copies selected entries from a byte-offset table into a new file.
@@ -138,8 +157,7 @@ void filter_database(const char* source, const char* destination,
138157
std::filesystem::path destination_subject_ids_path =
139158
destination_path / "subject_id";
140159
if (subject_ids.empty()) {
141-
copy_as_empty(source_path / "subject_id",
142-
destination_subject_ids_path);
160+
create_empty_file(destination_subject_ids_path);
143161
} else {
144162
std::ofstream subject_ids_file(
145163
destination_subject_ids_path,
@@ -196,8 +214,7 @@ void filter_database(const char* source, const char* destination,
196214
std::filesystem::path destination_subject_lengths_path =
197215
destination_path / "meds_reader.length";
198216
if (subject_lengths.empty()) {
199-
copy_as_empty(source_path / "meds_reader.length",
200-
destination_subject_lengths_path);
217+
create_empty_file(destination_subject_lengths_path);
201218
} else {
202219
std::ofstream subject_lengths_file(
203220
destination_subject_lengths_path,

0 commit comments

Comments
 (0)