Add temp file and FD support to TemporaryFileHandle

This commit adds file descriptor and temporary file management to
DuplicatableFileHandle, removing the redundant test-only
TemporaryFileHandle utility.

Changes:
- Add file descriptor constructor and setFd() method
- Add temporary file constructor with string_view content
- Add filePath member and automatic cleanup in destructor
- Add configurable temp-dir meson option (default: /tmp/bmcweb)
- Remove include/file_test_utilities.hpp
- Update all tests to use DuplicatableFileHandle
- Rename stringPath to filePath

These features will be used by the multipart parser to stream
large uploads to temporary files instead of keeping them in memory,
and by the update service to pass file descriptors over D-Bus.

Change-Id: I982f5928d453f9f0c13d91c3525006134ddc87b3
Signed-off-by: Rajeev Ranjan <ranjan.rajeev1609@gmail.com>
diff --git a/include/duplicatable_file_handle.hpp b/include/duplicatable_file_handle.hpp
index f199485..e346096 100644
--- a/include/duplicatable_file_handle.hpp
+++ b/include/duplicatable_file_handle.hpp
@@ -2,13 +2,63 @@
 
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-FileCopyrightText: Copyright OpenBMC Authors
+#include "bmcweb_config.h"
+
+#include "logging.hpp"
+
 #include <unistd.h>
 
 #include <boost/beast/core/file_posix.hpp>
 
+#include <cerrno>
+#include <filesystem>
+#include <string>
+#include <string_view>
+
 struct DuplicatableFileHandle
 {
     boost::beast::file_posix fileHandle;
+    std::string filePath;
+
+    // Construct from a file descriptor
+    explicit DuplicatableFileHandle(int fd)
+    {
+        fileHandle.native_handle(fd);
+    }
+
+    // Creates a temporary file with the contents provided, removes it on
+    // destruction.
+    explicit DuplicatableFileHandle(std::string_view contents)
+    {
+        std::filesystem::path tempDir("/tmp/bmcweb");
+        std::error_code ec;
+        std::filesystem::create_directories(tempDir, ec);
+        if (ec)
+        {
+            BMCWEB_LOG_ERROR("Failed to create directory {}: {}",
+                             tempDir.string(), ec.value());
+        }
+
+        filePath = (tempDir / "XXXXXXXXXXX").string();
+
+        int fd = mkstemp(filePath.data());
+        if (fd < 0)
+        {
+            BMCWEB_LOG_ERROR("Failed to create temporary file: {}", errno);
+            return;
+        }
+        ssize_t written = write(fd, contents.data(), contents.size());
+        if (written < 0 || static_cast<size_t>(written) != contents.size())
+        {
+            BMCWEB_LOG_ERROR("Failed to write to temporary file: {}", errno);
+        }
+        close(fd);
+    }
+
+    void setFd(int fd)
+    {
+        fileHandle.native_handle(fd);
+    }
 
     DuplicatableFileHandle() = default;
     DuplicatableFileHandle(DuplicatableFileHandle&&) noexcept = default;
@@ -29,5 +79,12 @@
     }
     DuplicatableFileHandle& operator=(DuplicatableFileHandle&& other) noexcept =
         default;
-    ~DuplicatableFileHandle() = default;
+
+    ~DuplicatableFileHandle()
+    {
+        if (!filePath.empty())
+        {
+            std::filesystem::remove(filePath);
+        }
+    }
 };
diff --git a/include/file_test_utilities.hpp b/include/file_test_utilities.hpp
deleted file mode 100644
index b12fbca..0000000
--- a/include/file_test_utilities.hpp
+++ /dev/null
@@ -1,42 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-// SPDX-FileCopyrightText: Copyright OpenBMC Authors
-#pragma once
-#include <unistd.h>
-
-#include <filesystem>
-#include <string>
-#include <string_view>
-
-#include <gtest/gtest.h>
-
-struct TemporaryFileHandle
-{
-    std::filesystem::path path;
-    std::string stringPath;
-
-    // Creates a temporary file with the contents provided, removes it on
-    // destruction.
-    explicit TemporaryFileHandle(std::string_view sampleData) :
-        path(std::filesystem::temp_directory_path() /
-             "bmcweb_http_response_test_XXXXXXXXXXX")
-    {
-        stringPath = path.string();
-
-        // NOLINTNEXTLINE(misc-include-cleaner)
-        int fd = mkstemp(stringPath.data());
-        EXPECT_GT(fd, 0);
-        EXPECT_EQ(write(fd, sampleData.data(), sampleData.size()),
-                  sampleData.size());
-        close(fd);
-    }
-
-    TemporaryFileHandle(const TemporaryFileHandle&) = delete;
-    TemporaryFileHandle(TemporaryFileHandle&&) = delete;
-    TemporaryFileHandle& operator=(const TemporaryFileHandle&) = delete;
-    TemporaryFileHandle& operator=(TemporaryFileHandle&&) = delete;
-
-    ~TemporaryFileHandle()
-    {
-        std::filesystem::remove(path);
-    }
-};