예제 #1
0
    def set_special_escapes(self, rbdir):
        """Set escape_dos_devices and escape_trailing_spaces from
        rdiff-backup-data dir, just like chars_to_quote"""
        se_rp = rbdir.append("special_escapes")
        if se_rp.lstat():
            se = se_rp.get_string().split("\n")
            actual_edd = ("escape_dos_devices" in se)
            actual_ets = ("escape_trailing_spaces" in se)
        else:
            log.Log(
                "The special escapes file '{ef}' was not found, "
                "will assume need to escape DOS devices and trailing "
                "spaces based on file systems".format(ef=se_rp), log.WARNING)
            if getattr(self, "src_fsa", None) is not None:
                actual_edd = (self.src_fsa.escape_dos_devices
                              and not self.dest_fsa.escape_dos_devices)
                actual_ets = (self.src_fsa.escape_trailing_spaces
                              and not self.dest_fsa.escape_trailing_spaces)
            else:
                # Single filesystem operation
                actual_edd = self.dest_fsa.escape_dos_devices
                actual_ets = self.dest_fsa.escape_trailing_spaces

        Globals.set_all('escape_dos_devices', actual_edd)
        log.Log("Backup: escape_dos_devices = {dd}".format(dd=actual_edd),
                log.INFO)

        Globals.set_all('escape_trailing_spaces', actual_ets)
        log.Log("Backup: escape_trailing_spaces = {ts}".format(ts=actual_ets),
                log.INFO)
예제 #2
0
    def set_special_escapes(self, repo):
        """
        Set escape_dos_devices and escape_trailing_spaces from
        rdiff-backup-data dir, just like chars_to_quote
        """
        se = repo.get_special_escapes()
        if se is not None:
            actual_edd = ("escape_dos_devices" in se)
            actual_ets = ("escape_trailing_spaces" in se)
        else:
            if getattr(self, "src_fsa", None) is not None:
                actual_edd = (self.src_fsa.escape_dos_devices
                              and not self.dest_fsa.escape_dos_devices)
                actual_ets = (self.src_fsa.escape_trailing_spaces
                              and not self.dest_fsa.escape_trailing_spaces)
            else:
                # Single filesystem operation
                actual_edd = self.dest_fsa.escape_dos_devices
                actual_ets = self.dest_fsa.escape_trailing_spaces

        Globals.set_all('escape_dos_devices', actual_edd)
        log.Log("Backup: escape_dos_devices = {dd}".format(dd=actual_edd),
                log.INFO)

        Globals.set_all('escape_trailing_spaces', actual_ets)
        log.Log("Backup: escape_trailing_spaces = {ts}".format(ts=actual_ets),
                log.INFO)
예제 #3
0
    def setup_quoting(self):
        """
        Set QuotedRPath versions of important RPaths if chars_to_quote is set.

        Return True if quoting needed to be done, False else.
        """
        # FIXME the problem is that the chars_to_quote can come from the command
        # line but can also be a value coming from the repository itself,
        # set globally by the fs_abilities.xxx_set_globals functions.
        if not Globals.chars_to_quote:
            return False

        if Globals.get_api_version() < 201:  # compat200
            FilenameMapping.set_init_quote_vals()
            self.base_dir = FilenameMapping.get_quotedrpath(self.base_dir)
            self.data_dir = FilenameMapping.get_quotedrpath(self.data_dir)
            self.incs_dir = FilenameMapping.get_quotedrpath(self.incs_dir)
        else:
            self.base_dir = map_filenames.get_quotedrpath(self.base_dir)
            self.data_dir = map_filenames.get_quotedrpath(self.data_dir)
            self.incs_dir = map_filenames.get_quotedrpath(self.incs_dir)

        Globals.set_all('rbdir', self.data_dir)  # compat200

        return True
