They are exposed via the getmntent API and proc filesystem entries dealing with mounts. This allows things like `df` to show volumes that are only mounted on directories, not on drive letters.
Addresses: https://cygwin.com/pipermail/cygwin/2025-February/257251.html Signed-off-by: Jeremy Drake <cyg...@jdrake.com> --- Rather amazingly, this seemed to work as I expected. Kind of gross due to keeping state in the _mytls.locals struct, but it seems to do the job. Does this approach make sense, or is there something I'm missing? winsup/cygwin/cygtls.cc | 7 ++ winsup/cygwin/fhandler/process.cc | 14 ++- winsup/cygwin/local_includes/cygtls.h | 9 +- winsup/cygwin/local_includes/mount.h | 1 + winsup/cygwin/mount.cc | 168 ++++++++++++++++++++------ 5 files changed, 158 insertions(+), 41 deletions(-) diff --git a/winsup/cygwin/cygtls.cc b/winsup/cygwin/cygtls.cc index 1134adc3e2..903ddb12f5 100644 --- a/winsup/cygwin/cygtls.cc +++ b/winsup/cygwin/cygtls.cc @@ -121,6 +121,13 @@ _cygtls::remove (DWORD wait) CloseHandle (h); } + /* Close handle and free memory used by getmntent */ + if (locals.volumesearchhandle) + { + FindVolumeClose (locals.volumesearchhandle); + locals.volumesearchhandle = NULL; + } + free_local (volumemountpoints); /* Close handle and free memory used by select. */ if (locals.select.sockevt) { diff --git a/winsup/cygwin/fhandler/process.cc b/winsup/cygwin/fhandler/process.cc index f779028116..555d1ddca2 100644 --- a/winsup/cygwin/fhandler/process.cc +++ b/winsup/cygwin/fhandler/process.cc @@ -1397,7 +1397,12 @@ format_process_mountstuff (void *data, char *&destbuf, bool mountinfo) /* Store old value of _my_tls.locals here. */ int iteration = _my_tls.locals.iteration; - unsigned available_drives = _my_tls.locals.available_drives; + int volumemountpointoffset = _my_tls.locals.volumemountpointoffset; + HANDLE volumesearchhandle = _my_tls.locals.volumesearchhandle; + WCHAR *volumemountpoints = _my_tls.locals.volumemountpoints; + DWORD volumemountpointslen = _my_tls.locals.volumemountpointslen; + _my_tls.locals.volumesearchhandle = NULL; + _my_tls.locals.volumemountpoints = NULL; /* This reinitializes the above values in _my_tls. */ setmntent (NULL, NULL); /* Restore iteration immediately since it's not used below. We use the @@ -1470,8 +1475,11 @@ format_process_mountstuff (void *data, char *&destbuf, bool mountinfo) } } - /* Restore available_drives */ - _my_tls.locals.available_drives = available_drives; + /* Restore old values of _my_tls.locals here. */ + _my_tls.locals.volumemountpointoffset = volumemountpointoffset; + _my_tls.locals.volumesearchhandle = volumesearchhandle; + _my_tls.locals.volumemountpoints = volumemountpoints; + _my_tls.locals.volumemountpointslen = volumemountpointslen; if (u_hdl) /* Only not-NULL if open_shared has been called. */ { diff --git a/winsup/cygwin/local_includes/cygtls.h b/winsup/cygwin/local_includes/cygtls.h index d814814b19..ba9e980ec1 100644 --- a/winsup/cygwin/local_includes/cygtls.h +++ b/winsup/cygwin/local_includes/cygtls.h @@ -93,10 +93,13 @@ struct _local_storage int dl_error; char dl_buffer[256]; - /* path.cc */ + /* mount.cc */ struct mntent mntbuf; int iteration; - unsigned available_drives; + int volumemountpointoffset; + HANDLE volumesearchhandle; + WCHAR *volumemountpoints; // note: malloced + DWORD volumemountpointslen; char mnt_type[80]; char mnt_opts[80]; char mnt_fsname[CYG_MAX_PATH]; @@ -181,7 +184,7 @@ public: /* Do NOT remove this public: line, it's a marker for gentls_offsets. */ siginfo_t *sigwait_info; HANDLE signal_arrived; bool will_wait_for_signal; -#if 1 +#if 0 long __align; /* Needed to align context to 16 byte. */ #endif /* context MUST be aligned to 16 byte, otherwise RtlCaptureContext fails. diff --git a/winsup/cygwin/local_includes/mount.h b/winsup/cygwin/local_includes/mount.h index b2acdf08b4..7120281069 100644 --- a/winsup/cygwin/local_includes/mount.h +++ b/winsup/cygwin/local_includes/mount.h @@ -216,6 +216,7 @@ class mount_info bool from_fstab (bool user, WCHAR [], PWCHAR); int cygdrive_win32_path (const char *src, char *dst, int& unit); + struct mntent *cygdrive_getmntent (); }; class dos_drive_mappings diff --git a/winsup/cygwin/mount.cc b/winsup/cygwin/mount.cc index bf26c4af3e..3ca0b94e45 100644 --- a/winsup/cygwin/mount.cc +++ b/winsup/cygwin/mount.cc @@ -1645,14 +1645,8 @@ fillout_mntent (const char *native_path, const char *posix_path, unsigned flags) struct mntent& ret=_my_tls.locals.mntbuf; bool append_bs = false; - /* Remove drivenum from list if we see a x: style path */ if (strlen (native_path) == 2 && native_path[1] == ':') - { - int drivenum = cyg_tolower (native_path[0]) - 'a'; - if (drivenum >= 0 && drivenum <= 31) - _my_tls.locals.available_drives &= ~(1 << drivenum); append_bs = true; - } /* Pass back pointers to mount_table strings reserved for use by getmntent rather than pointers to strings in the internal mount @@ -1744,41 +1738,133 @@ mount_item::getmntent () return fillout_mntent (native_path, posix_path, flags); } -static struct mntent * -cygdrive_getmntent () +struct mntent * +mount_info::cygdrive_getmntent () { - char native_path[4]; - char posix_path[CYG_MAX_PATH]; - DWORD mask = 1, drive = 'a'; - struct mntent *ret = NULL; + tmp_pathbuf tp; + char *win32_path, *posix_path; + DWORD endpos; + int err; + WCHAR volumename[64]; + volumename[0] = L'\0'; + if (!_my_tls.locals.volumesearchhandle) + { + _my_tls.locals.volumesearchhandle = FindFirstVolumeW (volumename, + sizeof (volumename) / sizeof (WCHAR)); + if (_my_tls.locals.volumesearchhandle == INVALID_HANDLE_VALUE) + { + __seterrno(); + _my_tls.locals.volumesearchhandle = NULL; + goto cleanup; + } + } - while (_my_tls.locals.available_drives) + if (!_my_tls.locals.volumemountpoints) { - for (/* nothing */; drive <= 'z'; mask <<= 1, drive++) - if (_my_tls.locals.available_drives & mask) - break; + _my_tls.locals.volumemountpoints = (WCHAR *) malloc (NT_MAX_PATH * sizeof (WCHAR)); + _my_tls.locals.volumemountpoints[0] = L'\0'; + _my_tls.locals.volumemountpointoffset = 0; + _my_tls.locals.volumemountpointslen = NT_MAX_PATH; + } + + while (!_my_tls.locals.volumemountpoints[_my_tls.locals.volumemountpointoffset]) + { + if (!volumename[0] && + !FindNextVolumeW (_my_tls.locals.volumesearchhandle, volumename, + sizeof (volumename) / sizeof (WCHAR))) + { + __seterrno (); + goto cleanup; + } - __small_sprintf (native_path, "%c:\\", cyg_toupper (drive)); - if (GetFileAttributes (native_path) == INVALID_FILE_ATTRIBUTES) + WCHAR *volumemountpoints = _my_tls.locals.volumemountpoints; + DWORD volumemountpointslen = _my_tls.locals.volumemountpointslen; + BOOL success; + while (!(success = GetVolumePathNamesForVolumeNameW (volumename, + volumemountpoints, volumemountpointslen, + &volumemountpointslen)) && + GetLastError () == ERROR_MORE_DATA && + (volumemountpoints = (WCHAR *) realloc (volumemountpoints, + volumemountpointslen * sizeof (WCHAR)))) { - _my_tls.locals.available_drives &= ~mask; - continue; + _my_tls.locals.volumemountpoints = volumemountpoints; + _my_tls.locals.volumemountpointslen = volumemountpointslen; + } + + if (!volumemountpoints) + { + set_errno (ENOMEM); + goto cleanup; + } + + if (!success) + { + if (GetLastError () != ERROR_NO_MORE_FILES) + __seterrno (); + else + set_errno (0); + goto cleanup; } - native_path[2] = '\0'; - __small_sprintf (posix_path, "%s%c", mount_table->cygdrive, drive); - ret = fillout_mntent (native_path, posix_path, mount_table->cygdrive_flags); - break; + + _my_tls.locals.volumemountpointoffset = 0; + volumename[0] = L'\0'; } - return ret; + endpos = _my_tls.locals.volumemountpointoffset + + wcslen (_my_tls.locals.volumemountpoints + + _my_tls.locals.volumemountpointoffset); + if (_my_tls.locals.volumemountpoints[endpos - 1] == L'\\') + _my_tls.locals.volumemountpoints[endpos - 1] = L'\0'; + win32_path = tp.c_get (); + sys_wcstombs (win32_path, NT_MAX_PATH, _my_tls.locals.volumemountpoints + + _my_tls.locals.volumemountpointoffset); + _my_tls.locals.volumemountpointoffset = endpos + 1; + + posix_path = tp.c_get (); + if ((err = conv_to_posix_path(win32_path, posix_path, 0))) + { + set_errno (err); + goto cleanup; + } + + return fillout_mntent (win32_path, posix_path, cygdrive_flags); + +cleanup: + save_errno errno_saver; + + if (_my_tls.locals.volumesearchhandle) + { + FindVolumeClose (_my_tls.locals.volumesearchhandle); + _my_tls.locals.volumesearchhandle = NULL; + } + if (_my_tls.locals.volumemountpoints) + { + free (_my_tls.locals.volumemountpoints); + _my_tls.locals.volumemountpoints = NULL; + } + return NULL; } struct mntent * mount_info::getmntent (int x) { if (x < 0 || x >= nmounts) - return cygdrive_getmntent (); - + { + struct mntent *ret; + /* de-duplicate against explicit mount entries */ + while ((ret = cygdrive_getmntent ())) + { + for (int i = 0; i < nmounts; ++i) + { + if (!strcmp (ret->mnt_dir, mount[i].posix_path) && + strcasematch (ret->mnt_fsname, mount[i].native_path)) + goto cygdrive_mntent_continue; + } + break; +cygdrive_mntent_continue:; + } + return ret; + } return mount[native_sorted[x]].getmntent (); } @@ -1943,14 +2029,16 @@ extern "C" FILE * setmntent (const char *filep, const char *) { _my_tls.locals.iteration = 0; - _my_tls.locals.available_drives = GetLogicalDrives (); - /* Filter floppy drives on A: and B: */ - if ((_my_tls.locals.available_drives & 1) - && get_disk_type (L"A:") == DT_FLOPPY) - _my_tls.locals.available_drives &= ~1; - if ((_my_tls.locals.available_drives & 2) - && get_disk_type (L"B:") == DT_FLOPPY) - _my_tls.locals.available_drives &= ~2; + if (_my_tls.locals.volumesearchhandle) + { + FindVolumeClose (_my_tls.locals.volumesearchhandle); + _my_tls.locals.volumesearchhandle = NULL; + } + if (_my_tls.locals.volumemountpoints) + { + free (_my_tls.locals.volumemountpoints); + _my_tls.locals.volumemountpoints = NULL; + } return (FILE *) filep; } @@ -1991,6 +2079,16 @@ getmntent_r (FILE *, struct mntent *mntbuf, char *buf, int buflen) extern "C" int endmntent (FILE *) { + if (_my_tls.locals.volumesearchhandle) + { + FindVolumeClose (_my_tls.locals.volumesearchhandle); + _my_tls.locals.volumesearchhandle = NULL; + } + if (_my_tls.locals.volumemountpoints) + { + free (_my_tls.locals.volumemountpoints); + _my_tls.locals.volumemountpoints = NULL; + } return 1; } -- 2.47.1.windows.2