--- /dev/null
+// Copyright (C) 2020 Joel Rosdahl and other contributors
+//
+// See doc/AUTHORS.adoc for a complete list of contributors.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include "system.hpp"
+
+#include "NonCopyable.hpp"
+
+class Fd : NonCopyable
+{
+public:
+ Fd() = default;
+ explicit Fd(int fd);
+ Fd(Fd&& other_fd);
+ ~Fd();
+
+ explicit operator bool() const;
+
+ int get() const;
+ int operator*() const;
+
+ Fd& operator=(Fd&& other_fd);
+
+ // Close wrapped fd before the lifetime of Fd has ended.
+ bool close();
+
+ // Release ownership of wrapped fd.
+ int release();
+
+private:
+ int m_fd = -1;
+};
+
+inline Fd::Fd(int fd) : m_fd(fd)
+{
+}
+
+inline Fd::Fd(Fd&& other_fd) : m_fd(other_fd.release())
+{
+}
+
+inline Fd::~Fd()
+{
+ close();
+}
+
+inline Fd::operator bool() const
+{
+ return m_fd != -1;
+}
+
+inline int
+Fd::get() const
+{
+ return m_fd;
+}
+
+inline int
+Fd::operator*() const
+{
+ assert(m_fd != -1);
+ return m_fd;
+}
+
+inline Fd&
+Fd::operator=(Fd&& other_fd)
+{
+ close();
+ m_fd = other_fd.release();
+ return *this;
+}
+
+inline bool
+Fd::close()
+{
+ return m_fd != -1 && ::close(release()) == 0;
+}
+
+inline int
+Fd::release()
+{
+ int fd = m_fd;
+ m_fd = -1;
+ return fd;
+}
--- /dev/null
+// Copyright (C) 2020 Joel Rosdahl and other contributors
+//
+// See doc/AUTHORS.adoc for a complete list of contributors.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include "system.hpp"
+
+#include <functional>
+
+class Finalizer
+{
+public:
+ Finalizer(std::function<void()> finalizer);
+ ~Finalizer();
+
+private:
+ std::function<void()> m_finalizer;
+};
+
+inline Finalizer::Finalizer(std::function<void()> finalizer)
+ : m_finalizer(finalizer)
+{
+}
+
+inline Finalizer::~Finalizer()
+{
+ m_finalizer();
+}
#ifdef INODE_CACHE_SUPPORTED
# include "Config.hpp"
+# include "Fd.hpp"
+# include "Finalizer.hpp"
# include "Stat.hpp"
# include "Util.hpp"
# include "ccache.hpp"
munmap(m_sr, sizeof(SharedRegion));
m_sr = nullptr;
}
- int fd = open(inode_cache_file.c_str(), O_RDWR);
- if (fd < 0) {
+ Fd fd(open(inode_cache_file.c_str(), O_RDWR));
+ if (!fd) {
cc_log("Failed to open inode cache %s: %s",
inode_cache_file.c_str(),
strerror(errno));
return false;
}
bool is_nfs;
- if (Util::is_nfs_fd(fd, &is_nfs) == 0 && is_nfs) {
+ if (Util::is_nfs_fd(*fd, &is_nfs) == 0 && is_nfs) {
cc_log(
"Inode cache not supported because the cache file is located on nfs: %s",
inode_cache_file.c_str());
- close(fd);
return false;
}
SharedRegion* sr = reinterpret_cast<SharedRegion*>(mmap(
- nullptr, sizeof(SharedRegion), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
- close(fd);
+ nullptr, sizeof(SharedRegion), PROT_READ | PROT_WRITE, MAP_SHARED, *fd, 0));
+ fd.close();
if (sr == reinterpret_cast<void*>(-1)) {
cc_log("Failed to mmap %s: %s", inode_cache_file.c_str(), strerror(errno));
return false;
// Create the new file to a temporary name to prevent other processes from
// mapping it before it is fully initialized.
- auto temp_fd = Util::create_temp_fd(filename);
+ auto temp_fd_and_path = Util::create_temp_fd(filename);
+ const auto& temp_path = temp_fd_and_path.second;
+
+ Fd temp_fd(temp_fd_and_path.first);
+ Finalizer temp_file_remover([=] { unlink(temp_path.c_str()); });
+
bool is_nfs;
- if (Util::is_nfs_fd(temp_fd.first, &is_nfs) == 0 && is_nfs) {
+ if (Util::is_nfs_fd(*temp_fd, &is_nfs) == 0 && is_nfs) {
cc_log(
"Inode cache not supported because the cache file would be located on"
" nfs: %s",
filename.c_str());
- unlink(temp_fd.second.c_str());
- close(temp_fd.first);
return false;
}
- int err = Util::fallocate(temp_fd.first, sizeof(SharedRegion));
+ int err = Util::fallocate(*temp_fd, sizeof(SharedRegion));
if (err) {
cc_log("Failed to allocate file space for inode cache: %s", strerror(err));
- unlink(temp_fd.second.c_str());
- close(temp_fd.first);
return false;
}
SharedRegion* sr =
sizeof(SharedRegion),
PROT_READ | PROT_WRITE,
MAP_SHARED,
- temp_fd.first,
+ *temp_fd,
0));
if (sr == reinterpret_cast<void*>(-1)) {
cc_log("Failed to mmap new inode cache: %s", strerror(errno));
- unlink(temp_fd.second.c_str());
- close(temp_fd.first);
return false;
}
}
munmap(sr, sizeof(SharedRegion));
- close(temp_fd.first);
+ temp_fd.close();
// link() will fail silently if a file with the same name already exists.
// This will be the case if two processes try to create a new file
// simultaneously. Thus close the current file handle and reopen a new one,
// which will make us use the first created file even if we didn't win the
// race.
- if (link(temp_fd.second.c_str(), filename.c_str()) != 0) {
+ if (link(temp_path.c_str(), filename.c_str()) != 0) {
cc_log("Failed to link new inode cache: %s", strerror(errno));
- unlink(temp_fd.second.c_str());
return false;
}
- unlink(temp_fd.second.c_str());
return true;
}
#include "Args.hpp"
#include "ArgsInfo.hpp"
#include "Context.hpp"
+#include "Fd.hpp"
#include "File.hpp"
+#include "Finalizer.hpp"
#include "FormatNonstdStringView.hpp"
#include "MiniTrace.hpp"
#include "ProgressBar.hpp"
bool system,
struct hash* depend_mode_hash)
{
- struct hash* fhash = nullptr;
bool is_pch = false;
if (path.length() >= 2 && path[0] == '<' && path[path.length() - 1] == '>') {
}
// Let's hash the include file content.
- std::unique_ptr<struct hash, decltype(&hash_free)> fhash_holder(hash_init(),
- &hash_free);
- fhash = fhash_holder.get();
+ struct hash* fhash = hash_init();
+ Finalizer fhash_finalizer([=] { hash_free(fhash); });
is_pch = is_precompiled_header(path.c_str());
if (is_pch) {
// Fall through
}
} else {
- int fd_stderr = open(path_stderr.c_str(), O_RDONLY | O_BINARY);
- if (fd_stderr != -1) {
- copy_fd(fd_stderr, STDERR_FILENO);
- close(fd_stderr);
+ Fd fd_stderr(open(path_stderr.c_str(), O_RDONLY | O_BINARY));
+ if (fd_stderr) {
+ copy_fd(*fd_stderr, STDERR_FILENO);
}
}
}
#include "hash.hpp"
+#include "Fd.hpp"
#include "Util.hpp"
#include "logging.hpp"
bool
hash_file(struct hash* hash, const char* fname)
{
- int fd = open(fname, O_RDONLY | O_BINARY);
- if (fd == -1) {
+ Fd fd(open(fname, O_RDONLY | O_BINARY));
+ if (!fd) {
cc_log("Failed to open %s: %s", fname, strerror(errno));
return false;
}
- bool ret = hash_fd(hash, fd, true);
- close(fd);
+ bool ret = hash_fd(hash, *fd, true);
return ret;
}
#include "legacy_util.hpp"
+#include "Fd.hpp"
#include "Util.hpp"
#include "exceptions.hpp"
#include "logging.hpp"
bool result;
# if defined(__linux__)
- int src_fd = open(src, O_RDONLY);
- if (src_fd == -1) {
+ Fd src_fd(open(src, O_RDONLY));
+ if (!src_fd) {
return false;
}
- int dest_fd;
+ Fd dest_fd;
char* tmp_file = nullptr;
if (via_tmp_file) {
tmp_file = x_strdup(dest);
- dest_fd = create_tmp_fd(&tmp_file);
+ dest_fd = Fd(create_tmp_fd(&tmp_file));
} else {
- dest_fd = open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
- if (dest_fd == -1) {
- close(dest_fd);
- close(src_fd);
+ dest_fd = Fd(open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666));
+ if (!dest_fd) {
return false;
}
}
int saved_errno = 0;
- if (ioctl(dest_fd, FICLONE, src_fd) == 0) {
+ if (ioctl(*dest_fd, FICLONE, *src_fd) == 0) {
result = true;
} else {
result = false;
saved_errno = errno;
}
- close(dest_fd);
- close(src_fd);
+ dest_fd.close();
+ src_fd.close();
if (via_tmp_file) {
if (x_rename(tmp_file, dest) != 0) {
{
bool result = false;
- int src_fd = open(src, O_RDONLY);
- if (src_fd == -1) {
+ Fd src_fd(open(src, O_RDONLY));
+ if (!src_fd) {
return false;
}
- int dest_fd;
+ Fd dest_fd;
char* tmp_file = nullptr;
if (via_tmp_file) {
tmp_file = x_strdup(dest);
- dest_fd = create_tmp_fd(&tmp_file);
+ dest_fd = Fd(create_tmp_fd(&tmp_file));
} else {
- dest_fd = open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
- if (dest_fd == -1) {
- close(dest_fd);
- close(src_fd);
+ dest_fd = Fd(open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666));
+ if (!dest_fd) {
return false;
}
}
- if (copy_fd(src_fd, dest_fd, true)) {
+ if (copy_fd(*src_fd, *dest_fd, true)) {
result = true;
}
- close(dest_fd);
- close(src_fd);
+ dest_fd.close();
+ src_fd.close();
if (via_tmp_file) {
if (x_rename(tmp_file, dest) != 0) {
// +1 to be able to detect EOF in the first read call
size_hint = (size_hint < 1024) ? 1024 : size_hint + 1;
- int fd = open(path, O_RDONLY | O_BINARY);
- if (fd == -1) {
+ Fd fd(open(path, O_RDONLY | O_BINARY));
+ if (!fd) {
return false;
}
size_t allocated = size_hint;
*data = static_cast<char*>(x_realloc(*data, allocated));
}
const size_t max_read = allocated - pos;
- ret = read(fd, *data + pos, max_read);
+ ret = read(*fd, *data + pos, max_read);
if (ret == 0 || (ret == -1 && errno != EINTR)) {
break;
}
}
}
}
- close(fd);
+
if (ret == -1) {
cc_log("Failed reading %s", path);
free(*data);
// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#include "../src/Config.hpp"
+#include "../src/Fd.hpp"
#include "../src/Util.hpp"
#include "TestUtil.hpp"
{
TestContext test_context;
- const char* filename = "test-file";
- int fd = creat(filename, S_IRUSR | S_IWUSR);
- CHECK(Util::fallocate(fd, 10000) == 0);
- close(fd);
- fd = open(filename, O_RDWR, S_IRUSR | S_IWUSR);
+ const char filename[] = "test-file";
+
+ CHECK(Util::fallocate(Fd(creat(filename, S_IRUSR | S_IWUSR)).get(), 10000)
+ == 0);
CHECK(Stat::stat(filename).size() == 10000);
- CHECK(Util::fallocate(fd, 5000) == 0);
- close(fd);
- fd = open(filename, O_RDWR, S_IRUSR | S_IWUSR);
+
+ CHECK(
+ Util::fallocate(Fd(open(filename, O_RDWR, S_IRUSR | S_IWUSR)).get(), 5000)
+ == 0);
CHECK(Stat::stat(filename).size() == 10000);
- CHECK(Util::fallocate(fd, 20000) == 0);
- close(fd);
+
+ CHECK(
+ Util::fallocate(Fd(open(filename, O_RDWR, S_IRUSR | S_IWUSR)).get(), 20000)
+ == 0);
CHECK(Stat::stat(filename).size() == 20000);
}