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)
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
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
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 */
45 #if defined (HAVE_LSTAT) && defined (HAVE_READLINK)
46 #include <sys/types.h>
56 #include "java_io_VMFile.h"
58 /* ***** PRIVATE FUNCTIONS DELCARATION ***** */
61 * Enables of disables the passed permission bit of a file.
63 static jboolean
set_file_permissions (JNIEnv
*env
, jstring name
,
68 /* ***** END: PRIVATE FUNCTIONS DELCARATION ***** */
70 /*************************************************************************/
73 * Method to create an empty file.
75 * Class: java_io_VMFile
77 * Signature: (Ljava/lang/String;)Z
80 JNIEXPORT jboolean JNICALL
81 Java_java_io_VMFile_create (JNIEnv
* env
,
82 jclass clazz
__attribute__ ((__unused__
)),
85 #ifndef WITHOUT_FILESYSTEM
90 filename
= JCL_jstring_to_cstring (env
, name
);
96 result
= cpio_openFile (filename
, &fd
, CPFILE_FLAG_CREATE
|CPFILE_FLAG_WRITE
, CPFILE_PERMISSION_NORMAL
);
97 if (result
!= CPNATIVE_OK
)
100 JCL_ThrowException (env
,
101 "java/io/IOException",
102 cpnative_getErrorString (result
));
103 JCL_free_cstring (env
, name
, filename
);
108 JCL_free_cstring (env
, name
, filename
);
110 #else /* not WITHOUT_FILESYSTEM */
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
122 * Signature: (Ljava/lang/String;)Z
125 JNIEXPORT jboolean JNICALL
126 Java_java_io_VMFile_canRead (JNIEnv
* env
,
127 jclass clazz
__attribute__ ((__unused__
)),
130 #ifndef WITHOUT_FILESYSTEM
131 const char *filename
;
134 /* Don't use the JCL convert function because it throws an exception
136 filename
= (*env
)->GetStringUTFChars (env
, name
, 0);
137 if (filename
== NULL
)
142 result
= cpio_checkAccess (filename
, CPFILE_FLAG_READ
);
144 (*env
)->ReleaseStringUTFChars (env
, name
, filename
);
145 if (result
!= CPNATIVE_OK
)
149 #else /* not WITHOUT_FILESYSTEM */
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
161 * Signature: (Ljava/lang/String;)Z
164 JNIEXPORT jboolean JNICALL
165 Java_java_io_VMFile_canWrite (JNIEnv
* env
,
166 jclass clazz
__attribute__ ((__unused__
)),
169 #ifndef WITHOUT_FILESYSTEM
170 const char *filename
;
173 /* Don't use the JCL convert function because it throws an exception
175 filename
= (*env
)->GetStringUTFChars (env
, name
, 0);
176 if (filename
== NULL
)
181 result
= cpio_checkAccess (filename
, CPFILE_FLAG_WRITE
);
183 (*env
)->ReleaseStringUTFChars (env
, name
, filename
);
184 if (result
!= CPNATIVE_OK
)
190 #else /* not WITHOUT_FILESYSTEM */
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
211 * Signature: (Ljava/lang/String;)Z
214 JNIEXPORT jboolean JNICALL
215 Java_java_io_VMFile_canExecute (JNIEnv
* env
,
216 jclass clazz
__attribute__ ((__unused__
)),
219 #ifndef WITHOUT_FILESYSTEM
220 const char *filename
;
223 /* Don't use the JCL convert function because it throws an exception
225 filename
= (*env
)->GetStringUTFChars (env
, name
, 0);
226 if (filename
== NULL
)
231 result
= cpio_checkAccess (filename
, CPFILE_FLAG_EXEC
);
233 (*env
)->ReleaseStringUTFChars (env
, name
, filename
);
234 if (result
!= CPNATIVE_OK
)
238 #else /* not WITHOUT_FILESYSTEM */
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__
)),
259 #ifndef WITHOUT_FILESYSTEM
260 const char *filename
;
263 /* Don't use the JCL convert function because it throws an exception
265 filename
= (*env
)->GetStringUTFChars (env
, name
, 0);
266 if (filename
== NULL
)
271 result
= cpio_setFileReadonly (filename
);
272 (*env
)->ReleaseStringUTFChars (env
, name
, filename
);
274 return result
== CPNATIVE_OK
? 1 : 0;
275 #else /* not WITHOUT_FILESYSTEM */
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__
)),
296 return set_file_permissions (env
, name
, readable
, ownerOnly
,
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__
)),
317 return set_file_permissions (env
, name
, writable
, ownerOnly
,
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__
)),
337 return set_file_permissions (env
, name
, executable
, ownerOnly
,
341 /*************************************************************************/
343 JNIEXPORT jlong JNICALL
344 Java_java_io_VMFile_getTotalSpace (JNIEnv
*env
,
345 jclass clazz
__attribute__ ((__unused__
)),
348 #ifndef WITHOUT_FILESYSTEM
351 const char *_path
= NULL
;
353 _path
= (*env
)->GetStringUTFChars (env
, path
, 0);
359 result
= cpio_df (_path
, TOTAL
);
361 (*env
)->ReleaseStringUTFChars (env
, path
, _path
);
365 #else /* not WITHOUT_FILESYSTEM */
367 #endif /* not WITHOUT_FILESYSTEM */
370 /*************************************************************************/
372 JNIEXPORT jlong JNICALL
373 Java_java_io_VMFile_getFreeSpace (JNIEnv
*env
,
374 jclass clazz
__attribute__ ((__unused__
)),
377 #ifndef WITHOUT_FILESYSTEM
380 const char *_path
= NULL
;
382 _path
= (*env
)->GetStringUTFChars (env
, path
, 0);
388 result
= cpio_df (_path
, FREE
);
390 (*env
)->ReleaseStringUTFChars (env
, path
, _path
);
394 #else /* not WITHOUT_FILESYSTEM */
396 #endif /* not WITHOUT_FILESYSTEM */
399 /*************************************************************************/
401 JNIEXPORT jlong JNICALL
402 Java_java_io_VMFile_getUsableSpace (JNIEnv
*env
,
403 jclass clazz
__attribute__ ((__unused__
)),
406 #ifndef WITHOUT_FILESYSTEM
409 const char *_path
= NULL
;
411 _path
= (*env
)->GetStringUTFChars (env
, path
, 0);
417 result
= cpio_df (_path
, USABLE
);
419 (*env
)->ReleaseStringUTFChars (env
, path
, _path
);
423 #else /* not WITHOUT_FILESYSTEM */
425 #endif /* not WITHOUT_FILESYSTEM */
428 /*************************************************************************/
431 * This method checks to see if a file exists.
433 * Class: java_io_VMFile
435 * Signature: (Ljava/lang/String;)Z
438 JNIEXPORT jboolean JNICALL
439 Java_java_io_VMFile_exists (JNIEnv
* env
,
440 jclass clazz
__attribute__ ((__unused__
)),
443 #ifndef WITHOUT_FILESYSTEM
444 const char *filename
;
447 /* Don't use the JCL convert function because it throws an exception
449 filename
= (*env
)->GetStringUTFChars (env
, name
, 0);
450 if (filename
== NULL
)
455 result
= cpio_isFileExists (filename
);
456 (*env
)->ReleaseStringUTFChars (env
, name
, filename
);
458 return result
== CPNATIVE_OK
? 1 : 0;
459 #else /* not WITHOUT_FILESYSTEM */
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
472 * Signature: (Ljava/lang/String;)Z
475 JNIEXPORT jboolean JNICALL
476 Java_java_io_VMFile_isFile (JNIEnv
* env
,
477 jclass clazz
__attribute__ ((__unused__
)),
480 #ifndef WITHOUT_FILESYSTEM
481 const char *filename
;
485 /* Don't use the JCL convert function because it throws an exception
487 filename
= (*env
)->GetStringUTFChars (env
, name
, 0);
488 if (filename
== NULL
)
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 */
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__
)),
517 #ifndef WITHOUT_FILESYSTEM
518 const char *filename
;
522 /* Don't use the JCL convert function because it throws an exception
524 filename
= (*env
)->GetStringUTFChars (env
, name
, 0);
525 if (filename
== NULL
)
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 */
536 #endif /* not WITHOUT_FILESYSTEM */
539 /*************************************************************************/
542 * This method returns the length of the file.
544 * Class: java_io_VMFile
546 * Signature: (Ljava/lang/String;)J
549 JNIEXPORT jlong JNICALL
550 Java_java_io_VMFile_length (JNIEnv
* env
,
551 jclass clazz
__attribute__ ((__unused__
)),
554 #ifndef WITHOUT_FILESYSTEM
555 const char *filename
;
560 /* Don't use the JCL convert function because it throws an exception
562 filename
= (*env
)->GetStringUTFChars (env
, name
, 0);
563 if (filename
== NULL
)
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
)
571 result
= cpio_getFileSize (tmpfd
, &length
);
572 if (result
!= CPNATIVE_OK
)
574 cpio_closeFile (tmpfd
);
578 result
= cpio_closeFile (tmpfd
);
579 (*env
)->ReleaseStringUTFChars (env
, name
, filename
);
581 return result
== CPNATIVE_OK
? length
: 0;
582 #else /* not WITHOUT_FILESYSTEM */
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__
)),
602 #ifndef WITHOUT_FILESYSTEM
603 const char *filename
;
607 /* Don't use the JCL convert function because it throws an exception
609 filename
= (*env
)->GetStringUTFChars (env
, name
, 0);
610 if (filename
== NULL
)
615 result
= cpio_getModificationTime (filename
, &mtime
);
616 (*env
)->ReleaseStringUTFChars (env
, name
, filename
);
618 return result
== CPNATIVE_OK
? mtime
: 0;
619 #else /* not WITHOUT_FILESYSTEM */
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
;
643 /* Don't use the JCL convert function because it throws an exception
645 filename
= (*env
)->GetStringUTFChars (env
, name
, 0);
646 if (filename
== NULL
)
651 result
= cpio_setModificationTime (filename
, newtime
);
652 (*env
)->ReleaseStringUTFChars (env
, name
, filename
);
654 return result
== CPNATIVE_OK
? 1 : 0;
655 #else /* not WITHOUT_FILESYSTEM */
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
668 * Signature: (Ljava/lang/String;)Z
671 JNIEXPORT jboolean JNICALL
672 Java_java_io_VMFile_delete (JNIEnv
* env
,
673 jclass clazz
__attribute__ ((__unused__
)),
676 #ifndef WITHOUT_FILESYSTEM
677 const char *filename
;
680 /* Don't use the JCL convert function because it throws an exception
682 filename
= (*env
)->GetStringUTFChars (env
, name
, 0);
683 if (filename
== NULL
)
688 result
= cpio_removeFile (filename
);
689 (*env
)->ReleaseStringUTFChars (env
, name
, filename
);
691 return result
== CPNATIVE_OK
? 1 : 0;
692 #else /* not WITHOUT_FILESYSTEM */
694 #endif /* not WITHOUT_FILESYSTEM */
697 /*************************************************************************/
700 * This method creates a directory.
702 * Class: java_io_VMFile
704 * Signature: (Ljava/lang/String;)Z
707 JNIEXPORT jboolean JNICALL
708 Java_java_io_VMFile_mkdir (JNIEnv
* env
,
709 jclass clazz
__attribute__ ((__unused__
)),
712 #ifndef WITHOUT_FILESYSTEM
713 const char *pathname
;
716 /* Don't use the JCL convert function because it throws an exception
718 pathname
= (*env
)->GetStringUTFChars (env
, name
, 0);
719 if (pathname
== NULL
)
724 result
= cpio_mkdir (pathname
);
725 (*env
)->ReleaseStringUTFChars (env
, name
, pathname
);
727 return (result
== CPNATIVE_OK
) ? 1 : 0;
728 #else /* not WITHOUT_FILESYSTEM */
730 #endif /* not WITHOUT_FILESYSTEM */
733 /*************************************************************************/
736 * This method renames a (link to a) file.
738 * Class: java_io_VMFile
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
;
752 /* Don't use the JCL convert function because it throws an exception
754 old_filename
= (*env
)->GetStringUTFChars (env
, t
, 0);
755 if (old_filename
== NULL
)
760 new_filename
= (*env
)->GetStringUTFChars (env
, d
, 0);
761 if (new_filename
== NULL
)
763 (*env
)->ReleaseStringUTFChars (env
, t
, old_filename
);
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 */
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
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__
)),
793 #ifndef WITHOUT_FILESYSTEM
794 const int REALLOC_SIZE
= 10;
800 char *filename
= (char *) JCL_malloc (env
, FILENAME_MAX
);
801 unsigned long int filelist_count
, max_filelist_count
;
804 jobjectArray filearray
;
808 /* Don't use the JCL convert function because it throws an exception
810 dirname
= (*env
)->GetStringUTFChars (env
, name
, 0);
816 /* open directory for reading */
817 result
= cpio_openDir (dirname
, &handle
);
819 (*env
)->ReleaseStringUTFChars (env
, name
, dirname
);
821 if (result
!= CPNATIVE_OK
)
826 /* allocate filelist */
827 filelist
= (char **) JCL_malloc (env
, sizeof (char *) * REALLOC_SIZE
);
828 if (filelist
== NULL
)
830 result
= cpio_closeDir (handle
);
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
,
847 (max_filelist_count
+
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
);
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
);
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
);
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
);
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
]);
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
);
921 /* save into array */
922 (*env
)->SetObjectArrayElement (env
, filearray
, i
, str
);
924 /* delete local reference */
925 (*env
)->DeleteLocalRef (env
, str
);
929 for (i
= 0; i
< filelist_count
; i
++)
931 JCL_free (env
, filelist
[i
]);
933 JCL_free (env
, filelist
);
936 #else /* not WITHOUT_FILESYSTEM */
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.
954 #define CHUNKSIZ (1 << CHUNKLOG)
957 nextChunkSize (int size
)
959 return ((size
>> CHUNKLOG
) + ((size
& (CHUNKSIZ
- 1)) ? 1 : 0)) << CHUNKLOG
;
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
);
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"
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__
)),
1001 #ifndef WITHOUT_FILESYSTEM
1008 #if defined (HAVE_LSTAT) && defined (HAVE_READLINK)
1010 #endif /* HAVE_LSTAT && HAVE_READLINK */
1012 path
= JCL_jstring_to_cstring (env
, jpath
);
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");
1024 len
= strlen (path
);
1025 srcl
= nextChunkSize (len
+ 1);
1026 src
= JCL_malloc (env
, srcl
);
1029 JCL_free_cstring (env
, jpath
, path
);
1033 JCL_free_cstring (env
, jpath
, path
);
1036 dstl
= nextChunkSize (2);
1037 dst
= JCL_malloc (env
, dstl
);
1040 JCL_free (env
, src
);
1046 fschecks
= JNI_TRUE
;
1048 while (src
[srci
] != '\0')
1050 int tmpi
, dsti_save
;
1053 while (src
[srci
] == '/')
1056 /* Find next slash. */
1057 while (src
[srci
] != '/' && src
[srci
] != '\0')
1060 /* We hit the end. */
1064 /* Handle "." and "..". */
1065 if (len
== 1 && src
[tmpi
] == '.')
1067 if (len
== 2 && src
[tmpi
] == '.' && src
[tmpi
+ 1] == '.')
1069 while (dsti
> 1 && dst
[dsti
- 1] != '/')
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
;
1082 /* Handle real path components. */
1083 dst
= maybeGrowBuf (env
,
1084 dst
, &dstl
, dsti
+ (dsti
> 1 ? 1 : 0) + len
+ 1);
1087 JCL_free (env
, src
);
1093 strncpy (&dst
[dsti
], &src
[tmpi
], len
);
1095 if (fschecks
== JNI_FALSE
)
1098 #if defined (HAVE_LSTAT) && defined (HAVE_READLINK)
1100 if (lstat (dst
, &sb
) == 0)
1102 if (S_ISLNK (sb
.st_mode
))
1104 int tmpl
= CHUNKSIZ
;
1105 char *tmp
= JCL_malloc (env
, tmpl
);
1108 JCL_free (env
, src
);
1109 JCL_free (env
, dst
);
1115 tmpi
= readlink (dst
, tmp
, tmpl
);
1118 JCL_free (env
, src
);
1119 JCL_free (env
, dst
);
1120 JCL_free (env
, tmp
);
1121 JCL_ThrowException (env
, "java/io/IOException",
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);
1136 JCL_free (env
, src
);
1137 JCL_free (env
, dst
);
1141 strcpy (&tmp
[tmpi
], &src
[srci
]);
1142 JCL_free (env
, src
);
1147 /* Either replace or append dst depending on whether the
1148 * link is relative or absolute.
1150 dsti
= src
[0] == '/' ? 1 : dsti_save
;
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 */
1166 jpath
= (*env
)->NewStringUTF (env
, dst
);
1167 JCL_free (env
, src
);
1168 JCL_free (env
, dst
);
1170 #else /* not WITHOUT_FILESYSTEM */
1172 #endif /* not WITHOUT_FILESYSTEM */
1175 /*************************************************************************/
1177 /* ***** PRIVATE FUNCTIONS IMPLEMENTATION ***** */
1179 static jboolean
set_file_permissions (JNIEnv
*env
, jstring name
,
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
1190 filename
= (*env
)->GetStringUTFChars (env
, name
, 0);
1191 if (filename
== NULL
)
1198 permissions
|= CPFILE_FLAG_USR
;
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 */
1213 #endif /* not WITHOUT_FILESYSTEM */