diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 197bf3fe4..586220188 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,19 @@ +2011-12-22 Corinna Vinschen + + * external.cc (cygwin_internal): Implement CW_ALLOC_DRIVE_MAP, + CW_MAP_DRIVE_MAP, CW_FREE_DRIVE_MAP. + * fhandler_process.cc: Include mount.h. + (get_volume_path_names_for_volume_name): Move to mount.cc. + (struct dos_drive_mappings): Ditto. + * mount.cc (get_volume_path_names_for_volume_name): Move here. + (dos_drive_mappings::dos_drive_mappings): Ditto. + (dos_drive_mappings::fixup_if_match): Ditto. + (dos_drive_mappings::~dos_drive_mappings): Ditto. + * mount.h (class dos_drive_mappings): Declare her. + * include/sys/cygwin.h (cygwin_getinfo_types): Add CW_ALLOC_DRIVE_MAP, + CW_MAP_DRIVE_MAP, CW_FREE_DRIVE_MAP. + * include/cygwin/version.h: Bump API minor number. + 2011-12-22 Corinna Vinschen * fhandler_process.cc: Drop unneeded includes. diff --git a/winsup/cygwin/external.cc b/winsup/cygwin/external.cc index 947680420..e6e349395 100644 --- a/winsup/cygwin/external.cc +++ b/winsup/cygwin/external.cc @@ -528,6 +528,31 @@ cygwin_internal (cygwin_getinfo_types t, ...) } break; + case CW_ALLOC_DRIVE_MAP: + { + dos_drive_mappings *ddm = new dos_drive_mappings (); + res = (uintptr_t) ddm; + } + break; + + case CW_MAP_DRIVE_MAP: + { + dos_drive_mappings *ddm = va_arg (arg, dos_drive_mappings *); + wchar_t *pathbuf = va_arg (arg, wchar_t *); + if (ddm && pathbuf) + res = (uintptr_t) ddm->fixup_if_match (pathbuf); + } + break; + + case CW_FREE_DRIVE_MAP: + { + dos_drive_mappings *ddm = va_arg (arg, dos_drive_mappings *); + if (ddm) + delete ddm; + res = 0; + } + break; + default: set_errno (ENOSYS); } diff --git a/winsup/cygwin/fhandler_process.cc b/winsup/cygwin/fhandler_process.cc index 18d1ea90f..12ba292c7 100644 --- a/winsup/cygwin/fhandler_process.cc +++ b/winsup/cygwin/fhandler_process.cc @@ -25,6 +25,7 @@ details. */ #include "ntdll.h" #include "cygtls.h" #include "pwdgrp.h" +#include "mount.h" #include "tls_pbuf.h" #include #include @@ -541,169 +542,6 @@ format_process_winexename (void *data, char *&destbuf) return len + 1; } -static bool -get_volume_path_names_for_volume_name (LPCWSTR vol, LPWSTR mounts) -{ - DWORD len; - if (GetVolumePathNamesForVolumeNameW (vol, mounts, NT_MAX_PATH, &len)) - return true; - - /* Windows 2000 doesn't have GetVolumePathNamesForVolumeNameW. - Just assume that mount points are not longer than MAX_PATH. */ - WCHAR drives[MAX_PATH], dvol[MAX_PATH], mp[MAX_PATH + 3]; - if (!GetLogicalDriveStringsW (MAX_PATH, drives)) - return false; - for (PWCHAR drive = drives; *drive; drive = wcschr (drive, '\0') + 1) - { - if (!GetVolumeNameForVolumeMountPointW (drive, dvol, MAX_PATH)) - continue; - if (!wcscasecmp (vol, dvol)) - mounts = wcpcpy (mounts, drive) + 1; - wcscpy (mp, drive); - HANDLE h = FindFirstVolumeMountPointW (dvol, mp + 3, MAX_PATH); - if (h == INVALID_HANDLE_VALUE) - continue; - do - { - if (GetVolumeNameForVolumeMountPointW (mp, dvol, MAX_PATH)) - if (!wcscasecmp (vol, dvol)) - mounts = wcpcpy (mounts, drive) + 1; - } - while (FindNextVolumeMountPointW (h, mp, MAX_PATH)); - FindVolumeMountPointClose (h); - } - *mounts = L'\0'; - return true; -} - -struct dos_drive_mappings -{ - struct mapping - { - mapping *next; - size_t doslen; - size_t ntlen; - wchar_t *dospath; - wchar_t *ntdevpath; - }; - mapping *mappings; - - dos_drive_mappings () - : mappings(0) - { - tmp_pathbuf tp; - wchar_t vol[64]; /* Long enough for Volume GUID string */ - wchar_t *devpath = tp.w_get (); - wchar_t *mounts = tp.w_get (); - - /* Iterate over all volumes, fetch the first path from the list of - DOS paths the volume is mounted to, or use the GUID volume path - otherwise. */ - HANDLE sh = FindFirstVolumeW (vol, 64); - if (sh == INVALID_HANDLE_VALUE) - debug_printf ("FindFirstVolumeW, %E"); - else - do - { - /* Skip drives which are not mounted. */ - if (!get_volume_path_names_for_volume_name (vol, mounts) - || mounts[0] == L'\0') - continue; - *wcsrchr (vol, L'\\') = L'\0'; - if (QueryDosDeviceW (vol + 4, devpath, NT_MAX_PATH)) - { - /* The DOS drive mapping can be another symbolic link. If so, - the mapping won't work since the section name is the name - after resolving all symlinks. Resolve symlinks here, too. */ - for (int syml_cnt = 0; syml_cnt < SYMLOOP_MAX; ++syml_cnt) - { - UNICODE_STRING upath; - OBJECT_ATTRIBUTES attr; - NTSTATUS status; - HANDLE h; - - RtlInitUnicodeString (&upath, devpath); - InitializeObjectAttributes (&attr, &upath, - OBJ_CASE_INSENSITIVE, NULL, NULL); - status = NtOpenSymbolicLinkObject (&h, SYMBOLIC_LINK_QUERY, - &attr); - if (!NT_SUCCESS (status)) - break; - RtlInitEmptyUnicodeString (&upath, devpath, (NT_MAX_PATH - 1) - * sizeof (WCHAR)); - status = NtQuerySymbolicLinkObject (h, &upath, NULL); - NtClose (h); - if (!NT_SUCCESS (status)) - break; - devpath[upath.Length / sizeof (WCHAR)] = L'\0'; - } - mapping *m = new mapping (); - if (m) - { - m->dospath = wcsdup (mounts); - m->ntdevpath = wcsdup (devpath); - if (!m->dospath || !m->ntdevpath) - { - free (m->dospath); - free (m->ntdevpath); - delete m; - continue; - } - m->doslen = wcslen (m->dospath); - m->dospath[--m->doslen] = L'\0'; /* Drop trailing backslash */ - m->ntlen = wcslen (m->ntdevpath); - m->next = mappings; - mappings = m; - } - } - else - debug_printf ("Unable to determine the native mapping for %ls " - "(error %lu)", vol, GetLastError ()); - } - while (FindNextVolumeW (sh, vol, 64)); - FindVolumeClose (sh); - } - - wchar_t *fixup_if_match (wchar_t *path) - { - /* Check for network drive first. */ - if (!wcsncmp (path, L"\\Device\\Mup\\", 12)) - { - path += 10; - path[0] = L'\\'; - return path; - } - /* Then test local drives. */ - for (mapping *m = mappings; m; m = m->next) - if (!wcsncmp (m->ntdevpath, path, m->ntlen)) - { - wchar_t *tmppath; - - if (m->ntlen > m->doslen) - wcsncpy (path += m->ntlen - m->doslen, m->dospath, m->doslen); - else if ((tmppath = wcsdup (path + m->ntlen)) != NULL) - { - wcpcpy (wcpcpy (path, m->dospath), tmppath); - free (tmppath); - } - break; - } - return path; - } - - ~dos_drive_mappings () - { - mapping *n = 0; - for (mapping *m = mappings; m; m = n) - { - n = m->next; - free (m->dospath); - free (m->ntdevpath); - delete m; - } - } -}; - struct heap_info { struct heap diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h index db9a18b4d..997578ed8 100644 --- a/winsup/cygwin/include/cygwin/version.h +++ b/winsup/cygwin/include/cygwin/version.h @@ -424,12 +424,13 @@ details. */ 253: Export TIOCSCTTY, tcgetsid. 254: Export getgrouplist. 255: Export ptsname_r. + 256: Add CW_ALLOC_DRIVE_MAP, CW_MAP_DRIVE_MAP, CW_FREE_DRIVE_MAP. */ /* Note that we forgot to bump the api for ualarm, strtoll, strtoull */ #define CYGWIN_VERSION_API_MAJOR 0 -#define CYGWIN_VERSION_API_MINOR 255 +#define CYGWIN_VERSION_API_MINOR 256 /* There is also a compatibity version number associated with the shared memory regions. It is incremented when incompatible diff --git a/winsup/cygwin/include/sys/cygwin.h b/winsup/cygwin/include/sys/cygwin.h index 85c452677..97f3e959e 100644 --- a/winsup/cygwin/include/sys/cygwin.h +++ b/winsup/cygwin/include/sys/cygwin.h @@ -137,7 +137,10 @@ typedef enum CW_CVT_MNT_OPTS, CW_LST_MNT_OPTS, CW_STRERROR, - CW_CVT_ENV_TO_WINENV + CW_CVT_ENV_TO_WINENV, + CW_ALLOC_DRIVE_MAP, + CW_MAP_DRIVE_MAP, + CW_FREE_DRIVE_MAP } cygwin_getinfo_types; #define CW_LOCK_PINFO CW_LOCK_PINFO diff --git a/winsup/cygwin/mount.cc b/winsup/cygwin/mount.cc index bfb63f801..1bdd0a2e8 100644 --- a/winsup/cygwin/mount.cc +++ b/winsup/cygwin/mount.cc @@ -1873,3 +1873,154 @@ endmntent (FILE *) { return 1; } + +static bool +get_volume_path_names_for_volume_name (LPCWSTR vol, LPWSTR mounts) +{ + DWORD len; + if (GetVolumePathNamesForVolumeNameW (vol, mounts, NT_MAX_PATH, &len)) + return true; + + /* Windows 2000 doesn't have GetVolumePathNamesForVolumeNameW. + Just assume that mount points are not longer than MAX_PATH. */ + WCHAR drives[MAX_PATH], dvol[MAX_PATH], mp[MAX_PATH + 3]; + if (!GetLogicalDriveStringsW (MAX_PATH, drives)) + return false; + for (PWCHAR drive = drives; *drive; drive = wcschr (drive, '\0') + 1) + { + if (!GetVolumeNameForVolumeMountPointW (drive, dvol, MAX_PATH)) + continue; + if (!wcscasecmp (vol, dvol)) + mounts = wcpcpy (mounts, drive) + 1; + wcscpy (mp, drive); + HANDLE h = FindFirstVolumeMountPointW (dvol, mp + 3, MAX_PATH); + if (h == INVALID_HANDLE_VALUE) + continue; + do + { + if (GetVolumeNameForVolumeMountPointW (mp, dvol, MAX_PATH)) + if (!wcscasecmp (vol, dvol)) + mounts = wcpcpy (mounts, drive) + 1; + } + while (FindNextVolumeMountPointW (h, mp, MAX_PATH)); + FindVolumeMountPointClose (h); + } + *mounts = L'\0'; + return true; +} + +dos_drive_mappings::dos_drive_mappings () +: mappings(0) +{ + tmp_pathbuf tp; + wchar_t vol[64]; /* Long enough for Volume GUID string */ + wchar_t *devpath = tp.w_get (); + wchar_t *mounts = tp.w_get (); + + /* Iterate over all volumes, fetch the first path from the list of + DOS paths the volume is mounted to, or use the GUID volume path + otherwise. */ + HANDLE sh = FindFirstVolumeW (vol, 64); + if (sh == INVALID_HANDLE_VALUE) + debug_printf ("FindFirstVolumeW, %E"); + else + do + { + /* Skip drives which are not mounted. */ + if (!get_volume_path_names_for_volume_name (vol, mounts) + || mounts[0] == L'\0') + continue; + *wcsrchr (vol, L'\\') = L'\0'; + if (QueryDosDeviceW (vol + 4, devpath, NT_MAX_PATH)) + { + /* The DOS drive mapping can be another symbolic link. If so, + the mapping won't work since the section name is the name + after resolving all symlinks. Resolve symlinks here, too. */ + for (int syml_cnt = 0; syml_cnt < SYMLOOP_MAX; ++syml_cnt) + { + UNICODE_STRING upath; + OBJECT_ATTRIBUTES attr; + NTSTATUS status; + HANDLE h; + + RtlInitUnicodeString (&upath, devpath); + InitializeObjectAttributes (&attr, &upath, + OBJ_CASE_INSENSITIVE, NULL, NULL); + status = NtOpenSymbolicLinkObject (&h, SYMBOLIC_LINK_QUERY, + &attr); + if (!NT_SUCCESS (status)) + break; + RtlInitEmptyUnicodeString (&upath, devpath, (NT_MAX_PATH - 1) + * sizeof (WCHAR)); + status = NtQuerySymbolicLinkObject (h, &upath, NULL); + NtClose (h); + if (!NT_SUCCESS (status)) + break; + devpath[upath.Length / sizeof (WCHAR)] = L'\0'; + } + mapping *m = new mapping (); + if (m) + { + m->dospath = wcsdup (mounts); + m->ntdevpath = wcsdup (devpath); + if (!m->dospath || !m->ntdevpath) + { + free (m->dospath); + free (m->ntdevpath); + delete m; + continue; + } + m->doslen = wcslen (m->dospath); + m->dospath[--m->doslen] = L'\0'; /* Drop trailing backslash */ + m->ntlen = wcslen (m->ntdevpath); + m->next = mappings; + mappings = m; + } + } + else + debug_printf ("Unable to determine the native mapping for %ls " + "(error %lu)", vol, GetLastError ()); + } + while (FindNextVolumeW (sh, vol, 64)); + FindVolumeClose (sh); +} + +wchar_t * +dos_drive_mappings::fixup_if_match (wchar_t *path) +{ + /* Check for network drive first. */ + if (!wcsncmp (path, L"\\Device\\Mup\\", 12)) + { + path += 10; + path[0] = L'\\'; + return path; + } + /* Then test local drives. */ + for (mapping *m = mappings; m; m = m->next) + if (!wcsncmp (m->ntdevpath, path, m->ntlen)) + { + wchar_t *tmppath; + + if (m->ntlen > m->doslen) + wcsncpy (path += m->ntlen - m->doslen, m->dospath, m->doslen); + else if ((tmppath = wcsdup (path + m->ntlen)) != NULL) + { + wcpcpy (wcpcpy (path, m->dospath), tmppath); + free (tmppath); + } + break; + } + return path; +} + +dos_drive_mappings::~dos_drive_mappings () +{ + mapping *n = 0; + for (mapping *m = mappings; m; m = n) + { + n = m->next; + free (m->dospath); + free (m->ntdevpath); + delete m; + } +} diff --git a/winsup/cygwin/mount.h b/winsup/cygwin/mount.h index 0f0690a82..606e9f595 100644 --- a/winsup/cygwin/mount.h +++ b/winsup/cygwin/mount.h @@ -197,4 +197,22 @@ class mount_info int cygdrive_win32_path (const char *src, char *dst, int& unit); }; + +class dos_drive_mappings +{ + struct mapping + { + mapping *next; + size_t doslen; + size_t ntlen; + wchar_t *dospath; + wchar_t *ntdevpath; + }; + mapping *mappings; + +public: + dos_drive_mappings (); + ~dos_drive_mappings (); + wchar_t *fixup_if_match (wchar_t *path); +}; #endif