1 /* 2 * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <limits.h> 29 #include <fcntl.h> 30 #include <dirent.h> 31 #include <unistd.h> 32 #include <pwd.h> 33 #include <grp.h> 34 #include <errno.h> 35 #include <dlfcn.h> 36 #include <sys/types.h> 37 #include <sys/stat.h> 38 #include <sys/statvfs.h> 39 #include <sys/time.h> 40 41 #ifdef __solaris__ 42 #include <strings.h> 43 #include <sys/mnttab.h> 44 #include <sys/mkdev.h> 45 #endif 46 47 #ifdef __linux__ 48 #include <string.h> 49 #include <mntent.h> 50 #endif 51 52 #include "jni.h" 53 #include "jni_util.h" 54 #include "jlong.h" 55 56 #include "sun_nio_fs_UnixNativeDispatcher.h" 57 58 /** 59 * Size of password or group entry when not available via sysconf 60 */ 61 #define ENT_BUF_SIZE 1024 62 63 #define RESTARTABLE(_cmd, _result) do { \ 64 do { \ 65 _result = _cmd; \ 66 } while((_result == -1) && (errno == EINTR)); \ 67 } while(0) 68 69 #define RESTARTABLE_RETURN_PTR(_cmd, _result) do { \ 70 do { \ 71 _result = _cmd; \ 72 } while((_result == NULL) && (errno == EINTR)); \ 73 } while(0) 74 75 static jfieldID attrs_st_mode; 76 static jfieldID attrs_st_ino; 77 static jfieldID attrs_st_dev; 78 static jfieldID attrs_st_rdev; 79 static jfieldID attrs_st_nlink; 80 static jfieldID attrs_st_uid; 81 static jfieldID attrs_st_gid; 82 static jfieldID attrs_st_size; 83 static jfieldID attrs_st_atime; 84 static jfieldID attrs_st_mtime; 85 static jfieldID attrs_st_ctime; 86 87 static jfieldID attrs_f_frsize; 88 static jfieldID attrs_f_blocks; 89 static jfieldID attrs_f_bfree; 90 static jfieldID attrs_f_bavail; 91 92 static jfieldID entry_name; 93 static jfieldID entry_dir; 94 static jfieldID entry_fstype; 95 static jfieldID entry_options; 96 static jfieldID entry_dev; 97 98 /** 99 * System calls that may not be available at run time. 100 */ 101 typedef int openat64_func(int, const char *, int, ...); 102 typedef int fstatat64_func(int, const char *, struct stat64 *, int); 103 typedef int unlinkat_func(int, const char*, int); 104 typedef int renameat_func(int, const char*, int, const char*); 105 typedef int futimesat_func(int, const char *, const struct timeval *); 106 typedef DIR* fdopendir_func(int); 107 108 static openat64_func* my_openat64_func = NULL; 109 static fstatat64_func* my_fstatat64_func = NULL; 110 static unlinkat_func* my_unlinkat_func = NULL; 111 static renameat_func* my_renameat_func = NULL; 112 static futimesat_func* my_futimesat_func = NULL; 113 static fdopendir_func* my_fdopendir_func = NULL; 114 115 /** 116 * fstatat missing from glibc on Linux. Temporary workaround 117 * for x86/x64. 118 */ 119 #if defined(__linux__) && defined(__i386) 120 #define FSTATAT64_SYSCALL_AVAILABLE 121 static int fstatat64_wrapper(int dfd, const char *path, 122 struct stat64 *statbuf, int flag) 123 { 124 #ifndef __NR_fstatat64 125 #define __NR_fstatat64 300 126 #endif 127 return syscall(__NR_fstatat64, dfd, path, statbuf, flag); 128 } 129 #endif 130 131 #if defined(__linux__) && defined(__x86_64__) 132 #define FSTATAT64_SYSCALL_AVAILABLE 133 static int fstatat64_wrapper(int dfd, const char *path, 134 struct stat64 *statbuf, int flag) 135 { 136 #ifndef __NR_newfstatat 137 #define __NR_newfstatat 262 138 #endif 139 return syscall(__NR_newfstatat, dfd, path, statbuf, flag); 140 } 141 #endif 142 143 /** 144 * Call this to throw an internal UnixException when a system/library 145 * call fails 146 */ 147 static void throwUnixException(JNIEnv* env, int errnum) { 148 jobject x = JNU_NewObjectByName(env, "sun/nio/fs/UnixException", 149 "(I)V", errnum); 150 if (x != NULL) { 151 (*env)->Throw(env, x); 152 } 153 } 154 155 /** 156 * Initialization 157 */ 158 JNIEXPORT jint JNICALL 159 Java_sun_nio_fs_UnixNativeDispatcher_init(JNIEnv* env, jclass this) 160 { 161 jint flags = 0; 162 jclass clazz; 163 164 clazz = (*env)->FindClass(env, "sun/nio/fs/UnixFileAttributes"); 165 if (clazz == NULL) { 166 return 0; 167 } 168 attrs_st_mode = (*env)->GetFieldID(env, clazz, "st_mode", "I"); 169 attrs_st_ino = (*env)->GetFieldID(env, clazz, "st_ino", "J"); 170 attrs_st_dev = (*env)->GetFieldID(env, clazz, "st_dev", "J"); 171 attrs_st_rdev = (*env)->GetFieldID(env, clazz, "st_rdev", "J"); 172 attrs_st_nlink = (*env)->GetFieldID(env, clazz, "st_nlink", "I"); 173 attrs_st_uid = (*env)->GetFieldID(env, clazz, "st_uid", "I"); 174 attrs_st_gid = (*env)->GetFieldID(env, clazz, "st_gid", "I"); 175 attrs_st_size = (*env)->GetFieldID(env, clazz, "st_size", "J"); 176 attrs_st_atime = (*env)->GetFieldID(env, clazz, "st_atime", "J"); 177 attrs_st_mtime = (*env)->GetFieldID(env, clazz, "st_mtime", "J"); 178 attrs_st_ctime = (*env)->GetFieldID(env, clazz, "st_ctime", "J"); 179 180 clazz = (*env)->FindClass(env, "sun/nio/fs/UnixFileStoreAttributes"); 181 if (clazz == NULL) { 182 return 0; 183 } 184 attrs_f_frsize = (*env)->GetFieldID(env, clazz, "f_frsize", "J"); 185 attrs_f_blocks = (*env)->GetFieldID(env, clazz, "f_blocks", "J"); 186 attrs_f_bfree = (*env)->GetFieldID(env, clazz, "f_bfree", "J"); 187 attrs_f_bavail = (*env)->GetFieldID(env, clazz, "f_bavail", "J"); 188 189 clazz = (*env)->FindClass(env, "sun/nio/fs/UnixMountEntry"); 190 if (clazz == NULL) { 191 return 0; 192 } 193 entry_name = (*env)->GetFieldID(env, clazz, "name", "[B"); 194 entry_dir = (*env)->GetFieldID(env, clazz, "dir", "[B"); 195 entry_fstype = (*env)->GetFieldID(env, clazz, "fstype", "[B"); 196 entry_options = (*env)->GetFieldID(env, clazz, "opts", "[B"); 197 entry_dev = (*env)->GetFieldID(env, clazz, "dev", "J"); 198 199 /* system calls that might not be available at run time */ 200 201 #if defined(__solaris__) && defined(_LP64) 202 /* Solaris 64-bit does not have openat64/fstatat64 */ 203 my_openat64_func = (openat64_func*)dlsym(RTLD_DEFAULT, "openat"); 204 my_fstatat64_func = (fstatat64_func*)dlsym(RTLD_DEFAULT, "fstatat"); 205 #else 206 my_openat64_func = (openat64_func*) dlsym(RTLD_DEFAULT, "openat64"); 207 my_fstatat64_func = (fstatat64_func*) dlsym(RTLD_DEFAULT, "fstatat64"); 208 #endif 209 my_unlinkat_func = (unlinkat_func*) dlsym(RTLD_DEFAULT, "unlinkat"); 210 my_renameat_func = (renameat_func*) dlsym(RTLD_DEFAULT, "renameat"); 211 my_futimesat_func = (futimesat_func*) dlsym(RTLD_DEFAULT, "futimesat"); 212 my_fdopendir_func = (fdopendir_func*) dlsym(RTLD_DEFAULT, "fdopendir"); 213 214 #if defined(FSTATAT64_SYSCALL_AVAILABLE) 215 /* fstatat64 missing from glibc */ 216 if (my_fstatat64_func == NULL) 217 my_fstatat64_func = (fstatat64_func*)&fstatat64_wrapper; 218 #endif 219 220 if (my_openat64_func != NULL && my_fstatat64_func != NULL && 221 my_unlinkat_func != NULL && my_renameat_func != NULL && 222 my_futimesat_func != NULL && my_fdopendir_func != NULL) 223 { 224 flags |= sun_nio_fs_UnixNativeDispatcher_HAS_AT_SYSCALLS; 225 } 226 227 return flags; 228 } 229 230 JNIEXPORT jbyteArray JNICALL 231 Java_sun_nio_fs_UnixNativeDispatcher_getcwd(JNIEnv* env, jclass this) { 232 jbyteArray result = NULL; 233 char buf[PATH_MAX+1]; 234 235 /* EINTR not listed as a possible error */ 236 char* cwd = getcwd(buf, sizeof(buf)); 237 if (cwd == NULL) { 238 throwUnixException(env, errno); 239 } else { 240 jsize len = (jsize)strlen(buf); 241 result = (*env)->NewByteArray(env, len); 242 if (result != NULL) { 243 (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)buf); 244 } 245 } 246 return result; 247 } 248 249 JNIEXPORT jbyteArray 250 Java_sun_nio_fs_UnixNativeDispatcher_strerror(JNIEnv* env, jclass this, jint error) 251 { 252 char* msg; 253 jsize len; 254 jbyteArray bytes; 255 256 msg = strerror((int)error); 257 len = strlen(msg); 258 bytes = (*env)->NewByteArray(env, len); 259 if (bytes != NULL) { 260 (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)msg); 261 } 262 return bytes; 263 } 264 265 JNIEXPORT jint 266 Java_sun_nio_fs_UnixNativeDispatcher_dup(JNIEnv* env, jclass this, jint fd) { 267 268 int res = -1; 269 270 RESTARTABLE(dup((int)fd), res); 271 if (fd == -1) { 272 throwUnixException(env, errno); 273 } 274 return (jint)res; 275 } 276 277 JNIEXPORT jlong JNICALL 278 Java_sun_nio_fs_UnixNativeDispatcher_fopen0(JNIEnv* env, jclass this, 279 jlong pathAddress, jlong modeAddress) 280 { 281 FILE* fp = NULL; 282 const char* path = (const char*)jlong_to_ptr(pathAddress); 283 const char* mode = (const char*)jlong_to_ptr(modeAddress); 284 285 do { 286 fp = fopen(path, mode); 287 } while (fp == NULL && errno == EINTR); 288 289 if (fp == NULL) { 290 throwUnixException(env, errno); 291 } 292 293 return ptr_to_jlong(fp); 294 } 295 296 JNIEXPORT void JNICALL 297 Java_sun_nio_fs_UnixNativeDispatcher_fclose(JNIEnv* env, jclass this, jlong stream) 298 { 299 int res; 300 FILE* fp = jlong_to_ptr(stream); 301 302 do { 303 res = fclose(fp); 304 } while (res == EOF && errno == EINTR); 305 if (res == EOF) { 306 throwUnixException(env, errno); 307 } 308 } 309 310 JNIEXPORT jint JNICALL 311 Java_sun_nio_fs_UnixNativeDispatcher_open0(JNIEnv* env, jclass this, 312 jlong pathAddress, jint oflags, jint mode) 313 { 314 jint fd; 315 const char* path = (const char*)jlong_to_ptr(pathAddress); 316 317 RESTARTABLE(open64(path, (int)oflags, (mode_t)mode), fd); 318 if (fd == -1) { 319 throwUnixException(env, errno); 320 } 321 return fd; 322 } 323 324 JNIEXPORT jint JNICALL 325 Java_sun_nio_fs_UnixNativeDispatcher_openat0(JNIEnv* env, jclass this, jint dfd, 326 jlong pathAddress, jint oflags, jint mode) 327 { 328 jint fd; 329 const char* path = (const char*)jlong_to_ptr(pathAddress); 330 331 if (my_openat64_func == NULL) { 332 JNU_ThrowInternalError(env, "should not reach here"); 333 return -1; 334 } 335 336 RESTARTABLE((*my_openat64_func)(dfd, path, (int)oflags, (mode_t)mode), fd); 337 if (fd == -1) { 338 throwUnixException(env, errno); 339 } 340 return fd; 341 } 342 343 JNIEXPORT void JNICALL 344 Java_sun_nio_fs_UnixNativeDispatcher_close(JNIEnv* env, jclass this, jint fd) { 345 int err; 346 /* TDB - need to decide if EIO and other errors should cause exception */ 347 RESTARTABLE(close((int)fd), err); 348 } 349 350 JNIEXPORT jint JNICALL 351 Java_sun_nio_fs_UnixNativeDispatcher_read(JNIEnv* env, jclass this, jint fd, 352 jlong address, jint nbytes) 353 { 354 ssize_t n; 355 void* bufp = jlong_to_ptr(address); 356 RESTARTABLE(read((int)fd, bufp, (size_t)nbytes), n); 357 if (n == -1) { 358 throwUnixException(env, errno); 359 } 360 return (jint)n; 361 } 362 363 JNIEXPORT jint JNICALL 364 Java_sun_nio_fs_UnixNativeDispatcher_write(JNIEnv* env, jclass this, jint fd, 365 jlong address, jint nbytes) 366 { 367 ssize_t n; 368 void* bufp = jlong_to_ptr(address); 369 RESTARTABLE(write((int)fd, bufp, (size_t)nbytes), n); 370 if (n == -1) { 371 throwUnixException(env, errno); 372 } 373 return (jint)n; 374 } 375 376 /** 377 * Copy stat64 members into sun.nio.fs.UnixFileAttributes 378 */ 379 static void prepAttributes(JNIEnv* env, struct stat64* buf, jobject attrs) { 380 (*env)->SetIntField(env, attrs, attrs_st_mode, (jint)buf->st_mode); 381 (*env)->SetLongField(env, attrs, attrs_st_ino, (jlong)buf->st_ino); 382 (*env)->SetLongField(env, attrs, attrs_st_dev, (jlong)buf->st_dev); 383 (*env)->SetLongField(env, attrs, attrs_st_rdev, (jlong)buf->st_rdev); 384 (*env)->SetIntField(env, attrs, attrs_st_nlink, (jint)buf->st_nlink); 385 (*env)->SetIntField(env, attrs, attrs_st_uid, (jint)buf->st_uid); 386 (*env)->SetIntField(env, attrs, attrs_st_gid, (jint)buf->st_gid); 387 (*env)->SetLongField(env, attrs, attrs_st_size, (jlong)buf->st_size); 388 (*env)->SetLongField(env, attrs, attrs_st_atime, (jlong)buf->st_atime); 389 (*env)->SetLongField(env, attrs, attrs_st_mtime, (jlong)buf->st_mtime); 390 (*env)->SetLongField(env, attrs, attrs_st_ctime, (jlong)buf->st_ctime); 391 } 392 393 JNIEXPORT void JNICALL 394 Java_sun_nio_fs_UnixNativeDispatcher_stat0(JNIEnv* env, jclass this, 395 jlong pathAddress, jobject attrs) 396 { 397 int err; 398 struct stat64 buf; 399 const char* path = (const char*)jlong_to_ptr(pathAddress); 400 401 RESTARTABLE(stat64(path, &buf), err); 402 if (err == -1) { 403 throwUnixException(env, errno); 404 } else { 405 prepAttributes(env, &buf, attrs); 406 } 407 } 408 409 JNIEXPORT void JNICALL 410 Java_sun_nio_fs_UnixNativeDispatcher_lstat0(JNIEnv* env, jclass this, 411 jlong pathAddress, jobject attrs) 412 { 413 int err; 414 struct stat64 buf; 415 const char* path = (const char*)jlong_to_ptr(pathAddress); 416 417 RESTARTABLE(lstat64(path, &buf), err); 418 if (err == -1) { 419 throwUnixException(env, errno); 420 } else { 421 prepAttributes(env, &buf, attrs); 422 } 423 } 424 425 JNIEXPORT void JNICALL 426 Java_sun_nio_fs_UnixNativeDispatcher_fstat(JNIEnv* env, jclass this, jint fd, 427 jobject attrs) 428 { 429 int err; 430 struct stat64 buf; 431 432 RESTARTABLE(fstat64((int)fd, &buf), err); 433 if (err == -1) { 434 throwUnixException(env, errno); 435 } else { 436 prepAttributes(env, &buf, attrs); 437 } 438 } 439 440 JNIEXPORT void JNICALL 441 Java_sun_nio_fs_UnixNativeDispatcher_fstatat0(JNIEnv* env, jclass this, jint dfd, 442 jlong pathAddress, jint flag, jobject attrs) 443 { 444 int err; 445 struct stat64 buf; 446 const char* path = (const char*)jlong_to_ptr(pathAddress); 447 448 if (my_fstatat64_func == NULL) { 449 JNU_ThrowInternalError(env, "should not reach here"); 450 return; 451 } 452 RESTARTABLE((*my_fstatat64_func)((int)dfd, path, &buf, (int)flag), err); 453 if (err == -1) { 454 throwUnixException(env, errno); 455 } else { 456 prepAttributes(env, &buf, attrs); 457 } 458 } 459 460 JNIEXPORT void JNICALL 461 Java_sun_nio_fs_UnixNativeDispatcher_chmod0(JNIEnv* env, jclass this, 462 jlong pathAddress, jint mode) 463 { 464 int err; 465 const char* path = (const char*)jlong_to_ptr(pathAddress); 466 467 RESTARTABLE(chmod(path, (mode_t)mode), err); 468 if (err == -1) { 469 throwUnixException(env, errno); 470 } 471 } 472 473 JNIEXPORT void JNICALL 474 Java_sun_nio_fs_UnixNativeDispatcher_fchmod(JNIEnv* env, jclass this, jint filedes, 475 jint mode) 476 { 477 int err; 478 479 RESTARTABLE(fchmod((int)filedes, (mode_t)mode), err); 480 if (err == -1) { 481 throwUnixException(env, errno); 482 } 483 } 484 485 486 JNIEXPORT void JNICALL 487 Java_sun_nio_fs_UnixNativeDispatcher_chown0(JNIEnv* env, jclass this, 488 jlong pathAddress, jint uid, jint gid) 489 { 490 int err; 491 const char* path = (const char*)jlong_to_ptr(pathAddress); 492 493 RESTARTABLE(chown(path, (uid_t)uid, (gid_t)gid), err); 494 if (err == -1) { 495 throwUnixException(env, errno); 496 } 497 } 498 499 JNIEXPORT void JNICALL 500 Java_sun_nio_fs_UnixNativeDispatcher_lchown0(JNIEnv* env, jclass this, jlong pathAddress, jint uid, jint gid) 501 { 502 int err; 503 const char* path = (const char*)jlong_to_ptr(pathAddress); 504 505 RESTARTABLE(lchown(path, (uid_t)uid, (gid_t)gid), err); 506 if (err == -1) { 507 throwUnixException(env, errno); 508 } 509 } 510 511 JNIEXPORT void JNICALL 512 Java_sun_nio_fs_UnixNativeDispatcher_fchown(JNIEnv* env, jclass this, jint filedes, jint uid, jint gid) 513 { 514 int err; 515 516 RESTARTABLE(fchown(filedes, (uid_t)uid, (gid_t)gid), err); 517 if (err == -1) { 518 throwUnixException(env, errno); 519 } 520 } 521 522 JNIEXPORT void JNICALL 523 Java_sun_nio_fs_UnixNativeDispatcher_utimes0(JNIEnv* env, jclass this, 524 jlong pathAddress, jlong accessTime, jlong modificationTime) 525 { 526 int err; 527 struct timeval times[2]; 528 const char* path = (const char*)jlong_to_ptr(pathAddress); 529 530 times[0].tv_sec = accessTime / 1000000; 531 times[0].tv_usec = accessTime % 1000000; 532 533 times[1].tv_sec = modificationTime / 1000000; 534 times[1].tv_usec = modificationTime % 1000000; 535 536 RESTARTABLE(utimes(path, ×[0]), err); 537 if (err == -1) { 538 throwUnixException(env, errno); 539 } 540 } 541 542 JNIEXPORT void JNICALL 543 Java_sun_nio_fs_UnixNativeDispatcher_futimes(JNIEnv* env, jclass this, jint filedes, 544 jlong accessTime, jlong modificationTime) 545 { 546 struct timeval times[2]; 547 int err = 0; 548 549 times[0].tv_sec = accessTime / 1000000; 550 times[0].tv_usec = accessTime % 1000000; 551 552 times[1].tv_sec = modificationTime / 1000000; 553 times[1].tv_usec = modificationTime % 1000000; 554 555 if (my_futimesat_func != NULL) { 556 RESTARTABLE((*my_futimesat_func)(filedes, NULL, ×[0]), err); 557 if (err == -1) { 558 throwUnixException(env, errno); 559 } 560 } 561 } 562 563 JNIEXPORT jlong JNICALL 564 Java_sun_nio_fs_UnixNativeDispatcher_opendir0(JNIEnv* env, jclass this, 565 jlong pathAddress) 566 { 567 DIR* dir; 568 const char* path = (const char*)jlong_to_ptr(pathAddress); 569 570 /* EINTR not listed as a possible error */ 571 dir = opendir(path); 572 if (dir == NULL) { 573 throwUnixException(env, errno); 574 } 575 return ptr_to_jlong(dir); 576 } 577 578 JNIEXPORT jlong JNICALL 579 Java_sun_nio_fs_UnixNativeDispatcher_fdopendir(JNIEnv* env, jclass this, int dfd) { 580 DIR* dir; 581 582 if (my_fdopendir_func == NULL) { 583 JNU_ThrowInternalError(env, "should not reach here"); 584 return (jlong)-1; 585 } 586 587 /* EINTR not listed as a possible error */ 588 dir = (*my_fdopendir_func)((int)dfd); 589 if (dir == NULL) { 590 throwUnixException(env, errno); 591 } 592 return ptr_to_jlong(dir); 593 } 594 595 JNIEXPORT void JNICALL 596 Java_sun_nio_fs_UnixNativeDispatcher_closedir(JNIEnv* env, jclass this, jlong dir) { 597 int err; 598 DIR* dirp = jlong_to_ptr(dir); 599 600 RESTARTABLE(closedir(dirp), err); 601 if (errno == -1) { 602 throwUnixException(env, errno); 603 } 604 } 605 606 JNIEXPORT jbyteArray JNICALL 607 Java_sun_nio_fs_UnixNativeDispatcher_readdir(JNIEnv* env, jclass this, jlong value) { 608 char entry[sizeof(struct dirent64) + PATH_MAX + 1]; 609 struct dirent64* ptr = (struct dirent64*)&entry; 610 struct dirent64* result; 611 int res; 612 DIR* dirp = jlong_to_ptr(value); 613 614 /* EINTR not listed as a possible error */ 615 /* TDB: reentrant version probably not required here */ 616 res = readdir64_r(dirp, ptr, &result); 617 if (res != 0) { 618 throwUnixException(env, res); 619 return NULL; 620 } else { 621 if (result == NULL) { 622 return NULL; 623 } else { 624 jsize len = strlen(ptr->d_name); 625 jbyteArray bytes = (*env)->NewByteArray(env, len); 626 if (bytes != NULL) { 627 (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)(ptr->d_name)); 628 } 629 return bytes; 630 } 631 } 632 } 633 634 JNIEXPORT void JNICALL 635 Java_sun_nio_fs_UnixNativeDispatcher_mkdir0(JNIEnv* env, jclass this, 636 jlong pathAddress, jint mode) 637 { 638 const char* path = (const char*)jlong_to_ptr(pathAddress); 639 640 /* EINTR not listed as a possible error */ 641 if (mkdir(path, (mode_t)mode) == -1) { 642 throwUnixException(env, errno); 643 } 644 } 645 646 JNIEXPORT void JNICALL 647 Java_sun_nio_fs_UnixNativeDispatcher_rmdir0(JNIEnv* env, jclass this, 648 jlong pathAddress) 649 { 650 const char* path = (const char*)jlong_to_ptr(pathAddress); 651 652 /* EINTR not listed as a possible error */ 653 if (rmdir(path) == -1) { 654 throwUnixException(env, errno); 655 } 656 } 657 658 JNIEXPORT void JNICALL 659 Java_sun_nio_fs_UnixNativeDispatcher_link0(JNIEnv* env, jclass this, 660 jlong existingAddress, jlong newAddress) 661 { 662 int err; 663 const char* existing = (const char*)jlong_to_ptr(existingAddress); 664 const char* newname = (const char*)jlong_to_ptr(newAddress); 665 666 RESTARTABLE(link(existing, newname), err); 667 if (err == -1) { 668 throwUnixException(env, errno); 669 } 670 } 671 672 673 JNIEXPORT void JNICALL 674 Java_sun_nio_fs_UnixNativeDispatcher_unlink0(JNIEnv* env, jclass this, 675 jlong pathAddress) 676 { 677 const char* path = (const char*)jlong_to_ptr(pathAddress); 678 679 /* EINTR not listed as a possible error */ 680 if (unlink(path) == -1) { 681 throwUnixException(env, errno); 682 } 683 } 684 685 JNIEXPORT void JNICALL 686 Java_sun_nio_fs_UnixNativeDispatcher_unlinkat0(JNIEnv* env, jclass this, jint dfd, 687 jlong pathAddress, jint flags) 688 { 689 const char* path = (const char*)jlong_to_ptr(pathAddress); 690 691 if (my_unlinkat_func == NULL) { 692 JNU_ThrowInternalError(env, "should not reach here"); 693 return; 694 } 695 696 /* EINTR not listed as a possible error */ 697 if ((*my_unlinkat_func)((int)dfd, path, (int)flags) == -1) { 698 throwUnixException(env, errno); 699 } 700 } 701 702 JNIEXPORT void JNICALL 703 Java_sun_nio_fs_UnixNativeDispatcher_rename0(JNIEnv* env, jclass this, 704 jlong fromAddress, jlong toAddress) 705 { 706 const char* from = (const char*)jlong_to_ptr(fromAddress); 707 const char* to = (const char*)jlong_to_ptr(toAddress); 708 709 /* EINTR not listed as a possible error */ 710 if (rename(from, to) == -1) { 711 throwUnixException(env, errno); 712 } 713 } 714 715 JNIEXPORT void JNICALL 716 Java_sun_nio_fs_UnixNativeDispatcher_renameat0(JNIEnv* env, jclass this, 717 jint fromfd, jlong fromAddress, jint tofd, jlong toAddress) 718 { 719 const char* from = (const char*)jlong_to_ptr(fromAddress); 720 const char* to = (const char*)jlong_to_ptr(toAddress); 721 722 if (my_renameat_func == NULL) { 723 JNU_ThrowInternalError(env, "should not reach here"); 724 return; 725 } 726 727 /* EINTR not listed as a possible error */ 728 if ((*my_renameat_func)((int)fromfd, from, (int)tofd, to) == -1) { 729 throwUnixException(env, errno); 730 } 731 } 732 733 JNIEXPORT void JNICALL 734 Java_sun_nio_fs_UnixNativeDispatcher_symlink0(JNIEnv* env, jclass this, 735 jlong targetAddress, jlong linkAddress) 736 { 737 const char* target = (const char*)jlong_to_ptr(targetAddress); 738 const char* link = (const char*)jlong_to_ptr(linkAddress); 739 740 /* EINTR not listed as a possible error */ 741 if (symlink(target, link) == -1) { 742 throwUnixException(env, errno); 743 } 744 } 745 746 JNIEXPORT jbyteArray JNICALL 747 Java_sun_nio_fs_UnixNativeDispatcher_readlink0(JNIEnv* env, jclass this, 748 jlong pathAddress) 749 { 750 jbyteArray result = NULL; 751 char target[PATH_MAX+1]; 752 const char* path = (const char*)jlong_to_ptr(pathAddress); 753 754 /* EINTR not listed as a possible error */ 755 int n = readlink(path, target, sizeof(target)); 756 if (n == -1) { 757 throwUnixException(env, errno); 758 } else { 759 jsize len; 760 if (n == sizeof(target)) { 761 n--; 762 } 763 target[n] = '\0'; 764 len = (jsize)strlen(target); 765 result = (*env)->NewByteArray(env, len); 766 if (result != NULL) { 767 (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)target); 768 } 769 } 770 return result; 771 } 772 773 JNIEXPORT jbyteArray JNICALL 774 Java_sun_nio_fs_UnixNativeDispatcher_realpath0(JNIEnv* env, jclass this, 775 jlong pathAddress) 776 { 777 jbyteArray result = NULL; 778 char resolved[PATH_MAX+1]; 779 const char* path = (const char*)jlong_to_ptr(pathAddress); 780 781 /* EINTR not listed as a possible error */ 782 if (realpath(path, resolved) == NULL) { 783 throwUnixException(env, errno); 784 } else { 785 jsize len = (jsize)strlen(resolved); 786 result = (*env)->NewByteArray(env, len); 787 if (result != NULL) { 788 (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)resolved); 789 } 790 } 791 return result; 792 } 793 794 JNIEXPORT void JNICALL 795 Java_sun_nio_fs_UnixNativeDispatcher_access0(JNIEnv* env, jclass this, 796 jlong pathAddress, jint amode) 797 { 798 int err; 799 const char* path = (const char*)jlong_to_ptr(pathAddress); 800 801 RESTARTABLE(access(path, (int)amode), err); 802 if (err == -1) { 803 throwUnixException(env, errno); 804 } 805 } 806 807 JNIEXPORT void JNICALL 808 Java_sun_nio_fs_UnixNativeDispatcher_statvfs0(JNIEnv* env, jclass this, 809 jlong pathAddress, jobject attrs) 810 { 811 int err; 812 struct statvfs64 buf; 813 const char* path = (const char*)jlong_to_ptr(pathAddress); 814 815 816 RESTARTABLE(statvfs64(path, &buf), err); 817 if (err == -1) { 818 throwUnixException(env, errno); 819 } else { 820 (*env)->SetLongField(env, attrs, attrs_f_frsize, long_to_jlong(buf.f_frsize)); 821 (*env)->SetLongField(env, attrs, attrs_f_blocks, long_to_jlong(buf.f_blocks)); 822 (*env)->SetLongField(env, attrs, attrs_f_bfree, long_to_jlong(buf.f_bfree)); 823 (*env)->SetLongField(env, attrs, attrs_f_bavail, long_to_jlong(buf.f_bavail)); 824 } 825 } 826 827 JNIEXPORT jlong JNICALL 828 Java_sun_nio_fs_UnixNativeDispatcher_pathconf0(JNIEnv* env, jclass this, 829 jlong pathAddress, jint name) 830 { 831 long err; 832 const char* path = (const char*)jlong_to_ptr(pathAddress); 833 834 err = pathconf(path, (int)name); 835 if (err == -1) { 836 throwUnixException(env, errno); 837 } 838 return (jlong)err; 839 } 840 841 JNIEXPORT jlong JNICALL 842 Java_sun_nio_fs_UnixNativeDispatcher_fpathconf(JNIEnv* env, jclass this, 843 jint fd, jint name) 844 { 845 long err; 846 847 err = fpathconf((int)fd, (int)name); 848 if (err == -1) { 849 throwUnixException(env, errno); 850 } 851 return (jlong)err; 852 } 853 854 JNIEXPORT void JNICALL 855 Java_sun_nio_fs_UnixNativeDispatcher_mknod0(JNIEnv* env, jclass this, 856 jlong pathAddress, jint mode, jlong dev) 857 { 858 int err; 859 const char* path = (const char*)jlong_to_ptr(pathAddress); 860 861 RESTARTABLE(mknod(path, (mode_t)mode, (dev_t)dev), err); 862 if (err == -1) { 863 throwUnixException(env, errno); 864 } 865 } 866 867 JNIEXPORT jbyteArray JNICALL 868 Java_sun_nio_fs_UnixNativeDispatcher_getpwuid(JNIEnv* env, jclass this, jint uid) 869 { 870 jbyteArray result = NULL; 871 int buflen; 872 char* pwbuf; 873 874 /* allocate buffer for password record */ 875 buflen = (int)sysconf(_SC_GETPW_R_SIZE_MAX); 876 if (buflen == -1) 877 buflen = ENT_BUF_SIZE; 878 pwbuf = (char*)malloc(buflen); 879 if (pwbuf == NULL) { 880 JNU_ThrowOutOfMemoryError(env, "native heap"); 881 } else { 882 struct passwd pwent; 883 struct passwd* p = NULL; 884 int res = 0; 885 886 errno = 0; 887 #ifdef __solaris__ 888 RESTARTABLE_RETURN_PTR(getpwuid_r((uid_t)uid, &pwent, pwbuf, (size_t)buflen), p); 889 #else 890 RESTARTABLE(getpwuid_r((uid_t)uid, &pwent, pwbuf, (size_t)buflen, &p), res); 891 #endif 892 893 if (res != 0 || p == NULL || p->pw_name == NULL || *(p->pw_name) == '\0') { 894 /* not found or error */ 895 if (errno == 0) 896 errno = ENOENT; 897 throwUnixException(env, errno); 898 } else { 899 jsize len = strlen(p->pw_name); 900 result = (*env)->NewByteArray(env, len); 901 if (result != NULL) { 902 (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)(p->pw_name)); 903 } 904 } 905 free(pwbuf); 906 } 907 908 return result; 909 } 910 911 912 JNIEXPORT jbyteArray JNICALL 913 Java_sun_nio_fs_UnixNativeDispatcher_getgrgid(JNIEnv* env, jclass this, jint gid) 914 { 915 jbyteArray result = NULL; 916 int buflen; 917 int retry; 918 919 /* initial size of buffer for group record */ 920 buflen = (int)sysconf(_SC_GETGR_R_SIZE_MAX); 921 if (buflen == -1) 922 buflen = ENT_BUF_SIZE; 923 924 do { 925 struct group grent; 926 struct group* g = NULL; 927 int res = 0; 928 929 char* grbuf = (char*)malloc(buflen); 930 if (grbuf == NULL) { 931 JNU_ThrowOutOfMemoryError(env, "native heap"); 932 return NULL; 933 } 934 935 errno = 0; 936 #ifdef __solaris__ 937 RESTARTABLE_RETURN_PTR(getgrgid_r((gid_t)gid, &grent, grbuf, (size_t)buflen), g); 938 #else 939 RESTARTABLE(getgrgid_r((gid_t)gid, &grent, grbuf, (size_t)buflen, &g), res); 940 #endif 941 942 retry = 0; 943 if (res != 0 || g == NULL || g->gr_name == NULL || *(g->gr_name) == '\0') { 944 /* not found or error */ 945 if (errno == ERANGE) { 946 /* insufficient buffer size so need larger buffer */ 947 buflen += ENT_BUF_SIZE; 948 retry = 1; 949 } else { 950 if (errno == 0) 951 errno = ENOENT; 952 throwUnixException(env, errno); 953 } 954 } else { 955 jsize len = strlen(g->gr_name); 956 result = (*env)->NewByteArray(env, len); 957 if (result != NULL) { 958 (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)(g->gr_name)); 959 } 960 } 961 962 free(grbuf); 963 964 } while (retry); 965 966 return result; 967 } 968 969 JNIEXPORT jint JNICALL 970 Java_sun_nio_fs_UnixNativeDispatcher_getpwnam0(JNIEnv* env, jclass this, 971 jlong nameAddress) 972 { 973 jint uid = -1; 974 int buflen; 975 char* pwbuf; 976 977 /* allocate buffer for password record */ 978 buflen = (int)sysconf(_SC_GETPW_R_SIZE_MAX); 979 if (buflen == -1) 980 buflen = ENT_BUF_SIZE; 981 pwbuf = (char*)malloc(buflen); 982 if (pwbuf == NULL) { 983 JNU_ThrowOutOfMemoryError(env, "native heap"); 984 } else { 985 struct passwd pwent; 986 struct passwd* p = NULL; 987 int res = 0; 988 const char* name = (const char*)jlong_to_ptr(nameAddress); 989 990 errno = 0; 991 #ifdef __solaris__ 992 RESTARTABLE_RETURN_PTR(getpwnam_r(name, &pwent, pwbuf, (size_t)buflen), p); 993 #else 994 RESTARTABLE(getpwnam_r(name, &pwent, pwbuf, (size_t)buflen, &p), res); 995 #endif 996 997 if (res != 0 || p == NULL || p->pw_name == NULL || *(p->pw_name) == '\0') { 998 /* not found or error */ 999 if (errno != 0 && errno != ENOENT && errno != ESRCH) 1000 throwUnixException(env, errno); 1001 } else { 1002 uid = p->pw_uid; 1003 } 1004 free(pwbuf); 1005 } 1006 1007 return uid; 1008 } 1009 1010 JNIEXPORT jint JNICALL 1011 Java_sun_nio_fs_UnixNativeDispatcher_getgrnam0(JNIEnv* env, jclass this, 1012 jlong nameAddress) 1013 { 1014 jint gid = -1; 1015 int buflen, retry; 1016 1017 /* initial size of buffer for group record */ 1018 buflen = (int)sysconf(_SC_GETGR_R_SIZE_MAX); 1019 if (buflen == -1) 1020 buflen = ENT_BUF_SIZE; 1021 1022 do { 1023 struct group grent; 1024 struct group* g = NULL; 1025 int res = 0; 1026 char *grbuf; 1027 const char* name = (const char*)jlong_to_ptr(nameAddress); 1028 1029 grbuf = (char*)malloc(buflen); 1030 if (grbuf == NULL) { 1031 JNU_ThrowOutOfMemoryError(env, "native heap"); 1032 return -1; 1033 } 1034 1035 errno = 0; 1036 #ifdef __solaris__ 1037 RESTARTABLE_RETURN_PTR(getgrnam_r(name, &grent, grbuf, (size_t)buflen), g); 1038 #else 1039 RESTARTABLE(getgrnam_r(name, &grent, grbuf, (size_t)buflen, &g), res); 1040 #endif 1041 1042 retry = 0; 1043 if (res != 0 || g == NULL || g->gr_name == NULL || *(g->gr_name) == '\0') { 1044 /* not found or error */ 1045 if (errno != 0 && errno != ENOENT && errno != ESRCH) { 1046 if (errno == ERANGE) { 1047 /* insufficient buffer size so need larger buffer */ 1048 buflen += ENT_BUF_SIZE; 1049 retry = 1; 1050 } else { 1051 throwUnixException(env, errno); 1052 } 1053 } 1054 } else { 1055 gid = g->gr_gid; 1056 } 1057 1058 free(grbuf); 1059 1060 } while (retry); 1061 1062 return gid; 1063 } 1064 1065 JNIEXPORT jint JNICALL 1066 Java_sun_nio_fs_UnixNativeDispatcher_getextmntent(JNIEnv* env, jclass this, 1067 jlong value, jobject entry) 1068 { 1069 #ifdef __solaris__ 1070 struct extmnttab ent; 1071 #else 1072 struct mntent ent; 1073 char buf[1024]; 1074 int buflen = sizeof(buf); 1075 struct mntent* m; 1076 #endif 1077 FILE* fp = jlong_to_ptr(value); 1078 jsize len; 1079 jbyteArray bytes; 1080 char* name; 1081 char* dir; 1082 char* fstype; 1083 char* options; 1084 dev_t dev; 1085 1086 #ifdef __solaris__ 1087 if (getextmntent(fp, &ent, 0)) 1088 return -1; 1089 name = ent.mnt_special; 1090 dir = ent.mnt_mountp; 1091 fstype = ent.mnt_fstype; 1092 options = ent.mnt_mntopts; 1093 dev = makedev(ent.mnt_major, ent.mnt_minor); 1094 if (dev == NODEV) { 1095 /* possible bug on Solaris 8 and 9 */ 1096 throwUnixException(env, errno); 1097 return -1; 1098 } 1099 #else 1100 m = getmntent_r(fp, &ent, (char*)&buf, buflen); 1101 if (m == NULL) 1102 return -1; 1103 name = m->mnt_fsname; 1104 dir = m->mnt_dir; 1105 fstype = m->mnt_type; 1106 options = m->mnt_opts; 1107 dev = 0; 1108 #endif 1109 1110 len = strlen(name); 1111 bytes = (*env)->NewByteArray(env, len); 1112 if (bytes == NULL) 1113 return -1; 1114 (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)name); 1115 (*env)->SetObjectField(env, entry, entry_name, bytes); 1116 1117 len = strlen(dir); 1118 bytes = (*env)->NewByteArray(env, len); 1119 if (bytes == NULL) 1120 return -1; 1121 (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)dir); 1122 (*env)->SetObjectField(env, entry, entry_dir, bytes); 1123 1124 len = strlen(fstype); 1125 bytes = (*env)->NewByteArray(env, len); 1126 if (bytes == NULL) 1127 return -1; 1128 (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)fstype); 1129 (*env)->SetObjectField(env, entry, entry_fstype, bytes); 1130 1131 len = strlen(options); 1132 bytes = (*env)->NewByteArray(env, len); 1133 if (bytes == NULL) 1134 return -1; 1135 (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)options); 1136 (*env)->SetObjectField(env, entry, entry_options, bytes); 1137 1138 if (dev != 0) 1139 (*env)->SetLongField(env, entry, entry_dev, (jlong)dev); 1140 1141 return 0; 1142 }