binman: Allow reading an entry from an image
authorSimon Glass <sjg@chromium.org>
Mon, 8 Jul 2019 20:25:50 +0000 (14:25 -0600)
committerSimon Glass <sjg@chromium.org>
Wed, 24 Jul 2019 19:54:08 +0000 (12:54 -0700)
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 <sjg@chromium.org>
tools/binman/control.py
tools/binman/entry.py
tools/binman/etype/blob.py
tools/binman/ftest.py
tools/binman/image.py

index 813c8b1bf9edd0a07eeb42097b186865936d1736..b244e7a0cd08d0241b747be3d808df4afa2c9555 100644 (file)
@@ -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
 
index 33d3f1e4d42949fb59c8c0e2b9163ee236ac2f36..1c382f3b852e775cce53e79c09523522929135ce 100644 (file)
@@ -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]
index a4ff0efcebc7b140f1ae3ab1377453dbe880bbf2..00cad33718cac69d3dd775f96001004211316b9b 100644 (file)
@@ -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
index ad828041f3060d60f1ea9cd57ac8203cba1b31dc..c11dd1b85abbc42de629b5664c71728873a68f51 100644 (file)
@@ -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()
index bbb5e23c3b237b0b45b8976d18cb7e9b0ee7d16f..fb6e591ca60d34bb169068dc843b9f9deb3d7419 100644 (file)
@@ -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"""