* 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.
This commit is contained in:
		| @@ -1,3 +1,19 @@ | ||||
| 2011-12-22  Corinna Vinschen  <vinschen@redhat.com> | ||||
|  | ||||
| 	* 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  <vinschen@redhat.com> | ||||
|  | ||||
| 	* fhandler_process.cc: Drop unneeded includes. | ||||
|   | ||||
| @@ -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); | ||||
|     } | ||||
|   | ||||
| @@ -25,6 +25,7 @@ details. */ | ||||
| #include "ntdll.h" | ||||
| #include "cygtls.h" | ||||
| #include "pwdgrp.h" | ||||
| #include "mount.h" | ||||
| #include "tls_pbuf.h" | ||||
| #include <sys/param.h> | ||||
| #include <ctype.h> | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user