* path.cc (struct _FAST_CWD): Redefine to new layout used since patch
for KB 2393802. Adjust comments throughout. (struct _FAST_CWD_OLD): Rename former definition. (cwdstuff::override_win32_cwd): Check if the OS is using the old or the new FAST_CWD structure layout and handle accordingly.
This commit is contained in:
		
							parent
							
								
									8447bf9f9f
								
							
						
					
					
						commit
						32d86d2ab2
					
				|  | @ -1,3 +1,11 @@ | ||||||
|  | 2011-02-13  Corinna Vinschen  <corinna@vinschen.de> | ||||||
|  | 
 | ||||||
|  | 	* path.cc (struct _FAST_CWD): Redefine to new layout used since patch | ||||||
|  | 	for KB 2393802.  Adjust comments throughout. | ||||||
|  | 	(struct _FAST_CWD_OLD): Rename former definition. | ||||||
|  | 	(cwdstuff::override_win32_cwd): Check if the OS is using the old or the | ||||||
|  | 	new FAST_CWD structure layout and handle accordingly. | ||||||
|  | 
 | ||||||
| 2011-02-11  Christopher Faylor  <me+cygwin@cgf.cx> | 2011-02-11  Christopher Faylor  <me+cygwin@cgf.cx> | ||||||
| 
 | 
 | ||||||
| 	* mkstatic: Make sure that we are not cd'ed to temporary directory on | 	* mkstatic: Make sure that we are not cd'ed to temporary directory on | ||||||
|  |  | ||||||
|  | @ -3432,6 +3432,20 @@ cygwin_split_path (const char *path, char *dir, char *file) | ||||||
|    minimal locking and it's much more multi-thread friendly.  Presumably |    minimal locking and it's much more multi-thread friendly.  Presumably | ||||||
|    it minimizes contention when accessing the CWD. */ |    it minimizes contention when accessing the CWD. */ | ||||||
| typedef struct _FAST_CWD { | typedef struct _FAST_CWD { | ||||||
|  |   UNICODE_STRING Path;			/* Path's Buffer member always refers
 | ||||||
|  | 					   to the following Buffer array. */ | ||||||
|  |   HANDLE         DirectoryHandle; | ||||||
|  |   LONG           FSCharacteristics;	/* Taken from FileFsDeviceInformation */ | ||||||
|  |   LONG           ReferenceCount;	/* Only release when this is 0. */ | ||||||
|  |   ULONG          OldDismountCount;	/* Reflects the system DismountCount
 | ||||||
|  | 					   at the time the CWD has been set. */ | ||||||
|  |   WCHAR          Buffer[MAX_PATH]; | ||||||
|  | } FAST_CWD, *PFAST_CWD; | ||||||
|  | 
 | ||||||
|  | /* This is the old FAST_CWD structure up to the patch from KB 2393802,
 | ||||||
|  |    release in February 2011.  Hopefully it's not used for long anymore, | ||||||
|  |    but for quite some time we can't rely on this fact. */ | ||||||
|  | typedef struct _FAST_CWD_OLD { | ||||||
|   LONG           ReferenceCount;	/* Only release when this is 0. */ |   LONG           ReferenceCount;	/* Only release when this is 0. */ | ||||||
|   HANDLE         DirectoryHandle; |   HANDLE         DirectoryHandle; | ||||||
|   ULONG          OldDismountCount;	/* Reflects the system DismountCount
 |   ULONG          OldDismountCount;	/* Reflects the system DismountCount
 | ||||||
|  | @ -3439,7 +3453,7 @@ typedef struct _FAST_CWD { | ||||||
|   UNICODE_STRING Path;			/* Path's Buffer member always refers
 |   UNICODE_STRING Path;			/* Path's Buffer member always refers
 | ||||||
| 					   to the following Buffer array. */ | 					   to the following Buffer array. */ | ||||||
|   WCHAR          Buffer[MAX_PATH]; |   WCHAR          Buffer[MAX_PATH]; | ||||||
| } FAST_CWD, *PFAST_CWD; | } FAST_CWD_OLD, *PFAST_CWD_OLD; | ||||||
| 
 | 
 | ||||||
