Skip to content

Replace CFile + CString path concatenation — std::filesystem or boost::filesystem

Classification

Abandoned by operator decision on 2026-05-21. This historical record preserves the old Boost/POCO analysis only as provenance; do not promote it without a new active item.

Summary

File operations go through CFile (MFC) and path manipulation is done via CString concatenation, which handles path separators inconsistently and provides no type-safety between path fragments and arbitrary strings.

Two equivalent replacement paths are documented. std::filesystem (C++17) and boost::filesystem have nearly identical APIs — the C++17 version is preferred unless Boost is already a dependency.

Affected Files

File Current usage
srchybrid/SafeFile.h:74-82 CSafeFile : public CFile — wraps MFC file
srchybrid/PartFile.h:145-156 GetFullName(), GetTmpPath(), GetRealFileSize() return CString paths
40+ additional files Mix of CFile, GetDiskFileSize(), _tmakepath, _tsplitpath calls

Current Code (PartFile.h)

const CString& GetFullName() const { return m_fullname; }
void SetFullName(const CString &name) { m_fullname = name; }
CString GetTmpPath() const;
EMFileSize GetRealFileSize() const { return GetDiskFileSize(GetFilePath()); }

Option A — std::filesystem (C++17, no Boost dependency)

Preferred. Zero new dependencies; C++17 already required by the project.

#include <filesystem>
namespace fs = std::filesystem;

// Type-safe path composition — correct separator on any OS
fs::path fullPath = fs::path(baseDir) / filename;
fs::path tmpPath  = fullPath.parent_path() / (fullPath.stem().wstring() + L".part");

// File queries — no manual GetFileAttributes / FindFirstFile
if (fs::exists(fullPath)) {
    uintmax_t  size  = fs::file_size(fullPath);
    auto       mtime = fs::last_write_time(fullPath);
}

// Safe removal — error_code variant avoids exception overhead
std::error_code ec;
fs::remove(fullPath, ec);

// Rename (atomic replacement — see also BUG-009)
fs::rename(tmpPath, fullPath, ec);

CString interop during gradual migration:

// Convert fs::path ↔ CString
fs::path fromCStr(const CString& s) { return fs::path((LPCTSTR)s); }
CString  toCStr(const fs::path& p)  { return CString(p.c_str()); }

Pros: No dependencies; identical to Boost.Filesystem API in most cases; integrates with std::error_code instead of Boost's equivalent.


Option B — boost::filesystem

Use only if Boost is already adopted for REF-008.

#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;

// API is nearly identical to std::filesystem:
fs::path fullPath = fs::path(baseDir) / filename;
if (fs::exists(fullPath)) {
    uintmax_t size = fs::file_size(fullPath);
}
boost::system::error_code ec;
fs::remove(fullPath, ec);

Key differences from std::filesystem: - Uses boost::system::error_code instead of std::error_code - fs::path::string() returns UTF-8 on all platforms (std::filesystem uses native encoding on Windows — may need wstring()) - Slightly more mature on MSVC pre-2019


Migration Strategy (both options)

  1. Add namespace fs = std::filesystem; (or boost::filesystem) to stdafx.h or a new PathUtils.h.
  2. Replace GetDiskFileSize() calls with fs::file_size().
  3. Replace _tmakepath / _tsplitpath patterns with fs::path composition.
  4. Migrate CSafeFile to wrap std::fstream instead of CFile.
  5. Coordinate with FEAT-010 (long path support) — std::filesystem on Win10 with long-path manifest handles paths > MAX_PATH natively.

Recommendation

Use Option A (std::filesystem) — available in C++17, no dependency, API virtually identical to boost::filesystem.

Files

  • srchybrid/SafeFile.h / .cpp
  • srchybrid/PartFile.h / .cpp
  • srchybrid/OtherFunctions.cppGetDiskFileSize() and path helpers
  • 40+ consumer files (migrate gradually)

Acceptance Criteria

  • [ ] _tmakepath / _tsplitpath calls replaced with fs::path composition
  • [ ] GetDiskFileSize() replaced with fs::file_size()
  • [ ] Path separator inconsistencies eliminated
  • [ ] CString-based path concat (dir + _T("\\") + file) replaced throughout the migrated files
  • [ ] Long paths handled correctly (via std::filesystem on Win10 with manifest)