blob: 1b6f1efdc147b10825d9a433f846edc4a687542d [file] [log] [blame]
Andrew Scull18834872018-10-12 11:48:09 +01001/*
Andrew Walbran692b3252019-03-07 15:51:31 +00002 * Copyright 2018 The Hafnium Authors.
Andrew Scull18834872018-10-12 11:48:09 +01003 *
Andrew Walbrane959ec12020-06-17 15:01:09 +01004 * 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.
Andrew Scull18834872018-10-12 11:48:09 +01007 */
8
Andrew Scull18c78fc2018-08-20 12:57:41 +01009#include "hf/cpio.h"
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010010
11#include <stdint.h>
12
Dmitrii Martynov8f9c7182023-01-25 18:14:30 +030013#include "hf/dlog.h"
Andrew Scull8d9e1212019-04-05 13:52:55 +010014#include "hf/std.h"
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010015
Dmitrii Martynov8f9c7182023-01-25 18:14:30 +030016#define CPIO_OLD_BINARY_FORMAT_MAGIC 070707
17
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010018#pragma pack(push, 1)
19struct cpio_header {
20 uint16_t magic;
21 uint16_t dev;
22 uint16_t ino;
23 uint16_t mode;
24 uint16_t uid;
25 uint16_t gid;
26 uint16_t nlink;
27 uint16_t rdev;
28 uint16_t mtime[2];
29 uint16_t namesize;
30 uint16_t filesize[2];
31};
32#pragma pack(pop)
33
Wedson Almeida Filho9ee60e92018-07-23 18:56:56 +010034/**
35 * Retrieves the next file stored in the cpio archive stored in the cpio, and
36 * advances the iterator such that another call to this function would return
37 * the following file.
38 */
David Brazdil136f2942019-09-23 14:11:03 +010039static bool cpio_next(struct memiter *iter, const char **name,
40 const void **contents, size_t *size)
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010041{
Andrew Scull3c351e92020-01-28 11:26:05 +000042 static const char trailer[] = "TRAILER!!!";
Wedson Almeida Filho9ee60e92018-07-23 18:56:56 +010043 size_t len;
Dmitrii Martynov8f9c7182023-01-25 18:14:30 +030044 struct memiter lit;
45 const struct cpio_header *h;
46
47 if (!iter) {
48 return false;
49 }
50
51 lit = *iter;
52
53 h = (const struct cpio_header *)lit.next;
54 if (!h) {
55 return false;
56 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010057
Wedson Almeida Filho9ee60e92018-07-23 18:56:56 +010058 if (!memiter_advance(&lit, sizeof(struct cpio_header))) {
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010059 return false;
Andrew Scull7364a8e2018-07-19 15:39:29 +010060 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010061
Dmitrii Martynov8f9c7182023-01-25 18:14:30 +030062 if (h->magic != CPIO_OLD_BINARY_FORMAT_MAGIC) {
63 dlog_error("cpio: only old binary format is supported\n");
64 return false;
65 }
Wedson Almeida Filho9ee60e92018-07-23 18:56:56 +010066
Dmitrii Martynov8f9c7182023-01-25 18:14:30 +030067 *name = lit.next;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010068
Wedson Almeida Filho9ee60e92018-07-23 18:56:56 +010069 len = (h->namesize + 1) & ~1;
70 if (!memiter_advance(&lit, len)) {
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010071 return false;
Andrew Scull7364a8e2018-07-19 15:39:29 +010072 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010073
Dmitrii Martynov8f9c7182023-01-25 18:14:30 +030074 /* previous memiter_advance checks for boundaries */
75 if (h->namesize == 0U || (*name)[h->namesize - 1] != '\0') {
76 return false;
77 }
78
Wedson Almeida Filho9ee60e92018-07-23 18:56:56 +010079 *contents = lit.next;
80
81 len = (size_t)h->filesize[0] << 16 | h->filesize[1];
82 if (!memiter_advance(&lit, (len + 1) & ~1)) {
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010083 return false;
Andrew Scull7364a8e2018-07-19 15:39:29 +010084 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010085
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010086 /* Stop enumerating files when we hit the end marker. */
Andrew Scull3c351e92020-01-28 11:26:05 +000087 if (!strncmp(*name, trailer, sizeof(trailer))) {
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010088 return false;
Andrew Scull7364a8e2018-07-19 15:39:29 +010089 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010090
Wedson Almeida Filho9ee60e92018-07-23 18:56:56 +010091 *size = len;
92 *iter = lit;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010093
94 return true;
95}
David Brazdil136f2942019-09-23 14:11:03 +010096
97/**
98 * Looks for a file in the given cpio archive. The file, if found, is returned
99 * in the "it" argument.
100 */
101bool cpio_get_file(const struct memiter *cpio, const struct string *name,
102 struct memiter *it)
103{
104 const char *fname;
105 const void *fcontents;
106 size_t fsize;
107 struct memiter iter = *cpio;
108
109 while (cpio_next(&iter, &fname, &fcontents, &fsize)) {
Andrew Scull3c351e92020-01-28 11:26:05 +0000110 if (!strncmp(fname, string_data(name), STRING_MAX_SIZE)) {
David Brazdil136f2942019-09-23 14:11:03 +0100111 memiter_init(it, fcontents, fsize);
112 return true;
113 }
114 }
115
116 return false;
117}