| /* fast_cwd_ptr is a pointer to the global pointer in ntdll.dll pointing
 | /* fast_cwd_ptr is a pointer to the global pointer in ntdll.dll pointing
 | ||||||
|    to the FAST_CWD structure which constitutes the CWD. |    to the FAST_CWD structure which constitutes the CWD. | ||||||
|  | @ -3556,7 +3570,10 @@ cwdstuff::override_win32_cwd (bool init, ULONG old_dismount_count) | ||||||
| 	     fast_cwd_ptr, we can simply replace the RtlSetCurrentDirectory_U | 	     fast_cwd_ptr, we can simply replace the RtlSetCurrentDirectory_U | ||||||
| 	     function entirely, just as on pre-Vista. */ | 	     function entirely, just as on pre-Vista. */ | ||||||
| 	  PVOID heap = peb.ProcessHeap; | 	  PVOID heap = peb.ProcessHeap; | ||||||
| 	  /* First allocate a new FAST_CWD strcuture on the heap. */ | 	  /* First allocate a new FAST_CWD structure on the heap.
 | ||||||
|  | 	     The new FAST_CWD structure is 4 byte bigger than the old one, | ||||||
|  | 	     but we simply don't care, so we allocate always room for the | ||||||
|  | 	     new one. */ | ||||||
| 	  PFAST_CWD f_cwd = (PFAST_CWD) | 	  PFAST_CWD f_cwd = (PFAST_CWD) | ||||||
| 			    RtlAllocateHeap (heap, 0, sizeof (FAST_CWD)); | 			    RtlAllocateHeap (heap, 0, sizeof (FAST_CWD)); | ||||||
| 	  if (!f_cwd) | 	  if (!f_cwd) | ||||||
|  | @ -3564,35 +3581,82 @@ cwdstuff::override_win32_cwd (bool init, ULONG old_dismount_count) | ||||||
| 	      debug_printf ("RtlAllocateHeap failed"); | 	      debug_printf ("RtlAllocateHeap failed"); | ||||||
| 	      return; | 	      return; | ||||||
| 	    } | 	    } | ||||||
| 	  /* Fill in the values. */ | 	  /* Fill in the values.  Fortunately it's simple to check for the
 | ||||||
| 	  f_cwd->ReferenceCount = 1; | 	     new structure.  Path.MaximumLength takes the same space as the | ||||||
| 	  f_cwd->DirectoryHandle = dir; | 	     high word of the old ReferenceCount.  We know that MaximumLength | ||||||
| 	  f_cwd->OldDismountCount = old_dismount_count; | 	     is always MAX_PATH.  For the ref count this would account for a | ||||||
| 	  RtlInitEmptyUnicodeString (&f_cwd->Path, f_cwd->Buffer, | 	     pratically impossible value between 34078720 and 34079240. */ | ||||||
| 				     MAX_PATH * sizeof (WCHAR)); | 	  if ((*fast_cwd_ptr)->Path.MaximumLength == MAX_PATH * sizeof (WCHAR)) | ||||||
| 	  copy_cwd_str (&f_cwd->Path, error ? &ro_u_pipedir : &win32); |  | ||||||
| 	  /* Use PEB lock when switching fast_cwd_ptr to the new FAST_CWD
 |  | ||||||
| 	     structure and writing the CWD to the user process parameter |  | ||||||
| 	     block.  This is equivalent to calling RtlAcquirePebLock/ |  | ||||||
| 	     RtlReleasePebLock, but without having to go through the FS |  | ||||||
| 	     selector again. */ |  | ||||||
| 	  RtlEnterCriticalSection (peb.FastPebLock); |  | ||||||
| 	  PFAST_CWD old_cwd = *fast_cwd_ptr; |  | ||||||
| 	  *fast_cwd_ptr = f_cwd; |  | ||||||
| 	  upp_cwd_str = f_cwd->Path; |  | ||||||
| 	  upp_cwd_hdl = dir; |  | ||||||
| 	  RtlLeaveCriticalSection (peb.FastPebLock); |  | ||||||
| 	  /* Decrement the reference count.  If it's down to 0, free structure
 |  | ||||||
| 	     from heap. */ |  | ||||||
| 	  if (old_cwd && InterlockedDecrement (&old_cwd->ReferenceCount) == 0) |  | ||||||
| 	    { | 	    { | ||||||
| 	      /* In contrast to pre-Vista, the handle on init is always a fresh
 | 	      /* New FAST_CWD structure. */ | ||||||
| 		 one and not the handle inherited from the parent process.  So | 	      IO_STATUS_BLOCK io; | ||||||
| 		 we always have to close it here.  However, the handle could | 	      FILE_FS_DEVICE_INFORMATION ffdi; | ||||||
| 		 be NULL, if we cd'ed into a virtual dir. */ | 
 | ||||||
| 	      if (old_cwd->DirectoryHandle) | 	      RtlInitEmptyUnicodeString (&f_cwd->Path, f_cwd->Buffer, | ||||||
| 		NtClose (old_cwd->DirectoryHandle); | 					 MAX_PATH * sizeof (WCHAR)); | ||||||
| 	      RtlFreeHeap (heap, 0, old_cwd); | 	      f_cwd->DirectoryHandle = dir; | ||||||
|  | 	      /* The new structure stores the device characteristics of the
 | ||||||
|  | 		 volume holding the dir.  RtlGetCurrentDirectory_U checks | ||||||
|  | 		 if the FILE_REMOVABLE_MEDIA flag is set and, if so, checks if | ||||||
|  | 		 the volume is still the same as the one used when opening | ||||||
|  | 		 the directory handle. | ||||||
|  | 		 We don't call NtQueryVolumeInformationFile for the \\?\PIPE, | ||||||
|  | 		 though.  It just returns STATUS_INVALID_HANDLE anyway. */ | ||||||
|  | 	      f_cwd->FSCharacteristics =  | ||||||
|  | 		(!error | ||||||
|  | 		 && NT_SUCCESS (NtQueryVolumeInformationFile (dir, &io, &ffdi, | ||||||
|  | 				       sizeof ffdi, FileFsDeviceInformation))) | ||||||
|  | 		? ffdi.Characteristics : 0; | ||||||
|  | 	      f_cwd->ReferenceCount = 1; | ||||||
|  | 	      f_cwd->OldDismountCount = old_dismount_count; | ||||||
|  | 	      copy_cwd_str (&f_cwd->Path, error ? &ro_u_pipedir : &win32); | ||||||
|  | 	      /* Use PEB lock when switching fast_cwd_ptr to the new FAST_CWD
 | ||||||
|  | 		 structure and writing the CWD to the user process parameter | ||||||
|  | 		 block.  This is equivalent to calling RtlAcquirePebLock/ | ||||||
|  | 		 RtlReleasePebLock, but without having to go through the FS | ||||||
|  | 		 selector again. */ | ||||||
|  | 	      RtlEnterCriticalSection (peb.FastPebLock); | ||||||
|  | 	      PFAST_CWD old_cwd = *fast_cwd_ptr; | ||||||
|  | 	      *fast_cwd_ptr = f_cwd; | ||||||
|  | 	      upp_cwd_str = f_cwd->Path; | ||||||
|  | 	      upp_cwd_hdl = dir; | ||||||
|  | 	      RtlLeaveCriticalSection (peb.FastPebLock); | ||||||
|  | 	      /* Decrement the reference count.  If it's down to 0, free
 | ||||||
|  | 		 structure from heap. */ | ||||||
|  | 	      if (InterlockedDecrement (&old_cwd->ReferenceCount) == 0) | ||||||
|  | 		{ | ||||||
|  | 		  /* In contrast to pre-Vista, the handle on init is always a
 | ||||||
|  | 		     fresh one and not the handle inherited from the parent | ||||||
|  | 		     process.  So we always have to close it here.  However, the | ||||||
|  | 		     handle could be NULL, if we cd'ed into a virtual dir. */ | ||||||
|  | 		  if (old_cwd->DirectoryHandle) | ||||||
|  | 		    NtClose (old_cwd->DirectoryHandle); | ||||||
|  | 		  RtlFreeHeap (heap, 0, old_cwd); | ||||||
|  | 		} | ||||||
|  | 	    } | ||||||
|  | 	  else | ||||||
|  | 	    { | ||||||
|  | 	      /* Old FAST_CWD structure.  Otherwise same procedure as above,
 | ||||||
|  | 	         except for the non-existant FSCharacteristics member. */ | ||||||
|  | 	      PFAST_CWD_OLD f_cwd_old = (PFAST_CWD_OLD) f_cwd; | ||||||
|  | 	      f_cwd_old->ReferenceCount = 1; | ||||||
|  | 	      f_cwd_old->DirectoryHandle = dir; | ||||||
|  | 	      f_cwd_old->OldDismountCount = old_dismount_count; | ||||||
|  | 	      RtlInitEmptyUnicodeString (&f_cwd_old->Path, f_cwd_old->Buffer, | ||||||
|  | 					 MAX_PATH * sizeof (WCHAR)); | ||||||
|  | 	      copy_cwd_str (&f_cwd_old->Path, error ? &ro_u_pipedir : &win32); | ||||||
|  | 	      RtlEnterCriticalSection (peb.FastPebLock); | ||||||
|  | 	      PFAST_CWD_OLD old_cwd = (PFAST_CWD_OLD) *fast_cwd_ptr; | ||||||
|  | 	      *fast_cwd_ptr = (PFAST_CWD) f_cwd_old; | ||||||
|  | 	      upp_cwd_str = f_cwd_old->Path; | ||||||
|  | 	      upp_cwd_hdl = dir; | ||||||
|  | 	      RtlLeaveCriticalSection (peb.FastPebLock); | ||||||
|  | 	      if (InterlockedDecrement (&old_cwd->ReferenceCount) == 0) | ||||||
|  | 		{ | ||||||
|  | 		  if (old_cwd->DirectoryHandle) | ||||||
|  | 		    NtClose (old_cwd->DirectoryHandle); | ||||||
|  | 		  RtlFreeHeap (heap, 0, old_cwd); | ||||||
|  | 		} | ||||||
| 	    } | 	    } | ||||||
| 	} | 	} | ||||||
|       else |       else | ||||||
|  | @ -3636,8 +3700,12 @@ cwdstuff::override_win32_cwd (bool init, ULONG old_dismount_count) | ||||||
| 	  PFAST_CWD f_cwd = (PFAST_CWD) | 	  PFAST_CWD f_cwd = (PFAST_CWD) | ||||||
| 			    ((PBYTE) upp_cwd_str.Buffer | 			    ((PBYTE) upp_cwd_str.Buffer | ||||||
| 			     - __builtin_offsetof (struct _FAST_CWD, Buffer)); | 			     - __builtin_offsetof (struct _FAST_CWD, Buffer)); | ||||||
|  | 	  if (f_cwd->Path.MaximumLength == MAX_PATH * sizeof (WCHAR)) | ||||||
|  | 	    f_cwd->DirectoryHandle = dir; | ||||||
|  | 	  else | ||||||
|  | 	    ((PFAST_CWD_OLD) f_cwd)->DirectoryHandle = dir; | ||||||
| 	  h = upp_cwd_hdl; | 	  h = upp_cwd_hdl; | ||||||
| 	  f_cwd->DirectoryHandle = upp_cwd_hdl = dir; | 	  upp_cwd_hdl = dir; | ||||||
| 	  RtlLeaveCriticalSection (peb.FastPebLock); | 	  RtlLeaveCriticalSection (peb.FastPebLock); | ||||||
| 	  /* In contrast to pre-Vista, the handle on init is always a fresh one
 | 	  /* In contrast to pre-Vista, the handle on init is always a fresh one
 | ||||||
| 	     and not the handle inherited from the parent process.  So we always | 	     and not the handle inherited from the parent process.  So we always | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue