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