3

I am trying to modify a file system image packed with cpio. For that reason I first need to extract and later pack the image. As the image contains a whole file system all the files are given in absolute file names, so I can't directly pack and unpack it, since it would conflict with my machine's root system.

So when unpacking I used --no-absolute-filenames to unpack it to a working directory of my choice. Now I want to pack it again. If I just pack it i'd only get files like that:

/path/to/working/directory/file1
/path/to/working/directory/file2
/path/to/working/directory/file3

or

./file1
./file2
./file3

instead of

/file1
/file2
/file3

Does anyone know how I could get the desired output? Google didn't help me so far.

I really need absolute path names in the output file, because I am using it for an u-boot uImage file system image, and that requires the paths to be absolute, or it won't boot.

0

2 Answers 2

3

If you have python and:

  • install libarchive-c (e.g. using pip install libarchive-c)
  • have all your files under directory root in the current directory ( I used
    mkdir -p root/xyz ; echo 1 > root/abc.txt ; echo 2> root/xyz/def.txt )
  • save the following as abscpio and make it executable (chmod 755 abscpio)

    #! /usr/bin/env python
    import os
    import sys
    from libarchive import ffi
    from libarchive.write import (
       new_archive_write, ArchiveWrite, new_archive_read_disk)
    from libarchive.entry import new_archive_entry, ArchiveEntry
    from libarchive.ffi import (
        ARCHIVE_EOF,
        entry_sourcepath,
        entry_clear,
        read_next_header2,
        read_disk_descend,
        write_header,
        write_data,
        write_finish_entry,
    )
    
    
    class AbsArchiveWrite(ArchiveWrite):
    
       def add_abs_file(self, path, store_path):
          """Read the given paths from disk and add them to the archive.
          """
          write_p = self._pointer
    
          block_size = ffi.write_get_bytes_per_block(write_p)
          if block_size <= 0:
             block_size = 10240  # pragma: no cover
    
          with new_archive_entry() as entry_p:
             entry = ArchiveEntry(None, entry_p)
             with new_archive_read_disk(path) as read_p:
                while 1:
                   r = read_next_header2(read_p, entry_p)
                   if r == ARCHIVE_EOF:
                      break
                   entry.pathname = store_path
                   read_disk_descend(read_p)
                   write_header(write_p, entry_p)
                   try:
                      with open(entry_sourcepath(entry_p), 'rb') as f:
                         while 1:
                            data = f.read(block_size)
                            if not data:
                               break
                            write_data(write_p, data, len(data))
                   except IOError as e:
                      if e.errno != 21:
                         raise  # pragma: no cover
                   write_finish_entry(write_p)
                   entry_clear(entry_p)
                   if os.path.isdir(path):
                      break
    
    
    base_dir = sys.argv[2]
    
    with new_archive_write('cpio', None) as archive_p:
       ffi.write_open_filename_w(archive_p, sys.argv[1])
       a = AbsArchiveWrite(archive_p)
    
       for root, dir_names, file_names in os.walk(base_dir):
          for dir_name in dir_names:
             full_name = os.path.join(root, dir_name)
             a.add_abs_file(full_name, full_name.replace(base_dir, '/', 1))
          for file_name in file_names:
             full_name = os.path.join(root, file_name)
             a.add_abs_file(full_name, full_name.replace(base_dir, '/', 1))
    
    print '----- listing ' + sys.argv[1]
    os.system('cpio -itv -I ' + sys.argv[1])
    

you can do:

abscpio my_arch.cpio root/

with as output something similar to:

----- listing my_arch.cpio
drwxrwxr-x   2 anthon   users           0 Jun 25 18:59 /xyz
-rw-rw-r--   1 anthon   users           2 Jun 25 18:59 /abc.txt
-rw-rw-r--   1 anthon   users           0 Jun 25 18:59 /xyz/def.txt

for production you might want to delete the last two lines from the script.

Links are stored as well, but I haven't tried other "file" types.

1

Use pax and its -s option to rename files as they are added to the archive. Pax is POSIX's replacement for the traditional utilities tar and cpio; some Linux distributions don't install it by default but it should always be available as a package.

pax -w -x cpio -s '~^[/]*~~' root-directory >archive.cpio

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .