GCC Code Coverage Report


Directory: ./
File: Os/SandboxedFile.cpp
Date: 2026-09-23 21:11:01
Exec Total Coverage
Lines: 54 60 90.0%
Functions: 15 18 83.3%
Branches: 18 21 85.7%

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