b2f563b862a968b1be2df19cac408ef420db69f3
[openafs.git] / src / JAVA / libjafs / File.c
1 /*
2  * Copyright (c) 2001-2002 International Business Machines Corp.
3  * All rights reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  * 
9  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
10  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
11  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
12  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR
13  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
14  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
15  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
16  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
17  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
18  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
19  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
20  */
21
22 #if 0
23 #include <afs/param.h>
24 #include <errno.h>
25 #endif
26
27 #include "Internal.h"
28 #include "org_openafs_jafs_File.h"
29
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #include <jni.h>
33 #include <pthread.h>
34 #include <afs/afs_usrops.h>
35 #include <afs/prs_fs.h>
36 #include <sys/time.h>
37 #include <unistd.h>
38
39 /* Access Rights */
40 #define UAFS_READ 1
41 #define UAFS_WRITE 2
42 #define UAFS_INSERT 4
43 #define UAFS_LOOKUP 8
44 #define UAFS_DELETE 16
45 #define UAFS_LOCK 32
46 #define UAFS_ADMIN 64
47
48 #ifdef DMALLOC
49 #include "dmalloc.h"
50 #endif
51
52 void setFileNotExistsAttributes(JNIEnv *env, jobject *obj);
53
54 typedef struct {
55     char *fileName;
56     void *next;
57 } FileNameNode;
58
59 /*static char compile_date[] = COMPILE_DATE;*/
60
61 int sub_time(struct timeval *tv1, struct timeval *tv2)
62 {
63    if (tv2->tv_usec > tv1->tv_usec) {
64      tv1->tv_usec += 1000000;
65      tv1->tv_usec -= 1;
66    }
67
68    tv1->tv_usec -= tv2->tv_usec;
69    tv1->tv_sec -= tv2->tv_sec;
70 }
71
72 /**
73  * Sets dirName to the absolute path according to the path field
74  * within the Java File object (obj).
75  *
76  * env      the Java environment
77  * obj      the current Java object
78  */
79 char* getAbsolutePath(JNIEnv *env, jobject *obj, char *dirName)
80 {
81     jclass thisClass;
82     jstring jDirName;
83     jmethodID getAbsolutePathID;
84     char *auxDirName;
85     jfieldID fid;
86
87     thisClass = (*env)->GetObjectClass(env, *obj);
88     if( thisClass == NULL ) {
89       fprintf(stderr, "File::getAbsolutePath(): GetObjectClass failed\n");
90       return NULL;
91     }
92
93     fid = (*env)->GetFieldID(env, thisClass, "path", "Ljava/lang/String;");
94     if ( fid == NULL ) {
95       fprintf(stderr, "File::getAbsolutePath(): GetFieldID (path) failed\n");
96       return NULL;
97     }
98
99     jDirName = (*env)->GetObjectField(env, *obj, fid);
100     if( jDirName == NULL ) {
101       fprintf(stderr, "File::getAbsolutePath(): failed to get file name\n");
102       return NULL;
103     }
104
105     auxDirName = getNativeString(env, jDirName);
106     if ( auxDirName == NULL ) {
107       fprintf(stderr, "File::getAbsolutePath(): failed to get translated file name\n");
108       return NULL;
109     }
110     strcpy(dirName, auxDirName);
111     free( auxDirName );
112 }
113
114 /**
115  * Performs a file stat on the actual AFS file and populates  
116  * the Java object's respective field members with the appropriate values.
117  * method will, if authorized, perform a stat on the
118  * actual AFS file and update its respective field members; defining
119  * this file object's attributes.
120  *
121  * env      the Java environment
122  * obj      the current Java object
123  *
124  * return  true if and only if the current user is allowed to stat the file;
125  *         false otherwise.
126  *
127  * throws AFSException
128  */
129 JNIEXPORT jboolean JNICALL Java_org_openafs_jafs_File_setAttributes
130   (JNIEnv *env, jobject obj)
131 {
132     char target[FILENAME_MAX+1];
133     char dirName[FILENAME_MAX];
134     jclass thisClass;
135     jfieldID fid;
136     struct stat st;
137     int rc, fd;
138     int mtpoint = 0;
139     jboolean islink = JNI_FALSE;
140     int i;
141     struct timeval tv0, tv1;
142     struct timezone tz;
143
144     /*memset(target, 0, FILENAME_MAX);*/
145
146     *dirName = '\0';
147     getAbsolutePath(env, &obj, dirName);
148
149     /*fprintf(stderr, "dirName=%s\n", dirName);*/
150
151     if(*dirName == '\0') {
152       fprintf(stderr, "File::setAttributes(): failed to get dirName\n");
153       return JNI_FALSE;
154     }
155
156     thisClass = (*env) -> GetObjectClass(env, obj);
157     if(thisClass == NULL) {
158       fprintf(stderr, "File::setAttributes(): GetObjectClass failed\n");
159       return JNI_FALSE;
160     }
161
162     gettimeofday(&tv0, &tz);
163     if ((strcmp(dirName, "/afs") == 0) || (strcmp(dirName, "/afs/") == 0)) {
164       rc = 1;   /* special case for /afs since statmountpoint fails on it */
165     } else {
166       rc = uafs_statmountpoint(dirName);
167       gettimeofday(&tv1, &tz);
168       sub_time(&tv1, &tv0);
169       /*printf("%s: statmountpoint %d.%06d\n", dirName, tv1.tv_sec, tv1.tv_usec);*/
170     }
171
172     if(rc < 0) {
173       setError(env, &obj, errno);
174       if(errno == ENOENT) {
175         setFileNotExistsAttributes(env, &obj);
176         return JNI_TRUE;   /* not really an error */
177       } else {
178         fprintf(stderr, "File::setAttributes(): uafs_statmountpoint failed "
179                         "for %s (%s)\n", dirName, error_message(errno));
180         return JNI_FALSE;
181       }
182     }
183
184     if (rc == 1) {
185       /* this is an AFS mount point; we don't want to stat it */
186       /* fake up a stat entry instead */
187       mtpoint = 1;
188       st.st_mtime = 0;
189       st.st_size = 2048;
190       st.st_mode = 0;  /* don't match anything */
191     } else {
192       mtpoint = 0;
193       fid = (*env)->GetFieldID(env, thisClass, "isLink", "Z");
194       if (fid == 0) {
195         fprintf(stderr, "File::setAttributes(): GetFieldID (isLink) failed\n");
196         setError(env, &obj, -1);
197         return JNI_FALSE;
198       }
199       islink = (*env)->GetBooleanField(env, obj, fid);
200       if (islink != JNI_TRUE) {
201         rc = uafs_lstat(dirName, &st);
202       } else {
203         /* Here we are being called on a link object for the second time,
204            so we want info on the object pointed to by the link. */
205         fprintf(stderr, "islink = TRUE on file %s\n", dirName);
206         rc = uafs_stat(dirName, &st);
207       }
208
209       if(rc < 0) {
210         setError(env, &obj, errno);
211         fprintf(stderr, "uafs_lstat failed for dir %s: error %d\n",
212                          dirName, errno);
213         if(errno == ENOENT) {
214           setFileNotExistsAttributes(env, &obj);
215           return JNI_TRUE;
216         }
217         fprintf(stderr, 
218             "File::setAttributes(): uafs_stat failed for %s (%s)\n", 
219              dirName, error_message(errno));
220         return JNI_FALSE;
221       }
222     }
223
224     fid = (*env)->GetFieldID(env, thisClass, "exists", "Z");
225     if (fid == 0) {
226       fprintf(stderr, 
227             "File::setAttributes(): GetFieldID (exists) failed\n");
228       setError(env, &obj, -1);
229       return JNI_FALSE;
230     }
231     (*env)->SetBooleanField(env, obj, fid, JNI_TRUE);
232
233     fid = (*env)->GetFieldID(env, thisClass, "isDirectory", "Z");
234     if (fid == 0) {
235       fprintf(stderr, 
236             "File::setAttributes(): GetFieldID (isDirectory) failed\n");
237       setError(env, &obj, -1);
238       return JNI_FALSE;
239     }
240     if ((st.st_mode & S_IFMT) == S_IFDIR && !mtpoint) {
241       (*env)->SetBooleanField(env, obj, fid, JNI_TRUE);
242     } else {
243       (*env)->SetBooleanField(env, obj, fid, JNI_FALSE);
244     }
245
246     fid = (*env)->GetFieldID(env, thisClass, "isFile", "Z");
247     if (fid == 0) {
248       fprintf(stderr, 
249             "File::setAttributes(): GetFieldID (isFile) failed\n");
250       setError(env, &obj, -1);
251       return JNI_FALSE;
252     }
253     if ((st.st_mode & S_IFMT) == S_IFREG) {
254       (*env)->SetBooleanField(env, obj, fid, JNI_TRUE);
255     } else {
256       (*env)->SetBooleanField(env, obj, fid, JNI_FALSE);
257     }
258
259     fid = (*env)->GetFieldID(env, thisClass, "isLink", "Z");
260     if (fid == 0) {
261       fprintf(stderr, 
262             "File::setAttributes(): GetFieldID (isLink) failed\n");
263       setError(env, &obj, -1);
264       return JNI_FALSE;
265     }
266
267     if (islink != JNI_TRUE) {    /* don't re-process link */
268       if ((st.st_mode & S_IFMT) == S_IFLNK) {
269         (*env)->SetBooleanField(env, obj, fid, JNI_TRUE);
270
271         /* Find the target of the link */
272         rc = uafs_readlink(dirName, target, FILENAME_MAX);
273         if (rc < 0) {
274           fprintf(stderr, "File::setAttributes(): uafs_readlink failed\n");
275           setError(env, &obj, errno);
276           return JNI_FALSE;
277         } else {
278           target[rc] = 0;     /* weird that we have to do this */
279           /*fprintf(stderr, "readlink %s succeeded, target=%s, rc=%d\n", dirName,
280             target, rc);*/
281         }
282
283         rc = setString(env, &obj, "target", target);
284         if (rc < 0) {
285           fprintf(stderr, "setString dirName=%s target=%s failed\n",
286                            dirName, target);
287         }
288       } else {
289         (*env)->SetBooleanField(env, obj, fid, JNI_FALSE);
290       }
291     }
292
293     fid = (*env)->GetFieldID(env, thisClass, "isMountPoint", "Z");
294     if (fid == 0) {
295       fprintf(stderr, 
296             "File::setAttributes(): GetFieldID (isMountPoint) failed\n");
297       setError(env, &obj, -1);
298       return JNI_FALSE;
299     }
300
301     if (mtpoint) {
302       (*env)->SetBooleanField(env, obj, fid, JNI_TRUE);
303     } else {
304       (*env)->SetBooleanField(env, obj, fid, JNI_FALSE);
305     }
306
307     fid = (*env)->GetFieldID(env, thisClass, "lastModified", "J");
308     if (fid == 0) {
309       fprintf(stderr, 
310             "File::setAttributes(): GetFieldID (lastModified) failed\n");
311       setError(env, &obj, -1);
312       return JNI_FALSE;
313     }
314     (*env)->SetLongField(env, obj, fid, ((jlong) st.st_mtime)*1000);
315
316     fid = (*env)->GetFieldID(env, thisClass, "length", "J");
317     if (fid == 0) {
318       fprintf(stderr, 
319             "File::setAttributes(): GetFieldID (length) failed\n");
320       setError(env, &obj, -1);
321       return JNI_FALSE;
322     }
323     (*env)->SetLongField(env, obj, fid, st.st_size);
324
325     setError(env, &obj, 0);
326
327     return JNI_TRUE;
328 }
329
330 /**
331  * Returns the permission/ACL mask for the represented directory
332  *
333  * env      the Java environment
334  * obj      the current Java object
335  *
336  * return  permission/ACL mask
337  */
338 JNIEXPORT jint JNICALL Java_org_openafs_jafs_File_getRights
339   (JNIEnv *env, jobject obj)
340 {
341     char dirName[FILENAME_MAX];
342     jclass thisClass;
343     jfieldID fid;
344     int rc;
345     int afs_rights;
346     int rights;
347
348     *dirName = '\0';
349     getAbsolutePath(env, &obj, dirName);
350
351     if(*dirName == '\0') {
352       fprintf(stderr, "File::getRights(): failed to get dirName\n");
353       setError(env, &obj, -1);
354       return JNI_FALSE;
355     }
356
357     /*-Access Rights-
358      * UAFS_READ 1
359      * UAFS_WRITE 2
360      * UAFS_INSERT 4
361      * UAFS_LOOKUP 8
362      * UAFS_DELETE 16
363      * UAFS_LOCK 32
364      * UAFS_ADMIN 64
365      */
366
367     rights = 0;
368     afs_rights = uafs_getRights(dirName);
369     if (afs_rights < 0) {
370       setError(env, &obj, errno);
371       return -1;
372     }
373     
374     if (afs_rights & PRSFS_READ)
375       rights |= UAFS_READ;
376     if (afs_rights & PRSFS_WRITE)
377       rights |= UAFS_WRITE;
378     if (afs_rights & PRSFS_INSERT)
379       rights |= UAFS_INSERT;
380     if (afs_rights & PRSFS_LOOKUP)
381       rights |= UAFS_LOOKUP;
382     if (afs_rights & PRSFS_DELETE)
383       rights |= UAFS_DELETE;
384     if (afs_rights & PRSFS_LOCK)
385       rights |= UAFS_LOCK;
386     if (afs_rights & PRSFS_ADMINISTER)
387       rights |= UAFS_ADMIN;
388     
389     return rights;
390 }
391
392
393 /**
394  * List the contents of the represented directory.
395  *
396  * env      the Java environment
397  * obj      the current Java object
398  *
399  * return   the directory handle
400  */
401 JNIEXPORT jlong JNICALL Java_org_openafs_jafs_File_listNative
402   (JNIEnv *env, jobject obj, jobject buffer)
403 {
404     char dirName[FILENAME_MAX];
405     jclass arrayListClass;
406     jmethodID addID;
407     jstring entryJString;
408     usr_DIR *dirp;
409     struct usr_dirent *enp;
410     int i, dirSize;
411
412     *dirName='\0';
413     getAbsolutePath(env, &obj, dirName);
414     if(*dirName == '\0') {
415       fprintf(stderr, "File::listNative(): failed to get dirName\n");
416       setError(env, &obj, -1);
417       return 0;
418     }
419     arrayListClass = (*env)->GetObjectClass(env, buffer);
420     if(arrayListClass == NULL) {
421       fprintf(stderr, "File::listNative(): GetObjectClass failed\n");
422       setError(env, &obj, -1);
423       return 0;
424     }
425     addID = (*env) -> GetMethodID(env, arrayListClass, "add", 
426                                   "(Ljava/lang/Object;)Z");
427     if(addID == 0) {
428       fprintf(stderr, 
429             "File::listNative(): failed to get addID\n");
430       setError(env, &obj, -1);
431       return 0;
432     }
433     dirp = uafs_opendir(dirName);
434     if(dirp == NULL) {
435       fprintf(stderr, "File::listNative(): uafs_opendir(%s) failed(%s)\n",
436                        dirName, error_message(errno));
437       setError(env, &obj, errno);
438       //throwAFSSecurityException( env, errno );
439       return 0;
440     }
441     while((enp = uafs_readdir(dirp)) != NULL) {
442         if(strcmp(enp->d_name, ".") == 0 || strcmp(enp->d_name, "..") == 0) {
443         continue;
444         }
445       entryJString = (*env) -> NewStringUTF(env, enp->d_name);
446       if(entryJString == NULL) {
447         fprintf(stderr, "File::listNative(): NewStringUTF failed\n");
448         setError(env, &obj, -1);
449         return 0;
450       }
451       (*env) -> CallBooleanMethod(env, buffer, addID, entryJString);
452     }
453     /*uafs_closedir(dirp);*/
454
455     setError(env, &obj, 0);
456
457     return (jlong) dirp;
458 }
459
460 /**
461  * Close the currently open directory using a provided directory handle.
462  *
463  * env      the Java environment
464  * obj      the current Java object
465  *
466  * return  true if the directory closes without error
467  */
468 JNIEXPORT jboolean JNICALL Java_org_openafs_jafs_File_closeDir
469   (JNIEnv *env, jobject obj, jlong dp)
470 {
471   usr_DIR *dirp = (usr_DIR *) dp;
472   int rc;
473   
474   rc = uafs_closedir(dirp);
475   if (rc < 0) {
476     setError(env, &obj, errno);
477     return JNI_FALSE;
478   } else {
479     return JNI_TRUE;
480   }
481 }
482
483
484 /**
485  * Removes/deletes the represented file.
486  *
487  * env      the Java environment
488  * obj      the current Java object
489  *
490  * return  true if the file is removed without error
491  */
492 JNIEXPORT jboolean JNICALL Java_org_openafs_jafs_File_rmfile
493   (JNIEnv *env, jobject obj)
494 {
495     char dirName[FILENAME_MAX];
496     int rc;
497
498     *dirName='\0';
499     getAbsolutePath(env, &obj, dirName);
500     if(*dirName == '\0') {
501       setError(env, &obj, EINVAL);
502       fprintf(stderr, "File::rmfile(): failed to get dirName\n");
503       return JNI_FALSE;
504     }
505     rc = uafs_unlink(dirName);
506     if(rc < 0) {
507       setError(env, &obj, errno);
508       fprintf(stderr, "File::rmfile(): uafs_unlink failed\n");
509       return JNI_FALSE;
510     }
511     setError(env, &obj, 0);
512     return JNI_TRUE;
513 }
514
515 /**
516  * Removes/deletes the represented directory.
517  *
518  * env      the Java environment
519  * obj      the current Java object
520  *
521  * return  true if the directory is removed without error
522  */
523 JNIEXPORT jboolean JNICALL Java_org_openafs_jafs_File_rmdir
524   (JNIEnv *env, jobject obj)
525 {
526     char dirName[FILENAME_MAX];
527     int rc;
528
529     *dirName='\0';
530     getAbsolutePath(env, &obj, dirName);
531     if(*dirName == '\0') {
532       setError(env, &obj, -1);
533       fprintf(stderr, "File::rmdir(): failed to get dirName\n");
534       return JNI_FALSE;
535     }
536     rc = uafs_rmdir(dirName);
537     if(rc < 0) {
538       setError(env, &obj, errno);
539       fprintf(stderr, "File::rmdir(): uafs_unlink failed\n");
540       return JNI_FALSE;
541     }
542     setError(env, &obj, 0);
543     return JNI_TRUE;
544 }
545
546 /**
547  * Creates the directory named by this abstract pathname.
548  *
549  * env      the Java environment
550  * obj      the current Java object
551  *
552  * return  true if and only if the directory was
553  *          created; false otherwise
554  */
555 JNIEXPORT jboolean JNICALL Java_org_openafs_jafs_File_mkdir
556   (JNIEnv *env, jobject obj)
557 {
558     char dirName[FILENAME_MAX];
559     int rc;
560
561     *dirName='\0';
562     getAbsolutePath(env, &obj, dirName);
563     if(*dirName == '\0') {
564       setError(env, &obj, EINVAL);
565       fprintf(stderr, "File::mkdir(): failed to get dirName\n");
566       return JNI_FALSE;
567     }
568     rc = uafs_mkdir(dirName, 0755);
569     if(rc < 0) {
570       setError(env, &obj, errno);
571       fprintf(stderr, "File::mkdir(): uafs_mkdir failed\n");
572       return JNI_FALSE;
573     }
574     setError(env, &obj, 0);
575     return JNI_TRUE;
576 }
577
578 /**
579  * Renames the file denoted by this abstract pathname.
580  *
581  * env      the Java environment
582  * obj      the current Java object
583  * dest     the new abstract pathname for the named file
584  * 
585  * return   true if and only if the renaming succeeded;
586  *          false otherwise
587  *
588  * throws   NullPointerException  
589  *          If parameter dest is null
590  */
591 JNIEXPORT jboolean JNICALL Java_org_openafs_jafs_File_renameTo
592   (JNIEnv *env, jobject obj, jobject newFile)
593 {
594     char thisDirName[FILENAME_MAX], newDirName[FILENAME_MAX];
595     int rc;
596
597     *thisDirName='\0';
598     getAbsolutePath(env, &obj, thisDirName);
599     if(*thisDirName == '\0') {
600       setError(env, &obj, -1);
601       fprintf(stderr, "File::renameTo(): failed to get dirName for this \n");
602       return JNI_FALSE;
603     }
604     *newDirName='\0';
605     getAbsolutePath(env, &newFile, newDirName);
606     if(*newDirName == '\0') {
607       setError(env, &obj, -1);
608       fprintf(stderr, "File::renameTo(): failed to get dirName for new \n");
609       return JNI_FALSE;
610     }
611     rc = uafs_rename(thisDirName, newDirName);
612     if(rc < 0) {
613       setError(env, &obj, errno);
614       fprintf(stderr, "File::renameTo(): uafs_rename failed\n");
615       return JNI_FALSE;
616     }
617     return JNI_TRUE;
618 }
619
620 /**
621  * Set all the necessary fields within the Java File class to indicate the
622  * does not exist.
623  *
624  * env      the Java environment
625  * obj      the current Java object
626  */
627 void setFileNotExistsAttributes
628     (JNIEnv *env, jobject *obj)
629 {
630     jclass thisClass;
631     jfieldID fid;
632
633     thisClass = (*env) -> GetObjectClass(env, *obj);
634     if(thisClass == NULL) {
635       fprintf(stderr, 
636             "File::setFileNotExistsAttributes(): GetObjectClass failed\n");
637       return;
638     }
639
640     fid = (*env)->GetFieldID(env, thisClass, "exists", "Z");
641     if (fid == 0) {
642       fprintf(stderr, 
643             "File::setFileNotExistsAttributes(): GetFieldID (exists) failed\n");
644       return;
645     }
646     (*env)->SetBooleanField(env, *obj, fid, JNI_FALSE);
647
648     fid = (*env)->GetFieldID(env, thisClass, "isDirectory", "Z");
649     if (fid == 0) {
650       fprintf(stderr, 
651             "File::setFileNotExistsAttributes(): GetFieldID (isDirectory) failed\n");
652       return;
653     }
654     (*env)->SetBooleanField(env, *obj, fid, JNI_FALSE);
655
656     fid = (*env)->GetFieldID(env, thisClass, "isFile", "Z");
657     if (fid == 0) {
658       fprintf(stderr, 
659             "File::setFileNotExistsAttributes(): GetFieldID (isDirectory) failed\n");
660       return;
661     }
662     (*env)->SetBooleanField(env, *obj, fid, JNI_FALSE);
663
664     fid = (*env)->GetFieldID(env, thisClass, "lastModified", "J");
665     if (fid == 0) {
666       fprintf(stderr, 
667             "File::setFileNotExistsAttributes(): GetFieldID (lastModified) failed\n");
668       return;
669     }
670     (*env)->SetLongField(env, *obj, fid, 0);
671
672     
673     fid = (*env)->GetFieldID(env, thisClass, "length", "J");
674     if (fid == 0) {
675       fprintf(stderr, 
676             "File::setFileNotExistsAttributes(): GetFieldID (length) failed\n");
677       return;
678     }
679     (*env)->SetLongField(env, *obj, fid, 0);
680
681     return;
682 }