1 /*
2  * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 #include "jni.h"
27 #include "jni_util.h"
28 #include "jvm.h"
29 #include "jlong.h"
30 
31 #include <stdio.h>
32 #include <string.h>
33 #include <dlfcn.h>
34 #include <errno.h>
35 #include <mntent.h>
36 
37 #include "sun_nio_fs_LinuxNativeDispatcher.h"
38 
39 typedef size_t fgetxattr_func(int fd, const char* name, void* value, size_t size);
40 typedef int fsetxattr_func(int fd, const char* name, void* value, size_t size, int flags);
41 typedef int fremovexattr_func(int fd, const char* name);
42 typedef int flistxattr_func(int fd, char* list, size_t size);
43 
44 fgetxattr_func* my_fgetxattr_func = NULL;
45 fsetxattr_func* my_fsetxattr_func = NULL;
46 fremovexattr_func* my_fremovexattr_func = NULL;
47 flistxattr_func* my_flistxattr_func = NULL;
48 
49 static jfieldID entry_name;
50 static jfieldID entry_dir;
51 static jfieldID entry_fstype;
52 static jfieldID entry_options;
53 
throwUnixException(JNIEnv * env,int errnum)54 static void throwUnixException(JNIEnv* env, int errnum) {
55     jobject x = JNU_NewObjectByName(env, "sun/nio/fs/UnixException",
56         "(I)V", errnum);
57     if (x != NULL) {
58         (*env)->Throw(env, x);
59     }
60 }
61 
62 JNIEXPORT void JNICALL
Java_sun_nio_fs_LinuxNativeDispatcher_init(JNIEnv * env,jclass clazz)63 Java_sun_nio_fs_LinuxNativeDispatcher_init(JNIEnv *env, jclass clazz)
64 {
65     my_fgetxattr_func = (fgetxattr_func*)dlsym(RTLD_DEFAULT, "fgetxattr");
66     my_fsetxattr_func = (fsetxattr_func*)dlsym(RTLD_DEFAULT, "fsetxattr");
67     my_fremovexattr_func = (fremovexattr_func*)dlsym(RTLD_DEFAULT, "fremovexattr");
68     my_flistxattr_func = (flistxattr_func*)dlsym(RTLD_DEFAULT, "flistxattr");
69 
70     clazz = (*env)->FindClass(env, "sun/nio/fs/UnixMountEntry");
71     CHECK_NULL(clazz);
72     entry_name = (*env)->GetFieldID(env, clazz, "name", "[B");
73     CHECK_NULL(entry_name);
74     entry_dir = (*env)->GetFieldID(env, clazz, "dir", "[B");
75     CHECK_NULL(entry_dir);
76     entry_fstype = (*env)->GetFieldID(env, clazz, "fstype", "[B");
77     CHECK_NULL(entry_fstype);
78     entry_options = (*env)->GetFieldID(env, clazz, "opts", "[B");
79     CHECK_NULL(entry_options);
80 }
81 
82 JNIEXPORT jint JNICALL
Java_sun_nio_fs_LinuxNativeDispatcher_fgetxattr0(JNIEnv * env,jclass clazz,jint fd,jlong nameAddress,jlong valueAddress,jint valueLen)83 Java_sun_nio_fs_LinuxNativeDispatcher_fgetxattr0(JNIEnv* env, jclass clazz,
84     jint fd, jlong nameAddress, jlong valueAddress, jint valueLen)
85 {
86     size_t res = -1;
87     const char* name = jlong_to_ptr(nameAddress);
88     void* value = jlong_to_ptr(valueAddress);
89 
90     if (my_fgetxattr_func == NULL) {
91         errno = ENOTSUP;
92     } else {
93         /* EINTR not documented */
94         res = (*my_fgetxattr_func)(fd, name, value, valueLen);
95     }
96     if (res == (size_t)-1)
97         throwUnixException(env, errno);
98     return (jint)res;
99 }
100 
101 JNIEXPORT void JNICALL
Java_sun_nio_fs_LinuxNativeDispatcher_fsetxattr0(JNIEnv * env,jclass clazz,jint fd,jlong nameAddress,jlong valueAddress,jint valueLen)102 Java_sun_nio_fs_LinuxNativeDispatcher_fsetxattr0(JNIEnv* env, jclass clazz,
103     jint fd, jlong nameAddress, jlong valueAddress, jint valueLen)
104 {
105     int res = -1;
106     const char* name = jlong_to_ptr(nameAddress);
107     void* value = jlong_to_ptr(valueAddress);
108 
109     if (my_fsetxattr_func == NULL) {
110         errno = ENOTSUP;
111     } else {
112         /* EINTR not documented */
113         res = (*my_fsetxattr_func)(fd, name, value, valueLen, 0);
114     }
115     if (res == -1)
116         throwUnixException(env, errno);
117 }
118 
119 JNIEXPORT void JNICALL
Java_sun_nio_fs_LinuxNativeDispatcher_fremovexattr0(JNIEnv * env,jclass clazz,jint fd,jlong nameAddress)120 Java_sun_nio_fs_LinuxNativeDispatcher_fremovexattr0(JNIEnv* env, jclass clazz,
121     jint fd, jlong nameAddress)
122 {
123     int res = -1;
124     const char* name = jlong_to_ptr(nameAddress);
125 
126     if (my_fremovexattr_func == NULL) {
127         errno = ENOTSUP;
128     } else {
129         /* EINTR not documented */
130         res = (*my_fremovexattr_func)(fd, name);
131     }
132     if (res == -1)
133         throwUnixException(env, errno);
134 }
135 
136 JNIEXPORT jint JNICALL
Java_sun_nio_fs_LinuxNativeDispatcher_flistxattr(JNIEnv * env,jclass clazz,jint fd,jlong listAddress,jint size)137 Java_sun_nio_fs_LinuxNativeDispatcher_flistxattr(JNIEnv* env, jclass clazz,
138     jint fd, jlong listAddress, jint size)
139 {
140     size_t res = -1;
141     char* list = jlong_to_ptr(listAddress);
142 
143     if (my_flistxattr_func == NULL) {
144         errno = ENOTSUP;
145     } else {
146         /* EINTR not documented */
147         res = (*my_flistxattr_func)(fd, list, (size_t)size);
148     }
149     if (res == (size_t)-1)
150         throwUnixException(env, errno);
151     return (jint)res;
152 }
153 
154 JNIEXPORT jlong JNICALL
Java_sun_nio_fs_LinuxNativeDispatcher_setmntent0(JNIEnv * env,jclass this,jlong pathAddress,jlong modeAddress)155 Java_sun_nio_fs_LinuxNativeDispatcher_setmntent0(JNIEnv* env, jclass this, jlong pathAddress,
156                                                  jlong modeAddress)
157 {
158     FILE* fp = NULL;
159     const char* path = (const char*)jlong_to_ptr(pathAddress);
160     const char* mode = (const char*)jlong_to_ptr(modeAddress);
161 
162     do {
163         fp = setmntent(path, mode);
164     } while (fp == NULL && errno == EINTR);
165     if (fp == NULL) {
166         throwUnixException(env, errno);
167     }
168     return ptr_to_jlong(fp);
169 }
170 
171 JNIEXPORT jint JNICALL
Java_sun_nio_fs_LinuxNativeDispatcher_getmntent(JNIEnv * env,jclass this,jlong value,jobject entry)172 Java_sun_nio_fs_LinuxNativeDispatcher_getmntent(JNIEnv* env, jclass this,
173     jlong value, jobject entry)
174 {
175     struct mntent ent;
176     char buf[1024];
177     int buflen = sizeof(buf);
178     struct mntent* m;
179     FILE* fp = jlong_to_ptr(value);
180     jsize len;
181     jbyteArray bytes;
182     char* name;
183     char* dir;
184     char* fstype;
185     char* options;
186 
187     m = getmntent_r(fp, &ent, (char*)&buf, buflen);
188     if (m == NULL)
189         return -1;
190     name = m->mnt_fsname;
191     dir = m->mnt_dir;
192     fstype = m->mnt_type;
193     options = m->mnt_opts;
194 
195     len = strlen(name);
196     bytes = (*env)->NewByteArray(env, len);
197     if (bytes == NULL)
198         return -1;
199     (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)name);
200     (*env)->SetObjectField(env, entry, entry_name, bytes);
201 
202     len = strlen(dir);
203     bytes = (*env)->NewByteArray(env, len);
204     if (bytes == NULL)
205         return -1;
206     (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)dir);
207     (*env)->SetObjectField(env, entry, entry_dir, bytes);
208 
209     len = strlen(fstype);
210     bytes = (*env)->NewByteArray(env, len);
211     if (bytes == NULL)
212         return -1;
213     (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)fstype);
214     (*env)->SetObjectField(env, entry, entry_fstype, bytes);
215 
216     len = strlen(options);
217     bytes = (*env)->NewByteArray(env, len);
218     if (bytes == NULL)
219         return -1;
220     (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)options);
221     (*env)->SetObjectField(env, entry, entry_options, bytes);
222 
223     return 0;
224 }
225 
226 JNIEXPORT void JNICALL
Java_sun_nio_fs_LinuxNativeDispatcher_endmntent(JNIEnv * env,jclass this,jlong stream)227 Java_sun_nio_fs_LinuxNativeDispatcher_endmntent(JNIEnv* env, jclass this, jlong stream)
228 {
229     FILE* fp = jlong_to_ptr(stream);
230     /* FIXME - man page doesn't explain how errors are returned */
231     endmntent(fp);
232 }
233