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