예제 #4
0
    def setup(self, src_dir=None, owners_map=None):
        if self.must_be_writable and not self._create():
            return 1

        if (self.can_be_sub_path
                and self.base_dir.conn is Globals.local_connection):
            Security.reset_restrict_path(self.base_dir)

        Globals.set_all('rbdir', self.data_dir)  # compat200

        if Globals.get_api_version() >= 201:  # compat200
            if self.base_dir.conn is Globals.local_connection:
                # should be more efficient than going through the connection
                from rdiffbackup.locations import _repo_shadow
                self._shadow = _repo_shadow.RepoShadow
            else:
                self._shadow = self.base_dir.conn._repo_shadow.RepoShadow
            if self.must_be_writable:
                self.fs_abilities = self._shadow.get_fs_abilities_readwrite(
                    self.base_dir)
            else:
                self.fs_abilities = self._shadow.get_fs_abilities_readonly(
                    self.base_dir)
            if not self.fs_abilities:
                return 1  # something was wrong
            else:
                log.Log(
                    "--- Repository file system capabilities ---\n" +
                    str(self.fs_abilities), log.INFO)

            if src_dir is None:
                self.remote_transfer = None  # just in case
                ret_code = fs_abilities.SingleRepoSetGlobals(self)()
                if ret_code != 0:
                    return ret_code
            else:
                # FIXME this shouldn't be necessary, and the setting of variable
                # across the connection should happen through the shadow
                Globals.set_all("backup_writer", self.base_dir.conn)
                self.base_dir.conn.Globals.set_local("isbackup_writer", True)
                # this is the new way, more dedicated but not sufficient yet
                self.remote_transfer = (src_dir.base_dir.conn
                                        is not self.base_dir.conn)
                ret_code = fs_abilities.Dir2RepoSetGlobals(src_dir, self)()
                if ret_code != 0:
                    return ret_code
            self.setup_quoting()
            self.setup_paths()

        if owners_map is not None:
            ret_code = self.init_owners_mapping(**owners_map)
            if ret_code != 0:
                return ret_code

        return 0  # all is good
예제 #5
0
def get_readonly_fsa(desc_string, rp):
    """Return an fsa with given description_string

    Will be initialized read_only with given RPath rp.  We separate
    this out into a separate function so the request can be vetted by
    the security module.

    """
    if os.name == "nt":
        log.Log("Hardlinks disabled by default on Windows", log.INFO)
        Globals.set_all('preserve_hardlinks', 0)
    return FSAbilities(desc_string, rp, read_only=True)
예제 #6
0
def set_current_time(reftime=None):
    """
    Sets the current time in curtime and curtimestr on all systems
    """
    if reftime is None:
        reftime = time.time()
    if Globals.get_api_version() < 201:  # compat200
        for conn in Globals.connections:
            conn.Time.setcurtime_local(int(reftime))
    else:
        Globals.set_all("current_time", reftime)
        Globals.set_all("current_time_string", timetostring(reftime))
예제 #7
0
    def set_chars_to_quote(self, rbdir):
        """Set chars_to_quote from rdiff-backup-data dir"""
        if Globals.chars_to_quote is not None:
            return  # already overridden

        ctq_rp = rbdir.append(b"chars_to_quote")
        if ctq_rp.lstat():
            Globals.set_all("chars_to_quote", ctq_rp.get_bytes())
        else:
            log.Log(
                "chars_to_quote file '{qf}' not found, assuming no quoting "
                "required in backup repository".format(qf=ctq_rp), log.WARNING)
            Globals.set_all("chars_to_quote", b"")
예제 #8
0
    def set_chars_to_quote(self, rbdir):
        """Set chars_to_quote setting for backup session

        Unlike most other options, the chars_to_quote setting also
        depends on the current settings in the rdiff-backup-data
        directory, not just the current fs features.

        """
        ctq = self._compare_ctq_file(rbdir, self._get_ctq_from_fsas())

        Globals.set_all('chars_to_quote', ctq)
        if Globals.chars_to_quote:
            FilenameMapping.set_init_quote_vals()
예제 #9
0
    def set_special_escapes(self, repo):
        """
        Escaping DOS devices and trailing periods/spaces works like
        regular filename escaping.

        If only the destination requires it, then we do it.
        Otherwise, it is not necessary, since the files
        couldn't have been created in the first place. We also record
        whether we have done it in order to handle the case where a
        volume which was escaped is later restored by an OS that does
        not require it.
        """

        suggested_edd = (self.dest_fsa.escape_dos_devices
                         and not self.src_fsa.escape_dos_devices)
        suggested_ets = (self.dest_fsa.escape_trailing_spaces
                         and not self.src_fsa.escape_trailing_spaces)

        se = repo.get_special_escapes()
        if se is None:
            actual_edd, actual_ets = suggested_edd, suggested_ets
            se = set()
            if actual_edd:
                se.add("escape_dos_devices")
            if actual_ets:
                se.add("escape_trailing_spaces")
            repo.set_special_escapes(se)
        else:
            actual_edd = ("escape_dos_devices" in se)
            actual_ets = ("escape_trailing_spaces" in se)

            if actual_edd != suggested_edd and not suggested_edd:
                log.Log(
                    "System no longer needs DOS devices to be escaped, "
                    "but we will retain for backwards compatibility",
                    log.WARNING)
            if actual_ets != suggested_ets and not suggested_ets:
                log.Log(
                    "System no longer needs trailing spaces or periods to be "
                    "escaped, but we will retain for backwards compatibility",
                    log.WARNING)

        Globals.set_all('escape_dos_devices', actual_edd)
        log.Log("Backup: escape_dos_devices = {dd}".format(dd=actual_edd),
                log.INFO)

        Globals.set_all('escape_trailing_spaces', actual_ets)
        log.Log("Backup: escape_trailing_spaces = {ts}".format(ts=actual_ets),
                log.INFO)
