//
// aegis - project change supervisor
// Copyright (C) 1999, 2003-2008 Peter Miller
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see
// .
//
#include
#include // for assert
#include
#include
#include
#include
#include
input_cpio::~input_cpio()
{
}
input_cpio::input_cpio(input &arg) :
deeper(arg)
{
}
long
input_cpio::read_inner(void *, size_t)
{
assert(0);
return -1;
}
long
input_cpio::ftell_inner()
{
assert(0);
return 0;
}
nstring
input_cpio::name()
{
return deeper->name();
}
long
input_cpio::length()
{
return deeper->length();
}
input
input_cpio::child(nstring &archive_name)
{
//
// Return a closed input at end-of-file
//
trace(("input_cpio::child(this = %08lX)\n{\n", (long)this));
if (deeper->peek() < 0)
{
trace(("return NULL\n"));
trace(("}\n"));
return 0;
}
//
// read the file header
//
for (const char *magic = "070701"; *magic; ++magic)
{
int c = deeper->getch();
if (c != *magic)
deeper->fatal_error("cpio: wrong magic number");
}
hex8(); // inode
hex8(); // mode
hex8(); // uid
hex8(); // gid
hex8(); // nlinks
hex8(); // mtime
long hlength = hex8();
trace_long(hlength);
hex8(); // dev_major
hex8(); // dev_minor
hex8(); // rdev_major
hex8(); // rdev_minor
long namlen = hex8();
trace(("namlen = %ld\n", namlen));
hex8(); // no checksum
trace(("archive_name = \"%s\"\n", archive_name.c_str()));
archive_name = get_name(namlen);
padding();
//
// The trailer record tells us when to stop.
//
if (archive_name == "TRAILER!!!")
{
trace(("NULL\n"));
trace(("}\n"));
return 0;
}
//
// Figure out how much of the deeper input is to be cropped out for
// this child.
//
long alength = (hlength + 3) & ~3;
trace_long(alength);
input_crop *icp = 0;
if (alength == hlength)
{
icp = new input_crop(deeper, hlength);
}
else
{
input temp(new input_crop(deeper, alength));
icp = new input_crop(temp, hlength);
}
//
// Set the name of the child, so we get nice error messages.
//
nstring filename =
nstring::format("%s(%s)", deeper->name().c_str(), archive_name.c_str());
icp->set_name(filename);
//
// Report success.
//
trace(("return %08lX\n", (long)icp));
trace(("}\n"));
return icp;
}
void
input_cpio::padding()
{
int n = deeper->ftell();
n %= 4;
if (n)
deeper->skip(4 - n);
}
int
input_cpio::hex_digit(bool &first)
{
int c = deeper->getch();
switch (c)
{
default:
fatal_error("cpio: invalid hex digit");
// NOTREACHED
case ' ':
if (first)
return 0;
fatal_error("cpio: invalid hex number");
// NOTREACHED
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
first = false;
return (c - '0');
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
first = false;
return (c - 'a' + 10);
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
first = first;
return (c - 'A' + 10);
}
}
long
input_cpio::hex8()
{
long result = 0;
bool first = true;
for (int j = 0; j < 8; ++j)
{
int c = hex_digit(first);
result = (result << 4) + c;
}
if (first)
deeper->fatal_error("cpio: invalid hex number");
return result;
}
nstring
input_cpio::get_name(long namlen)
{
trace(("input_cpio::get_name(namelen = %ld)\n", namlen));
static nstring_accumulator name_buffer;
//
// make sure out name_buffer is big enough.
//
if (namlen < 2)
deeper->fatal_error("cpio: invalid name length");
--namlen;
//
// Read the filename, checking each character.
//
name_buffer.clear();
for (long j = 0; j < namlen; ++j)
{
int c = deeper->getch();
if (c <= 0)
deeper->fatal_error("cpio: short file");
if (isspace((unsigned char)c))
deeper->fatal_error("cpio: invalid name (white space)");
if (!isprint((unsigned char)c))
deeper->fatal_error("cpio: invalid name (unprintable)");
name_buffer.push_back(c);
}
//
// Must have a NUL on the end.
//
if (deeper->getch() != 0)
deeper->fatal_error("cpio: invalid character");
//
// Build the result and return.
//
trace(("name_buffer = \"%.*s\"\n", (int)name_buffer.size(),
name_buffer.get_data()));
return name_buffer.mkstr();
}
bool
input_cpio::is_remote()
const
{
return deeper->is_remote();
}