]> Savannah Git Hosting - gnulib.git/commitdiff
windows-stat-inodes: New module.
authorBruno Haible <bruno@clisp.org>
Sun, 14 May 2017 12:20:01 +0000 (14:20 +0200)
committerBruno Haible <bruno@clisp.org>
Sun, 14 May 2017 15:38:24 +0000 (17:38 +0200)
* m4/windows-stat-inodes.m4: New file.
* m4/sys_types_h.m4 (gl_SYS_TYPES_H): Set WINDOWS_STAT_INODES.
* modules/sys_types (Makefile.am): Substitute WINDOWS_STAT_INODES.
* lib/sys_types.in.h [WINDOWS_STAT_INODES]: Override dev_t and ino_t.
(_GL_WINDOWS_STAT_INODES): New macro.
* lib/stat-w32.c: Set _WIN32_WINNT. Include <string.h>, verify.h.
(GetFileInformationByHandleExFunc): New variable.
(initialize): Initialize it.
(_gl_fstat_by_handle) [_GL_WINDOWS_STAT_INODES]: Initialize st_dev and
st_ino appropriately.
* lib/stat.c (rpl_stat): Use the directory entry based approach only as
a fallback, because it does not provide st_dev and st_ino values.
* modules/fstat (Depends-on): Add 'verify'.
* modules/windows-stat-inodes: New file.
* doc/windows-stat-inodes.texi: New file.
* doc/gnulib.texi: Include it.
* doc/posix-headers/sys_stat.texi: Mention the new module.

12 files changed:
ChangeLog
doc/gnulib.texi
doc/posix-headers/sys_stat.texi
doc/windows-stat-inodes.texi [new file with mode: 0644]
lib/stat-w32.c
lib/stat.c
lib/sys_types.in.h
m4/sys_types_h.m4
m4/windows-stat-inodes.m4 [new file with mode: 0644]
modules/fstat
modules/sys_types
modules/windows-stat-inodes [new file with mode: 0644]

index 3e78f773fc66e2c843a46c9048fde0871ee3fc48..488d25894c1c28ea820ce2cd455f6f8f266344b9 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,24 @@
+2017-05-14  Bruno Haible  <bruno@clisp.org>
+
+       windows-stat-inodes: New module.
+       * m4/windows-stat-inodes.m4: New file.
+       * m4/sys_types_h.m4 (gl_SYS_TYPES_H): Set WINDOWS_STAT_INODES.
+       * modules/sys_types (Makefile.am): Substitute WINDOWS_STAT_INODES.
+       * lib/sys_types.in.h [WINDOWS_STAT_INODES]: Override dev_t and ino_t.
+       (_GL_WINDOWS_STAT_INODES): New macro.
+       * lib/stat-w32.c: Set _WIN32_WINNT. Include <string.h>, verify.h.
+       (GetFileInformationByHandleExFunc): New variable.
+       (initialize): Initialize it.
+       (_gl_fstat_by_handle) [_GL_WINDOWS_STAT_INODES]: Initialize st_dev and
+       st_ino appropriately.
+       * lib/stat.c (rpl_stat): Use the directory entry based approach only as
+       a fallback, because it does not provide st_dev and st_ino values.
+       * modules/fstat (Depends-on): Add 'verify'.
+       * modules/windows-stat-inodes: New file.
+       * doc/windows-stat-inodes.texi: New file.
+       * doc/gnulib.texi: Include it.
+       * doc/posix-headers/sys_stat.texi: Mention the new module.
+
 2017-05-14  Bruno Haible  <bruno@clisp.org>
 
        stat-time tests: Workaround for native Windows.
index 5cadf468eaa5e5596dbe61af2843b0b1933b7e68..3eb7a1db8b648e477d527bb84439133785052f10 100644 (file)
@@ -6324,6 +6324,7 @@ to POSIX that it can be treated like any other Unix-like platform.
 @menu
 * Libtool and Windows::
 * Large File Support::
+* Inode numbers on Windows::
 * Precise file timestamps on Windows::
 * Avoiding the year 2038 problem::
 * Windows sockets::
@@ -6334,6 +6335,8 @@ to POSIX that it can be treated like any other Unix-like platform.
 
 @include largefile.texi
 
+@include windows-stat-inodes.texi
+
 @include windows-stat-timespec.texi
 
 @include year2038.texi
