>From c5f7c7c69b3b986c49930c1c7ac37c552a3be738 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Sun, 15 Sep 2019 17:41:29 +0200 Subject: [PATCH 2/3] creat: New module. * lib/fcntl.in.h (creat): New declaration. * lib/creat.c: New file, based on lib/open.c. * m4/creat.m4: New file. * m4/open-slash.m4: New file, extracted from m4/open.m4. * m4/open.m4 (gl_FUNC_OPEN): Move trailing-slash test to open-slash.m4. Invoke gl_OPEN_TRAILING_SLASH_BUG. * modules/open (Files): Add m4/open-slash.m4. * m4/fcntl_h.m4 (gl_FCNTL_H_DEFAULTS): Initialize GNULIB_CREAT, REPLACE_CREAT. * modules/fcntl-h (Makefile.am): Substitute GNULIB_CREAT, REPLACE_CREAT. * modules/creat: New file. * tests/test-fcntl-h-c++.cc (creat): Check signature. * doc/posix-functions/creat.texi: Mention the new module. --- ChangeLog | 17 +++++++++ doc/posix-functions/creat.texi | 17 ++++++--- lib/creat.c | 78 ++++++++++++++++++++++++++++++++++++++++++ lib/fcntl.in.h | 22 +++++++++++- m4/creat.m4 | 23 +++++++++++++ m4/fcntl_h.m4 | 4 ++- m4/open-slash.m4 | 59 ++++++++++++++++++++++++++++++++ m4/open.m4 | 41 +--------------------- modules/creat | 29 ++++++++++++++++ modules/fcntl-h | 2 ++ modules/open | 1 + tests/test-fcntl-h-c++.cc | 4 +++ 12 files changed, 250 insertions(+), 47 deletions(-) create mode 100644 lib/creat.c create mode 100644 m4/creat.m4 create mode 100644 m4/open-slash.m4 create mode 100644 modules/creat diff --git a/ChangeLog b/ChangeLog index 9f97bb0..f7309fa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,22 @@ 2019-09-15 Bruno Haible + creat: New module. + * lib/fcntl.in.h (creat): New declaration. + * lib/creat.c: New file, based on lib/open.c. + * m4/creat.m4: New file. + * m4/open-slash.m4: New file, extracted from m4/open.m4. + * m4/open.m4 (gl_FUNC_OPEN): Move trailing-slash test to open-slash.m4. + Invoke gl_OPEN_TRAILING_SLASH_BUG. + * modules/open (Files): Add m4/open-slash.m4. + * m4/fcntl_h.m4 (gl_FCNTL_H_DEFAULTS): Initialize GNULIB_CREAT, + REPLACE_CREAT. + * modules/fcntl-h (Makefile.am): Substitute GNULIB_CREAT, REPLACE_CREAT. + * modules/creat: New file. + * tests/test-fcntl-h-c++.cc (creat): Check signature. + * doc/posix-functions/creat.texi: Mention the new module. + +2019-09-15 Bruno Haible + open tests: Enhance test. * tests/test-open.h (test_open): Test the creation of an executable regular file. Also improve initial cleanup. diff --git a/doc/posix-functions/creat.texi b/doc/posix-functions/creat.texi index f144777..f7b86a7 100644 --- a/doc/posix-functions/creat.texi +++ b/doc/posix-functions/creat.texi @@ -4,10 +4,21 @@ POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/functions/creat.html} -Gnulib module: --- +Gnulib module: creat Portability problems fixed by Gnulib: @itemize +@item +This function does not support modes with execution bits (such as 0700) +on some platforms: +MSVC 14. +@item +On platforms where @code{off_t} is a 32-bit type, @code{creat} may not work +correctly with files larger than 2 GB. (Cf. @code{AC_SYS_LARGEFILE}.) +@item +This function does not fail when the file name argument ends in a slash +and (without the slash) names a nonexistent file, on some platforms: +FreeBSD 7.2, AIX 7.1, HP-UX 11.31, Solaris 9. @end itemize Portability problems not fixed by Gnulib: @@ -16,8 +27,4 @@ Portability problems not fixed by Gnulib: On Windows, this function returns a file handle in @code{O_TEXT} mode. If you need a file handle in @code{O_BINARY} mode, you need to use the function @code{open} instead. -@item -On platforms where @code{off_t} is a 32-bit type, @code{creat} may not work -correctly to create files larger than 2 GB. The fix is to use the -@code{AC_SYS_LARGEFILE} macro. @end itemize diff --git a/lib/creat.c b/lib/creat.c new file mode 100644 index 0000000..f66430d --- /dev/null +++ b/lib/creat.c @@ -0,0 +1,78 @@ +/* Create a file. + Copyright (C) 2007-2019 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 . */ + +/* If the user's config.h happens to include , let it include only + the system's here, so that orig_creat doesn't recurse to + rpl_creat. */ +#define __need_system_fcntl_h +#include + +/* Get the original definition of creat. It might be defined as a macro. */ +#include +#include +#undef __need_system_fcntl_h + +static int +orig_creat (const char *filename, mode_t mode) +{ + return creat (filename, mode); +} + +/* Specification. */ +/* Write "fcntl.h" here, not , otherwise OSF/1 5.1 DTK cc eliminates + this include because of the preliminary #include above. */ +#include "fcntl.h" + +#include +#include +#include + +int +creat (const char *filename, mode_t mode) +{ +#if OPEN_TRAILING_SLASH_BUG + /* If the filename ends in a slash, then fail. + Rationale: POSIX + says that + "A pathname that contains at least one non-slash character and that + ends with one or more trailing slashes shall be resolved as if a + single dot character ( '.' ) were appended to the pathname." + and + "The special filename dot shall refer to the directory specified by + its predecessor." + creat() is defined as being equivalent to open() with flags + O_CREAT | O_TRUNC | O_WRONLY. Therefore: + If the named file already exists as a directory, then creat() must fail + with errno = EISDIR. + If the named file does not exist or does not name a directory, then + creat() must fail since creat() cannot create directories. */ + { + size_t len = strlen (filename); + if (len > 0 && filename[len - 1] == '/') + { + errno = EISDIR; + return -1; + } + } +#endif + +#if defined _WIN32 && !defined __CYGWIN__ + /* Remap the 'x' bits to the 'r' bits. */ + mode = (mode & ~0111) | ((mode & 0111) << 2); +#endif + + return orig_creat (filename, mode); +} diff --git a/lib/fcntl.in.h b/lib/fcntl.in.h index eb70dc6..557e6c1 100644 --- a/lib/fcntl.in.h +++ b/lib/fcntl.in.h @@ -67,7 +67,7 @@ #endif /* Native Windows platforms declare open(), creat() in . */ -#if (@GNULIB_OPEN@ || defined GNULIB_POSIXCHECK) \ +#if (@GNULIB_CREAT@ || @GNULIB_OPEN@ || defined GNULIB_POSIXCHECK) \ && (defined _WIN32 && ! defined __CYGWIN__) # include #endif @@ -82,6 +82,26 @@ /* Declare overridden functions. */ +#if @GNULIB_CREAT@ +# if @REPLACE_CREAT@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef creat +# define creat rpl_creat +# endif +_GL_FUNCDECL_RPL (creat, int, (const char *filename, mode_t mode) + _GL_ARG_NONNULL ((1))); +_GL_CXXALIAS_RPL (creat, int, (const char *filename, mode_t mode)); +# else +_GL_CXXALIAS_SYS (creat, int, (const char *filename, mode_t mode)); +# endif +_GL_CXXALIASWARN (creat); +#elif defined GNULIB_POSIXCHECK +# undef creat +/* Assume creat is always declared. */ +_GL_WARN_ON_USE (creat, "creat is not always POSIX compliant - " + "use gnulib module creat for portability"); +#endif + #if @GNULIB_FCNTL@ # if @REPLACE_FCNTL@ # if !(defined __cplusplus && defined GNULIB_NAMESPACE) diff --git a/m4/creat.m4 b/m4/creat.m4 new file mode 100644 index 0000000..a428a72 --- /dev/null +++ b/m4/creat.m4 @@ -0,0 +1,23 @@ +# creat.m4 serial 1 +dnl Copyright (C) 2019 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_CREAT], +[ + AC_REQUIRE([AC_CANONICAL_HOST]) + case "$host_os" in + mingw*) + REPLACE_CREAT=1 + ;; + *) + gl_OPEN_TRAILING_SLASH_BUG + case "$gl_cv_func_open_slash" in + *no) + REPLACE_CREAT=1 + ;; + esac + ;; + esac +]) diff --git a/m4/fcntl_h.m4 b/m4/fcntl_h.m4 index a86fdae..60dc5e2 100644 --- a/m4/fcntl_h.m4 +++ b/m4/fcntl_h.m4 @@ -1,4 +1,4 @@ -# serial 15 +# serial 16 # Configure fcntl.h. dnl Copyright (C) 2006-2007, 2009-2019 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation @@ -37,6 +37,7 @@ AC_DEFUN([gl_FCNTL_MODULE_INDICATOR], AC_DEFUN([gl_FCNTL_H_DEFAULTS], [ + GNULIB_CREAT=0; AC_SUBST([GNULIB_CREAT]) GNULIB_FCNTL=0; AC_SUBST([GNULIB_FCNTL]) GNULIB_NONBLOCKING=0; AC_SUBST([GNULIB_NONBLOCKING]) GNULIB_OPEN=0; AC_SUBST([GNULIB_OPEN]) @@ -44,6 +45,7 @@ AC_DEFUN([gl_FCNTL_H_DEFAULTS], 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_CREAT=0; AC_SUBST([REPLACE_CREAT]) REPLACE_FCNTL=0; AC_SUBST([REPLACE_FCNTL]) REPLACE_OPEN=0; AC_SUBST([REPLACE_OPEN]) REPLACE_OPENAT=0; AC_SUBST([REPLACE_OPENAT]) diff --git a/m4/open-slash.m4 b/m4/open-slash.m4 new file mode 100644 index 0000000..a8756ae --- /dev/null +++ b/m4/open-slash.m4 @@ -0,0 +1,59 @@ +# open-slash.m4 serial 1 +dnl Copyright (C) 2007-2019 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 Tests whether open() and creat() recognize a trailing slash. +dnl Sets gl_cv_func_open_slash. +AC_DEFUN([gl_OPEN_TRAILING_SLASH_BUG], +[ + AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + dnl open("foo/") should not create a file when the file name has a + dnl trailing slash. FreeBSD only has the problem on symlinks. + AC_CHECK_FUNCS_ONCE([lstat]) + AC_CACHE_CHECK([whether open recognizes a trailing slash], + [gl_cv_func_open_slash], + [# Assume that if we have lstat, we can also check symlinks. + if test $ac_cv_func_lstat = yes; then + touch conftest.tmp + ln -s conftest.tmp conftest.lnk + fi + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ +#include +#if HAVE_UNISTD_H +# include +#endif +int main () +{ + int result = 0; +#if HAVE_LSTAT + if (open ("conftest.lnk/", O_RDONLY) != -1) + result |= 1; +#endif + if (open ("conftest.sl/", O_CREAT, 0600) >= 0) + result |= 2; + return result; +}]])], + [gl_cv_func_open_slash=yes], + [gl_cv_func_open_slash=no], + [ +changequote(,)dnl + case "$host_os" in + freebsd* | aix* | hpux* | solaris2.[0-9] | solaris2.[0-9].*) + gl_cv_func_open_slash="guessing no" ;; + *) + gl_cv_func_open_slash="guessing yes" ;; + esac +changequote([,])dnl + ]) + rm -f conftest.sl conftest.tmp conftest.lnk + ]) + case "$gl_cv_func_open_slash" in + *no) + AC_DEFINE([OPEN_TRAILING_SLASH_BUG], [1], + [Define to 1 if open() fails to recognize a trailing slash.]) + ;; + esac +]) diff --git a/m4/open.m4 b/m4/open.m4 index 5d73f4d..6cf0beb 100644 --- a/m4/open.m4 +++ b/m4/open.m4 @@ -19,48 +19,9 @@ AC_DEFUN([gl_FUNC_OPEN], if test "$gl_cv_macro_O_CLOEXEC" != yes; then REPLACE_OPEN=1 fi - AC_CACHE_CHECK([whether open recognizes a trailing slash], - [gl_cv_func_open_slash], - [# Assume that if we have lstat, we can also check symlinks. - if test $ac_cv_func_lstat = yes; then - touch conftest.tmp - ln -s conftest.tmp conftest.lnk - fi - AC_RUN_IFELSE( - [AC_LANG_SOURCE([[ -#include -#if HAVE_UNISTD_H -# include -#endif -int main () -{ - int result = 0; -#if HAVE_LSTAT - if (open ("conftest.lnk/", O_RDONLY) != -1) - result |= 1; -#endif - if (open ("conftest.sl/", O_CREAT, 0600) >= 0) - result |= 2; - return result; -}]])], - [gl_cv_func_open_slash=yes], - [gl_cv_func_open_slash=no], - [ -changequote(,)dnl - case "$host_os" in - freebsd* | aix* | hpux* | solaris2.[0-9] | solaris2.[0-9].*) - gl_cv_func_open_slash="guessing no" ;; - *) - gl_cv_func_open_slash="guessing yes" ;; - esac -changequote([,])dnl - ]) - rm -f conftest.sl conftest.tmp conftest.lnk - ]) + gl_OPEN_TRAILING_SLASH_BUG case "$gl_cv_func_open_slash" in *no) - AC_DEFINE([OPEN_TRAILING_SLASH_BUG], [1], - [Define to 1 if open() fails to recognize a trailing slash.]) REPLACE_OPEN=1 ;; esac diff --git a/modules/creat b/modules/creat new file mode 100644 index 0000000..d95d6ba --- /dev/null +++ b/modules/creat @@ -0,0 +1,29 @@ +Description: +creat() function: create a file. + +Files: +lib/creat.c +m4/creat.m4 +m4/open-slash.m4 + +Depends-on: +fcntl-h +largefile + +configure.ac: +gl_FUNC_CREAT +if test $REPLACE_CREAT = 1; then + AC_LIBOBJ([creat]) +fi +gl_FCNTL_MODULE_INDICATOR([creat]) + +Makefile.am: + +Include: + + +License: +LGPLv2+ + +Maintainer: +all diff --git a/modules/fcntl-h b/modules/fcntl-h index eeac31f..ff74dec 100644 --- a/modules/fcntl-h +++ b/modules/fcntl-h @@ -31,12 +31,14 @@ fcntl.h: fcntl.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) -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_CREAT''@/$(GNULIB_CREAT)/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_CREAT''@|$(REPLACE_CREAT)|g' \ -e 's|@''REPLACE_FCNTL''@|$(REPLACE_FCNTL)|g' \ -e 's|@''REPLACE_OPEN''@|$(REPLACE_OPEN)|g' \ -e 's|@''REPLACE_OPENAT''@|$(REPLACE_OPENAT)|g' \ diff --git a/modules/open b/modules/open index 62c1a05..91debfc 100644 --- a/modules/open +++ b/modules/open @@ -5,6 +5,7 @@ Files: lib/open.c m4/open.m4 m4/open-cloexec.m4 +m4/open-slash.m4 m4/mode_t.m4 Depends-on: diff --git a/tests/test-fcntl-h-c++.cc b/tests/test-fcntl-h-c++.cc index 31a2ad2..16e3c6f 100644 --- a/tests/test-fcntl-h-c++.cc +++ b/tests/test-fcntl-h-c++.cc @@ -24,6 +24,10 @@ #include "signature.h" +#if GNULIB_TEST_CREAT +SIGNATURE_CHECK (GNULIB_NAMESPACE::creat, int, (const char *, mode_t)); +#endif + #if GNULIB_TEST_FCNTL SIGNATURE_CHECK (GNULIB_NAMESPACE::fcntl, int, (int, int, ...)); #endif -- 2.7.4