From f268d260e39ec2ad28eb62db4ad641e2cb58e311 Mon Sep 17 00:00:00 2001
From: bugdea1er <bugdealer@icloud.com>
Date: Tue, 21 Jan 2025 23:53:32 +0300
Subject: [PATCH] Add `file::size` method

---
 include/tmp/file | 11 +++++++++++
 src/file.cpp     | 32 ++++++++++++++++++++++++++++++++
 tests/file.cpp   | 12 ++++++++++++
 3 files changed, 55 insertions(+)

diff --git a/include/tmp/file b/include/tmp/file
index b5839e2..986235f 100644
--- a/include/tmp/file
+++ b/include/tmp/file
@@ -72,6 +72,17 @@ public:
                    std::string_view label = "",
                    std::string_view extension = "");
 
+  /// Returns the size of this file
+  /// @returns the size of this file, in bytes
+  /// @throws std::filesystem::filesystem_error if cannot get a file size
+  std::uintmax_t size() const;
+
+  /// Returns the size of this file
+  /// @param[out] ec Parameter for error reporting
+  /// @returns the size of this file, in bytes
+  /// @throws std::filesystem::filesystem_error if cannot get a file size
+  std::uintmax_t size(std::error_code& ec) const;
+
   /// Reads the entire contents of this file
   /// @returns A string with this file contents
   /// @throws std::filesystem::filesystem_error if cannot read the file contents
diff --git a/src/file.cpp b/src/file.cpp
index d67bc4c..7ab3d17 100644
--- a/src/file.cpp
+++ b/src/file.cpp
@@ -19,6 +19,7 @@
 #include <Windows.h>
 #else
 #include <cerrno>
+#include <sys/stat.h>
 #include <unistd.h>
 #endif
 
@@ -131,6 +132,37 @@ file file::copy(const fs::path& path, std::string_view label,
   return tmpfile;
 }
 
+std::uintmax_t file::size() const {
+  std::error_code ec;
+  std::uintmax_t result = size(ec);
+
+  if (ec) {
+    throw fs::filesystem_error("Cannot get a temporary file size", path(), ec);
+  }
+
+  return result;
+}
+
+std::uintmax_t file::size(std::error_code& ec) const {
+#ifdef _WIN32
+  LARGE_INTERGER size;
+  if (!GetFileSize(native_handle(), &size)) {
+    ec = std::error_code(GetLastError(), std::system_category());
+    return static_cast<std::uintmax_t>(-1);
+  }
+
+  return size;
+#else
+  struct stat stat;
+  if (fstat(native_handle(), &stat) == -1) {
+    ec = std::error_code(errno, std::system_category());
+    return static_cast<std::uintmax_t>(-1);
+  }
+
+  return stat.st_size;
+#endif
+}
+
 std::string file::read() const {
   std::error_code ec;
   std::string content = read(ec);
diff --git a/tests/file.cpp b/tests/file.cpp
index dc1de7d..211d863 100644
--- a/tests/file.cpp
+++ b/tests/file.cpp
@@ -110,6 +110,18 @@ TEST(file, copy_directory) {
   EXPECT_THROW(file::copy(tmpdir), fs::filesystem_error);
 }
 
+/// Tests getting a file size
+TEST(file, size) {
+  file empty = file();
+  EXPECT_EQ(empty.size(), 0);
+
+  std::string_view content = "Hello, world!";
+
+  file nonempty = file();
+  nonempty.write(content);
+  EXPECT_EQ(nonempty.size(), content.size());
+}
+
 /// Tests binary file reading
 TEST(file, read_binary) {
   file tmpfile = file();