Beispiel #1
0
    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)
Beispiel #2
0
    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