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