views:

95

answers:

4

I am opening a file with read access and allowing subsequent read|write|delete file share access to the file (tailing the file). If the file is deleted during processing is there a way to detect that the file is pending delete (see Files section http://msdn.microsoft.com/en-us/library/aa363858(v=VS.85).aspx)? If some outside process (the owning process) has issued a delete, I want to close my handle as soon as possible to allow the file deletion so as not to interfere with any logic in the owning process.

I'm in c# and see no method of detecting the pending delete. The file was opened using a FileStream object. Is there some method for detecting the delete in c# or in some other windows function?

A: 

FileSystemWatcher would probably be the closest thing, but it can't detect a "pending" delete; when the file IS deleted, an event will be raised on FileSystemWatcher, and you can attach a handler that will gracefully interrupt your file processing. If the lock (or lack of one) you acquire in opening the file makes it possible for the file to be deleted at all, simply closing your read-only FileStream when that happens should not affect the file system.

The basic steps of a file watcher are to create one, passing an instance of a FileInfo object to the constructor. FileInfos can be created inexpensively by just instantiating one, passing it the path and filename of the file as a string. Then, set its NotifyFilter to the type(s) of file system modifications you want to watch for on this file. Finally, attach your process's event handler to the OnDeleted event. This event handler can probably be as simple as setting a bit flag somewhere that your main process can read, and closing the FileStream. You'll then get an exception on your next attempt to work with the stream; catch it, read the flag, and if it's set just gracefully stop doing file stuff. You can also put the file processing in a seperate worker thread, and the event handler can just tell the thread to die in some graceful method.

KeithS
The problem is that I have an open handle to the file which will prevent the delete from completing -- it's pending. I need to detect the delete so I can close my handle so the delete completes.
Mitch
That's not possible afaik. The Delete will fail - what you are really asking for is a way to detect a desire to delete in another process. It's not practical to implement a means in the OS to notify all current file users that some other process is trying to delete a file that's in use, pending the delete until other users decide to close down their usage (what if they refuse?). What if the deleting process then changes its mind or exits for some reason? Interactions are too horrible to contemplate.
Steve Townsend
Are you saying the owning process's request to delete the file will fail? If so, that is incorrect. The delete succeeds and the file is pending delete until all handles are closed. Once there are no more handles open to the file it is deleted. During the pending delete, subsequent requests to access the file receive an access denied exception. See: http://msdn.microsoft.com/en-us/library/aa363915(v=VS.85).aspx or http://msdn.microsoft.com/en-us/library/aa363858(v=VS.85).aspx.
Mitch
A: 

I would use a different signaling mechanism. (I am making the assumption all file access is within your control and not from a closed external program, mainly due to the flags being employed.)

The only "solution" within those bounds I can think of is a poll on file-access and check the exception (if any) you get back. Perhaps there is something much more tricky (at a lower-level than the win32 file API?!?), but this is already going down the "uhg path" :-)

pst
I am accepting this as the answer as this is all I was able to do. Having an open handle to the file, everytime I need to go back and read from the handle I also try to open the file again. If I get back a UnauthorizedAccessException (see msdn) then I ASSUME the file has been deleted and close my handle. I'm sure this is expensive, but there was nothing else I could come up with.
Mitch
A: 

If the file is small enough, your application could process a copy of the file, rather than the file itself. Also, if your application needs to know whether the owning process deleted the original file, set up a FileSystemWatcher (FSW) on the file. When the file disappears, the FSW could set a flag to interrupt processing:

private bool _fileExists = true;

public void Process(string pathToOriginalFile, string pathToCopy)
{
    File.Copy(pathToOriginalFile, pathToCopy);

    FileSystemWatcher watcher = new FileSystemWatcher();
    watcher.Path = pathToOriginalFile;
    watcher.Deleted += new FileSystemEventHandler(OnFileDeleted);

    bool doneProcessing = false;
    watcher.EnableRaisingEvents = true;

    while(_fileExists && !doneProcessing)
    {
        // process the copy here
    }

    ...
}

private void OnFileDeleted(object source, FileSystemEventArgs e)
{
    _fileExists = false;
}
Again, the FileSystemWatcher won't work because the file doesn't get deleted until all handles to the file are closed. As I have a handle to the file it is pending delete until I close my handle.
Mitch
You'll release the handle to the original file after you've made a copy of the file. And if I'm not mistaken, the FSW will have a handle to the _directory_ in which the file resides, not a handle to the file.
You're right, I should of read your answer a little closer. These files could potentially be any size though and processing a copy would not be feasible in all cases.
Mitch
A: 

No, there's no clean way to do this. If you were concerned about other processes opening and/or modifying the file, then oplocks could help you. But if you're just looking for notification of when the delete disposition gets set to deleted, there isn't a straightforward way to do this (sans building a file system filter, hooking the APIs, etc. all of which spooky for an application do be doing w/o very good reason).

jrtipton