JDK-8265430 : (fs) No support for IO_REPARSE_TAG_CLOUD_x tags, file reported as "other"
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.nio
  • Affected Version: 9,16
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: windows
  • CPU: x86_64
  • Submitted: 2021-04-18
  • Updated: 2024-09-18
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
tbdUnresolved
Description
ADDITIONAL SYSTEM INFORMATION :
Windows Server 2019 Standard (VM)

Issue originally found using:
 OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.10+9)
 Open JDK 64-Bit Server VM AdoptOpenJDK (build 11.0.10+9, mixed mode)

and also confirmed using:
OpenJDK 64-Bit Server VM (build 16+36-2231, mixed mode, sharing)

The OpenJ9 JVM also behaved in the same way

A DESCRIPTION OF THE PROBLEM :
When starting a modular Java app on Windows Server 2019, interaction with a Windows file process can result in a FindException when scanning the module path.

There is a Microsoft Windows process (believed to be file de-duplication) that can run periodically on servers which creates reparse points and tags on many files, including jar files.   (MS docs on reparse point is "0x9000601A  - IO_REPARSE_TAG_CLOUD_6 - Used by the Cloud Files filter, for files managed by a sync engine such as OneDrive. Server-side interpretation only, not meaningful over the wire.")
Once this MS process has run, starting a Java application from the module path using one of the affected jar files gives:

  Error occurred during initialization of boot layer
  java.lang.module.FindException: Module format not recognized: MyApp.jar

The simplest way to cause this issue is to run "java --list-modules -p MyApp.jar"    Anything that causes a module path scan throws the FindException.

However, there is no problem if the app is run from a class path via "java -cp "MyApp.jar;MyLib/*" -jar MyApp.jar"

It is inconsistent that the same jar files can be read from a class path but not from a module path. Although a workaround is to run the app without using modules, this seems to be a backward step.


The FindException is thrown at line 250 of  jdk.internal.module.ModulePath.   When processing a jar file to locate module-info.class, ModulePath (line 324) calls  "attrs.isRegularFile()" where "attrs" is declared as type BasicFileAttributes which for Windows is implemented by sun.nio.fs.WindowsFileAttributes

In WindowsFileAttributes, the relevant methods are:

   public boolean isRegularFile() {
        return !isSymbolicLink() && !isDirectory() && !isOther();
   }
   public boolean isOther() {
        if (isSymbolicLink())
            return false;
        // return true if device or reparse point
        return ((fileAttrs & (FILE_ATTRIBUTE_DEVICE | FILE_ATTRIBUTE_REPARSE_POINT)) != 0);
   }

The jar files in question are not symbolic links and not directories, but the FILE_ATTRIBUTE_REPARSE_POINT bit is set so isRegularFile() returns false and the FindException is thrown,   However, testing shows that the jar file can be read using standard Java code and a valid ModuleDescriptor can be built.   The ModulePath code would have read the jar file successfully but in essence gave up too early when isRegularFile() returned false.


A possible fix is to replace the call to isRegularFile() at ModulePath line 324 with:

     if (!isSymbolicLink() && !isDirectory()) {    // not checking for isOther()

then attempt to read the file and only throw an Exception if there is an IO error or module-info.class cannot be located.  There are proably better fixes than this, but essentially the proposed approach is to ignore isOther(), proceeed to read the file, and only throw an Exception if the file is unreadable.  At the very least, behaviour should be consistent with that of ClassLoader which I believe does not call isRegularFile().

Another possible approach would be to copy the jar file(s) to the Temp directory as ModulePAth currently does for custom file systems.   Copying creates a "clean" copy of a jar file without a reparse point and associated tag data.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
This is a little challenging as it requires a jar file that has had a reparse point attribute set ("L" attribute).  Since copying a file with this attribute results in its removal, I can't supply a file.  Also, it could probably only be opened on the system that created the reparse data.  However, assuming that such a jar file is available (or can be mocked up), the steps are below.  I'm also happy to test any solution.

1.  Assume Java application jar file with reparse attribute set is MyApp.jar.
2.  At a Windows command line, attempt to run "java --list-modules -p MyApp.jar

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
A list of JDK and application modules
ACTUAL -

  Error occurred during initialization of boot layer
  java.lang.module.FindException: Module format not recognized: MyApp.jar

---------- BEGIN SOURCE ----------
Not applicable - just list the modules from any modular jar file
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Don't run the application using JPMS - run from a classpath.

FREQUENCY : always



Comments
The Microsoft documentation states: "The following reparse tags, with the exception of IO_REPARSE_TAG_SYMLINK, are processed on the server and are not processed by a client after transmission over the wire. Clients SHOULD treat associated reparse data as opaque data.<2>" https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/c8e77b37-3909-4fe6-a4ea-2b9d423b1ee4 "<2> Section 2.1.2.1: These are Microsoft reparse tags. Except where explicitly allowed, clients MUST NOT process the Microsoft reparse tag data buffers." https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/d4bc551b-7aaf-4b4f-ba0e-3a75e7c528f0#Appendix_A_2 Given the foregoing, I wonder whether reparse tags other than IO_REPARSE_TAG_SYMLINK (and perhaps eventually IO_REPARSE_TAG_MOUNT_POINT) could safely be ignored, and such opaque reparse points be considered to be regular files or directories depending on whether FILE_ATTRIBUTE_DIRECTORY is set? The reparse data in these cases would be treated in effect as opaque metadata.
18-09-2024

This isn't really a modules issue, instead it's a question on what BasicFileAttributes.isXXX should return for these reparse points. As things stand, isOther will be true because it's not a regular file, directory, or sym link.
19-04-2021