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 <br...@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. 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 +@include 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}: +@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 index 0000000..f3c0581 --- /dev/null +++ b/doc/windows-stat-inodes.texi @@ -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}. 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; \ } > $@-t && \ mv $@-t $@ 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