How to Prevent Files Created with GetTempFileName Being Automatically Deleted upon Reboot - windows

Our application collects data from an external device. This data primarily resides in memory, but is spooled to disk in temporary files until the user explicitly saves the data. This is to provide some recovery chance if the application crashes for some reason. Generally speaking, it works just fine.
Lately we've discovered, thanks to Windows becoming more forceful about automatic updates, that these files get deleted automatically during a reboot. So if Windows kills our application to automatically apply updates, the temporary files that would have allowed recovery are gone after the reboot.
I've tested the issue by killing the application on purpose and rebooting; indeed, the temporary files have vanished after the reboot.
The files are created using the Win32 API call GetTempFileName, along with GetTempPath. Everything I've read on the subject says these files are not automatically deleted ever, but they clearly are being deleted.
What can I do to stop this? Or should I just change where our safety data is stored?

What you are seeing is a new "Storage Sense" feature added in Windows 10.
How to Clear Temporary Files Automatically in Windows 10.
Windows 10 got the ability to clear temporary files automatically in a recent build. Starting with build 15014, a new option appeared in Settings.
When enabled, it can be set to clear items like temporary files, Recycle Bin, etc. You can turn them off individually.
Alternatively, another option would be to change your app to save its temporary files in a non-system temp folder that you control, rather than using GetTempPath(). And maybe also use something other than GetTempFileName() to create your temporary file names (like using date/times or guids instead), so Windows can't possibly track the temporary files you create. Then perhaps your files won't be deleted automatically by Storage Sense anymore.

The best solution IMO is not using the temporary folder which contains (as the name suggests) temporary files that can be deleted without any consequences.
Instead you should store them somewhere in the LocalAppdata folder.
Use SHGetFolderPath function to retrieve the actual location of the LocalAppData folder.
In LocalAppData create a folder whose name is that of your company and/or product name or some combination of both and store all your pseudo temporary files there.

Related

Folders created by Program causes read-only to appear

So, I stumbled across a little problem, I can't seem to figure out.
I have a NAS where I dump data on and a script to download files I need back to my PC.
While doing so, it creates a folder for the file. After that, I run a different script that encodes the video files to save some space.
However, for some reason, the files and folders keep getting a 'read-only' lock that prevents the source file to be deleted after compression.
So I have to get into each individual folder and remove the read-only permission.
Is there some way to disable the read-only lock?
The Owner if the Root folder is my personal account, with full access.
Changing it to SYSTEM or Admin with full access doesn't change anything.

Directory location for writing cache file

Hi I am trying to find out what is the best location to save a cache file.
I have an Windows form application that updates user's data from the server using a custom tool.
I want to write the timestamp of the latest updates done on user's machine in the cache file.
Where is the best location for keeping this file:
1. in application directory (c:\program files..)
2. in a temp location e.g. Users profile folder or c:\windows\temp
3. in any location (e.g. c:\dataupdates) where user has full access to read/write to.
Not in the application directory. That much is clear. :) The application directory shouldn't even be writable by the program (or actually by the user account that runs the program). Although some applications still use this location, it has actually been deprecated since Windows 95, I believe, and it has become a real pain since the more rigid UAC applied in Windows Vista and 7.
So the most obvious options are:
The temp folder, which is for temporary files. Note however, that you will need to clean those files up. Temp folder is not automatically cleared by default, so adding new files all the time will consume increasingly much space on the hard drive. On the other hand, some users do clear their temp folders, or may have scripts installed that do that for them, so you cannot trust such files to remain. Also, this is not always C:\Temp of whatever. You'll have to ask Windows what the location is.
You can pick 'any' location. Note that you cannot write anywhere. You cannot even expect the C drive to exist. If you choose this, then you have to make it a configurable setting.
The %app data% directory, my personal favorite, which is a special directory for applications to store their data in. The advantage is, that you can ask Windows for this location, and you can make up a relative path based on that directory, so you don't really have to make it an application setting. For more info on how to get it, see also this question: C# getting the path of %AppData%
I would definitely choose the App Data path for this purpose.

How do I set file permissions for non-admin users in VB6?

