Logger System 0.1.3
High-performance C++20 thread-safe logging system with asynchronous capabilities
Loading...
Searching...
No Matches
kcenon::logger::utils::file_utils Class Reference

File utility functions for path validation and sanitization. More...

#include <file_utils.h>

Collaboration diagram for kcenon::logger::utils::file_utils:
Collaboration graph

Static Public Member Functions

static common::VoidResult validate_log_path (const std::filesystem::path &path, const std::filesystem::path &allowed_base="")
 Validate log file path against path traversal attacks.
 
static std::string sanitize_filename (const std::string &filename)
 Sanitize filename by removing/replacing dangerous characters.
 
static common::VoidResult set_file_permissions (const std::filesystem::path &file, std::filesystem::perms perms=std::filesystem::perms::owner_read|std::filesystem::perms::owner_write)
 Set file permissions (Unix/POSIX systems)
 
static bool is_absolute (const std::filesystem::path &path)
 Check if path is absolute.
 
static std::size_t get_file_size (const std::filesystem::path &path)
 Get file size.
 
static bool is_writable (const std::filesystem::path &path)
 Check if file exists and is writable.
 
static std::string generate_temp_filename (const std::string &prefix="temp", const std::string &extension=".tmp")
 Generate safe temporary filename.
 

Detailed Description

File utility functions for path validation and sanitization.

Provides security-focused file operations including path traversal prevention, filename sanitization, and permission management.

Note
These utilities are essential for Phase 4 (Security Hardening).

Definition at line 28 of file file_utils.h.

Member Function Documentation

◆ generate_temp_filename()

static std::string kcenon::logger::utils::file_utils::generate_temp_filename ( const std::string & prefix = "temp",
const std::string & extension = ".tmp" )
inlinestatic

Generate safe temporary filename.

Parameters
prefixPrefix for temporary file
extensionExtension for file (default: .tmp)
Returns
Safe temporary filename with timestamp

Format: prefix_YYYYMMDDHHMMSS_random.extension

Note
Thread-safe. Does not create the file.
Includes timestamp and random component for uniqueness.

Definition at line 311 of file file_utils.h.

314 {
315 auto now = std::chrono::system_clock::now();
316 auto time_t = std::chrono::system_clock::to_time_t(now);
317
318 std::tm tm_buf{};
319#ifdef _WIN32
320 localtime_s(&tm_buf, &time_t);
321#else
322 localtime_r(&time_t, &tm_buf);
323#endif
324
325 // Format: prefix_YYYYMMDDHHMMSS_random.ext
326 char buffer[64];
327 std::snprintf(buffer, sizeof(buffer),
328 "%s_%04d%02d%02d%02d%02d%02d_%d%s",
329 sanitize_filename(prefix).c_str(),
330 tm_buf.tm_year + 1900,
331 tm_buf.tm_mon + 1,
332 tm_buf.tm_mday,
333 tm_buf.tm_hour,
334 tm_buf.tm_min,
335 tm_buf.tm_sec,
336 static_cast<int>(std::chrono::steady_clock::now().time_since_epoch().count() % 10000),
337 extension.c_str());
338
339 return std::string(buffer);
340 }
static std::string sanitize_filename(const std::string &filename)
Sanitize filename by removing/replacing dangerous characters.
Definition file_utils.h:138

References sanitize_filename().

Here is the call graph for this function:

◆ get_file_size()

static std::size_t kcenon::logger::utils::file_utils::get_file_size ( const std::filesystem::path & path)
inlinestatic

Get file size.

Parameters
pathPath to file
Returns
File size in bytes, or 0 if file doesn't exist/error
Note
Thread-safe. Does not modify filesystem.
Returns 0 on error (file not found, no permissions, etc.)

Definition at line 260 of file file_utils.h.

260 {
261 std::error_code ec;
262 auto size = std::filesystem::file_size(path, ec);
263 if (ec) {
264 return 0;
265 }
266 return static_cast<std::size_t>(size);
267 }
@ size
Rotate based on file size only.

References kcenon::logger::size.

◆ is_absolute()

