linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
From: Milton Miller <miltonm@bga.com>
To: linuxppc-dev@ozlabs.org
Cc: Paul Mackerras <paulus@samba.org>,
	David Gibson <david@gibson.dropbear.id.au>
Subject: [PATCH 10/15] bootwrapper: add cpio file extraction library.
Date: Tue, 10 Jul 2007 17:11:42 -0500 (CDT)	[thread overview]
Message-ID: <boot-6-10.miltonm@bga.com> (raw)
In-Reply-To: <boot-6-00.miltonm@bga.com>

Add a library to search through a cpio or initramfs to a specified
path contained in a cpio.

Signed-off-by: Milton Miller <miltonm@bga.com>
--- 
Status: tested and working.  

This file is designed to also be usable in a stand alone user space
application.

Index: work.git/arch/powerpc/boot/cpio.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ work.git/arch/powerpc/boot/cpio.c	2007-07-10 04:03:40.000000000 -0500
@@ -0,0 +1,306 @@
+/*
+ * 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 2 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, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Copyright 2007 IBM Corporation.
+ *
+ * Authors: Milton Miller <miltonm@bga.com>
+ *
+ */
+
+#include "cpio.h"
+#include "string.h"
+
+struct cpio_header {
+	char ino[8];
+	char mode[8];
+	char uid[8];
+	char gid[8];
+	char nlink[8];
+	char mtime[8];
+	char filesize[8];
+	char maj[8];
+	char min[8];
+	char rmaj[8];
+	char rmin[8];
+	char namesize[8];
+	char chksum[8];
+} cpio_header_buf;
+
+static int check_magic(char magic[6])
+{
+	return !memcmp(magic,"070701",6) || !memcmp(magic,"070702",6);
+}
+
+static int read_magic(struct gunzip_state *stream)
+{
+	int len;
+	char magic[6];
+
+	len = gunzip_partial(stream, magic, sizeof(magic));
+	if (len == 0)
+		return 0;
+
+	if (len == sizeof(magic) && check_magic(magic))
+		return len;
+
+
+	/* Not the right magic or short read.  We might have stumbled
+	 * onto a compressed archive immediately following an
+	 * uncompressed one, or just some NUL bytes at the end of the
+	 * archive.  Inform the higher layers by the negative length.
+	 */
+	return -len;
+}
+
+static int get_cpio_header(struct gunzip_state *stream)
+{
+	int len;
+
+	len = read_magic(stream);
+	if (len <= 0)
+		return len;
+
+	gunzip_exactly(stream, &cpio_header_buf, sizeof(cpio_header_buf));
+	len += sizeof(cpio_header_buf);
+
+	return len;
+}
+
+static unsigned int cpio_str_to_num(char hexascii[8])
+{
+	unsigned int num = 0;
+	char c;
+	int d;
+
+	for (d=0; d < 8; d++) {
+		c = hexascii[d];
+		num <<= 4;
+		if (c >= '0' && c <= '9') {
+			num += c - '0';
+		} else if (c >= 'A' && c <= 'F') {
+			num += c - 'A' + 10;
+		} else if (c >= 'a' && c <= 'f') {
+			num += c - 'a' + 10;
+		} else {
+			cpio_error("bad cpio archive header: "
+					"invalid a hex digit");
+		}
+	}
+
+	return num;
+}
+
+static char name_buf[MAX_PATH+1];
+static const char cpio_end[] = "TRAILER!!!";
+#define CPIO_END_LEN sizeof(cpio_end)
+
+/* check_next_file
+ * Look for @path in @stream.  Set @consumed to the number of bytes
+ * succesfully read and processed.  return 1 on match, 0 for discarding
+ * an unmatched file, -1 on end of archive (either detected trailer or
+ * EOF on stream), or -(1 + bytes read) for a short read or bad magic
+ * number.  (For the short or bad read, the consumed is not changed).
+ */
+static int check_next_file(char *path, int pathlen,
+		struct gunzip_state *stream, int *consumed)
+{
+	int len, total, match;
+
+	if (pathlen > MAX_PATH) {
+		cpio_error("path too long to search\n");
+	}
+	total = get_cpio_header(stream);
+	if (total <= 0)
+		return total - 1;
+
+	len = cpio_str_to_num(cpio_header_buf.namesize);
+
+	if (len == pathlen || len == CPIO_END_LEN) {
+		gunzip_exactly(stream, name_buf, len);
+		total += len;
+		match = !strcmp(name_buf, path);
+		if (!match && !cpio_str_to_num(cpio_header_buf.filesize))
+			match = -!strcmp(name_buf, cpio_end);
+	} else {
+		gunzip_discard(stream, len);
+		total += len;
+		name_buf[0] = '\0';
+		match = 0;
+	}
+
+	len = total % 4;
+	if (len) {
+		gunzip_discard(stream, 4 - len);
+		total += 4 - len;
+	}
+
+	if (!match) {
+		len = cpio_str_to_num(cpio_header_buf.filesize);
+		gunzip_discard(stream, len);
+		total += len;
+
+		len = total % 4;
+		if (len) {
+			gunzip_discard(stream, 4 - len);
+			total += 4 - len;
+		}
+	}
+
+	*consumed += total;
+	return match;
+}
+
+static char *this_buf;
+static int this_archive;
+
+/* find_in_cpio.
+ * find a pathname @path in a single cpio archive described by @stream.
+ * Return is the same as check_next_file.
+ */
+int find_in_cpio(char *path, struct gunzip_state *stream)
+{
+	int found;
+	int pathlen = strlen(path) + 1;
+
+	this_archive = 0;
+	do {
+		found = check_next_file(path, pathlen, stream, &this_archive);
+	} while (found == 0);
+
+	return found;
+}
+
+/* find_in_initramfs
+ * Search a initramfs buffer for a given path name.  Returns 0 on
+ * not found, or 1 with @state ready to read the file.
+ *
+ * Note: this returns the first match, not the last.   The kernel
+ * decompressor  effectivly uses the last match.  This code also
+ * doesn't worry about the directories in the path existing.
+ */
+int find_in_initramfs(char *path, char *buf, int len,
+		struct gunzip_state *stream)
+{
+	int found, total = 0;
+	int pathlen = strlen(path) + 1;
+	int *ibuf;
+
+	do {
+		/* get to word boundary, but stop if not NUL */
+		for (; total % 4 && total < len - 4; total++)
+			if (buf[total])
+				break;
+
+		if ((total % 4) == 0) {
+			/* fast forward over NUL words.  */
+			for (ibuf = (int *)&buf[total];
+					total < len - sizeof(*ibuf) && !*ibuf;
+					ibuf++)
+			total += sizeof(*ibuf);
+		}
+
+		/* check remainder of a short archive -- it must all be
+		 * zero as both gzip header and cpio header are bigger
+		 * than this.
+		 */
+		if (total >= len - 4) {
+			for (;total < len; total++) {
+				if (buf[len]) {
+					cpio_error("Junk at end of buffer");
+				}
+			}
+			break;
+		}  else if (total % 4) {
+			/*
+			 * If we are unalinged and not at the end of the buffer
+			 * we must be following a compressed archive.  Only
+			 * NUL and gzip headers are allowed.  We skipped NUL.
+			 */
+			if (!(buf[total] == 0x1b && buf[total + 1] == 0x8b))
+				cpio_error("unalinged junk in buffer");
+		}
+
+		this_buf = buf + total;
+		this_archive = 0;
+
+		gunzip_start(stream, this_buf, len - total);
+
+		do {
+			found = check_next_file(path, pathlen, stream,
+					&this_archive);
+		} while (!found);
+
+		if (found > 0)
+			return found;
+
+		if (stream->s.workspace) {
+			int discard;
+
+			if (found < -1) {
+				cpio_error("Junk in compressed archive");
+			}
+
+			/* we either found EOF or TRAILER!!!.  In the later
+			 * case we need to discard to the end of the gzip
+			 * contents.
+			 */
+			do {
+				discard =  gunzip_partial(stream, name_buf,
+					MAX_PATH);
+				this_archive += discard;
+			} while (discard);
+
+			/*
+			 * Peek at how many input bytes were consumed.
+			 * reset our consumed input.
+			 */
+			total += stream->s.total_in + 8;
+
+			/* clean up zlib */
+			discard = gunzip_finish(stream, name_buf, 0);
+		} else {
+			if (this_archive % 4) {
+				cpio_error("Archive not multiple of 4?");
+			}
+			total += this_archive;
+
+			if (!this_archive) {
+				cpio_error("junk between archives");
+			}
+			/* don't check the < -1 of found, it might be an
+			 * archive.  This will be caught by the !this_archive
+			 * check on the next loop.
+			 */
+		}
+	} while (total < len);
+
+	return 0;
+}
+
+void get_cpio_info(void **archive_start, int *consumed)
+{
+	*archive_start = this_buf;
+	*consumed = this_archive;
+}
+
+int get_cpio_file_mode(void)
+{
+	return cpio_str_to_num(cpio_header_buf.mode);
+}
+
+int get_cpio_file_size(void)
+{
+	return cpio_str_to_num(cpio_header_buf.filesize);
+}
Index: work.git/arch/powerpc/boot/cpio.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ work.git/arch/powerpc/boot/cpio.h	2007-07-10 04:03:40.000000000 -0500
@@ -0,0 +1,12 @@
+#include "gunzip_util.h"
+
+extern int find_in_cpio(char *path, struct gunzip_state *stream);
+extern int find_in_initramfs(char *path, char *buf, int len,
+		struct gunzip_state *state);
+extern void get_cpio_info(void **archive_start, int *consumed);
+extern int get_cpio_file_size(void);
+extern int get_cpio_file_mode(void);
+
+#define MAX_PATH 256
+
+extern void cpio_error(char *msg);
Index: work.git/arch/powerpc/boot/Makefile
===================================================================
--- work.git.orig/arch/powerpc/boot/Makefile	2007-07-10 04:02:24.000000000 -0500
+++ work.git/arch/powerpc/boot/Makefile	2007-07-10 04:03:57.000000000 -0500
@@ -36,13 +36,13 @@ $(obj)/ebony.o: BOOTCFLAGS += -mcpu=440
 
 zlib       := inffast.c inflate.c inftrees.c
 zlibheader := inffast.h inffixed.h inflate.h inftrees.h infutil.h
-zliblinuxheader := zlib.h zconf.h zutil.h
+zliblinuxheader := zlib.h zconf.h zutil.h stat.h
 
 $(addprefix $(obj)/,$(zlib) gunzip_util.o main.o): \
 	$(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader))
 
 src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \
-		flatdevtree_conv.c marshal.c memranges.c kexec.c \
+		flatdevtree_conv.c marshal.c memranges.c kexec.c cpio.c \
 		ns16550.c serial.c simple_alloc.c div64.S util.S rtas.c \
 		gunzip_util.c elf_util.c $(zlib) devtree.c oflib.c ofconsole.c \
 		44x.c ebony.c mv64x60.c mpsc.c mv64x60_i2c.c cuboot.c

  parent reply	other threads:[~2007-07-10 22:11 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-07-10 22:07 [PATCH 0/15] bootwrapper: support for kexec to zImage Milton Miller
2007-07-10 22:07 ` [PATCH 1/15] boot: find initrd location from device-tree Milton Miller
2007-07-19  2:10   ` David Gibson
2007-07-10 22:08 ` [PATCH 2/15] boot: record header bytes in gunzip_start Milton Miller
2007-07-19  2:11   ` David Gibson
2007-07-19  4:46     ` Milton Miller
2007-07-10 22:08 ` [PATCH 3/15] boot: simplfy gunzip_finish Milton Miller
2007-07-19  2:39   ` David Gibson
2007-07-19  4:01     ` Milton Miller
2007-07-19  4:31       ` David Gibson
2007-07-10 22:08 ` [PATCH 4/15] bootwrapper: smp support code Milton Miller
2007-07-10 22:09 ` [PATCH 5/15] bootwrapper: occupied memory ranges Milton Miller
2007-07-10 22:09 ` [PATCH 6/15] bootwrapper: switch 64 bit cpus to 32 bit mode Milton Miller
2007-07-10 22:57   ` Segher Boessenkool
2007-07-10 22:10 ` [PATCH 7/15] bootwrapper: Add kexec callable zImage wrapper Milton Miller
2007-07-10 23:16   ` Segher Boessenkool
2007-07-10 22:10 ` [PATCH 8/15] bootwrapper: convert flatdevtree to version 16 Milton Miller
2007-07-10 22:11 ` [PATCH 9/15] bootwrapper: rtas support Milton Miller
2007-07-10 22:11 ` Milton Miller [this message]
2007-07-10 22:12 ` [PATCH 11/15] bootwrapper: allow vmlinuz to be an external payload Milton Miller
2007-07-10 23:11   ` Segher Boessenkool
2007-07-10 22:12 ` [PATCH 12/15] bootwrapper: extract the vmlinux from initramfs Milton Miller
2007-07-10 22:12 ` [PATCH 13/15] bootwrapper: attach an empty vmlinux Milton Miller
2007-07-10 22:12 ` [PATCH 14/15] boot: add a hook to start cpus Milton Miller
2007-07-10 22:12 ` [PATCH/EXAMPLE 15/15] bootwrapper: example sreset marshalling Milton Miller
  -- strict thread matches above, loose matches on Subject: below --
2007-09-21 23:02 [PATCH 0/15] bootwrapper: kexec and external payloads Milton Miller
2007-09-21 23:05 ` [PATCH 10/15] bootwrapper: add cpio file extraction library Milton Miller

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=boot-6-10.miltonm@bga.com \
    --to=miltonm@bga.com \
    --cc=david@gibson.dropbear.id.au \
    --cc=linuxppc-dev@ozlabs.org \
    --cc=paulus@samba.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).