Browse Source

separate closing from deferred closing for streams.. make context work...

don't leak file in SeekableArchive..
test_fixup
John-Mark Gurney 2 years ago
parent
commit
ba5832c545
3 changed files with 56 additions and 7 deletions
  1. BIN
      fixtures/testfile.tar.gz
  2. +9
    -7
      libarchive/__init__.py
  3. +47
    -0
      tests.py

BIN
fixtures/testfile.tar.gz View File


+ 9
- 7
libarchive/__init__.py View File

@@ -24,6 +24,7 @@
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import os
import pathlib
import stat
import sys
import time
@@ -200,7 +201,7 @@ class EntryReadStream(object):
return self

def __exit__(self, *args):
return
self.close()

def __iter__(self):
if self.closed:
@@ -438,17 +439,20 @@ class Archive(object):
self.encoding = encoding
self.blocksize = blocksize
self.password = password
if isinstance(f, pathlib.PurePath):
f = str(f)
if isinstance(f, str):
self.filename = f
f = open(f, mode)
# Only close it if we opened it...
self._defer_close = True
self._doclose = True
elif hasattr(f, 'fileno'):
self.filename = getattr(f, 'name', None)
# Leave the fd alone, caller should manage it...
self._defer_close = False
self._doclose = False
else:
raise Exception('Provided file is not path or open file.')
self._defer_close = False
self.f = f
self.mode = mode
# Guess the format/filter from file name (if not provided)
@@ -493,7 +497,7 @@ class Archive(object):
return self

def __exit__(self, type, value, traceback):
self.denit()
self.close()

def __del__(self):
self.close()
@@ -563,7 +567,7 @@ class Archive(object):
if hasattr(self.f, "fileno"):
os.fsync(self.f.fileno())
# and then close it, if we opened it...
if getattr(self, '_close', None):
if self._doclose and getattr(self.f, 'close', None):
self.f.close()

@property
@@ -665,8 +669,6 @@ class SeekableArchive(Archive):
self._stream = None
# Convert file to open file. We need this to reopen the archive.
mode = kwargs.setdefault('mode', 'r')
if isinstance(f, str):
f = open(f, mode)
super(SeekableArchive, self).__init__(f, **kwargs)
self.entries = []
self.eof = False


+ 47
- 0
tests.py View File

@@ -27,7 +27,9 @@
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import os, unittest, tempfile, random, string, sys
import hashlib
import io
import pathlib
import shutil
import zipfile

@@ -368,6 +370,51 @@ class TestHighLevelAPI(unittest.TestCase, MakeTempMixIn):
with io.FileIO(zf.fileno(), mode='r', closefd=False) as f:
self._test_listing_content(f)

_defaulthash = 'sha512'

def _readfp(fp):
while True:
r = fp.read(64*1024)
# libarchive returns None on EOF
if r == b'' or r is None:
return

yield r

def _hashfp(fp):
hash = getattr(hashlib, _defaulthash)()
for r in _readfp(fp):
hash.update(r)

return '%s:%s' % (_defaulthash, hash.hexdigest())


class TestArchive(unittest.TestCase):
def setUp(self):
self.fixtures = pathlib.Path(__file__).parent / 'fixtures'

def test_closed(self):
fname = self.fixtures / 'testfile.tar.gz'

with Archive(fname) as arch:
origfp = arch.f

hashes = []

for i in arch:
if not i.isfile():
continue

with arch.readstream(i.size) as fp:
hashes.append(_hashfp(fp))

self.assertTrue(fp.closed)
self.assertIsNone(arch._stream)

self.assertEqual(hashes, [ 'sha512:90f8342520f0ac57fb5a779f5d331c2fa87aa40f8799940257f9ba619940951e67143a8d746535ed0284924b2b7bc1478f095198800ba96d01847d7b56ca465c', 'sha512:7d5768d47b6bc27dc4fa7e9732cfa2de506ca262a2749cb108923e5dddffde842bbfee6cb8d692fb43aca0f12946c521cce2633887914ca1f96898478d10ad3f' ])

self.assertTrue(arch.f.closed)


if __name__ == '__main__':
unittest.main()

Loading…
Cancel
Save