1# SPDX-License-Identifier: GPL-2.0+
2# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
5# Entry-type module for blobs, which are binary objects read from files
6#
7
8from binman.entry import Entry
9from binman import state
10from dtoc import fdt_util
11from u_boot_pylib import tools
12from u_boot_pylib import tout
13
14class Entry_blob(Entry):
15    """Arbitrary binary blob
16
17    Note: This should not be used by itself. It is normally used as a parent
18    class by other entry types.
19
20    Properties / Entry arguments:
21        - filename: Filename of file to read into entry
22        - compress: Compression algorithm to use:
23            none: No compression
24            lz4: Use lz4 compression (via 'lz4' command-line utility)
25
26    This entry reads data from a file and places it in the entry. The
27    default filename is often specified specified by the subclass. See for
28    example the 'u-boot' entry which provides the filename 'u-boot.bin'.
29
30    If compression is enabled, an extra 'uncomp-size' property is written to
31    the node (if enabled with -u) which provides the uncompressed size of the
32    data.
33    """
34    def __init__(self, section, etype, node, auto_write_symbols=False):
35        super().__init__(section, etype, node,
36                         auto_write_symbols=auto_write_symbols)
37        self._filename = fdt_util.GetString(self._node, 'filename', self.etype)
38        self.elf_fname = fdt_util.GetString(self._node, 'elf-filename',
39                                            self.elf_fname)
40        self.elf_base_sym = fdt_util.GetString(self._node, 'elf-base-sym')
41        if not self.auto_write_symbols:
42            if fdt_util.GetBool(self._node, 'write-symbols'):
43                self.auto_write_symbols = True
44
45    def ObtainContents(self, fake_size: int = 0) -> bool:
46        self._filename = self.GetDefaultFilename()
47        self._pathname = tools.get_input_filename(self._filename,
48            self.external and (self.optional or self.section.GetAllowMissing()))
49        # Allow the file to be missing
50        if not self._pathname:
51            if not fake_size and self.assume_size:
52                fake_size = self.assume_size
53            self._pathname = self.check_fake_fname(self._filename, fake_size)
54            self.missing = True
55            if self.optional:
56                self.mark_absent("missing but optional")
57            if not self.faked:
58                content_size = 0
59                if self.assume_size: # Ensure we get test coverage on next line
60                    content_size = self.assume_size
61                self.SetContents(tools.get_bytes(0, content_size))
62                return True
63
64        self.ReadBlobContents()
65        return True
66
67    def ReadFileContents(self, pathname):
68        """Read blob contents into memory
69
70        This function compresses the data before returning if needed.
71
72        We assume the data is small enough to fit into memory. If this
73        is used for large filesystem image that might not be true.
74        In that case, Image.BuildImage() could be adjusted to use a
75        new Entry method which can read in chunks. Then we could copy
76        the data in chunks and avoid reading it all at once. For now
77        this seems like an unnecessary complication.
78
79        Args:
80            pathname (str): Pathname to read from
81
82        Returns:
83            bytes: Data read
84        """
85        state.TimingStart('read')
86        indata = tools.read_file(pathname)
87        state.TimingAccum('read')
88        state.TimingStart('compress')
89        data = self.CompressData(indata)
90        state.TimingAccum('compress')
91        return data
92
93    def ReadBlobContents(self):
94        data = self.ReadFileContents(self._pathname)
95        self.SetContents(data)
96        return True
97
98    def GetDefaultFilename(self):
99        return self._filename
100
101    def ProcessContents(self):
102        # The blob may have changed due to WriteSymbols()
103        return self.ProcessContentsUpdate(self.data)
104
105    def CheckFakedBlobs(self, faked_blobs_list):
106        """Check if any entries in this section have faked external blobs
107
108        If there are faked blobs, the entries are added to the list
109
110        Args:
111            faked_blobs_list: List of Entry objects to be added to
112        """
113        if self.faked:
114            faked_blobs_list.append(self)
115