Path: blob/master/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c
41133 views
/*1* Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#include <stdio.h>26#include <stdlib.h>27#include <limits.h>28#include <fcntl.h>29#include <dirent.h>30#include <unistd.h>31#include <errno.h>32#include <dlfcn.h>33#include <sys/types.h>34#include <sys/stat.h>35#ifdef MACOSX36#include <sys/param.h>37#include <sys/mount.h>38#else39#include <sys/statvfs.h>40#endif41#include <sys/time.h>4243#if defined(__linux__) || defined(_ALLBSD_SOURCE)44#include <sys/xattr.h>45#endif4647/* For POSIX-compliant getpwuid_r */48#include <pwd.h>49#include <grp.h>5051#ifdef __linux__52#include <sys/syscall.h>53#endif5455#if defined(__linux__) || defined(_AIX)56#include <string.h>57#endif5859#ifdef _ALLBSD_SOURCE60#include <string.h>6162#define stat64 stat63#ifndef MACOSX64#define statvfs64 statvfs65#endif6667#define open64 open68#define fstat64 fstat69#define lstat64 lstat70#define readdir64 readdir71#endif7273#include "jni.h"74#include "jni_util.h"75#include "jlong.h"7677#include "sun_nio_fs_UnixNativeDispatcher.h"7879#if defined(_AIX)80#define DIR DIR6481#define dirent dirent6482#define opendir opendir6483#define readdir readdir6484#define closedir closedir6485#endif8687/**88* Size of password or group entry when not available via sysconf89*/90#define ENT_BUF_SIZE 10249192#define RESTARTABLE(_cmd, _result) do { \93do { \94_result = _cmd; \95} while((_result == -1) && (errno == EINTR)); \96} while(0)9798#define RESTARTABLE_RETURN_PTR(_cmd, _result) do { \99do { \100_result = _cmd; \101} while((_result == NULL) && (errno == EINTR)); \102} while(0)103104static jfieldID attrs_st_mode;105static jfieldID attrs_st_ino;106static jfieldID attrs_st_dev;107static jfieldID attrs_st_rdev;108static jfieldID attrs_st_nlink;109static jfieldID attrs_st_uid;110static jfieldID attrs_st_gid;111static jfieldID attrs_st_size;112static jfieldID attrs_st_atime_sec;113static jfieldID attrs_st_atime_nsec;114static jfieldID attrs_st_mtime_sec;115static jfieldID attrs_st_mtime_nsec;116static jfieldID attrs_st_ctime_sec;117static jfieldID attrs_st_ctime_nsec;118119#ifdef _DARWIN_FEATURE_64_BIT_INODE120static jfieldID attrs_st_birthtime_sec;121#endif122123static jfieldID attrs_f_frsize;124static jfieldID attrs_f_blocks;125static jfieldID attrs_f_bfree;126static jfieldID attrs_f_bavail;127128static jfieldID entry_name;129static jfieldID entry_dir;130static jfieldID entry_fstype;131static jfieldID entry_options;132static jfieldID entry_dev;133134/**135* System calls that may not be available at run time.136*/137typedef int openat64_func(int, const char *, int, ...);138typedef int fstatat64_func(int, const char *, struct stat64 *, int);139typedef int unlinkat_func(int, const char*, int);140typedef int renameat_func(int, const char*, int, const char*);141typedef int futimesat_func(int, const char *, const struct timeval *);142typedef int utimensat_func(int, const char *, const struct timespec *, int flags);143typedef int futimens_func(int, const struct timespec *);144typedef int lutimes_func(const char *, const struct timeval *);145typedef DIR* fdopendir_func(int);146147static openat64_func* my_openat64_func = NULL;148static fstatat64_func* my_fstatat64_func = NULL;149static unlinkat_func* my_unlinkat_func = NULL;150static renameat_func* my_renameat_func = NULL;151static futimesat_func* my_futimesat_func = NULL;152static utimensat_func* my_utimensat_func = NULL;153static futimens_func* my_futimens_func = NULL;154static lutimes_func* my_lutimes_func = NULL;155static fdopendir_func* my_fdopendir_func = NULL;156157#ifdef __ANDROID__158/*159* TODO: Android lacks support for the methods listed below. In it's place are160* alternatives that use existing Android functionality, but lack reentrant161* support. Determine if the following are the most suitable alternatives.162*163*/164int getgrgid_r(gid_t gid, struct group* grp, char* buf, size_t buflen, struct group** result) {165166*result = NULL;167errno = 0;168grp = getgrgid(gid);169if (grp == NULL) {170return errno;171}172// buf not used by caller (see below)173*result = grp;174return 0;175}176177int getgrnam_r(const char *name, struct group* grp, char* buf, size_t buflen, struct group** result) {178179*result = NULL;180errno = 0;181grp = getgrnam(name);182if (grp == NULL) {183return errno;184}185// buf not used by caller (see below)186*result = grp;187return 0;188189}190#endif191192/**193* fstatat missing from glibc on Linux.194*/195#if defined(__linux__) && (defined(__i386) || defined(__arm__))196#define FSTATAT64_SYSCALL_AVAILABLE197static int fstatat64_wrapper(int dfd, const char *path,198struct stat64 *statbuf, int flag)199{200#ifndef __NR_fstatat64201#define __NR_fstatat64 300202#endif203return syscall(__NR_fstatat64, dfd, path, statbuf, flag);204}205#endif206207#if defined(__linux__) && defined(_LP64) && defined(__NR_newfstatat)208#define FSTATAT64_SYSCALL_AVAILABLE209static int fstatat64_wrapper(int dfd, const char *path,210struct stat64 *statbuf, int flag)211{212return syscall(__NR_newfstatat, dfd, path, statbuf, flag);213}214#endif215216/**217* Call this to throw an internal UnixException when a system/library218* call fails219*/220static void throwUnixException(JNIEnv* env, int errnum) {221jobject x = JNU_NewObjectByName(env, "sun/nio/fs/UnixException",222"(I)V", errnum);223if (x != NULL) {224(*env)->Throw(env, x);225}226}227228/**229* Initialization230*/231JNIEXPORT jint JNICALL232Java_sun_nio_fs_UnixNativeDispatcher_init(JNIEnv* env, jclass this)233{234jint capabilities = 0;235jclass clazz;236237clazz = (*env)->FindClass(env, "sun/nio/fs/UnixFileAttributes");238CHECK_NULL_RETURN(clazz, 0);239attrs_st_mode = (*env)->GetFieldID(env, clazz, "st_mode", "I");240CHECK_NULL_RETURN(attrs_st_mode, 0);241attrs_st_ino = (*env)->GetFieldID(env, clazz, "st_ino", "J");242CHECK_NULL_RETURN(attrs_st_ino, 0);243attrs_st_dev = (*env)->GetFieldID(env, clazz, "st_dev", "J");244CHECK_NULL_RETURN(attrs_st_dev, 0);245attrs_st_rdev = (*env)->GetFieldID(env, clazz, "st_rdev", "J");246CHECK_NULL_RETURN(attrs_st_rdev, 0);247attrs_st_nlink = (*env)->GetFieldID(env, clazz, "st_nlink", "I");248CHECK_NULL_RETURN(attrs_st_nlink, 0);249attrs_st_uid = (*env)->GetFieldID(env, clazz, "st_uid", "I");250CHECK_NULL_RETURN(attrs_st_uid, 0);251attrs_st_gid = (*env)->GetFieldID(env, clazz, "st_gid", "I");252CHECK_NULL_RETURN(attrs_st_gid, 0);253attrs_st_size = (*env)->GetFieldID(env, clazz, "st_size", "J");254CHECK_NULL_RETURN(attrs_st_size, 0);255attrs_st_atime_sec = (*env)->GetFieldID(env, clazz, "st_atime_sec", "J");256CHECK_NULL_RETURN(attrs_st_atime_sec, 0);257attrs_st_atime_nsec = (*env)->GetFieldID(env, clazz, "st_atime_nsec", "J");258CHECK_NULL_RETURN(attrs_st_atime_nsec, 0);259attrs_st_mtime_sec = (*env)->GetFieldID(env, clazz, "st_mtime_sec", "J");260CHECK_NULL_RETURN(attrs_st_mtime_sec, 0);261attrs_st_mtime_nsec = (*env)->GetFieldID(env, clazz, "st_mtime_nsec", "J");262CHECK_NULL_RETURN(attrs_st_mtime_nsec, 0);263attrs_st_ctime_sec = (*env)->GetFieldID(env, clazz, "st_ctime_sec", "J");264CHECK_NULL_RETURN(attrs_st_ctime_sec, 0);265attrs_st_ctime_nsec = (*env)->GetFieldID(env, clazz, "st_ctime_nsec", "J");266CHECK_NULL_RETURN(attrs_st_ctime_nsec, 0);267268#ifdef _DARWIN_FEATURE_64_BIT_INODE269attrs_st_birthtime_sec = (*env)->GetFieldID(env, clazz, "st_birthtime_sec", "J");270CHECK_NULL_RETURN(attrs_st_birthtime_sec, 0);271#endif272273clazz = (*env)->FindClass(env, "sun/nio/fs/UnixFileStoreAttributes");274CHECK_NULL_RETURN(clazz, 0);275attrs_f_frsize = (*env)->GetFieldID(env, clazz, "f_frsize", "J");276CHECK_NULL_RETURN(attrs_f_frsize, 0);277attrs_f_blocks = (*env)->GetFieldID(env, clazz, "f_blocks", "J");278CHECK_NULL_RETURN(attrs_f_blocks, 0);279attrs_f_bfree = (*env)->GetFieldID(env, clazz, "f_bfree", "J");280CHECK_NULL_RETURN(attrs_f_bfree, 0);281attrs_f_bavail = (*env)->GetFieldID(env, clazz, "f_bavail", "J");282CHECK_NULL_RETURN(attrs_f_bavail, 0);283284clazz = (*env)->FindClass(env, "sun/nio/fs/UnixMountEntry");285CHECK_NULL_RETURN(clazz, 0);286entry_name = (*env)->GetFieldID(env, clazz, "name", "[B");287CHECK_NULL_RETURN(entry_name, 0);288entry_dir = (*env)->GetFieldID(env, clazz, "dir", "[B");289CHECK_NULL_RETURN(entry_dir, 0);290entry_fstype = (*env)->GetFieldID(env, clazz, "fstype", "[B");291CHECK_NULL_RETURN(entry_fstype, 0);292entry_options = (*env)->GetFieldID(env, clazz, "opts", "[B");293CHECK_NULL_RETURN(entry_options, 0);294entry_dev = (*env)->GetFieldID(env, clazz, "dev", "J");295CHECK_NULL_RETURN(entry_dev, 0);296297/* system calls that might not be available at run time */298299#if defined(_ALLBSD_SOURCE)300my_openat64_func = (openat64_func*)dlsym(RTLD_DEFAULT, "openat");301my_fstatat64_func = (fstatat64_func*)dlsym(RTLD_DEFAULT, "fstatat");302#else303my_openat64_func = (openat64_func*) dlsym(RTLD_DEFAULT, "openat64");304my_fstatat64_func = (fstatat64_func*) dlsym(RTLD_DEFAULT, "fstatat64");305#endif306my_unlinkat_func = (unlinkat_func*) dlsym(RTLD_DEFAULT, "unlinkat");307my_renameat_func = (renameat_func*) dlsym(RTLD_DEFAULT, "renameat");308#ifndef _ALLBSD_SOURCE309my_futimesat_func = (futimesat_func*) dlsym(RTLD_DEFAULT, "futimesat");310my_lutimes_func = (lutimes_func*) dlsym(RTLD_DEFAULT, "lutimes");311#endif312#ifdef __ANDROID__313my_utimensat_func = (utimensat_func*) dlsym(RTLD_DEFAULT, "utimensat");314#endif315my_futimens_func = (futimens_func*) dlsym(RTLD_DEFAULT, "futimens");316#if defined(_AIX)317my_fdopendir_func = (fdopendir_func*) dlsym(RTLD_DEFAULT, "fdopendir64");318#else319my_fdopendir_func = (fdopendir_func*) dlsym(RTLD_DEFAULT, "fdopendir");320#endif321322#if defined(FSTATAT64_SYSCALL_AVAILABLE)323/* fstatat64 missing from glibc */324if (my_fstatat64_func == NULL)325my_fstatat64_func = (fstatat64_func*)&fstatat64_wrapper;326#endif327328/* supports futimes or futimesat, futimens, and/or lutimes */329330#ifdef _ALLBSD_SOURCE331capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_FUTIMES;332capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_LUTIMES;333#else334if (my_futimesat_func != NULL || my_utimensat_func != NULL)335capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_FUTIMES;336if (my_lutimes_func != NULL)337capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_LUTIMES;338#endif339if (my_futimens_func != NULL)340capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_FUTIMENS;341342/* supports openat, etc. */343344if (my_openat64_func != NULL && my_fstatat64_func != NULL &&345my_unlinkat_func != NULL && my_renameat_func != NULL &&346(my_futimesat_func != NULL || my_utimensat_func != NULL) && my_fdopendir_func != NULL)347{348capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_OPENAT;349}350351/* supports file birthtime */352353#ifdef _DARWIN_FEATURE_64_BIT_INODE354capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_BIRTHTIME;355#endif356357/* supports extended attributes */358359#ifdef _SYS_XATTR_H_360capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_XATTR;361#endif362363return capabilities;364}365366JNIEXPORT jbyteArray JNICALL367Java_sun_nio_fs_UnixNativeDispatcher_getcwd(JNIEnv* env, jclass this) {368jbyteArray result = NULL;369char buf[PATH_MAX+1];370371/* EINTR not listed as a possible error */372char* cwd = getcwd(buf, sizeof(buf));373if (cwd == NULL) {374throwUnixException(env, errno);375} else {376jsize len = (jsize)strlen(buf);377result = (*env)->NewByteArray(env, len);378if (result != NULL) {379(*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)buf);380}381}382return result;383}384385JNIEXPORT jbyteArray386Java_sun_nio_fs_UnixNativeDispatcher_strerror(JNIEnv* env, jclass this, jint error)387{388char tmpbuf[1024];389jsize len;390jbyteArray bytes;391392getErrorString((int)errno, tmpbuf, sizeof(tmpbuf));393len = strlen(tmpbuf);394bytes = (*env)->NewByteArray(env, len);395if (bytes != NULL) {396(*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)tmpbuf);397}398return bytes;399}400401JNIEXPORT jint402Java_sun_nio_fs_UnixNativeDispatcher_dup(JNIEnv* env, jclass this, jint fd) {403404int res = -1;405406RESTARTABLE(dup((int)fd), res);407if (res == -1) {408throwUnixException(env, errno);409}410return (jint)res;411}412413JNIEXPORT void JNICALL414Java_sun_nio_fs_UnixNativeDispatcher_rewind(JNIEnv* env, jclass this, jlong stream)415{416FILE* fp = jlong_to_ptr(stream);417int saved_errno;418419errno = 0;420rewind(fp);421saved_errno = errno;422if (ferror(fp)) {423throwUnixException(env, saved_errno);424}425}426427/**428* This function returns line length without NUL terminator or -1 on EOF.429*/430JNIEXPORT jint JNICALL431Java_sun_nio_fs_UnixNativeDispatcher_getlinelen(JNIEnv* env, jclass this, jlong stream)432{433FILE* fp = jlong_to_ptr(stream);434size_t lineSize = 0;435char * lineBuffer = NULL;436int saved_errno;437438ssize_t res = getline(&lineBuffer, &lineSize, fp);439saved_errno = errno;440441/* Should free lineBuffer no matter result, according to man page */442if (lineBuffer != NULL)443free(lineBuffer);444445if (feof(fp))446return -1;447448/* On successfull return res >= 0, otherwise res is -1 */449if (res == -1)450throwUnixException(env, saved_errno);451452if (res > INT_MAX)453throwUnixException(env, EOVERFLOW);454455return (jint)res;456}457458JNIEXPORT jint JNICALL459Java_sun_nio_fs_UnixNativeDispatcher_open0(JNIEnv* env, jclass this,460jlong pathAddress, jint oflags, jint mode)461{462jint fd;463const char* path = (const char*)jlong_to_ptr(pathAddress);464465RESTARTABLE(open64(path, (int)oflags, (mode_t)mode), fd);466if (fd == -1) {467throwUnixException(env, errno);468}469return fd;470}471472JNIEXPORT jint JNICALL473Java_sun_nio_fs_UnixNativeDispatcher_openat0(JNIEnv* env, jclass this, jint dfd,474jlong pathAddress, jint oflags, jint mode)475{476jint fd;477const char* path = (const char*)jlong_to_ptr(pathAddress);478479if (my_openat64_func == NULL) {480JNU_ThrowInternalError(env, "should not reach here");481return -1;482}483484RESTARTABLE((*my_openat64_func)(dfd, path, (int)oflags, (mode_t)mode), fd);485if (fd == -1) {486throwUnixException(env, errno);487}488return fd;489}490491JNIEXPORT void JNICALL492Java_sun_nio_fs_UnixNativeDispatcher_close0(JNIEnv* env, jclass this, jint fd) {493int res;494495#if defined(_AIX)496/* AIX allows close to be restarted after EINTR */497RESTARTABLE(close((int)fd), res);498#else499res = close((int)fd);500#endif501if (res == -1 && errno != EINTR) {502throwUnixException(env, errno);503}504}505506JNIEXPORT jint JNICALL507Java_sun_nio_fs_UnixNativeDispatcher_read(JNIEnv* env, jclass this, jint fd,508jlong address, jint nbytes)509{510ssize_t n;511void* bufp = jlong_to_ptr(address);512RESTARTABLE(read((int)fd, bufp, (size_t)nbytes), n);513if (n == -1) {514throwUnixException(env, errno);515}516return (jint)n;517}518519JNIEXPORT jint JNICALL520Java_sun_nio_fs_UnixNativeDispatcher_write(JNIEnv* env, jclass this, jint fd,521jlong address, jint nbytes)522{523ssize_t n;524void* bufp = jlong_to_ptr(address);525RESTARTABLE(write((int)fd, bufp, (size_t)nbytes), n);526if (n == -1) {527throwUnixException(env, errno);528}529return (jint)n;530}531532/**533* Copy stat64 members into sun.nio.fs.UnixFileAttributes534*/535static void prepAttributes(JNIEnv* env, struct stat64* buf, jobject attrs) {536(*env)->SetIntField(env, attrs, attrs_st_mode, (jint)buf->st_mode);537(*env)->SetLongField(env, attrs, attrs_st_ino, (jlong)buf->st_ino);538(*env)->SetLongField(env, attrs, attrs_st_dev, (jlong)buf->st_dev);539(*env)->SetLongField(env, attrs, attrs_st_rdev, (jlong)buf->st_rdev);540(*env)->SetIntField(env, attrs, attrs_st_nlink, (jint)buf->st_nlink);541(*env)->SetIntField(env, attrs, attrs_st_uid, (jint)buf->st_uid);542(*env)->SetIntField(env, attrs, attrs_st_gid, (jint)buf->st_gid);543(*env)->SetLongField(env, attrs, attrs_st_size, (jlong)buf->st_size);544(*env)->SetLongField(env, attrs, attrs_st_atime_sec, (jlong)buf->st_atime);545(*env)->SetLongField(env, attrs, attrs_st_mtime_sec, (jlong)buf->st_mtime);546(*env)->SetLongField(env, attrs, attrs_st_ctime_sec, (jlong)buf->st_ctime);547548#ifdef _DARWIN_FEATURE_64_BIT_INODE549(*env)->SetLongField(env, attrs, attrs_st_birthtime_sec, (jlong)buf->st_birthtime);550#endif551552#ifndef MACOSX553(*env)->SetLongField(env, attrs, attrs_st_atime_nsec, (jlong)buf->st_atim.tv_nsec);554(*env)->SetLongField(env, attrs, attrs_st_mtime_nsec, (jlong)buf->st_mtim.tv_nsec);555(*env)->SetLongField(env, attrs, attrs_st_ctime_nsec, (jlong)buf->st_ctim.tv_nsec);556#else557(*env)->SetLongField(env, attrs, attrs_st_atime_nsec, (jlong)buf->st_atimespec.tv_nsec);558(*env)->SetLongField(env, attrs, attrs_st_mtime_nsec, (jlong)buf->st_mtimespec.tv_nsec);559(*env)->SetLongField(env, attrs, attrs_st_ctime_nsec, (jlong)buf->st_ctimespec.tv_nsec);560#endif561}562563JNIEXPORT void JNICALL564Java_sun_nio_fs_UnixNativeDispatcher_stat0(JNIEnv* env, jclass this,565jlong pathAddress, jobject attrs)566{567int err;568struct stat64 buf;569const char* path = (const char*)jlong_to_ptr(pathAddress);570571RESTARTABLE(stat64(path, &buf), err);572if (err == -1) {573throwUnixException(env, errno);574} else {575prepAttributes(env, &buf, attrs);576}577}578579JNIEXPORT jint JNICALL580Java_sun_nio_fs_UnixNativeDispatcher_stat1(JNIEnv* env, jclass this, jlong pathAddress) {581int err;582struct stat64 buf;583const char* path = (const char*)jlong_to_ptr(pathAddress);584585RESTARTABLE(stat64(path, &buf), err);586if (err == -1) {587return 0;588} else {589return (jint)buf.st_mode;590}591}592593JNIEXPORT void JNICALL594Java_sun_nio_fs_UnixNativeDispatcher_lstat0(JNIEnv* env, jclass this,595jlong pathAddress, jobject attrs)596{597int err;598struct stat64 buf;599const char* path = (const char*)jlong_to_ptr(pathAddress);600601RESTARTABLE(lstat64(path, &buf), err);602if (err == -1) {603throwUnixException(env, errno);604} else {605prepAttributes(env, &buf, attrs);606}607}608609JNIEXPORT void JNICALL610Java_sun_nio_fs_UnixNativeDispatcher_fstat(JNIEnv* env, jclass this, jint fd,611jobject attrs)612{613int err;614struct stat64 buf;615616RESTARTABLE(fstat64((int)fd, &buf), err);617if (err == -1) {618throwUnixException(env, errno);619} else {620prepAttributes(env, &buf, attrs);621}622}623624JNIEXPORT void JNICALL625Java_sun_nio_fs_UnixNativeDispatcher_fstatat0(JNIEnv* env, jclass this, jint dfd,626jlong pathAddress, jint flag, jobject attrs)627{628int err;629struct stat64 buf;630const char* path = (const char*)jlong_to_ptr(pathAddress);631632if (my_fstatat64_func == NULL) {633JNU_ThrowInternalError(env, "should not reach here");634return;635}636RESTARTABLE((*my_fstatat64_func)((int)dfd, path, &buf, (int)flag), err);637if (err == -1) {638throwUnixException(env, errno);639} else {640prepAttributes(env, &buf, attrs);641}642}643644JNIEXPORT void JNICALL645Java_sun_nio_fs_UnixNativeDispatcher_chmod0(JNIEnv* env, jclass this,646jlong pathAddress, jint mode)647{648int err;649const char* path = (const char*)jlong_to_ptr(pathAddress);650651RESTARTABLE(chmod(path, (mode_t)mode), err);652if (err == -1) {653throwUnixException(env, errno);654}655}656657JNIEXPORT void JNICALL658Java_sun_nio_fs_UnixNativeDispatcher_fchmod(JNIEnv* env, jclass this, jint filedes,659jint mode)660{661int err;662663RESTARTABLE(fchmod((int)filedes, (mode_t)mode), err);664if (err == -1) {665throwUnixException(env, errno);666}667}668669670JNIEXPORT void JNICALL671Java_sun_nio_fs_UnixNativeDispatcher_chown0(JNIEnv* env, jclass this,672jlong pathAddress, jint uid, jint gid)673{674int err;675const char* path = (const char*)jlong_to_ptr(pathAddress);676677RESTARTABLE(chown(path, (uid_t)uid, (gid_t)gid), err);678if (err == -1) {679throwUnixException(env, errno);680}681}682683JNIEXPORT void JNICALL684Java_sun_nio_fs_UnixNativeDispatcher_lchown0(JNIEnv* env, jclass this, jlong pathAddress, jint uid, jint gid)685{686int err;687const char* path = (const char*)jlong_to_ptr(pathAddress);688689RESTARTABLE(lchown(path, (uid_t)uid, (gid_t)gid), err);690if (err == -1) {691throwUnixException(env, errno);692}693}694695JNIEXPORT void JNICALL696Java_sun_nio_fs_UnixNativeDispatcher_fchown(JNIEnv* env, jclass this, jint filedes, jint uid, jint gid)697{698int err;699700RESTARTABLE(fchown(filedes, (uid_t)uid, (gid_t)gid), err);701if (err == -1) {702throwUnixException(env, errno);703}704}705706JNIEXPORT void JNICALL707Java_sun_nio_fs_UnixNativeDispatcher_utimes0(JNIEnv* env, jclass this,708jlong pathAddress, jlong accessTime, jlong modificationTime)709{710int err;711struct timeval times[2];712const char* path = (const char*)jlong_to_ptr(pathAddress);713714times[0].tv_sec = accessTime / 1000000;715times[0].tv_usec = accessTime % 1000000;716717times[1].tv_sec = modificationTime / 1000000;718times[1].tv_usec = modificationTime % 1000000;719720RESTARTABLE(utimes(path, ×[0]), err);721if (err == -1) {722throwUnixException(env, errno);723}724}725726JNIEXPORT void JNICALL727Java_sun_nio_fs_UnixNativeDispatcher_futimes(JNIEnv* env, jclass this, jint filedes,728jlong accessTime, jlong modificationTime)729{730struct timeval times[2];731struct timespec times2[2];732int err = 0;733734times[0].tv_sec = times2[0].tv_sec = accessTime / 1000000;735times[0].tv_usec = accessTime % 1000000;736737times[1].tv_sec = times2[1].tv_sec = modificationTime / 1000000;738times[1].tv_usec = modificationTime % 1000000;739740times2[0].tv_nsec = times[0].tv_usec * 1000;741times2[1].tv_nsec = times[1].tv_usec * 1000;742743#ifdef _ALLBSD_SOURCE744RESTARTABLE(futimes(filedes, ×[0]), err);745#else746if (my_futimesat_func == NULL && my_utimensat_func == NULL) {747JNU_ThrowInternalError(env, "my_futimesat_func and my_utimensat_func are NULL");748return;749}750if (my_futimesat_func != NULL) {751RESTARTABLE((*my_futimesat_func)(filedes, NULL, ×[0]), err);752} else {753RESTARTABLE((*my_utimensat_func)(filedes, NULL, ×2[0], 0), err);754}755#endif756if (err == -1) {757throwUnixException(env, errno);758}759}760761JNIEXPORT void JNICALL762Java_sun_nio_fs_UnixNativeDispatcher_futimens(JNIEnv* env, jclass this, jint filedes,763jlong accessTime, jlong modificationTime)764{765struct timespec times[2];766int err = 0;767768times[0].tv_sec = accessTime / 1000000000;769times[0].tv_nsec = accessTime % 1000000000;770771times[1].tv_sec = modificationTime / 1000000000;772times[1].tv_nsec = modificationTime % 1000000000;773774if (my_futimens_func == NULL) {775JNU_ThrowInternalError(env, "my_futimens_func is NULL");776return;777}778RESTARTABLE((*my_futimens_func)(filedes, ×[0]), err);779if (err == -1) {780throwUnixException(env, errno);781}782}783784JNIEXPORT void JNICALL785Java_sun_nio_fs_UnixNativeDispatcher_lutimes0(JNIEnv* env, jclass this,786jlong pathAddress, jlong accessTime, jlong modificationTime)787{788int err;789struct timeval times[2];790const char* path = (const char*)jlong_to_ptr(pathAddress);791792times[0].tv_sec = accessTime / 1000000;793times[0].tv_usec = accessTime % 1000000;794795times[1].tv_sec = modificationTime / 1000000;796times[1].tv_usec = modificationTime % 1000000;797798#ifdef _ALLBSD_SOURCE799RESTARTABLE(lutimes(path, ×[0]), err);800#else801if (my_lutimes_func == NULL) {802JNU_ThrowInternalError(env, "my_lutimes_func is NULL");803return;804}805RESTARTABLE((*my_lutimes_func)(path, ×[0]), err);806#endif807if (err == -1) {808throwUnixException(env, errno);809}810}811812JNIEXPORT jlong JNICALL813Java_sun_nio_fs_UnixNativeDispatcher_opendir0(JNIEnv* env, jclass this,814jlong pathAddress)815{816DIR* dir;817const char* path = (const char*)jlong_to_ptr(pathAddress);818819/* EINTR not listed as a possible error */820dir = opendir(path);821if (dir == NULL) {822throwUnixException(env, errno);823}824return ptr_to_jlong(dir);825}826827JNIEXPORT jlong JNICALL828Java_sun_nio_fs_UnixNativeDispatcher_fdopendir(JNIEnv* env, jclass this, int dfd) {829DIR* dir;830831if (my_fdopendir_func == NULL) {832JNU_ThrowInternalError(env, "should not reach here");833return (jlong)-1;834}835836/* EINTR not listed as a possible error */837dir = (*my_fdopendir_func)((int)dfd);838if (dir == NULL) {839throwUnixException(env, errno);840}841return ptr_to_jlong(dir);842}843844JNIEXPORT void JNICALL845Java_sun_nio_fs_UnixNativeDispatcher_closedir(JNIEnv* env, jclass this, jlong dir) {846DIR* dirp = jlong_to_ptr(dir);847848if (closedir(dirp) == -1 && errno != EINTR) {849throwUnixException(env, errno);850}851}852853JNIEXPORT jbyteArray JNICALL854Java_sun_nio_fs_UnixNativeDispatcher_readdir(JNIEnv* env, jclass this, jlong value) {855DIR* dirp = jlong_to_ptr(value);856struct dirent* ptr;857858errno = 0;859ptr = readdir(dirp);860if (ptr == NULL) {861if (errno != 0) {862throwUnixException(env, errno);863}864return NULL;865} else {866jsize len = strlen(ptr->d_name);867jbyteArray bytes = (*env)->NewByteArray(env, len);868if (bytes != NULL) {869(*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)(ptr->d_name));870}871return bytes;872}873}874875JNIEXPORT void JNICALL876Java_sun_nio_fs_UnixNativeDispatcher_mkdir0(JNIEnv* env, jclass this,877jlong pathAddress, jint mode)878{879const char* path = (const char*)jlong_to_ptr(pathAddress);880881/* EINTR not listed as a possible error */882if (mkdir(path, (mode_t)mode) == -1) {883throwUnixException(env, errno);884}885}886887JNIEXPORT void JNICALL888Java_sun_nio_fs_UnixNativeDispatcher_rmdir0(JNIEnv* env, jclass this,889jlong pathAddress)890{891const char* path = (const char*)jlong_to_ptr(pathAddress);892893/* EINTR not listed as a possible error */894if (rmdir(path) == -1) {895throwUnixException(env, errno);896}897}898899JNIEXPORT void JNICALL900Java_sun_nio_fs_UnixNativeDispatcher_link0(JNIEnv* env, jclass this,901jlong existingAddress, jlong newAddress)902{903int err;904const char* existing = (const char*)jlong_to_ptr(existingAddress);905const char* newname = (const char*)jlong_to_ptr(newAddress);906907RESTARTABLE(link(existing, newname), err);908if (err == -1) {909throwUnixException(env, errno);910}911}912913914JNIEXPORT void JNICALL915Java_sun_nio_fs_UnixNativeDispatcher_unlink0(JNIEnv* env, jclass this,916jlong pathAddress)917{918const char* path = (const char*)jlong_to_ptr(pathAddress);919920/* EINTR not listed as a possible error */921if (unlink(path) == -1) {922throwUnixException(env, errno);923}924}925926JNIEXPORT void JNICALL927Java_sun_nio_fs_UnixNativeDispatcher_unlinkat0(JNIEnv* env, jclass this, jint dfd,928jlong pathAddress, jint flags)929{930const char* path = (const char*)jlong_to_ptr(pathAddress);931932if (my_unlinkat_func == NULL) {933JNU_ThrowInternalError(env, "should not reach here");934return;935}936937/* EINTR not listed as a possible error */938if ((*my_unlinkat_func)((int)dfd, path, (int)flags) == -1) {939throwUnixException(env, errno);940}941}942943JNIEXPORT void JNICALL944Java_sun_nio_fs_UnixNativeDispatcher_rename0(JNIEnv* env, jclass this,945jlong fromAddress, jlong toAddress)946{947const char* from = (const char*)jlong_to_ptr(fromAddress);948const char* to = (const char*)jlong_to_ptr(toAddress);949950/* EINTR not listed as a possible error */951if (rename(from, to) == -1) {952throwUnixException(env, errno);953}954}955956JNIEXPORT void JNICALL957Java_sun_nio_fs_UnixNativeDispatcher_renameat0(JNIEnv* env, jclass this,958jint fromfd, jlong fromAddress, jint tofd, jlong toAddress)959{960const char* from = (const char*)jlong_to_ptr(fromAddress);961const char* to = (const char*)jlong_to_ptr(toAddress);962963if (my_renameat_func == NULL) {964JNU_ThrowInternalError(env, "should not reach here");965return;966}967968/* EINTR not listed as a possible error */969if ((*my_renameat_func)((int)fromfd, from, (int)tofd, to) == -1) {970throwUnixException(env, errno);971}972}973974JNIEXPORT void JNICALL975Java_sun_nio_fs_UnixNativeDispatcher_symlink0(JNIEnv* env, jclass this,976jlong targetAddress, jlong linkAddress)977{978const char* target = (const char*)jlong_to_ptr(targetAddress);979const char* link = (const char*)jlong_to_ptr(linkAddress);980981/* EINTR not listed as a possible error */982if (symlink(target, link) == -1) {983throwUnixException(env, errno);984}985}986987JNIEXPORT jbyteArray JNICALL988Java_sun_nio_fs_UnixNativeDispatcher_readlink0(JNIEnv* env, jclass this,989jlong pathAddress)990{991jbyteArray result = NULL;992char target[PATH_MAX+1];993const char* path = (const char*)jlong_to_ptr(pathAddress);994995/* EINTR not listed as a possible error */996int n = readlink(path, target, sizeof(target));997if (n == -1) {998throwUnixException(env, errno);999} else {1000jsize len;1001if (n == sizeof(target)) {1002/* Traditionally readlink(2) should not return more than */1003/* PATH_MAX bytes (no terminating null byte is appended). */1004throwUnixException(env, ENAMETOOLONG);1005return NULL;1006}1007target[n] = '\0';1008len = (jsize)strlen(target);1009result = (*env)->NewByteArray(env, len);1010if (result != NULL) {1011(*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)target);1012}1013}1014return result;1015}10161017JNIEXPORT jbyteArray JNICALL1018Java_sun_nio_fs_UnixNativeDispatcher_realpath0(JNIEnv* env, jclass this,1019jlong pathAddress)1020{1021jbyteArray result = NULL;1022char resolved[PATH_MAX+1];1023const char* path = (const char*)jlong_to_ptr(pathAddress);10241025/* EINTR not listed as a possible error */1026if (realpath(path, resolved) == NULL) {1027throwUnixException(env, errno);1028} else {1029jsize len = (jsize)strlen(resolved);1030result = (*env)->NewByteArray(env, len);1031if (result != NULL) {1032(*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)resolved);1033}1034}1035return result;1036}10371038JNIEXPORT void JNICALL1039Java_sun_nio_fs_UnixNativeDispatcher_access0(JNIEnv* env, jclass this,1040jlong pathAddress, jint amode)1041{1042int err;1043const char* path = (const char*)jlong_to_ptr(pathAddress);10441045RESTARTABLE(access(path, (int)amode), err);1046if (err == -1) {1047throwUnixException(env, errno);1048}1049}10501051JNIEXPORT jboolean JNICALL1052Java_sun_nio_fs_UnixNativeDispatcher_exists0(JNIEnv* env, jclass this, jlong pathAddress) {1053int err;1054const char* path = (const char*)jlong_to_ptr(pathAddress);1055RESTARTABLE(access(path, F_OK), err);1056return (err == 0) ? JNI_TRUE : JNI_FALSE;1057}10581059JNIEXPORT void JNICALL1060Java_sun_nio_fs_UnixNativeDispatcher_statvfs0(JNIEnv* env, jclass this,1061jlong pathAddress, jobject attrs)1062{1063int err;1064#ifdef MACOSX1065struct statfs buf;1066#else1067struct statvfs64 buf;1068#endif1069const char* path = (const char*)jlong_to_ptr(pathAddress);10701071#ifdef MACOSX1072RESTARTABLE(statfs(path, &buf), err);1073#else1074RESTARTABLE(statvfs64(path, &buf), err);1075#endif1076if (err == -1) {1077throwUnixException(env, errno);1078} else {1079#ifdef _AIX1080/* AIX returns ULONG_MAX in buf.f_blocks for the /proc file system. */1081/* This is too big for a Java signed long and fools various tests. */1082if (buf.f_blocks == ULONG_MAX) {1083buf.f_blocks = 0;1084}1085/* The number of free or available blocks can never exceed the total number of blocks */1086if (buf.f_blocks == 0) {1087buf.f_bfree = 0;1088buf.f_bavail = 0;1089}1090#endif1091#ifdef MACOSX1092(*env)->SetLongField(env, attrs, attrs_f_frsize, long_to_jlong(buf.f_bsize));1093#else1094(*env)->SetLongField(env, attrs, attrs_f_frsize, long_to_jlong(buf.f_frsize));1095#endif1096(*env)->SetLongField(env, attrs, attrs_f_blocks, long_to_jlong(buf.f_blocks));1097(*env)->SetLongField(env, attrs, attrs_f_bfree, long_to_jlong(buf.f_bfree));1098(*env)->SetLongField(env, attrs, attrs_f_bavail, long_to_jlong(buf.f_bavail));1099}1100}11011102JNIEXPORT void JNICALL1103Java_sun_nio_fs_UnixNativeDispatcher_mknod0(JNIEnv* env, jclass this,1104jlong pathAddress, jint mode, jlong dev)1105{1106int err;1107const char* path = (const char*)jlong_to_ptr(pathAddress);11081109RESTARTABLE(mknod(path, (mode_t)mode, (dev_t)dev), err);1110if (err == -1) {1111throwUnixException(env, errno);1112}1113}11141115JNIEXPORT jbyteArray JNICALL1116Java_sun_nio_fs_UnixNativeDispatcher_getpwuid(JNIEnv* env, jclass this, jint uid)1117{1118jbyteArray result = NULL;1119int buflen;1120char* pwbuf;11211122/* allocate buffer for password record */1123buflen = (int)sysconf(_SC_GETPW_R_SIZE_MAX);1124if (buflen == -1)1125buflen = ENT_BUF_SIZE;1126pwbuf = (char*)malloc(buflen);1127if (pwbuf == NULL) {1128JNU_ThrowOutOfMemoryError(env, "native heap");1129} else {1130struct passwd pwent;1131struct passwd* p = NULL;1132int res = 0;11331134errno = 0;1135RESTARTABLE(getpwuid_r((uid_t)uid, &pwent, pwbuf, (size_t)buflen, &p), res);11361137if (res != 0 || p == NULL || p->pw_name == NULL || *(p->pw_name) == '\0') {1138/* not found or error */1139if (errno == 0)1140errno = ENOENT;1141throwUnixException(env, errno);1142} else {1143jsize len = strlen(p->pw_name);1144result = (*env)->NewByteArray(env, len);1145if (result != NULL) {1146(*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)(p->pw_name));1147}1148}1149free(pwbuf);1150}11511152return result;1153}115411551156JNIEXPORT jbyteArray JNICALL1157Java_sun_nio_fs_UnixNativeDispatcher_getgrgid(JNIEnv* env, jclass this, jint gid)1158{1159jbyteArray result = NULL;1160int buflen;1161int retry;11621163/* initial size of buffer for group record */1164buflen = (int)sysconf(_SC_GETGR_R_SIZE_MAX);1165if (buflen == -1)1166buflen = ENT_BUF_SIZE;11671168do {1169struct group grent;1170struct group* g = NULL;1171int res = 0;11721173char* grbuf = (char*)malloc(buflen);1174if (grbuf == NULL) {1175JNU_ThrowOutOfMemoryError(env, "native heap");1176return NULL;1177}11781179errno = 0;1180RESTARTABLE(getgrgid_r((gid_t)gid, &grent, grbuf, (size_t)buflen, &g), res);11811182retry = 0;1183if (res != 0 || g == NULL || g->gr_name == NULL || *(g->gr_name) == '\0') {1184/* not found or error */1185if (errno == ERANGE) {1186/* insufficient buffer size so need larger buffer */1187buflen += ENT_BUF_SIZE;1188retry = 1;1189} else {1190if (errno == 0)1191errno = ENOENT;1192throwUnixException(env, errno);1193}1194} else {1195jsize len = strlen(g->gr_name);1196result = (*env)->NewByteArray(env, len);1197if (result != NULL) {1198(*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)(g->gr_name));1199}1200}12011202free(grbuf);12031204} while (retry);12051206return result;1207}12081209JNIEXPORT jint JNICALL1210Java_sun_nio_fs_UnixNativeDispatcher_getpwnam0(JNIEnv* env, jclass this,1211jlong nameAddress)1212{1213jint uid = -1;1214int buflen;1215char* pwbuf;12161217/* allocate buffer for password record */1218buflen = (int)sysconf(_SC_GETPW_R_SIZE_MAX);1219if (buflen == -1)1220buflen = ENT_BUF_SIZE;1221pwbuf = (char*)malloc(buflen);1222if (pwbuf == NULL) {1223JNU_ThrowOutOfMemoryError(env, "native heap");1224} else {1225struct passwd pwent;1226struct passwd* p = NULL;1227int res = 0;1228const char* name = (const char*)jlong_to_ptr(nameAddress);12291230errno = 0;1231RESTARTABLE(getpwnam_r(name, &pwent, pwbuf, (size_t)buflen, &p), res);12321233if (res != 0 || p == NULL || p->pw_name == NULL || *(p->pw_name) == '\0') {1234/* not found or error */1235if (errno != 0 && errno != ENOENT && errno != ESRCH &&1236errno != EBADF && errno != EPERM)1237{1238throwUnixException(env, errno);1239}1240} else {1241uid = p->pw_uid;1242}1243free(pwbuf);1244}12451246return uid;1247}12481249JNIEXPORT jint JNICALL1250Java_sun_nio_fs_UnixNativeDispatcher_getgrnam0(JNIEnv* env, jclass this,1251jlong nameAddress)1252{1253jint gid = -1;1254int buflen, retry;12551256/* initial size of buffer for group record */1257buflen = (int)sysconf(_SC_GETGR_R_SIZE_MAX);1258if (buflen == -1)1259buflen = ENT_BUF_SIZE;12601261do {1262struct group grent;1263struct group* g = NULL;1264int res = 0;1265char *grbuf;1266const char* name = (const char*)jlong_to_ptr(nameAddress);12671268grbuf = (char*)malloc(buflen);1269if (grbuf == NULL) {1270JNU_ThrowOutOfMemoryError(env, "native heap");1271return -1;1272}12731274errno = 0;1275RESTARTABLE(getgrnam_r(name, &grent, grbuf, (size_t)buflen, &g), res);12761277retry = 0;1278if (res != 0 || g == NULL || g->gr_name == NULL || *(g->gr_name) == '\0') {1279/* not found or error */1280if (errno != 0 && errno != ENOENT && errno != ESRCH &&1281errno != EBADF && errno != EPERM)1282{1283if (errno == ERANGE) {1284/* insufficient buffer size so need larger buffer */1285buflen += ENT_BUF_SIZE;1286retry = 1;1287} else {1288throwUnixException(env, errno);1289}1290}1291} else {1292gid = g->gr_gid;1293}12941295free(grbuf);12961297} while (retry);12981299return gid;1300}13011302JNIEXPORT jint JNICALL1303Java_sun_nio_fs_UnixNativeDispatcher_fgetxattr0(JNIEnv* env, jclass clazz,1304jint fd, jlong nameAddress, jlong valueAddress, jint valueLen)1305{1306size_t res = -1;1307const char* name = jlong_to_ptr(nameAddress);1308void* value = jlong_to_ptr(valueAddress);13091310#ifdef __linux__1311res = fgetxattr(fd, name, value, valueLen);1312#elif _ALLBSD_SOURCE1313res = fgetxattr(fd, name, value, valueLen, 0, 0);1314#else1315throwUnixException(env, ENOTSUP);1316#endif13171318if (res == (size_t)-1)1319throwUnixException(env, errno);1320return (jint)res;1321}13221323JNIEXPORT void JNICALL1324Java_sun_nio_fs_UnixNativeDispatcher_fsetxattr0(JNIEnv* env, jclass clazz,1325jint fd, jlong nameAddress, jlong valueAddress, jint valueLen)1326{1327int res = -1;1328const char* name = jlong_to_ptr(nameAddress);1329void* value = jlong_to_ptr(valueAddress);13301331#ifdef __linux__1332res = fsetxattr(fd, name, value, valueLen, 0);1333#elif _ALLBSD_SOURCE1334res = fsetxattr(fd, name, value, valueLen, 0, 0);1335#else1336throwUnixException(env, ENOTSUP);1337#endif13381339if (res == -1)1340throwUnixException(env, errno);1341}13421343JNIEXPORT void JNICALL1344Java_sun_nio_fs_UnixNativeDispatcher_fremovexattr0(JNIEnv* env, jclass clazz,1345jint fd, jlong nameAddress)1346{1347int res = -1;1348const char* name = jlong_to_ptr(nameAddress);13491350#ifdef __linux__1351res = fremovexattr(fd, name);1352#elif _ALLBSD_SOURCE1353res = fremovexattr(fd, name, 0);1354#else1355throwUnixException(env, ENOTSUP);1356#endif13571358if (res == -1)1359throwUnixException(env, errno);1360}13611362JNIEXPORT jint JNICALL1363Java_sun_nio_fs_UnixNativeDispatcher_flistxattr(JNIEnv* env, jclass clazz,1364jint fd, jlong listAddress, jint size)1365{1366size_t res = -1;1367char* list = jlong_to_ptr(listAddress);13681369#ifdef __linux__1370res = flistxattr(fd, list, (size_t)size);1371#elif _ALLBSD_SOURCE1372res = flistxattr(fd, list, (size_t)size, 0);1373#else1374throwUnixException(env, ENOTSUP);1375#endif13761377if (res == (size_t)-1)1378throwUnixException(env, errno);1379return (jint)res;1380}138113821383