jdk/src/solaris/native/java/io/UnixFileSystem_md.c
changeset 2 90ce3da70b43
child 692 50a393caed65
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/native/java/io/UnixFileSystem_md.c	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,559 @@
+/*
+ * Copyright 1998-2006 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <string.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <limits.h>
+
+#include "jni.h"
+#include "jni_util.h"
+#include "jlong.h"
+#include "jvm.h"
+#include "io_util.h"
+#include "java_io_FileSystem.h"
+#include "java_io_UnixFileSystem.h"
+
+
+/* -- Field IDs -- */
+
+static struct {
+    jfieldID path;
+} ids;
+
+
+JNIEXPORT void JNICALL
+Java_java_io_UnixFileSystem_initIDs(JNIEnv *env, jclass cls)
+{
+    jclass fileClass = (*env)->FindClass(env, "java/io/File");
+    if (!fileClass) return;
+    ids.path = (*env)->GetFieldID(env, fileClass,
+                                  "path", "Ljava/lang/String;");
+}
+
+
+/* -- Large-file support -- */
+
+/* LINUX_FIXME: ifdef __solaris__ here is wrong.  We need to move the
+ * definition of stat64 into a solaris_largefile.h and create a
+ * linux_largefile.h with a good stat64 structure to compile on
+ * glibc2.0 based systems.
+ */
+#if defined(__solaris__) && !defined(_LFS_LARGEFILE) || !_LFS_LARGEFILE
+
+/* The stat64 structure must be provided for systems without large-file support
+   (e.g., Solaris 2.5.1).  These definitions are copied from the Solaris 2.6
+   <sys/stat.h> and <sys/types.h> files.
+ */
+
+typedef longlong_t      off64_t;        /* offsets within files */
+typedef u_longlong_t    ino64_t;        /* expanded inode type  */
+typedef longlong_t      blkcnt64_t;     /* count of file blocks */
+
+struct  stat64 {
+        dev_t   st_dev;
+        long    st_pad1[3];
+        ino64_t st_ino;
+        mode_t  st_mode;
+        nlink_t st_nlink;
+        uid_t   st_uid;
+        gid_t   st_gid;
+        dev_t   st_rdev;
+        long    st_pad2[2];
+        off64_t st_size;
+        timestruc_t st_atim;
+        timestruc_t st_mtim;
+        timestruc_t st_ctim;
+        long    st_blksize;
+        blkcnt64_t st_blocks;
+        char    st_fstype[_ST_FSTYPSZ];
+        long    st_pad4[8];
+};
+
+#endif  /* !_LFS_LARGEFILE */
+
+typedef int (*STAT64)(const char *, struct stat64 *);
+
+#if defined(__linux__) && defined(_LARGEFILE64_SOURCE)
+static STAT64 stat64_ptr = &stat64;
+#else
+static STAT64 stat64_ptr = NULL;
+#endif
+
+#ifndef __linux__
+#ifdef __GNUC__
+static void init64IO(void) __attribute__((constructor));
+#else
+#pragma init(init64IO)
+#endif
+#endif
+
+static void init64IO(void) {
+    void *handle = dlopen(0, RTLD_LAZY);
+    stat64_ptr = (STAT64) dlsym(handle, "_stat64");
+    dlclose(handle);
+}
+
+
+/* -- Path operations -- */
+
+extern int canonicalize(char *path, const char *out, int len);
+
+JNIEXPORT jstring JNICALL
+Java_java_io_UnixFileSystem_canonicalize0(JNIEnv *env, jobject this,
+                                          jstring pathname)
+{
+    jstring rv = NULL;
+
+    WITH_PLATFORM_STRING(env, pathname, path) {
+        char canonicalPath[JVM_MAXPATHLEN];
+        if (canonicalize(JVM_NativePath((char *)path),
+                         canonicalPath, JVM_MAXPATHLEN) < 0) {
+            JNU_ThrowIOExceptionWithLastError(env, "Bad pathname");
+        } else {
+            rv = JNU_NewStringPlatform(env, canonicalPath);
+        }
+    } END_PLATFORM_STRING(env, path);
+    return rv;
+}
+
+
+/* -- Attribute accessors -- */
+
+
+static jboolean
+statMode(const char *path, int *mode)
+{
+    if (stat64_ptr) {
+        struct stat64 sb;
+        if (((*stat64_ptr)(path, &sb)) == 0) {
+            *mode = sb.st_mode;
+            return JNI_TRUE;
+        }
+    } else {
+        struct stat sb;
+        if (stat(path, &sb) == 0) {
+            *mode = sb.st_mode;
+            return JNI_TRUE;
+        }
+    }
+    return JNI_FALSE;
+}
+
+
+JNIEXPORT jint JNICALL
+Java_java_io_UnixFileSystem_getBooleanAttributes0(JNIEnv *env, jobject this,
+                                                  jobject file)
+{
+    jint rv = 0;
+
+    WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
+        int mode;
+        if (statMode(path, &mode)) {
+            int fmt = mode & S_IFMT;
+            rv = (jint) (java_io_FileSystem_BA_EXISTS
+                  | ((fmt == S_IFREG) ? java_io_FileSystem_BA_REGULAR : 0)
+                  | ((fmt == S_IFDIR) ? java_io_FileSystem_BA_DIRECTORY : 0));
+        }
+    } END_PLATFORM_STRING(env, path);
+    return rv;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_java_io_UnixFileSystem_checkAccess(JNIEnv *env, jobject this,
+                                        jobject file, jint a)
+{
+    jboolean rv = JNI_FALSE;
+    int mode;
+    switch (a) {
+    case java_io_FileSystem_ACCESS_READ:
+        mode = R_OK;
+        break;
+    case java_io_FileSystem_ACCESS_WRITE:
+        mode = W_OK;
+        break;
+    case java_io_FileSystem_ACCESS_EXECUTE:
+        mode = X_OK;
+        break;
+    default: assert(0);
+    }
+    WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
+        if (access(path, mode) == 0) {
+            rv = JNI_TRUE;
+        }
+    } END_PLATFORM_STRING(env, path);
+    return rv;
+}
+
+
+JNIEXPORT jboolean JNICALL
+Java_java_io_UnixFileSystem_setPermission(JNIEnv *env, jobject this,
+                                          jobject file,
+                                          jint access,
+                                          jboolean enable,
+                                          jboolean owneronly)
+{
+    jboolean rv = JNI_FALSE;
+
+    WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
+        int amode, mode;
+        switch (access) {
+        case java_io_FileSystem_ACCESS_READ:
+            if (owneronly)
+                amode = S_IRUSR;
+            else
+                amode = S_IRUSR | S_IRGRP | S_IROTH;
+            break;
+        case java_io_FileSystem_ACCESS_WRITE:
+            if (owneronly)
+                amode = S_IWUSR;
+            else
+                amode = S_IWUSR | S_IWGRP | S_IWOTH;
+            break;
+        case java_io_FileSystem_ACCESS_EXECUTE:
+            if (owneronly)
+                amode = S_IXUSR;
+            else
+                amode = S_IXUSR | S_IXGRP | S_IXOTH;
+            break;
+        default:
+            assert(0);
+        }
+        if (statMode(path, &mode)) {
+            if (enable)
+                mode |= amode;
+            else
+                mode &= ~amode;
+            if (chmod(path, mode) >= 0) {
+                rv = JNI_TRUE;
+            }
+        }
+    } END_PLATFORM_STRING(env, path);
+    return rv;
+}
+
+JNIEXPORT jlong JNICALL
+Java_java_io_UnixFileSystem_getLastModifiedTime(JNIEnv *env, jobject this,
+                                                jobject file)
+{
+    jlong rv = 0;
+
+    WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
+        if (stat64_ptr) {
+            struct stat64 sb;
+            if (((*stat64_ptr)(path, &sb)) == 0) {
+                rv = 1000 * (jlong)sb.st_mtime;
+            }
+        } else {
+            struct stat sb;
+            if (stat(path, &sb) == 0) {
+                rv = 1000 * (jlong)sb.st_mtime;
+            }
+        }
+    } END_PLATFORM_STRING(env, path);
+    return rv;
+}
+
+
+JNIEXPORT jlong JNICALL
+Java_java_io_UnixFileSystem_getLength(JNIEnv *env, jobject this,
+                                      jobject file)
+{
+    jlong rv = 0;
+
+    WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
+        if (stat64_ptr) {
+            struct stat64 sb;
+            if (((*stat64_ptr)(path, &sb)) == 0) {
+                rv = sb.st_size;
+            }
+        } else {
+            struct stat sb;
+            if (stat(path, &sb) == 0) {
+                rv = sb.st_size;
+            }
+        }
+    } END_PLATFORM_STRING(env, path);
+    return rv;
+}
+
+
+/* -- File operations -- */
+
+
+JNIEXPORT jboolean JNICALL
+Java_java_io_UnixFileSystem_createFileExclusively(JNIEnv *env, jclass cls,
+                                                  jstring pathname)
+{
+    jboolean rv = JNI_FALSE;
+
+    WITH_PLATFORM_STRING(env, pathname, path) {
+        int fd;
+        if (!strcmp (path, "/")) {
+            fd = JVM_EEXIST;    /* The root directory always exists */
+        } else {
+            fd = JVM_Open(path, JVM_O_RDWR | JVM_O_CREAT | JVM_O_EXCL, 0666);
+        }
+        if (fd < 0) {
+            if (fd != JVM_EEXIST) {
+                JNU_ThrowIOExceptionWithLastError(env, path);
+            }
+        } else {
+            JVM_Close(fd);
+            rv = JNI_TRUE;
+        }
+    } END_PLATFORM_STRING(env, path);
+    return rv;
+}
+
+
+JNIEXPORT jboolean JNICALL
+Java_java_io_UnixFileSystem_delete0(JNIEnv *env, jobject this,
+                                    jobject file)
+{
+    jboolean rv = JNI_FALSE;
+
+    WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
+        if (remove(path) == 0) {
+            rv = JNI_TRUE;
+        }
+    } END_PLATFORM_STRING(env, path);
+    return rv;
+}
+
+
+JNIEXPORT jobjectArray JNICALL
+Java_java_io_UnixFileSystem_list(JNIEnv *env, jobject this,
+                                 jobject file)
+{
+    DIR *dir = NULL;
+    struct dirent64 *ptr;
+    struct dirent64 *result;
+    int len, maxlen;
+    jobjectArray rv, old;
+
+    WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
+        dir = opendir(path);
+    } END_PLATFORM_STRING(env, path);
+    if (dir == NULL) return NULL;
+
+    ptr = malloc(sizeof(struct dirent64) + (PATH_MAX + 1));
+    if (ptr == NULL) {
+        JNU_ThrowOutOfMemoryError(env, "heap allocation failed");
+        closedir(dir);
+        return NULL;
+    }
+
+    /* Allocate an initial String array */
+    len = 0;
+    maxlen = 16;
+    rv = (*env)->NewObjectArray(env, maxlen, JNU_ClassString(env), NULL);
+    if (rv == NULL) goto error;
+
+    /* Scan the directory */
+    while ((readdir64_r(dir, ptr, &result) == 0)  && (result != NULL)) {
+        jstring name;
+        if (!strcmp(ptr->d_name, ".") || !strcmp(ptr->d_name, ".."))
+            continue;
+        if (len == maxlen) {
+            old = rv;
+            rv = (*env)->NewObjectArray(env, maxlen <<= 1,
+                                        JNU_ClassString(env), NULL);
+            if (rv == NULL) goto error;
+            if (JNU_CopyObjectArray(env, rv, old, len) < 0) goto error;
+            (*env)->DeleteLocalRef(env, old);
+        }
+        name = JNU_NewStringPlatform(env, ptr->d_name);
+        if (name == NULL) goto error;
+        (*env)->SetObjectArrayElement(env, rv, len++, name);
+        (*env)->DeleteLocalRef(env, name);
+    }
+    closedir(dir);
+    free(ptr);
+
+    /* Copy the final results into an appropriately-sized array */
+    old = rv;
+    rv = (*env)->NewObjectArray(env, len, JNU_ClassString(env), NULL);
+    if (rv == NULL) {
+        return NULL;
+    }
+    if (JNU_CopyObjectArray(env, rv, old, len) < 0) {
+        return NULL;
+    }
+    return rv;
+
+ error:
+    closedir(dir);
+    free(ptr);
+    return NULL;
+}
+
+
+JNIEXPORT jboolean JNICALL
+Java_java_io_UnixFileSystem_createDirectory(JNIEnv *env, jobject this,
+                                            jobject file)
+{
+    jboolean rv = JNI_FALSE;
+
+    WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
+        if (mkdir(path, 0777) == 0) {
+            rv = JNI_TRUE;
+        }
+    } END_PLATFORM_STRING(env, path);
+    return rv;
+}
+
+
+JNIEXPORT jboolean JNICALL
+Java_java_io_UnixFileSystem_rename0(JNIEnv *env, jobject this,
+                                    jobject from, jobject to)
+{
+    jboolean rv = JNI_FALSE;
+
+    WITH_FIELD_PLATFORM_STRING(env, from, ids.path, fromPath) {
+        WITH_FIELD_PLATFORM_STRING(env, to, ids.path, toPath) {
+            if (rename(fromPath, toPath) == 0) {
+                rv = JNI_TRUE;
+            }
+        } END_PLATFORM_STRING(env, toPath);
+    } END_PLATFORM_STRING(env, fromPath);
+    return rv;
+}
+
+
+/* Bug in solaris /usr/include/sys/time.h? */
+#ifdef __solaris__
+extern int utimes(const char *, const struct timeval *);
+#elif defined(__linux___)
+extern int utimes(const char *, struct timeval *);
+#endif
+
+
+JNIEXPORT jboolean JNICALL
+Java_java_io_UnixFileSystem_setLastModifiedTime(JNIEnv *env, jobject this,
+                                                jobject file, jlong time)
+{
+    jboolean rv = JNI_FALSE;
+
+    WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
+        struct timeval tv[2];
+#ifdef __solaris__
+        timestruc_t ts;
+
+        if (stat64_ptr) {
+            struct stat64 sb;
+            if (((*stat64_ptr)(path, &sb)) == 0)
+                ts = sb.st_atim;
+            else
+                goto error;
+        } else {
+            struct stat sb;
+            if (stat(path, &sb) == 0)
+                ts = sb.st_atim;
+            else
+                goto error;
+        }
+#endif
+
+        /* Preserve access time */
+#ifdef __linux__
+        struct stat sb;
+
+        if (stat(path, &sb) == 0) {
+
+        tv[0].tv_sec = sb.st_atime;
+        tv[0].tv_usec = 0;
+        }
+#else
+        tv[0].tv_sec = ts.tv_sec;
+        tv[0].tv_usec = ts.tv_nsec / 1000;
+#endif
+
+        /* Change last-modified time */
+        tv[1].tv_sec = time / 1000;
+        tv[1].tv_usec = (time % 1000) * 1000;
+
+        if (utimes(path, tv) >= 0)
+            rv = JNI_TRUE;
+
+    error: ;
+    } END_PLATFORM_STRING(env, path);
+
+    return rv;
+}
+
+
+JNIEXPORT jboolean JNICALL
+Java_java_io_UnixFileSystem_setReadOnly(JNIEnv *env, jobject this,
+                                        jobject file)
+{
+    jboolean rv = JNI_FALSE;
+
+    WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
+        int mode;
+        if (statMode(path, &mode)) {
+            if (chmod(path, mode & ~(S_IWUSR | S_IWGRP | S_IWOTH)) >= 0) {
+                rv = JNI_TRUE;
+            }
+        }
+    } END_PLATFORM_STRING(env, path);
+    return rv;
+}
+
+JNIEXPORT jlong JNICALL
+Java_java_io_UnixFileSystem_getSpace(JNIEnv *env, jobject this,
+                                     jobject file, jint t)
+{
+    jlong rv = 0L;
+
+    WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
+        struct statvfs fsstat;
+        memset(&fsstat, 0, sizeof(struct statvfs));
+        if (statvfs(path, &fsstat) == 0) {
+            switch(t) {
+            case java_io_FileSystem_SPACE_TOTAL:
+                rv = jlong_mul(long_to_jlong(fsstat.f_frsize),
+                               long_to_jlong(fsstat.f_blocks));
+                break;
+            case java_io_FileSystem_SPACE_FREE:
+                rv = jlong_mul(long_to_jlong(fsstat.f_frsize),
+                               long_to_jlong(fsstat.f_bfree));
+                break;
+            case java_io_FileSystem_SPACE_USABLE:
+                rv = jlong_mul(long_to_jlong(fsstat.f_frsize),
+                               long_to_jlong(fsstat.f_bavail));
+                break;
+            default:
+                assert(0);
+            }
+        }
+    } END_PLATFORM_STRING(env, path);
+    return rv;
+}