aboutsummaryrefslogtreecommitdiffstats
path: root/src/fileio.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fileio.c')
-rw-r--r--src/fileio.c184
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 `~'. */)
2425bool 2425bool
2426check_existing (const char *filename) 2426check_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)
2441static bool 2433static bool
2442check_executable (char *filename) 2434check_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
2463static bool 2443static bool
2464check_writable (const char *filename) 2444check_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. */
2593DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0, 2541DEFUN ("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.
2703See `file-symlink-p' to distinguish symlinks. */) 2651See `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. */
2671bool
2672file_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
2725DEFUN ("file-accessible-directory-p", Ffile_accessible_directory_p, 2683DEFUN ("file-accessible-directory-p", Ffile_accessible_directory_p,
@@ -2733,21 +2691,65 @@ if the directory so specified exists and really is a readable and
2733searchable directory. */) 2691searchable 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. */
2713bool
2714file_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
2753DEFUN ("file-regular-p", Ffile_regular_p, Sfile_regular_p, 1, 1, 0, 2755DEFUN ("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));