AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
write.c
Go to the documentation of this file.
1
5
6#include <core/system.h>
7
8#include <fs/vfs.h>
9#include <fs/iobuf.h>
10
11#include <aquila/fcntl.h>
12#include <aquila/errno.h>
13
26{
27 if (!(file->flags & (O_WRONLY | O_RDWR))) /* not open for writing */
28 return -EBADF;
29
30 /* appending: each write goes at the end, wherever the offset was
31 * (POSIX: as if by an lseek() to the end, then the write) */
32 if ((file->flags & O_APPEND) && S_ISREG(file->vnode->mode))
33 file->offset = file->vnode->size;
34
35 if (file->flags & O_NONBLOCK) {
36 if (vfs_file_can_write(file, io->resid)) {
37 ssize_t retval = vfs_write_io(file->vnode, file->offset, io);
38
39 if (retval < 0)
40 return retval;
41
42 file->offset += retval;
43
44 /* there's data now: wake up the readers waiting for some */
45 if (file->vnode->read_queue)
46 waitq_wakeup(file->vnode->read_queue);
47
48 return retval;
49 } else {
50 /* the write would have to wait */
51 return -EAGAIN;
52 }
53 } else {
54 size_t size = io->resid;
55
56 while (io->resid) {
57 ssize_t r = vfs_write_io(file->vnode, file->offset + (size - io->resid), io);
58
59 if (r < 0) {
60 /* report the error only if nothing was written */
61 if (io->resid == size)
62 return r;
63 break;
64 }
65
66 /* done: everything is written, the user buffer faulted, or the
67 * end of the file was reached */
68 if (!io->resid || io->fault || vfs_file_eof(file))
69 break;
70
71 /* readers may be asleep waiting for what was just written
72 * (a pipe's ring holds less than one stdio buffer) */
73 if (file->vnode->read_queue)
74 waitq_wakeup(file->vnode->read_queue);
75
76 /* nothing would wake a waiting writer up: no more fits */
77 if (!file->vnode->write_queue)
78 break;
79
80 /* wait for room; a signal ends the call, which returns what
81 * was written so far, or the error if nothing was */
82 int err = waitq_sleep(file->vnode->write_queue);
83
84 if (err) {
85 if (io->resid == size)
86 return err;
87 break;
88 }
89 }
90
91 ssize_t retval = size - io->resid;
92
93 file->offset += retval;
94
95 /* there's data now: wake up the readers waiting for some */
96 if (file->vnode->read_queue)
97 waitq_wakeup(file->vnode->read_queue);
98
99 return retval;
100 }
101}
int vfs_file_eof(struct file *file)
Says whether an open file is at its end, so that a read returns 0 rather than waiting.
Definition fops.c:325
int vfs_file_can_write(struct file *file, size_t size)
Says whether a write to an open file would go on without waiting, for poll(), select() and non-blocki...
Definition fops.c:295
ssize_t posix_file_write(struct file *file, struct iobuf *io)
Writes to an open file at its offset, and moves the offset past what was written.
Definition write.c:25
An open file (POSIX's "open file description", fs/file.c).
Definition vfs.h:157
off_t offset
Definition vfs.h:163
int flags
Definition vfs.h:164
An iobuf.
Definition iobuf.h:35
int fault
Definition iobuf.h:40
size_t resid
Definition iobuf.h:38
long int ssize_t
Definition types.h:12
void waitq_wakeup(struct waitq *waitq)
Wakes up every thread sleeping on a wait queue, and every thread polling it.
Definition waitq.c:178
int waitq_sleep(struct waitq *waitq)
Puts the current thread to sleep on a wait queue until it is woken up.
Definition waitq.c:50
ssize_t vfs_write_io(struct vnode *vnode, off_t off, struct iobuf *io)
Writes to a vnode from an iobuf (user or kernel memory).
Definition write.c:22