зеркало из https://github.com/microsoft/lsvmtools.git
966 строки
24 KiB
C
966 строки
24 KiB
C
/*
|
|
**==============================================================================
|
|
**
|
|
** LSVMTools
|
|
**
|
|
** MIT License
|
|
**
|
|
** Copyright (c) Microsoft Corporation. All rights reserved.
|
|
**
|
|
** Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
** of this software and associated documentation files (the "Software"), to deal
|
|
** in the Software without restriction, including without limitation the rights
|
|
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
** copies of the Software, and to permit persons to whom the Software is
|
|
** furnished to do so, subject to the following conditions:
|
|
**
|
|
** The above copyright notice and this permission notice shall be included in
|
|
** all copies or substantial portions of the Software.
|
|
**
|
|
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
** SOFTWARE
|
|
**
|
|
**==============================================================================
|
|
*/
|
|
#include "config.h"
|
|
#include "cpio.h"
|
|
#include <lsvmutils/print.h>
|
|
#include <lsvmutils/alloc.h>
|
|
#include <lsvmutils/strings.h>
|
|
#if !defined(BUILD_EFI)
|
|
#include <lsvmutils/file.h>
|
|
#endif /* !defined(BUILD_EFI) */
|
|
#include "print.h"
|
|
|
|
#define CPIO_BLOCK_SIZE ((UINTN)512)
|
|
|
|
/* This is an empty CPIO archive (with just a trailer) */
|
|
static unsigned char _empty_archive[] =
|
|
{
|
|
0x30, 0x37, 0x30, 0x37, 0x30, 0x31, 0x30, 0x30,
|
|
0x32, 0x43, 0x30, 0x43, 0x42, 0x38, 0x30, 0x30,
|
|
0x30, 0x30, 0x34, 0x31, 0x45, 0x44, 0x30, 0x30,
|
|
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
|
|
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
|
|
0x30, 0x30, 0x30, 0x30, 0x30, 0x32, 0x35, 0x37,
|
|
0x45, 0x30, 0x33, 0x36, 0x34, 0x43, 0x30, 0x30,
|
|
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
|
|
0x30, 0x30, 0x30, 0x30, 0x46, 0x43, 0x30, 0x30,
|
|
0x30, 0x30, 0x30, 0x30, 0x30, 0x32, 0x30, 0x30,
|
|
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
|
|
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
|
|
0x30, 0x30, 0x30, 0x30, 0x30, 0x32, 0x30, 0x30,
|
|
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x2E, 0x00,
|
|
0x30, 0x37, 0x30, 0x37, 0x30, 0x31, 0x30, 0x30,
|
|
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
|
|
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
|
|
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
|
|
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
|
|
0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x30,
|
|
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
|
|
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
|
|
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
|
|
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
|
|
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
|
|
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
|
|
0x30, 0x30, 0x30, 0x30, 0x30, 0x42, 0x30, 0x30,
|
|
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x54, 0x52,
|
|
0x41, 0x49, 0x4C, 0x45, 0x52, 0x21, 0x21, 0x21,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
unsigned int _empty_archive_size = ARRSIZE(_empty_archive);
|
|
|
|
static void _DumpHeader(const CPIOHeader* self)
|
|
{
|
|
PRINTF0("=== CPIOHeader\n");
|
|
PRINTF("magic{%.*a}\n", (int)sizeof(self->magic), self->magic);
|
|
PRINTF("ino{%.*a}\n", (int)sizeof(self->ino), self->ino);
|
|
PRINTF("mode{%.*a}\n", (int)sizeof(self->mode), self->mode);
|
|
PRINTF("uid{%.*a}\n", (int)sizeof(self->uid), self->uid);
|
|
PRINTF("gid{%.*a}\n", (int)sizeof(self->gid), self->gid);
|
|
PRINTF("nlink{%.*a}\n", (int)sizeof(self->nlink), self->nlink);
|
|
PRINTF("mtime{%.*a}\n", (int)sizeof(self->mtime), self->mtime);
|
|
PRINTF("filesize{%.*a}\n", (int)sizeof(self->filesize), self->filesize);
|
|
PRINTF("devmajor{%.*a}\n", (int)sizeof(self->devmajor), self->devmajor);
|
|
PRINTF("devminor{%.*a}\n", (int)sizeof(self->devminor), self->devminor);
|
|
PRINTF("rdevmajor{%.*a}\n", (int)sizeof(self->rdevmajor), self->rdevmajor);
|
|
PRINTF("rdevminor{%.*a}\n", (int)sizeof(self->rdevminor), self->rdevminor);
|
|
PRINTF("namesize{%.*a}\n", (int)sizeof(self->namesize), self->namesize);
|
|
PRINTF("check{%.*a}\n", (int)sizeof(self->check), self->check);
|
|
}
|
|
|
|
static int _HexToInt(
|
|
const char* str,
|
|
unsigned int len)
|
|
{
|
|
const char* p;
|
|
int r = 1;
|
|
int x = 0;
|
|
|
|
for (p = str + len; p != str; p--)
|
|
{
|
|
int xdigit = p[-1];
|
|
int d;
|
|
|
|
if (xdigit >= '0' && xdigit <= '9')
|
|
{
|
|
d = xdigit - '0';
|
|
}
|
|
else if (xdigit >= 'A' && xdigit <= 'F')
|
|
{
|
|
d = (xdigit - 'A') + 10;
|
|
}
|
|
else
|
|
return -1;
|
|
|
|
x += r * d;
|
|
r *= 16;
|
|
}
|
|
|
|
return x;
|
|
}
|
|
|
|
static char _HexDigit(
|
|
unsigned int x)
|
|
{
|
|
switch (x)
|
|
{
|
|
case 0x0: return '0';
|
|
case 0x1: return '1';
|
|
case 0x2: return '2';
|
|
case 0x3: return '3';
|
|
case 0x4: return '4';
|
|
case 0x5: return '5';
|
|
case 0x6: return '6';
|
|
case 0x7: return '7';
|
|
case 0x8: return '8';
|
|
case 0x9: return '9';
|
|
case 0xA: return 'A';
|
|
case 0xB: return 'B';
|
|
case 0xC: return 'C';
|
|
case 0xD: return 'D';
|
|
case 0xE: return 'E';
|
|
case 0xF: return 'F';
|
|
}
|
|
|
|
return '\0';
|
|
}
|
|
|
|
static void _IntToHex(
|
|
char buf[8],
|
|
unsigned int x)
|
|
{
|
|
buf[0] = _HexDigit((x & 0xF0000000) >> 28);
|
|
buf[1] = _HexDigit((x & 0x0F000000) >> 24);
|
|
buf[2] = _HexDigit((x & 0x00F00000) >> 20);
|
|
buf[3] = _HexDigit((x & 0x000F0000) >> 16);
|
|
buf[4] = _HexDigit((x & 0x0000F000) >> 12);
|
|
buf[5] = _HexDigit((x & 0x00000F00) >> 8);
|
|
buf[6] = _HexDigit((x & 0x000000F0) >> 4);
|
|
buf[7] = _HexDigit((x & 0x0000000F) >> 0);
|
|
}
|
|
|
|
static int _RoundUpToMultiple(UINTN x, UINTN m)
|
|
{
|
|
return (int)((x + (m - 1)) / m * m);
|
|
}
|
|
|
|
int CPIOMatchMagicNumber(const char* s)
|
|
{
|
|
return
|
|
s[0] == '0' && s[1] == '7' && s[2] == '0' &&
|
|
s[3] == '7' && s[4] == '0' && s[5] == '1';
|
|
}
|
|
|
|
int CPIOTest(const void* data, UINTN size)
|
|
{
|
|
int rc = -1;
|
|
|
|
if (size < sizeof(CPIOHeader))
|
|
goto done;
|
|
|
|
if (!CPIOMatchMagicNumber(((const CPIOHeader*)data)->magic))
|
|
goto done;
|
|
|
|
rc = 0;
|
|
|
|
done:
|
|
return rc;
|
|
}
|
|
|
|
static int _GetFileMode(const CPIOHeader* header)
|
|
{
|
|
return _HexToInt(header->mode, 8);
|
|
}
|
|
|
|
static int _GetFileSize(const CPIOHeader* header)
|
|
{
|
|
return _HexToInt(header->filesize, 8);
|
|
}
|
|
|
|
static int _GetNameSize(const CPIOHeader* header)
|
|
{
|
|
return _HexToInt(header->namesize, 8);
|
|
}
|
|
|
|
static const char* _GetName(const CPIOHeader* header)
|
|
{
|
|
return (char*)(header + 1);
|
|
}
|
|
|
|
/* Get total size of an entry: HEADER + NAME + DATA + PADDING */
|
|
int CPIOGetEntrySize(const CPIOHeader* header)
|
|
{
|
|
int filesize;
|
|
int namesize;
|
|
|
|
if ((filesize = _GetFileSize(header)) == -1)
|
|
return -1;
|
|
|
|
if ((namesize = _GetNameSize(header)) == -1)
|
|
return -1;
|
|
|
|
return
|
|
_RoundUpToMultiple(sizeof(CPIOHeader) + namesize, 4) +
|
|
_RoundUpToMultiple(filesize, 4);
|
|
}
|
|
|
|
static UINTN _ComputeHeaderSize(
|
|
const char* path,
|
|
UINTN fileSize)
|
|
{
|
|
UINTN size = 0;
|
|
|
|
size += sizeof(CPIOHeader);
|
|
size += strlen(path) + 1;
|
|
size = _RoundUpToMultiple(size, 4);
|
|
size += fileSize;
|
|
size = _RoundUpToMultiple(size, 4);
|
|
|
|
return size;
|
|
}
|
|
|
|
static UINTN _ComputeTrailerSize()
|
|
{
|
|
UINTN size = 0;
|
|
|
|
size += sizeof(CPIOHeader);
|
|
size += sizeof("TRAILER!!!");
|
|
size = _RoundUpToMultiple(size, 4);
|
|
|
|
return size;
|
|
}
|
|
|
|
int CPIOCheckEntry(
|
|
const CPIOHeader* header,
|
|
const void* cpioEnd)
|
|
{
|
|
int rc = 0;
|
|
int remaining;
|
|
int size;
|
|
|
|
/* Calculate the remaining space */
|
|
remaining = (int)((char*)cpioEnd - (char*)header);
|
|
|
|
/* If not enough space left for another header */
|
|
if (sizeof(CPIOHeader) > remaining)
|
|
{
|
|
rc = -1;
|
|
goto done;
|
|
}
|
|
|
|
/* Check magic number */
|
|
if (!CPIOMatchMagicNumber(header->magic))
|
|
{
|
|
rc = -1;
|
|
goto done;
|
|
}
|
|
|
|
/* Get total size of this entry */
|
|
if ((size = CPIOGetEntrySize(header)) == -1)
|
|
{
|
|
rc = -1;
|
|
goto done;
|
|
}
|
|
|
|
/* If not enough space left */
|
|
if (size > remaining)
|
|
{
|
|
rc = -1;
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
return rc;
|
|
}
|
|
|
|
int CPIONextHeader(
|
|
const CPIOHeader** header,
|
|
const void* cpioEnd)
|
|
{
|
|
int rc = 0;
|
|
int size;
|
|
const char* name;
|
|
|
|
/* Check parameters */
|
|
if (!header || !*header)
|
|
{
|
|
rc = -1;
|
|
goto done;
|
|
}
|
|
|
|
/* Check for valid entry */
|
|
if (CPIOCheckEntry(*header, cpioEnd) != 0)
|
|
{
|
|
*header = NULL;
|
|
rc = -1;
|
|
goto done;
|
|
}
|
|
|
|
/* Get the name */
|
|
name = (const char*)(*header + 1);
|
|
|
|
/* If this is the trailer, then no more headers */
|
|
if (strcmp(name, "TRAILER!!!") == 0)
|
|
{
|
|
*header = NULL;
|
|
rc = 0;
|
|
goto done;
|
|
}
|
|
|
|
/* Get total size of this entry */
|
|
if ((size = CPIOGetEntrySize(*header)) == -1)
|
|
{
|
|
rc = -1;
|
|
goto done;
|
|
}
|
|
|
|
/* Get the next header */
|
|
*header = (CPIOHeader*)((char*)(*header) + size);
|
|
|
|
/* Check for valid entry */
|
|
if (CPIOCheckEntry(*header, cpioEnd) != 0)
|
|
{
|
|
*header = NULL;
|
|
rc = -1;
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
return rc;
|
|
}
|
|
|
|
static int _FindHeader(
|
|
const void* cpioData,
|
|
UINTN cpioSize,
|
|
const char* path,
|
|
const CPIOHeader** headerOut)
|
|
{
|
|
int rc = -1;
|
|
const CPIOHeader* header = (const CPIOHeader*)cpioData;
|
|
const void* cpioEnd = (char*)cpioData + cpioSize;
|
|
|
|
*headerOut = NULL;
|
|
|
|
while (header)
|
|
{
|
|
if (CPIOCheckEntry(header, cpioEnd) != 0)
|
|
goto done;
|
|
|
|
if (strcmp(_GetName(header), path) == 0)
|
|
{
|
|
*headerOut = header;
|
|
rc = 0;
|
|
goto done;
|
|
}
|
|
|
|
if (CPIONextHeader(&header, cpioEnd) != 0)
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
return rc;
|
|
}
|
|
|
|
int CPIONew(
|
|
void** data,
|
|
UINTN* size)
|
|
{
|
|
int rc = -1;
|
|
|
|
if (!data || !size)
|
|
return -1;
|
|
|
|
if (!(*data = Malloc(_empty_archive_size)))
|
|
goto done;
|
|
|
|
Memcpy(*data, _empty_archive, _empty_archive_size);
|
|
*size = _empty_archive_size;
|
|
|
|
rc = 0;
|
|
|
|
done:
|
|
return rc;
|
|
}
|
|
|
|
int CPIOAddFile(
|
|
const void* cpioDataIn,
|
|
UINTN cpioSizeIn,
|
|
const char* path,
|
|
const void* fileData,
|
|
UINTN fileSize,
|
|
unsigned int mode,
|
|
void** cpioDataOut,
|
|
UINTN* cpioSizeOut)
|
|
{
|
|
int rc = -1;
|
|
const CPIOHeader* trailer = NULL;
|
|
CPIOHeader newHeader;
|
|
|
|
/* Check parameters */
|
|
if (!cpioDataIn || !cpioSizeIn || !path || !cpioDataOut || !cpioSizeOut)
|
|
goto done;
|
|
|
|
/* Initialize output parameters */
|
|
*cpioDataOut = NULL;
|
|
*cpioSizeOut = 0;
|
|
|
|
/* Find the CPIO trailer */
|
|
if (_FindHeader(cpioDataIn, cpioSizeIn, "TRAILER!!!", &trailer) != 0)
|
|
goto done;
|
|
|
|
/* Compute the size of the new CPIO archive */
|
|
*cpioSizeOut = (char*)trailer - (char*)cpioDataIn;
|
|
*cpioSizeOut += _ComputeHeaderSize(path, fileSize);
|
|
*cpioSizeOut += _ComputeTrailerSize();
|
|
*cpioSizeOut = _RoundUpToMultiple(*cpioSizeOut, CPIO_BLOCK_SIZE);
|
|
|
|
/* Initialize the header for the new file */
|
|
newHeader = *trailer;
|
|
_IntToHex(newHeader.ino, 0x12345678);
|
|
_IntToHex(newHeader.mode, mode);
|
|
_IntToHex(newHeader.uid, 0);
|
|
_IntToHex(newHeader.gid, 0);
|
|
_IntToHex(newHeader.nlink, 1);
|
|
_IntToHex(newHeader.mtime, 0x56734BA4); /* hardcode a time */
|
|
_IntToHex(newHeader.filesize, (unsigned int)fileSize);
|
|
_IntToHex(newHeader.devmajor, 8);
|
|
_IntToHex(newHeader.devminor, 2);
|
|
_IntToHex(newHeader.rdevmajor, 0);
|
|
_IntToHex(newHeader.rdevminor, 0);
|
|
_IntToHex(newHeader.namesize, (unsigned int)(strlen(path) + 1));
|
|
_IntToHex(newHeader.check, 0);
|
|
|
|
#if 0
|
|
_DumpHeader(&newHeader);
|
|
#endif
|
|
|
|
/* Allocate the memory for the new CPIO archive */
|
|
if (!(*cpioDataOut = Calloc(1, *cpioSizeOut)))
|
|
goto done;
|
|
|
|
/* Copy over old CPIO archive to new CPIO archive (exclude trailer) */
|
|
Memcpy(*cpioDataOut, cpioDataIn, (char*)trailer - (char*)cpioDataIn);
|
|
|
|
/* Append new file and trailer */
|
|
{
|
|
UINTN offset = (char*)trailer - (char*)cpioDataIn;
|
|
char* p = (char*)*cpioDataOut;
|
|
|
|
/* New file header */
|
|
Memcpy(p + offset, &newHeader, sizeof(CPIOHeader));
|
|
offset += sizeof(CPIOHeader);
|
|
|
|
/* New file name (pad to 4-byte boundary) */
|
|
Memcpy(p + offset, path, strlen(path) + 1);
|
|
offset += strlen(path) + 1;
|
|
offset = _RoundUpToMultiple(offset, 4);
|
|
|
|
/* New file data (pad to 4-byte boundary) */
|
|
if (fileData)
|
|
{
|
|
Memcpy(p + offset, fileData, fileSize);
|
|
offset += fileSize;
|
|
}
|
|
|
|
offset = _RoundUpToMultiple(offset, 4);
|
|
|
|
/* Trailer header */
|
|
Memcpy(p + offset, trailer, sizeof(CPIOHeader));
|
|
offset += sizeof(CPIOHeader);
|
|
|
|
/* New file name */
|
|
Memcpy(p + offset, "TRAILER!!!", sizeof("TRAILER!!!"));
|
|
offset += sizeof("TRAILER!!!");
|
|
|
|
/* Pad to 4-byte boundary */
|
|
offset = _RoundUpToMultiple(offset, 4);
|
|
|
|
/* Pad to block size */
|
|
offset = _RoundUpToMultiple(offset, CPIO_BLOCK_SIZE);
|
|
|
|
/* Sanity check the resulting size */
|
|
if (offset != *cpioSizeOut)
|
|
goto done;
|
|
}
|
|
|
|
rc = 0;
|
|
|
|
done:
|
|
|
|
if (rc != 0)
|
|
{
|
|
if (cpioDataOut && *cpioDataOut)
|
|
{
|
|
Free(*cpioDataOut);
|
|
*cpioDataOut = NULL;
|
|
*cpioSizeOut = 0;
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
int CPIORemoveFile(
|
|
const void* cpioDataIn,
|
|
UINTN cpioSizeIn,
|
|
const char* path,
|
|
void** cpioDataOut,
|
|
UINTN* cpioSizeOut)
|
|
{
|
|
int rc = -1;
|
|
const CPIOHeader* header = NULL;
|
|
int offset = 0;
|
|
|
|
/* Check parameters */
|
|
if (!cpioDataIn || !cpioSizeIn || !path || !cpioDataOut || !cpioSizeOut)
|
|
goto done;
|
|
|
|
/* Initialize output parameters */
|
|
*cpioDataOut = NULL;
|
|
*cpioSizeOut = 0;
|
|
|
|
/* Find the CPIO header for this path */
|
|
if (_FindHeader(cpioDataIn, cpioSizeIn, path, &header) != 0)
|
|
goto done;
|
|
|
|
*cpioSizeOut = 0;
|
|
|
|
/* Allocate the memory for the new CPIO archive */
|
|
if (!(*cpioDataOut = Calloc(1, cpioSizeIn)))
|
|
goto done;
|
|
|
|
/* Copy over each header (skipping the one that matches 'path') */
|
|
{
|
|
header = (const CPIOHeader*)cpioDataIn;
|
|
const void* cpioEnd = (unsigned char*)cpioDataIn + cpioSizeIn;
|
|
int found = 0;
|
|
|
|
while (header)
|
|
{
|
|
if (CPIOCheckEntry(header, cpioEnd) != 0)
|
|
goto done;
|
|
|
|
if (strcmp(_GetName(header), path) == 0)
|
|
{
|
|
/* Skip this one */
|
|
found = 1;
|
|
}
|
|
else
|
|
{
|
|
int size = CPIOGetEntrySize(header);
|
|
Memcpy((unsigned char*)*cpioDataOut + offset, header, size);
|
|
offset += size;
|
|
}
|
|
|
|
if (CPIONextHeader(&header, cpioEnd) != 0)
|
|
goto done;
|
|
}
|
|
|
|
if (!found)
|
|
goto done;
|
|
}
|
|
|
|
/* Calculate the size of the output CPIO buffer */
|
|
{
|
|
offset = _RoundUpToMultiple(offset, CPIO_BLOCK_SIZE);
|
|
*cpioSizeOut = offset;
|
|
}
|
|
|
|
rc = 0;
|
|
|
|
done:
|
|
|
|
if (rc != 0)
|
|
{
|
|
if (cpioDataOut && *cpioDataOut)
|
|
{
|
|
Free(*cpioDataOut);
|
|
*cpioDataOut = NULL;
|
|
*cpioSizeOut = 0;
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
int CPIOGetFile(
|
|
const void* cpioData,
|
|
UINTN cpioSize,
|
|
const char* src,
|
|
void** destData,
|
|
UINTN* destSize)
|
|
{
|
|
int rc = -1;
|
|
const CPIOHeader* header = NULL;
|
|
UINTN headerSize;
|
|
void* fileData = NULL;
|
|
UINTN fileSize;
|
|
|
|
/* Check parameters */
|
|
if (!cpioData || !cpioSize || !src || !destData || !destSize)
|
|
goto done;
|
|
|
|
/* Initialize output parameters */
|
|
*destData = NULL;
|
|
*destSize = 0;
|
|
|
|
/* Find the CPIO header for this path */
|
|
if (_FindHeader(cpioData, cpioSize, src, &header) != 0)
|
|
goto done;
|
|
|
|
/* Determine size of this file */
|
|
fileSize = _GetFileSize(header);
|
|
|
|
/* Allocate the memory for this file */
|
|
if (fileSize && !(fileData = Malloc(fileSize)))
|
|
goto done;
|
|
|
|
/* Compute the full full size of header (including path) */
|
|
headerSize = sizeof(CPIOHeader);
|
|
headerSize += _GetNameSize(header);
|
|
headerSize = _RoundUpToMultiple(headerSize, 4);
|
|
|
|
/* Copy the file to output buffer */
|
|
Memcpy(fileData, (unsigned char*)header + headerSize, fileSize);
|
|
|
|
/* Set output parameters */
|
|
*destData = fileData;
|
|
*destSize = fileSize;
|
|
|
|
rc = 0;
|
|
|
|
done:
|
|
|
|
if (rc != 0 && fileData)
|
|
Free(fileData);
|
|
|
|
return rc;
|
|
}
|
|
|
|
int CPIODumpFile(
|
|
const void* cpioData,
|
|
UINTN cpioSize)
|
|
{
|
|
int rc = -1;
|
|
|
|
/* Check parameters */
|
|
if (!cpioData)
|
|
goto done;
|
|
|
|
/* Is data too small to contain at least one header? */
|
|
if (cpioSize < sizeof(CPIOHeader))
|
|
goto done;
|
|
|
|
/* Dump the file */
|
|
{
|
|
const CPIOHeader* header = (const CPIOHeader*)cpioData;
|
|
const void* cpioEnd = (char*)cpioData + cpioSize;
|
|
|
|
while (header)
|
|
{
|
|
if (CPIOCheckEntry(header, cpioEnd) != 0)
|
|
goto done;
|
|
|
|
_DumpHeader(header);
|
|
PRINTF("name{%a}\n", _GetName(header));
|
|
|
|
if (CPIONextHeader(&header, cpioEnd) != 0)
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
rc = 0;
|
|
|
|
done:
|
|
|
|
return rc;
|
|
}
|
|
|
|
int CPIOCheckFile(
|
|
const void* cpioData,
|
|
UINTN cpioSize,
|
|
const char* path)
|
|
{
|
|
int rc = -1;
|
|
|
|
/* Check parameters */
|
|
if (!cpioData || !path)
|
|
goto done;
|
|
|
|
/* Is data too small to contain at least one header? */
|
|
if (cpioSize < sizeof(CPIOHeader))
|
|
goto done;
|
|
|
|
/* Check the file */
|
|
{
|
|
const CPIOHeader* header = (const CPIOHeader*)cpioData;
|
|
const void* cpioEnd = (char*)cpioData + cpioSize;
|
|
|
|
while (header)
|
|
{
|
|
if (CPIOCheckEntry(header, cpioEnd) != 0)
|
|
goto done;
|
|
|
|
if (strcmp(_GetName(header), path) == 0)
|
|
goto done;
|
|
|
|
if (CPIONextHeader(&header, cpioEnd) != 0)
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
rc = 0;
|
|
|
|
done:
|
|
|
|
return rc;
|
|
}
|
|
|
|
int CPIOSplitFile(
|
|
const void* cpioData,
|
|
UINTN cpioSize,
|
|
const void* subfilesData[CPIO_MAX_SUBFILES],
|
|
UINTN subfilesSize[CPIO_MAX_SUBFILES],
|
|
UINTN* numSubfiles)
|
|
{
|
|
int rc = -1;
|
|
|
|
/* Reject bad parameters */
|
|
if (!cpioData || !cpioSize || !subfilesData || !subfilesSize ||
|
|
!numSubfiles)
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
/* Set the number of subfiles */
|
|
*numSubfiles = 0;
|
|
|
|
/* Find the next subfile */
|
|
while (cpioSize)
|
|
{
|
|
const void* cpioEnd = (const unsigned char*)cpioData + cpioSize;
|
|
const unsigned char* subfileData = (unsigned char*)cpioData;
|
|
UINTN subfileSize = 0;
|
|
BOOLEAN isCPIO = TRUE;
|
|
|
|
/* Check for overflow */
|
|
if (*numSubfiles >= CPIO_MAX_SUBFILES)
|
|
goto done;
|
|
|
|
/* Determine size of this subfile */
|
|
if (cpioSize >= sizeof(CPIOHeader))
|
|
{
|
|
const CPIOHeader* header = (const CPIOHeader*)cpioData;
|
|
|
|
while (header)
|
|
{
|
|
if (!CPIOMatchMagicNumber(header->magic))
|
|
{
|
|
subfileSize = cpioSize;
|
|
isCPIO = FALSE;
|
|
break;
|
|
}
|
|
|
|
if (CPIOCheckEntry(header, cpioEnd) != 0)
|
|
goto done;
|
|
|
|
subfileSize += CPIOGetEntrySize(header);
|
|
|
|
if (CPIONextHeader(&header, cpioEnd) != 0)
|
|
goto done;
|
|
}
|
|
|
|
if (isCPIO)
|
|
{
|
|
/* Pad to 4-byte boundary */
|
|
subfileSize = _RoundUpToMultiple(subfileSize, 4);
|
|
|
|
/* Pad to block size */
|
|
subfileSize = _RoundUpToMultiple(subfileSize, CPIO_BLOCK_SIZE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
subfileSize = cpioSize;
|
|
}
|
|
|
|
/* Set cpioData:cpioSize to refer to next subfile */
|
|
cpioData = subfileData + subfileSize;
|
|
cpioSize -= subfileSize;
|
|
|
|
/* Insert next subfile into caller's array */
|
|
subfilesData[*numSubfiles] = subfileData;
|
|
subfilesSize[*numSubfiles] = subfileSize;
|
|
(*numSubfiles)++;
|
|
}
|
|
|
|
rc = 0;
|
|
|
|
done:
|
|
|
|
return rc;
|
|
}
|
|
|
|
BOOLEAN CPIOIsFile(
|
|
const void* cpioData,
|
|
UINTN cpioSize,
|
|
const char* path)
|
|
{
|
|
const CPIOHeader* header = NULL;
|
|
|
|
/* Check parameters */
|
|
if (!cpioData || !cpioSize || !path)
|
|
return FALSE;
|
|
|
|
/* Find the CPIO header for this path */
|
|
if (_FindHeader(cpioData, cpioSize, path, &header) != 0)
|
|
return FALSE;
|
|
|
|
if (!(_GetFileMode(header) & CPIO_MODE_IFREG))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN CPIOIsDir(
|
|
const void* cpioData,
|
|
UINTN cpioSize,
|
|
const char* path)
|
|
{
|
|
const CPIOHeader* header = NULL;
|
|
|
|
/* Check parameters */
|
|
if (!cpioData || !cpioSize || !path)
|
|
return FALSE;
|
|
|
|
/* Find the CPIO header for this path */
|
|
if (_FindHeader(cpioData, cpioSize, path, &header) != 0)
|
|
return FALSE;
|
|
|
|
if (!(_GetFileMode(header) & CPIO_MODE_IFDIR))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
int CPIOFindFilesByBaseName(
|
|
const void* cpioData,
|
|
UINTN cpioSize,
|
|
const char* baseName,
|
|
StrArr* arr)
|
|
{
|
|
int rc = -1;
|
|
|
|
/* Clear the output array */
|
|
if (arr)
|
|
StrArrRelease(arr);
|
|
|
|
/* Check parameters */
|
|
if (!cpioData || !baseName || !arr)
|
|
goto done;
|
|
|
|
/* Is data too small to contain at least one header? */
|
|
if (cpioSize < sizeof(CPIOHeader))
|
|
goto done;
|
|
|
|
/* Dump the file */
|
|
{
|
|
const CPIOHeader* header = (const CPIOHeader*)cpioData;
|
|
const void* cpioEnd = (char*)cpioData + cpioSize;
|
|
|
|
while (header)
|
|
{
|
|
const char* bn;
|
|
const char* path;
|
|
|
|
if (CPIOCheckEntry(header, cpioEnd) != 0)
|
|
goto done;
|
|
|
|
if (!(path = _GetName(header)))
|
|
goto done;
|
|
|
|
if ((bn = Strrchr(path, '/')))
|
|
bn++;
|
|
else
|
|
bn = path;
|
|
|
|
if (Strcmp(baseName, bn) == 0)
|
|
{
|
|
if (StrArrAppend(arr, path) != 0)
|
|
goto done;
|
|
}
|
|
|
|
if (CPIONextHeader(&header, cpioEnd) != 0)
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
rc = 0;
|
|
|
|
done:
|
|
|
|
return rc;
|
|
}
|
|
|