Merge tag 'u-boot-imx-20191009' of https://gitlab.denx.de/u-boot/custodians/u-boot-imx
[oweals/u-boot.git] / tools / binman / control.py
index c3f358d45c40a2e5afaa0047aeb8bfbce86f2e0a..cb51bc2dd4663683d9df1915aab2cb263a09c808 100644 (file)
@@ -118,47 +118,6 @@ def ReadEntry(image_fname, entry_path, decomp=True):
     return entry.ReadData(decomp)
 
 
-def WriteEntry(image_fname, entry_path, data, decomp=True, allow_resize=True):
-    """Replace an entry in an image
-
-    This replaces the data in a particular entry in an image. This size of the
-    new data must match the size of the old data unless allow_resize is True.
-
-    Args:
-        image_fname: Image filename to process
-        entry_path: Path to entry to extract
-        data: Data to replace with
-        decomp: True to compress the data if needed, False if data is
-            already compressed so should be used as is
-        allow_resize: True to allow entries to change size (this does a re-pack
-            of the entries), False to raise an exception
-
-    Returns:
-        Image object that was updated
-    """
-    tout.Info("WriteEntry '%s', file '%s'" % (entry_path, image_fname))
-    image = Image.FromFile(image_fname)
-    entry = image.FindEntryPath(entry_path)
-    state.PrepareFromLoadedData(image)
-    image.LoadData()
-
-    # If repacking, drop the old offset/size values except for the original
-    # ones, so we are only left with the constraints.
-    if allow_resize:
-        image.ResetForPack()
-    tout.Info('Writing data to %s' % entry.GetPath())
-    if not entry.WriteData(data, decomp):
-        if not image.allow_repack:
-            entry.Raise('Entry data size does not match, but allow-repack is not present for this image')
-        if not allow_resize:
-            entry.Raise('Entry data size does not match, but resize is disabled')
-    tout.Info('Processing image')
-    ProcessImage(image, update_fdt=True, write_map=False, get_contents=False,
-                 allow_resize=allow_resize)
-    tout.Info('WriteEntry done')
-    return image
-
-
 def ExtractEntries(image_fname, output_fname, outdir, entry_paths,
                    decomp=True):
     """Extract the data from one or more entries and write it to files
@@ -169,7 +128,7 @@ def ExtractEntries(image_fname, output_fname, outdir, entry_paths,
             otherwise
         outdir: Output directory to use (for any number of files), else None
         entry_paths: List of entry paths to extract
-        decomp: True to compress the entry data
+        decomp: True to decompress the entry data
 
     Returns:
         List of EntryInfo records that were written
@@ -179,9 +138,9 @@ def ExtractEntries(image_fname, output_fname, outdir, entry_paths,
     # Output an entry to a single file, as a special case
     if output_fname:
         if not entry_paths:
-            raise ValueError('Must specify an entry path to write with -o')
+            raise ValueError('Must specify an entry path to write with -f')
         if len(entry_paths) != 1:
-            raise ValueError('Must specify exactly one entry path to write with -o')
+            raise ValueError('Must specify exactly one entry path to write with -f')
         entry = image.FindEntryPath(entry_paths[0])
         data = entry.ReadData(decomp)
         tools.WriteFile(output_fname, data)
@@ -210,6 +169,155 @@ def ExtractEntries(image_fname, output_fname, outdir, entry_paths,
     return einfos
 
 
+def BeforeReplace(image, allow_resize):
+    """Handle getting an image ready for replacing entries in it
+
+    Args:
+        image: Image to prepare
+    """
+    state.PrepareFromLoadedData(image)
+    image.LoadData()
+
+    # If repacking, drop the old offset/size values except for the original
+    # ones, so we are only left with the constraints.
+    if allow_resize:
+        image.ResetForPack()
+
+
+def ReplaceOneEntry(image, entry, data, do_compress, allow_resize):
+    """Handle replacing a single entry an an image
+
+    Args:
+        image: Image to update
+        entry: Entry to write
+        data: Data to replace with
+        do_compress: True to compress the data if needed, False if data is
+            already compressed so should be used as is
+        allow_resize: True to allow entries to change size (this does a re-pack
+            of the entries), False to raise an exception
+    """
+    if not entry.WriteData(data, do_compress):
+        if not image.allow_repack:
+            entry.Raise('Entry data size does not match, but allow-repack is not present for this image')
+        if not allow_resize:
+            entry.Raise('Entry data size does not match, but resize is disabled')
+
+
+def AfterReplace(image, allow_resize, write_map):
+    """Handle write out an image after replacing entries in it
+
+    Args:
+        image: Image to write
+        allow_resize: True to allow entries to change size (this does a re-pack
+            of the entries), False to raise an exception
+        write_map: True to write a map file
+    """
+    tout.Info('Processing image')
+    ProcessImage(image, update_fdt=True, write_map=write_map,
+                 get_contents=False, allow_resize=allow_resize)
+
+
+def WriteEntryToImage(image, entry, data, do_compress=True, allow_resize=True,
+                      write_map=False):
+    BeforeReplace(image, allow_resize)
+    tout.Info('Writing data to %s' % entry.GetPath())
+    ReplaceOneEntry(image, entry, data, do_compress, allow_resize)
+    AfterReplace(image, allow_resize=allow_resize, write_map=write_map)
+
+
+def WriteEntry(image_fname, entry_path, data, do_compress=True,
+               allow_resize=True, write_map=False):
+    """Replace an entry in an image
+
+    This replaces the data in a particular entry in an image. This size of the
+    new data must match the size of the old data unless allow_resize is True.
+
+    Args:
+        image_fname: Image filename to process
+        entry_path: Path to entry to extract
+        data: Data to replace with
+        do_compress: True to compress the data if needed, False if data is
+            already compressed so should be used as is
+        allow_resize: True to allow entries to change size (this does a re-pack
+            of the entries), False to raise an exception
+        write_map: True to write a map file
+
+    Returns:
+        Image object that was updated
+    """
+    tout.Info("Write entry '%s', file '%s'" % (entry_path, image_fname))
+    image = Image.FromFile(image_fname)
+    entry = image.FindEntryPath(entry_path)
+    WriteEntryToImage(image, entry, data, do_compress=do_compress,
+                      allow_resize=allow_resize, write_map=write_map)
+
+    return image
+
+
+def ReplaceEntries(image_fname, input_fname, indir, entry_paths,
+                   do_compress=True, allow_resize=True, write_map=False):
+    """Replace the data from one or more entries from input files
+
+    Args:
+        image_fname: Image filename to process
+        input_fname: Single input ilename to use if replacing one file, None
+            otherwise
+        indir: Input directory to use (for any number of files), else None
+        entry_paths: List of entry paths to extract
+        do_compress: True if the input data is uncompressed and may need to be
+            compressed if the entry requires it, False if the data is already
+            compressed.
+        write_map: True to write a map file
+
+    Returns:
+        List of EntryInfo records that were written
+    """
+    image = Image.FromFile(image_fname)
+
+    # Replace an entry from a single file, as a special case
+    if input_fname:
+        if not entry_paths:
+            raise ValueError('Must specify an entry path to read with -f')
+        if len(entry_paths) != 1:
+            raise ValueError('Must specify exactly one entry path to write with -f')
+        entry = image.FindEntryPath(entry_paths[0])
+        data = tools.ReadFile(input_fname)
+        tout.Notice("Read %#x bytes from file '%s'" % (len(data), input_fname))
+        WriteEntryToImage(image, entry, data, do_compress=do_compress,
+                          allow_resize=allow_resize, write_map=write_map)
+        return
+
+    # Otherwise we will input from a path given by the entry path of each entry.
+    # This means that files must appear in subdirectories if they are part of
+    # a sub-section.
+    einfos = image.GetListEntries(entry_paths)[0]
+    tout.Notice("Replacing %d matching entries in image '%s'" %
+                (len(einfos), image_fname))
+
+    BeforeReplace(image, allow_resize)
+
+    for einfo in einfos:
+        entry = einfo.entry
+        if entry.GetEntries():
+            tout.Info("Skipping section entry '%s'" % entry.GetPath())
+            continue
+
+        path = entry.GetPath()[1:]
+        fname = os.path.join(indir, path)
+
+        if os.path.exists(fname):
+            tout.Notice("Write entry '%s' from file '%s'" %
+                        (entry.GetPath(), fname))
+            data = tools.ReadFile(fname)
+            ReplaceOneEntry(image, entry, data, do_compress, allow_resize)
+        else:
+            tout.Warning("Skipping entry '%s' from missing file '%s'" %
+                         (entry.GetPath(), fname))
+
+    AfterReplace(image, allow_resize=allow_resize, write_map=write_map)
+    return image
+
+
 def PrepareImagesAndDtbs(dtb_fname, select_images, update_fdt):
     """Prepare the images to be processed and select the device tree
 
@@ -311,7 +419,7 @@ def ProcessImage(image, update_fdt, write_map, get_contents=True,
     # since changing an offset from 0x100 to 0x104 (for example) can
     # alter the compressed size of the device tree. So we need a
     # third pass for this.
-    passes = 3
+    passes = 5
     for pack_pass in range(passes):
         try:
             image.PackEntries()
@@ -333,7 +441,7 @@ def ProcessImage(image, update_fdt, write_map, get_contents=True,
             break
         image.ResetForPack()
     if not sizes_ok:
-        image.Raise('Entries expanded after packing (tried %s passes)' %
+        image.Raise('Entries changed size after packing (tried %s passes)' %
                     passes)
 
     image.WriteSymbols()
@@ -360,19 +468,23 @@ def Binman(args):
         command.Run(pager, fname)
         return 0
 
-    if args.cmd == 'ls':
-        try:
-            tools.PrepareOutputDir(None)
-            ListEntries(args.image, args.paths)
-        finally:
-            tools.FinaliseOutputDir()
-        return 0
-
-    if args.cmd == 'extract':
+    if args.cmd in ['ls', 'extract', 'replace']:
         try:
+            tout.Init(args.verbosity)
             tools.PrepareOutputDir(None)
-            ExtractEntries(args.image, args.filename, args.outdir, args.paths,
-                           not args.uncompressed)
+            if args.cmd == 'ls':
+                ListEntries(args.image, args.paths)
+
+            if args.cmd == 'extract':
+                ExtractEntries(args.image, args.filename, args.outdir, args.paths,
+                               not args.uncompressed)
+
+            if args.cmd == 'replace':
+                ReplaceEntries(args.image, args.filename, args.indir, args.paths,
+                               do_compress=not args.compressed,
+                               allow_resize=not args.fix_size, write_map=args.map)
+        except:
+            raise
         finally:
             tools.FinaliseOutputDir()
         return 0