예제 #10
0
    def _set_no_compression_regexp(self):
        """
        Sets the no_compression_regexp setting globally
        """
        try:  # compat200
            no_compression_string = os.fsencode(
                Globals.no_compression_regexp_string)
        except AttributeError:
            no_compression_string = os.fsencode(
                self.values.not_compressed_regexp)
        try:
            no_compression_regexp = re.compile(no_compression_string)
        except re.error:
            log.Log("No compression regular expression '{ex}' doesn't "
                    "compile".format(ex=no_compression_string), log.ERROR)
            return Globals.RET_CODE_ERR

        Globals.set_all('no_compression_regexp', no_compression_regexp)

        return Globals.RET_CODE_OK
예제 #11
0
    def setup(self):
        """
        Prepare the execution of the action.

        Return 0 if everything looked good, else an error code.
        """
        if self.values.tempdir:
            # At least until Python 3.10, the module tempfile doesn't work
            # properly,
            # especially under Windows, if tempdir is stored as bytes.
            # See https://github.com/python/cpython/pull/20442
            tempfile.tempdir = self.values.tempdir
        # Set default change ownership flag, umask, relay regexps
        os.umask(0o77)
        Globals.set_all("client_conn", Globals.local_connection)
        for conn in Globals.connections:
            conn.robust.install_signal_handlers()
            conn.Hardlink.initialize_dictionaries()  # compat200

        return 0
예제 #12
0
    def _update_triple(self, src_support, dest_support, attr_triple):
        """
        Update global settings for feature based on fsa results

        This is slightly different from Dir2RepoSetGlobals._update_triple
        because (using the mirror_metadata file) rpaths from the
        source may have more information than the file system
        supports.
        """
        active_attr, write_attr, conn_attr = attr_triple
        if Globals.get(active_attr) == 0:
            return  # don't override 0
        for attr in attr_triple:
            Globals.set_all(attr, None)
        if not dest_support:
            return  # if dest doesn't support, do nothing
        Globals.set_all(active_attr, 1)
        self.out_conn.Globals.set_local(conn_attr, 1)
        self.out_conn.Globals.set_local(write_attr, 1)
        if src_support:
            self.in_conn.Globals.set_local(conn_attr, 1)
예제 #13
0
 def _update_triple(self, fsa_support, attr_triple):
     """Update global vars from single fsa test"""
     active_attr, write_attr, conn_attr = attr_triple
     if Globals.get(active_attr) == 0:
         return  # don't override 0
     for attr in attr_triple:
         Globals.set_all(attr, None)
     if not fsa_support:
         return
     Globals.set_all(active_attr, 1)
     Globals.set_all(write_attr, 1)
     self.conn.Globals.set_local(conn_attr, 1)
예제 #14
0
    def set_chars_to_quote(self, repo):
        """
        Set chars_to_quote from rdiff-backup-data dir
        """
        if Globals.chars_to_quote is not None:
            return  # already overridden

        ctq = repo.get_chars_to_quote()
        if ctq is not None:
            regexp, unregexp = map_filenames.get_quoting_regexps(
                ctq, Globals.quoting_char)
            Globals.set_all("chars_to_quote", ctq)
            Globals.set_all('chars_to_quote_regexp', regexp)
            Globals.set_all('chars_to_quote_unregexp', unregexp)
        else:
            log.Log(
                "chars_to_quote config not found, assuming no quoting "
                "required in backup repository".format(), log.WARNING)
            Globals.set_all("chars_to_quote", b"")
예제 #15
0
 def _update_triple(self, src_support, dest_support, attr_triple):
     """Many of the settings have a common form we can handle here"""
     active_attr, write_attr, conn_attr = attr_triple
     if Globals.get(active_attr) == 0:
         return  # don't override 0
     for attr in attr_triple:
         Globals.set_all(attr, None)
     if not src_support:
         return  # if source doesn't support, nothing
     Globals.set_all(active_attr, 1)
     self.in_conn.Globals.set_local(conn_attr, 1)
     if dest_support:
         Globals.set_all(write_attr, 1)
         self.out_conn.Globals.set_local(conn_attr, 1)
예제 #16
0
    def set_chars_to_quote(self, repo):
        """
        Set chars_to_quote setting for backup session

        Unlike most other options, the chars_to_quote setting also
        depends on the current settings in the rdiff-backup-data
        directory, not just the current fs features.
        """
        ctq = self._compare_ctq_file(repo, self._get_ctq_from_fsas())
        regexp, unregexp = map_filenames.get_quoting_regexps(
            ctq, Globals.quoting_char)

        Globals.set_all('chars_to_quote', ctq)
        Globals.set_all('chars_to_quote_regexp', regexp)
        Globals.set_all('chars_to_quote_unregexp', unregexp)
