class _Reader(io.RawIOBase): """ Context Manager to read a snapshot. """ def __init__(self, process, stream, path, diff, showProgress): self.process = process self.stream = stream self.path = path self.diff = diff self.bytesRead = None self.progress = DisplayProgress() if showProgress else None def __enter__(self): self.bytesRead = 0 if self.progress is not None: self.progress.open() return self def __exit__(self, exceptionType, exception, trace): self.stream.close() if self.progress is not None: self.progress.close() if self.process is None: return logger.debug("Waiting for send process to finish...") self.process.wait() if self.process.returncode != 0: logger.error("btrfs send errors") for line in self.process.stderr: sys.stderr.write(line) if exception is None and self.process.returncode != 0: raise Exception("send returned error %d. %s may be corrupt." % (self.process.returncode, self.path)) def read(self, size): # If it's the first big chunk (header) # Tweak the volume information to match what we expect. data = self.stream.read(size) if FIXUP_DURING_SEND and self.bytesRead == 0: data = send.replaceIDs( data, self.diff.toUUID, self.diff.toGen, self.diff.fromUUID, self.diff.fromGen, ) self.bytesRead += len(data) if self.progress is not None: self.progress.update(self.bytesRead) return data def seek(self, offset, whence): self.stream.seek(offset, offset, whence) if whence == io.SEEK_SET: self.bytesRead = offset elif whence == io.SEEK_CUR: pass elif whence == io.SEEK_END: self.bytesRead = None
class _Reader(io.RawIOBase): """ Context Manager to read a snapshot. """ def __init__(self, process, stream, path, diff, showProgress): self.process = process self.stream = stream self.path = path self.diff = diff self.bytesRead = None self.progress = DisplayProgress() if showProgress else None def __enter__(self): self.bytesRead = 0 if self.progress is not None: self.progress.open() return self def __exit__(self, exceptionType, exception, trace): self.stream.close() if self.progress is not None: self.progress.close() if self.process is None: return logger.debug("Waiting for send process to finish...") self.process.wait() if self.process.returncode != 0: logger.error("btrfs send errors") for line in self.process.stderr: sys.stderr.write(line) if exception is None and self.process.returncode != 0: raise Exception( "send returned error %d. %s may be corrupt." % (self.process.returncode, self.path) ) def read(self, size): # If it's the first big chunk (header) # Tweak the volume information to match what we expect. data = self.stream.read(size) if FIXUP_DURING_SEND and self.bytesRead == 0: data = send.replaceIDs( data, self.diff.toUUID, self.diff.toGen, self.diff.fromUUID, self.diff.fromGen, ) self.bytesRead += len(data) if self.progress is not None: self.progress.update(self.bytesRead) return data def seek(self, offset, whence): self.stream.seek(offset, offset, whence) if whence == io.SEEK_SET: self.bytesRead = offset elif whence == io.SEEK_CUR: pass elif whence == io.SEEK_END: self.bytesRead = None
class _Writer(io.RawIOBase): """ Context Manager to write a snapshot. """ def __init__(self, process, stream, path, diff, showProgress): self.process = process self.stream = stream self.path = path self.diff = diff self.bytesWritten = None self.progress = DisplayProgress(diff.size) if showProgress else None def __enter__(self): self.bytesWritten = 0 if self.progress is not None: self.progress.open() return self def __exit__(self, exceptionType, exception, trace): self.stream.close() if self.progress is not None: self.progress.close() if self.process is None: return logger.debug("Waiting for receive process to finish...") self.process.wait() if exception is None and self.process.returncode == 0: # Fixup with SET_RECEIVED_SUBVOL if FIXUP_AFTER_RECEIVE: received = btrfs.SnapShot(self.path) received.SET_RECEIVED_SUBVOL( uuid=self.diff.toUUID, stransid=self.diff.toGen, ) return if self.process.returncode != 0: logger.error("btrfs receive errors") for line in self.process.stderr: sys.stderr.write(line) if os.path.exists(self.path): # This tries to mark partial (failed) transfers. partial = self.path + ".part" if os.path.exists(partial): partial = self.path + "_" + datetime.datetime.now().isoformat( ) + ".part" os.rename(self.path, partial) logger.debug("Renamed %s to %s", self.path, partial) if exception is None: raise Exception("receive %s returned error %d." % ( self.path, self.process.returncode, )) def write(self, data): # If it's the first big chunk (header) # Tweak the volume information to match what we expect. if FIXUP_DURING_RECEIVE and self.bytesWritten == 0: data = send.replaceIDs( data, self.diff.toUUID, self.diff.toGen, self.diff.fromUUID, self.diff.fromGen, ) self.stream.write(data) self.bytesWritten += len(data) if self.progress is not None: self.progress.update(self.bytesWritten)
class _Writer(io.RawIOBase): """ Context Manager to write a snapshot. """ def __init__(self, process, stream, path, diff, showProgress): self.process = process self.stream = stream self.path = path self.diff = diff self.bytesWritten = None self.progress = DisplayProgress(diff.size) if showProgress else None def __enter__(self): self.bytesWritten = 0 if self.progress is not None: self.progress.open() return self def __exit__(self, exceptionType, exception, trace): self.stream.close() if self.progress is not None: self.progress.close() if self.process is None: return logger.debug("Waiting for receive process to finish...") self.process.wait() if exception is None and self.process.returncode == 0: # Fixup with SET_RECEIVED_SUBVOL if FIXUP_AFTER_RECEIVE: received = btrfs.SnapShot(self.path) received.SET_RECEIVED_SUBVOL( uuid=self.diff.toUUID, stransid=self.diff.toGen, ) return if self.process.returncode != 0: logger.error("btrfs receive errors") for line in self.process.stderr: sys.stderr.write(line) if os.path.exists(self.path): # This tries to mark partial (failed) transfers. partial = self.path + ".part" if os.path.exists(partial): partial = self.path + "_" + datetime.datetime.now().isoformat() + ".part" os.rename(self.path, partial) logger.debug("Renamed %s to %s", self.path, partial) if exception is None: raise Exception( "receive %s returned error %d." % (self.path, self.process.returncode, ) ) def write(self, data): # If it's the first big chunk (header) # Tweak the volume information to match what we expect. if FIXUP_DURING_RECEIVE and self.bytesWritten == 0: data = send.replaceIDs( data, self.diff.toUUID, self.diff.toGen, self.diff.fromUUID, self.diff.fromGen, ) self.stream.write(data) self.bytesWritten += len(data) if self.progress is not None: self.progress.update(self.bytesWritten)