AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
vops.c
Go to the documentation of this file.
1
9
10#include <ext2.h>
11#include <core/time.h>
12#include <fs/iobuf.h>
13
23ssize_t ext2_read(struct vnode *node, off_t offset, struct iobuf *io)
24{
25 int err = 0;
26
27 struct ext2 *desc = node->p;
28
29 size_t bs = desc->bs;
30 struct ext2_inode inode;
31
32 if ((err = ext2_inode_read(desc, node->ino, &inode)))
33 return err;
34
35 if ((size_t) offset >= inode.size)
36 return 0;
37
38 size_t size = MIN(io->resid, (size_t) (inode.size - offset));
39
40 /* a fast symbolic link keeps its target in the block pointers */
41 if (S_ISLNK(inode.mode) && !inode.blocks)
42 return iobuf_out(io, (char *) inode.direct_pointer + offset, size);
43
44 char *block = kmalloc(bs, &M_BUFFER, 0);
45
46 if (!block)
47 return -ENOMEM;
48
49 size_t done = 0;
50 ssize_t r = 0;
51
52 while (done < size) {
53 size_t off = (offset + done) % bs;
54 size_t len = MIN(bs - off, size - done);
55
56 if ((r = ext2_inode_block_read(desc, &inode, (offset + done) / bs, block)))
57 break;
58
59 if ((r = iobuf_out(io, block + off, len)) < 0)
60 break;
61
62 done += r;
63
64 /* a fault stopped the copy */
65 if ((size_t) r < len)
66 break;
67 }
68
69 kfree(block);
70 return done ? (ssize_t) done : r;
71}
72
83ssize_t ext2_write(struct vnode *node, off_t offset, struct iobuf *io)
84{
85 size_t size = io->resid;
86
87 vfs_log(LOG_DEBUG, "ext2_write(inode=%p, offset=%d, size=%d)\n", node, offset, size);
88
89 int err = 0;
90 struct ext2 *desc = node->p;
91
92 size_t bs = desc->bs;
94
95 if ((err = ext2_inode_read(desc, node->ino, &ext2_inode)))
96 return err;
97
98 /* a short symbolic link keeps its target in the block pointers (a
99 * "fast" link: e2fsck expects every link under 60 bytes to be one) */
100 if (S_ISLNK(node->mode) && !ext2_inode.blocks &&
101 (size_t) offset + size < sizeof(ext2_inode.direct_pointer) + 12) {
102 ssize_t r = iobuf_in(io, (char *) ext2_inode.direct_pointer + offset, size);
103
104 if (r <= 0)
105 return r;
106
107 if ((size_t) offset + r > ext2_inode.size)
108 ext2_inode.size = node->size = (size_t) offset + r;
109
110 return ext2_inode_write(desc, node->ino, &ext2_inode) < 0 ? -EIO : r;
111 }
112
113 size_t old_size = ext2_inode.size;
114
115 if ((size_t) offset + size > ext2_inode.size) {
116 ext2_inode.size = (size_t) offset + size;
117 ext2_trunc(node, (size_t) offset + size);
118 }
119
120 size = MIN(size, (size_t) (ext2_inode.size - offset));
121
122 char *block = kmalloc(bs, &M_BUFFER, 0);
123
124 if (!block)
125 return -ENOMEM;
126
127 size_t done = 0;
128 ssize_t r = 0;
129
130 while (done < size) {
131 size_t off = (offset + done) % bs;
132 size_t len = MIN(bs - off, size - done);
133
134 /* writing part of a block: read the rest of it first (if it can't
135 * be read, it isn't written over) */
136 if ((off || len < bs) &&
137 (r = ext2_inode_block_read(desc, &ext2_inode, (offset + done) / bs, block)))
138 break;
139
140 if ((r = iobuf_in(io, block + off, len)) <= 0)
141 break;
142
143 if ((err = ext2_inode_block_write(desc, &ext2_inode, node->ino, (offset + done) / bs, block))) {
144 r = err;
145 break;
146 }
147
148 done += r;
149
150 /* a fault stopped the copy */
151 if ((size_t) r < len)
152 break;
153 }
154
155 kfree(block);
156
157 /* if it stopped short, the file ends where the data does */
158 if (done < size && (size_t) offset + size > old_size)
159 ext2_trunc(node, MAX(old_size, (size_t) offset + done));
160
161 /* a short write, if some of the data was written */
162 return done ? (ssize_t) done : r;
163}
164
174ssize_t ext2_readdir(struct vnode *dir, off_t offset, struct dirent *dirent)
175{
176 int err = 0;
177
178 if (!S_ISDIR(dir->mode))
179 return -ENOTDIR;
180
181 struct ext2 *desc = dir->p;
182 struct ext2_inode inode;
183
184 if ((err = ext2_inode_read(desc, dir->ino, &inode)))
185 return err;
186
187 if (!S_ISDIR(inode.mode))
188 return -ENOTDIR;
189
190 size_t bs = desc->bs;
191 size_t blocks_nr = inode.size / bs;
192
193 /* not on the stack: a block is up to 4 KiB, and i386's kernel stack
194 * is 8 KiB */
195 char *buf = kmalloc(bs, &M_BUFFER, 0);
196 if (!buf) return -ENOMEM;
197
198 struct ext2_dentry *dentry;
199 off_t idx = 0;
200 char found = 0;
201
202 for (size_t i = 0; i < blocks_nr; ++i) {
203 if ((err = ext2_inode_block_read(desc, &inode, i, buf))) {
204 kfree(buf);
205 return err;
206 }
207
208 dentry = (struct ext2_dentry *) buf;
209
210 /* while an entry's header and name fit in the block */
211 while ((char *) dentry + sizeof(*dentry) <= buf + bs) {
212 if (!dentry->size) /* a corrupted entry */
213 break;
214
215 if ((char *) dentry->name + dentry->length > buf + bs)
216 break;
217
218 /* an unused entry */
219 if (!dentry->ino) {
220 dentry = (struct ext2_dentry *) ((char *) dentry + dentry->size);
221 continue;
222 }
223
224 if (idx == offset) {
225 dirent->d_ino = dentry->ino;
226 memcpy(dirent->d_name, (char *) dentry->name, dentry->length);
227 dirent->d_name[dentry->length] = '\0';
228 found = 1;
229 break;
230 }
231
232 dentry = (struct ext2_dentry *) ((char *) dentry + dentry->size);
233 ++idx;
234 }
235
236 if (found)
237 break;
238 }
239
240 kfree(buf);
241 return found;
242}
243
252int ext2_trunc(struct vnode *inode, off_t len)
253{
254 if ((size_t) len == inode->size)
255 return 0;
256
257 /* growing only changes the size: the new part is a hole */
258 if ((size_t) len > inode->size) {
259 inode->size = len;
260 ext2_inode_sync(inode);
261 return 0;
262 }
263
264 /* shrinking: free the blocks past the new end */
265 struct ext2 *desc = inode->p;
266 struct ext2_inode einode;
267 size_t bs = desc->bs;
268 int err;
269
270 if ((err = ext2_inode_read(desc, inode->ino, &einode)))
271 return err;
272
273 ext2_blocks_free(desc, &einode, (len + bs - 1) / bs);
274
275 /* zero the rest of the last block, so that it reads as zeros if the
276 * file grows again (a block that can't be read isn't written over) */
277 if (len % bs) {
278 char *buf = kmalloc(bs, &M_BUFFER, 0);
279
280 if (!buf)
281 return -ENOMEM;
282
283 if (!(err = ext2_inode_block_read(desc, &einode, len / bs, buf))) {
284 memset(buf + len % bs, 0, bs - len % bs);
285 err = ext2_inode_block_write(desc, &einode, inode->ino, len / bs, buf);
286 }
287
288 kfree(buf);
289
290 if (err)
291 return err;
292 }
293
294 einode.size = len;
295 inode->size = len;
296 return ext2_inode_write(desc, inode->ino, &einode) < 0 ? -EIO : 0;
297}
298
312int ext2_vmknod(struct vnode *dir, const char *fn, mode_t mode, dev_t dev, struct uio *uio, struct vnode **ref)
313{
314 int err = 0;
315
316 if (!fn || !*fn)
317 return -EINVAL;
318
319 struct ext2 *desc = dir->p;
320 struct ext2_inode dir_inode;
321
322 if ((err = ext2_inode_read(desc, dir->ino, &dir_inode)))
323 return err;
324
325 /* is the name taken? */
326 ino_t ino;
327
328 if (!(err = ext2_dentry_find(desc, &dir_inode, fn, &ino)))
329 return -EEXIST;
330
331 if (err != -ENOENT)
332 return err;
333
334 if ((err = ext2_inode_alloc(desc, &ino)))
335 return err;
336
337 struct ext2_inode inode;
338
339 memset(&inode, 0, sizeof(struct ext2_inode));
340
341 inode.mode = mode;
342 inode.uid = uio->uid;
343 inode.gid = uio->gid;
344
345 /* a device node's number, where ext2_inode_build() reads it */
346 if (S_ISCHR(mode) || S_ISBLK(mode))
348
349 struct timespec ts;
350 gettime(&ts);
351
352 inode.ctime = ts.tv_sec;
353 inode.atime = ts.tv_sec;
354 inode.mtime = ts.tv_sec;
355
356 if (S_ISDIR(mode)) { /* a directory starts with . and .. */
357 inode.nlink = 2;
358 inode.size = desc->bs;
359
360 /* zeroed, so that the names are padded with NULs (if there's no
361 * memory, the inode is freed again below) */
362 char *buf = kmalloc(desc->bs, &M_BUFFER, M_ZERO);
363
364 if (!buf) {
365 err = -ENOMEM;
366 } else {
367 struct ext2_dentry *d = (struct ext2_dentry *) buf;
368 d->ino = ino;
369 d->size = 12;
370 d->length = 1;
371 d->type = desc->filetype ? EXT2_DENTRY_TYPE_DIR : 0;
372 memcpy(d->name, ".", 1);
373 d = (struct ext2_dentry *) ((char *) d + 12);
374 d->ino = dir->ino;
375 d->size = desc->bs - 12;
376 d->length = 2;
377 d->type = desc->filetype ? EXT2_DENTRY_TYPE_DIR : 0;
378 memcpy(d->name, "..", 2);
379 err = ext2_inode_block_write(desc, &inode, ino, 0, buf);
380 kfree(buf);
381 }
382 } else {
383 inode.nlink = 1;
384 err = ext2_inode_write(desc, ino, &inode);
385 }
386
387 /* if it couldn't be added to the directory, the inode is freed */
388 if (err || (err = ext2_dentry_create(dir, fn, ino, inode.mode))) {
389 ext2_inode_discard(desc, ino);
390 return err;
391 }
392
393 if (S_ISDIR(mode)) {
394 /* the parent gets a link, the new directory's .. */
395 dir->nlink++;
396 ext2_inode_sync(dir);
397
398 desc->groups[(ino - 1) / desc->superblock->ginodes].directories_count++;
400 }
401
402 return ref ? ext2_inode_build(desc, ino, ref) : 0;
403}
404
414int ext2_finddir(struct vnode *dir, const char *fn, struct dirent *dirent)
415{
416 int err = 0;
417
418 struct ext2 *desc = dir->p;
419
420 uint32_t inode = dir->ino;
421
422 struct ext2_inode i;
423 ino_t inode_nr;
424
425 if ((err = ext2_inode_read(desc, inode, &i)) ||
426 (err = ext2_dentry_find(desc, &i, fn, &inode_nr)))
427 return err;
428
429 if (dirent)
430 dirent->d_ino = inode_nr;
431
432 return 0;
433}
434
443int ext2_vget(struct vnode *super, ino_t ino, struct vnode **ref)
444{
445 struct ext2 *desc = super->p;
446
447 return ref ? ext2_inode_build(desc, ino, ref) : 0;
448}
449
457{
458 struct ext2 *desc = vnode->p;
459 struct ext2_inode inode;
460 int err;
461
462 if ((err = ext2_inode_read(desc, vnode->ino, &inode)))
463 return err;
464
465 inode.mode = vnode->mode;
466 inode.uid = vnode->uid;
467 inode.gid = vnode->gid;
468 inode.atime = vnode->atime.tv_sec;
469 inode.mtime = vnode->mtime.tv_sec;
470 inode.ctime = vnode->ctime.tv_sec;
471
472 return ext2_inode_write(desc, vnode->ino, &inode);
473}
#define DEV_MAJOR(dev)
Definition dev.h:77
#define DEV(major, minor)
Definition dev.h:76
#define DEV_MINOR(dev)
Definition dev.h:78
int ext2_bgd_table_rewrite(struct ext2 *desc)
Writes the block group descriptor table back to the disk, after a change to a group's counts.
Definition block.c:34
int ext2_dentry_create(struct vnode *dir, const char *name, ino_t ino, mode_t mode)
Adds an entry to a directory.
Definition dentry.c:87
int ext2_dentry_find(struct ext2 *desc, struct ext2_inode *inode, const char *name, ino_t *ino)
Finds the inode number of a name in a directory.
Definition dentry.c:20
int ext2_inode_build(struct ext2 *desc, ino_t ino, struct vnode **ref_inode)
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 ext2.c:29
int ext2_inode_sync(struct vnode *inode)
Writes a vnode's attributes back to its inode on the disk.
Definition ext2.c:93
ssize_t ext2_write(struct vnode *node, off_t offset, struct iobuf *io)
Writes to a file, which grows if the write goes past its end.
Definition vops.c:83
void ext2_blocks_free(struct ext2 *desc, struct ext2_inode *inode, size_t from)
Frees a file's blocks, from a block on, when the file is truncated or removed.
Definition remove.c:69
ssize_t ext2_read(struct vnode *node, off_t offset, struct iobuf *io)
Reads from a file.
Definition vops.c:23
int ext2_inode_alloc(struct ext2 *desc, ino_t *ino)
Allocates a free inode: its bit is set in its group's inode bitmap, and the free counts go down.
Definition inode.c:281
int ext2_vget(struct vnode *super, ino_t ino, struct vnode **ref)
Gets the vnode of an inode, by its number.
Definition vops.c:443
int ext2_inode_read(struct ext2 *desc, ino_t inode, struct ext2_inode *ref)
Reads an inode from the disk.
Definition inode.c:33
int ext2_trunc(struct vnode *inode, off_t len)
Changes a file's length.
Definition vops.c:252
void ext2_inode_discard(struct ext2 *desc, ino_t ino)
Frees an inode that has no links left, and the blocks it uses.
Definition remove.c:131
int ext2_inode_block_read(struct ext2 *desc, struct ext2_inode *inode, size_t idx, void *buf)
Reads a block of a file.
Definition inode.c:144
#define EXT2_DENTRY_TYPE_DIR
Definition ext2.h:158
int ext2_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:312
int ext2_inode_write(struct ext2 *desc, ino_t inode, struct ext2_inode *i)
Writes an inode to the disk.
Definition inode.c:51
ssize_t ext2_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:174
int ext2_setattr(struct vnode *vnode)
Stores a vnode's attributes (mode, owner, times) in its inode.
Definition vops.c:456
int ext2_finddir(struct vnode *dir, const char *fn, struct dirent *dirent)
Finds the entry of a directory that has a name.
Definition vops.c:414
int ext2_inode_block_write(struct ext2 *desc, struct ext2_inode *inode, uint32_t inode_nr, size_t idx, void *buf)
Writes a block of a file, allocating it and the indirect blocks above it if they don't exist yet.
Definition inode.c:235
#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
#define M_ZERO
Definition kvmem.h:26
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
#define LOG_DEBUG
Definition printk.h:19
unsigned int uint32_t
Definition stddef.h:22
__SIZE_TYPE__ size_t
Definition stddef.h:7
A device driver: its operations, any of which may be NULL.
Definition dev.h:28
A directory entry, as it is on the disk.
Definition ext2.h:142
uint16_t size
entry total size
Definition ext2.h:146
uint8_t name[0]
the name follows (not NUL-terminated)
Definition ext2.h:152
uint32_t ino
inode number
Definition ext2.h:144
uint8_t type
entry type
Definition ext2.h:150
uint8_t length
name length
Definition ext2.h:148
uint16_t directories_count
Definition ext2.h:109
An inode, as it is on the disk.
Definition ext2.h:114
uint32_t ctime
Definition ext2.h:119
uint16_t nlink
Definition ext2.h:123
uint16_t gid
Definition ext2.h:122
uint32_t blocks
Definition ext2.h:124
uint32_t size
Definition ext2.h:117
uint32_t mtime
Definition ext2.h:120
uint32_t direct_pointer[12]
Definition ext2.h:128
uint16_t mode
Definition ext2.h:115
uint32_t atime
Definition ext2.h:118
uint16_t uid
Definition ext2.h:116
uint32_t ginodes
number of inodes per block group
Definition ext2.h:56
A mounted ext2 filesystem.
Definition ext2.h:168
struct ext2_superblock * superblock
Definition ext2.h:170
struct ext2_group * groups
Definition ext2.h:171
size_t bs
the block size
Definition ext2.h:177
int filetype
directory entries have their file's type (EXT2_INCOMPAT_FILETYPE); without it, the byte is 0
Definition ext2.h:184
An iobuf.
Definition iobuf.h:35
size_t resid
Definition iobuf.h:38
time_t tv_sec
Definition types.h:31
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
_time_t atime
Definition vfs.h:123
_time_t ctime
Definition vfs.h:125
nlink_t nlink
Definition vfs.h:121
_time_t mtime
Definition vfs.h:124
gid_t gid
Definition vfs.h:120
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
uid_t uid
Definition vfs.h:119
int gettime(struct timespec *ts)
Reads the wall clock (CLOCK_REALTIME).
Definition time.c:29
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