When a File Exists, but Doesn’t
I stumbled across a rather obnoxious “feature” in Vista today that I thought I should share with everyone. With Vista, Windows finally enforces file system permissions and separates applications from user data. It does this by restricting write access to the C:\ directory. A user can read and write freely in their C:\Users\$username\ directory, but when they try to write to C:\Program Files or C:\Windows, they are presented with a UAC prompt that demands administrator privileges.
This poses a problem for legacy applications that weren’t written with Vista’s security model in mind. When you launch a program you are starting it with your permission set, which by default doesn’t have write access to the C:\ root. If a program tries to write to say, C:\Windows, it will be denied. To ease compatibility problems, Vista redirects these programs to a virtual directory that the program does have write access to. A program trying to write to C:\Windows will be redirected to C:\Users\$username\AppData\Local\VirtualStore\Windows and will never know there was a problem.
I discovered this the hard way this morning. I have an application that normally needs to run with elevated privileges. It has to start a kernel-mode service, read a log file in C:\Windows and write its own log file there. When the application starts up it loads its own log file and displays it to the screen. I wanted to run the application with a clean slate, so I stopped the service, deleted the services log and deleted the applications log. I started up the program and was surprised that it was still loading its log file. I thought I had deleted it! Both Explorer and the command prompt claimed that the file was gone. I tried to enter the path directly into Explorer and it couldn’t load the file. But still, my application could load it. I thought there might have been some strange caching with .Net applications, so I wrote a Win32 C program that loads the file and that one worked too! So, now I’ve got two applications that claim to be loading a file that doesn’t exist! Now I’m starting to get confused. I run my program in Debug mode and drop into the debugger when it tries to load the file. I was hoping that the debugger could give me more information about the file that it’s loading. Even the debugger is telling me that it’s loading a log file in C:\Windows that doesn’t exist! How can a debugger lie? Ok, I know the answer to that, but it really doesn’t apply here… The most bizarre part of this is that I could read the file from the command prompt with Edit, but only if I ran as a standard user, not an administrator.
As you can see, the admin prompt loads nothing, but the standard one loads the log. What could possibly be going on here!? It turns out, the Vista developers decided it would be better to completely lie to an application instead of allowing it to crash. Apparently, I opened my application once as a standard user, and it got redirected to C:\Users\$usersname\AppData\Local\VirtualStore\Windows and wrote the log there. Whenever an application tried to load a file from a protected folder, it will check that location, and then check the Virtual Store. If the file is in the VS, then the application is given a handle to that, but the OS never tells the program where the file actually is located. This keeps the transition invisible to legacy programs who will end up just reading and writing from the virtual store. This would explain why Edit could only find the file if it was opened under standard user, since the admin one wouldn’t know which user’s virtual store to look into.
This was all quite aggravating to me and violates venerable UNIX law:
when you fail, fail loudly with lots on information to stderr
I guess this is what happens when you try to make changes to a system but still support backwards compatibility. My opinion is that developers have been allowed to abuse the user permission system in Windows for too long, and don’t deserve the niceties provided but this feature. If you want to write in a protect folder, you must run with elevated privileges, otherwise you catch the error or crash. This Virtual Store is no more than a lie and operating systems shouldn’t lie.