Issue1145

Title "abort: path 'a/f' traverses symbolic link 'a'" prevents fixing the problem with `hg rm`
Priority feature Status chatting
Superseder Nosy List djc, dov, mdounin, parren, pmezard, tjd2002, tonfa
Assigned To Topics patch

Created on 2008-05-28.12:19:45 by parren, last changed 2011-12-30.22:40:44 by mpm.

Files
File name Uploaded Type Edit Remove
patch-hg-issue1145-2.txt mdounin, 2008-07-30.00:54:38 text/plain
patch-hg-issue1145-stable.txt mdounin, 2008-07-28.02:50:52 text/plain
patch-hg-issue1145.txt mdounin, 2008-07-28.02:50:37 text/plain
Messages
msg12454 (view) Author: tjd2002 Date: 2010-05-07.22:14:57
This issue (or a closely related one) seems also to be triggered by repos 
generated by a convert from SVN (see issue 2166). Perhaps someone wants to 
examine that one more closely to see if it is a separate bug in the 'convert' 
process, or just a duplicate of this one.

If it is a dupe, then I think the svn conversion case is still interesting 
because the workarounds proposed here (hg mv the link) don't seem to work. 
due to the initial hg update being aborted.
msg12453 (view) Author: tjd2002 Date: 2010-05-07.22:06:14
being nosy
msg7824 (view) Author: mdounin Date: 2008-11-03.15:06:50
Your patch works only if we happend to get file in question in cmp (lookup 
list from dirstate.status()).  Forcing file to have correct time in dirstate 
makes this clear:

> cat test-symlink-issue1145
#!/bin/sh

"$TESTDIR/hghave" symlink || exit 80

hg init a
cd a

mkdir a
touch a/f
hg ci -Ama

# force dirstate to have correct time for the files
sleep 1
hg stat 2>&1 > /dev/null

mv a b

echo '% stat without symlink'
hg stat

ln -s b a

echo '% stat with symlink created'
hg stat

echo '% trying to removing a'
hg rm -A a

> ./run-tests.py test-symlink-issue1145

ERROR: test-symlink-issue1145 output changed
--- Expected output
+++ Test output
@@ -3,8 +3,7 @@
 ! a/f
 ? b/f
 % stat with symlink created
-! a/f
 ? a
 ? b/f
 % trying to removing a
-removing a/f
+not removing a/f: file still exists (use -f to force removal)
.
Failed test-symlink-issue1145: output changed
# Ran 1 tests, 0 skipped, 1 failed.
msg7795 (view) Author: tonfa Date: 2008-11-02.14:37:25
I think auditing the path in dirstate is really too expensive (that's a very
common path).

How about the following ?

diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -1003,11 +1003,14 @@
                 fixup = []
                 # do a full compare of any files that might have changed
                 for f in cmp:
-                    if (f not in ctx1 or ctx2.flags(f) != ctx1.flags(f)
-                        or ctx1[f].cmp(ctx2[f].data())):
-                        modified.append(f)
-                    else:
-                        fixup.append(f)
+                    try:
+                        if (f not in ctx1 or ctx2.flags(f) != ctx1.flags(f)
+                            or ctx1[f].cmp(ctx2[f].data())):
+                            modified.append(f)
+                        else:
+                            fixup.append(f)
+                    except util.Abort: # file not readable ?
+                        deleted.append(f)
 
                 if listclean:
                     clean += fixup
msg7789 (view) Author: djc Date: 2008-11-02.13:54:57
Adding some nosies.
msg6631 (view) Author: mdounin Date: 2008-07-30.00:54:38
Updated patch against crew - with "except util.Abort:" instead of "except".
msg6621 (view) Author: mdounin Date: 2008-07-28.02:50:37
Attached patches are against crew and crew-stable.  They both do the same 
thing but a bit different due to refactoring happened between crew-stable and 
crew.

Summary: dirstate.status() does stat() on files that are in dirstate map but 
wasn't reached by normal walk for some reason (e.g. due to .hgignore), and 
treats them as present if stat() succeeded.  This prevents it from noticing 
that file a/f (as in original report) actually missing, and this in turn leads 
to abort() later.

