/[rdiff-backup]/rdiff-backup/rdiff_backup/fs_abilities.py
ViewVC logotype

Diff of /rdiff-backup/rdiff_backup/fs_abilities.py

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.18 by bescoto, Fri Oct 21 02:27:33 2005 UTC revision 1.19 by bescoto, Mon Oct 24 17:16:05 2005 UTC
# Line 28  FSAbilities object describing it. Line 28  FSAbilities object describing it.
28  """  """
29    
30  import errno, os  import errno, os
31  import Globals, log, TempFile, selection, robust  import Globals, log, TempFile, selection, robust, SetConnections, \
32               static, FilenameMapping
33    
34  class FSAbilities:  class FSAbilities:
35          """Store capabilities of given file system"""          """Store capabilities of given file system"""
36          chars_to_quote = None # Hold characters not allowable in file names          extended_filenames = None # True if filenames can handle ":" etc.
37          case_sensitive = None # True if "foobar" and "FoObAr" are different files          case_sensitive = None # True if "foobar" and "FoObAr" are different files
38          ownership = None # True if chown works on this filesystem          ownership = None # True if chown works on this filesystem
39          acls = None # True if access control lists supported          acls = None # True if access control lists supported
# Line 40  class FSAbilities: Line 41  class FSAbilities:
41          hardlinks = None # True if hard linking supported          hardlinks = None # True if hard linking supported
42          fsync_dirs = None # True if directories can be fsync'd          fsync_dirs = None # True if directories can be fsync'd
43          dir_inc_perms = None # True if regular files can have full permissions          dir_inc_perms = None # True if regular files can have full permissions
44          resource_forks = None # True if regular_file/..namedfork/rsrc holds resource fork          resource_forks = None # True if system supports resource forks
45          carbonfile = None # True if Mac Carbon file data is supported.          carbonfile = None # True if Mac Carbon file data is supported.
46          name = None # Short string, not used for any technical purpose          name = None # Short string, not used for any technical purpose
47          read_only = None # True if capabilities were determined non-destructively          read_only = None # True if capabilities were determined non-destructively
# Line 78  class FSAbilities: Line 79  class FSAbilities:
79                          else: return ('Detected abilities for %s file system' %                          else: return ('Detected abilities for %s file system' %
80                                                    (read_string,))                                                    (read_string,))
81    
                 def add_ctq_line():  
                         """Get line describing chars to quote"""  
                         ctq_str = (self.chars_to_quote is None and 'N/A'  
                                            or repr(self.chars_to_quote))  
                         addline('Characters needing quoting', ctq_str)  
   
82                  s.append(get_title_line())                  s.append(get_title_line())
83                  if not self.read_only:                  if not self.read_only:
                         add_ctq_line()  
