From 2f60fa4fb53a269c9b1430e4b3606dd1588e3a31 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Wed, 19 Mar 2025 13:50:47 +0100 Subject: [PATCH] mountlist: Improve implementation on native Windows. * lib/mountlist.c (read_file_system_list) [_WIN32 && !__CYGWIN__]: Also return the mount points inside the file systems. --- ChangeLog | 4 +++ lib/mountlist.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 94 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index c33496dec9..5390fea9be 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2025-03-19 Bruno Haible + mountlist: Improve implementation on native Windows. + * lib/mountlist.c (read_file_system_list) [_WIN32 && !__CYGWIN__]: + Also return the mount points inside the file systems. + mountlist: Improve implementation on native Windows. * lib/mountlist.c (read_file_system_list) [_WIN32 && !__CYGWIN__]: Return the mntroot of drives mapped by SUBST or NET USE. diff --git a/lib/mountlist.c b/lib/mountlist.c index 23ebdf6750..2ed4b138ba 100644 --- a/lib/mountlist.c +++ b/lib/mountlist.c @@ -1195,7 +1195,96 @@ read_file_system_list (bool need_fs_type) } } } - + { + /* Windows also has true mount points, called "mounted folders". See + + For testing: */ + /* Enumerate the volumes. See + + + */ + wchar_t vol_name[MAX_PATH + 1]; + HANDLE h = FindFirstVolumeW (vol_name, sizeof (vol_name) / sizeof (vol_name[0])); + if (h != INVALID_HANDLE_VALUE) + { + do + { + /* Look where the volume vol_name is mounted. + There are two APIs for doing this: + - FindFirstVolumeMountPointW, FindNextVolumeMountPointW, + FindVolumeMountPointClose. This API always fails with + error code ERROR_ACCESS_DENIED. + - GetVolumePathNamesForVolumeNameW. This API works but + may require a significantly larger buffer. + */ + wchar_t stack_buf[MAX_PATH + 2]; + wchar_t *malloced_buf = NULL; + wchar_t *buf = stack_buf; + DWORD bufsize = sizeof (stack_buf) / sizeof (wchar_t); + BOOL success; + for (;;) + { + success = GetVolumePathNamesForVolumeNameW (vol_name, buf, bufsize, &bufsize); + if (!success && GetLastError () == ERROR_MORE_DATA) + { + free (malloced_buf); + malloced_buf = (wchar_t *) xmalloc (bufsize * sizeof (wchar_t)); + buf = malloced_buf; + } + else + break; + } + if (success) + { + wchar_t *mount_dir = buf; + while (*mount_dir != L'\0') + { + /* Drive mounts are already handled above. */ + if (!(mount_dir[0] >= L'A' && mount_dir[0] <= L'Z' + && mount_dir[1] == L':' && mount_dir[2] == L'\\' + && mount_dir[3] == L'\0')) + { + char mountdir[MAX_PATH + 1]; + size_t mountdir_len = wcstombs (mountdir, mount_dir, sizeof (mountdir)); + if (mountdir_len > 0 && mountdir_len <= MAX_PATH) + { + char fs_name[MAX_PATH + 1]; + /* Get the name of the file system. See: + . */ + if (GetVolumeInformation (mountdir, NULL, 0, NULL, NULL, NULL, + fs_name, sizeof fs_name)) + { + me = xmalloc (sizeof *me); + me->me_mountdir = xstrdup (mountdir); + me->me_remote = false; + /* Here we could use vol_name, something like '\\?\Volume{...}'. */ + me->me_devname = NULL; + me->me_mntroot = NULL; + me->me_dev = (dev_t) -1; + me->me_dummy = 0; + me->me_type = xstrdup (fs_name); + me->me_type_malloced = 1; + + /* Add to the linked list. */ + *mtail = me; + mtail = &me->me_next; + } + } + else + { + /* mount_dir is too long or not convertible to the + locale encoding. */ + } + } + mount_dir += wcslen (mount_dir) + 1; + } + } + free (malloced_buf); + } + while (FindNextVolumeW (h, vol_name, sizeof (vol_name) / sizeof (vol_name[0]))); + FindVolumeClose (h); + } + } #endif *mtail = NULL; -- 2.39.5