--- a/mercurial/util.py Fri Apr 21 15:47:27 2006 -0700
+++ b/mercurial/util.py Fri Apr 21 16:09:43 2006 -0700
@@ -215,6 +215,30 @@
elif name == root:
return ''
else:
+ # Determine whether `name' is in the hierarchy at or beneath `root',
+ # by iterating name=dirname(name) until that causes no change (can't
+ # check name == '/', because that doesn't work on windows). For each
+ # `name', compare dev/inode numbers. If they match, the list `rel'
+ # holds the reversed list of components making up the relative file
+ # name we want.
+ root_st = os.stat(root)
+ rel = []
+ while True:
+ try:
+ name_st = os.stat(name)
+ except OSError:
+ break
+ if os.path.samestat(name_st, root_st):
+ rel.reverse()
+ name = os.path.join(*rel)
+ audit_path(name)
+ return pconvert(name)
+ dirname, basename = os.path.split(name)
+ rel.append(basename)
+ if dirname == name:
+ break
+ name = dirname
+
raise Abort('%s not under root' % myname)
def matcher(canonroot, cwd='', names=['.'], inc=[], exc=[], head='', src=None):
--- a/tests/test-symlinks Fri Apr 21 15:47:27 2006 -0700
+++ b/tests/test-symlinks Fri Apr 21 16:09:43 2006 -0700
@@ -40,3 +40,18 @@
# it should show a.c, dir/a.o and dir/b.o deleted
hg status
hg status a.c
+
+echo '# test absolute path through symlink outside repo'
+cd ..
+p=`pwd`
+hg init x
+ln -s x y
+cd x
+touch f
+hg add f
+hg status $p/y/f
+
+echo '# try symlink outside repo to file inside'
+ln -s x/f ../z
+# this should fail
+hg status ../z && { echo hg mistakenly exited with status 0; exit 1; } || :
--- a/tests/test-symlinks.out Fri Apr 21 15:47:27 2006 -0700
+++ b/tests/test-symlinks.out Fri Apr 21 16:09:43 2006 -0700
@@ -9,3 +9,7 @@
? .hgignore
a.c: unsupported file type (type is fifo)
! a.c
+# test absolute path through symlink outside repo
+A f
+# try symlink outside repo to file inside
+abort: ../z not under root