1 /*
2 * Copyright (c) 2018 Linaro Limited
3 * Copyright (c) 2025 Antmicro
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7 #ifndef ZEPHYR_INCLUDE_SYS_FDTABLE_H_
8 #define ZEPHYR_INCLUDE_SYS_FDTABLE_H_
9
10 #include <stdarg.h>
11 #include <time.h>
12
13 /* FIXME: For native_posix ssize_t, off_t. */
14 #include <sys/types.h>
15 #include <zephyr/kernel.h>
16 #include <zephyr/sys/util.h>
17
18 #ifdef CONFIG_PICOLIBC
19 #define ZVFS_O_APPEND 0x0400
20 #define ZVFS_O_CREAT 0x0040
21 #define ZVFS_O_TRUNC 0x0200
22 #else
23 #define ZVFS_O_APPEND 0x0008
24 #define ZVFS_O_CREAT 0x0200
25 #define ZVFS_O_TRUNC 0x0400
26 #endif
27
28 #define ZVFS_O_RDONLY 00
29 #define ZVFS_O_WRONLY 01
30 #define ZVFS_O_RDWR 02
31
32 #define ZVFS_O_EXCL 0x0800
33 #define ZVFS_O_NONBLOCK 0x4000
34
35 #define ZVFS_F_DUPFD 0
36 #define ZVFS_F_GETFL 3
37 #define ZVFS_F_SETFL 4
38
39 /* File mode bits */
40 #define ZVFS_MODE_IFMT 0170000
41 #define ZVFS_MODE_UNSPEC 0000000
42 #define ZVFS_MODE_IFIFO 0010000
43 #define ZVFS_MODE_IFCHR 0020000
44 #define ZVFS_MODE_IMSGQ 0030000
45 #define ZVFS_MODE_IFDIR 0040000
46 #define ZVFS_MODE_IFSEM 0050000
47 #define ZVFS_MODE_IFBLK 0060000
48 #define ZVFS_MODE_IFSHM 0070000
49 #define ZVFS_MODE_IFREG 0100000
50 #define ZVFS_MODE_IFLNK 0120000
51 #define ZVFS_MODE_IFSOCK 0140000
52
53 #define ZVFS_POLLIN BIT(0)
54 #define ZVFS_POLLPRI BIT(1)
55 #define ZVFS_POLLOUT BIT(2)
56 #define ZVFS_POLLERR BIT(3)
57 #define ZVFS_POLLHUP BIT(4)
58 #define ZVFS_POLLNVAL BIT(5)
59
60 /* FIXME: use k_off_t and k_ssize_t to avoid the POSIX->Zephyr->POSIX dependency cycle */
61 #ifdef CONFIG_NEWLIB_LIBC
62 #ifndef _OFF_T_DECLARED
63 typedef __off_t off_t;
64 #define _OFF_T_DECLARED
65 #endif
66 #ifndef _SSIZE_T_DECLARED
67 typedef _ssize_t ssize_t;
68 #define _SSIZE_T_DECLARED
69 #endif
70 #endif
71
72 #include <zephyr/fs/fs.h>
73
74 #ifdef __cplusplus
75 extern "C" {
76 #endif
77
78 /**
79 * File descriptor virtual method table.
80 * Currently all operations beyond read/write/close go thru ioctl method.
81 */
82 struct fd_op_vtable {
83 union {
84 ssize_t (*read)(void *obj, void *buf, size_t sz);
85 ssize_t (*read_offs)(void *obj, void *buf, size_t sz, size_t offset);
86 };
87 union {
88 ssize_t (*write)(void *obj, const void *buf, size_t sz);
89 ssize_t (*write_offs)(void *obj, const void *buf, size_t sz, size_t offset);
90 };
91 union {
92 int (*close)(void *obj);
93 int (*close2)(void *obj, int fd);
94 };
95 int (*ioctl)(void *obj, unsigned int request, va_list args);
96 };
97
98 /**
99 * @brief Reserve file descriptor.
100 *
101 * This function allows to reserve a space for file descriptor entry in
102 * the underlying table, and thus allows caller to fail fast if no free
103 * descriptor is available. If this function succeeds, zvfs_finalize_fd()
104 * or zvfs_free_fd() must be called mandatorily.
105 *
106 * @return Allocated file descriptor, or -1 in case of error (errno is set)
107 */
108 int zvfs_reserve_fd(void);
109
110 /**
111 * @brief Finalize creation of file descriptor, with type.
112 *
113 * This function should be called exactly once after zvfs_reserve_fd(), and
114 * should not be called in any other case.
115 *
116 * The difference between this function and @ref zvfs_finalize_fd is that the
117 * latter does not relay type information of the created file descriptor.
118 *
119 * Values permitted for @a mode are one of `ZVFS_MODE_..`.
120 *
121 * @param fd File descriptor previously returned by zvfs_reserve_fd()
122 * @param obj pointer to I/O object structure
123 * @param vtable pointer to I/O operation implementations for the object
124 * @param mode File type as specified above.
125 */
126 void zvfs_finalize_typed_fd(int fd, void *obj, const struct fd_op_vtable *vtable, uint32_t mode);
127
128 /**
129 * @brief Finalize creation of file descriptor.
130 *
131 * This function should be called exactly once after zvfs_reserve_fd(), and
132 * should not be called in any other case.
133 *
134 * @param fd File descriptor previously returned by zvfs_reserve_fd()
135 * @param obj pointer to I/O object structure
136 * @param vtable pointer to I/O operation implementations for the object
137 */
zvfs_finalize_fd(int fd,void * obj,const struct fd_op_vtable * vtable)138 static inline void zvfs_finalize_fd(int fd, void *obj, const struct fd_op_vtable *vtable)
139 {
140 zvfs_finalize_typed_fd(fd, obj, vtable, ZVFS_MODE_UNSPEC);
141 }
142
143 /**
144 * @brief Allocate file descriptor for underlying I/O object.
145 *
146 * This function combines operations of zvfs_reserve_fd() and zvfs_finalize_fd()
147 * in one step, and provided for convenience.
148 *
149 * @param obj pointer to I/O object structure
150 * @param vtable pointer to I/O operation implementations for the object
151 *
152 * @return Allocated file descriptor, or -1 in case of error (errno is set)
153 */
154 int zvfs_alloc_fd(void *obj, const struct fd_op_vtable *vtable);
155
156 /**
157 * @brief Release reserved file descriptor.
158 *
159 * This function may be called once after zvfs_reserve_fd(), and should
160 * not be called in any other case.
161 *
162 * @param fd File descriptor previously returned by zvfs_reserve_fd()
163 */
164 void zvfs_free_fd(int fd);
165
166 /**
167 * @brief Get underlying object pointer from file descriptor.
168 *
169 * This function is useful for functions other than read/write/ioctl
170 * to look up underlying I/O object by fd, optionally checking its
171 * type (using vtable reference). If fd refers to invalid entry,
172 * NULL will be returned with errno set to EBADF. If fd is valid,
173 * but vtable param is not NULL and doesn't match object's vtable,
174 * NULL is returned and errno set to err param.
175 *
176 * @param fd File descriptor previously returned by zvfs_reserve_fd()
177 * @param vtable Expected object vtable or NULL
178 * @param err errno value to set if object vtable doesn't match
179 *
180 * @return Object pointer or NULL, with errno set
181 */
182 void *zvfs_get_fd_obj(int fd, const struct fd_op_vtable *vtable, int err);
183
184 /**
185 * @brief Get underlying object pointer and vtable pointer from file descriptor.
186 *
187 * @param fd File descriptor previously returned by zvfs_reserve_fd()
188 * @param vtable A pointer to a pointer variable to store the vtable
189 * @param lock An optional pointer to a pointer variable to store the mutex
190 * preventing concurrent descriptor access. The lock is not taken,
191 * it is just returned for the caller to use if necessary. Pass NULL
192 * if the lock is not needed by the caller.
193 *
194 * @return Object pointer or NULL, with errno set
195 */
196 void *zvfs_get_fd_obj_and_vtable(int fd, const struct fd_op_vtable **vtable,
197 struct k_mutex **lock);
198
199 /**
200 * @brief Get the mutex and condition variable associated with the given object and vtable.
201 *
202 * @param obj Object previously returned by a call to e.g. @ref zvfs_get_fd_obj.
203 * @param vtable A pointer the vtable associated with @p obj.
204 * @param lock An optional pointer to a pointer variable to store the mutex
205 * preventing concurrent descriptor access. The lock is not taken,
206 * it is just returned for the caller to use if necessary. Pass NULL
207 * if the lock is not needed by the caller.
208 * @param cond An optional pointer to a pointer variable to store the condition variable
209 * to notify waiting threads in the case of concurrent descriptor access. Pass NULL
210 * if the condition variable is not needed by the caller.
211 *
212 * @return `true` on success, `false` otherwise.
213 */
214 bool zvfs_get_obj_lock_and_cond(void *obj, const struct fd_op_vtable *vtable, struct k_mutex **lock,
215 struct k_condvar **cond);
216
217 /**
218 * @brief Call ioctl vmethod on an object using varargs.
219 *
220 * We need this helper function because ioctl vmethod is declared to
221 * take va_list and the only portable way to construct va_list is from
222 * function's ... parameters.
223 *
224 * @param vtable vtable containing ioctl function pointer
225 * @param obj Object to call ioctl on
226 * @param request ioctl request number
227 * @param ... Variadic arguments to ioctl
228 */
zvfs_fdtable_call_ioctl(const struct fd_op_vtable * vtable,void * obj,unsigned long request,...)229 static inline int zvfs_fdtable_call_ioctl(const struct fd_op_vtable *vtable, void *obj,
230 unsigned long request, ...)
231 {
232 va_list args;
233 int res;
234
235 va_start(args, request);
236 res = vtable->ioctl(obj, request, args);
237 va_end(args);
238
239 return res;
240 }
241
242 /**
243 * Structure for result of the ZFD_IOCTL_STAT ioctl call.
244 * Contains fields for all currently supported details. Defined to avoid POSIX dependency.
245 */
246 struct zvfs_stat {
247 off_t size;
248 uint32_t mode;
249 };
250
251 struct zvfs_pollfd {
252 int fd;
253 short events;
254 short revents;
255 };
256
257 __syscall int zvfs_poll(struct zvfs_pollfd *fds, int nfds, int poll_timeout);
258
259 struct zvfs_fd_set {
260 uint32_t bitset[DIV_ROUND_UP(ZVFS_OPEN_SIZE, 32)];
261 };
262
263 /** @brief Number of file descriptors which can be added @ref zvfs_fd_set */
264 #define ZVFS_FD_SETSIZE (sizeof(((struct zvfs_fd_set *)0)->bitset) * 8)
265
266 void ZVFS_FD_CLR(int fd, struct zvfs_fd_set *fdset);
267 int ZVFS_FD_ISSET(int fd, struct zvfs_fd_set *fdset);
268 void ZVFS_FD_SET(int fd, struct zvfs_fd_set *fdset);
269 void ZVFS_FD_ZERO(struct zvfs_fd_set *fdset);
270
271 __syscall int zvfs_select(int nfds, struct zvfs_fd_set *ZRESTRICT readfds,
272 struct zvfs_fd_set *ZRESTRICT writefds,
273 struct zvfs_fd_set *ZRESTRICT errorfds,
274 const struct timespec *ZRESTRICT timeout, const void *ZRESTRICT sigmask);
275
276 /**
277 * Request codes for fd_op_vtable.ioctl().
278 *
279 * Note that these codes are internal Zephyr numbers, for internal
280 * Zephyr operations (and subject to change without notice, not part
281 * of "stable ABI"). These are however expected to co-exist with
282 * "well-known" POSIX/Linux ioctl numbers, and not clash with them.
283 */
284 enum {
285 /* Codes below 0x100 are reserved for fcntl() codes. */
286 ZFD_IOCTL_FSYNC = 0x100,
287 ZFD_IOCTL_LSEEK,
288 ZFD_IOCTL_POLL_PREPARE,
289 ZFD_IOCTL_POLL_UPDATE,
290 ZFD_IOCTL_POLL_OFFLOAD,
291 ZFD_IOCTL_SET_LOCK,
292 ZFD_IOCTL_STAT,
293 ZFD_IOCTL_TRUNCATE,
294 ZFD_IOCTL_MMAP,
295
296 /* Codes above 0x5400 and below 0x5500 are reserved for termios, FIO, etc */
297 ZFD_IOCTL_FIONREAD = 0x541B,
298 ZFD_IOCTL_FIONBIO = 0x5421,
299 };
300
301 /**
302 * @brief Open a file with a given name.
303 *
304 * @param name Name of the file
305 * @param flags Access modes for @ref fs_open
306 * @param vtable Pointer to structure with appropriate i/o functions
307 *
308 * @return Index of newly created file descriptor on success, -1 on error with errno set.
309 */
310 int zvfs_open(const char *name, int flags, struct fd_op_vtable *vtable);
311
312 /**
313 * @brief Get information about file.
314 *
315 * @param fd File descriptor index
316 * @param buf Pointer to result structure
317 *
318 * @return 0 on success, -1 with errno set on error.
319 */
320 int zvfs_fstat(int fd, struct zvfs_stat *buf);
321
322 /**
323 * @brief Close file.
324 *
325 * @param fd File descriptor index
326 *
327 * @return 0 on success, -1 with errno set on error.
328 */
329 int zvfs_close(int fd);
330
331 /**
332 * @brief Read bytes from file.
333 *
334 * @param fd File descriptor index
335 * @param buf Destination buffer
336 * @param sz Number of bytes to read
337 * @param from_offset Pointer to variable specifying starting position;
338 * current offset will be used if NULL
339 *
340 * @return Number of bytes read successfully, or -1 with errno set on failure
341 */
342 ssize_t zvfs_read(int fd, void *buf, size_t sz, const size_t *from_offset);
343
344 /**
345 * @brief Write bytes to file.
346 *
347 * @param fd File descriptor index
348 * @param buf Source buffer
349 * @param sz Number of bytes to write
350 * @param from_offset Pointer to variable specifying starting position;
351 * current offset will be used if NULL
352 *
353 * @return Number of bytes written successfully, or -1 with errno set on failure
354 */
355 ssize_t zvfs_write(int fd, const void *buf, size_t sz, const size_t *from_offset);
356
357 #ifdef CONFIG_ZVFS_DEFAULT_FILE_VMETHODS
358 int zvfs_ioctl_vmeth(void *obj, unsigned int request, va_list args);
359 int zvfs_close_vmeth(void *obj);
360 ssize_t zvfs_write_vmeth(void *obj, const void *buffer, size_t count);
361 ssize_t zvfs_read_vmeth(void *obj, void *buffer, size_t count);
362 #endif
363
364 /**
365 * @brief Delete file or directory.
366 *
367 * @param path Path or name of file to be removed.
368 *
369 * @return 0 on success, -1 with errno set on error.
370 */
371 int zvfs_unlink(const char *path);
372
373 /**
374 * @brief Rename file or directory, moving it if necessary.
375 *
376 * @param old Current name
377 * @param newp Target name
378 *
379 * @return 0 on success, -1 with errno set on error.
380 */
381 int zvfs_rename(const char *old, const char *newp);
382
383 #ifdef __cplusplus
384 }
385 #endif
386
387 #include <zephyr/syscalls/fdtable.h>
388
389 #endif /* ZEPHYR_INCLUDE_SYS_FDTABLE_H_ */
390