1

I have two folder in a remote FileShare and I am trying to move the first one inside the second. To do this, I wrote a CLR that pretty much does the following:

if (Directory.Exists(destinationFolder))
{
    Directory.Delete(destinationFolder, true);
}

if (Directory.Exists(sourceFolder))
{
    Directory.Move(sourceFolder, destinationFolder);
}

This works as expected but there are some cases that am getting the following error:

System.IO.IOException: Cannot create a file when that file already exists. System.IO.IOException: at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) at System.IO.Directory.InternalMove(String sourceDirName, String destDirName, Boolean checkHost)

I was not able to narrow it down. It seems random to me since I can not reproduced it. I run this code block, over 50 times and I could not get the same error (or any error to tell the truth) as before. - Do you see anything wrong with code? - Do you have any "guesses" on what may caused this error?

The only thing I can think, is even though the Directory.Delete(destinationFolder, true); return the system does not delete the directory immediately and thus when Directory.Move(sourceFolder, destinationFolder); runs, the destinationFolder still exists.

(29/12/2016) This is not a duplicate of Cannot create a file when that file already exists when using Directory.Move. There, the user has a 'mistake' in her code and creates (Directory.CreateDirectory(destinationdirectory);) the destination folder. I am not creating the destination folder, nevertheless, I am deleting it if exists. I looked the comments and the answers but none of them gave a solution to my issue.

(30/12/2016) I have tried all the suggestions from the comments and answer but still nothing strange happens. No errors and no unexpected behaviors.

Community
  • 1
  • 1
