PatchworkOS  c9fea19
A non-POSIX operating system.
Loading...
Searching...
No Matches
io.h
Go to the documentation of this file.
1#ifndef _SYS_IO_H
2#define _SYS_IO_H 1
3
4#include <alloca.h>
5#include <assert.h>
6#include <stdarg.h>
7#include <stdint.h>
8
9#if defined(__cplusplus)
10extern "C"
11{
12#endif
13
14#include "_internal/ERR.h"
15#include "_internal/MAX_NAME.h"
16#include "_internal/MAX_PATH.h"
17#include "_internal/NULL.h"
18#include "_internal/SEEK.h"
19#include "_internal/clock_t.h"
20#include "_internal/config.h"
21#include "_internal/fd_t.h"
22#include "_internal/time_t.h"
23
24/**
25 * @brief System IO header.
26 * @ingroup libstd
27 * @defgroup libstd_sys_io System IO
28 *
29 * The `sys/io.h` header handles interaction with PatchworkOS's file system,
30 * following the philosophy that everything is a file. This means interacting with physical devices,
31 * inter-process communication (like shared memory), and much more is handled via files.
32 *
33 * ### Flags
34 *
35 * Functions like `open()` do not have a specific argument for flags, instead the filepath itself contains the flags.
36 * This means that for example there is no need for a special "truncate" redirect in a shell (>>) instead you can just
37 * add the "trunc" flag to the filepath and use a normal redirect (>).
38 *
39 * Here is an example filepath: `/this/is/a/path:with:some:flags`.
40 *
41 * Check the 'src/kernel/fs/path.h' file for a list of available flags.
42 *
43 * @{
44 */
45
46#define STDIN_FILENO 0
47#define STDOUT_FILENO 1
48#define STDERR_FILENO 2
49
50/**
51 * @brief Pipe read end.
52 *
53 * The `PIPE_READ` constant defines which file descriptor in `fd` from a `open2` call on the `/dev/pipe` file will
54 * be the read end of the pipe.
55 *
56 */
57#define PIPE_READ 0
58/**
59 * @brief Pipe write end.
60 *
61 * The `PIPE_WRITE` constant defines which file descriptor in `fd` from a `open2` call on the `/dev/pipe` file will
62 * be the write end of the pipe.
63 *
64 */
65#define PIPE_WRITE 1
66
67/**
68 * @brief Maximum buffer size for the `F()` macro.
69 */
70#define F_MAX_SIZE 512
71
72/**
73 * @brief Format string macro.
74 *
75 * This macro is a helper to create formatted strings on the stack. Very useful for functions like `open()`.
76 *
77 * @note This could be reimplemented using thread local storage to avoid using `alloca()`, but we then end up needing to
78 * set a maximum limit for how many `F()` strings can be used simultaneously. Using `alloca()` means we can use as many
79 * as we want, as long as we have enough stack space, even if it is more dangerous.
80 *
81 * @warning Will truncate the string if it exceeds `F_MAX_SIZE`.
82 */
83#define F(format, ...) \
84 ({ \
85 char* _buffer = alloca(F_MAX_SIZE); \
86 int _len = snprintf(_buffer, F_MAX_SIZE, format, __VA_ARGS__); \
87 assert(_len >= 0 && "F() formatting error"); \
88 _buffer; \
89 })
90
91/**
92 * @brief System call for opening files.
93 *
94 * The `open()` function opens a file located at a given path.
95 *
96 * @param path The path to the desired file.
97 * @return On success, the file descriptor, on failure returns `ERR` and `errno` is set.
98 */
99fd_t open(const char* path);
100
101/**
102 * @brief System call for opening 2 file descriptors from one file.
103
104 * This is intended as a more generic
105 implementation
106 * of system calls like pipe() in for example Linux. One example use case of this system call is pipes, if
107 * `open2` is called on `/dev/pipe` then `fd[0]` will store the read end of the pipe and `fd[1]` will store the
108 write
109 * end of the pipe. But if `open()` is called on `/dev/pipe` then the returned file descriptor would be both
110 * ends.
111 *
112 * @param path The path to the desired file.
113 * @param fd An array of two `fd_t` where the new file descriptors will be stored.
114 * @return On success, 0, on failure returns `ERR` and `errno` is set.
115 */
116uint64_t open2(const char* path, fd_t fd[2]);
117
118/**
119 * @brief System call for opening files relative to another file descriptor.
120 *
121 * @param from The file descriptor to open the file relative to, or `FD_NONE` to open from the current working
122 * directory.
123 * @param path The path to the desired file.
124 * @return On success, the file descriptor, on failure returns `ERR` and `errno` is set.
125 */
126fd_t openat(fd_t from, const char* path);
127
128/**
129 * @brief System call for closing files.
130 *
131 * @param fd The file descriptor to close.
132 * @return On success, 0, on failure returns `ERR` and `errno` is set.
133 */
135
136/**
137 * @brief System call for reading from files.
138 *
139 * @param fd The file descriptor to read from.
140 * @param buffer A pointer to the buffer where the data will be stored.
141 * @param count The maximum number of bytes to read.
142 * @return On success, the number of bytes read. On end-of-file, 0. On failure, `ERR` and `errno`
143 * is set.
144 */
146
147/**
148 * @brief Wrapper for reading a file directly into a null-terminated string.
149 *
150 * The `sread()` function reads the entire contents of a file into a newly allocated null-terminated string.
151 * The caller is responsible for freeing the returned string.
152 *
153 * @param fd The file descriptor to read from.
154 * @return On success, a pointer to the null-terminated string. On failure, `NULL` and `errno` is set.
155 */
156char* sread(fd_t fd);
157
158/**
159 * @brief System call for writing to files.
160 *
161 * @param fd The file descriptor to write to.
162 * @param buffer A pointer to the buffer containing the data to write.
163 * @param count The number of bytes to write.
164 * @return On success, the number of bytes written. On failure, `ERR` and `errno` is set.
165 */
166uint64_t write(fd_t fd, const void* buffer, uint64_t count);
167
168/**
169 * @brief Wrapper for writing a null-terminated string to a file.
170 *
171 * @param fd The file descriptor to write to.
172 * @param string The null-terminated string to write.
173 * @return On success, the number of bytes written. On failure, `ERR` and `errno` is set.
174 */
175uint64_t swrite(fd_t fd, const char* string);
176
177/**
178 * @brief Wrapper for reading a file directly using a path.
179 *
180 * Equivalent to calling `open()`, `seek()`, `read()`, and `close()` in sequence.
181 *
182 * @param path The path to the file.
183 * @param buffer A pointer to the buffer where the data will be stored.
184 * @param count The maximum number of bytes to read.
185 * @param offset The offset in the file to start reading from.
186 * @return On success, the number of bytes read. On end-of-file, 0. On failure, `ERR` and `errno` is set.
187 */
188uint64_t readfile(const char* path, void* buffer, uint64_t count, uint64_t offset);
189
190/**
191 * @brief Wrapper for reading an entire file directly into a null-terminated string.
192 *
193 * The `sreadfile()` function reads the entire contents of a file into a newly allocated null-terminated string.
194 * The caller is responsible for freeing the returned string.
195 *
196 * Equivalent to calling `open()`, `sread()`, and `close()` in sequence.
197 *
198 * @param path The path to the file.
199 * @return On success, a pointer to the null-terminated string. On failure, `NULL` and `errno` is set.
200 */
201char* sreadfile(const char* path);
202
203/**
204 * @brief Wrapper for writing to a file directly using a path.
205 *
206 * Equivalent to calling `open()`, `seek()`, `write()`, and `close()` in sequence.
207 *
208 * @param path The path to the file.
209 * @param buffer A pointer to the buffer containing the data to write.
210 * @param count The number of bytes to write.
211 * @param offset The offset in the file to start writing to.
212 * @return On success, the number of bytes written. On failure, `ERR` and `errno` is set.
213 */
214uint64_t writefile(const char* path, const void* buffer, uint64_t count, uint64_t offset);
215
216/**
217 * @brief Wrapper for writing a null-terminated string directly to a file using a path.
218 *
219 * Equivalent to calling `open()`, `swrite()`, and `close()` in sequence.
220 *
221 * @param path The path to the file.
222 * @param string The null-terminated string to write.
223 * @return On success, the number of bytes written. On failure, `ERR` and `errno` is set.
224 */
225uint64_t swritefile(const char* path, const char* string);
226
227/**
228 * @brief Type for the `seek()` origin argument.
229 *
230 */
232
233/**
234 * @brief System call for changing the file offset.
235 *
236 * @param fd The file descriptor.
237 * @param offset The offset to move the file pointer.
238 * @param origin The origin that the offset is relative to (e.g., `SEEK_SET`, `SEEK_CUR`, `SEEK_END`).
239 * @return On success, the new offset from the beginning of the file. On failure, `ERR` and `errno` is
240 * set.
241 */
242uint64_t seek(fd_t fd, int64_t offset, seek_origin_t origin);
243
244/**
245 * @brief System call for changing the cwd.
246 *
247 * @param path The path to the new directory.
248 * @return On success, 0. On failure, `ERR` and `errno` is set.
249 */
250uint64_t chdir(const char* path);
251
252/**
253 * @brief Poll events type.
254 *
255 */
256typedef enum
257{
258 POLLNONE = 0, ///< None
259 POLLIN = (1 << 0), ///< File descriptor is ready to read.
260 POLLOUT = (1 << 1), ///< File descriptor is ready to write.
261 POLLERR = (1 << 2), ///< File descriptor caused an error.
262 POLLHUP = (1 << 3), ///< Stream socket peer closed connection, or shut down writing of connection.
263 POLLNVAL = (1 << 4), ///< Invalid file descriptor.
265
266/**
267 * @brief Poll event values that will always be checked and included even if not specified.
268 */
269#define POLL_SPECIAL (POLLERR | POLLHUP | POLLNVAL)
270
271/**
272 * @brief Poll file descriptor structure.
273 *
274 */
275typedef struct pollfd
276{
277 fd_t fd; ///< The file descriptor to poll.
278 poll_events_t events; ///< The events to wait for.
279 poll_events_t revents; ///< The events that occurred.
280} pollfd_t;
281
282/**
283 * @brief System call for polling files.
284 *
285 * @param fds An array of `pollfd_t` structures, each specifying a file descriptor to poll in pollfd_t::fd and the
286 * events to wait for in pollfd_t::events.
287 * @param amount The number of `pollfd_t` structures in the `fds` array.
288 * @param timeout The maximum time (in clock ticks) to wait for an event. If `CLOCKS_NEVER`, it waits forever.
289 * @return On success, the number of file descriptors for which the events occurred. On timeout, 0. On
290 * failure, `ERR` and `errno` is set.
291 */
292uint64_t poll(pollfd_t* fds, uint64_t amount, clock_t timeout);
293
294/**
295 * @brief Wrapper for polling one file.
296 *
297 * The `poll1()` function waits for events on a single file descriptor. Otherwise it is identical to `poll()` and exists
298 * simply for convenience.
299 *
300 * @param fd The file descriptor to poll.
301 * @param events The events to wait for (e.g., `POLLIN`, `POLLOUT`).
302 * @param timeout The maximum time (in clock ticks) to wait for an event. If `CLOCKS_NEVER`, it waits forever.
303 * @return On success, the events that occurred. On timeout, 0. On failure, the `POLLERR` event bit is
304 * set and `errno` is set.
305 */
306poll_events_t poll1(fd_t fd, poll_events_t events, clock_t timeout);
307
308/**
309 * @brief Inode type enum.
310 *
311 */
312typedef enum
313{
314 INODE_FILE, ///< Is a file.
315 INODE_DIR, ///< Is a directory.
317
318/**
319 * @brief Inode number enum.
320 *
321 */
323
324/**
325 * @brief Stat type.
326 *
327 */
328typedef struct
329{
330 inode_number_t number; ///< The number of the entries inode.
331 inode_type_t type; ///< The type of the entries inode.
332 uint64_t size; ///< The size of the file that is visible outside the filesystem.
333 uint64_t blocks; ///< The amount of blocks used on disk to store the file.
334 uint64_t linkAmount; ///< The amount of times the inode appears in dentries.
335 time_t accessTime; ///< Unix time stamp for the last inode access.
336 time_t modifyTime; ///< Unix time stamp for last file content alteration.
337 time_t changeTime; ///< Unix time stamp for the last file metadata alteration.
338 time_t createTime; ///< Unix time stamp for the creation of the inode.
339 char name[MAX_NAME]; ///< The name of the entry, not the full filepath.
340 uint8_t padding[64]; ///< Padding to leave space for future expansion.
341} stat_t;
342
343#ifdef static_assert
344static_assert(sizeof(stat_t) == 168, "invalid stat_t size");
345#endif
346
347/**
348 * @brief System call for retrieving info about a file or directory.
349 *
350 * @param path The path to the file or directory.
351 * @param stat A pointer to a `stat_t` structure where the file information will be stored.
352 * @return On success, 0. On failure, `ERR` and `errno` is set.
353 */
354uint64_t stat(const char* path, stat_t* stat);
355
356/**
357 * @brief System call for extended driver behaviour.
358 *
359 * The `ioctl()` function allows drivers to implement unusual behaviour that would be impossible or impractical with a
360 * normal file-based API.
361 *
362 * @param fd The file descriptor of the file.
363 * @param request The driver-dependent request code.
364 * @param argp A pointer to an argument that depends on the request, can be `NULL` if size is 0.
365 * @param size The size of the argument pointed to by `argp`.
366 * @return On success, the return value depends on the driver but is usually 0. On failure, `ERR` and `errno` is
367 * set.
368 */
369uint64_t ioctl(fd_t fd, uint64_t request, void* argp, uint64_t size);
370
371/**
372 * @brief System call for duplicating file descriptors.
373 *
374 * @param oldFd The open file descriptor to duplicate.
375 * @return On success, the new file descriptor. On failure, `ERR` and `errno` is set.
376 */
377fd_t dup(fd_t oldFd);
378
379/**
380 * @brief System call for duplicating file descriptors, with a destination.
381 *
382 * @param oldFd The open file descriptor to duplicate.
383 * @param newFd The desired new file descriptor.
384 * @return On success, the new file descriptor. On failure, `ERR` and `errno` is set.
385 */
386fd_t dup2(fd_t oldFd, fd_t newFd);
387
388/**
389 * @brief Directory entry struct.
390 *
391 */
392typedef struct
393{
394 inode_number_t number; ///< The number of the entries inode.
395 inode_type_t type; ///< The type of the entries inode.
396 char path[MAX_PATH]; ///< The relative path of the directory.
397} dirent_t;
398
399/**
400 * @brief System call for reading directory entires.
401 *
402 * @param fd The file descriptor of the directory to read.
403 * @param buffer The destination buffer.
404 * @param count The size of the buffer in bytes.
405 * @return On success, the total number of bytes written to the buffer. On failure,
406 * returns `ERR` and `errno` is set.
407 */
409
410/**
411 * @brief Wrapper for creating a directory.
412 *
413 * @param path The path of the directory to create.
414 * @return On success, 0. On failure, `ERR` and `errno` is set.
415 */
416uint64_t mkdir(const char* path);
417
418/**
419 * @brief Wrapper for removing a directory.
420 *
421 * @param path The path of the directory to remove.
422 * @return On success, 0. On failure, `ERR` and `errno` is set.
423 */
424uint64_t rmdir(const char* path);
425
426/**
427 * @brief System call for creating a hardlink.
428 *
429 * @param oldPath
430 * @param newPath
431 * @return On success, 0. On failure, `ERR` and `errno` is set.
432 */
433uint64_t link(const char* oldPath, const char* newPath);
434
435/**
436 * @brief Wrapper for removing a file.
437 *
438 * @param path The path of the file to remove.
439 * @return On success, 0. On failure, `ERR` and `errno` is set.
440 */
441uint64_t unlink(const char* path);
442
443/**
444 * @brief Size of keys in bytes.
445 */
446#define KEY_SIZE 16
447
448/**
449 * @brief Key type.
450 *
451 * Used with `share()` and `claim()` to send file descriptors between processes.
452 */
453typedef struct
454{
456} key_t;
457
458/**
459 * @brief System call for sharing a file descriptor with another process.
460 *
461 * Note that the file descriptor itself is not whats sent but the underlying file object.
462 *
463 * @param key Output pointer to store the generated key.
464 * @param fd The file descriptor to share.
465 * @param timeout The time until the shared file descriptor expires. If `CLOCKS_NEVER`, it never expires.
466 * @return On success, `0`. On failure, `ERR` and `errno` is set.
467 */
468uint64_t share(key_t* key, fd_t fd, clock_t timeout);
469
470/**
471 * @brief System call for claiming a shared file descriptor.
472 *
473 * After claiming a shared file descriptor, the key is no longer valid and cannot be used again.
474 *
475 * @param key Pointer to the key identifying the shared file descriptor.
476 * @return On success, the claimed file descriptor. On failure, `ERR` and `errno` is set.
477 */
478fd_t claim(key_t* key);
479
480/**
481 * @brief Mount flags type.
482 * @enum mount_flags_t
483 *
484 * The propagation flags apply recursively, such that specifying both `MOUNT_PROPAGATE_PARENT` and
485 * `MOUNT_PROPAGATE_CHILDREN` will propagate the mount to every namespace in the hierarchy.
486 */
487typedef enum
488{
489 MOUNT_NONE = 0, ///< No special mount flags.
490 MOUNT_PROPAGATE_PARENT = 1 << 0, ///< Propagate the mount to parent namespaces.
491 MOUNT_PROPAGATE_CHILDREN = 1 << 1, ///< Propagate the mount to child namespaces.
492 MOUNT_OVERWRITE = 1 << 2, ///< Overwrite any existing mount at the mountpoint.
494
495/**
496 * @brief System call for binding a file descriptor to a mountpoint.
497 *
498 * @param source The file descriptor to bind, must represent a directory.
499 * @param mountpoint The mountpoint path.
500 * @param flags The mount flags.
501 * @return On success, `0`. On failure, `ERR` and `errno` is set.
502 */
503uint64_t bind(fd_t source, const char* mountpoint, mount_flags_t flags);
504
505/** @} */
506
507#if defined(__cplusplus)
508}
509#endif
510
511#endif
#define MAX_NAME
Maximum length of names.
Definition MAX_NAME.h:11
#define MAX_PATH
Maximum length of filepaths.
Definition MAX_PATH.h:11
fd_t dup2(fd_t oldFd, fd_t newFd)
System call for duplicating file descriptors, with a destination.
Definition dup2.c:9
uint64_t stat(const char *path, stat_t *stat)
System call for retrieving info about a file or directory.
Definition stat.c:9
uint64_t getdents(fd_t fd, dirent_t *buffer, uint64_t count)
System call for reading directory entires.
Definition getdents.c:9
#define KEY_SIZE
Size of keys in bytes.
Definition io.h:446
fd_t open(const char *path)
System call for opening files.
Definition open.c:9
mount_flags_t
Mount flags type.
Definition io.h:488
inode_type_t
Inode type enum.
Definition io.h:313
fd_t claim(key_t *key)
System call for claiming a shared file descriptor.
Definition claim.c:6
poll_events_t poll1(fd_t fd, poll_events_t events, clock_t timeout)
Wrapper for polling one file.
Definition poll1.c:9
uint64_t inode_number_t
Inode number enum.
Definition io.h:322
uint64_t close(fd_t fd)
System call for closing files.
Definition close.c:9
uint64_t swrite(fd_t fd, const char *string)
Wrapper for writing a null-terminated string to a file.
Definition swrite.c:4
uint64_t seek(fd_t fd, int64_t offset, seek_origin_t origin)
System call for changing the file offset.
Definition seek.c:9
uint64_t ioctl(fd_t fd, uint64_t request, void *argp, uint64_t size)
System call for extended driver behaviour.
Definition ioctl.c:9
fd_t dup(fd_t oldFd)
System call for duplicating file descriptors.
Definition dup.c:9
uint64_t mkdir(const char *path)
Wrapper for creating a directory.
Definition mkdir.c:10
uint64_t swritefile(const char *path, const char *string)
Wrapper for writing a null-terminated string directly to a file using a path.
Definition swritefile.c:4
fd_t openat(fd_t from, const char *path)
System call for opening files relative to another file descriptor.
uint64_t readfile(const char *path, void *buffer, uint64_t count, uint64_t offset)
Wrapper for reading a file directly using a path.
Definition readfile.c:3
uint64_t bind(fd_t source, const char *mountpoint, mount_flags_t flags)
System call for binding a file descriptor to a mountpoint.
Definition bind.c:5
uint64_t poll(pollfd_t *fds, uint64_t amount, clock_t timeout)
System call for polling files.
Definition poll.c:9
uint64_t chdir(const char *path)
System call for changing the cwd.
Definition chdir.c:9
uint64_t unlink(const char *path)
Wrapper for removing a file.
Definition unlink.c:5
uint8_t seek_origin_t
Type for the seek() origin argument.
Definition io.h:231
uint64_t read(fd_t fd, void *buffer, uint64_t count)
System call for reading from files.
Definition read.c:9
poll_events_t
Poll events type.
Definition io.h:257
char * sread(fd_t fd)
Wrapper for reading a file directly into a null-terminated string.
Definition sread.c:5
char * sreadfile(const char *path)
Wrapper for reading an entire file directly into a null-terminated string.
Definition sreadfile.c:3
uint64_t open2(const char *path, fd_t fd[2])
System call for opening 2 file descriptors from one file.
Definition open2.c:9
uint64_t share(key_t *key, fd_t fd, clock_t timeout)
System call for sharing a file descriptor with another process.
Definition share.c:6
uint64_t write(fd_t fd, const void *buffer, uint64_t count)
System call for writing to files.
Definition write.c:9
uint64_t rmdir(const char *path)
Wrapper for removing a directory.
Definition rmdir.c:6
uint64_t link(const char *oldPath, const char *newPath)
System call for creating a hardlink.
Definition link.c:9
uint64_t writefile(const char *path, const void *buffer, uint64_t count, uint64_t offset)
Wrapper for writing to a file directly using a path.
Definition writefile.c:3
@ MOUNT_NONE
No special mount flags.
Definition io.h:489
@ MOUNT_PROPAGATE_PARENT
Propagate the mount to parent namespaces.
Definition io.h:490
@ MOUNT_OVERWRITE
Overwrite any existing mount at the mountpoint.
Definition io.h:492
@ MOUNT_PROPAGATE_CHILDREN
Propagate the mount to child namespaces.
Definition io.h:491
@ INODE_FILE
Is a file.
Definition io.h:314
@ INODE_DIR
Is a directory.
Definition io.h:315
@ POLLIN
File descriptor is ready to read.
Definition io.h:259
@ POLLNONE
None.
Definition io.h:258
@ POLLHUP
Stream socket peer closed connection, or shut down writing of connection.
Definition io.h:262
@ POLLNVAL
Invalid file descriptor.
Definition io.h:263
@ POLLOUT
File descriptor is ready to write.
Definition io.h:260
@ POLLERR
File descriptor caused an error.
Definition io.h:261
__UINT64_TYPE__ fd_t
A file descriptor.
Definition fd_t.h:12
__UINT64_TYPE__ clock_t
A nanosecond time.
Definition clock_t.h:13
static clock_source_t source
Structure to describe the HPET to the sys time subsystem.
Definition hpet.c:192
EFI_PHYSICAL_ADDRESS buffer
Definition mem.c:15
static const path_flag_t flags[]
Definition path.c:42
static atomic_long count
Definition main.c:10
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
__UINT8_TYPE__ uint8_t
Definition stdint.h:11
__INT64_TYPE__ int64_t
Definition stdint.h:16
Directory entry struct.
Definition io.h:393
inode_type_t type
The type of the entries inode.
Definition io.h:395
inode_number_t number
The number of the entries inode.
Definition io.h:394
Key type.
Definition io.h:454
Poll file descriptor structure.
Definition io.h:276
poll_events_t revents
The events that occurred.
Definition io.h:279
poll_events_t events
The events to wait for.
Definition io.h:278
fd_t fd
The file descriptor to poll.
Definition io.h:277
Stat type.
Definition io.h:329
time_t accessTime
Unix time stamp for the last inode access.
Definition io.h:335
uint64_t linkAmount
The amount of times the inode appears in dentries.
Definition io.h:334
inode_number_t number
The number of the entries inode.
Definition io.h:330
uint64_t size
The size of the file that is visible outside the filesystem.
Definition io.h:332
inode_type_t type
The type of the entries inode.
Definition io.h:331
time_t modifyTime
Unix time stamp for last file content alteration.
Definition io.h:336
time_t changeTime
Unix time stamp for the last file metadata alteration.
Definition io.h:337
uint64_t blocks
The amount of blocks used on disk to store the file.
Definition io.h:333
time_t createTime
Unix time stamp for the creation of the inode.
Definition io.h:338
long long unsigned time_t
Definition time_t.h:4