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