Dawn Framework 1.0
Universal data acquisition framework for embedded systems
fileio.cxx
1// dawn/src/io/fileio.cxx
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5
6#include "dawn/io/fileio.hxx"
7
8#include <fcntl.h>
9#include <sys/stat.h>
10#include <unistd.h>
11
12#include <cstring>
13
14using namespace dawn;
15
18static const char g_prefix_data[] = "/data/";
19static const char g_prefix_tmp[] = "/tmp/";
20
21int CIOFile::configureDesc(const CDescObject &desc)
22{
23 const SObjectCfg::SObjectCfgItem *item = nullptr;
24 size_t offset = 0;
25 size_t nbytes = 0;
26 size_t i = 0;
27
28 for (i = 0; i < desc.getSize(); i++)
29 {
30 item = desc.objectCfgItemAtOffset(offset);
31
33 {
34 offset += cfgCmnOffset(item);
35 continue;
36 }
37
39 {
40 DAWNERR("unsupported fileio cfg 0x%08" PRIx32 "\n", item->cfgid.v);
41 return -EINVAL;
42 }
43
44 switch (item->cfgid.s.id)
45 {
47 {
48 nbytes = (size_t)item->cfgid.s.size * 4u;
49
50 if (nbytes >= PATH_MAX)
51 {
52 DAWNERR("file path too long: %zu bytes\n", nbytes);
53 return -ENAMETOOLONG;
54 }
55
56 std::memcpy(path, &item->data, nbytes);
57 path[nbytes] = '\0';
58
59 if (std::strstr(path, "..") != nullptr)
60 {
61 DAWNERR("path traversal not allowed: %s\n", path);
62 return -EACCES;
63 }
64
65 if (std::strncmp(path, g_prefix_data, sizeof(g_prefix_data) - 1) != 0 &&
66 std::strncmp(path, g_prefix_tmp, sizeof(g_prefix_tmp) - 1) != 0)
67 {
68 DAWNERR("path not in allowed directory: %s\n", path);
69 return -EACCES;
70 }
71
72 offset += (1 + (size_t)item->cfgid.s.size);
73 break;
74 }
75
77 {
78 const uint8_t *tmp = reinterpret_cast<const uint8_t *>(&item->data);
79
80 perm = *tmp;
81
82 if (perm > IO_FILE_PERM_WRITE_ONCE)
83 {
84 DAWNERR("invalid file permission: %u\n", (unsigned)perm);
85 return -EINVAL;
86 }
87
88 offset += 2;
89 break;
90 }
91
92 default:
93 {
94 DAWNERR("unsupported fileio cfg 0x%08" PRIx32 "\n", item->cfgid.v);
95 return -EINVAL;
96 }
97 }
98 }
99
100 return OK;
101}
102
103CIOFile::~CIOFile()
104{
105 deinit();
106}
107
109{
110 struct stat st;
111 int flags;
112 int ret;
113
114 ret = configureDesc(getDesc());
115 if (ret != OK)
116 {
117 return ret;
118 }
119
120 writeOnceLocked = false;
121
122 // Select open flags based on permission
123
124 if (perm == IO_FILE_PERM_READ)
125 {
126 flags = O_RDONLY;
127 }
128 else if (perm == IO_FILE_PERM_WRITE || perm == IO_FILE_PERM_WRITE_ONCE)
129 {
130 flags = O_WRONLY | O_CREAT;
131 }
132 else
133 {
134 // IO_FILE_PERM_RW
135
136 flags = O_RDWR | O_CREAT;
137 }
138
139 fd = open(path, flags, 0666);
140 if (fd < 0)
141 {
142 DAWNERR("failed to open %s: %d\n", path, errno);
143 return -errno;
144 }
145
146 // Determine file size for readable files
147
148 fsize = 0;
149 if (isRead())
150 {
151 ret = fstat(fd, &st);
152 if (ret < 0)
153 {
154 DAWNERR("fstat failed for %s: %d\n", path, errno);
155 close(fd);
156 fd = -1;
157 return -errno;
158 }
159
160 fsize = (size_t)st.st_size;
161 }
162 else if (perm == IO_FILE_PERM_WRITE_ONCE)
163 {
164 ret = fstat(fd, &st);
165 if (ret < 0)
166 {
167 DAWNERR("fstat failed for %s: %d\n", path, errno);
168 close(fd);
169 fd = -1;
170 return -errno;
171 }
172
173 writeOnceLocked = st.st_size > 0;
174 }
175
176 return OK;
177}
178
180{
181 if (fd >= 0)
182 {
183 close(fd);
184 fd = -1;
185 }
186
187 return OK;
188}
189
190int CIOFile::getDataImpl(IODataCmn &data, size_t len)
191{
192 ssize_t nread;
193
194 if (len != 1)
195 {
196 return -EINVAL;
197 }
198
199 if (data.getDataSize() < fsize)
200 {
201 return -ENOMEM;
202 }
203
204 if (lseek(fd, 0, SEEK_SET) < 0)
205 {
206 DAWNERR("lseek failed: %d\n", errno);
207 return -EIO;
208 }
209
210 nread = read(fd, data.getDataPtr(0), fsize);
211 if (nread < 0)
212 {
213 DAWNERR("read failed: %d\n", errno);
214 return -EIO;
215 }
216
217 return OK;
218}
219
221{
222 ssize_t nwritten;
223 int ret;
224
225 if (perm == IO_FILE_PERM_WRITE_ONCE && writeOnceLocked)
226 {
227 DAWNERR("write-once file already written: %s\n", path);
228 return -EPERM;
229 }
230
231 ret = ftruncate(fd, 0);
232 if (ret < 0)
233 {
234 DAWNERR("ftruncate failed: %d\n", errno);
235 return -EIO;
236 }
237
238 if (lseek(fd, 0, SEEK_SET) < 0)
239 {
240 DAWNERR("lseek failed: %d\n", errno);
241 return -EIO;
242 }
243
244 nwritten = write(fd, data.getDataPtr(0), data.getDataSize());
245 if (nwritten < 0)
246 {
247 DAWNERR("write failed: %d\n", errno);
248 return -EIO;
249 }
250
251 fsize = (size_t)nwritten;
252
253 if (perm == IO_FILE_PERM_WRITE_ONCE)
254 {
255 writeOnceLocked = true;
256 }
257
258 return OK;
259}
260
261int CIOFile::getDataAtImpl(IODataCmn &data, size_t len, size_t offset)
262{
263 ssize_t nread;
264
265 if (len != 1)
266 {
267 return -EINVAL;
268 }
269
270 if (offset >= fsize)
271 {
272 return -EINVAL;
273 }
274
275 if (lseek(fd, (off_t)offset, SEEK_SET) < 0)
276 {
277 DAWNERR("lseek failed: %d\n", errno);
278 return -EIO;
279 }
280
281 nread = read(fd, data.getDataPtr(0), data.getDataSize());
282 if (nread < 0)
283 {
284 DAWNERR("read failed: %d\n", errno);
285 return -EIO;
286 }
287
288 return OK;
289}
290
291int CIOFile::setDataAtImpl(IODataCmn &data, size_t offset)
292{
293 ssize_t nwritten;
294 int ret;
295 size_t endpos;
296
297 if (perm == IO_FILE_PERM_WRITE_ONCE && writeOnceLocked)
298 {
299 DAWNERR("write-once file already written: %s\n", path);
300 return -EPERM;
301 }
302
303 if (offset == 0)
304 {
305 ret = ftruncate(fd, 0);
306 if (ret < 0)
307 {
308 DAWNERR("ftruncate failed: %d\n", errno);
309 return -EIO;
310 }
311 }
312
313 if (lseek(fd, (off_t)offset, SEEK_SET) < 0)
314 {
315 DAWNERR("lseek failed: %d\n", errno);
316 return -EIO;
317 }
318
319 nwritten = write(fd, data.getDataPtr(0), data.getDataSize());
320 if (nwritten < 0)
321 {
322 DAWNERR("write failed: %d\n", errno);
323 return -EIO;
324 }
325
326 endpos = offset + (size_t)nwritten;
327 if (offset == 0 || endpos > fsize)
328 {
329 fsize = endpos;
330 }
331
332 if (perm == IO_FILE_PERM_WRITE_ONCE)
333 {
334 writeOnceLocked = true;
335 }
336
337 return OK;
338}
339
340#ifdef CONFIG_DAWN_IO_NOTIFY
341int CIOFile::getFd() const
342{
343 return -1;
344}
345#endif
346
348{
349 return fsize;
350}
351
353{
354 // Block payload uses 1-byte data units.
355
356 return fsize;
357}
358
359bool CIOFile::isRead() const
360{
361 return perm == IO_FILE_PERM_READ || perm == IO_FILE_PERM_RW;
362}
363
365{
366 return perm == IO_FILE_PERM_WRITE || perm == IO_FILE_PERM_RW || perm == IO_FILE_PERM_WRITE_ONCE;
367}
Descriptor wrapper for individual object configuration.
size_t getSize() const
Get number of configuration items for this object.
SObjectCfg::SObjectCfgItem * objectCfgItemAtOffset(size_t offset) const
Get configuration item at specified offset.
virtual int getFd() const
Get file descriptor for notifications.
Definition common.hxx:425
size_t cfgCmnOffset(const SObjectCfg::SObjectCfgItem *cfg)
Get offset of configuration item in descriptor.
Definition common.cxx:144
@ IO_CLASS_ANY
Any I/O class.
Definition common.hxx:86
@ IO_CLASS_FILE
File system I/O.
Definition common.hxx:109
int setDataImpl(IODataCmn &data)
Set data implementation (override in derived classes).
Definition fileio.cxx:220
@ IO_FILE_PERM_RW
Read-write.
Definition fileio.hxx:33
@ IO_FILE_PERM_WRITE
Write-only.
Definition fileio.hxx:32
@ IO_FILE_PERM_WRITE_ONCE
Write-once.
Definition fileio.hxx:34
@ IO_FILE_PERM_READ
Read-only.
Definition fileio.hxx:31
int getDataImpl(IODataCmn &data, size_t len)
Get data implementation (override in derived classes).
Definition fileio.cxx:190
size_t getDataDim() const
Get data vector dimension.
Definition fileio.cxx:352
int getDataAtImpl(IODataCmn &data, size_t len, size_t offset)
Get data at byte offset (override in seekable IOs).
Definition fileio.cxx:261
int deinit()
De-initialize object.
Definition fileio.cxx:179
@ IO_FILE_CFG_PATH
File path (null-terminated string, DTYPE_CHAR).
Definition fileio.hxx:40
@ IO_FILE_CFG_PERM
Permission mode (EIOFilePerm, DTYPE_UINT8).
Definition fileio.hxx:41
size_t getDataSize() const
Get data size in bytes.
Definition fileio.cxx:347
bool isWrite() const
Check if IO supports write operations.
Definition fileio.cxx:364
bool isRead() const
Check if IO supports read operations.
Definition fileio.cxx:359
int setDataAtImpl(IODataCmn &data, size_t offset)
Set data at byte offset (override in seekable IOs).
Definition fileio.cxx:291
int configure()
Configure object from descriptor data.
Definition fileio.cxx:108
CDescObject & getDesc()
Get descriptor object for this object.
Definition object.cxx:190
Out-of-tree user-extension hooks for Dawn.
Definition bindable.hxx:13
Base interface for I/O data buffers (static and dynamic).
Definition idata.hxx:21
virtual void * getDataPtr(size_t batch=0)=0
Get pointer to data only (skips timestamp if present).
virtual size_t getDataSize()=0
Get data size in bytes.
Single configuration item within object.
ObjectCfgData_t data[]
Configuration data array (flexible, size from cfgid.s.size).
UObjectCfgId cfgid
Configuration ID header (type, class, id, size, rw, dtype).
ObjectCfgId v
Raw 32-bit ConfigID value (for storage, comparison).
Definition objectcfg.hxx:82
uint32_t cls
Object class (bits 21-29, max 511).
uint32_t id
Configuration identifier (bits 0-4, max 31).
Definition objectcfg.hxx:94
uint32_t size
Configuration data size in 32-bit words (bits 5-14, max 1023).
struct dawn::SObjectCfg::UObjectCfgId::@10 s
Bit-field structure for named member access.