diff options
Diffstat (limited to 'src/fileio.c')
| -rw-r--r-- | src/fileio.c | 184 |
1 files changed, 92 insertions, 92 deletions
diff --git a/src/fileio.c b/src/fileio.c index b9541e78838..572f6d8ef83 100644 --- a/src/fileio.c +++ b/src/fileio.c | |||
| @@ -2425,15 +2425,7 @@ On Unix, this is a name starting with a `/' or a `~'. */) | |||
| 2425 | bool | 2425 | bool |
| 2426 | check_existing (const char *filename) | 2426 | check_existing (const char *filename) |
| 2427 | { | 2427 | { |
| 2428 | #ifdef DOS_NT | 2428 | return faccessat (AT_FDCWD, filename, F_OK, AT_EACCESS) == 0; |
| 2429 | /* The full emulation of Posix 'stat' is too expensive on | ||
| 2430 | DOS/Windows, when all we want to know is whether the file exists. | ||
| 2431 | So we use 'access' instead, which is much more lightweight. */ | ||
| 2432 | return (access (filename, F_OK) >= 0); | ||
| 2433 | #else | ||
| 2434 | struct stat st; | ||
| 2435 | return (stat (filename, &st) >= 0); | ||
| 2436 | #endif | ||
| 2437 | } | 2429 | } |
| 2438 | 2430 | ||
| 2439 | /* Return true if file FILENAME exists and can be executed. */ | 2431 | /* Return true if file FILENAME exists and can be executed. */ |
| @@ -2441,56 +2433,40 @@ check_existing (const char *filename) | |||
| 2441 | static bool | 2433 | static bool |
| 2442 | check_executable (char *filename) | 2434 | check_executable (char *filename) |
| 2443 | { | 2435 | { |
| 2444 | #ifdef DOS_NT | 2436 | return faccessat (AT_FDCWD, filename, X_OK, AT_EACCESS) == 0; |
| 2445 | struct stat st; | ||
| 2446 | if (stat (filename, &st) < 0) | ||
| 2447 | return 0; | ||
| 2448 | return ((st.st_mode & S_IEXEC) != 0); | ||
| 2449 | #else /* not DOS_NT */ | ||
| 2450 | #ifdef HAVE_EUIDACCESS | ||
| 2451 | return (euidaccess (filename, 1) >= 0); | ||
| 2452 | #else | ||
| 2453 | /* Access isn't quite right because it uses the real uid | ||
| 2454 | and we really want to test with the effective uid. | ||
| 2455 | But Unix doesn't give us a right way to do it. */ | ||
| 2456 | return (access (filename, 1) >= 0); | ||
| 2457 | #endif | ||
| 2458 | #endif /* not DOS_NT */ | ||
| 2459 | } | 2437 | } |
| 2460 | 2438 | ||
| 2461 | /* Return true if file FILENAME exists and can be written. */ | 2439 | /* Return true if file FILENAME exists and can be accessed |
| 2440 | according to AMODE, which should include W_OK. | ||
| 2441 | On failure, return false and set errno. */ | ||
| 2462 | 2442 | ||
| 2463 | static bool | 2443 | static bool |
| 2464 | check_writable (const char *filename) | 2444 | check_writable (const char *filename, int amode) |
| 2465 | { | 2445 | { |
| 2466 | #ifdef MSDOS | 2446 | #ifdef MSDOS |
| 2447 | /* FIXME: an faccessat implementation should be added to the | ||
| 2448 | DOS/Windows ports and this #ifdef branch should be removed. */ | ||
| 2467 | struct stat st; | 2449 | struct stat st; |
| 2468 | if (stat (filename, &st) < 0) | 2450 | if (stat (filename, &st) < 0) |
| 2469 | return 0; | 2451 | return 0; |
| 2452 | errno = EPERM; | ||
| 2470 | return (st.st_mode & S_IWRITE || S_ISDIR (st.st_mode)); | 2453 | return (st.st_mode & S_IWRITE || S_ISDIR (st.st_mode)); |
| 2471 | #else /* not MSDOS */ | 2454 | #else /* not MSDOS */ |
| 2472 | #ifdef HAVE_EUIDACCESS | 2455 | bool res = faccessat (AT_FDCWD, filename, amode, AT_EACCESS) == 0; |
| 2473 | bool res = (euidaccess (filename, 2) >= 0); | ||
| 2474 | #ifdef CYGWIN | 2456 | #ifdef CYGWIN |
| 2475 | /* euidaccess may have returned failure because Cygwin couldn't | 2457 | /* faccessat may have returned failure because Cygwin couldn't |
| 2476 | determine the file's UID or GID; if so, we return success. */ | 2458 | determine the file's UID or GID; if so, we return success. */ |
| 2477 | if (!res) | 2459 | if (!res) |
| 2478 | { | 2460 | { |
| 2461 | int faccessat_errno = errno; | ||
| 2479 | struct stat st; | 2462 | struct stat st; |
| 2480 | if (stat (filename, &st) < 0) | 2463 | if (stat (filename, &st) < 0) |
| 2481 | return 0; | 2464 | return 0; |
| 2482 | res = (st.st_uid == -1 || st.st_gid == -1); | 2465 | res = (st.st_uid == -1 || st.st_gid == -1); |
| 2466 | errno = faccessat_errno; | ||
| 2483 | } | 2467 | } |
| 2484 | #endif /* CYGWIN */ | 2468 | #endif /* CYGWIN */ |
| 2485 | return res; | 2469 | return res; |
| 2486 | #else /* not HAVE_EUIDACCESS */ | ||
| 2487 | /* Access isn't quite right because it uses the real uid | ||
| 2488 | and we really want to test with the effective uid. | ||
| 2489 | But Unix doesn't give us a right way to do it. | ||
| 2490 | Opening with O_WRONLY could work for an ordinary file, | ||
| 2491 | but would lose for directories. */ | ||
| 2492 | return (access (filename, 2) >= 0); | ||
| 2493 | #endif /* not HAVE_EUIDACCESS */ | ||
| 2494 | #endif /* not MSDOS */ | 2470 | #endif /* not MSDOS */ |
| 2495 | } | 2471 | } |
| 2496 | 2472 | ||
| @@ -2547,9 +2523,6 @@ See also `file-exists-p' and `file-attributes'. */) | |||
| 2547 | { | 2523 | { |
| 2548 | Lisp_Object absname; | 2524 | Lisp_Object absname; |
| 2549 | Lisp_Object handler; | 2525 | Lisp_Object handler; |
| 2550 | int desc; | ||
| 2551 | int flags; | ||
| 2552 | struct stat statbuf; | ||
| 2553 | 2526 | ||
| 2554 | CHECK_STRING (filename); | 2527 | CHECK_STRING (filename); |
| 2555 | absname = Fexpand_file_name (filename, Qnil); | 2528 | absname = Fexpand_file_name (filename, Qnil); |
| @@ -2561,35 +2534,10 @@ See also `file-exists-p' and `file-attributes'. */) | |||
| 2561 | return call2 (handler, Qfile_readable_p, absname); | 2534 | return call2 (handler, Qfile_readable_p, absname); |
| 2562 | 2535 | ||
| 2563 | absname = ENCODE_FILE (absname); | 2536 | absname = ENCODE_FILE (absname); |
| 2564 | 2537 | return (faccessat (AT_FDCWD, SSDATA (absname), R_OK, AT_EACCESS) == 0 | |
| 2565 | #if defined (DOS_NT) || defined (macintosh) | 2538 | ? Qt : Qnil); |
| 2566 | /* Under MS-DOS, Windows, and Macintosh, open does not work for | ||
| 2567 | directories. */ | ||
| 2568 | if (access (SDATA (absname), 0) == 0) | ||
| 2569 | return Qt; | ||
| 2570 | return Qnil; | ||
| 2571 | #else /* not DOS_NT and not macintosh */ | ||
| 2572 | flags = O_RDONLY; | ||
| 2573 | #ifdef O_NONBLOCK | ||
| 2574 | /* Opening a fifo without O_NONBLOCK can wait. | ||
| 2575 | We don't want to wait. But we don't want to mess wth O_NONBLOCK | ||
| 2576 | except in the case of a fifo, on a system which handles it. */ | ||
| 2577 | desc = stat (SSDATA (absname), &statbuf); | ||
| 2578 | if (desc < 0) | ||
| 2579 | return Qnil; | ||
| 2580 | if (S_ISFIFO (statbuf.st_mode)) | ||
| 2581 | flags |= O_NONBLOCK; | ||
| 2582 | #endif | ||
| 2583 | desc = emacs_open (SSDATA (absname), flags, 0); | ||
| 2584 | if (desc < 0) | ||
| 2585 | return Qnil; | ||
| 2586 | emacs_close (desc); | ||
| 2587 | return Qt; | ||
| 2588 | #endif /* not DOS_NT and not macintosh */ | ||
| 2589 | } | 2539 | } |
| 2590 | 2540 | ||
| 2591 | /* Having this before file-symlink-p mysteriously caused it to be forgotten | ||
| 2592 | on the RT/PC. */ | ||
| 2593 | DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0, | 2541 | DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0, |
| 2594 | doc: /* Return t if file FILENAME can be written or created by you. */) | 2542 | doc: /* Return t if file FILENAME can be written or created by you. */) |
| 2595 | (Lisp_Object filename) | 2543 | (Lisp_Object filename) |
| @@ -2607,14 +2555,15 @@ DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0, | |||
| 2607 | return call2 (handler, Qfile_writable_p, absname); | 2555 | return call2 (handler, Qfile_writable_p, absname); |
| 2608 | 2556 | ||
| 2609 | encoded = ENCODE_FILE (absname); | 2557 | encoded = ENCODE_FILE (absname); |
| 2610 | if (check_existing (SSDATA (encoded))) | 2558 | if (check_writable (SSDATA (encoded), W_OK)) |
| 2611 | return (check_writable (SSDATA (encoded)) | 2559 | return Qt; |
| 2612 | ? Qt : Qnil); | 2560 | if (errno != ENOENT) |
| 2561 | return Qnil; | ||
| 2613 | 2562 | ||
| 2614 | dir = Ffile_name_directory (absname); | 2563 | dir = Ffile_name_directory (absname); |
| 2564 | eassert (!NILP (dir)); | ||
| 2615 | #ifdef MSDOS | 2565 | #ifdef MSDOS |
| 2616 | if (!NILP (dir)) | 2566 | dir = Fdirectory_file_name (dir); |
| 2617 | dir = Fdirectory_file_name (dir); | ||
| 2618 | #endif /* MSDOS */ | 2567 | #endif /* MSDOS */ |
| 2619 | 2568 | ||
| 2620 | dir = ENCODE_FILE (dir); | 2569 | dir = ENCODE_FILE (dir); |
| @@ -2622,10 +2571,9 @@ DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0, | |||
| 2622 | /* The read-only attribute of the parent directory doesn't affect | 2571 | /* The read-only attribute of the parent directory doesn't affect |
| 2623 | whether a file or directory can be created within it. Some day we | 2572 | whether a file or directory can be created within it. Some day we |
| 2624 | should check ACLs though, which do affect this. */ | 2573 | should check ACLs though, which do affect this. */ |
| 2625 | return (access (SDATA (dir), D_OK) < 0) ? Qnil : Qt; | 2574 | return file_directory_p (SDATA (dir)) ? Qt : Qnil; |
| 2626 | #else | 2575 | #else |
| 2627 | return (check_writable (!NILP (dir) ? SSDATA (dir) : "") | 2576 | return check_writable (SSDATA (dir), W_OK | X_OK) ? Qt : Qnil; |
| 2628 | ? Qt : Qnil); | ||
| 2629 | #endif | 2577 | #endif |
| 2630 | } | 2578 | } |
| 2631 | 2579 | ||
| @@ -2703,8 +2651,7 @@ Symbolic links to directories count as directories. | |||
| 2703 | See `file-symlink-p' to distinguish symlinks. */) | 2651 | See `file-symlink-p' to distinguish symlinks. */) |
| 2704 | (Lisp_Object filename) | 2652 | (Lisp_Object filename) |
| 2705 | { | 2653 | { |
| 2706 | register Lisp_Object absname; | 2654 | Lisp_Object absname; |
| 2707 | struct stat st; | ||
| 2708 | Lisp_Object handler; | 2655 | Lisp_Object handler; |
| 2709 | 2656 | ||
| 2710 | absname = expand_and_dir_to_file (filename, BVAR (current_buffer, directory)); | 2657 | absname = expand_and_dir_to_file (filename, BVAR (current_buffer, directory)); |
| @@ -2717,9 +2664,20 @@ See `file-symlink-p' to distinguish symlinks. */) | |||
| 2717 | 2664 | ||
| 2718 | absname = ENCODE_FILE (absname); | 2665 | absname = ENCODE_FILE (absname); |
| 2719 | 2666 | ||
| 2720 | if (stat (SSDATA (absname), &st) < 0) | 2667 | return file_directory_p (SSDATA (absname)) ? Qt : Qnil; |
| 2721 | return Qnil; | 2668 | } |
| 2722 | return S_ISDIR (st.st_mode) ? Qt : Qnil; | 2669 | |
| 2670 | /* Return true if FILE is a directory or a symlink to a directory. */ | ||
| 2671 | bool | ||
| 2672 | file_directory_p (char const *file) | ||
| 2673 | { | ||
| 2674 | #ifdef WINDOWSNT | ||
| 2675 | /* This is cheaper than 'stat'. */ | ||
| 2676 | return faccessat (AT_FDCWD, file, D_OK, AT_EACCESS) == 0; | ||
| 2677 | #else | ||
| 2678 | struct stat st; | ||
| 2679 | return stat (file, &st) == 0 && S_ISDIR (st.st_mode); | ||
| 2680 | #endif | ||
| 2723 | } | 2681 | } |
| 2724 | 2682 | ||
| 2725 | DEFUN ("file-accessible-directory-p", Ffile_accessible_directory_p, | 2683 | DEFUN ("file-accessible-directory-p", Ffile_accessible_directory_p, |
| @@ -2733,21 +2691,65 @@ if the directory so specified exists and really is a readable and | |||
| 2733 | searchable directory. */) | 2691 | searchable directory. */) |
| 2734 | (Lisp_Object filename) | 2692 | (Lisp_Object filename) |
| 2735 | { | 2693 | { |
| 2694 | Lisp_Object absname; | ||
| 2736 | Lisp_Object handler; | 2695 | Lisp_Object handler; |
| 2737 | bool tem; | 2696 | |
| 2738 | struct gcpro gcpro1; | 2697 | CHECK_STRING (filename); |
| 2698 | absname = Fexpand_file_name (filename, Qnil); | ||
| 2739 | 2699 | ||
| 2740 | /* If the file name has special constructs in it, | 2700 | /* If the file name has special constructs in it, |
| 2741 | call the corresponding file handler. */ | 2701 | call the corresponding file handler. */ |
| 2742 | handler = Ffind_file_name_handler (filename, Qfile_accessible_directory_p); | 2702 | handler = Ffind_file_name_handler (absname, Qfile_accessible_directory_p); |
| 2743 | if (!NILP (handler)) | 2703 | if (!NILP (handler)) |
| 2744 | return call2 (handler, Qfile_accessible_directory_p, filename); | 2704 | return call2 (handler, Qfile_accessible_directory_p, absname); |
| 2745 | 2705 | ||
| 2746 | GCPRO1 (filename); | 2706 | absname = ENCODE_FILE (absname); |
| 2747 | tem = (NILP (Ffile_directory_p (filename)) | 2707 | return file_accessible_directory_p (SSDATA (absname)) ? Qt : Qnil; |
| 2748 | || NILP (Ffile_executable_p (filename))); | 2708 | } |
| 2749 | UNGCPRO; | 2709 | |
| 2750 | return tem ? Qnil : Qt; | 2710 | /* If FILE is a searchable directory or a symlink to a |
| 2711 | searchable directory, return true. Otherwise return | ||
| 2712 | false and set errno to an error number. */ | ||
| 2713 | bool | ||
| 2714 | file_accessible_directory_p (char const *file) | ||
| 2715 | { | ||
| 2716 | #ifdef DOS_NT | ||
| 2717 | /* There's no need to test whether FILE is searchable, as the | ||
| 2718 | searchable/executable bit is invented on DOS_NT platforms. */ | ||
| 2719 | return file_directory_p (file); | ||
| 2720 | #else | ||
| 2721 | /* On POSIXish platforms, use just one system call; this avoids a | ||
| 2722 | race and is typically faster. */ | ||
| 2723 | ptrdiff_t len = strlen (file); | ||
| 2724 | char const *dir; | ||
| 2725 | bool ok; | ||
| 2726 | int saved_errno; | ||
| 2727 | USE_SAFE_ALLOCA; | ||
| 2728 | |||
| 2729 | /* Normally a file "FOO" is an accessible directory if "FOO/." exists. | ||
| 2730 | There are three exceptions: "", "/", and "//". Leave "" alone, | ||
| 2731 | as it's invalid. Append only "." to the other two exceptions as | ||
| 2732 | "/" and "//" are distinct on some platforms, whereas "/", "///", | ||
| 2733 | "////", etc. are all equivalent. */ | ||
| 2734 | if (! len) | ||
| 2735 | dir = file; | ||
| 2736 | else | ||
| 2737 | { | ||
| 2738 | /* Just check for trailing '/' when deciding whether to append '/'. | ||
| 2739 | That's simpler than testing the two special cases "/" and "//", | ||
| 2740 | and it's a safe optimization here. */ | ||
| 2741 | char *buf = SAFE_ALLOCA (len + 3); | ||
| 2742 | memcpy (buf, file, len); | ||
| 2743 | strcpy (buf + len, "/." + (file[len - 1] == '/')); | ||
| 2744 | dir = buf; | ||
| 2745 | } | ||
| 2746 | |||
| 2747 | ok = check_existing (dir); | ||
| 2748 | saved_errno = errno; | ||
| 2749 | SAFE_FREE (); | ||
| 2750 | errno = saved_errno; | ||
| 2751 | return ok; | ||
| 2752 | #endif | ||
| 2751 | } | 2753 | } |
| 2752 | 2754 | ||
| 2753 | DEFUN ("file-regular-p", Ffile_regular_p, Sfile_regular_p, 1, 1, 0, | 2755 | DEFUN ("file-regular-p", Ffile_regular_p, Sfile_regular_p, 1, 1, 0, |
| @@ -3044,10 +3046,8 @@ Use the current time if TIMESTAMP is nil. TIMESTAMP is in the format of | |||
| 3044 | if (set_file_times (-1, SSDATA (encoded_absname), t, t)) | 3046 | if (set_file_times (-1, SSDATA (encoded_absname), t, t)) |
| 3045 | { | 3047 | { |
| 3046 | #ifdef MSDOS | 3048 | #ifdef MSDOS |
| 3047 | struct stat st; | ||
| 3048 | |||
| 3049 | /* Setting times on a directory always fails. */ | 3049 | /* Setting times on a directory always fails. */ |
| 3050 | if (stat (SSDATA (encoded_absname), &st) == 0 && S_ISDIR (st.st_mode)) | 3050 | if (file_directory_p (SSDATA (encoded_absname))) |
| 3051 | return Qnil; | 3051 | return Qnil; |
| 3052 | #endif | 3052 | #endif |
| 3053 | report_file_error ("Setting file times", Fcons (absname, Qnil)); | 3053 | report_file_error ("Setting file times", Fcons (absname, Qnil)); |