def _restore_data(self, read_pipe): try: data_chunk = read_pipe.recv_bytes() decompressor = compress.Decompressor(self.compression_algo) decryptor = None if self.encrypt_pass_file: decryptor = crypt.AESDecrypt(self.encrypt_pass_file, data_chunk[:crypt.BS]) data_chunk = data_chunk[crypt.BS:] while True: try: data_chunk = self._process_restore_data( data_chunk, decompressor, decryptor) except Exception: data_chunk += read_pipe.recv_bytes() continue if data_chunk: yield io.BytesIO(data_chunk) data_chunk = read_pipe.recv_bytes() except EOFError: LOG.info("[*] EOF from pipe. Flushing buffer.") data_chunk = decompressor.flush() if data_chunk: yield io.BytesIO(data_chunk)
def restore_level(self, restore_resource, read_pipe, backup, except_queue): """Restore the provided file into restore_abs_path. Decrypt the file if backup_opt_dict.encrypt_pass_file key is provided. Freezer rsync header data structure: header_len, RSYNC_DATA_STRUCT_VERSION, file_mode, os_stat.st_uid, os_stat.st_gid, os_stat.st_size, mtime, ctime, uname, gname, file_type, linkname :param restore_resource: :param read_pipe: :param backup: :param except_queue: :return: """ try: metadata = backup.metadata() if (not self.encrypt_pass_file and metadata.get("encryption", False)): raise Exception("Cannot restore encrypted backup without key") self.compression_algo = metadata.get('compression', self.compression_algo) if not os.path.exists(restore_resource): raise ValueError( 'Provided restore path does not exist: {0}'.format( restore_resource)) if self.dry_run: restore_resource = '/dev/null' raw_data_chunk = read_pipe.recv_bytes() self.compressor = compress.Decompressor(self.compression_algo) if self.encrypt_pass_file: self.cipher = crypt.AESDecrypt(self.encrypt_pass_file, raw_data_chunk[:16]) raw_data_chunk = raw_data_chunk[16:] data_chunk = self.process_restore_data(raw_data_chunk) header_str = r'^(\d{1,})\00' flushed = False while True: header_match = re.search(header_str, data_chunk) if not header_match and not flushed: try: data_chunk += self.process_restore_data( read_pipe.recv_bytes()) continue except EOFError: LOG.info("EOFError: Pipe closed. Flushing buffer...") data_chunk += self.compressor.flush() flushed = True if data_chunk and header_match: header_len = int(header_match.group(1)) if header_len > len(data_chunk) and not flushed: try: data_chunk += self.process_restore_data( read_pipe.recv_bytes()) except EOFError: LOG.info("[*] End of File: Pipe closed. " "Flushing the buffer.") data_chunk += self.compressor.flush() flushed = True header = data_chunk[:header_len] header_list = header.split('\00') data_chunk = data_chunk[header_len:] data_chunk = self.make_files(header_list, restore_resource, read_pipe, data_chunk, flushed, backup.level) else: LOG.info('No more data available...') break except Exception as e: LOG.exception(e) except_queue.put(e) raise