From 3d83c00bb5ff2b832538eddcd6c3c2a2ac6b4b3b Mon Sep 17 00:00:00 2001
From: Roel Standaert <roel@emweb.be>
Date: Wed, 18 Jan 2023 16:37:32 +0100
Subject: [PATCH] WT-11262: replace uses of stat with boost::filesystem

- Git example: `S_ISDIR` may become `boost::filesystem::is_directory`
- fcgi server: stat() is used for an exists check, so we can use
  `boost::filesystem::exists`
- HTTP configuration: multiple checks are done on the same file. Let's
  use `boost::filesystem::status` instead of stat()
- web configuration: stat() is used for an exists check, so we can use
  `boost::filesystem::exists`

Linking with Boost::filesystem where necessary.
---
 ReleaseNotes.html                     | 14 +++++++++++
 examples/CMakeLists.txt               |  1 +
 examples/gitmodel/Git.C               |  9 +++----
 examples/widgetgallery/CMakeLists.txt |  4 +++
 src/fcgi/CMakeLists.txt               |  2 ++
 src/fcgi/Server.C                     | 10 +++++---
 src/http/Configuration.C              | 35 +++++++++++----------------
 src/web/Configuration.C               | 10 +++++---
 8 files changed, 51 insertions(+), 34 deletions(-)

diff --git a/ReleaseNotes.html b/ReleaseNotes.html
index ae7b054db..72869cbd1 100644
--- a/ReleaseNotes.html
+++ b/ReleaseNotes.html
@@ -30,6 +30,20 @@ behaviour.
   </li>
 </ul>
 
+<h2>Release 4.9.2 (TBD)</h2>
+
+<p>
+  Wt 4.9.2 is a patch release that addresses the following issues:
+</p>
+
+<ul>
+  <li>
+    <a href="https://redmine.emweb.be/issues/11262" target="_blank">Issue #11262</a>:
+    fixed an issue where 32 bit Linux builds could cause <code>stat()</code> to
+    fail with <code>EOVERFLOW</code>.
+  </li>
+</ul>
+
 <h2>Release 4.9.1 (January 20, 2023)</h2>
 
 <p>
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index fbc6b03d7..fdf1ac661 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -74,6 +74,7 @@ IF("${CMAKE_CURRENT_LIST_DIR}" STREQUAL "${CMAKE_SOURCE_DIR}")
 
     IF(${Boost_FOUND})
       SET(BOOST_FS_LIB ${Boost_FILESYSTEM_LIBRARY})
+      set(BOOST_SYSTEM_LIB "")
       SET(BOOST_WT_FOUND true)
       INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIR})
       LINK_DIRECTORIES(${Boost_LIBRARY_DIRS})
diff --git a/examples/gitmodel/Git.C b/examples/gitmodel/Git.C
index 399dd566e..b78fbbed4 100644
--- a/examples/gitmodel/Git.C
+++ b/examples/gitmodel/Git.C
@@ -14,8 +14,7 @@
 #include <boost/algorithm/string/classification.hpp>
 #include <boost/algorithm/string/predicate.hpp>
 #include <boost/algorithm/string/split.hpp>
-
-#include <sys/stat.h>
+#include <boost/filesystem.hpp>
 
 using namespace Wt;
 
@@ -205,9 +204,9 @@ Git::Git()
 
 void Git::setRepositoryPath(const std::string& repositoryPath)
 {
-  struct stat sb;
-  is_bare_ = !(stat((repositoryPath + "/.git").c_str(), &sb) == 0 &&
-               S_ISDIR(sb.st_mode));
+  namespace fs = boost::filesystem;
+  boost::system::error_code ignored;
+  is_bare_ = !fs::is_directory(fs::path(repositoryPath) / ".git", ignored);
   repository_ = repositoryPath;
   checkRepository();
 }
diff --git a/examples/widgetgallery/CMakeLists.txt b/examples/widgetgallery/CMakeLists.txt
index 97767f229..ee8451a44 100644
--- a/examples/widgetgallery/CMakeLists.txt
+++ b/examples/widgetgallery/CMakeLists.txt
@@ -29,6 +29,10 @@ WT_ADD_EXAMPLE(widgetgallery.wt
   ${WIDGETGALLERY_SOURCES}
 )
 
+if(NOT WIN32)
+  target_link_libraries(widgetgallery.wt ${BOOST_FS_LIB} ${BOOST_SYSTEM_LIB})
+endif()
+
 IF(TARGET Boost::headers)
   TARGET_LINK_LIBRARIES(widgetgallery.wt Boost::headers)
 ENDIF()
diff --git a/src/fcgi/CMakeLists.txt b/src/fcgi/CMakeLists.txt
index 2c132afa8..1bb9a1747 100644
--- a/src/fcgi/CMakeLists.txt
+++ b/src/fcgi/CMakeLists.txt
@@ -34,6 +34,8 @@ IF(CONNECTOR_FCGI)
       TARGET_LINK_LIBRARIES(wtfcgi PRIVATE ${WT_THREAD_LIB})
     ENDIF(MULTI_THREADED_BUILD)
 
