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> --- winsup/cygwin/cygtls.cc | 6 ++ winsup/cygwin/fhandler/process.cc | 19 ++--- winsup/cygwin/local_includes/cygtls.h | 6 +- winsup/cygwin/local_includes/mount.h | 5 +- winsup/cygwin/mount.cc | 116 ++++++++++++++++++-------- 5 files changed, 100 insertions(+), 52 deletions(-) diff --git a/winsup/cygwin/cygtls.cc b/winsup/cygwin/cygtls.cc index 1134adc3e2..13d133f47c 100644 --- a/winsup/cygwin/cygtls.cc +++ b/winsup/cygwin/cygtls.cc @@ -121,6 +121,12 @@ _cygtls::remove (DWORD wait) CloseHandle (h); } + if (locals.drivemappings) + { + delete locals.drivemappings; + locals.drivemappings = NULL; + } + /* 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..550da2a820 100644 --- a/winsup/cygwin/fhandler/process.cc +++ b/winsup/cygwin/fhandler/process.cc @@ -1395,16 +1395,11 @@ format_process_mountstuff (void *data, char *&destbuf, bool mountinfo) u_shared = user_shared; mount_info *mtab = &u_shared->mountinfo; - /* Store old value of _my_tls.locals here. */ - int iteration = _my_tls.locals.iteration; - unsigned available_drives = _my_tls.locals.available_drives; - /* This reinitializes the above values in _my_tls. */ - setmntent (NULL, NULL); - /* Restore iteration immediately since it's not used below. We use the - local iteration variable instead*/ - _my_tls.locals.iteration = iteration; - - for (iteration = 0; (mnt = mtab->getmntent (iteration)); ++iteration) + /* Store old value of _my_tls.locals.drivemappings here. */ + class dos_drive_mappings *drivemappings = _my_tls.locals.drivemappings; + _my_tls.locals.drivemappings = NULL; + + for (int iteration = 0; (mnt = mtab->getmntent (iteration)); ++iteration) { /* We have no access to the drives mapped into another user session and _my_tls.locals.available_drives contains the mappings of the current @@ -1470,8 +1465,8 @@ format_process_mountstuff (void *data, char *&destbuf, bool mountinfo) } } - /* Restore available_drives */ - _my_tls.locals.available_drives = available_drives; + /* Restore old value of _my_tls.locals.drivemappings here. */ + _my_tls.locals.drivemappings = drivemappings; 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..dfd3198435 100644 --- a/winsup/cygwin/local_includes/cygtls.h +++ b/winsup/cygwin/local_includes/cygtls.h @@ -93,10 +93,10 @@ struct _local_storage int dl_error; char dl_buffer[256]; - /* path.cc */ + /* mount.cc */ struct mntent mntbuf; int iteration; - unsigned available_drives; + class dos_drive_mappings *drivemappings; char mnt_type[80]; char mnt_opts[80]; char mnt_fsname[CYG_MAX_PATH]; @@ -181,7 +181,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 c96b34781e..3049de8ba3 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 @@ -231,11 +232,13 @@ class dos_drive_mappings wchar_t *path; size_t len; } dos; - } *mappings; + } *mappings, *cur_mapping; + mapping::dosmount *cur_dos; public: dos_drive_mappings (); ~dos_drive_mappings (); wchar_t *fixup_if_match (wchar_t *path); + const wchar_t *next_dos_mount (); }; #endif diff --git a/winsup/cygwin/mount.cc b/winsup/cygwin/mount.cc index 4be24fbe84..722dc2aef5 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,74 @@ 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; + const wchar_t *wide_path; + char *win32_path, *posix_path; + int err; - while (_my_tls.locals.available_drives) + if (!_my_tls.locals.drivemappings) + _my_tls.locals.drivemappings = new dos_drive_mappings (); + + wide_path = _my_tls.locals.drivemappings->next_dos_mount (); + if (wide_path) { - for (/* nothing */; drive <= 'z'; mask <<= 1, drive++) - if (_my_tls.locals.available_drives & mask) - break; + win32_path = tp.c_get (); + sys_wcstombs (win32_path, NT_MAX_PATH, wide_path); + posix_path = tp.c_get (); + if ((err = conv_to_posix_path (win32_path, posix_path, 0))) + { + set_errno (err); + return NULL; + } - __small_sprintf (native_path, "%c:\\", cyg_toupper (drive)); - if (GetFileAttributes (native_path) == INVALID_FILE_ATTRIBUTES) + return fillout_mntent (win32_path, posix_path, cygdrive_flags); + } + else + { + if (_my_tls.locals.drivemappings) { - _my_tls.locals.available_drives &= ~mask; - continue; + delete _my_tls.locals.drivemappings; + _my_tls.locals.drivemappings = NULL; } - 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; + return NULL; } - - return ret; } 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 ())) + { + tmp_pathbuf tp; + char *backslash_fsname = NULL; + for (int i = 0; i < nmounts; ++i) + { + if (!strcmp (ret->mnt_dir, mount[i].posix_path)) + { + /* mount_item::native_path has backslashes, but + mntent::mnt_fsname has forward slashes. Lazily + backslashify only if mnt_dir equals posix_path. */ + if (!backslash_fsname) + { + backslash_fsname = tp.c_get (); + backslashify (ret->mnt_fsname, backslash_fsname, false); + } + if (strcasematch (backslash_fsname, mount[i].native_path)) + goto cygdrive_mntent_continue; + } + } + break; +cygdrive_mntent_continue:; + } + return ret; + } return mount[native_sorted[x]].getmntent (); } @@ -1943,14 +1970,11 @@ 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.drivemappings) + { + delete _my_tls.locals.drivemappings; + _my_tls.locals.drivemappings = NULL; + } return (FILE *) filep; } @@ -1996,6 +2020,8 @@ endmntent (FILE *) dos_drive_mappings::dos_drive_mappings () : mappings(0) +, cur_mapping(0) +, cur_dos(0) { tmp_pathbuf tp; wchar_t vol[64]; /* Long enough for Volume GUID string */ @@ -2112,6 +2138,24 @@ dos_drive_mappings::fixup_if_match (wchar_t *path) return path; } +const wchar_t * +dos_drive_mappings::next_dos_mount () +{ + if (cur_dos) + cur_dos = cur_dos->next; + while (!cur_dos) + { + if (cur_mapping) + cur_mapping = cur_mapping->next; + else + cur_mapping = mappings; + if (!cur_mapping) + return NULL; + cur_dos = &cur_mapping->dos; + } + return cur_dos->path; +} + dos_drive_mappings::~dos_drive_mappings () { mapping *n = 0; -- 2.47.1.windows.2