2

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.

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
2

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

When I used to use cpio I would always use it in a relative path name fashion.

So with your example, I would

cd /to/where/the/root/is/
find . -print -depth | cpio -ov > /myarchivestore/archive.cpio

Then to restore relative paths (whilst at /),

cd /
cpio -iv < archive.cpio < /myarchivestore.cpio

otherwise you will encounter exactly your original problem.

  • The problem is, that I need the absolute path names. I am using it for an uImage file system image, and that thing sadly requires absolute path names, or it won't boot. – Dakkaron Jun 25 '15 at 15:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.