I'm currently testing these two patches, as mingw prerequisites before I can get linkat() working. In particular, mingw is lousy at SAME_INODE, since all three of [fl]stat produce st_ino == 0 for all files (then again, mingw never claimed POSIX compliance!). Code was always taking the identical-file path, even for distinct files.
I'm also preparing a followup patch for coreutils usage of SAME_INODE. Thoughts before I apply this? >From 0719361730021a335bb932bfe4ce2f0524f43649 Mon Sep 17 00:00:00 2001 From: Eric Blake <e...@byu.net> Date: Wed, 23 Sep 2009 14:13:00 -0600 Subject: [PATCH 1/2] lstat: avoid mingw compilation error The openat module required lstat, but then repeated the checks for whether lstat worked. When cross-compiling to mingw, this led to a wrong answer and tried compiling lstat.c, even though it was not necessary, with a result of a compiler warning about undeclared lstat. * m4/lstat.m4 (gl_FUNC_LSTAT): Avoid duplicate calls to AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK, and deal with missing lstat ourselves. * lib/lstat.c [!HAVE_LSTAT]: Do nothing if <sys/stat.h> override was adequate. * m4/sys_stat_h.m4 (gl_HEADER_SYS_STAT_H): Let lstat module handle the checks for lstat. Signed-off-by: Eric Blake <e...@byu.net> --- ChangeLog | 9 +++++++++ lib/lstat.c | 23 ++++++++++++++++------- m4/lstat.m4 | 10 ++++++---- m4/sys_stat_h.m4 | 12 +----------- 4 files changed, 32 insertions(+), 22 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8a4aebf..7ed6953 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,14 @@ 2009-09-23 Eric Blake <e...@byu.net> + lstat: avoid mingw compilation error + * m4/lstat.m4 (gl_FUNC_LSTAT): Avoid duplicate calls to + AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK, and deal with missing + lstat ourselves. + * lib/lstat.c [!HAVE_LSTAT]: Do nothing if <sys/stat.h> override + was adequate. + * m4/sys_stat_h.m4 (gl_HEADER_SYS_STAT_H): Let lstat module handle + the checks for lstat. + link: fix test failure on Solaris 9 * lib/link.c (rpl_link): Don't assume link will catch bogus trailing slash on source. diff --git a/lib/lstat.c b/lib/lstat.c index a05f674..27a0cb5 100644 --- a/lib/lstat.c +++ b/lib/lstat.c @@ -20,11 +20,18 @@ #include <config.h> +#if !HAVE_LSTAT +/* On systems that lack symlinks, our replacement <sys/stat.h> already + defined lstat as stat, so there is nothing further to do other than + avoid an empty file. */ +typedef int dummy; +#else /* HAVE_LSTAT */ + /* Get the original definition of lstat. It might be defined as a macro. */ -#define __need_system_sys_stat_h -#include <sys/types.h> -#include <sys/stat.h> -#undef __need_system_sys_stat_h +# define __need_system_sys_stat_h +# include <sys/types.h> +# include <sys/stat.h> +# undef __need_system_sys_stat_h static inline int orig_lstat (const char *filename, struct stat *buf) @@ -33,10 +40,10 @@ orig_lstat (const char *filename, struct stat *buf) } /* Specification. */ -#include <sys/stat.h> +# include <sys/stat.h> -#include <string.h> -#include <errno.h> +# include <string.h> +# include <errno.h> /* lstat works differently on Linux and Solaris systems. POSIX (see `pathname resolution' in the glossary) requires that programs like @@ -81,3 +88,5 @@ rpl_lstat (const char *file, struct stat *sbuf) } return stat (file, sbuf); } + +#endif /* HAVE_LSTAT */ diff --git a/m4/lstat.m4 b/m4/lstat.m4 index 74c78fe..089d0ff 100644 --- a/m4/lstat.m4 +++ b/m4/lstat.m4 @@ -1,4 +1,4 @@ -# serial 19 +# serial 20 # Copyright (C) 1997-2001, 2003-2009 Free Software Foundation, Inc. # @@ -12,15 +12,17 @@ AC_DEFUN([gl_FUNC_LSTAT], [ AC_REQUIRE([gl_SYS_STAT_H_DEFAULTS]) dnl If lstat does not exist, the replacement <sys/stat.h> does - dnl "#define lstat stat", and lstat.c does not need to be compiled. + dnl "#define lstat stat", and lstat.c is a no-op. AC_CHECK_FUNCS_ONCE([lstat]) if test $ac_cv_func_lstat = yes; then - AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK - dnl Note: AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK does AC_LIBOBJ([lstat]). + AC_REQUIRE([AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK]) if test $ac_cv_func_lstat_dereferences_slashed_symlink = no; then + dnl Note: AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK does AC_LIBOBJ([lstat]). REPLACE_LSTAT=1 fi # Prerequisites of lib/lstat.c. AC_REQUIRE([AC_C_INLINE]) + else + HAVE_LSTAT=0 fi ]) diff --git a/m4/sys_stat_h.m4 b/m4/sys_stat_h.m4 index df7b238..147c517 100644 --- a/m4/sys_stat_h.m4 +++ b/m4/sys_stat_h.m4 @@ -1,4 +1,4 @@ -# sys_stat_h.m4 serial 16 -*- Autoconf -*- +# sys_stat_h.m4 serial 17 -*- Autoconf -*- dnl Copyright (C) 2006-2009 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -11,16 +11,6 @@ AC_DEFUN([gl_HEADER_SYS_STAT_H], [ AC_REQUIRE([gl_SYS_STAT_H_DEFAULTS]) - dnl Check for lstat. Systems that lack it (mingw) also lack symlinks, so - dnl stat is a good replacement. - AC_CHECK_FUNCS_ONCE([lstat]) - if test $ac_cv_func_lstat = yes; then - HAVE_LSTAT=1 - else - HAVE_LSTAT=0 - fi - AC_SUBST([HAVE_LSTAT]) - dnl For the mkdir substitute. AC_REQUIRE([AC_C_INLINE]) --- 1.6.1.2 >From 5538c910e1acd307a3d3e69f6d80044b1f3d935a Mon Sep 17 00:00:00 2001 From: Eric Blake <e...@byu.net> Date: Wed, 23 Sep 2009 14:51:29 -0600 Subject: [PATCH 2/2] same-inode: make SAME_INODE tri-state, to port to mingw Mingw has the annoying habit (already documented in doc/posix-functions/*stat) that st_ino is always 0. This means that naive uses of SAME_INODE(a,b) would succeed, even on distinct files. Here's an analysis of all gnulib modules that used the macro before this commit: chdir-safer is safe - SAME_INODE protected by HAVE_READLINK cycle-check - mingw has no dir hard links and no symlinks, so no directory cycles can occur, and we should ignore -1 fts - SAME_INODE protected by FTS_DEBUG hash-triple - using -1 gives more hash collisions, but the results are still correct openat-proc - SAME_INODE protected by stat("/proc/self") same - no dir cycles, so files are only same with identical name link-follow.m4 - configure test already correct on mingw test-canonicalize* - test already passes on mingw test-[l]stat - test already passes on mingw * NEWS: Mention this change. * lib/same-inode.h (same-inode.h): Recognize mingw limitation of st_ino always being 0. * lib/cycle-check.h (CYCLE_CHECK_REFLECT_CHDIR_UP): Update caller. * lib/cycle-check.c (cycle_check): Likewise. * lib/same.c (same_name): Likewise. Signed-off-by: Eric Blake <e...@byu.net> --- ChangeLog | 8 ++++++++ NEWS | 3 +++ lib/cycle-check.c | 5 +++-- lib/cycle-check.h | 4 ++-- lib/same-inode.h | 16 +++++++++++++--- lib/same.c | 7 +++++-- 6 files changed, 34 insertions(+), 9 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7ed6953..a729fdf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,13 @@ 2009-09-23 Eric Blake <e...@byu.net> + same-inode: make SAME_INODE tri-state, to port to mingw + * NEWS: Mention this change. + * lib/same-inode.h (same-inode.h): Recognize mingw limitation of + st_ino always being 0. + * lib/cycle-check.h (CYCLE_CHECK_REFLECT_CHDIR_UP): Update caller. + * lib/cycle-check.c (cycle_check): Likewise. + * lib/same.c (same_name): Likewise. + lstat: avoid mingw compilation error * m4/lstat.m4 (gl_FUNC_LSTAT): Avoid duplicate calls to AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK, and deal with missing diff --git a/NEWS b/NEWS index 62c631f..87fc884 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,9 @@ User visible incompatible changes Date Modules Changes +2009-09-23 same-inode The macro SAME_INODE is now tri-state, adding -1 + for unknown. + 2009-09-16 canonicalize-lgpl The include file is changed from "canonicalize.h" to <stdlib.h>. diff --git a/lib/cycle-check.c b/lib/cycle-check.c index e120460..a5b6df1 100644 --- a/lib/cycle-check.c +++ b/lib/cycle-check.c @@ -1,6 +1,7 @@ /* help detect directory cycles efficiently - Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + Copyright (C) 2003, 2004, 2005, 2006, 2009 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 @@ -62,7 +63,7 @@ cycle_check (struct cycle_check_state *state, struct stat const *sb) /* If the current directory ever happens to be the same as the one we last recorded for the cycle detection, then it's obviously part of a cycle. */ - if (state->chdir_counter && SAME_INODE (*sb, state->dev_ino)) + if (state->chdir_counter && SAME_INODE (*sb, state->dev_ino) == 1) return true; /* If the number of `descending' chdir calls is a power of two, diff --git a/lib/cycle-check.h b/lib/cycle-check.h index ee3bf21..ea9b9c4 100644 --- a/lib/cycle-check.h +++ b/lib/cycle-check.h @@ -1,6 +1,6 @@ /* help detect directory cycles efficiently - Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc. + Copyright (C) 2003, 2004, 2006, 2009 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 @@ -41,7 +41,7 @@ bool cycle_check (struct cycle_check_state *state, struct stat const *sb); /* You must call cycle_check at least once before using this macro. */ \ if ((State)->chdir_counter == 0) \ abort (); \ - if (SAME_INODE ((State)->dev_ino, SB_subdir)) \ + if (SAME_INODE ((State)->dev_ino, SB_subdir) == 1) \ { \ (State)->dev_ino.st_dev = (SB_dir).st_dev; \ (State)->dev_ino.st_ino = (SB_dir).st_ino; \ diff --git a/lib/same-inode.h b/lib/same-inode.h index 0632711..4b89dd1 100644 --- a/lib/same-inode.h +++ b/lib/same-inode.h @@ -1,6 +1,6 @@ /* Determine whether two stat buffers refer to the same file. - Copyright (C) 2006 Free Software Foundation, Inc. + Copyright (C) 2006, 2009 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 @@ -18,8 +18,18 @@ #ifndef SAME_INODE_H # define SAME_INODE_H 1 +/* Perform a tri-state query on whether STAT_BUF_1 and STAT_BUF_2 + represent the same file. Return 1 for equal, 0 for distinct, and + -1 for indeterminate (the latter is generally possible only on + mingw). Algorithms that use this macro must be prepared to handle + the indeterminate case without wrong results. For example, if an + optimization is possible if two files are the same but unsafe if + distinct, use SAME_INODE()==1; whereas for an optimization that is + possible only for distinct files, use !SAME_INODE(). */ + # define SAME_INODE(Stat_buf_1, Stat_buf_2) \ - ((Stat_buf_1).st_ino == (Stat_buf_2).st_ino \ - && (Stat_buf_1).st_dev == (Stat_buf_2).st_dev) + (((Stat_buf_1).st_ino == (Stat_buf_2).st_ino \ + && (Stat_buf_1).st_dev == (Stat_buf_2).st_dev) \ + ? 1 - 2 * !(Stat_buf_1).st_ino : 0) #endif diff --git a/lib/same.c b/lib/same.c index af3a95e..5251fb8 100644 --- a/lib/same.c +++ b/lib/same.c @@ -1,7 +1,7 @@ /* Determine whether two file names refer to the same file. - Copyright (C) 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2005, 2006 Free - Software Foundation, Inc. + Copyright (C) 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2005, 2006, + 2009 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 @@ -97,6 +97,9 @@ same_name (const char *source, const char *dest) } same = SAME_INODE (source_dir_stats, dest_dir_stats); + if (same < 0) + same = (identical_basenames + && strcmp (source_basename, dest_basename) == 0); #if ! _POSIX_NO_TRUNC && HAVE_PATHCONF && defined _PC_NAME_MAX if (same && ! identical_basenames) -- 1.6.1.2