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