diff options
author | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
---|---|---|
committer | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
commit | 554fd8c5195424bdbcabf5de30fdc183aba391bd (patch) | |
tree | 976dc5ab7fddf506dadce60ae936f43f58787092 /libjava/classpath/native/jni/java-io/java_io_VMFile.c | |
download | cbb-gcc-4.6.4-upstream.tar.bz2 cbb-gcc-4.6.4-upstream.tar.xz |
obtained gcc-4.6.4.tar.bz2 from upstream website;upstream
verified gcc-4.6.4.tar.bz2.sig;
imported gcc-4.6.4 source tree from verified upstream tarball.
downloading a git-generated archive based on the 'upstream' tag
should provide you with a source tree that is binary identical
to the one extracted from the above tarball.
if you have obtained the source via the command 'git clone',
however, do note that line-endings of files in your working
directory might differ from line-endings of the respective
files in the upstream repository.
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.c | 1214 |
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 */ +} |