diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index f7cc25d6b..7eb216320 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,14 @@ +2009-09-25 Eric Blake + + * syscalls.cc (fchmodat): lchmod is not yet implemented. + (euidaccess): New function. + * path.cc (realpath): Update comment. + (canonicalize_file_name): New function. + * include/cygwin/stdlib.h (canonicalize_file_name): Declare it. + * include/cygwin/version.h (CYGWIN_VERSION_API_MINOR): Bump. + * cygwin.din: Export canonicalize_file_name, eaccess, euidaccess. + * posix.sgml: Mention them. + 2009-09-25 Eric Blake * fhandler.h (fhandler_base::fhaccess): Add parameter. diff --git a/winsup/cygwin/cygwin.din b/winsup/cygwin/cygwin.din index 52cd362c2..bee9cd1c1 100644 --- a/winsup/cygwin/cygwin.din +++ b/winsup/cygwin/cygwin.din @@ -165,6 +165,7 @@ cabsf NOSIGFE _cabsf = cabsf NOSIGFE calloc SIGFE _calloc = calloc SIGFE +canonicalize_file_name SIGFE cbrt NOSIGFE _cbrt = cbrt NOSIGFE cbrtf NOSIGFE @@ -296,6 +297,7 @@ dup SIGFE _dup = dup SIGFE dup2 SIGFE _dup2 = dup2 SIGFE +eaccess = euidaccess SIGFE ecvt SIGFE _ecvt = ecvt SIGFE ecvtbuf SIGFE @@ -341,6 +343,7 @@ _erff = erff NOSIGFE err SIGFE __errno NOSIGFE errx SIGFE +euidaccess SIGFE execl SIGFE _execl = execl SIGFE execle SIGFE diff --git a/winsup/cygwin/include/cygwin/stdlib.h b/winsup/cygwin/include/cygwin/stdlib.h index d16e4bbe8..edf00a073 100644 --- a/winsup/cygwin/include/cygwin/stdlib.h +++ b/winsup/cygwin/include/cygwin/stdlib.h @@ -1,6 +1,6 @@ /* stdlib.h - Copyright 2005, 2006, 2007 Red Hat Inc. + Copyright 2005, 2006, 2007, 2008, 2009 Red Hat Inc. This file is part of Cygwin. @@ -23,6 +23,7 @@ void setprogname (const char *); #ifndef __STRICT_ANSI__ char *realpath (const char *, char *); +char *canonicalize_file_name (const char *); int unsetenv (const char *); char *initstate (unsigned seed, char *state, size_t size); long random (void); diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h index cf0a1168b..bd051031a 100644 --- a/winsup/cygwin/include/cygwin/version.h +++ b/winsup/cygwin/include/cygwin/version.h @@ -366,12 +366,13 @@ details. */ 210: New ctype layout using variable ctype pointer. Export __ctype_ptr__. 211: Export fpurge, mkstemps. 212: Add and export libstdc++ malloc wrappers. + 213: Export canonicalize_file_name, eaccess, euidaccess. */ /* Note that we forgot to bump the api for ualarm, strtoll, strtoull */ #define CYGWIN_VERSION_API_MAJOR 0 -#define CYGWIN_VERSION_API_MINOR 212 +#define CYGWIN_VERSION_API_MINOR 213 /* There is also a compatibity version number associated with the shared memory regions. It is incremented when incompatible diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index 89552d999..e543dd4b7 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -2845,7 +2845,7 @@ cygwin_conv_to_full_posix_path (const char *path, char *posix_path) MAX_PATH); } -/* The realpath function is supported on some UNIX systems. */ +/* The realpath function is required by POSIX:2008. */ extern "C" char * realpath (const char *path, char *resolved) @@ -2876,11 +2876,9 @@ realpath (const char *path, char *resolved) path_conv real_path (tpath, PC_SYM_FOLLOW | PC_POSIX, stat_suffixes); - /* Linux has this funny non-standard extension. If "resolved" is NULL, - realpath mallocs the space by itself and returns it to the application. - The application is responsible for calling free() then. This extension - is backed by POSIX, which allows implementation-defined behaviour if - "resolved" is NULL. That's good enough for us to do the same here. */ + /* POSIX 2008 requires malloc'ing if resolved is NULL, and states + that using non-NULL resolved is asking for portability + problems. */ if (!real_path.error && real_path.exists ()) { @@ -2894,14 +2892,24 @@ realpath (const char *path, char *resolved) return resolved; } - /* FIXME: on error, we are supposed to put the name of the path - component which could not be resolved into RESOLVED. */ + /* FIXME: on error, Linux puts the name of the path + component which could not be resolved into RESOLVED, but POSIX + does not require this. */ if (resolved) resolved[0] = '\0'; set_errno (real_path.error ?: ENOENT); return NULL; } +/* Linux provides this extension. Since the only portable use of + realpath requires a NULL second argument, we might as well have a + one-argument wrapper. */ +extern "C" char * +canonicalize_file_name (const char *path) +{ + return realpath (path, NULL); +} + /* Return non-zero if path is a POSIX path list. This is exported to the world as cygwin_foo by cygwin.din. diff --git a/winsup/cygwin/posix.sgml b/winsup/cygwin/posix.sgml index 1b9d8259e..48dce6c96 100644 --- a/winsup/cygwin/posix.sgml +++ b/winsup/cygwin/posix.sgml @@ -890,6 +890,7 @@ also IEEE Std 1003.1-2008 (POSIX.1-2008). dn_expand dn_skipname drem + eaccess endusershell err errx @@ -1005,6 +1006,7 @@ also IEEE Std 1003.1-2008 (POSIX.1-2008). asnprintf asprintf asprintf_r + canonicalize_file_name dremf envz_add envz_entry @@ -1012,6 +1014,7 @@ also IEEE Std 1003.1-2008 (POSIX.1-2008). envz_merge envz_remove envz_strip + euidaccess exp10 exp10f fcloseall diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index 3eb77fd07..da9cda507 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -1580,6 +1580,29 @@ access (const char *fn, int flags) return res; } +/* Linux provides this extension; it is basically a wrapper around the + POSIX:2008 faccessat (AT_FDCWD, fn, flags, AT_EACCESS). We also + provide eaccess as an alias for this, in cygwin.din. */ +extern "C" int +euidaccess (const char *fn, int flags) +{ + // flags were incorrectly specified + int res = -1; + if (flags & ~(F_OK|R_OK|W_OK|X_OK)) + set_errno (EINVAL); + else + { + fhandler_base *fh = build_fh_name (fn, NULL, PC_SYM_FOLLOW, stat_suffixes); + if (fh) + { + res = fh->fhaccess (flags, true); + delete fh; + } + } + debug_printf ("returning %d", res); + return res; +} + static void rename_append_suffix (path_conv &pc, const char *path, size_t len, const char *suffix) @@ -3878,9 +3901,12 @@ fchmodat (int dirfd, const char *pathname, mode_t mode, int flags) myfault efault; if (efault.faulted (EFAULT)) return -1; - if (flags & ~AT_SYMLINK_NOFOLLOW) + if (flags) { - set_errno (EINVAL); + /* BSD has lchmod, but Linux does not. POSIX says + AT_SYMLINK_NOFOLLOW is allowed to fail on symlinks; but Linux + blindly fails even for non-symlinks. */ + set_errno ((flags & ~AT_SYMLINK_NOFOLLOW) ? EINVAL : EOPNOTSUPP); return -1; } char *path = tp.c_get ();