changeset 12065:fbde8fb7f644

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 <ebb9@byu.net>
author Eric Blake <ebb9@byu.net>
date Wed, 23 Sep 2009 14:51:29 -0600
parents e9a820d62f5a
children 5e590c10bc80
files ChangeLog NEWS lib/cycle-check.c lib/cycle-check.h lib/same-inode.h lib/same.c
diffstat 6 files changed, 34 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
 2009-09-23  Eric Blake  <ebb9@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
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,9 @@
 
 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>.
--- 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 @@
   /* 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,
--- 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 @@
       /* 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;		\
--- 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
--- 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 = 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)