mingw: teach dirent about symlinks

Move the `S_IFLNK` detection to `file_attr_to_st_mode()`. Implement `DT_LNK` detection in dirent.c's `readdir()` function. Signed-off-by: Karsten Blees <karsten.blees@gmail.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Karsten Blees committed Jan 9, 2026 at 20:05 UTC 8a4f4131aad8d2b176f83df628ee3a8d6e19ba6c
3 files changed +11 -13
compat/mingw.c
+3 -10
@@ -946,21 +946,14 @@ int mingw_lstat(const char *file_name, struct stat *buf)
946 buf->st_gid = 0;
947 buf->st_uid = 0;
948 buf->st_nlink = 1;
949 - buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
949 + buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes,
950 + findbuf.dwReserved0);
951 buf->st_size = fdata.nFileSizeLow |
952 (((off_t)fdata.nFileSizeHigh)<<32);
953 buf->st_dev = buf->st_rdev = 0; /* not used by Git */
954 filetime_to_timespec(&(fdata.ftLastAccessTime), &(buf->st_atim));
955 filetime_to_timespec(&(fdata.ftLastWriteTime), &(buf->st_mtim));
956 filetime_to_timespec(&(fdata.ftCreationTime), &(buf->st_ctim));
956 - if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
957 - if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
958 - (findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) {
959 - buf->st_mode = S_IFLNK | S_IREAD;
960 - if (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
961 - buf->st_mode |= S_IWRITE;
962 - }
963 - }
957 return 0;
958 }
959 error:
@@ -1003,7 +996,7 @@ static int get_file_info_by_handle(HANDLE hnd, struct stat *buf)
996 buf->st_gid = 0;
997 buf->st_uid = 0;
998 buf->st_nlink = 1;
1006 - buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
999 + buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes, 0);
1000 buf->st_size = fdata.nFileSizeLow |
1001 (((off_t)fdata.nFileSizeHigh)<<32);
1002 buf->st_dev = buf->st_rdev = 0; /* not used by Git */
compat/win32.h
+4 -2
@@ -6,10 +6,12 @@
6 #include <windows.h>
7 #endif
8
9 -static inline int file_attr_to_st_mode (DWORD attr)
9 +static inline int file_attr_to_st_mode (DWORD attr, DWORD tag)
10 {
11 int fMode = S_IREAD;
12 - if (attr & FILE_ATTRIBUTE_DIRECTORY)
12 + if ((attr & FILE_ATTRIBUTE_REPARSE_POINT) && tag == IO_REPARSE_TAG_SYMLINK)
13 + fMode |= S_IFLNK;
14 + else if (attr & FILE_ATTRIBUTE_DIRECTORY)
15 fMode |= S_IFDIR;
16 else
17 fMode |= S_IFREG;
compat/win32/dirent.c
+4 -1
@@ -12,7 +12,10 @@ static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAW *fdata)
12 xwcstoutf(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
13
14 /* Set file type, based on WIN32_FIND_DATA */
15 - if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
15 + if ((fdata->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
16 + && fdata->dwReserved0 == IO_REPARSE_TAG_SYMLINK)
17 + ent->d_type = DT_LNK;
18 + else if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
19 ent->d_type = DT_DIR;
20 else
21 ent->d_type = DT_REG;