1# Copyright 2002 Ben Escoto 2# 3# This file is part of rdiff-backup. 4# 5# rdiff-backup is free software; you can redistribute it and/or modify 6# under the terms of the GNU General Public License as published by the 7# Free Software Foundation; either version 2 of the License, or (at your 8# option) any later version. 9# 10# rdiff-backup is distributed in the hope that it will be useful, but 11# WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13# General Public License for more details. 14# 15# You should have received a copy of the GNU General Public License 16# along with rdiff-backup; if not, write to the Free Software 17# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 18# 02110-1301, USA 19"""Hold a variety of constants usually set at initialization.""" 20 21import re 22import os 23from . import log 24 25# The current version of rdiff-backup 26# Get it from package info or fall back to DEV version. 27try: 28 import pkg_resources 29 version = pkg_resources.get_distribution("rdiff-backup").version 30except BaseException: 31 version = "DEV" 32 33# If this is set, use this value in seconds as the current time 34# instead of reading it from the clock. 35current_time = None 36 37# This determines how many bytes to read at a time when copying 38blocksize = 131072 39 40# This is used by the BufferedRead class to determine how many 41# bytes to request from the underlying file per read(). Larger 42# values may save on connection overhead and latency. 43conn_bufsize = 393216 44 45# This is used in the CacheCollatedPostProcess and MiscIterToFile 46# classes. The number represents the number of rpaths which may be 47# stuck in buffers when moving over a remote connection. 48pipeline_max_length = 500 49 50# True if script is running as a server 51server = None 52 53# uid and gid of the owner of the rdiff-backup process. This can 54# vary depending on the connection. 55try: 56 process_uid = os.getuid() 57 process_gid = os.getgid() 58 process_groups = [process_gid] + os.getgroups() 59except AttributeError: 60 process_uid = 0 61 process_gid = 0 62 process_groups = [0] 63 64# If true, when copying attributes, also change target's uid/gid 65change_ownership = None 66 67# If true, change the permissions of unwriteable mirror files 68# (such as directories) so that they can be written, and then 69# change them back. This defaults to 1 just in case the process 70# is not running as root (root doesn't need to change 71# permissions). 72change_mirror_perms = (process_uid != 0) 73 74# If true, try to reset the atimes of the source partition. 75preserve_atime = None 76 77# The following three attributes represent whether extended attributes 78# are supported. If eas_active is true, then the current session 79# supports them. If eas_write is true, then the extended attributes 80# should also be written to the destination side. Finally, eas_conn 81# is relative to the current connection, and should be true iff that 82# particular connection supports extended attributes. 83eas_active = None 84eas_write = None 85eas_conn = None 86 87# The following settings are like the extended attribute settings, but 88# apply to access control lists instead. 89acls_active = None 90acls_write = None 91acls_conn = None 92 93# Like the above, but applies to support of Windows 94# access control lists. 95win_acls_active = None 96win_acls_write = None 97win_acls_conn = None 98 99# Like above two setting groups, but applies to support of Mac OS X 100# style resource forks. 101resource_forks_active = None 102resource_forks_write = None 103resource_forks_conn = None 104 105# Like the above, but applies to MacOS Carbon Finder creator/type info. 106# As of 1.0.2 this has defaulted to off because of bugs 107carbonfile_active = None 108carbonfile_write = None 109carbonfile_conn = None 110 111# This will be set as soon as the LocalConnection class loads 112local_connection = None 113 114# All connections should be added to the following list, so 115# further global changes can be propagated to the remote systems. 116# The first element should be Globals.local_connection. For a 117# server, the second is the connection to the client. 118connections = [] 119 120# Each process should have a connection number unique to the 121# session. The client has connection number 0. 122connection_number = 0 123 124# Dictionary pairing connection numbers with connections. Set in 125# SetConnections for all connections. 126connection_dict = {} 127 128# True if the script is the end that reads the source directory 129# for backups. It is true for purely local sessions. 130isbackup_reader = None 131 132# Connection of the real backup reader (for which isbackup_reader 133# is true) 134backup_reader = None 135 136# True if the script is the end that writes to the increment and 137# mirror directories. True for purely local sessions. 138isbackup_writer = None 139 140# Connection of the backup writer 141backup_writer = None 142 143# Connection of the client 144client_conn = None 145 146# When backing up, issource should be true on the reader and isdest on 147# the writer. When restoring, issource should be true on the mirror 148# and isdest should be true on the target. 149issource = None 150isdest = None 151 152# This list is used by the set function below. When a new 153# connection is created with init_connection, its Globals class 154# will match this one for all the variables mentioned in this 155# list. 156changed_settings = [] 157 158# The RPath or QuotedRPath of the rdiff-backup-data directory. 159rbdir = None 160 161# chars_to_quote is a string whose characters should be quoted. It 162# should be true if certain characters in filenames on the source side 163# should be escaped (see FilenameMapping for more info). 164chars_to_quote = None 165quoting_char = b';' 166 167# evaluate if DOS device names (AUX, PRN, CON, NUL, COM, LPT) should be quoted 168# or spaces at the end of file and directory names. 169# The default is based on the operating system type (nt or posix). 170escape_dos_devices = os.name == 'nt' 171escape_trailing_spaces = os.name == 'nt' 172 173# If true, the timestamps use the following format: "2008-09-01T04-49-04-07-00" 174# (instead of "2008-09-01T04:49:04-07:00"). This creates timestamps which 175# don't need to be escaped on Windows. 176use_compatible_timestamps = 0 177 178# Normally there shouldn't be any case of duplicate timestamp but it seems 179# we had the issue at some point in time, hence we need the flag to allow 180# users to clean up their repository. The default is to abort on such cases. 181 182allow_duplicate_timestamps = False 183 184# If true, emit output intended to be easily readable by a 185# computer. False means output is intended for humans. 186parsable_output = None 187 188# If true, then hardlinks will be preserved to mirror and recorded 189# in the increments directory. There is also a difference here 190# between None and 0. When restoring, None or 1 means to preserve 191# hardlinks iff can find a hardlink dictionary. 0 means ignore 192# hardlink information regardless. 193preserve_hardlinks = 1 194 195# If this is false, then rdiff-backup will not compress any 196# increments. Default is to compress based on regexp below. 197compression = 1 198 199# Increments based on files whose names match this 200# case-insensitive regular expression won't be compressed (applies 201# to .snapshots and .diffs). The second below will be the 202# compiled version of the first. 203no_compression_regexp_string = ( 204 b"(?i).*\\.(gz|z|bz|bz2|tgz|zip|zst|rpm|deb|" 205 b"jpg|jpeg|gif|png|jp2|mp3|mp4|ogg|ogv|oga|ogm|avi|wmv|mpeg|mpg|rm|mov|mkv|flac|shn|pgp|" 206 b"gpg|rz|lz4|lzh|lzo|zoo|lharc|rar|arj|asc|vob|mdf)$") 207no_compression_regexp = None 208 209# If true, filelists and directory statistics will be split on 210# nulls instead of newlines. 211null_separator = None 212 213# Determines whether or not ssh will be run with the -C switch 214ssh_compression = 1 215 216# If true, print statistics after successful backup 217print_statistics = None 218 219# Controls whether file_statistics file is written in 220# rdiff-backup-data dir. These can sometimes take up a lot of space. 221file_statistics = 1 222 223# On the writer connection, the following will be set to the mirror 224# Select iterator. 225select_mirror = None 226 227# On the backup writer connection, holds the root incrementing branch 228# object. Access is provided to increment error counts. 229ITRB = None 230 231# security_level has 4 values and controls which requests from remote 232# systems will be honored. "all" means anything goes. "read-only" 233# means that the requests must not write to disk. "update-only" means 234# that requests shouldn't destructively update the disk (but normal 235# incremental updates are OK). "minimal" means only listen to a few 236# basic requests. 237security_level = "all" 238 239# If this is set, it indicates that the remote connection should only 240# deal with paths inside of restrict_path. 241restrict_path = None 242 243# If set, a file will be marked as changed if its inode changes. See 244# the man page under --no-compare-inode for more information. 245compare_inode = 1 246 247# If set, directories can be fsync'd just like normal files, to 248# guarantee that any changes have been comitted to disk. 249fsync_directories = None 250 251# If set, exit with error instead of dropping ACLs or ACL entries. 252never_drop_acls = None 253 254# Apply this mask to permissions before chmoding. (Set to 0777 to 255# prevent highbit permissions on systems which don't support them.) 256permission_mask = 0o7777 257 258# If true, symlinks permissions are affected by the process umask, and 259# we should change the umask when creating them in order to preserve 260# the original permissions 261symlink_perms = None 262 263# If set, the path that should be used instead of the default Python 264# tempfile.tempdir value on remote connections 265remote_tempdir = None 266 267# Fsync everything by default. Use --no-fsync only if you really know what you are doing 268# Not having the data written to disk may render your backup unusable in case of FS failure. 269# Using --no-fsync disables only fsync of files during backup and sync() system call upon backup finish 270# and pre-regress 271do_fsync = True 272 273 274def get(name): 275 """Return the value of something in this module""" 276 return globals()[name] 277 278 279def is_not_None(name): 280 """Returns true if value is not None""" 281 return globals()[name] is not None 282 283 284def set(name, val): 285 """Set the value of something in this module 286 287 Use this instead of writing the values directly if the setting 288 matters to remote sides. This function updates the 289 changed_settings list, so other connections know to copy the 290 changes. 291 292 """ 293 changed_settings.append(name) 294 globals()[name] = val 295 296 297def set_local(name, val): 298 """Like set above, but only set current connection""" 299 globals()[name] = val 300 301 302def set_integer(name, val): 303 """Like set, but make sure val is an integer""" 304 try: 305 intval = int(val) 306 except ValueError: 307 log.Log.FatalError("Variable %s must be set to an integer -\n" 308 "received %s instead." % (name, val)) 309 set(name, intval) 310 311 312def set_float(name, val, min=None, max=None, inclusive=1): 313 """Like set, but make sure val is float within given bounds""" 314 315 def error(): 316 s = "Variable %s must be set to a float" % (name, ) 317 if min is not None and max is not None: 318 s += " between %s and %s " % (min, max) 319 if inclusive: 320 s += "inclusive" 321 else: 322 s += "not inclusive" 323 elif min is not None or max is not None: 324 if inclusive: 325 inclusive_string = "or equal to " 326 else: 327 inclusive_string = "" 328 if min is not None: 329 s += " greater than %s%s" % (inclusive_string, min) 330 else: 331 s += " less than %s%s" % (inclusive_string, max) 332 log.Log.FatalError(s) 333 334 try: 335 f = float(val) 336 except ValueError: 337 error() 338 if min is not None: 339 if inclusive and f < min: 340 error() 341 elif not inclusive and f <= min: 342 error() 343 if max is not None: 344 if inclusive and f > max: 345 error() 346 elif not inclusive and f >= max: 347 error() 348 set(name, f) 349 350 351def get_dict_val(name, key): 352 """Return val from dictionary in this class""" 353 return globals()[name][key] 354 355 356def set_dict_val(name, key, val): 357 """Set value for dictionary in this class""" 358 globals()[name][key] = val 359 360 361def postset_regexp(name, re_string, flags=None): 362 """Compile re_string on all existing connections, set to name""" 363 for conn in connections: 364 conn.Globals.postset_regexp_local(name, re_string, flags) 365 366 367def postset_regexp_local(name, re_string, flags): 368 """Set name to compiled re_string locally""" 369 if flags: 370 globals()[name] = re.compile(re_string, flags) 371 else: 372 globals()[name] = re.compile(re_string) 373