[PATCH 2 of 2] fix symlinks on symlink-capable os but non-capable filesystem (issue1149)

Dov Feldstern dfeldstern at fastimap.com
Thu Jul 31 14:50:16 CDT 2008


# HG changeset patch
# User Dov Feldstern <dfeldstern at fastimap.com>
# Date 1217533299 -10800
# Node ID e168d51006fa780a115022a1ed3543d98a9ef5a8
# Parent  1a42f2a5dcdb22ecc291918076cec1481a329c5e
fix symlinks on symlink-capable os but non-capable filesystem (issue1149)

Currently (since breaking in 14789f30ac11), cloning a repository with symlinks
to a non-symlink-capable filesystem, using a symlinks-aware operating system
(e.g., vfat on linux) breaks with the message:
abort: Operation not permitted

This patch fixes that:
1. write a symlink directly as a symlink (currently it's being written as a
   file, and only then switched to a symlink by set_flags); note that writing
   as a symlink already makes sure that the fs supports symlinks.
2. set_flags should only switch a file to a symlink on a symlink-capable fs.

diff -r 1a42f2a5dcdb -r e168d51006fa hgext/convert/subversion.py
--- a/hgext/convert/subversion.py	Thu Jul 31 22:41:19 2008 +0300
+++ b/hgext/convert/subversion.py	Thu Jul 31 22:41:39 2008 +0300
@@ -997,7 +997,7 @@
             fp = open(hook, 'w')
             fp.write(pre_revprop_change)
             fp.close()
-            util.set_flags(hook, "x")
+            util.set_flags(hook, "x", self.wopener._can_symlink)
 
         xport = transport.SvnRaTransport(url=geturl(path))
         self.uuid = svn.ra.get_uuid(xport.ra)
@@ -1024,7 +1024,8 @@
                 # systematically is just as expensive and much simpler.
                 was_exec = 'x' not in flags
 
-            util.set_flags(self.wjoin(filename), flags)
+            util.set_flags(self.wjoin(filename), flags,
+                           self.wopener._can_symlink)
             if was_exec:
                 if 'x' not in flags:
                     self.delexec.append(filename)
diff -r 1a42f2a5dcdb -r e168d51006fa mercurial/localrepo.py
--- a/mercurial/localrepo.py	Thu Jul 31 22:41:19 2008 +0300
+++ b/mercurial/localrepo.py	Thu Jul 31 22:41:39 2008 +0300
@@ -544,8 +544,11 @@
             os.unlink(self.wjoin(filename))
         except OSError:
             pass
-        self.wopener(filename, 'w').write(data)
-        util.set_flags(self.wjoin(filename), flags)
+        if 'l' in flags:
+            self.wopener.symlink(data, filename)
+        else:
+            self.wopener(filename, 'w').write(data)
+        util.set_flags(self.wjoin(filename), flags, self.wopener._can_symlink)
 
     def wwritedata(self, filename, data):
         return self._filter("decode", filename, data)
diff -r 1a42f2a5dcdb -r e168d51006fa mercurial/merge.py
--- a/mercurial/merge.py	Thu Jul 31 22:41:19 2008 +0300
+++ b/mercurial/merge.py	Thu Jul 31 22:41:39 2008 +0300
@@ -348,7 +348,7 @@
                 repo.ui.warn(" %s\n" % nf)
         elif m == "e": # exec
             flags = a[2]
-            util.set_flags(repo.wjoin(f), flags)
+            util.set_flags(repo.wjoin(f), flags, repo.wopener._can_symlink)
 
     return updated, merged, removed, unresolved
 
diff -r 1a42f2a5dcdb -r e168d51006fa mercurial/patch.py
--- a/mercurial/patch.py	Thu Jul 31 22:41:19 2008 +0300
+++ b/mercurial/patch.py	Thu Jul 31 22:41:39 2008 +0300
@@ -1108,7 +1108,7 @@
             if ctype == 'ADD' and not os.path.exists(dst):
                 repo.wwrite(gp.path, '', flags)
             else:
-                util.set_flags(dst, flags)
+                util.set_flags(dst, flags, repo.wopener._can_symlink)
     cmdutil.addremove(repo, cfiles)
     files = patches.keys()
     files.extend([r for r in removes if r not in files])
diff -r 1a42f2a5dcdb -r e168d51006fa mercurial/util.py
--- a/mercurial/util.py	Thu Jul 31 22:41:19 2008 +0300
+++ b/mercurial/util.py	Thu Jul 31 22:41:39 2008 +0300
@@ -1069,7 +1069,7 @@
         '''return False if pid dead, True if running or not known'''
         return True
 
-    def set_flags(f, flags):
+    def set_flags(f, flags, can_symlink):
         pass
 
     def set_binary(fd):
@@ -1216,12 +1216,12 @@
         """check whether a file is executable"""
         return (os.lstat(f).st_mode & 0100 != 0)
 
-    def set_flags(f, flags):
+    def set_flags(f, flags, can_symlink):
         s = os.lstat(f).st_mode
         x = "x" in flags
         l = "l" in flags
         if l:
-            if not stat.S_ISLNK(s):
+            if can_symlink and not stat.S_ISLNK(s):
                 # switch file to link
                 data = file(f).read()
                 os.unlink(f)


More information about the Mercurial-devel mailing list