7130915: File.equals does not give expected results when path contains Non-English characters on Mac OS X
Summary: to support Unicode nfd/nfc file path on Macos
Reviewed-by: alanb
--- a/jdk/make/java/nio/Makefile Thu Jul 19 18:19:04 2012 +0100
+++ b/jdk/make/java/nio/Makefile Thu Jul 19 21:23:53 2012 -0700
@@ -282,6 +282,9 @@
sun/nio/fs/BsdFileSystem.java \
sun/nio/fs/BsdFileSystemProvider.java \
sun/nio/fs/BsdNativeDispatcher.java \
+ sun/nio/fs/MacOSXFileSystemProvider.java \
+ sun/nio/fs/MacOSXFileSystem.java \
+ sun/nio/fs/MacOSXNativeDispatcher.java \
sun/nio/fs/PollingWatchService.java \
sun/nio/fs/UnixChannelFactory.java \
sun/nio/fs/UnixCopyFile.java \
@@ -311,6 +314,7 @@
\
GnomeFileTypeDetector.c \
BsdNativeDispatcher.c \
+ MacOSXNativeDispatcher.c \
UnixCopyFile.c \
UnixNativeDispatcher.c \
\
@@ -385,7 +389,7 @@
OTHER_LDLIBS += -L$(LIBDIR)/$(LIBARCH) -ljava -lnet -lpthread $(LIBDL)
endif
ifeq ($(PLATFORM), macosx)
-OTHER_LDLIBS += -L$(LIBDIR) -ljava -lnet -pthread
+OTHER_LDLIBS += -L$(LIBDIR) -ljava -lnet -pthread -framework CoreFoundation
endif
ifeq ($(PLATFORM), solaris)
OTHER_LDLIBS += $(JVMLIB) $(LIBSOCKET) -lposix4 $(LIBDL) -lsendfile \
--- a/jdk/src/share/native/java/io/io_util.h Thu Jul 19 18:19:04 2012 +0100
+++ b/jdk/src/share/native/java/io/io_util.h Thu Jul 19 21:23:53 2012 -0700
@@ -25,9 +25,6 @@
#include "jni.h"
#include "jni_util.h"
-#ifdef MACOSX
-char* convertToNFDIfNeeded(const char *origPath, char *buf, size_t bufsize);
-#endif
extern jfieldID IO_fd_fdID;
extern jfieldID IO_handle_fdID;
@@ -59,7 +56,6 @@
void throwFileNotFoundException(JNIEnv *env, jstring path);
-
/*
* Macros for managing platform strings. The typical usage pattern is:
*
@@ -88,35 +84,6 @@
* declares a unique variable.
*/
-#ifdef MACOSX
-
-#define WITH_PLATFORM_STRING(env, strexp, var) \
- if (1) { \
- const char *var; \
- jstring _##var##str = (strexp); \
- if (_##var##str == NULL) { \
- JNU_ThrowNullPointerException((env), NULL); \
- goto _##var##end; \
- } \
- const char *temp_var = JNU_GetStringPlatformChars((env), _##var##str, NULL); \
- if (temp_var == NULL) goto _##var##end; \
- char buf[MAXPATHLEN]; \
- var = convertToNFDIfNeeded(temp_var, buf, sizeof(buf));
-
-#define WITH_FIELD_PLATFORM_STRING(env, object, id, var) \
- WITH_PLATFORM_STRING(env, \
- ((object == NULL) \
- ? NULL \
- : (*(env))->GetObjectField((env), (object), (id))), \
- var)
-
-#define END_PLATFORM_STRING(env, var) \
- JNU_ReleaseStringPlatformChars(env, _##var##str, temp_var); \
- _##var##end: ; \
- } else ((void)NULL)
-
-#else
-
#define WITH_PLATFORM_STRING(env, strexp, var) \
if (1) { \
const char *var; \
@@ -140,8 +107,6 @@
_##var##end: ; \
} else ((void)NULL)
-#endif
-
/* Macros for transforming Java Strings into native Unicode strings.
* Works analogously to WITH_PLATFORM_STRING.
--- a/jdk/src/solaris/classes/sun/nio/fs/BsdNativeDispatcher.java Thu Jul 19 18:19:04 2012 +0100
+++ b/jdk/src/solaris/classes/sun/nio/fs/BsdNativeDispatcher.java Thu Jul 19 21:23:53 2012 -0700
@@ -33,7 +33,7 @@
*/
class BsdNativeDispatcher extends UnixNativeDispatcher {
- private BsdNativeDispatcher() { }
+ protected BsdNativeDispatcher() { }
/**
* struct fsstat_iter *getfsstat();
@@ -55,11 +55,6 @@
private static native void initIDs();
static {
- AccessController.doPrivileged(new PrivilegedAction<Void>() {
- public Void run() {
- System.loadLibrary("nio");
- return null;
- }});
- initIDs();
+ initIDs();
}
}
--- a/jdk/src/solaris/classes/sun/nio/fs/DefaultFileSystemProvider.java Thu Jul 19 18:19:04 2012 +0100
+++ b/jdk/src/solaris/classes/sun/nio/fs/DefaultFileSystemProvider.java Thu Jul 19 21:23:53 2012 -0700
@@ -69,7 +69,7 @@
if (osname.equals("Linux"))
return createProvider("sun.nio.fs.LinuxFileSystemProvider");
if (osname.equals("Darwin") || osname.contains("OS X"))
- return createProvider("sun.nio.fs.BsdFileSystemProvider");
+ return createProvider("sun.nio.fs.MacOSXFileSystemProvider");
throw new AssertionError("Platform not recognized");
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/MacOSXFileSystem.java Thu Jul 19 21:23:53 2012 -0700
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.*;
+import java.io.IOException;
+import java.util.*;
+import java.util.regex.Pattern;
+import java.security.AccessController;
+import sun.security.action.GetPropertyAction;
+
+import static sun.nio.fs.MacOSXNativeDispatcher.*;
+
+/**
+ * MacOS implementation of FileSystem
+ */
+
+class MacOSXFileSystem extends BsdFileSystem {
+
+ MacOSXFileSystem(UnixFileSystemProvider provider, String dir) {
+ super(provider, dir);
+ }
+
+ // match in unicode canon_eq
+ Pattern compilePathMatchPattern(String expr) {
+ return Pattern.compile(expr, Pattern.CANON_EQ) ;
+ }
+
+ char[] normalizeNativePath(char[] path) {
+ for (char c : path) {
+ if (c > 0x80)
+ return normalizepath(path, kCFStringNormalizationFormD);
+ }
+ return path;
+ }
+
+ String normalizeJavaPath(String path) {
+ for (int i = 0; i < path.length(); i++) {
+ if (path.charAt(i) > 0x80)
+ return new String(normalizepath(path.toCharArray(),
+ kCFStringNormalizationFormC));
+ }
+ return path;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/MacOSXFileSystemProvider.java Thu Jul 19 21:23:53 2012 -0700
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.io.IOException;
+
+/**
+ * MacOSX implementation of FileSystemProvider
+ */
+
+public class MacOSXFileSystemProvider extends BsdFileSystemProvider {
+ public MacOSXFileSystemProvider() {
+ super();
+ }
+
+ @Override
+ MacOSXFileSystem newFileSystem(String dir) {
+ return new MacOSXFileSystem(this, dir);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/MacOSXNativeDispatcher.java Thu Jul 19 21:23:53 2012 -0700
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.nio.fs;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * MacOSX specific system calls.
+ */
+
+class MacOSXNativeDispatcher extends BsdNativeDispatcher {
+ private MacOSXNativeDispatcher() { }
+
+ static final int kCFStringNormalizationFormC = 2;
+ static final int kCFStringNormalizationFormD = 0;
+ static native char[] normalizepath(char[] path, int form);
+}
--- a/jdk/src/solaris/classes/sun/nio/fs/UnixFileSystem.java Thu Jul 19 18:19:04 2012 +0100
+++ b/jdk/src/solaris/classes/sun/nio/fs/UnixFileSystem.java Thu Jul 19 21:23:53 2012 -0700
@@ -302,7 +302,8 @@
}
// return matcher
- final Pattern pattern = Pattern.compile(expr);
+ final Pattern pattern = compilePathMatchPattern(expr);
+
return new PathMatcher() {
@Override
public boolean matches(Path path) {
@@ -310,11 +311,10 @@
}
};
}
+
private static final String GLOB_SYNTAX = "glob";
private static final String REGEX_SYNTAX = "regex";
-
-
@Override
public final UserPrincipalLookupService getUserPrincipalLookupService() {
return LookupService.instance;
@@ -339,4 +339,23 @@
};
}
+ // Override if the platform has different path match requrement, such as
+ // case insensitive or Unicode canonical equal on MacOSX
+ Pattern compilePathMatchPattern(String expr) {
+ return Pattern.compile(expr);
+ }
+
+ // Override if the platform uses different Unicode normalization form
+ // for native file path. For example on MacOSX, the native path is stored
+ // in Unicode NFD form.
+ char[] normalizeNativePath(char[] path) {
+ return path;
+ }
+
+ // Override if the native file path use non-NFC form. For example on MacOSX,
+ // the native path is stored in Unicode NFD form, the path need to be
+ // normalized back to NFC before passed back to Java level.
+ String normalizeJavaPath(String path) {
+ return path;
+ }
}
--- a/jdk/src/solaris/classes/sun/nio/fs/UnixPath.java Thu Jul 19 18:19:04 2012 +0100
+++ b/jdk/src/solaris/classes/sun/nio/fs/UnixPath.java Thu Jul 19 21:23:53 2012 -0700
@@ -68,7 +68,7 @@
UnixPath(UnixFileSystem fs, String input) {
// removes redundant slashes and checks for invalid characters
- this(fs, encode(normalizeAndCheck(input)));
+ this(fs, encode(fs, normalizeAndCheck(input)));
}
// package-private
@@ -116,7 +116,7 @@
}
// encodes the given path-string into a sequence of bytes
- private static byte[] encode(String input) {
+ private static byte[] encode(UnixFileSystem fs, String input) {
SoftReference<CharsetEncoder> ref = encoder.get();
CharsetEncoder ce = (ref != null) ? ref.get() : null;
if (ce == null) {
@@ -126,7 +126,7 @@
encoder.set(new SoftReference<CharsetEncoder>(ce));
}
- char[] ca = input.toCharArray();
+ char[] ca = fs.normalizeNativePath(input.toCharArray());
// size output buffer for worse-case size
byte[] ba = new byte[(int)(ca.length * (double)ce.maxBytesPerChar())];
@@ -728,7 +728,7 @@
if (c1 != c2) {
return c1 - c2;
}
- k++;
+ k++;
}
return len1 - len2;
}
@@ -757,8 +757,9 @@
@Override
public String toString() {
// OK if two or more threads create a String
- if (stringValue == null)
- stringValue = new String(path); // platform encoding
+ if (stringValue == null) {
+ stringValue = fs.normalizeJavaPath(new String(path)); // platform encoding
+ }
return stringValue;
}
--- a/jdk/src/solaris/native/java/io/UnixFileSystem_md.c Thu Jul 19 18:19:04 2012 +0100
+++ b/jdk/src/solaris/native/java/io/UnixFileSystem_md.c Thu Jul 19 21:23:53 2012 -0700
@@ -38,6 +38,7 @@
#include "jlong.h"
#include "jvm.h"
#include "io_util.h"
+#include "io_util_md.h"
#include "java_io_FileSystem.h"
#include "java_io_UnixFileSystem.h"
@@ -80,7 +81,11 @@
canonicalPath, JVM_MAXPATHLEN) < 0) {
JNU_ThrowIOExceptionWithLastError(env, "Bad pathname");
} else {
+#ifdef MACOSX
+ rv = newStringPlatform(env, canonicalPath);
+#else
rv = JNU_NewStringPlatform(env, canonicalPath);
+#endif
}
} END_PLATFORM_STRING(env, path);
return rv;
@@ -311,7 +316,11 @@
if (JNU_CopyObjectArray(env, rv, old, len) < 0) goto error;
(*env)->DeleteLocalRef(env, old);
}
+#ifdef MACOSX
+ name = newStringPlatform(env, ptr->d_name);
+#else
name = JNU_NewStringPlatform(env, ptr->d_name);
+#endif
if (name == NULL) goto error;
(*env)->SetObjectArrayElement(env, rv, len++, name);
(*env)->DeleteLocalRef(env, name);
--- a/jdk/src/solaris/native/java/io/io_util_md.c Thu Jul 19 18:19:04 2012 +0100
+++ b/jdk/src/solaris/native/java/io/io_util_md.c Thu Jul 19 21:23:53 2012 -0700
@@ -34,37 +34,32 @@
#include <CoreFoundation/CoreFoundation.h>
-static inline char *convertToNFD(const char *path, char *buf, size_t bufsize)
+__private_extern__
+jstring newStringPlatform(JNIEnv *env, const char* str)
{
- CFMutableStringRef mutable = CFStringCreateMutable(NULL, 0);
- CFStringAppendCString(mutable, path, kCFStringEncodingUTF8);
- CFStringNormalize(mutable, kCFStringNormalizationFormD);
-
- CFStringGetCString(mutable, buf, bufsize, kCFStringEncodingUTF8);
-
- CFRelease(mutable);
- return buf;
-}
-
-/* Converts the path to NFD form if it was in NFC form. Returns a pointer to
- * the converting string which could be buf (if the converstion took place) or
- * origPath if no conversion was needed
- */
-__private_extern__
-char* convertToNFDIfNeeded(const char *origPath, char *buf, size_t bufsize)
-{
- const char *current = origPath;
- int c;
- for (c = *current; c != 0; current++, c = *current) {
- if (c < 0) {
- // Need to convert
- return convertToNFD(origPath, buf, bufsize);
+ jstring rv = NULL;
+ CFMutableStringRef csref = CFStringCreateMutable(NULL, 0);
+ if (csref == NULL) {
+ JNU_ThrowOutOfMemoryError(env, "native heap");
+ } else {
+ CFStringAppendCString(csref, str, kCFStringEncodingUTF8);
+ CFStringNormalize(csref, kCFStringNormalizationFormC);
+ int clen = CFStringGetLength(csref);
+ int ulen = (clen + 1) * 2; // utf16 + zero padding
+ char* chars = malloc(ulen);
+ if (chars == NULL) {
+ CFRelease(csref);
+ JNU_ThrowOutOfMemoryError(env, "native heap");
+ } else {
+ if (CFStringGetCString(csref, chars, ulen, kCFStringEncodingUTF16)) {
+ rv = (*env)->NewString(env, (jchar*)chars, clen);
+ }
+ free(chars);
+ CFRelease(csref);
}
}
-
- return (char *)origPath;
+ return rv;
}
-
#endif
void
--- a/jdk/src/solaris/native/java/io/io_util_md.h Thu Jul 19 18:19:04 2012 +0100
+++ b/jdk/src/solaris/native/java/io/io_util_md.h Thu Jul 19 21:23:53 2012 -0700
@@ -72,3 +72,7 @@
* IO helper function(s)
*/
void fileClose(JNIEnv *env, jobject this, jfieldID fid);
+
+#ifdef MACOSX
+jstring newStringPlatform(JNIEnv *env, const char* str);
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/native/sun/nio/fs/MacOSXNativeDispatcher.c Thu Jul 19 21:23:53 2012 -0700
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "jni.h"
+#include "jni_util.h"
+#include "jvm.h"
+#include "jlong.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <CoreFoundation/CoreFoundation.h>
+
+JNIEXPORT jcharArray JNICALL
+Java_sun_nio_fs_MacOSXNativeDispatcher_normalizepath(JNIEnv* env, jclass this,
+ jcharArray path,
+ jint form)
+{
+ jcharArray result = NULL;
+ char chars_buf[(PATH_MAX + 1) * 2]; // utf16 + zero padding
+ CFMutableStringRef csref = CFStringCreateMutable(NULL, 0);
+ if (csref == NULL) {
+ JNU_ThrowOutOfMemoryError(env, "native heap");
+ } else {
+ char *chars = (char*)(*env)->GetPrimitiveArrayCritical(env, path, 0);
+ jsize len = (*env)->GetArrayLength(env, path);
+ CFStringAppendCharacters(csref, (const UniChar*)chars, len);
+ (*env)->ReleasePrimitiveArrayCritical(env, path, chars, 0);
+ CFStringNormalize(csref, form);
+ len = CFStringGetLength(csref);
+ if (len < PATH_MAX) {
+ if (CFStringGetCString(csref, chars_buf, sizeof(chars_buf), kCFStringEncodingUTF16)) {
+ result = (*env)->NewCharArray(env, len);
+ (*env)->SetCharArrayRegion(env, result, 0, len, (jchar*)&chars_buf);
+ }
+ } else {
+ int ulen = (len + 1) * 2;
+ chars = malloc(ulen);
+ if (chars == NULL) {
+ CFRelease(csref);
+ JNU_ThrowOutOfMemoryError(env, "native heap");
+ return result;
+ } else {
+ if (CFStringGetCString(csref, chars, ulen, kCFStringEncodingUTF16)) {
+ result = (*env)->NewCharArray(env, len);
+ (*env)->SetCharArrayRegion(env, result, 0, len, (jchar*)chars);
+ }
+ free(chars);
+ }
+ }
+ CFRelease(csref);
+ }
+ return result;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/io/File/MacPathTest.java Thu Jul 19 21:23:53 2012 -0700
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 7130915
+ * @summary Tests file path with nfc/nfd forms on MacOSX
+ * @build MacPathTest
+ * @run shell MacPathTest.sh
+ */
+
+import java.io.*;
+import java.text.*;
+import java.util.*;
+
+public class MacPathTest {
+
+ public static void main(String args[]) throws Throwable {
+ String osname = System.getProperty("os.name");
+ if (!osname.contains("OS X") && !osname.contains("Darwin"))
+ return;
+
+ // English
+ test("TestDir_apple", // test dir
+ "dir_macosx", // dir
+ "file_macosx"); // file
+
+ // Japanese composite character
+ test("TestDir_\u30c8\u30a4\u30e4\u30cb\u30ca\u30eb/",
+ "dir_\u30a4\u30c1\u30b4\u306e\u30b1\u30fc\u30ad",
+ "file_\u30a4\u30c1\u30b4\u306e\u30b1\u30fc\u30ad");
+
+ // latin-1 supplementory
+ test("TestDir_K\u00f6rperlich\u00e4\u00df/",
+ "dir_Entt\u00e4uschung",
+ "file_Entt\u00e4uschung");
+
+ test("TestDir_K\u00f6rperlich\u00e4\u00df/",
+ "dir_Entt\u00c4uschung",
+ "file_Entt\u00c4uschung");
+
+ // Korean syblla
+ test("TestDir_\uac00\uac01\uac02",
+ "dir_\uac20\uac21\uac22",
+ "file_\uacc0\uacc1\uacc2");
+ }
+
+ private static void removeAll(File file) throws Throwable {
+ if (file.isDirectory()) {
+ for (File f : file.listFiles()) {
+ removeAll(f);
+ }
+ }
+ file.delete();
+ }
+
+ private static boolean equal(Object x, Object y) {
+ return x == null ? y == null : x.equals(y);
+ }
+
+ private static boolean match(File target, File src) {
+ if (target.equals(src)) {
+ String fname = target.toString();
+ System.out.printf(" ->matched : [%s], length=%d%n", fname, fname.length());
+ return true;
+ }
+ return false;
+ }
+
+ private static void open_read(String what, File file) throws Throwable {
+ try (FileInputStream fis = new FileInputStream(file)) {
+ byte[] bytes = new byte[10];
+ fis.read(bytes);
+ System.out.printf(" %s:%s%n", what, new String(bytes));
+ }
+ }
+
+ private static void test(String testdir, String dname, String fname_nfc)
+ throws Throwable
+ {
+ String fname = null;
+ String dname_nfd = Normalizer.normalize(dname, Normalizer.Form.NFD);
+ String fname_nfd = Normalizer.normalize(fname_nfc, Normalizer.Form.NFD);
+
+ System.out.printf("%n%n--------Testing...----------%n");
+ File base = new File(testdir);
+ File dir = new File(base, dname);
+ File dir_nfd = new File(base, dname_nfd);
+ File file_nfc = new File(base, fname_nfc);
+ File file_nfd = new File(base, fname_nfd);
+
+ System.out.printf("base :[%s][len=%d]%n", testdir, testdir.length());
+ System.out.printf("dir :[%s][len=%d]%n", dname, dname.length());
+ System.out.printf("fname_nfc :[%s][len=%d]%n", fname_nfc, fname_nfc.length());
+ System.out.printf("fname_nfd :[%s][len=%d]%n", fname_nfd, fname_nfd.length());
+
+ fname = file_nfc.toString();
+ System.out.printf("file_nfc ->[%s][len=%d]%n", fname, fname.length());
+ fname = file_nfd.toString();
+ System.out.printf("file_nfd ->[%s][len=%d]%n%n", fname, fname.length());
+
+ removeAll(base);
+ dir.mkdirs();
+
+ fname = dir.toString();
+ System.out.printf(":Directory [%s][len=%d] created%n", fname, fname.length());
+
+ //////////////////////////////////////////////////////////////
+ if (!dir.isDirectory() || !dir_nfd.isDirectory()) {
+ throw new RuntimeException("File.isDirectory() failed");
+ }
+
+ //////////////////////////////////////////////////////////////
+ // write to via nfd
+ try (FileOutputStream fos = new FileOutputStream(file_nfd)) {
+ fos.write('n'); fos.write('f'); fos.write('d');
+ }
+ open_read("read in with nfc (from nfd)", file_nfc);
+ file_nfd.delete();
+
+ //////////////////////////////////////////////////////////////
+ // write to with nfc
+ try (FileOutputStream fos = new FileOutputStream(file_nfc)) {
+ fos.write('n'); fos.write('f'); fos.write('c');
+ }
+ open_read("read in with nfd (from nfc)", file_nfd);
+ //file_nfc.delete();
+
+ //////////////////////////////////////////////////////////////
+ boolean found_dir = false;
+ boolean found_file_nfc = false;
+ boolean found_file_nfd = false;
+
+ for (File f : base.listFiles()) {
+ fname = f.toString();
+ System.out.printf("Found : [%s], length=%d%n", fname, fname.length());
+ found_dir |= match(dir, f);
+ found_file_nfc |= match(file_nfc, f);
+ found_file_nfd |= match(file_nfd, f);
+ }
+
+ if (!found_dir || !found_file_nfc || !found_file_nfc) {
+ throw new RuntimeException("File.equal() failed");
+ }
+ removeAll(base);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/io/File/MacPathTest.sh Thu Jul 19 21:23:53 2012 -0700
@@ -0,0 +1,39 @@
+#! /bin/sh
+
+#
+# Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+#
+OS=`uname -s`
+case "$OS" in
+ Darwin ) ;;
+ * )
+ exit 0
+ ;;
+esac
+
+if [ "x$TESTJAVA" = x ]; then
+ TESTJAVA=$1; shift
+ TESTCLASSES=.
+fi
+
+export LC_ALL=en_US.UTF-8 ;${TESTJAVA}/bin/java -cp ${TESTCLASSES} MacPathTest
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/Path/MacPathTest.java Thu Jul 19 21:23:53 2012 -0700
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 7130915
+ * @summary Tests file path with nfc/nfd forms on MacOSX
+ * @library ../
+ * @build MacPathTest
+ * @run shell MacPathTest.sh
+ */
+
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.text.*;
+import java.util.*;
+import java.util.regex.*;
+
+public class MacPathTest {
+
+ public static void main(String args[]) throws Throwable {
+ String osname = System.getProperty("os.name");
+ if (!osname.contains("OS X") && !osname.contains("Darwin"))
+ return;
+ System.out.printf("sun.jnu.encoding=%s, file.encoding=%s%n",
+ System.getProperty("file.encoding"),
+ System.getProperty("sun.jnu.encoding"));
+ // English
+ test("TestDir_apple", // test dir
+ "dir_macosx", // dir
+ "file_macosx"); // file
+
+ // Japanese composite character
+ test("TestDir_\u30c8\u30a4\u30e4\u30cb\u30ca\u30eb/",
+ "dir_\u30a4\u30c1\u30b4\u306e\u30b1\u30fc\u30ad",
+ "file_\u30a4\u30c1\u30b4\u306e\u30b1\u30fc\u30ad");
+
+ // latin-1 supplementory
+ test("TestDir_K\u00f6rperlich\u00e4\u00df/",
+ "dir_Entt\u00e4uschung",
+ "file_Entt\u00e4uschung");
+
+ test("TestDir_K\u00f6rperlich\u00e4\u00df/",
+ "dir_Entt\u00c4uschung",
+ "file_Entt\u00c4uschung");
+
+ // Korean syblla
+ test("TestDir_\uac00\uac01\uac02",
+ "dir_\uac20\uac21\uac22",
+ "file_\uacc0\uacc1\uacc2");
+ }
+
+ private static boolean equal(Object x, Object y) {
+ return x == null ? y == null : x.equals(y);
+ }
+
+ private static boolean match(Path target, Path src) {
+ String fname = target.toString();
+ System.out.printf(" --> Trying [%s], length=%d...", fname, fname.length());
+ if (target.equals(src)) {
+ System.out.println(" MATCHED!");
+ return true;
+ } else {
+ System.out.println(" NOT MATCHED!");
+ }
+ return false;
+ }
+
+ private static void test(String testdir, String dname, String fname_nfc)
+ throws Throwable
+ {
+ String fname = null;
+ String dname_nfd = Normalizer.normalize(dname, Normalizer.Form.NFD);
+ String fname_nfd = Normalizer.normalize(fname_nfc, Normalizer.Form.NFD);
+
+ System.out.printf("%n%n--------Testing...----------%n");
+ Path bpath = Paths.get(testdir);
+ Path dpath = Paths.get(testdir, dname);
+ Path dpath_nfd = Paths.get(testdir, dname_nfd);
+ Path fpath_nfc = Paths.get(testdir, fname_nfc);
+ Path fpath_nfd = Paths.get(testdir, fname_nfd);
+
+ if (Files.exists(bpath))
+ TestUtil.removeAll(bpath);
+ Files.createDirectories(dpath);
+
+ fname = dpath.toString();
+ System.out.printf(":Directory [%s][len=%d] created%n", fname, fname.length());
+
+ //////////////////////////////////////////////////////////////
+ if (!Files.isDirectory(dpath) || !Files.isDirectory(dpath_nfd)) {
+ throw new RuntimeException("Files.isDirectory(...) failed");
+ }
+
+ //////////////////////////////////////////////////////////////
+ // write out with nfd, read in with nfc + case
+ Files.write(fpath_nfd, new byte[] { 'n', 'f', 'd'});
+ System.out.println(" read in with nfc (from nfd):" + new String(Files.readAllBytes(fpath_nfc)));
+
+ // check attrs with nfc + case
+ Set<PosixFilePermission> pfp = Files.getPosixFilePermissions(fpath_nfd);
+ if (!equal(pfp, Files.getPosixFilePermissions(fpath_nfc)) ) {
+ throw new RuntimeException("Files.getPosixfilePermission(...) failed");
+ }
+ Files.delete(fpath_nfd);
+
+ // write out with nfc, read in with nfd + case
+ Files.write(fpath_nfc, new byte[] { 'n', 'f', 'c'});
+ System.out.println(" read in with nfd (from nfc):" + new String(Files.readAllBytes(fpath_nfd)));
+
+ // check attrs with nfc + case
+ pfp = Files.getPosixFilePermissions(fpath_nfc);
+ if (!equal(pfp, Files.getPosixFilePermissions(fpath_nfd))) {
+ throw new RuntimeException("Files.getPosixfilePermission(...) failed");
+ }
+ //////////////////////////////////////////////////////////////
+ boolean found_dir = false;
+ boolean found_file_nfc = false;
+ boolean found_file_nfd = false;
+ try (DirectoryStream<Path> stream = Files.newDirectoryStream(bpath)) {
+ for (Path path: stream) {
+ fname = path.toString();
+ System.out.printf("Found : [%s], length=%d%n", fname, fname.length());
+ found_dir |= match(dpath, path);
+ found_file_nfc |= match(fpath_nfc, path);
+ found_file_nfd |= match(fpath_nfd, path);
+ }
+ }
+ if (!found_dir || !found_file_nfc || !found_file_nfd) {
+ throw new RuntimeException("File.equal() failed");
+ }
+ // glob
+ String glob = "*" + fname_nfd.substring(2); // remove leading "FI" from "FILE..."
+ System.out.println("glob=" + glob);
+ boolean globmatched = false;
+ try (DirectoryStream<Path> stream = Files.newDirectoryStream(bpath, glob)) {
+ for (Path path: stream) {
+ fname = path.toString();
+ System.out.printf("PathMatch : [%s], length=%d%n", fname, fname.length());
+ globmatched |= match(fpath_nfc, path);
+ }
+ }
+ if (!globmatched) {
+ //throw new RuntimeException("path matcher failed");
+ // it appears we have a regex.anon_eq bug in hangul syllable handling
+ System.out.printf("pathmatcher failed, glob=[%s]%n", glob);
+ System.out.printf(" -> fname_nfd.matches(fname_nfc)=%b%n",
+ Pattern.compile(fname_nfd, Pattern.CANON_EQ)
+ .matcher(fname_nfc)
+ .matches());
+ System.out.printf(" -> fname_nfc.matches(fname_nfd)=%b%n",
+ Pattern.compile(fname_nfc, Pattern.CANON_EQ)
+ .matcher(fname_nfd)
+ .matches());
+ }
+ TestUtil.removeAll(bpath);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/Path/MacPathTest.sh Thu Jul 19 21:23:53 2012 -0700
@@ -0,0 +1,39 @@
+#! /bin/sh
+
+#
+# Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+#
+OS=`uname -s`
+case "$OS" in
+ Darwin ) ;;
+ * )
+ exit 0
+ ;;
+esac
+
+if [ "x$TESTJAVA" = x ]; then
+ TESTJAVA=$1; shift
+ TESTCLASSES=.
+fi
+
+export LC_ALL=en_US.UTF-8; ${TESTJAVA}/bin/java -cp ${TESTCLASSES} MacPathTest