From patchwork Mon Jul 8 20:25:50 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1129323 X-Patchwork-Delegate: sjg@chromium.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.denx.de (client-ip=81.169.180.215; helo=lists.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=chromium.org Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="bRicApCz"; dkim-atps=neutral Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 45jHKJ2DqLz9sP7 for ; Tue, 9 Jul 2019 06:36:02 +1000 (AEST) Received: by lists.denx.de (Postfix, from userid 105) id 4BD87C21D65; Mon, 8 Jul 2019 20:32:55 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=RCVD_IN_MSPIKE_H2, T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id 11AF2C21E3B; Mon, 8 Jul 2019 20:28:26 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 19C33C21E50; Mon, 8 Jul 2019 20:28:02 +0000 (UTC) Received: from mail-io1-f68.google.com (mail-io1-f68.google.com [209.85.166.68]) by lists.denx.de (Postfix) with ESMTPS id C99E3C21E08 for ; Mon, 8 Jul 2019 20:27:58 +0000 (UTC) Received: by mail-io1-f68.google.com with SMTP id k8so38350774iot.1 for ; Mon, 08 Jul 2019 13:27:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=yM+FwSoohNNJkS0mnA4O5TITLNrQZeEA3Nu84i/dWFs=; b=bRicApCzwDflO1q/JweKYlgzdvzcM8auJH5qwabl5asfxRK9G3+m5NLSCKZczXyFhz QnKeo28E2BJNpvL/wtqQsoq6Y6loCXLogmgIMqtEjaxomDNCq0qSceiA8rHB2qmsPBus a48snxaX0tnSqmLxPgcMBj8lD2zsJLK9sMcds= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=yM+FwSoohNNJkS0mnA4O5TITLNrQZeEA3Nu84i/dWFs=; b=cbW21C7JWd1jx+zBTS3c+CNc2JRZbrdhFs1zBVOm7/1IXypeA+c3US1Az1k4j2yjMh lO0gg2OP1wcYZY+35DsgJnv/pnrOrKlXDlvzYZp2IXTYhHtKijIJO41z6nv4pUZbF7+E EtgcjKK1axZbfkPWSj7nUX3sNxfFHt5LBjvsWvvBgj8+Z4iPXp4J7mP7uQ9cYn9uM299 m54Ec0ol5gxJvjG3nKN5i62kkdc/BJ92QaDHVeyeNIZ3sH7UNSdlVVgDHzAxeQIt6SIM kQ671yI24hfhkWF1v1BFf6SCGHmR8iO4y8RLPQCNTBOZEUGU0p1Dwu0lebltKvnvTIfY Y4sA== X-Gm-Message-State: APjAAAUo2CpznY5SuddgAarSws7wn22s6s0bL/lLnqQMZz2GgT4Di8BO /6GyKNz0UqfgDH98/bKMAu3Of1GhNHs= X-Google-Smtp-Source: APXvYqxTVfK8GSI8OQM8Vz+GDIiKDCvFCQTCIWffZC278BbLlap7RL8io976iZZLbvxdasAH4Rrn/g== X-Received: by 2002:a02:b914:: with SMTP id v20mr23328342jan.83.1562617677634; Mon, 08 Jul 2019 13:27:57 -0700 (PDT) Received: from kiwi.bld.corp.google.com ([2620:15c:183:0:8223:87c:a681:66aa]) by smtp.gmail.com with ESMTPSA id v13sm16692359ioq.13.2019.07.08.13.27.56 (version=TLS1_3 cipher=AEAD-AES256-GCM-SHA384 bits=256/256); Mon, 08 Jul 2019 13:27:57 -0700 (PDT) From: Simon Glass To: U-Boot Mailing List Date: Mon, 8 Jul 2019 14:25:50 -0600 Message-Id: <20190708202553.225715-29-sjg@chromium.org> X-Mailer: git-send-email 2.22.0.410.gd8fdbe21b5-goog In-Reply-To: <20190708202553.225715-1-sjg@chromium.org> References: <20190708202553.225715-1-sjg@chromium.org> MIME-Version: 1.0 Cc: Tom Rini Subject: [U-Boot] [PATCH v2 28/31] binman: Allow reading an entry from an image X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" It is useful to be able to extract entry contents from an image to see what is inside. Add a simple function to read the contents of an entry, decompressing it by default. Signed-off-by: Simon Glass Signed-off-by: Simon Glass --- Changes in v2: None tools/binman/control.py | 20 ++++++++++++++++++ tools/binman/entry.py | 21 +++++++++++++++++++ tools/binman/etype/blob.py | 13 ++++++++++++ tools/binman/ftest.py | 42 ++++++++++++++++++++++++++++++++++++++ tools/binman/image.py | 4 +++- 5 files changed, 99 insertions(+), 1 deletion(-) diff --git a/tools/binman/control.py b/tools/binman/control.py index 813c8b1bf9e..b244e7a0cd0 100644 --- a/tools/binman/control.py +++ b/tools/binman/control.py @@ -98,6 +98,26 @@ def ListEntries(image_fname, entry_paths): out += txt print(out.rstrip()) + +def ReadEntry(image_fname, entry_path, decomp=True): + """Extract an entry from an image + + This extracts the data from a particular entry in an image + + Args: + image_fname: Image filename to process + entry_path: Path to entry to extract + decomp: True to return uncompressed data, if the data is compress + False to return the raw data + + Returns: + data extracted from the entry + """ + image = Image.FromFile(image_fname) + entry = image.FindEntryPath(entry_path) + return entry.ReadData(decomp) + + def Binman(args): """The main control code for binman diff --git a/tools/binman/entry.py b/tools/binman/entry.py index 33d3f1e4d42..1c382f3b852 100644 --- a/tools/binman/entry.py +++ b/tools/binman/entry.py @@ -659,3 +659,24 @@ features to produce new behaviours. """ self.AddEntryInfo(entries, indent, self.name, self.etype, self.size, self.image_pos, self.uncomp_size, self.offset, self) + + def ReadData(self, decomp=True): + """Read the data for an entry from the image + + This is used when the image has been read in and we want to extract the + data for a particular entry from that image. + + Args: + decomp: True to decompress any compressed data before returning it; + False to return the raw, uncompressed data + + Returns: + Entry data (bytes) + """ + # Use True here so that we get an uncompressed section to work from, + # although compressed sections are currently not supported + data = self.section.ReadData(True) + tout.Info('%s: Reading data from offset %#x-%#x, size %#x (avail %#x)' % + (self.GetPath(), self.offset, self.offset + self.size, + self.size, len(data))) + return data[self.offset:self.offset + self.size] diff --git a/tools/binman/etype/blob.py b/tools/binman/etype/blob.py index a4ff0efcebc..00cad33718c 100644 --- a/tools/binman/etype/blob.py +++ b/tools/binman/etype/blob.py @@ -9,6 +9,7 @@ from entry import Entry import fdt_util import state import tools +import tout class Entry_blob(Entry): """Entry containing an arbitrary binary blob @@ -66,3 +67,15 @@ class Entry_blob(Entry): def GetDefaultFilename(self): return self._filename + + def ReadData(self, decomp=True): + indata = Entry.ReadData(self, decomp) + if decomp: + data = tools.Decompress(indata, self.compress) + if self.uncomp_size: + tout.Info("%s: Decompressing data size %#x with algo '%s' to data size %#x" % + (self.GetPath(), len(indata), self.compress, + len(data))) + else: + data = indata + return data diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index ad828041f30..c11dd1b85ab 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -69,6 +69,8 @@ FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " + COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data' REFCODE_DATA = b'refcode' +EXTRACT_DTB_SIZE = 0x3c9 + class TestFunctional(unittest.TestCase): """Functional tests for binman @@ -2423,6 +2425,46 @@ class TestFunctional(unittest.TestCase): """Test listing the files in a sub-entry of a section""" self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb']) + def _RunExtractCmd(self, entry_name, decomp=True): + """Extract an entry from an image + + Args: + entry_name: Entry name to extract + decomp: True to decompress the data if compressed, False to leave + it in its raw uncompressed format + + Returns: + data from entry + """ + self._CheckLz4() + self._DoReadFileRealDtb('130_list_fdtmap.dts') + image_fname = tools.GetOutputFilename('image.bin') + return control.ReadEntry(image_fname, entry_name, decomp) + + def testExtractSimple(self): + """Test extracting a single file""" + data = self._RunExtractCmd('u-boot') + self.assertEqual(U_BOOT_DATA, data) + + def testExtractBadEntry(self): + """Test extracting a bad section path""" + with self.assertRaises(ValueError) as e: + self._RunExtractCmd('section/does-not-exist') + self.assertIn("Entry 'does-not-exist' not found in '/section'", + str(e.exception)) + + def testExtractMissingFile(self): + """Test extracting file that does not exist""" + with self.assertRaises(IOError) as e: + control.ReadEntry('missing-file', 'name') + + def testExtractBadFile(self): + """Test extracting an invalid file""" + fname = os.path.join(self._indir, 'badfile') + tools.WriteFile(fname, b'') + with self.assertRaises(ValueError) as e: + control.ReadEntry(fname, 'name') + if __name__ == "__main__": unittest.main() diff --git a/tools/binman/image.py b/tools/binman/image.py index bbb5e23c3b2..fb6e591ca60 100644 --- a/tools/binman/image.py +++ b/tools/binman/image.py @@ -82,7 +82,9 @@ class Image(section.Entry_section): dtb.Scan() # Return an Image with the associated nodes - return Image('image', dtb.GetRoot()) + image = Image('image', dtb.GetRoot()) + image._data = data + return image def Raise(self, msg): """Convenience function to raise an error referencing an image"""