The patch uses util.path_auditor to make sure files dirstate stat()'s doesn't 
traverse symobolic links and thus prevents problem from appearing. And now 
it's possible to do 'hg rm a' (plus hg status now actually produce correct 
status).

Note: this doesn't fix 'hg rm a/f' case, and I don't think we should fix it.  
Just use 'hg rm a' instead.

Note: this doesn't fix revert as mentioned in the original report.  The issue 
looks completely separate and I'm not sure what to do with it.  At least, it's 
in line with our current behaviour when file shadows directory.
msg6186 (view) Author: mdounin Date: 2008-06-06.12:06:11
Quick look reveals that there are at least two places where path auditor 
aborts here:

1. In localrepo.status(), line 1023, when we compare file in working directory 
with file in repo if no mtime information available in dirstate.  Note that 
this is racy (i.e. you may not get it if mtime present in dirstate).

2. In util.match(), when exact filename 'a/f' passed to rm.

I think that first case is relatively easy to fix (i.e. just assume that there 
is no such file) and I try it as soon as I have some more time.

The second case looks much more fragile for me, and I currently don't know 
what to do with it. May be it should be left as is (i.e. "hg rm -A a/f" won't 
work, but "hg rm -A a" would).
msg6184 (view) Author: djc Date: 2008-06-06.08:07:00
mdounin, since you seemed to have fixed issue660 nicely, which is somewhat
related, care to take a look at this?
msg6116 (view) Author: parren Date: 2008-05-28.12:19:43
The symlink traversal check gets in the way of using `hg rm -A` to fix the
problem. Workaround: Remove the offending symlink, clean up, then recreate it.
Or use `hg mv`, which is cleaner anyway.

I suggest we fix `hg rm -A`, and add a note to the error message returned by `hg
stat` on how to fix the problem using `hg rm` or `hg mv`.

Test case:

#! /bin/bash
hg init repo ; cd repo
mkdir a ; touch a/f
hg ci -Am a
mv a b
hg stat
ln -s b a
hg stat # fails
hg rm -A a # fails
hg rm -A a/a # fails

Revert also fails:

#! /bin/bash
hg init repo ; cd repo
mkdir a ; touch a/f
hg ci -Am a
hg mv a b
ln -s b a
hg add a
hg revert -a # fails

However, move works:

#! /bin/bash
hg init repo ; cd repo
mkdir a ; touch a/f
hg ci -Am a
mv a b
hg stat
ln -s b a
hg stat # fails
hg mv -A a b
hg stat -C
hg ci -Am b
History
Date User Action Args
2011-12-30 22:40:44mpmsetpriority: bug -> feature
nosy: tonfa, pmezard, dov, mdounin, parren, djc, tjd2002
2010-10-09 15:59:34benjaminunlinkissue1744 superseder
2010-05-07 22:14:57tjd2002setnosy: tonfa, pmezard, dov, mdounin, parren, djc, tjd2002
messages: + msg12454
2010-05-07 22:06:14tjd2002setnosy: + tjd2002
messages: + msg12453
2009-08-05 20:45:27sspweb01200linkissue1744 superseder
2008-11-03 15:06:52mdouninsetnosy: tonfa, pmezard, dov, mdounin, parren, djc
messages: + msg7824
2008-11-02 14:37:25tonfasetnosy: tonfa, pmezard, dov, mdounin, parren, djc
messages: + msg7795
2008-11-02 13:54:57djcsetnosy: + pmezard, tonfa
messages: + msg7789
2008-07-30 21:12:47dovsetnosy: + dov
2008-07-30 07:21:55djcsettopic: + patch
nosy: mdounin, parren, djc
2008-07-30 00:54:45mdouninsetfiles: + patch-hg-issue1145-2.txt
nosy: mdounin, parren, djc
messages: + msg6631
2008-07-28 02:50:52mdouninsetfiles: + patch-hg-issue1145-stable.txt
nosy: mdounin, parren, djc
2008-07-28 02:50:38mdouninsetfiles: + patch-hg-issue1145.txt
nosy: mdounin, parren, djc
messages: + msg6621
2008-06-06 12:06:12mdouninsetnosy: mdounin, parren, djc
messages: + msg6186
2008-06-06 08:07:00djcsetnosy: + djc, mdounin
messages: + msg6184
2008-05-28 12:19:45parrencreate