def extract_member(self, identity_object, root_dir, dir, new_filename, umask, force_file_permissions=None,
                       force_dir_permissions=None, allow_clobber=False):
        _check_mode(self._mode, 'r')

        tarinfo_obj = identity_object

        output_location = os.path.join(root_dir, dir, new_filename)

        if os.path.exists(output_location) and not allow_clobber:
            raise ClobberError(output_location)

        # Extract the file to the given location.

        saved_name = tarinfo_obj.name
        tarinfo_obj.name = os.path.join(dir, new_filename)
        saved_mode = tarinfo_obj.mode
        tarinfo_obj.mode = _calc_perms(tarinfo_obj.mode, umask) # Apply umask to permissions.

        try:
            self._tarfile_obj.extract(tarinfo_obj, root_dir)
        except EnvironmentError, e:
            if e.errno == 13:

                def f():
                    # Have already done this, but permissions might
                    # have caused a fallacious answer previously:
                    if os.path.exists(output_location) and not allow_clobber:
                        raise ClobberError(output_location)
                    elif os.path.exists(output_location) and allow_clobber:
                        if os.path.isdir(output_location):
                            # can ignore dirs; we can overwrite them
                            # whatever their current perms
                            pass
                        else:
                            # non-write permissions will prevent
                            # .extract method from overwriting, so
                            # unlink first:
                            os.unlink(output_location)
                    return self._tarfile_obj.extract(tarinfo_obj, root_dir)

                number_dotdot = _count_dotdot(dir)

                if number_dotdot != 0:
                    # This is the reason why allow_dotdot_paths = True is v. dangerous:
                    barrier_dir = None
#                     shunted_root_dir = os.path.join(root_dir, '../' * number_dotdot)
#                     normed_shunted_root_dir = os.path.normpath(shunted_root_dir)
#                     barrier_dir = normed_shunted_root_dir
                else:
                    barrier_dir=root_dir

                _provide_dir_with_perms_then_exec(dir=os.path.join(root_dir, dir), function=f, perms=0700, barrier_dir=barrier_dir)
            else:
                raise
    def extract_member(self, identity_object, root_dir, dir, new_filename, umask, force_file_permissions=None,
                       force_dir_permissions=None, allow_clobber=False):
        _check_mode(self._mode, 'r')

        tarinfo_obj = identity_object

        output_location = os.path.join(root_dir, dir, new_filename)

        if os.path.exists(output_location) and not allow_clobber:
            raise ClobberError(output_location)

        # Extract the file to the given location.

        saved_name = tarinfo_obj.name
        tarinfo_obj.name = os.path.join(dir, new_filename)
        saved_mode = tarinfo_obj.mode
        tarinfo_obj.mode = _calc_perms(tarinfo_obj.mode, umask) # Apply umask to permissions.

        try:
            self._tarfile_obj.extract(tarinfo_obj, root_dir)
        except EnvironmentError, e:
            if e.errno == 13:

                def f():
                    # Have already done this, but permissions might
                    # have caused a fallacious answer previously:
                    if os.path.exists(output_location) and not allow_clobber:
                        raise ClobberError(output_location)
                    elif os.path.exists(output_location) and allow_clobber:
                        if os.path.isdir(output_location):
                            # can ignore dirs; we can overwrite them
                            # whatever their current perms
                            pass
                        else:
                            # non-write permissions will prevent
                            # .extract method from overwriting, so
                            # unlink first:
                            os.unlink(output_location)
                    return self._tarfile_obj.extract(tarinfo_obj, root_dir)

                number_dotdot = _count_dotdot(dir)

                if number_dotdot != 0:
                    # This is the reason why allow_dotdot_paths = True is v. dangerous:
                    barrier_dir = None
#                     shunted_root_dir = os.path.join(root_dir, '../' * number_dotdot)
#                     normed_shunted_root_dir = os.path.normpath(shunted_root_dir)
#                     barrier_dir = normed_shunted_root_dir
                else:
                    barrier_dir=root_dir

                _provide_dir_with_perms_then_exec(dir=os.path.join(root_dir, dir), function=f, perms=0700, barrier_dir=barrier_dir)
            else:
                raise
                    os.chmod(output_location, force_file_permissions)
                except EnvironmentError, e:
                    if e.errno == 13:
                        f = lambda: os.chmod(output_location, force_file_permissions)
                        _provide_dir_with_perms_then_exec(dir=os.path.join(root_dir, dir), function=f, perms=0700, barrier_dir=root_dir)
                    else:
                        raise

        elif type == 'dir':
            if force_dir_permissions is not None:
                try:
                    os.chmod(output_location, force_dir_permissions)
                except EnvironmentError, e:
                    if e.errno == 13:
                        f = lambda: os.chmod(output_location, force_dir_permissions)
                        _provide_dir_with_perms_then_exec(dir=os.path.join(root_dir, dir), function=f, perms=0700, barrier_dir=root_dir)
                    else:
                        raise
        else:
            # We don't attempt to play with permissions of special
            # file types.
            pass

    def add_member(self, file_loc, archive_name=None, force_file_permissions=None, force_dir_permissions=None):
        _check_mode(self._mode, 'w')

        if archive_name is None:
            archive_name = file_loc

        tarinfo_obj = self._tarfile_obj.gettarinfo(name=file_loc, arcname=archive_name)
