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

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.

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 to Prevent Files Created with GetTempFileName Being Automatically Deleted upon Reboot

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.

Rename a file that multiple processes are trying to use

I have 2 applications running in parallel, both doing the following:
check for file not containing "processed"
process the file and then rename it to filename+processed
for every file, only one application shall use it (on a first come first served basis)
I get the files and I also lock them so the other application cannot process it. But when it comes to renaming the file I get a problem. To rename the file, wanted to use the File.renameTo function. However, for that to work, I have to release the lock on the file. But when I release the lock another process may try to use the file. Exactly that should not happen.
Is there any way to prevent the application B from using the file between application A releasing the lock and finishing renaming the file?
EDIT
Some more information:
File creation if the file doesn't exist has to be prevented.
The file will be processed RandomAccessFile (with read and write permission; this creates a new file if it doesn't exist).
Note: On linux, one can rename a file that is locked, so this problem doesn't occur there. However, on Windows a locked file cannot be renamed; I have to release the lock, then rename it. But the time, during which the lock is released creates enables other applications to see that the file is available and then they will try to use it.
Windows applications can do this using the SetFileInformationByHandle function, which allows you to rename the file using the handle you already have open. You probably can't do this natively from Java.
However, a more straightforward solution would be to rename the file (to filename+processing, for example) before you start processing it. Whichever process successfully renames the file in this way is the one responsible for processing it and eventually renaming it to filename+processed.

How can I tell if a file's been renamed?

I'm updating some legacy code to more efficiently use .ini files for parameter storage. Basically, it caches all the settings internally once they're read so that they can be read again without opening the file. Before using the cache, I compare the cache creation time to the last modified time of the file, and recreate the cache with the updated file. This works great, except when users rename files, because that action doesn't update the last modified time.
So if I copy my app.ini to app - copy.ini, modify app - copy.ini outside of my program, then delete app.ini and rename the copy to app.ini, my program is now using an outdated cache. Even if my program caught the deletion of app.ini and cleared the cache, it would not rebuild the cache when the copy was renamed. The program is designed to run for a very long time unattended, so I would like to avoid continually monitoring the file - only check it once I need to read a parameter.
What you are needing is a filewatcher for vb6, you could try it by interop with .net or use something like this VB6 Implementation
For that scenario, you could keep a hash of the contents of each .ini file the program is using and periodically check each file. If the hash is different than what it was last time you checked, then it's contents were changed or it's a different file caused by this rename scenario.

Impossible to remove directory

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().

Resources