예제 #1
0
    def _writer_helper(self, typestr, time, meta_class, force=False):
        """
        Returns a writer class or None if the meta class isn't active.

        For testing purposes, the force option allows to skip the activity
        validation.
        """
        if time is None:
            timestr = Time.getcurtimestr()
        else:
            timestr = Time.timetobytes(time)
        triple = map(os.fsencode, (meta_class.get_prefix(), timestr, typestr))
        filename = b'.'.join(triple)
        rp = self.data_dir.append(filename)
        assert not rp.lstat(), "File '{rp}' shouldn't exist.".format(rp=rp)
        assert rp.isincfile(), (
            "Path '{irp}' must be an increment file.".format(irp=rp))
        if meta_class.is_active() or force:
            # Before API 201, metafiles couldn't be compressed
            return meta_class(rp, 'w',
                              compress=(Globals.compression
                                        or Globals.get_api_version() < 201),
                              callback=self._add_incrp)
        else:
            return None
예제 #2
0
    def setup(self):
        # in setup we return as soon as we detect an issue to avoid changing
        # too much
        return_code = super().setup()
        if return_code != 0:
            return return_code

        return_code = self._set_no_compression_regexp()
        if return_code != 0:
            return return_code

        return_code = self.dir.setup()
        if return_code != 0:
            return return_code

        owners_map = {
            "users_map": self.values.user_mapping_file,
            "groups_map": self.values.group_mapping_file,
            "preserve_num_ids": self.values.preserve_numerical_ids
        }
        return_code = self.repo.setup(self.dir, owners_map=owners_map)
        if return_code != 0:
            return return_code

        # TODO validate how much of the following lines and methods
        # should go into the directory/repository modules
        if Globals.get_api_version() < 201:  # compat200
            SetConnections.BackupInitConnections(self.dir.base_dir.conn,
                                                 self.repo.base_dir.conn)
            self.repo.base_dir.conn.fs_abilities.backup_set_globals(
                self.dir.base_dir, self.values.force)
            self.repo.setup_quoting()

        previous_time = self.repo.get_mirror_time()
        if previous_time >= Time.getcurtime():
            log.Log("The last backup is not in the past. Aborting.", log.ERROR)
            return 1
        if log.Log.verbosity > 0:
            try:  # the target repository must be writable
                log.Log.open_logfile(self.repo.data_dir.append("backup.log"))
            except (log.LoggerError, Security.Violation) as exc:
                log.Log("Unable to open logfile due to '{ex}'".format(ex=exc),
                        log.ERROR)
                return 1
        log.ErrorLog.open(Time.getcurtimestr(),
                          compress=self.values.compression)

        (select_opts, select_data) = selection.get_prepared_selections(
            self.values.selections)
        self.dir.set_select(select_opts, select_data)
        self._warn_if_infinite_recursion(self.dir.base_dir, self.repo.base_dir)

        return 0
예제 #3
0
    def _operate_backup(self, previous_time=None):
        """
        Execute the actual backup operation
        """
        log.Log(
            "Starting backup operation from source path {sp} to destination "
            "path {dp}".format(sp=self.dir.base_dir, dp=self.repo.base_dir),
            log.NOTE)

        if previous_time:
            self.repo.touch_current_mirror(Time.getcurtimestr())

        source_rpiter = self.dir.get_select()
        dest_sigiter = self.repo.get_sigs(source_rpiter, previous_time)
        source_diffiter = self.dir.get_diffs(dest_sigiter)
        self.repo.patch_or_increment(source_diffiter, previous_time)

        if previous_time:
            self.repo.remove_current_mirror()
        else:
            self.repo.touch_current_mirror(Time.getcurtimestr())

        self.repo.close_statistics(time.time())
예제 #4
0
def backup_touch_curmirror_local(rpin, rpout):
    """
    Make a file like current_mirror.time.data to record time

    When doing an incremental backup, this should happen before any
    other writes, and the file should be removed after all writes.
    That way we can tell whether the previous session aborted if there
    are two current_mirror files.

    When doing the initial full backup, the file can be created after
    everything else is in place.
    """
    mirrorrp = Globals.rbdir.append(b'.'.join(
        map(os.fsencode, (b"current_mirror", Time.getcurtimestr(), "data"))))
    log.Log("Writing mirror marker {mm}".format(mm=mirrorrp), log.DEBUG)
    try:
        pid = os.getpid()
    except BaseException:
        pid = "NA"
    mirrorrp.write_string("PID %s\n" % (pid, ))
    mirrorrp.fsync_with_dir()