AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
vops.c
Go to the documentation of this file.
1
8
9#include <minix.h>
10#include <fs/iobuf.h>
11
21ssize_t minix_read(struct vnode *vnode, off_t offset, struct iobuf *io)
22{
23 int err = 0;
24
25 struct minix *desc = vnode->p;
26
27 size_t bs = desc->bs;
28 struct minix_inode m_inode;
29
30 if ((err = minix_inode_read(desc, vnode->ino, &m_inode)) < 0)
31 return err;
32
33 if ((size_t) offset >= m_inode.size)
34 return 0;
35
36 size_t size = MIN(io->resid, (size_t) (m_inode.size - offset));
37 char *block = kmalloc(bs, &M_BUFFER, 0);
38
39 if (!block)
40 return -ENOMEM;
41
42 size_t done = 0;
43 ssize_t r = 0;
44
45 while (done < size) {
46 size_t off = (offset + done) % bs;
47 size_t len = MIN(bs - off, size - done);
48
49 if ((r = minix_inode_block_read(desc, &m_inode, (offset + done) / bs, block)) < 0)
50 break;
51
52 if ((r = iobuf_out(io, block + off, len)) < 0)
53 break;
54
55 done += r;
56
57 /* a fault stopped the copy */
58 if ((size_t) r < len)
59 break;
60 }
61
62 kfree(block);
63 return done ? (ssize_t) done : r;
64}
65
75ssize_t minix_write(struct vnode *vnode, off_t offset, struct iobuf *io)
76{
77 int err = 0;
78
79 struct minix *desc = vnode->p;
80 size_t size = io->resid, old_size = vnode->size;
81
82 if ((size_t) offset + size > vnode->size) {
83 minix_trunc(vnode, (size_t) offset + size);
84 }
85
86 size_t bs = desc->bs;
87 struct minix_inode m_inode;
88
89 if ((err = minix_inode_read(desc, vnode->ino, &m_inode)) < 0)
90 return err;
91
92 if ((size_t) offset >= m_inode.size) {
93 m_inode.size = offset + size;
94 if ((err = minix_inode_write(desc, vnode->ino, &m_inode)) < 0)
95 return err;
96 }
97
98 size = MIN(size, (size_t) (m_inode.size - offset));
99 char *block = kmalloc(bs, &M_BUFFER, 0);
100
101 if (!block)
102 return -ENOMEM;
103
104 size_t done = 0;
105 ssize_t r = 0;
106
107 while (done < size) {
108 size_t off = (offset + done) % bs;
109 size_t len = MIN(bs - off, size - done);
110
111 /* writing part of a block: read the rest of it first */
112 if ((off || len < bs) &&
113 (r = minix_inode_block_read(desc, &m_inode, (offset + done) / bs, block)) < 0)
114 break;
115
116 if ((r = iobuf_in(io, block + off, len)) <= 0)
117 break;
118
119 ssize_t w = minix_inode_block_write(desc, &m_inode, vnode->ino, (offset + done) / bs, block);
120
121 if (w < 0) {
122 r = w;
123 break;
124 }
125
126 done += r;
127
128 /* a fault stopped the copy */
129 if ((size_t) r < len)
130 break;
131 }
132
133 kfree(block);
134
135 /* if it stopped short, the file ends where the data does */
136 if (done < size && (size_t) offset + size > old_size)
137 minix_trunc(vnode, MAX(old_size, (size_t) offset + done));
138
139 return done ? (ssize_t) done : r;
140}
141
151ssize_t minix_readdir(struct vnode *dir, off_t off, struct dirent *dirent)
152{
153 int err = 0;
154
155 struct minix *desc = dir->p;
156 size_t bs = desc->bs;
157 char block[bs];
158
159 if (!S_ISDIR(dir->mode))
160 return -ENOTDIR;
161
162 struct minix_inode m_inode;
163
164 if ((err = minix_inode_read(desc, dir->ino, &m_inode)))
165 goto error;
166
167 if (!S_ISDIR(m_inode.mode))
168 return -ENOTDIR;
169
170 size_t nr_blocks = (m_inode.size + bs - 1) / bs;
171
172 struct minix_dentry *dentry;
173 uint32_t inode_nr;
174 off_t idx = 0;
175
176 for (size_t i = 0; i < nr_blocks; ++i) {
177 minix_inode_block_read(desc, &m_inode, i, block);
178
179 dentry = (struct minix_dentry *) block;
180
181 while ((char *) dentry < (char *) block + bs) {
182 if (dentry->ino) {
183 if (idx++ == off) {
184 dirent->d_ino = dentry->ino;
185
186 memcpy(dirent->d_name, (char *) dentry->name, desc->name_len);
187 dirent->d_name[desc->name_len] = '\0';
188 return 1;
189 }
190 }
191
192 dentry = (struct minix_dentry *) ((char *) dentry + desc->dentry_size);
193 }
194 }
195
196 /* past the last entry */
197 return 0;
198
199error:
200 return err;
201}
202
216int minix_vmknod(struct vnode *dir, const char *fn, mode_t mode, dev_t dev, struct uio *uio, struct vnode **ref)
217{
218 int err = 0;
219
220 if (!fn || !*fn)
221 return -EINVAL;
222
223 struct minix *desc = dir->p;
224 struct minix_inode dir_inode;
225
226 if ((err = minix_inode_read(desc, dir->ino, &dir_inode)))
227 goto error;
228
229 if (!S_ISDIR(dir_inode.mode))
230 return -ENOTDIR;
231
232 if (minix_dentry_find(desc, &dir_inode, fn)) {
233 return -EEXIST;
234 }
235
236 ino_t ino = minix_inode_alloc(desc);
237
238 if (!ino) { /* out of inodes */
239 err = -ENOSPC;
240 goto error;
241 }
242
243 struct minix_inode m_inode;
244
245 if ((err = minix_inode_read(desc, ino, &m_inode))) {
246 /* not handled: the inode is cleared below anyway */
247 }
248
249 memset(&m_inode, 0, sizeof(struct minix_inode));
250
251 m_inode.mode = mode;
252 m_inode.uid = uio->uid;
253 m_inode.gid = uio->gid;
254
255 /* a device node's number, where minix_inode_build() reads it */
256 if (S_ISCHR(mode) || S_ISBLK(mode))
257 m_inode.zones[0] = DEV(DEV_MAJOR(dev), DEV_MINOR(dev));
258
259 if (S_ISDIR(mode)) { /* a directory starts with . and .. */
260 m_inode.nlinks = 2;
261 m_inode.size = 2 * desc->dentry_size;
262
263 char buf[desc->bs];
264 memset(buf, 0, sizeof(buf));
265
266 struct minix_dentry *dentry = (struct minix_dentry *) buf;
267 dentry->ino = ino;
268 memcpy(dentry->name, ".", 1);
269
270 dentry = (struct minix_dentry *) ((char *) dentry + desc->dentry_size);
271 dentry->ino = dir->ino;
272 memcpy(dentry->name, "..", 2);
273
274 if ((err = minix_inode_block_write(desc, &m_inode, ino, 0, buf)))
275 goto free_inode;
276 } else {
277 m_inode.nlinks = 1;
278 m_inode.size = 0;
279 }
280
281 if ((err = minix_inode_write(desc, ino, &m_inode)))
282 goto free_inode;
283
284 /* its entry in the directory; without one, the new inode goes */
285 if ((err = minix_dentry_create(dir, fn, ino, m_inode.mode)))
286 goto free_inode;
287
288 if (S_ISDIR(mode)) {
289 /* the parent gets a link, the new directory's `..`: on the inode
290 * as it is on the disk now (with the new entry), and in its vnode */
291 if (!minix_inode_read(desc, dir->ino, &dir_inode)) {
292 dir_inode.nlinks += 1;
293 minix_inode_write(desc, dir->ino, &dir_inode);
294 dir->nlink = dir_inode.nlinks;
295 }
296 }
297
298 if (ref)
299 minix_inode_build(desc, ino, ref);
300
301 return 0;
302
303free_inode:
304 /* only a directory has zones (a device node's first zone slot is its
305 * device number) */
306 if (S_ISDIR(mode))
307 minix_zones_free(desc, &m_inode, 0);
308
309 minix_inode_free(desc, ino);
310error:
311 return err;
312}
313
324int minix_finddir(struct vnode *dir, const char *fn, struct dirent *dirent)
325{
326 int err = 0;
327
328 struct minix *desc = dir->p;
329
330 uint32_t id = dir->ino;
331
332 struct minix_inode m_inode;
333
334 if ((err = minix_inode_read(desc, id, &m_inode)))
335 goto error;
336
337 if (!S_ISDIR(m_inode.mode))
338 return -ENOTDIR;
339
340 ino_t ino = minix_dentry_find(desc, &m_inode, fn);
341
342 if (!ino)
343 return -ENOENT;
344
345 if (dirent) {
346 dirent->d_ino = ino;
347 }
348
349 return 0;
350
351error:
352 return err;
353}
354
363int minix_vget(struct vnode *super, ino_t ino, struct vnode **ref)
364{
365 struct minix *desc = super->p;
366
367 if (ref) return minix_inode_build(desc, ino, ref);
368
369 return 0;
370}
371
380int minix_trunc(struct vnode *vnode, off_t len)
381{
382 if ((size_t) len == vnode->size)
383 return 0;
384
385 /* growing only changes the size: the new part is a hole */
386 if ((size_t) len > vnode->size) {
387 vnode->size = len;
389 return 0;
390 }
391
392 /* shrinking: the zones past the new end are freed, and the rest of the
393 * last one is zeroed (so the file reads zeros there if it grows
394 * again) */
395 struct minix *desc = vnode->p;
396 struct minix_inode m_inode;
397 size_t bs = desc->bs;
398 int err;
399
400 if ((err = minix_inode_read(desc, vnode->ino, &m_inode)))
401 return err;
402
403 if (len % bs) {
404 char *buf = kmalloc(bs, &M_BUFFER, 0);
405
406 if (!buf)
407 return -ENOMEM;
408
409 /* a zone that can't be read isn't written over */
410 if (!(err = minix_inode_block_read(desc, &m_inode, len / bs, buf))) {
411 memset(buf + len % bs, 0, bs - len % bs);
412 err = minix_inode_block_write(desc, &m_inode, vnode->ino, len / bs, buf);
413 }
414
415 kfree(buf);
416
417 if (err)
418 return err;
419 }
420
421 minix_zones_free(desc, &m_inode, (len + bs - 1) / bs);
422
423 m_inode.size = len;
424 vnode->size = len;
425 return minix_inode_write(desc, vnode->ino, &m_inode);
426}
#define DEV_MAJOR(dev)
Definition dev.h:77
#define DEV(major, minor)
Definition dev.h:76
#define DEV_MINOR(dev)
Definition dev.h:78
#define MIN(a, b)
Definition system.h:11
#define MAX(a, b)
Definition system.h:10
ssize_t iobuf_out(struct iobuf *io, const void *src, size_t n)
Copies bytes from the kernel into the iobuf's buffer, and moves past them.
Definition iobuf.c:115
ssize_t iobuf_in(struct iobuf *io, void *dst, size_t n)
Copies bytes from the iobuf's buffer into the kernel, and moves past them.
Definition iobuf.c:135
void * kmalloc(size_t size, struct malloc_type *type, int flags)
Allocates memory for one of the kernel's structures.
Definition kvmem.c:123
void kfree(void *)
Frees an object that kmalloc() gave.
Definition kvmem.c:146
void * memset(void *dst, int c, size_t n)
Sets n bytes to c.
Definition libc.c:23
void * memcpy(void *dst, const void *src, size_t n)
Copies n bytes; dst and src must not overlap.
Definition libc.c:11
uint32_t minix_dentry_find(struct minix *desc, struct minix_inode *m_inode, const char *name)
Finds the inode number of a name in a directory.
Definition dentry.c:19
int minix_dentry_create(struct vnode *dir, const char *name, ino_t ino, mode_t mode)
Adds an entry to a directory, in its first free slot.
Definition dentry.c:68
ssize_t minix_inode_block_write(struct minix *desc, struct minix_inode *inode, ino_t ino, size_t idx, void *buf)
Writes a zone of a file, allocating it and the indirect zones above it if they don't exist yet.
Definition inode.c:208
ssize_t minix_inode_block_read(struct minix *desc, struct minix_inode *m_inode, size_t idx, void *buf)
Reads a zone of a file.
Definition inode.c:141
int minix_inode_read(struct minix *desc, ino_t ino, struct minix_inode *ref)
Reads an inode from the disk.
Definition inode.c:31
int minix_inode_write(struct minix *desc, ino_t ino, struct minix_inode *ref)
Writes an inode to the disk.
Definition inode.c:63
void minix_zones_free(struct minix *desc, struct minix_inode *inode, size_t from)
Frees a file's zones, from a zone on, when the file is truncated or removed.
Definition inode.c:315
void minix_inode_free(struct minix *desc, ino_t ino)
Frees an inode: its bit is cleared in the inode bitmap, which is written back at once.
Definition inode.c:366
ino_t minix_inode_alloc(struct minix *desc)
Allocates a free inode: its bit is set in the inode bitmap, which is written back to the disk at once...
Definition inode.c:340
int minix_inode_build(struct minix *desc, ino_t ino, struct vnode **ref)
Gets the vnode of an inode: the cached one if it's in use, or a new one made from the inode on the di...
Definition minix.c:30
int minix_inode_sync(struct vnode *inode)
Writes a vnode's attributes back to its inode on the disk.
Definition minix.c:87
ssize_t minix_read(struct vnode *inode, off_t offset, struct iobuf *io)
Reads from a file.
Definition vops.c:21
int minix_vget(struct vnode *super, ino_t ino, struct vnode **ref)
Gets the vnode of an inode, by its number.
Definition vops.c:363
int minix_finddir(struct vnode *dir, const char *fn, struct dirent *dirent)
Finds the entry of a directory that has a name.
Definition vops.c:324
int minix_trunc(struct vnode *inode, off_t len)
Changes a file's length.
Definition vops.c:380
ssize_t minix_readdir(struct vnode *dir, off_t offset, struct dirent *dirent)
Reads a directory's entry at an offset; unused entries don't count.
Definition vops.c:151
int minix_vmknod(struct vnode *dir, const char *fn, mode_t mode, dev_t dev, struct uio *uio, struct vnode **ref)
Makes a node in a directory: a new inode, and an entry for it.
Definition vops.c:216
ssize_t minix_write(struct vnode *inode, off_t offset, struct iobuf *io)
Writes to a file, which grows if the write goes past its end.
Definition vops.c:75
unsigned int uint32_t
Definition stddef.h:22
A device driver: its operations, any of which may be NULL.
Definition dev.h:28
An iobuf.
Definition iobuf.h:35
size_t resid
Definition iobuf.h:38
A directory entry, as it is on the disk: 0 as the inode number is an unused entry.
Definition minix.h:76
uint8_t name[0]
Definition minix.h:78
uint16_t ino
Definition minix.h:77
A minix v1 inode, as it is on the disk.
Definition minix.h:64
uint8_t gid
Definition minix.h:69
uint32_t size
Definition minix.h:67
uint16_t uid
Definition minix.h:66
uint16_t mode
Definition minix.h:65
uint16_t zones[9]
Definition minix.h:71
uint8_t nlinks
Definition minix.h:70
A mounted minix filesystem.
Definition minix.h:82
size_t bs
Definition minix.h:101
size_t name_len
Definition minix.h:88
size_t dentry_size
Definition minix.h:87
Who does a filesystem operation: where its paths start, and its credentials and umask.
Definition vfs.h:60
gid_t gid
Definition vfs.h:64
uid_t uid
Definition vfs.h:63
A file in memory (a vnode): what its inode says, and the kernel's own state.
Definition vfs.h:113
ino_t ino
Definition vfs.h:114
nlink_t nlink
Definition vfs.h:121
size_t size
Definition vfs.h:115
void * p
the filesystem's own data
Definition vfs.h:130
mode_t mode
Definition vfs.h:118
uint16_t dev_t
Definition types.h:18
uintptr_t ino_t
Definition types.h:23
long int ssize_t
Definition types.h:12
long int off_t
Definition types.h:10
uint32_t mode_t
Definition types.h:15