summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog67
-rw-r--r--src/Makefile.in3
-rw-r--r--src/callproc.c12
-rw-r--r--src/charset.c2
-rw-r--r--src/conf_post.h4
-rw-r--r--src/fileio.c184
-rw-r--r--src/lisp.h2
-rw-r--r--src/lread.c92
-rw-r--r--src/nsterm.m2
-rw-r--r--src/process.c36
-rw-r--r--src/sysdep.c6
-rw-r--r--src/term.c4
-rw-r--r--src/w32.c18
-rw-r--r--src/xrdb.c101
14 files changed, 297 insertions, 236 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 1d94cef6577..a6b42e8a58c 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,70 @@
+2012-11-14 Paul Eggert <eggert@cs.ucla.edu>
+
+ Use faccessat, not access, when checking file permissions (Bug#12632).
+ This fixes a bug that has been present in Emacs since its creation.
+ It was reported by Chris Torek in 1983 even before GNU Emacs existed,
+ which must set some sort of record. (Torek's bug report was against
+ a predecessor of GNU Emacs, but GNU Emacs happened to have the
+ same common flaw.) See Torek's Usenet posting
+ "setuid/setgid programs & Emacs" Article-I.D.: sri-arpa.858
+ Posted: Fri Apr 8 14:18:56 1983.
+ * Makefile.in (LIB_EACCESS): New macro.
+ (LIBES): Use it.
+ * callproc.c (init_callproc):
+ * charset.c (init_charset):
+ * fileio.c (check_existing, check_executable, check_writable)
+ (Ffile_readable_p):
+ * lread.c (openp, load_path_check):
+ * process.c (allocate_pty):
+ * xrdb.c (file_p):
+ Use effective UID when checking permissions, not real UID.
+ * callproc.c (init_callproc):
+ * charset.c (init_charset):
+ * lread.c (load_path_check, init_lread):
+ Test whether directories are accessible, not merely whether they exist.
+ * conf_post.h (GNULIB_SUPPORT_ONLY_AT_FDCWD): New macro.
+ * fileio.c (check_existing, check_executable, check_writable)
+ (Ffile_readable_p):
+ Use symbolic names instead of integers for the flags, as they're
+ portable now.
+ (check_writable): New arg AMODE. All uses changed.
+ Set errno on failure.
+ (Ffile_readable_p): Use faccessat, not stat + open + close.
+ (Ffile_writable_p): No need to call check_existing + check_writable.
+ Just call check_writable and then look at errno. This saves a syscall.
+ dir should never be nil; replace an unnecessary runtime check
+ with an eassert. When checking the parent directory of a nonexistent
+ file, check that the directory is searchable as well as writable, as
+ we can't create files in unsearchable directories.
+ (file_directory_p): New function, which uses 'stat' on most platforms
+ but faccessat with D_OK (for efficiency) if WINDOWSNT.
+ (Ffile_directory_p, Fset_file_times): Use it.
+ (file_accessible_directory_p): New function, which uses a single
+ syscall for efficiency.
+ (Ffile_accessible_directory_p): Use it.
+ * xrdb.c (file_p): Use file_directory_p.
+ * lisp.h (file_directory_p, file_accessible_directory_p): New decls.
+ * lread.c (openp): When opening a file, use fstat rather than
+ stat, as that avoids a permissions race. When not opening a file,
+ use file_directory_p rather than stat.
+ (dir_warning): First arg is now a usage string, not a format.
+ Use errno. All uses changed.
+ * nsterm.m (ns_term_init): Remove unnecessary call to file-readable
+ that merely introduced a race.
+ * process.c, sysdep.c, term.c: All uses of '#ifdef O_NONBLOCK'
+ changed to '#if O_NONBLOCK', to accommodate gnulib O_* style,
+ and similarly for the other O_* flags.
+ * w32.c (sys_faccessat): Rename from sys_access and switch to
+ faccessat's API. All uses changed.
+ * xrdb.c: Do not include <sys/stat.h>; no longer needed.
+ (magic_db): Rename from magic_file_p.
+ (magic_db, search_magic_path): Return an XrmDatabase rather than a
+ char *, so that we don't have to test for file existence
+ separately from opening the file for reading. This removes a race
+ fixes a permission-checking problem, and simplifies the code.
+ All uses changed.
+ (file_p): Remove; no longer needed.
+
2012-11-13 Dmitry Antipov <dmantipov@yandex.ru>
Omit glyphs initialization at startup.
diff --git a/src/Makefile.in b/src/Makefile.in
index c24e421bbbc..d034ad04796 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -150,6 +150,7 @@ M17N_FLT_CFLAGS = @M17N_FLT_CFLAGS@
M17N_FLT_LIBS = @M17N_FLT_LIBS@
LIB_CLOCK_GETTIME=@LIB_CLOCK_GETTIME@
+LIB_EACCESS=@LIB_EACCESS@
LIB_TIMER_TIME=@LIB_TIMER_TIME@
DBUS_CFLAGS = @DBUS_CFLAGS@
@@ -392,7 +393,7 @@ otherobj= $(TERMCAP_OBJ) $(PRE_ALLOC_OBJ) $(GMALLOC_OBJ) $(RALLOC_OBJ) \
LIBES = $(LIBS) $(W32_LIBS) $(LIBX_BASE) $(LIBIMAGE) \
$(LIBX_OTHER) $(LIBSOUND) \
$(RSVG_LIBS) $(IMAGEMAGICK_LIBS) $(LIB_CLOCK_GETTIME) \
- $(LIB_TIMER_TIME) $(DBUS_LIBS) \
+ $(LIB_EACCESS) $(LIB_TIMER_TIME) $(DBUS_LIBS) \
$(LIB_EXECINFO) \
$(LIBXML2_LIBS) $(LIBGPM) $(LIBRESOLV) $(LIBS_SYSTEM) \
$(LIBS_TERMCAP) $(GETLOADAVG_LIBS) $(SETTINGS_LIBS) $(LIBSELINUX_LIBS) \
diff --git a/src/callproc.c b/src/callproc.c
index c7bbe36e605..8ecaba2b408 100644
--- a/src/callproc.c
+++ b/src/callproc.c
@@ -1576,15 +1576,13 @@ init_callproc (void)
#endif
{
tempdir = Fdirectory_file_name (Vexec_directory);
- if (access (SSDATA (tempdir), 0) < 0)
- dir_warning ("Warning: arch-dependent data dir (%s) does not exist.\n",
- Vexec_directory);
+ if (! file_accessible_directory_p (SSDATA (tempdir)))
+ dir_warning ("arch-dependent data dir", Vexec_directory);
}
tempdir = Fdirectory_file_name (Vdata_directory);
- if (access (SSDATA (tempdir), 0) < 0)
- dir_warning ("Warning: arch-independent data dir (%s) does not exist.\n",
- Vdata_directory);
+ if (! file_accessible_directory_p (SSDATA (tempdir)))
+ dir_warning ("arch-independent data dir", Vdata_directory);
sh = (char *) getenv ("SHELL");
Vshell_file_name = build_string (sh ? sh : "/bin/sh");
@@ -1593,7 +1591,7 @@ init_callproc (void)
Vshared_game_score_directory = Qnil;
#else
Vshared_game_score_directory = build_string (PATH_GAME);
- if (NILP (Ffile_directory_p (Vshared_game_score_directory)))
+ if (NILP (Ffile_accessible_directory_p (Vshared_game_score_directory)))
Vshared_game_score_directory = Qnil;
#endif
}
diff --git a/src/charset.c b/src/charset.c
index 6b999824dab..c9133c780e8 100644
--- a/src/charset.c
+++ b/src/charset.c
@@ -2293,7 +2293,7 @@ init_charset (void)
{
Lisp_Object tempdir;
tempdir = Fexpand_file_name (build_string ("charsets"), Vdata_directory);
- if (access (SSDATA (tempdir), 0) < 0)
+ if (! file_accessible_directory_p (SSDATA (tempdir)))
{
/* This used to be non-fatal (dir_warning), but it should not
happen, and if it does sooner or later it will cause some
diff --git a/src/conf_post.h b/src/conf_post.h
index 66390ddf103..b1997e79081 100644
--- a/src/conf_post.h
+++ b/src/conf_post.h
@@ -178,6 +178,10 @@ extern void _DebPrint (const char *fmt, ...);
#endif
#endif
+/* Tell gnulib to omit support for openat-related functions having a
+ first argument other than AT_FDCWD. */
+#define GNULIB_SUPPORT_ONLY_AT_FDCWD
+
#include <string.h>
#include <stdlib.h>
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 `~'. */)
bool
check_existing (const char *filename)
{
-#ifdef DOS_NT
- /* The full emulation of Posix 'stat' is too expensive on
- DOS/Windows, when all we want to know is whether the file exists.
- So we use 'access' instead, which is much more lightweight. */
- return (access (filename, F_OK) >= 0);
-#else
- struct stat st;
- return (stat (filename, &st) >= 0);
-#endif
+ return faccessat (AT_FDCWD, filename, F_OK, AT_EACCESS) == 0;
}
/* Return true if file FILENAME exists and can be executed. */
@@ -2441,56 +2433,40 @@ check_existing (const char *filename)
static bool
check_executable (char *filename)
{
-#ifdef DOS_NT
- struct stat st;
- if (stat (filename, &st) < 0)
- return 0;
- return ((st.st_mode & S_IEXEC) != 0);
-#else /* not DOS_NT */
-#ifdef HAVE_EUIDACCESS
- return (euidaccess (filename, 1) >= 0);
-#else
- /* Access isn't quite right because it uses the real uid
- and we really want to test with the effective uid.
- But Unix doesn't give us a right way to do it. */
- return (access (filename, 1) >= 0);
-#endif
-#endif /* not DOS_NT */
+ return faccessat (AT_FDCWD, filename, X_OK, AT_EACCESS) == 0;
}
-/* Return true if file FILENAME exists and can be written. */
+/* Return true if file FILENAME exists and can be accessed
+ according to AMODE, which should include W_OK.
+ On failure, return false and set errno. */
static bool
-check_writable (const char *filename)
+check_writable (const char *filename, int amode)
{
#ifdef MSDOS
+ /* FIXME: an faccessat implementation should be added to the
+ DOS/Windows ports and this #ifdef branch should be removed. */
struct stat st;
if (stat (filename, &st) < 0)
return 0;
+ errno = EPERM;
return (st.st_mode & S_IWRITE || S_ISDIR (st.st_mode));
#else /* not MSDOS */
-#ifdef HAVE_EUIDACCESS
- bool res = (euidaccess (filename, 2) >= 0);
+ bool res = faccessat (AT_FDCWD, filename, amode, AT_EACCESS) == 0;
#ifdef CYGWIN
- /* euidaccess may have returned failure because Cygwin couldn't
+ /* faccessat may have returned failure because Cygwin couldn't
determine the file's UID or GID; if so, we return success. */
if (!res)
{
+ int faccessat_errno = errno;
struct stat st;
if (stat (filename, &st) < 0)
return 0;
res = (st.st_uid == -1 || st.st_gid == -1);
+ errno = faccessat_errno;
}
#endif /* CYGWIN */
return res;
-#else /* not HAVE_EUIDACCESS */
- /* Access isn't quite right because it uses the real uid
- and we really want to test with the effective uid.
- But Unix doesn't give us a right way to do it.
- Opening with O_WRONLY could work for an ordinary file,
- but would lose for directories. */
- return (access (filename, 2) >= 0);
-#endif /* not HAVE_EUIDACCESS */
#endif /* not MSDOS */
}
@@ -2547,9 +2523,6 @@ See also `file-exists-p' and `file-attributes'. */)
{
Lisp_Object absname;
Lisp_Object handler;
- int desc;
- int flags;
- struct stat statbuf;
CHECK_STRING (filename);
absname = Fexpand_file_name (filename, Qnil);
@@ -2561,35 +2534,10 @@ See also `file-exists-p' and `file-attributes'. */)
return call2 (handler, Qfile_readable_p, absname);
absname = ENCODE_FILE (absname);
-
-#if defined (DOS_NT) || defined (macintosh)
- /* Under MS-DOS, Windows, and Macintosh, open does not work for
- directories. */
- if (access (SDATA (absname), 0) == 0)
- return Qt;
- return Qnil;
-#else /* not DOS_NT and not macintosh */
- flags = O_RDONLY;
-#ifdef O_NONBLOCK
- /* Opening a fifo without O_NONBLOCK can wait.
- We don't want to wait. But we don't want to mess wth O_NONBLOCK
- except in the case of a fifo, on a system which handles it. */
- desc = stat (SSDATA (absname), &statbuf);
- if (desc < 0)
- return Qnil;
- if (S_ISFIFO (statbuf.st_mode))
- flags |= O_NONBLOCK;
-#endif
- desc = emacs_open (SSDATA (absname), flags, 0);
- if (desc < 0)
- return Qnil;
- emacs_close (desc);
- return Qt;
-#endif /* not DOS_NT and not macintosh */
+ return (faccessat (AT_FDCWD, SSDATA (absname), R_OK, AT_EACCESS) == 0
+ ? Qt : Qnil);
}
-/* Having this before file-symlink-p mysteriously caused it to be forgotten
- on the RT/PC. */
DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0,
doc: /* Return t if file FILENAME can be written or created by you. */)
(Lisp_Object filename)
@@ -2607,14 +2555,15 @@ DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0,
return call2 (handler, Qfile_writable_p, absname);
encoded = ENCODE_FILE (absname);
- if (check_existing (SSDATA (encoded)))
- return (check_writable (SSDATA (encoded))
- ? Qt : Qnil);
+ if (check_writable (SSDATA (encoded), W_OK))
+ return Qt;
+ if (errno != ENOENT)
+ return Qnil;
dir = Ffile_name_directory (absname);
+ eassert (!NILP (dir));
#ifdef MSDOS
- if (!NILP (dir))
- dir = Fdirectory_file_name (dir);
+ dir = Fdirectory_file_name (dir);
#endif /* MSDOS */
dir = ENCODE_FILE (dir);
@@ -2622,10 +2571,9 @@ DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0,
/* The read-only attribute of the parent directory doesn't affect
whether a file or directory can be created within it. Some day we
should check ACLs though, which do affect this. */
- return (access (SDATA (dir), D_OK) < 0) ? Qnil : Qt;
+ return file_directory_p (SDATA (dir)) ? Qt : Qnil;
#else
- return (check_writable (!NILP (dir) ? SSDATA (dir) : "")
- ? Qt : Qnil);
+ return check_writable (SSDATA (dir), W_OK | X_OK) ? Qt : Qnil;
#endif
}
@@ -2703,8 +2651,7 @@ Symbolic links to directories count as directories.
See `file-symlink-p' to distinguish symlinks. */)
(Lisp_Object filename)
{
- register Lisp_Object absname;
- struct stat st;
+ Lisp_Object absname;
Lisp_Object handler;
absname = expand_and_dir_to_file (filename, BVAR (current_buffer, directory));
@@ -2717,9 +2664,20 @@ See `file-symlink-p' to distinguish symlinks. */)
absname = ENCODE_FILE (absname);
- if (stat (SSDATA (absname), &st) < 0)
- return Qnil;
- return S_ISDIR (st.st_mode) ? Qt : Qnil;
+ return file_directory_p (SSDATA (absname)) ? Qt : Qnil;
+}
+
+/* Return true if FILE is a directory or a symlink to a directory. */
+bool
+file_directory_p (char const *file)
+{
+#ifdef WINDOWSNT
+ /* This is cheaper than 'stat'. */
+ return faccessat (AT_FDCWD, file, D_OK, AT_EACCESS) == 0;
+#else
+ struct stat st;
+ return stat (file, &st) == 0 && S_ISDIR (st.st_mode);
+#endif
}
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
searchable directory. */)
(Lisp_Object filename)
{
+ Lisp_Object absname;
Lisp_Object handler;
- bool tem;
- struct gcpro gcpro1;
+
+ CHECK_STRING (filename);
+ absname = Fexpand_file_name (filename, Qnil);
/* If the file name has special constructs in it,
call the corresponding file handler. */
- handler = Ffind_file_name_handler (filename, Qfile_accessible_directory_p);
+ handler = Ffind_file_name_handler (absname, Qfile_accessible_directory_p);
if (!NILP (handler))
- return call2 (handler, Qfile_accessible_directory_p, filename);
+ return call2 (handler, Qfile_accessible_directory_p, absname);
- GCPRO1 (filename);
- tem = (NILP (Ffile_directory_p (filename))
- || NILP (Ffile_executable_p (filename)));
- UNGCPRO;
- return tem ? Qnil : Qt;
+ absname = ENCODE_FILE (absname);
+ return file_accessible_directory_p (SSDATA (absname)) ? Qt : Qnil;
+}
+
+/* If FILE is a searchable directory or a symlink to a
+ searchable directory, return true. Otherwise return
+ false and set errno to an error number. */
+bool
+file_accessible_directory_p (char const *file)
+{
+#ifdef DOS_NT
+ /* There's no need to test whether FILE is searchable, as the
+ searchable/executable bit is invented on DOS_NT platforms. */
+ return file_directory_p (file);
+#else
+ /* On POSIXish platforms, use just one system call; this avoids a
+ race and is typically faster. */
+ ptrdiff_t len = strlen (file);
+ char const *dir;
+ bool ok;
+ int saved_errno;
+ USE_SAFE_ALLOCA;
+
+ /* Normally a file "FOO" is an accessible directory if "FOO/." exists.
+ There are three exceptions: "", "/", and "//". Leave "" alone,
+ as it's invalid. Append only "." to the other two exceptions as
+ "/" and "//" are distinct on some platforms, whereas "/", "///",
+ "////", etc. are all equivalent. */
+ if (! len)
+ dir = file;
+ else
+ {
+ /* Just check for trailing '/' when deciding whether to append '/'.
+ That's simpler than testing the two special cases "/" and "//",
+ and it's a safe optimization here. */
+ char *buf = SAFE_ALLOCA (len + 3);
+ memcpy (buf, file, len);
+ strcpy (buf + len, "/." + (file[len - 1] == '/'));
+ dir = buf;
+ }
+
+ ok = check_existing (dir);
+ saved_errno = errno;
+ SAFE_FREE ();
+ errno = saved_errno;
+ return ok;
+#endif
}
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
if (set_file_times (-1, SSDATA (encoded_absname), t, t))
{
#ifdef MSDOS
- struct stat st;
-
/* Setting times on a directory always fails. */
- if (stat (SSDATA (encoded_absname), &st) == 0 && S_ISDIR (st.st_mode))
+ if (file_directory_p (SSDATA (encoded_absname)))
return Qnil;
#endif
report_file_error ("Setting file times", Fcons (absname, Qnil));
diff --git a/src/lisp.h b/src/lisp.h
index 72e38fa4653..67ae28a488f 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -3202,6 +3202,8 @@ extern Lisp_Object close_file_unwind (Lisp_Object);
extern Lisp_Object restore_point_unwind (Lisp_Object);
extern _Noreturn void report_file_error (const char *, Lisp_Object);
extern void internal_delete_file (Lisp_Object);
+extern bool file_directory_p (const char *);
+extern bool file_accessible_directory_p (const char *);
extern void syms_of_fileio (void);
extern Lisp_Object make_temp_name (Lisp_Object, bool);
extern Lisp_Object Qdelete_file;
diff --git a/src/lread.c b/src/lread.c
index 3a82e0057e2..5859a2f85a9 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -1403,7 +1403,7 @@ Returns the file's name in absolute form, or nil if not found.
If SUFFIXES is non-nil, it should be a list of suffixes to append to
file name when searching.
If non-nil, PREDICATE is used instead of `file-readable-p'.
-PREDICATE can also be an integer to pass to the access(2) function,
+PREDICATE can also be an integer to pass to the faccessat(2) function,
in which case file-name-handlers are ignored.
This function will normally skip directories, so if you want it to find
directories, make sure the PREDICATE function returns `dir-ok' for them. */)
@@ -1441,7 +1441,6 @@ static Lisp_Object Qdir_ok;
int
openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes, Lisp_Object *storeptr, Lisp_Object predicate)
{
- int fd;
ptrdiff_t fn_size = 100;
char buf[100];
char *fn = buf;
@@ -1496,7 +1495,6 @@ openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes, Lisp_Object *sto
{
ptrdiff_t fnlen, lsuffix = SBYTES (XCAR (tail));
Lisp_Object handler;
- bool exists;
/* Concatenate path element/specified name with the suffix.
If the directory starts with /:, remove that. */
@@ -1520,6 +1518,7 @@ openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes, Lisp_Object *sto
handler = Ffind_file_name_handler (string, Qfile_exists_p);
if ((!NILP (handler) || !NILP (predicate)) && !NATNUMP (predicate))
{
+ bool exists;
if (NILP (predicate))
exists = !NILP (Ffile_readable_p (string));
else
@@ -1541,37 +1540,40 @@ openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes, Lisp_Object *sto
}
else
{
-#ifndef WINDOWSNT
- struct stat st;
-#endif
+ int fd;
const char *pfn;
encoded_fn = ENCODE_FILE (string);
pfn = SSDATA (encoded_fn);
-#ifdef WINDOWSNT
- exists = access (pfn, F_OK) == 0 && access (pfn, D_OK) < 0;
-#else
- exists = (stat (pfn, &st) == 0 && ! S_ISDIR (st.st_mode));
-#endif
- if (exists)
- {
- /* Check that we can access or open it. */
- if (NATNUMP (predicate))
- fd = (((XFASTINT (predicate) & ~INT_MAX) == 0
- && access (pfn, XFASTINT (predicate)) == 0)
- ? 1 : -1);
- else
- fd = emacs_open (pfn, O_RDONLY, 0);
- if (fd >= 0)
+ /* Check that we can access or open it. */
+ if (NATNUMP (predicate))
+ fd = (((XFASTINT (predicate) & ~INT_MAX) == 0
+ && (faccessat (AT_FDCWD, pfn, XFASTINT (predicate),
+ AT_EACCESS)
+ == 0)
+ && ! file_directory_p (pfn))
+ ? 1 : -1);
+ else
+ {
+ struct stat st;
+ fd = emacs_open (pfn, O_RDONLY, 0);
+ if (0 <= fd
+ && (fstat (fd, &st) != 0 || S_ISDIR (st.st_mode)))
{
- /* We succeeded; return this descriptor and filename. */
- if (storeptr)
- *storeptr = string;
- UNGCPRO;
- return fd;
+ emacs_close (fd);
+ fd = -1;
}
}
+
+ if (fd >= 0)
+ {
+ /* We succeeded; return this descriptor and filename. */
+ if (storeptr)
+ *storeptr = string;
+ UNGCPRO;
+ return fd;
+ }
}
}
if (absolute)
@@ -4087,9 +4089,8 @@ load_path_check (void)
if (STRINGP (dirfile))
{
dirfile = Fdirectory_file_name (dirfile);
- if (access (SSDATA (dirfile), 0) < 0)
- dir_warning ("Warning: Lisp directory `%s' does not exist.\n",
- XCAR (path_tail));
+ if (! file_accessible_directory_p (SSDATA (dirfile)))
+ dir_warning ("Lisp directory", XCAR (path_tail));
}
}
}
@@ -4201,11 +4202,11 @@ init_lread (void)
Lisp_Object tem, tem1;
/* Add to the path the lisp subdir of the installation
- dir, if it exists. Note: in out-of-tree builds,
+ dir, if it is accessible. Note: in out-of-tree builds,
this directory is empty save for Makefile. */
tem = Fexpand_file_name (build_string ("lisp"),
Vinstallation_directory);
- tem1 = Ffile_exists_p (tem);
+ tem1 = Ffile_accessible_directory_p (tem);
if (!NILP (tem1))
{
if (NILP (Fmember (tem, Vload_path)))
@@ -4222,10 +4223,10 @@ init_lread (void)
Lisp dirs instead. */
Vload_path = nconc2 (Vload_path, dump_path);
- /* Add leim under the installation dir, if it exists. */
+ /* Add leim under the installation dir, if it is accessible. */
tem = Fexpand_file_name (build_string ("leim"),
Vinstallation_directory);
- tem1 = Ffile_exists_p (tem);
+ tem1 = Ffile_accessible_directory_p (tem);
if (!NILP (tem1))
{
if (NILP (Fmember (tem, Vload_path)))
@@ -4237,7 +4238,7 @@ init_lread (void)
{
tem = Fexpand_file_name (build_string ("site-lisp"),
Vinstallation_directory);
- tem1 = Ffile_exists_p (tem);
+ tem1 = Ffile_accessible_directory_p (tem);
if (!NILP (tem1))
{
if (NILP (Fmember (tem, Vload_path)))
@@ -4282,7 +4283,7 @@ init_lread (void)
{
tem = Fexpand_file_name (build_string ("site-lisp"),
Vsource_directory);
- tem1 = Ffile_exists_p (tem);
+ tem1 = Ffile_accessible_directory_p (tem);
if (!NILP (tem1))
{
if (NILP (Fmember (tem, Vload_path)))
@@ -4338,21 +4339,28 @@ init_lread (void)
Vloads_in_progress = Qnil;
}
-/* Print a warning, using format string FORMAT, that directory DIRNAME
- does not exist. Print it on stderr and put it in *Messages*. */
+/* Print a warning that directory intended for use USE and with name
+ DIRNAME cannot be accessed. On entry, errno should correspond to
+ the access failure. Print the warning on stderr and put it in
+ *Messages*. */
void
-dir_warning (const char *format, Lisp_Object dirname)
+dir_warning (char const *use, Lisp_Object dirname)
{
- fprintf (stderr, format, SDATA (dirname));
+ static char const format[] = "Warning: %s `%s': %s\n";
+ int access_errno = errno;
+ fprintf (stderr, format, use, SSDATA (dirname), strerror (access_errno));
/* Don't log the warning before we've initialized!! */
if (initialized)
{
+ char const *diagnostic = emacs_strerror (access_errno);
USE_SAFE_ALLOCA;
- char *buffer = SAFE_ALLOCA (SBYTES (dirname)
- + strlen (format) - (sizeof "%s" - 1) + 1);
- ptrdiff_t message_len = esprintf (buffer, format, SDATA (dirname));
+ char *buffer = SAFE_ALLOCA (sizeof format - 3 * (sizeof "%s" - 1)
+ + strlen (use) + SBYTES (dirname)
+ + strlen (diagnostic));
+ ptrdiff_t message_len = esprintf (buffer, format, use, SSDATA (dirname),
+ diagnostic);
message_dolog (buffer, message_len, 0, STRING_MULTIBYTE (dirname));
SAFE_FREE ();
}
diff --git a/src/nsterm.m b/src/nsterm.m
index 7ba1608268b..804ab825dee 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -4112,8 +4112,6 @@ ns_term_init (Lisp_Object display_name)
color_file = Fexpand_file_name (build_string ("rgb.txt"),
Fsymbol_value (intern ("data-directory")));
- if (NILP (Ffile_readable_p (color_file)))
- fatal ("Could not find %s.\n", SDATA (color_file));
color_map = Fx_load_color_file (color_file);
if (NILP (color_map))
diff --git a/src/process.c b/src/process.c
index 43f0239d301..728abebe758 100644
--- a/src/process.c
+++ b/src/process.c
@@ -208,7 +208,7 @@ static EMACS_INT update_tick;
#ifndef NON_BLOCKING_CONNECT
#ifdef HAVE_SELECT
#if defined (HAVE_GETPEERNAME) || defined (GNU_LINUX)
-#if defined (O_NONBLOCK) || defined (O_NDELAY)
+#if O_NONBLOCK || O_NDELAY
#if defined (EWOULDBLOCK) || defined (EINPROGRESS)
#define NON_BLOCKING_CONNECT
#endif /* EWOULDBLOCK || EINPROGRESS */
@@ -655,7 +655,7 @@ allocate_pty (void)
PTY_OPEN;
#else /* no PTY_OPEN */
{
-# ifdef O_NONBLOCK
+# if O_NONBLOCK
fd = emacs_open (pty_name, O_RDWR | O_NONBLOCK, 0);
# else
fd = emacs_open (pty_name, O_RDWR | O_NDELAY, 0);
@@ -672,7 +672,7 @@ allocate_pty (void)
#else
sprintf (pty_name, "/dev/tty%c%x", c, i);
#endif /* no PTY_TTY_NAME_SPRINTF */
- if (access (pty_name, 6) != 0)
+ if (faccessat (AT_FDCWD, pty_name, R_OK | W_OK, AT_EACCESS) != 0)
{
emacs_close (fd);
# ifndef __sgi
@@ -1624,7 +1624,7 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
#if ! defined (USG) || defined (USG_SUBTTY_WORKS)
/* On most USG systems it does not work to open the pty's tty here,
then close it and reopen it in the child. */
-#ifdef O_NOCTTY
+#if O_NOCTTY
/* Don't let this terminal become our controlling terminal
(in case we don't have one). */
forkout = forkin = emacs_open (pty_name, O_RDWR | O_NOCTTY, 0);
@@ -1678,11 +1678,11 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
}
#endif
-#ifdef O_NONBLOCK
+#if O_NONBLOCK
fcntl (inchannel, F_SETFL, O_NONBLOCK);
fcntl (outchannel, F_SETFL, O_NONBLOCK);
#else
-#ifdef O_NDELAY
+#if O_NDELAY
fcntl (inchannel, F_SETFL, O_NDELAY);
fcntl (outchannel, F_SETFL, O_NDELAY);
#endif
@@ -1943,7 +1943,7 @@ create_pty (Lisp_Object process)
#if ! defined (USG) || defined (USG_SUBTTY_WORKS)
/* On most USG systems it does not work to open the pty's tty here,
then close it and reopen it in the child. */
-#ifdef O_NOCTTY
+#if O_NOCTTY
/* Don't let this terminal become our controlling terminal
(in case we don't have one). */
int forkout = emacs_open (pty_name, O_RDWR | O_NOCTTY, 0);
@@ -1963,11 +1963,11 @@ create_pty (Lisp_Object process)
}
#endif /* HAVE_PTYS */
-#ifdef O_NONBLOCK
+#if O_NONBLOCK
fcntl (inchannel, F_SETFL, O_NONBLOCK);
fcntl (outchannel, F_SETFL, O_NONBLOCK);
#else
-#ifdef O_NDELAY
+#if O_NDELAY
fcntl (inchannel, F_SETFL, O_NDELAY);
fcntl (outchannel, F_SETFL, O_NDELAY);
#endif
@@ -2927,7 +2927,7 @@ usage: (make-network-process &rest ARGS) */)
{
/* Don't support network sockets when non-blocking mode is
not available, since a blocked Emacs is not useful. */
-#if !defined (O_NONBLOCK) && !defined (O_NDELAY)
+#if !O_NONBLOCK && !O_NDELAY
error ("Network servers not supported");
#else
is_server = 1;
@@ -3193,7 +3193,7 @@ usage: (make-network-process &rest ARGS) */)
#ifdef NON_BLOCKING_CONNECT
if (is_non_blocking_client)
{
-#ifdef O_NONBLOCK
+#if O_NONBLOCK
ret = fcntl (s, F_SETFL, O_NONBLOCK);
#else
ret = fcntl (s, F_SETFL, O_NDELAY);
@@ -3410,10 +3410,10 @@ usage: (make-network-process &rest ARGS) */)
chan_process[inch] = proc;
-#ifdef O_NONBLOCK
+#if O_NONBLOCK
fcntl (inch, F_SETFL, O_NONBLOCK);
#else
-#ifdef O_NDELAY
+#if O_NDELAY
fcntl (inch, F_SETFL, O_NDELAY);
#endif
#endif
@@ -4145,10 +4145,10 @@ server_accept_connection (Lisp_Object server, int channel)
chan_process[s] = proc;
-#ifdef O_NONBLOCK
+#if O_NONBLOCK
fcntl (s, F_SETFL, O_NONBLOCK);
#else
-#ifdef O_NDELAY
+#if O_NDELAY
fcntl (s, F_SETFL, O_NDELAY);
#endif
#endif
@@ -4849,11 +4849,11 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
#endif
/* ISC 4.1 defines both EWOULDBLOCK and O_NONBLOCK,
and Emacs uses O_NONBLOCK, so what we get is EAGAIN. */
-#ifdef O_NONBLOCK
+#if O_NONBLOCK
else if (nread == -1 && errno == EAGAIN)
;
#else
-#ifdef O_NDELAY
+#if O_NDELAY
else if (nread == -1 && errno == EAGAIN)
;
/* Note that we cannot distinguish between no input
@@ -7348,7 +7348,7 @@ init_process_emacs (void)
#ifdef HAVE_GETSOCKNAME
ADD_SUBFEATURE (QCservice, Qt);
#endif
-#if defined (O_NONBLOCK) || defined (O_NDELAY)
+#if O_NONBLOCK || O_NDELAY
ADD_SUBFEATURE (QCserver, Qt);
#endif
diff --git a/src/sysdep.c b/src/sysdep.c
index aa9d0f38c3c..a7f3de2f1b1 100644
--- a/src/sysdep.c
+++ b/src/sysdep.c
@@ -1287,7 +1287,7 @@ reset_sys_modes (struct tty_display_info *tty_out)
old_fcntl_owner[fileno (tty_out->input)]);
}
#endif /* F_SETOWN */
-#ifdef O_NDELAY
+#if O_NDELAY
fcntl (fileno (tty_out->input), F_SETFL,
fcntl (fileno (tty_out->input), F_GETFL, 0) & ~O_NDELAY);
#endif
@@ -2384,12 +2384,12 @@ serial_open (char *port)
fd = emacs_open ((char*) port,
O_RDWR
-#ifdef O_NONBLOCK
+#if O_NONBLOCK
| O_NONBLOCK
#else
| O_NDELAY
#endif
-#ifdef O_NOCTTY
+#if O_NOCTTY
| O_NOCTTY
#endif
, 0);
diff --git a/src/term.c b/src/term.c
index 578c701858f..96549290da5 100644
--- a/src/term.c
+++ b/src/term.c
@@ -2992,7 +2992,7 @@ init_tty (const char *name, const char *terminal_type, int must_succeed)
int fd;
FILE *file;
-#ifdef O_IGNORE_CTTY
+#if O_IGNORE_CTTY
if (!ctty)
/* Open the terminal device. Don't recognize it as our
controlling terminal, and don't make it the controlling tty
@@ -3023,7 +3023,7 @@ init_tty (const char *name, const char *terminal_type, int must_succeed)
name);
}
-#ifndef O_IGNORE_CTTY
+#if !O_IGNORE_CTTY
if (!ctty)
dissociate_if_controlling_tty (fd);
#endif
diff --git a/src/w32.c b/src/w32.c
index 5ac1bc3eb7c..0e7da449b81 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -1597,7 +1597,7 @@ init_environment (char ** argv)
see if it succeeds. But I think that's too much to ask. */
/* MSVCRT's _access crashes with D_OK. */
- if (tmp && sys_access (tmp, D_OK) == 0)
+ if (tmp && sys_faccessat (AT_FDCWD, tmp, D_OK, AT_EACCESS) == 0)
{
char * var = alloca (strlen (tmp) + 8);
sprintf (var, "TMPDIR=%s", tmp);
@@ -2714,10 +2714,16 @@ logon_network_drive (const char *path)
long file names. */
int
-sys_access (const char * path, int mode)
+sys_faccessat (int dirfd, const char * path, int mode, int flags)
{
DWORD attributes;
+ if (dirfd != AT_FDCWD)
+ {
+ errno = EBADF;
+ return -1;
+ }
+
/* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
newer versions blow up when passed D_OK. */
path = map_w32_filename (path, NULL);
@@ -2960,7 +2966,7 @@ sys_mktemp (char * template)
{
int save_errno = errno;
p[0] = first_char[i];
- if (sys_access (template, 0) < 0)
+ if (sys_faccessat (AT_FDCWD, template, F_OK, AT_EACCESS) < 0)
{
errno = save_errno;
return template;
@@ -4011,7 +4017,7 @@ symlink (char const *filename, char const *linkname)
{
/* Non-absolute FILENAME is understood as being relative to
LINKNAME's directory. We need to prepend that directory to
- FILENAME to get correct results from sys_access below, since
+ FILENAME to get correct results from sys_faccessat below, since
otherwise it will interpret FILENAME relative to the
directory where the Emacs process runs. Note that
make-symbolic-link always makes sure LINKNAME is a fully
@@ -4025,10 +4031,10 @@ symlink (char const *filename, char const *linkname)
strncpy (tem, linkfn, p - linkfn);
tem[p - linkfn] = '\0';
strcat (tem, filename);
- dir_access = sys_access (tem, D_OK);
+ dir_access = sys_faccessat (AT_FDCWD, tem, D_OK, AT_EACCESS);
}
else
- dir_access = sys_access (filename, D_OK);
+ dir_access = sys_faccessat (AT_FDCWD, filename, D_OK, AT_EACCESS);
/* Since Windows distinguishes between symlinks to directories and
to files, we provide a kludgy feature: if FILENAME doesn't
diff --git a/src/xrdb.c b/src/xrdb.c
index 9d056a607e4..59b0876ebf8 100644
--- a/src/xrdb.c
+++ b/src/xrdb.c
@@ -41,7 +41,6 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#ifdef HAVE_PWD_H
#include <pwd.h>
#endif
-#include <sys/stat.h>
#ifdef USE_MOTIF
/* For Vdouble_click_time. */
@@ -50,7 +49,6 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
char *x_get_string_resource (XrmDatabase rdb, const char *name,
const char *class);
-static int file_p (const char *filename);
/* X file search path processing. */
@@ -108,7 +106,7 @@ x_get_customization_string (XrmDatabase db, const char *name,
database associated with display.
(This is x_customization_string.)
- Return the expanded file name if it exists and is readable, and
+ Return the resource database if its file was read successfully, and
refers to %L only when the LANG environment variable is set, or
otherwise provided by X.
@@ -117,10 +115,11 @@ x_get_customization_string (XrmDatabase db, const char *name,
Return NULL otherwise. */
-static char *
-magic_file_p (const char *string, ptrdiff_t string_len, const char *class,
- const char *escaped_suffix)
+static XrmDatabase
+magic_db (const char *string, ptrdiff_t string_len, const char *class,
+ const char *escaped_suffix)
{
+ XrmDatabase db;
char *lang = getenv ("LANG");
ptrdiff_t path_size = 100;
@@ -217,14 +216,9 @@ magic_file_p (const char *string, ptrdiff_t string_len, const char *class,
}
path[path_len] = '\0';
-
- if (! file_p (path))
- {
- xfree (path);
- return NULL;
- }
-
- return path;
+ db = XrmGetFileDatabase (path);
+ xfree (path);
+ return db;
}
@@ -258,22 +252,11 @@ gethomedir (void)
}
-static int
-file_p (const char *filename)
-{
- struct stat status;
-
- return (access (filename, 4) == 0 /* exists and is readable */
- && stat (filename, &status) == 0 /* get the status */
- && (S_ISDIR (status.st_mode)) == 0); /* not a directory */
-}
-
-
/* Find the first element of SEARCH_PATH which exists and is readable,
after expanding the %-escapes. Return 0 if we didn't find any, and
the path name of the one we found otherwise. */
-static char *
+static XrmDatabase
search_magic_path (const char *search_path, const char *class,
const char *escaped_suffix)
{
@@ -286,18 +269,16 @@ search_magic_path (const char *search_path, const char *class,
if (p > s)
{
- char *path = magic_file_p (s, p - s, class, escaped_suffix);
- if (path)
- return path;
+ XrmDatabase db = magic_db (s, p - s, class, escaped_suffix);
+ if (db)
+ return db;
}
else if (*p == ':')
{
- char *path;
-
- s = "%N%S";
- path = magic_file_p (s, strlen (s), class, escaped_suffix);
- if (path)
- return path;
+ static char const ns[] = "%N%S";
+ XrmDatabase db = magic_db (ns, strlen (ns), class, escaped_suffix);
+ if (db)
+ return db;
}
if (*p == ':')
@@ -312,21 +293,12 @@ search_magic_path (const char *search_path, const char *class,
static XrmDatabase
get_system_app (const char *class)
{
- XrmDatabase db = NULL;
const char *path;
- char *p;
path = getenv ("XFILESEARCHPATH");
if (! path) path = PATH_X_DEFAULTS;
- p = search_magic_path (path, class, 0);
- if (p)
- {
- db = XrmGetFileDatabase (p);
- xfree (p);
- }
-
- return db;
+ return search_magic_path (path, class, 0);
}
@@ -340,35 +312,40 @@ get_fallback (Display *display)
static XrmDatabase
get_user_app (const char *class)
{
+ XrmDatabase db = 0;
const char *path;
- char *file = 0;
- char *free_it = 0;
/* Check for XUSERFILESEARCHPATH. It is a path of complete file
names, not directories. */
- if (((path = getenv ("XUSERFILESEARCHPATH"))
- && (file = search_magic_path (path, class, 0)))
+ path = getenv ("XUSERFILESEARCHPATH");
+ if (path)
+ db = search_magic_path (path, class, 0);
+ if (! db)
+ {
/* Check for APPLRESDIR; it is a path of directories. In each,
we have to search for LANG/CLASS and then CLASS. */
- || ((path = getenv ("XAPPLRESDIR"))
- && ((file = search_magic_path (path, class, "/%L/%N"))
- || (file = search_magic_path (path, class, "/%N"))))
+ path = getenv ("XAPPLRESDIR");
+ if (path)
+ {
+ db = search_magic_path (path, class, "/%L/%N");
+ if (!db)
+ db = search_magic_path (path, class, "/%N");
+ }
+ }
+ if (! db)
+ {
/* Check in the home directory. This is a bit of a hack; let's
hope one's home directory doesn't contain any %-escapes. */
- || (free_it = gethomedir (),
- ((file = search_magic_path (free_it, class, "%L/%N"))
- || (file = search_magic_path (free_it, class, "%N")))))
- {
- XrmDatabase db = XrmGetFileDatabase (file);
- xfree (file);
- xfree (free_it);
- return db;
+ char *home = gethomedir ();
+ db = search_magic_path (home, class, "%L/%N");
+ if (! db)
+ db = search_magic_path (home, class, "%N");
+ xfree (home);
}
- xfree (free_it);
- return NULL;
+ return db;
}