fixing some restore problems
authorEduardo Robles Elvira <edulix@wadobo.com>
Fri, 20 Sep 2013 08:14:03 +0000 (10:14 +0200)
committerEduardo Robles Elvira <edulix@wadobo.com>
Fri, 20 Sep 2013 08:14:03 +0000 (10:14 +0200)
* files that are not in the index being restored are now removed

* directories' mtime was not being restored sometimes because it
  wasn't finding the tarobj

deltatar/deltatar.py

index 8527671..e050453 100644 (file)
@@ -1124,11 +1124,15 @@ class DeltaTar(object):
                     op_type = ipath['type']
 
                 # filter paths
-                # TODO: think about changes of type "dir converted to file" and
-                # how can that affect filtering op_type
                 if self.filter_path(upath, '.', op_type == 'directory') == NO_MATCH:
                     continue
 
+                # if types of the file mismatch, the file needs to be deleted
+                # and re-restored
+                if ipath is not None and dpath is not None and\
+                        dpath['type'] != ipath['type']:
+                    helper.delete(upath)
+
                 # if file not found in dpath, we can directly restore from index
                 if not dpath:
                     # if the file doesn't exist and it needs to be deleted, it
@@ -1145,14 +1149,18 @@ class DeltaTar(object):
                 # we have to restore the file, but first we need to delete the
                 # current existing file.
                 # we don't delete the file if it's a directory, because it might
-                # just have changed mtime, so it's quite improductive to remove
+                # just have changed mtime, so it's quite inefficient to remove
                 # it
-                if ipath and (ipath['type'] != 'directory' or
-                        ipath['path'].startswith('delete://')):
-                    helper.delete(upath)
                 if ipath:
+                    if ipath['type'] != 'directory' or ipath['path'].startswith('delete://'):
+                        helper.delete(upath)
                     helper.restore(ipath, l_no)
 
+                # if the file is not in the index (so it comes from the target
+                # directory) then we have to delete it
+                else:
+                    helper.delete(upath)
+
             helper.restore_directories_permissions()
             index_it.release()
             os.chdir(cwd)
@@ -1341,17 +1349,38 @@ class RestoreHelper(object):
         '''
         Restore directory permissions when everything have been restored
         '''
+        try:
+            import grp, pwd
+        except ImportError:
+            grp = pwd = None
+
         self._directories.sort(key=operator.attrgetter('name'))
         self._directories.reverse()
-        tarobj = self._data[0]['tarobj']
 
         # Set correct owner, mtime and filemode on directories.
         for member in self._directories:
             dirpath = member.name
             try:
-                tarobj.chmod(member, dirpath)
-                tarobj.utime(member, dirpath)
-                tarobj.chown(member, dirpath)
+                os.chmod(dirpath, member.mode)
+                os.utime(dirpath, (member.mtime, member.mtime))
+                if pwd and hasattr(os, "geteuid") and os.geteuid() == 0:
+                    # We have to be root to do so.
+                    try:
+                        g = grp.getgrnam(member.gname)[2]
+                    except KeyError:
+                        g = member.gid
+                    try:
+                        u = pwd.getpwnam(member.uname)[2]
+                    except KeyError:
+                        u = member.uid
+                    try:
+                        if member.issym() and hasattr(os, "lchown"):
+                            os.lchown(dirpath, u, g)
+                        else:
+                            os.chown(dirpath, u, g)
+                    except EnvironmentError:
+                        raise tarfile.ExtractError("could not change owner")
+
             except tarfile.ExtractError, e:
                 self._deltatar.logger.warn('tarfile: %s' % e)