84                          add_boolean_list([('Ownership changing', self.ownership),                          add_boolean_list([('Ownership changing', self.ownership),
85                                                            ('Hard linking', self.hardlinks),                                                            ('Hard linking', self.hardlinks),
86                                                            ('fsync() directories', self.fsync_dirs),                                                            ('fsync() directories', self.fsync_dirs),
87                                                            ('Directory inc permissions',                                                            ('Directory inc permissions',
88                                                             self.dir_inc_perms),                                                             self.dir_inc_perms),
89                                                            ('High-bit permissions', self.high_perms)])                                                            ('High-bit permissions', self.high_perms),
90                                                              ('Extended filenames', self.extended_filenames)])
91                  add_boolean_list([('Access control lists', self.acls),                  add_boolean_list([('Access control lists', self.acls),
92                                                    ('Extended attributes', self.eas),                                                    ('Extended attributes', self.eas),
93                                                    ('Case sensitivity', self.case_sensitive),                                                    ('Case sensitivity', self.case_sensitive),
# Line 122  class FSAbilities: Line 117  class FSAbilities:
117                  self.set_case_sensitive_readonly(rp)                  self.set_case_sensitive_readonly(rp)
118                  return self                  return self
119    
120          def init_readwrite(self, rbdir, use_ctq_file = 1,          def init_readwrite(self, rbdir):
                                            override_chars_to_quote = None):  
121                  """Set variables using fs tested at rp_base.  Run locally.                  """Set variables using fs tested at rp_base.  Run locally.
122    
123                  This method creates a temp directory in rp_base and writes to                  This method creates a temp directory in rp_base and writes to
124                  it in order to test various features.  Use on a file system                  it in order to test various features.  Use on a file system
125                  that will be written to.                  that will be written to.
126    
                 This sets self.chars_to_quote, self.ownership, self.acls,  
                 self.eas, self.hardlinks, and self.fsync_dirs.  
   
                 If user_ctq_file is true, try reading the "chars_to_quote"  
                 file in directory.  
   
127                  """                  """
128                  assert rbdir.conn is Globals.local_connection                  assert rbdir.conn is Globals.local_connection
129                  if not rbdir.isdir():                  if not rbdir.isdir():
# Line 143  class FSAbilities: Line 131  class FSAbilities:
131                          rbdir.mkdir()                          rbdir.mkdir()
132                  self.root_rp = rbdir                  self.root_rp = rbdir
133                  self.read_only = 0                  self.read_only = 0
   
134                  subdir = TempFile.new_in_dir(rbdir)                  subdir = TempFile.new_in_dir(rbdir)
135                  subdir.mkdir()                  subdir.mkdir()
136    
137                    self.set_extended_filenames(subdir)
138                    self.set_case_sensitive_readwrite(subdir)
139                  self.set_ownership(subdir)                  self.set_ownership(subdir)
140                  self.set_hardlinks(subdir)                  self.set_hardlinks(subdir)
141                  self.set_fsync_dirs(subdir)                  self.set_fsync_dirs(subdir)
# Line 155  class FSAbilities: Line 145  class FSAbilities:
145                  self.set_resource_fork_readwrite(subdir)                  self.set_resource_fork_readwrite(subdir)
146                  self.set_carbonfile()                  self.set_carbonfile()
147                  self.set_high_perms_readwrite(subdir)                  self.set_high_perms_readwrite(subdir)
148                  if override_chars_to_quote is None: self.set_chars_to_quote(subdir)  
                 else: self.chars_to_quote = override_chars_to_quote  
                 if use_ctq_file: self.compare_chars_to_quote(rbdir)  
149                  subdir.delete()                  subdir.delete()
150                  return self                  return self
151    
         def compare_chars_to_quote(self, rbdir):  
                 """Read chars_to_quote file, compare with current settings"""  
                 assert self.chars_to_quote is not None  
                 ctq_rp = rbdir.append("chars_to_quote")  
                 def write_new_chars():  
                         """Replace old chars_to_quote file with new value"""  
                         if ctq_rp.lstat(): ctq_rp.delete()  
                         fp = ctq_rp.open("wb")  
                         fp.write(self.chars_to_quote)  
                         assert not fp.close()  
   
                 if not ctq_rp.lstat(): write_new_chars()  
                 else:  
                         old_chars = ctq_rp.get_data()  
                         if old_chars != self.chars_to_quote:  
                                 if self.chars_to_quote == "":  
                                         log.Log("Warning: File system no longer needs quoting, "  
                                                         "but will retain for backwards compatibility.", 2)  
                                         self.chars_to_quote = old_chars  
                                 else: log.Log.FatalError("""New quoting requirements  
   
 This may be caused when you copy an rdiff-backup directory from a  
 normal file system on to a windows one that cannot support the same  
 characters.  If you want to risk it, remove the file  
 rdiff-backup-data/chars_to_quote.  
 """)  
   
152          def set_ownership(self, testdir):          def set_ownership(self, testdir):
153                  """Set self.ownership to true iff testdir's ownership can be changed"""                  """Set self.ownership to true iff testdir's ownership can be changed"""
154                  tmp_rp = testdir.append("foo")                  tmp_rp = testdir.append("foo")
# Line 196  rdiff-backup-data/chars_to_quote. Line 157  rdiff-backup-data/chars_to_quote.
157                  try:                  try:
158                          tmp_rp.chown(uid+1, gid+1) # just choose random uid/gid                          tmp_rp.chown(uid+1, gid+1) # just choose random uid/gid
159                          tmp_rp.chown(0, 0)                          tmp_rp.chown(0, 0)
160                  except (IOError, OSError), exc: self.ownership = 0                  except (IOError, OSError): self.ownership = 0
161                  else: self.ownership = 1                  else: self.ownership = 1
162                  tmp_rp.delete()                  tmp_rp.delete()
163    
# Line 209  rdiff-backup-data/chars_to_quote. Line 170  rdiff-backup-data/chars_to_quote.
170                          hl_dest.hardlink(hl_source.path)                          hl_dest.hardlink(hl_source.path)
171                          if hl_source.getinode() != hl_dest.getinode():                          if hl_source.getinode() != hl_dest.getinode():
172                                  raise IOError(errno.EOPNOTSUPP, "Hard links don't compare")                                  raise IOError(errno.EOPNOTSUPP, "Hard links don't compare")
173                  except (IOError, OSError), exc:                  except (IOError, OSError):
174                          log.Log("Warning: hard linking not supported by filesystem "                          log.Log("Warning: hard linking not supported by filesystem "
175                                          "at %s" % (self.root_rp.path,), 3)                                          "at %s" % (self.root_rp.path,), 3)
176                          self.hardlinks = 0                          self.hardlinks = 0
# Line 219  rdiff-backup-data/chars_to_quote. Line 180  rdiff-backup-data/chars_to_quote.
180                  """Set self.fsync_dirs if directories can be fsync'd"""                  """Set self.fsync_dirs if directories can be fsync'd"""
181                  assert testdir.conn is Globals.local_connection                  assert testdir.conn is Globals.local_connection
182                  try: testdir.fsync()                  try: testdir.fsync()
183                  except (IOError, OSError), exc:                  except (IOError, OSError):
184                          log.Log("Directories on file system at %s are not fsyncable.\n"                          log.Log("Directories on file system at %s are not fsyncable.\n"
185                                          "Assuming it's unnecessary." % (testdir.path,), 4)                                          "Assuming it's unnecessary." % (testdir.path,), 4)
186                          self.fsync_dirs = 0                          self.fsync_dirs = 0
187                  else: self.fsync_dirs = 1                  else: self.fsync_dirs = 1
188    
189          def set_chars_to_quote(self, subdir):          def set_extended_filenames(self, subdir):
190                  """Set self.chars_to_quote by trying to write various paths"""                  """Set self.extended_filenames by trying to write a path"""
191                  def is_case_sensitive():                  assert not self.read_only
192                          """Return true if file system is case sensitive"""  
193                          upper_a = subdir.append("A")                  # Make sure ordinary filenames ok
194                          upper_a.touch()                  ordinary_filename = '5-_ a.'
195                          lower_a = subdir.append("a")                  ord_rp = subdir.append(ordinary_filename)
196                          if lower_a.lstat():                  ord_rp.touch()
197                                  lower_a.delete()                  assert ord_rp.lstat()
198                                  upper_a.setdata()                  ord_rp.delete()
                                 assert not upper_a.lstat()  
                                 self.case_sensitive = 0  
                         else:  
                                 upper_a.delete()  
                                 self.case_sensitive = 1  
                         return self.case_sensitive  
   
                 def supports_unusual_chars():  
                         """Test handling of several chars sometimes not supported"""  
                         for filename in [':', '\\', chr(175)]:  
                                 try:  
                                         rp = subdir.append(filename)  
                                         rp.touch()  
                                 except (IOError, OSError):  
                                         assert not rp.lstat()  
                                         return 0  
                                 else:  
                                         assert rp.lstat()  
                                         rp.delete()  
                         return 1  
199    
200                  def sanity_check():                  extended_filename = ':\\' + chr(175)
201                          """Make sure basic filenames writable"""                  try:
202                          for filename in ['5-_ a.']:                          ext_rp = subdir.append(extended_filename)
203                                  rp = subdir.append(filename)                          ext_rp.touch()
204                                  rp.touch()                  except (IOError, OSError):
205                                  assert rp.lstat()                          assert not ext_rp.lstat()
206                                  rp.delete()                          self.extended_filenames = 0
   
                 sanity_check()  
                 if is_case_sensitive():  
                         if supports_unusual_chars(): self.chars_to_quote = ""  
                         else: self.chars_to_quote = "^A-Za-z0-9_ -."  
207                  else:                  else:
208                          if supports_unusual_chars(): self.chars_to_quote = "A-Z;"                          assert ext_rp.lstat()
209                          else: self.chars_to_quote = "^a-z0-9_ -."                          ext_rp.delete()
210                            self.extended_filenames = 1
211    
212          def set_acls(self, rp):          def set_acls(self, rp):
213                  """Set self.acls based on rp.  Does not write.  Needs to be local"""                  """Set self.acls based on rp.  Does not write.  Needs to be local"""
# Line 285  rdiff-backup-data/chars_to_quote. Line 222  rdiff-backup-data/chars_to_quote.
222                          return                          return
223    
224                  try: posix1e.ACL(file=rp.path)                  try: posix1e.ACL(file=rp.path)
225                  except IOError, exc:                  except IOError:
226                          log.Log("ACLs not supported by filesystem at %s" % (rp.path,), 4)                          log.Log("ACLs not supported by filesystem at %s" % (rp.path,), 4)
227                          self.acls = 0                          self.acls = 0
228                  else: self.acls = 1                  else: self.acls = 1
229    
230            def set_case_sensitive_readwrite(self, subdir):
231                    """Determine if directory at rp is case sensitive by writing"""
232                    assert not self.read_only
233                    upper_a = subdir.append("A")
234                    upper_a.touch()
235                    lower_a = subdir.append("a")
236                    if lower_a.lstat():
237                            lower_a.delete()
238                            upper_a.setdata()
239                            assert not upper_a.lstat()
240                            self.case_sensitive = 0
241                    else:
242                            upper_a.delete()
243                            self.case_sensitive = 1
244    
245          def set_case_sensitive_readonly(self, rp):          def set_case_sensitive_readonly(self, rp):
246                  """Determine if directory at rp is case sensitive without writing"""                  """Determine if directory at rp is case sensitive without writing"""
247                  def find_letter(subdir):                  def find_letter(subdir):
# Line 349  rdiff-backup-data/chars_to_quote. Line 301  rdiff-backup-data/chars_to_quote.
301                          if write:                          if write:
302                                  xattr.setxattr(rp.path, "user.test", "test val")                                  xattr.setxattr(rp.path, "user.test", "test val")
303                                  assert xattr.getxattr(rp.path, "user.test") == "test val"                                  assert xattr.getxattr(rp.path, "user.test") == "test val"
304                  except IOError, exc:                  except IOError:
305                          log.Log("Extended attributes not supported by "                          log.Log("Extended attributes not supported by "
306                                          "filesystem at %s" % (rp.path,), 4)                                          "filesystem at %s" % (rp.path,), 4)
307                          self.eas = 0                          self.eas = 0
# Line 402  rdiff-backup-data/chars_to_quote. Line 354  rdiff-backup-data/chars_to_quote.
354                          fp_read = open(os.path.join(reg_rp.path, '..namedfork', 'rsrc'), 'rb')                          fp_read = open(os.path.join(reg_rp.path, '..namedfork', 'rsrc'), 'rb')
355                          s_back = fp_read.read()                          s_back = fp_read.read()
356                          assert not fp_read.close()                          assert not fp_read.close()
357                  except (OSError, IOError), e: self.resource_forks = 0                  except (OSError, IOError): self.resource_forks = 0
358                  else: self.resource_forks = (s_back == s)                  else: self.resource_forks = (s_back == s)
359                  reg_rp.delete()                  reg_rp.delete()
360    
# Line 421  rdiff-backup-data/chars_to_quote. Line 373  rdiff-backup-data/chars_to_quote.
373                                          fp = rfork.open('rb')                                          fp = rfork.open('rb')
374                                          fp.read()                                          fp.read()
375                                          assert not fp.close()                                          assert not fp.close()
376                                  except (OSError, IOError), e:                                  except (OSError, IOError):
377                                          self.resource_forks = 0                                          self.resource_forks = 0
378                                          return                                          return
379                                  self.resource_forks = 1                                  self.resource_forks = 1
# Line 435  rdiff-backup-data/chars_to_quote. Line 387  rdiff-backup-data/chars_to_quote.
387                  try:                  try:
388                          tmp_rp.chmod(07000)                          tmp_rp.chmod(07000)
389                          tmp_rp.chmod(07777)                          tmp_rp.chmod(07777)
390                  except (OSError, IOError), e: self.high_perms = 0                  except (OSError, IOError): self.high_perms = 0
391                  else: self.high_perms = 1                  else: self.high_perms = 1
392                  tmp_rp.delete()                  tmp_rp.delete()
393    
394  def get_fsabilities_readonly(desc_string, rp):  def get_readonly_fsa(desc_string, rp):
395          """Return an FSAbilities object with given description_string          """Return an fsa with given description_string
396    
397          Will be initialized read_only with given RPath rp.          Will be initialized read_only with given RPath rp.  We separate
398            this out into a separate function so the request can be vetted by
399            the security module.
400    
401          """          """
402          return FSAbilities(desc_string).init_readonly(rp)          return FSAbilities(desc_string).init_readonly(rp)
403    
404  def get_fsabilities_readwrite(desc_string, rb, use_ctq_file = 1, ctq = None):  
405          """Like above but initialize read/write and pass other arguments"""  class SetGlobals:
406          return FSAbilities(desc_string).init_readwrite(          """Various functions for setting Globals vars given FSAbilities above
407                  rb, use_ctq_file = use_ctq_file, override_chars_to_quote = ctq)  
408            Container for BackupSetGlobals and RestoreSetGlobals (don't use directly)
409  def get_fsabilities_restoresource(rp):  
410          """Used when restoring, get abilities of source directory"""          """
411          fsa = FSAbilities('source').init_readonly(rp)          def __init__(self, in_conn, out_conn, src_fsa, dest_fsa):
412          ctq_rp = rp.append("chars_to_quote")                  """Just store some variables for use below"""
413          if ctq_rp.lstat(): fsa.chars_to_quote = ctq_rp.get_data()                  self.in_conn, self.out_conn = in_conn, out_conn
414          else: fsa.chars_to_quote = ""                  self.src_fsa, self.dest_fsa = src_fsa, dest_fsa
415          return fsa  
416            def set_eas(self):
417                    self.update_triple(self.src_fsa.eas, self.dest_fsa.eas,
418                                                       ('eas_active', 'eas_write', 'eas_conn'))
419    
420            def set_acls(self):
421                    self.update_triple(self.src_fsa.acls, self.dest_fsa.acls,
422                                                       ('acls_active', 'acls_write', 'acls_conn'))
423                    if Globals.never_drop_acls and not Globals.acls_active:
424                            Log.FatalError("--never-drop-acls specified, but ACL support\n"
425                                                       "missing from destination filesystem")
426    
427            def set_resource_forks(self):
428                    self.update_triple(self.src_fsa.resource_forks,
429                                                       self.dest_fsa.resource_forks,
430                                                       ('resource_forks_active', 'resource_forks_write',
431                                                            'resource_forks_conn'))
432    
433            def set_carbonfile(self):
434                    self.update_triple(self.src_fsa.carbonfile, self.dest_fsa.carbonfile,
435                              ('carbonfile_active', 'carbonfile_write', 'carbonfile_conn'))
436                    if self.src_fsa.carbonfile and not Globals.carbonfile_active:
437                            Log("Source may have carbonfile support, but support defaults to "
438                                    "off.\n  Use --carbonfile to enable.", 5)
439    
440            def set_hardlinks(self):
441                    if Globals.preserve_hardlinks != 0:
442                            SetConnections.UpdateGlobal('preserve_hardlinks',
443                                                                                    self.dest_fsa.hardlinks)
444    
445            def set_fsync_directories(self):
446                    SetConnections.UpdateGlobal('fsync_directories',
447                                                                            self.dest_fsa.fsync_dirs)
448    
449            def set_change_ownership(self):
450                    SetConnections.UpdateGlobal('change_ownership',
451                                                                            self.dest_fsa.ownership)
452    
453            def set_high_perms(self):
454                    if not self.dest_fsa.high_perms:
455                            SetConnections.UpdateGlobal('permission_mask', 0777)
456    
457    
458    class BackupSetGlobals(SetGlobals):
459            """Functions for setting fsa related globals for backup session"""
460            def update_triple(self, src_support, dest_support, attr_triple):
461                    """Many of the settings have a common form we can handle here"""
462                    active_attr, write_attr, conn_attr = attr_triple
463                    if Globals.get(active_attr) == 0: return # don't override 0
464                    for attr in attr_triple: SetConnections.UpdateGlobal(attr, None)
465                    if not src_support: return # if source doesn't support, nothing
466                    SetConnections.UpdateGlobal(active_attr, 1)
467                    self.in_conn.Globals.set_local(conn_attr, 1)
468                    if dest_support:
469                            SetConnections.UpdateGlobal(write_attr, 1)
470                            self.out_conn.Globals.set_local(conn_attr, 1)
471    
472            def set_chars_to_quote(self, rbdir):
473                    """Set chars_to_quote setting for backup session
474    
475                    Unlike the other options, the chars_to_quote setting also
476                    depends on the current settings in the rdiff-backup-data
477                    directory, not just the current fs features.
478    
479                    """
480                    ctq = self.compare_ctq_file(rbdir, self.get_ctq_from_fsas())
481    
482                    SetConnections.UpdateGlobal('chars_to_quote', ctq)
483                    if Globals.chars_to_quote: FilenameMapping.set_init_quote_vals()
484    
485            def get_ctq_from_fsas(self):
486                    """Determine chars_to_quote just from filesystems, no ctq file"""
487                    if not self.src_fsa.case_sensitive and self.dest_fsa.case_sensitive:
488                            if self.dest_fsa.extended_filenames:
489                                    return "A-Z;" # Quote upper case and quoting char
490                            else: return "^a-z0-9_ -." # quote everything but basic chars
491    
492                    if self.dest_fsa.extended_filenames:
493                            return "" # Don't quote anything
494                    else: return "^A-Za-z0-9_ -."
495    
496            def compare_ctq_file(self, rbdir, suggested_ctq):
497                    """Compare ctq file with suggested result, return actual ctq"""
498                    ctq_rp = rbdir.append("chars_to_quote")
499                    if not ctq_rp.lstat():
500                            if Globals.chars_to_quote is None: actual_ctq = suggested_ctq
501                            else: actual_ctq = Globals.chars_to_quote
502                            ctq_rp.write_string(actual_ctq)
503                            return actual_ctq
504    
505                    if Globals.chars_to_quote is None: actual_ctq = ctq_rp.get_data()
506                    else: actual_ctq = Globals.chars_to_quote # Globals override
507    
508                    if actual_ctq == suggested_ctq: return actual_ctq
509                    if suggested_ctq == "":
510                            log.Log("Warning: File system no longer needs quoting, "
511                                            "but we will retain for backwards compatibility.", 2)
512                            return actual_ctq
513                    log.Log.FatalError("""New quoting requirements!
514    
515    The quoting this session appears to need do not match those in
516    
517    %s
518    
519    This may be caused when you copy an rdiff-backup repository from a
520    normal file system onto a windows one that cannot support the same
521    characters, or if you backup a case-sensitive file system onto a
522    case-insensitive one that previously only had case-insensitive ones
523    backed up onto it.
524    
525    If you want to risk it, remove the file
526    rdiff-backup-data/chars_to_quote.""" % (ctq_rp.path,))
527    
528    
529    class RestoreSetGlobals(SetGlobals):
530            """Functions for setting fsa-related globals for restore session"""
531            def update_triple(self, src_support, dest_support, attr_triple):
532                    """Update global settings for feature based on fsa results
533    
534                    This is slightly different from BackupSetGlobals.update_triple
535                    because (using the mirror_metadata file) rpaths from the
536                    source may have more information than the file system
537                    supports.
538    
539                    """
540                    active_attr, write_attr, conn_attr = attr_triple
541                    if Globals.get(active_attr) == 0: return # don't override 0
542                    for attr in attr_triple: SetConnections.UpdateGlobal(attr, None)
543                    if not dest_support: return # if dest doesn't support, do nothing
544                    SetConnections.UpdateGlobal(active_attr, 1)
545                    self.out_conn.Globals.set_local(conn_attr, 1)
546                    self.out_conn.Globals.set_local(write_attr, 1)
547                    if src_support: self.in_conn.Globals.set_local(conn_attr, 1)
548    
549            def set_chars_to_quote(self, rbdir):
550                    """Set chars_to_quote from rdiff-backup-data dir"""
551                    if Globals.chars_to_quote is not None: return # already overridden
552                    
553                    ctq_rp = rbdir.append("chars_to_quote")
554                    if ctq_rp.lstat():
555                            SetConnections.UpdateGlobal("chars_to_quote", ctq_rp.get_data())
556                    else:
557                            log.Log("Warning: chars_to_quote file not found,\n"
558                                            "assuming no quoting in backup repository.", 2)
559                            SetConnections.UpdateGlobal("chars_to_quote", "")
560    
561    
562    class SingleSetGlobals(RestoreSetGlobals):
563            """For setting globals when dealing only with one filesystem"""
564            def __init__(self, conn, fsa):
565                    self.conn = conn
566                    self.dest_fsa = fsa
567    
568            def update_triple(self, fsa_support, attr_triple):
569                    """Update global vars from single fsa test"""
570                    active_attr, write_attr, conn_attr = attr_triple
571                    if Globals.get(active_attr) == 0: return # don't override 0
572                    for attr in attr_triple: SetConnections.UpdateGlobal(attr, None)
573                    if not fsa_support: return
574                    SetConnections.UpdateGlobal(active_attr, 1)
575                    SetConnections.UpdateGlobal(write_attr, 1)
576                    self.conn.Globals.set_local(conn_attr, 1)
577    
578            def set_eas(self):
579                    self.update_triple(self.dest_fsa.eas,
580                                                       ('eas_active', 'eas_write', 'eas_conn'))
581            def set_acls(self):
582                    self.update_triple(self.dest_fsa.acls,
583                                                      ('acls_active', 'acls_write', 'acls_conn'))
584            def set_resource_forks(self):
585                    self.update_triple(self.dest_fsa.resource_forks,
586                                                       ('resource_forks_active',
587                                                            'resource_forks_write', 'resource_forks_conn'))
588            def set_carbonfile(self):
589                    self.update_triple(self.dest_fsa.carbonfile,
590                             ('carbonfile_active', 'carbonfile_write', 'carbonfile_conn'))
591    
592    
593    def backup_set_globals(rpin):
594            """Given rps for source filesystem and repository, set fsa globals
595    
596            This should be run on the destination connection, because we may
597            need to write a new chars_to_quote file.
598    
599            """
600            assert Globals.rbdir.conn is Globals.local_connection
601            src_fsa = rpin.conn.fs_abilities.get_readonly_fsa('source', rpin)
602            log.Log(str(src_fsa), 4)
603            dest_fsa = FSAbilities('destination').init_readwrite(Globals.rbdir)
604            log.Log(str(dest_fsa), 4)
605    
606            bsg = BackupSetGlobals(rpin.conn, Globals.rbdir.conn, src_fsa, dest_fsa)
607            bsg.set_eas()
608            bsg.set_acls()
609            bsg.set_resource_forks()
610            bsg.set_carbonfile()
611            bsg.set_hardlinks()
612            bsg.set_fsync_directories()
613            bsg.set_change_ownership()
614            bsg.set_high_perms()
615            bsg.set_chars_to_quote(Globals.rbdir)
616    
617    def restore_set_globals(rpout):
618            """Set fsa related globals for restore session, given in/out rps"""
619            assert rpout.conn is Globals.local_connection
620            src_fsa = Globals.rbdir.conn.fs_abilities.get_readonly_fsa(
621                                      'rdiff-backup repository', Globals.rbdir)
622            log.Log(str(src_fsa), 4)
623            dest_fsa = FSAbilities('restore target').init_readwrite(rpout)
624            log.Log(str(dest_fsa), 4)
625    
626            rsg = RestoreSetGlobals(Globals.rbdir.conn, rpout.conn, src_fsa, dest_fsa)
627            rsg.set_eas()
628            rsg.set_acls()
629            rsg.set_resource_forks()
630            rsg.set_carbonfile()
631            rsg.set_hardlinks()
632            # No need to fsync anything when restoring
633            rsg.set_change_ownership()
634            rsg.set_high_perms()
635            rsg.set_chars_to_quote(Globals.rbdir)
636    
637    def single_set_globals(rp, read_only = None):
638            """Set fsa related globals for operation on single filesystem"""
639            if read_only:
640                    fsa = rp.conn.fs_abilities.get_readonly_fsa(rp.path, rp)
641            else: fsa = FSAbilities(rp.path).init_readwrite(rp)
642            log.Log(str(fsa), 4)
643    
644            ssg = SingleSetGlobals(rp.conn, fsa)
645            ssg.set_eas()
646            ssg.set_acls()
647            ssg.set_resource_forks()
648            ssg.set_carbonfile()
649            if not read_only:
650                    ssg.set_hardlinks()
651                    ssg.set_change_ownership()
652                    ssg.set_high_perms()
653            ssg.set_chars_to_quote(Globals.rbdir)
654    

Legend:
Removed from v.1.18  
changed lines
  Added in v.1.19

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26