GCC Code Coverage Report


Directory: ./
File: Os/SandboxedFile.cpp
Date: 2026-09-23 22:11:34
Exec Total Coverage
Lines: 42 58 72.4%
Functions: 11 18 61.1%
Branches: 15 17 88.2%

Line Branch Exec Source
1 // ======================================================================
2 // \title Os/SandboxedFile.cpp
3 // \brief Implementation of directory-sandboxed file wrapper
4 // ======================================================================
5 #include <Fw/Types/Assert.hpp>
6 #include <Fw/Types/StringUtils.hpp>
7 #include <Os/SandboxedFile.hpp>
8 #include <cstring>
9
10 namespace Os {
11
12 // Fail-closed: open() returns OUTSIDE_SANDBOX until configure() is called
13
1/1
✓ Branch 2 taken 6 times.
6 SandboxedFile::SandboxedFile() : m_file(), m_allowedDirectory(""), m_configured(false) {}
14
15 6 SandboxedFile::~SandboxedFile() {
16
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 4 times.
6 if (m_file.isOpen()) {
17 2 m_file.close();
18 }
19 6 }
20
21 8 void SandboxedFile::configure(const char* allowedDirectory) {
22 8 FW_ASSERT(allowedDirectory != nullptr);
23 8 FW_ASSERT(!m_file.isOpen());
24
25 // Resolve the allowed directory (relative paths resolve against CWD)
26 char resolved[FilePathUtils::MAX_PATH_LENGTH];
27 const FilePathUtils::Status resolveStatus =
28
1/1
✓ Branch 1 taken 8 times.
8 FilePathUtils::resolveFromCwd(allowedDirectory, resolved, sizeof(resolved));
29 8 FW_ASSERT(resolveStatus == FilePathUtils::VALID);
30
31 // Ensure trailing '/'
32
1/1
✓ Branch 1 taken 8 times.
8 const FwSizeType resolvedLen = Fw::StringUtils::string_length(resolved, FilePathUtils::MAX_PATH_LENGTH);
33 8 FW_ASSERT(resolvedLen > 0);
34 8 FW_ASSERT(resolvedLen + 2 <= FilePathUtils::MAX_PATH_LENGTH);
35
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
8 if (resolved[resolvedLen - 1] != '/') {
36 6 resolved[resolvedLen] = '/';
37 6 resolved[resolvedLen + 1] = '\0';
38 }
39
40
1/1
✓ Branch 1 taken 8 times.
8 m_allowedDirectory = resolved;
41 8 m_configured = true;
42 8 }
43
44 ✗ bool SandboxedFile::isConfigured() const {
45 ✗ return m_configured;
46 }
47
48 6 Os::FileInterface::Status SandboxedFile::open(const char* path,
49 Os::FileInterface::Mode mode,
50 Os::FileInterface::OverwriteType overwrite) {
51 6 FW_ASSERT(path != nullptr);
52
53
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!m_configured) {
54 ✗ return Os::FileInterface::Status::OUTSIDE_SANDBOX;
55 }
56
57 // Resolve path against CWD then check containment
58 char resolvedPath[FilePathUtils::MAX_PATH_LENGTH];
59
1/1
✓ Branch 1 taken 6 times.
6 const FilePathUtils::Status resolveStatus = FilePathUtils::resolveFromCwd(path, resolvedPath, sizeof(resolvedPath));
60
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (resolveStatus != FilePathUtils::VALID) {
61 ✗ return Os::FileInterface::Status::OUTSIDE_SANDBOX;
62 }
63
64
3/3
✓ Branch 2 taken 6 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 4 times.
6 if (FilePathUtils::checkContainment(resolvedPath, m_allowedDirectory.toChar()) != FilePathUtils::VALID) {
65 2 return Os::FileInterface::Status::OUTSIDE_SANDBOX;
66 }
67
68
1/1
✓ Branch 1 taken 4 times.
4 return m_file.open(resolvedPath, mode, overwrite);
69 }
70
71 3 void SandboxedFile::close() {
72 3 m_file.close();
73 3 }
74
75 ✗ bool SandboxedFile::isOpen() const {
76 ✗ return m_file.isOpen();
77 }
78
79 ✗ Os::FileInterface::Status SandboxedFile::size(FwSizeType& size_result) {
80 ✗ return m_file.size(size_result);
81 }
82
83 1 Os::FileInterface::Status SandboxedFile::position(FwSizeType& position_result) {
84 1 return m_file.position(position_result);
85 }
86
87 ✗ Os::FileInterface::Status SandboxedFile::preallocate(FwSizeType offset, FwSizeType length) {
88 ✗ return m_file.preallocate(offset, length);
89 }
90
91 4 Os::FileInterface::Status SandboxedFile::seek(FwSignedSizeType offset, Os::FileInterface::SeekType seekType) {
92 4 return m_file.seek(offset, seekType);
93 }
94
95 ✗ Os::FileInterface::Status SandboxedFile::flush() {
96 ✗ return m_file.flush();
97 }
98
99 1 Os::FileInterface::Status SandboxedFile::read(U8* buffer, FwSizeType& size, Os::FileInterface::WaitType wait) {
100 1 return m_file.read(buffer, size, wait);
101 }
102
103 1 Os::FileInterface::Status SandboxedFile::read(U8* buffer, FwSizeType& size) {
104 1 return m_file.read(buffer, size);
105 }
106
107 3 Os::FileInterface::Status SandboxedFile::write(const U8* buffer, FwSizeType& size, Os::FileInterface::WaitType wait) {
108 3 return m_file.write(buffer, size, wait);
109 }
110
111 ✗ Os::FileInterface::Status SandboxedFile::write(const U8* buffer, FwSizeType& size) {
112 ✗ return m_file.write(buffer, size);
113 }
114
115 1 Os::FileInterface::Status SandboxedFile::calculateCrc(U32& crc) {
116 1 return m_file.calculateCrc(crc);
117 }
118
119 ✗ const char* SandboxedFile::getSandboxDirectory() const {
120 ✗ return m_allowedDirectory.toChar();
121 }
122
123 } // namespace Os
124