6

Given a bunch of files in the current directory, I want to be able to zip them such that, when extracted, they'd be placed in some given directories. For example, say I have these in $PWD:

ls
fsck
xz
chroot

And when I run unzip foo.zip, they each get extracted to these directories:

/bin
/sbin
/usr/bin
/usr/sbin

The closest I could find is that these files must already exist in whatever directory paths I want the files to be extracted to (using $PWD as root directory):

$ zip foo.zip bin/ls sbin/fsck usr/bin/xz usr/sbin/chroot

Then, on a system where I want this extraction to happen, I would have to:

$ cd /
$ sudo unzip foo.zip
1
  • 1
    it makes sense that a zip file can't contain absolute destination paths, otherwise this would be a security issue (i.e., uncompressing a zip file could maliciously replace system files). As a proof of concept, it could replace the .ssh/authorized_keys file.
    – pqnet
    Aug 12, 2014 at 2:58

1 Answer 1

4

I don't see a way to do this using the zip command, but it's easy in python.

Note that the zip file format specification, section 4.4.17.1, says that the pathname cannot start with a '/', so I can't help with that part.

The python zipfile module will let you override a file's pathname when you add it to the zip archive; just pass the desired name as the optional 2nd argument to ZipFile.write:

ZipFile.write(filename[, arcname[, compress_type]])
Write the file named filename to the archive, giving it the archive name arcname (by default, this will be the same as filename, but without a drive letter and with leading path separators removed). If given, compress_type overrides the value given for the compression parameter to the constructor for the new entry.
Note: Archive names should be relative to the archive root, that is, they should not start with a path separator.

Here's an example:

$ touch 1 2 3
$ python
Python 2.7.6 (default, Mar 22 2014, 22:59:56) 
>>> import zipfile
>>> with zipfile.ZipFile('bundle.zip', 'w') as bundle:
...   bundle.write('1', '/bin/1')
...   bundle.write('2', '/sbin/2')
...   bundle.write('3', '/usr/bin/3')
... 
>>> 
$ unzip -l bundle
Archive:  bundle.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
        0  2014-08-11 13:00   bin/1
        0  2014-08-11 13:00   sbin/2
        0  2014-08-11 13:00   usr/bin/3
---------                     -------
        0                     3 files

Note that zipfile.write will remove any leading '/' from the pathname, to conform with the standard.

5
  • This still requires one to cd to / directory before extracting.
    – tshepang
    Aug 11, 2014 at 22:43
  • @Tshepang Yes, the zip file format specification says that the pathname cannot start with a '/'. If you give zipfile.write a pathname that starts with '/', it will be removed. I've edited my answer to add this. Aug 12, 2014 at 2:27
  • to create such a zip wouldn't be sufficient to create the directory structure inside a temporary dir, hard linking the needed files, and then generate the zip file from there?
    – pqnet
    Aug 12, 2014 at 2:56
  • @pqnet I mentioned that approach in my Question.
    – tshepang
    Aug 12, 2014 at 8:20
  • 1
    @Tshepang sorry I misunderstood your words thinking that you would actually use the root directory. What I meant to say is that unless you are using python as packaging tool (so that you don't have to parse the lists) this solution is pretty much the same thing.
    – pqnet
    Aug 12, 2014 at 8:42

You must log in to answer this question.

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