summaryrefslogtreecommitdiff
path: root/rdiff-backup/rdiff_backup/fs_abilities.py
diff options
context:
space:
mode:
Diffstat (limited to 'rdiff-backup/rdiff_backup/fs_abilities.py')
-rw-r--r--rdiff-backup/rdiff_backup/fs_abilities.py146
1 files changed, 77 insertions, 69 deletions
diff --git a/rdiff-backup/rdiff_backup/fs_abilities.py b/rdiff-backup/rdiff_backup/fs_abilities.py
index e6084c6..98c43f8 100644
--- a/rdiff-backup/rdiff_backup/fs_abilities.py
+++ b/rdiff-backup/rdiff_backup/fs_abilities.py
@@ -1,4 +1,4 @@
-# Copyright 2002 Ben Escoto
+# Copyright 2003 Ben Escoto
#
# This file is part of rdiff-backup.
#
@@ -50,12 +50,14 @@ class FSAbilities:
Only self.acls and self.eas are set.
"""
+ self.root_rp = rp
self.read_only = 1
self.set_eas(rp, 0)
self.set_acls(rp)
return self
- def init_readwrite(self, rbdir, use_ctq_file = 1):
+ def init_readwrite(self, rbdir, use_ctq_file = 1,
+ override_chars_to_quote = None):
"""Set variables using fs tested at rp_base
This method creates a temp directory in rp_base and writes to
@@ -69,17 +71,21 @@ class FSAbilities:
file in directory.
"""
- assert rbdir.isdir()
+ if not rbdir.isdir():
+ assert not rbdir.lstat(), (rbdir.path, rbdir.lstat())
+ rbdir.mkdir()
+ self.root_rp = rbdir
self.read_only = 0
- subdir = TempFile.new_in_dir(rbdir)
+ subdir = rbdir.conn.TempFile.new_in_dir(rbdir)
subdir.mkdir()
self.set_ownership(subdir)
self.set_hardlinks(subdir)
self.set_fsync_dirs(subdir)
self.set_eas(subdir, 1)
self.set_acls(subdir)
- self.set_chars_to_quote(subdir)
+ 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)
subdir.delete()
return self
@@ -95,19 +101,14 @@ class FSAbilities:
fp.write(self.chars_to_quote)
assert not fp.close()
- def get_old_chars():
- fp = ctq_rp.open("rb")
- old_chars = fp.read()
- assert not fp.close()
- return old_chars
-
if not ctq_rp.lstat(): write_new_chars()
else:
- old_chars = get_old_chars()
+ 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.FatalError("""New quoting requirements
This may be caused when you copy an rdiff-backup directory from a
@@ -127,7 +128,7 @@ rdiff-backup-data/chars_to_quote.
except (IOError, OSError), exc:
if exc[0] == errno.EPERM:
log.Log("Warning: ownership cannot be changed on filesystem "
- "at device %s" % (testdir.getdevloc(),), 2)
+ "at %s" % (self.root_rp.path,), 2)
self.ownership = 0
else: raise
else: self.ownership = 1
@@ -143,21 +144,15 @@ rdiff-backup-data/chars_to_quote.
assert hl_source.getinode() == hl_dest.getinode()
except (IOError, OSError), exc:
if exc[0] in (errno.EOPNOTSUPP, errno.EPERM):
- log.Log("Warning: hard linking not supported by filesystem %s"
- % (testdir.getdevloc(),), 2)
+ log.Log("Warning: hard linking not supported by filesystem "
+ "at %s" % (self.root_rp.path,), 2)
self.hardlinks = 0
else: raise
else: self.hardlinks = 1
def set_fsync_dirs(self, testdir):
"""Set self.fsync_dirs if directories can be fsync'd"""
- try: testdir.fsync()
- except (IOError, OSError), exc:
- log.Log("Warning: Directories on file system at %s are not "
- "fsyncable.\nAssuming it's unnecessary." %
- (testdir.getdevloc(),), 2)
- self.fsync_dirs = 0
- else: self.fsync_dirs = 1
+ self.fsync_dirs = testdir.conn.fs_abilities.test_fsync_local(testdir)
def set_chars_to_quote(self, subdir):
"""Set self.chars_to_quote by trying to write various paths"""
@@ -189,7 +184,7 @@ rdiff-backup-data/chars_to_quote.
def sanity_check():
"""Make sure basic filenames writable"""
- for filename in ['5-_ a']:
+ for filename in ['5-_ a.']:
rp = subdir.append(filename)
rp.touch()
assert rp.lstat()
@@ -198,57 +193,70 @@ rdiff-backup-data/chars_to_quote.
sanity_check()
if is_case_sensitive():
if supports_unusual_chars(): self.chars_to_quote = ""
- else: self.chars_to_quote = "^A-Za-z0-9_ -"
+ else: self.chars_to_quote = "^A-Za-z0-9_ -."
else:
if supports_unusual_chars(): self.chars_to_quote = "A-Z;"
- else: self.chars_to_quote = "^a-z0-9_ -"
+ else: self.chars_to_quote = "^a-z0-9_ -."
def set_acls(self, rp):
"""Set self.acls based on rp. Does not write. Needs to be local"""
- assert Globals.local_connection is rp.conn
- assert rp.lstat()
- try: import posix1e
- except ImportError:
- log.Log("Warning: Unable to import module posix1e from pylibacl "
- "package.\nACLs not supported on device %s" %
- (rp.getdevloc(),), 2)
- self.acls = 0
- return
-
- try: posix1e.ACL(file=rp.path)
- except IOError, exc:
- if exc[0] == errno.EOPNOTSUPP:
- log.Log("Warning: ACLs appear not to be supported by "
- "filesystem on device %s" % (rp.getdevloc(),), 2)
- self.acls = 0
- else: raise
- else: self.acls = 1
+ self.acls = rp.conn.fs_abilities.test_acls_local(rp)
def set_eas(self, rp, write):
- """Set extended attributes from rp. Run locally.
-
- Tests writing if write is true.
-
- """
- assert Globals.local_connection is rp.conn
- assert rp.lstat()
- try: import xattr
- except ImportError:
- log.Log("Warning: Unable to import module xattr. ACLs not "
- "supported on device %s" % (rp.getdevloc(),), 2)
- self.eas = 0
- return
-
- try:
- xattr.listxattr(rp.path)
- if write:
- xattr.setxattr(rp.path, "user.test", "test val")
- assert xattr.getxattr(rp.path, "user.test") == "test val"
- except IOError, exc:
- if exc[0] == errno.EOPNOTSUPP:
- log.Log("Warning: Extended attributes not supported by "
- "filesystem on device %s" % (rp.getdevloc(),), 2)
- self.eas = 0
- else: raise
- else: self.eas = 1
+ """Set extended attributes from rp. Tests writing if write is true."""
+ self.eas = rp.conn.fs_abilities.test_eas_local(rp, write)
+
+
+def test_eas_local(rp, write):
+ """Test ea support. Must be called locally. Usedy by set_eas above."""
+ assert Globals.local_connection is rp.conn
+ assert rp.lstat()
+ try: import xattr
+ except ImportError:
+ log.Log("Warning: Unable to import module xattr. ACLs not "
+ "supported on filesystem at %s" % (rp.path,), 2)
+ return 0
+
+ try:
+ xattr.listxattr(rp.path)
+ if write:
+ xattr.setxattr(rp.path, "user.test", "test val")
+ assert xattr.getxattr(rp.path, "user.test") == "test val"
+ except IOError, exc:
+ if exc[0] == errno.EOPNOTSUPP:
+ log.Log("Warning: Extended attributes not supported by "
+ "filesystem at %s" % (rp.path,), 2)
+ return 0
+ else: raise
+ else: return 1
+
+def test_acls_local(rp):
+ """Test acl support. Call locally. Does not write."""
+ assert Globals.local_connection is rp.conn
+ assert rp.lstat()
+ try: import posix1e
+ except ImportError:
+ log.Log("Warning: Unable to import module posix1e from pylibacl "
+ "package.\nACLs not supported on filesystem at %s" %
+ (rp.path,), 2)
+ return 0
+
+ try: posix1e.ACL(file=rp.path)
+ except IOError, exc:
+ if exc[0] == errno.EOPNOTSUPP:
+ log.Log("Warning: ACLs appear not to be supported by "
+ "filesystem at %s" % (rp.path,), 2)
+ return 0
+ else: raise
+ else: return 1
+
+def test_fsync_local(rp):
+ """Test fsyncing directories locally"""
+ assert rp.conn is Globals.local_connection
+ try: rp.fsync()
+ except (IOError, OSError), exc:
+ log.Log("Warning: Directories on file system at %s are not "
+ "fsyncable.\nAssuming it's unnecessary." % (rp.path,), 2)
+ return 0
+ else: return 1