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