Bug 211160 - IWorkspaceRoot.findFilesForLocation cannot handle two levels of indirection.
Summary: IWorkspaceRoot.findFilesForLocation cannot handle two levels of indirection.
Status: RESOLVED FIXED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: Resources (show other bugs)
Version: 3.4   Edit
Hardware: PC Linux
: P3 normal with 2 votes (vote)
Target Milestone: 4.3   Edit
Assignee: Platform-Resources-Inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on: 233939
Blocks:
  Show dependency tree
 
Reported: 2007-11-27 23:04 EST by Robert Konigsberg CLA
Modified: 2012-12-10 05:05 EST (History)
6 users (show)

See Also:


Attachments
Reproducible test case (2.95 KB, text/x-java)
2007-11-27 23:04 EST, Robert Konigsberg CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Robert Konigsberg CLA 2007-11-27 23:04:55 EST
Created attachment 83940 [details]
Reproducible test case

Build ID: I20070625-1500

Steps To Reproduce:
Don't worry, I've attached a sample test.


mkdir -p /tmp/mytest/first
mkdir /tmp/mytest/second

echo FooBarBaz > /tmp/mytest/first/datafile
ln -s /tmp/mytest/first /tmp/mytest/first-link
ln -s /tmp/mytest/first-link/datafile /tmp/mytest/second/datafile

This creates:
(A) /tmp/mytest/first/datafile
(B) /tmp/mytest/first-link -> /tmp/mytest/first
(C) /tmp/mytest/second/datafile -> /tmp/mytest/first-link/datafile

In other words, C links to B and B links to A.

Now, on to Eclipse.

Create an Eclipse project, and create a linked folder to /tmp/mytest/second, that creates, in the Eclipse project a reference to /tmp/mytest/second/datafile.

I can easily view the contents of that file through all the links.

However, if I use IWorkspaceRoot.getFilesForLocation and pass "/tmp/mytest/second/datafile", it returns no results.

More information:

I have supplied a test case that will show this failing, and will also show that when doing the same thing with /tmp/mytest/first-link and /tmp/mytest/first, these tests still pass.

I don't know how to classify this. It's probably not major to you, but my project hinges on this working, or by getting around it. :(
Comment 1 Robert Konigsberg CLA 2007-11-28 12:12:20 EST
My comment C -> B and B -> A is actually not correct, since B links based on the parent directory.

It's likely that this problem can be simplified (perhaps the unix symbolic links can all be files, or perhaps only one symbolic link is required) but I wanted to reproduce my precise case first and foremost. Feel free to simplify the problem, but note that my expectation is that, in my sample test case, all tests should pass.

Also: if this isn't clear, to reproduce:

1. Run the 5 shell commands I provided. This creates the directories, files and links that are required to run the test.
2. Run the supplied test class.
I expect all tests to pass. The third one fails on the last two asserts. 
Comment 2 Robert Konigsberg CLA 2007-11-28 12:36:17 EST
Here's yet more information. I believe the problem is in FileSystemResourceManager.allPathsForLocation.

The first thing allPathsForLocation does is canonicalize the input location. Since the test class involves an Eclipse linked directory, I would expect the file to be found while searching through the project's links (at the bottom of the method.)

However, testLocation is not similarly canonicalized. Canonicalizing testLocation may cause different problems altogether, so that's where I leave it up to you guys as the experts!
Comment 3 Robert Konigsberg CLA 2007-12-11 21:41:37 EST
Any thoughts?
Comment 4 Robert Konigsberg CLA 2008-03-03 16:20:16 EST
Hi, there's been no activity on this since I reported it 3 months ago. Can someone at least verify the reproducible test case? Thanks!
Comment 5 David Kyle CLA 2008-03-03 16:23:31 EST
We are seeing the same problem with Build ID: I20070621-1340 (3.3.0). One of our users tried to "bend" the workspace by creating unix symbolic links (ln -s). Our code that used IWorkspaceRoot.getFilesForLocation(IPath) failed to see the resources.
Comment 6 Robert Konigsberg CLA 2008-03-03 16:40:45 EST
David,

We got by by replacing calls to findFilesForLocation with this method. This is good enough for our idiosyncrasies, but I'd rather just use findFilesByLocation. Feel free to use this, but use at your own risk.

 /*
   * Find the first match of a location within a project, based on the project's
   * links.
   *
   * This is a mutated version of FileSystemResourceManager.allPathsForLocation,
   * and doesn't do some of the canonicalization that is getting us in trouble.
   *
   * This doesn't do may other useful things such as:
   * - Find multiple versions of the file.
   * - Use FILE-type links.
   * - Find things other than IFile objects.
   * - Canonicalize to resolve additional levels of UNIX filesystem symbolic links.
   * Many of those things are fairly simple, but we don't need them and I'm going
   * for addressing those things that we need.
   */
  private static IFile findByLocation(IPath location, IProject project) {
    IPathVariableManager varMan = ResourcesPlugin.getWorkspace().getPathVariableManager();

    ProjectDescription description = ((Project) project).internalGetDescription();
    if (description == null) {
      return null;
    }

    @SuppressWarnings("unchecked") Map<?, LinkDescription> links = description.getLinks();
    if (links == null) {
      return null;
    }

    // This method presumes that links can not be children of one another.
    for (LinkDescription link : links.values()) {
      if (link.getType() != IResource.FOLDER) {
        continue;
      }

      // This isn't really necessary for us, but I'm following the recipe
      // for FileSystemResourceManager.allPathsForLocation in case we do use
      // variables in that way.
      // While trying to be minimal, I also don't want to introduce bugs
      // silently.
      URI resolvedUri = varMan.resolveURI(link.getLocationURI());
      if (resolvedUri == null) {
        continue;
      }

      // if we are looking for file: locations try to get a file: location for this link
      if (!resolvedUri.getScheme().equals("file")) {
        // Not dealing with non-file URIs. No thanks.
        continue;
      }

      IPath linkPath = Path.fromOSString(resolvedUri.getPath());
      if (linkPath.isPrefixOf(location)) {
        IPath suffix = location.removeFirstSegments(linkPath.matchingFirstSegments(location));
        IPath foundPath = project.getFullPath()
            .append(link.getProjectRelativePath()).append(suffix);
        return ResourcesPlugin.getWorkspace().getRoot().getFile(foundPath);
      }
    }
    return null;
  }
Comment 7 Terry Parker CLA 2012-12-06 11:38:12 EST
I retested this bug and found that the attached test case now succeeds with Eclipse 3.8.0, so this bug can be marked as fixed.
Comment 8 Szymon Brandys CLA 2012-12-10 05:05:49 EST
Thanks Terry for checking.