When I copy a file with CopyFile, will the source file be locked in any way?
Say - if the copy operation starts, and then someone wants to open the source file, will it succeed? What if the "someone" requests exclusive access to the file, will his Win32 API call (probably a CreateFile) fail, or will it wait (or whatever) until the copy operation is done?
If somebody requests exclusive access to a file that's already opened, that request will fail. Windows does not have a file open mode that consists of, "If somebody else is using the file, bump him off."
As I recall, CopyFile opens the source file so that others can read, but not write it.
Related
I'm creating a program (doesn't really matter the objective but it happens to be purely to mess around and learn more about windows) which reads and writes to a file which is in use by another program (for example notepad or word).
Obviously I'm having trouble deleting it as I'm getting an access denied error because the file is in use.
My first idea was I should use CloseHandle (kernel32.dll) to close the handle to that file, but I have no clue how to find that handle in the first place.
Any ideas? I'm doing this in Rust, so if there are any language-specific suggestions that would be best but if not, that's more than fine too.
On another note, what would happen to the program after the handle has been closed? Would word or notepad still be able to edit it or would a subsequent save delete the changes made by my program or perhaps it wouldn't even save?
This behaviour you observe is not related to Rust or to any other programming language, since this is system-specific.
The CreateFileA() win32 call offers, thanks to its third parameter (dwShareMode), a means to explicitly specify how sharing could happen with the open file.
Unfortunately (for you) this call is performed beforehand by the other program you try to hijack, not yours; your program cannot do anything, it's too late once the file is open.
Not that on UNIX the situation is different because the path to the file in the file-system is just a reference to the content of this file, as an open() operation is.
Thus, if you remove (rm) the file indicated by this path, you just remove the reference (unlink()) but not its actual content if it is still referenced by an open file descriptor.
The actual deletion of the file content only happens when no reference to it exists anymore.
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.
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.
Most of the vendors that FTP files to us we have the vendor place a file on our FTP server as one extension and after the PUT is complete rename the file to *.FTP. This signals to our process that the file is completely downloaded and our custom process will pick up the file and automatically process it with defined scripts.
I have this new vendor who state that they are not writing the FTP script and cannot tell their system to rename the file after the PUT takes place. So my question, is there a way with a .bat file to check to see if end of file exists?
The reason for doing this is that there's a potential that our custom process may pick up the file and process it before it's fully loaded on the ftp server.
Any thoughts?
Wait until the file's last modified time is at least ten minutes in the past. Alternatively, wait until the file's size hasn't changed for five minutes.
might be a bit of a hacky solution, but could you get the size of the file, then check again after a wait period, if it changes don't process. Update initial value?
I want to call a copyFile function from within the source file to be copied. The VBA FileCopy function does not allow the source file to be open while it is copied. I am thinking of using CopyFile or CopyFileEx (to show a progress bar) instead.
Therefore, do those functions work if the source file is open?
Yes, CopyFileEx() has the COPY_FILE_OPEN_SOURCE_FOR_WRITE option, allowing you to copy a file that was opened for writing. You'd still need cooperation from the owner of the file, it would have had to open the file allowing read sharing.
Beware of the trouble you can get into with this option, you'll essentially get a random snapshot of the file, you could copy the file while the app was in the middle of writing to the file. Such a copy isn't usually readable anymore. You'd be lucky if the app trying to read such a copy crashes and dies. But the more likely outcome is subtly corrupt data.
Yes, Win32 CopyFile and CopyFileEx (and CopyFile2) all will open a file that is already open by someone else, as long as the other party has specified FILE_SHARE_READ.
Specifically, my latest tries (on Windows 10 1809) show that these function will try to open the file
1st, with GENERIC_READ + FILE_SHARE_READ - thus blocking any later writers.
2nd, transparently(!), fall back to GENERIC_READ + FILE_SHARE_READ & FILE_SHARE_WRITE if someone else has the file already open for write access, thereby even copying a file that is written by someone else.