Path: blob/master/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c
67760 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 futimens_func(int, const struct timespec *);143typedef int lutimes_func(const char *, const struct timeval *);144typedef DIR* fdopendir_func(int);145146static openat64_func* my_openat64_func = NULL;147static fstatat64_func* my_fstatat64_func = NULL;148static unlinkat_func* my_unlinkat_func = NULL;149static renameat_func* my_renameat_func = NULL;150static futimesat_func* my_futimesat_func = NULL;151static futimens_func* my_futimens_func = NULL;152static lutimes_func* my_lutimes_func = NULL;153static fdopendir_func* my_fdopendir_func = NULL;154155/**156* fstatat missing from glibc on Linux.157*/158#if defined(__linux__) && (defined(__i386) || defined(__arm__))159#define FSTATAT64_SYSCALL_AVAILABLE160static int fstatat64_wrapper(int dfd, const char *path,161struct stat64 *statbuf, int flag)162{163#ifndef __NR_fstatat64164#define __NR_fstatat64 300165#endif166return syscall(__NR_fstatat64, dfd, path, statbuf, flag);167}168#endif169170#if defined(__linux__) && defined(_LP64) && defined(__NR_newfstatat)171#define FSTATAT64_SYSCALL_AVAILABLE172static int fstatat64_wrapper(int dfd, const char *path,173struct stat64 *statbuf, int flag)174{175return syscall(__NR_newfstatat, dfd, path, statbuf, flag);176}177#endif178179/**180* Call this to throw an internal UnixException when a system/library181* call fails182*/183static void throwUnixException(JNIEnv* env, int errnum) {184jobject x = JNU_NewObjectByName(env, "sun/nio/fs/UnixException",185"(I)V", errnum);186if (x != NULL) {187(*env)->Throw(env, x);188}189}190191/**192* Initialization193*/194JNIEXPORT jint JNICALL195Java_sun_nio_fs_UnixNativeDispatcher_init(JNIEnv* env, jclass this)196{197jint capabilities = 0;198jclass clazz;199200clazz = (*env)->FindClass(env, "sun/nio/fs/UnixFileAttributes");201CHECK_NULL_RETURN(clazz, 0);202attrs_st_mode = (*env)->GetFieldID(env, clazz, "st_mode", "I");203CHECK_NULL_RETURN(attrs_st_mode, 0);204attrs_st_ino = (*env)->GetFieldID(env, clazz, "st_ino", "J");205CHECK_NULL_RETURN(attrs_st_ino, 0);206attrs_st_dev = (*env)->GetFieldID(env, clazz, "st_dev", "J");207CHECK_NULL_RETURN(attrs_st_dev, 0);208attrs_st_rdev = (*env)->GetFieldID(env, clazz, "st_rdev", "J");209CHECK_NULL_RETURN(attrs_st_rdev, 0);210attrs_st_nlink = (*env)->GetFieldID(env, clazz, "st_nlink", "I");211CHECK_NULL_RETURN(attrs_st_nlink, 0);212attrs_st_uid = (*env)->GetFieldID(env, clazz, "st_uid", "I");213CHECK_NULL_RETURN(attrs_st_uid, 0);214attrs_st_gid = (*env)->GetFieldID(env, clazz, "st_gid", "I");215CHECK_NULL_RETURN(attrs_st_gid, 0);216attrs_st_size = (*env)->GetFieldID(env, clazz, "st_size", "J");217CHECK_NULL_RETURN(attrs_st_size, 0);218attrs_st_atime_sec = (*env)->GetFieldID(env, clazz, "st_atime_sec", "J");219CHECK_NULL_RETURN(attrs_st_atime_sec, 0);220attrs_st_atime_nsec = (*env)->GetFieldID(env, clazz, "st_atime_nsec", "J");221CHECK_NULL_RETURN(attrs_st_atime_nsec, 0);222attrs_st_mtime_sec = (*env)->GetFieldID(env, clazz, "st_mtime_sec", "J");223CHECK_NULL_RETURN(attrs_st_mtime_sec, 0);224attrs_st_mtime_nsec = (*env)->GetFieldID(env, clazz, "st_mtime_nsec", "J");225CHECK_NULL_RETURN(attrs_st_mtime_nsec, 0);226attrs_st_ctime_sec = (*env)->GetFieldID(env, clazz, "st_ctime_sec", "J");227CHECK_NULL_RETURN(attrs_st_ctime_sec, 0);228attrs_st_ctime_nsec = (*env)->GetFieldID(env, clazz, "st_ctime_nsec", "J");229CHECK_NULL_RETURN(attrs_st_ctime_nsec, 0);230231#ifdef _DARWIN_FEATURE_64_BIT_INODE232attrs_st_birthtime_sec = (*env)->GetFieldID(env, clazz, "st_birthtime_sec", "J");233CHECK_NULL_RETURN(attrs_st_birthtime_sec, 0);234#endif235236clazz = (*env)->FindClass(env, "sun/nio/fs/UnixFileStoreAttributes");237CHECK_NULL_RETURN(clazz, 0);238attrs_f_frsize = (*env)->GetFieldID(env, clazz, "f_frsize", "J");239CHECK_NULL_RETURN(attrs_f_frsize, 0);240attrs_f_blocks = (*env)->GetFieldID(env, clazz, "f_blocks", "J");241CHECK_NULL_RETURN(attrs_f_blocks, 0);242attrs_f_bfree = (*env)->GetFieldID(env, clazz, "f_bfree", "J");243CHECK_NULL_RETURN(attrs_f_bfree, 0);244attrs_f_bavail = (*env)->GetFieldID(env, clazz, "f_bavail", "J");245CHECK_NULL_RETURN(attrs_f_bavail, 0);246247clazz = (*env)->FindClass(env, "sun/nio/fs/UnixMountEntry");248CHECK_NULL_RETURN(clazz, 0);249entry_name = (*env)->GetFieldID(env, clazz, "name", "[B");250CHECK_NULL_RETURN(entry_name, 0);251entry_dir = (*env)->GetFieldID(env, clazz, "dir", "[B");252CHECK_NULL_RETURN(entry_dir, 0);253entry_fstype = (*env)->GetFieldID(env, clazz, "fstype", "[B");254CHECK_NULL_RETURN(entry_fstype, 0);255entry_options = (*env)->GetFieldID(env, clazz, "opts", "[B");256CHECK_NULL_RETURN(entry_options, 0);257entry_dev = (*env)->GetFieldID(env, clazz, "dev", "J");258CHECK_NULL_RETURN(entry_dev, 0);259260/* system calls that might not be available at run time */261262#if defined(_ALLBSD_SOURCE)263my_openat64_func = (openat64_func*)dlsym(RTLD_DEFAULT, "openat");264my_fstatat64_func = (fstatat64_func*)dlsym(RTLD_DEFAULT, "fstatat");265#else266my_openat64_func = (openat64_func*) dlsym(RTLD_DEFAULT, "openat64");267my_fstatat64_func = (fstatat64_func*) dlsym(RTLD_DEFAULT, "fstatat64");268#endif269my_unlinkat_func = (unlinkat_func*) dlsym(RTLD_DEFAULT, "unlinkat");270my_renameat_func = (renameat_func*) dlsym(RTLD_DEFAULT, "renameat");271#ifndef _ALLBSD_SOURCE272my_futimesat_func = (futimesat_func*) dlsym(RTLD_DEFAULT, "futimesat");273my_lutimes_func = (lutimes_func*) dlsym(RTLD_DEFAULT, "lutimes");274#endif275my_futimens_func = (futimens_func*) dlsym(RTLD_DEFAULT, "futimens");276#if defined(_AIX)277my_fdopendir_func = (fdopendir_func*) dlsym(RTLD_DEFAULT, "fdopendir64");278#else279my_fdopendir_func = (fdopendir_func*) dlsym(RTLD_DEFAULT, "fdopendir");280#endif281282#if defined(FSTATAT64_SYSCALL_AVAILABLE)283/* fstatat64 missing from glibc */284if (my_fstatat64_func == NULL)285my_fstatat64_func = (fstatat64_func*)&fstatat64_wrapper;286#endif287288/* supports futimes or futimesat, futimens, and/or lutimes */289290#ifdef _ALLBSD_SOURCE291capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_FUTIMES;292capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_LUTIMES;293#else294if (my_futimesat_func != NULL)295capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_FUTIMES;296if (my_lutimes_func != NULL)297capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_LUTIMES;298#endif299if (my_futimens_func != NULL)300capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_FUTIMENS;301302/* supports openat, etc. */303304if (my_openat64_func != NULL && my_fstatat64_func != NULL &&305my_unlinkat_func != NULL && my_renameat_func != NULL &&306my_futimesat_func != NULL && my_fdopendir_func != NULL)307{308capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_OPENAT;309}310311/* supports file birthtime */312313#ifdef _DARWIN_FEATURE_64_BIT_INODE314capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_BIRTHTIME;315#endif316317/* supports extended attributes */318319#if defined(_SYS_XATTR_H) || defined(_SYS_XATTR_H_)320capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_XATTR;321#endif322323return capabilities;324}325326JNIEXPORT jbyteArray JNICALL327Java_sun_nio_fs_UnixNativeDispatcher_getcwd(JNIEnv* env, jclass this) {328jbyteArray result = NULL;329char buf[PATH_MAX+1];330331/* EINTR not listed as a possible error */332char* cwd = getcwd(buf, sizeof(buf));333if (cwd == NULL) {334throwUnixException(env, errno);335} else {336jsize len = (jsize)strlen(buf);337result = (*env)->NewByteArray(env, len);338if (result != NULL) {339(*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)buf);340}341}342return result;343}344345JNIEXPORT jbyteArray346Java_sun_nio_fs_UnixNativeDispatcher_strerror(JNIEnv* env, jclass this, jint error)347{348char tmpbuf[1024];349jsize len;350jbyteArray bytes;351352getErrorString((int)errno, tmpbuf, sizeof(tmpbuf));353len = strlen(tmpbuf);354bytes = (*env)->NewByteArray(env, len);355if (bytes != NULL) {356(*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)tmpbuf);357}358return bytes;359}360361JNIEXPORT jint362Java_sun_nio_fs_UnixNativeDispatcher_dup(JNIEnv* env, jclass this, jint fd) {363364int res = -1;365366RESTARTABLE(dup((int)fd), res);367if (res == -1) {368throwUnixException(env, errno);369}370return (jint)res;371}372373JNIEXPORT void JNICALL374Java_sun_nio_fs_UnixNativeDispatcher_rewind(JNIEnv* env, jclass this, jlong stream)375{376FILE* fp = jlong_to_ptr(stream);377int saved_errno;378379errno = 0;380rewind(fp);381saved_errno = errno;382if (ferror(fp)) {383throwUnixException(env, saved_errno);384}385}386387/**388* This function returns line length without NUL terminator or -1 on EOF.389*/390JNIEXPORT jint JNICALL391Java_sun_nio_fs_UnixNativeDispatcher_getlinelen(JNIEnv* env, jclass this, jlong stream)392{393FILE* fp = jlong_to_ptr(stream);394size_t lineSize = 0;395char * lineBuffer = NULL;396int saved_errno;397398ssize_t res = getline(&lineBuffer, &lineSize, fp);399saved_errno = errno;400401/* Should free lineBuffer no matter result, according to man page */402if (lineBuffer != NULL)403free(lineBuffer);404405if (feof(fp))406return -1;407408/* On successfull return res >= 0, otherwise res is -1 */409if (res == -1)410throwUnixException(env, saved_errno);411412if (res > INT_MAX)413throwUnixException(env, EOVERFLOW);414415return (jint)res;416}417418JNIEXPORT jint JNICALL419Java_sun_nio_fs_UnixNativeDispatcher_open0(JNIEnv* env, jclass this,420jlong pathAddress, jint oflags, jint mode)421{422jint fd;423const char* path = (const char*)jlong_to_ptr(pathAddress);424425RESTARTABLE(open64(path, (int)oflags, (mode_t)mode), fd);426if (fd == -1) {427throwUnixException(env, errno);428}429return fd;430}431432JNIEXPORT jint JNICALL433Java_sun_nio_fs_UnixNativeDispatcher_openat0(JNIEnv* env, jclass this, jint dfd,434jlong pathAddress, jint oflags, jint mode)435{436jint fd;437const char* path = (const char*)jlong_to_ptr(pathAddress);438439if (my_openat64_func == NULL) {440JNU_ThrowInternalError(env, "should not reach here");441return -1;442}443444RESTARTABLE((*my_openat64_func)(dfd, path, (int)oflags, (mode_t)mode), fd);445if (fd == -1) {446throwUnixException(env, errno);447}448return fd;449}450451JNIEXPORT void JNICALL452Java_sun_nio_fs_UnixNativeDispatcher_close0(JNIEnv* env, jclass this, jint fd) {453int res;454455#if defined(_AIX)456/* AIX allows close to be restarted after EINTR */457RESTARTABLE(close((int)fd), res);458#else459res = close((int)fd);460#endif461if (res == -1 && errno != EINTR) {462throwUnixException(env, errno);463}464}465466JNIEXPORT jint JNICALL467Java_sun_nio_fs_UnixNativeDispatcher_read(JNIEnv* env, jclass this, jint fd,468jlong address, jint nbytes)469{470ssize_t n;471void* bufp = jlong_to_ptr(address);472RESTARTABLE(read((int)fd, bufp, (size_t)nbytes), n);473if (n == -1) {474throwUnixException(env, errno);475}476return (jint)n;477}478479JNIEXPORT jint JNICALL480Java_sun_nio_fs_UnixNativeDispatcher_write(JNIEnv* env, jclass this, jint fd,481jlong address, jint nbytes)482{483ssize_t n;484void* bufp = jlong_to_ptr(address);485RESTARTABLE(write((int)fd, bufp, (size_t)nbytes), n);486if (n == -1) {487throwUnixException(env, errno);488}489return (jint)n;490}491492/**493* Copy stat64 members into sun.nio.fs.UnixFileAttributes494*/495static void prepAttributes(JNIEnv* env, struct stat64* buf, jobject attrs) {496(*env)->SetIntField(env, attrs, attrs_st_mode, (jint)buf->st_mode);497(*env)->SetLongField(env, attrs, attrs_st_ino, (jlong)buf->st_ino);498(*env)->SetLongField(env, attrs, attrs_st_dev, (jlong)buf->st_dev);499(*env)->SetLongField(env, attrs, attrs_st_rdev, (jlong)buf->st_rdev);500(*env)->SetIntField(env, attrs, attrs_st_nlink, (jint)buf->st_nlink);501(*env)->SetIntField(env, attrs, attrs_st_uid, (jint)buf->st_uid);502(*env)->SetIntField(env, attrs, attrs_st_gid, (jint)buf->st_gid);503(*env)->SetLongField(env, attrs, attrs_st_size, (jlong)buf->st_size);504(*env)->SetLongField(env, attrs, attrs_st_atime_sec, (jlong)buf->st_atime);505(*env)->SetLongField(env, attrs, attrs_st_mtime_sec, (jlong)buf->st_mtime);506(*env)->SetLongField(env, attrs, attrs_st_ctime_sec, (jlong)buf->st_ctime);507508#ifdef _DARWIN_FEATURE_64_BIT_INODE509(*env)->SetLongField(env, attrs, attrs_st_birthtime_sec, (jlong)buf->st_birthtime);510#endif511512#ifndef MACOSX513(*env)->SetLongField(env, attrs, attrs_st_atime_nsec, (jlong)buf->st_atim.tv_nsec);514(*env)->SetLongField(env, attrs, attrs_st_mtime_nsec, (jlong)buf->st_mtim.tv_nsec);515(*env)->SetLongField(env, attrs, attrs_st_ctime_nsec, (jlong)buf->st_ctim.tv_nsec);516#else517(*env)->SetLongField(env, attrs, attrs_st_atime_nsec, (jlong)buf->st_atimespec.tv_nsec);518(*env)->SetLongField(env, attrs, attrs_st_mtime_nsec, (jlong)buf->st_mtimespec.tv_nsec);519(*env)->SetLongField(env, attrs, attrs_st_ctime_nsec, (jlong)buf->st_ctimespec.tv_nsec);520#endif521}522523JNIEXPORT void JNICALL524Java_sun_nio_fs_UnixNativeDispatcher_stat0(JNIEnv* env, jclass this,525jlong pathAddress, jobject attrs)526{527int err;528struct stat64 buf;529const char* path = (const char*)jlong_to_ptr(pathAddress);530531RESTARTABLE(stat64(path, &buf), err);532if (err == -1) {533throwUnixException(env, errno);534} else {535prepAttributes(env, &buf, attrs);536}537}538539JNIEXPORT jint JNICALL540Java_sun_nio_fs_UnixNativeDispatcher_stat1(JNIEnv* env, jclass this, jlong pathAddress) {541int err;542struct stat64 buf;543const char* path = (const char*)jlong_to_ptr(pathAddress);544545RESTARTABLE(stat64(path, &buf), err);546if (err == -1) {547return 0;548} else {549return (jint)buf.st_mode;550}551}552553JNIEXPORT void JNICALL554Java_sun_nio_fs_UnixNativeDispatcher_lstat0(JNIEnv* env, jclass this,555jlong pathAddress, jobject attrs)556{557int err;558struct stat64 buf;559const char* path = (const char*)jlong_to_ptr(pathAddress);560561RESTARTABLE(lstat64(path, &buf), err);562if (err == -1) {563throwUnixException(env, errno);564} else {565prepAttributes(env, &buf, attrs);566}567}568569JNIEXPORT void JNICALL570Java_sun_nio_fs_UnixNativeDispatcher_fstat(JNIEnv* env, jclass this, jint fd,571jobject attrs)572{573int err;574struct stat64 buf;575576RESTARTABLE(fstat64((int)fd, &buf), err);577if (err == -1) {578throwUnixException(env, errno);579} else {580prepAttributes(env, &buf, attrs);581}582}583584JNIEXPORT void JNICALL585Java_sun_nio_fs_UnixNativeDispatcher_fstatat0(JNIEnv* env, jclass this, jint dfd,586jlong pathAddress, jint flag, jobject attrs)587{588int err;589struct stat64 buf;590const char* path = (const char*)jlong_to_ptr(pathAddress);591592if (my_fstatat64_func == NULL) {593JNU_ThrowInternalError(env, "should not reach here");594return;595}596RESTARTABLE((*my_fstatat64_func)((int)dfd, path, &buf, (int)flag), err);597if (err == -1) {598throwUnixException(env, errno);599} else {600prepAttributes(env, &buf, attrs);601}602}603604JNIEXPORT void JNICALL605Java_sun_nio_fs_UnixNativeDispatcher_chmod0(JNIEnv* env, jclass this,606jlong pathAddress, jint mode)607{608int err;609const char* path = (const char*)jlong_to_ptr(pathAddress);610611RESTARTABLE(chmod(path, (mode_t)mode), err);612if (err == -1) {613throwUnixException(env, errno);614}615}616617JNIEXPORT void JNICALL618Java_sun_nio_fs_UnixNativeDispatcher_fchmod(JNIEnv* env, jclass this, jint filedes,619jint mode)620{621int err;622623RESTARTABLE(fchmod((int)filedes, (mode_t)mode), err);624if (err == -1) {625throwUnixException(env, errno);626}627}628629630JNIEXPORT void JNICALL631Java_sun_nio_fs_UnixNativeDispatcher_chown0(JNIEnv* env, jclass this,632jlong pathAddress, jint uid, jint gid)633{634int err;635const char* path = (const char*)jlong_to_ptr(pathAddress);636637RESTARTABLE(chown(path, (uid_t)uid, (gid_t)gid), err);638if (err == -1) {639throwUnixException(env, errno);640}641}642643JNIEXPORT void JNICALL644Java_sun_nio_fs_UnixNativeDispatcher_lchown0(JNIEnv* env, jclass this, jlong pathAddress, jint uid, jint gid)645{646int err;647const char* path = (const char*)jlong_to_ptr(pathAddress);648649RESTARTABLE(lchown(path, (uid_t)uid, (gid_t)gid), err);650if (err == -1) {651throwUnixException(env, errno);652}653}654655JNIEXPORT void JNICALL656Java_sun_nio_fs_UnixNativeDispatcher_fchown(JNIEnv* env, jclass this, jint filedes, jint uid, jint gid)657{658int err;659660RESTARTABLE(fchown(filedes, (uid_t)uid, (gid_t)gid), err);661if (err == -1) {662throwUnixException(env, errno);663}664}665666JNIEXPORT void JNICALL667Java_sun_nio_fs_UnixNativeDispatcher_utimes0(JNIEnv* env, jclass this,668jlong pathAddress, jlong accessTime, jlong modificationTime)669{670int err;671struct timeval times[2];672const char* path = (const char*)jlong_to_ptr(pathAddress);673674times[0].tv_sec = accessTime / 1000000;675times[0].tv_usec = accessTime % 1000000;676677times[1].tv_sec = modificationTime / 1000000;678times[1].tv_usec = modificationTime % 1000000;679680RESTARTABLE(utimes(path, ×[0]), err);681if (err == -1) {682throwUnixException(env, errno);683}684}685686JNIEXPORT void JNICALL687Java_sun_nio_fs_UnixNativeDispatcher_futimes(JNIEnv* env, jclass this, jint filedes,688jlong accessTime, jlong modificationTime)689{690struct timeval times[2];691int err = 0;692693times[0].tv_sec = accessTime / 1000000;694times[0].tv_usec = accessTime % 1000000;695696times[1].tv_sec = modificationTime / 1000000;697times[1].tv_usec = modificationTime % 1000000;698699#ifdef _ALLBSD_SOURCE700RESTARTABLE(futimes(filedes, ×[0]), err);701#else702if (my_futimesat_func == NULL) {703JNU_ThrowInternalError(env, "my_futimesat_func is NULL");704return;705}706RESTARTABLE((*my_futimesat_func)(filedes, NULL, ×[0]), err);707#endif708if (err == -1) {709throwUnixException(env, errno);710}711}712713JNIEXPORT void JNICALL714Java_sun_nio_fs_UnixNativeDispatcher_futimens(JNIEnv* env, jclass this, jint filedes,715jlong accessTime, jlong modificationTime)716{717struct timespec times[2];718int err = 0;719720times[0].tv_sec = accessTime / 1000000000;721times[0].tv_nsec = accessTime % 1000000000;722723times[1].tv_sec = modificationTime / 1000000000;724times[1].tv_nsec = modificationTime % 1000000000;725726if (my_futimens_func == NULL) {727JNU_ThrowInternalError(env, "my_futimens_func is NULL");728return;729}730RESTARTABLE((*my_futimens_func)(filedes, ×[0]), err);731if (err == -1) {732throwUnixException(env, errno);733}734}735736JNIEXPORT void JNICALL737Java_sun_nio_fs_UnixNativeDispatcher_lutimes0(JNIEnv* env, jclass this,738jlong pathAddress, jlong accessTime, jlong modificationTime)739{740int err;741struct timeval times[2];742const char* path = (const char*)jlong_to_ptr(pathAddress);743744times[0].tv_sec = accessTime / 1000000;745times[0].tv_usec = accessTime % 1000000;746747times[1].tv_sec = modificationTime / 1000000;748times[1].tv_usec = modificationTime % 1000000;749750#ifdef _ALLBSD_SOURCE751RESTARTABLE(lutimes(path, ×[0]), err);752#else753if (my_lutimes_func == NULL) {754JNU_ThrowInternalError(env, "my_lutimes_func is NULL");755return;756}757RESTARTABLE((*my_lutimes_func)(path, ×[0]), err);758#endif759if (err == -1) {760throwUnixException(env, errno);761}762}763764JNIEXPORT jlong JNICALL765Java_sun_nio_fs_UnixNativeDispatcher_opendir0(JNIEnv* env, jclass this,766jlong pathAddress)767{768DIR* dir;769const char* path = (const char*)jlong_to_ptr(pathAddress);770771/* EINTR not listed as a possible error */772dir = opendir(path);773if (dir == NULL) {774throwUnixException(env, errno);775}776return ptr_to_jlong(dir);777}778779JNIEXPORT jlong JNICALL780Java_sun_nio_fs_UnixNativeDispatcher_fdopendir(JNIEnv* env, jclass this, int dfd) {781DIR* dir;782783if (my_fdopendir_func == NULL) {784JNU_ThrowInternalError(env, "should not reach here");785return (jlong)-1;786}787788/* EINTR not listed as a possible error */789dir = (*my_fdopendir_func)((int)dfd);790if (dir == NULL) {791throwUnixException(env, errno);792}793return ptr_to_jlong(dir);794}795796JNIEXPORT void JNICALL797Java_sun_nio_fs_UnixNativeDispatcher_closedir(JNIEnv* env, jclass this, jlong dir) {798DIR* dirp = jlong_to_ptr(dir);799800if (closedir(dirp) == -1 && errno != EINTR) {801throwUnixException(env, errno);802}803}804805JNIEXPORT jbyteArray JNICALL806Java_sun_nio_fs_UnixNativeDispatcher_readdir(JNIEnv* env, jclass this, jlong value) {807DIR* dirp = jlong_to_ptr(value);808struct dirent* ptr;809810errno = 0;811ptr = readdir(dirp);812if (ptr == NULL) {813if (errno != 0) {814throwUnixException(env, errno);815}816return NULL;817} else {818jsize len = strlen(ptr->d_name);819jbyteArray bytes = (*env)->NewByteArray(env, len);820if (bytes != NULL) {821(*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)(ptr->d_name));822}823return bytes;824}825}826827JNIEXPORT void JNICALL828Java_sun_nio_fs_UnixNativeDispatcher_mkdir0(JNIEnv* env, jclass this,829jlong pathAddress, jint mode)830{831const char* path = (const char*)jlong_to_ptr(pathAddress);832833/* EINTR not listed as a possible error */834if (mkdir(path, (mode_t)mode) == -1) {835throwUnixException(env, errno);836}837}838839JNIEXPORT void JNICALL840Java_sun_nio_fs_UnixNativeDispatcher_rmdir0(JNIEnv* env, jclass this,841jlong pathAddress)842{843const char* path = (const char*)jlong_to_ptr(pathAddress);844845/* EINTR not listed as a possible error */846if (rmdir(path) == -1) {847throwUnixException(env, errno);848}849}850851JNIEXPORT void JNICALL852Java_sun_nio_fs_UnixNativeDispatcher_link0(JNIEnv* env, jclass this,853jlong existingAddress, jlong newAddress)854{855int err;856const char* existing = (const char*)jlong_to_ptr(existingAddress);857const char* newname = (const char*)jlong_to_ptr(newAddress);858859RESTARTABLE(link(existing, newname), err);860if (err == -1) {861throwUnixException(env, errno);862}863}864865866JNIEXPORT void JNICALL867Java_sun_nio_fs_UnixNativeDispatcher_unlink0(JNIEnv* env, jclass this,868jlong pathAddress)869{870const char* path = (const char*)jlong_to_ptr(pathAddress);871872/* EINTR not listed as a possible error */873if (unlink(path) == -1) {874throwUnixException(env, errno);875}876}877878JNIEXPORT void JNICALL879Java_sun_nio_fs_UnixNativeDispatcher_unlinkat0(JNIEnv* env, jclass this, jint dfd,880jlong pathAddress, jint flags)881{882const char* path = (const char*)jlong_to_ptr(pathAddress);883884if (my_unlinkat_func == NULL) {885JNU_ThrowInternalError(env, "should not reach here");886return;887}888889/* EINTR not listed as a possible error */890if ((*my_unlinkat_func)((int)dfd, path, (int)flags) == -1) {891throwUnixException(env, errno);892}893}894895JNIEXPORT void JNICALL896Java_sun_nio_fs_UnixNativeDispatcher_rename0(JNIEnv* env, jclass this,897jlong fromAddress, jlong toAddress)898{899const char* from = (const char*)jlong_to_ptr(fromAddress);900const char* to = (const char*)jlong_to_ptr(toAddress);901902/* EINTR not listed as a possible error */903if (rename(from, to) == -1) {904throwUnixException(env, errno);905}906}907908JNIEXPORT void JNICALL909Java_sun_nio_fs_UnixNativeDispatcher_renameat0(JNIEnv* env, jclass this,910jint fromfd, jlong fromAddress, jint tofd, jlong toAddress)911{912const char* from = (const char*)jlong_to_ptr(fromAddress);913const char* to = (const char*)jlong_to_ptr(toAddress);914915if (my_renameat_func == NULL) {916JNU_ThrowInternalError(env, "should not reach here");917return;918}919920/* EINTR not listed as a possible error */921if ((*my_renameat_func)((int)fromfd, from, (int)tofd, to) == -1) {922throwUnixException(env, errno);923}924}925926JNIEXPORT void JNICALL927Java_sun_nio_fs_UnixNativeDispatcher_symlink0(JNIEnv* env, jclass this,928jlong targetAddress, jlong linkAddress)929{930const char* target = (const char*)jlong_to_ptr(targetAddress);931const char* link = (const char*)jlong_to_ptr(linkAddress);932933/* EINTR not listed as a possible error */934if (symlink(target, link) == -1) {935throwUnixException(env, errno);936}937}938939JNIEXPORT jbyteArray JNICALL940Java_sun_nio_fs_UnixNativeDispatcher_readlink0(JNIEnv* env, jclass this,941jlong pathAddress)942{943jbyteArray result = NULL;944char target[PATH_MAX+1];945const char* path = (const char*)jlong_to_ptr(pathAddress);946947/* EINTR not listed as a possible error */948int n = readlink(path, target, sizeof(target));949if (n == -1) {950throwUnixException(env, errno);951} else {952jsize len;953if (n == sizeof(target)) {954/* Traditionally readlink(2) should not return more than */955/* PATH_MAX bytes (no terminating null byte is appended). */956throwUnixException(env, ENAMETOOLONG);957return NULL;958}959target[n] = '\0';960len = (jsize)strlen(target);961result = (*env)->NewByteArray(env, len);962if (result != NULL) {963(*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)target);964}965}966return result;967}968969JNIEXPORT jbyteArray JNICALL970Java_sun_nio_fs_UnixNativeDispatcher_realpath0(JNIEnv* env, jclass this,971jlong pathAddress)972{973jbyteArray result = NULL;974char resolved[PATH_MAX+1];975const char* path = (const char*)jlong_to_ptr(pathAddress);976977/* EINTR not listed as a possible error */978if (realpath(path, resolved) == NULL) {979throwUnixException(env, errno);980} else {981jsize len = (jsize)strlen(resolved);982result = (*env)->NewByteArray(env, len);983if (result != NULL) {984(*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)resolved);985}986}987return result;988}989990JNIEXPORT void JNICALL991Java_sun_nio_fs_UnixNativeDispatcher_access0(JNIEnv* env, jclass this,992jlong pathAddress, jint amode)993{994int err;995const char* path = (const char*)jlong_to_ptr(pathAddress);996997RESTARTABLE(access(path, (int)amode), err);998if (err == -1) {999throwUnixException(env, errno);1000}1001}10021003JNIEXPORT jboolean JNICALL1004Java_sun_nio_fs_UnixNativeDispatcher_exists0(JNIEnv* env, jclass this, jlong pathAddress) {1005int err;1006const char* path = (const char*)jlong_to_ptr(pathAddress);1007RESTARTABLE(access(path, F_OK), err);1008return (err == 0) ? JNI_TRUE : JNI_FALSE;1009}10101011JNIEXPORT void JNICALL1012Java_sun_nio_fs_UnixNativeDispatcher_statvfs0(JNIEnv* env, jclass this,1013jlong pathAddress, jobject attrs)1014{1015int err;1016#ifdef MACOSX1017struct statfs buf;1018#else1019struct statvfs64 buf;1020#endif1021const char* path = (const char*)jlong_to_ptr(pathAddress);10221023#ifdef MACOSX1024RESTARTABLE(statfs(path, &buf), err);1025#else1026RESTARTABLE(statvfs64(path, &buf), err);1027#endif1028if (err == -1) {1029throwUnixException(env, errno);1030} else {1031#ifdef _AIX1032/* AIX returns ULONG_MAX in buf.f_blocks for the /proc file system. */1033/* This is too big for a Java signed long and fools various tests. */1034if (buf.f_blocks == ULONG_MAX) {1035buf.f_blocks = 0;1036}1037/* The number of free or available blocks can never exceed the total number of blocks */1038if (buf.f_blocks == 0) {1039buf.f_bfree = 0;1040buf.f_bavail = 0;1041}1042#endif1043#ifdef MACOSX1044(*env)->SetLongField(env, attrs, attrs_f_frsize, long_to_jlong(buf.f_bsize));1045#else1046(*env)->SetLongField(env, attrs, attrs_f_frsize, long_to_jlong(buf.f_frsize));1047#endif1048(*env)->SetLongField(env, attrs, attrs_f_blocks, long_to_jlong(buf.f_blocks));1049(*env)->SetLongField(env, attrs, attrs_f_bfree, long_to_jlong(buf.f_bfree));1050(*env)->SetLongField(env, attrs, attrs_f_bavail, long_to_jlong(buf.f_bavail));1051}1052}10531054JNIEXPORT void JNICALL1055Java_sun_nio_fs_UnixNativeDispatcher_mknod0(JNIEnv* env, jclass this,1056jlong pathAddress, jint mode, jlong dev)1057{1058int err;1059const char* path = (const char*)jlong_to_ptr(pathAddress);10601061RESTARTABLE(mknod(path, (mode_t)mode, (dev_t)dev), err);1062if (err == -1) {1063throwUnixException(env, errno);1064}1065}10661067JNIEXPORT jbyteArray JNICALL1068Java_sun_nio_fs_UnixNativeDispatcher_getpwuid(JNIEnv* env, jclass this, jint uid)1069{1070jbyteArray result = NULL;1071int buflen;1072char* pwbuf;10731074/* allocate buffer for password record */1075buflen = (int)sysconf(_SC_GETPW_R_SIZE_MAX);1076if (buflen == -1)1077buflen = ENT_BUF_SIZE;1078pwbuf = (char*)malloc(buflen);1079if (pwbuf == NULL) {1080JNU_ThrowOutOfMemoryError(env, "native heap");1081} else {1082struct passwd pwent;1083struct passwd* p = NULL;1084int res = 0;10851086errno = 0;1087RESTARTABLE(getpwuid_r((uid_t)uid, &pwent, pwbuf, (size_t)buflen, &p), res);10881089if (res != 0 || p == NULL || p->pw_name == NULL || *(p->pw_name) == '\0') {1090/* not found or error */1091if (errno == 0)1092errno = ENOENT;1093throwUnixException(env, errno);1094} else {1095jsize len = strlen(p->pw_name);1096result = (*env)->NewByteArray(env, len);1097if (result != NULL) {1098(*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)(p->pw_name));1099}1100}1101free(pwbuf);1102}11031104return result;1105}110611071108JNIEXPORT jbyteArray JNICALL1109Java_sun_nio_fs_UnixNativeDispatcher_getgrgid(JNIEnv* env, jclass this, jint gid)1110{1111jbyteArray result = NULL;1112int buflen;1113int retry;11141115/* initial size of buffer for group record */1116buflen = (int)sysconf(_SC_GETGR_R_SIZE_MAX);1117if (buflen == -1)1118buflen = ENT_BUF_SIZE;11191120do {1121struct group grent;1122struct group* g = NULL;1123int res = 0;11241125char* grbuf = (char*)malloc(buflen);1126if (grbuf == NULL) {1127JNU_ThrowOutOfMemoryError(env, "native heap");1128return NULL;1129}11301131errno = 0;1132RESTARTABLE(getgrgid_r((gid_t)gid, &grent, grbuf, (size_t)buflen, &g), res);11331134retry = 0;1135if (res != 0 || g == NULL || g->gr_name == NULL || *(g->gr_name) == '\0') {1136/* not found or error */1137if (errno == ERANGE) {1138/* insufficient buffer size so need larger buffer */1139buflen += ENT_BUF_SIZE;1140retry = 1;1141} else {1142if (errno == 0)1143errno = ENOENT;1144throwUnixException(env, errno);1145}1146} else {1147jsize len = strlen(g->gr_name);1148result = (*env)->NewByteArray(env, len);1149if (result != NULL) {1150(*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)(g->gr_name));1151}1152}11531154free(grbuf);11551156} while (retry);11571158return result;1159}11601161JNIEXPORT jint JNICALL1162Java_sun_nio_fs_UnixNativeDispatcher_getpwnam0(JNIEnv* env, jclass this,1163jlong nameAddress)1164{1165jint uid = -1;1166int buflen;1167char* pwbuf;11681169/* allocate buffer for password record */1170buflen = (int)sysconf(_SC_GETPW_R_SIZE_MAX);1171if (buflen == -1)1172buflen = ENT_BUF_SIZE;1173pwbuf = (char*)malloc(buflen);1174if (pwbuf == NULL) {1175JNU_ThrowOutOfMemoryError(env, "native heap");1176} else {1177struct passwd pwent;1178struct passwd* p = NULL;1179int res = 0;1180const char* name = (const char*)jlong_to_ptr(nameAddress);11811182errno = 0;1183RESTARTABLE(getpwnam_r(name, &pwent, pwbuf, (size_t)buflen, &p), res);11841185if (res != 0 || p == NULL || p->pw_name == NULL || *(p->pw_name) == '\0') {1186/* not found or error */1187if (errno != 0 && errno != ENOENT && errno != ESRCH &&1188errno != EBADF && errno != EPERM)1189{1190throwUnixException(env, errno);1191}1192} else {1193uid = p->pw_uid;1194}1195free(pwbuf);1196}11971198return uid;1199}12001201JNIEXPORT jint JNICALL1202Java_sun_nio_fs_UnixNativeDispatcher_getgrnam0(JNIEnv* env, jclass this,1203jlong nameAddress)1204{1205jint gid = -1;1206int buflen, retry;12071208/* initial size of buffer for group record */1209buflen = (int)sysconf(_SC_GETGR_R_SIZE_MAX);1210if (buflen == -1)1211buflen = ENT_BUF_SIZE;12121213do {1214struct group grent;1215struct group* g = NULL;1216int res = 0;1217char *grbuf;1218const char* name = (const char*)jlong_to_ptr(nameAddress);12191220grbuf = (char*)malloc(buflen);1221if (grbuf == NULL) {1222JNU_ThrowOutOfMemoryError(env, "native heap");1223return -1;1224}12251226errno = 0;1227RESTARTABLE(getgrnam_r(name, &grent, grbuf, (size_t)buflen, &g), res);12281229retry = 0;1230if (res != 0 || g == NULL || g->gr_name == NULL || *(g->gr_name) == '\0') {1231/* not found or error */1232if (errno != 0 && errno != ENOENT && errno != ESRCH &&1233errno != EBADF && errno != EPERM)1234{1235if (errno == ERANGE) {1236/* insufficient buffer size so need larger buffer */1237buflen += ENT_BUF_SIZE;1238retry = 1;1239} else {1240throwUnixException(env, errno);1241}1242}1243} else {1244gid = g->gr_gid;1245}12461247free(grbuf);12481249} while (retry);12501251return gid;1252}12531254JNIEXPORT jint JNICALL1255Java_sun_nio_fs_UnixNativeDispatcher_fgetxattr0(JNIEnv* env, jclass clazz,1256jint fd, jlong nameAddress, jlong valueAddress, jint valueLen)1257{1258size_t res = -1;1259const char* name = jlong_to_ptr(nameAddress);1260void* value = jlong_to_ptr(valueAddress);12611262#ifdef __linux__1263res = fgetxattr(fd, name, value, valueLen);1264#elif _ALLBSD_SOURCE1265res = fgetxattr(fd, name, value, valueLen, 0, 0);1266#else1267throwUnixException(env, ENOTSUP);1268#endif12691270if (res == (size_t)-1)1271throwUnixException(env, errno);1272return (jint)res;1273}12741275JNIEXPORT void JNICALL1276Java_sun_nio_fs_UnixNativeDispatcher_fsetxattr0(JNIEnv* env, jclass clazz,1277jint fd, jlong nameAddress, jlong valueAddress, jint valueLen)1278{1279int res = -1;1280const char* name = jlong_to_ptr(nameAddress);1281void* value = jlong_to_ptr(valueAddress);12821283#ifdef __linux__1284res = fsetxattr(fd, name, value, valueLen, 0);1285#elif _ALLBSD_SOURCE1286res = fsetxattr(fd, name, value, valueLen, 0, 0);1287#else1288throwUnixException(env, ENOTSUP);1289#endif12901291if (res == -1)1292throwUnixException(env, errno);1293}12941295JNIEXPORT void JNICALL1296Java_sun_nio_fs_UnixNativeDispatcher_fremovexattr0(JNIEnv* env, jclass clazz,1297jint fd, jlong nameAddress)1298{1299int res = -1;1300const char* name = jlong_to_ptr(nameAddress);13011302#ifdef __linux__1303res = fremovexattr(fd, name);1304#elif _ALLBSD_SOURCE1305res = fremovexattr(fd, name, 0);1306#else1307throwUnixException(env, ENOTSUP);1308#endif13091310if (res == -1)1311throwUnixException(env, errno);1312}13131314JNIEXPORT jint JNICALL1315Java_sun_nio_fs_UnixNativeDispatcher_flistxattr(JNIEnv* env, jclass clazz,1316jint fd, jlong listAddress, jint size)1317{1318size_t res = -1;1319char* list = jlong_to_ptr(listAddress);13201321#ifdef __linux__1322res = flistxattr(fd, list, (size_t)size);1323#elif _ALLBSD_SOURCE1324res = flistxattr(fd, list, (size_t)size, 0);1325#else1326throwUnixException(env, ENOTSUP);1327#endif13281329if (res == (size_t)-1)1330throwUnixException(env, errno);1331return (jint)res;1332}133313341335