예제 #17
0
 def setUp(self):
     """Start server"""
     Globals.change_source_perms = 1
     Globals.set_all('checkpoint_interval', 3)
     user_group.init_user_mapping()
     user_group.init_group_mapping()
예제 #18
0
def BackupInitConnections(reading_conn, writing_conn):  # compat200
    """Backup specific connection initialization"""
    reading_conn.Globals.set_local("isbackup_reader", True)
    writing_conn.Globals.set_local("isbackup_writer", True)
    Globals.set_all("backup_reader", reading_conn)
    Globals.set_all("backup_writer", writing_conn)
예제 #19
0
def _reset_connections(src_rp, dest_rp):
    """Reset some global connection information"""
    Security._security_level = "override"
    Globals.isbackup_reader = Globals.isbackup_writer = None
    Globals.set_all('rbdir', None)
예제 #20
0
 def set_compatible_timestamps(self):
     if Globals.chars_to_quote.find(b":") > -1:
         Globals.set_all('use_compatible_timestamps', 1)
         # Update the current time string to new timestamp format
         Time.set_current_time(Time.getcurtime())
         log.Log("Enabled use_compatible_timestamps", log.INFO)
예제 #21
0
 def set_symlink_perms(self):
     Globals.set_all('symlink_perms', self.dest_fsa.symlink_perms)
예제 #22
0
 def set_high_perms(self):
     if not self.dest_fsa.high_perms:
         Globals.set_all('permission_mask', 0o777)
예제 #23
0
 def set_change_ownership(self):
     Globals.set_all('change_ownership', self.dest_fsa.ownership)
예제 #24
0
 def set_fsync_directories(self):
     Globals.set_all('fsync_directories', self.dest_fsa.fsync_dirs)
예제 #25
0
 def set_hardlinks(self):
     if Globals.preserve_hardlinks != 0:
         Globals.set_all('preserve_hardlinks', self.dest_fsa.hardlinks)
예제 #26
0
    def setup(self, src_dir=None, owners_map=None):
        if self.must_be_writable and not self._create():
            return Globals.RET_CODE_ERR

        if (self.can_be_sub_path
                and self.base_dir.conn is Globals.local_connection):
            Security.reset_restrict_path(self.base_dir)

        Globals.set_all('rbdir', self.data_dir)  # compat200

        if Globals.get_api_version() >= 201:  # compat200
            if self.base_dir.conn is Globals.local_connection:
                # should be more efficient than going through the connection
                from rdiffbackup.locations import _repo_shadow
                self._shadow = _repo_shadow.RepoShadow
            else:
                self._shadow = self.base_dir.conn._repo_shadow.RepoShadow

            if not self.lock():
                if self.force:
                    log.Log(
                        "Repository is locked by file {lf}, another "
                        "action is probably on-going. Enforcing anyway "
                        "at your own risk".format(lf=self.lockfile),
                        log.WARNING)
                else:
                    log.Log(
                        "Repository is locked by file {lf}, another "
                        "action is probably on-going. Either wait, remove "
                        "the lock or use the --force option".format(
                            lf=self.lockfile), log.ERROR)
                    return Globals.RET_CODE_ERR

            if self.must_be_writable:
                self.fs_abilities = self._shadow.get_fs_abilities_readwrite(
                    self.base_dir)
            else:
                self.fs_abilities = self._shadow.get_fs_abilities_readonly(
                    self.base_dir)
            if not self.fs_abilities:
                return Globals.RET_CODE_ERR
            else:
                log.Log(
                    "--- Repository file system capabilities ---\n" +
                    str(self.fs_abilities), log.INFO)

            if src_dir is None:
                self.remote_transfer = None  # just in case
                ret_code = fs_abilities.SingleRepoSetGlobals(self)()
                if ret_code != 0:
                    return ret_code
            else:
                # FIXME this shouldn't be necessary, and the setting of variable
                # across the connection should happen through the shadow
                Globals.set_all("backup_writer", self.base_dir.conn)
                self.base_dir.conn.Globals.set_local("isbackup_writer", True)
                # this is the new way, more dedicated but not sufficient yet
                self.remote_transfer = (src_dir.base_dir.conn
                                        is not self.base_dir.conn)
                ret_code = fs_abilities.Dir2RepoSetGlobals(src_dir, self)()
                if ret_code != 0:
                    return ret_code
            self.setup_quoting()
            self.setup_paths()

        if owners_map is not None:
            ret_code = self.init_owners_mapping(**owners_map)
            if ret_code != 0:
                return ret_code

        return Globals.RET_CODE_OK