Using Directory.Delete() and Directory.CreateDirectory() to overwrite a folder

Many filesystem operations are not synchonous on some filesystems (in case of windows - NTFS). Take for example RemoveDirectory call (which is called by Directory.DeleteDirectory at some point):

The RemoveDirectory function marks a directory for deletion on close. Therefore, the directory is not removed until the last handle to the directory is closed.

As you see, it will not really delete directory until all handles to it are closed, but Directory.DeleteDirectory will complete fine. In your case that is also most likely such concurrency problem - directory is not really created while you executing Directory.Exists.

So, just periodically check what you need and don't consider filesystem calls in .NET to be synchronous. You can also use FileSystemWatcher in some cases to avoid polling.

EDIT: I was thinking how to reproduce it, and here is the code:

internal class Program {
    private static void Main(string[] args) {
        const string path = "G:\\test_dir";
        while (true) {         
            if (Directory.Exists(path))
                Directory.Delete(path);       
            Directory.CreateDirectory(path);   
            if (!Directory.Exists(path))
                throw new Exception("Confirmed");                 
        }            
    }        
}

You see that if all filesystem calls were synchronous (in .NET), this code should run without problem. Now, before running that code, create empty directory at specified path (preferrably don't use SSD for that) and open it with windows explorer. Now run the code. For me it either throws Confirmed (which exactly reproduces your issue) or throws on Directory.Delete saying that directory does not exist (almost the same case). It does it 100% of the time for me.

Here is another code which when running on my machine confirms that it's certainly possible for File.Exists to return true directly after File.Delete call:

internal class Program {
    private static void Main(string[] args) {
        while (true) {
            const string path = @"G:\test_dir\test.txt";
            if (File.Exists(path))
                File.Delete(path);
            if (File.Exists(path))
                throw new Exception("Confirmed");
            File.Create(path).Dispose();
        }
    }        
 }

exception

To do this, I opened G:\test_dir folder and during execution of this code tried to open constantly appearing and disappearing test.txt file. After couple of tries, Confirmed exception was thrown (while I didn't create or delete that file, and after exception is thrown, it's not present on filesystem already). So race conditions are possible in multiple cases and my answer is correct one.


I wrote myself a little C# method for synchronous folder deletion using Directory.Delete(). Feel free to copy:

private bool DeleteDirectorySync(string directory, int timeoutInMilliseconds = 5000)
{
    if (!Directory.Exists(directory))
    {
        return true;
    }

    var watcher = new FileSystemWatcher
    {
        Path = Path.Combine(directory, ".."),
        NotifyFilter = NotifyFilters.DirectoryName,
        Filter = directory,
    };
    var task = Task.Run(() => watcher.WaitForChanged(WatcherChangeTypes.Deleted, timeoutInMilliseconds));

    // we must not start deleting before the watcher is running
    while (task.Status != TaskStatus.Running)
    {
        Thread.Sleep(100);
    }

    try
    {
        Directory.Delete(directory, true);
    }
    catch
    {
        return false;
    }

    return !task.Result.TimedOut;
}

Note that getting task.Result will block the thread until the task is finished, keeping the CPU load of this thread idle. So that is the point where it gets synchronous.