bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

windows-stat-inodes: new module


From: Bruno Haible
Subject: windows-stat-inodes: new module
Date: Sun, 14 May 2017 17:59:53 +0200
User-agent: KMail/5.1.3 (Linux/4.4.0-75-generic; KDE/5.18.0; x86_64; ; )

This patch implements the 'windows-stat-inodes' module, that provide good
st_dev and st_ino values on native Windows - at least for most files.

On files where it cannot do so (unreadable files or directories), it sets
both fields to 0. This is not as good as Cygwin does; Cygwin provides
non-zero st_ino in these cases too. I don't know whether this is because
Cygwin uses NtOpenFile and NtQueryInformationFile instead of Windows API,
or because Cygwin uses a hash code of the file name as a fallback.
I could have used a hash code of the file name as well (say, 64 bits
from an SHA-1 hash sum), but this could lead to bugs (e.g. with symbolic
links or hard links). Therefore I find it preferable to just set
st_dev = st_ino = 0 in this case, and let the users of st_ino deal with
it with care.


2017-05-14  Bruno Haible  <address@hidden>

        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.

diff --git a/doc/gnulib.texi b/doc/gnulib.texi
index 5cadf46..3eb7a1d 100644
--- a/doc/gnulib.texi
+++ b/doc/gnulib.texi
@@ -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
 
address@hidden windows-stat-inodes.texi
+
 @include windows-stat-timespec.texi
 
 @include year2038.texi
diff --git a/doc/posix-headers/sys_stat.texi b/doc/posix-headers/sys_stat.texi
index 4c176aa..42a27ba 100644
--- a/doc/posix-headers/sys_stat.texi
+++ b/doc/posix-headers/sys_stat.texi
@@ -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}:
address@hidden
address@hidden
+On Windows platforms (excluding Cygwin), @code{st_ino} is always 0.
address@hidden 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.
address@hidden
 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
index 0000000..f3c0581
--- /dev/null
+++ b/doc/windows-stat-inodes.texi
@@ -0,0 +1,14 @@
address@hidden Inode numbers on Windows
address@hidden Inode numbers on Windows
+
+The module @samp{windows-stat-inodes} ensures that,
+on native Windows platforms, @code{struct stat} contains
address@hidden, @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),
address@hidden 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}.
diff --git a/lib/stat-w32.c b/lib/stat-w32.c
index 515311d..b4c762c 100644
--- a/lib/stat-w32.c
+++ b/lib/stat-w32.c
@@ -20,10 +20,15 @@
 
 #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>
 
@@ -31,7 +36,16 @@
 #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;
diff --git a/lib/stat.c b/lib/stat.c
index 199e216..a73a344 100644
--- a/lib/stat.c
+++ b/lib/stat.c
@@ -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;
diff --git a/lib/sys_types.in.h b/lib/sys_types.in.h
index c5fea83..fd11fdc 100644
--- a/lib/sys_types.in.h
+++ b/lib/sys_types.in.h
@@ -42,6 +42,48 @@
 # 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__) \
diff --git a/m4/sys_types_h.m4 b/m4/sys_types_h.m4
index 2eb4e9e..e590670 100644
--- a/m4/sys_types_h.m4
+++ b/m4/sys_types_h.m4
@@ -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
index 0000000..d3739a3
--- /dev/null
+++ b/m4/windows-stat-inodes.m4
@@ -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
+])
diff --git a/modules/fstat b/modules/fstat
index 076b5f7..7a62c6a 100644
--- a/modules/fstat
+++ b/modules/fstat
@@ -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:
diff --git a/modules/sys_types b/modules/sys_types
index 2e9c427..81a11aa 100644
--- a/modules/sys_types
+++ b/modules/sys_types
@@ -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; \
        } > address@hidden && \
        mv address@hidden $@
diff --git a/modules/windows-stat-inodes b/modules/windows-stat-inodes
new file mode 100644
index 0000000..0607937
--- /dev/null
+++ b/modules/windows-stat-inodes
@@ -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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]