From phil@hercules.centerline.com  Fri Nov 22 19:57:17 2002
Date: Fri, 22 Nov 2002 19:57:15 -0500 (EST)
From: Phil Budne <phil@hercules.centerline.com>
Message-Id: <200211230057.TAA46809@hercules.centerline.com>
To: phil@ultimate.com
Subject: diff

*** tar-1.13.25/src/incremen.c.orig	Wed Aug 29 14:20:19 2001
--- tar-1.13.25/src/incremen.c	Fri Nov 22 19:56:17 2002
***************
*** 1,3 ****
--- 1,10 ----
+ /* should be set by autoconf */
+ #define HAVE_STATVFS 0
+ #define HAVE_LINUX_STATFS 0
+ #define HAVE_BSD_STATFS 1
+ #define HAVE_SUNOS4_STATFS 0
+ #define HAVE_ST_VFSTYPE 0
+ 
  /* GNU dump extensions to tar.
  
     Copyright 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001 Free
***************
*** 97,109 ****
  static Hash_table *directory_table;
  
  #if HAVE_ST_FSTYPE_STRING
!   static char const nfs_string[] = "nfs";
! # define NFS_FILE_STAT(st) (strcmp ((st).st_fstype, nfs_string) == 0)
  #else
! # define ST_DEV_MSB(st) (~ (dev_t) 0 << (sizeof (st).st_dev * CHAR_BIT - 1))
! # define NFS_FILE_STAT(st) (((st).st_dev & ST_DEV_MSB (st)) != 0)
  #endif
  
  /* Calculate the hash of a directory.  */
  static unsigned
  hash_directory (void const *entry, unsigned n_buckets)
--- 104,227 ----
  static Hash_table *directory_table;
  
  #if HAVE_ST_FSTYPE_STRING
!   static const char nfs[] = "nfs";
! # define ISNFS(path,stp) (strcmp ((stp)->st_fstype, nfs) == 0)
! #elif HAVE_ST_VFSTYPE
! /* AIX */
! #include <sys/stat.h>
! #include <sys/vmount.h>
! #ifdef MNT_NFS3
! #  define ISNFS(path,stp) \
! 	((stp)->st_vfstype == MNT_NFS || (stp)->st_vfstype == MNT_NFS3)
  #else
! #  define ISNFS(path,stp) ((stp)->st_vfstype == MNT_NFS)
  #endif
  
+ #elif HAVE_STATVFS
+ /* works on SunOS5, HP-UX 10.20, HP-UX 11.0, IRIX 6.5, AIX 4.3 */
+ 
+ #include <sys/types.h>
+ #include <sys/statvfs.h>
+ #define NEED_CACHE
+ 
+ static int
+ isnfs(char *path, struct stat *stp)
+ {
+   struct statvfs f;
+ 
+   if (statvfs(path, &f) < 0)
+     return 0;
+ 
+   return strcmp(f.f_basetype, "nfs3") == 0 || strcmp(f.f_basetype, "nfs") == 0;
+ }
+ #elif HAVE_BSD_STATFS
+ /* BSD4.4 */
+ #include <sys/param.h>
+ #include <sys/mount.h>
+ #define NEED_CACHE
+ 
+ static int
+ isnfs(char *path, struct stat *stp)
+ {
+   struct statfs f;
+ 
+   if (statfs(path, &f) < 0)
+     return 0;
+   return strcmp(f.f_fstypename, "nfs") == 0;
+ }
+ #elif HAVE_LINUX_STATFS
+ #include <sys/vfs.h>
+ 
+ /* it's in linux/nfs_fs.h, but can't include it?! */
+ #define NFS_SUPER_MAGIC 0x6969
+ #define NEED_CACHE
+ 
+ static int
+ isnfs(char *path, struct stat *stp)
+ {
+   struct statfs f;
+ 
+   if (statfs(path, &f) < 0)
+     return 0;
+ 
+   return f.f_type == NFS_SUPER_MAGIC;
+ }
+ #elif HAVE_SUNOS4_STATFS
+ #include <sys/types.h>
+ #include <sys/vfs.h>
+ #define NEED_CACHE
+ 
+ static int
+ isnfs(path)
+      char *path;
+ {
+   struct statfs f;
+ 
+   if (statfs(path, &f) < 0)
+     return 0;
+ 
+   /* SunOS4 only supports NFSv2 which doesn't return inode info */
+   return f.f_files == -1 && f.f_ffree == -1;
+ }
+ #else
+ /* try ustat call, check for f_tinode == -1??? */
+ 
+ /* fall back to the old and unreliable way.... */
+ # define ST_DEV_MSB(stp) (~ (dev_t) 0 << (sizeof (stp)->st_dev * CHAR_BIT - 1))
+ # define ISNFS(path,stp) (((stp)->st_dev & ST_DEV_MSB (stp)) != 0)
+ /* check minor(dev) == 0xff?? */
+ #endif
+ 
+ #ifdef NEED_CACHE
+ # define ISNFS(path,stp) check_nfs_cache(path,stp)
+ 
+ #define ISNFS_CACHE_LOG2 0	/* log2 of number of cache entries */
+ #define ISNFS_CACHE_ENTRIES (1<<(ISNFS_CACHE_LOG2)) /* must be power of 2 */
+ #define ISNFS_CACHE_MASK (ISNFS_CACHE_ENTRIES-1)
+ 
+ struct isnfs_cache_line {
+     dev_t dev;
+     char flags;
+ } isnfs_cache[ISNFS_CACHE_ENTRIES];
+ 
+ #define NC_VALID 01
+ #define NC_ISNFS 02
+ 
+ static int
+ check_nfs_cache(char *path, struct stat *stp)
+ {
+   struct isnfs_cache_line *cp = isnfs_cache + (stp->st_dev & ISNFS_CACHE_MASK);
+   if (!(cp->flags & NC_VALID) || cp->dev != stp->st_dev) {
+     /* here with mismatched cache entry, or invalid cache entry */
+     cp->dev = stp->st_dev;
+     cp->flags = NC_VALID;
+     if (isnfs(path, stp))
+       cp->flags |= NC_ISNFS;
+   }
+   return (cp->flags & NC_ISNFS) != 0;
+ }
+ #endif /* NEED_CACHE */
+ 
  /* Calculate the hash of a directory.  */
  static unsigned
  hash_directory (void const *entry, unsigned n_buckets)
***************
*** 233,239 ****
  
  	      if (S_ISDIR (stat_data.st_mode))
  		{
! 		  bool nfs = NFS_FILE_STAT (stat_data);
  
  		  if (directory = find_directory (name_buffer), directory)
  		    {
--- 351,357 ----
  
  	      if (S_ISDIR (stat_data.st_mode))
  		{
! 		  bool nfs = ISNFS (name_buffer, &stat_data);
  
  		  if (directory = find_directory (name_buffer), directory)
  		    {
***************
*** 244,250 ****
  			 directories, consider all NFS devices as equal,
  			 relying on the i-node to establish differences.  */
  
! 		      if (! (((directory->nfs & nfs)
  			      || directory->device_number == stat_data.st_dev)
  			     && directory->inode_number == stat_data.st_ino))
  			{
--- 362,368 ----
  			 directories, consider all NFS devices as equal,
  			 relying on the i-node to establish differences.  */
  
! 		      if (! (((directory->nfs && nfs)
  			      || directory->device_number == stat_data.st_dev)
  			     && directory->inode_number == stat_data.st_ino))
  			{