I have an old update program written in vb6, which runs as admin. However, because it runs as admin, all the files it downloads and saves are read-only to other users. Even files in public places like the shared application data folder (which is where I'm saving the files in question).
I'm lucky I found this before the 'vista-compatible' release. Vista hides the problem by redirecting non-admin writes and future reads to a sortof 'virtual' folder. But the next update may replace the file, and the non-admin program will still go to the virtual folder and use the old file.
As the admin user, how do I allow other users full control of files I write in vb6?
The way I do this is to make it an Installer responsibility.
Use VSI 1.1 to create an Installer MSI for your application. Create an application data folder under CommonAppDataFolder.
As a post-build step run a script to perform the following:
Set the MSI database for a per-machine installation: Property table, row with ALLUSERS set to 1.
In the Directory table, locate the entry for CommonAppDataFolder and obtain its directory Index. Use this Index to query the Directory table for an entry where CommonAppDataFolder is the parent and obtain its Index (this is your app data subfolder).
Look in the File table to obtain the component Index of your program.
Create the CreateFolder table in the database if it isn't present. Add a row to CreateFolder for the desired application subdirectory by its Index, tying it to your program's component Index.
Create the LockPermissions table if it isn't present. Insert a new LockPermissions row for your application data subdirectory, giving it FILE_ALL_ACCESS for Everyone.
That's about it.
You can do it this way, or use VSI 1.1 and then edit the MSI using Orca, or probably by using a 3rd party MSI authoring tool these entries will be settable via its GUI and can be saved in the Installer project. I just use a small WSH script I run after each VSI 1.1 build.
AFAIK this is the recommended way of accomplishing such things according to Windows application guidelines. If your needs are fancier you might use multiple subdirectories or sub-subdirectories some allowing full access, some read-only, etc.
Your program can locate the folder using Shell Automation objects or by calling Shell32 as a standard DLL (using Declare Function or a TLB).
It's not necessarily who writes the file, but where they write it to. The program files folder and it's sub folders are read-only to all standard users by default. Try using the All Users Application Data folder instead.
This is a little tricky for VB6, since it was not at all designed with Vista in mind. Some of the relevant folders were re-named and there's no way I know to get vb6 to give you the exact folder you want short of using a "Declare Function" alias to call directly into the windows API.
So the easiest reliable way I know to find a suitable location is to use the %ALLUSERSPROFILE% environment variable. That returns "C:\Documents and Settings\All Users" by default on XP and "C:\ProgramData" by default on Vista. From there you can look for an "Application Data" folder. It won't be there and you don't need it on Vista, but creating one if it doesn't exist won't hurt anything. That gives you a consistent folder structure on both systems from which you can create a sub folder for your app to use as a work space.
And one final note: this isn't a new change for Vista. Program Files folders have always been read-only to standard users by default. XP worked the same way. It's just that so many people run as administrators in XP you might be able to get away with it.

MoveFileEx with MOVEFILE_DELAY_UNTIL_REBOOT deleting rather than moving

I have an automatic update system that replaces my existing program files on reboot. (Suffice to say, it's a very complicated program with many drivers, services, and user level modules. There really is no other way. Trust me.)
The function MoveFileEx is used with MOVEFILE_DELAY_UNTIL_REBOOT to setup this file replacement. I'm finding that it works just fine, normally. However, if the source and target files are on different drives, the target is deleted but the source is not moved. The result is that when the user installs the software on a drive different from the system partition, an update deletes the product file rather than update them.
Now, I see in the documentation for MoveFileEx that MOVEFILE_COPY_ALLOWED should be used when moving a file from one volume to another. But it also says that flag cannot be used with MOVEFILE_DELAY_UNTIL_REBOOT.
Q: How can I move a file on reboot, overwriting an existing file, when the source and the target are not on the same volume?
Why don't you just copy the files to the drive where the user installed your program?
As far as I see there is no direct way to do what you want relying only on this function.
Finding writable location on the same drive might be a problem on Vista, but you mention you have services - if they run with LocalSystem privilleges have them write the new files.
One other simple update mechanism that I have used ( not working for drivers though) is to have dedicated update program - kill/end everything, let the update program do its work and start everything up again.

Renaming A Running Process' File Image On Windows

I have a Windows service application on Vista SP1 and I've found that users are renaming its executable file (while it's running) and then rebooting, thus causing it to fail to start on next bootup because the service manager can no longer find the exe file since it's been renamed.
I seem to recall that with older versions of Windows you couldn't do this because the OS placed a lock on the file. Even with Vista SP1 I still cannot copy over the existing file when it's running - Windows reports that the file is in use - makes sense. So why should I be allowed to rename it? What happens if Windows needs to page in a new code page from the exe but the file has been renamed since it was started? I ran Process Monitor while renaming the exe file, etc, but Process Mon didn't report anything strange and just logged changing the filename like any other file.
Does anyone know what's going on here behind the scenes? It's seem counter intuitive that Windows would allow a running process' filename (or its dependent DLLs) to be changed. What am I missing here?
your concept is wrong ... the filename is not the center of the file-io universe ... the handle to the open file is. the file is not moved to a different section of disk when you rename it, it's still in the same place and the part of the disk the internal data structure for the open file is still pointing to the same place. bottom line is that your observations are correct. you can rename a running program without causing problems. you can create a new file with the same name as the running program once you've renamed it. this is actually useful behavior if you want to update software while the software is running.
As long as the file is still there, Windows can still read from it - it's the underlying file that matters, not its name.
I can happily rename running executables on my XP machine.
The OS keeps an open handle to the .exe file,. Renaming the file simply changes some filesystem metadata about the file, without invalidating open handles. So when the OS goes to page in more code, it just uses the file handle it already has open.
Replacing the file (writing over its contents) is another matter entirely, and I'm guessing the OS opens with the FILE_SHARE_WRITE flag unset, so no other processes can write to the .exe file.
Might be a stupid question but, why do users have access to rename the file if they are not suppose to rename the file? But yeah, it's allowed because, as the good answers point out, the open handle to the file isn't lost until the application exits. And there are some uses for it as well, even though I'm not convinced updating an application by renaming its file is a good practice.
You might consider having your service listen to changes to the directory that your service is installed in. If it detects a rename, then it could rename itself back to what it's supposed to be.
There are two aspects to the notion of file here:
The data on the disk - that's the actual file.
The file-name (could be several or none) which you can give that data - called directory entries.
What you are renaming is the directory entry, which still references the same data. Windows doesn't care about your doing so, as it still can access the data when it needs to. The running process is mapped to the data, not the name.

Resources