index 4c176aa7cd68cbeb7df8fce7d5e942a9268e1059..42a27ba0d5d275998ad801a503e49c91ed0cfb0e 100644 (file)
@@ -5,7 +5,7 @@ POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/based
 
 Gnulib module: sys_stat
 
-Portability problems fixed by Gnulib:
+Portability problems fixed by Gnulib module @code{sys_stat}:
 @itemize
 @item
 The type @code{mode_t} is not defined on some platforms:
@@ -31,14 +31,18 @@ On some platforms, @code{struct stat} does not include @code{st_atim},
 @samp{stat-time} for accessors to portably get at subsecond resolution.
 @end itemize
 
+Portability problems fixed by Gnulib module @code{sys_stat}, together with module @code{windows-stat-inodes}:
+@itemize
+@item
+On Windows platforms (excluding Cygwin), @code{st_ino} is always 0.
+@end itemize
+
 Portability problems not fixed by Gnulib:
 @itemize
 @item
 The macro @code{S_IFBLK} is missing on some platforms:
 MSVC 9.
 @item
-On Windows platforms (excluding Cygwin), @code{st_ino} is always 0.
-@item
 On OpenVMS, @code{st_ino} is an array of three @code{ino_t} values,
 not a single value.
 @item
diff --git a/doc/windows-stat-inodes.texi b/doc/windows-stat-inodes.texi
new file mode 100644 (file)
index 0000000..f3c0581
--- /dev/null
@@ -0,0 +1,14 @@
+@node Inode numbers on Windows
+@section Inode numbers on Windows
+
+The module @samp{windows-stat-inodes} ensures that,
+on native Windows platforms, @code{struct stat} contains
+@code{st_dev}, @code{st_ino} fields that are able to distinguish
+different inodes.
+
+Note: Such values can only be provided for most files on the
+file system.  For a few files (such as inaccessible files),
+@code{st_dev} and @code{st_ino} are set to 0.  Therefore,
+you should test whether @code{st_dev != 0 && st_ino != 0},
+before going to make inferences based on the file identity
+based on @code{st_dev} and @code{st_ino}.
index 515311d8349ede92291107aab72db6e31631054f..b4c762c3150b6bfa60b1d881be3d47165fdf6b00 100644 (file)
 
 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
 
+/* Ensure that <windows.h> defines FILE_ID_INFO.  */
+#undef _WIN32_WINNT
+#define _WIN32_WINNT _WIN32_WINNT_WIN8
+
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <errno.h>
 #include <limits.h>
+#include <string.h>
 #include <unistd.h>
 #include <windows.h>
 
 #include "stat-w32.h"
 
 #include "pathmax.h"
+#include "verify.h"
 
+#if _GL_WINDOWS_STAT_INODES == 2
+/* GetFileInformationByHandleEx was introduced only in Windows Vista.  */
+typedef DWORD (WINAPI * GetFileInformationByHandleExFuncType) (HANDLE hFile,
+                                                               FILE_INFO_BY_HANDLE_CLASS fiClass,
+                                                               LPVOID lpBuffer,
+                                                               DWORD dwBufferSize);
+static GetFileInformationByHandleExFuncType GetFileInformationByHandleExFunc = NULL;
+#endif
 /* GetFinalPathNameByHandle was introduced only in Windows Vista.  */
 typedef DWORD (WINAPI * GetFinalPathNameByHandleFuncType) (HANDLE hFile,
                                                            LPTSTR lpFilePath,
@@ -46,8 +60,12 @@ initialize (void)
   HMODULE kernel32 = LoadLibrary ("kernel32.dll");
   if (kernel32 != NULL)
     {
+#if _GL_WINDOWS_STAT_INODES == 2
+      GetFileInformationByHandleExFunc =
+        (GetFileInformationByHandleExFuncType) GetProcAddress (kernel32, "GetFileInformationByHandleEx");
+#endif
       GetFinalPathNameByHandleFunc =
-       (GetFinalPathNameByHandleFuncType) GetProcAddress (kernel32, "GetFinalPathNameByHandleA");
+        (GetFinalPathNameByHandleFuncType) GetProcAddress (kernel32, "GetFinalPathNameByHandleA");
     }
   initialized = TRUE;
 }
@@ -137,10 +155,71 @@ _gl_fstat_by_handle (HANDLE h, const char *path, struct stat *buf)
           return -1;
         }
 
