Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8265430

(fs) No support for IO_REPARSE_TAG_CLOUD_x tags, file reported as "other"

    XMLWordPrintable

Details

    • x86_64
    • windows

    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


      Attachments

        Activity

          People

            bpb Brian Burkhalter
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated: