* cygheap.h (enum fcwd_version_t): Move here from path.cc.
(class fcwd_access_t): Ditto. Only declare methods. (class cwdstuff): Move fast_cwd_ptr and fast_cwd_version from shared DLL section here. * path.cc: Keep fcwd_access_t method definitions. (fcwd_access_t::fast_cwd_version): New method. (find_fast_cwd_pointer): Change comment. Mention test on W8CP. (cwdstuff::init): Initialize fast_cwd_ptr and fast_cwd_version.
This commit is contained in:
		| @@ -1,3 +1,14 @@ | ||||
| 2012-03-05  Corinna Vinschen  <corinna@vinschen.de> | ||||
|  | ||||
| 	* cygheap.h (enum fcwd_version_t): Move here from path.cc. | ||||
| 	(class fcwd_access_t): Ditto.  Only declare methods. | ||||
| 	(class cwdstuff): Move fast_cwd_ptr and fast_cwd_version from shared | ||||
| 	DLL section here. | ||||
| 	* path.cc: Keep fcwd_access_t method definitions. | ||||
| 	(fcwd_access_t::fast_cwd_version): New method. | ||||
| 	(find_fast_cwd_pointer): Change comment.  Mention test on W8CP. | ||||
| 	(cwdstuff::init): Initialize fast_cwd_ptr and fast_cwd_version. | ||||
|  | ||||
| 2012-03-05  Corinna Vinschen  <corinna@vinschen.de> | ||||
|  | ||||
| 	* dll_init.cc (dll_list::operator[]): Extend comment a bit more to | ||||
|   | ||||
| @@ -204,7 +204,87 @@ public: | ||||
|  | ||||
| /* cwd cache stuff.  */ | ||||
|  | ||||
| class muto; | ||||
| enum fcwd_version_t { | ||||
|   FCWD_OLD, | ||||
|   FCWD_W7, | ||||
|   FCWD_W8 | ||||
| }; | ||||
|  | ||||
| /* This class is used to store the CWD starting with Windows Vista. | ||||
|    The CWD storage in the RTL_USER_PROCESS_PARAMETERS block is only | ||||
|    an afterthought now.  The actual CWD storage is a FAST_CWD structure | ||||
|    which is allocated on the process heap.  The new method only requires | ||||
|    minimal locking and it's much more multi-thread friendly.  Presumably | ||||
|    it minimizes contention when accessing the CWD. | ||||
|    The class fcwd_access_t is supposed to encapsulate the gory implementation | ||||
|    details depending on OS version from the calling functions. */ | ||||
| class fcwd_access_t { | ||||
|   /* This is the layout used in Windows 8 developer preview. */ | ||||
|   struct FAST_CWD_8 { | ||||
|     LONG           ReferenceCount;	/* Only release when this is 0. */ | ||||
|     HANDLE         DirectoryHandle; | ||||
|     ULONG          OldDismountCount;	/* Reflects the system DismountCount | ||||
| 					   at the time the CWD has been set. */ | ||||
|     UNICODE_STRING Path;		/* Path's Buffer member always refers | ||||
| 					   to the following Buffer array. */ | ||||
|     LONG           FSCharacteristics;	/* Taken from FileFsDeviceInformation */ | ||||
|     WCHAR          Buffer[MAX_PATH]; | ||||
|   }; | ||||
|   /* This is the layout used in Windows 7 and Vista. */ | ||||
|   struct FAST_CWD_7 { | ||||
|     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]; | ||||
|   }; | ||||
|   /* This is the old FAST_CWD structure up to the patch from KB 2393802, | ||||
|      release in February 2011. */ | ||||
|   struct FAST_CWD_OLD { | ||||
|     LONG           ReferenceCount;	/* Only release when this is 0. */ | ||||
|     HANDLE         DirectoryHandle; | ||||
|     ULONG          OldDismountCount;	/* Reflects the system DismountCount | ||||
| 					   at the time the CWD has been set. */ | ||||
|     UNICODE_STRING Path;		/* Path's Buffer member always refers | ||||
| 					   to the following Buffer array. */ | ||||
|     WCHAR          Buffer[MAX_PATH]; | ||||
|   }; | ||||
|   union { | ||||
|     FAST_CWD_OLD fold; | ||||
|     FAST_CWD_7   f7; | ||||
|     FAST_CWD_8   f8; | ||||
|   }; | ||||
|  | ||||
| #define IMPLEMENT(type, name) \ | ||||
|   type name () { \ | ||||
|     switch (fast_cwd_version ()) { \ | ||||
|       case FCWD_OLD: \ | ||||
|       default: \ | ||||
| 	return fold.name; \ | ||||
|       case FCWD_W7: \ | ||||
| 	return f7.name; \ | ||||
|       case FCWD_W8: \ | ||||
| 	return f8.name; \ | ||||
|     } \ | ||||
|   } | ||||
|   IMPLEMENT (LONG &, ReferenceCount) | ||||
|   IMPLEMENT (HANDLE &, DirectoryHandle) | ||||
|   IMPLEMENT (ULONG &, OldDismountCount) | ||||
|   IMPLEMENT (UNICODE_STRING &, Path) | ||||
|   IMPLEMENT (WCHAR *, Buffer) | ||||
|   void SetFSCharacteristics (LONG val); | ||||
|   static fcwd_version_t &fast_cwd_version (void); | ||||
|  | ||||
| public: | ||||
|   void CopyPath (UNICODE_STRING &target); | ||||
|   void Free (PVOID heap); | ||||
|   void FillIn (HANDLE dir, PUNICODE_STRING name, ULONG old_dismount_count); | ||||
|   static void SetDirHandleFromBufferPointer (PWCHAR buf_p, HANDLE dir); | ||||
|   static void SetVersionFromPointer (PBYTE buf_p, bool is_buffer); | ||||
| }; | ||||
|  | ||||
| class cwdstuff | ||||
| { | ||||
| @@ -217,6 +297,16 @@ private: | ||||
| 			   a native Win32 application.  See cwdstuff::set for | ||||
| 			   how it gets set.  See child_info_spawn::worker for how | ||||
| 			   it's evaluated. */ | ||||
|  | ||||
|   friend class fcwd_access_t; | ||||
|   /* fast_cwd_ptr is a pointer to the global RtlpCurDirRef pointer in | ||||
|      ntdll.dll pointing to the FAST_CWD structure which constitutes the CWD. | ||||
|      Unfortunately RtlpCurDirRef is not exported from ntdll.dll. */ | ||||
|   fcwd_access_t **fast_cwd_ptr; | ||||
|   /* Type of FAST_CWD used on this system.  Keeping this information | ||||
|      available in shared memory avoids to test for the version every time | ||||
|      around.  Default to new version. */ | ||||
|   fcwd_version_t fast_cwd_version; | ||||
|   void override_win32_cwd (bool, ULONG); | ||||
|  | ||||
| public: | ||||
|   | ||||
| @@ -3510,205 +3510,132 @@ copy_cwd_str (PUNICODE_STRING tgt, PUNICODE_STRING src) | ||||
|    USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | ||||
|    DAMAGE. */ | ||||
|  | ||||
| /* This class is used to store the CWD starting with Windows Vista. | ||||
|    The CWD storage in the RTL_USER_PROCESS_PARAMETERS block is only | ||||
|    an afterthought now.  The actual CWD storage is a FAST_CWD structure | ||||
|    which is allocated on the process heap.  The new method only requires | ||||
|    minimal locking and it's much more multi-thread friendly.  Presumably | ||||
|    it minimizes contention when accessing the CWD. | ||||
|    The class fcwd_access_t is supposed to encapsulate the gory implementation | ||||
|    details depending on OS version from the calling functions. */ | ||||
| class fcwd_access_t { | ||||
|   /* This is the layout used in Windows 8 developer preview. */ | ||||
|   struct FAST_CWD_8 { | ||||
|     LONG           ReferenceCount;	/* Only release when this is 0. */ | ||||
|     HANDLE         DirectoryHandle; | ||||
|     ULONG          OldDismountCount;	/* Reflects the system DismountCount | ||||
| 					   at the time the CWD has been set. */ | ||||
|     UNICODE_STRING Path;		/* Path's Buffer member always refers | ||||
| 					   to the following Buffer array. */ | ||||
|     LONG           FSCharacteristics;	/* Taken from FileFsDeviceInformation */ | ||||
|     WCHAR          Buffer[MAX_PATH]; | ||||
|   }; | ||||
|   /* This is the layout used in Windows 7 and Vista. */ | ||||
|   struct FAST_CWD_7 { | ||||
|     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]; | ||||
|   }; | ||||
|   /* This is the old FAST_CWD structure up to the patch from KB 2393802, | ||||
|      release in February 2011. */ | ||||
|   struct FAST_CWD_OLD { | ||||
|     LONG           ReferenceCount;	/* Only release when this is 0. */ | ||||
|     HANDLE         DirectoryHandle; | ||||
|     ULONG          OldDismountCount;	/* Reflects the system DismountCount | ||||
| 					   at the time the CWD has been set. */ | ||||
|     UNICODE_STRING Path;		/* Path's Buffer member always refers | ||||
| 					   to the following Buffer array. */ | ||||
|     WCHAR          Buffer[MAX_PATH]; | ||||
|   }; | ||||
|   union { | ||||
|     FAST_CWD_OLD fold; | ||||
|     FAST_CWD_7   f7; | ||||
|     FAST_CWD_8   f8; | ||||
|   }; | ||||
|  | ||||
|   /* Type of FAST_CWD used on this system.  Keeping this information available | ||||
|      in shared memory avoids to test for the version every time around. | ||||
|      Default to new version. */ | ||||
|   enum fcwd_version_t { | ||||
|     FCWD_OLD, | ||||
|     FCWD_W7, | ||||
|     FCWD_W8 | ||||
|   }; | ||||
|   static fcwd_version_t fast_cwd_version; | ||||
|  | ||||
| #define IMPLEMENT(type, name) \ | ||||
|   type name () { \ | ||||
|     switch (fast_cwd_version) { \ | ||||
|       case FCWD_OLD: \ | ||||
|       default: \ | ||||
| 	return fold.name; \ | ||||
|       case FCWD_W7: \ | ||||
| 	return f7.name; \ | ||||
|       case FCWD_W8: \ | ||||
| 	return f8.name; \ | ||||
|     } \ | ||||
|   } | ||||
|   IMPLEMENT (LONG &, ReferenceCount) | ||||
|   IMPLEMENT (HANDLE &, DirectoryHandle) | ||||
|   IMPLEMENT (ULONG &, OldDismountCount) | ||||
|   IMPLEMENT (UNICODE_STRING &, Path) | ||||
|   IMPLEMENT (WCHAR *, Buffer) | ||||
| void | ||||
| fcwd_access_t::SetFSCharacteristics (LONG val) | ||||
| { | ||||
|   /* Special case FSCharacteristics.  Didn't exist originally. */ | ||||
|   void SetFSCharacteristics (LONG val) | ||||
|   switch (fast_cwd_version ()) | ||||
|     { | ||||
|       switch (fast_cwd_version) | ||||
| 	{ | ||||
| 	case FCWD_OLD: | ||||
| 	  break; | ||||
| 	case FCWD_W7: | ||||
| 	  f7.FSCharacteristics = val; | ||||
| 	  break; | ||||
| 	case FCWD_W8: | ||||
| 	  f8.FSCharacteristics = val; | ||||
| 	  break; | ||||
| 	} | ||||
|     } | ||||
| public: | ||||
|   void CopyPath (UNICODE_STRING &target) | ||||
|     { | ||||
|       /* Copy the Path contents over into the UNICODE_STRING referenced by | ||||
| 	 target.  This is used to set the CurrentDirectoryName in the | ||||
| 	 user parameter block. */ | ||||
|       target = Path (); | ||||
|     } | ||||
|   void Free (PVOID heap) | ||||
|     { | ||||
|       /* Decrement the reference count.  If it's down to 0, free | ||||
| 	 structure from heap. */ | ||||
|       if (this && InterlockedDecrement (&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. */ | ||||
| 	  HANDLE h = DirectoryHandle (); | ||||
| 	  if (h) | ||||
| 	    NtClose (h); | ||||
| 	  RtlFreeHeap (heap, 0, this); | ||||
| 	} | ||||
|     } | ||||
|   void FillIn (HANDLE dir, PUNICODE_STRING name, ULONG old_dismount_count) | ||||
|     { | ||||
|       /* Fill in all values into this FAST_CWD structure. */ | ||||
|       DirectoryHandle () = dir; | ||||
|       ReferenceCount () = 1; | ||||
|       OldDismountCount () = old_dismount_count; | ||||
|       /* 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. */ | ||||
|       if (fast_cwd_version != FCWD_OLD) | ||||
| 	{ | ||||
| 	  SetFSCharacteristics (0); | ||||
| 	  if (name != &ro_u_pipedir) | ||||
| 	    { | ||||
| 	      IO_STATUS_BLOCK io; | ||||
| 	      FILE_FS_DEVICE_INFORMATION ffdi; | ||||
| 	      if (NT_SUCCESS (NtQueryVolumeInformationFile (dir, &io, &ffdi, | ||||
| 			      sizeof ffdi, FileFsDeviceInformation))) | ||||
| 		SetFSCharacteristics (ffdi.Characteristics); | ||||
| 	    } | ||||
| 	} | ||||
|       RtlInitEmptyUnicodeString (&Path (), Buffer (), | ||||
| 				 MAX_PATH * sizeof (WCHAR)); | ||||
|       copy_cwd_str (&Path (), name); | ||||
|     case FCWD_OLD: | ||||
|       break; | ||||
|     case FCWD_W7: | ||||
|       f7.FSCharacteristics = val; | ||||
|       break; | ||||
|     case FCWD_W8: | ||||
|       f8.FSCharacteristics = val; | ||||
|       break; | ||||
|     } | ||||
| } | ||||
|  | ||||
|   static void SetDirHandleFromBufferPointer (PWCHAR buf_p, HANDLE dir) | ||||
| fcwd_version_t & | ||||
| fcwd_access_t::fast_cwd_version () | ||||
| { | ||||
|   return cygheap->cwd.fast_cwd_version; | ||||
| } | ||||
|  | ||||
| void | ||||
| fcwd_access_t::CopyPath (UNICODE_STRING &target) | ||||
| { | ||||
|   /* Copy the Path contents over into the UNICODE_STRING referenced by | ||||
|      target.  This is used to set the CurrentDirectoryName in the | ||||
|      user parameter block. */ | ||||
|   target = Path (); | ||||
| } | ||||
|  | ||||
| void | ||||
| fcwd_access_t::Free (PVOID heap) | ||||
| { | ||||
|   /* Decrement the reference count.  If it's down to 0, free | ||||
|      structure from heap. */ | ||||
|   if (this && InterlockedDecrement (&ReferenceCount ()) == 0) | ||||
|     { | ||||
|       /* Input: The buffer pointer as it's stored in the user parameter block | ||||
| 	 and a directory handle. | ||||
| 	 This function computes the address to the FAST_CWD structure based | ||||
| 	 on the version and overwrites the directory handle.  It is only | ||||
| 	 used if we couldn't figure out the address of fast_cwd_ptr. */ | ||||
|       fcwd_access_t *f_cwd; | ||||
|       switch (fast_cwd_version) | ||||
|       /* 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. */ | ||||
|       HANDLE h = DirectoryHandle (); | ||||
|       if (h) | ||||
| 	NtClose (h); | ||||
|       RtlFreeHeap (heap, 0, this); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void | ||||
| fcwd_access_t::FillIn (HANDLE dir, PUNICODE_STRING name, | ||||
| 			ULONG old_dismount_count) | ||||
| { | ||||
|   /* Fill in all values into this FAST_CWD structure. */ | ||||
|   DirectoryHandle () = dir; | ||||
|   ReferenceCount () = 1; | ||||
|   OldDismountCount () = old_dismount_count; | ||||
|   /* 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. */ | ||||
|   if (fast_cwd_version () != FCWD_OLD) | ||||
|     { | ||||
|       SetFSCharacteristics (0); | ||||
|       if (name != &ro_u_pipedir) | ||||
| 	{ | ||||
| 	case FCWD_OLD: | ||||
| 	default: | ||||
| 	  f_cwd = (fcwd_access_t *) | ||||
| 	    ((PBYTE) buf_p - __builtin_offsetof (FAST_CWD_OLD, Buffer)); | ||||
| 	case FCWD_W7: | ||||
| 	  f_cwd = (fcwd_access_t *) | ||||
| 	    ((PBYTE) buf_p - __builtin_offsetof (FAST_CWD_7, Buffer)); | ||||
| 	case FCWD_W8: | ||||
| 	  f_cwd = (fcwd_access_t *) | ||||
| 	    ((PBYTE) buf_p - __builtin_offsetof (FAST_CWD_8, Buffer)); | ||||
| 	  IO_STATUS_BLOCK io; | ||||
| 	  FILE_FS_DEVICE_INFORMATION ffdi; | ||||
| 	  if (NT_SUCCESS (NtQueryVolumeInformationFile (dir, &io, &ffdi, | ||||
| 			  sizeof ffdi, FileFsDeviceInformation))) | ||||
| 	    SetFSCharacteristics (ffdi.Characteristics); | ||||
| 	} | ||||
|       f_cwd->DirectoryHandle () = dir; | ||||
|     } | ||||
|   static void SetVersionFromPointer (PBYTE buf_p, bool is_buffer) | ||||
|   RtlInitEmptyUnicodeString (&Path (), Buffer (), | ||||
| 			     MAX_PATH * sizeof (WCHAR)); | ||||
|   copy_cwd_str (&Path (), name); | ||||
| } | ||||
|  | ||||
| void | ||||
| fcwd_access_t::SetDirHandleFromBufferPointer (PWCHAR buf_p, HANDLE dir) | ||||
| { | ||||
|   /* Input: The buffer pointer as it's stored in the user parameter block | ||||
|      and a directory handle. | ||||
|      This function computes the address to the FAST_CWD structure based | ||||
|      on the version and overwrites the directory handle.  It is only | ||||
|      used if we couldn't figure out the address of fast_cwd_ptr. */ | ||||
|   fcwd_access_t *f_cwd; | ||||
|   switch (fast_cwd_version ()) | ||||
|     { | ||||
|       /* Given a pointer to the FAST_CWD structure (is_buffer == false) or a | ||||
| 	 pointer to the Buffer within (is_buffer == true), this function | ||||
| 	 computes the FAST_CWD version by checking that Path.MaximumLength | ||||
| 	 equals MAX_PATH, and that Path.Buffer == Buffer. */ | ||||
|       if (is_buffer) | ||||
| 	buf_p -= __builtin_offsetof (FAST_CWD_8, Buffer); | ||||
|       fcwd_access_t *f_cwd = (fcwd_access_t *) buf_p; | ||||
|       if (f_cwd->f8.Path.MaximumLength == MAX_PATH * sizeof (WCHAR) | ||||
| 	  && f_cwd->f8.Path.Buffer == f_cwd->f8.Buffer) | ||||
| 	fast_cwd_version = FCWD_W8; | ||||
|       else if (f_cwd->f7.Path.MaximumLength == MAX_PATH * sizeof (WCHAR) | ||||
| 	       && f_cwd->f7.Path.Buffer == f_cwd->f7.Buffer) | ||||
| 	fast_cwd_version = FCWD_W7; | ||||
|       else | ||||
| 	fast_cwd_version = FCWD_OLD; | ||||
|     case FCWD_OLD: | ||||
|     default: | ||||
|       f_cwd = (fcwd_access_t *) | ||||
| 	((PBYTE) buf_p - __builtin_offsetof (FAST_CWD_OLD, Buffer)); | ||||
|     case FCWD_W7: | ||||
|       f_cwd = (fcwd_access_t *) | ||||
| 	((PBYTE) buf_p - __builtin_offsetof (FAST_CWD_7, Buffer)); | ||||
|     case FCWD_W8: | ||||
|       f_cwd = (fcwd_access_t *) | ||||
| 	((PBYTE) buf_p - __builtin_offsetof (FAST_CWD_8, Buffer)); | ||||
|     } | ||||
| }; | ||||
| fcwd_access_t::fcwd_version_t fcwd_access_t::fast_cwd_version | ||||
|   __attribute__((section (".cygwin_dll_common"), shared)) | ||||
|   = fcwd_access_t::FCWD_W7; | ||||
| /* fast_cwd_ptr is a pointer to the global RtlpCurDirRef pointer in | ||||
|    ntdll.dll pointing to the FAST_CWD structure which constitutes the CWD. | ||||
|    Unfortunately RtlpCurDirRef is not exported from ntdll.dll. | ||||
|    We put the pointer into the common shared DLL segment.  This allows to | ||||
|    restrict the call to find_fast_cwd_pointer() to once per Cygwin session | ||||
|    per user session.  This works, because ASLR randomizes the load address | ||||
|    of DLLs only once at boot time. */ | ||||
| static fcwd_access_t **fast_cwd_ptr | ||||
|   __attribute__((section (".cygwin_dll_common"), shared)) | ||||
|   = (fcwd_access_t **) -1; | ||||
|   f_cwd->DirectoryHandle () = dir; | ||||
| } | ||||
|  | ||||
| void | ||||
| fcwd_access_t::SetVersionFromPointer (PBYTE buf_p, bool is_buffer) | ||||
| { | ||||
|   /* Given a pointer to the FAST_CWD structure (is_buffer == false) or a | ||||
|      pointer to the Buffer within (is_buffer == true), this function | ||||
|      computes the FAST_CWD version by checking that Path.MaximumLength | ||||
|      equals MAX_PATH, and that Path.Buffer == Buffer. */ | ||||
|   if (is_buffer) | ||||
|     buf_p -= __builtin_offsetof (FAST_CWD_8, Buffer); | ||||
|   fcwd_access_t *f_cwd = (fcwd_access_t *) buf_p; | ||||
|   if (f_cwd->f8.Path.MaximumLength == MAX_PATH * sizeof (WCHAR) | ||||
|       && f_cwd->f8.Path.Buffer == f_cwd->f8.Buffer) | ||||
|     fast_cwd_version () = FCWD_W8; | ||||
|   else if (f_cwd->f7.Path.MaximumLength == MAX_PATH * sizeof (WCHAR) | ||||
| 	   && f_cwd->f7.Path.Buffer == f_cwd->f7.Buffer) | ||||
|     fast_cwd_version () = FCWD_W7; | ||||
|   else | ||||
|     fast_cwd_version () = FCWD_OLD; | ||||
| } | ||||
|  | ||||
| #define peek32(x)	(*(uint32_t *)(x)) | ||||
|  | ||||
| @@ -3718,8 +3645,9 @@ static fcwd_access_t **fast_cwd_ptr | ||||
|    Therefore we have to use some knowledge to figure out the address. | ||||
|  | ||||
|    This code has been tested on Vista 32/64 bit, Server 2008 32/64 bit, | ||||
|    Windows 7 32/64 bit, and Server 2008 R2 (which is only 64 bit anyway). | ||||
|    There's some hope that this will still work for Windows 8... */ | ||||
|    Windows 7 32/64 bit, Server 2008 R2 (which is only 64 bit anyway), | ||||
|    and W8CP 32/64 bit.  There's some hope this will still work for | ||||
|    Windows 8 RTM... */ | ||||
| static fcwd_access_t ** | ||||
| find_fast_cwd_pointer () | ||||
| { | ||||
| @@ -3950,8 +3878,13 @@ cwdstuff::init () | ||||
|   if (win32.Buffer) | ||||
|     override_win32_cwd (true, SharedUserData.DismountCount); | ||||
|   else | ||||
|     /* Initially re-open the cwd to allow POSIX semantics. */ | ||||
|     set (NULL, NULL); | ||||
|     { | ||||
|       /* Initialize fast_cwd stuff. */ | ||||
|       fast_cwd_ptr = (fcwd_access_t **) -1; | ||||
|       fast_cwd_version = FCWD_W7; | ||||
|       /* Initially re-open the cwd to allow POSIX semantics. */ | ||||
|       set (NULL, NULL); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /* Chdir and fill out the elements of a cwdstuff struct. */ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user