+#if _GL_WINDOWS_STAT_INODES
+      /* st_ino can be determined through
+         GetFileInformationByHandle
+         <https://msdn.microsoft.com/en-us/library/aa364952.aspx>
+         <https://msdn.microsoft.com/en-us/library/aa363788.aspx>
+         as 64 bits, or through
+         GetFileInformationByHandleEx with argument FileIdInfo
+         <https://msdn.microsoft.com/en-us/library/aa364953.aspx>
+         <https://msdn.microsoft.com/en-us/library/hh802691.aspx>
+         as 128 bits.
+         The latter requires -D_WIN32_WINNT=_WIN32_WINNT_WIN8 or higher.  */
+      /* Experiments show that GetFileInformationByHandleEx does not provide
+         much more information than GetFileInformationByHandle:
+           * The dwVolumeSerialNumber from GetFileInformationByHandle is equal
+             to the low 32 bits of the 64-bit VolumeSerialNumber from
+             GetFileInformationByHandleEx, and is apparently sufficient for
+             identifying the device.
+           * The nFileIndex from GetFileInformationByHandle is equal to the low
+             64 bits of the 128-bit FileId from GetFileInformationByHandleEx,
+             and the high 64 bits of this 128-bit FileId are zero.
+           * On a FAT file system, GetFileInformationByHandleEx fails with error
+             ERROR_INVALID_PARAMETER, whereas GetFileInformationByHandle
+             succeeds.
+           * On a CIFS/SMB file system, GetFileInformationByHandleEx fails with
+             error ERROR_INVALID_LEVEL, whereas GetFileInformationByHandle
+             succeeds.  */
+# if _GL_WINDOWS_STAT_INODES == 2
+      if (GetFileInformationByHandleExFunc != NULL)
+        {
+          FILE_ID_INFO id;
+          if (GetFileInformationByHandleExFunc (h, FileIdInfo, &id, sizeof (id)))
+            {
+              buf->st_dev = id.VolumeSerialNumber;
+              verify (sizeof (ino_t) == sizeof (id.FileId));
+              memcpy (&buf->st_ino, &id.FileId, sizeof (ino_t));
+              goto ino_done;
+            }
+          else
+            {
+              switch (GetLastError ())
+                {
+                case ERROR_INVALID_PARAMETER: /* older Windows version, or FAT */
+                case ERROR_INVALID_LEVEL: /* CIFS/SMB file system */
+                  goto fallback;
+                default:
+                  goto failed;
+                }
+            }
+        }
+     fallback: ;
+      /* Fallback for older Windows versions.  */
+      buf->st_dev = info.dwVolumeSerialNumber;
+      buf->st_ino._gl_ino[0] = ((ULONGLONG) info.nFileIndexHigh << 32) | (ULONGLONG) info.nFileIndexLow;
+      buf->st_ino._gl_ino[1] = 0;
+     ino_done: ;
+# else /* _GL_WINDOWS_STAT_INODES == 1 */
+      buf->st_dev = info.dwVolumeSerialNumber;
+      buf->st_ino = ((ULONGLONG) info.nFileIndexHigh << 32) | (ULONGLONG) info.nFileIndexLow;
+# endif
+#else
       /* st_ino is not wide enough for identifying a file on a device.
          Without st_ino, st_dev is pointless.  */
       buf->st_dev = 0;
       buf->st_ino = 0;
+#endif
 
       /* st_mode.  */
       unsigned int mode =
