AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
cpio.c
Go to the documentation of this file.
1
10
11#include <core/system.h>
12#include <core/module.h>
13#include <core/panic.h>
14#include <core/time.h>
15
16#include <fs/vfs.h>
17#include <fs/initramfs.h>
18#include <fs/iobuf.h>
19#include <fs/posix.h>
20#include <fs/rofs.h>
21
22#include <cpio.h>
23
24MALLOC_DEFINE(M_CPIO, "cpio", "CPIO structure");
25
27static void cpio_dirent_name(struct dirent *dirent, const char *name)
28{
29 size_t len = strlen(name);
30
31 if (len >= MAXNAMELEN)
32 len = MAXNAMELEN - 1;
33
34 memcpy(dirent->d_name, name, len);
35 dirent->d_name[len] = '\0';
36}
37
40static int cpio_root_node(struct vnode *super, struct vnode **ref)
41{
42 int err = 0;
43 struct vnode *vnode = NULL;
44 struct cpio *p = NULL;
45
46 vnode = kmalloc(sizeof(struct vnode), &M_VNODE, M_ZERO);
47 if (vnode == NULL) {
48 err = -ENOMEM;
49 goto error;
50 }
51
52 p = kmalloc(sizeof(struct cpio), &M_CPIO, 0);
53 if (p == NULL) {
54 err = -ENOMEM;
55 goto error;
56 }
57
58 vnode->ino = (ino_t) vnode;
59 vnode->size = 0;
60 vnode->mode = S_IFDIR | 0775;
61 vnode->uid = 0;
62 vnode->gid = 0;
63 vnode->nlink = 2;
64 vnode->ref = 1;
65
66 struct timespec ts;
67 gettime(&ts);
68
69 vnode->ctime = ts;
70 vnode->atime = ts;
71 vnode->mtime = ts;
72
73 vnode->fs = &cpiofs;
74 vnode->p = p;
75
76 p->super = super;
77 p->parent = NULL;
78 p->dir = NULL;
79 p->count = 0;
80 p->data = 0;
81 p->next = NULL;
82
83 if (ref) *ref = vnode;
84
85 return 0;
86
87error:
88 if (p)
89 kfree(p);
90 if (vnode)
91 kfree(vnode);
92
93 return err;
94}
95
98static int cpio_new_node(const char *name, struct cpio_hdr *hdr, size_t sz, size_t data, struct vnode *sp, struct vnode **ref)
99{
100 int err = 0;
101 struct vnode *vnode = NULL;
102 struct cpio *p = NULL;
103
104 vnode = kmalloc(sizeof(struct vnode), &M_VNODE, M_ZERO);
105
106 if (vnode == NULL) {
107 err = -ENOMEM;
108 goto error;
109 }
110
111 p = kmalloc(sizeof(struct cpio), &M_CPIO, 0);
112 if (p == NULL) {
113 err = -ENOMEM;
114 goto error;
115 }
116
117 vnode->ino = (vino_t) vnode;
118 vnode->size = sz;
119 vnode->uid = 0;
120 vnode->gid = 0;
121 vnode->mode = hdr->mode;
122 vnode->nlink = hdr->nlink;
123 vnode->mtime = (struct timespec) {.tv_sec = hdr->mtime[0] * 0x10000 + hdr->mtime[1], .tv_nsec = 0};
124 vnode->rdev = hdr->rdev;
125
126 vnode->fs = &cpiofs;
127 vnode->p = p;
128
129 p->super = sp;
130 p->parent = NULL;
131 p->dir = NULL;
132 p->count = 0;
133 p->data = data;
134 p->next = NULL;
135
136 /* its own copy of the name */
137 if (!(p->name = strdup(name))) {
138 err = -ENOMEM;
139 goto error;
140 }
141
142 if (ref) *ref = vnode;
143
144 return 0;
145
146error:
147 if (p)
148 kfree(p);
149 if (vnode)
150 kfree(vnode);
151 return err;
152}
153
156static struct vnode *cpio_new_child_node(struct vnode *parent, struct vnode *child)
157{
158 if (!parent || !child)
159 return NULL;
160
161 if (!S_ISDIR(parent->mode))
162 return NULL;
163
164 struct cpio *pp = (struct cpio *) parent->p;
165 struct cpio *cp = (struct cpio *) child->p;
166
167 struct vnode *tmp = pp->dir;
168
169 cp->next = tmp;
170 pp->dir = child;
171
172 pp->count++;
173 cp->parent = parent;
174
175 return child;
176}
177
180static struct vnode *cpio_find(struct vnode *root, const char *path)
181{
182 /* the path's components; NULL for an empty path (or no memory) */
183 char **tokens = tokenize(path, '/');
184 struct vnode *cur = NULL;
185
186 if (!S_ISDIR(root->mode))
187 goto done;
188
189 cur = root;
190 struct vnode *dir = ((struct cpio *) cur->p)->dir;
191
192 if (!dir) { /* the root has no entries yet */
193 if (tokens && *tokens)
194 cur = NULL;
195
196 goto done;
197 }
198
199 for (char **token_p = tokens; token_p && *token_p; ++token_p) {
200 char *token = *token_p;
201 int found = 0;
202
203 for (struct vnode *e = dir; e; e = ((struct cpio *) e->p)->next) {
204 if (((struct cpio *) e->p)->name &&
205 !strcmp(((struct cpio *) e->p)->name, token)) {
206 cur = e;
207 dir = ((struct cpio *) e->p)->dir;
208 found = 1;
209 break;
210 }
211 }
212
213 if (!found) { /* no such entry */
214 cur = NULL;
215 goto done;
216 }
217 }
218
219done:
220 free_tokens(tokens);
221 return cur;
222}
223
226static int cpio_finddir(struct vnode *root, const char *name, struct dirent *dirent)
227{
228 if (!S_ISDIR(root->mode))
229 return -ENOTDIR;
230
231 /* its parent (the root has none) */
232 if (!strcmp(name, "..")) {
233 struct vnode *parent = ((struct cpio *) root->p)->parent;
234
235 if (!parent)
236 return -ENOENT;
237
238 if (dirent) {
239 dirent->d_ino = (vino_t) parent;
240 cpio_dirent_name(dirent, name);
241 }
242
243 return 0;
244 }
245
246 struct vnode *dir = ((struct cpio *) root->p)->dir;
247
248 if (!dir) /* the directory is empty */
249 return -ENOENT;
250
251 for (struct vnode *e = dir; e; e = ((struct cpio *) e->p)->next) {
252 if (((struct cpio *) e->p)->name &&
253 !strcmp(((struct cpio *) e->p)->name, name)) {
254 if (dirent) {
255 dirent->d_ino = (vino_t) e;
256 cpio_dirent_name(dirent, name);
257 }
258
259 return 0;
260 }
261 }
262
263 return -ENOENT;
264}
265
267static int cpio_vget(struct vnode *super, ino_t ino, struct vnode **vnode)
268{
269 *vnode = (struct vnode *) ino;
270 return 0;
271}
272
273#define MAX_NAMESIZE 1024
274
280static int cpio_load(struct vnode *dev, struct vnode **super)
281{
282 /* the root directory */
283 struct vnode *rootfs = NULL;
284 int err = cpio_root_node(dev, &rootfs);
285
286 if (err)
287 return err;
288
289 struct cpio_hdr hdr;
290 size_t offset = 0;
291 size_t size = 0;
292
293 for (; offset < dev->size;
294 offset += sizeof(struct cpio_hdr) + (hdr.namesize+1)/2*2 + (size+1)/2*2) {
295
296 size_t data_offset = offset;
297 vfs_read(dev, data_offset, sizeof(struct cpio_hdr), &hdr);
298
299 if (hdr.magic != CPIO_BIN_MAGIC) {
300 panic("Invalid CPIO archive\n");
301 }
302
303 size = hdr.filesize[0] * 0x10000 + hdr.filesize[1];
304
305 data_offset += sizeof(struct cpio_hdr);
306
307 /* namesize comes from the archive: don't trust it */
308 size_t namesize = MIN(hdr.namesize, MAX_NAMESIZE - 1);
309
310 char path[MAX_NAMESIZE];
311 vfs_read(dev, data_offset, namesize, path);
312 path[namesize] = '\0';
313
314 if (!strcmp(path, ".")) continue;
315 if (!strcmp(path, "TRAILER!!!")) break; /* the end of the archive */
316
317 char *dir = NULL;
318 char *name = NULL;
319
320 /* split the path at its last '/': the directory, and the name */
321 for (int i = (int) namesize - 1; i >= 0; --i) {
322 if (path[i] == '/') {
323 path[i] = '\0';
324 name = &path[i+1];
325 dir = path;
326 break;
327 }
328 }
329
330 if (!name) {
331 name = path;
332 dir = "/";
333 }
334
335 data_offset += hdr.namesize + (hdr.namesize % 2);
336
337 /* its directory comes before it in the archive */
338 struct vnode *parent = cpio_find(rootfs, dir);
339
340 if (!parent) {
341 printk("cpio: %s/%s: its directory isn't in the archive\n", dir, name);
342 continue;
343 }
344
345 struct vnode *_node = NULL;
346
347 if ((err = cpio_new_node(name, &hdr, size, data_offset, dev, &_node)))
348 return err;
349
350 cpio_new_child_node(parent, _node);
351 }
352
353 if (super)
354 *super = rootfs;
355
356 return 0;
357}
358
360static ssize_t cpio_read(struct vnode *vnode, off_t offset, struct iobuf *io)
361{
362 if ((size_t) offset >= vnode->size)
363 return 0;
364
365 struct cpio *p = vnode->p;
366 struct vnode *super = p->super;
367
368 /* read no further than the file's end */
369 size_t cut = iobuf_limit(io, vnode->size - offset);
370 ssize_t ret = vfs_read_io(super, p->data + offset, io);
371 iobuf_unlimit(io, cut);
372
373 return ret;
374}
375
379static ssize_t cpio_readdir(struct vnode *node, off_t offset, struct dirent *dirent)
380{
381 if (offset == 0) {
382 strcpy(dirent->d_name, ".");
383 return 1;
384 }
385
386 if (offset == 1) {
387 strcpy(dirent->d_name, "..");
388 return 1;
389 }
390
391 offset -= 2;
392
393 struct cpio *p = (struct cpio *) node->p;
394
395 if ((size_t) offset == p->count)
396 return 0;
397
398 int i = 0;
399 struct vnode *dir = p->dir;
400
401 for (struct vnode *e = dir; e; e = ((struct cpio *) e->p)->next) {
402 if (i == offset) {
403 dirent->d_ino = (size_t) e;
404 cpio_dirent_name(dirent, ((struct cpio *) e->p)->name);
405 break;
406 }
407 ++i;
408 }
409
410 return i == offset;
411}
412
414static int cpio_close(struct vnode *vnode)
415{
416 return 0;
417}
418
421static int cpio_eof(struct file *file)
422{
423 if (S_ISDIR(file->vnode->mode)) {
424 return (size_t) file->offset >= ((struct cpio *) file->vnode->p)->count + 2;
425 } else {
426 return (size_t) file->offset >= file->vnode->size;
427 }
428}
429
431static int cpio_init()
432{
434}
435
436struct fs cpiofs = {
437 .name = "cpio",
438 .load = cpio_load,
439
440 .vops = {
441 .read = cpio_read,
442 .readdir = cpio_readdir,
443 .finddir = cpio_finddir,
444 .vget = cpio_vget,
445 .close = cpio_close,
446
447 .write = rofs_write,
448 .trunc = rofs_trunc,
449 .vmknod = rofs_vmknod,
450 .vunlink = rofs_vunlink,
451 .vlink = rofs_vlink,
452 .vrename = rofs_vrename,
453 .setattr = rofs_setattr,
454 },
455
456 .fops = {
457 .open = posix_file_open,
458 .close = posix_file_close,
459 .read = posix_file_read,
460 .write = posix_file_write,
461 .readdir = posix_file_readdir,
462 .lseek = posix_file_lseek,
463
464 .eof = cpio_eof,
465 },
466};
467
468MODULE_INIT(initramfs_cpio, cpio_init, NULL)
#define panic(s)
Definition panic.h:15
static int cpio_new_node(const char *name, struct cpio_hdr *hdr, size_t sz, size_t data, struct vnode *sp, struct vnode **ref)
Makes the vnode of an archive member: its name, its header, its data's size and where the data starts...
Definition cpio.c:98
static ssize_t cpio_read(struct vnode *vnode, off_t offset, struct iobuf *io)
Reads a file's data, from the archive.
Definition cpio.c:360
#define MAX_NAMESIZE
Definition cpio.c:273
static struct vnode * cpio_find(struct vnode *root, const char *path)
Finds the vnode at a path from the root, while the archive is loaded.
Definition cpio.c:180
struct fs cpiofs
Definition cpio.c:436
static int cpio_root_node(struct vnode *super, struct vnode **ref)
Makes the root directory's vnode, for the archive on device super.
Definition cpio.c:40
static int cpio_init()
Registers cpiofs as an archiver for the RAM disk, at boot.
Definition cpio.c:431
static void cpio_dirent_name(struct dirent *dirent, const char *name)
Copies an entry's name into a struct dirent, cut to fit.
Definition cpio.c:27
static int cpio_finddir(struct vnode *root, const char *name, struct dirent *dirent)
Finds the entry of a directory that has a name; .. is the directory's parent.
Definition cpio.c:226
static int cpio_vget(struct vnode *super, ino_t ino, struct vnode **vnode)
Gets a vnode by its inode number, which is its address.
Definition cpio.c:267
static ssize_t cpio_readdir(struct vnode *node, off_t offset, struct dirent *dirent)
Reads a directory's entry at an offset.
Definition cpio.c:379
static int cpio_load(struct vnode *dev, struct vnode **super)
Loads the archive on a device: the root directory, then a vnode for each member, linked into its dire...
Definition cpio.c:280
static int cpio_close(struct vnode *vnode)
Releases a vnode: nothing to do, the tree stays in memory.
Definition cpio.c:414
static int cpio_eof(struct file *file)
Says whether an open file (or directory) is at its end.
Definition cpio.c:421
static struct vnode * cpio_new_child_node(struct vnode *parent, struct vnode *child)
Adds a vnode to a directory's entries.
Definition cpio.c:156
#define CPIO_BIN_MAGIC
Definition cpio.h:8
#define MIN(a, b)
Definition system.h:11
int initramfs_archiver_register(struct fs *fs)
Registers a filesystem that can make a root from a RAM disk archive.
Definition initramfs.c:32
#define MALLOC_DEFINE(type, _name, _desc)
Definition kvmem.h:30
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 * memcpy(void *dst, const void *src, size_t n)
Copies n bytes; dst and src must not overlap.
Definition libc.c:11
off_t posix_file_lseek(struct file *file, off_t offset, int whence)
Moves an open file's offset: to offset (SEEK_SET), by offset from where it is (SEEK_CUR),...
Definition lseek.c:22
#define MODULE_INIT(name, i, f)
Definition module.h:10
int posix_file_open(struct file *file)
Finishes opening a file: with O_TRUNC, a regular file is truncated to 0 bytes.
Definition open.c:17
int posix_file_close(struct file *file)
Closes an open file by dropping its reference to its vnode.
Definition close.c:15
ssize_t posix_file_read(struct file *file, struct iobuf *io)
Reads from an open file at its offset, and moves the offset past what was read.
Definition read.c:29
ssize_t posix_file_readdir(struct file *file, struct dirent *dirent)
Reads the directory entry at an open directory's offset, and moves the offset past it.
Definition readdir.c:22
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
int printk(const char *fmt,...)
Writes a kernel message, to the message buffer and the consoles.
Definition printk.c:249
ssize_t vfs_read(struct vnode *vnode, off_t off, size_t size, void *buf)
Reads from a vnode into a kernel buffer.
Definition read.c:52
ssize_t vfs_read_io(struct vnode *vnode, off_t off, struct iobuf *io)
Reads from a vnode into an iobuf (user or kernel memory).
Definition read.c:20
ssize_t rofs_write(struct vnode *vnode, off_t offset, struct iobuf *io)
Refuses a write to a read-only filesystem.
Definition rofs.c:19
int rofs_setattr(struct vnode *vnode)
Refuses to change a node's attributes on a read-only filesystem.
Definition rofs.c:100
int rofs_vunlink(struct vnode *dir, const char *fn, struct uio *uio)
Refuses to remove a name from a read-only filesystem.
Definition rofs.c:60
int rofs_vmknod(struct vnode *dir, const char *fn, uint32_t mode, dev_t dev, struct uio *uio, struct vnode **ref)
Refuses to make a node on a read-only filesystem.
Definition rofs.c:47
int rofs_vrename(struct vnode *odir, const char *ofn, struct vnode *ndir, const char *nfn, struct uio *uio)
Refuses to rename on a read-only filesystem.
Definition rofs.c:89
int rofs_trunc(struct vnode *vnode, off_t len)
Refuses to truncate a file on a read-only filesystem.
Definition rofs.c:31
int rofs_vlink(struct vnode *dir, const char *fn, struct vnode *vnode, struct uio *uio)
Refuses to make a hard link on a read-only filesystem.
Definition rofs.c:74
#define NULL
Definition stddef.h:27
__SIZE_TYPE__ size_t
Definition stddef.h:7
The header of a member of an old binary cpio archive, as it is in the archive: its name follows,...
Definition cpio.h:12
uint16_t filesize[2]
Definition cpio.h:23
uint16_t nlink
Definition cpio.h:19
uint16_t rdev
Definition cpio.h:20
uint16_t magic
Definition cpio.h:13
uint16_t namesize
Definition cpio.h:22
uint16_t mode
Definition cpio.h:16
uint16_t mtime[2]
Definition cpio.h:21
What cpiofs keeps for each of its vnodes, a member of the archive.
Definition cpio.h:27
struct vnode * super
Definition cpio.h:28
const char * name
Definition cpio.h:34
size_t data
Definition cpio.h:32
struct vnode * parent
Definition cpio.h:29
size_t count
Definition cpio.h:31
struct vnode * dir
Definition cpio.h:30
struct vnode * next
Definition cpio.h:35
A device driver: its operations, any of which may be NULL.
Definition dev.h:28
An open file (POSIX's "open file description", fs/file.c).
Definition vfs.h:157
off_t offset
Definition vfs.h:163
A filesystem type.
Definition vfs.h:98
char * name
Definition vfs.h:99
An iobuf.
Definition iobuf.h:35
time_t tv_sec
Definition types.h:31
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
size_t ref
how many references there are to it
Definition vfs.h:133
nlink_t nlink
Definition vfs.h:121
struct fs * fs
Definition vfs.h:127
_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
dev_t rdev
Definition vfs.h:117
int gettime(struct timespec *ts)
Reads the wall clock (CLOCK_REALTIME).
Definition time.c:29
uintptr_t ino_t
Definition types.h:23
uintptr_t vino_t
Definition types.h:14
long int ssize_t
Definition types.h:12
long int off_t
Definition types.h:10