Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/native/sun/nio/fs/UnixNativeDispatcher.c
32288 views
/*1* Copyright (c) 2008, 2019, 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 <pwd.h>32#include <grp.h>33#include <errno.h>34#include <dlfcn.h>35#include <sys/types.h>36#include <sys/stat.h>37#ifndef __ANDROID__38#include <sys/statvfs.h>39#else40#include <sys/vfs.h>41#endif42#include <sys/time.h>4344#ifdef __solaris__45#include <strings.h>46#endif4748#if defined(__linux__) || defined(_AIX)49#include <string.h>50#endif5152#if defined(_ALLBSD_SOURCE) || defined(__ANDROID__)53#include <string.h>5455#define stat64 stat5657#ifdef __ANDROID__58#define statvfs64 statfs59#else60#define statvfs64 statvfs61#endif6263#define open64 open64#define fstat64 fstat65#define lstat64 lstat66#define dirent64 dirent67#define readdir64_r readdir_r68#endif6970#include "jni.h"71#include "jni_util.h"72#include "jlong.h"7374#include "sun_nio_fs_UnixNativeDispatcher.h"7576/**77* Size of password or group entry when not available via sysconf78*/79#define ENT_BUF_SIZE 10248081#define RESTARTABLE(_cmd, _result) do { \82do { \83_result = _cmd; \84} while((_result == -1) && (errno == EINTR)); \85} while(0)8687#define RESTARTABLE_RETURN_PTR(_cmd, _result) do { \88do { \89_result = _cmd; \90} while((_result == NULL) && (errno == EINTR)); \91} while(0)9293static jfieldID attrs_st_mode;94static jfieldID attrs_st_ino;95static jfieldID attrs_st_dev;96static jfieldID attrs_st_rdev;97static jfieldID attrs_st_nlink;98static jfieldID attrs_st_uid;99static jfieldID attrs_st_gid;100static jfieldID attrs_st_size;101static jfieldID attrs_st_atime_sec;102static jfieldID attrs_st_atime_nsec;103static jfieldID attrs_st_mtime_sec;104static jfieldID attrs_st_mtime_nsec;105static jfieldID attrs_st_ctime_sec;106static jfieldID attrs_st_ctime_nsec;107108#ifdef _DARWIN_FEATURE_64_BIT_INODE109static jfieldID attrs_st_birthtime_sec;110#endif111112static jfieldID attrs_f_frsize;113static jfieldID attrs_f_blocks;114static jfieldID attrs_f_bfree;115static jfieldID attrs_f_bavail;116117static jfieldID entry_name;118static jfieldID entry_dir;119static jfieldID entry_fstype;120static jfieldID entry_options;121static jfieldID entry_dev;122123/**124* System calls that may not be available at run time.125*/126typedef int openat64_func(int, const char *, int, ...);127typedef int fstatat64_func(int, const char *, struct stat64 *, int);128typedef int unlinkat_func(int, const char*, int);129typedef int renameat_func(int, const char*, int, const char*);130131#ifdef __ANDROID__132typedef int utimensat_func(int, const char *, const struct timespec *, int flags);133#else134typedef int futimesat_func(int, const char *, const struct timeval *);135#endif136137typedef DIR* fdopendir_func(int);138139static openat64_func* my_openat64_func = NULL;140static fstatat64_func* my_fstatat64_func = NULL;141static unlinkat_func* my_unlinkat_func = NULL;142static renameat_func* my_renameat_func = NULL;143144#ifdef __ANDROID__145static utimensat_func* my_utimensat_func = NULL;146#else147static futimesat_func* my_futimesat_func = NULL;148#endif149150static fdopendir_func* my_fdopendir_func = NULL;151152#ifdef __ANDROID__153/*154* TODO: Android lacks support for the methods listed below. In it's place are155* alternatives that use existing Android functionality, but lack reentrant156* support. Determine if the following are the most suitable alternatives.157*158*/159int getgrgid_r(gid_t gid, struct group* grp, char* buf, size_t buflen, struct group** result) {160161*result = NULL;162errno = 0;163grp = getgrgid(gid);164if (grp == NULL) {165return errno;166}167// buf not used by caller (see below)168*result = grp;169return 0;170}171172int getgrnam_r(const char *name, struct group* grp, char* buf, size_t buflen, struct group** result) {173174*result = NULL;175errno = 0;176grp = getgrnam(name);177if (grp == NULL) {178return errno;179}180// buf not used by caller (see below)181*result = grp;182return 0;183184}185#endif186187/**188* fstatat missing from glibc on Linux. Temporary workaround189* for x86/x64.190*/191#if defined(__linux__) && defined(__i386)192#define FSTATAT64_SYSCALL_AVAILABLE193static int fstatat64_wrapper(int dfd, const char *path,194struct stat64 *statbuf, int flag)195{196#ifndef __NR_fstatat64197#define __NR_fstatat64 300198#endif199return syscall(__NR_fstatat64, dfd, path, statbuf, flag);200}201#endif202203#if defined(__linux__) && defined(__x86_64__)204#define FSTATAT64_SYSCALL_AVAILABLE205static int fstatat64_wrapper(int dfd, const char *path,206struct stat64 *statbuf, int flag)207{208#ifndef __NR_newfstatat209#define __NR_newfstatat 262210#endif211return syscall(__NR_newfstatat, dfd, path, statbuf, flag);212}213#endif214215/**216* Call this to throw an internal UnixException when a system/library217* call fails218*/219static void throwUnixException(JNIEnv* env, int errnum) {220jobject x = JNU_NewObjectByName(env, "sun/nio/fs/UnixException",221"(I)V", errnum);222if (x != NULL) {223(*env)->Throw(env, x);224}225}226227/**228* Initialization229*/230JNIEXPORT jint JNICALL231Java_sun_nio_fs_UnixNativeDispatcher_init(JNIEnv* env, jclass this)232{233jint capabilities = 0;234jclass clazz;235236clazz = (*env)->FindClass(env, "sun/nio/fs/UnixFileAttributes");237CHECK_NULL_RETURN(clazz, 0);238attrs_st_mode = (*env)->GetFieldID(env, clazz, "st_mode", "I");239CHECK_NULL_RETURN(attrs_st_mode, 0);240attrs_st_ino = (*env)->GetFieldID(env, clazz, "st_ino", "J");241CHECK_NULL_RETURN(attrs_st_ino, 0);242attrs_st_dev = (*env)->GetFieldID(env, clazz, "st_dev", "J");243CHECK_NULL_RETURN(attrs_st_dev, 0);244attrs_st_rdev = (*env)->GetFieldID(env, clazz, "st_rdev", "J");245CHECK_NULL_RETURN(attrs_st_rdev, 0);246attrs_st_nlink = (*env)->GetFieldID(env, clazz, "st_nlink", "I");247CHECK_NULL_RETURN(attrs_st_nlink, 0);248attrs_st_uid = (*env)->GetFieldID(env, clazz, "st_uid", "I");249CHECK_NULL_RETURN(attrs_st_uid, 0);250attrs_st_gid = (*env)->GetFieldID(env, clazz, "st_gid", "I");251CHECK_NULL_RETURN(attrs_st_gid, 0);252attrs_st_size = (*env)->GetFieldID(env, clazz, "st_size", "J");253CHECK_NULL_RETURN(attrs_st_size, 0);254attrs_st_atime_sec = (*env)->GetFieldID(env, clazz, "st_atime_sec", "J");255CHECK_NULL_RETURN(attrs_st_atime_sec, 0);256attrs_st_atime_nsec = (*env)->GetFieldID(env, clazz, "st_atime_nsec", "J");257CHECK_NULL_RETURN(attrs_st_atime_nsec, 0);258attrs_st_mtime_sec = (*env)->GetFieldID(env, clazz, "st_mtime_sec", "J");259CHECK_NULL_RETURN(attrs_st_mtime_sec, 0);260attrs_st_mtime_nsec = (*env)->GetFieldID(env, clazz, "st_mtime_nsec", "J");261CHECK_NULL_RETURN(attrs_st_mtime_nsec, 0);262attrs_st_ctime_sec = (*env)->GetFieldID(env, clazz, "st_ctime_sec", "J");263CHECK_NULL_RETURN(attrs_st_ctime_sec, 0);264attrs_st_ctime_nsec = (*env)->GetFieldID(env, clazz, "st_ctime_nsec", "J");265CHECK_NULL_RETURN(attrs_st_ctime_nsec, 0);266267#ifdef _DARWIN_FEATURE_64_BIT_INODE268attrs_st_birthtime_sec = (*env)->GetFieldID(env, clazz, "st_birthtime_sec", "J");269CHECK_NULL_RETURN(attrs_st_birthtime_sec, 0);270#endif271272clazz = (*env)->FindClass(env, "sun/nio/fs/UnixFileStoreAttributes");273CHECK_NULL_RETURN(clazz, 0);274attrs_f_frsize = (*env)->GetFieldID(env, clazz, "f_frsize", "J");275CHECK_NULL_RETURN(attrs_f_frsize, 0);276attrs_f_blocks = (*env)->GetFieldID(env, clazz, "f_blocks", "J");277CHECK_NULL_RETURN(attrs_f_blocks, 0);278attrs_f_bfree = (*env)->GetFieldID(env, clazz, "f_bfree", "J");279CHECK_NULL_RETURN(attrs_f_bfree, 0);280attrs_f_bavail = (*env)->GetFieldID(env, clazz, "f_bavail", "J");281CHECK_NULL_RETURN(attrs_f_bavail, 0);282283clazz = (*env)->FindClass(env, "sun/nio/fs/UnixMountEntry");284CHECK_NULL_RETURN(clazz, 0);285entry_name = (*env)->GetFieldID(env, clazz, "name", "[B");286CHECK_NULL_RETURN(entry_name, 0);287entry_dir = (*env)->GetFieldID(env, clazz, "dir", "[B");288CHECK_NULL_RETURN(entry_dir, 0);289entry_fstype = (*env)->GetFieldID(env, clazz, "fstype", "[B");290CHECK_NULL_RETURN(entry_fstype, 0);291entry_options = (*env)->GetFieldID(env, clazz, "opts", "[B");292CHECK_NULL_RETURN(entry_options, 0);293entry_dev = (*env)->GetFieldID(env, clazz, "dev", "J");294CHECK_NULL_RETURN(entry_dev, 0);295296/* system calls that might not be available at run time */297298#if (defined(__solaris__) && defined(_LP64)) || defined(_ALLBSD_SOURCE)299/* Solaris 64-bit does not have openat64/fstatat64 */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#ifdef __ANDROID__309my_utimensat_func = (utimensat_func*) dlsym(RTLD_DEFAULT, "utimensat");310#else311my_futimesat_func = (futimesat_func*) dlsym(RTLD_DEFAULT, "futimesat");312#endif313my_fdopendir_func = (fdopendir_func*) dlsym(RTLD_DEFAULT, "fdopendir");314315#if defined(FSTATAT64_SYSCALL_AVAILABLE)316/* fstatat64 missing from glibc */317if (my_fstatat64_func == NULL)318my_fstatat64_func = (fstatat64_func*)&fstatat64_wrapper;319#endif320321/* supports futimes or futimesat */322#ifdef __ANDROID__323if (my_utimensat_func != NULL) {324capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_FUTIMES;325}326#else /* __ANDROID__ */327#ifdef _ALLBSD_SOURCE328capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_FUTIMES;329#else330if (my_futimesat_func != NULL) {331capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_FUTIMES;332}333#endif334#endif335336/* supports openat, etc. */337338if (my_openat64_func != NULL && my_fstatat64_func != NULL &&339my_unlinkat_func != NULL && my_renameat_func != NULL &&340#ifdef __ANDROID__341my_utimensat_func != NULL)342#else343my_futimesat_func != NULL && my_fdopendir_func != NULL)344#endif345346{347capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_OPENAT;348}349350/* supports file birthtime */351352#ifdef _DARWIN_FEATURE_64_BIT_INODE353capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_BIRTHTIME;354#endif355356return capabilities;357}358359JNIEXPORT jbyteArray JNICALL360Java_sun_nio_fs_UnixNativeDispatcher_getcwd(JNIEnv* env, jclass this) {361jbyteArray result = NULL;362char buf[PATH_MAX+1];363364/* EINTR not listed as a possible error */365char* cwd = getcwd(buf, sizeof(buf));366if (cwd == NULL) {367throwUnixException(env, errno);368} else {369jsize len = (jsize)strlen(buf);370result = (*env)->NewByteArray(env, len);371if (result != NULL) {372(*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)buf);373}374}375return result;376}377378JNIEXPORT jbyteArray379Java_sun_nio_fs_UnixNativeDispatcher_strerror(JNIEnv* env, jclass this, jint error)380{381char tmpbuf[1024];382jsize len;383jbyteArray bytes;384385getErrorString((int)errno, tmpbuf, sizeof(tmpbuf));386len = strlen(tmpbuf);387bytes = (*env)->NewByteArray(env, len);388if (bytes != NULL) {389(*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)tmpbuf);390}391return bytes;392}393394JNIEXPORT jint395Java_sun_nio_fs_UnixNativeDispatcher_dup(JNIEnv* env, jclass this, jint fd) {396397int res = -1;398399RESTARTABLE(dup((int)fd), res);400if (res == -1) {401throwUnixException(env, errno);402}403return (jint)res;404}405406JNIEXPORT jlong JNICALL407Java_sun_nio_fs_UnixNativeDispatcher_fopen0(JNIEnv* env, jclass this,408jlong pathAddress, jlong modeAddress)409{410FILE* fp = NULL;411const char* path = (const char*)jlong_to_ptr(pathAddress);412const char* mode = (const char*)jlong_to_ptr(modeAddress);413414do {415fp = fopen(path, mode);416} while (fp == NULL && errno == EINTR);417418if (fp == NULL) {419throwUnixException(env, errno);420}421422return ptr_to_jlong(fp);423}424425JNIEXPORT void JNICALL426Java_sun_nio_fs_UnixNativeDispatcher_fclose(JNIEnv* env, jclass this, jlong stream)427{428FILE* fp = jlong_to_ptr(stream);429430/* NOTE: fclose() wrapper is only used with read-only streams.431* If it ever is used with write streams, it might be better to add432* RESTARTABLE(fflush(fp)) before closing, to make sure the stream433* is completely written even if fclose() failed.434*/435if (fclose(fp) == EOF && errno != EINTR) {436throwUnixException(env, errno);437}438}439440JNIEXPORT void JNICALL441Java_sun_nio_fs_UnixNativeDispatcher_rewind(JNIEnv* env, jclass this, jlong stream)442{443FILE* fp = jlong_to_ptr(stream);444int saved_errno;445446errno = 0;447rewind(fp);448saved_errno = errno;449if (ferror(fp)) {450throwUnixException(env, saved_errno);451}452}453454JNIEXPORT jint JNICALL455Java_sun_nio_fs_UnixNativeDispatcher_open0(JNIEnv* env, jclass this,456jlong pathAddress, jint oflags, jint mode)457{458jint fd;459const char* path = (const char*)jlong_to_ptr(pathAddress);460461RESTARTABLE(open64(path, (int)oflags, (mode_t)mode), fd);462if (fd == -1) {463throwUnixException(env, errno);464}465return fd;466}467468JNIEXPORT jint JNICALL469Java_sun_nio_fs_UnixNativeDispatcher_openat0(JNIEnv* env, jclass this, jint dfd,470jlong pathAddress, jint oflags, jint mode)471{472jint fd;473const char* path = (const char*)jlong_to_ptr(pathAddress);474475if (my_openat64_func == NULL) {476JNU_ThrowInternalError(env, "should not reach here");477return -1;478}479480RESTARTABLE((*my_openat64_func)(dfd, path, (int)oflags, (mode_t)mode), fd);481if (fd == -1) {482throwUnixException(env, errno);483}484return fd;485}486487JNIEXPORT void JNICALL488Java_sun_nio_fs_UnixNativeDispatcher_close(JNIEnv* env, jclass this, jint fd) {489int err;490/* TDB - need to decide if EIO and other errors should cause exception */491RESTARTABLE(close((int)fd), err);492}493494JNIEXPORT jint JNICALL495Java_sun_nio_fs_UnixNativeDispatcher_read(JNIEnv* env, jclass this, jint fd,496jlong address, jint nbytes)497{498ssize_t n;499void* bufp = jlong_to_ptr(address);500RESTARTABLE(read((int)fd, bufp, (size_t)nbytes), n);501if (n == -1) {502throwUnixException(env, errno);503}504return (jint)n;505}506507JNIEXPORT jint JNICALL508Java_sun_nio_fs_UnixNativeDispatcher_write(JNIEnv* env, jclass this, jint fd,509jlong address, jint nbytes)510{511ssize_t n;512void* bufp = jlong_to_ptr(address);513RESTARTABLE(write((int)fd, bufp, (size_t)nbytes), n);514if (n == -1) {515throwUnixException(env, errno);516}517return (jint)n;518}519520/**521* Copy stat64 members into sun.nio.fs.UnixFileAttributes522*/523static void prepAttributes(JNIEnv* env, struct stat64* buf, jobject attrs) {524(*env)->SetIntField(env, attrs, attrs_st_mode, (jint)buf->st_mode);525(*env)->SetLongField(env, attrs, attrs_st_ino, (jlong)buf->st_ino);526(*env)->SetLongField(env, attrs, attrs_st_dev, (jlong)buf->st_dev);527(*env)->SetLongField(env, attrs, attrs_st_rdev, (jlong)buf->st_rdev);528(*env)->SetIntField(env, attrs, attrs_st_nlink, (jint)buf->st_nlink);529(*env)->SetIntField(env, attrs, attrs_st_uid, (jint)buf->st_uid);530(*env)->SetIntField(env, attrs, attrs_st_gid, (jint)buf->st_gid);531(*env)->SetLongField(env, attrs, attrs_st_size, (jlong)buf->st_size);532(*env)->SetLongField(env, attrs, attrs_st_atime_sec, (jlong)buf->st_atime);533(*env)->SetLongField(env, attrs, attrs_st_mtime_sec, (jlong)buf->st_mtime);534(*env)->SetLongField(env, attrs, attrs_st_ctime_sec, (jlong)buf->st_ctime);535536#ifdef _DARWIN_FEATURE_64_BIT_INODE537(*env)->SetLongField(env, attrs, attrs_st_birthtime_sec, (jlong)buf->st_birthtime);538#endif539540#if (_POSIX_C_SOURCE >= 200809L) || defined(__solaris__)541(*env)->SetLongField(env, attrs, attrs_st_atime_nsec, (jlong)buf->st_atim.tv_nsec);542(*env)->SetLongField(env, attrs, attrs_st_mtime_nsec, (jlong)buf->st_mtim.tv_nsec);543(*env)->SetLongField(env, attrs, attrs_st_ctime_nsec, (jlong)buf->st_ctim.tv_nsec);544#endif545}546547JNIEXPORT void JNICALL548Java_sun_nio_fs_UnixNativeDispatcher_stat0(JNIEnv* env, jclass this,549jlong pathAddress, jobject attrs)550{551int err;552struct stat64 buf;553const char* path = (const char*)jlong_to_ptr(pathAddress);554555RESTARTABLE(stat64(path, &buf), err);556if (err == -1) {557throwUnixException(env, errno);558} else {559prepAttributes(env, &buf, attrs);560}561}562563JNIEXPORT void JNICALL564Java_sun_nio_fs_UnixNativeDispatcher_lstat0(JNIEnv* env, jclass this,565jlong pathAddress, jobject attrs)566{567int err;568struct stat64 buf;569const char* path = (const char*)jlong_to_ptr(pathAddress);570571RESTARTABLE(lstat64(path, &buf), err);572if (err == -1) {573throwUnixException(env, errno);574} else {575prepAttributes(env, &buf, attrs);576}577}578579JNIEXPORT void JNICALL580Java_sun_nio_fs_UnixNativeDispatcher_fstat(JNIEnv* env, jclass this, jint fd,581jobject attrs)582{583int err;584struct stat64 buf;585586RESTARTABLE(fstat64((int)fd, &buf), err);587if (err == -1) {588throwUnixException(env, errno);589} else {590prepAttributes(env, &buf, attrs);591}592}593594JNIEXPORT void JNICALL595Java_sun_nio_fs_UnixNativeDispatcher_fstatat0(JNIEnv* env, jclass this, jint dfd,596jlong pathAddress, jint flag, jobject attrs)597{598int err;599struct stat64 buf;600const char* path = (const char*)jlong_to_ptr(pathAddress);601602if (my_fstatat64_func == NULL) {603JNU_ThrowInternalError(env, "should not reach here");604return;605}606RESTARTABLE((*my_fstatat64_func)((int)dfd, path, &buf, (int)flag), err);607if (err == -1) {608throwUnixException(env, errno);609} else {610prepAttributes(env, &buf, attrs);611}612}613614JNIEXPORT void JNICALL615Java_sun_nio_fs_UnixNativeDispatcher_chmod0(JNIEnv* env, jclass this,616jlong pathAddress, jint mode)617{618int err;619const char* path = (const char*)jlong_to_ptr(pathAddress);620621RESTARTABLE(chmod(path, (mode_t)mode), err);622if (err == -1) {623throwUnixException(env, errno);624}625}626627JNIEXPORT void JNICALL628Java_sun_nio_fs_UnixNativeDispatcher_fchmod(JNIEnv* env, jclass this, jint filedes,629jint mode)630{631int err;632633RESTARTABLE(fchmod((int)filedes, (mode_t)mode), err);634if (err == -1) {635throwUnixException(env, errno);636}637}638639640JNIEXPORT void JNICALL641Java_sun_nio_fs_UnixNativeDispatcher_chown0(JNIEnv* env, jclass this,642jlong pathAddress, jint uid, jint gid)643{644int err;645const char* path = (const char*)jlong_to_ptr(pathAddress);646647RESTARTABLE(chown(path, (uid_t)uid, (gid_t)gid), err);648if (err == -1) {649throwUnixException(env, errno);650}651}652653JNIEXPORT void JNICALL654Java_sun_nio_fs_UnixNativeDispatcher_lchown0(JNIEnv* env, jclass this, jlong pathAddress, jint uid, jint gid)655{656int err;657const char* path = (const char*)jlong_to_ptr(pathAddress);658659RESTARTABLE(lchown(path, (uid_t)uid, (gid_t)gid), err);660if (err == -1) {661throwUnixException(env, errno);662}663}664665JNIEXPORT void JNICALL666Java_sun_nio_fs_UnixNativeDispatcher_fchown(JNIEnv* env, jclass this, jint filedes, jint uid, jint gid)667{668int err;669670RESTARTABLE(fchown(filedes, (uid_t)uid, (gid_t)gid), err);671if (err == -1) {672throwUnixException(env, errno);673}674}675676JNIEXPORT void JNICALL677Java_sun_nio_fs_UnixNativeDispatcher_utimes0(JNIEnv* env, jclass this,678jlong pathAddress, jlong accessTime, jlong modificationTime)679{680int err;681struct timeval times[2];682const char* path = (const char*)jlong_to_ptr(pathAddress);683684times[0].tv_sec = accessTime / 1000000;685times[0].tv_usec = accessTime % 1000000;686687times[1].tv_sec = modificationTime / 1000000;688times[1].tv_usec = modificationTime % 1000000;689690RESTARTABLE(utimes(path, ×[0]), err);691if (err == -1) {692throwUnixException(env, errno);693}694}695696JNIEXPORT void JNICALL697Java_sun_nio_fs_UnixNativeDispatcher_futimes(JNIEnv* env, jclass this, jint filedes,698jlong accessTime, jlong modificationTime)699{700701int err = 0;702#ifdef __ANDROID__703struct timespec times[2];704times[0].tv_sec = accessTime / 1000000;705times[0].tv_nsec = (accessTime % 1000000) * 1000;706707times[1].tv_sec = modificationTime / 1000000;708times[1].tv_nsec = (modificationTime % 1000000) * 1000;709710if (my_utimensat_func == NULL) {711JNU_ThrowInternalError(env, "my_utimensat is NULL");712return;713}714715RESTARTABLE((*my_utimensat_func)(filedes, NULL, ×[0], 0), err);716#else //__ANDROID__717struct timeval times[2];718times[0].tv_sec = accessTime / 1000000;719times[0].tv_usec = accessTime % 1000000;720721times[1].tv_sec = modificationTime / 1000000;722times[1].tv_usec = modificationTime % 1000000;723724#ifdef _ALLBSD_SOURCE725RESTARTABLE(futimes(filedes, ×[0]), err);726#else727if (my_futimesat_func == NULL) {728JNU_ThrowInternalError(env, "my_ftimesat_func is NULL");729return;730}731RESTARTABLE((*my_futimesat_func)(filedes, NULL, ×[0]), err);732#endif733#endif //__ANDROID__734if (err == -1) {735throwUnixException(env, errno);736}737}738739JNIEXPORT jlong JNICALL740Java_sun_nio_fs_UnixNativeDispatcher_opendir0(JNIEnv* env, jclass this,741jlong pathAddress)742{743DIR* dir;744const char* path = (const char*)jlong_to_ptr(pathAddress);745746/* EINTR not listed as a possible error */747dir = opendir(path);748if (dir == NULL) {749throwUnixException(env, errno);750}751return ptr_to_jlong(dir);752}753754JNIEXPORT jlong JNICALL755Java_sun_nio_fs_UnixNativeDispatcher_fdopendir(JNIEnv* env, jclass this, int dfd) {756DIR* dir;757758if (my_fdopendir_func == NULL) {759JNU_ThrowInternalError(env, "should not reach here");760return (jlong)-1;761}762763/* EINTR not listed as a possible error */764dir = (*my_fdopendir_func)((int)dfd);765if (dir == NULL) {766throwUnixException(env, errno);767}768return ptr_to_jlong(dir);769}770771JNIEXPORT void JNICALL772Java_sun_nio_fs_UnixNativeDispatcher_closedir(JNIEnv* env, jclass this, jlong dir) {773DIR* dirp = jlong_to_ptr(dir);774775if (closedir(dirp) == -1 && errno != EINTR) {776throwUnixException(env, errno);777}778}779780JNIEXPORT jbyteArray JNICALL781Java_sun_nio_fs_UnixNativeDispatcher_readdir(JNIEnv* env, jclass this, jlong value) {782struct dirent64* result;783struct {784struct dirent64 buf;785char name_extra[PATH_MAX + 1 - sizeof result->d_name];786} entry;787struct dirent64* ptr = &entry.buf;788int res;789DIR* dirp = jlong_to_ptr(value);790791/* EINTR not listed as a possible error */792/* TDB: reentrant version probably not required here */793res = readdir64_r(dirp, ptr, &result);794795#ifdef _AIX796/* On AIX, readdir_r() returns EBADF (i.e. '9') and sets 'result' to NULL for the */797/* directory stream end. Otherwise, 'errno' will contain the error code. */798if (res != 0) {799res = (result == NULL && res == EBADF) ? 0 : errno;800}801#endif802803if (res != 0) {804throwUnixException(env, res);805return NULL;806} else {807if (result == NULL) {808return NULL;809} else {810jsize len = strlen(ptr->d_name);811jbyteArray bytes = (*env)->NewByteArray(env, len);812if (bytes != NULL) {813(*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)(ptr->d_name));814}815return bytes;816}817}818}819820JNIEXPORT void JNICALL821Java_sun_nio_fs_UnixNativeDispatcher_mkdir0(JNIEnv* env, jclass this,822jlong pathAddress, jint mode)823{824const char* path = (const char*)jlong_to_ptr(pathAddress);825826/* EINTR not listed as a possible error */827if (mkdir(path, (mode_t)mode) == -1) {828throwUnixException(env, errno);829}830}831832JNIEXPORT void JNICALL833Java_sun_nio_fs_UnixNativeDispatcher_rmdir0(JNIEnv* env, jclass this,834jlong pathAddress)835{836const char* path = (const char*)jlong_to_ptr(pathAddress);837838/* EINTR not listed as a possible error */839if (rmdir(path) == -1) {840throwUnixException(env, errno);841}842}843844JNIEXPORT void JNICALL845Java_sun_nio_fs_UnixNativeDispatcher_link0(JNIEnv* env, jclass this,846jlong existingAddress, jlong newAddress)847{848int err;849const char* existing = (const char*)jlong_to_ptr(existingAddress);850const char* newname = (const char*)jlong_to_ptr(newAddress);851852RESTARTABLE(link(existing, newname), err);853if (err == -1) {854throwUnixException(env, errno);855}856}857858859JNIEXPORT void JNICALL860Java_sun_nio_fs_UnixNativeDispatcher_unlink0(JNIEnv* env, jclass this,861jlong pathAddress)862{863const char* path = (const char*)jlong_to_ptr(pathAddress);864865/* EINTR not listed as a possible error */866if (unlink(path) == -1) {867throwUnixException(env, errno);868}869}870871JNIEXPORT void JNICALL872Java_sun_nio_fs_UnixNativeDispatcher_unlinkat0(JNIEnv* env, jclass this, jint dfd,873jlong pathAddress, jint flags)874{875const char* path = (const char*)jlong_to_ptr(pathAddress);876877if (my_unlinkat_func == NULL) {878JNU_ThrowInternalError(env, "should not reach here");879return;880}881882/* EINTR not listed as a possible error */883if ((*my_unlinkat_func)((int)dfd, path, (int)flags) == -1) {884throwUnixException(env, errno);885}886}887888JNIEXPORT void JNICALL889Java_sun_nio_fs_UnixNativeDispatcher_rename0(JNIEnv* env, jclass this,890jlong fromAddress, jlong toAddress)891{892const char* from = (const char*)jlong_to_ptr(fromAddress);893const char* to = (const char*)jlong_to_ptr(toAddress);894895/* EINTR not listed as a possible error */896if (rename(from, to) == -1) {897throwUnixException(env, errno);898}899}900901JNIEXPORT void JNICALL902Java_sun_nio_fs_UnixNativeDispatcher_renameat0(JNIEnv* env, jclass this,903jint fromfd, jlong fromAddress, jint tofd, jlong toAddress)904{905const char* from = (const char*)jlong_to_ptr(fromAddress);906const char* to = (const char*)jlong_to_ptr(toAddress);907908if (my_renameat_func == NULL) {909JNU_ThrowInternalError(env, "should not reach here");910return;911}912913/* EINTR not listed as a possible error */914if ((*my_renameat_func)((int)fromfd, from, (int)tofd, to) == -1) {915throwUnixException(env, errno);916}917}918919JNIEXPORT void JNICALL920Java_sun_nio_fs_UnixNativeDispatcher_symlink0(JNIEnv* env, jclass this,921jlong targetAddress, jlong linkAddress)922{923const char* target = (const char*)jlong_to_ptr(targetAddress);924const char* link = (const char*)jlong_to_ptr(linkAddress);925926/* EINTR not listed as a possible error */927if (symlink(target, link) == -1) {928throwUnixException(env, errno);929}930}931932JNIEXPORT jbyteArray JNICALL933Java_sun_nio_fs_UnixNativeDispatcher_readlink0(JNIEnv* env, jclass this,934jlong pathAddress)935{936jbyteArray result = NULL;937char target[PATH_MAX+1];938const char* path = (const char*)jlong_to_ptr(pathAddress);939940/* EINTR not listed as a possible error */941int n = readlink(path, target, sizeof(target));942if (n == -1) {943throwUnixException(env, errno);944} else {945jsize len;946if (n == sizeof(target)) {947n--;948}949target[n] = '\0';950len = (jsize)strlen(target);951result = (*env)->NewByteArray(env, len);952if (result != NULL) {953(*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)target);954}955}956return result;957}958959JNIEXPORT jbyteArray JNICALL960Java_sun_nio_fs_UnixNativeDispatcher_realpath0(JNIEnv* env, jclass this,961jlong pathAddress)962{963#ifdef __ANDROID__964struct stat64 buf;965int err;966#endif967968jbyteArray result = NULL;969char resolved[PATH_MAX+1];970const char* path = (const char*)jlong_to_ptr(pathAddress);971972/* EINTR not listed as a possible error */973if (realpath(path, resolved) == NULL) {974throwUnixException(env, errno);975} else {976#ifdef __ANDROID__977/* android's realpath doesn't fail for non-existent files */978RESTARTABLE(lstat64(path, &buf), err);979if (err == -1 && errno == ENOENT) {980throwUnixException(env, errno);981} else982#endif983{984985jsize len = (jsize)strlen(resolved);986result = (*env)->NewByteArray(env, len);987if (result != NULL) {988(*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)resolved);989}990}991}992return result;993}994995JNIEXPORT void JNICALL996Java_sun_nio_fs_UnixNativeDispatcher_access0(JNIEnv* env, jclass this,997jlong pathAddress, jint amode)998{999int err;1000const char* path = (const char*)jlong_to_ptr(pathAddress);10011002RESTARTABLE(access(path, (int)amode), err);1003if (err == -1) {1004throwUnixException(env, errno);1005}1006}10071008JNIEXPORT void JNICALL1009Java_sun_nio_fs_UnixNativeDispatcher_statvfs0(JNIEnv* env, jclass this,1010jlong pathAddress, jobject attrs)1011{1012int err;1013struct statvfs64 buf;1014const char* path = (const char*)jlong_to_ptr(pathAddress);101510161017RESTARTABLE(statvfs64(path, &buf), err);1018if (err == -1) {1019throwUnixException(env, errno);1020} else {1021#ifdef _AIX1022/* AIX returns ULONG_MAX in buf.f_blocks for the /proc file system. */1023/* This is too big for a Java signed long and fools various tests. */1024if (buf.f_blocks == ULONG_MAX) {1025buf.f_blocks = 0;1026}1027/* The number of free or available blocks can never exceed the total number of blocks */1028if (buf.f_blocks == 0) {1029buf.f_bfree = 0;1030buf.f_bavail = 0;1031}1032#endif1033(*env)->SetLongField(env, attrs, attrs_f_frsize, long_to_jlong(buf.f_frsize));1034(*env)->SetLongField(env, attrs, attrs_f_blocks, long_to_jlong(buf.f_blocks));1035(*env)->SetLongField(env, attrs, attrs_f_bfree, long_to_jlong(buf.f_bfree));1036(*env)->SetLongField(env, attrs, attrs_f_bavail, long_to_jlong(buf.f_bavail));1037}1038}10391040JNIEXPORT jlong JNICALL1041Java_sun_nio_fs_UnixNativeDispatcher_pathconf0(JNIEnv* env, jclass this,1042jlong pathAddress, jint name)1043{1044long err;1045const char* path = (const char*)jlong_to_ptr(pathAddress);10461047err = pathconf(path, (int)name);1048if (err == -1) {1049throwUnixException(env, errno);1050}1051return (jlong)err;1052}10531054JNIEXPORT jlong JNICALL1055Java_sun_nio_fs_UnixNativeDispatcher_fpathconf(JNIEnv* env, jclass this,1056jint fd, jint name)1057{1058long err;10591060err = fpathconf((int)fd, (int)name);1061if (err == -1) {1062throwUnixException(env, errno);1063}1064return (jlong)err;1065}10661067JNIEXPORT void JNICALL1068Java_sun_nio_fs_UnixNativeDispatcher_mknod0(JNIEnv* env, jclass this,1069jlong pathAddress, jint mode, jlong dev)1070{1071int err;1072const char* path = (const char*)jlong_to_ptr(pathAddress);10731074RESTARTABLE(mknod(path, (mode_t)mode, (dev_t)dev), err);1075if (err == -1) {1076throwUnixException(env, errno);1077}1078}10791080JNIEXPORT jbyteArray JNICALL1081Java_sun_nio_fs_UnixNativeDispatcher_getpwuid(JNIEnv* env, jclass this, jint uid)1082{1083jbyteArray result = NULL;1084int buflen;1085char* pwbuf;10861087/* allocate buffer for password record */1088buflen = (int)sysconf(_SC_GETPW_R_SIZE_MAX);1089if (buflen == -1)1090buflen = ENT_BUF_SIZE;1091pwbuf = (char*)malloc(buflen);1092if (pwbuf == NULL) {1093JNU_ThrowOutOfMemoryError(env, "native heap");1094} else {1095struct passwd pwent;1096struct passwd* p = NULL;1097int res = 0;10981099errno = 0;1100#ifdef __solaris__1101RESTARTABLE_RETURN_PTR(getpwuid_r((uid_t)uid, &pwent, pwbuf, (size_t)buflen), p);1102#else1103RESTARTABLE(getpwuid_r((uid_t)uid, &pwent, pwbuf, (size_t)buflen, &p), res);1104#endif11051106if (res != 0 || p == NULL || p->pw_name == NULL || *(p->pw_name) == '\0') {1107/* not found or error */1108if (errno == 0)1109errno = ENOENT;1110throwUnixException(env, errno);1111} else {1112jsize len = strlen(p->pw_name);1113result = (*env)->NewByteArray(env, len);1114if (result != NULL) {1115(*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)(p->pw_name));1116}1117}1118free(pwbuf);1119}11201121return result;1122}112311241125JNIEXPORT jbyteArray JNICALL1126Java_sun_nio_fs_UnixNativeDispatcher_getgrgid(JNIEnv* env, jclass this, jint gid)1127{1128jbyteArray result = NULL;1129int buflen;1130int retry;11311132/* initial size of buffer for group record */1133buflen = (int)sysconf(_SC_GETGR_R_SIZE_MAX);1134if (buflen == -1)1135buflen = ENT_BUF_SIZE;11361137do {1138struct group grent;1139struct group* g = NULL;1140int res = 0;11411142char* grbuf = (char*)malloc(buflen);1143if (grbuf == NULL) {1144JNU_ThrowOutOfMemoryError(env, "native heap");1145return NULL;1146}11471148errno = 0;1149#ifdef __solaris__1150RESTARTABLE_RETURN_PTR(getgrgid_r((gid_t)gid, &grent, grbuf, (size_t)buflen), g);1151#else1152RESTARTABLE(getgrgid_r((gid_t)gid, &grent, grbuf, (size_t)buflen, &g), res);1153#endif11541155retry = 0;1156if (res != 0 || g == NULL || g->gr_name == NULL || *(g->gr_name) == '\0') {1157/* not found or error */1158if (errno == ERANGE) {1159/* insufficient buffer size so need larger buffer */1160buflen += ENT_BUF_SIZE;1161retry = 1;1162} else {1163if (errno == 0)1164errno = ENOENT;1165throwUnixException(env, errno);1166}1167} else {1168jsize len = strlen(g->gr_name);1169result = (*env)->NewByteArray(env, len);1170if (result != NULL) {1171(*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)(g->gr_name));1172}1173}11741175free(grbuf);11761177} while (retry);11781179return result;1180}11811182JNIEXPORT jint JNICALL1183Java_sun_nio_fs_UnixNativeDispatcher_getpwnam0(JNIEnv* env, jclass this,1184jlong nameAddress)1185{1186jint uid = -1;1187int buflen;1188char* pwbuf;11891190/* allocate buffer for password record */1191buflen = (int)sysconf(_SC_GETPW_R_SIZE_MAX);1192if (buflen == -1)1193buflen = ENT_BUF_SIZE;1194pwbuf = (char*)malloc(buflen);1195if (pwbuf == NULL) {1196JNU_ThrowOutOfMemoryError(env, "native heap");1197} else {1198struct passwd pwent;1199struct passwd* p = NULL;1200int res = 0;1201const char* name = (const char*)jlong_to_ptr(nameAddress);12021203errno = 0;1204#ifdef __solaris__1205RESTARTABLE_RETURN_PTR(getpwnam_r(name, &pwent, pwbuf, (size_t)buflen), p);1206#else1207RESTARTABLE(getpwnam_r(name, &pwent, pwbuf, (size_t)buflen, &p), res);1208#endif12091210if (res != 0 || p == NULL || p->pw_name == NULL || *(p->pw_name) == '\0') {1211/* not found or error */1212if (errno != 0 && errno != ENOENT && errno != ESRCH)1213throwUnixException(env, errno);1214} else {1215uid = p->pw_uid;1216}1217free(pwbuf);1218}12191220return uid;1221}12221223JNIEXPORT jint JNICALL1224Java_sun_nio_fs_UnixNativeDispatcher_getgrnam0(JNIEnv* env, jclass this,1225jlong nameAddress)1226{1227jint gid = -1;1228int buflen, retry;12291230/* initial size of buffer for group record */1231buflen = (int)sysconf(_SC_GETGR_R_SIZE_MAX);1232if (buflen == -1)1233buflen = ENT_BUF_SIZE;12341235do {1236struct group grent;1237struct group* g = NULL;1238int res = 0;1239char *grbuf;1240const char* name = (const char*)jlong_to_ptr(nameAddress);12411242grbuf = (char*)malloc(buflen);1243if (grbuf == NULL) {1244JNU_ThrowOutOfMemoryError(env, "native heap");1245return -1;1246}12471248errno = 0;1249#ifdef __solaris__1250RESTARTABLE_RETURN_PTR(getgrnam_r(name, &grent, grbuf, (size_t)buflen), g);1251#else1252RESTARTABLE(getgrnam_r(name, &grent, grbuf, (size_t)buflen, &g), res);1253#endif12541255retry = 0;1256if (res != 0 || g == NULL || g->gr_name == NULL || *(g->gr_name) == '\0') {1257/* not found or error */1258if (errno != 0 && errno != ENOENT && errno != ESRCH) {1259if (errno == ERANGE) {1260/* insufficient buffer size so need larger buffer */1261buflen += ENT_BUF_SIZE;1262retry = 1;1263} else {1264throwUnixException(env, errno);1265}1266}1267} else {1268gid = g->gr_gid;1269}12701271free(grbuf);12721273} while (retry);12741275return gid;1276}127712781279