class tarArchiveTool(ArchiveTool):

    # Overide this in child classes tarbz2ArchiveTool and
    # targzArchiveTool to make the mode string reflect the required
    # compression.

    def _mode_string(string):
        return string + ':'

    _mode_string = staticmethod(_mode_string)

    def __init__(self, file_loc, mode, allow_clobber=False):
        if mode not in ('r', 'w'): raise ValueError('mode argument must equal "r" or "w"')

        if mode == 'w':
            if os.path.exists(file_loc) and not allow_clobber:
                raise ClobberError(file_loc)

        # Set adjusted mode to reflect whether we are dealing with a
        # tar.gz tar.bz2 or just a tar.
        adjusted_mode = self._mode_string(mode)

        self._tarfile_obj = tarfile.open(name=file_loc, mode=adjusted_mode)
        self._tarfile_obj.errorlevel=2
        self._mode = mode
        self._filename = os.path.basename(file_loc)
        self._file_loc = file_loc

    def list_all_members(self):
        _check_mode(self._mode, 'r')

        f = lambda tarinfo_obj:  { 'name' : os.path.basename(os.path.normpath(tarinfo_obj.name)),
                                   'dir' : os.path.dirname(os.path.normpath(tarinfo_obj.name)),
                                   'file_type' : _file_type(tarinfo_obj),
                                   'identity_object' : tarinfo_obj }

        return map(f, self._tarfile_obj.getmembers())

    def extract_member(self, identity_object, root_dir, dir, new_filename, umask, force_file_permissions=None,
                       force_dir_permissions=None, allow_clobber=False):
        _check_mode(self._mode, 'r')

        tarinfo_obj = identity_object

        output_location = os.path.join(root_dir, dir, new_filename)

        if os.path.exists(output_location) and not allow_clobber:
            raise ClobberError(output_location)

        # Extract the file to the given location.

        saved_name = tarinfo_obj.name
        tarinfo_obj.name = os.path.join(dir, new_filename)
        saved_mode = tarinfo_obj.mode
        tarinfo_obj.mode = _calc_perms(tarinfo_obj.mode, umask) # Apply umask to permissions.

        try:
            self._tarfile_obj.extract(tarinfo_obj, root_dir)
        except EnvironmentError, e:
            if e.errno == 13:

                def f():
                    # Have already done this, but permissions might
                    # have caused a fallacious answer previously:
                    if os.path.exists(output_location) and not allow_clobber:
                        raise ClobberError(output_location)
                    elif os.path.exists(output_location) and allow_clobber:
                        if os.path.isdir(output_location):
                            # can ignore dirs; we can overwrite them
                            # whatever their current perms
                            pass
                        else:
                            # non-write permissions will prevent
                            # .extract method from overwriting, so
                            # unlink first:
                            os.unlink(output_location)
                    return self._tarfile_obj.extract(tarinfo_obj, root_dir)

                number_dotdot = _count_dotdot(dir)

                if number_dotdot != 0:
                    # This is the reason why allow_dotdot_paths = True is v. dangerous:
                    barrier_dir = None
#                     shunted_root_dir = os.path.join(root_dir, '../' * number_dotdot)
#                     normed_shunted_root_dir = os.path.normpath(shunted_root_dir)
#                     barrier_dir = normed_shunted_root_dir
                else:
                    barrier_dir=root_dir

                _provide_dir_with_perms_then_exec(dir=os.path.join(root_dir, dir), function=f, perms=0700, barrier_dir=barrier_dir)
            else:
                raise

        tarinfo_obj.name = saved_name
        tarinfo_obj.mode = saved_mode

        # If we've been asked to force permissions, do so:
        type = _file_type(tarinfo_obj)

        if type == 'regular':
            if force_file_permissions is not None:
                try:
                    os.chmod(output_location, force_file_permissions)
                except EnvironmentError, e:
                    if e.errno == 13:
                        f = lambda: os.chmod(output_location, force_file_permissions)
                        _provide_dir_with_perms_then_exec(dir=os.path.join(root_dir, dir), function=f, perms=0700, barrier_dir=root_dir)
                    else:
                        raise
                    os.chmod(output_location, force_file_permissions)
                except EnvironmentError, e:
                    if e.errno == 13:
                        f = lambda: os.chmod(output_location, force_file_permissions)
                        _provide_dir_with_perms_then_exec(dir=os.path.join(root_dir, dir), function=f, perms=0700, barrier_dir=root_dir)
                    else:
                        raise

        elif type == 'dir':
            if force_dir_permissions is not None:
                try:
                    os.chmod(output_location, force_dir_permissions)
                except EnvironmentError, e:
                    if e.errno == 13:
                        f = lambda: os.chmod(output_location, force_dir_permissions)
                        _provide_dir_with_perms_then_exec(dir=os.path.join(root_dir, dir), function=f, perms=0700, barrier_dir=root_dir)
                    else:
                        raise
        else:
            # We don't attempt to play with permissions of special
            # file types.
            pass

    def add_member(self, file_loc, archive_name=None, force_file_permissions=None, force_dir_permissions=None):
        _check_mode(self._mode, 'w')

        if archive_name is None:
            archive_name = file_loc

        tarinfo_obj = self._tarfile_obj.gettarinfo(name=file_loc, arcname=archive_name)