On Wed, 10 Dec 2025 23:00:11 GMT, Francisco Ferrari Bihurriet <[email protected]> wrote:
>> I'm a little confused. Now that we have agreed to no longer revolve >> symlinks, `/tmp/a/b/../f2` should indeed be `/tmp/a/f2`. Since it does not >> exist, we simply fail. Why is this a problem? Did I miss anything? > > Hmm, I also got confused for a moment, it seems important to make a > distinction between file links and directory links, and how each platform > handles each of them. > > We are no longer resolving any type of link, here: > > https://github.com/openjdk/jdk/blob/c33bf62c2831acefd90ec476fcfb6d853be873ee/src/java.base/share/classes/java/security/Security.java#L250-L258 > > `currentPath.resolveSibling(path)` is equivalent to > `currentPath.getParent().resolve(path)` when `currentPath` has a parent. > > If `currentPath` is `/tmp/a/b/f1` and `path` is `../f2`, after line 257, path > will be `/tmp/a/b/../f2`. > > In the [previous _Linux_ example](#discussion_r2607247993), `/tmp/a/b` is a > **directory** symbolic link to `/tmp/x/y`, so `/tmp/a/b/../f2` still reads > `/tmp/x/f2` (at the OS level) when opening the file. > > <details> > <summary>Extension of that <em>Linux</em> example's <code>jshell</code> > snippet showing how <code>/tmp/a/b/../f2</code> can be opened</summary> > > > jshell -<<'EOF' > Path current = Path.of("/tmp/a/b/f1"); > Path included = current.resolveSibling("../f2"); > > Map<String, Path> opts = new LinkedHashMap<String, Path>(); > opts.put("included", included); > opts.put("included.toRealPath()", included.toRealPath()); > opts.put("included.toRealPath(LinkOption.NOFOLLOW_LINKS)", > included.toRealPath(LinkOption.NOFOLLOW_LINKS)); > opts.put("included.normalize()", included.normalize()); > > for (Map.Entry<String, Path> opt : opts.entrySet()) { > System.out.println(); > System.out.println(opt.getKey() + " -> " + opt.getValue()); > Files.newInputStream(opt.getValue()); > System.out.println("succesfully opened"); > } > EOF > > > Output: > > > included -> /tmp/a/b/../f2 > succesfully opened > > included.toRealPath() -> /tmp/x/f2 > succesfully opened > > included.toRealPath(LinkOption.NOFOLLOW_LINKS) -> /tmp/a/b/../f2 > succesfully opened > > included.normalize() -> /tmp/a/f2 > Exception java.nio.file.NoSuchFileException: /tmp/a/f2 > at UnixException.translateToIOException (UnixException.java:92) > at UnixException.rethrowAsIOException (UnixException.java:106) > at UnixException.rethrowAsIOException (UnixException.java:111) > at UnixFileSystemProvider.newByteChannel > (UnixFileSystemProvider.java:261) > at Files.newByteChannel (Files.java:380) > at Files.newByteChannel (Files.java:432) > at FileSystemProvider.newInputStream (FileSystemProvider.java:420) > at Files.newInputStream (Files.java:160) > at (#8:4) > > > </details> > > With that observation, I tried to re-introduce 7abb62c069ad3... Thanks for the detailed explanation. I like your attitude to leave the path resolution to the simplest API. For debugging output, I prefer the 3rd choice for the same reason that it's the simplest. Also, it preserves the original include form. I would assume the reader wants to see this. ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/24465#discussion_r2608776622
