X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=lib%2Ffstatat.c;fp=lib%2Ffstatat.c;h=ebbecfd14abdf1e2785f85d729fecb8f5ce025e2;hb=20fcfc81ece044b8b0a6768ec6cf47be4e22a2e6;hp=0000000000000000000000000000000000000000;hpb=d57728a6ca2413a7c564d8b7bb13d9e5a5a180f3;p=debian%2Fgzip diff --git a/lib/fstatat.c b/lib/fstatat.c new file mode 100644 index 0000000..ebbecfd --- /dev/null +++ b/lib/fstatat.c @@ -0,0 +1,135 @@ +/* Work around an fstatat bug on Solaris 9. + + Copyright (C) 2006, 2009-2016 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 . */ + +/* Written by Paul Eggert and Jim Meyering. */ + +/* If the user's config.h happens to include , let it include only + the system's here, so that orig_fstatat doesn't recurse to + rpl_fstatat. */ +#define __need_system_sys_stat_h +#include + +/* Get the original definition of fstatat. It might be defined as a macro. */ +#include +#include +#undef __need_system_sys_stat_h + +#if HAVE_FSTATAT +static int +orig_fstatat (int fd, char const *filename, struct stat *buf, int flags) +{ + return fstatat (fd, filename, buf, flags); +} +#endif + +/* Write "sys/stat.h" here, not , otherwise OSF/1 5.1 DTK cc + eliminates this include because of the preliminary #include + above. */ +#include "sys/stat.h" + +#include +#include +#include + +#if HAVE_FSTATAT && HAVE_WORKING_FSTATAT_ZERO_FLAG + +# ifndef LSTAT_FOLLOWS_SLASHED_SYMLINK +# define LSTAT_FOLLOWS_SLASHED_SYMLINK 0 +# endif + +/* fstatat should always follow symbolic links that end in /, but on + Solaris 9 it doesn't if AT_SYMLINK_NOFOLLOW is specified. + Likewise, trailing slash on a non-directory should be an error. + These are the same problems that lstat.c and stat.c address, so + solve it in a similar way. + + AIX 7.1 fstatat (AT_FDCWD, ..., 0) always fails, which is a bug. + Work around this bug if FSTATAT_AT_FDCWD_0_BROKEN is nonzero. */ + +int +rpl_fstatat (int fd, char const *file, struct stat *st, int flag) +{ + int result = orig_fstatat (fd, file, st, flag); + size_t len; + + if (LSTAT_FOLLOWS_SLASHED_SYMLINK || result != 0) + return result; + len = strlen (file); + if (flag & AT_SYMLINK_NOFOLLOW) + { + /* Fix lstat behavior. */ + if (file[len - 1] != '/' || S_ISDIR (st->st_mode)) + return 0; + if (!S_ISLNK (st->st_mode)) + { + errno = ENOTDIR; + return -1; + } + result = orig_fstatat (fd, file, st, flag & ~AT_SYMLINK_NOFOLLOW); + } + /* Fix stat behavior. */ + if (result == 0 && !S_ISDIR (st->st_mode) && file[len - 1] == '/') + { + errno = ENOTDIR; + return -1; + } + return result; +} + +#else /* ! (HAVE_FSTATAT && HAVE_WORKING_FSTATAT_ZERO_FLAG) */ + +/* On mingw, the gnulib defines 'stat' as a function-like + macro; but using it in AT_FUNC_F2 causes compilation failure + because the preprocessor sees a use of a macro that requires two + arguments but is only given one. Hence, we need an inline + forwarder to get past the preprocessor. */ +static int +stat_func (char const *name, struct stat *st) +{ + return stat (name, st); +} + +/* Likewise, if there is no native 'lstat', then the gnulib + defined it as stat, which also needs adjustment. */ +# if !HAVE_LSTAT +# undef lstat +# define lstat stat_func +# endif + +/* Replacement for Solaris' function by the same name. + + First, try to simulate it via l?stat ("/proc/self/fd/FD/FILE"). + Failing that, simulate it via save_cwd/fchdir/(stat|lstat)/restore_cwd. + If either the save_cwd or the restore_cwd fails (relatively unlikely), + then give a diagnostic and exit nonzero. + Otherwise, this function works just like Solaris' fstatat. */ + +# define AT_FUNC_NAME fstatat +# define AT_FUNC_F1 lstat +# define AT_FUNC_F2 stat_func +# define AT_FUNC_USE_F1_COND AT_SYMLINK_NOFOLLOW +# define AT_FUNC_POST_FILE_PARAM_DECLS , struct stat *st, int flag +# define AT_FUNC_POST_FILE_ARGS , st +# include "at-func.c" +# undef AT_FUNC_NAME +# undef AT_FUNC_F1 +# undef AT_FUNC_F2 +# undef AT_FUNC_USE_F1_COND +# undef AT_FUNC_POST_FILE_PARAM_DECLS +# undef AT_FUNC_POST_FILE_ARGS + +#endif /* !HAVE_FSTATAT */