1 /*
2  * Copyright 2018 The Hafnium Authors.
3  *
4  * Use of this source code is governed by a BSD-style
5  * license that can be found in the LICENSE file or at
6  * https://opensource.org/licenses/BSD-3-Clause.
7  */
8 
9 #include "hf/cpio.h"
10 
11 #include <stdint.h>
12 
13 #include "hf/std.h"
14 
15 #pragma pack(push, 1)
16 struct cpio_header {
17 	uint16_t magic;
18 	uint16_t dev;
19 	uint16_t ino;
20 	uint16_t mode;
21 	uint16_t uid;
22 	uint16_t gid;
23 	uint16_t nlink;
24 	uint16_t rdev;
25 	uint16_t mtime[2];
26 	uint16_t namesize;
27 	uint16_t filesize[2];
28 };
29 #pragma pack(pop)
30 
31 /**
32  * Retrieves the next file stored in the cpio archive stored in the cpio, and
33  * advances the iterator such that another call to this function would return
34  * the following file.
35  */
cpio_next(struct memiter * iter,const char ** name,const void ** contents,size_t * size)36 static bool cpio_next(struct memiter *iter, const char **name,
37 		      const void **contents, size_t *size)
38 {
39 	static const char trailer[] = "TRAILER!!!";
40 	size_t len;
41 	struct memiter lit = *iter;
42 	const struct cpio_header *h = (const struct cpio_header *)lit.next;
43 
44 	if (!memiter_advance(&lit, sizeof(struct cpio_header))) {
45 		return false;
46 	}
47 
48 	*name = lit.next;
49 
50 	/* TODO: Check magic. */
51 
52 	len = (h->namesize + 1) & ~1;
53 	if (!memiter_advance(&lit, len)) {
54 		return false;
55 	}
56 
57 	*contents = lit.next;
58 
59 	len = (size_t)h->filesize[0] << 16 | h->filesize[1];
60 	if (!memiter_advance(&lit, (len + 1) & ~1)) {
61 		return false;
62 	}
63 
64 	/* TODO: Check that string is null-terminated. */
65 
66 	/* Stop enumerating files when we hit the end marker. */
67 	if (!strncmp(*name, trailer, sizeof(trailer))) {
68 		return false;
69 	}
70 
71 	*size = len;
72 	*iter = lit;
73 
74 	return true;
75 }
76 
77 /**
78  * Looks for a file in the given cpio archive. The file, if found, is returned
79  * in the "it" argument.
80  */
cpio_get_file(const struct memiter * cpio,const struct string * name,struct memiter * it)81 bool cpio_get_file(const struct memiter *cpio, const struct string *name,
82 		   struct memiter *it)
83 {
84 	const char *fname;
85 	const void *fcontents;
86 	size_t fsize;
87 	struct memiter iter = *cpio;
88 
89 	while (cpio_next(&iter, &fname, &fcontents, &fsize)) {
90 		if (!strncmp(fname, string_data(name), STRING_MAX_SIZE)) {
91 			memiter_init(it, fcontents, fsize);
92 			return true;
93 		}
94 	}
95 
96 	return false;
97 }
98