static bool kcenon::logger::utils::file_utils::is_absolute ( const std::filesystem::path & path)
inlinestatic

Check if path is absolute.

Parameters
pathPath to check
Returns
true if path is absolute, false otherwise
Note
Thread-safe.

Definition at line 248 of file file_utils.h.

248 {
249 return path.is_absolute();
250 }

◆ is_writable()

static bool kcenon::logger::utils::file_utils::is_writable ( const std::filesystem::path & path)
inlinestatic

Check if file exists and is writable.

Parameters
pathPath to file
Returns
true if file exists and is writable, false otherwise
Note
Thread-safe. Does not modify filesystem.

Definition at line 276 of file file_utils.h.

276 {
277 std::error_code ec;
278
279 // If file doesn't exist, check if parent directory is writable
280 if (!std::filesystem::exists(path, ec)) {
281 auto parent = path.parent_path();
282 if (parent.empty()) {
283 parent = ".";
284 }
285 return std::filesystem::exists(parent, ec) &&
286 !ec; // Basic existence check
287 }
288
289 // File exists, check status
290 auto status = std::filesystem::status(path, ec);
291 if (ec) {
292 return false;
293 }
294
295 // Check if we have write permissions
296 auto perms = status.permissions();
297 return (perms & std::filesystem::perms::owner_write) != std::filesystem::perms::none;
298 }

◆ sanitize_filename()

static std::string kcenon::logger::utils::file_utils::sanitize_filename ( const std::string & filename)
inlinestatic

Sanitize filename by removing/replacing dangerous characters.

Parameters
filenameFilename to sanitize
Returns
Sanitized filename safe for filesystem use

Transformations:

  • Removes path separators (/, )
  • Replaces control characters with underscore
  • Removes null bytes
  • Truncates to reasonable length (255 characters)
  • Preserves extension if present
Note
Thread-safe. Creates a new string.
Does not validate path components, only sanitizes filename.

Usage example:

std::string safe_name = file_utils::sanitize_filename(
user_input_filename
);

Definition at line 138 of file file_utils.h.

138 {
139 if (filename.empty()) {
140 return "unnamed.log";
141 }
142
143 std::string result;
144 result.reserve(filename.size());
145
146 for (char c : filename) {
147 // Remove path separators
148 if (c == '/' || c == '\\') {
149 continue;
150 }
151
152 // Remove null bytes
153 if (c == '\0') {
154 continue;
155 }
156
157 // Replace control characters with underscore
158 if (c < 32 || c == 127) {
159 result += '_';
160 continue;
161 }
162
163 // Remove potentially dangerous characters
164 if (c == ':' || c == '*' || c == '?' || c == '"' ||
165 c == '<' || c == '>' || c == '|') {
166 result += '_';
167 continue;
168 }
169
170 result += c;
171 }
172
173 // Truncate to safe length (255 is common filesystem limit)
174 if (result.size() > 255) {
175 // Try to preserve extension
176 size_t ext_pos = result.find_last_of('.');
177 if (ext_pos != std::string::npos && ext_pos > 250) {
178 // Extension is reasonable, keep it
179 std::string ext = result.substr(ext_pos);
180 result = result.substr(0, 255 - ext.size()) + ext;
181 } else {
182 result = result.substr(0, 255);
183 }
184 }
185
186 // Ensure result is not empty
187 if (result.empty()) {
188 return "unnamed.log";
189 }
190
191 return result;
192 }

Referenced by generate_temp_filename().

Here is the caller graph for this function:

◆ set_file_permissions()

static common::VoidResult kcenon::logger::utils::file_utils::set_file_permissions ( const std::filesystem::path & file,
std::filesystem::perms perms = std::filesystem::perms::owner_read | std::filesystem::perms::owner_write )
inlinestatic

Set file permissions (Unix/POSIX systems)

Parameters
filePath to file
permsPermissions to set (default: owner read/write only)
Returns
common::VoidResult Success or error

Default permissions (0600):

  • Owner: read + write
  • Group: none
  • Others: none
Note
On Windows, this function has limited effect (read-only flag).
Thread-safe. Modifies filesystem.
Important for Phase 4 security (encryption keys, sensitive logs).

