libjava/ChangeLog:
[official-gcc.git] / libjava / classpath / native / jni / java-io / java_io_VMFile.c
bloba15cec769eee8dc4171995dfdaeaed0bfc8d9c1c
1 /* java_io_VMFile.c - Native methods for java.io.File class
2 Copyright (C) 1998, 2004, 2006 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
38 /* do not move; needed here because of some macro definitions */
39 #include <config.h>
41 #include <assert.h>
42 #include <stdio.h>
43 #include <stdlib.h>
45 #if defined (HAVE_LSTAT) && defined (HAVE_READLINK)
46 #include <sys/types.h>
47 #include <sys/stat.h>
48 #include <unistd.h>
49 #endif
51 #include <jni.h>
52 #include <jcl.h>
53 #include "cpio.h"
54 #include "cpnative.h"
56 #include "java_io_VMFile.h"
58 /* ***** PRIVATE FUNCTIONS DELCARATION ***** */
60 /**
61 * Enables of disables the passed permission bit of a file.
63 static jboolean set_file_permissions (JNIEnv *env, jstring name,
64 jboolean enable,
65 jboolean ownerOnly,
66 int permissions);
68 /* ***** END: PRIVATE FUNCTIONS DELCARATION ***** */
70 /*************************************************************************/
73 * Method to create an empty file.
75 * Class: java_io_VMFile
76 * Method: create
77 * Signature: (Ljava/lang/String;)Z
80 JNIEXPORT jboolean JNICALL
81 Java_java_io_VMFile_create (JNIEnv * env,
82 jclass clazz __attribute__ ((__unused__)),
83 jstring name)
85 #ifndef WITHOUT_FILESYSTEM
86 const char *filename;
87 int fd;
88 int result;
90 filename = JCL_jstring_to_cstring (env, name);
91 if (filename == NULL)
93 return 0;
96 result = cpio_openFile (filename, &fd, CPFILE_FLAG_CREATE|CPFILE_FLAG_WRITE, CPFILE_PERMISSION_NORMAL);
97 if (result != CPNATIVE_OK)
99 if (result != EEXIST)
100 JCL_ThrowException (env,
101 "java/io/IOException",
102 cpnative_getErrorString (result));
103 JCL_free_cstring (env, name, filename);
104 return 0;
106 cpio_closeFile (fd);
108 JCL_free_cstring (env, name, filename);
109 return 1;
110 #else /* not WITHOUT_FILESYSTEM */
111 return 0;
112 #endif /* not WITHOUT_FILESYSTEM */
115 /*************************************************************************/
118 * This method checks to see if we have read permission on a file.
120 * Class: java_io_VMFile
121 * Method: canRead
122 * Signature: (Ljava/lang/String;)Z
125 JNIEXPORT jboolean JNICALL
126 Java_java_io_VMFile_canRead (JNIEnv * env,
127 jclass clazz __attribute__ ((__unused__)),
128 jstring name)
130 #ifndef WITHOUT_FILESYSTEM
131 const char *filename;
132 int result;
134 /* Don't use the JCL convert function because it throws an exception
135 on failure */
136 filename = (*env)->GetStringUTFChars (env, name, 0);
137 if (filename == NULL)
139 return JNI_FALSE;
142 result = cpio_checkAccess (filename, CPFILE_FLAG_READ);
144 (*env)->ReleaseStringUTFChars (env, name, filename);
145 if (result != CPNATIVE_OK)
146 return JNI_FALSE;
148 return JNI_TRUE;
149 #else /* not WITHOUT_FILESYSTEM */
150 return JNI_FALSE;
151 #endif /* not WITHOUT_FILESYSTEM */
154 /*************************************************************************/
157 * This method checks to see if we have write permission on a file.
159 * Class: java_io_VMFile
160 * Method: canWrite
161 * Signature: (Ljava/lang/String;)Z
164 JNIEXPORT jboolean JNICALL
165 Java_java_io_VMFile_canWrite (JNIEnv * env,
166 jclass clazz __attribute__ ((__unused__)),
167 jstring name)
169 #ifndef WITHOUT_FILESYSTEM
170 const char *filename;
171 int result;
173 /* Don't use the JCL convert function because it throws an exception
174 on failure */
175 filename = (*env)->GetStringUTFChars (env, name, 0);
176 if (filename == NULL)
178 return JNI_FALSE;
181 result = cpio_checkAccess (filename, CPFILE_FLAG_WRITE);
183 (*env)->ReleaseStringUTFChars (env, name, filename);
184 if (result != CPNATIVE_OK)
186 return JNI_FALSE;
189 return JNI_TRUE;
190 #else /* not WITHOUT_FILESYSTEM */
191 return JNI_FALSE;
192 #endif /* not WITHOUT_FILESYSTEM */
195 /*************************************************************************/
197 JNIEXPORT jboolean JNICALL
198 Java_java_io_VMFile_canWriteDirectory (JNIEnv *env, jclass clazz, jstring path)
200 /* this is only valid on *nix systems */
201 return Java_java_io_VMFile_canWrite(env, clazz, path);
204 /*************************************************************************/
207 * This method checks to see if we have execute permission on a file.
209 * Class: java_io_VMFile
210 * Method: canExecute
211 * Signature: (Ljava/lang/String;)Z
214 JNIEXPORT jboolean JNICALL
215 Java_java_io_VMFile_canExecute (JNIEnv * env,
216 jclass clazz __attribute__ ((__unused__)),
217 jstring name)
219 #ifndef WITHOUT_FILESYSTEM
220 const char *filename;
221 int result;
223 /* Don't use the JCL convert function because it throws an exception
224 on failure */
225 filename = (*env)->GetStringUTFChars (env, name, 0);
226 if (filename == NULL)
228 return JNI_FALSE;
231 result = cpio_checkAccess (filename, CPFILE_FLAG_EXEC);
233 (*env)->ReleaseStringUTFChars (env, name, filename);
234 if (result != CPNATIVE_OK)
235 return JNI_FALSE;
237 return JNI_TRUE;
238 #else /* not WITHOUT_FILESYSTEM */
239 return JNI_FALSE;
240 #endif /* not WITHOUT_FILESYSTEM */
244 /*************************************************************************/
247 * This method makes a file read only.
249 * Class: java_io_VMFile
250 * Method: setReadOnly
251 * Signature: (Ljava/lang/String;)Z
254 JNIEXPORT jboolean JNICALL
255 Java_java_io_VMFile_setReadOnly (JNIEnv * env,
256 jclass clazz __attribute__ ((__unused__)),
257 jstring name)
259 #ifndef WITHOUT_FILESYSTEM
260 const char *filename;
261 int result;
263 /* Don't use the JCL convert function because it throws an exception
264 on failure */
265 filename = (*env)->GetStringUTFChars (env, name, 0);
266 if (filename == NULL)
268 return 0;
271 result = cpio_setFileReadonly (filename);
272 (*env)->ReleaseStringUTFChars (env, name, filename);
274 return result == CPNATIVE_OK ? 1 : 0;
275 #else /* not WITHOUT_FILESYSTEM */
276 return 0;
277 #endif /* not WITHOUT_FILESYSTEM */
280 /*************************************************************************/
283 * This method changes the read permission bit of a file.
285 * Class: java_io_VMFile
286 * Method: setReadable
287 * Signature: (Ljava/lang/String;ZZ)Z
289 JNIEXPORT jboolean JNICALL
290 Java_java_io_VMFile_setReadable (JNIEnv *env,
291 jclass clazz __attribute__ ((__unused__)),
292 jstring name,
293 jboolean readable,
294 jboolean ownerOnly)
296 return set_file_permissions (env, name, readable, ownerOnly,
297 CPFILE_FLAG_READ);
301 /*************************************************************************/
304 * This method changes the write permission bit of a file.
306 * Class: java_io_VMFile
307 * Method: setWritable
308 * Signature: (Ljava/lang/String;ZZ)Z
310 JNIEXPORT jboolean JNICALL
311 Java_java_io_VMFile_setWritable (JNIEnv *env,
312 jclass clazz __attribute__ ((__unused__)),
313 jstring name,
314 jboolean writable,
315 jboolean ownerOnly)
317 return set_file_permissions (env, name, writable, ownerOnly,
318 CPFILE_FLAG_WRITE);
321 /*************************************************************************/
324 * This method changes the execute permission bit of a file.
326 * Class: java_io_VMFile
327 * Method: setExecutable
328 * Signature: (Ljava/lang/String;ZZ)Z
330 JNIEXPORT jboolean JNICALL
331 Java_java_io_VMFile_setExecutable (JNIEnv *env,
332 jclass clazz __attribute__ ((__unused__)),
333 jstring name,
334 jboolean executable,
335 jboolean ownerOnly)
337 return set_file_permissions (env, name, executable, ownerOnly,
338 CPFILE_FLAG_EXEC);
341 /*************************************************************************/
343 JNIEXPORT jlong JNICALL
344 Java_java_io_VMFile_getTotalSpace (JNIEnv *env,
345 jclass clazz __attribute__ ((__unused__)),
346 jstring path)
348 #ifndef WITHOUT_FILESYSTEM
350 jlong result;
351 const char *_path = NULL;
353 _path = (*env)->GetStringUTFChars (env, path, 0);
354 if (_path == NULL)
356 return 0L;
359 result = cpio_df (_path, TOTAL);
361 (*env)->ReleaseStringUTFChars (env, path, _path);
363 return result;
365 #else /* not WITHOUT_FILESYSTEM */
366 return 0L;
367 #endif /* not WITHOUT_FILESYSTEM */
370 /*************************************************************************/
372 JNIEXPORT jlong JNICALL
373 Java_java_io_VMFile_getFreeSpace (JNIEnv *env,
374 jclass clazz __attribute__ ((__unused__)),
375 jstring path)
377 #ifndef WITHOUT_FILESYSTEM
379 jlong result;
380 const char *_path = NULL;
382 _path = (*env)->GetStringUTFChars (env, path, 0);
383 if (_path == NULL)
385 return 0L;
388 result = cpio_df (_path, FREE);
390 (*env)->ReleaseStringUTFChars (env, path, _path);
392 return result;
394 #else /* not WITHOUT_FILESYSTEM */
395 return 0L;
396 #endif /* not WITHOUT_FILESYSTEM */
399 /*************************************************************************/
401 JNIEXPORT jlong JNICALL
402 Java_java_io_VMFile_getUsableSpace (JNIEnv *env,
403 jclass clazz __attribute__ ((__unused__)),
404 jstring path)
406 #ifndef WITHOUT_FILESYSTEM
408 jlong result;
409 const char *_path = NULL;
411 _path = (*env)->GetStringUTFChars (env, path, 0);
412 if (_path == NULL)
414 return 0L;
417 result = cpio_df (_path, USABLE);
419 (*env)->ReleaseStringUTFChars (env, path, _path);
421 return result;
423 #else /* not WITHOUT_FILESYSTEM */
424 return 0L;
425 #endif /* not WITHOUT_FILESYSTEM */
428 /*************************************************************************/
431 * This method checks to see if a file exists.
433 * Class: java_io_VMFile
434 * Method: exists
435 * Signature: (Ljava/lang/String;)Z
438 JNIEXPORT jboolean JNICALL
439 Java_java_io_VMFile_exists (JNIEnv * env,
440 jclass clazz __attribute__ ((__unused__)),
441 jstring name)
443 #ifndef WITHOUT_FILESYSTEM
444 const char *filename;
445 int result;
447 /* Don't use the JCL convert function because it throws an exception
448 on failure */
449 filename = (*env)->GetStringUTFChars (env, name, 0);
450 if (filename == NULL)
452 return 0;
455 result = cpio_isFileExists (filename);
456 (*env)->ReleaseStringUTFChars (env, name, filename);
458 return result == CPNATIVE_OK ? 1 : 0;
459 #else /* not WITHOUT_FILESYSTEM */
460 return 0;
461 #endif /* not WITHOUT_FILESYSTEM */
464 /*************************************************************************/
467 * This method checks to see if a file is a "plain" file; that is, not
468 * a directory, pipe, etc.
470 * Class: java_io_VMFile
471 * Method: isFile
472 * Signature: (Ljava/lang/String;)Z
475 JNIEXPORT jboolean JNICALL
476 Java_java_io_VMFile_isFile (JNIEnv * env,
477 jclass clazz __attribute__ ((__unused__)),
478 jstring name)
480 #ifndef WITHOUT_FILESYSTEM
481 const char *filename;
482 int result;
483 jint entryType;
485 /* Don't use the JCL convert function because it throws an exception
486 on failure */
487 filename = (*env)->GetStringUTFChars (env, name, 0);
488 if (filename == NULL)
490 return 0;
493 result = cpio_checkType (filename, &entryType);
494 (*env)->ReleaseStringUTFChars (env, name, filename);
496 return result == CPNATIVE_OK && entryType == CPFILE_FILE ? 1 : 0;
497 #else /* not WITHOUT_FILESYSTEM */
498 return 0;
499 #endif /* not WITHOUT_FILESYSTEM */
502 /*************************************************************************/
505 * This method checks to see if a file is a directory or not.
507 * Class: java_io_VMFile
508 * Method: isDirectory
509 * Signature: (Ljava/lang/String;)Z
512 JNIEXPORT jboolean JNICALL
513 Java_java_io_VMFile_isDirectory (JNIEnv * env,
514 jclass clazz __attribute__ ((__unused__)),
515 jstring name)
517 #ifndef WITHOUT_FILESYSTEM
518 const char *filename;
519 int result;
520 jint entryType;
522 /* Don't use the JCL convert function because it throws an exception
523 on failure */
524 filename = (*env)->GetStringUTFChars (env, name, 0);
525 if (filename == NULL)
527 return 0;
530 result = cpio_checkType (filename, &entryType);
531 (*env)->ReleaseStringUTFChars (env, name, filename);
533 return result == CPNATIVE_OK && entryType == CPFILE_DIRECTORY ? 1 : 0;
534 #else /* not WITHOUT_FILESYSTEM */
535 return 0;
536 #endif /* not WITHOUT_FILESYSTEM */
539 /*************************************************************************/
542 * This method returns the length of the file.
544 * Class: java_io_VMFile
545 * Method: length
546 * Signature: (Ljava/lang/String;)J
549 JNIEXPORT jlong JNICALL
550 Java_java_io_VMFile_length (JNIEnv * env,
551 jclass clazz __attribute__ ((__unused__)),
552 jstring name)
554 #ifndef WITHOUT_FILESYSTEM
555 const char *filename;
556 int tmpfd;
557 jlong length;
558 int result;
560 /* Don't use the JCL convert function because it throws an exception
561 on failure */
562 filename = (*env)->GetStringUTFChars (env, name, 0);
563 if (filename == NULL)
564 return 0;
566 /* open file for reading, get size and close file */
567 result = cpio_openFile (filename, &tmpfd, CPFILE_FLAG_READ, 0);
568 if (result != CPNATIVE_OK)
569 return 0;
571 result = cpio_getFileSize (tmpfd, &length);
572 if (result != CPNATIVE_OK)
574 cpio_closeFile (tmpfd);
575 return 0;
578 result = cpio_closeFile (tmpfd);
579 (*env)->ReleaseStringUTFChars (env, name, filename);
581 return result == CPNATIVE_OK ? length : 0;
582 #else /* not WITHOUT_FILESYSTEM */
583 return 0;
584 #endif /* not WITHOUT_FILESYSTEM */
587 /*************************************************************************/
590 * This method returns the modification date of the file.
592 * Class: java_io_VMFile
593 * Method: lastModified
594 * Signature: (Ljava/lang/String;)J
597 JNIEXPORT jlong JNICALL
598 Java_java_io_VMFile_lastModified (JNIEnv * env,
599 jclass clazz __attribute__ ((__unused__)),
600 jstring name)
602 #ifndef WITHOUT_FILESYSTEM
603 const char *filename;
604 jlong mtime;
605 int result;
607 /* Don't use the JCL convert function because it throws an exception
608 on failure */
609 filename = (*env)->GetStringUTFChars (env, name, 0);
610 if (filename == NULL)
612 return 0;
615 result = cpio_getModificationTime (filename, &mtime);
616 (*env)->ReleaseStringUTFChars (env, name, filename);
618 return result == CPNATIVE_OK ? mtime : 0;
619 #else /* not WITHOUT_FILESYSTEM */
620 return 0;
621 #endif /* not WITHOUT_FILESYSTEM */
624 /*************************************************************************/
627 * This method sets the modification date of the file.
629 * Class: java_io_VMFile
630 * Method: setLastModified
631 * Signature: (Ljava/lang/String;J)Z
634 JNIEXPORT jboolean JNICALL
635 Java_java_io_VMFile_setLastModified (JNIEnv * env,
636 jclass clazz __attribute__ ((__unused__)),
637 jstring name, jlong newtime)
639 #ifndef WITHOUT_FILESYSTEM
640 const char *filename;
641 int result;
643 /* Don't use the JCL convert function because it throws an exception
644 on failure */
645 filename = (*env)->GetStringUTFChars (env, name, 0);
646 if (filename == NULL)
648 return 0;
651 result = cpio_setModificationTime (filename, newtime);
652 (*env)->ReleaseStringUTFChars (env, name, filename);
654 return result == CPNATIVE_OK ? 1 : 0;
655 #else /* not WITHOUT_FILESYSTEM */
656 return 0;
657 #endif /* not WITHOUT_FILESYSTEM */
660 /*************************************************************************/
663 * This method deletes a file (actually a name for a file - additional
664 * links could exist).
666 * Class: java_io_VMFile
667 * Method: delete
668 * Signature: (Ljava/lang/String;)Z
671 JNIEXPORT jboolean JNICALL
672 Java_java_io_VMFile_delete (JNIEnv * env,
673 jclass clazz __attribute__ ((__unused__)),
674 jstring name)
676 #ifndef WITHOUT_FILESYSTEM
677 const char *filename;
678 int result;
680 /* Don't use the JCL convert function because it throws an exception
681 on failure */
682 filename = (*env)->GetStringUTFChars (env, name, 0);
683 if (filename == NULL)
685 return 0;
688 result = cpio_removeFile (filename);
689 (*env)->ReleaseStringUTFChars (env, name, filename);
691 return result == CPNATIVE_OK ? 1 : 0;
692 #else /* not WITHOUT_FILESYSTEM */
693 return 0;
694 #endif /* not WITHOUT_FILESYSTEM */
697 /*************************************************************************/
700 * This method creates a directory.
702 * Class: java_io_VMFile
703 * Method: mkdir
704 * Signature: (Ljava/lang/String;)Z
707 JNIEXPORT jboolean JNICALL
708 Java_java_io_VMFile_mkdir (JNIEnv * env,
709 jclass clazz __attribute__ ((__unused__)),
710 jstring name)
712 #ifndef WITHOUT_FILESYSTEM
713 const char *pathname;
714 int result;
716 /* Don't use the JCL convert function because it throws an exception
717 on failure */
718 pathname = (*env)->GetStringUTFChars (env, name, 0);
719 if (pathname == NULL)
721 return 0;
724 result = cpio_mkdir (pathname);
725 (*env)->ReleaseStringUTFChars (env, name, pathname);
727 return (result == CPNATIVE_OK) ? 1 : 0;
728 #else /* not WITHOUT_FILESYSTEM */
729 return 0;
730 #endif /* not WITHOUT_FILESYSTEM */
733 /*************************************************************************/
736 * This method renames a (link to a) file.
738 * Class: java_io_VMFile
739 * Method: renameTo
740 * Signature: (Ljava/lang/String;Ljava/lang/String;)Z
743 JNIEXPORT jboolean JNICALL
744 Java_java_io_VMFile_renameTo (JNIEnv * env,
745 jclass clazz __attribute__ ((__unused__)),
746 jstring t, jstring d)
748 #ifndef WITHOUT_FILESYSTEM
749 const char *old_filename, *new_filename;
750 int result;
752 /* Don't use the JCL convert function because it throws an exception
753 on failure */
754 old_filename = (*env)->GetStringUTFChars (env, t, 0);
755 if (old_filename == NULL)
757 return 0;
760 new_filename = (*env)->GetStringUTFChars (env, d, 0);
761 if (new_filename == NULL)
763 (*env)->ReleaseStringUTFChars (env, t, old_filename);
764 return 0;
767 result = cpio_rename (old_filename, new_filename);
768 (*env)->ReleaseStringUTFChars (env, d, new_filename);
769 (*env)->ReleaseStringUTFChars (env, t, old_filename);
771 return (result == CPNATIVE_OK) ? 1 : 0;
772 #else /* not WITHOUT_FILESYSTEM */
773 return 0;
774 #endif /* not WITHOUT_FILESYSTEM */
777 /*************************************************************************/
780 * This method returns an array of String representing all the files
781 * in a directory except "." and "..".
783 * Class: java_io_VMFile
784 * Method: list
785 * Signature: (Ljava/lang/String;)[Ljava/lang/String;
788 JNIEXPORT jobjectArray JNICALL
789 Java_java_io_VMFile_list (JNIEnv * env,
790 jclass clazz __attribute__ ((__unused__)),
791 jstring name)
793 #ifndef WITHOUT_FILESYSTEM
794 const int REALLOC_SIZE = 10;
796 const char *dirname;
797 int result;
798 char **filelist;
799 void *handle;
800 char *filename = (char *) JCL_malloc (env, FILENAME_MAX);
801 unsigned long int filelist_count, max_filelist_count;
802 char **tmp_filelist;
803 jclass str_clazz;
804 jobjectArray filearray;
805 unsigned long int i;
806 jstring str;
808 /* Don't use the JCL convert function because it throws an exception
809 on failure */
810 dirname = (*env)->GetStringUTFChars (env, name, 0);
811 if (dirname == NULL)
813 return 0;
816 /* open directory for reading */
817 result = cpio_openDir (dirname, &handle);
819 (*env)->ReleaseStringUTFChars (env, name, dirname);
821 if (result != CPNATIVE_OK)
823 return 0;
826 /* allocate filelist */
827 filelist = (char **) JCL_malloc (env, sizeof (char *) * REALLOC_SIZE);
828 if (filelist == NULL)
830 result = cpio_closeDir (handle);
831 return 0;
833 filelist_count = 0;
834 max_filelist_count = REALLOC_SIZE;
836 /* read the files from the directory */
837 result = cpio_readDir (handle, filename);
838 while (result == CPNATIVE_OK)
840 if ((strcmp (filename, ".") != 0) && (strcmp (filename, "..") != 0))
842 /* allocate more memory if necessary */
843 if (filelist_count >= max_filelist_count)
845 tmp_filelist = (char **) JCL_realloc (env,
846 filelist,
847 (max_filelist_count +
848 REALLOC_SIZE) *
849 sizeof (char *));
850 if (tmp_filelist == NULL)
852 for (i = 0; i < filelist_count; i++)
854 JCL_free (env, filelist[i]);
856 JCL_free (env, filelist);
857 result = cpio_closeDir (handle);
858 return 0;
860 filelist = tmp_filelist;
861 max_filelist_count += REALLOC_SIZE;
864 /* save entry in list (avoid strdup, because it is not ANSI C, thus difficult to port) */
865 filelist[filelist_count] =
866 (char *) JCL_malloc (env, strlen (filename) + 1);
867 assert (filelist[filelist_count] != NULL);
868 strcpy (filelist[filelist_count], filename);
869 filelist_count++;
872 /* read next directory entry */
873 result = cpio_readDir (handle, filename);
876 JCL_free (env, filename);
878 /* close directory */
879 result = cpio_closeDir (handle);
881 /* put the list of files into a Java String array and return it */
882 str_clazz = (*env)->FindClass (env, "java/lang/String");
883 if (str_clazz == NULL)
885 for (i = 0; i < filelist_count; i++)
887 JCL_free (env, filelist[i]);
889 JCL_free (env, filelist);
890 return 0;
892 filearray = (*env)->NewObjectArray (env, filelist_count, str_clazz, 0);
893 if (filearray == NULL)
895 for (i = 0; i < filelist_count; i++)
897 JCL_free (env, filelist[i]);
899 JCL_free (env, filelist);
900 return 0;
903 (*env)->DeleteLocalRef (env, str_clazz);
905 for (i = 0; i < filelist_count; i++)
907 /* create new string */
908 str = (*env)->NewStringUTF (env, filelist[i]);
909 if (str == NULL)
911 /* We don't clean up everything here, but if this failed,
912 something serious happened anyway */
913 for (i = 0; i < filelist_count; i++)
915 JCL_free (env, filelist[i]);
917 JCL_free (env, filelist);
918 return 0;
921 /* save into array */
922 (*env)->SetObjectArrayElement (env, filearray, i, str);
924 /* delete local reference */
925 (*env)->DeleteLocalRef (env, str);
928 /* free resources */
929 for (i = 0; i < filelist_count; i++)
931 JCL_free (env, filelist[i]);
933 JCL_free (env, filelist);
935 return filearray;
936 #else /* not WITHOUT_FILESYSTEM */
937 return 0;
938 #endif /* not WITHOUT_FILESYSTEM */
941 /*************************************************************************/
944 * These two methods are used to maintain dynamically allocated
945 * buffers for getCanonicalPath without the overhead of calling
946 * realloc every time a buffer is modified. Buffers are sized
947 * at the smallest multiple of CHUNKSIZ that is greater than or
948 * equal to the desired length. The default CHUNKSIZ is 256,
949 * longer than most paths, so in most cases a getCanonicalPath
950 * will require only one malloc per buffer.
953 #define CHUNKLOG 8
954 #define CHUNKSIZ (1 << CHUNKLOG)
956 static int
957 nextChunkSize (int size)
959 return ((size >> CHUNKLOG) + ((size & (CHUNKSIZ - 1)) ? 1 : 0)) << CHUNKLOG;
962 static char *
963 maybeGrowBuf (JNIEnv *env, char *buf, int *size, int required)
965 if (required > *size)
967 *size = nextChunkSize (required);
968 buf = JCL_realloc (env, buf, *size);
970 return buf;
973 /*************************************************************************/
976 * This method converts a path to canonical form on GNU/Posix systems.
977 * This involves the removal of redundant separators, references to
978 * "." and "..", and symbolic links.
980 * The conversion proceeds on a component-by-component basis: symbolic
981 * links and references to ".." are resolved as and when they occur.
982 * This means that if "/foo/bar" is a symbolic link to "/baz" then the
983 * canonical form of "/foo/bar/.." is "/" and not "/foo".
985 * In order to mimic the behaviour of proprietary JVMs, non-existant
986 * path components are allowed (a departure from the normal GNU system
987 * convention). This means that if "/foo/bar" is a symbolic link to
988 * "/baz", the canonical form of "/non-existant-directory/../foo/bar"
989 * is "/baz".
991 * Class: java_io_VMFile
992 * Method: toCanonicalForm
993 * Signature: (Ljava/lang/String)Ljava/lang/String
996 JNIEXPORT jstring JNICALL
997 Java_java_io_VMFile_toCanonicalForm (JNIEnv *env,
998 jclass class __attribute__ ((__unused__)),
999 jstring jpath)
1001 #ifndef WITHOUT_FILESYSTEM
1002 const char *path;
1003 char *src, *dst;
1004 int srci, dsti;
1005 int srcl, dstl;
1006 int len;
1007 int fschecks;
1008 #if defined (HAVE_LSTAT) && defined (HAVE_READLINK)
1009 struct stat sb;
1010 #endif /* HAVE_LSTAT && HAVE_READLINK */
1012 path = JCL_jstring_to_cstring (env, jpath);
1013 if (path == NULL)
1014 return NULL;
1016 /* It is the caller's responsibility to ensure the path is absolute. */
1017 if (path[0] == 0 || path[0] != '/')
1019 JCL_free_cstring (env, jpath, path);
1020 JCL_ThrowException (env, "java/lang/RuntimeException", "Not absolute");
1021 return NULL;
1024 len = strlen (path);
1025 srcl = nextChunkSize (len + 1);
1026 src = JCL_malloc (env, srcl);
1027 if (src == NULL)
1029 JCL_free_cstring (env, jpath, path);
1030 return NULL;
1032 strcpy (src, path);
1033 JCL_free_cstring (env, jpath, path);
1034 srci = 1;
1036 dstl = nextChunkSize (2);
1037 dst = JCL_malloc (env, dstl);
1038 if (dst == NULL)
1040 JCL_free (env, src);
1041 return NULL;
1043 dst[0] = '/';
1044 dsti = 1;
1046 fschecks = JNI_TRUE;
1048 while (src[srci] != '\0')
1050 int tmpi, dsti_save;
1052 /* Skip slashes. */
1053 while (src[srci] == '/')
1054 srci++;
1055 tmpi = srci;
1056 /* Find next slash. */
1057 while (src[srci] != '/' && src[srci] != '\0')
1058 srci++;
1059 if (srci == tmpi)
1060 /* We hit the end. */
1061 break;
1062 len = srci - tmpi;
1064 /* Handle "." and "..". */
1065 if (len == 1 && src[tmpi] == '.')
1066 continue;
1067 if (len == 2 && src[tmpi] == '.' && src[tmpi + 1] == '.')
1069 while (dsti > 1 && dst[dsti - 1] != '/')
1070 dsti--;
1071 if (dsti != 1)
1072 dsti--;
1073 /* Reenable filesystem checking if disabled, as we might
1074 * have reversed over whatever caused the problem before.
1075 * At least one proprietary JVM has inconsistencies because
1076 * it does not do this.
1078 fschecks = JNI_TRUE;
1079 continue;
1082 /* Handle real path components. */
1083 dst = maybeGrowBuf (env,
1084 dst, &dstl, dsti + (dsti > 1 ? 1 : 0) + len + 1);
1085 if (dst == NULL)
1087 JCL_free (env, src);
1088 return NULL;
1090 dsti_save = dsti;
1091 if (dsti > 1)
1092 dst[dsti++] = '/';
1093 strncpy (&dst[dsti], &src[tmpi], len);
1094 dsti += len;
1095 if (fschecks == JNI_FALSE)
1096 continue;
1098 #if defined (HAVE_LSTAT) && defined (HAVE_READLINK)
1099 dst[dsti] = '\0';
1100 if (lstat (dst, &sb) == 0)
1102 if (S_ISLNK (sb.st_mode))
1104 int tmpl = CHUNKSIZ;
1105 char *tmp = JCL_malloc (env, tmpl);
1106 if (tmp == NULL)
1108 JCL_free (env, src);
1109 JCL_free (env, dst);
1110 return NULL;
1113 while (1)
1115 tmpi = readlink (dst, tmp, tmpl);
1116 if (tmpi < 1)
1118 JCL_free (env, src);
1119 JCL_free (env, dst);
1120 JCL_free (env, tmp);
1121 JCL_ThrowException (env, "java/io/IOException",
1122 "readlink failed");
1123 return NULL;
1125 if (tmpi < tmpl)
1126 break;
1127 tmpl += CHUNKSIZ;
1128 tmp = JCL_realloc (env, tmp, tmpl);
1131 /* Prepend the link's path to src. */
1132 tmp = maybeGrowBuf (env,
1133 tmp, &tmpl, tmpi + strlen (&src[srci]) + 1);
1134 if (tmp == NULL)
1136 JCL_free (env, src);
1137 JCL_free (env, dst);
1138 return NULL;
1141 strcpy (&tmp[tmpi], &src[srci]);
1142 JCL_free (env, src);
1143 src = tmp;
1144 srcl = tmpl;
1145 srci = 0;
1147 /* Either replace or append dst depending on whether the
1148 * link is relative or absolute.
1150 dsti = src[0] == '/' ? 1 : dsti_save;
1153 else
1155 /* Something doesn't exist, or we don't have permission to
1156 * read it, or a previous path component is a directory, or
1157 * a symlink is looped. Whatever, we can't check the
1158 * filesystem any more.
1160 fschecks = JNI_FALSE;
1162 #endif /* HAVE_LSTAT && HAVE_READLINK */
1164 dst[dsti] = '\0';
1166 jpath = (*env)->NewStringUTF (env, dst);
1167 JCL_free (env, src);
1168 JCL_free (env, dst);
1169 return jpath;
1170 #else /* not WITHOUT_FILESYSTEM */
1171 return NULL;
1172 #endif /* not WITHOUT_FILESYSTEM */
1175 /*************************************************************************/
1177 /* ***** PRIVATE FUNCTIONS IMPLEMENTATION ***** */
1179 static jboolean set_file_permissions (JNIEnv *env, jstring name,
1180 jboolean enable,
1181 jboolean ownerOnly,
1182 int permissions)
1184 #ifndef WITHOUT_FILESYSTEM
1185 const char *filename;
1186 int result = JNI_FALSE;
1188 /* Don't use the JCL convert function because it throws an exception
1189 on failure */
1190 filename = (*env)->GetStringUTFChars (env, name, 0);
1191 if (filename == NULL)
1193 return JNI_FALSE;
1196 if (ownerOnly)
1198 permissions |= CPFILE_FLAG_USR;
1201 if (!enable)
1203 permissions |= CPFILE_FLAG_OFF;
1206 result = cpio_chmod (filename, permissions);
1207 (*env)->ReleaseStringUTFChars (env, name, filename);
1209 return result == CPNATIVE_OK ? JNI_TRUE : JNI_FALSE;
1211 #else /* not WITHOUT_FILESYSTEM */
1212 return JNI_FALSE;
1213 #endif /* not WITHOUT_FILESYSTEM */