write_handle.write(data[:remainder])
return self.md5sum(path)
- def md5sum(self, filename):
+ def create_symlink(self, linkname, path):
+ os.symlink(linkname, path)
+ return self.md5sum(path, linkname=linkname)
+
+ def md5sum(self, filename, linkname=None):
'''
- Returns the md5sum of a file specified by its filename/path
+ Returns the md5sum of a file specified by its filename/path or, if
+ ``linkname`` is specified, the hash of both paths (for symlinks).
'''
md5 = hashlib.md5()
- with open(filename,'rb') as f:
- for chunk in iter(lambda: f.read(128*md5.block_size), b''):
- md5.update(chunk)
+ if linkname is None:
+ with open(filename,'rb') as f:
+ for chunk in iter(lambda: f.read(128*md5.block_size), b''):
+ md5.update(chunk)
+ else: # symlink; hash paths
+ md5.update(filename.encode("UTF-8"))
+ md5.update(linkname.encode("UTF-8"))
return md5.hexdigest()
# Author: Eduardo Robles Elvira <edulix@wadobo.com>
+import errno
import os
import re
import random
from . import BaseTest
from . import new_volume_handler
+SYMLINK_GOOD = 0
+SYMLINK_BAD = 1
class DeltaTarTest(BaseTest):
"""
print("TITEM: " + str(titem))
raise e
+ def test_create_no_symlinks(self):
+ '''
+ Creates a full backup from different varieties of symlinks. The
+ extracted archive may not contain any symlinks but the file contents
+ '''
+
+ os.system("rm -rf source_dir")
+ os.makedirs("source_dir/symlinks")
+ fd = os.open("source_dir/symlinks/valid_linkname",
+ os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o644)
+ os.write(fd, b"valid link target for symlink tests; please ignore\n")
+ os.close(fd)
+ # first one is good, the rest points nowhere
+ self.create_symlink("valid_linkname", "source_dir/symlinks/whatever")
+ self.create_symlink("/foo/bar/baz", "source_dir/symlinks/xyzzy")
+ self.create_symlink("burp/../buzz", "source_dir/symlinks/blup")
+ self.create_symlink("../../../../biz", "source_dir/symlinks/bleep")
+ deltatar = DeltaTar(mode=self.MODE, password=self.PASSWORD,
+ logger=self.consoleLogger)
+
+ # create first backup
+ deltatar.create_full_backup(source_path="source_dir",
+ backup_path="backup_dir")
+
+ assert os.path.exists("backup_dir")
+ shutil.rmtree("source_dir")
+ assert not os.path.exists("source_dir")
+
+ tar_filename = deltatar.volume_name_func('backup_dir', True, 0)
+ tar_path = os.path.join("backup_dir", tar_filename)
+
+ deltatar.restore_backup(target_path="source_dir",
+ backup_tar_path=tar_path)
+
+ for _r, _ds, fs in os.walk("source_dir/symlinks"):
+ # only the valid link plus the linked file may be found in the
+ # extracted archive
+ assert len(fs) == 2
+ for f in fs:
+ # the link must have been resolved and file contents must match
+ # the linked file
+ assert not os.path.islink(f)
+ with open("source_dir/symlinks/valid_linkname") as a:
+ with open("source_dir/symlinks/whatever") as b:
+ assert a.read() == b.read()
+
+
class DeltaTar2Test(DeltaTarTest):
'''
Same as DeltaTar but with specific ":" mode