Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 35 additions & 25 deletions src/Xamarin.Android.Build.Tasks/Tasks/RemoveDirFixed.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Runtime.InteropServices;
using Microsoft.Build.Framework;
using Xamarin.Android.Tools;
using Microsoft.Android.Build.Tasks;
Expand All @@ -38,6 +40,9 @@ public class RemoveDirFixed : AndroidTask
{
public override string TaskPrefix => "RDF";

const int ERROR_ACCESS_DENIED = -2147024891;
const int ERROR_SHARING_VIOLATION = -2147024864;

public override bool RunTask ()
{
var temporaryRemovedDirectories = new List<ITaskItem> (Directories.Length);
Expand All @@ -48,36 +53,41 @@ public override bool RunTask ()
Log.LogDebugMessage ($"Directory did not exist: {fullPath}");
continue;
}
int retryCount = 0;
int attempts = Files.GetFileWriteRetryAttempts ();
int delay = Files.GetFileWriteRetryDelay ();
try {
// try to do a normal "fast" delete of the directory.
Directory.Delete (fullPath, true);
temporaryRemovedDirectories.Add (directory);
} catch (UnauthorizedAccessException ex) {
// if that fails we probably have readonly files (or locked files)
// so try to make them writable and try again.
try {
Files.SetDirectoryWriteable (fullPath);
Directory.Delete (fullPath, true);
temporaryRemovedDirectories.Add (directory);
} catch (Exception inner) {
Log.LogUnhandledException (TaskPrefix, ex);
Log.LogUnhandledException (TaskPrefix, inner);
}
} catch (DirectoryNotFoundException ex) {
// This could be a file inside the directory over MAX_PATH.
// We can attempt using the \\?\ syntax.
if (OS.IsWindows) {
while (retryCount <= attempts) {
try {
fullPath = Files.ToLongPath (fullPath);
Log.LogDebugMessage ("Trying long path: " + fullPath);
// try to do a normal "fast" delete of the directory.
// only do the set writable on the second attempt
if (retryCount == 1)
Files.SetDirectoryWriteable (fullPath);
Directory.Delete (fullPath, true);
temporaryRemovedDirectories.Add (directory);
} catch (Exception inner) {
Log.LogUnhandledException (TaskPrefix, ex);
Log.LogUnhandledException (TaskPrefix, inner);
break;
} catch (Exception e) {
switch (e) {
case DirectoryNotFoundException:
if (OS.IsWindows) {
fullPath = Files.ToLongPath (fullPath);
Log.LogDebugMessage ("Trying long path: " + fullPath);
break;
}
throw;
case UnauthorizedAccessException:
case IOException:
int code = Marshal.GetHRForException(e);
if ((code != ERROR_ACCESS_DENIED && code != ERROR_SHARING_VIOLATION) || retryCount >= attempts) {
throw;
};
break;
default:
throw;
}
Thread.Sleep (delay);
retryCount++;
}
} else {
Log.LogUnhandledException (TaskPrefix, ex);
}
} catch (Exception ex) {
Log.LogUnhandledException (TaskPrefix, ex);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
using Xamarin.Android.Tasks;
using Xamarin.Android.Tools;
using Microsoft.Android.Build.Tasks;
using TPL = System.Threading.Tasks;
using System.Threading;

namespace Xamarin.Android.Build.Tests
{
Expand Down Expand Up @@ -83,5 +85,44 @@ public void LongPath ()
Assert.AreEqual (1, task.RemovedDirectories.Length, "Changes should have been made.");
DirectoryAssert.DoesNotExist (tempDirectory);
}

[Test, Category ("SmokeTests")]
public void DirectoryInUse ()
{
if (OS.IsMac) {
Assert.Ignore ("This is not an issue on macos.");
return;
}
var file = NewFile ();
var task = CreateTask ();
using (var f = File.OpenWrite (file)) {
Assert.IsFalse (task.Execute (), "task.Execute() should have failed.");
Assert.AreEqual (0, task.RemovedDirectories.Length, "Changes should not have been made.");
DirectoryAssert.Exists (tempDirectory);
}
}

[Test, Category ("SmokeTests")]
public async TPL.Task DirectoryInUseWithRetry ()
{
if (OS.IsMac) {
Assert.Ignore ("This is not an issue on macos.");
return;
}
var file = NewFile ();
var task = CreateTask ();
var ev = new ManualResetEvent (false);
var t = TPL.Task.Run (async () => {
using (var f = File.OpenWrite (file)) {
ev.Set ();
await TPL.Task.Delay (2500);
}
});
ev.WaitOne ();
Assert.IsTrue (task.Execute (), "task.Execute() should have succeeded.");
Assert.AreEqual (1, task.RemovedDirectories.Length, "Changes should have been made.");
DirectoryAssert.DoesNotExist (tempDirectory);
await t;
}
}
}
Loading