summaryrefslogtreecommitdiff
path: root/libjava/classpath/native/jni/java-io/java_io_VMFile.c
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/classpath/native/jni/java-io/java_io_VMFile.c')
-rw-r--r--libjava/classpath/native/jni/java-io/java_io_VMFile.c1214
1 files changed, 1214 insertions, 0 deletions
diff --git a/libjava/classpath/native/jni/java-io/java_io_VMFile.c b/libjava/classpath/native/jni/java-io/java_io_VMFile.c
new file mode 100644
index 000000000..a15cec769
--- /dev/null
+++ b/libjava/classpath/native/jni/java-io/java_io_VMFile.c
@@ -0,0 +1,1214 @@
+/* java_io_VMFile.c - Native methods for java.io.File class
+ Copyright (C) 1998, 2004, 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+/* do not move; needed here because of some macro definitions */
+#include <config.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#if defined (HAVE_LSTAT) && defined (HAVE_READLINK)
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#endif
+
+#include <jni.h>
+#include <jcl.h>
+#include "cpio.h"
+#include "cpnative.h"
+
+#include "java_io_VMFile.h"
+
+/* ***** PRIVATE FUNCTIONS DELCARATION ***** */
+
+/**
+ * Enables of disables the passed permission bit of a file.
+ */
+static jboolean set_file_permissions (JNIEnv *env, jstring name,
+ jboolean enable,
+ jboolean ownerOnly,
+ int permissions);
+
+/* ***** END: PRIVATE FUNCTIONS DELCARATION ***** */
+
+/*************************************************************************/
+
+/*
+ * Method to create an empty file.
+ *
+ * Class: java_io_VMFile
+ * Method: create
+ * Signature: (Ljava/lang/String;)Z
+ */
+
+JNIEXPORT jboolean JNICALL
+Java_java_io_VMFile_create (JNIEnv * env,
+ jclass clazz __attribute__ ((__unused__)),
+ jstring name)
+{
+#ifndef WITHOUT_FILESYSTEM
+ const char *filename;
+ int fd;
+ int result;
+
+ filename = JCL_jstring_to_cstring (env, name);
+ if (filename == NULL)
+ {
+ return 0;
+ }
+
+ result = cpio_openFile (filename, &fd, CPFILE_FLAG_CREATE|CPFILE_FLAG_WRITE, CPFILE_PERMISSION_NORMAL);
+ if (result != CPNATIVE_OK)
+ {
+ if (result != EEXIST)
+ JCL_ThrowException (env,
+ "java/io/IOException",
+ cpnative_getErrorString (result));
+ JCL_free_cstring (env, name, filename);
+ return 0;
+ }
+ cpio_closeFile (fd);
+
+ JCL_free_cstring (env, name, filename);
+ return 1;
+#else /* not WITHOUT_FILESYSTEM */
+ return 0;
+#endif /* not WITHOUT_FILESYSTEM */
+}
+
+/*************************************************************************/
+
+/*
+ * This method checks to see if we have read permission on a file.
+ *
+ * Class: java_io_VMFile
+ * Method: canRead
+ * Signature: (Ljava/lang/String;)Z
+ */
+
+JNIEXPORT jboolean JNICALL
+Java_java_io_VMFile_canRead (JNIEnv * env,
+ jclass clazz __attribute__ ((__unused__)),
+ jstring name)
+{
+#ifndef WITHOUT_FILESYSTEM
+ const char *filename;
+ int result;
+
+ /* Don't use the JCL convert function because it throws an exception
+ on failure */
+ filename = (*env)->GetStringUTFChars (env, name, 0);
+ if (filename == NULL)
+ {
+ return JNI_FALSE;
+ }
+
+ result = cpio_checkAccess (filename, CPFILE_FLAG_READ);
+
+ (*env)->ReleaseStringUTFChars (env, name, filename);
+ if (result != CPNATIVE_OK)
+ return JNI_FALSE;
+
+ return JNI_TRUE;
+#else /* not WITHOUT_FILESYSTEM */
+ return JNI_FALSE;
+#endif /* not WITHOUT_FILESYSTEM */
+}
+
+/*************************************************************************/
+
+/*
+ * This method checks to see if we have write permission on a file.
+ *
+ * Class: java_io_VMFile
+ * Method: canWrite
+ * Signature: (Ljava/lang/String;)Z
+ */
+
+JNIEXPORT jboolean JNICALL
+Java_java_io_VMFile_canWrite (JNIEnv * env,
+ jclass clazz __attribute__ ((__unused__)),
+ jstring name)
+{
+#ifndef WITHOUT_FILESYSTEM
+ const char *filename;
+ int result;
+
+ /* Don't use the JCL convert function because it throws an exception
+ on failure */
+ filename = (*env)->GetStringUTFChars (env, name, 0);
+ if (filename == NULL)
+ {
+ return JNI_FALSE;
+ }
+
+ result = cpio_checkAccess (filename, CPFILE_FLAG_WRITE);
+
+ (*env)->ReleaseStringUTFChars (env, name, filename);
+ if (result != CPNATIVE_OK)
+ {
+ return JNI_FALSE;
+ }
+
+ return JNI_TRUE;
+#else /* not WITHOUT_FILESYSTEM */
+ return JNI_FALSE;
+#endif /* not WITHOUT_FILESYSTEM */
+}
+
+/*************************************************************************/
+
+JNIEXPORT jboolean JNICALL
+Java_java_io_VMFile_canWriteDirectory (JNIEnv *env, jclass clazz, jstring path)
+{
+ /* this is only valid on *nix systems */
+ return Java_java_io_VMFile_canWrite(env, clazz, path);
+}
+
+/*************************************************************************/
+
+/*
+ * This method checks to see if we have execute permission on a file.
+ *
+ * Class: java_io_VMFile
+ * Method: canExecute
+ * Signature: (Ljava/lang/String;)Z
+ */
+
+JNIEXPORT jboolean JNICALL
+Java_java_io_VMFile_canExecute (JNIEnv * env,
+ jclass clazz __attribute__ ((__unused__)),
+ jstring name)
+{
+#ifndef WITHOUT_FILESYSTEM
+ const char *filename;
+ int result;
+
+ /* Don't use the JCL convert function because it throws an exception
+ on failure */
+ filename = (*env)->GetStringUTFChars (env, name, 0);
+ if (filename == NULL)
+ {
+ return JNI_FALSE;
+ }
+
+ result = cpio_checkAccess (filename, CPFILE_FLAG_EXEC);
+
+ (*env)->ReleaseStringUTFChars (env, name, filename);
+ if (result != CPNATIVE_OK)
+ return JNI_FALSE;
+
+ return JNI_TRUE;
+#else /* not WITHOUT_FILESYSTEM */
+ return JNI_FALSE;
+#endif /* not WITHOUT_FILESYSTEM */
+}
+
+
+/*************************************************************************/
+
+/*
+ * This method makes a file read only.
+ *
+ * Class: java_io_VMFile
+ * Method: setReadOnly
+ * Signature: (Ljava/lang/String;)Z
+ */
+
+JNIEXPORT jboolean JNICALL
+Java_java_io_VMFile_setReadOnly (JNIEnv * env,
+ jclass clazz __attribute__ ((__unused__)),
+ jstring name)
+{
+#ifndef WITHOUT_FILESYSTEM
+ const char *filename;
+ int result;
+
+ /* Don't use the JCL convert function because it throws an exception
+ on failure */
+ filename = (*env)->GetStringUTFChars (env, name, 0);
+ if (filename == NULL)
+ {
+ return 0;
+ }
+
+ result = cpio_setFileReadonly (filename);
+ (*env)->ReleaseStringUTFChars (env, name, filename);
+
+ return result == CPNATIVE_OK ? 1 : 0;
+#else /* not WITHOUT_FILESYSTEM */
+ return 0;
+#endif /* not WITHOUT_FILESYSTEM */
+}
+
+/*************************************************************************/
+
+/*
+ * This method changes the read permission bit of a file.
+ *
+ * Class: java_io_VMFile
+ * Method: setReadable
+ * Signature: (Ljava/lang/String;ZZ)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_java_io_VMFile_setReadable (JNIEnv *env,
+ jclass clazz __attribute__ ((__unused__)),
+ jstring name,
+ jboolean readable,
+ jboolean ownerOnly)
+{
+ return set_file_permissions (env, name, readable, ownerOnly,
+ CPFILE_FLAG_READ);
+}
+
+
+/*************************************************************************/
+
+/*
+ * This method changes the write permission bit of a file.
+ *
+ * Class: java_io_VMFile
+ * Method: setWritable
+ * Signature: (Ljava/lang/String;ZZ)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_java_io_VMFile_setWritable (JNIEnv *env,
+ jclass clazz __attribute__ ((__unused__)),
+ jstring name,
+ jboolean writable,
+ jboolean ownerOnly)
+{
+ return set_file_permissions (env, name, writable, ownerOnly,
+ CPFILE_FLAG_WRITE);
+}
+
+/*************************************************************************/
+
+/*
+ * This method changes the execute permission bit of a file.
+ *
+ * Class: java_io_VMFile
+ * Method: setExecutable
+ * Signature: (Ljava/lang/String;ZZ)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_java_io_VMFile_setExecutable (JNIEnv *env,
+ jclass clazz __attribute__ ((__unused__)),
+ jstring name,
+ jboolean executable,
+ jboolean ownerOnly)
+{
+ return set_file_permissions (env, name, executable, ownerOnly,
+ CPFILE_FLAG_EXEC);
+}
+
+/*************************************************************************/
+
+JNIEXPORT jlong JNICALL
+Java_java_io_VMFile_getTotalSpace (JNIEnv *env,
+ jclass clazz __attribute__ ((__unused__)),
+ jstring path)
+{
+#ifndef WITHOUT_FILESYSTEM
+
+ jlong result;
+ const char *_path = NULL;
+
+ _path = (*env)->GetStringUTFChars (env, path, 0);
+ if (_path == NULL)
+ {
+ return 0L;
+ }
+
+ result = cpio_df (_path, TOTAL);
+
+ (*env)->ReleaseStringUTFChars (env, path, _path);
+
+ return result;
+
+#else /* not WITHOUT_FILESYSTEM */
+ return 0L;
+#endif /* not WITHOUT_FILESYSTEM */
+}
+
+/*************************************************************************/
+
+JNIEXPORT jlong JNICALL
+Java_java_io_VMFile_getFreeSpace (JNIEnv *env,
+ jclass clazz __attribute__ ((__unused__)),
+ jstring path)
+{
+#ifndef WITHOUT_FILESYSTEM
+
+ jlong result;
+ const char *_path = NULL;
+
+ _path = (*env)->GetStringUTFChars (env, path, 0);
+ if (_path == NULL)
+ {
+ return 0L;
+ }
+
+ result = cpio_df (_path, FREE);
+
+ (*env)->ReleaseStringUTFChars (env, path, _path);
+
+ return result;
+
+#else /* not WITHOUT_FILESYSTEM */
+ return 0L;
+#endif /* not WITHOUT_FILESYSTEM */
+}
+
+/*************************************************************************/
+
+JNIEXPORT jlong JNICALL
+Java_java_io_VMFile_getUsableSpace (JNIEnv *env,
+ jclass clazz __attribute__ ((__unused__)),
+ jstring path)
+{
+#ifndef WITHOUT_FILESYSTEM
+
+ jlong result;
+ const char *_path = NULL;
+
+ _path = (*env)->GetStringUTFChars (env, path, 0);
+ if (_path == NULL)
+ {
+ return 0L;
+ }
+
+ result = cpio_df (_path, USABLE);
+
+ (*env)->ReleaseStringUTFChars (env, path, _path);
+
+ return result;
+
+#else /* not WITHOUT_FILESYSTEM */
+ return 0L;
+#endif /* not WITHOUT_FILESYSTEM */
+}
+
+/*************************************************************************/
+
+/*
+ * This method checks to see if a file exists.
+ *
+ * Class: java_io_VMFile
+ * Method: exists
+ * Signature: (Ljava/lang/String;)Z
+ */
+
+JNIEXPORT jboolean JNICALL
+Java_java_io_VMFile_exists (JNIEnv * env,
+ jclass clazz __attribute__ ((__unused__)),
+ jstring name)
+{
+#ifndef WITHOUT_FILESYSTEM
+ const char *filename;
+ int result;
+
+ /* Don't use the JCL convert function because it throws an exception
+ on failure */
+ filename = (*env)->GetStringUTFChars (env, name, 0);
+ if (filename == NULL)
+ {
+ return 0;
+ }
+
+ result = cpio_isFileExists (filename);
+ (*env)->ReleaseStringUTFChars (env, name, filename);
+
+ return result == CPNATIVE_OK ? 1 : 0;
+#else /* not WITHOUT_FILESYSTEM */
+ return 0;
+#endif /* not WITHOUT_FILESYSTEM */
+}
+
+/*************************************************************************/
+
+/*
+ * This method checks to see if a file is a "plain" file; that is, not
+ * a directory, pipe, etc.
+ *
+ * Class: java_io_VMFile
+ * Method: isFile
+ * Signature: (Ljava/lang/String;)Z
+ */
+
+JNIEXPORT jboolean JNICALL
+Java_java_io_VMFile_isFile (JNIEnv * env,
+ jclass clazz __attribute__ ((__unused__)),
+ jstring name)
+{
+#ifndef WITHOUT_FILESYSTEM
+ const char *filename;
+ int result;
+ jint entryType;
+
+ /* Don't use the JCL convert function because it throws an exception
+ on failure */
+ filename = (*env)->GetStringUTFChars (env, name, 0);
+ if (filename == NULL)
+ {
+ return 0;
+ }
+
+ result = cpio_checkType (filename, &entryType);
+ (*env)->ReleaseStringUTFChars (env, name, filename);
+
+ return result == CPNATIVE_OK && entryType == CPFILE_FILE ? 1 : 0;
+#else /* not WITHOUT_FILESYSTEM */
+ return 0;
+#endif /* not WITHOUT_FILESYSTEM */
+}
+
+/*************************************************************************/
+
+/*
+ * This method checks to see if a file is a directory or not.
+ *
+ * Class: java_io_VMFile
+ * Method: isDirectory
+ * Signature: (Ljava/lang/String;)Z
+ */
+
+JNIEXPORT jboolean JNICALL
+Java_java_io_VMFile_isDirectory (JNIEnv * env,
+ jclass clazz __attribute__ ((__unused__)),
+ jstring name)
+{
+#ifndef WITHOUT_FILESYSTEM
+ const char *filename;
+ int result;
+ jint entryType;
+
+ /* Don't use the JCL convert function because it throws an exception
+ on failure */
+ filename = (*env)->GetStringUTFChars (env, name, 0);
+ if (filename == NULL)
+ {
+ return 0;
+ }
+
+ result = cpio_checkType (filename, &entryType);
+ (*env)->ReleaseStringUTFChars (env, name, filename);
+
+ return result == CPNATIVE_OK && entryType == CPFILE_DIRECTORY ? 1 : 0;
+#else /* not WITHOUT_FILESYSTEM */
+ return 0;
+#endif /* not WITHOUT_FILESYSTEM */
+}
+
+/*************************************************************************/
+
+/*
+ * This method returns the length of the file.
+ *
+ * Class: java_io_VMFile
+ * Method: length
+ * Signature: (Ljava/lang/String;)J
+ */
+
+JNIEXPORT jlong JNICALL
+Java_java_io_VMFile_length (JNIEnv * env,
+ jclass clazz __attribute__ ((__unused__)),
+ jstring name)
+{
+#ifndef WITHOUT_FILESYSTEM
+ const char *filename;
+ int tmpfd;
+ jlong length;
+ int result;
+
+ /* Don't use the JCL convert function because it throws an exception
+ on failure */
+ filename = (*env)->GetStringUTFChars (env, name, 0);
+ if (filename == NULL)
+ return 0;
+
+ /* open file for reading, get size and close file */
+ result = cpio_openFile (filename, &tmpfd, CPFILE_FLAG_READ, 0);
+ if (result != CPNATIVE_OK)
+ return 0;
+
+ result = cpio_getFileSize (tmpfd, &length);
+ if (result != CPNATIVE_OK)
+ {
+ cpio_closeFile (tmpfd);
+ return 0;
+ }
+
+ result = cpio_closeFile (tmpfd);
+ (*env)->ReleaseStringUTFChars (env, name, filename);
+
+ return result == CPNATIVE_OK ? length : 0;
+#else /* not WITHOUT_FILESYSTEM */
+ return 0;
+#endif /* not WITHOUT_FILESYSTEM */
+}
+
+/*************************************************************************/
+
+/*
+ * This method returns the modification date of the file.
+ *
+ * Class: java_io_VMFile
+ * Method: lastModified
+ * Signature: (Ljava/lang/String;)J
+ */
+
+JNIEXPORT jlong JNICALL
+Java_java_io_VMFile_lastModified (JNIEnv * env,
+ jclass clazz __attribute__ ((__unused__)),
+ jstring name)
+{
+#ifndef WITHOUT_FILESYSTEM
+ const char *filename;
+ jlong mtime;
+ int result;
+
+ /* Don't use the JCL convert function because it throws an exception
+ on failure */
+ filename = (*env)->GetStringUTFChars (env, name, 0);
+ if (filename == NULL)
+ {
+ return 0;
+ }
+
+ result = cpio_getModificationTime (filename, &mtime);
+ (*env)->ReleaseStringUTFChars (env, name, filename);
+
+ return result == CPNATIVE_OK ? mtime : 0;
+#else /* not WITHOUT_FILESYSTEM */
+ return 0;
+#endif /* not WITHOUT_FILESYSTEM */
+}
+
+/*************************************************************************/
+
+/*
+ * This method sets the modification date of the file.
+ *
+ * Class: java_io_VMFile
+ * Method: setLastModified
+ * Signature: (Ljava/lang/String;J)Z
+ */
+
+JNIEXPORT jboolean JNICALL
+Java_java_io_VMFile_setLastModified (JNIEnv * env,
+ jclass clazz __attribute__ ((__unused__)),
+ jstring name, jlong newtime)
+{
+#ifndef WITHOUT_FILESYSTEM
+ const char *filename;
+ int result;
+
+ /* Don't use the JCL convert function because it throws an exception
+ on failure */
+ filename = (*env)->GetStringUTFChars (env, name, 0);
+ if (filename == NULL)
+ {
+ return 0;
+ }
+
+ result = cpio_setModificationTime (filename, newtime);
+ (*env)->ReleaseStringUTFChars (env, name, filename);
+
+ return result == CPNATIVE_OK ? 1 : 0;
+#else /* not WITHOUT_FILESYSTEM */
+ return 0;
+#endif /* not WITHOUT_FILESYSTEM */
+}
+
+/*************************************************************************/
+
+/*
+ * This method deletes a file (actually a name for a file - additional
+ * links could exist).
+ *
+ * Class: java_io_VMFile
+ * Method: delete
+ * Signature: (Ljava/lang/String;)Z
+ */
+
+JNIEXPORT jboolean JNICALL
+Java_java_io_VMFile_delete (JNIEnv * env,
+ jclass clazz __attribute__ ((__unused__)),
+ jstring name)
+{
+#ifndef WITHOUT_FILESYSTEM
+ const char *filename;
+ int result;
+
+ /* Don't use the JCL convert function because it throws an exception
+ on failure */
+ filename = (*env)->GetStringUTFChars (env, name, 0);
+ if (filename == NULL)
+ {
+ return 0;
+ }
+
+ result = cpio_removeFile (filename);
+ (*env)->ReleaseStringUTFChars (env, name, filename);
+
+ return result == CPNATIVE_OK ? 1 : 0;
+#else /* not WITHOUT_FILESYSTEM */
+ return 0;
+#endif /* not WITHOUT_FILESYSTEM */
+}
+
+/*************************************************************************/
+
+/*
+ * This method creates a directory.
+ *
+ * Class: java_io_VMFile
+ * Method: mkdir
+ * Signature: (Ljava/lang/String;)Z
+ */
+
+JNIEXPORT jboolean JNICALL
+Java_java_io_VMFile_mkdir (JNIEnv * env,
+ jclass clazz __attribute__ ((__unused__)),
+ jstring name)
+{
+#ifndef WITHOUT_FILESYSTEM
+ const char *pathname;
+ int result;
+
+ /* Don't use the JCL convert function because it throws an exception
+ on failure */
+ pathname = (*env)->GetStringUTFChars (env, name, 0);
+ if (pathname == NULL)
+ {
+ return 0;
+ }
+
+ result = cpio_mkdir (pathname);
+ (*env)->ReleaseStringUTFChars (env, name, pathname);
+
+ return (result == CPNATIVE_OK) ? 1 : 0;
+#else /* not WITHOUT_FILESYSTEM */
+ return 0;
+#endif /* not WITHOUT_FILESYSTEM */
+}
+
+/*************************************************************************/
+
+/*
+ * This method renames a (link to a) file.
+ *
+ * Class: java_io_VMFile
+ * Method: renameTo
+ * Signature: (Ljava/lang/String;Ljava/lang/String;)Z
+ */
+
+JNIEXPORT jboolean JNICALL
+Java_java_io_VMFile_renameTo (JNIEnv * env,
+ jclass clazz __attribute__ ((__unused__)),
+ jstring t, jstring d)
+{
+#ifndef WITHOUT_FILESYSTEM
+ const char *old_filename, *new_filename;
+ int result;
+
+ /* Don't use the JCL convert function because it throws an exception
+ on failure */
+ old_filename = (*env)->GetStringUTFChars (env, t, 0);
+ if (old_filename == NULL)
+ {
+ return 0;
+ }
+
+ new_filename = (*env)->GetStringUTFChars (env, d, 0);
+ if (new_filename == NULL)
+ {
+ (*env)->ReleaseStringUTFChars (env, t, old_filename);
+ return 0;
+ }
+
+ result = cpio_rename (old_filename, new_filename);
+ (*env)->ReleaseStringUTFChars (env, d, new_filename);
+ (*env)->ReleaseStringUTFChars (env, t, old_filename);
+
+ return (result == CPNATIVE_OK) ? 1 : 0;
+#else /* not WITHOUT_FILESYSTEM */
+ return 0;
+#endif /* not WITHOUT_FILESYSTEM */
+}
+
+/*************************************************************************/
+
+/*
+ * This method returns an array of String representing all the files
+ * in a directory except "." and "..".
+ *
+ * Class: java_io_VMFile
+ * Method: list
+ * Signature: (Ljava/lang/String;)[Ljava/lang/String;
+ */
+
+JNIEXPORT jobjectArray JNICALL
+Java_java_io_VMFile_list (JNIEnv * env,
+ jclass clazz __attribute__ ((__unused__)),
+ jstring name)
+{
+#ifndef WITHOUT_FILESYSTEM
+ const int REALLOC_SIZE = 10;
+
+ const char *dirname;
+ int result;
+ char **filelist;
+ void *handle;
+ char *filename = (char *) JCL_malloc (env, FILENAME_MAX);
+ unsigned long int filelist_count, max_filelist_count;
+ char **tmp_filelist;
+ jclass str_clazz;
+ jobjectArray filearray;
+ unsigned long int i;
+ jstring str;
+
+ /* Don't use the JCL convert function because it throws an exception
+ on failure */
+ dirname = (*env)->GetStringUTFChars (env, name, 0);
+ if (dirname == NULL)
+ {
+ return 0;
+ }
+
+ /* open directory for reading */
+ result = cpio_openDir (dirname, &handle);
+
+ (*env)->ReleaseStringUTFChars (env, name, dirname);
+
+ if (result != CPNATIVE_OK)
+ {
+ return 0;
+ }
+
+ /* allocate filelist */
+ filelist = (char **) JCL_malloc (env, sizeof (char *) * REALLOC_SIZE);
+ if (filelist == NULL)
+ {
+ result = cpio_closeDir (handle);
+ return 0;
+ }
+ filelist_count = 0;
+ max_filelist_count = REALLOC_SIZE;
+
+ /* read the files from the directory */
+ result = cpio_readDir (handle, filename);
+ while (result == CPNATIVE_OK)
+ {
+ if ((strcmp (filename, ".") != 0) && (strcmp (filename, "..") != 0))
+ {
+ /* allocate more memory if necessary */
+ if (filelist_count >= max_filelist_count)
+ {
+ tmp_filelist = (char **) JCL_realloc (env,
+ filelist,
+ (max_filelist_count +
+ REALLOC_SIZE) *
+ sizeof (char *));
+ if (tmp_filelist == NULL)
+ {
+ for (i = 0; i < filelist_count; i++)
+ {
+ JCL_free (env, filelist[i]);
+ }
+ JCL_free (env, filelist);
+ result = cpio_closeDir (handle);
+ return 0;
+ }
+ filelist = tmp_filelist;
+ max_filelist_count += REALLOC_SIZE;
+ }
+
+ /* save entry in list (avoid strdup, because it is not ANSI C, thus difficult to port) */
+ filelist[filelist_count] =
+ (char *) JCL_malloc (env, strlen (filename) + 1);
+ assert (filelist[filelist_count] != NULL);
+ strcpy (filelist[filelist_count], filename);
+ filelist_count++;
+ }
+
+ /* read next directory entry */
+ result = cpio_readDir (handle, filename);
+ }
+
+ JCL_free (env, filename);
+
+ /* close directory */
+ result = cpio_closeDir (handle);
+
+ /* put the list of files into a Java String array and return it */
+ str_clazz = (*env)->FindClass (env, "java/lang/String");
+ if (str_clazz == NULL)
+ {
+ for (i = 0; i < filelist_count; i++)
+ {
+ JCL_free (env, filelist[i]);
+ }
+ JCL_free (env, filelist);
+ return 0;
+ }
+ filearray = (*env)->NewObjectArray (env, filelist_count, str_clazz, 0);
+ if (filearray == NULL)
+ {
+ for (i = 0; i < filelist_count; i++)
+ {
+ JCL_free (env, filelist[i]);
+ }
+ JCL_free (env, filelist);
+ return 0;
+ }
+
+ (*env)->DeleteLocalRef (env, str_clazz);
+
+ for (i = 0; i < filelist_count; i++)
+ {
+ /* create new string */
+ str = (*env)->NewStringUTF (env, filelist[i]);
+ if (str == NULL)
+ {
+ /* We don't clean up everything here, but if this failed,
+ something serious happened anyway */
+ for (i = 0; i < filelist_count; i++)
+ {
+ JCL_free (env, filelist[i]);
+ }
+ JCL_free (env, filelist);
+ return 0;
+ }
+
+ /* save into array */
+ (*env)->SetObjectArrayElement (env, filearray, i, str);
+
+ /* delete local reference */
+ (*env)->DeleteLocalRef (env, str);
+ }
+
+ /* free resources */
+ for (i = 0; i < filelist_count; i++)
+ {
+ JCL_free (env, filelist[i]);
+ }
+ JCL_free (env, filelist);
+
+ return filearray;
+#else /* not WITHOUT_FILESYSTEM */
+ return 0;
+#endif /* not WITHOUT_FILESYSTEM */
+}
+
+/*************************************************************************/
+
+/*
+ * These two methods are used to maintain dynamically allocated
+ * buffers for getCanonicalPath without the overhead of calling
+ * realloc every time a buffer is modified. Buffers are sized
+ * at the smallest multiple of CHUNKSIZ that is greater than or
+ * equal to the desired length. The default CHUNKSIZ is 256,
+ * longer than most paths, so in most cases a getCanonicalPath
+ * will require only one malloc per buffer.
+ */
+
+#define CHUNKLOG 8
+#define CHUNKSIZ (1 << CHUNKLOG)
+
+static int
+nextChunkSize (int size)
+{
+ return ((size >> CHUNKLOG) + ((size & (CHUNKSIZ - 1)) ? 1 : 0)) << CHUNKLOG;
+}
+
+static char *
+maybeGrowBuf (JNIEnv *env, char *buf, int *size, int required)
+{
+ if (required > *size)
+ {
+ *size = nextChunkSize (required);
+ buf = JCL_realloc (env, buf, *size);
+ }
+ return buf;
+}
+
+/*************************************************************************/
+
+/*
+ * This method converts a path to canonical form on GNU/Posix systems.
+ * This involves the removal of redundant separators, references to
+ * "." and "..", and symbolic links.
+ *
+ * The conversion proceeds on a component-by-component basis: symbolic
+ * links and references to ".." are resolved as and when they occur.
+ * This means that if "/foo/bar" is a symbolic link to "/baz" then the
+ * canonical form of "/foo/bar/.." is "/" and not "/foo".
+ *
+ * In order to mimic the behaviour of proprietary JVMs, non-existant
+ * path components are allowed (a departure from the normal GNU system
+ * convention). This means that if "/foo/bar" is a symbolic link to
+ * "/baz", the canonical form of "/non-existant-directory/../foo/bar"
+ * is "/baz".
+ *
+ * Class: java_io_VMFile
+ * Method: toCanonicalForm
+ * Signature: (Ljava/lang/String)Ljava/lang/String
+ */
+
+JNIEXPORT jstring JNICALL
+Java_java_io_VMFile_toCanonicalForm (JNIEnv *env,
+ jclass class __attribute__ ((__unused__)),
+ jstring jpath)
+{
+#ifndef WITHOUT_FILESYSTEM
+ const char *path;
+ char *src, *dst;
+ int srci, dsti;
+ int srcl, dstl;
+ int len;
+ int fschecks;
+#if defined (HAVE_LSTAT) && defined (HAVE_READLINK)
+ struct stat sb;
+#endif /* HAVE_LSTAT && HAVE_READLINK */
+
+ path = JCL_jstring_to_cstring (env, jpath);
+ if (path == NULL)
+ return NULL;
+
+ /* It is the caller's responsibility to ensure the path is absolute. */
+ if (path[0] == 0 || path[0] != '/')
+ {
+ JCL_free_cstring (env, jpath, path);
+ JCL_ThrowException (env, "java/lang/RuntimeException", "Not absolute");
+ return NULL;
+ }
+
+ len = strlen (path);
+ srcl = nextChunkSize (len + 1);
+ src = JCL_malloc (env, srcl);
+ if (src == NULL)
+ {
+ JCL_free_cstring (env, jpath, path);
+ return NULL;
+ }
+ strcpy (src, path);
+ JCL_free_cstring (env, jpath, path);
+ srci = 1;
+
+ dstl = nextChunkSize (2);
+ dst = JCL_malloc (env, dstl);
+ if (dst == NULL)
+ {
+ JCL_free (env, src);
+ return NULL;
+ }
+ dst[0] = '/';
+ dsti = 1;
+
+ fschecks = JNI_TRUE;
+
+ while (src[srci] != '\0')
+ {
+ int tmpi, dsti_save;
+
+ /* Skip slashes. */
+ while (src[srci] == '/')
+ srci++;
+ tmpi = srci;
+ /* Find next slash. */
+ while (src[srci] != '/' && src[srci] != '\0')
+ srci++;
+ if (srci == tmpi)
+ /* We hit the end. */
+ break;
+ len = srci - tmpi;
+
+ /* Handle "." and "..". */
+ if (len == 1 && src[tmpi] == '.')
+ continue;
+ if (len == 2 && src[tmpi] == '.' && src[tmpi + 1] == '.')
+ {
+ while (dsti > 1 && dst[dsti - 1] != '/')
+ dsti--;
+ if (dsti != 1)
+ dsti--;
+ /* Reenable filesystem checking if disabled, as we might
+ * have reversed over whatever caused the problem before.
+ * At least one proprietary JVM has inconsistencies because
+ * it does not do this.
+ */
+ fschecks = JNI_TRUE;
+ continue;
+ }
+
+ /* Handle real path components. */
+ dst = maybeGrowBuf (env,
+ dst, &dstl, dsti + (dsti > 1 ? 1 : 0) + len + 1);
+ if (dst == NULL)
+ {
+ JCL_free (env, src);
+ return NULL;
+ }
+ dsti_save = dsti;
+ if (dsti > 1)
+ dst[dsti++] = '/';
+ strncpy (&dst[dsti], &src[tmpi], len);
+ dsti += len;
+ if (fschecks == JNI_FALSE)
+ continue;
+
+#if defined (HAVE_LSTAT) && defined (HAVE_READLINK)
+ dst[dsti] = '\0';
+ if (lstat (dst, &sb) == 0)
+ {
+ if (S_ISLNK (sb.st_mode))
+ {
+ int tmpl = CHUNKSIZ;
+ char *tmp = JCL_malloc (env, tmpl);
+ if (tmp == NULL)
+ {
+ JCL_free (env, src);
+ JCL_free (env, dst);
+ return NULL;
+ }
+
+ while (1)
+ {
+ tmpi = readlink (dst, tmp, tmpl);
+ if (tmpi < 1)
+ {
+ JCL_free (env, src);
+ JCL_free (env, dst);
+ JCL_free (env, tmp);
+ JCL_ThrowException (env, "java/io/IOException",
+ "readlink failed");
+ return NULL;
+ }
+ if (tmpi < tmpl)
+ break;
+ tmpl += CHUNKSIZ;
+ tmp = JCL_realloc (env, tmp, tmpl);
+ }
+
+ /* Prepend the link's path to src. */
+ tmp = maybeGrowBuf (env,
+ tmp, &tmpl, tmpi + strlen (&src[srci]) + 1);
+ if (tmp == NULL)
+ {
+ JCL_free (env, src);
+ JCL_free (env, dst);
+ return NULL;
+ }
+
+ strcpy (&tmp[tmpi], &src[srci]);
+ JCL_free (env, src);
+ src = tmp;
+ srcl = tmpl;
+ srci = 0;
+
+ /* Either replace or append dst depending on whether the
+ * link is relative or absolute.
+ */
+ dsti = src[0] == '/' ? 1 : dsti_save;
+ }
+ }
+ else
+ {
+ /* Something doesn't exist, or we don't have permission to
+ * read it, or a previous path component is a directory, or
+ * a symlink is looped. Whatever, we can't check the
+ * filesystem any more.
+ */
+ fschecks = JNI_FALSE;
+ }
+#endif /* HAVE_LSTAT && HAVE_READLINK */
+ }
+ dst[dsti] = '\0';
+
+ jpath = (*env)->NewStringUTF (env, dst);
+ JCL_free (env, src);
+ JCL_free (env, dst);
+ return jpath;
+#else /* not WITHOUT_FILESYSTEM */
+ return NULL;
+#endif /* not WITHOUT_FILESYSTEM */
+}
+
+/*************************************************************************/
+
+/* ***** PRIVATE FUNCTIONS IMPLEMENTATION ***** */
+
+static jboolean set_file_permissions (JNIEnv *env, jstring name,
+ jboolean enable,
+ jboolean ownerOnly,
+ int permissions)
+{
+#ifndef WITHOUT_FILESYSTEM
+ const char *filename;
+ int result = JNI_FALSE;
+
+ /* Don't use the JCL convert function because it throws an exception
+ on failure */
+ filename = (*env)->GetStringUTFChars (env, name, 0);
+ if (filename == NULL)
+ {
+ return JNI_FALSE;
+ }
+
+ if (ownerOnly)
+ {
+ permissions |= CPFILE_FLAG_USR;
+ }
+
+ if (!enable)
+ {
+ permissions |= CPFILE_FLAG_OFF;
+ }
+
+ result = cpio_chmod (filename, permissions);
+ (*env)->ReleaseStringUTFChars (env, name, filename);
+
+ return result == CPNATIVE_OK ? JNI_TRUE : JNI_FALSE;
+
+#else /* not WITHOUT_FILESYSTEM */
+ return JNI_FALSE;
+#endif /* not WITHOUT_FILESYSTEM */
+}