@@ -263,7 +342,11 @@ _gl_fstat_by_handle (HANDLE h, const char *path, struct stat *buf)
   else if (type == FILE_TYPE_CHAR || type == FILE_TYPE_PIPE)
     {
       buf->st_dev = 0;
+#if _GL_WINDOWS_STAT_INODES == 2
+      buf->st_ino._gl_ino[0] = buf->st_ino._gl_ino[1] = 0;
+#else
       buf->st_ino = 0;
+#endif
       buf->st_mode = (type == FILE_TYPE_PIPE ? _S_IFIFO : _S_IFCHR);
       buf->st_nlink = 1;
       buf->st_uid = 0;
index 199e216cc5d4bc745b841f1b69d4cd908452d0c0..a73a3445cd34e540766522893e48e545d4b61d05 100644 (file)
@@ -176,134 +176,160 @@ rpl_stat (char const *name, struct stat *buf)
      UNC root directories (e.g. '\\server\share').
      The second approach fails for some system files (e.g. 'C:\pagefile.sys'
      and 'C:\hiberfil.sys'): ERROR_SHARING_VIOLATION.
-     So we use the first approach for nearly all files, and the second one
-     only for root and UNC root directories.  */
+     The second approach gives more information (in particular, correct
+     st_dev, st_ino, st_nlink fields).
+     So we use the second approach and, as a fallback except for root and
+     UNC root directories, also the first approach.  */
   {
     int ret;
-    if (!((rlen == drive_prefix_len + 1 && ISSLASH (rname[drive_prefix_len]))
-          || is_unc_root (rname)))
-      {
-        /* Approach based on the directory entry.  */
-
-        if (strchr (rname, '?') != NULL || strchr (rname, '*') != NULL)
-          {
-            /* Other Windows API functions would fail with error
-               ERROR_INVALID_NAME.  */
-            if (malloca_rname != NULL)
-              freea (malloca_rname);
-            errno = ENOENT;
-            return -1;
-          }
-
-        /* Get the details about the directory entry.  */
-        WIN32_FIND_DATA info;
-        HANDLE h = FindFirstFile (rname, &info);
-        if (h == INVALID_HANDLE_VALUE)
-          goto failed;
-
-        /* Test for error conditions before starting to fill *buf.  */
-        if (sizeof (buf->st_size) <= 4 && info.nFileSizeHigh > 0)
-          {
-            FindClose (h);
-            if (malloca_rname != NULL)
-              freea (malloca_rname);
-            errno = EOVERFLOW;
-            return -1;
-          }
-
-        /* st_ino is not wide enough for identifying a file on a device.
-           Without st_ino, st_dev is pointless.  */
-        buf->st_dev = 0;
-        buf->st_ino = 0;
-
-        /* st_mode.  */
-        unsigned int mode =
-          /* XXX How to handle FILE_ATTRIBUTE_REPARSE_POINT ?  */
-          ((info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? _S_IFDIR | S_IEXEC_UGO : _S_IFREG)
-          | S_IREAD_UGO
-          | ((info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? 0 : S_IWRITE_UGO);
-        if (!(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
-          {
-            /* Determine whether the file is executable by looking at the file
-               name suffix.  */
-            if (info.nFileSizeHigh > 0 || info.nFileSizeLow > 0)
-              {
-                const char *last_dot = NULL;
-                const char *p;
-                for (p = info.cFileName; *p != '\0'; p++)
-                  if (*p == '.')
-                    last_dot = p;
-                if (last_dot != NULL)
-                  {
-                    const char *suffix = last_dot + 1;
-                    if (_stricmp (suffix, "exe") == 0
-                        || _stricmp (suffix, "bat") == 0
-                        || _stricmp (suffix, "cmd") == 0
-                        || _stricmp (suffix, "com") == 0)
-                      mode |= S_IEXEC_UGO;
-                  }
-              }
-          }
-        buf->st_mode = mode;
-
-        /* st_nlink.  Ignore hard links here.  */
-        buf->st_nlink = 1;
-
-        /* There's no easy way to map the Windows SID concept to an integer.  */
-        buf->st_uid = 0;
-        buf->st_gid = 0;
-
-        /* st_rdev is irrelevant for normal files and directories.  */
-        buf->st_rdev = 0;
-
-        /* st_size.  */
-        if (sizeof (buf->st_size) <= 4)
-          /* Range check already done above.  */
-          buf->st_size = info.nFileSizeLow;
-        else
-          buf->st_size = ((long long) info.nFileSizeHigh << 32) | (long long) info.nFileSizeLow;
-
-        /* st_atime, st_mtime, st_ctime.  */
+
+    {
+      /* Approach based on the file.  */
+
+      /* Open a handle to the file.
+         CreateFile
+         <https://msdn.microsoft.com/en-us/library/aa363858.aspx>
+         <https://msdn.microsoft.com/en-us/library/aa363874.aspx>  */
+      HANDLE h =
+        CreateFile (rname,
+                    FILE_READ_ATTRIBUTES,
+                    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                    NULL,
+                    OPEN_EXISTING,
+                    /* FILE_FLAG_POSIX_SEMANTICS (treat file names that differ only
+                       in case as different) makes sense only when applied to *all*
+                       filesystem operations.  */
+                    FILE_FLAG_BACKUP_SEMANTICS /* | FILE_FLAG_POSIX_SEMANTICS */,
+                    NULL);
+      if (h != INVALID_HANDLE_VALUE)
+        {
+          ret = _gl_fstat_by_handle (h, rname, buf);
+          CloseHandle (h);
+          goto done;
+        }
+    }
+
+    /* Test for root and UNC root directories.  */
+    if ((rlen == drive_prefix_len + 1 && ISSLASH (rname[drive_prefix_len]))
+        || is_unc_root (rname))
+      goto failed;
+
+    /* Fallback.  */
+    {
+      /* Approach based on the directory entry.  */
+
+      if (strchr (rname, '?') != NULL || strchr (rname, '*') != NULL)
+        {
+          /* Other Windows API functions would fail with error
+             ERROR_INVALID_NAME.  */
+          if (malloca_rname != NULL)
+            freea (malloca_rname);
+          errno = ENOENT;
+          return -1;
+        }
+
+      /* Get the details about the directory entry.  This can be done through
+         FindFirstFile
+         <https://msdn.microsoft.com/en-us/library/aa364418.aspx>
+         <https://msdn.microsoft.com/en-us/library/aa365740.aspx>
+         or through
+         FindFirstFileEx with argument FindExInfoBasic
+         <https://msdn.microsoft.com/en-us/library/aa364419.aspx>
+         <https://msdn.microsoft.com/en-us/library/aa364415.aspx>
+         <https://msdn.microsoft.com/en-us/library/aa365740.aspx>  */
+      WIN32_FIND_DATA info;
+      HANDLE h = FindFirstFile (rname, &info);
+      if (h == INVALID_HANDLE_VALUE)
+        goto failed;
+
+      /* Test for error conditions before starting to fill *buf.  */
+      if (sizeof (buf->st_size) <= 4 && info.nFileSizeHigh > 0)
+        {
+          FindClose (h);
+          if (malloca_rname != NULL)
+            freea (malloca_rname);
+          errno = EOVERFLOW;
+          return -1;
+        }
+
+# if _GL_WINDOWS_STAT_INODES
+      buf->st_dev = 0;
+#  if _GL_WINDOWS_STAT_INODES == 2
+      buf->st_ino._gl_ino[0] = buf->st_ino._gl_ino[1] = 0;
+#  else /* _GL_WINDOWS_STAT_INODES == 1 */
+      buf->st_ino = 0;
+#  endif
+# else
+      /* st_ino is not wide enough for identifying a file on a device.
+         Without st_ino, st_dev is pointless.  */
+      buf->st_dev = 0;
+      buf->st_ino = 0;
+# endif
+
+      /* st_mode.  */
+      unsigned int mode =
+        /* XXX How to handle FILE_ATTRIBUTE_REPARSE_POINT ?  */
+        ((info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? _S_IFDIR | S_IEXEC_UGO : _S_IFREG)
+        | S_IREAD_UGO
+        | ((info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? 0 : S_IWRITE_UGO);
+      if (!(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
+        {
+          /* Determine whether the file is executable by looking at the file
+             name suffix.  */
+          if (info.nFileSizeHigh > 0 || info.nFileSizeLow > 0)
+            {
+              const char *last_dot = NULL;
+              const char *p;
+              for (p = info.cFileName; *p != '\0'; p++)
+                if (*p == '.')
+                  last_dot = p;
+              if (last_dot != NULL)
+                {
+                  const char *suffix = last_dot + 1;
+                  if (_stricmp (suffix, "exe") == 0
+                      || _stricmp (suffix, "bat") == 0
+                      || _stricmp (suffix, "cmd") == 0
+                      || _stricmp (suffix, "com") == 0)
+                    mode |= S_IEXEC_UGO;
+                }
+            }
+        }
+      buf->st_mode = mode;
+
+      /* st_nlink.  Ignore hard links here.  */
+      buf->st_nlink = 1;
+
+      /* There's no easy way to map the Windows SID concept to an integer.  */
+      buf->st_uid = 0;
+      buf->st_gid = 0;
+
+      /* st_rdev is irrelevant for normal files and directories.  */
+      buf->st_rdev = 0;
+
+      /* st_size.  */
+      if (sizeof (buf->st_size) <= 4)
+        /* Range check already done above.  */
+        buf->st_size = info.nFileSizeLow;
+      else
+        buf->st_size = ((long long) info.nFileSizeHigh << 32) | (long long) info.nFileSizeLow;
+
+      /* st_atime, st_mtime, st_ctime.  */
 # if _GL_WINDOWS_STAT_TIMESPEC
-        buf->st_atim = _gl_convert_FILETIME_to_timespec (&info.ftLastAccessTime);
-        buf->st_mtim = _gl_convert_FILETIME_to_timespec (&info.ftLastWriteTime);
-        buf->st_ctim = _gl_convert_FILETIME_to_timespec (&info.ftCreationTime);
+      buf->st_atim = _gl_convert_FILETIME_to_timespec (&info.ftLastAccessTime);
+      buf->st_mtim = _gl_convert_FILETIME_to_timespec (&info.ftLastWriteTime);
+      buf->st_ctim = _gl_convert_FILETIME_to_timespec (&info.ftCreationTime);
 # else
-        buf->st_atime = _gl_convert_FILETIME_to_POSIX (&info.ftLastAccessTime);
-        buf->st_mtime = _gl_convert_FILETIME_to_POSIX (&info.ftLastWriteTime);
-        buf->st_ctime = _gl_convert_FILETIME_to_POSIX (&info.ftCreationTime);
+      buf->st_atime = _gl_convert_FILETIME_to_POSIX (&info.ftLastAccessTime);
+      buf->st_mtime = _gl_convert_FILETIME_to_POSIX (&info.ftLastWriteTime);
+      buf->st_ctime = _gl_convert_FILETIME_to_POSIX (&info.ftCreationTime);
 # endif
 
-        FindClose (h);
+      FindClose (h);
 
-        ret = 0;
-      }
-    else
-      {
-        /* Approach based on the file.  */
-
-        /* Open a handle to the file.
-           CreateFile
-           <https://msdn.microsoft.com/en-us/library/aa363858.aspx>
-           <https://msdn.microsoft.com/en-us/library/aa363874.aspx>  */
-        HANDLE h =
-          CreateFile (rname,
-                      FILE_READ_ATTRIBUTES,
-                      FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
-                      NULL,
-                      OPEN_EXISTING,
-                      /* FILE_FLAG_POSIX_SEMANTICS (treat file names that differ only
-                         in case as different) makes sense only when applied to *all*
-                         filesystem operations.  */
-                      FILE_FLAG_BACKUP_SEMANTICS /* | FILE_FLAG_POSIX_SEMANTICS */,
-                      NULL);
-        if (h == INVALID_HANDLE_VALUE)
-          goto failed;
-
-        ret = _gl_fstat_by_handle (h, rname, buf);
-        CloseHandle (h);
-      }
+      ret = 0;
+    }
 
+   done:
     if (ret >= 0 && check_dir && !S_ISDIR (buf->st_mode))
       {
         errno = ENOTDIR;
index c5fea83a0165fa9dd4940a8a01dbf651b370cda3..fd11fdc0987de7f8a5de04df2a97e3edd1ee3536 100644 (file)
 # define _GL_WINDOWS_64_BIT_OFF_T 1
 #endif
 
+/* Override dev_t and ino_t if distinguishable inodes support is requested
+   on native Windows.  */
+#if @WINDOWS_STAT_INODES@
+
+# if @WINDOWS_STAT_INODES@ == 2
+/* Experimental, not useful in Windows 10.  */
+
+/* Define dev_t to a 64-bit type.  */
+#  if !defined GNULIB_defined_dev_t
+typedef unsigned long long int rpl_dev_t;
+#   undef dev_t
+#   define dev_t rpl_dev_t
+#   define GNULIB_defined_dev_t 1
+#  endif
+
+/* Define ino_t to a 128-bit type.  */
+#  if !defined GNULIB_defined_ino_t
+/* MSVC does not have a 128-bit integer type.
+   GCC has a 128-bit integer type __int128, but only on 64-bit targets.  */
+typedef struct { unsigned long long int _gl_ino[2]; } rpl_ino_t;
+#   undef ino_t
+#   define ino_t rpl_ino_t
+#   define GNULIB_defined_ino_t 1
+#  endif
+
+# else /* @WINDOWS_STAT_INODES@ == 1 */
+
+/* Define ino_t to a 64-bit type.  */
+#  if !defined GNULIB_defined_ino_t
+typedef unsigned long long int rpl_ino_t;
+#   undef ino_t
+#   define ino_t rpl_ino_t
+#   define GNULIB_defined_ino_t 1
+#  endif
+
+# endif
+
+/* Indicator, for gnulib internal purposes.  */
+# define _GL_WINDOWS_STAT_INODES @WINDOWS_STAT_INODES@
+
+#endif
+
 /* MSVC 9 defines size_t in <stddef.h>, not in <sys/types.h>.  */
 /* But avoid namespace pollution on glibc systems.  */
 #if ((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__) \
index 2eb4e9e44e231c6af4e6ccfc641ab7255e9e8479..e5906709f692aba98206764eb9d41a8b5d98fe0e 100644 (file)
@@ -1,4 +1,4 @@
-# sys_types_h.m4 serial 6
+# sys_types_h.m4 serial 7
 dnl Copyright (C) 2011-2017 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -17,6 +17,14 @@ AC_DEFUN_ONCE([gl_SYS_TYPES_H],
 
   dnl Whether to override the 'off_t' type.
   AC_REQUIRE([gl_TYPE_OFF_T])
+
+  dnl Whether to override the 'dev_t' and 'ino_t' types.
+  m4_ifdef([gl_WINDOWS_STAT_INODES], [
+    AC_REQUIRE([gl_WINDOWS_STAT_INODES])
+  ], [
+    WINDOWS_STAT_INODES=0
+  ])
+  AC_SUBST([WINDOWS_STAT_INODES])
 ])
 
 AC_DEFUN([gl_SYS_TYPES_H_DEFAULTS],
diff --git a/m4/windows-stat-inodes.m4 b/m4/windows-stat-inodes.m4
new file mode 100644 (file)
index 0000000..d3739a3
--- /dev/null
@@ -0,0 +1,19 @@
+# windows-stat-inodes.m4 serial 1
+dnl Copyright (C) 2017 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 Enable inode identification in 'struct stat' on native Windows platforms.
+dnl Set WINDOWS_STAT_INODES to
+dnl - 0 -> keep the default (dev_t = 32-bit, ino_t = 16-bit),
+dnl - 1 -> override types normally (dev_t = 32-bit, ino_t = 64-bit),
+dnl - 2 -> override types in an extended way (dev_t = 64-bit, ino_t = 128-bit).
+AC_DEFUN([gl_WINDOWS_STAT_INODES],
+[
+  AC_REQUIRE([AC_CANONICAL_HOST])
+  case "$host_os" in
+    mingw*) WINDOWS_STAT_INODES=1 ;;
+    *)      WINDOWS_STAT_INODES=0 ;;
+  esac
+])
index 076b5f7dbbfe2965ff0fdf48aeaec6ff28076391..7a62c6a72c5dad381174d00fd73237e5dad32620 100644 (file)
@@ -12,6 +12,7 @@ sys_stat
 largefile
 pathmax         [test $REPLACE_FSTAT = 1]
 unistd          [test $REPLACE_FSTAT = 1]
+verify          [test $REPLACE_FSTAT = 1]
 msvc-nothrow    [test $REPLACE_FSTAT = 1]
 
 configure.ac:
index 2e9c4278674bfc6e688845677aad49352ad35593..81a11aa4f36b138df403f3d9ddac4f35677eeaa0 100644 (file)
@@ -29,6 +29,7 @@ sys/types.h: sys_types.in.h $(top_builddir)/config.status
              -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
              -e 's|@''NEXT_SYS_TYPES_H''@|$(NEXT_SYS_TYPES_H)|g' \
              -e 's|@''WINDOWS_64_BIT_OFF_T''@|$(WINDOWS_64_BIT_OFF_T)|g' \
+             -e 's|@''WINDOWS_STAT_INODES''@|$(WINDOWS_STAT_INODES)|g' \
              < $(srcdir)/sys_types.in.h; \
        } > $@-t && \
        mv $@-t $@
diff --git a/modules/windows-stat-inodes b/modules/windows-stat-inodes
new file mode 100644 (file)
index 0000000..0607937
--- /dev/null
@@ -0,0 +1,27 @@
+Description:
+On native Windows platforms, ensure that 'struct stat' contains values
+in the st_dev, st_ino fields that are able to distinguish different inodes.
+
+Comment:
+This module should not be used as a dependency from a test module,
+otherwise when this module occurs as a tests-related module, it will
+have side effects on the compilation of the main modules in lib/.
+
+Files:
+m4/windows-stat-inodes.m4
+
+Depends-on:
+windows-stat-override
+
+configure.ac:
+AC_REQUIRE([gl_WINDOWS_STAT_INODES])
+
+Makefile.am:
+
+Include:
+
+License:
+LGPLv2+
+
+Maintainer:
+Bruno Haible