Mercurial > hg > truffle
comparison src/os/bsd/vm/perfMemory_bsd.cpp @ 21820:fb677d6aebea
8062675: jmap is unable to display information about java processes and prints only pids
Summary: backout fix 8050808 which caused this regression and as requested.
Reviewed-by: hseigel
author | asaha |
---|---|
date | Mon, 10 Nov 2014 09:47:41 -0800 |
parents | 5ca2ea5eeff0 |
children | 9a227eaac2dc |
comparison
equal
deleted
inserted
replaced
21819:b1cf34d57e78 | 21820:fb677d6aebea |
---|---|
195 // successful conversion, return the pid | 195 // successful conversion, return the pid |
196 return pid; | 196 return pid; |
197 } | 197 } |
198 | 198 |
199 | 199 |
200 // Check if the given statbuf is considered a secure directory for | 200 // check if the given path is considered a secure directory for |
201 // the backing store files. Returns true if the directory is considered | |
202 // a secure location. Returns false if the statbuf is a symbolic link or | |
203 // if an error occurred. | |
204 // | |
205 static bool is_statbuf_secure(struct stat *statp) { | |
206 if (S_ISLNK(statp->st_mode) || !S_ISDIR(statp->st_mode)) { | |
207 // The path represents a link or some non-directory file type, | |
208 // which is not what we expected. Declare it insecure. | |
209 // | |
210 return false; | |
211 } | |
212 // We have an existing directory, check if the permissions are safe. | |
213 // | |
214 if ((statp->st_mode & (S_IWGRP|S_IWOTH)) != 0) { | |
215 // The directory is open for writing and could be subjected | |
216 // to a symlink or a hard link attack. Declare it insecure. | |
217 // | |
218 return false; | |
219 } | |
220 // See if the uid of the directory matches the effective uid of the process. | |
221 // | |
222 if (statp->st_uid != geteuid()) { | |
223 // The directory was not created by this user, declare it insecure. | |
224 // | |
225 return false; | |
226 } | |
227 return true; | |
228 } | |
229 | |
230 | |
231 // Check if the given path is considered a secure directory for | |
232 // the backing store files. Returns true if the directory exists | 201 // the backing store files. Returns true if the directory exists |
233 // and is considered a secure location. Returns false if the path | 202 // and is considered a secure location. Returns false if the path |
234 // is a symbolic link or if an error occurred. | 203 // is a symbolic link or if an error occurred. |
235 // | 204 // |
236 static bool is_directory_secure(const char* path) { | 205 static bool is_directory_secure(const char* path) { |
240 RESTARTABLE(::lstat(path, &statbuf), result); | 209 RESTARTABLE(::lstat(path, &statbuf), result); |
241 if (result == OS_ERR) { | 210 if (result == OS_ERR) { |
242 return false; | 211 return false; |
243 } | 212 } |
244 | 213 |
245 // The path exists, see if it is secure. | 214 // the path exists, now check it's mode |
246 return is_statbuf_secure(&statbuf); | 215 if (S_ISLNK(statbuf.st_mode) || !S_ISDIR(statbuf.st_mode)) { |
247 } | 216 // the path represents a link or some non-directory file type, |
248 | 217 // which is not what we expected. declare it insecure. |
249 | 218 // |
250 // Check if the given directory file descriptor is considered a secure | |
251 // directory for the backing store files. Returns true if the directory | |
252 // exists and is considered a secure location. Returns false if the path | |
253 // is a symbolic link or if an error occurred. | |
254 // | |
255 static bool is_dirfd_secure(int dir_fd) { | |
256 struct stat statbuf; | |
257 int result = 0; | |
258 | |
259 RESTARTABLE(::fstat(dir_fd, &statbuf), result); | |
260 if (result == OS_ERR) { | |
261 return false; | 219 return false; |
262 } | 220 } |
263 | 221 else { |
264 // The path exists, now check its mode. | 222 // we have an existing directory, check if the permissions are safe. |
265 return is_statbuf_secure(&statbuf); | 223 // |
266 } | 224 if ((statbuf.st_mode & (S_IWGRP|S_IWOTH)) != 0) { |
267 | 225 // the directory is open for writing and could be subjected |
268 | 226 // to a symlnk attack. declare it insecure. |
269 // Check to make sure fd1 and fd2 are referencing the same file system object. | 227 // |
270 // | 228 return false; |
271 static bool is_same_fsobject(int fd1, int fd2) { | 229 } |
272 struct stat statbuf1; | |
273 struct stat statbuf2; | |
274 int result = 0; | |
275 | |
276 RESTARTABLE(::fstat(fd1, &statbuf1), result); | |
277 if (result == OS_ERR) { | |
278 return false; | |
279 } | |
280 RESTARTABLE(::fstat(fd2, &statbuf2), result); | |
281 if (result == OS_ERR) { | |
282 return false; | |
283 } | |
284 | |
285 if ((statbuf1.st_ino == statbuf2.st_ino) && | |
286 (statbuf1.st_dev == statbuf2.st_dev)) { | |
287 return true; | |
288 } else { | |
289 return false; | |
290 } | |
291 } | |
292 | |
293 | |
294 // Open the directory of the given path and validate it. | |
295 // Return a DIR * of the open directory. | |
296 // | |
297 static DIR *open_directory_secure(const char* dirname) { | |
298 // Open the directory using open() so that it can be verified | |
299 // to be secure by calling is_dirfd_secure(), opendir() and then check | |
300 // to see if they are the same file system object. This method does not | |
301 // introduce a window of opportunity for the directory to be attacked that | |
302 // calling opendir() and is_directory_secure() does. | |
303 int result; | |
304 DIR *dirp = NULL; | |
305 RESTARTABLE(::open(dirname, O_RDONLY|O_NOFOLLOW), result); | |
306 if (result == OS_ERR) { | |
307 // Directory doesn't exist or is a symlink, so there is nothing to cleanup. | |
308 if (PrintMiscellaneous && Verbose) { | |
309 if (errno == ELOOP) { | |
310 warning("directory %s is a symlink and is not secure\n", dirname); | |
311 } else { | |
312 warning("could not open directory %s: %s\n", dirname, strerror(errno)); | |
313 } | |
314 } | |
315 return dirp; | |
316 } | |
317 int fd = result; | |
318 | |
319 // Determine if the open directory is secure. | |
320 if (!is_dirfd_secure(fd)) { | |
321 // The directory is not a secure directory. | |
322 os::close(fd); | |
323 return dirp; | |
324 } | |
325 | |
326 // Open the directory. | |
327 dirp = ::opendir(dirname); | |
328 if (dirp == NULL) { | |
329 // The directory doesn't exist, close fd and return. | |
330 os::close(fd); | |
331 return dirp; | |
332 } | |
333 | |
334 // Check to make sure fd and dirp are referencing the same file system object. | |
335 if (!is_same_fsobject(fd, dirfd(dirp))) { | |
336 // The directory is not secure. | |
337 os::close(fd); | |
338 os::closedir(dirp); | |
339 dirp = NULL; | |
340 return dirp; | |
341 } | |
342 | |
343 // Close initial open now that we know directory is secure | |
344 os::close(fd); | |
345 | |
346 return dirp; | |
347 } | |
348 | |
349 // NOTE: The code below uses fchdir(), open() and unlink() because | |
350 // fdopendir(), openat() and unlinkat() are not supported on all | |
351 // versions. Once the support for fdopendir(), openat() and unlinkat() | |
352 // is available on all supported versions the code can be changed | |
353 // to use these functions. | |
354 | |
355 // Open the directory of the given path, validate it and set the | |
356 // current working directory to it. | |
357 // Return a DIR * of the open directory and the saved cwd fd. | |
358 // | |
359 static DIR *open_directory_secure_cwd(const char* dirname, int *saved_cwd_fd) { | |
360 | |
361 // Open the directory. | |
362 DIR* dirp = open_directory_secure(dirname); | |
363 if (dirp == NULL) { | |
364 // Directory doesn't exist or is insecure, so there is nothing to cleanup. | |
365 return dirp; | |
366 } | |
367 int fd = dirfd(dirp); | |
368 | |
369 // Open a fd to the cwd and save it off. | |
370 int result; | |
371 RESTARTABLE(::open(".", O_RDONLY), result); | |
372 if (result == OS_ERR) { | |
373 *saved_cwd_fd = -1; | |
374 } else { | |
375 *saved_cwd_fd = result; | |
376 } | |
377 | |
378 // Set the current directory to dirname by using the fd of the directory. | |
379 result = fchdir(fd); | |
380 | |
381 return dirp; | |
382 } | |
383 | |
384 // Close the directory and restore the current working directory. | |
385 // | |
386 static void close_directory_secure_cwd(DIR* dirp, int saved_cwd_fd) { | |
387 | |
388 int result; | |
389 // If we have a saved cwd change back to it and close the fd. | |
390 if (saved_cwd_fd != -1) { | |
391 result = fchdir(saved_cwd_fd); | |
392 ::close(saved_cwd_fd); | |
393 } | |
394 | |
395 // Close the directory. | |
396 os::closedir(dirp); | |
397 } | |
398 | |
399 // Check if the given file descriptor is considered a secure. | |
400 // | |
401 static bool is_file_secure(int fd, const char *filename) { | |
402 | |
403 int result; | |
404 struct stat statbuf; | |
405 | |
406 // Determine if the file is secure. | |
407 RESTARTABLE(::fstat(fd, &statbuf), result); | |
408 if (result == OS_ERR) { | |
409 if (PrintMiscellaneous && Verbose) { | |
410 warning("fstat failed on %s: %s\n", filename, strerror(errno)); | |
411 } | |
412 return false; | |
413 } | |
414 if (statbuf.st_nlink > 1) { | |
415 // A file with multiple links is not expected. | |
416 if (PrintMiscellaneous && Verbose) { | |
417 warning("file %s has multiple links\n", filename); | |
418 } | |
419 return false; | |
420 } | 230 } |
421 return true; | 231 return true; |
422 } | 232 } |
233 | |
423 | 234 |
424 // return the user name for the given user id | 235 // return the user name for the given user id |
425 // | 236 // |
426 // the caller is expected to free the allocated memory. | 237 // the caller is expected to free the allocated memory. |
427 // | 238 // |
504 char* oldest_user = NULL; | 315 char* oldest_user = NULL; |
505 time_t oldest_ctime = 0; | 316 time_t oldest_ctime = 0; |
506 | 317 |
507 const char* tmpdirname = os::get_temp_directory(); | 318 const char* tmpdirname = os::get_temp_directory(); |
508 | 319 |
509 // open the temp directory | 320 DIR* tmpdirp = os::opendir(tmpdirname); |
510 DIR* tmpdirp = open_directory_secure(tmpdirname); | 321 |
511 if (tmpdirp == NULL) { | 322 if (tmpdirp == NULL) { |
512 // Cannot open the directory to get the user name, return. | |
513 return NULL; | 323 return NULL; |
514 } | 324 } |
515 | 325 |
516 // for each entry in the directory that matches the pattern hsperfdata_*, | 326 // for each entry in the directory that matches the pattern hsperfdata_*, |
517 // open the directory and check if the file for the given vmid exists. | 327 // open the directory and check if the file for the given vmid exists. |
532 strlen(tmpdirname) + strlen(dentry->d_name) + 2, mtInternal); | 342 strlen(tmpdirname) + strlen(dentry->d_name) + 2, mtInternal); |
533 strcpy(usrdir_name, tmpdirname); | 343 strcpy(usrdir_name, tmpdirname); |
534 strcat(usrdir_name, "/"); | 344 strcat(usrdir_name, "/"); |
535 strcat(usrdir_name, dentry->d_name); | 345 strcat(usrdir_name, dentry->d_name); |
536 | 346 |
537 // open the user directory | 347 DIR* subdirp = os::opendir(usrdir_name); |
538 DIR* subdirp = open_directory_secure(usrdir_name); | |
539 | 348 |
540 if (subdirp == NULL) { | 349 if (subdirp == NULL) { |
541 FREE_C_HEAP_ARRAY(char, usrdir_name, mtInternal); | 350 FREE_C_HEAP_ARRAY(char, usrdir_name, mtInternal); |
351 continue; | |
352 } | |
353 | |
354 // Since we don't create the backing store files in directories | |
355 // pointed to by symbolic links, we also don't follow them when | |
356 // looking for the files. We check for a symbolic link after the | |
357 // call to opendir in order to eliminate a small window where the | |
358 // symlink can be exploited. | |
359 // | |
360 if (!is_directory_secure(usrdir_name)) { | |
361 FREE_C_HEAP_ARRAY(char, usrdir_name, mtInternal); | |
362 os::closedir(subdirp); | |
542 continue; | 363 continue; |
543 } | 364 } |
544 | 365 |
545 struct dirent* udentry; | 366 struct dirent* udentry; |
546 char* udbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(usrdir_name), mtInternal); | 367 char* udbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(usrdir_name), mtInternal); |
642 } | 463 } |
643 } | 464 } |
644 } | 465 } |
645 | 466 |
646 | 467 |
468 // remove file | |
469 // | |
470 // this method removes the file with the given file name in the | |
471 // named directory. | |
472 // | |
473 static void remove_file(const char* dirname, const char* filename) { | |
474 | |
475 size_t nbytes = strlen(dirname) + strlen(filename) + 2; | |
476 char* path = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal); | |
477 | |
478 strcpy(path, dirname); | |
479 strcat(path, "/"); | |
480 strcat(path, filename); | |
481 | |
482 remove_file(path); | |
483 | |
484 FREE_C_HEAP_ARRAY(char, path, mtInternal); | |
485 } | |
486 | |
487 | |
647 // cleanup stale shared memory resources | 488 // cleanup stale shared memory resources |
648 // | 489 // |
649 // This method attempts to remove all stale shared memory files in | 490 // This method attempts to remove all stale shared memory files in |
650 // the named user temporary directory. It scans the named directory | 491 // the named user temporary directory. It scans the named directory |
651 // for files matching the pattern ^$[0-9]*$. For each file found, the | 492 // for files matching the pattern ^$[0-9]*$. For each file found, the |
653 // determine if the process is alive. If the process is not alive, | 494 // determine if the process is alive. If the process is not alive, |
654 // any stale file resources are removed. | 495 // any stale file resources are removed. |
655 // | 496 // |
656 static void cleanup_sharedmem_resources(const char* dirname) { | 497 static void cleanup_sharedmem_resources(const char* dirname) { |
657 | 498 |
658 int saved_cwd_fd; | 499 // open the user temp directory |
659 // open the directory and set the current working directory to it | 500 DIR* dirp = os::opendir(dirname); |
660 DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd); | 501 |
661 if (dirp == NULL) { | 502 if (dirp == NULL) { |
662 // directory doesn't exist or is insecure, so there is nothing to cleanup | 503 // directory doesn't exist, so there is nothing to cleanup |
504 return; | |
505 } | |
506 | |
507 if (!is_directory_secure(dirname)) { | |
508 // the directory is not a secure directory | |
663 return; | 509 return; |
664 } | 510 } |
665 | 511 |
666 // for each entry in the directory that matches the expected file | 512 // for each entry in the directory that matches the expected file |
667 // name pattern, determine if the file resources are stale and if | 513 // name pattern, determine if the file resources are stale and if |
671 // loop under these conditions is dependent upon the implementation of | 517 // loop under these conditions is dependent upon the implementation of |
672 // opendir/readdir. | 518 // opendir/readdir. |
673 // | 519 // |
674 struct dirent* entry; | 520 struct dirent* entry; |
675 char* dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(dirname), mtInternal); | 521 char* dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(dirname), mtInternal); |
676 | |
677 errno = 0; | 522 errno = 0; |
678 while ((entry = os::readdir(dirp, (struct dirent *)dbuf)) != NULL) { | 523 while ((entry = os::readdir(dirp, (struct dirent *)dbuf)) != NULL) { |
679 | 524 |
680 pid_t pid = filename_to_pid(entry->d_name); | 525 pid_t pid = filename_to_pid(entry->d_name); |
681 | 526 |
682 if (pid == 0) { | 527 if (pid == 0) { |
683 | 528 |
684 if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) { | 529 if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) { |
685 | 530 |
686 // attempt to remove all unexpected files, except "." and ".." | 531 // attempt to remove all unexpected files, except "." and ".." |
687 unlink(entry->d_name); | 532 remove_file(dirname, entry->d_name); |
688 } | 533 } |
689 | 534 |
690 errno = 0; | 535 errno = 0; |
691 continue; | 536 continue; |
692 } | 537 } |
705 // process should be in a different user specific directory. | 550 // process should be in a different user specific directory. |
706 // | 551 // |
707 if ((pid == os::current_process_id()) || | 552 if ((pid == os::current_process_id()) || |
708 (kill(pid, 0) == OS_ERR && (errno == ESRCH || errno == EPERM))) { | 553 (kill(pid, 0) == OS_ERR && (errno == ESRCH || errno == EPERM))) { |
709 | 554 |
710 unlink(entry->d_name); | 555 remove_file(dirname, entry->d_name); |
711 } | 556 } |
712 errno = 0; | 557 errno = 0; |
713 } | 558 } |
714 | 559 os::closedir(dirp); |
715 // close the directory and reset the current working directory | |
716 close_directory_secure_cwd(dirp, saved_cwd_fd); | |
717 | |
718 FREE_C_HEAP_ARRAY(char, dbuf, mtInternal); | 560 FREE_C_HEAP_ARRAY(char, dbuf, mtInternal); |
719 } | 561 } |
720 | 562 |
721 // make the user specific temporary directory. Returns true if | 563 // make the user specific temporary directory. Returns true if |
722 // the directory exists and is secure upon return. Returns false | 564 // the directory exists and is secure upon return. Returns false |
769 // could not make/find the directory or the found directory | 611 // could not make/find the directory or the found directory |
770 // was not secure | 612 // was not secure |
771 return -1; | 613 return -1; |
772 } | 614 } |
773 | 615 |
774 int saved_cwd_fd; | |
775 // open the directory and set the current working directory to it | |
776 DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd); | |
777 if (dirp == NULL) { | |
778 // Directory doesn't exist or is insecure, so cannot create shared | |
779 // memory file. | |
780 return -1; | |
781 } | |
782 | |
783 // Open the filename in the current directory. | |
784 // Cannot use O_TRUNC here; truncation of an existing file has to happen | |
785 // after the is_file_secure() check below. | |
786 int result; | 616 int result; |
787 RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_NOFOLLOW, S_IREAD|S_IWRITE), result); | 617 |
618 RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_TRUNC, S_IREAD|S_IWRITE), result); | |
788 if (result == OS_ERR) { | 619 if (result == OS_ERR) { |
789 if (PrintMiscellaneous && Verbose) { | 620 if (PrintMiscellaneous && Verbose) { |
790 if (errno == ELOOP) { | 621 warning("could not create file %s: %s\n", filename, strerror(errno)); |
791 warning("file %s is a symlink and is not secure\n", filename); | 622 } |
792 } else { | |
793 warning("could not create file %s: %s\n", filename, strerror(errno)); | |
794 } | |
795 } | |
796 // close the directory and reset the current working directory | |
797 close_directory_secure_cwd(dirp, saved_cwd_fd); | |
798 | |
799 return -1; | 623 return -1; |
800 } | 624 } |
801 // close the directory and reset the current working directory | |
802 close_directory_secure_cwd(dirp, saved_cwd_fd); | |
803 | 625 |
804 // save the file descriptor | 626 // save the file descriptor |
805 int fd = result; | 627 int fd = result; |
806 | 628 |
807 // check to see if the file is secure | |
808 if (!is_file_secure(fd, filename)) { | |
809 ::close(fd); | |
810 return -1; | |
811 } | |
812 | |
813 // truncate the file to get rid of any existing data | |
814 RESTARTABLE(::ftruncate(fd, (off_t)0), result); | |
815 if (result == OS_ERR) { | |
816 if (PrintMiscellaneous && Verbose) { | |
817 warning("could not truncate shared memory file: %s\n", strerror(errno)); | |
818 } | |
819 ::close(fd); | |
820 return -1; | |
821 } | |
822 // set the file size | 629 // set the file size |
823 RESTARTABLE(::ftruncate(fd, (off_t)size), result); | 630 RESTARTABLE(::ftruncate(fd, (off_t)size), result); |
824 if (result == OS_ERR) { | 631 if (result == OS_ERR) { |
825 if (PrintMiscellaneous && Verbose) { | 632 if (PrintMiscellaneous && Verbose) { |
826 warning("could not set shared memory file size: %s\n", strerror(errno)); | 633 warning("could not set shared memory file size: %s\n", strerror(errno)); |
874 } | 681 } |
875 else { | 682 else { |
876 THROW_MSG_(vmSymbols::java_io_IOException(), strerror(errno), OS_ERR); | 683 THROW_MSG_(vmSymbols::java_io_IOException(), strerror(errno), OS_ERR); |
877 } | 684 } |
878 } | 685 } |
879 int fd = result; | 686 |
880 | 687 return result; |
881 // check to see if the file is secure | |
882 if (!is_file_secure(fd, filename)) { | |
883 ::close(fd); | |
884 return -1; | |
885 } | |
886 | |
887 return fd; | |
888 } | 688 } |
889 | 689 |
890 // create a named shared memory region. returns the address of the | 690 // create a named shared memory region. returns the address of the |
891 // memory region on success or NULL on failure. A return value of | 691 // memory region on success or NULL on failure. A return value of |
892 // NULL will ultimately disable the shared memory feature. | 692 // NULL will ultimately disable the shared memory feature. |
914 return NULL; | 714 return NULL; |
915 | 715 |
916 char* dirname = get_user_tmp_dir(user_name); | 716 char* dirname = get_user_tmp_dir(user_name); |
917 char* filename = get_sharedmem_filename(dirname, vmid); | 717 char* filename = get_sharedmem_filename(dirname, vmid); |
918 | 718 |
919 // get the short filename | |
920 char* short_filename = strrchr(filename, '/'); | |
921 if (short_filename == NULL) { | |
922 short_filename = filename; | |
923 } else { | |
924 short_filename++; | |
925 } | |
926 | |
927 // cleanup any stale shared memory files | 719 // cleanup any stale shared memory files |
928 cleanup_sharedmem_resources(dirname); | 720 cleanup_sharedmem_resources(dirname); |
929 | 721 |
930 assert(((size > 0) && (size % os::vm_page_size() == 0)), | 722 assert(((size > 0) && (size % os::vm_page_size() == 0)), |
931 "unexpected PerfMemory region size"); | 723 "unexpected PerfMemory region size"); |
932 | 724 |
933 fd = create_sharedmem_resources(dirname, short_filename, size); | 725 fd = create_sharedmem_resources(dirname, filename, size); |
934 | 726 |
935 FREE_C_HEAP_ARRAY(char, user_name, mtInternal); | 727 FREE_C_HEAP_ARRAY(char, user_name, mtInternal); |
936 FREE_C_HEAP_ARRAY(char, dirname, mtInternal); | 728 FREE_C_HEAP_ARRAY(char, dirname, mtInternal); |
937 | 729 |
938 if (fd == -1) { | 730 if (fd == -1) { |
1043 | 835 |
1044 // map the high level access mode to the appropriate permission | 836 // map the high level access mode to the appropriate permission |
1045 // constructs for the file and the shared memory mapping. | 837 // constructs for the file and the shared memory mapping. |
1046 if (mode == PerfMemory::PERF_MODE_RO) { | 838 if (mode == PerfMemory::PERF_MODE_RO) { |
1047 mmap_prot = PROT_READ; | 839 mmap_prot = PROT_READ; |
1048 file_flags = O_RDONLY | O_NOFOLLOW; | 840 file_flags = O_RDONLY; |
1049 } | 841 } |
1050 else if (mode == PerfMemory::PERF_MODE_RW) { | 842 else if (mode == PerfMemory::PERF_MODE_RW) { |
1051 #ifdef LATER | 843 #ifdef LATER |
1052 mmap_prot = PROT_READ | PROT_WRITE; | 844 mmap_prot = PROT_READ | PROT_WRITE; |
1053 file_flags = O_RDWR | O_NOFOLLOW; | 845 file_flags = O_RDWR; |
1054 #else | 846 #else |
1055 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), | 847 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), |
1056 "Unsupported access mode"); | 848 "Unsupported access mode"); |
1057 #endif | 849 #endif |
1058 } | 850 } |