1 /* java_io_VMFile.c - Native methods for java.io.File class
2 Copyright (C) 1998, 2004, 2006 Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
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.
10
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.
15
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.
20
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.
25
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. */
37
38 /* do not move; needed here because of some macro definitions */
39 #include <config.h>
40
41 #include <assert.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44
45 #if defined (HAVE_LSTAT) && defined (HAVE_READLINK)
46 #include <sys/types.h>
47 #include <sys/stat.h>
48 #include <unistd.h>
49 #endif
50
51 #include <jni.h>
52 #include <jcl.h>
53 #include "cpio.h"
54 #include "cpnative.h"
55
56 #include "java_io_VMFile.h"
57
58 /* ***** PRIVATE FUNCTIONS DELCARATION ***** */
59
60 /**
61 * Enables of disables the passed permission bit of a file.
62 */
63 static jboolean set_file_permissions (JNIEnv *env, jstring name,
64 jboolean enable,
65 jboolean ownerOnly,
66 int permissions);
67
68 /* ***** END: PRIVATE FUNCTIONS DELCARATION ***** */
69
70 /*************************************************************************/
71
72 /*
73 * Method to create an empty file.
74 *
75 * Class: java_io_VMFile
76 * Method: create
77 * Signature: (Ljava/lang/String;)Z
78 */
79
80 JNIEXPORT jboolean JNICALL
Java_java_io_VMFile_create(JNIEnv * env,jclass clazz,jstring name)81 Java_java_io_VMFile_create (JNIEnv * env,
82 jclass clazz __attribute__ ((__unused__)),
83 jstring name)
84 {
85 #ifndef WITHOUT_FILESYSTEM
86 const char *filename;
87 int fd;
88 int result;
89
90 filename = JCL_jstring_to_cstring (env, name);
91 if (filename == NULL)
92 {
93 return 0;
94 }
95
96 result = cpio_openFile (filename, &fd, CPFILE_FLAG_CREATE|CPFILE_FLAG_WRITE, CPFILE_PERMISSION_NORMAL);
97 if (result != CPNATIVE_OK)
98 {
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;
105 }
106 cpio_closeFile (fd);
107
108 JCL_free_cstring (env, name, filename);
109 return 1;
110 #else /* not WITHOUT_FILESYSTEM */
111 return 0;
112 #endif /* not WITHOUT_FILESYSTEM */
113 }
114
115 /*************************************************************************/
116
117 /*
118 * This method checks to see if we have read permission on a file.
119 *
120 * Class: java_io_VMFile
121 * Method: canRead
122 * Signature: (Ljava/lang/String;)Z
123 */
124
125 JNIEXPORT jboolean JNICALL
Java_java_io_VMFile_canRead(JNIEnv * env,jclass clazz,jstring name)126 Java_java_io_VMFile_canRead (JNIEnv * env,
127 jclass clazz __attribute__ ((__unused__)),
128 jstring name)
129 {
130 #ifndef WITHOUT_FILESYSTEM
131 const char *filename;
132 int result;
133
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)
138 {
139 return JNI_FALSE;
140 }
141
142 result = cpio_checkAccess (filename, CPFILE_FLAG_READ);
143
144 (*env)->ReleaseStringUTFChars (env, name, filename);
145 if (result != CPNATIVE_OK)
146 return JNI_FALSE;
147
148 return JNI_TRUE;
149 #else /* not WITHOUT_FILESYSTEM */
150 return JNI_FALSE;
151 #endif /* not WITHOUT_FILESYSTEM */
152 }
153
154 /*************************************************************************/
155
156 /*
157 * This method checks to see if we have write permission on a file.
158 *
159 * Class: java_io_VMFile
160 * Method: canWrite
161 * Signature: (Ljava/lang/String;)Z
162 */
163
164 JNIEXPORT jboolean JNICALL
Java_java_io_VMFile_canWrite(JNIEnv * env,jclass clazz,jstring name)165 Java_java_io_VMFile_canWrite (JNIEnv * env,
166 jclass clazz __attribute__ ((__unused__)),
167 jstring name)
168 {
169 #ifndef WITHOUT_FILESYSTEM
170 const char *filename;
171 int result;
172
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)
177 {
178 return JNI_FALSE;
179 }
180
181 result = cpio_checkAccess (filename, CPFILE_FLAG_WRITE);
182
183 (*env)->ReleaseStringUTFChars (env, name, filename);
184 if (result != CPNATIVE_OK)
185 {
186 return JNI_FALSE;
187 }
188
189 return JNI_TRUE;
190 #else /* not WITHOUT_FILESYSTEM */
191 return JNI_FALSE;
192 #endif /* not WITHOUT_FILESYSTEM */
193 }
194
195 /*************************************************************************/
196
197 JNIEXPORT jboolean JNICALL
Java_java_io_VMFile_canWriteDirectory(JNIEnv * env,jclass clazz,jstring path)198 Java_java_io_VMFile_canWriteDirectory (JNIEnv *env, jclass clazz, jstring path)
199 {
200 /* this is only valid on *nix systems */
201 return Java_java_io_VMFile_canWrite(env, clazz, path);
202 }
203
204 /*************************************************************************/
205
206 /*
207 * This method checks to see if we have execute permission on a file.
208 *
209 * Class: java_io_VMFile
210 * Method: canExecute
211 * Signature: (Ljava/lang/String;)Z
212 */
213
214 JNIEXPORT jboolean JNICALL
Java_java_io_VMFile_canExecute(JNIEnv * env,jclass clazz,jstring name)215 Java_java_io_VMFile_canExecute (JNIEnv * env,
216 jclass clazz __attribute__ ((__unused__)),
217 jstring name)
218 {
219 #ifndef WITHOUT_FILESYSTEM
220 const char *filename;
221 int result;
222
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)
227 {
228 return JNI_FALSE;
229 }
230
231 result = cpio_checkAccess (filename, CPFILE_FLAG_EXEC);
232
233 (*env)->ReleaseStringUTFChars (env, name, filename);
234 if (result != CPNATIVE_OK)
235 return JNI_FALSE;
236
237 return JNI_TRUE;
238 #else /* not WITHOUT_FILESYSTEM */
239 return JNI_FALSE;
240 #endif /* not WITHOUT_FILESYSTEM */
241 }
242
243
244 /*************************************************************************/
245
246 /*
247 * This method makes a file read only.
248 *
249 * Class: java_io_VMFile
250 * Method: setReadOnly
251 * Signature: (Ljava/lang/String;)Z
252 */
253
254 JNIEXPORT jboolean JNICALL
Java_java_io_VMFile_setReadOnly(JNIEnv * env,jclass clazz,jstring name)255 Java_java_io_VMFile_setReadOnly (JNIEnv * env,
256 jclass clazz __attribute__ ((__unused__)),
257 jstring name)
258 {
259 #ifndef WITHOUT_FILESYSTEM
260 const char *filename;
261 int result;
262
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)
267 {
268 return 0;
269 }
270
271 result = cpio_setFileReadonly (filename);
272 (*env)->ReleaseStringUTFChars (env, name, filename);
273
274 return result == CPNATIVE_OK ? 1 : 0;
275 #else /* not WITHOUT_FILESYSTEM */
276 return 0;
277 #endif /* not WITHOUT_FILESYSTEM */
278 }
279
280 /*************************************************************************/
281
282 /*
283 * This method changes the read permission bit of a file.
284 *
285 * Class: java_io_VMFile
286 * Method: setReadable
287 * Signature: (Ljava/lang/String;ZZ)Z
288 */
289 JNIEXPORT jboolean JNICALL
Java_java_io_VMFile_setReadable(JNIEnv * env,jclass clazz,jstring name,jboolean readable,jboolean ownerOnly)290 Java_java_io_VMFile_setReadable (JNIEnv *env,
291 jclass clazz __attribute__ ((__unused__)),
292 jstring name,
293 jboolean readable,
294 jboolean ownerOnly)
295 {
296 return set_file_permissions (env, name, readable, ownerOnly,
297 CPFILE_FLAG_READ);
298 }
299
300
301 /*************************************************************************/
302
303 /*
304 * This method changes the write permission bit of a file.
305 *
306 * Class: java_io_VMFile
307 * Method: setWritable
308 * Signature: (Ljava/lang/String;ZZ)Z
309 */
310 JNIEXPORT jboolean JNICALL
Java_java_io_VMFile_setWritable(JNIEnv * env,jclass clazz,jstring name,jboolean writable,jboolean ownerOnly)311 Java_java_io_VMFile_setWritable (JNIEnv *env,
312 jclass clazz __attribute__ ((__unused__)),
313 jstring name,
314 jboolean writable,
315 jboolean ownerOnly)
316 {
317 return set_file_permissions (env, name, writable, ownerOnly,
318 CPFILE_FLAG_WRITE);
319 }
320
321 /*************************************************************************/
322
323 /*
324 * This method changes the execute permission bit of a file.
325 *
326 * Class: java_io_VMFile
327 * Method: setExecutable
328 * Signature: (Ljava/lang/String;ZZ)Z
329 */
330 JNIEXPORT jboolean JNICALL
Java_java_io_VMFile_setExecutable(JNIEnv * env,jclass clazz,jstring name,jboolean executable,jboolean ownerOnly)331 Java_java_io_VMFile_setExecutable (JNIEnv *env,
332 jclass clazz __attribute__ ((__unused__)),
333 jstring name,
334 jboolean executable,
335 jboolean ownerOnly)
336 {
337 return set_file_permissions (env, name, executable, ownerOnly,
338 CPFILE_FLAG_EXEC);
339 }
340
341 /*************************************************************************/
342
343 JNIEXPORT jlong JNICALL
Java_java_io_VMFile_getTotalSpace(JNIEnv * env,jclass clazz,jstring path)344 Java_java_io_VMFile_getTotalSpace (JNIEnv *env,
345 jclass clazz __attribute__ ((__unused__)),
346 jstring path)
347 {
348 #ifndef WITHOUT_FILESYSTEM
349
350 jlong result;
351 const char *_path = NULL;
352
353 _path = (*env)->GetStringUTFChars (env, path, 0);
354 if (_path == NULL)
355 {
356 return 0L;
357 }
358
359 result = cpio_df (_path, TOTAL);
360
361 (*env)->ReleaseStringUTFChars (env, path, _path);
362
363 return result;
364
365 #else /* not WITHOUT_FILESYSTEM */
366 return 0L;
367 #endif /* not WITHOUT_FILESYSTEM */
368 }
369
370 /*************************************************************************/
371
372 JNIEXPORT jlong JNICALL
Java_java_io_VMFile_getFreeSpace(JNIEnv * env,jclass clazz,jstring path)373 Java_java_io_VMFile_getFreeSpace (JNIEnv *env,
374 jclass clazz __attribute__ ((__unused__)),
375 jstring path)
376 {
377 #ifndef WITHOUT_FILESYSTEM
378
379 jlong result;
380 const char *_path = NULL;
381
382 _path = (*env)->GetStringUTFChars (env, path, 0);
383 if (_path == NULL)
384 {
385 return 0L;
386 }
387
388 result = cpio_df (_path, FREE);
389
390 (*env)->ReleaseStringUTFChars (env, path, _path);
391
392 return result;
393
394 #else /* not WITHOUT_FILESYSTEM */
395 return 0L;
396 #endif /* not WITHOUT_FILESYSTEM */
397 }
398
399 /*************************************************************************/
400
401 JNIEXPORT jlong JNICALL
Java_java_io_VMFile_getUsableSpace(JNIEnv * env,jclass clazz,jstring path)402 Java_java_io_VMFile_getUsableSpace (JNIEnv *env,
403 jclass clazz __attribute__ ((__unused__)),
404 jstring path)
405 {
406 #ifndef WITHOUT_FILESYSTEM
407
408 jlong result;
409 const char *_path = NULL;
410
411 _path = (*env)->GetStringUTFChars (env, path, 0);
412 if (_path == NULL)
413 {
414 return 0L;
415 }
416
417 result = cpio_df (_path, USABLE);
418
419 (*env)->ReleaseStringUTFChars (env, path, _path);
420
421 return result;
422
423 #else /* not WITHOUT_FILESYSTEM */
424 return 0L;
425 #endif /* not WITHOUT_FILESYSTEM */
426 }
427
428 /*************************************************************************/
429
430 /*
431 * This method checks to see if a file exists.
432 *
433 * Class: java_io_VMFile
434 * Method: exists
435 * Signature: (Ljava/lang/String;)Z
436 */
437
438 JNIEXPORT jboolean JNICALL
Java_java_io_VMFile_exists(JNIEnv * env,jclass clazz,jstring name)439 Java_java_io_VMFile_exists (JNIEnv * env,
440 jclass clazz __attribute__ ((__unused__)),
441 jstring name)
442 {
443 #ifndef WITHOUT_FILESYSTEM
444 const char *filename;
445 int result;
446
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)
451 {
452 return 0;
453 }
454
455 result = cpio_isFileExists (filename);
456 (*env)->ReleaseStringUTFChars (env, name, filename);
457
458 return result == CPNATIVE_OK ? 1 : 0;
459 #else /* not WITHOUT_FILESYSTEM */
460 return 0;
461 #endif /* not WITHOUT_FILESYSTEM */
462 }
463
464 /*************************************************************************/
465
466 /*
467 * This method checks to see if a file is a "plain" file; that is, not
468 * a directory, pipe, etc.
469 *
470 * Class: java_io_VMFile
471 * Method: isFile
472 * Signature: (Ljava/lang/String;)Z
473 */
474
475 JNIEXPORT jboolean JNICALL
Java_java_io_VMFile_isFile(JNIEnv * env,jclass clazz,jstring name)476 Java_java_io_VMFile_isFile (JNIEnv * env,
477 jclass clazz __attribute__ ((__unused__)),
478 jstring name)
479 {
480 #ifndef WITHOUT_FILESYSTEM
481 const char *filename;
482 int result;
483 jint entryType;
484
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)
489 {
490 return 0;
491 }
492
493 result = cpio_checkType (filename, &entryType);
494 (*env)->ReleaseStringUTFChars (env, name, filename);
495
496 return result == CPNATIVE_OK && entryType == CPFILE_FILE ? 1 : 0;
497 #else /* not WITHOUT_FILESYSTEM */
498 return 0;
499 #endif /* not WITHOUT_FILESYSTEM */
500 }
501
502 /*************************************************************************/
503
504 /*
505 * This method checks to see if a file is a directory or not.
506 *
507 * Class: java_io_VMFile
508 * Method: isDirectory
509 * Signature: (Ljava/lang/String;)Z
510 */
511
512 JNIEXPORT jboolean JNICALL
Java_java_io_VMFile_isDirectory(JNIEnv * env,jclass clazz,jstring name)513 Java_java_io_VMFile_isDirectory (JNIEnv * env,
514 jclass clazz __attribute__ ((__unused__)),
515 jstring name)
516 {
517 #ifndef WITHOUT_FILESYSTEM
518 const char *filename;
519 int result;
520 jint entryType;
521
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)
526 {
527 return 0;
528 }
529
530 result = cpio_checkType (filename, &entryType);
531 (*env)->ReleaseStringUTFChars (env, name, filename);
532
533 return result == CPNATIVE_OK && entryType == CPFILE_DIRECTORY ? 1 : 0;
534 #else /* not WITHOUT_FILESYSTEM */
535 return 0;
536 #endif /* not WITHOUT_FILESYSTEM */
537 }
538
539 /*************************************************************************/
540
541 /*
542 * This method returns the length of the file.
543 *
544 * Class: java_io_VMFile
545 * Method: length
546 * Signature: (Ljava/lang/String;)J
547 */
548
549 JNIEXPORT jlong JNICALL
Java_java_io_VMFile_length(JNIEnv * env,jclass clazz,jstring name)550 Java_java_io_VMFile_length (JNIEnv * env,
551 jclass clazz __attribute__ ((__unused__)),
552 jstring name)
553 {
554 #ifndef WITHOUT_FILESYSTEM
555 const char *filename;
556 int tmpfd;
557 jlong length;
558 int result;
559
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;
565
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;
570
571 result = cpio_getFileSize (tmpfd, &length);
572 if (result != CPNATIVE_OK)
573 {
574 cpio_closeFile (tmpfd);
575 return 0;
576 }
577
578 result = cpio_closeFile (tmpfd);
579 (*env)->ReleaseStringUTFChars (env, name, filename);
580
581 return result == CPNATIVE_OK ? length : 0;
582 #else /* not WITHOUT_FILESYSTEM */
583 return 0;
584 #endif /* not WITHOUT_FILESYSTEM */
585 }
586
587 /*************************************************************************/
588
589 /*
590 * This method returns the modification date of the file.
591 *
592 * Class: java_io_VMFile
593 * Method: lastModified
594 * Signature: (Ljava/lang/String;)J
595 */
596
597 JNIEXPORT jlong JNICALL
Java_java_io_VMFile_lastModified(JNIEnv * env,jclass clazz,jstring name)598 Java_java_io_VMFile_lastModified (JNIEnv * env,
599 jclass clazz __attribute__ ((__unused__)),
600 jstring name)
601 {
602 #ifndef WITHOUT_FILESYSTEM
603 const char *filename;
604 jlong mtime;
605 int result;
606
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)
611 {
612 return 0;
613 }
614
615 result = cpio_getModificationTime (filename, &mtime);
616 (*env)->ReleaseStringUTFChars (env, name, filename);
617
618 return result == CPNATIVE_OK ? mtime : 0;
619 #else /* not WITHOUT_FILESYSTEM */
620 return 0;
621 #endif /* not WITHOUT_FILESYSTEM */
622 }
623
624 /*************************************************************************/
625
626 /*
627 * This method sets the modification date of the file.
628 *
629 * Class: java_io_VMFile
630 * Method: setLastModified
631 * Signature: (Ljava/lang/String;J)Z
632 */
633
634 JNIEXPORT jboolean JNICALL
Java_java_io_VMFile_setLastModified(JNIEnv * env,jclass clazz,jstring name,jlong newtime)635 Java_java_io_VMFile_setLastModified (JNIEnv * env,
636 jclass clazz __attribute__ ((__unused__)),
637 jstring name, jlong newtime)
638 {
639 #ifndef WITHOUT_FILESYSTEM
640 const char *filename;
641 int result;
642
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)
647 {
648 return 0;
649 }
650
651 result = cpio_setModificationTime (filename, newtime);
652 (*env)->ReleaseStringUTFChars (env, name, filename);
653
654 return result == CPNATIVE_OK ? 1 : 0;
655 #else /* not WITHOUT_FILESYSTEM */
656 return 0;
657 #endif /* not WITHOUT_FILESYSTEM */
658 }
659
660 /*************************************************************************/
661
662 /*
663 * This method deletes a file (actually a name for a file - additional
664 * links could exist).
665 *
666 * Class: java_io_VMFile
667 * Method: delete
668 * Signature: (Ljava/lang/String;)Z
669 */
670
671 JNIEXPORT jboolean JNICALL
Java_java_io_VMFile_delete(JNIEnv * env,jclass clazz,jstring name)672 Java_java_io_VMFile_delete (JNIEnv * env,
673 jclass clazz __attribute__ ((__unused__)),
674 jstring name)
675 {
676 #ifndef WITHOUT_FILESYSTEM
677 const char *filename;
678 int result;
679
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)
684 {
685 return 0;
686 }
687
688 result = cpio_removeFile (filename);
689 (*env)->ReleaseStringUTFChars (env, name, filename);
690
691 return result == CPNATIVE_OK ? 1 : 0;
692 #else /* not WITHOUT_FILESYSTEM */
693 return 0;
694 #endif /* not WITHOUT_FILESYSTEM */
695 }
696
697 /*************************************************************************/
698
699 /*
700 * This method creates a directory.
701 *
702 * Class: java_io_VMFile
703 * Method: mkdir
704 * Signature: (Ljava/lang/String;)Z
705 */
706
707 JNIEXPORT jboolean JNICALL
Java_java_io_VMFile_mkdir(JNIEnv * env,jclass clazz,jstring name)708 Java_java_io_VMFile_mkdir (JNIEnv * env,
709 jclass clazz __attribute__ ((__unused__)),
710 jstring name)
711 {
712 #ifndef WITHOUT_FILESYSTEM
713 const char *pathname;
714 int result;
715
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)
720 {
721 return 0;
722 }
723
724 result = cpio_mkdir (pathname);
725 (*env)->ReleaseStringUTFChars (env, name, pathname);
726
727 return (result == CPNATIVE_OK) ? 1 : 0;
728 #else /* not WITHOUT_FILESYSTEM */
729 return 0;
730 #endif /* not WITHOUT_FILESYSTEM */
731 }
732
733 /*************************************************************************/
734
735 /*
736 * This method renames a (link to a) file.
737 *
738 * Class: java_io_VMFile
739 * Method: renameTo
740 * Signature: (Ljava/lang/String;Ljava/lang/String;)Z
741 */
742
743 JNIEXPORT jboolean JNICALL
Java_java_io_VMFile_renameTo(JNIEnv * env,jclass clazz,jstring t,jstring d)744 Java_java_io_VMFile_renameTo (JNIEnv * env,
745 jclass clazz __attribute__ ((__unused__)),
746 jstring t, jstring d)
747 {
748 #ifndef WITHOUT_FILESYSTEM
749 const char *old_filename, *new_filename;
750 int result;
751
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)
756 {
757 return 0;
758 }
759
760 new_filename = (*env)->GetStringUTFChars (env, d, 0);
761 if (new_filename == NULL)
762 {
763 (*env)->ReleaseStringUTFChars (env, t, old_filename);
764 return 0;
765 }
766
767 result = cpio_rename (old_filename, new_filename);
768 (*env)->ReleaseStringUTFChars (env, d, new_filename);
769 (*env)->ReleaseStringUTFChars (env, t, old_filename);
770
771 return (result == CPNATIVE_OK) ? 1 : 0;
772 #else /* not WITHOUT_FILESYSTEM */
773 return 0;
774 #endif /* not WITHOUT_FILESYSTEM */
775 }
776
777 /*************************************************************************/
778
779 /*
780 * This method returns an array of String representing all the files
781 * in a directory except "." and "..".
782 *
783 * Class: java_io_VMFile
784 * Method: list
785 * Signature: (Ljava/lang/String;)[Ljava/lang/String;
786 */
787
788 JNIEXPORT jobjectArray JNICALL
Java_java_io_VMFile_list(JNIEnv * env,jclass clazz,jstring name)789 Java_java_io_VMFile_list (JNIEnv * env,
790 jclass clazz __attribute__ ((__unused__)),
791 jstring name)
792 {
793 #ifndef WITHOUT_FILESYSTEM
794 const int REALLOC_SIZE = 10;
795
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;
807
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)
812 {
813 return 0;
814 }
815
816 /* open directory for reading */
817 result = cpio_openDir (dirname, &handle);
818
819 (*env)->ReleaseStringUTFChars (env, name, dirname);
820
821 if (result != CPNATIVE_OK)
822 {
823 return 0;
824 }
825
826 /* allocate filelist */
827 filelist = (char **) JCL_malloc (env, sizeof (char *) * REALLOC_SIZE);
828 if (filelist == NULL)
829 {
830 result = cpio_closeDir (handle);
831 return 0;
832 }
833 filelist_count = 0;
834 max_filelist_count = REALLOC_SIZE;
835
836 /* read the files from the directory */
837 result = cpio_readDir (handle, filename);
838 while (result == CPNATIVE_OK)
839 {
840 if ((strcmp (filename, ".") != 0) && (strcmp (filename, "..") != 0))
841 {
842 /* allocate more memory if necessary */
843 if (filelist_count >= max_filelist_count)
844 {
845 tmp_filelist = (char **) JCL_realloc (env,
846 filelist,
847 (max_filelist_count +
848 REALLOC_SIZE) *
849 sizeof (char *));
850 if (tmp_filelist == NULL)
851 {
852 for (i = 0; i < filelist_count; i++)
853 {
854 JCL_free (env, filelist[i]);
855 }
856 JCL_free (env, filelist);
857 result = cpio_closeDir (handle);
858 return 0;
859 }
860 filelist = tmp_filelist;
861 max_filelist_count += REALLOC_SIZE;
862 }
863
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++;
870 }
871
872 /* read next directory entry */
873 result = cpio_readDir (handle, filename);
874 }
875
876 JCL_free (env, filename);
877
878 /* close directory */
879 result = cpio_closeDir (handle);
880
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)
884 {
885 for (i = 0; i < filelist_count; i++)
886 {
887 JCL_free (env, filelist[i]);
888 }
889 JCL_free (env, filelist);
890 return 0;
891 }
892 filearray = (*env)->NewObjectArray (env, filelist_count, str_clazz, 0);
893 if (filearray == NULL)
894 {
895 for (i = 0; i < filelist_count; i++)
896 {
897 JCL_free (env, filelist[i]);
898 }
899 JCL_free (env, filelist);
900 return 0;
901 }
902
903 (*env)->DeleteLocalRef (env, str_clazz);
904
905 for (i = 0; i < filelist_count; i++)
906 {
907 /* create new string */
908 str = (*env)->NewStringUTF (env, filelist[i]);
909 if (str == NULL)
910 {
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++)
914 {
915 JCL_free (env, filelist[i]);
916 }
917 JCL_free (env, filelist);
918 return 0;
919 }
920
921 /* save into array */
922 (*env)->SetObjectArrayElement (env, filearray, i, str);
923
924 /* delete local reference */
925 (*env)->DeleteLocalRef (env, str);
926 }
927
928 /* free resources */
929 for (i = 0; i < filelist_count; i++)
930 {
931 JCL_free (env, filelist[i]);
932 }
933 JCL_free (env, filelist);
934
935 return filearray;
936 #else /* not WITHOUT_FILESYSTEM */
937 return 0;
938 #endif /* not WITHOUT_FILESYSTEM */
939 }
940
941 /*************************************************************************/
942
943 /*
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.
951 */
952
953 #define CHUNKLOG 8
954 #define CHUNKSIZ (1 << CHUNKLOG)
955
956 static int
nextChunkSize(int size)957 nextChunkSize (int size)
958 {
959 return ((size >> CHUNKLOG) + ((size & (CHUNKSIZ - 1)) ? 1 : 0)) << CHUNKLOG;
960 }
961
962 static char *
maybeGrowBuf(JNIEnv * env,char * buf,int * size,int required)963 maybeGrowBuf (JNIEnv *env, char *buf, int *size, int required)
964 {
965 if (required > *size)
966 {
967 *size = nextChunkSize (required);
968 buf = JCL_realloc (env, buf, *size);
969 }
970 return buf;
971 }
972
973 /*************************************************************************/
974
975 /*
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.
979 *
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".
984 *
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".
990 *
991 * Class: java_io_VMFile
992 * Method: toCanonicalForm
993 * Signature: (Ljava/lang/String)Ljava/lang/String
994 */
995
996 JNIEXPORT jstring JNICALL
Java_java_io_VMFile_toCanonicalForm(JNIEnv * env,jclass class,jstring jpath)997 Java_java_io_VMFile_toCanonicalForm (JNIEnv *env,
998 jclass class __attribute__ ((__unused__)),
999 jstring jpath)
1000 {
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 */
1011
1012 path = JCL_jstring_to_cstring (env, jpath);
1013 if (path == NULL)
1014 return NULL;
1015
1016 /* It is the caller's responsibility to ensure the path is absolute. */
1017 if (path[0] == 0 || path[0] != '/')
1018 {
1019 JCL_free_cstring (env, jpath, path);
1020 JCL_ThrowException (env, "java/lang/RuntimeException", "Not absolute");
1021 return NULL;
1022 }
1023
1024 len = strlen (path);
1025 srcl = nextChunkSize (len + 1);
1026 src = JCL_malloc (env, srcl);
1027 if (src == NULL)
1028 {
1029 JCL_free_cstring (env, jpath, path);
1030 return NULL;
1031 }
1032 strcpy (src, path);
1033 JCL_free_cstring (env, jpath, path);
1034 srci = 1;
1035
1036 dstl = nextChunkSize (2);
1037 dst = JCL_malloc (env, dstl);
1038 if (dst == NULL)
1039 {
1040 JCL_free (env, src);
1041 return NULL;
1042 }
1043 dst[0] = '/';
1044 dsti = 1;
1045
1046 fschecks = JNI_TRUE;
1047
1048 while (src[srci] != '\0')
1049 {
1050 int tmpi, dsti_save;
1051
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;
1063
1064 /* Handle "." and "..". */
1065 if (len == 1 && src[tmpi] == '.')
1066 continue;
1067 if (len == 2 && src[tmpi] == '.' && src[tmpi + 1] == '.')
1068 {
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.
1077 */
1078 fschecks = JNI_TRUE;
1079 continue;
1080 }
1081
1082 /* Handle real path components. */
1083 dst = maybeGrowBuf (env,
1084 dst, &dstl, dsti + (dsti > 1 ? 1 : 0) + len + 1);
1085 if (dst == NULL)
1086 {
1087 JCL_free (env, src);
1088 return NULL;
1089 }
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;
1097
1098 #if defined (HAVE_LSTAT) && defined (HAVE_READLINK)
1099 dst[dsti] = '\0';
1100 if (lstat (dst, &sb) == 0)
1101 {
1102 if (S_ISLNK (sb.st_mode))
1103 {
1104 int tmpl = CHUNKSIZ;
1105 char *tmp = JCL_malloc (env, tmpl);
1106 if (tmp == NULL)
1107 {
1108 JCL_free (env, src);
1109 JCL_free (env, dst);
1110 return NULL;
1111 }
1112
1113 while (1)
1114 {
1115 tmpi = readlink (dst, tmp, tmpl);
1116 if (tmpi < 1)
1117 {
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;
1124 }
1125 if (tmpi < tmpl)
1126 break;
1127 tmpl += CHUNKSIZ;
1128 tmp = JCL_realloc (env, tmp, tmpl);
1129 }
1130
1131 /* Prepend the link's path to src. */
1132 tmp = maybeGrowBuf (env,
1133 tmp, &tmpl, tmpi + strlen (&src[srci]) + 1);
1134 if (tmp == NULL)
1135 {
1136 JCL_free (env, src);
1137 JCL_free (env, dst);
1138 return NULL;
1139 }
1140
1141 strcpy (&tmp[tmpi], &src[srci]);
1142 JCL_free (env, src);
1143 src = tmp;
1144 srcl = tmpl;
1145 srci = 0;
1146
1147 /* Either replace or append dst depending on whether the
1148 * link is relative or absolute.
1149 */
1150 dsti = src[0] == '/' ? 1 : dsti_save;
1151 }
1152 }
1153 else
1154 {
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.
1159 */
1160 fschecks = JNI_FALSE;
1161 }
1162 #endif /* HAVE_LSTAT && HAVE_READLINK */
1163 }
1164 dst[dsti] = '\0';
1165
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 */
1173 }
1174
1175 /*************************************************************************/
1176
1177 /* ***** PRIVATE FUNCTIONS IMPLEMENTATION ***** */
1178
set_file_permissions(JNIEnv * env,jstring name,jboolean enable,jboolean ownerOnly,int permissions)1179 static jboolean set_file_permissions (JNIEnv *env, jstring name,
1180 jboolean enable,
1181 jboolean ownerOnly,
1182 int permissions)
1183 {
1184 #ifndef WITHOUT_FILESYSTEM
1185 const char *filename;
1186 int result = JNI_FALSE;
1187
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)
1192 {
1193 return JNI_FALSE;
1194 }
1195
1196 if (ownerOnly)
1197 {
1198 permissions |= CPFILE_FLAG_USR;
1199 }
1200
1201 if (!enable)
1202 {
1203 permissions |= CPFILE_FLAG_OFF;
1204 }
1205
1206 result = cpio_chmod (filename, permissions);
1207 (*env)->ReleaseStringUTFChars (env, name, filename);
1208
1209 return result == CPNATIVE_OK ? JNI_TRUE : JNI_FALSE;
1210
1211 #else /* not WITHOUT_FILESYSTEM */
1212 return JNI_FALSE;
1213 #endif /* not WITHOUT_FILESYSTEM */
1214 }
1215