+    target_link_libraries(wtfcgi PRIVATE ${BOOST_FS_LIB} ${BOOST_SYSTEM_LIB})
+
     SET_TARGET_PROPERTIES(
       wtfcgi
     PROPERTIES
diff --git a/src/fcgi/Server.C b/src/fcgi/Server.C
index d36c5b1a0..c6bcb6429 100644
--- a/src/fcgi/Server.C
+++ b/src/fcgi/Server.C
@@ -7,7 +7,6 @@
 #include <signal.h>
 #include <stdlib.h>
 #include <unistd.h>
-#include <sys/stat.h>
 #include <sys/socket.h>
 #include <sys/types.h>
 #include <sys/un.h>
@@ -33,6 +32,8 @@
 
 #include <boost/algorithm/string.hpp>
 
+#include <boost/filesystem.hpp>
+
 using std::exit;
 using std::strcpy;
 using std::strlen;
@@ -546,12 +547,13 @@ void Server::handleRequest(int serverSocket)
      * See if the session is alive.
      */
     if (haveSessionId) {
-      struct stat finfo;
-
       // exists, try to connect (for 1 second)
       std::string path = socketPath(sessionId);
-      if (stat(path.c_str(), &finfo) != -1)
+
+      boost::system::error_code ignored;
+      if (boost::filesystem::exists(path, ignored)) {
         clientSocket = connectToSession(sessionId, path, 10);
+      }
     }
 
     while (clientSocket == -1) {
diff --git a/src/http/Configuration.C b/src/http/Configuration.C
index 0fe689dae..0d75435f3 100644
--- a/src/http/Configuration.C
+++ b/src/http/Configuration.C
@@ -12,8 +12,8 @@
 #include "WebUtils.h"
 #include "StringUtils.h"
 
-#include <sys/types.h>
-#include <sys/stat.h>
+#include <boost/filesystem.hpp>
+
 #ifndef WT_WIN32
 #include <unistd.h>
 #endif
@@ -436,18 +436,6 @@ Wt::WLogEntry Configuration::log(const std::string& type) const
   return e;
 }
 
-#ifdef _MSC_VER
-static inline bool S_ISREG(unsigned short mode)
-{
-   return (mode & S_IFREG) != 0;
-}
-
-static inline bool S_ISDIR(unsigned short mode)
-{
-   return (mode & S_IFDIR) != 0;
-}
-#endif
-
 void Configuration::checkPath(const po::variables_map& vm,
                               std::string varName,
                               std::string varDescription,
@@ -468,31 +456,36 @@ void Configuration::checkPath(std::string& result,
                               std::string varDescription,
                               int options)
 {
-  struct stat t;
-  if (stat(result.c_str(), &t) != 0) {
-    std::perror("stat");
+  namespace fs = boost::filesystem;
+  boost::system::error_code ec;
+  const auto status = fs::status(result, ec);
+  if (ec) {
+    throw Wt::WServer::Exception(varDescription
+                                 + " (\"" + result + "\") not valid: "
+                                 + ec.message());
+  } else if (!exists(status)) {
     throw Wt::WServer::Exception(varDescription
-                                 + " (\"" + result + "\") not valid.");
+                                 + " (\"" + result + "\") does not exist.");
   } else {
     if (options & Directory) {
       while (result[result.length()-1] == '/')
         result = result.substr(0, result.length() - 1);
 
-      if (!S_ISDIR(t.st_mode)) {
+      if (!is_directory(status)) {
         throw Wt::WServer::Exception(varDescription + " (\"" + result
                                      + "\") must be a directory.");
       }
     }
 
     if (options & RegularFile) {
-      if (!S_ISREG(t.st_mode)) {
+      if (!is_regular_file(status)) {
         throw Wt::WServer::Exception(varDescription + " (\"" + result
                                      + "\") must be a regular file.");
       }
     }
 #ifndef WT_WIN32
     if (options & Private) {
-      if (t.st_mode & (S_IRWXG | S_IRWXO)) {
+      if ((status.permissions() & (fs::perms::group_all | fs::perms::others_all)) != fs::perms::no_perms) {
         throw Wt::WServer::Exception(varDescription + " (\"" + result
                             + "\") must be unreadable for group and others.");
       }
diff --git a/src/web/Configuration.C b/src/web/Configuration.C
index 9f1586489..efb9bdae5 100644
--- a/src/web/Configuration.C
+++ b/src/web/Configuration.C
@@ -12,11 +12,11 @@
 #include "WebUtils.h"
 
 #include <boost/algorithm/string.hpp>
+#include <boost/filesystem.hpp>
+
 #ifdef WT_BOOST_CONF_LOCK
 #include <boost/thread.hpp>
 #endif
-#include <sys/types.h>
-#include <sys/stat.h>
 #include <fcntl.h>
 #include <algorithm>
 #include <array>
@@ -1399,9 +1399,11 @@ bool Configuration::registerSessionId(const std::string& oldId,
     if (!newId.empty()) {
       std::string socketPath = sessionSocketPath(newId);
 
-      struct stat finfo;
-      if (stat(socketPath.c_str(), &finfo) != -1)
+      namespace fs = boost::filesystem;
+      boost::system::error_code ignored;
+      if (fs::exists(socketPath, ignored)) {
         return false;
+      }
 
       if (oldId.empty()) {
         if (sessionPolicy_ == SharedProcess) {
-- 
2.34.1

