+ /* New FAST_CWD structure. */
+ IO_STATUS_BLOCK io;
+ FILE_FS_DEVICE_INFORMATION ffdi;
+
+ RtlInitEmptyUnicodeString (&f_cwd->Path, f_cwd->Buffer,
+ MAX_PATH * sizeof (WCHAR));
+ 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);
+ }