Skip to content

Commit ea33224

Browse files
authored
Tar pit (#291)
* Fix for broken directory * use cache * changelog * version bump * remove pyyaml from test requirements * drop python 3.3 * changelog * remove 3.3 from CI * rename _directory to _directory_entries * version bump
1 parent 4e6031f commit ea33224

File tree

7 files changed

+58
-49
lines changed

7 files changed

+58
-49
lines changed

Diff for: .travis.yml

-3
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,6 @@ matrix:
2020
- python: "3.4"
2121
env:
2222
- SETUPTOOLS=setuptools PIP=pip
23-
- python: "3.3"
24-
env:
25-
- SETUPTOOLS=setuptools~=39.2 PIP="pip<=18.0"
2623

2724
before_install:
2825
- pip install $SETUPTOOLS $PIP -U

Diff for: CHANGELOG.md

+6-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](http://keepachangelog.com/)
66
and this project adheres to [Semantic Versioning](http://semver.org/).
77

8-
## [2.5.6] - Unreleased
8+
## [2.5.6] - 2019-06-08
99

1010
### Added
1111

@@ -14,6 +14,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1414
### Fixed
1515

1616
- Fixed FTP test suite when time is not UTC-0 @mrg0029
17+
- Fixed issues with paths in tarfs https://github.com/PyFilesystem/pyfilesystem2/issues/284
18+
19+
### Changed
20+
21+
- Dropped Python3.3 support
1722

1823
## [2.4.5] - 2019-05-05
1924

Diff for: fs/_version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
"""Version, used in module and setup.py.
22
"""
3-
__version__ = "2.4.6a0"
3+
__version__ = "2.4.6"

Diff for: fs/tarfs.py

+25-10
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from .base import FS
1818
from .compress import write_tar
1919
from .enums import ResourceType
20+
from .errors import IllegalBackReference
2021
from .info import Info
2122
from .iotools import RawWrapper
2223
from .opener import open_fs
@@ -275,14 +276,26 @@ def __init__(self, file, encoding="utf-8"):
275276
self._directory_cache = None
276277

277278
@property
278-
def _directory(self):
279+
def _directory_entries(self):
279280
"""Lazy directory cache."""
280281
if self._directory_cache is None:
281282
_decode = self._decode
282-
_directory = ((_decode(info.name).strip("/"), info) for info in self._tar)
283-
self._directory_cache = OrderedDict(
284-
(name, info) for name, info in _directory if normpath(name)
283+
_directory_entries = (
284+
(_decode(info.name).strip("/"), info) for info in self._tar
285285
)
286+
287+
def _list_tar():
288+
for name, info in _directory_entries:
289+
try:
290+
_name = normpath(name)
291+
except IllegalBackReference:
292+
# Back references outside root, must be up to no good.
293+
pass
294+
else:
295+
if _name:
296+
yield _name, info
297+
298+
self._directory_cache = OrderedDict(_list_tar())
286299
return self._directory_cache
287300

288301
def __repr__(self):
@@ -327,7 +340,7 @@ def getinfo(self, path, namespaces=None):
327340
else:
328341
try:
329342
implicit = False
330-
member = self._tar.getmember(self._encode(_path))
343+
member = self._directory_entries[_path]
331344
except KeyError:
332345
if not self.isdir(_path):
333346
raise errors.ResourceNotFound(path)
@@ -370,14 +383,14 @@ def getinfo(self, path, namespaces=None):
370383
def isdir(self, path):
371384
_path = relpath(self.validatepath(path))
372385
try:
373-
return self._directory[_path].isdir()
386+
return self._directory_entries[_path].isdir()
374387
except KeyError:
375-
return any(isbase(_path, name) for name in self._directory)
388+
return any(isbase(_path, name) for name in self._directory_entries)
376389

377390
def isfile(self, path):
378391
_path = relpath(self.validatepath(path))
379392
try:
380-
return self._directory[_path].isfile()
393+
return self._directory_entries[_path].isfile()
381394
except KeyError:
382395
return False
383396

@@ -393,7 +406,9 @@ def listdir(self, path):
393406
if not self.gettype(path) is ResourceType.directory:
394407
raise errors.DirectoryExpected(path)
395408

396-
children = (frombase(_path, n) for n in self._directory if isbase(_path, n))
409+
children = (
410+
frombase(_path, n) for n in self._directory_entries if isbase(_path, n)
411+
)
397412
content = (parts(child)[1] for child in children if relpath(child))
398413
return list(OrderedDict.fromkeys(content))
399414

@@ -415,7 +430,7 @@ def openbin(self, path, mode="r", buffering=-1, **options):
415430
raise errors.ResourceReadOnly(path)
416431

417432
try:
418-
member = self._tar.getmember(self._encode(_path))
433+
member = self._directory_entries[_path]
419434
except KeyError:
420435
six.raise_from(errors.ResourceNotFound(path), None)
421436

Diff for: setup.py

+21-29
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,24 @@
22

33
from setuptools import setup, find_packages
44

5-
with open('fs/_version.py') as f:
5+
with open("fs/_version.py") as f:
66
exec(f.read())
77

88
CLASSIFIERS = [
9-
'Development Status :: 5 - Production/Stable',
10-
'Intended Audience :: Developers',
11-
'License :: OSI Approved :: MIT License',
12-
'Operating System :: OS Independent',
13-
'Programming Language :: Python',
14-
'Programming Language :: Python :: 2.7',
15-
'Programming Language :: Python :: 3.3',
16-
'Programming Language :: Python :: 3.4',
17-
'Programming Language :: Python :: 3.5',
18-
'Programming Language :: Python :: 3.6',
19-
'Programming Language :: Python :: 3.7',
20-
'Topic :: System :: Filesystems',
9+
"Development Status :: 5 - Production/Stable",
10+
"Intended Audience :: Developers",
11+
"License :: OSI Approved :: MIT License",
12+
"Operating System :: OS Independent",
13+
"Programming Language :: Python",
14+
"Programming Language :: Python :: 2.7",
15+
"Programming Language :: Python :: 3.4",
16+
"Programming Language :: Python :: 3.5",
17+
"Programming Language :: Python :: 3.6",
18+
"Programming Language :: Python :: 3.7",
19+
"Topic :: System :: Filesystems",
2120
]
2221

23-
REQUIREMENTS = [
24-
"appdirs~=1.4.3",
25-
"pytz",
26-
"setuptools",
27-
"six~=1.10",
28-
]
22+
REQUIREMENTS = ["appdirs~=1.4.3", "pytz", "setuptools", "six~=1.10"]
2923

3024
setup(
3125
author="Will McGugan",
@@ -34,21 +28,19 @@
3428
description="Python's filesystem abstraction layer",
3529
install_requires=REQUIREMENTS,
3630
extras_require={
37-
"scandir :python_version < '3.5'": ['scandir~=1.5'],
38-
":python_version < '3.4'": ['enum34~=1.1.6'],
39-
":python_version < '3.6'": ['typing~=3.6'],
40-
":python_version < '3.0'": ['backports.os~=0.1']
31+
"scandir :python_version < '3.5'": ["scandir~=1.5"],
32+
":python_version < '3.4'": ["enum34~=1.1.6"],
33+
":python_version < '3.6'": ["typing~=3.6"],
34+
":python_version < '3.0'": ["backports.os~=0.1"],
4135
},
4236
license="MIT",
43-
name='fs',
37+
name="fs",
4438
packages=find_packages(exclude=("tests",)),
45-
package_data = {
46-
'fs': ['py.typed'],
47-
},
39+
package_data={"fs": ["py.typed"]},
4840
zip_safe=False,
49-
platforms=['any'],
41+
platforms=["any"],
5042
test_suite="nose.collector",
51-
tests_require=['appdirs', 'mock', 'pytz', 'pyftpdlib'],
43+
tests_require=["appdirs", "mock", "pytz", "pyftpdlib"],
5244
url="https://github.com/PyFilesystem/pyfilesystem2",
5345
version=__version__,
5446
)

Diff for: testrequirements.txt

-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ appdirs~=1.4.0
22
coverage
33
mock
44
pyftpdlib==1.5.2
5-
PyYAML<4.1 ; python_version == '3.3'
65
python-coveralls
76
pytz==2016.7
87
nose

Diff for: tests/test_tarfs.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ def test_getinfo(self):
188188
self.assertTrue(top.get("tar", "is_file"))
189189

190190

191-
class TestBrokenDir(unittest.TestCase):
191+
class TestBrokenPaths(unittest.TestCase):
192192
@classmethod
193193
def setUpClass(cls):
194194
cls.tmpfs = open_fs("temp://tarfstest")
@@ -200,7 +200,8 @@ def tearDownClass(cls):
200200
def setUp(self):
201201
self.tempfile = self.tmpfs.open("test.tar", "wb+")
202202
with tarfile.open(mode="w", fileobj=self.tempfile) as tf:
203-
tf.addfile(tarfile.TarInfo("."), io.StringIO)
203+
tf.addfile(tarfile.TarInfo("."), io.StringIO())
204+
tf.addfile(tarfile.TarInfo("../foo.txt"), io.StringIO())
204205
self.tempfile.seek(0)
205206
self.fs = tarfs.TarFS(self.tempfile)
206207

@@ -228,8 +229,8 @@ def setUp(self):
228229
self.tempfile = self.tmpfs.open("test.tar", "wb+")
229230
with tarfile.open(mode="w", fileobj=self.tempfile) as tf:
230231
tf.addfile(tarfile.TarInfo("foo/bar/baz/spam.txt"), io.StringIO())
231-
tf.addfile(tarfile.TarInfo("foo/eggs.bin"), io.StringIO())
232-
tf.addfile(tarfile.TarInfo("foo/yolk/beans.txt"), io.StringIO())
232+
tf.addfile(tarfile.TarInfo("./foo/eggs.bin"), io.StringIO())
233+
tf.addfile(tarfile.TarInfo("./foo/yolk/beans.txt"), io.StringIO())
233234
info = tarfile.TarInfo("foo/yolk")
234235
info.type = tarfile.DIRTYPE
235236
tf.addfile(info, io.BytesIO())

0 commit comments

Comments
 (0)