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