When using extractall with the factory, see #660, there seems to be no way to handle symlinks. The read method is simply called with the symbolic link path itself instead of the file contents, resulting in the file being extracted wrong.
To Reproduce
Create file with 7z archive with relative symbolic link:
mkdir -p foo && ( cd foo && echo iriya > ufo && ln -s ufo saucer; ) &&
7z a -snl with-symlink.7z foo &&
rm -r foo/
The factory example as fixed in #660 with with-symlink.7z given as the file path:
from typing import override, Union, Optional
from py7zr import Py7zIO, SevenZipFile, WriterFactory
class MyIO(Py7zIO):
def __init__(self, limit):
self._limit = limit
self._buffer = None
self._empty = True
@override
def write(self, s: Union[bytes, bytearray]):
"""keep only bytes of limit"""
if self._empty:
self._buffer = s[:self._limit]
self._empty = False
@override
def read(self, size: Optional[int] = None) -> bytes:
size = 0 if size is None else size
if self._empty:
return bytes()
return self._buffer[:size]
@override
def seek(self, offset: int, whence: int = 0) -> int:
return 0
@override
def flush(self) -> None:
pass
@override
def size(self) -> int:
return len(self._buffer)
class MyFactory(WriterFactory):
def __init__(self, size):
self.size = size
self.products = {}
@override
def create(self, filename: str) -> Py7zIO:
product = MyIO(self.size)
self.products[filename] = product
return product
size = 10
factory = MyFactory(size)
with SevenZipFile('with-symlink.7z', 'r') as archive:
archive.extractall(factory=factory)
for filename, fileobj in factory.products.items():
print(f'{filename}: {fileobj.read(size)}...')
Output:
foo/saucer: bytearray(b'ufo')...
foo/ufo: bytearray(b'iriya\n')...
As can be seen, the symbolic link foo/saucer pointing to -> ufo relatively, simply gets called with Py7zrIO.write(<link contents>) and there is no way to detect that it is a symbolic link and not real file data.
Expected behavior
I think, ideally this meta information should be somehow given to the MyFactory.create call as an additional argument or such, so that a symbolic link can be created on the file system instead of creating a Py7zIO-derived file object.
Environment (please complete the following information):
- OS: Ubuntu 24.04
- Python: 3.12.3
- py7zr version: 1.0.0
Test data(please attach in the report):
test-file-is-in-zip-because-of-github-upload-restrictions.zip
When using
extractallwith the factory, see #660, there seems to be no way to handle symlinks. The read method is simply called with the symbolic link path itself instead of the file contents, resulting in the file being extracted wrong.To Reproduce
Create file with 7z archive with relative symbolic link:
The factory example as fixed in #660 with
with-symlink.7zgiven as the file path:Output:
As can be seen, the symbolic link
foo/saucerpointing to ->uforelatively, simply gets called withPy7zrIO.write(<link contents>)and there is no way to detect that it is a symbolic link and not real file data.Expected behavior
I think, ideally this meta information should be somehow given to the
MyFactory.createcall as an additional argument or such, so that a symbolic link can be created on the file system instead of creating a Py7zIO-derived file object.Environment (please complete the following information):
Test data(please attach in the report):
test-file-is-in-zip-because-of-github-upload-restrictions.zip