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 #if defined(__linux__) || defined(_AIX) 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 #ifdef _AIX 298 /* strerror() is not thread-safe on AIX so we have to use strerror_r() */ 299 char buffer[256]; 300 msg = (strerror_r((int)error, buffer, 256) == 0) ? buffer : "Error while calling strerror_r"; 301 #else 302 msg = strerror((int)error); 303 #endif 304 len = strlen(msg); 305 bytes = (*env)->NewByteArray(env, len); 306 if (bytes != NULL) { 307 (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)msg); 308 } 309 return bytes; 310 } 311 312 JNIEXPORT jint 313 Java_sun_nio_fs_UnixNativeDispatcher_dup(JNIEnv* env, jclass this, jint fd) { 314 315 int res = -1; 316 317 RESTARTABLE(dup((int)fd), res); 318 if (fd == -1) { 319 throwUnixException(env, errno); 320 } 321 return (jint)res; 322 } 323 324 JNIEXPORT jlong JNICALL 325 Java_sun_nio_fs_UnixNativeDispatcher_fopen0(JNIEnv* env, jclass this, 326 jlong pathAddress, jlong modeAddress) 327 { 328 FILE* fp = NULL; 329 const char* path = (const char*)jlong_to_ptr(pathAddress); 330 const char* mode = (const char*)jlong_to_ptr(modeAddress); 331 332 do { 333 fp = fopen(path, mode); 334 } while (fp == NULL && errno == EINTR); 335 336 if (fp == NULL) { 337 throwUnixException(env, errno); 338 } 339 340 return ptr_to_jlong(fp); 341 } 342 343 JNIEXPORT void JNICALL 344 Java_sun_nio_fs_UnixNativeDispatcher_fclose(JNIEnv* env, jclass this, jlong stream) 345 { 346 int res; 347 FILE* fp = jlong_to_ptr(stream); 348 349 do { 350 res = fclose(fp); 351 } while (res == EOF && errno == EINTR); 352 if (res == EOF) { 353 throwUnixException(env, errno); 354 } 355 } 356 357 JNIEXPORT jint JNICALL 358 Java_sun_nio_fs_UnixNativeDispatcher_open0(JNIEnv* env, jclass this, 359 jlong pathAddress, jint oflags, jint mode) 360 { 361 jint fd; 362 const char* path = (const char*)jlong_to_ptr(pathAddress); 363 364 RESTARTABLE(open64(path, (int)oflags, (mode_t)mode), fd); 365 if (fd == -1) { 366 throwUnixException(env, errno); 367 } 368 return fd; 369 } 370 371 JNIEXPORT jint JNICALL 372 Java_sun_nio_fs_UnixNativeDispatcher_openat0(JNIEnv* env, jclass this, jint dfd, 373 jlong pathAddress, jint oflags, jint mode) 374 { 375 jint fd; 376 const char* path = (const char*)jlong_to_ptr(pathAddress); 377 378 if (my_openat64_func == NULL) { 379 JNU_ThrowInternalError(env, "should not reach here"); 380 return -1; 381 } 382 383 RESTARTABLE((*my_openat64_func)(dfd, path, (int)oflags, (mode_t)mode), fd); 384 if (fd == -1) { 385 throwUnixException(env, errno); 386 } 387 return fd; 388 } 389 390 JNIEXPORT void JNICALL 391 Java_sun_nio_fs_UnixNativeDispatcher_close(JNIEnv* env, jclass this, jint fd) { 392 int err; 393 /* TDB - need to decide if EIO and other errors should cause exception */ 394 RESTARTABLE(close((int)fd), err); 395 } 396 397 JNIEXPORT jint JNICALL 398 Java_sun_nio_fs_UnixNativeDispatcher_read(JNIEnv* env, jclass this, jint fd, 399 jlong address, jint nbytes) 400 { 401 ssize_t n; 402 void* bufp = jlong_to_ptr(address); 403 RESTARTABLE(read((int)fd, bufp, (size_t)nbytes), n); 404 if (n == -1) { 405 throwUnixException(env, errno); 406 } 407 return (jint)n; 408 } 409 410 JNIEXPORT jint JNICALL 411 Java_sun_nio_fs_UnixNativeDispatcher_write(JNIEnv* env, jclass this, jint fd, 412 jlong address, jint nbytes) 413 { 414 ssize_t n; 415 void* bufp = jlong_to_ptr(address); 416 RESTARTABLE(write((int)fd, bufp, (size_t)nbytes), n); 417 if (n == -1) { 418 throwUnixException(env, errno); 419 } 420 return (jint)n; 421 } 422 423 /** 424 * Copy stat64 members into sun.nio.fs.UnixFileAttributes 425 */ 426 static void prepAttributes(JNIEnv* env, struct stat64* buf, jobject attrs) { 427 (*env)->SetIntField(env, attrs, attrs_st_mode, (jint)buf->st_mode); 428 (*env)->SetLongField(env, attrs, attrs_st_ino, (jlong)buf->st_ino); 429 (*env)->SetLongField(env, attrs, attrs_st_dev, (jlong)buf->st_dev); 430 (*env)->SetLongField(env, attrs, attrs_st_rdev, (jlong)buf->st_rdev); 431 (*env)->SetIntField(env, attrs, attrs_st_nlink, (jint)buf->st_nlink); 432 (*env)->SetIntField(env, attrs, attrs_st_uid, (jint)buf->st_uid); 433 (*env)->SetIntField(env, attrs, attrs_st_gid, (jint)buf->st_gid); 434 (*env)->SetLongField(env, attrs, attrs_st_size, (jlong)buf->st_size); 435 (*env)->SetLongField(env, attrs, attrs_st_atime_sec, (jlong)buf->st_atime); 436 (*env)->SetLongField(env, attrs, attrs_st_mtime_sec, (jlong)buf->st_mtime); 437 (*env)->SetLongField(env, attrs, attrs_st_ctime_sec, (jlong)buf->st_ctime); 438 439 #ifdef _DARWIN_FEATURE_64_BIT_INODE 440 (*env)->SetLongField(env, attrs, attrs_st_birthtime_sec, (jlong)buf->st_birthtime); 441 #endif 442 443 #if (_POSIX_C_SOURCE >= 200809L) || defined(__solaris__) 444 (*env)->SetLongField(env, attrs, attrs_st_atime_nsec, (jlong)buf->st_atim.tv_nsec); 445 (*env)->SetLongField(env, attrs, attrs_st_mtime_nsec, (jlong)buf->st_mtim.tv_nsec); 446 (*env)->SetLongField(env, attrs, attrs_st_ctime_nsec, (jlong)buf->st_ctim.tv_nsec); 447 #endif 448 } 449 450 JNIEXPORT void JNICALL 451 Java_sun_nio_fs_UnixNativeDispatcher_stat0(JNIEnv* env, jclass this, 452 jlong pathAddress, jobject attrs) 453 { 454 int err; 455 struct stat64 buf; 456 const char* path = (const char*)jlong_to_ptr(pathAddress); 457 458 RESTARTABLE(stat64(path, &buf), err); 459 if (err == -1) { 460 throwUnixException(env, errno); 461 } else { 462 prepAttributes(env, &buf, attrs); 463 } 464 } 465 466 JNIEXPORT void JNICALL 467 Java_sun_nio_fs_UnixNativeDispatcher_lstat0(JNIEnv* env, jclass this, 468 jlong pathAddress, jobject attrs) 469 { 470 int err; 471 struct stat64 buf; 472 const char* path = (const char*)jlong_to_ptr(pathAddress); 473 474 RESTARTABLE(lstat64(path, &buf), err); 475 if (err == -1) { 476 throwUnixException(env, errno); 477 } else { 478 prepAttributes(env, &buf, attrs); 479 } 480 } 481 482 JNIEXPORT void JNICALL 483 Java_sun_nio_fs_UnixNativeDispatcher_fstat(JNIEnv* env, jclass this, jint fd, 484 jobject attrs) 485 { 486 int err; 487 struct stat64 buf; 488 489 RESTARTABLE(fstat64((int)fd, &buf), err); 490 if (err == -1) { 491 throwUnixException(env, errno); 492 } else { 493 prepAttributes(env, &buf, attrs); 494 } 495 } 496 497 JNIEXPORT void JNICALL 498 Java_sun_nio_fs_UnixNativeDispatcher_fstatat0(JNIEnv* env, jclass this, jint dfd, 499 jlong pathAddress, jint flag, jobject attrs) 500 { 501 int err; 502 struct stat64 buf; 503 const char* path = (const char*)jlong_to_ptr(pathAddress); 504 505 if (my_fstatat64_func == NULL) { 506 JNU_ThrowInternalError(env, "should not reach here"); 507 return; 508 } 509 RESTARTABLE((*my_fstatat64_func)((int)dfd, path, &buf, (int)flag), err); 510 if (err == -1) { 511 throwUnixException(env, errno); 512 } else { 513 prepAttributes(env, &buf, attrs); 514 } 515 } 516 517 JNIEXPORT void JNICALL 518 Java_sun_nio_fs_UnixNativeDispatcher_chmod0(JNIEnv* env, jclass this, 519 jlong pathAddress, jint mode) 520 { 521 int err; 522 const char* path = (const char*)jlong_to_ptr(pathAddress); 523 524 RESTARTABLE(chmod(path, (mode_t)mode), err); 525 if (err == -1) { 526 throwUnixException(env, errno); 527 } 528 } 529 530 JNIEXPORT void JNICALL 531 Java_sun_nio_fs_UnixNativeDispatcher_fchmod(JNIEnv* env, jclass this, jint filedes, 532 jint mode) 533 { 534 int err; 535 536 RESTARTABLE(fchmod((int)filedes, (mode_t)mode), err); 537 if (err == -1) { 538 throwUnixException(env, errno); 539 } 540 } 541 542 543 JNIEXPORT void JNICALL 544 Java_sun_nio_fs_UnixNativeDispatcher_chown0(JNIEnv* env, jclass this, 545 jlong pathAddress, jint uid, jint gid) 546 { 547 int err; 548 const char* path = (const char*)jlong_to_ptr(pathAddress); 549 550 RESTARTABLE(chown(path, (uid_t)uid, (gid_t)gid), err); 551 if (err == -1) { 552 throwUnixException(env, errno); 553 } 554 } 555 556 JNIEXPORT void JNICALL 557 Java_sun_nio_fs_UnixNativeDispatcher_lchown0(JNIEnv* env, jclass this, jlong pathAddress, jint uid, jint gid) 558 { 559 int err; 560 const char* path = (const char*)jlong_to_ptr(pathAddress); 561 562 RESTARTABLE(lchown(path, (uid_t)uid, (gid_t)gid), err); 563 if (err == -1) { 564 throwUnixException(env, errno); 565 } 566 } 567 568 JNIEXPORT void JNICALL 569 Java_sun_nio_fs_UnixNativeDispatcher_fchown(JNIEnv* env, jclass this, jint filedes, jint uid, jint gid) 570 { 571 int err; 572 573 RESTARTABLE(fchown(filedes, (uid_t)uid, (gid_t)gid), err); 574 if (err == -1) { 575 throwUnixException(env, errno); 576 } 577 } 578 579 JNIEXPORT void JNICALL 580 Java_sun_nio_fs_UnixNativeDispatcher_utimes0(JNIEnv* env, jclass this, 581 jlong pathAddress, jlong accessTime, jlong modificationTime) 582 { 583 int err; 584 struct timeval times[2]; 585 const char* path = (const char*)jlong_to_ptr(pathAddress); 586 587 times[0].tv_sec = accessTime / 1000000; 588 times[0].tv_usec = accessTime % 1000000; 589 590 times[1].tv_sec = modificationTime / 1000000; 591 times[1].tv_usec = modificationTime % 1000000; 592 593 RESTARTABLE(utimes(path, ×[0]), err); 594 if (err == -1) { 595 throwUnixException(env, errno); 596 } 597 } 598 599 JNIEXPORT void JNICALL 600 Java_sun_nio_fs_UnixNativeDispatcher_futimes(JNIEnv* env, jclass this, jint filedes, 601 jlong accessTime, jlong modificationTime) 602 { 603 struct timeval times[2]; 604 int err = 0; 605 606 times[0].tv_sec = accessTime / 1000000; 607 times[0].tv_usec = accessTime % 1000000; 608 609 times[1].tv_sec = modificationTime / 1000000; 610 times[1].tv_usec = modificationTime % 1000000; 611 612 #ifdef _ALLBSD_SOURCE 613 RESTARTABLE(futimes(filedes, ×[0]), err); 614 #else 615 if (my_futimesat_func == NULL) { 616 JNU_ThrowInternalError(env, "my_ftimesat_func is NULL"); 617 return; 618 } 619 RESTARTABLE((*my_futimesat_func)(filedes, NULL, ×[0]), err); 620 #endif 621 if (err == -1) { 622 throwUnixException(env, errno); 623 } 624 } 625 626 JNIEXPORT jlong JNICALL 627 Java_sun_nio_fs_UnixNativeDispatcher_opendir0(JNIEnv* env, jclass this, 628 jlong pathAddress) 629 { 630 DIR* dir; 631 const char* path = (const char*)jlong_to_ptr(pathAddress); 632 633 /* EINTR not listed as a possible error */ 634 dir = opendir(path); 635 if (dir == NULL) { 636 throwUnixException(env, errno); 637 } 638 return ptr_to_jlong(dir); 639 } 640 641 JNIEXPORT jlong JNICALL 642 Java_sun_nio_fs_UnixNativeDispatcher_fdopendir(JNIEnv* env, jclass this, int dfd) { 643 DIR* dir; 644 645 if (my_fdopendir_func == NULL) { 646 JNU_ThrowInternalError(env, "should not reach here"); 647 return (jlong)-1; 648 } 649 650 /* EINTR not listed as a possible error */ 651 dir = (*my_fdopendir_func)((int)dfd); 652 if (dir == NULL) { 653 throwUnixException(env, errno); 654 } 655 return ptr_to_jlong(dir); 656 } 657 658 JNIEXPORT void JNICALL 659 Java_sun_nio_fs_UnixNativeDispatcher_closedir(JNIEnv* env, jclass this, jlong dir) { 660 int err; 661 DIR* dirp = jlong_to_ptr(dir); 662 663 RESTARTABLE(closedir(dirp), err); 664 if (errno == -1) { 665 throwUnixException(env, errno); 666 } 667 } 668 669 JNIEXPORT jbyteArray JNICALL 670 Java_sun_nio_fs_UnixNativeDispatcher_readdir(JNIEnv* env, jclass this, jlong value) { 671 struct dirent64* result; 672 struct { 673 struct dirent64 buf; 674 char name_extra[PATH_MAX + 1 - sizeof result->d_name]; 675 } entry; 676 struct dirent64* ptr = &entry.buf; 677 int res; 678 DIR* dirp = jlong_to_ptr(value); 679 680 /* EINTR not listed as a possible error */ 681 /* TDB: reentrant version probably not required here */ 682 res = readdir64_r(dirp, ptr, &result); 683 684 #ifdef _AIX 685 /* On AIX, readdir_r() returns EBADF (i.e. '9') and sets 'result' to NULL for the */ 686 /* directory stream end. Otherwise, 'errno' will contain the error code. */ 687 if (res != 0) { 688 res = (result == NULL && res == EBADF) ? 0 : errno; 689 } 690 #endif 691 692 if (res != 0) { 693 throwUnixException(env, res); 694 return NULL; 695 } else { 696 if (result == NULL) { 697 return NULL; 698 } else { 699 jsize len = strlen(ptr->d_name); 700 jbyteArray bytes = (*env)->NewByteArray(env, len); 701 if (bytes != NULL) { 702 (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)(ptr->d_name)); 703 } 704 return bytes; 705 } 706 } 707 } 708 709 JNIEXPORT void JNICALL 710 Java_sun_nio_fs_UnixNativeDispatcher_mkdir0(JNIEnv* env, jclass this, 711 jlong pathAddress, jint mode) 712 { 713 const char* path = (const char*)jlong_to_ptr(pathAddress); 714 715 /* EINTR not listed as a possible error */ 716 if (mkdir(path, (mode_t)mode) == -1) { 717 throwUnixException(env, errno); 718 } 719 } 720 721 JNIEXPORT void JNICALL 722 Java_sun_nio_fs_UnixNativeDispatcher_rmdir0(JNIEnv* env, jclass this, 723 jlong pathAddress) 724 { 725 const char* path = (const char*)jlong_to_ptr(pathAddress); 726 727 /* EINTR not listed as a possible error */ 728 if (rmdir(path) == -1) { 729 throwUnixException(env, errno); 730 } 731 } 732 733 JNIEXPORT void JNICALL 734 Java_sun_nio_fs_UnixNativeDispatcher_link0(JNIEnv* env, jclass this, 735 jlong existingAddress, jlong newAddress) 736 { 737 int err; 738 const char* existing = (const char*)jlong_to_ptr(existingAddress); 739 const char* newname = (const char*)jlong_to_ptr(newAddress); 740 741 RESTARTABLE(link(existing, newname), err); 742 if (err == -1) { 743 throwUnixException(env, errno); 744 } 745 } 746 747 748 JNIEXPORT void JNICALL 749 Java_sun_nio_fs_UnixNativeDispatcher_unlink0(JNIEnv* env, jclass this, 750 jlong pathAddress) 751 { 752 const char* path = (const char*)jlong_to_ptr(pathAddress); 753 754 /* EINTR not listed as a possible error */ 755 if (unlink(path) == -1) { 756 throwUnixException(env, errno); 757 } 758 } 759 760 JNIEXPORT void JNICALL 761 Java_sun_nio_fs_UnixNativeDispatcher_unlinkat0(JNIEnv* env, jclass this, jint dfd, 762 jlong pathAddress, jint flags) 763 { 764 const char* path = (const char*)jlong_to_ptr(pathAddress); 765 766 if (my_unlinkat_func == NULL) { 767 JNU_ThrowInternalError(env, "should not reach here"); 768 return; 769 } 770 771 /* EINTR not listed as a possible error */ 772 if ((*my_unlinkat_func)((int)dfd, path, (int)flags) == -1) { 773 throwUnixException(env, errno); 774 } 775 } 776 777 JNIEXPORT void JNICALL 778 Java_sun_nio_fs_UnixNativeDispatcher_rename0(JNIEnv* env, jclass this, 779 jlong fromAddress, jlong toAddress) 780 { 781 const char* from = (const char*)jlong_to_ptr(fromAddress); 782 const char* to = (const char*)jlong_to_ptr(toAddress); 783 784 /* EINTR not listed as a possible error */ 785 if (rename(from, to) == -1) { 786 throwUnixException(env, errno); 787 } 788 } 789 790 JNIEXPORT void JNICALL 791 Java_sun_nio_fs_UnixNativeDispatcher_renameat0(JNIEnv* env, jclass this, 792 jint fromfd, jlong fromAddress, jint tofd, jlong toAddress) 793 { 794 const char* from = (const char*)jlong_to_ptr(fromAddress); 795 const char* to = (const char*)jlong_to_ptr(toAddress); 796 797 if (my_renameat_func == NULL) { 798 JNU_ThrowInternalError(env, "should not reach here"); 799 return; 800 } 801 802 /* EINTR not listed as a possible error */ 803 if ((*my_renameat_func)((int)fromfd, from, (int)tofd, to) == -1) { 804 throwUnixException(env, errno); 805 } 806 } 807 808 JNIEXPORT void JNICALL 809 Java_sun_nio_fs_UnixNativeDispatcher_symlink0(JNIEnv* env, jclass this, 810 jlong targetAddress, jlong linkAddress) 811 { 812 const char* target = (const char*)jlong_to_ptr(targetAddress); 813 const char* link = (const char*)jlong_to_ptr(linkAddress); 814 815 /* EINTR not listed as a possible error */ 816 if (symlink(target, link) == -1) { 817 throwUnixException(env, errno); 818 } 819 } 820 821 JNIEXPORT jbyteArray JNICALL 822 Java_sun_nio_fs_UnixNativeDispatcher_readlink0(JNIEnv* env, jclass this, 823 jlong pathAddress) 824 { 825 jbyteArray result = NULL; 826 char target[PATH_MAX+1]; 827 const char* path = (const char*)jlong_to_ptr(pathAddress); 828 829 /* EINTR not listed as a possible error */ 830 int n = readlink(path, target, sizeof(target)); 831 if (n == -1) { 832 throwUnixException(env, errno); 833 } else { 834 jsize len; 835 if (n == sizeof(target)) { 836 n--; 837 } 838 target[n] = '\0'; 839 len = (jsize)strlen(target); 840 result = (*env)->NewByteArray(env, len); 841 if (result != NULL) { 842 (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)target); 843 } 844 } 845 return result; 846 } 847 848 JNIEXPORT jbyteArray JNICALL 849 Java_sun_nio_fs_UnixNativeDispatcher_realpath0(JNIEnv* env, jclass this, 850 jlong pathAddress) 851 { 852 jbyteArray result = NULL; 853 char resolved[PATH_MAX+1]; 854 const char* path = (const char*)jlong_to_ptr(pathAddress); 855 856 /* EINTR not listed as a possible error */ 857 if (realpath(path, resolved) == NULL) { 858 throwUnixException(env, errno); 859 } else { 860 jsize len = (jsize)strlen(resolved); 861 result = (*env)->NewByteArray(env, len); 862 if (result != NULL) { 863 (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)resolved); 864 } 865 } 866 return result; 867 } 868 869 JNIEXPORT void JNICALL 870 Java_sun_nio_fs_UnixNativeDispatcher_access0(JNIEnv* env, jclass this, 871 jlong pathAddress, jint amode) 872 { 873 int err; 874 const char* path = (const char*)jlong_to_ptr(pathAddress); 875 876 RESTARTABLE(access(path, (int)amode), err); 877 if (err == -1) { 878 throwUnixException(env, errno); 879 } 880 } 881 882 JNIEXPORT void JNICALL 883 Java_sun_nio_fs_UnixNativeDispatcher_statvfs0(JNIEnv* env, jclass this, 884 jlong pathAddress, jobject attrs) 885 { 886 int err; 887 struct statvfs64 buf; 888 const char* path = (const char*)jlong_to_ptr(pathAddress); 889 890 891 RESTARTABLE(statvfs64(path, &buf), err); 892 if (err == -1) { 893 throwUnixException(env, errno); 894 } else { 895 #ifdef _AIX 896 /* AIX returns ULONG_MAX in buf.f_blocks for the /proc file system. */ 897 /* This is too big for a Java signed long and fools various tests. */ 898 if (buf.f_blocks == ULONG_MAX) { 899 buf.f_blocks = 0; 900 } 901 /* The number of free or available blocks can never exceed the total number of blocks */ 902 if (buf.f_blocks == 0) { 903 buf.f_bfree = 0; 904 buf.f_bavail = 0; 905 } 906 #endif 907 (*env)->SetLongField(env, attrs, attrs_f_frsize, long_to_jlong(buf.f_frsize)); 908 (*env)->SetLongField(env, attrs, attrs_f_blocks, long_to_jlong(buf.f_blocks)); 909 (*env)->SetLongField(env, attrs, attrs_f_bfree, long_to_jlong(buf.f_bfree)); 910 (*env)->SetLongField(env, attrs, attrs_f_bavail, long_to_jlong(buf.f_bavail)); 911 } 912 } 913 914 JNIEXPORT jlong JNICALL 915 Java_sun_nio_fs_UnixNativeDispatcher_pathconf0(JNIEnv* env, jclass this, 916 jlong pathAddress, jint name) 917 { 918 long err; 919 const char* path = (const char*)jlong_to_ptr(pathAddress); 920 921 err = pathconf(path, (int)name); 922 if (err == -1) { 923 throwUnixException(env, errno); 924 } 925 return (jlong)err; 926 } 927 928 JNIEXPORT jlong JNICALL 929 Java_sun_nio_fs_UnixNativeDispatcher_fpathconf(JNIEnv* env, jclass this, 930 jint fd, jint name) 931 { 932 long err; 933 934 err = fpathconf((int)fd, (int)name); 935 if (err == -1) { 936 throwUnixException(env, errno); 937 } 938 return (jlong)err; 939 } 940 941 JNIEXPORT void JNICALL 942 Java_sun_nio_fs_UnixNativeDispatcher_mknod0(JNIEnv* env, jclass this, 943 jlong pathAddress, jint mode, jlong dev) 944 { 945 int err; 946 const char* path = (const char*)jlong_to_ptr(pathAddress); 947 948 RESTARTABLE(mknod(path, (mode_t)mode, (dev_t)dev), err); 949 if (err == -1) { 950 throwUnixException(env, errno); 951 } 952 } 953 954 JNIEXPORT jbyteArray JNICALL 955 Java_sun_nio_fs_UnixNativeDispatcher_getpwuid(JNIEnv* env, jclass this, jint uid) 956 { 957 jbyteArray result = NULL; 958 int buflen; 959 char* pwbuf; 960 961 /* allocate buffer for password record */ 962 buflen = (int)sysconf(_SC_GETPW_R_SIZE_MAX); 963 if (buflen == -1) 964 buflen = ENT_BUF_SIZE; 965 pwbuf = (char*)malloc(buflen); 966 if (pwbuf == NULL) { 967 JNU_ThrowOutOfMemoryError(env, "native heap"); 968 } else { 969 struct passwd pwent; 970 struct passwd* p = NULL; 971 int res = 0; 972 973 errno = 0; 974 #ifdef __solaris__ 975 RESTARTABLE_RETURN_PTR(getpwuid_r((uid_t)uid, &pwent, pwbuf, (size_t)buflen), p); 976 #else 977 RESTARTABLE(getpwuid_r((uid_t)uid, &pwent, pwbuf, (size_t)buflen, &p), res); 978 #endif 979 980 if (res != 0 || p == NULL || p->pw_name == NULL || *(p->pw_name) == '\0') { 981 /* not found or error */ 982 if (errno == 0) 983 #ifdef _AIX 984 /* On AIX, getpwuid_r returns ESRCH if user does not exist. */ 985 errno = ESRCH; 986 #else 987 errno = ENOENT; 988 #endif 989 throwUnixException(env, errno); 990 } else { 991 jsize len = strlen(p->pw_name); 992 result = (*env)->NewByteArray(env, len); 993 if (result != NULL) { 994 (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)(p->pw_name)); 995 } 996 } 997 free(pwbuf); 998 } 999 1000 return result; 1001 } 1002 1003 1004 JNIEXPORT jbyteArray JNICALL 1005 Java_sun_nio_fs_UnixNativeDispatcher_getgrgid(JNIEnv* env, jclass this, jint gid) 1006 { 1007 jbyteArray result = NULL; 1008 int buflen; 1009 int retry; 1010 1011 /* initial size of buffer for group record */ 1012 buflen = (int)sysconf(_SC_GETGR_R_SIZE_MAX); 1013 if (buflen == -1) 1014 buflen = ENT_BUF_SIZE; 1015 1016 do { 1017 struct group grent; 1018 struct group* g = NULL; 1019 int res = 0; 1020 1021 char* grbuf = (char*)malloc(buflen); 1022 if (grbuf == NULL) { 1023 JNU_ThrowOutOfMemoryError(env, "native heap"); 1024 return NULL; 1025 } 1026 1027 errno = 0; 1028 #ifdef __solaris__ 1029 RESTARTABLE_RETURN_PTR(getgrgid_r((gid_t)gid, &grent, grbuf, (size_t)buflen), g); 1030 #else 1031 RESTARTABLE(getgrgid_r((gid_t)gid, &grent, grbuf, (size_t)buflen, &g), res); 1032 #endif 1033 1034 retry = 0; 1035 if (res != 0 || g == NULL || g->gr_name == NULL || *(g->gr_name) == '\0') { 1036 /* not found or error */ 1037 if (errno == ERANGE) { 1038 /* insufficient buffer size so need larger buffer */ 1039 buflen += ENT_BUF_SIZE; 1040 retry = 1; 1041 } else { 1042 if (errno == 0) 1043 #ifdef _AIX 1044 /* On AIX, getgrgid_r returns ESRCH if group does not exist. */ 1045 errno = ESRCH; 1046 #else 1047 errno = ENOENT; 1048 #endif 1049 throwUnixException(env, errno); 1050 } 1051 } else { 1052 jsize len = strlen(g->gr_name); 1053 result = (*env)->NewByteArray(env, len); 1054 if (result != NULL) { 1055 (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)(g->gr_name)); 1056 } 1057 } 1058 1059 free(grbuf); 1060 1061 } while (retry); 1062 1063 return result; 1064 } 1065 1066 JNIEXPORT jint JNICALL 1067 Java_sun_nio_fs_UnixNativeDispatcher_getpwnam0(JNIEnv* env, jclass this, 1068 jlong nameAddress) 1069 { 1070 jint uid = -1; 1071 int buflen; 1072 char* pwbuf; 1073 1074 /* allocate buffer for password record */ 1075 buflen = (int)sysconf(_SC_GETPW_R_SIZE_MAX); 1076 if (buflen == -1) 1077 buflen = ENT_BUF_SIZE; 1078 pwbuf = (char*)malloc(buflen); 1079 if (pwbuf == NULL) { 1080 JNU_ThrowOutOfMemoryError(env, "native heap"); 1081 } else { 1082 struct passwd pwent; 1083 struct passwd* p = NULL; 1084 int res = 0; 1085 const char* name = (const char*)jlong_to_ptr(nameAddress); 1086 1087 errno = 0; 1088 #ifdef __solaris__ 1089 RESTARTABLE_RETURN_PTR(getpwnam_r(name, &pwent, pwbuf, (size_t)buflen), p); 1090 #else 1091 RESTARTABLE(getpwnam_r(name, &pwent, pwbuf, (size_t)buflen, &p), res); 1092 #endif 1093 1094 if (res != 0 || p == NULL || p->pw_name == NULL || *(p->pw_name) == '\0') { 1095 /* not found or error */ 1096 if (errno != 0 && errno != ENOENT && errno != ESRCH) 1097 throwUnixException(env, errno); 1098 } else { 1099 uid = p->pw_uid; 1100 } 1101 free(pwbuf); 1102 } 1103 1104 return uid; 1105 } 1106 1107 JNIEXPORT jint JNICALL 1108 Java_sun_nio_fs_UnixNativeDispatcher_getgrnam0(JNIEnv* env, jclass this, 1109 jlong nameAddress) 1110 { 1111 jint gid = -1; 1112 int buflen, retry; 1113 1114 /* initial size of buffer for group record */ 1115 buflen = (int)sysconf(_SC_GETGR_R_SIZE_MAX); 1116 if (buflen == -1) 1117 buflen = ENT_BUF_SIZE; 1118 1119 do { 1120 struct group grent; 1121 struct group* g = NULL; 1122 int res = 0; 1123 char *grbuf; 1124 const char* name = (const char*)jlong_to_ptr(nameAddress); 1125 1126 grbuf = (char*)malloc(buflen); 1127 if (grbuf == NULL) { 1128 JNU_ThrowOutOfMemoryError(env, "native heap"); 1129 return -1; 1130 } 1131 1132 errno = 0; 1133 #ifdef __solaris__ 1134 RESTARTABLE_RETURN_PTR(getgrnam_r(name, &grent, grbuf, (size_t)buflen), g); 1135 #else 1136 RESTARTABLE(getgrnam_r(name, &grent, grbuf, (size_t)buflen, &g), res); 1137 #endif 1138 1139 retry = 0; 1140 if (res != 0 || g == NULL || g->gr_name == NULL || *(g->gr_name) == '\0') { 1141 /* not found or error */ 1142 if (errno != 0 && errno != ENOENT && errno != ESRCH) { 1143 if (errno == ERANGE) { 1144 /* insufficient buffer size so need larger buffer */ 1145 buflen += ENT_BUF_SIZE; 1146 retry = 1; 1147 } else { 1148 throwUnixException(env, errno); 1149 } 1150 } 1151 } else { 1152 gid = g->gr_gid; 1153 } 1154 1155 free(grbuf); 1156 1157 } while (retry); 1158 1159 return gid; 1160 }