DRIVE_GetUnixCwd and drives other than the current one

Troy Rollo wine at troy.rollo.name
Tue Jul 22 20:48:27 CDT 2003


It appears that Wine is storing and using a "current directory" for each DOS 
drive. According to some testing we have just done on Windows 2000 and 
Windows 98, Windows only stores a current directory for the current drive.

"But CMD.EXE seems to remember drives, and their children too", comes the 
reply.

Well, sort of. The documentation for CreateProcess talks about environment 
variables used to hold the current directory for each drive, with an 
environment variable with a name of the form "=C:" having the value, say 
"C:\WINDOWS". That documentation suggests you must make sure all these 
environment variables are set if you construct a new environment block, and 
that you need to get the values of them using "GetFullPathName". Shock, 
horror, the Windows documentation is wrong.

What actually happens is that CMD.EXE and COMMAND.COM independently set those 
environment variables when you change directories in those shells. 
SetCurrentDirectory has no effect on those environment variables - either in 
the current process or in child processes. It is the responsibility of the 
application to set them if it wants the children to have access to its 
current directory on drives other than its current drive.

However, SetCurrentDirectory("D:") (assuming a starting point of drive "C") 
will read those environment variables to determine which directory of drive 
"D" to go to. You can even 'SetEnvironmentVariable("=D:", "\\foo")' to make 
the next 'SetCurrentDirectory("D:")' end up in "D:\foo".

GetFullPathName also picks up the environment variable if the path requested 
is not on the current drive (although it also checks that the path is valid, 
so 'GetFullPathName("A:\\", ...)' will rattle drive A if drive A is empty). 
If there's no environment variable, both GetFullPathName and 
SetCurrentDirectory assume "x:\".

If the drive in question is the current drive, SetCurrentDirectory and 
GetFullPathName both ignore the environment variables and use the value from 
GetCurrentDirectory. So, for example:

	// Start with no "=D:" variable in environment
	SetCurrentDirectory("d:\\bar");
	SetCurrentDirectory("c:");
	SetCurrentDirectory("d:");
	// Current directory now d:\
	SetCurrentDirectory("d:\\bar");
	SetCurrentDirectory("c:");
	SetEnvironmentVariable("=D:", "\\foo");
	SetCurrentDirectory("d:");
	// Current directory now "d:\\foo";
	SetEnvironmentVariable("=D:", "\\bar");
	SetCurrentDirectory("d:");
	// Current directory still d:\\foo

The Borland C++ run-time libraries have code in their chdir functions that 
sets these variables, but it's inside a "#if 0" section, presumably 
reflecting an attempt to be compatible with MSC.

I'm not aware of anything that relies on this perverse behaviour, so whether 
Wine needs to be adjusted to mimic it may be an open question. It is probably 
of more interest to people who want to pass an environment block to 
CreateProcess. If you're doing that, ignore what the documentation says about 
including "=C:" & etc environment variables in the environment block - simply 
start with the environment block returned by GetEnvironmentBlock and make the 
desired changes, ensuring the block is sorted according to instructions I 
gave previously on one of the Cygwin mailing lists.




More information about the wine-devel mailing list