Impossible to remove directory - winapi

Evidently I've never had to delete a directory using win32 sdk before, because its apparently an impossible task. I've tried anything and everything - RemoveDirectory,
SHFileOperation with FO_DELETE, etc.
Currently I call CreateDirectory in one thread, start another thread, copy some files to this directory in the new thread, then delete all the files in the directory in the new thread, and then back in the original thread that created the directory, try to delete the now empty directory and it fails. The directory really and truly is empty when I try to delete it, but it makes no difference. The whole thread aspect is irrelevant I think because at one point everything was in one thread and it didn't work. I'm currently setting a SecurityAttributes structure on CreateDirectory to grant access to everyone, but it makes no difference. RemoveDirectory in the past has returned '32' on GetLastError, which I believe is Sharing violation.
But even if I just try to delete the empty directory from the command line, it refuses saying, "The process cannot access the file because it is being used by another process."
until I shut down the entire application that created the directory. (Note: the directory is created in GetTempPath.)

Error 32 is indeed "The process cannot access the file because it is being used by another process."
Are you perhaps using FindFirstFile() to build your copy list? - that will lock the directory until FindClose().

Related

Deleting a locked file created with TempFile

I have a GUI (lxn/walk) app patcher that downloads a file via ftp, streams it to a temporary file and extracts the contents to update the local files. The remove file command is deferred.
This works unless the user exits the program while the file is downloading, then the file isn’t deleted.
I tried to fix this by doing a graceful exit by catching the signal and removing the file there. But unfortunately it throws an error that the file can’t be deleted because it is being used by another program. Which makes sense because the another program is actually itself still writing to the temporary file.
Now I’m stuck and don’t know what to do to make sure that the temporary file is automatically gone once the patcher is not running. How do I do that correctly?
The file could also be created as a normal file, not just a temp file. I would just like to ask too, where in windows is best to write a temporary file?
Now I’m stuck and don’t know what to do to make sure that the temporary file is automatically gone once the patcher is not running. How do I do that correctly?
There are no guaranteed ways to accomplish this as many things beyond the control of the application can cause it to exit. A power failure or kernel panic due to some hardware issue can crash the machine or force it to be restarted.
A strategy that is in common use is to implement a check on program startup for the status of the previous run. Some applications create a lock file at start and remove it on graceful exit. If this lock file exists when the program is restarted, this means the previous run did not result in a clean exit, and the application can take any corrective action. The exact action to be taken depends on the nature of the application, some refuse to start, others give warnings to users.
I would just like to ask too, where in windows is best to write a temporary file?
Each OS has its own location for temporary files. If you eliminate the dir argument to TempFile, it will create it in the appropriate location, as mentioned in the documentation:
TempFile creates a new temporary file in the directory dir, opens the
file for reading and writing, and returns the resulting *os.File. The
filename is generated by taking pattern and adding a random string to
the end. If pattern includes a "*", the random string replaces the
last "*". If dir is the empty string, TempFile uses the default
directory for temporary files (see os.TempDir). Multiple programs
calling TempFile simultaneously will not choose the same file. The
caller can use f.Name() to find the pathname of the file. It is the
caller's responsibility to remove the file when no longer needed.
From os.TempDir we see the following:
On Unix systems, it returns $TMPDIR if non-empty, else /tmp. On
Windows, it uses GetTempPath, returning the first non-empty value
from %TMP%, %TEMP%, %USERPROFILE%, or the Windows directory. On
Plan 9, it returns /tmp.
The directory is neither guaranteed to exist nor have accessible
permissions.

How can an empty directory be in use and how do I do it on Windows?

On Windows I have an empty directory which I cannot delete because it is "in use". After restarting, I can delete this directory. This happens occasionally, and it confuses me.
I am quite familiar with the Win32 API, but I have no idea what it means for an empty directory to be "in use". (And yes, I have hidden files and folders set to visible.)
How do I make this happen myself? What Win32 API calls should I make to make an empty directory of my choice "in use"?
Somebody has a open handle to the directory. Usually by SetCurrentDirectory, or the current directory in cmd.exe or sometimes by CreateFile.
Use the handle search in Process Explorer to find open handles to a specific directory.

Script to watch for file changes & if detected, backup the original first.

As per the title I'm looking for a way to backup files (SQL queries to be specific) when they are saved over/replaced.
This is to prevent accidental saving without a decent fall back.
I think that using a combination of Powershell and .NET FileSystemWatcher might be a good combo and instead of an alert I could take the original and append datetime to it in another location.
(https://gallery.technet.microsoft.com/scriptcenter/Powershell-FileSystemWatche-dfd7084b)
So my question is, how to interrupt that save process within Windows and copy the file out before it's saved over?
I'm thinking it might not be possible without calling the PS when a save is initiated on that specific directory.
I have access to PS, VBS and elevated cmd.
TIA for any pointers or further reading.
There's no way to backup/save the previous before a newer version overwrites it as there are no OnBeforeX events in the FileSystemWatcher.
Changed: Occurs when a file or directory in the specified Path is changed.
Created: Occurs when a file or directory in the specified Path is created.
Deleted: Occurs when a file or directory in the specified Path is deleted.
Disposed: Occurs when the component is disposed by a call to the Dispose method. (Inherited from Component.)
Error: Occurs when the instance of FileSystemWatcher is unable to continue monitoring changes or when the internal buffer overflows.
Renamed: Occurs when a file or directory in the specified Path is renamed.
The only way to do this would be to perform an initial back up of all the files. Then backup, with a timestamp pre/suffix, after each Changed event.

How to get a process exclusive lock on a folder in Windows?

Is it possible to lock a directory in Windows so as to ensure that no other process is reading or modifying files inside the directory for the duration of the lock, while at the same time allowing the process with the lock to modify and move files and directory itself freely?
This is not a real answer, but as a workaround:
Move the directory to a subdirectory specific to your application, which is on the same volume.
Advantages:
Prevents users and other programs from modifying the file at the old location, as the files will no longer be there
Importantly, will fail if a process already has a file open within that directory, thus ensuring that the "acquired" lock is indeed "exclusive"
Disadvantages:
It's a hack
The software will need to be adapted to work with the directory at a different path than where it was initially
Users and programs attempting to access the files will encounter unusual behavior or errors ("Path not found" instead of "Access denied")
Does not protect against programs that may poke into your application-specific subdirectory
Will leave the directory "locked" (moved to a location the user probably can't find) if your program crashes while the "lock" is "held"

Win32 current directory, locking & shell integration

In Win32, your main thread's current working directory is set to the location the executable was launched from. My problem is that even after a call to SetCurrentDirectory() to somewhere else, the process apparently still has a filesystem object referencing this initial startup directory (verifiable with a tool like Process Explorer) - which means this director cannot be deleted by the process.
Does anybody here know of a not-too-hacky solution? I'm specifically running into the problem with a program that integrates with explorer (adding a verb to HKCR\Directory\shell registry key), I need to process files in a right-clicked directory and the remove the source directory, which is impossible because the initial working directory is set to, you guessed it, the right-clicked directory.
EDIT: I'll go for the "use helper launch-from-sane-directory" approach. It might not be super elegant, but it will work and doesn't require any nasty hacks.
Your easiest solution may be to just spawn a little helper process that runs in whatever directory you specify (c:\, e.g.) and then just exit and let it do its thing. It may need to be synchronized with a mutex, or perhaps just retry two or three times on a timer...
I had another thought: You may be able to use CreateFile() with FILE_FLAG_DELETE_ON_CLOSE. Then it should go away when everyone lets go of it, but only if it was opened with FILE_SHARE_DELETE.

Resources