Do not rely on filemode differences in case of symbolic links

When checking whether a file in the working tree has been modified -
WorkingTreeIterator.isModified() - we should not trust the filemode
in case of symbolic links, but check the timestamp and also the
content, if requested. Without this fix symlinks will always be shown
in EGit as modified files on Windows systems.

Change-Id: I367c807df5a7e85e828ddacff7fee7901441f187
Signed-off-by: Philipp Thun <philipp.thun@sap.com>
This commit is contained in:
Philipp Thun 2010-12-14 11:31:41 +01:00
parent c6ca443b61
commit bab053afdd
2 changed files with 34 additions and 9 deletions

View File

@ -46,6 +46,9 @@
import java.io.File; import java.io.File;
import java.security.MessageDigest; import java.security.MessageDigest;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.dircache.DirCacheCheckout;
import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectId;
@ -175,6 +178,24 @@ public void testComputeFileObjectId() throws Exception {
assertEquals(expect, top.getEntryObjectId()); assertEquals(expect, top.getEntryObjectId());
} }
public void testIsModifiedSymlink() throws Exception {
File f = writeTrashFile("symlink", "content");
Git git = new Git(db);
git.add().addFilepattern("symlink").call();
git.commit().setMessage("commit").call();
// Modify previously committed DirCacheEntry and write it back to disk
DirCacheEntry dce = db.readDirCache().getEntry("symlink");
dce.setFileMode(FileMode.SYMLINK);
DirCacheCheckout.checkoutEntry(db, f, dce);
FileTreeIterator fti = new FileTreeIterator(trash, db.getFS(), db
.getConfig().get(WorkingTreeOptions.KEY));
while (!fti.getEntryPathString().equals("symlink"))
fti.next(1);
assertFalse(fti.isModified(dce, false));
}
private static String nameOf(final AbstractTreeIterator i) { private static String nameOf(final AbstractTreeIterator i) {
return RawParseUtils.decode(Constants.CHARSET, i.path, 0, i.pathLen); return RawParseUtils.decode(Constants.CHARSET, i.path, 0, i.pathLen);
} }

View File

@ -556,15 +556,19 @@ public boolean isModified(DirCacheEntry entry, boolean forceContentCheck) {
// bitwise presentation of modeDiff we'll have a '1' when the two modes // bitwise presentation of modeDiff we'll have a '1' when the two modes
// differ at this position. // differ at this position.
int modeDiff = getEntryRawMode() ^ entry.getRawMode(); int modeDiff = getEntryRawMode() ^ entry.getRawMode();
// Ignore the executable file bits if checkFilemode tells me to do so.
// Ignoring is done by setting the bits representing a EXECUTABLE_FILE // Do not rely on filemode differences in case of symbolic links
// to '0' in modeDiff if (modeDiff != 0 && !FileMode.SYMLINK.equals(entry.getRawMode())) {
if (!state.options.isFileMode()) // Ignore the executable file bits if WorkingTreeOptions tell me to
modeDiff &= ~FileMode.EXECUTABLE_FILE.getBits(); // do so. Ignoring is done by setting the bits representing a
if (modeDiff != 0) // EXECUTABLE_FILE to '0' in modeDiff
// Report a modification if the modes still (after potentially if (!state.options.isFileMode())
// ignoring EXECUTABLE_FILE bits) differ modeDiff &= ~FileMode.EXECUTABLE_FILE.getBits();
return true; if (modeDiff != 0)
// Report a modification if the modes still (after potentially
// ignoring EXECUTABLE_FILE bits) differ
return true;
}
// Git under windows only stores seconds so we round the timestamp // Git under windows only stores seconds so we round the timestamp
// Java gives us if it looks like the timestamp in index is seconds // Java gives us if it looks like the timestamp in index is seconds