#include "fmtmacros.hpp"
#include <util/conversion.hpp>
+#include <util/file.hpp>
#include <fcntl.h>
#include <libgen.h>
if (!fd_is_on_known_to_work_file_system(*tmp_file.fd)) {
return false;
}
- int err = Util::fallocate(*tmp_file.fd, sizeof(SharedRegion));
- if (err != 0) {
- LOG("Failed to allocate file space for inode cache: {}", strerror(err));
+
+ if (auto result = util::fallocate(*tmp_file.fd, sizeof(SharedRegion));
+ !result) {
+ LOG("Failed to allocate file space for inode cache: {}", result.error());
return false;
}
SharedRegion* sr =
}
}
-int
-fallocate(int fd, long new_size)
-{
-#ifdef HAVE_POSIX_FALLOCATE
- const int posix_fallocate_err = posix_fallocate(fd, 0, new_size);
- if (posix_fallocate_err == 0 || posix_fallocate_err != EINVAL) {
- return posix_fallocate_err;
- }
- // The underlying filesystem does not support the operation so fall back to
- // lseek.
-#endif
- off_t saved_pos = lseek(fd, 0, SEEK_END);
- off_t old_size = lseek(fd, 0, SEEK_END);
- if (old_size == -1) {
- int err = errno;
- lseek(fd, saved_pos, SEEK_SET);
- return err;
- }
- if (old_size >= new_size) {
- lseek(fd, saved_pos, SEEK_SET);
- return 0;
- }
- long bytes_to_write = new_size - old_size;
- void* buf = calloc(bytes_to_write, 1);
- if (!buf) {
- lseek(fd, saved_pos, SEEK_SET);
- return ENOMEM;
- }
- int err = 0;
- try {
- util::write_fd(fd, buf, bytes_to_write);
- } catch (core::Error&) {
- err = errno;
- }
- lseek(fd, saved_pos, SEEK_SET);
- free(buf);
- return err;
-}
-
std::string
format_argv_for_logging(const char* const* argv)
{
// Like create_dir but throws Fatal on error.
void ensure_dir_exists(std::string_view dir);
-// Extends file size to at least new_size by calling posix_fallocate() if
-// supported, otherwise by writing zeros last to the file.
-//
-// Note that existing holes are not filled in case posix_fallocate() is not
-// supported.
-//
-// Returns 0 on success, an error number otherwise.
-int fallocate(int fd, long new_size);
-
// Format `argv` as a simple string for logging purposes. That is, the result is
// not intended to be machine parsable. `argv` must be terminated by a nullptr.
std::string format_argv_for_logging(const char* const* argv);
#include "file.hpp"
#include <Fd.hpp>
+#include <Finalizer.hpp>
#include <Logging.hpp>
#include <Stat.hpp>
#include <TemporaryFile.hpp>
}
}
+nonstd::expected<void, std::string>
+fallocate(int fd, size_t new_size)
+{
+#ifdef HAVE_POSIX_FALLOCATE
+ const int posix_fallocate_err = posix_fallocate(fd, 0, new_size);
+ if (posix_fallocate_err == 0) {
+ return {};
+ }
+ if (posix_fallocate_err != EINVAL) {
+ return nonstd::make_unexpected(strerror(posix_fallocate_err));
+ }
+ // The underlying filesystem does not support the operation so fall back to
+ // lseek.
+#endif
+ off_t saved_pos = lseek(fd, 0, SEEK_END);
+ off_t old_size = lseek(fd, 0, SEEK_END);
+ if (old_size == -1) {
+ int err = errno;
+ lseek(fd, saved_pos, SEEK_SET);
+ return nonstd::make_unexpected(strerror(err));
+ }
+ if (static_cast<size_t>(old_size) >= new_size) {
+ lseek(fd, saved_pos, SEEK_SET);
+ return {};
+ }
+ long bytes_to_write = new_size - old_size;
+
+ void* buf = calloc(bytes_to_write, 1);
+ if (!buf) {
+ lseek(fd, saved_pos, SEEK_SET);
+ return nonstd::make_unexpected(strerror(ENOMEM));
+ }
+ Finalizer buf_freer([&] { free(buf); });
+
+ if (auto result = util::write_fd(fd, buf, bytes_to_write); !result) {
+ return result;
+ }
+ lseek(fd, saved_pos, SEEK_SET);
+ return {};
+}
+
nonstd::expected<void, std::string>
read_fd(int fd, DataReceiver data_receiver)
{
void create_cachedir_tag(const std::string& dir);
+// Extends file size of `fd` to at least `new_size` by calling posix_fallocate()
+// if supported, otherwise by writing zeros last to the file.
+//
+// Note that existing holes are not filled in case posix_fallocate() is not
+// supported.
+nonstd::expected<void, std::string> fallocate(int fd, size_t new_size);
+
// Return how much a file of `size` bytes likely would take on disk.
uint64_t likely_size_on_disk(uint64_t size);
"Failed to create directory create/dir/file: Not a directory");
}
-TEST_CASE("Util::fallocate")
-{
- TestContext test_context;
-
- 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(open(filename, O_RDWR, S_IRUSR | S_IWUSR)).get(), 5000)
- == 0);
- CHECK(Stat::stat(filename).size() == 10000);
-
- CHECK(
- Util::fallocate(Fd(open(filename, O_RDWR, S_IRUSR | S_IWUSR)).get(), 20000)
- == 0);
- CHECK(Stat::stat(filename).size() == 20000);
-}
-
TEST_CASE("Util::format_argv_for_logging")
{
const char* argv_0[] = {nullptr};
#include "TestUtil.hpp"
+#include <Fd.hpp>
+#include <Stat.hpp>
#include <util/Bytes.hpp>
#include <util/file.hpp>
#include <util/string.hpp>
#include <third_party/doctest.h>
+#include <fcntl.h>
+
#include <cstring>
#include <string>
#include <string_view>
using TestUtil::TestContext;
+TEST_CASE("util::fallocate")
+{
+ TestContext test_context;
+
+ const char filename[] = "test-file";
+
+ CHECK(util::fallocate(Fd(creat(filename, S_IRUSR | S_IWUSR)).get(), 10000));
+ CHECK(Stat::stat(filename).size() == 10000);
+
+ CHECK(
+ util::fallocate(Fd(open(filename, O_RDWR, S_IRUSR | S_IWUSR)).get(), 5000));
+ CHECK(Stat::stat(filename).size() == 10000);
+
+ CHECK(util::fallocate(Fd(open(filename, O_RDWR, S_IRUSR | S_IWUSR)).get(),
+ 20000));
+ CHECK(Stat::stat(filename).size() == 20000);
+}
+
TEST_CASE("util::likely_size_on_disk")
{
CHECK(util::likely_size_on_disk(0) == 0);