|
1 /* |
|
2 * Copyright 2008-2009 Sun Microsystems, Inc. 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. Sun designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
|
22 * CA 95054 USA or visit www.sun.com if you need additional information or |
|
23 * have any questions. |
|
24 */ |
|
25 |
|
26 #include <stdio.h> |
|
27 #include <stdlib.h> |
|
28 #include <limits.h> |
|
29 #include <fcntl.h> |
|
30 #include <dirent.h> |
|
31 #include <unistd.h> |
|
32 #include <pwd.h> |
|
33 #include <grp.h> |
|
34 #include <errno.h> |
|
35 #include <dlfcn.h> |
|
36 #include <sys/types.h> |
|
37 #include <sys/stat.h> |
|
38 #include <sys/statvfs.h> |
|
39 #include <sys/time.h> |
|
40 |
|
41 #ifdef __solaris__ |
|
42 #include <strings.h> |
|
43 #include <sys/mnttab.h> |
|
44 #include <sys/mkdev.h> |
|
45 #endif |
|
46 |
|
47 #ifdef __linux__ |
|
48 #include <string.h> |
|
49 #include <mntent.h> |
|
50 #endif |
|
51 |
|
52 #include "jni.h" |
|
53 #include "jni_util.h" |
|
54 #include "jlong.h" |
|
55 |
|
56 #include "sun_nio_fs_UnixNativeDispatcher.h" |
|
57 |
|
58 #define RESTARTABLE(_cmd, _result) do { \ |
|
59 do { \ |
|
60 _result = _cmd; \ |
|
61 } while((_result == -1) && (errno == EINTR)); \ |
|
62 } while(0) |
|
63 |
|
64 static jfieldID attrs_st_mode; |
|
65 static jfieldID attrs_st_ino; |
|
66 static jfieldID attrs_st_dev; |
|
67 static jfieldID attrs_st_rdev; |
|
68 static jfieldID attrs_st_nlink; |
|
69 static jfieldID attrs_st_uid; |
|
70 static jfieldID attrs_st_gid; |
|
71 static jfieldID attrs_st_size; |
|
72 static jfieldID attrs_st_atime; |
|
73 static jfieldID attrs_st_mtime; |
|
74 static jfieldID attrs_st_ctime; |
|
75 |
|
76 static jfieldID attrs_f_frsize; |
|
77 static jfieldID attrs_f_blocks; |
|
78 static jfieldID attrs_f_bfree; |
|
79 static jfieldID attrs_f_bavail; |
|
80 |
|
81 static jfieldID entry_name; |
|
82 static jfieldID entry_dir; |
|
83 static jfieldID entry_fstype; |
|
84 static jfieldID entry_options; |
|
85 static jfieldID entry_dev; |
|
86 |
|
87 /** |
|
88 * System calls that may not be available at build time. |
|
89 */ |
|
90 typedef int openat64_func(int, const char *, int, ...); |
|
91 typedef int fstatat64_func(int, const char *, struct stat64 *, int); |
|
92 typedef int unlinkat_func(int, const char*, int); |
|
93 typedef int renameat_func(int, const char*, int, const char*); |
|
94 typedef int futimesat_func(int, const char *, const struct timeval *); |
|
95 typedef DIR* fdopendir_func(int); |
|
96 |
|
97 static openat64_func* my_openat64_func = NULL; |
|
98 static fstatat64_func* my_fstatat64_func = NULL; |
|
99 static unlinkat_func* my_unlinkat_func = NULL; |
|
100 static renameat_func* my_renameat_func = NULL; |
|
101 static futimesat_func* my_futimesat_func = NULL; |
|
102 static fdopendir_func* my_fdopendir_func = NULL; |
|
103 |
|
104 /** |
|
105 * fstatat missing from glibc on Linux. Temporary workaround |
|
106 * for x86/x64. |
|
107 */ |
|
108 #if defined(__linux__) && defined(__i386) |
|
109 #define FSTATAT64_SYSCALL_AVAILABLE |
|
110 static int fstatat64_wrapper(int dfd, const char *path, |
|
111 struct stat64 *statbuf, int flag) |
|
112 { |
|
113 #ifndef __NR_fstatat64 |
|
114 #define __NR_fstatat64 300 |
|
115 #endif |
|
116 return syscall(__NR_fstatat64, dfd, path, statbuf, flag); |
|
117 } |
|
118 #endif |
|
119 |
|
120 #if defined(__linux__) && defined(__x86_64__) |
|
121 #define FSTATAT64_SYSCALL_AVAILABLE |
|
122 static int fstatat64_wrapper(int dfd, const char *path, |
|
123 struct stat64 *statbuf, int flag) |
|
124 { |
|
125 #ifndef __NR_newfstatat |
|
126 #define __NR_newfstatat 262 |
|
127 #endif |
|
128 return syscall(__NR_newfstatat, dfd, path, statbuf, flag); |
|
129 } |
|
130 #endif |
|
131 |
|
132 /** |
|
133 * Call this to throw an internal UnixException when a system/library |
|
134 * call fails |
|
135 */ |
|
136 static void throwUnixException(JNIEnv* env, int errnum) { |
|
137 jobject x = JNU_NewObjectByName(env, "sun/nio/fs/UnixException", |
|
138 "(I)V", errnum); |
|
139 if (x != NULL) { |
|
140 (*env)->Throw(env, x); |
|
141 } |
|
142 } |
|
143 |
|
144 /** |
|
145 * Initialize jfieldIDs |
|
146 */ |
|
147 JNIEXPORT void JNICALL |
|
148 Java_sun_nio_fs_UnixNativeDispatcher_initIDs(JNIEnv* env, jclass this) |
|
149 { |
|
150 jclass clazz; |
|
151 |
|
152 clazz = (*env)->FindClass(env, "sun/nio/fs/UnixFileAttributes"); |
|
153 if (clazz == NULL) { |
|
154 return; |
|
155 } |
|
156 attrs_st_mode = (*env)->GetFieldID(env, clazz, "st_mode", "I"); |
|
157 attrs_st_ino = (*env)->GetFieldID(env, clazz, "st_ino", "J"); |
|
158 attrs_st_dev = (*env)->GetFieldID(env, clazz, "st_dev", "J"); |
|
159 attrs_st_rdev = (*env)->GetFieldID(env, clazz, "st_rdev", "J"); |
|
160 attrs_st_nlink = (*env)->GetFieldID(env, clazz, "st_nlink", "I"); |
|
161 attrs_st_uid = (*env)->GetFieldID(env, clazz, "st_uid", "I"); |
|
162 attrs_st_gid = (*env)->GetFieldID(env, clazz, "st_gid", "I"); |
|
163 attrs_st_size = (*env)->GetFieldID(env, clazz, "st_size", "J"); |
|
164 attrs_st_atime = (*env)->GetFieldID(env, clazz, "st_atime", "J"); |
|
165 attrs_st_mtime = (*env)->GetFieldID(env, clazz, "st_mtime", "J"); |
|
166 attrs_st_ctime = (*env)->GetFieldID(env, clazz, "st_ctime", "J"); |
|
167 |
|
168 clazz = (*env)->FindClass(env, "sun/nio/fs/UnixFileStoreAttributes"); |
|
169 if (clazz == NULL) { |
|
170 return; |
|
171 } |
|
172 attrs_f_frsize = (*env)->GetFieldID(env, clazz, "f_frsize", "J"); |
|
173 attrs_f_blocks = (*env)->GetFieldID(env, clazz, "f_blocks", "J"); |
|
174 attrs_f_bfree = (*env)->GetFieldID(env, clazz, "f_bfree", "J"); |
|
175 attrs_f_bavail = (*env)->GetFieldID(env, clazz, "f_bavail", "J"); |
|
176 |
|
177 clazz = (*env)->FindClass(env, "sun/nio/fs/UnixMountEntry"); |
|
178 if (clazz == NULL) { |
|
179 return; |
|
180 } |
|
181 entry_name = (*env)->GetFieldID(env, clazz, "name", "[B"); |
|
182 entry_dir = (*env)->GetFieldID(env, clazz, "dir", "[B"); |
|
183 entry_fstype = (*env)->GetFieldID(env, clazz, "fstype", "[B"); |
|
184 entry_options = (*env)->GetFieldID(env, clazz, "opts", "[B"); |
|
185 entry_dev = (*env)->GetFieldID(env, clazz, "dev", "J"); |
|
186 |
|
187 /* system calls that might not be available at build time */ |
|
188 |
|
189 #if defined(__solaris__) && defined(_LP64) |
|
190 /* Solaris 64-bit does not have openat64/fstatat64 */ |
|
191 my_openat64_func = (openat64_func*)dlsym(RTLD_DEFAULT, "openat"); |
|
192 my_fstatat64_func = (fstatat64_func*)dlsym(RTLD_DEFAULT, "fstatat"); |
|
193 #else |
|
194 my_openat64_func = (openat64_func*) dlsym(RTLD_DEFAULT, "openat64"); |
|
195 my_fstatat64_func = (fstatat64_func*) dlsym(RTLD_DEFAULT, "fstatat64"); |
|
196 #endif |
|
197 my_unlinkat_func = (unlinkat_func*) dlsym(RTLD_DEFAULT, "unlinkat"); |
|
198 my_renameat_func = (renameat_func*) dlsym(RTLD_DEFAULT, "renameat"); |
|
199 my_futimesat_func = (futimesat_func*) dlsym(RTLD_DEFAULT, "futimesat"); |
|
200 my_fdopendir_func = (fdopendir_func*) dlsym(RTLD_DEFAULT, "fdopendir"); |
|
201 |
|
202 #if defined(FSTATAT64_SYSCALL_AVAILABLE) |
|
203 /* fstatat64 missing from glibc */ |
|
204 if (my_fstatat64_func == NULL) |
|
205 my_fstatat64_func = (fstatat64_func*)&fstatat64_wrapper; |
|
206 #endif |
|
207 } |
|
208 |
|
209 JNIEXPORT jbyteArray JNICALL |
|
210 Java_sun_nio_fs_UnixNativeDispatcher_getcwd(JNIEnv* env, jclass this) { |
|
211 jbyteArray result = NULL; |
|
212 char buf[PATH_MAX+1]; |
|
213 |
|
214 /* EINTR not listed as a possible error */ |
|
215 char* cwd = getcwd(buf, sizeof(buf)); |
|
216 if (cwd == NULL) { |
|
217 throwUnixException(env, errno); |
|
218 } else { |
|
219 jsize len = (jsize)strlen(buf); |
|
220 result = (*env)->NewByteArray(env, len); |
|
221 if (result != NULL) { |
|
222 (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)buf); |
|
223 } |
|
224 } |
|
225 return result; |
|
226 } |
|
227 |
|
228 JNIEXPORT jbyteArray |
|
229 Java_sun_nio_fs_UnixNativeDispatcher_strerror(JNIEnv* env, jclass this, jint error) |
|
230 { |
|
231 char* msg; |
|
232 jsize len; |
|
233 jbyteArray bytes; |
|
234 |
|
235 msg = strerror((int)error); |
|
236 len = strlen(msg); |
|
237 bytes = (*env)->NewByteArray(env, len); |
|
238 if (bytes != NULL) { |
|
239 (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)msg); |
|
240 } |
|
241 return bytes; |
|
242 } |
|
243 |
|
244 JNIEXPORT jint |
|
245 Java_sun_nio_fs_UnixNativeDispatcher_dup(JNIEnv* env, jclass this, jint fd) { |
|
246 |
|
247 int res = -1; |
|
248 |
|
249 RESTARTABLE(dup((int)fd), res); |
|
250 if (fd == -1) { |
|
251 throwUnixException(env, errno); |
|
252 } |
|
253 return (jint)res; |
|
254 } |
|
255 |
|
256 JNIEXPORT jlong JNICALL |
|
257 Java_sun_nio_fs_UnixNativeDispatcher_fopen0(JNIEnv* env, jclass this, |
|
258 jlong pathAddress, jlong modeAddress) |
|
259 { |
|
260 FILE* fp = NULL; |
|
261 const char* path = (const char*)jlong_to_ptr(pathAddress); |
|
262 const char* mode = (const char*)jlong_to_ptr(modeAddress); |
|
263 |
|
264 do { |
|
265 fp = fopen(path, mode); |
|
266 } while (fp == NULL && errno == EINTR); |
|
267 |
|
268 if (fp == NULL) { |
|
269 throwUnixException(env, errno); |
|
270 } |
|
271 |
|
272 return ptr_to_jlong(fp); |
|
273 } |
|
274 |
|
275 JNIEXPORT void JNICALL |
|
276 Java_sun_nio_fs_UnixNativeDispatcher_fclose(JNIEnv* env, jclass this, jlong stream) |
|
277 { |
|
278 int res; |
|
279 FILE* fp = jlong_to_ptr(stream); |
|
280 |
|
281 do { |
|
282 res = fclose(fp); |
|
283 } while (res == EOF && errno == EINTR); |
|
284 if (res == EOF) { |
|
285 throwUnixException(env, errno); |
|
286 } |
|
287 } |
|
288 |
|
289 JNIEXPORT jint JNICALL |
|
290 Java_sun_nio_fs_UnixNativeDispatcher_open0(JNIEnv* env, jclass this, |
|
291 jlong pathAddress, jint oflags, jint mode) |
|
292 { |
|
293 jint fd; |
|
294 const char* path = (const char*)jlong_to_ptr(pathAddress); |
|
295 |
|
296 RESTARTABLE(open64(path, (int)oflags, (mode_t)mode), fd); |
|
297 if (fd == -1) { |
|
298 throwUnixException(env, errno); |
|
299 } |
|
300 return fd; |
|
301 } |
|
302 |
|
303 JNIEXPORT jint JNICALL |
|
304 Java_sun_nio_fs_UnixNativeDispatcher_openat0(JNIEnv* env, jclass this, jint dfd, |
|
305 jlong pathAddress, jint oflags, jint mode) |
|
306 { |
|
307 jint fd; |
|
308 const char* path = (const char*)jlong_to_ptr(pathAddress); |
|
309 |
|
310 if (my_openat64_func == NULL) { |
|
311 JNU_ThrowInternalError(env, "should not reach here"); |
|
312 return -1; |
|
313 } |
|
314 |
|
315 RESTARTABLE((*my_openat64_func)(dfd, path, (int)oflags, (mode_t)mode), fd); |
|
316 if (fd == -1) { |
|
317 throwUnixException(env, errno); |
|
318 } |
|
319 return fd; |
|
320 } |
|
321 |
|
322 JNIEXPORT void JNICALL |
|
323 Java_sun_nio_fs_UnixNativeDispatcher_close(JNIEnv* env, jclass this, jint fd) { |
|
324 int err; |
|
325 /* TDB - need to decide if EIO and other errors should cause exception */ |
|
326 RESTARTABLE(close((int)fd), err); |
|
327 } |
|
328 |
|
329 JNIEXPORT jint JNICALL |
|
330 Java_sun_nio_fs_UnixNativeDispatcher_read(JNIEnv* env, jclass this, jint fd, |
|
331 jlong address, jint nbytes) |
|
332 { |
|
333 ssize_t n; |
|
334 void* bufp = jlong_to_ptr(address); |
|
335 RESTARTABLE(read((int)fd, bufp, (size_t)nbytes), n); |
|
336 if (n == -1) { |
|
337 throwUnixException(env, errno); |
|
338 } |
|
339 return (jint)n; |
|
340 } |
|
341 |
|
342 JNIEXPORT jint JNICALL |
|
343 Java_sun_nio_fs_UnixNativeDispatcher_write(JNIEnv* env, jclass this, jint fd, |
|
344 jlong address, jint nbytes) |
|
345 { |
|
346 ssize_t n; |
|
347 void* bufp = jlong_to_ptr(address); |
|
348 RESTARTABLE(write((int)fd, bufp, (size_t)nbytes), n); |
|
349 if (n == -1) { |
|
350 throwUnixException(env, errno); |
|
351 } |
|
352 return (jint)n; |
|
353 } |
|
354 |
|
355 /** |
|
356 * Copy stat64 members into sun.nio.fs.UnixFileAttributes |
|
357 */ |
|
358 static void prepAttributes(JNIEnv* env, struct stat64* buf, jobject attrs) { |
|
359 (*env)->SetIntField(env, attrs, attrs_st_mode, (jint)buf->st_mode); |
|
360 (*env)->SetLongField(env, attrs, attrs_st_ino, (jlong)buf->st_ino); |
|
361 (*env)->SetLongField(env, attrs, attrs_st_dev, (jlong)buf->st_dev); |
|
362 (*env)->SetLongField(env, attrs, attrs_st_rdev, (jlong)buf->st_rdev); |
|
363 (*env)->SetIntField(env, attrs, attrs_st_nlink, (jint)buf->st_nlink); |
|
364 (*env)->SetIntField(env, attrs, attrs_st_uid, (jint)buf->st_uid); |
|
365 (*env)->SetIntField(env, attrs, attrs_st_gid, (jint)buf->st_gid); |
|
366 (*env)->SetLongField(env, attrs, attrs_st_size, (jlong)buf->st_size); |
|
367 (*env)->SetLongField(env, attrs, attrs_st_atime, (jlong)buf->st_atime * 1000); |
|
368 (*env)->SetLongField(env, attrs, attrs_st_mtime, (jlong)buf->st_mtime * 1000); |
|
369 (*env)->SetLongField(env, attrs, attrs_st_ctime, (jlong)buf->st_ctime * 1000); |
|
370 } |
|
371 |
|
372 JNIEXPORT void JNICALL |
|
373 Java_sun_nio_fs_UnixNativeDispatcher_stat0(JNIEnv* env, jclass this, |
|
374 jlong pathAddress, jobject attrs) |
|
375 { |
|
376 int err; |
|
377 struct stat64 buf; |
|
378 const char* path = (const char*)jlong_to_ptr(pathAddress); |
|
379 |
|
380 RESTARTABLE(stat64(path, &buf), err); |
|
381 if (err == -1) { |
|
382 throwUnixException(env, errno); |
|
383 } else { |
|
384 prepAttributes(env, &buf, attrs); |
|
385 } |
|
386 } |
|
387 |
|
388 JNIEXPORT void JNICALL |
|
389 Java_sun_nio_fs_UnixNativeDispatcher_lstat0(JNIEnv* env, jclass this, |
|
390 jlong pathAddress, jobject attrs) |
|
391 { |
|
392 int err; |
|
393 struct stat64 buf; |
|
394 const char* path = (const char*)jlong_to_ptr(pathAddress); |
|
395 |
|
396 RESTARTABLE(lstat64(path, &buf), err); |
|
397 if (err == -1) { |
|
398 throwUnixException(env, errno); |
|
399 } else { |
|
400 prepAttributes(env, &buf, attrs); |
|
401 } |
|
402 } |
|
403 |
|
404 JNIEXPORT void JNICALL |
|
405 Java_sun_nio_fs_UnixNativeDispatcher_fstat(JNIEnv* env, jclass this, jint fd, |
|
406 jobject attrs) |
|
407 { |
|
408 int err; |
|
409 struct stat64 buf; |
|
410 |
|
411 RESTARTABLE(fstat64((int)fd, &buf), err); |
|
412 if (err == -1) { |
|
413 throwUnixException(env, errno); |
|
414 } else { |
|
415 prepAttributes(env, &buf, attrs); |
|
416 } |
|
417 } |
|
418 |
|
419 JNIEXPORT void JNICALL |
|
420 Java_sun_nio_fs_UnixNativeDispatcher_fstatat0(JNIEnv* env, jclass this, jint dfd, |
|
421 jlong pathAddress, jint flag, jobject attrs) |
|
422 { |
|
423 int err; |
|
424 struct stat64 buf; |
|
425 const char* path = (const char*)jlong_to_ptr(pathAddress); |
|
426 |
|
427 if (my_fstatat64_func == NULL) { |
|
428 JNU_ThrowInternalError(env, "should not reach here"); |
|
429 return; |
|
430 } |
|
431 RESTARTABLE((*my_fstatat64_func)((int)dfd, path, &buf, (int)flag), err); |
|
432 if (err == -1) { |
|
433 throwUnixException(env, errno); |
|
434 } else { |
|
435 prepAttributes(env, &buf, attrs); |
|
436 } |
|
437 } |
|
438 |
|
439 JNIEXPORT void JNICALL |
|
440 Java_sun_nio_fs_UnixNativeDispatcher_chmod0(JNIEnv* env, jclass this, |
|
441 jlong pathAddress, jint mode) |
|
442 { |
|
443 int err; |
|
444 const char* path = (const char*)jlong_to_ptr(pathAddress); |
|
445 |
|
446 RESTARTABLE(chmod(path, (mode_t)mode), err); |
|
447 if (err == -1) { |
|
448 throwUnixException(env, errno); |
|
449 } |
|
450 } |
|
451 |
|
452 JNIEXPORT void JNICALL |
|
453 Java_sun_nio_fs_UnixNativeDispatcher_fchmod(JNIEnv* env, jclass this, jint filedes, |
|
454 jint mode) |
|
455 { |
|
456 int err; |
|
457 |
|
458 RESTARTABLE(fchmod((int)filedes, (mode_t)mode), err); |
|
459 if (err == -1) { |
|
460 throwUnixException(env, errno); |
|
461 } |
|
462 } |
|
463 |
|
464 |
|
465 JNIEXPORT void JNICALL |
|
466 Java_sun_nio_fs_UnixNativeDispatcher_chown0(JNIEnv* env, jclass this, |
|
467 jlong pathAddress, jint uid, jint gid) |
|
468 { |
|
469 int err; |
|
470 const char* path = (const char*)jlong_to_ptr(pathAddress); |
|
471 |
|
472 RESTARTABLE(chown(path, (uid_t)uid, (gid_t)gid), err); |
|
473 if (err == -1) { |
|
474 throwUnixException(env, errno); |
|
475 } |
|
476 } |
|
477 |
|
478 JNIEXPORT void JNICALL |
|
479 Java_sun_nio_fs_UnixNativeDispatcher_lchown0(JNIEnv* env, jclass this, jlong pathAddress, jint uid, jint gid) |
|
480 { |
|
481 int err; |
|
482 const char* path = (const char*)jlong_to_ptr(pathAddress); |
|
483 |
|
484 RESTARTABLE(lchown(path, (uid_t)uid, (gid_t)gid), err); |
|
485 if (err == -1) { |
|
486 throwUnixException(env, errno); |
|
487 } |
|
488 } |
|
489 |
|
490 JNIEXPORT void JNICALL |
|
491 Java_sun_nio_fs_UnixNativeDispatcher_fchown(JNIEnv* env, jclass this, jint filedes, jint uid, jint gid) |
|
492 { |
|
493 int err; |
|
494 |
|
495 RESTARTABLE(fchown(filedes, (uid_t)uid, (gid_t)gid), err); |
|
496 if (err == -1) { |
|
497 throwUnixException(env, errno); |
|
498 } |
|
499 } |
|
500 |
|
501 JNIEXPORT void JNICALL |
|
502 Java_sun_nio_fs_UnixNativeDispatcher_utimes0(JNIEnv* env, jclass this, |
|
503 jlong pathAddress, jlong accessTime, jlong modificationTime) |
|
504 { |
|
505 int err; |
|
506 struct timeval times[2]; |
|
507 const char* path = (const char*)jlong_to_ptr(pathAddress); |
|
508 |
|
509 times[0].tv_sec = accessTime / 1000; |
|
510 times[0].tv_usec = (accessTime % 1000) * 1000; |
|
511 |
|
512 times[1].tv_sec = modificationTime / 1000; |
|
513 times[1].tv_usec = (modificationTime % 1000) * 1000; |
|
514 |
|
515 RESTARTABLE(utimes(path, ×[0]), err); |
|
516 if (err == -1) { |
|
517 throwUnixException(env, errno); |
|
518 } |
|
519 } |
|
520 |
|
521 JNIEXPORT void JNICALL |
|
522 Java_sun_nio_fs_UnixNativeDispatcher_futimes(JNIEnv* env, jclass this, jint filedes, |
|
523 jlong accessTime, jlong modificationTime) |
|
524 { |
|
525 struct timeval times[2]; |
|
526 int err = 0; |
|
527 |
|
528 times[0].tv_sec = accessTime / 1000; |
|
529 times[0].tv_usec = (accessTime % 1000) * 1000; |
|
530 |
|
531 times[1].tv_sec = modificationTime / 1000; |
|
532 times[1].tv_usec = (modificationTime % 1000) * 1000; |
|
533 |
|
534 if (my_futimesat_func != NULL) { |
|
535 RESTARTABLE((*my_futimesat_func)(filedes, NULL, ×[0]), err); |
|
536 if (err == -1) { |
|
537 throwUnixException(env, errno); |
|
538 } |
|
539 } |
|
540 } |
|
541 |
|
542 JNIEXPORT jlong JNICALL |
|
543 Java_sun_nio_fs_UnixNativeDispatcher_opendir0(JNIEnv* env, jclass this, |
|
544 jlong pathAddress) |
|
545 { |
|
546 DIR* dir; |
|
547 const char* path = (const char*)jlong_to_ptr(pathAddress); |
|
548 |
|
549 /* EINTR not listed as a possible error */ |
|
550 dir = opendir(path); |
|
551 if (dir == NULL) { |
|
552 throwUnixException(env, errno); |
|
553 } |
|
554 return ptr_to_jlong(dir); |
|
555 } |
|
556 |
|
557 JNIEXPORT jlong JNICALL |
|
558 Java_sun_nio_fs_UnixNativeDispatcher_fdopendir(JNIEnv* env, jclass this, int dfd) { |
|
559 DIR* dir; |
|
560 |
|
561 if (my_fdopendir_func == NULL) { |
|
562 JNU_ThrowInternalError(env, "should not reach here"); |
|
563 return (jlong)-1; |
|
564 } |
|
565 |
|
566 /* EINTR not listed as a possible error */ |
|
567 dir = (*my_fdopendir_func)((int)dfd); |
|
568 if (dir == NULL) { |
|
569 throwUnixException(env, errno); |
|
570 } |
|
571 return ptr_to_jlong(dir); |
|
572 } |
|
573 |
|
574 JNIEXPORT void JNICALL |
|
575 Java_sun_nio_fs_UnixNativeDispatcher_closedir(JNIEnv* env, jclass this, jlong dir) { |
|
576 int err; |
|
577 DIR* dirp = jlong_to_ptr(dir); |
|
578 |
|
579 RESTARTABLE(closedir(dirp), err); |
|
580 if (errno == -1) { |
|
581 throwUnixException(env, errno); |
|
582 } |
|
583 } |
|
584 |
|
585 JNIEXPORT jbyteArray JNICALL |
|
586 Java_sun_nio_fs_UnixNativeDispatcher_readdir(JNIEnv* env, jclass this, jlong value) { |
|
587 char entry[sizeof(struct dirent64) + PATH_MAX + 1]; |
|
588 struct dirent64* ptr = (struct dirent64*)&entry; |
|
589 struct dirent64* result; |
|
590 int res; |
|
591 DIR* dirp = jlong_to_ptr(value); |
|
592 |
|
593 /* EINTR not listed as a possible error */ |
|
594 /* TDB: reentrant version probably not required here */ |
|
595 res = readdir64_r(dirp, ptr, &result); |
|
596 if (res != 0) { |
|
597 throwUnixException(env, res); |
|
598 return NULL; |
|
599 } else { |
|
600 if (result == NULL) { |
|
601 return NULL; |
|
602 } else { |
|
603 jsize len = strlen(ptr->d_name); |
|
604 jbyteArray bytes = (*env)->NewByteArray(env, len); |
|
605 if (bytes != NULL) { |
|
606 (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)(ptr->d_name)); |
|
607 } |
|
608 return bytes; |
|
609 } |
|
610 } |
|
611 } |
|
612 |
|
613 JNIEXPORT void JNICALL |
|
614 Java_sun_nio_fs_UnixNativeDispatcher_mkdir0(JNIEnv* env, jclass this, |
|
615 jlong pathAddress, jint mode) |
|
616 { |
|
617 const char* path = (const char*)jlong_to_ptr(pathAddress); |
|
618 |
|
619 /* EINTR not listed as a possible error */ |
|
620 if (mkdir(path, (mode_t)mode) == -1) { |
|
621 throwUnixException(env, errno); |
|
622 } |
|
623 } |
|
624 |
|
625 JNIEXPORT void JNICALL |
|
626 Java_sun_nio_fs_UnixNativeDispatcher_rmdir0(JNIEnv* env, jclass this, |
|
627 jlong pathAddress) |
|
628 { |
|
629 const char* path = (const char*)jlong_to_ptr(pathAddress); |
|
630 |
|
631 /* EINTR not listed as a possible error */ |
|
632 if (rmdir(path) == -1) { |
|
633 throwUnixException(env, errno); |
|
634 } |
|
635 } |
|
636 |
|
637 JNIEXPORT void JNICALL |
|
638 Java_sun_nio_fs_UnixNativeDispatcher_link0(JNIEnv* env, jclass this, |
|
639 jlong existingAddress, jlong newAddress) |
|
640 { |
|
641 int err; |
|
642 const char* existing = (const char*)jlong_to_ptr(existingAddress); |
|
643 const char* newname = (const char*)jlong_to_ptr(newAddress); |
|
644 |
|
645 RESTARTABLE(link(existing, newname), err); |
|
646 if (err == -1) { |
|
647 throwUnixException(env, errno); |
|
648 } |
|
649 } |
|
650 |
|
651 |
|
652 JNIEXPORT void JNICALL |
|
653 Java_sun_nio_fs_UnixNativeDispatcher_unlink0(JNIEnv* env, jclass this, |
|
654 jlong pathAddress) |
|
655 { |
|
656 const char* path = (const char*)jlong_to_ptr(pathAddress); |
|
657 |
|
658 /* EINTR not listed as a possible error */ |
|
659 if (unlink(path) == -1) { |
|
660 throwUnixException(env, errno); |
|
661 } |
|
662 } |
|
663 |
|
664 JNIEXPORT void JNICALL |
|
665 Java_sun_nio_fs_UnixNativeDispatcher_unlinkat0(JNIEnv* env, jclass this, jint dfd, |
|
666 jlong pathAddress, jint flags) |
|
667 { |
|
668 const char* path = (const char*)jlong_to_ptr(pathAddress); |
|
669 |
|
670 if (my_unlinkat_func == NULL) { |
|
671 JNU_ThrowInternalError(env, "should not reach here"); |
|
672 return; |
|
673 } |
|
674 |
|
675 /* EINTR not listed as a possible error */ |
|
676 if ((*my_unlinkat_func)((int)dfd, path, (int)flags) == -1) { |
|
677 throwUnixException(env, errno); |
|
678 } |
|
679 } |
|
680 |
|
681 JNIEXPORT void JNICALL |
|
682 Java_sun_nio_fs_UnixNativeDispatcher_rename0(JNIEnv* env, jclass this, |
|
683 jlong fromAddress, jlong toAddress) |
|
684 { |
|
685 const char* from = (const char*)jlong_to_ptr(fromAddress); |
|
686 const char* to = (const char*)jlong_to_ptr(toAddress); |
|
687 |
|
688 /* EINTR not listed as a possible error */ |
|
689 if (rename(from, to) == -1) { |
|
690 throwUnixException(env, errno); |
|
691 } |
|
692 } |
|
693 |
|
694 JNIEXPORT void JNICALL |
|
695 Java_sun_nio_fs_UnixNativeDispatcher_renameat0(JNIEnv* env, jclass this, |
|
696 jint fromfd, jlong fromAddress, jint tofd, jlong toAddress) |
|
697 { |
|
698 const char* from = (const char*)jlong_to_ptr(fromAddress); |
|
699 const char* to = (const char*)jlong_to_ptr(toAddress); |
|
700 |
|
701 if (my_renameat_func == NULL) { |
|
702 JNU_ThrowInternalError(env, "should not reach here"); |
|
703 return; |
|
704 } |
|
705 |
|
706 /* EINTR not listed as a possible error */ |
|
707 if ((*my_renameat_func)((int)fromfd, from, (int)tofd, to) == -1) { |
|
708 throwUnixException(env, errno); |
|
709 } |
|
710 } |
|
711 |
|
712 JNIEXPORT void JNICALL |
|
713 Java_sun_nio_fs_UnixNativeDispatcher_symlink0(JNIEnv* env, jclass this, |
|
714 jlong targetAddress, jlong linkAddress) |
|
715 { |
|
716 const char* target = (const char*)jlong_to_ptr(targetAddress); |
|
717 const char* link = (const char*)jlong_to_ptr(linkAddress); |
|
718 |
|
719 /* EINTR not listed as a possible error */ |
|
720 if (symlink(target, link) == -1) { |
|
721 throwUnixException(env, errno); |
|
722 } |
|
723 } |
|
724 |
|
725 JNIEXPORT jbyteArray JNICALL |
|
726 Java_sun_nio_fs_UnixNativeDispatcher_readlink0(JNIEnv* env, jclass this, |
|
727 jlong pathAddress) |
|
728 { |
|
729 jbyteArray result = NULL; |
|
730 char target[PATH_MAX+1]; |
|
731 const char* path = (const char*)jlong_to_ptr(pathAddress); |
|
732 |
|
733 /* EINTR not listed as a possible error */ |
|
734 int n = readlink(path, target, sizeof(target)); |
|
735 if (n == -1) { |
|
736 throwUnixException(env, errno); |
|
737 } else { |
|
738 jsize len; |
|
739 if (n == sizeof(target)) { |
|
740 n--; |
|
741 } |
|
742 target[n] = '\0'; |
|
743 len = (jsize)strlen(target); |
|
744 result = (*env)->NewByteArray(env, len); |
|
745 if (result != NULL) { |
|
746 (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)target); |
|
747 } |
|
748 } |
|
749 return result; |
|
750 } |
|
751 |
|
752 JNIEXPORT jbyteArray JNICALL |
|
753 Java_sun_nio_fs_UnixNativeDispatcher_realpath0(JNIEnv* env, jclass this, |
|
754 jlong pathAddress) |
|
755 { |
|
756 jbyteArray result = NULL; |
|
757 char resolved[PATH_MAX+1]; |
|
758 const char* path = (const char*)jlong_to_ptr(pathAddress); |
|
759 |
|
760 /* EINTR not listed as a possible error */ |
|
761 if (realpath(path, resolved) == NULL) { |
|
762 throwUnixException(env, errno); |
|
763 } else { |
|
764 jsize len = (jsize)strlen(resolved); |
|
765 result = (*env)->NewByteArray(env, len); |
|
766 if (result != NULL) { |
|
767 (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)resolved); |
|
768 } |
|
769 } |
|
770 return result; |
|
771 } |
|
772 |
|
773 JNIEXPORT void JNICALL |
|
774 Java_sun_nio_fs_UnixNativeDispatcher_access0(JNIEnv* env, jclass this, |
|
775 jlong pathAddress, jint amode) |
|
776 { |
|
777 int err; |
|
778 const char* path = (const char*)jlong_to_ptr(pathAddress); |
|
779 |
|
780 RESTARTABLE(access(path, (int)amode), err); |
|
781 if (err == -1) { |
|
782 throwUnixException(env, errno); |
|
783 } |
|
784 } |
|
785 |
|
786 JNIEXPORT void JNICALL |
|
787 Java_sun_nio_fs_UnixNativeDispatcher_statvfs0(JNIEnv* env, jclass this, |
|
788 jlong pathAddress, jobject attrs) |
|
789 { |
|
790 int err; |
|
791 struct statvfs64 buf; |
|
792 const char* path = (const char*)jlong_to_ptr(pathAddress); |
|
793 |
|
794 |
|
795 RESTARTABLE(statvfs64(path, &buf), err); |
|
796 if (err == -1) { |
|
797 throwUnixException(env, errno); |
|
798 } else { |
|
799 (*env)->SetLongField(env, attrs, attrs_f_frsize, long_to_jlong(buf.f_frsize)); |
|
800 (*env)->SetLongField(env, attrs, attrs_f_blocks, long_to_jlong(buf.f_blocks)); |
|
801 (*env)->SetLongField(env, attrs, attrs_f_bfree, long_to_jlong(buf.f_bfree)); |
|
802 (*env)->SetLongField(env, attrs, attrs_f_bavail, long_to_jlong(buf.f_bavail)); |
|
803 } |
|
804 } |
|
805 |
|
806 JNIEXPORT jlong JNICALL |
|
807 Java_sun_nio_fs_UnixNativeDispatcher_pathconf0(JNIEnv* env, jclass this, |
|
808 jlong pathAddress, jint name) |
|
809 { |
|
810 long err; |
|
811 const char* path = (const char*)jlong_to_ptr(pathAddress); |
|
812 |
|
813 err = pathconf(path, (int)name); |
|
814 if (err == -1) { |
|
815 throwUnixException(env, errno); |
|
816 } |
|
817 return (jlong)err; |
|
818 } |
|
819 |
|
820 JNIEXPORT jlong JNICALL |
|
821 Java_sun_nio_fs_UnixNativeDispatcher_fpathconf(JNIEnv* env, jclass this, |
|
822 jint fd, jint name) |
|
823 { |
|
824 long err; |
|
825 |
|
826 err = fpathconf((int)fd, (int)name); |
|
827 if (err == -1) { |
|
828 throwUnixException(env, errno); |
|
829 } |
|
830 return (jlong)err; |
|
831 } |
|
832 |
|
833 JNIEXPORT void JNICALL |
|
834 Java_sun_nio_fs_UnixNativeDispatcher_mknod0(JNIEnv* env, jclass this, |
|
835 jlong pathAddress, jint mode, jlong dev) |
|
836 { |
|
837 int err; |
|
838 const char* path = (const char*)jlong_to_ptr(pathAddress); |
|
839 |
|
840 RESTARTABLE(mknod(path, (mode_t)mode, (dev_t)dev), err); |
|
841 if (err == -1) { |
|
842 throwUnixException(env, errno); |
|
843 } |
|
844 } |
|
845 |
|
846 JNIEXPORT jbyteArray JNICALL |
|
847 Java_sun_nio_fs_UnixNativeDispatcher_getpwuid(JNIEnv* env, jclass this, jint uid) |
|
848 { |
|
849 jbyteArray result = NULL; |
|
850 int buflen; |
|
851 |
|
852 buflen = (int)sysconf(_SC_GETPW_R_SIZE_MAX); |
|
853 if (buflen == -1) { |
|
854 throwUnixException(env, errno); |
|
855 } else { |
|
856 char* pwbuf = (char*)malloc(buflen); |
|
857 if (pwbuf == NULL) { |
|
858 JNU_ThrowOutOfMemoryError(env, "native heap"); |
|
859 } else { |
|
860 struct passwd pwent; |
|
861 struct passwd* p; |
|
862 int res = 0; |
|
863 |
|
864 #ifdef __solaris__ |
|
865 p = getpwuid_r((uid_t)uid, &pwent, pwbuf, (size_t)buflen); |
|
866 #else |
|
867 res = getpwuid_r((uid_t)uid, &pwent, pwbuf, (size_t)buflen, &p); |
|
868 #endif |
|
869 |
|
870 if (res != 0 || p == NULL || p->pw_name == NULL || *(p->pw_name) == '\0') { |
|
871 throwUnixException(env, errno); |
|
872 } else { |
|
873 jsize len = strlen(p->pw_name); |
|
874 result = (*env)->NewByteArray(env, len); |
|
875 if (result != NULL) { |
|
876 (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)(p->pw_name)); |
|
877 } |
|
878 } |
|
879 free(pwbuf); |
|
880 } |
|
881 } |
|
882 return result; |
|
883 } |
|
884 |
|
885 |
|
886 JNIEXPORT jbyteArray JNICALL |
|
887 Java_sun_nio_fs_UnixNativeDispatcher_getgrgid(JNIEnv* env, jclass this, jint gid) |
|
888 { |
|
889 jbyteArray result = NULL; |
|
890 int buflen; |
|
891 |
|
892 buflen = (int)sysconf(_SC_GETGR_R_SIZE_MAX); |
|
893 if (buflen == -1) { |
|
894 throwUnixException(env, errno); |
|
895 } else { |
|
896 char* grbuf = (char*)malloc(buflen); |
|
897 if (grbuf == NULL) { |
|
898 JNU_ThrowOutOfMemoryError(env, "native heap"); |
|
899 } else { |
|
900 struct group grent; |
|
901 struct group* g; |
|
902 int res = 0; |
|
903 |
|
904 #ifdef __solaris__ |
|
905 g = getgrgid_r((gid_t)gid, &grent, grbuf, (size_t)buflen); |
|
906 #else |
|
907 res = getgrgid_r((gid_t)gid, &grent, grbuf, (size_t)buflen, &g); |
|
908 #endif |
|
909 if (res != 0 || g == NULL || g->gr_name == NULL || *(g->gr_name) == '\0') { |
|
910 throwUnixException(env, errno); |
|
911 } else { |
|
912 jsize len = strlen(g->gr_name); |
|
913 result = (*env)->NewByteArray(env, len); |
|
914 if (result != NULL) { |
|
915 (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)(g->gr_name)); |
|
916 } |
|
917 } |
|
918 free(grbuf); |
|
919 } |
|
920 } |
|
921 return result; |
|
922 } |
|
923 |
|
924 JNIEXPORT jint JNICALL |
|
925 Java_sun_nio_fs_UnixNativeDispatcher_getpwnam0(JNIEnv* env, jclass this, |
|
926 jlong nameAddress) |
|
927 { |
|
928 jint uid = -1; |
|
929 int buflen; |
|
930 char* pwbuf; |
|
931 struct passwd pwent; |
|
932 struct passwd* p; |
|
933 int res = 0; |
|
934 const char* name = (const char*)jlong_to_ptr(nameAddress); |
|
935 |
|
936 buflen = (int)sysconf(_SC_GETPW_R_SIZE_MAX); |
|
937 if (buflen == -1) { |
|
938 throwUnixException(env, errno); |
|
939 return -1; |
|
940 } |
|
941 pwbuf = (char*)malloc(buflen); |
|
942 if (pwbuf == NULL) { |
|
943 JNU_ThrowOutOfMemoryError(env, "native heap"); |
|
944 return -1; |
|
945 } |
|
946 |
|
947 #ifdef __solaris__ |
|
948 p = getpwnam_r(name, &pwent, pwbuf, (size_t)buflen); |
|
949 #else |
|
950 res = getpwnam_r(name, &pwent, pwbuf, (size_t)buflen, &p); |
|
951 #endif |
|
952 |
|
953 if (res != 0 || p == NULL || p->pw_name == NULL || *(p->pw_name) == '\0') { |
|
954 /* not found or error */ |
|
955 } else { |
|
956 uid = p->pw_uid; |
|
957 } |
|
958 |
|
959 free(pwbuf); |
|
960 |
|
961 return uid; |
|
962 } |
|
963 |
|
964 JNIEXPORT jint JNICALL |
|
965 Java_sun_nio_fs_UnixNativeDispatcher_getgrnam0(JNIEnv* env, jclass this, |
|
966 jlong nameAddress) |
|
967 { |
|
968 jint gid = -1; |
|
969 int buflen; |
|
970 char* grbuf; |
|
971 struct group grent; |
|
972 struct group* g; |
|
973 int res = 0; |
|
974 const char* name = (const char*)jlong_to_ptr(nameAddress); |
|
975 |
|
976 buflen = (int)sysconf(_SC_GETGR_R_SIZE_MAX); |
|
977 if (buflen == -1) { |
|
978 throwUnixException(env, errno); |
|
979 return -1; |
|
980 } |
|
981 grbuf = (char*)malloc(buflen); |
|
982 if (grbuf == NULL) { |
|
983 JNU_ThrowOutOfMemoryError(env, "native heap"); |
|
984 return -1; |
|
985 } |
|
986 |
|
987 #ifdef __solaris__ |
|
988 g = getgrnam_r(name, &grent, grbuf, (size_t)buflen); |
|
989 #else |
|
990 res = getgrnam_r(name, &grent, grbuf, (size_t)buflen, &g); |
|
991 #endif |
|
992 |
|
993 if (res != 0 || g == NULL || g->gr_name == NULL || *(g->gr_name) == '\0') { |
|
994 /* not found or error */ |
|
995 } else { |
|
996 gid = g->gr_gid; |
|
997 } |
|
998 free(grbuf); |
|
999 |
|
1000 return gid; |
|
1001 } |
|
1002 |
|
1003 JNIEXPORT jint JNICALL |
|
1004 Java_sun_nio_fs_UnixNativeDispatcher_getextmntent(JNIEnv* env, jclass this, |
|
1005 jlong value, jobject entry) |
|
1006 { |
|
1007 #ifdef __solaris__ |
|
1008 struct extmnttab ent; |
|
1009 #else |
|
1010 struct mntent ent; |
|
1011 char buf[1024]; |
|
1012 int buflen = sizeof(buf); |
|
1013 struct mntent* m; |
|
1014 #endif |
|
1015 FILE* fp = jlong_to_ptr(value); |
|
1016 jsize len; |
|
1017 jbyteArray bytes; |
|
1018 char* name; |
|
1019 char* dir; |
|
1020 char* fstype; |
|
1021 char* options; |
|
1022 dev_t dev; |
|
1023 |
|
1024 #ifdef __solaris__ |
|
1025 if (getextmntent(fp, &ent, 0)) |
|
1026 return -1; |
|
1027 name = ent.mnt_special; |
|
1028 dir = ent.mnt_mountp; |
|
1029 fstype = ent.mnt_fstype; |
|
1030 options = ent.mnt_mntopts; |
|
1031 dev = makedev(ent.mnt_major, ent.mnt_minor); |
|
1032 if (dev == NODEV) { |
|
1033 /* possible bug on Solaris 8 and 9 */ |
|
1034 throwUnixException(env, errno); |
|
1035 return -1; |
|
1036 } |
|
1037 #else |
|
1038 m = getmntent_r(fp, &ent, (char*)&buf, buflen); |
|
1039 if (m == NULL) |
|
1040 return -1; |
|
1041 name = m->mnt_fsname; |
|
1042 dir = m->mnt_dir; |
|
1043 fstype = m->mnt_type; |
|
1044 options = m->mnt_opts; |
|
1045 dev = 0; |
|
1046 #endif |
|
1047 |
|
1048 len = strlen(name); |
|
1049 bytes = (*env)->NewByteArray(env, len); |
|
1050 if (bytes == NULL) |
|
1051 return -1; |
|
1052 (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)name); |
|
1053 (*env)->SetObjectField(env, entry, entry_name, bytes); |
|
1054 |
|
1055 len = strlen(dir); |
|
1056 bytes = (*env)->NewByteArray(env, len); |
|
1057 if (bytes == NULL) |
|
1058 return -1; |
|
1059 (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)dir); |
|
1060 (*env)->SetObjectField(env, entry, entry_dir, bytes); |
|
1061 |
|
1062 len = strlen(fstype); |
|
1063 bytes = (*env)->NewByteArray(env, len); |
|
1064 if (bytes == NULL) |
|
1065 return -1; |
|
1066 (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)fstype); |
|
1067 (*env)->SetObjectField(env, entry, entry_fstype, bytes); |
|
1068 |
|
1069 len = strlen(options); |
|
1070 bytes = (*env)->NewByteArray(env, len); |
|
1071 if (bytes == NULL) |
|
1072 return -1; |
|
1073 (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)options); |
|
1074 (*env)->SetObjectField(env, entry, entry_options, bytes); |
|
1075 |
|
1076 if (dev != 0) |
|
1077 (*env)->SetLongField(env, entry, entry_dev, (jlong)dev); |
|
1078 |
|
1079 return 0; |
|
1080 } |