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