The current BsdFileSystem.getMountEntries() implementation parses /etc/fstab. Apple doesn't use /etc/fstab so that wont work for Apple, however all BSD's and Apple have getfsstat(2). Please test the attached patch on OS X to see if it makes the following test program work:
*** MountTest.java ***: import java.util.*; import java.io.*; import java.nio.file.*; import java.nio.file.attribute.*; class MountTest { public static void main(String[] a) { for (FileStore store: FileSystems.getDefault().getFileStores()) { System.out.println("FileStore: " + store); System.out.println(" type: " + store.type() + " isReadOnly: " + store.isReadOnly()); try { FileStoreSpaceAttributes attrs = Attributes.readFileStoreSpaceAttributes( store); long total = attrs.totalSpace() / 1024; long used = (attrs.totalSpace() - attrs.unallocatedSpace()) / 1024; long avail = attrs.usableSpace() / 1024; System.out.format(" total %12d used %12d avail %12d%n", total, used, ava il); } catch(IOException ex) { ex.printStackTrace(); } } } }
diff -r edf86ee176b8 make/java/nio/Makefile --- a/make/java/nio/Makefile Fri May 22 13:55:33 2009 -0700 +++ b/make/java/nio/Makefile Tue May 26 09:02:25 2009 -0400 @@ -275,6 +275,7 @@ sun/nio/fs/BsdFileStore.java \ sun/nio/fs/BsdFileSystem.java \ sun/nio/fs/BsdFileSystemProvider.java \ + sun/nio/fs/BsdNativeDispatcher.java \ sun/nio/fs/PollingWatchService.java \ sun/nio/fs/UnixChannelFactory.java \ sun/nio/fs/UnixCopyFile.java \ @@ -303,6 +304,7 @@ UnixAsynchronousSocketChannelImpl.c \ \ GnomeFileTypeDetector.c \ + BsdNativeDispatcher.c \ UnixCopyFile.c \ UnixNativeDispatcher.c @@ -313,6 +315,7 @@ sun/nio/ch/UnixAsynchronousSocketChannelImpl.java \ \ sun/nio/fs/GnomeFileTypeDetector.java \ + sun/nio/fs/BsdNativeDispatcher.java \ sun/nio/fs/UnixCopyFile.java \ sun/nio/fs/UnixNativeDispatcher.java diff -r edf86ee176b8 make/java/nio/mapfile-bsd --- a/make/java/nio/mapfile-bsd Fri May 22 13:55:33 2009 -0700 +++ b/make/java/nio/mapfile-bsd Tue May 26 09:02:25 2009 -0400 @@ -36,25 +36,6 @@ Java_sun_nio_ch_DatagramDispatcher_readv0; Java_sun_nio_ch_DatagramDispatcher_write0; Java_sun_nio_ch_DatagramDispatcher_writev0; - Java_sun_nio_ch_EPollArrayWrapper_epollCreate; - Java_sun_nio_ch_EPollArrayWrapper_epollCtl; - Java_sun_nio_ch_EPollArrayWrapper_epollWait; - Java_sun_nio_ch_EPollArrayWrapper_fdLimit; - Java_sun_nio_ch_EPollArrayWrapper_init; - Java_sun_nio_ch_EPollArrayWrapper_interrupt; - Java_sun_nio_ch_EPollArrayWrapper_offsetofData; - Java_sun_nio_ch_EPollArrayWrapper_sizeofEPollEvent; - Java_sun_nio_ch_EPoll_init; - Java_sun_nio_ch_EPoll_eventSize; - Java_sun_nio_ch_EPoll_eventsOffset; - Java_sun_nio_ch_EPoll_dataOffset; - Java_sun_nio_ch_EPoll_epollCreate; - Java_sun_nio_ch_EPoll_epollCtl; - Java_sun_nio_ch_EPoll_epollWait; - Java_sun_nio_ch_EPollPort_close0; - Java_sun_nio_ch_EPollPort_drain1; - Java_sun_nio_ch_EPollPort_interrupt; - Java_sun_nio_ch_EPollPort_socketpair; Java_sun_nio_ch_FileChannelImpl_close0; Java_sun_nio_ch_FileChannelImpl_initIDs; Java_sun_nio_ch_FileChannelImpl_map0; @@ -126,23 +107,11 @@ Java_sun_nio_fs_GnomeFileTypeDetector_probeUsingGio; Java_sun_nio_fs_GnomeFileTypeDetector_initializeGnomeVfs; Java_sun_nio_fs_GnomeFileTypeDetector_probeUsingGnomeVfs; - Java_sun_nio_fs_BsdWatchService_init; - Java_sun_nio_fs_BsdWatchService_eventSize; - Java_sun_nio_fs_BsdWatchService_eventOffsets; - Java_sun_nio_fs_BsdWatchService_inotifyInit; - Java_sun_nio_fs_BsdWatchService_inotifyAddWatch; - Java_sun_nio_fs_BsdWatchService_inotifyRmWatch; - Java_sun_nio_fs_BsdWatchService_configureBlocking; - Java_sun_nio_fs_BsdWatchService_socketpair; - Java_sun_nio_fs_BsdWatchService_poll; - Java_sun_nio_fs_BsdNativeDispatcher_init; - Java_sun_nio_fs_BsdNativeDispatcher_fgetxattr0; - Java_sun_nio_fs_BsdNativeDispatcher_flistxattr; - Java_sun_nio_fs_BsdNativeDispatcher_fsetxattr0; - Java_sun_nio_fs_BsdNativeDispatcher_fremovexattr0; - Java_sun_nio_fs_BsdNativeDispatcher_setmntent0; - Java_sun_nio_fs_BsdNativeDispatcher_endmntent; Java_sun_nio_fs_UnixNativeDispatcher_initIDs; + Java_sun_nio_fs_BsdNativeDispatcher_initIDs; + Java_sun_nio_fs_BsdNativeDispatcher_getfsstat; + Java_sun_nio_fs_BsdNativeDispatcher_fsstatEntry; + Java_sun_nio_fs_BsdNativeDispatcher_endfsstat; Java_sun_nio_fs_UnixNativeDispatcher_getcwd; Java_sun_nio_fs_UnixNativeDispatcher_strerror; Java_sun_nio_fs_UnixNativeDispatcher_dup; diff -r edf86ee176b8 src/solaris/classes/sun/nio/fs/BsdFileSystem.java --- a/src/solaris/classes/sun/nio/fs/BsdFileSystem.java Fri May 22 13:55:33 2009 -0700 +++ b/src/solaris/classes/sun/nio/fs/BsdFileSystem.java Tue May 26 09:02:25 2009 -0400 @@ -31,7 +31,6 @@ import java.util.*; import java.security.AccessController; import sun.security.action.GetPropertyAction; -import static sun.nio.fs.UnixNativeDispatcher.*; /** * Bsd implementation of FileSystem @@ -95,24 +94,23 @@ } /** - * Returns object to iterate over entries in /etc/fstab + * Returns object to iterate over mount entries */ @Override Iterable<UnixMountEntry> getMountEntries() { ArrayList<UnixMountEntry> entries = new ArrayList<UnixMountEntry>(); try { - UnixPath fstab = new UnixPath(this, "/etc/fstab"); - long fp = fopen(fstab, "r"); + long iter = BsdNativeDispatcher.getfsstat(); try { for (;;) { UnixMountEntry entry = new UnixMountEntry(); - int res = getextmntent(fp, entry); + int res = BsdNativeDispatcher.fsstatEntry(iter, entry); if (res < 0) break; entries.add(entry); } } finally { - fclose(fp); + BsdNativeDispatcher.endfsstat(iter); } } catch (UnixException x) { diff -r edf86ee176b8 src/solaris/classes/sun/nio/fs/BsdNativeDispatcher.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/solaris/classes/sun/nio/fs/BsdNativeDispatcher.java Tue May 26 09:02:25 2009 -0400 @@ -0,0 +1,65 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.security.AccessController; +import java.security.PrivilegedAction; + +/** + * Bsd specific system calls. + */ + +class BsdNativeDispatcher extends UnixNativeDispatcher { + private BsdNativeDispatcher() { } + + /** + * struct fsstat_iter *getfsstat(); + */ + static native long getfsstat() throws UnixException; + + /** + * int fsstatEntry(struct fsstat_iter * iter, UnixMountEntry entry); + */ + static native int fsstatEntry(long iter, UnixMountEntry entry) + throws UnixException; + + /** + * void endfsstat(struct fsstat_iter * iter); + */ + static native void endfsstat(long iter) throws UnixException; + + // initialize field IDs + private static native void initIDs(); + + static { + AccessController.doPrivileged(new PrivilegedAction<Void>() { + public Void run() { + System.loadLibrary("nio"); + return null; + }}); + initIDs(); + } +} diff -r edf86ee176b8 src/solaris/native/sun/nio/fs/BsdNativeDispatcher.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/solaris/native/sun/nio/fs/BsdNativeDispatcher.c Tue May 26 09:02:25 2009 -0400 @@ -0,0 +1,201 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +#include "jni.h" +#include "jni_util.h" +#include "jvm.h" +#include "jlong.h" + +#include <sys/param.h> +#include <sys/mount.h> + +#include <stdlib.h> +#include <string.h> + +static jfieldID entry_name; +static jfieldID entry_dir; +static jfieldID entry_fstype; +static jfieldID entry_options; +static jfieldID entry_dev; + +struct fsstat_iter { + struct statfs *buf; + int pos; + int nentries; +}; + +#include "sun_nio_fs_BsdNativeDispatcher.h" + +static void throwUnixException(JNIEnv* env, int errnum) { + jobject x = JNU_NewObjectByName(env, "sun/nio/fs/UnixException", + "(I)V", errnum); + if (x != NULL) { + (*env)->Throw(env, x); + } +} + +/** + * Initialize jfieldIDs + */ +JNIEXPORT void JNICALL +Java_sun_nio_fs_BsdNativeDispatcher_initIDs(JNIEnv* env, jclass this) +{ + jclass clazz; + + clazz = (*env)->FindClass(env, "sun/nio/fs/UnixMountEntry"); + if (clazz == NULL) { + return; + } + entry_name = (*env)->GetFieldID(env, clazz, "name", "[B"); + entry_dir = (*env)->GetFieldID(env, clazz, "dir", "[B"); + entry_fstype = (*env)->GetFieldID(env, clazz, "fstype", "[B"); + entry_options = (*env)->GetFieldID(env, clazz, "opts", "[B"); + entry_dev = (*env)->GetFieldID(env, clazz, "dev", "J"); +} + +JNIEXPORT jlong JNICALL +Java_sun_nio_fs_BsdNativeDispatcher_getfsstat(JNIEnv* env, jclass this) +{ + int nentries; + size_t bufsize; + struct fsstat_iter *iter = (struct fsstat_iter *)malloc(sizeof(*iter)); + + if (iter == NULL) { + JNU_ThrowOutOfMemoryError(env, "native heap"); + return NULL; + } + + iter->pos = 0; + iter->nentries = 0; + iter->buf = NULL; + + nentries = getfsstat(NULL, 0, MNT_NOWAIT); + + if (nentries <= 0) { + free(iter); + throwUnixException(env, errno); + return NULL; + } + + // It's possible that a new filesystem gets mounted between + // the first getfsstat and the second so loop until consistant + + while (nentries != iter->nentries) { + if (iter->buf != NULL) + free(iter->buf); + + bufsize = nentries * sizeof(struct statfs); + iter->nentries = nentries; + + iter->buf = (struct statfs *)malloc(bufsize); + if (iter->buf == NULL) { + free(iter); + JNU_ThrowOutOfMemoryError(env, "native heap"); + return NULL; + } + + nentries = getfsstat(iter->buf, bufsize, MNT_WAIT); + if (nentries <= 0) { + free(iter->buf); + free(iter); + throwUnixException(env, errno); + return NULL; + } + } + + return (jlong)iter; +} + +JNIEXPORT jint JNICALL +Java_sun_nio_fs_BsdNativeDispatcher_fsstatEntry(JNIEnv* env, jclass this, + jlong value, jobject entry) +{ + struct fsstat_iter *iter = jlong_to_ptr(value); + jsize len; + jbyteArray bytes; + char* name; + char* dir; + char* fstype; + char* options; + dev_t dev; + + if (iter == NULL || iter->pos >= iter->nentries) + return -1; + + name = iter->buf[iter->pos].f_mntfromname; + dir = iter->buf[iter->pos].f_mntonname; + fstype = iter->buf[iter->pos].f_fstypename; + if (iter->buf[iter->pos].f_flags & MNT_RDONLY) + options="ro"; + else + options=""; + dev = 0; + + iter->pos++; + + len = strlen(name); + bytes = (*env)->NewByteArray(env, len); + if (bytes == NULL) + return -1; + (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)name); + (*env)->SetObjectField(env, entry, entry_name, bytes); + + len = strlen(dir); + bytes = (*env)->NewByteArray(env, len); + if (bytes == NULL) + return -1; + (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)dir); + (*env)->SetObjectField(env, entry, entry_dir, bytes); + + len = strlen(fstype); + bytes = (*env)->NewByteArray(env, len); + if (bytes == NULL) + return -1; + (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)fstype); + (*env)->SetObjectField(env, entry, entry_fstype, bytes); + + len = strlen(options); + bytes = (*env)->NewByteArray(env, len); + if (bytes == NULL) + return -1; + (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)options); + (*env)->SetObjectField(env, entry, entry_options, bytes); + + if (dev != 0) + (*env)->SetLongField(env, entry, entry_dev, (jlong)dev); + + return 0; +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_BsdNativeDispatcher_endfsstat(JNIEnv* env, jclass this, jlong value) +{ + struct fsstat_iter *iter = jlong_to_ptr(value); + + if (iter != NULL) { + free(iter->buf); + free(iter); + } +}