Beispiel #1
0
 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
Beispiel #2
0
 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
Beispiel #3
0
    def send(self, diff):
        """ Return Context Manager for a file-like (stream) object to send a diff. """
        if Store.skipDryRun(logger, self.dryrun)("send %s", diff):
            return None

        (diffTo, diffFrom) = self.toArg.diff(diff)
        self._client.send(diffTo, diffFrom)

        progress = DisplayProgress(diff.size) if self.showProgress is True else None
        return _SSHStream(self._client, progress)
Beispiel #4
0
    def receive(self, diff, paths):
        """ Return Context Manager for a file-like (stream) object to store a diff. """
        path = self.selectReceivePath(paths)
        path = self._relativePath(path)

        if Store.skipDryRun(logger, self.dryrun)("receive to %s", path):
            return None

        (diffTo, diffFrom) = self.toArg.diff(diff)
        self._client.receive(path, diffTo, diffFrom)

        progress = DisplayProgress(diff.size) if self.showProgress is True else None
        return _SSHStream(self._client, progress)
Beispiel #5
0
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
Beispiel #6
0
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)
Beispiel #7
0
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
Beispiel #8
0
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)