1 /* 2 * Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved. 3 * Copyright (c) 2013, 2019 SAP SE. All rights reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. Oracle designates this 9 * particular file as subject to the "Classpath" exception as provided 10 * by Oracle in the LICENSE file that accompanied this code. 11 * 12 * This code is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 * version 2 for more details (a copy is included in the LICENSE file that 16 * accompanied this code). 17 * 18 * You should have received a copy of the GNU General Public License version 19 * 2 along with this work; if not, write to the Free Software Foundation, 20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 * 22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 * or visit www.oracle.com if you need additional information or have any 24 * questions. 25 */ 26 27 #include <stdlib.h> 28 #include <string.h> 29 #include <errno.h> 30 #include <sys/types.h> 31 #include <sys/mntctl.h> 32 33 #include "jni.h" 34 #include "jni_util.h" 35 36 #include "sun_nio_fs_AixNativeDispatcher.h" 37 38 static jfieldID entry_name; 39 static jfieldID entry_dir; 40 static jfieldID entry_fstype; 41 static jfieldID entry_options; 42 43 static jclass entry_cls; 44 45 /** 46 * Call this to throw an internal UnixException when a system/library 47 * call fails 48 */ 49 static void throwUnixException(JNIEnv* env, int errnum) { 50 jobject x = JNU_NewObjectByName(env, "sun/nio/fs/UnixException", 51 "(I)V", errnum); 52 if (x != NULL) { 53 (*env)->Throw(env, x); 54 } 55 } 56 57 /** 58 * Initialization 59 */ 60 JNIEXPORT void JNICALL 61 Java_sun_nio_fs_AixNativeDispatcher_init(JNIEnv* env, jclass this) 62 { 63 jclass clazz; 64 65 clazz = (*env)->FindClass(env, "sun/nio/fs/UnixMountEntry"); 66 CHECK_NULL(clazz); 67 entry_name = (*env)->GetFieldID(env, clazz, "name", "[B"); 68 CHECK_NULL(entry_name); 69 entry_dir = (*env)->GetFieldID(env, clazz, "dir", "[B"); 70 CHECK_NULL(entry_dir); 71 entry_fstype = (*env)->GetFieldID(env, clazz, "fstype", "[B"); 72 CHECK_NULL(entry_fstype); 73 entry_options = (*env)->GetFieldID(env, clazz, "opts", "[B"); 74 CHECK_NULL(entry_options); 75 entry_cls = (*env)->NewGlobalRef(env, clazz); 76 if (entry_cls == NULL) { 77 JNU_ThrowOutOfMemoryError(env, NULL); 78 return; 79 } 80 } 81 82 /** 83 * Special implementation of getextmntent (see SolarisNativeDispatcher.c) 84 * that returns all entries at once. 85 */ 86 JNIEXPORT jobjectArray JNICALL 87 Java_sun_nio_fs_AixNativeDispatcher_getmntctl(JNIEnv* env, jclass this) 88 { 89 int must_free_buf = 0; 90 char stack_buf[1024]; 91 char* buffer = stack_buf; 92 size_t buffer_size = 1024; 93 int num_entries; 94 int i; 95 jobjectArray ret; 96 struct vmount * vm; 97 98 for (i = 0; i < 5; i++) { 99 num_entries = mntctl(MCTL_QUERY, buffer_size, buffer); 100 if (num_entries != 0) { 101 break; 102 } 103 if (must_free_buf) { 104 free(buffer); 105 } 106 buffer_size *= 8; 107 buffer = malloc(buffer_size); 108 must_free_buf = 1; 109 } 110 /* Treat zero entries like errors. */ 111 if (num_entries <= 0) { 112 if (must_free_buf) { 113 free(buffer); 114 } 115 throwUnixException(env, errno); 116 return NULL; 117 } 118 ret = (*env)->NewObjectArray(env, num_entries, entry_cls, NULL); 119 if (ret == NULL) { 120 if (must_free_buf) { 121 free(buffer); 122 } 123 return NULL; 124 } 125 vm = (struct vmount*)buffer; 126 for (i = 0; i < num_entries; i++) { 127 jsize len; 128 jbyteArray bytes; 129 const char* fstype; 130 /* We set all relevant attributes so there is no need to call constructor. */ 131 jobject entry = (*env)->AllocObject(env, entry_cls); 132 if (entry == NULL) { 133 if (must_free_buf) { 134 free(buffer); 135 } 136 return NULL; 137 } 138 (*env)->SetObjectArrayElement(env, ret, i, entry); 139 140 /* vm->vmt_data[...].vmt_size is 32 bit aligned and also includes NULL byte. */ 141 /* Since we only need the characters, it is necessary to check string size manually. */ 142 len = strlen((char*)vm + vm->vmt_data[VMT_OBJECT].vmt_off); 143 bytes = (*env)->NewByteArray(env, len); 144 if (bytes == NULL) { 145 if (must_free_buf) { 146 free(buffer); 147 } 148 return NULL; 149 } 150 (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)((char *)vm + vm->vmt_data[VMT_OBJECT].vmt_off)); 151 (*env)->SetObjectField(env, entry, entry_name, bytes); 152 153 len = strlen((char*)vm + vm->vmt_data[VMT_STUB].vmt_off); 154 bytes = (*env)->NewByteArray(env, len); 155 if (bytes == NULL) { 156 if (must_free_buf) { 157 free(buffer); 158 } 159 return NULL; 160 } 161 (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)((char *)vm + vm->vmt_data[VMT_STUB].vmt_off)); 162 (*env)->SetObjectField(env, entry, entry_dir, bytes); 163 164 switch (vm->vmt_gfstype) { 165 case MNT_J2: 166 fstype = "jfs2"; 167 break; 168 case MNT_NAMEFS: 169 fstype = "namefs"; 170 break; 171 case MNT_NFS: 172 fstype = "nfs"; 173 break; 174 case MNT_JFS: 175 fstype = "jfs"; 176 break; 177 case MNT_CDROM: 178 fstype = "cdrom"; 179 break; 180 case MNT_PROCFS: 181 fstype = "procfs"; 182 break; 183 case MNT_NFS3: 184 fstype = "nfs3"; 185 break; 186 case MNT_AUTOFS: 187 fstype = "autofs"; 188 break; 189 case MNT_UDF: 190 fstype = "udfs"; 191 break; 192 case MNT_NFS4: 193 fstype = "nfs4"; 194 break; 195 case MNT_CIFS: 196 fstype = "smbfs"; 197 break; 198 default: 199 fstype = "unknown"; 200 } 201 len = strlen(fstype); 202 bytes = (*env)->NewByteArray(env, len); 203 if (bytes == NULL) { 204 if (must_free_buf) { 205 free(buffer); 206 } 207 return NULL; 208 } 209 (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)fstype); 210 (*env)->SetObjectField(env, entry, entry_fstype, bytes); 211 212 len = strlen((char*)vm + vm->vmt_data[VMT_ARGS].vmt_off); 213 bytes = (*env)->NewByteArray(env, len); 214 if (bytes == NULL) { 215 if (must_free_buf) { 216 free(buffer); 217 } 218 return NULL; 219 } 220 (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)((char *)vm + vm->vmt_data[VMT_ARGS].vmt_off)); 221 (*env)->SetObjectField(env, entry, entry_options, bytes); 222 223 /* goto the next vmount structure: */ 224 vm = (struct vmount *)((char *)vm + vm->vmt_length); 225 } 226 227 if (must_free_buf) { 228 free(buffer); 229 } 230 return ret; 231 }