And with this patch, mount points other than the 26 drives are listed.
For example, I created a separate disk, formatted it as NTFS, mounted
it at S:\, added some files, unmounted it from S:\, and finally
mounted it at C:\Users\bruno\mt_scratch.

The test program now reports:

??? C:\ ??? NFTS local
??? P:\ C:\Users\Public NFTS local
??? T:\ \\larid\tmp NTFS remote
??? C:\Users\bruno\mt_scratch\ ??? NTFS local


2025-03-19  Bruno Haible  <br...@clisp.org>

        mountlist: Improve implementation on native Windows.
        * lib/mountlist.c (read_file_system_list) [_WIN32 && !__CYGWIN__]:
        Also return the mount points inside the file systems.

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
+       
<https://learn.microsoft.com/en-us/windows/win32/fileio/volume-mount-points>
+       For testing: 
<https://learn.microsoft.com/en-us/windows-server/storage/disk-management/assign-a-mount-point-folder-path-to-a-drive>
  */
+    /* Enumerate the volumes.  See
+       
<https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-findfirstvolumew>
+       
<https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-findnextvolumew>
+       
<https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-findvolumeclose>
  */
+    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.
+                   
<https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getvolumepathnamesforvolumenamew>
  */
+            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:
+                               
<https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getvolumeinformationa>.
  */
+                            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;




Reply via email to