blob: 6cf87575fb144cd2cea24d376dd7c8e4a989f4e8 [file] [log] [blame]
/*
* Copyright 2018 The Hafnium Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "hf/cpio.h"
#include <stdint.h>
#include "hf/std.h"
#pragma pack(push, 1)
struct cpio_header {
uint16_t magic;
uint16_t dev;
uint16_t ino;
uint16_t mode;
uint16_t uid;
uint16_t gid;
uint16_t nlink;
uint16_t rdev;
uint16_t mtime[2];
uint16_t namesize;
uint16_t filesize[2];
};
#pragma pack(pop)
/**
* Retrieves the next file stored in the cpio archive stored in the cpio, and
* advances the iterator such that another call to this function would return
* the following file.
*/
static bool cpio_next(struct memiter *iter, const char **name,
const void **contents, size_t *size)
{
static const char trailer[] = "TRAILER!!!";
size_t len;
struct memiter lit = *iter;
const struct cpio_header *h = (const struct cpio_header *)lit.next;
if (!memiter_advance(&lit, sizeof(struct cpio_header))) {
return false;
}
*name = lit.next;
/* TODO: Check magic. */
len = (h->namesize + 1) & ~1;
if (!memiter_advance(&lit, len)) {
return false;
}
*contents = lit.next;
len = (size_t)h->filesize[0] << 16 | h->filesize[1];
if (!memiter_advance(&lit, (len + 1) & ~1)) {
return false;
}
/* TODO: Check that string is null-terminated. */
/* Stop enumerating files when we hit the end marker. */
if (!strncmp(*name, trailer, sizeof(trailer))) {
return false;
}
*size = len;
*iter = lit;
return true;
}
/**
* Looks for a file in the given cpio archive. The file, if found, is returned
* in the "it" argument.
*/
bool cpio_get_file(const struct memiter *cpio, const struct string *name,
struct memiter *it)
{
const char *fname;
const void *fcontents;
size_t fsize;
struct memiter iter = *cpio;
while (cpio_next(&iter, &fname, &fcontents, &fsize)) {
if (!strncmp(fname, string_data(name), STRING_MAX_SIZE)) {
memiter_init(it, fcontents, fsize);
return true;
}
}
return false;
}