--- /dev/null 2012-06-25 21:56:10.000000000 -0700 +++ new/src/solaris/classes/java/io/MacOSXFileSystem.java 2012-06-25 21:56:10.000000000 -0700 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 1998, 2010, 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 java.io; + +import java.util.Locale; + +class MacOSXFileSystem extends UnixFileSystem { + + @Override + public int compare(File f1, File f2) { + return f1.getPath().compareToIgnoreCase(f2.getPath()); + } + + @Override + public int hashCode(File f) { + return f.getPath().toLowerCase(Locale.ENGLISH).hash32() ^ 1234321; + } + +} --- old/src/share/native/java/io/io_util.h 2012-06-25 21:56:11.000000000 -0700 +++ new/src/share/native/java/io/io_util.h 2012-06-25 21:56:10.000000000 -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. --- old/src/solaris/native/java/io/FileSystem_md.c 2012-06-25 21:56:11.000000000 -0700 +++ new/src/solaris/native/java/io/FileSystem_md.c 2012-06-25 21:56:11.000000000 -0700 @@ -31,5 +31,9 @@ JNIEXPORT jobject JNICALL Java_java_io_FileSystem_getFileSystem(JNIEnv *env, jclass ignored) { +#ifdef MACOSX + return JNU_NewObjectByName(env, "java/io/MacOSXFileSystem", "()V"); +#else return JNU_NewObjectByName(env, "java/io/UnixFileSystem", "()V"); +#endif } --- old/src/solaris/native/java/io/UnixFileSystem_md.c 2012-06-25 21:56:12.000000000 -0700 +++ new/src/solaris/native/java/io/UnixFileSystem_md.c 2012-06-25 21:56:12.000000000 -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); --- old/src/solaris/native/java/io/io_util_md.c 2012-06-25 21:56:13.000000000 -0700 +++ new/src/solaris/native/java/io/io_util_md.c 2012-06-25 21:56:12.000000000 -0700 @@ -34,37 +34,25 @@ #include -static inline char *convertToNFD(const char *path, char *buf, size_t bufsize) -{ - 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) +jstring newStringPlatform(JNIEnv *env, const char* str) { - 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); + 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) { + if (CFStringGetCString(csref, chars, ulen, kCFStringEncodingUTF16)) { + rv = (*env)->NewString(env, (jchar*)chars, clen); } + free(chars); } - - return (char *)origPath; + CFRelease(csref); + return rv; } - #endif void --- old/src/solaris/native/java/io/io_util_md.h 2012-06-25 21:56:13.000000000 -0700 +++ new/src/solaris/native/java/io/io_util_md.h 2012-06-25 21:56:13.000000000 -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 --- old/src/solaris/classes/sun/nio/fs/DefaultFileSystemProvider.java 2012-06-25 21:56:14.000000000 -0700 +++ new/src/solaris/classes/sun/nio/fs/DefaultFileSystemProvider.java 2012-06-25 21:56:14.000000000 -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"); } } --- old/src/solaris/classes/sun/nio/fs/BsdNativeDispatcher.java 2012-06-25 21:56:15.000000000 -0700 +++ new/src/solaris/classes/sun/nio/fs/BsdNativeDispatcher.java 2012-06-25 21:56:15.000000000 -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() { - public Void run() { - System.loadLibrary("nio"); - return null; - }}); - initIDs(); + initIDs(); } } --- old/src/solaris/classes/sun/nio/fs/UnixFileSystem.java 2012-06-25 21:56:16.000000000 -0700 +++ new/src/solaris/classes/sun/nio/fs/UnixFileSystem.java 2012-06-25 21:56:15.000000000 -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,39 @@ }; } + // BsdFileSystem overrides following methods for MacOSX path + Pattern compilePathMatchPattern(String expr) { + return Pattern.compile(expr); + } + + char[] normalizeNativePath(char[] path) { + return path; + } + + String normalizeJavaPath(String path) { + return path; + } + + public int hashCodePath(UnixPath path) { + return sun.misc.Hashing.murmur3_32(path.asByteArray()); + } + + int comparePaths(UnixPath path1, UnixPath path2) { + byte[] v1 = path1.asByteArray(); + byte[] v2 = path2.asByteArray(); + int len1 = v1.length; + int len2 = v2.length; + int n = Math.min(len1, len2); + int k = 0; + while (k < n) { + int c1 = v1[k] & 0xff; + int c2 = v2[k] & 0xff; + if (c1 != c2) { + return c1 - c2; + } + k++; + } + return len1 - len2; + } + } --- old/src/solaris/classes/sun/nio/fs/UnixPath.java 2012-06-25 21:56:16.000000000 -0700 +++ new/src/solaris/classes/sun/nio/fs/UnixPath.java 2012-06-25 21:56:16.000000000 -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 ref = encoder.get(); CharsetEncoder ce = (ref != null) ? ref.get() : null; if (ce == null) { @@ -126,7 +126,7 @@ encoder.set(new SoftReference(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())]; @@ -714,23 +714,7 @@ @Override public int compareTo(Path other) { - int len1 = path.length; - int len2 = ((UnixPath) other).path.length; - - int n = Math.min(len1, len2); - byte v1[] = path; - byte v2[] = ((UnixPath) other).path; - - int k = 0; - while (k < n) { - int c1 = v1[k] & 0xff; - int c2 = v2[k] & 0xff; - if (c1 != c2) { - return c1 - c2; - } - k++; - } - return len1 - len2; + return fs.comparePaths(this, (UnixPath) other); } @Override @@ -744,21 +728,18 @@ @Override public int hashCode() { // OK if two or more threads compute hash - int h = hash; - if (h == 0) { - for (int i = 0; i< path.length; i++) { - h = 31*h + (path[i] & 0xff); - } - hash = h; + if (hash == 0) { + hash = fs.hashCodePath(this); } - return h; + return hash; } @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; } --- /dev/null 2012-06-25 21:56:17.000000000 -0700 +++ new/src/solaris/classes/sun/nio/fs/MacOSXFileSystemProvider.java 2012-06-25 21:56:17.000000000 -0700 @@ -0,0 +1,50 @@ +/* + * 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); + } + + @Override + MacOSXFileStore getFileStore(UnixPath path) throws IOException { + return new MacOSXFileStore(path); + } +} --- /dev/null 2012-06-25 21:56:18.000000000 -0700 +++ new/src/solaris/classes/sun/nio/fs/MacOSXFileSystem.java 2012-06-25 21:56:17.000000000 -0700 @@ -0,0 +1,84 @@ +/* + * 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); + } + + char[] normalizeNativePath(char[] path) { + for (char c : path) { + if (c > 0x80) + return normalizepath(path, kCFStringNormalizationFormD); + } + return path; + } + + String normalizeJavaPath(String path) { + char[] chars = path.toCharArray(); // TBD: optimize + for (int i = 0; i < path.length(); i++) { + if (path.charAt(i) > 0x80) + return new String(normalizepath(path.toCharArray(), + kCFStringNormalizationFormC)); + } + return path; + } + + public int hashCodePath(UnixPath path) { + return path.toString().toLowerCase(Locale.ENGLISH).hash32(); + } + + int comparePaths(UnixPath path1, UnixPath path2) { + return path1.toString().compareToIgnoreCase(path2.toString()); + } + + // match in unicode_case_insensitive + Pattern compilePathMatchPattern(String expr) { + return Pattern.compile(expr, + Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE | Pattern.CANON_EQ) ; + } + + @Override + FileStore getFileStore(UnixMountEntry entry) throws IOException { + return new MacOSXFileStore(this, entry); + } + +} --- /dev/null 2012-06-25 21:56:18.000000000 -0700 +++ new/src/solaris/classes/sun/nio/fs/MacOSXFileStore.java 2012-06-25 21:56:18.000000000 -0700 @@ -0,0 +1,46 @@ +/* + * 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 FileStore + */ + +class MacOSXFileStore + extends BsdFileStore +{ + MacOSXFileStore(UnixPath file) throws IOException { + super(file); + } + + MacOSXFileStore(UnixFileSystem fs, UnixMountEntry entry) throws IOException { + super(fs, entry); + } +} --- /dev/null 2012-06-25 21:56:19.000000000 -0700 +++ new/src/solaris/classes/sun/nio/fs/MacOSXNativeDispatcher.java 2012-06-25 21:56:19.000000000 -0700 @@ -0,0 +1,52 @@ +/* + * 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() { } + + final static int kCFStringNormalizationFormC = 2; + final static int kCFStringNormalizationFormD = 0; + static native char[] normalizepath(char[] path, int form); + /* + static native boolean isCaseSensitive0(long pathAddr); + static boolean isCaseSensitive(UnixPath path) { + NativeBuffer buffer = copyToNativeBuffer(path); + return isCaseSensitive0(buffer.address()); + } + */ +} + + + + --- /dev/null 2012-06-25 21:56:20.000000000 -0700 +++ new/src/solaris/native/sun/nio/fs/MacOSXNativeDispatcher.c 2012-06-25 21:56:19.000000000 -0700 @@ -0,0 +1,92 @@ +/* + * 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 +#include + +#include +#include + +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); + 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) { + 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; +} + +/* +JNIEXPORT jboolean JNICALL +Java_sun_nio_fs_MacOSXNativeDispatcher_isCaseSensitive0(JNIEnv* env, jclass this, + jlong pathAddress) +{ + const char* path = (const char*)jlong_to_ptr(pathAddress); + OSStatus err; + FSRef volRef; + FSCatalogInfo volCatInfo; + GetVolParmsInfoBuffer volParms; + + if (noErr == FSPathMakeRef((const UInt8 *) path, &volRef, NULL) && + noErr == FSGetCatalogInfo(&volRef, kFSCatInfoVolume, &volCatInfo, NULL, NULL, NULL) && + noErr == FSGetVolumeParms(volCatInfo.volume, &volParms, sizeof(volParms))) { + return volParms.vMExtendedAttributes & (1L << bIsCaseSensitive) != 0; + } else { + return false; // default + } +} +*/ + + --- /dev/null 2012-06-25 21:56:20.000000000 -0700 +++ new/test/java/io/File/MacPathTest.java 2012-06-25 21:56:20.000000000 -0700 @@ -0,0 +1,201 @@ +/* + * 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 7168427 + * @summary Tests file path with nfc/nfd forms and high/low cases on MacOSX + * @library .. + */ + +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 + "DIR_MacOSx", // dir_case + "file_macosx", // file + "FILE_MaCoSx"); // file_case + + // Japanese composite character + test("TestDir_\u30c8\u30a4\u30e4\u30cb\u30ca\u30eb/", + "dir_\u30a4\u30c1\u30b4\u306e\u30b1\u30fc\u30ad", + "DIR_\u30a4\u30c1\u30b4\u306e\u30b1\u30fc\u30ad", + "file_\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", + "DIR_entT\u00c4uschunG", + "file_Entt\u00e4uschung", + "FILE_eNtT\u00c4uScHuNg"); + + test("TestDir_K\u00f6rperlich\u00e4\u00df/", + "dir_Entt\u00c4uschung", + "DIR_entT\u00e4uschunG", + "file_Entt\u00c4uschung", + "FILE_eNtT\u00e4uScHuNg"); + + // Korean syblla + test("TestDir_\uac00\uac01\uac02", + "dir_\uac20\uac21\uac22", + "DIR_\uac20\uac21\uac22", + "file_\uacc0\uacc1\uacc2", + "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 dname_case, + String fname_nfc, String fname_nfc_case) + throws Throwable + { + String fname = null; + String fname_nfd = Normalizer.normalize(fname_nfc, Normalizer.Form.NFD); + String fname_nfd_case = Normalizer.normalize(fname_nfc_case, Normalizer.Form.NFD); + + String dname_nfd = Normalizer.normalize(dname, Normalizer.Form.NFD); + String dname_case_nfd = Normalizer.normalize(dname_case, 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 dir_case = new File(base, dname_case); + File dir_case_nfd = new File(base, dname_case_nfd); + File file_nfc = new File(base, fname_nfc); + File file_nfd = new File(base, fname_nfd); + File file_nfc_case = new File(base, fname_nfc_case); + File file_nfd_case = new File(base, fname_nfd_case); + + 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("dir_case :[%s][len=%d]%n", dname_case, dname_case.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()); + System.out.printf("fname_nfc_case :[%s][len=%d]%n", fname_nfc_case, fname_nfc_case.length()); + System.out.printf("fname_nfd_case :[%s][len=%d]%n", fname_nfd_case, fname_nfd_case.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() || + !dir_case.isDirectory() || !dir_case_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); + open_read("read in with nfc_case (from nfc)", file_nfc_case); + open_read("read in with nfd_case (from nfc)", file_nfd_case); + 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); + open_read("read in with nfd_case (from nfc)", file_nfd_case); + open_read("read in with nfc_case (from nfc)", file_nfc_case); + //file_nfc.delete(); + + ////////////////////////////////////////////////////////////// + boolean found_dir = false; + boolean found_dir_case = false; + boolean found_file_nfc = false; + boolean found_file_nfd = false; + boolean found_file_nfc_case = false; + boolean found_file_nfd_case = 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_dir_case |= match(dir_case, f); + found_file_nfc |= match(file_nfc, f); + found_file_nfd |= match(file_nfd, f); + found_file_nfc_case |= match(file_nfc_case, f); + found_file_nfd_case |= match(file_nfd_case, f); + } + + if (!found_dir || !found_dir_case || + !found_file_nfc || !found_file_nfc || + !found_file_nfc_case || !found_file_nfc_case) { + throw new RuntimeException("File.equal() failed"); + } + removeAll(base); + } +} --- /dev/null 2012-06-25 21:56:21.000000000 -0700 +++ new/test/java/nio/file/Path/MacPathTest.java 2012-06-25 21:56:21.000000000 -0700 @@ -0,0 +1,220 @@ +/* + * 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 7168427 + * @summary Tests file path with nfc/nfd forms and high/low cases on MacOSX + * @library .. + */ + +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; + + // English + test("TestDir_apple", // test dir + "dir_macosx", // dir + "DIR_MacOSx", // dir_case + "file_macosx", // file + "FILE_MaCoSx"); // file_case + + // Japanese composite character + test("TestDir_\u30c8\u30a4\u30e4\u30cb\u30ca\u30eb/", + "dir_\u30a4\u30c1\u30b4\u306e\u30b1\u30fc\u30ad", + "DIR_\u30a4\u30c1\u30b4\u306e\u30b1\u30fc\u30ad", + "file_\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", + "DIR_entT\u00c4uschunG", + "file_Entt\u00e4uschung", + "FILE_eNtT\u00c4uScHuNg"); + + test("TestDir_K\u00f6rperlich\u00e4\u00df/", + "dir_Entt\u00c4uschung", + "DIR_entT\u00e4uschunG", + "file_Entt\u00c4uschung", + "FILE_eNtT\u00e4uScHuNg"); + + // Korean syblla + test("TestDir_\uac00\uac01\uac02", + "dir_\uac20\uac21\uac22", + "DIR_\uac20\uac21\uac22", + "file_\uacc0\uacc1\uacc2", + "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 dname_case, + String fname_nfc, String fname_nfc_case) + throws Throwable + { + String fname = null; + String fname_nfd = Normalizer.normalize(fname_nfc, Normalizer.Form.NFD); + String fname_nfd_case = Normalizer.normalize(fname_nfc_case, Normalizer.Form.NFD); + + String dname_nfd = Normalizer.normalize(dname, Normalizer.Form.NFD); + String dname_case_nfd = Normalizer.normalize(dname_case, 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 dpath_case = Paths.get(testdir, dname_case); + Path dpath_case_nfd = Paths.get(testdir, dname_case_nfd); + Path fpath_nfc = Paths.get(testdir, fname_nfc); + Path fpath_nfd = Paths.get(testdir, fname_nfd); + Path fpath_nfc_case = Paths.get(testdir, fname_nfc); + Path fpath_nfd_case = Paths.get(testdir, fname_nfd); + + if (Files.exists(bpath)) + TestUtil.removeAll(bpath); + Files.createDirectories(dpath); + + try { + Files.createDirectory(dpath_case); + throw new RuntimeException("Files.createDirectory() did NOT failed"); + } catch (FileAlreadyExistsException faee) { + // expected + System.out.println("FAEE thrown as Expected"); + } + + fname = dpath.toString(); + System.out.printf(":Directory [%s][len=%d] created%n", fname, fname.length()); + + ////////////////////////////////////////////////////////////// + if (!Files.isDirectory(dpath) || !Files.isDirectory(dpath_nfd) || + !Files.isDirectory(dpath_case) || !Files.isDirectory(dpath_case_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))); + System.out.println(" read in with nfc_case (from nfd):" + new String(Files.readAllBytes(fpath_nfc_case))); + System.out.println(" read in with nfd_case (from nfd):" + new String(Files.readAllBytes(fpath_nfd_case))); + + // check attrs with nfc + case + Set pfp = Files.getPosixFilePermissions(fpath_nfd); + if (!equal(pfp, Files.getPosixFilePermissions(fpath_nfc)) || + !equal(pfp, Files.getPosixFilePermissions(fpath_nfc_case)) || + !equal(pfp, Files.getPosixFilePermissions(fpath_nfd_case))) { + 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))); + System.out.println(" read in with nfd_case (from nfc):" + new String(Files.readAllBytes(fpath_nfd_case))); + System.out.println(" read in with nfc_case (from nfc):" + new String(Files.readAllBytes(fpath_nfc_case))); + + // check attrs with nfc + case + pfp = Files.getPosixFilePermissions(fpath_nfc); + if (!equal(pfp, Files.getPosixFilePermissions(fpath_nfd)) || + !equal(pfp, Files.getPosixFilePermissions(fpath_nfd_case)) || + !equal(pfp, Files.getPosixFilePermissions(fpath_nfc_case))) { + throw new RuntimeException("Files.getPosixfilePermission(...) failed"); + } + ////////////////////////////////////////////////////////////// + boolean found_dir = false; + boolean found_dir_case = false; + boolean found_file_nfc = false; + boolean found_file_nfd = false; + boolean found_file_nfc_case = false; + boolean found_file_nfd_case = false; + try (DirectoryStream 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_dir_case |= match(dpath_case, path); + found_file_nfc |= match(fpath_nfc, path); + found_file_nfd |= match(fpath_nfd, path); + found_file_nfc_case |= match(fpath_nfc_case, path); + found_file_nfd_case |= match(fpath_nfd_case, path); + } + } + if (!found_dir || !found_dir_case || + !found_file_nfc || !found_file_nfd || + !found_file_nfc_case || !found_file_nfd_case) { + throw new RuntimeException("File.equal() failed"); + } + + // glob + String glob = "*" + fname_nfd_case.substring(2); // remove leading "FI" from "FILE..." + System.out.println("glob=" + glob); + boolean globmatched = false; + try (DirectoryStream 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.UNICODE_CASE | Pattern.CANON_EQ) + .matcher(fname_nfc) + .matches()); + System.out.printf(" -> fname_nfc.matches(fname_nfd)=%b%n", + Pattern.compile(fname_nfc, Pattern.UNICODE_CASE | Pattern.CANON_EQ) + .matcher(fname_nfd) + .matches()); + } + + TestUtil.removeAll(bpath); + } +} + --- old/make/java/java/Makefile 2012-06-25 21:56:22.000000000 -0700 +++ new/make/java/java/Makefile 2012-06-25 21:56:21.000000000 -0700 @@ -83,6 +83,7 @@ else # PLATFORM FILES_java += java/lang/UNIXProcess.java \ java/io/UnixFileSystem.java \ + java/io/MacOSXFileSystem.java \ java/util/prefs/FileSystemPreferences.java \ java/util/prefs/FileSystemPreferencesFactory.java \ --- old/make/java/nio/Makefile 2012-06-25 21:56:22.000000000 -0700 +++ new/make/java/nio/Makefile 2012-06-25 21:56:22.000000000 -0700 @@ -282,6 +282,10 @@ 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/MacOSXFileStore.java \ + sun/nio/fs/MacOSXNativeDispatcher.java \ sun/nio/fs/PollingWatchService.java \ sun/nio/fs/UnixChannelFactory.java \ sun/nio/fs/UnixCopyFile.java \ @@ -311,6 +315,7 @@ \ GnomeFileTypeDetector.c \ BsdNativeDispatcher.c \ + MacOSXNativeDispatcher.c \ UnixCopyFile.c \ UnixNativeDispatcher.c \ \ @@ -385,7 +390,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 \