Branch data Line data Source code
1 : : /* SPDX-FileCopyrightText: Copyright 2026 Cozens Software Solutions Limited
2 : : * SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 OR LicenseRef-PolyForm-Internal-Use-1.0.0 OR LicenseRef-COSOSO-Commercial
3 : : */
4 : :
5 : : #include "SolidSyslogVxWorks64File.h"
6 : :
7 : : #include <errno.h>
8 : : #include <stdbool.h>
9 : : #include <stddef.h>
10 : :
11 : : #include "vxWorks.h"
12 : :
13 : : #include <sys/stat.h>
14 : :
15 : : #include "dosFsLib.h"
16 : : #include "ioLib.h"
17 : :
18 : : #include "SolidSyslogError.h"
19 : : #include "SolidSyslogErrorCategory.h"
20 : : #include "SolidSyslogFileCategories.h"
21 : : #include "SolidSyslogFileDefinition.h"
22 : : #include "SolidSyslogNullFile.h"
23 : : #include "SolidSyslogVxWorks64FileErrors.h"
24 : : #include "SolidSyslogVxWorks64FilePrivate.h"
25 : :
26 : : const struct SolidSyslogErrorSource SolidSyslogVxWorks64FileErrorSource = {"VxWorks64File", SolidSyslogFileErrors_Name};
27 : :
28 : : /* rw------- : dosFs ignores the mode, HRFS keeps it. Spelled in hex because
29 : : * MISRA 7.1 rules out the octal the permission bits are usually written in. */
30 : : enum
31 : : {
32 : : VXWORKS64FILE_OWNER_READ_WRITE = 0x180
33 : : };
34 : :
35 : : static bool VxWorks64File_Open(struct SolidSyslogFile* base, const char* path);
36 : : static void VxWorks64File_Close(struct SolidSyslogFile* base);
37 : : static bool VxWorks64File_IsOpen(struct SolidSyslogFile* base);
38 : : static bool VxWorks64File_Read(struct SolidSyslogFile* base, void* buf, size_t count);
39 : : static bool VxWorks64File_Write(struct SolidSyslogFile* base, const void* buf, size_t count);
40 : : static void VxWorks64File_SeekTo(struct SolidSyslogFile* base, size_t offset);
41 : : static bool VxWorks64File_Size(struct SolidSyslogFile* base, size_t* size);
42 : : static void VxWorks64File_Truncate(struct SolidSyslogFile* base);
43 : : static bool VxWorks64File_Exists(struct SolidSyslogFile* base, const char* path);
44 : : static bool VxWorks64File_Delete(struct SolidSyslogFile* base, const char* path);
45 : :
46 : : static inline struct SolidSyslogVxWorks64File* VxWorks64File_SelfFromBase(struct SolidSyslogFile* base);
47 : : static inline bool VxWorks64File_IsWholeTransfer(int transferred, size_t count);
48 : : static inline bool VxWorks64File_Commit(int fd);
49 : : static inline bool VxWorks64File_Sync(int fd);
50 : : static inline bool VxWorks64File_CommitFileSystem(int fd);
51 : : static inline void VxWorks64File_ReportFailure(enum SolidSyslogFileErrors code, int nativeErrno);
52 : : static inline bool VxWorks64File_IsNotThere(int removeErrno);
53 : :
54 : 86 : void SolidSyslogVxWorks64File_Initialise(struct SolidSyslogFile* base)
55 : : {
56 : 86 : struct SolidSyslogVxWorks64File* self = VxWorks64File_SelfFromBase(base);
57 : 86 : self->Base.Open = VxWorks64File_Open;
58 : 86 : self->Base.Close = VxWorks64File_Close;
59 : 86 : self->Base.IsOpen = VxWorks64File_IsOpen;
60 : 86 : self->Base.Read = VxWorks64File_Read;
61 : 86 : self->Base.Write = VxWorks64File_Write;
62 : 86 : self->Base.SeekTo = VxWorks64File_SeekTo;
63 : 86 : self->Base.Size = VxWorks64File_Size;
64 : 86 : self->Base.Truncate = VxWorks64File_Truncate;
65 : 86 : self->Base.Exists = VxWorks64File_Exists;
66 : 86 : self->Base.Delete = VxWorks64File_Delete;
67 : 86 : self->Fd = ERROR;
68 : 86 : }
69 : :
70 : 86 : void SolidSyslogVxWorks64File_Cleanup(struct SolidSyslogFile* base)
71 : : {
72 : 86 : VxWorks64File_Close(base);
73 : : /* Use-after-destroy lands on the NullFile vtable. */
74 : 86 : *base = *SolidSyslogNullFile_Get();
75 : 86 : }
76 : :
77 : 602 : static inline struct SolidSyslogVxWorks64File* VxWorks64File_SelfFromBase(struct SolidSyslogFile* base)
78 : : {
79 : 602 : return (struct SolidSyslogVxWorks64File*) base;
80 : : }
81 : :
82 : 68 : static bool VxWorks64File_Open(struct SolidSyslogFile* base, const char* path)
83 : : {
84 : 68 : struct SolidSyslogVxWorks64File* self = VxWorks64File_SelfFromBase(base);
85 : 68 : self->Fd = open(path, O_RDWR | O_CREAT, VXWORKS64FILE_OWNER_READ_WRITE);
86 : : /* Read errno straight after the call that set it, with nothing between
87 : : * (MISRA 22.10). */
88 [ + + ]: 68 : int openErrno = (self->Fd == ERROR) ? errno : 0;
89 : 68 : bool opened = self->Fd != ERROR;
90 [ + + ]: 68 : if (!opened)
91 : : {
92 : 3 : VxWorks64File_ReportFailure(SOLIDSYSLOG_FILE_ERROR_OPEN_FAILED, openErrno);
93 : : }
94 : 68 : return opened;
95 : : }
96 : :
97 : : /* The fault, with the errno behind it when the call left one. */
98 : : // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) -- every caller passes a named code and the errno it read
99 : 22 : static inline void VxWorks64File_ReportFailure(enum SolidSyslogFileErrors code, int nativeErrno)
100 : : {
101 [ + + ]: 22 : if (nativeErrno != 0)
102 : : {
103 : 19 : SolidSyslog_ErrorWithNativeCode(
104 : : SOLIDSYSLOG_FILE_IO_FAILED_SEVERITY,
105 : : &SolidSyslogVxWorks64FileErrorSource,
106 : : SOLIDSYSLOG_CAT_FILE_IO_FAILED,
107 : : (int32_t) code,
108 : : (int32_t) nativeErrno
109 : : );
110 : : }
111 : : else
112 : : {
113 : 3 : VxWorks64File_Report(SOLIDSYSLOG_FILE_IO_FAILED_SEVERITY, SOLIDSYSLOG_CAT_FILE_IO_FAILED, code);
114 : : }
115 : 22 : }
116 : :
117 : 111 : static void VxWorks64File_Close(struct SolidSyslogFile* base)
118 : : {
119 : 111 : struct SolidSyslogVxWorks64File* self = VxWorks64File_SelfFromBase(base);
120 [ + + ]: 111 : if (VxWorks64File_IsOpen(base))
121 : : {
122 : 65 : int status = close(self->Fd);
123 [ + + ]: 65 : int closeErrno = (status == ERROR) ? errno : 0;
124 : : /* The descriptor is released whether or not the close could flush. */
125 : 65 : self->Fd = ERROR;
126 [ + + ]: 65 : if (status == ERROR)
127 : : {
128 : 2 : VxWorks64File_ReportFailure(SOLIDSYSLOG_FILE_ERROR_CLOSE_FAILED, closeErrno);
129 : : }
130 : : }
131 : 111 : }
132 : :
133 : 192 : static bool VxWorks64File_IsOpen(struct SolidSyslogFile* base)
134 : : {
135 : 192 : const struct SolidSyslogVxWorks64File* self = VxWorks64File_SelfFromBase(base);
136 : 192 : return self->Fd != ERROR;
137 : : }
138 : :
139 : 29 : static bool VxWorks64File_Read(struct SolidSyslogFile* base, void* buf, size_t count)
140 : : {
141 : 29 : const struct SolidSyslogVxWorks64File* self = VxWorks64File_SelfFromBase(base);
142 : 29 : int transferred = read(self->Fd, (char*) buf, count);
143 : : /* A short read sets no errno; the store judges it. */
144 [ + + ]: 29 : int readErrno = (transferred == ERROR) ? errno : 0;
145 [ + + ]: 29 : if (transferred == ERROR)
146 : : {
147 : 2 : VxWorks64File_ReportFailure(SOLIDSYSLOG_FILE_ERROR_READ_FAILED, readErrno);
148 : : }
149 : 29 : return VxWorks64File_IsWholeTransfer(transferred, count);
150 : : }
151 : :
152 : : /* The kernel's read and write answer an int: ERROR, or how many bytes moved. */
153 : 66 : static inline bool VxWorks64File_IsWholeTransfer(int transferred, size_t count)
154 : : {
155 [ + + + + ]: 66 : return (transferred >= 0) && ((size_t) transferred == count);
156 : : }
157 : :
158 : 37 : static bool VxWorks64File_Write(struct SolidSyslogFile* base, const void* buf, size_t count)
159 : : {
160 : 37 : const struct SolidSyslogVxWorks64File* self = VxWorks64File_SelfFromBase(base);
161 : : /* The kernel's write takes a char*, though it only reads the buffer. */
162 : 37 : int written = write(self->Fd, (char*) buf, count);
163 : : /* A short write sets no errno. */
164 [ + + ]: 37 : int writeErrno = (written == ERROR) ? errno : 0;
165 : 37 : bool committed = VxWorks64File_IsWholeTransfer(written, count);
166 [ + + ]: 37 : if (committed)
167 : : {
168 : 32 : committed = VxWorks64File_Commit(self->Fd);
169 : : }
170 : : else
171 : : {
172 : 5 : VxWorks64File_ReportFailure(SOLIDSYSLOG_FILE_ERROR_WRITE_FAILED, writeErrno);
173 : : }
174 : 37 : return committed;
175 : : }
176 : :
177 : : /* FIOSYNC flushes the file to its device, then FIOCOMMITFS commits any
178 : : * transaction beneath it. */
179 : 32 : static inline bool VxWorks64File_Commit(int fd)
180 : : {
181 : 32 : bool committed = VxWorks64File_Sync(fd);
182 [ + + ]: 32 : if (committed)
183 : : {
184 : 29 : committed = VxWorks64File_CommitFileSystem(fd);
185 : : }
186 : 32 : return committed;
187 : : }
188 : :
189 : 32 : static inline bool VxWorks64File_Sync(int fd)
190 : : {
191 : 32 : int status = ioctl(fd, FIOSYNC, 0);
192 [ + + ]: 32 : int syncErrno = (status == ERROR) ? errno : 0;
193 : 32 : bool synced = status != ERROR;
194 [ + + ]: 32 : if (!synced)
195 : : {
196 : 3 : VxWorks64File_ReportFailure(SOLIDSYSLOG_FILE_ERROR_SYNC_FAILED, syncErrno);
197 : : }
198 : 32 : return synced;
199 : : }
200 : :
201 : 29 : static inline bool VxWorks64File_CommitFileSystem(int fd)
202 : : {
203 : 29 : int status = ioctl(fd, FIOCOMMITFS, 0);
204 [ + + ]: 29 : int commitErrno = (status == ERROR) ? errno : 0;
205 : : /* ENOTSUP: no transaction to commit. */
206 [ + + + + ]: 29 : bool committed = (status != ERROR) || (commitErrno == ENOTSUP);
207 [ + + ]: 29 : if (!committed)
208 : : {
209 : 3 : VxWorks64File_ReportFailure(SOLIDSYSLOG_FILE_ERROR_COMMIT_FAILED, commitErrno);
210 : : }
211 : 29 : return committed;
212 : : }
213 : :
214 : 43 : static void VxWorks64File_SeekTo(struct SolidSyslogFile* base, size_t offset)
215 : : {
216 : 43 : const struct SolidSyslogVxWorks64File* self = VxWorks64File_SelfFromBase(base);
217 : 43 : off_t position = lseek(self->Fd, (off_t) offset, SEEK_SET);
218 [ + + ]: 43 : int seekErrno = (position == ERROR) ? errno : 0;
219 [ + + ]: 43 : if (position == ERROR)
220 : : {
221 : 1 : VxWorks64File_ReportFailure(SOLIDSYSLOG_FILE_ERROR_SEEK_FAILED, seekErrno);
222 : : }
223 : 43 : }
224 : :
225 : 18 : static bool VxWorks64File_Size(struct SolidSyslogFile* base, size_t* size)
226 : : {
227 : 18 : const struct SolidSyslogVxWorks64File* self = VxWorks64File_SelfFromBase(base);
228 : 18 : off_t end = lseek(self->Fd, 0, SEEK_END);
229 : 18 : bool known = end != ERROR;
230 [ + + ]: 18 : int sizeErrno = known ? 0 : errno;
231 [ + + ]: 18 : if (!known)
232 : : {
233 : 2 : VxWorks64File_ReportFailure(SOLIDSYSLOG_FILE_ERROR_SIZE_FAILED, sizeErrno);
234 : : }
235 [ + + ]: 18 : *size = known ? (size_t) end : 0U;
236 : 18 : return known;
237 : : }
238 : :
239 : 18 : static void VxWorks64File_Truncate(struct SolidSyslogFile* base)
240 : : {
241 : 18 : const struct SolidSyslogVxWorks64File* self = VxWorks64File_SelfFromBase(base);
242 : 18 : int status = ioctl(self->Fd, FIOTRUNC, 0);
243 [ + + ]: 18 : int truncateErrno = (status == ERROR) ? errno : 0;
244 [ + + ]: 18 : if (status == ERROR)
245 : : {
246 : 1 : VxWorks64File_ReportFailure(SOLIDSYSLOG_FILE_ERROR_TRUNCATE_FAILED, truncateErrno);
247 : : }
248 : 18 : }
249 : :
250 : : /* stat answers for the path without opening it, so a scan of the block index
251 : : * space costs no descriptors. A path without a status answers false whatever
252 : : * the reason, and reports nothing: the open that follows on the same volume
253 : : * reports, and the store freezes on it. */
254 : 1308 : static bool VxWorks64File_Exists(struct SolidSyslogFile* base, const char* path)
255 : : {
256 : : (void) base;
257 : : struct stat status;
258 : 1308 : return stat(path, &status) == OK;
259 : : }
260 : :
261 : : /* True only for a path remove took away or found absent. Any other failure
262 : : * leaves the file on the volume, and answering false lets the store freeze
263 : : * rather than forget a block it will find again at its next start-up. */
264 : 7 : static bool VxWorks64File_Delete(struct SolidSyslogFile* base, const char* path)
265 : : {
266 : : (void) base;
267 : 7 : STATUS status = remove(path);
268 [ + + ]: 7 : int removeErrno = (status == ERROR) ? errno : 0;
269 [ + + + + ]: 7 : return (status == OK) || VxWorks64File_IsNotThere(removeErrno);
270 : : }
271 : :
272 : : /* Each file system names an absent path its own way, measured on the target:
273 : : * HRFS sets ENOENT, dosFs S_dosFsLib_FILE_NOT_FOUND. */
274 : 6 : static inline bool VxWorks64File_IsNotThere(int removeErrno)
275 : : {
276 [ + + + + ]: 6 : return (removeErrno == ENOENT) || (removeErrno == S_dosFsLib_FILE_NOT_FOUND);
277 : : }
|