1
1
mirror of https://github.com/rui314/mold.git synced 2024-08-16 08:20:23 +03:00
This commit is contained in:
Rui Ueyama 2024-07-09 13:00:05 +09:00
parent 18da5b654e
commit 02ca830f42
3 changed files with 63 additions and 69 deletions

View File

@ -743,7 +743,7 @@ public:
u8 *buf = nullptr;
std::vector<u8> buf2;
std::string path;
i64 fd = -1;
int fd = -1;
i64 filesize = 0;
bool is_mmapped = false;
bool is_unmapped = false;
@ -756,7 +756,7 @@ protected:
template <typename Context>
class MallocOutputFile : public OutputFile<Context> {
public:
MallocOutputFile(Context &ctx, std::string path, i64 filesize, i64 perm)
MallocOutputFile(Context &ctx, std::string path, i64 filesize, int perm)
: OutputFile<Context>(path, filesize, false), ptr(new u8[filesize]),
perm(perm) {
this->buf = ptr.get();

View File

@ -15,50 +15,47 @@ inline u32 get_umask() {
}
template <typename Context>
static std::pair<i64, char *>
open_or_create_file(Context &ctx, std::string path, i64 filesize, i64 perm) {
std::string tmpl = filepath(path).parent_path() / ".mold-XXXXXX";
char *path2 = (char *)save_string(ctx, tmpl).data();
i64 fd = mkstemp(path2);
if (fd == -1)
Fatal(ctx) << "cannot open " << path2 << ": " << errno_string();
static int
open_or_create_file(Context &ctx, std::string path, std::string tmpfile,
int perm) {
// Reuse an existing file if exists and writable because on Linux,
// writing to an existing file is much faster than creating a fresh
// file and writing to it.
if (ctx.overwrite_output_file && rename(path.c_str(), path2) == 0) {
::close(fd);
fd = ::open(path2, O_RDWR | O_CREAT, perm);
if (fd != -1 && !ftruncate(fd, filesize) && !fchmod(fd, perm & ~get_umask()))
return {fd, path2};
unlink(path2);
fd = ::open(path2, O_RDWR | O_CREAT, perm);
if (fd == -1)
Fatal(ctx) << "cannot open " << path2 << ": " << errno_string();
if (ctx.overwrite_output_file && rename(path.c_str(), tmpfile.c_str()) == 0) {
i64 fd = ::open(tmpfile.c_str(), O_RDWR | O_CREAT, perm);
if (fd != -1)
return fd;
unlink(tmpfile.c_str());
}
if (fchmod(fd, (perm & ~get_umask())) == -1)
Fatal(ctx) << "fchmod failed: " << errno_string();
#ifdef __linux__
if (fallocate(fd, 0, 0, filesize) == 0)
return {fd, path2};
#endif
if (ftruncate(fd, filesize) == -1)
Fatal(ctx) << "ftruncate failed: " << errno_string();
return {fd, path2};
i64 fd = ::open(tmpfile.c_str(), O_RDWR | O_CREAT, perm);
if (fd == -1)
Fatal(ctx) << "cannot open " << tmpfile << ": " << errno_string();
return fd;
}
template <typename Context>
class MemoryMappedOutputFile : public OutputFile<Context> {
public:
MemoryMappedOutputFile(Context &ctx, std::string path, i64 filesize, i64 perm)
MemoryMappedOutputFile(Context &ctx, std::string path, i64 filesize, int perm)
: OutputFile<Context>(path, filesize, true) {
std::tie(this->fd, output_tmpfile) =
open_or_create_file(ctx, path, filesize, perm);
std::filesystem::path dir = filepath(path).parent_path();
std::string filename = filepath(path).filename().string();
std::string tmpfile = dir / ("." + filename + "." + std::to_string(getpid()));
this->fd = open_or_create_file(ctx, path, tmpfile, perm);
if (fchmod(this->fd, perm & ~get_umask()) == -1)
Fatal(ctx) << "fchmod failed: " << errno_string();
if (ftruncate(this->fd, filesize) == -1)
Fatal(ctx) << "ftruncate failed: " << errno_string();
output_tmpfile = (char *)save_string(ctx, tmpfile).data();
#ifdef __linux__
fallocate(this->fd, 0, 0, filesize);
#endif
this->buf = (u8 *)mmap(nullptr, filesize, PROT_READ | PROT_WRITE,
MAP_SHARED, this->fd, 0);
@ -107,7 +104,7 @@ private:
template <typename Context>
std::unique_ptr<OutputFile<Context>>
OutputFile<Context>::open(Context &ctx, std::string path, i64 filesize, i64 perm) {
OutputFile<Context>::open(Context &ctx, std::string path, i64 filesize, int perm) {
Timer t(ctx, "open_file");
if (path.starts_with('/') && !ctx.arg.chroot.empty())

View File

@ -9,36 +9,35 @@ namespace mold {
template <typename Context>
class MemoryMappedOutputFile : public OutputFile<Context> {
public:
MemoryMappedOutputFile(Context &ctx, std::string path, i64 filesize, i64 perm)
MemoryMappedOutputFile(Context &ctx, std::string path, i64 filesize, int perm)
: OutputFile<Context>(path, filesize, true) {
// TODO: use intermediate temporary file for output.
DWORD file_attrs =
(perm & 0200) ? FILE_ATTRIBUTE_NORMAL : FILE_ATTRIBUTE_READONLY;
file_handle =
CreateFileA(path.c_str(), GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
nullptr, CREATE_ALWAYS, file_attrs, nullptr);
if (file_handle == INVALID_HANDLE_VALUE)
DWORD attrs = (perm & 0200) ? FILE_ATTRIBUTE_NORMAL : FILE_ATTRIBUTE_READONLY;
handle = CreateFileA(path.c_str(), GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
nullptr, CREATE_ALWAYS, attrs, nullptr);
if (handle == INVALID_HANDLE_VALUE)
Fatal(ctx) << "cannot open " << path << ": " << GetLastError();
HANDLE mapping_handle = CreateFileMapping(
file_handle, nullptr, PAGE_READWRITE, 0, filesize, nullptr);
if (!mapping_handle)
HANDLE map = CreateFileMapping(handle, nullptr, PAGE_READWRITE, 0,
filesize, nullptr);
if (!map)
Fatal(ctx) << path << ": CreateFileMapping failed: " << GetLastError();
this->buf =
(u8 *)MapViewOfFile(mapping_handle, FILE_MAP_WRITE, 0, 0, filesize);
CloseHandle(mapping_handle);
this->buf = (u8 *)MapViewOfFile(map, FILE_MAP_WRITE, 0, 0, filesize);
if (!this->buf)
Fatal(ctx) << path << ": MapViewOfFile failed: " << GetLastError();
CloseHandle(map);
mold::output_buffer_start = this->buf;
mold::output_buffer_end = this->buf + filesize;
}
~MemoryMappedOutputFile() {
if (file_handle != INVALID_HANDLE_VALUE)
CloseHandle(file_handle);
if (handle != INVALID_HANDLE_VALUE)
CloseHandle(handle);
}
void close(Context &ctx) override {
@ -47,28 +46,27 @@ public:
UnmapViewOfFile(this->buf);
if (!this->buf2.empty()) {
if (SetFilePointer(file_handle, 0, nullptr, FILE_END) ==
INVALID_SET_FILE_POINTER)
Fatal(ctx) << this->path
<< ": SetFilePointer failed: " << GetLastError();
if (SetFilePointer(handle, 0, nullptr, FILE_END) == INVALID_SET_FILE_POINTER)
Fatal(ctx) << this->path << ": SetFilePointer failed: "
<< GetLastError();
DWORD written;
if (!WriteFile(file_handle, this->buf2.data(), this->buf2.size(),
&written, nullptr))
if (!WriteFile(handle, this->buf2.data(), this->buf2.size(), &written,
nullptr))
Fatal(ctx) << this->path << ": WriteFile failed: " << GetLastError();
}
CloseHandle(file_handle);
file_handle = INVALID_HANDLE_VALUE;
CloseHandle(handle);
handle = INVALID_HANDLE_VALUE;
}
private:
HANDLE file_handle;
HANDLE handle;
};
template <typename Context>
std::unique_ptr<OutputFile<Context>>
OutputFile<Context>::open(Context &ctx, std::string path, i64 filesize, i64 perm) {
OutputFile<Context>::open(Context &ctx, std::string path, i64 filesize, int perm) {
Timer t(ctx, "open_file");
if (path.starts_with('/') && !ctx.arg.chroot.empty())
@ -78,14 +76,13 @@ OutputFile<Context>::open(Context &ctx, std::string path, i64 filesize, i64 perm
if (path == "-") {
is_special = true;
} else {
HANDLE file_handle =
CreateFileA(path.c_str(), GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
if (file_handle != INVALID_HANDLE_VALUE) {
if (GetFileType(file_handle) != FILE_TYPE_DISK)
HANDLE h = CreateFileA(path.c_str(), GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
if (h != INVALID_HANDLE_VALUE) {
if (GetFileType(h) != FILE_TYPE_DISK)
is_special = true;
CloseHandle(file_handle);
CloseHandle(h);
}
}