2

Here is the problem. I have a symlink pointing to some other directory:

$ls -l /foo/bar
lrwxrwxrwx  /foo/bar  ->  /target/bar

in the foo directory there is a file x

$ls -l /foo
lrwxrwxrwx   me me  314   x

Now, I want to have an access to x by the following path /foo/bar/../x

$ls -l /foo/bar/../x : No such file or directory

This doesn't work in Bash, but is there any way to make it work from Java using the File api? The directory structure can be pretty much arbitrary so there might be cases like /foo/bar/1/2/3/4/5/../../../../../../x, etc.

In other words I am looking for the content of the magic() method checking the existence of a file (assuming the previously mentioned directory structure):

magic("/foo/x") ... true
magic("/foo/bar/../x") ... true
magic("/foo/bar/1//../../x") ... true
magic("/foo/bar/1/2/3/4/5/../../../../../../x") ... true
magic("/foo/bar//1/../2/../../x") ... true
magic("/foo/bar/1/2/../3/../../../x") ... true
magic("/foo/bar/1/2/./../3/../4//../../../x") ... true

magic("/foo/bar/x") ... false
magic("/foo/bar/1/../x") ... false
magic("/foo/bar/1/2/3/4/../../../../../../x") ... false
magic("/foo/bar//1/../2/../x") ... false

NOTE 1: getCanonicalPath() doesn't work for me, because it firstly resolves the symlinks and then all the ".." or "." in path. I need it to be done vice-versa.

NOTE 2: There might me other symlinks in the path and it should work in the same sense (dir 2 may be a symlink).

NOTE 3: The file x is located only in the /foo.

So far, it looks like I need a parser for context-free grammar, isn't there any easier solution to this problem?

Jiri Kremser
  • 12,471
  • 7
  • 45
  • 72
  • 1
    This is an artifact of how Linux resolves paths. It's not Bash or Java doing this. – Oliver Charlesworth Mar 05 '13 at 20:50
  • 1
    What are you trying to do? If what you wanted to do was possible, accessing file system paths would be completely ambiguous. – Falmarri Mar 05 '13 at 20:51
  • @Falmarri: I just need it :) It is difficult to explain it using the whole picture, that's why I've extracted only the essence of the problem here. – Jiri Kremser Mar 05 '13 at 20:53
  • @OliCharlesworth I know, and I need it to behave the way I've described. It is a part of a module doing some provisioning. – Jiri Kremser Mar 05 '13 at 20:54
  • @JiriKremser: Ok. Well it's unlikely that you'll find a pre-canned solution, as it's not a normal thing to want to do. If you **really** need to do this, then tokenizing and counting occurrences of ".." doesn't sound like the hardest thing in the world... – Oliver Charlesworth Mar 05 '13 at 20:55
  • @OliCharlesworth Yeah, that's what I was afraid of. I can find out if some chunk of a path is a symlink using this http://stackoverflow.com/questions/2490351/detecting-a-symlink-in-java approach. I guess, I need only to resolve the ".." in the paths and not the symlinks. Kind of doable. – Jiri Kremser Mar 05 '13 at 20:59
  • @JiriKremser: Why do you need to check? Isn't it just a case of stripping out as many path components as there are ".." components? – Oliver Charlesworth Mar 05 '13 at 21:02

2 Answers2

4

If I understand you correctly, the Path.normalize() method should be doing exactly what you want?

It eliminates .. (among other things), and it's documentation says

This method does not access the file system; the path may not locate a file that exists. Eliminating ".." and a preceding name from a path may result in the path that locates a different file than the original path. This can arise when the preceding name is a symbolic link.

You don't need to resolve the other symlinks on the path, the OS will resolve them when you try to access the file in the end. If you want to resolve the symlinks anyway, call Path.toRealPath() afterwards (not giving NOFOLLOW_LINKS as argument).

Philipp Wendler
  • 11,184
  • 7
  • 52
  • 87
  • +1 Wow, so my comment above was wrong; such a method **does** exist! In what circumstances would this ever be useful? – Oliver Charlesworth Mar 05 '13 at 21:03
  • @OliCharlesworth I don't know, but it seems to pretty common. Python has an equivalent function (`os.path.normpath()`: http://docs.python.org/2/library/os.path.html#os.path.normpath). – Philipp Wendler Mar 05 '13 at 21:06
  • Probably API designers add such a method it because it is relatively easy, it does not need the file system (so no IOExceptions and no slow disk access) and it is not platform dependent. – Philipp Wendler Mar 05 '13 at 21:08
  • And it could be used for places where you have a path that does not nessencary map to the file system. Very useful when dealing with URLs. – Johannes Kuhn Jun 12 '13 at 14:01
0

Path is a Java7 API. If you're stuck with Java6, I think the following would fit the bill, too: http://commons.apache.org/proper/commons-io/javadocs/api-1.4/org/apache/commons/io/FilenameUtils.html#normalize%28java.lang.String%29

metlos
  • 19
  • 1