Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

File permission on zip member reported incorrectly #1

Open
travcunn opened this issue Mar 6, 2015 · 1 comment
Open

File permission on zip member reported incorrectly #1

travcunn opened this issue Mar 6, 2015 · 1 comment
Labels

Comments

@travcunn
Copy link

travcunn commented Mar 6, 2015

https://code.google.com/p/python-libarchive/issues/detail?id=6

Reported by [email protected], Jan 10, 2015

What steps will reproduce the problem?

  $ cd /tmp
  $ cp /etc/resolv.conf test1
  $ cp /etc/resolv.conf test2
  $ chmod 444 test1
  $ chmod 666 test2
  $ zip test.zip test1 test2
  $ /tmp/t1.py

What is the expected output? What do you see instead?
Expected output is:

  test2
  33206
  test1
  33060

Output displayed is:

  test2
  33206
  test1
  33206

What version of the product are you using? On what operating system?
libarchive-3.1.2, python-libarchive-3.1.2-1
RHEL6

Please provide any additional information below.
The problem is most likely with libarchive/init.py. I wrote another python program, /tmp/t2.py, using the raw libarchive commands and it gave the expected output.

/tmp/t1.py

#!/opt/fsw/pkgutils16/lib/aux/python/bin/python

import os
import sys

import libarchive.zip

zipfile = '/tmp/test.zip'

z = libarchive.zip.ZipFile (zipfile, 'r')

for entry in z:
  print entry.pathname
  print entry.mode

z.close ()

/tmp/t2.py

#!/opt/fsw/pkgutils16/lib/aux/python/bin/python

import os
import sys

from libarchive import _libarchive

zipfile = '/tmp/test.zip'

a = _libarchive.archive_read_new()
_libarchive.archive_read_support_format_zip(a)

_libarchive.archive_read_open_filename(a, zipfile, 10240)

e = _libarchive.archive_entry_new()
while True:
  r = _libarchive.archive_read_next_header2(a, e)
  if r == _libarchive.ARCHIVE_EOF:
    break
  path = _libarchive.archive_entry_pathname(e).decode('utf-8')
  mode = _libarchive.archive_entry_filetype(e)
  perm = _libarchive.archive_entry_perm(e)

  print path, mode, perm, mode | perm

_libarchive.archive_entry_free(e)
_libarchive.archive_read_close(a)
_libarchive.archive_read_free(a)
@travcunn travcunn added the bug label Mar 6, 2015
@travcunn
Copy link
Author

travcunn commented May 7, 2015

I was able to replicate this issue as well.

If you are interested in specifying permissions yourself, here's how you can do it:
Internally we are writing file-like objects to ZipFiles and specifying file permissions explicitly (664) rather than deriving permissions from the file-like object. To do so, override both ZipEntry.from_archive and ZipEntry.from_file class methods and specify mode=FILE_PERMISSION_664 as a kwarg when initializing a ZipFile entry.

Here is a snippet of our usage:

# 664 permissions
FILE_PERMISSION_664 = stat.S_IFREG | 0 | 0 | 0 | (stat.S_IRUSR | stat.S_IWUSR) | \
    (stat.S_IRGRP | stat.S_IWGRP) | stat.S_IROTH


class PermissiveZipEntry(ZipEntry):
    """
    A type of ZipEntry that sets files added to zip files to 664.
    """

    @classmethod
    def from_archive(cls, archive, encoding=ENCODING):
        """
        Instantiates an Entry class and sets all the properties from an
        archive header.
        """
        e = _libarchive.archive_entry_new()
        try:
            call_and_check(_libarchive.archive_read_next_header2, archive._a,
                           archive._a, e)
            mode = _libarchive.archive_entry_filetype(e)
            mode |= _libarchive.archive_entry_perm(e)
            entry = cls(
                pathname=_libarchive.archive_entry_pathname(e).decode(encoding),
                size=_libarchive.archive_entry_size(e),
                mtime=_libarchive.archive_entry_mtime(e),
                mode=FILE_PERMISSION_664,
                hpos=archive.header_position,
            )
        finally:
            _libarchive.archive_entry_free(e)
        return entry

    @classmethod
    def from_file(cls, f, entry=None, encoding=ENCODING):
        """
        Instantiates an Entry class and sets all the properties from a file on
        the file system. f can be a file-like object or a path.
        """
        if entry is None:
            entry = cls(encoding=encoding)
        if entry.pathname is None:
            if isinstance(f, basestring):
                st = os.stat(f)
                entry.pathname = f
                entry.size = st.st_size
                entry.mtime = st.st_mtime
            elif hasattr(f, 'fileno'):
                st = os.fstat(f.fileno())
                entry.pathname = getattr(f, 'name', None)
                entry.size = st.st_size
                entry.mtime = st.st_mtime
            else:
                entry.pathname = getattr(f, 'pathname', None)
                entry.size = getattr(f, 'size', 0)
                entry.mtime = getattr(f, 'mtime', time.time())
            entry.mode = FILE_PERMISSION
        return entry

    def to_archive(self, archive):
        """ Creates an archive header and writes it to the given archive. """
        e = _libarchive.archive_entry_new()
        try:
            _libarchive.archive_entry_set_pathname(e, self.pathname.encode(self.encoding))
            _libarchive.archive_entry_set_filetype(e, stat.S_IFMT(self.mode))
            _libarchive.archive_entry_set_perm(e, stat.S_IMODE(self.mode))
            _libarchive.archive_entry_set_size(e, self.size)
            _libarchive.archive_entry_set_mtime(e, self.mtime, 0)
            call_and_check(_libarchive.archive_write_header, archive._a,
                           archive._a, e)
            #self.hpos = archive.header_position
        finally:
            _libarchive.archive_entry_free(e)

    def isdir(self):
        return stat.S_ISDIR(self.mode)

    def isfile(self):
        return stat.S_ISREG(self.mode)

    def issym(self):
        return stat.S_ISLNK(self.mode)

    def isfifo(self):
        return stat.S_ISFIFO(self.mode)

    def ischr(self):
        return stat.S_ISCHR(self.mode)

    def isblk(self):
        return stat.S_ISBLK(self.mode)


# Create a ZipFile with file permissions of 664
f = open('/tmp/test.zip', 'w')
# Create a ZipFile with an entry class of PermissiveZipEntry
z = ZipFile(f, mode='w', entry_class=PermissiveZipEntry)
# write to the zip file here
z.close()
f.close()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant