From: Christian Herdtweck Date: Tue, 19 Jul 2016 10:54:15 +0000 (+0200) Subject: Ensure files are closed when starting new volume. X-Git-Url: http://developer.intra2net.com/git/?a=commitdiff_plain;h=75ff2f499d65bc3aa775ed376eff836923d5bdcd;p=python-delta-tar Ensure files are closed when starting new volume. Move closing of old volume from handler to own code (handlers might try to close again, should not be a problem). Also ensure files are closed if volume handler fails. --- diff --git a/deltatar/tarfile.py b/deltatar/tarfile.py index 1115373..fcb6dcc 100644 --- a/deltatar/tarfile.py +++ b/deltatar/tarfile.py @@ -2729,7 +2729,6 @@ class TarFile(object): raise Exception("We need to create a new volume and you " "didn't supply a new_volume_handler") - # the new volume handler should do everything needed to # start working in a new volume. usually, the handler calls # to self.open_volume @@ -2741,9 +2740,29 @@ class TarFile(object): tarinfo.volume_offset = tarinfo.size - source_size_left self.volume_tarinfo = tarinfo - # the “new_volume_handler” is supposed to call .close() on the - # “fileobj” _Stream - self.new_volume_handler(self, self.base_name, self.volume_number) + # close current volume file (even if fileobj is external) + self.fileobj.close() + + try: + if not self.new_volume_handler or\ + not callable(self.new_volume_handler): + + # complain + raise Exception("We need to create a new volume and " + "you didn't supply a " + "new_volume_handler") + + self.new_volume_handler(self, self.base_name, + self.volume_number) + except Exception: + # close files + if fileobj: + fileobj.close() + if self.fileobj: + if not self._extfileobj: + self.fileobj.close() + self.closed = True + raise self.volume_tarinfo = None @@ -3049,40 +3068,41 @@ class TarFile(object): source.seek(tarinfo.offset_data) decrypt = False iterate = True - target = bltn_open(targetpath, "wb") + target = None + try: + target = bltn_open(targetpath, "wb") - if tarinfo.sparse is not None: - try: + if tarinfo.sparse is not None: for offset, size in tarinfo.sparse: target.seek(offset) copyfileobj(source, target, size) target.seek(tarinfo.size) target.truncate() - finally: - target.close() return - while iterate: - iterate = False - try: - copyfileobj(source, target, tarinfo.size) - except OSError: - source.close() - # only if we are extracting a multivolume this can be treated - if not self.new_volume_handler: - raise Exception("We need to read a new volume and you" - " didn't supply a new_volume_handler") - - # the new volume handler should do everything needed to - # start working in a new volume. usually, the handler calls - # to self.open_volume - self.volume_number += 1 - self.new_volume_handler(self, self.base_name, self.volume_number) - tarinfo = self.firstmember - source = self.fileobj - iterate = True - finally: - if iterate is False: target.close() + while iterate: + iterate = False + try: + copyfileobj(source, target, tarinfo.size) + except OSError: + source.close() + # only if we are extracting a multivolume this can be treated + if not self.new_volume_handler: + raise Exception("We need to read a new volume and you" + " didn't supply a new_volume_handler") + + # the new volume handler should do everything needed to + # start working in a new volume. usually, the handler calls + # to self.open_volume + self.volume_number += 1 + self.new_volume_handler(self, self.base_name, self.volume_number) + tarinfo = self.firstmember + source = self.fileobj + iterate = True + + finally: + if target: + target.close() def makeunknown(self, tarinfo, targetpath):