Skip to content

Commit

Permalink
Cygwin: expose all windows volume mount points.
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
jeremyd2019 committed Feb 8, 2025
1 parent e5eb9ee commit 6c8d24a
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 41 deletions.
7 changes: 7 additions & 0 deletions winsup/cygwin/cygtls.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
14 changes: 11 additions & 3 deletions winsup/cygwin/fhandler/process.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1373,7 +1373,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
Expand Down Expand Up @@ -1446,8 +1451,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. */
{
Expand Down
9 changes: 6 additions & 3 deletions winsup/cygwin/local_includes/cygtls.h
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down Expand Up @@ -181,7 +184,7 @@ class _cygtls
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.
Expand Down
1 change: 1 addition & 0 deletions winsup/cygwin/local_includes/mount.h
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,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
Expand Down
168 changes: 133 additions & 35 deletions winsup/cygwin/mount.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1783,14 +1783,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
Expand Down Expand Up @@ -1882,41 +1876,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;
}

__small_sprintf (native_path, "%c:\\", cyg_toupper (drive));
if (GetFileAttributes (native_path) == INVALID_FILE_ATTRIBUTES)
while (!_my_tls.locals.volumemountpoints[_my_tls.locals.volumemountpointoffset])
{
if (!volumename[0] &&
!FindNextVolumeW (_my_tls.locals.volumesearchhandle, volumename,
sizeof (volumename) / sizeof (WCHAR)))
{
_my_tls.locals.available_drives &= ~mask;
continue;
__seterrno ();
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;

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.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;
}

_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 ();
}

Expand Down Expand Up @@ -2081,14 +2167,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;
}

Expand Down Expand Up @@ -2129,6 +2217,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;
}

Expand Down

0 comments on commit 6c8d24a

Please sign in to comment.