mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2024-12-21 10:24:55 +00:00
Use faccessat, not access, when checking file permissions.
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. * .bzrignore: Add lib/fcntl.h. * configure.ac (euidaccess): Remove check; gnulib does this for us now. (gl_FCNTL_O_FLAGS): Define a dummy version. * lib/at-func.c, lib/euidaccess.c, lib/faccessat.c, lib/fcntl.in.h: * lib/getgroups.c, lib/group-member.c, lib/root-uid.h: * lib/xalloc-oversized.h, m4/euidaccess.m4, m4/faccessat.m4: * m4/fcntl_h.m4, m4/getgroups.m4, m4/group-member.m4: New files, from gnulib. * lib/gnulib.mk, m4/gnulib-comp.m4: Regenerate. * admin/merge-gnulib (GNULIB_MODULES): Add faccessat. (GNULIB_TOOL_FLAGS): Avoid at-internal, fchdir, malloc-posix, openat-die, openat-h, save-cwd. Do not avoid fcntl-h. Omit gnulib's m4/fcntl-o.m4. * nt/inc/ms-w32.h (AT_FDCWD, AT_EACCESS): New symbols. (access): Remove. (faccessat): New macro. * src/Makefile.in (LIB_EACCESS): New macro. (LIBES): Use it. * src/callproc.c (init_callproc): * src/charset.c (init_charset): * src/fileio.c (check_existing, check_executable, check_writable) (Ffile_readable_p): * src/lread.c (openp, load_path_check): * src/process.c (allocate_pty): * src/xrdb.c (file_p): Use effective UID when checking permissions, not real UID. * src/callproc.c (init_callproc): * src/charset.c (init_charset): * src/lread.c (load_path_check, init_lread): Test whether directories are accessible, not merely whether they exist. * src/conf_post.h (GNULIB_SUPPORT_ONLY_AT_FDCWD): New macro. * src/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. * src/xrdb.c (file_p): Use file_directory_p. * src/lisp.h (file_directory_p, file_accessible_directory_p): New decls. * src/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. * src/nsterm.m (ns_term_init): Remove unnecessary call to file-readable that merely introduced a race. * src/process.c, src/sysdep.c, src/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. * src/w32.c (sys_faccessat): Rename from sys_access and switch to faccessat's API. All uses changed. * src/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. Fixes: debbugs:12632
This commit is contained in:
parent
9c3912d3d9
commit
73dcdb9f30
13
ChangeLog
13
ChangeLog
@ -1,3 +1,16 @@
|
||||
2012-11-14 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
Use faccessat, not access, when checking file permissions (Bug#12632).
|
||||
* .bzrignore: Add lib/fcntl.h.
|
||||
* configure.ac (euidaccess): Remove check; gnulib does this for us now.
|
||||
(gl_FCNTL_O_FLAGS): Define a dummy version.
|
||||
* lib/at-func.c, lib/euidaccess.c, lib/faccessat.c, lib/fcntl.in.h:
|
||||
* lib/getgroups.c, lib/group-member.c, lib/root-uid.h:
|
||||
* lib/xalloc-oversized.h, m4/euidaccess.m4, m4/faccessat.m4:
|
||||
* m4/fcntl_h.m4, m4/getgroups.m4, m4/group-member.m4:
|
||||
New files, from gnulib.
|
||||
* lib/gnulib.mk, m4/gnulib-comp.m4: Regenerate.
|
||||
|
||||
2012-11-05 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
Assume at least POSIX.1-1988 for getpgrp, setpgid, setsid (Bug#12800).
|
||||
|
@ -1,3 +1,11 @@
|
||||
2012-11-14 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
Use faccessat, not access, when checking file permissions (Bug#12632).
|
||||
* merge-gnulib (GNULIB_MODULES): Add faccessat.
|
||||
(GNULIB_TOOL_FLAGS): Avoid at-internal, fchdir, malloc-posix,
|
||||
openat-die, openat-h, save-cwd. Do not avoid fcntl-h.
|
||||
Omit gnulib's m4/fcntl-o.m4.
|
||||
|
||||
2012-11-05 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
Assume at least POSIX.1-1988 for getpgrp, setpgid, setsid (Bug#12800).
|
||||
|
@ -28,7 +28,7 @@ GNULIB_URL=git://git.savannah.gnu.org/gnulib.git
|
||||
GNULIB_MODULES='
|
||||
alloca-opt c-ctype c-strcase
|
||||
careadlinkat close-stream crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512
|
||||
dtoastr dtotimespec dup2 environ execinfo
|
||||
dtoastr dtotimespec dup2 environ execinfo faccessat
|
||||
filemode getloadavg getopt-gnu gettime gettimeofday
|
||||
ignore-value intprops largefile lstat
|
||||
manywarnings mktime pselect pthread_sigmask readlink
|
||||
@ -39,9 +39,12 @@ GNULIB_MODULES='
|
||||
'
|
||||
|
||||
GNULIB_TOOL_FLAGS='
|
||||
--avoid=errno --avoid=fcntl --avoid=fcntl-h --avoid=fstat
|
||||
--avoid=msvc-inval --avoid=msvc-nothrow
|
||||
--avoid=raise --avoid=select --avoid=sigprocmask --avoid=sys_types
|
||||
--avoid=at-internal
|
||||
--avoid=errno --avoid=fchdir --avoid=fcntl --avoid=fstat
|
||||
--avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow
|
||||
--avoid=openat-die --avoid=openat-h
|
||||
--avoid=raise
|
||||
--avoid=save-cwd --avoid=select --avoid=sigprocmask --avoid=sys_types
|
||||
--avoid=threadlib
|
||||
--conditional-dependencies --import --no-changelog --no-vc-files
|
||||
--makefile-name=gnulib.mk
|
||||
@ -85,7 +88,7 @@ test -x "$gnulib_srcdir"/gnulib-tool || {
|
||||
}
|
||||
|
||||
"$gnulib_srcdir"/gnulib-tool --dir="$src" $GNULIB_TOOL_FLAGS $GNULIB_MODULES &&
|
||||
rm -- "$src"m4/gnulib-cache.m4 "$src"m4/warn-on-use.m4 &&
|
||||
rm -- "$src"m4/fcntl-o.m4 "$src"m4/gnulib-cache.m4 "$src"m4/warn-on-use.m4 &&
|
||||
cp -- "$gnulib_srcdir"/build-aux/texinfo.tex "$src"doc/misc &&
|
||||
cp -- "$gnulib_srcdir"/build-aux/move-if-change "$src"build-aux &&
|
||||
autoreconf -i -I m4 -- ${src:+"$src"}
|
||||
|
@ -572,6 +572,8 @@ else
|
||||
test "x$NON_GCC_TEST_OPTIONS" != x && CC="$CC $NON_GCC_TEST_OPTIONS"
|
||||
fi
|
||||
|
||||
# Avoid gnulib's tests for O_NOATIME and O_NOFOLLOW, as we don't use them.
|
||||
AC_DEFUN([gl_FCNTL_O_FLAGS])
|
||||
# Avoid gnulib's threadlib module, as we do threads our own way.
|
||||
AC_DEFUN([gl_THREADLIB])
|
||||
|
||||
@ -2872,7 +2874,7 @@ AC_SUBST(BLESSMAIL_TARGET)
|
||||
AC_CHECK_FUNCS(gethostname \
|
||||
closedir getrusage get_current_dir_name \
|
||||
lrand48 \
|
||||
fpathconf select euidaccess getpagesize setlocale \
|
||||
fpathconf select getpagesize setlocale \
|
||||
utimes getrlimit setrlimit getcwd shutdown getaddrinfo \
|
||||
strsignal setitimer \
|
||||
sendto recvfrom getsockname getpeername getifaddrs freeifaddrs \
|
||||
|
146
lib/at-func.c
Normal file
146
lib/at-func.c
Normal file
@ -0,0 +1,146 @@
|
||||
/* Define at-style functions like fstatat, unlinkat, fchownat, etc.
|
||||
Copyright (C) 2006, 2009-2012 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* written by Jim Meyering */
|
||||
|
||||
#include "dosname.h" /* solely for definition of IS_ABSOLUTE_FILE_NAME */
|
||||
|
||||
#ifdef GNULIB_SUPPORT_ONLY_AT_FDCWD
|
||||
# include <errno.h>
|
||||
# ifndef ENOTSUP
|
||||
# define ENOTSUP EINVAL
|
||||
# endif
|
||||
#else
|
||||
# include "openat.h"
|
||||
# include "openat-priv.h"
|
||||
# include "save-cwd.h"
|
||||
#endif
|
||||
|
||||
#ifdef AT_FUNC_USE_F1_COND
|
||||
# define CALL_FUNC(F) \
|
||||
(flag == AT_FUNC_USE_F1_COND \
|
||||
? AT_FUNC_F1 (F AT_FUNC_POST_FILE_ARGS) \
|
||||
: AT_FUNC_F2 (F AT_FUNC_POST_FILE_ARGS))
|
||||
# define VALIDATE_FLAG(F) \
|
||||
if (flag & ~AT_FUNC_USE_F1_COND) \
|
||||
{ \
|
||||
errno = EINVAL; \
|
||||
return FUNC_FAIL; \
|
||||
}
|
||||
#else
|
||||
# define CALL_FUNC(F) (AT_FUNC_F1 (F AT_FUNC_POST_FILE_ARGS))
|
||||
# define VALIDATE_FLAG(F) /* empty */
|
||||
#endif
|
||||
|
||||
#ifdef AT_FUNC_RESULT
|
||||
# define FUNC_RESULT AT_FUNC_RESULT
|
||||
#else
|
||||
# define FUNC_RESULT int
|
||||
#endif
|
||||
|
||||
#ifdef AT_FUNC_FAIL
|
||||
# define FUNC_FAIL AT_FUNC_FAIL
|
||||
#else
|
||||
# define FUNC_FAIL -1
|
||||
#endif
|
||||
|
||||
/* Call AT_FUNC_F1 to operate on FILE, which is in the directory
|
||||
open on descriptor FD. If AT_FUNC_USE_F1_COND is defined to a value,
|
||||
AT_FUNC_POST_FILE_PARAM_DECLS must include a parameter named flag;
|
||||
call AT_FUNC_F2 if FLAG is 0 or fail if FLAG contains more bits than
|
||||
AT_FUNC_USE_F1_COND. Return int and fail with -1 unless AT_FUNC_RESULT
|
||||
or AT_FUNC_FAIL are defined. If possible, do it without changing the
|
||||
working directory. Otherwise, resort to using save_cwd/fchdir,
|
||||
then AT_FUNC_F?/restore_cwd. If either the save_cwd or the restore_cwd
|
||||
fails, then give a diagnostic and exit nonzero. */
|
||||
FUNC_RESULT
|
||||
AT_FUNC_NAME (int fd, char const *file AT_FUNC_POST_FILE_PARAM_DECLS)
|
||||
{
|
||||
VALIDATE_FLAG (flag);
|
||||
|
||||
if (fd == AT_FDCWD || IS_ABSOLUTE_FILE_NAME (file))
|
||||
return CALL_FUNC (file);
|
||||
|
||||
#ifdef GNULIB_SUPPORT_ONLY_AT_FDCWD
|
||||
errno = ENOTSUP;
|
||||
return FUNC_FAIL;
|
||||
#else
|
||||
{
|
||||
/* Be careful to choose names unlikely to conflict with
|
||||
AT_FUNC_POST_FILE_PARAM_DECLS. */
|
||||
struct saved_cwd saved_cwd;
|
||||
int saved_errno;
|
||||
FUNC_RESULT err;
|
||||
|
||||
{
|
||||
char proc_buf[OPENAT_BUFFER_SIZE];
|
||||
char *proc_file = openat_proc_name (proc_buf, fd, file);
|
||||
if (proc_file)
|
||||
{
|
||||
FUNC_RESULT proc_result = CALL_FUNC (proc_file);
|
||||
int proc_errno = errno;
|
||||
if (proc_file != proc_buf)
|
||||
free (proc_file);
|
||||
/* If the syscall succeeds, or if it fails with an unexpected
|
||||
errno value, then return right away. Otherwise, fall through
|
||||
and resort to using save_cwd/restore_cwd. */
|
||||
if (FUNC_FAIL != proc_result)
|
||||
return proc_result;
|
||||
if (! EXPECTED_ERRNO (proc_errno))
|
||||
{
|
||||
errno = proc_errno;
|
||||
return proc_result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (save_cwd (&saved_cwd) != 0)
|
||||
openat_save_fail (errno);
|
||||
if (0 <= fd && fd == saved_cwd.desc)
|
||||
{
|
||||
/* If saving the working directory collides with the user's
|
||||
requested fd, then the user's fd must have been closed to
|
||||
begin with. */
|
||||
free_cwd (&saved_cwd);
|
||||
errno = EBADF;
|
||||
return FUNC_FAIL;
|
||||
}
|
||||
|
||||
if (fchdir (fd) != 0)
|
||||
{
|
||||
saved_errno = errno;
|
||||
free_cwd (&saved_cwd);
|
||||
errno = saved_errno;
|
||||
return FUNC_FAIL;
|
||||
}
|
||||
|
||||
err = CALL_FUNC (file);
|
||||
saved_errno = (err == FUNC_FAIL ? errno : 0);
|
||||
|
||||
if (restore_cwd (&saved_cwd) != 0)
|
||||
openat_restore_fail (errno);
|
||||
|
||||
free_cwd (&saved_cwd);
|
||||
|
||||
if (saved_errno)
|
||||
errno = saved_errno;
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#undef CALL_FUNC
|
||||
#undef FUNC_RESULT
|
||||
#undef FUNC_FAIL
|
221
lib/euidaccess.c
Normal file
221
lib/euidaccess.c
Normal file
@ -0,0 +1,221 @@
|
||||
/* euidaccess -- check if effective user id can access file
|
||||
|
||||
Copyright (C) 1990-1991, 1995, 1998, 2000, 2003-2006, 2008-2012 Free
|
||||
Software Foundation, Inc.
|
||||
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by David MacKenzie and Torbjorn Granlund.
|
||||
Adapted for GNU C library by Roland McGrath. */
|
||||
|
||||
#ifndef _LIBC
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "root-uid.h"
|
||||
|
||||
#if HAVE_LIBGEN_H
|
||||
# include <libgen.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#ifndef __set_errno
|
||||
# define __set_errno(val) errno = (val)
|
||||
#endif
|
||||
|
||||
#if defined EACCES && !defined EACCESS
|
||||
# define EACCESS EACCES
|
||||
#endif
|
||||
|
||||
#ifndef F_OK
|
||||
# define F_OK 0
|
||||
# define X_OK 1
|
||||
# define W_OK 2
|
||||
# define R_OK 4
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _LIBC
|
||||
|
||||
# define access __access
|
||||
# define getuid __getuid
|
||||
# define getgid __getgid
|
||||
# define geteuid __geteuid
|
||||
# define getegid __getegid
|
||||
# define group_member __group_member
|
||||
# define euidaccess __euidaccess
|
||||
# undef stat
|
||||
# define stat stat64
|
||||
|
||||
#endif
|
||||
|
||||
/* Return 0 if the user has permission of type MODE on FILE;
|
||||
otherwise, return -1 and set 'errno'.
|
||||
Like access, except that it uses the effective user and group
|
||||
id's instead of the real ones, and it does not always check for read-only
|
||||
file system, text busy, etc. */
|
||||
|
||||
int
|
||||
euidaccess (const char *file, int mode)
|
||||
{
|
||||
#if HAVE_FACCESSAT /* glibc, AIX 7, Solaris 11, Cygwin 1.7 */
|
||||
return faccessat (AT_FDCWD, file, mode, AT_EACCESS);
|
||||
#elif defined EFF_ONLY_OK /* IRIX, OSF/1, Interix */
|
||||
return access (file, mode | EFF_ONLY_OK);
|
||||
#elif defined ACC_SELF /* AIX */
|
||||
return accessx (file, mode, ACC_SELF);
|
||||
#elif HAVE_EACCESS /* FreeBSD */
|
||||
return eaccess (file, mode);
|
||||
#else /* Mac OS X, NetBSD, OpenBSD, HP-UX, Solaris, Cygwin, mingw, BeOS */
|
||||
|
||||
uid_t uid = getuid ();
|
||||
gid_t gid = getgid ();
|
||||
uid_t euid = geteuid ();
|
||||
gid_t egid = getegid ();
|
||||
struct stat stats;
|
||||
|
||||
# if HAVE_DECL_SETREGID && PREFER_NONREENTRANT_EUIDACCESS
|
||||
|
||||
/* Define PREFER_NONREENTRANT_EUIDACCESS if you prefer euidaccess to
|
||||
return the correct result even if this would make it
|
||||
nonreentrant. Define this only if your entire application is
|
||||
safe even if the uid or gid might temporarily change. If your
|
||||
application uses signal handlers or threads it is probably not
|
||||
safe. */
|
||||
|
||||
if (mode == F_OK)
|
||||
return stat (file, &stats);
|
||||
else
|
||||
{
|
||||
int result;
|
||||
int saved_errno;
|
||||
|
||||
if (uid != euid)
|
||||
setreuid (euid, uid);
|
||||
if (gid != egid)
|
||||
setregid (egid, gid);
|
||||
|
||||
result = access (file, mode);
|
||||
saved_errno = errno;
|
||||
|
||||
/* Restore them. */
|
||||
if (uid != euid)
|
||||
setreuid (uid, euid);
|
||||
if (gid != egid)
|
||||
setregid (gid, egid);
|
||||
|
||||
errno = saved_errno;
|
||||
return result;
|
||||
}
|
||||
|
||||
# else
|
||||
|
||||
/* The following code assumes the traditional Unix model, and is not
|
||||
correct on systems that have ACLs or the like. However, it's
|
||||
better than nothing, and it is reentrant. */
|
||||
|
||||
unsigned int granted;
|
||||
if (uid == euid && gid == egid)
|
||||
/* If we are not set-uid or set-gid, access does the same. */
|
||||
return access (file, mode);
|
||||
|
||||
if (stat (file, &stats) != 0)
|
||||
return -1;
|
||||
|
||||
/* The super-user can read and write any file, and execute any file
|
||||
that anyone can execute. */
|
||||
if (euid == ROOT_UID
|
||||
&& ((mode & X_OK) == 0
|
||||
|| (stats.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))))
|
||||
return 0;
|
||||
|
||||
/* Convert the mode to traditional form, clearing any bogus bits. */
|
||||
if (R_OK == 4 && W_OK == 2 && X_OK == 1 && F_OK == 0)
|
||||
mode &= 7;
|
||||
else
|
||||
mode = ((mode & R_OK ? 4 : 0)
|
||||
+ (mode & W_OK ? 2 : 0)
|
||||
+ (mode & X_OK ? 1 : 0));
|
||||
|
||||
if (mode == 0)
|
||||
return 0; /* The file exists. */
|
||||
|
||||
/* Convert the file's permission bits to traditional form. */
|
||||
if (S_IRUSR == (4 << 6) && S_IWUSR == (2 << 6) && S_IXUSR == (1 << 6)
|
||||
&& S_IRGRP == (4 << 3) && S_IWGRP == (2 << 3) && S_IXGRP == (1 << 3)
|
||||
&& S_IROTH == (4 << 0) && S_IWOTH == (2 << 0) && S_IXOTH == (1 << 0))
|
||||
granted = stats.st_mode;
|
||||
else
|
||||
granted = ((stats.st_mode & S_IRUSR ? 4 << 6 : 0)
|
||||
+ (stats.st_mode & S_IWUSR ? 2 << 6 : 0)
|
||||
+ (stats.st_mode & S_IXUSR ? 1 << 6 : 0)
|
||||
+ (stats.st_mode & S_IRGRP ? 4 << 3 : 0)
|
||||
+ (stats.st_mode & S_IWGRP ? 2 << 3 : 0)
|
||||
+ (stats.st_mode & S_IXGRP ? 1 << 3 : 0)
|
||||
+ (stats.st_mode & S_IROTH ? 4 << 0 : 0)
|
||||
+ (stats.st_mode & S_IWOTH ? 2 << 0 : 0)
|
||||
+ (stats.st_mode & S_IXOTH ? 1 << 0 : 0));
|
||||
|
||||
if (euid == stats.st_uid)
|
||||
granted >>= 6;
|
||||
else if (egid == stats.st_gid || group_member (stats.st_gid))
|
||||
granted >>= 3;
|
||||
|
||||
if ((mode & ~granted) == 0)
|
||||
return 0;
|
||||
__set_errno (EACCESS);
|
||||
return -1;
|
||||
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
#undef euidaccess
|
||||
#ifdef weak_alias
|
||||
weak_alias (__euidaccess, euidaccess)
|
||||
#endif
|
||||
|
||||
#ifdef TEST
|
||||
# include <error.h>
|
||||
# include <stdio.h>
|
||||
# include <stdlib.h>
|
||||
|
||||
char *program_name;
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
char *file;
|
||||
int mode;
|
||||
int err;
|
||||
|
||||
program_name = argv[0];
|
||||
if (argc < 3)
|
||||
abort ();
|
||||
file = argv[1];
|
||||
mode = atoi (argv[2]);
|
||||
|
||||
err = euidaccess (file, mode);
|
||||
printf ("%d\n", err);
|
||||
if (err != 0)
|
||||
error (0, errno, "%s", file);
|
||||
exit (0);
|
||||
}
|
||||
#endif
|
45
lib/faccessat.c
Normal file
45
lib/faccessat.c
Normal file
@ -0,0 +1,45 @@
|
||||
/* Check the access rights of a file relative to an open directory.
|
||||
Copyright (C) 2009-2012 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* written by Eric Blake */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifndef HAVE_ACCESS
|
||||
/* Mingw lacks access, but it also lacks real vs. effective ids, so
|
||||
the gnulib euidaccess module is good enough. */
|
||||
# undef access
|
||||
# define access euidaccess
|
||||
#endif
|
||||
|
||||
/* Invoke access or euidaccess on file, FILE, using mode MODE, in the directory
|
||||
open on descriptor FD. If possible, do it without changing the
|
||||
working directory. Otherwise, resort to using save_cwd/fchdir, then
|
||||
(access|euidaccess)/restore_cwd. If either the save_cwd or the
|
||||
restore_cwd fails, then give a diagnostic and exit nonzero.
|
||||
Note that this implementation only supports AT_EACCESS, although some
|
||||
native versions also support AT_SYMLINK_NOFOLLOW. */
|
||||
|
||||
#define AT_FUNC_NAME faccessat
|
||||
#define AT_FUNC_F1 euidaccess
|
||||
#define AT_FUNC_F2 access
|
||||
#define AT_FUNC_USE_F1_COND AT_EACCESS
|
||||
#define AT_FUNC_POST_FILE_PARAM_DECLS , int mode, int flag
|
||||
#define AT_FUNC_POST_FILE_ARGS , mode
|
||||
#include "at-func.c"
|
355
lib/fcntl.in.h
Normal file
355
lib/fcntl.in.h
Normal file
@ -0,0 +1,355 @@
|
||||
/* Like <fcntl.h>, but with non-working flags defined to 0.
|
||||
|
||||
Copyright (C) 2006-2012 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* written by Paul Eggert */
|
||||
|
||||
#if __GNUC__ >= 3
|
||||
@PRAGMA_SYSTEM_HEADER@
|
||||
#endif
|
||||
@PRAGMA_COLUMNS@
|
||||
|
||||
#if defined __need_system_fcntl_h
|
||||
/* Special invocation convention. */
|
||||
|
||||
/* Needed before <sys/stat.h>.
|
||||
May also define off_t to a 64-bit type on native Windows. */
|
||||
#include <sys/types.h>
|
||||
/* On some systems other than glibc, <sys/stat.h> is a prerequisite of
|
||||
<fcntl.h>. On glibc systems, we would like to avoid namespace pollution.
|
||||
But on glibc systems, <fcntl.h> includes <sys/stat.h> inside an
|
||||
extern "C" { ... } block, which leads to errors in C++ mode with the
|
||||
overridden <sys/stat.h> from gnulib. These errors are known to be gone
|
||||
with g++ version >= 4.3. */
|
||||
#if !(defined __GLIBC__ || defined __UCLIBC__) || (defined __cplusplus && defined GNULIB_NAMESPACE && !(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)))
|
||||
# include <sys/stat.h>
|
||||
#endif
|
||||
#@INCLUDE_NEXT@ @NEXT_FCNTL_H@
|
||||
|
||||
#else
|
||||
/* Normal invocation convention. */
|
||||
|
||||
#ifndef _@GUARD_PREFIX@_FCNTL_H
|
||||
|
||||
/* Needed before <sys/stat.h>.
|
||||
May also define off_t to a 64-bit type on native Windows. */
|
||||
#include <sys/types.h>
|
||||
/* On some systems other than glibc, <sys/stat.h> is a prerequisite of
|
||||
<fcntl.h>. On glibc systems, we would like to avoid namespace pollution.
|
||||
But on glibc systems, <fcntl.h> includes <sys/stat.h> inside an
|
||||
extern "C" { ... } block, which leads to errors in C++ mode with the
|
||||
overridden <sys/stat.h> from gnulib. These errors are known to be gone
|
||||
with g++ version >= 4.3. */
|
||||
#if !(defined __GLIBC__ || defined __UCLIBC__) || (defined __cplusplus && defined GNULIB_NAMESPACE && !(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)))
|
||||
# include <sys/stat.h>
|
||||
#endif
|
||||
/* The include_next requires a split double-inclusion guard. */
|
||||
#@INCLUDE_NEXT@ @NEXT_FCNTL_H@
|
||||
|
||||
#ifndef _@GUARD_PREFIX@_FCNTL_H
|
||||
#define _@GUARD_PREFIX@_FCNTL_H
|
||||
|
||||
#ifndef __GLIBC__ /* Avoid namespace pollution on glibc systems. */
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
/* Native Windows platforms declare open(), creat() in <io.h>. */
|
||||
#if (@GNULIB_OPEN@ || defined GNULIB_POSIXCHECK) \
|
||||
&& ((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__)
|
||||
# include <io.h>
|
||||
#endif
|
||||
|
||||
|
||||
/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */
|
||||
|
||||
/* The definition of _GL_ARG_NONNULL is copied here. */
|
||||
|
||||
/* The definition of _GL_WARN_ON_USE is copied here. */
|
||||
|
||||
|
||||
/* Declare overridden functions. */
|
||||
|
||||
#if @GNULIB_FCNTL@
|
||||
# if @REPLACE_FCNTL@
|
||||
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
|
||||
# undef fcntl
|
||||
# define fcntl rpl_fcntl
|
||||
# endif
|
||||
_GL_FUNCDECL_RPL (fcntl, int, (int fd, int action, ...));
|
||||
_GL_CXXALIAS_RPL (fcntl, int, (int fd, int action, ...));
|
||||
# else
|
||||
# if !@HAVE_FCNTL@
|
||||
_GL_FUNCDECL_SYS (fcntl, int, (int fd, int action, ...));
|
||||
# endif
|
||||
_GL_CXXALIAS_SYS (fcntl, int, (int fd, int action, ...));
|
||||
# endif
|
||||
_GL_CXXALIASWARN (fcntl);
|
||||
#elif defined GNULIB_POSIXCHECK
|
||||
# undef fcntl
|
||||
# if HAVE_RAW_DECL_FCNTL
|
||||
_GL_WARN_ON_USE (fcntl, "fcntl is not always POSIX compliant - "
|
||||
"use gnulib module fcntl for portability");
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if @GNULIB_OPEN@
|
||||
# if @REPLACE_OPEN@
|
||||
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
|
||||
# undef open
|
||||
# define open rpl_open
|
||||
# endif
|
||||
_GL_FUNCDECL_RPL (open, int, (const char *filename, int flags, ...)
|
||||
_GL_ARG_NONNULL ((1)));
|
||||
_GL_CXXALIAS_RPL (open, int, (const char *filename, int flags, ...));
|
||||
# else
|
||||
_GL_CXXALIAS_SYS (open, int, (const char *filename, int flags, ...));
|
||||
# endif
|
||||
/* On HP-UX 11, in C++ mode, open() is defined as an inline function with a
|
||||
default argument. _GL_CXXALIASWARN does not work in this case. */
|
||||
# if !defined __hpux
|
||||
_GL_CXXALIASWARN (open);
|
||||
# endif
|
||||
#elif defined GNULIB_POSIXCHECK
|
||||
# undef open
|
||||
/* Assume open is always declared. */
|
||||
_GL_WARN_ON_USE (open, "open is not always POSIX compliant - "
|
||||
"use gnulib module open for portability");
|
||||
#endif
|
||||
|
||||
#if @GNULIB_OPENAT@
|
||||
# if @REPLACE_OPENAT@
|
||||
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
|
||||
# undef openat
|
||||
# define openat rpl_openat
|
||||
# endif
|
||||
_GL_FUNCDECL_RPL (openat, int,
|
||||
(int fd, char const *file, int flags, /* mode_t mode */ ...)
|
||||
_GL_ARG_NONNULL ((2)));
|
||||
_GL_CXXALIAS_RPL (openat, int,
|
||||
(int fd, char const *file, int flags, /* mode_t mode */ ...));
|
||||
# else
|
||||
# if !@HAVE_OPENAT@
|
||||
_GL_FUNCDECL_SYS (openat, int,
|
||||
(int fd, char const *file, int flags, /* mode_t mode */ ...)
|
||||
_GL_ARG_NONNULL ((2)));
|
||||
# endif
|
||||
_GL_CXXALIAS_SYS (openat, int,
|
||||
(int fd, char const *file, int flags, /* mode_t mode */ ...));
|
||||
# endif
|
||||
_GL_CXXALIASWARN (openat);
|
||||
#elif defined GNULIB_POSIXCHECK
|
||||
# undef openat
|
||||
# if HAVE_RAW_DECL_OPENAT
|
||||
_GL_WARN_ON_USE (openat, "openat is not portable - "
|
||||
"use gnulib module openat for portability");
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
/* Fix up the FD_* macros, only known to be missing on mingw. */
|
||||
|
||||
#ifndef FD_CLOEXEC
|
||||
# define FD_CLOEXEC 1
|
||||
#endif
|
||||
|
||||
/* Fix up the supported F_* macros. Intentionally leave other F_*
|
||||
macros undefined. Only known to be missing on mingw. */
|
||||
|
||||
#ifndef F_DUPFD_CLOEXEC
|
||||
# define F_DUPFD_CLOEXEC 0x40000000
|
||||
/* Witness variable: 1 if gnulib defined F_DUPFD_CLOEXEC, 0 otherwise. */
|
||||
# define GNULIB_defined_F_DUPFD_CLOEXEC 1
|
||||
#else
|
||||
# define GNULIB_defined_F_DUPFD_CLOEXEC 0
|
||||
#endif
|
||||
|
||||
#ifndef F_DUPFD
|
||||
# define F_DUPFD 1
|
||||
#endif
|
||||
|
||||
#ifndef F_GETFD
|
||||
# define F_GETFD 2
|
||||
#endif
|
||||
|
||||
/* Fix up the O_* macros. */
|
||||
|
||||
#if !defined O_DIRECT && defined O_DIRECTIO
|
||||
/* Tru64 spells it 'O_DIRECTIO'. */
|
||||
# define O_DIRECT O_DIRECTIO
|
||||
#endif
|
||||
|
||||
#if !defined O_CLOEXEC && defined O_NOINHERIT
|
||||
/* Mingw spells it 'O_NOINHERIT'. */
|
||||
# define O_CLOEXEC O_NOINHERIT
|
||||
#endif
|
||||
|
||||
#ifndef O_CLOEXEC
|
||||
# define O_CLOEXEC 0
|
||||
#endif
|
||||
|
||||
#ifndef O_DIRECT
|
||||
# define O_DIRECT 0
|
||||
#endif
|
||||
|
||||
#ifndef O_DIRECTORY
|
||||
# define O_DIRECTORY 0
|
||||
#endif
|
||||
|
||||
#ifndef O_DSYNC
|
||||
# define O_DSYNC 0
|
||||
#endif
|
||||
|
||||
#ifndef O_EXEC
|
||||
# ifdef O_PATH
|
||||
# define O_EXEC O_PATH
|
||||
# else
|
||||
# define O_EXEC O_RDONLY /* This is often close enough in older systems. */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef O_IGNORE_CTTY
|
||||
# define O_IGNORE_CTTY 0
|
||||
#endif
|
||||
|
||||
#ifndef O_NDELAY
|
||||
# define O_NDELAY 0
|
||||
#endif
|
||||
|
||||
#ifndef O_NOATIME
|
||||
# define O_NOATIME 0
|
||||
#endif
|
||||
|
||||
#ifndef O_NONBLOCK
|
||||
# define O_NONBLOCK O_NDELAY
|
||||
#endif
|
||||
|
||||
/* If the gnulib module 'nonblocking' is in use, guarantee a working non-zero
|
||||
value of O_NONBLOCK. Otherwise, O_NONBLOCK is defined (above) to O_NDELAY
|
||||
or to 0 as fallback. */
|
||||
#if @GNULIB_NONBLOCKING@
|
||||
# if O_NONBLOCK
|
||||
# define GNULIB_defined_O_NONBLOCK 0
|
||||
# else
|
||||
# define GNULIB_defined_O_NONBLOCK 1
|
||||
# undef O_NONBLOCK
|
||||
# define O_NONBLOCK 0x40000000
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef O_NOCTTY
|
||||
# define O_NOCTTY 0
|
||||
#endif
|
||||
|
||||
#ifndef O_NOFOLLOW
|
||||
# define O_NOFOLLOW 0
|
||||
#endif
|
||||
|
||||
#ifndef O_NOLINK
|
||||
# define O_NOLINK 0
|
||||
#endif
|
||||
|
||||
#ifndef O_NOLINKS
|
||||
# define O_NOLINKS 0
|
||||
#endif
|
||||
|
||||
#ifndef O_NOTRANS
|
||||
# define O_NOTRANS 0
|
||||
#endif
|
||||
|
||||
#ifndef O_RSYNC
|
||||
# define O_RSYNC 0
|
||||
#endif
|
||||
|
||||
#ifndef O_SEARCH
|
||||
# ifdef O_PATH
|
||||
# define O_SEARCH O_PATH
|
||||
# else
|
||||
# define O_SEARCH O_RDONLY /* This is often close enough in older systems. */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef O_SYNC
|
||||
# define O_SYNC 0
|
||||
#endif
|
||||
|
||||
#ifndef O_TTY_INIT
|
||||
# define O_TTY_INIT 0
|
||||
#endif
|
||||
|
||||
#if ~O_ACCMODE & (O_RDONLY | O_WRONLY | O_RDWR | O_EXEC | O_SEARCH)
|
||||
# undef O_ACCMODE
|
||||
# define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR | O_EXEC | O_SEARCH)
|
||||
#endif
|
||||
|
||||
/* For systems that distinguish between text and binary I/O.
|
||||
O_BINARY is usually declared in fcntl.h */
|
||||
#if !defined O_BINARY && defined _O_BINARY
|
||||
/* For MSC-compatible compilers. */
|
||||
# define O_BINARY _O_BINARY
|
||||
# define O_TEXT _O_TEXT
|
||||
#endif
|
||||
|
||||
#if defined __BEOS__ || defined __HAIKU__
|
||||
/* BeOS 5 and Haiku have O_BINARY and O_TEXT, but they have no effect. */
|
||||
# undef O_BINARY
|
||||
# undef O_TEXT
|
||||
#endif
|
||||
|
||||
#ifndef O_BINARY
|
||||
# define O_BINARY 0
|
||||
# define O_TEXT 0
|
||||
#endif
|
||||
|
||||
/* Fix up the AT_* macros. */
|
||||
|
||||
/* Work around a bug in Solaris 9 and 10: AT_FDCWD is positive. Its
|
||||
value exceeds INT_MAX, so its use as an int doesn't conform to the
|
||||
C standard, and GCC and Sun C complain in some cases. If the bug
|
||||
is present, undef AT_FDCWD here, so it can be redefined below. */
|
||||
#if 0 < AT_FDCWD && AT_FDCWD == 0xffd19553
|
||||
# undef AT_FDCWD
|
||||
#endif
|
||||
|
||||
/* Use the same bit pattern as Solaris 9, but with the proper
|
||||
signedness. The bit pattern is important, in case this actually is
|
||||
Solaris with the above workaround. */
|
||||
#ifndef AT_FDCWD
|
||||
# define AT_FDCWD (-3041965)
|
||||
#endif
|
||||
|
||||
/* Use the same values as Solaris 9. This shouldn't matter, but
|
||||
there's no real reason to differ. */
|
||||
#ifndef AT_SYMLINK_NOFOLLOW
|
||||
# define AT_SYMLINK_NOFOLLOW 4096
|
||||
#endif
|
||||
|
||||
#ifndef AT_REMOVEDIR
|
||||
# define AT_REMOVEDIR 1
|
||||
#endif
|
||||
|
||||
/* Solaris 9 lacks these two, so just pick unique values. */
|
||||
#ifndef AT_SYMLINK_FOLLOW
|
||||
# define AT_SYMLINK_FOLLOW 2
|
||||
#endif
|
||||
|
||||
#ifndef AT_EACCESS
|
||||
# define AT_EACCESS 4
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _@GUARD_PREFIX@_FCNTL_H */
|
||||
#endif /* _@GUARD_PREFIX@_FCNTL_H */
|
||||
#endif
|
116
lib/getgroups.c
Normal file
116
lib/getgroups.c
Normal file
@ -0,0 +1,116 @@
|
||||
/* provide consistent interface to getgroups for systems that don't allow N==0
|
||||
|
||||
Copyright (C) 1996, 1999, 2003, 2006-2012 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* written by Jim Meyering */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if !HAVE_GETGROUPS
|
||||
|
||||
/* Provide a stub that fails with ENOSYS, since there is no group
|
||||
information available on mingw. */
|
||||
int
|
||||
getgroups (int n _GL_UNUSED, GETGROUPS_T *groups _GL_UNUSED)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#else /* HAVE_GETGROUPS */
|
||||
|
||||
# undef getgroups
|
||||
# ifndef GETGROUPS_ZERO_BUG
|
||||
# define GETGROUPS_ZERO_BUG 0
|
||||
# endif
|
||||
|
||||
/* On at least Ultrix 4.3 and NextStep 3.2, getgroups (0, NULL) always
|
||||
fails. On other systems, it returns the number of supplemental
|
||||
groups for the process. This function handles that special case
|
||||
and lets the system-provided function handle all others. However,
|
||||
it can fail with ENOMEM if memory is tight. It is unspecified
|
||||
whether the effective group id is included in the list. */
|
||||
|
||||
int
|
||||
rpl_getgroups (int n, gid_t *group)
|
||||
{
|
||||
int n_groups;
|
||||
GETGROUPS_T *gbuf;
|
||||
int saved_errno;
|
||||
|
||||
if (n < 0)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (n != 0 || !GETGROUPS_ZERO_BUG)
|
||||
{
|
||||
int result;
|
||||
if (sizeof *group == sizeof *gbuf)
|
||||
return getgroups (n, (GETGROUPS_T *) group);
|
||||
|
||||
if (SIZE_MAX / sizeof *gbuf <= n)
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
gbuf = malloc (n * sizeof *gbuf);
|
||||
if (!gbuf)
|
||||
return -1;
|
||||
result = getgroups (n, gbuf);
|
||||
if (0 <= result)
|
||||
{
|
||||
n = result;
|
||||
while (n--)
|
||||
group[n] = gbuf[n];
|
||||
}
|
||||
saved_errno = errno;
|
||||
free (gbuf);
|
||||
errno == saved_errno;
|
||||
return result;
|
||||
}
|
||||
|
||||
n = 20;
|
||||
while (1)
|
||||
{
|
||||
/* No need to worry about address arithmetic overflow here,
|
||||
since the ancient systems that we're running on have low
|
||||
limits on the number of secondary groups. */
|
||||
gbuf = malloc (n * sizeof *gbuf);
|
||||
if (!gbuf)
|
||||
return -1;
|
||||
n_groups = getgroups (n, gbuf);
|
||||
if (n_groups == -1 ? errno != EINVAL : n_groups < n)
|
||||
break;
|
||||
free (gbuf);
|
||||
n *= 2;
|
||||
}
|
||||
|
||||
saved_errno = errno;
|
||||
free (gbuf);
|
||||
errno = saved_errno;
|
||||
|
||||
return n_groups;
|
||||
}
|
||||
|
||||
#endif /* HAVE_GETGROUPS */
|
@ -21,7 +21,7 @@
|
||||
# the same distribution terms as the rest of that program.
|
||||
#
|
||||
# Generated by gnulib-tool.
|
||||
# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=errno --avoid=fcntl --avoid=fcntl-h --avoid=fstat --avoid=msvc-inval --avoid=msvc-nothrow --avoid=raise --avoid=select --avoid=sigprocmask --avoid=sys_types --avoid=threadlib --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt c-ctype c-strcase careadlinkat close-stream crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo filemode getloadavg getopt-gnu gettime gettimeofday ignore-value intprops largefile lstat manywarnings mktime pselect pthread_sigmask readlink socklen stat-time stdalign stdarg stdbool stdio strftime strtoimax strtoumax symlink sys_stat sys_time time timer-time timespec-add timespec-sub utimens warnings
|
||||
# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=at-internal --avoid=errno --avoid=fchdir --avoid=fcntl --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=openat-die --avoid=openat-h --avoid=raise --avoid=save-cwd --avoid=select --avoid=sigprocmask --avoid=sys_types --avoid=threadlib --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt c-ctype c-strcase careadlinkat close-stream crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo faccessat filemode getloadavg getopt-gnu gettime gettimeofday ignore-value intprops largefile lstat manywarnings mktime pselect pthread_sigmask readlink socklen stat-time stdalign stdarg stdbool stdio strftime strtoimax strtoumax symlink sys_stat sys_time time timer-time timespec-add timespec-sub utimens warnings
|
||||
|
||||
|
||||
MOSTLYCLEANFILES += core *.stackdump
|
||||
@ -158,6 +158,17 @@ EXTRA_libgnu_a_SOURCES += dup2.c
|
||||
|
||||
## end gnulib module dup2
|
||||
|
||||
## begin gnulib module euidaccess
|
||||
|
||||
if gl_GNULIB_ENABLED_euidaccess
|
||||
|
||||
endif
|
||||
EXTRA_DIST += euidaccess.c
|
||||
|
||||
EXTRA_libgnu_a_SOURCES += euidaccess.c
|
||||
|
||||
## end gnulib module euidaccess
|
||||
|
||||
## begin gnulib module execinfo
|
||||
|
||||
BUILT_SOURCES += $(EXECINFO_H)
|
||||
@ -183,6 +194,50 @@ EXTRA_libgnu_a_SOURCES += execinfo.c
|
||||
|
||||
## end gnulib module execinfo
|
||||
|
||||
## begin gnulib module faccessat
|
||||
|
||||
|
||||
EXTRA_DIST += at-func.c faccessat.c
|
||||
|
||||
EXTRA_libgnu_a_SOURCES += at-func.c faccessat.c
|
||||
|
||||
## end gnulib module faccessat
|
||||
|
||||
## begin gnulib module fcntl-h
|
||||
|
||||
BUILT_SOURCES += fcntl.h
|
||||
|
||||
# We need the following in order to create <fcntl.h> when the system
|
||||
# doesn't have one that works with the given compiler.
|
||||
fcntl.h: fcntl.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(WARN_ON_USE_H)
|
||||
$(AM_V_GEN)rm -f $@-t $@ && \
|
||||
{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \
|
||||
sed -e 's|@''GUARD_PREFIX''@|GL|g' \
|
||||
-e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \
|
||||
-e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
|
||||
-e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
|
||||
-e 's|@''NEXT_FCNTL_H''@|$(NEXT_FCNTL_H)|g' \
|
||||
-e 's/@''GNULIB_FCNTL''@/$(GNULIB_FCNTL)/g' \
|
||||
-e 's/@''GNULIB_NONBLOCKING''@/$(GNULIB_NONBLOCKING)/g' \
|
||||
-e 's/@''GNULIB_OPEN''@/$(GNULIB_OPEN)/g' \
|
||||
-e 's/@''GNULIB_OPENAT''@/$(GNULIB_OPENAT)/g' \
|
||||
-e 's|@''HAVE_FCNTL''@|$(HAVE_FCNTL)|g' \
|
||||
-e 's|@''HAVE_OPENAT''@|$(HAVE_OPENAT)|g' \
|
||||
-e 's|@''REPLACE_FCNTL''@|$(REPLACE_FCNTL)|g' \
|
||||
-e 's|@''REPLACE_OPEN''@|$(REPLACE_OPEN)|g' \
|
||||
-e 's|@''REPLACE_OPENAT''@|$(REPLACE_OPENAT)|g' \
|
||||
-e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
|
||||
-e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \
|
||||
-e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \
|
||||
< $(srcdir)/fcntl.in.h; \
|
||||
} > $@-t && \
|
||||
mv $@-t $@
|
||||
MOSTLYCLEANFILES += fcntl.h fcntl.h-t
|
||||
|
||||
EXTRA_DIST += fcntl.in.h
|
||||
|
||||
## end gnulib module fcntl-h
|
||||
|
||||
## begin gnulib module filemode
|
||||
|
||||
libgnu_a_SOURCES += filemode.c
|
||||
@ -200,6 +255,17 @@ EXTRA_libgnu_a_SOURCES += fpending.c
|
||||
|
||||
## end gnulib module fpending
|
||||
|
||||
## begin gnulib module getgroups
|
||||
|
||||
if gl_GNULIB_ENABLED_getgroups
|
||||
|
||||
endif
|
||||
EXTRA_DIST += getgroups.c
|
||||
|
||||
EXTRA_libgnu_a_SOURCES += getgroups.c
|
||||
|
||||
## end gnulib module getgroups
|
||||
|
||||
## begin gnulib module getloadavg
|
||||
|
||||
|
||||
@ -259,6 +325,17 @@ EXTRA_libgnu_a_SOURCES += gettimeofday.c
|
||||
|
||||
## end gnulib module gettimeofday
|
||||
|
||||
## begin gnulib module group-member
|
||||
|
||||
if gl_GNULIB_ENABLED_a9786850e999ae65a836a6041e8e5ed1
|
||||
|
||||
endif
|
||||
EXTRA_DIST += group-member.c
|
||||
|
||||
EXTRA_libgnu_a_SOURCES += group-member.c
|
||||
|
||||
## end gnulib module group-member
|
||||
|
||||
## begin gnulib module ignore-value
|
||||
|
||||
|
||||
@ -371,6 +448,15 @@ EXTRA_libgnu_a_SOURCES += readlink.c
|
||||
|
||||
## end gnulib module readlink
|
||||
|
||||
## begin gnulib module root-uid
|
||||
|
||||
if gl_GNULIB_ENABLED_6099e9737f757db36c47fa9d9f02e88c
|
||||
|
||||
endif
|
||||
EXTRA_DIST += root-uid.h
|
||||
|
||||
## end gnulib module root-uid
|
||||
|
||||
## begin gnulib module signal-h
|
||||
|
||||
BUILT_SOURCES += signal.h
|
||||
@ -1329,6 +1415,15 @@ EXTRA_DIST += verify.h
|
||||
|
||||
## end gnulib module verify
|
||||
|
||||
## begin gnulib module xalloc-oversized
|
||||
|
||||
if gl_GNULIB_ENABLED_682e609604ccaac6be382e4ee3a4eaec
|
||||
|
||||
endif
|
||||
EXTRA_DIST += xalloc-oversized.h
|
||||
|
||||
## end gnulib module xalloc-oversized
|
||||
|
||||
|
||||
mostlyclean-local: mostlyclean-generic
|
||||
@for dir in '' $(MOSTLYCLEANDIRS); do \
|
||||
|
119
lib/group-member.c
Normal file
119
lib/group-member.c
Normal file
@ -0,0 +1,119 @@
|
||||
/* group-member.c -- determine whether group id is in calling user's group list
|
||||
|
||||
Copyright (C) 1994, 1997-1998, 2003, 2005-2006, 2009-2012 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
/* Specification. */
|
||||
#include <unistd.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "xalloc-oversized.h"
|
||||
|
||||
/* Most processes have no more than this many groups, and for these
|
||||
processes we can avoid using malloc. */
|
||||
enum { GROUPBUF_SIZE = 100 };
|
||||
|
||||
struct group_info
|
||||
{
|
||||
gid_t *group;
|
||||
gid_t groupbuf[GROUPBUF_SIZE];
|
||||
};
|
||||
|
||||
static void
|
||||
free_group_info (struct group_info const *g)
|
||||
{
|
||||
if (g->group != g->groupbuf)
|
||||
free (g->group);
|
||||
}
|
||||
|
||||
static int
|
||||
get_group_info (struct group_info *gi)
|
||||
{
|
||||
int n_groups = getgroups (GROUPBUF_SIZE, gi->groupbuf);
|
||||
gi->group = gi->groupbuf;
|
||||
|
||||
if (n_groups < 0)
|
||||
{
|
||||
int n_group_slots = getgroups (0, NULL);
|
||||
if (0 <= n_group_slots
|
||||
&& ! xalloc_oversized (n_group_slots, sizeof *gi->group))
|
||||
{
|
||||
gi->group = malloc (n_group_slots * sizeof *gi->group);
|
||||
if (gi->group)
|
||||
n_groups = getgroups (n_group_slots, gi->group);
|
||||
}
|
||||
}
|
||||
|
||||
/* In case of error, the user loses. */
|
||||
return n_groups;
|
||||
}
|
||||
|
||||
/* Return non-zero if GID is one that we have in our groups list.
|
||||
Note that the groups list is not guaranteed to contain the current
|
||||
or effective group ID, so they should generally be checked
|
||||
separately. */
|
||||
|
||||
int
|
||||
group_member (gid_t gid)
|
||||
{
|
||||
int i;
|
||||
int found;
|
||||
struct group_info gi;
|
||||
int n_groups = get_group_info (&gi);
|
||||
|
||||
/* Search through the list looking for GID. */
|
||||
found = 0;
|
||||
for (i = 0; i < n_groups; i++)
|
||||
{
|
||||
if (gid == gi.group[i])
|
||||
{
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free_group_info (&gi);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
char *program_name;
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
|
||||
program_name = argv[0];
|
||||
|
||||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
gid_t gid;
|
||||
|
||||
gid = atoi (argv[i]);
|
||||
printf ("%d: %s\n", gid, group_member (gid) ? "yes" : "no");
|
||||
}
|
||||
exit (0);
|
||||
}
|
||||
|
||||
#endif /* TEST */
|
30
lib/root-uid.h
Normal file
30
lib/root-uid.h
Normal file
@ -0,0 +1,30 @@
|
||||
/* The user ID that always has appropriate privileges in the POSIX sense.
|
||||
|
||||
Copyright 2012 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Written by Paul Eggert. */
|
||||
|
||||
#ifndef ROOT_UID_H_
|
||||
#define ROOT_UID_H_
|
||||
|
||||
/* The user ID that always has appropriate privileges in the POSIX sense. */
|
||||
#ifdef __TANDEM
|
||||
# define ROOT_UID 65535
|
||||
#else
|
||||
# define ROOT_UID 0
|
||||
#endif
|
||||
|
||||
#endif
|
38
lib/xalloc-oversized.h
Normal file
38
lib/xalloc-oversized.h
Normal file
@ -0,0 +1,38 @@
|
||||
/* xalloc-oversized.h -- memory allocation size checking
|
||||
|
||||
Copyright (C) 1990-2000, 2003-2004, 2006-2012 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef XALLOC_OVERSIZED_H_
|
||||
# define XALLOC_OVERSIZED_H_
|
||||
|
||||
# include <stddef.h>
|
||||
|
||||
/* Return 1 if an array of N objects, each of size S, cannot exist due
|
||||
to size arithmetic overflow. S must be positive and N must be
|
||||
nonnegative. This is a macro, not a function, so that it
|
||||
works correctly even when SIZE_MAX < N.
|
||||
|
||||
By gnulib convention, SIZE_MAX represents overflow in size
|
||||
calculations, so the conservative dividend to use here is
|
||||
SIZE_MAX - 1, since SIZE_MAX might represent an overflowed value.
|
||||
However, malloc (SIZE_MAX) fails on all known hosts where
|
||||
sizeof (ptrdiff_t) <= sizeof (size_t), so do not bother to test for
|
||||
exactly-SIZE_MAX allocations on such hosts; this avoids a test and
|
||||
branch when S is known to be 1. */
|
||||
# define xalloc_oversized(n, s) \
|
||||
((size_t) (sizeof (ptrdiff_t) <= sizeof (size_t) ? -1 : -2) / (s) < (n))
|
||||
|
||||
#endif /* !XALLOC_OVERSIZED_H_ */
|
52
m4/euidaccess.m4
Normal file
52
m4/euidaccess.m4
Normal file
@ -0,0 +1,52 @@
|
||||
# euidaccess.m4 serial 15
|
||||
dnl Copyright (C) 2002-2012 Free Software Foundation, Inc.
|
||||
dnl This file is free software; the Free Software Foundation
|
||||
dnl gives unlimited permission to copy and/or distribute it,
|
||||
dnl with or without modifications, as long as this notice is preserved.
|
||||
|
||||
AC_DEFUN([gl_FUNC_NONREENTRANT_EUIDACCESS],
|
||||
[
|
||||
AC_REQUIRE([gl_FUNC_EUIDACCESS])
|
||||
AC_CHECK_DECLS([setregid])
|
||||
AC_DEFINE([PREFER_NONREENTRANT_EUIDACCESS], [1],
|
||||
[Define this if you prefer euidaccess to return the correct result
|
||||
even if this would make it nonreentrant. Define this only if your
|
||||
entire application is safe even if the uid or gid might temporarily
|
||||
change. If your application uses signal handlers or threads it
|
||||
is probably not safe.])
|
||||
])
|
||||
|
||||
AC_DEFUN([gl_FUNC_EUIDACCESS],
|
||||
[
|
||||
AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
|
||||
|
||||
dnl Persuade glibc <unistd.h> to declare euidaccess().
|
||||
AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
|
||||
|
||||
AC_CHECK_FUNCS([euidaccess])
|
||||
if test $ac_cv_func_euidaccess = no; then
|
||||
HAVE_EUIDACCESS=0
|
||||
fi
|
||||
])
|
||||
|
||||
# Prerequisites of lib/euidaccess.c.
|
||||
AC_DEFUN([gl_PREREQ_EUIDACCESS], [
|
||||
dnl Prefer POSIX faccessat over non-standard euidaccess.
|
||||
AC_CHECK_FUNCS_ONCE([faccessat])
|
||||
dnl Try various other non-standard fallbacks.
|
||||
AC_CHECK_HEADERS([libgen.h])
|
||||
AC_FUNC_GETGROUPS
|
||||
|
||||
# Solaris 9 and 10 need -lgen to get the eaccess function.
|
||||
# Save and restore LIBS so -lgen isn't added to it. Otherwise, *all*
|
||||
# programs in the package would end up linked with that potentially-shared
|
||||
# library, inducing unnecessary run-time overhead.
|
||||
LIB_EACCESS=
|
||||
AC_SUBST([LIB_EACCESS])
|
||||
gl_saved_libs=$LIBS
|
||||
AC_SEARCH_LIBS([eaccess], [gen],
|
||||
[test "$ac_cv_search_eaccess" = "none required" ||
|
||||
LIB_EACCESS=$ac_cv_search_eaccess])
|
||||
AC_CHECK_FUNCS([eaccess])
|
||||
LIBS=$gl_saved_libs
|
||||
])
|
28
m4/faccessat.m4
Normal file
28
m4/faccessat.m4
Normal file
@ -0,0 +1,28 @@
|
||||
# serial 6
|
||||
# See if we need to provide faccessat replacement.
|
||||
|
||||
dnl Copyright (C) 2009-2012 Free Software Foundation, Inc.
|
||||
dnl This file is free software; the Free Software Foundation
|
||||
dnl gives unlimited permission to copy and/or distribute it,
|
||||
dnl with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# Written by Eric Blake.
|
||||
|
||||
AC_DEFUN([gl_FUNC_FACCESSAT],
|
||||
[
|
||||
AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
|
||||
|
||||
dnl Persuade glibc <unistd.h> to declare faccessat().
|
||||
AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
|
||||
|
||||
AC_CHECK_FUNCS_ONCE([faccessat])
|
||||
if test $ac_cv_func_faccessat = no; then
|
||||
HAVE_FACCESSAT=0
|
||||
fi
|
||||
])
|
||||
|
||||
# Prerequisites of lib/faccessat.m4.
|
||||
AC_DEFUN([gl_PREREQ_FACCESSAT],
|
||||
[
|
||||
AC_CHECK_FUNCS([access])
|
||||
])
|
50
m4/fcntl_h.m4
Normal file
50
m4/fcntl_h.m4
Normal file
@ -0,0 +1,50 @@
|
||||
# serial 15
|
||||
# Configure fcntl.h.
|
||||
dnl Copyright (C) 2006-2007, 2009-2012 Free Software Foundation, Inc.
|
||||
dnl This file is free software; the Free Software Foundation
|
||||
dnl gives unlimited permission to copy and/or distribute it,
|
||||
dnl with or without modifications, as long as this notice is preserved.
|
||||
|
||||
dnl Written by Paul Eggert.
|
||||
|
||||
AC_DEFUN([gl_FCNTL_H],
|
||||
[
|
||||
AC_REQUIRE([gl_FCNTL_H_DEFAULTS])
|
||||
AC_REQUIRE([gl_FCNTL_O_FLAGS])
|
||||
gl_NEXT_HEADERS([fcntl.h])
|
||||
|
||||
dnl Ensure the type pid_t gets defined.
|
||||
AC_REQUIRE([AC_TYPE_PID_T])
|
||||
|
||||
dnl Ensure the type mode_t gets defined.
|
||||
AC_REQUIRE([AC_TYPE_MODE_T])
|
||||
|
||||
dnl Check for declarations of anything we want to poison if the
|
||||
dnl corresponding gnulib module is not in use, if it is not common
|
||||
dnl enough to be declared everywhere.
|
||||
gl_WARN_ON_USE_PREPARE([[#include <fcntl.h>
|
||||
]], [fcntl openat])
|
||||
])
|
||||
|
||||
AC_DEFUN([gl_FCNTL_MODULE_INDICATOR],
|
||||
[
|
||||
dnl Use AC_REQUIRE here, so that the default settings are expanded once only.
|
||||
AC_REQUIRE([gl_FCNTL_H_DEFAULTS])
|
||||
gl_MODULE_INDICATOR_SET_VARIABLE([$1])
|
||||
dnl Define it also as a C macro, for the benefit of the unit tests.
|
||||
gl_MODULE_INDICATOR_FOR_TESTS([$1])
|
||||
])
|
||||
|
||||
AC_DEFUN([gl_FCNTL_H_DEFAULTS],
|
||||
[
|
||||
GNULIB_FCNTL=0; AC_SUBST([GNULIB_FCNTL])
|
||||
GNULIB_NONBLOCKING=0; AC_SUBST([GNULIB_NONBLOCKING])
|
||||
GNULIB_OPEN=0; AC_SUBST([GNULIB_OPEN])
|
||||
GNULIB_OPENAT=0; AC_SUBST([GNULIB_OPENAT])
|
||||
dnl Assume proper GNU behavior unless another module says otherwise.
|
||||
HAVE_FCNTL=1; AC_SUBST([HAVE_FCNTL])
|
||||
HAVE_OPENAT=1; AC_SUBST([HAVE_OPENAT])
|
||||
REPLACE_FCNTL=0; AC_SUBST([REPLACE_FCNTL])
|
||||
REPLACE_OPEN=0; AC_SUBST([REPLACE_OPEN])
|
||||
REPLACE_OPENAT=0; AC_SUBST([REPLACE_OPENAT])
|
||||
])
|
107
m4/getgroups.m4
Normal file
107
m4/getgroups.m4
Normal file
@ -0,0 +1,107 @@
|
||||
# serial 18
|
||||
|
||||
dnl From Jim Meyering.
|
||||
dnl A wrapper around AC_FUNC_GETGROUPS.
|
||||
|
||||
# Copyright (C) 1996-1997, 1999-2004, 2008-2012 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
m4_version_prereq([2.70], [] ,[
|
||||
|
||||
# This is taken from the following Autoconf patch:
|
||||
# http://git.savannah.gnu.org/gitweb/?p=autoconf.git;a=commitdiff;h=7fbb553727ed7e0e689a17594b58559ecf3ea6e9
|
||||
AC_DEFUN([AC_FUNC_GETGROUPS],
|
||||
[
|
||||
AC_REQUIRE([AC_TYPE_GETGROUPS])dnl
|
||||
AC_REQUIRE([AC_TYPE_SIZE_T])dnl
|
||||
AC_REQUIRE([AC_CANONICAL_HOST])dnl for cross-compiles
|
||||
AC_CHECK_FUNC([getgroups])
|
||||
|
||||
# If we don't yet have getgroups, see if it's in -lbsd.
|
||||
# This is reported to be necessary on an ITOS 3000WS running SEIUX 3.1.
|
||||
ac_save_LIBS=$LIBS
|
||||
if test $ac_cv_func_getgroups = no; then
|
||||
AC_CHECK_LIB(bsd, getgroups, [GETGROUPS_LIB=-lbsd])
|
||||
fi
|
||||
|
||||
# Run the program to test the functionality of the system-supplied
|
||||
# getgroups function only if there is such a function.
|
||||
if test $ac_cv_func_getgroups = yes; then
|
||||
AC_CACHE_CHECK([for working getgroups], [ac_cv_func_getgroups_works],
|
||||
[AC_RUN_IFELSE(
|
||||
[AC_LANG_PROGRAM(
|
||||
[AC_INCLUDES_DEFAULT],
|
||||
[[/* On Ultrix 4.3, getgroups (0, 0) always fails. */
|
||||
return getgroups (0, 0) == -1;]])
|
||||
],
|
||||
[ac_cv_func_getgroups_works=yes],
|
||||
[ac_cv_func_getgroups_works=no],
|
||||
[case "$host_os" in # ((
|
||||
# Guess yes on glibc systems.
|
||||
*-gnu*) ac_cv_func_getgroups_works="guessing yes" ;;
|
||||
# If we don't know, assume the worst.
|
||||
*) ac_cv_func_getgroups_works="guessing no" ;;
|
||||
esac
|
||||
])
|
||||
])
|
||||
else
|
||||
ac_cv_func_getgroups_works=no
|
||||
fi
|
||||
case "$ac_cv_func_getgroups_works" in
|
||||
*yes)
|
||||
AC_DEFINE([HAVE_GETGROUPS], [1],
|
||||
[Define to 1 if your system has a working `getgroups' function.])
|
||||
;;
|
||||
esac
|
||||
LIBS=$ac_save_LIBS
|
||||
])# AC_FUNC_GETGROUPS
|
||||
|
||||
])
|
||||
|
||||
AC_DEFUN([gl_FUNC_GETGROUPS],
|
||||
[
|
||||
AC_REQUIRE([AC_TYPE_GETGROUPS])
|
||||
AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
|
||||
AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
|
||||
|
||||
AC_FUNC_GETGROUPS
|
||||
if test $ac_cv_func_getgroups != yes; then
|
||||
HAVE_GETGROUPS=0
|
||||
else
|
||||
if test "$ac_cv_type_getgroups" != gid_t \
|
||||
|| { case "$ac_cv_func_getgroups_works" in
|
||||
*yes) false;;
|
||||
*) true;;
|
||||
esac
|
||||
}; then
|
||||
REPLACE_GETGROUPS=1
|
||||
AC_DEFINE([GETGROUPS_ZERO_BUG], [1], [Define this to 1 if
|
||||
getgroups(0,NULL) does not return the number of groups.])
|
||||
else
|
||||
dnl Detect FreeBSD bug; POSIX requires getgroups(-1,ptr) to fail.
|
||||
AC_CACHE_CHECK([whether getgroups handles negative values],
|
||||
[gl_cv_func_getgroups_works],
|
||||
[AC_RUN_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT],
|
||||
[[int size = getgroups (0, 0);
|
||||
gid_t *list = malloc (size * sizeof *list);
|
||||
return getgroups (-1, list) != -1;]])],
|
||||
[gl_cv_func_getgroups_works=yes],
|
||||
[gl_cv_func_getgroups_works=no],
|
||||
[case "$host_os" in
|
||||
# Guess yes on glibc systems.
|
||||
*-gnu*) gl_cv_func_getgroups_works="guessing yes" ;;
|
||||
# If we don't know, assume the worst.
|
||||
*) gl_cv_func_getgroups_works="guessing no" ;;
|
||||
esac
|
||||
])])
|
||||
case "$gl_cv_func_getgroups_works" in
|
||||
*yes) ;;
|
||||
*) REPLACE_GETGROUPS=1 ;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
test -n "$GETGROUPS_LIB" && LIBS="$GETGROUPS_LIB $LIBS"
|
||||
])
|
@ -54,18 +54,23 @@ AC_DEFUN([gl_EARLY],
|
||||
# Code from module dtotimespec:
|
||||
# Code from module dup2:
|
||||
# Code from module environ:
|
||||
# Code from module euidaccess:
|
||||
# Code from module execinfo:
|
||||
# Code from module extensions:
|
||||
AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
|
||||
# Code from module extern-inline:
|
||||
# Code from module faccessat:
|
||||
# Code from module fcntl-h:
|
||||
# Code from module filemode:
|
||||
# Code from module fpending:
|
||||
# Code from module getgroups:
|
||||
# Code from module getloadavg:
|
||||
# Code from module getopt-gnu:
|
||||
# Code from module getopt-posix:
|
||||
# Code from module gettext-h:
|
||||
# Code from module gettime:
|
||||
# Code from module gettimeofday:
|
||||
# Code from module group-member:
|
||||
# Code from module ignore-value:
|
||||
# Code from module include_next:
|
||||
# Code from module intprops:
|
||||
@ -81,6 +86,7 @@ AC_DEFUN([gl_EARLY],
|
||||
# Code from module pselect:
|
||||
# Code from module pthread_sigmask:
|
||||
# Code from module readlink:
|
||||
# Code from module root-uid:
|
||||
# Code from module signal-h:
|
||||
# Code from module snippet/_Noreturn:
|
||||
# Code from module snippet/arg-nonnull:
|
||||
@ -122,6 +128,7 @@ AC_DEFUN([gl_EARLY],
|
||||
# Code from module utimens:
|
||||
# Code from module verify:
|
||||
# Code from module warnings:
|
||||
# Code from module xalloc-oversized:
|
||||
])
|
||||
|
||||
# This macro should be invoked from ./configure.ac, in the section
|
||||
@ -160,6 +167,14 @@ AC_DEFUN([gl_INIT],
|
||||
gl_UNISTD_MODULE_INDICATOR([environ])
|
||||
gl_EXECINFO_H
|
||||
AC_REQUIRE([gl_EXTERN_INLINE])
|
||||
gl_FUNC_FACCESSAT
|
||||
if test $HAVE_FACCESSAT = 0; then
|
||||
AC_LIBOBJ([faccessat])
|
||||
gl_PREREQ_FACCESSAT
|
||||
fi
|
||||
gl_MODULE_INDICATOR([faccessat])
|
||||
gl_UNISTD_MODULE_INDICATOR([faccessat])
|
||||
gl_FCNTL_H
|
||||
gl_FILEMODE
|
||||
gl_FUNC_FPENDING
|
||||
if test $ac_cv_func___fpending = no; then
|
||||
@ -278,18 +293,53 @@ AC_DEFUN([gl_INIT],
|
||||
gl_UNISTD_H
|
||||
gl_UTIMENS
|
||||
gl_gnulib_enabled_dosname=false
|
||||
gl_gnulib_enabled_euidaccess=false
|
||||
gl_gnulib_enabled_getgroups=false
|
||||
gl_gnulib_enabled_be453cec5eecf5731a274f2de7f2db36=false
|
||||
gl_gnulib_enabled_a9786850e999ae65a836a6041e8e5ed1=false
|
||||
gl_gnulib_enabled_pathmax=false
|
||||
gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c=false
|
||||
gl_gnulib_enabled_stat=false
|
||||
gl_gnulib_enabled_strtoll=false
|
||||
gl_gnulib_enabled_strtoull=false
|
||||
gl_gnulib_enabled_verify=false
|
||||
gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec=false
|
||||
func_gl_gnulib_m4code_dosname ()
|
||||
{
|
||||
if ! $gl_gnulib_enabled_dosname; then
|
||||
gl_gnulib_enabled_dosname=true
|
||||
fi
|
||||
}
|
||||
func_gl_gnulib_m4code_euidaccess ()
|
||||
{
|
||||
if ! $gl_gnulib_enabled_euidaccess; then
|
||||
gl_FUNC_EUIDACCESS
|
||||
if test $HAVE_EUIDACCESS = 0; then
|
||||
AC_LIBOBJ([euidaccess])
|
||||
gl_PREREQ_EUIDACCESS
|
||||
fi
|
||||
gl_UNISTD_MODULE_INDICATOR([euidaccess])
|
||||
gl_gnulib_enabled_euidaccess=true
|
||||
if test $HAVE_EUIDACCESS = 0; then
|
||||
func_gl_gnulib_m4code_a9786850e999ae65a836a6041e8e5ed1
|
||||
fi
|
||||
func_gl_gnulib_m4code_6099e9737f757db36c47fa9d9f02e88c
|
||||
if test $HAVE_EUIDACCESS = 0; then
|
||||
func_gl_gnulib_m4code_stat
|
||||
fi
|
||||
fi
|
||||
}
|
||||
func_gl_gnulib_m4code_getgroups ()
|
||||
{
|
||||
if ! $gl_gnulib_enabled_getgroups; then
|
||||
gl_FUNC_GETGROUPS
|
||||
if test $HAVE_GETGROUPS = 0 || test $REPLACE_GETGROUPS = 1; then
|
||||
AC_LIBOBJ([getgroups])
|
||||
fi
|
||||
gl_UNISTD_MODULE_INDICATOR([getgroups])
|
||||
gl_gnulib_enabled_getgroups=true
|
||||
fi
|
||||
}
|
||||
func_gl_gnulib_m4code_be453cec5eecf5731a274f2de7f2db36 ()
|
||||
{
|
||||
if ! $gl_gnulib_enabled_be453cec5eecf5731a274f2de7f2db36; then
|
||||
@ -298,6 +348,24 @@ AC_DEFUN([gl_INIT],
|
||||
gl_gnulib_enabled_be453cec5eecf5731a274f2de7f2db36=true
|
||||
fi
|
||||
}
|
||||
func_gl_gnulib_m4code_a9786850e999ae65a836a6041e8e5ed1 ()
|
||||
{
|
||||
if ! $gl_gnulib_enabled_a9786850e999ae65a836a6041e8e5ed1; then
|
||||
gl_FUNC_GROUP_MEMBER
|
||||
if test $HAVE_GROUP_MEMBER = 0; then
|
||||
AC_LIBOBJ([group-member])
|
||||
gl_PREREQ_GROUP_MEMBER
|
||||
fi
|
||||
gl_UNISTD_MODULE_INDICATOR([group-member])
|
||||
gl_gnulib_enabled_a9786850e999ae65a836a6041e8e5ed1=true
|
||||
if test $HAVE_GROUP_MEMBER = 0; then
|
||||
func_gl_gnulib_m4code_getgroups
|
||||
fi
|
||||
if test $HAVE_GROUP_MEMBER = 0; then
|
||||
func_gl_gnulib_m4code_682e609604ccaac6be382e4ee3a4eaec
|
||||
fi
|
||||
fi
|
||||
}
|
||||
func_gl_gnulib_m4code_pathmax ()
|
||||
{
|
||||
if ! $gl_gnulib_enabled_pathmax; then
|
||||
@ -305,6 +373,12 @@ AC_DEFUN([gl_INIT],
|
||||
gl_gnulib_enabled_pathmax=true
|
||||
fi
|
||||
}
|
||||
func_gl_gnulib_m4code_6099e9737f757db36c47fa9d9f02e88c ()
|
||||
{
|
||||
if ! $gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c; then
|
||||
gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c=true
|
||||
fi
|
||||
}
|
||||
func_gl_gnulib_m4code_stat ()
|
||||
{
|
||||
if ! $gl_gnulib_enabled_stat; then
|
||||
@ -356,6 +430,18 @@ AC_DEFUN([gl_INIT],
|
||||
gl_gnulib_enabled_verify=true
|
||||
fi
|
||||
}
|
||||
func_gl_gnulib_m4code_682e609604ccaac6be382e4ee3a4eaec ()
|
||||
{
|
||||
if ! $gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec; then
|
||||
gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec=true
|
||||
fi
|
||||
}
|
||||
if test $HAVE_FACCESSAT = 0; then
|
||||
func_gl_gnulib_m4code_dosname
|
||||
fi
|
||||
if test $HAVE_FACCESSAT = 0; then
|
||||
func_gl_gnulib_m4code_euidaccess
|
||||
fi
|
||||
if test $REPLACE_GETOPT = 1; then
|
||||
func_gl_gnulib_m4code_be453cec5eecf5731a274f2de7f2db36
|
||||
fi
|
||||
@ -382,12 +468,17 @@ AC_DEFUN([gl_INIT],
|
||||
fi
|
||||
m4_pattern_allow([^gl_GNULIB_ENABLED_])
|
||||
AM_CONDITIONAL([gl_GNULIB_ENABLED_dosname], [$gl_gnulib_enabled_dosname])
|
||||
AM_CONDITIONAL([gl_GNULIB_ENABLED_euidaccess], [$gl_gnulib_enabled_euidaccess])
|
||||
AM_CONDITIONAL([gl_GNULIB_ENABLED_getgroups], [$gl_gnulib_enabled_getgroups])
|
||||
AM_CONDITIONAL([gl_GNULIB_ENABLED_be453cec5eecf5731a274f2de7f2db36], [$gl_gnulib_enabled_be453cec5eecf5731a274f2de7f2db36])
|
||||
AM_CONDITIONAL([gl_GNULIB_ENABLED_a9786850e999ae65a836a6041e8e5ed1], [$gl_gnulib_enabled_a9786850e999ae65a836a6041e8e5ed1])
|
||||
AM_CONDITIONAL([gl_GNULIB_ENABLED_pathmax], [$gl_gnulib_enabled_pathmax])
|
||||
AM_CONDITIONAL([gl_GNULIB_ENABLED_6099e9737f757db36c47fa9d9f02e88c], [$gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c])
|
||||
AM_CONDITIONAL([gl_GNULIB_ENABLED_stat], [$gl_gnulib_enabled_stat])
|
||||
AM_CONDITIONAL([gl_GNULIB_ENABLED_strtoll], [$gl_gnulib_enabled_strtoll])
|
||||
AM_CONDITIONAL([gl_GNULIB_ENABLED_strtoull], [$gl_gnulib_enabled_strtoull])
|
||||
AM_CONDITIONAL([gl_GNULIB_ENABLED_verify], [$gl_gnulib_enabled_verify])
|
||||
AM_CONDITIONAL([gl_GNULIB_ENABLED_682e609604ccaac6be382e4ee3a4eaec], [$gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec])
|
||||
# End of code from modules
|
||||
m4_ifval(gl_LIBSOURCES_LIST, [
|
||||
m4_syscmd([test ! -d ]m4_defn([gl_LIBSOURCES_DIR])[ ||
|
||||
@ -536,6 +627,7 @@ AC_DEFUN([gl_FILE_LIST], [
|
||||
lib/alloca.in.h
|
||||
lib/allocator.c
|
||||
lib/allocator.h
|
||||
lib/at-func.c
|
||||
lib/c-ctype.c
|
||||
lib/c-ctype.h
|
||||
lib/c-strcase.h
|
||||
@ -549,14 +641,18 @@ AC_DEFUN([gl_FILE_LIST], [
|
||||
lib/dtoastr.c
|
||||
lib/dtotimespec.c
|
||||
lib/dup2.c
|
||||
lib/euidaccess.c
|
||||
lib/execinfo.c
|
||||
lib/execinfo.in.h
|
||||
lib/faccessat.c
|
||||
lib/fcntl.in.h
|
||||
lib/filemode.c
|
||||
lib/filemode.h
|
||||
lib/fpending.c
|
||||
lib/fpending.h
|
||||
lib/ftoastr.c
|
||||
lib/ftoastr.h
|
||||
lib/getgroups.c
|
||||
lib/getloadavg.c
|
||||
lib/getopt.c
|
||||
lib/getopt.in.h
|
||||
@ -565,6 +661,7 @@ AC_DEFUN([gl_FILE_LIST], [
|
||||
lib/gettext.h
|
||||
lib/gettime.c
|
||||
lib/gettimeofday.c
|
||||
lib/group-member.c
|
||||
lib/ignore-value.h
|
||||
lib/intprops.h
|
||||
lib/inttypes.in.h
|
||||
@ -577,6 +674,7 @@ AC_DEFUN([gl_FILE_LIST], [
|
||||
lib/pselect.c
|
||||
lib/pthread_sigmask.c
|
||||
lib/readlink.c
|
||||
lib/root-uid.h
|
||||
lib/sha1.c
|
||||
lib/sha1.h
|
||||
lib/sha256.c
|
||||
@ -618,6 +716,7 @@ AC_DEFUN([gl_FILE_LIST], [
|
||||
lib/utimens.c
|
||||
lib/utimens.h
|
||||
lib/verify.h
|
||||
lib/xalloc-oversized.h
|
||||
m4/00gnulib.m4
|
||||
m4/alloca.m4
|
||||
m4/c-strtod.m4
|
||||
@ -625,16 +724,22 @@ AC_DEFUN([gl_FILE_LIST], [
|
||||
m4/close-stream.m4
|
||||
m4/dup2.m4
|
||||
m4/environ.m4
|
||||
m4/euidaccess.m4
|
||||
m4/execinfo.m4
|
||||
m4/extensions.m4
|
||||
m4/extern-inline.m4
|
||||
m4/faccessat.m4
|
||||
m4/fcntl-o.m4
|
||||
m4/fcntl_h.m4
|
||||
m4/filemode.m4
|
||||
m4/fpending.m4
|
||||
m4/getgroups.m4
|
||||
m4/getloadavg.m4
|
||||
m4/getopt.m4
|
||||
m4/gettime.m4
|
||||
m4/gettimeofday.m4
|
||||
m4/gnulib-common.m4
|
||||
m4/group-member.m4
|
||||
m4/include_next.m4
|
||||
m4/inttypes.m4
|
||||
m4/largefile.m4
|
||||
|
29
m4/group-member.m4
Normal file
29
m4/group-member.m4
Normal file
@ -0,0 +1,29 @@
|
||||
# serial 14
|
||||
|
||||
# Copyright (C) 1999-2001, 2003-2007, 2009-2012 Free Software Foundation, Inc.
|
||||
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
dnl Written by Jim Meyering
|
||||
|
||||
AC_DEFUN([gl_FUNC_GROUP_MEMBER],
|
||||
[
|
||||
AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
|
||||
|
||||
dnl Persuade glibc <unistd.h> to declare group_member().
|
||||
AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
|
||||
|
||||
dnl Do this replacement check manually because I want the hyphen
|
||||
dnl (not the underscore) in the filename.
|
||||
AC_CHECK_FUNC([group_member], , [
|
||||
HAVE_GROUP_MEMBER=0
|
||||
])
|
||||
])
|
||||
|
||||
# Prerequisites of lib/group-member.c.
|
||||
AC_DEFUN([gl_PREREQ_GROUP_MEMBER],
|
||||
[
|
||||
AC_REQUIRE([AC_FUNC_GETGROUPS])
|
||||
])
|
@ -1,3 +1,10 @@
|
||||
2012-11-14 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
Use faccessat, not access, when checking file permissions (Bug#12632).
|
||||
* inc/ms-w32.h (AT_FDCWD, AT_EACCESS): New symbols.
|
||||
(access): Remove.
|
||||
(faccessat): New macro.
|
||||
|
||||
2012-11-05 Eli Zaretskii <eliz@gnu.org>
|
||||
|
||||
* inc/unistd.h (tcgetpgrp, setsid): Provide prototypes.
|
||||
|
@ -124,6 +124,10 @@ extern char *getenv ();
|
||||
#define MAXPATHLEN _MAX_PATH
|
||||
#endif
|
||||
|
||||
/* Use values compatible with gnulib, as there's no reason to differ. */
|
||||
#define AT_FDCWD (-3041965)
|
||||
#define AT_EACCESS 4
|
||||
|
||||
#ifdef HAVE_NTGUI
|
||||
#define HAVE_WINDOW_SYSTEM 1
|
||||
#define HAVE_MENUS 1
|
||||
@ -145,8 +149,6 @@ extern char *getenv ();
|
||||
#endif
|
||||
|
||||
/* Calls that are emulated or shadowed. */
|
||||
#undef access
|
||||
#define access sys_access
|
||||
#undef chdir
|
||||
#define chdir sys_chdir
|
||||
#undef chmod
|
||||
@ -161,6 +163,7 @@ extern char *getenv ();
|
||||
#define dup sys_dup
|
||||
#undef dup2
|
||||
#define dup2 sys_dup2
|
||||
#define faccessat sys_faccessat
|
||||
#define fopen sys_fopen
|
||||
#define link sys_link
|
||||
#define localtime sys_localtime
|
||||
|
@ -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.
|
||||
|
@ -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) \
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
||||
|
184
src/fileio.c
184
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));
|
||||
|
@ -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;
|
||||
|
92
src/lread.c
92
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 ();
|
||||
}
|
||||
|
@ -4112,8 +4112,6 @@ Needs to be here because ns_initialize_display_info () uses AppKit classes.
|
||||
|
||||
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))
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
18
src/w32.c
18
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
|
||||
|
107
src/xrdb.c
107
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"))))
|
||||
|
||||
/* 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;
|
||||
path = getenv ("XAPPLRESDIR");
|
||||
if (path)
|
||||
{
|
||||
db = search_magic_path (path, class, "/%L/%N");
|
||||
if (!db)
|
||||
db = search_magic_path (path, class, "/%N");
|
||||
}
|
||||
}
|
||||
|
||||
xfree (free_it);
|
||||
return NULL;
|
||||
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. */
|
||||
char *home = gethomedir ();
|
||||
db = search_magic_path (home, class, "%L/%N");
|
||||
if (! db)
|
||||
db = search_magic_path (home, class, "%N");
|
||||
xfree (home);
|
||||
}
|
||||
|
||||
return db;
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user