Athafoud
  • 2,898
  • 3
  • 40
  • 58
  • Possible duplicate of [Cannot create a file when that file already exists when using Directory.Move](http://stackoverflow.com/questions/12667770/cannot-create-a-file-when-that-file-already-exists-when-using-directory-move) – Nino Dec 28 '16 at 12:32
  • @Nino, In the linked post, the user has a 'mistake' in her code and creates (`Directory.CreateDirectory(destinationdirectory);`) the destination folder. I do not creating the destination folder, nevertheless, I am deleting it if exists. – Athafoud Dec 28 '16 at 12:35
  • it's the same exception. "Cannot create a file when that file already exists.". put your code in try catch block and debug it. When it falls into catch block, examine sourceFolder and destinationFolder variables. – Nino Dec 28 '16 at 12:37
  • @Nino, I have already tried this, as I say I was NOT able to reproduce this. By the time I am hitting an breakpoint the folder is already deleted and the code execution continues without an error. – Athafoud Dec 28 '16 at 12:41
  • you misunderstand me, put breakpoint in your catch block, when the exception already happened. This is too little code for me to write you an answer, I'm just trying to help you with suggestions. – Nino Dec 28 '16 at 12:45
  • also, try to add a little pause, like `System.Threading.Thread.Sleep(1000);` before `if (Directory.Exists(sourceFolder))` to suspent your applications thread for a second before continuing with move operation – Nino Dec 28 '16 at 12:49
  • @Nino, I tries this and I also tried to put while loop in the middle of the two `if`, to continuously check and sleep if the folder exists. I run my code almost 20 times, but not once the execution went through while. Meaning that the folder was deleted when exiting the first if. Your thread.sleep will solve any issues where the delete returns before the system deletes the folder. Also to answer you previous comment, I had the error only once and I cannot reproduce it, I have put try/catch in every possible location, but without an error thise do not help. – Athafoud Dec 28 '16 at 13:05
  • @Athafoud did you ever find a working solution for this? I'm getting the exact same behavior. – mxmissile Feb 15 '18 at 16:47
  • @mxmissile After a lot of tries I was not able to replicate the error. The code from that until now is accessed almost daily, but no issue occurred. Are you using the exact same simple code block as the one I described? Are you always getting this error? Have you tried the suggestion of Solomon Rutzky? – Athafoud Feb 15 '18 at 20:53
  • Not always, code runs about 200 to 300 times a day, but Exception only occurs once or twice a week randomly. – mxmissile Feb 16 '18 at 18:16
  • The only solution I can think is a 'dirty' one. You can retry several time (e.g 5) to delete / move, waiting let's say 1sec among re-tries. I this works, you then need to find what is 'locking' your folder. – Athafoud Feb 19 '18 at 18:57

2 Answers2

2

The only thing I can think [of] is even though the Directory.Delete(destinationFolder, true); return the system does not delete the directory immediately and thus when Directory.Move(sourceFolder, destinationFolder); runs, the destinationFolder still exists.

I would highly doubt that this is the cause of any issue. I suppose it is not impossible, especially since this is a folder on another system (remote file share) and not local, but I would still expect any write-behind caching being done on the remote system to be completely transparent to any file system requests, not just some of them.

I think it is more likely, given the code shown in the question, that somehow you initiated two threads at nearly the exact same time and hit a race condition wherein both threads were attempting to process the move operation at the same time. You can both detect such a condition and avoid any errors by making the following changes to your code:

string _LogFile = String.Concat(@"C:\TEMP\SQLCLR_", Guid.NewGuid(), ".log");

File.AppendAllText(_LogFile, @"Starting operation for: " + sourceFolder +
                              @" --> " + destinationFolder);

if (Directory.Exists(destinationFolder))
{
    File.AppendAllText(_LogFile, @"Deleting: " + destinationFolder);
    Directory.Delete(destinationFolder, true);
}

if (Directory.Exists(sourceFolder))
{
    if (!Directory.Exists(destinationFolder))
    {
        File.AppendAllText(_LogFile, @"Moving: " + sourceFolder);
        Directory.Move(sourceFolder, destinationFolder);
    }
    else
    {
        File.AppendAllText(_LogFile, @"Oops. " + destinationFolder +
                                     @" already exists. How odd indeed!");
    }
}

This will log the operation to a text file. It will indicate exactly which steps are being taken. It will also check for the existence of the destination before calling "move", something which is not currently being checked.

If there are two competing threads, you will get 2 log files since they are named using a GUID.

If, somehow, it actually is a delayed delete issue on the remote OS, that would be indicated by a single log file containing a line for the "Deleting.." and then one for the "Moving...". OR, if the "exists" check sees the not-yet-deleted destination, then you will see a line for "Oops".

Solomon Rutzky
  • 46,688
  • 9
  • 128
  • 171
  • I tried you code but nothing strange happens. "Deleting" appears before "Moving", as expected and I have only one log file. – Athafoud Dec 31 '16 at 21:09
  • 1
    @Athafoud That's good, right? And you did say that you cannot reproduce the error, right? So I assume it will either not happen again because it was something else going on in that moment that was doesn't usually happen but was there due to some aspect of the testing or the code at that point in time, OR it might take a while to happen, but if / when it does, you will have evidence of it :-) – Solomon Rutzky Dec 31 '16 at 21:26
  • Indeed this is good. `something else going on in that moment`, may have to do with @NicoRiff answer. Using your code suggestion I am now double checking if `destinationFolder` exists and I am logging possible `Ooops` errors. I will extend this to also log some running process dump, to check the case that other processes are accessing the folder. – Athafoud Jan 03 '17 at 13:19
0

According to MSDN you´ll get that exception in the following cases:

  • An attempt was made to move a directory to a different volume.
  • destDirName already exists.
  • The sourceDirName and destDirName parameters refer to the same file or directory.
  • The directory or a file within it is being used by another process.

You´ll have to check with some of above cases, there will be the solution for sure.

https://msdn.microsoft.com/en-us/library/system.io.directory.move(v=vs.110).aspx

NicoRiff
  • 4,803
  • 3
  • 25
  • 54
  • Without being sure, I think there is a different message for "The directory or a file within it is being used by another process.". I have seen it somewhere but I can not find the source. Despite that, the only process (as I am aware of) that may have been accessing the folder is the Windows Explorer. However I tried to reproduce this and I did not get any error. The Explorer windows just refresh by it self when the folder were deleted / moved. – Athafoud Dec 28 '16 at 12:39
  • maybe an antivirus issue?. Look for it with process explorer http://superuser.com/questions/117902/find-out-which-process-is-locking-a-file-or-folder-in-windows – NicoRiff Dec 28 '16 at 12:42
  • Thank you, I will check this in depth. – Athafoud Dec 28 '16 at 12:44