0N/A/*
3261N/A * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A#include <assert.h>
0N/A#include <sys/types.h>
0N/A#include <sys/time.h>
0N/A#include <sys/stat.h>
0N/A#include <sys/statvfs.h>
0N/A#include <string.h>
0N/A#include <stdlib.h>
0N/A#include <dlfcn.h>
0N/A#include <limits.h>
0N/A
0N/A#include "jni.h"
0N/A#include "jni_util.h"
0N/A#include "jlong.h"
0N/A#include "jvm.h"
0N/A#include "io_util.h"
5389N/A#include "io_util_md.h"
0N/A#include "java_io_FileSystem.h"
0N/A#include "java_io_UnixFileSystem.h"
0N/A
4632N/A#if defined(_ALLBSD_SOURCE)
4632N/A#define dirent64 dirent
4632N/A#define readdir64_r readdir_r
4632N/A#define stat64 stat
4632N/A#define statvfs64 statvfs
4632N/A#endif
0N/A
0N/A/* -- Field IDs -- */
0N/A
0N/Astatic struct {
0N/A jfieldID path;
0N/A} ids;
0N/A
0N/A
0N/AJNIEXPORT void JNICALL
0N/AJava_java_io_UnixFileSystem_initIDs(JNIEnv *env, jclass cls)
0N/A{
0N/A jclass fileClass = (*env)->FindClass(env, "java/io/File");
0N/A if (!fileClass) return;
0N/A ids.path = (*env)->GetFieldID(env, fileClass,
0N/A "path", "Ljava/lang/String;");
0N/A}
0N/A
0N/A/* -- Path operations -- */
0N/A
0N/Aextern int canonicalize(char *path, const char *out, int len);
0N/A
0N/AJNIEXPORT jstring JNICALL
0N/AJava_java_io_UnixFileSystem_canonicalize0(JNIEnv *env, jobject this,
0N/A jstring pathname)
0N/A{
0N/A jstring rv = NULL;
0N/A
0N/A WITH_PLATFORM_STRING(env, pathname, path) {
0N/A char canonicalPath[JVM_MAXPATHLEN];
0N/A if (canonicalize(JVM_NativePath((char *)path),
0N/A canonicalPath, JVM_MAXPATHLEN) < 0) {
0N/A JNU_ThrowIOExceptionWithLastError(env, "Bad pathname");
0N/A } else {
5389N/A#ifdef MACOSX
5389N/A rv = newStringPlatform(env, canonicalPath);
5389N/A#else
0N/A rv = JNU_NewStringPlatform(env, canonicalPath);
5389N/A#endif
0N/A }
0N/A } END_PLATFORM_STRING(env, path);
0N/A return rv;
0N/A}
0N/A
0N/A
0N/A/* -- Attribute accessors -- */
0N/A
0N/A
0N/Astatic jboolean
0N/AstatMode(const char *path, int *mode)
0N/A{
358N/A struct stat64 sb;
358N/A if (stat64(path, &sb) == 0) {
358N/A *mode = sb.st_mode;
358N/A return JNI_TRUE;
0N/A }
0N/A return JNI_FALSE;
0N/A}
0N/A
0N/A
0N/AJNIEXPORT jint JNICALL
0N/AJava_java_io_UnixFileSystem_getBooleanAttributes0(JNIEnv *env, jobject this,
0N/A jobject file)
0N/A{
0N/A jint rv = 0;
0N/A
0N/A WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
0N/A int mode;
0N/A if (statMode(path, &mode)) {
0N/A int fmt = mode & S_IFMT;
0N/A rv = (jint) (java_io_FileSystem_BA_EXISTS
0N/A | ((fmt == S_IFREG) ? java_io_FileSystem_BA_REGULAR : 0)
0N/A | ((fmt == S_IFDIR) ? java_io_FileSystem_BA_DIRECTORY : 0));
0N/A }
0N/A } END_PLATFORM_STRING(env, path);
0N/A return rv;
0N/A}
0N/A
0N/AJNIEXPORT jboolean JNICALL
0N/AJava_java_io_UnixFileSystem_checkAccess(JNIEnv *env, jobject this,
0N/A jobject file, jint a)
0N/A{
0N/A jboolean rv = JNI_FALSE;
2884N/A int mode = 0;
0N/A switch (a) {
0N/A case java_io_FileSystem_ACCESS_READ:
0N/A mode = R_OK;
0N/A break;
0N/A case java_io_FileSystem_ACCESS_WRITE:
0N/A mode = W_OK;
0N/A break;
0N/A case java_io_FileSystem_ACCESS_EXECUTE:
0N/A mode = X_OK;
0N/A break;
0N/A default: assert(0);
0N/A }
0N/A WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
0N/A if (access(path, mode) == 0) {
0N/A rv = JNI_TRUE;
0N/A }
0N/A } END_PLATFORM_STRING(env, path);
0N/A return rv;
0N/A}
0N/A
0N/A
0N/AJNIEXPORT jboolean JNICALL
0N/AJava_java_io_UnixFileSystem_setPermission(JNIEnv *env, jobject this,
0N/A jobject file,
0N/A jint access,
0N/A jboolean enable,
0N/A jboolean owneronly)
0N/A{
0N/A jboolean rv = JNI_FALSE;
0N/A
0N/A WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
2884N/A int amode = 0;
2884N/A int mode;
0N/A switch (access) {
0N/A case java_io_FileSystem_ACCESS_READ:
0N/A if (owneronly)
0N/A amode = S_IRUSR;
0N/A else
0N/A amode = S_IRUSR | S_IRGRP | S_IROTH;
0N/A break;
0N/A case java_io_FileSystem_ACCESS_WRITE:
0N/A if (owneronly)
0N/A amode = S_IWUSR;
0N/A else
0N/A amode = S_IWUSR | S_IWGRP | S_IWOTH;
0N/A break;
0N/A case java_io_FileSystem_ACCESS_EXECUTE:
0N/A if (owneronly)
0N/A amode = S_IXUSR;
0N/A else
0N/A amode = S_IXUSR | S_IXGRP | S_IXOTH;
0N/A break;
0N/A default:
0N/A assert(0);
0N/A }
0N/A if (statMode(path, &mode)) {
0N/A if (enable)
0N/A mode |= amode;
0N/A else
0N/A mode &= ~amode;
0N/A if (chmod(path, mode) >= 0) {
0N/A rv = JNI_TRUE;
0N/A }
0N/A }
0N/A } END_PLATFORM_STRING(env, path);
0N/A return rv;
0N/A}
0N/A
0N/AJNIEXPORT jlong JNICALL
0N/AJava_java_io_UnixFileSystem_getLastModifiedTime(JNIEnv *env, jobject this,
0N/A jobject file)
0N/A{
0N/A jlong rv = 0;
0N/A
0N/A WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
358N/A struct stat64 sb;
358N/A if (stat64(path, &sb) == 0) {
358N/A rv = 1000 * (jlong)sb.st_mtime;
0N/A }
0N/A } END_PLATFORM_STRING(env, path);
0N/A return rv;
0N/A}
0N/A
0N/A
0N/AJNIEXPORT jlong JNICALL
0N/AJava_java_io_UnixFileSystem_getLength(JNIEnv *env, jobject this,
0N/A jobject file)
0N/A{
0N/A jlong rv = 0;
0N/A
0N/A WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
358N/A struct stat64 sb;
358N/A if (stat64(path, &sb) == 0) {
358N/A rv = sb.st_size;
0N/A }
0N/A } END_PLATFORM_STRING(env, path);
0N/A return rv;
0N/A}
0N/A
0N/A
0N/A/* -- File operations -- */
0N/A
0N/A
0N/AJNIEXPORT jboolean JNICALL
0N/AJava_java_io_UnixFileSystem_createFileExclusively(JNIEnv *env, jclass cls,
0N/A jstring pathname)
0N/A{
0N/A jboolean rv = JNI_FALSE;
0N/A
0N/A WITH_PLATFORM_STRING(env, pathname, path) {
0N/A int fd;
0N/A if (!strcmp (path, "/")) {
0N/A fd = JVM_EEXIST; /* The root directory always exists */
0N/A } else {
0N/A fd = JVM_Open(path, JVM_O_RDWR | JVM_O_CREAT | JVM_O_EXCL, 0666);
0N/A }
0N/A if (fd < 0) {
0N/A if (fd != JVM_EEXIST) {
0N/A JNU_ThrowIOExceptionWithLastError(env, path);
0N/A }
0N/A } else {
0N/A JVM_Close(fd);
0N/A rv = JNI_TRUE;
0N/A }
0N/A } END_PLATFORM_STRING(env, path);
0N/A return rv;
0N/A}
0N/A
0N/A
0N/AJNIEXPORT jboolean JNICALL
0N/AJava_java_io_UnixFileSystem_delete0(JNIEnv *env, jobject this,
0N/A jobject file)
0N/A{
0N/A jboolean rv = JNI_FALSE;
0N/A
0N/A WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
0N/A if (remove(path) == 0) {
0N/A rv = JNI_TRUE;
0N/A }
0N/A } END_PLATFORM_STRING(env, path);
0N/A return rv;
0N/A}
0N/A
0N/A
0N/AJNIEXPORT jobjectArray JNICALL
0N/AJava_java_io_UnixFileSystem_list(JNIEnv *env, jobject this,
0N/A jobject file)
0N/A{
0N/A DIR *dir = NULL;
0N/A struct dirent64 *ptr;
0N/A struct dirent64 *result;
0N/A int len, maxlen;
0N/A jobjectArray rv, old;
0N/A
0N/A WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
0N/A dir = opendir(path);
0N/A } END_PLATFORM_STRING(env, path);
0N/A if (dir == NULL) return NULL;
0N/A
0N/A ptr = malloc(sizeof(struct dirent64) + (PATH_MAX + 1));
0N/A if (ptr == NULL) {
0N/A JNU_ThrowOutOfMemoryError(env, "heap allocation failed");
0N/A closedir(dir);
0N/A return NULL;
0N/A }
0N/A
0N/A /* Allocate an initial String array */
0N/A len = 0;
0N/A maxlen = 16;
0N/A rv = (*env)->NewObjectArray(env, maxlen, JNU_ClassString(env), NULL);
0N/A if (rv == NULL) goto error;
0N/A
0N/A /* Scan the directory */
0N/A while ((readdir64_r(dir, ptr, &result) == 0) && (result != NULL)) {
0N/A jstring name;
0N/A if (!strcmp(ptr->d_name, ".") || !strcmp(ptr->d_name, ".."))
0N/A continue;
0N/A if (len == maxlen) {
0N/A old = rv;
0N/A rv = (*env)->NewObjectArray(env, maxlen <<= 1,
0N/A JNU_ClassString(env), NULL);
0N/A if (rv == NULL) goto error;
0N/A if (JNU_CopyObjectArray(env, rv, old, len) < 0) goto error;
0N/A (*env)->DeleteLocalRef(env, old);
0N/A }
5389N/A#ifdef MACOSX
5389N/A name = newStringPlatform(env, ptr->d_name);
5389N/A#else
0N/A name = JNU_NewStringPlatform(env, ptr->d_name);
5389N/A#endif
0N/A if (name == NULL) goto error;
0N/A (*env)->SetObjectArrayElement(env, rv, len++, name);
0N/A (*env)->DeleteLocalRef(env, name);
0N/A }
0N/A closedir(dir);
0N/A free(ptr);
0N/A
0N/A /* Copy the final results into an appropriately-sized array */
0N/A old = rv;
0N/A rv = (*env)->NewObjectArray(env, len, JNU_ClassString(env), NULL);
0N/A if (rv == NULL) {
0N/A return NULL;
0N/A }
0N/A if (JNU_CopyObjectArray(env, rv, old, len) < 0) {
0N/A return NULL;
0N/A }
0N/A return rv;
0N/A
0N/A error:
0N/A closedir(dir);
0N/A free(ptr);
0N/A return NULL;
0N/A}
0N/A
0N/A
0N/AJNIEXPORT jboolean JNICALL
0N/AJava_java_io_UnixFileSystem_createDirectory(JNIEnv *env, jobject this,
0N/A jobject file)
0N/A{
0N/A jboolean rv = JNI_FALSE;
0N/A
0N/A WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
0N/A if (mkdir(path, 0777) == 0) {
0N/A rv = JNI_TRUE;
0N/A }
0N/A } END_PLATFORM_STRING(env, path);
0N/A return rv;
0N/A}
0N/A
0N/A
0N/AJNIEXPORT jboolean JNICALL
0N/AJava_java_io_UnixFileSystem_rename0(JNIEnv *env, jobject this,
0N/A jobject from, jobject to)
0N/A{
0N/A jboolean rv = JNI_FALSE;
0N/A
0N/A WITH_FIELD_PLATFORM_STRING(env, from, ids.path, fromPath) {
0N/A WITH_FIELD_PLATFORM_STRING(env, to, ids.path, toPath) {
0N/A if (rename(fromPath, toPath) == 0) {
0N/A rv = JNI_TRUE;
0N/A }
0N/A } END_PLATFORM_STRING(env, toPath);
0N/A } END_PLATFORM_STRING(env, fromPath);
0N/A return rv;
0N/A}
0N/A
0N/AJNIEXPORT jboolean JNICALL
0N/AJava_java_io_UnixFileSystem_setLastModifiedTime(JNIEnv *env, jobject this,
0N/A jobject file, jlong time)
0N/A{
0N/A jboolean rv = JNI_FALSE;
0N/A
0N/A WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
358N/A struct stat64 sb;
0N/A
358N/A if (stat64(path, &sb) == 0) {
358N/A struct timeval tv[2];
0N/A
358N/A /* Preserve access time */
358N/A tv[0].tv_sec = sb.st_atime;
358N/A tv[0].tv_usec = 0;
0N/A
358N/A /* Change last-modified time */
358N/A tv[1].tv_sec = time / 1000;
358N/A tv[1].tv_usec = (time % 1000) * 1000;
0N/A
358N/A if (utimes(path, tv) == 0)
358N/A rv = JNI_TRUE;
0N/A }
0N/A } END_PLATFORM_STRING(env, path);
0N/A
0N/A return rv;
0N/A}
0N/A
0N/A
0N/AJNIEXPORT jboolean JNICALL
0N/AJava_java_io_UnixFileSystem_setReadOnly(JNIEnv *env, jobject this,
0N/A jobject file)
0N/A{
0N/A jboolean rv = JNI_FALSE;
0N/A
0N/A WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
0N/A int mode;
0N/A if (statMode(path, &mode)) {
0N/A if (chmod(path, mode & ~(S_IWUSR | S_IWGRP | S_IWOTH)) >= 0) {
0N/A rv = JNI_TRUE;
0N/A }
0N/A }
0N/A } END_PLATFORM_STRING(env, path);
0N/A return rv;
0N/A}
0N/A
0N/AJNIEXPORT jlong JNICALL
0N/AJava_java_io_UnixFileSystem_getSpace(JNIEnv *env, jobject this,
0N/A jobject file, jint t)
0N/A{
0N/A jlong rv = 0L;
0N/A
0N/A WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
2193N/A struct statvfs64 fsstat;
2193N/A memset(&fsstat, 0, sizeof(fsstat));
2193N/A if (statvfs64(path, &fsstat) == 0) {
0N/A switch(t) {
0N/A case java_io_FileSystem_SPACE_TOTAL:
0N/A rv = jlong_mul(long_to_jlong(fsstat.f_frsize),
0N/A long_to_jlong(fsstat.f_blocks));
0N/A break;
0N/A case java_io_FileSystem_SPACE_FREE:
0N/A rv = jlong_mul(long_to_jlong(fsstat.f_frsize),
0N/A long_to_jlong(fsstat.f_bfree));
0N/A break;
0N/A case java_io_FileSystem_SPACE_USABLE:
0N/A rv = jlong_mul(long_to_jlong(fsstat.f_frsize),
0N/A long_to_jlong(fsstat.f_bavail));
0N/A break;
0N/A default:
0N/A assert(0);
0N/A }
0N/A }
0N/A } END_PLATFORM_STRING(env, path);
0N/A return rv;
0N/A}