Usage example:

// Make log file readable only by owner
"sensitive.log",
std::filesystem::perms::owner_read
);
static common::VoidResult set_file_permissions(const std::filesystem::path &file, std::filesystem::perms perms=std::filesystem::perms::owner_read|std::filesystem::perms::owner_write)
Set file permissions (Unix/POSIX systems)
Definition file_utils.h:218

Definition at line 218 of file file_utils.h.

222 {
223 try {
224 if (!std::filesystem::exists(file)) {
227 "File does not exist: " + file.string()
228 );
229 }
230
231 std::filesystem::permissions(file, perms);
232 return common::ok();
233 } catch (const std::filesystem::filesystem_error& e) {
236 std::string("Failed to set file permissions: ") + e.what()
237 );
238 }
239 }
VoidResult ok()
common::VoidResult make_logger_void_result(logger_error_code code, const std::string &message="")

References kcenon::logger::file_open_failed, kcenon::logger::file_permission_denied, kcenon::logger::make_logger_void_result(), and kcenon::common::ok().

Here is the call graph for this function:

◆ validate_log_path()

static common::VoidResult kcenon::logger::utils::file_utils::validate_log_path ( const std::filesystem::path & path,
const std::filesystem::path & allowed_base = "" )
inlinestatic

Validate log file path against path traversal attacks.

Parameters
pathFile path to validate
allowed_baseBase directory where log files are allowed (optional)
Returns
common::VoidResult Success if path is valid, error otherwise

Security checks:

  • Prevents path traversal (e.g., ../../../etc/passwd)
  • Ensures path is within allowed_base directory (if specified)
  • Validates path doesn't contain suspicious patterns
  • Uses canonical path resolution to prevent symlink attacks
Note
Thread-safe. Does not modify filesystem.
Critical for Phase 4 security requirements.

Usage example:

"logs/app.log",
"/var/log/myapp"
);
if (!result) {
// Path is invalid or outside allowed directory
}
static common::VoidResult validate_log_path(const std::filesystem::path &path, const std::filesystem::path &allowed_base="")
Validate log file path against path traversal attacks.
Definition file_utils.h:56

Definition at line 56 of file file_utils.h.

59 {
60 try {
61 // Check for obviously suspicious patterns
62 std::string path_str = path.string();
63
64 // Detect path traversal attempts
65 if (path_str.find("..") != std::string::npos) {
68 "Path contains '..' (path traversal attempt)"
69 );
70 }
71
72 // If allowed_base is specified, ensure path is within it
73 if (!allowed_base.empty()) {
74 // Convert both paths to canonical form (resolves symlinks)
75 std::filesystem::path canonical_path;
76 std::filesystem::path canonical_base;
77
78 // Get canonical base (must exist)
79 if (std::filesystem::exists(allowed_base)) {
80 canonical_base = std::filesystem::canonical(allowed_base);
81 } else {
82 canonical_base = std::filesystem::absolute(allowed_base);
83 }
84
85 // Get canonical path (may not exist yet for new files)
86 std::filesystem::path parent = path.parent_path();
87 if (!parent.empty() && std::filesystem::exists(parent)) {
88 canonical_path = std::filesystem::canonical(parent) / path.filename();
89 } else {
90 canonical_path = std::filesystem::absolute(path);
91 }
92
93 // Check if canonical_path starts with canonical_base
94 auto [base_end, path_end] = std::mismatch(
95 canonical_base.begin(), canonical_base.end(),
96 canonical_path.begin(), canonical_path.end()
97 );
98
99 if (base_end != canonical_base.end()) {
102 "Path is outside allowed directory: " + path_str
103 );
104 }
105 }
106
107 return common::ok(); // Valid path
108 } catch (const std::filesystem::filesystem_error& e) {
111 std::string("Path validation failed: ") + e.what()
112 );
113 }
114 }

References kcenon::logger::file_permission_denied, kcenon::logger::make_logger_void_result(), kcenon::common::ok(), and kcenon::logger::sanitization_failed.

Here is the call graph for this function:

The documentation for this class was generated from the following file: