1 /* 2 * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved. 3 * Copyright 2013 SAP AG. 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 /* 28 * Portions Copyright (c) 2014 IBM Corporation 29 */ 30 31 #include <stdlib.h> 32 #include <errno.h> 33 #include <sys/types.h> 34 #include <sys/mntctl.h> 35 36 #include "jni.h" 37 #include "jni_util.h" 38 #include "jvm.h" 39 #include "jlong.h" 40 41 #include <stdio.h> 42 #include <dlfcn.h> 43 #include <mntent.h> 44 #include <sys/vmount.h> 45 #include "net_util.h" 46 47 #include "sun_nio_fs_AixNativeDispatcher.h" 48 49 static jfieldID entry_name; 50 static jfieldID entry_dir; 51 static jfieldID entry_fstype; 52 static jfieldID entry_options; 53 54 static jclass entry_cls; 55 56 typedef size_t fgetxattr_func_t(int fd, const char* name, void* value, size_t size); 57 typedef int fsetxattr_func_t(int fd, const char* name, void* value, size_t size, int flags); 58 typedef int fremovexattr_func_t(int fd, const char* name); 59 typedef int flistxattr_func_t(int fd, char* list, size_t size); 60 61 fgetxattr_func_t* fgetxattr_func = NULL; 62 fsetxattr_func_t* fsetxattr_func = NULL; 63 fremovexattr_func_t* fremovexattr_func = NULL; 64 flistxattr_func_t* flistxattr_func = NULL; 65 66 67 68 /** 69 * Call this to throw an internal UnixException when a system/library 70 * call fails 71 */ 72 static void throwUnixException(JNIEnv* env, int errnum) { 73 jobject x = JNU_NewObjectByName(env, "sun/nio/fs/UnixException", 74 "(I)V", errnum); 75 if (x != NULL) { 76 (*env)->Throw(env, x); 77 } 78 } 79 80 /** 81 * Initialization 82 */ 83 JNIEXPORT void JNICALL 84 Java_sun_nio_fs_AixNativeDispatcher_init(JNIEnv* env, jclass this) 85 { 86 jint flags = 0; 87 jclass clazz; 88 89 clazz = (*env)->FindClass(env, "sun/nio/fs/UnixMountEntry"); 90 CHECK_NULL(clazz); 91 entry_name = (*env)->GetFieldID(env, clazz, "name", "[B"); 92 CHECK_NULL(entry_name); 93 entry_dir = (*env)->GetFieldID(env, clazz, "dir", "[B"); 94 CHECK_NULL(entry_dir); 95 entry_fstype = (*env)->GetFieldID(env, clazz, "fstype", "[B"); 96 CHECK_NULL(entry_fstype); 97 entry_options = (*env)->GetFieldID(env, clazz, "opts", "[B"); 98 CHECK_NULL(entry_options); 99 entry_cls = (*env)->NewGlobalRef(env, clazz); 100 if (entry_cls == NULL) { 101 JNU_ThrowOutOfMemoryError(env, NULL); 102 return; 103 } 104 105 fgetxattr_func = (fgetxattr_func_t*)dlsym(RTLD_DEFAULT, "fgetxattr"); 106 fsetxattr_func = (fsetxattr_func_t*)dlsym(RTLD_DEFAULT, "fsetxattr"); 107 fremovexattr_func = (fremovexattr_func_t*)dlsym(RTLD_DEFAULT, "fremovexattr"); 108 flistxattr_func = (flistxattr_func_t*)dlsym(RTLD_DEFAULT, "flistxattr"); 109 } 110 111 /** 112 * Special implementation of getextmntent (see SolarisNativeDispatcher.c) 113 * that returns all entries at once. 114 */ 115 JNIEXPORT jobjectArray JNICALL 116 Java_sun_nio_fs_AixNativeDispatcher_getmntctl(JNIEnv* env, jclass this) 117 { 118 int must_free_buf = 0; 119 char stack_buf[1024]; 120 char* buffer = stack_buf; 121 size_t buffer_size = 1024; 122 int num_entries; 123 int i; 124 jobjectArray ret; 125 struct vmount * vm; 126 127 for (i = 0; i < 5; i++) { 128 num_entries = mntctl(MCTL_QUERY, buffer_size, buffer); 129 if (num_entries != 0) { 130 break; 131 } 132 if (must_free_buf) { 133 free(buffer); 134 } 135 buffer_size *= 8; 136 buffer = malloc(buffer_size); 137 must_free_buf = 1; 138 } 139 /* Treat zero entries like errors. */ 140 if (num_entries <= 0) { 141 if (must_free_buf) { 142 free(buffer); 143 } 144 throwUnixException(env, errno); 145 return NULL; 146 } 147 ret = (*env)->NewObjectArray(env, num_entries, entry_cls, NULL); 148 if (ret == NULL) { 149 if (must_free_buf) { 150 free(buffer); 151 } 152 return NULL; 153 } 154 vm = (struct vmount*)buffer; 155 for (i = 0; i < num_entries; i++) { 156 jsize len; 157 jbyteArray bytes; 158 const char* fstype; 159 /* We set all relevant attributes so there is no need to call constructor. */ 160 jobject entry = (*env)->AllocObject(env, entry_cls); 161 if (entry == NULL) { 162 if (must_free_buf) { 163 free(buffer); 164 } 165 return NULL; 166 } 167 (*env)->SetObjectArrayElement(env, ret, i, entry); 168 169 /* vm->vmt_data[...].vmt_size is 32 bit aligned and also includes NULL byte. */ 170 /* Since we only need the characters, it is necessary to check string size manually. */ 171 len = strlen((char*)vm + vm->vmt_data[VMT_OBJECT].vmt_off); 172 bytes = (*env)->NewByteArray(env, len); 173 if (bytes == NULL) { 174 if (must_free_buf) { 175 free(buffer); 176 } 177 return NULL; 178 } 179 (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)((char *)vm + vm->vmt_data[VMT_OBJECT].vmt_off)); 180 (*env)->SetObjectField(env, entry, entry_name, bytes); 181 182 len = strlen((char*)vm + vm->vmt_data[VMT_STUB].vmt_off); 183 bytes = (*env)->NewByteArray(env, len); 184 if (bytes == NULL) { 185 if (must_free_buf) { 186 free(buffer); 187 } 188 return NULL; 189 } 190 (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)((char *)vm + vm->vmt_data[VMT_STUB].vmt_off)); 191 (*env)->SetObjectField(env, entry, entry_dir, bytes); 192 193 switch (vm->vmt_gfstype) { 194 case MNT_J2: 195 fstype = "jfs2"; 196 break; 197 case MNT_NAMEFS: 198 fstype = "namefs"; 199 break; 200 case MNT_NFS: 201 fstype = "nfs"; 202 break; 203 case MNT_JFS: 204 fstype = "jfs"; 205 break; 206 case MNT_CDROM: 207 fstype = "cdrom"; 208 break; 209 case MNT_PROCFS: 210 fstype = "procfs"; 211 break; 212 case MNT_NFS3: 213 fstype = "nfs3"; 214 break; 215 case MNT_AUTOFS: 216 fstype = "autofs"; 217 break; 218 case MNT_UDF: 219 fstype = "udfs"; 220 break; 221 case MNT_NFS4: 222 fstype = "nfs4"; 223 break; 224 case MNT_CIFS: 225 fstype = "smbfs"; 226 break; 227 default: 228 fstype = "unknown"; 229 } 230 len = strlen(fstype); 231 bytes = (*env)->NewByteArray(env, len); 232 if (bytes == NULL) { 233 if (must_free_buf) { 234 free(buffer); 235 } 236 return NULL; 237 } 238 (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)fstype); 239 (*env)->SetObjectField(env, entry, entry_fstype, bytes); 240 241 len = strlen((char*)vm + vm->vmt_data[VMT_ARGS].vmt_off); 242 bytes = (*env)->NewByteArray(env, len); 243 if (bytes == NULL) { 244 if (must_free_buf) { 245 free(buffer); 246 } 247 return NULL; 248 } 249 (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)((char *)vm + vm->vmt_data[VMT_ARGS].vmt_off)); 250 (*env)->SetObjectField(env, entry, entry_options, bytes); 251 252 /* goto the next vmount structure: */ 253 vm = (struct vmount *)((char *)vm + vm->vmt_length); 254 } 255 256 if (must_free_buf) { 257 free(buffer); 258 } 259 return ret; 260 } 261 262 JNIEXPORT jint JNICALL 263 Java_sun_nio_fs_AixNativeDispatcher_fgetxattr0(JNIEnv* env, jclass clazz, 264 jint fd, jlong nameAddress, jlong valueAddress, jint valueLen) 265 { 266 size_t res = -1; 267 const char* name = jlong_to_ptr(nameAddress); 268 void* value = jlong_to_ptr(valueAddress); 269 270 if (fgetxattr_func == NULL) { 271 errno = ENOTSUP; 272 } else { 273 /* EINTR not documented */ 274 res = (*fgetxattr_func)(fd, name, value, valueLen); 275 } 276 if (res == (size_t)-1) { 277 throwUnixException(env, errno); 278 } 279 return (jint)res; 280 } 281 282 JNIEXPORT void JNICALL 283 Java_sun_nio_fs_AixNativeDispatcher_fsetxattr0(JNIEnv* env, jclass clazz, 284 jint fd, jlong nameAddress, jlong valueAddress, jint valueLen) 285 { 286 int res = -1; 287 const char* name = jlong_to_ptr(nameAddress); 288 void* value = jlong_to_ptr(valueAddress); 289 290 if (fsetxattr_func == NULL) { 291 errno = ENOTSUP; 292 } else { 293 /* EINTR not documented */ 294 res = (*fsetxattr_func)(fd, name, value, valueLen, 0); 295 } 296 if (res == -1) { 297 throwUnixException(env, errno); 298 } 299 } 300 301 JNIEXPORT void JNICALL 302 Java_sun_nio_fs_AixNativeDispatcher_fremovexattr0(JNIEnv* env, jclass clazz, 303 jint fd, jlong nameAddress) 304 { 305 int res = -1; 306 const char* name = jlong_to_ptr(nameAddress); 307 308 if (fremovexattr_func == NULL) { 309 errno = ENOTSUP; 310 } else { 311 /* EINTR not documented */ 312 res = (*fremovexattr_func)(fd, name); 313 } 314 if (res == -1) { 315 throwUnixException(env, errno); 316 } 317 } 318 319 JNIEXPORT jint JNICALL 320 Java_sun_nio_fs_AixNativeDispatcher_flistxattr(JNIEnv* env, jclass clazz, 321 jint fd, jlong listAddress, jint size) 322 { 323 size_t res = -1; 324 char* list = jlong_to_ptr(listAddress); 325 326 if (flistxattr_func == NULL) { 327 errno = ENOTSUP; 328 } else { 329 /* EINTR not documented */ 330 res = (*flistxattr_func)(fd, list, (size_t)size); 331 } 332 if (res == (size_t)-1) { 333 throwUnixException(env, errno); 334 } 335 return (jint)res; 336 } 337 338 JNIEXPORT jint JNICALL 339 Java_sun_nio_fs_AixNativeDispatcher_queryMountEntrySize(JNIEnv* env, jclass this) 340 { 341 int size; 342 343 if (mntctl(MCTL_QUERY, sizeof(size), (char *)&size) != 0) { 344 return 0; 345 } 346 return size; 347 } 348 349 JNIEXPORT void JNICALL 350 Java_sun_nio_fs_AixNativeDispatcher_getAixMountEntries(JNIEnv* env, jclass this, jobject entries, jlong bufferAddress, jint size) 351 { 352 jmethodID addMethod, constructor; 353 jclass arrayListClass, unixMountEntryClass; 354 int entryNum; 355 char *buffer = NULL; 356 char *ptr = NULL; 357 char *name = NULL; 358 char *type = NULL; 359 char *path = NULL; 360 char *opts = NULL; 361 int len, count; 362 jboolean readOnly = JNI_FALSE; 363 jobject mountEntry; 364 jbyteArray bytes; 365 struct vmount * vmountPtr = NULL; 366 jfieldID entry_name; 367 jfieldID entry_dir; 368 jfieldID entry_fstype; 369 jfieldID entry_options; 370 371 arrayListClass = (*env)->FindClass(env, "java/util/ArrayList"); 372 if ((*env)->ExceptionOccurred(env)) { 373 return; 374 } 375 376 addMethod = (*env)->GetMethodID(env, arrayListClass, "add", "(Ljava/lang/Object;)Z"); 377 if ((*env)->ExceptionOccurred(env)) { 378 return; 379 } 380 381 unixMountEntryClass = (*env)->FindClass(env, "sun/nio/fs/UnixMountEntry"); 382 if ((*env)->ExceptionOccurred(env)) { 383 return; 384 } 385 386 constructor = (*env)->GetMethodID(env, unixMountEntryClass, "<init>", "()V"); 387 if ((*env)->ExceptionOccurred(env)) { 388 return; 389 } 390 391 buffer = (char *)jlong_to_ptr(bufferAddress); 392 393 entryNum = mntctl(MCTL_QUERY, size, buffer); 394 395 if (entryNum <= 0) { 396 return; 397 } 398 399 entry_name = (*env)->GetFieldID(env, unixMountEntryClass, "name", "[B"); 400 entry_dir = (*env)->GetFieldID(env, unixMountEntryClass, "dir", "[B"); 401 entry_fstype = (*env)->GetFieldID(env, unixMountEntryClass, "fstype", "[B"); 402 entry_options = (*env)->GetFieldID(env, unixMountEntryClass, "opts", "[B"); 403 404 ptr = buffer; 405 for (count = 0; count < entryNum; count++, ptr += vmountPtr->vmt_length) { 406 vmountPtr = (struct vmount *)ptr; 407 switch (vmountPtr->vmt_gfstype) { 408 case MNT_JFS: 409 type = "jfs"; 410 break; 411 case MNT_J2: 412 type = "jfs2"; 413 break; 414 case MNT_NFS: 415 type = "nfs"; 416 break; 417 case MNT_CDROM: 418 type = "cdrom"; 419 break; 420 case MNT_PROCFS: 421 type = "procfs"; 422 break; 423 default: 424 type = "unknown"; 425 } 426 if (vmountPtr->vmt_flags & MNT_READONLY) { 427 readOnly = JNI_TRUE; 428 } else { 429 readOnly = JNI_FALSE; 430 } 431 432 name = (char *)(ptr + vmountPtr->vmt_data[VMT_OBJECT].vmt_off); 433 path = (char *)(ptr + vmountPtr->vmt_data[VMT_STUB].vmt_off); 434 435 mountEntry = (*env)->NewObject(env, unixMountEntryClass, constructor); 436 437 // name 438 len = strlen(name); 439 bytes = (*env)->NewByteArray(env, len); 440 if (bytes == NULL) { 441 break; 442 } 443 (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)name); 444 (*env)->SetObjectField(env, mountEntry, entry_name, bytes); 445 446 // dir 447 len = strlen(path); 448 bytes = (*env)->NewByteArray(env, len); 449 if (bytes == NULL) { 450 break; 451 } 452 (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)path); 453 (*env)->SetObjectField(env, mountEntry, entry_dir, bytes); 454 455 // filetype 456 len = strlen(type); 457 bytes = (*env)->NewByteArray(env, len); 458 if (bytes == NULL) { 459 break; 460 } 461 (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)type); 462 (*env)->SetObjectField(env, mountEntry, entry_fstype, bytes); 463 464 // opts 465 if (readOnly) { 466 opts = "ro"; 467 } else { 468 opts = ""; 469 } 470 len = strlen(opts); 471 bytes = (*env)->NewByteArray(env, len); 472 if (bytes == NULL) { 473 break; 474 } 475 (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)opts); 476 (*env)->SetObjectField(env, mountEntry, entry_options, bytes); 477 478 if ((*env)->ExceptionOccurred(env)) { 479 (*env)->ExceptionDescribe(env); 480 goto error; 481 } 482 (*env)->CallBooleanMethod(env, entries, addMethod, mountEntry); 483 if ((*env)->ExceptionOccurred(env)) { 484 (*env)->ExceptionDescribe(env); 485 goto error; 486 } 487 } 488 489 error: 490 return; 491 }