Merge "Handle readonly directories in tmpdir"
diff --git a/ui/build/util.go b/ui/build/util.go
index f698ccd..96088fe 100644
--- a/ui/build/util.go
+++ b/ui/build/util.go
@@ -62,9 +62,24 @@
 func ensureEmptyDirectoriesExist(ctx Context, dirs ...string) {
 	// remove all the directories
 	for _, dir := range dirs {
-		err := os.RemoveAll(dir)
-		if err != nil {
-			ctx.Fatalf("Error removing %s: %q\n", dir, err)
+		seenErr := map[string]bool{}
+		for {
+			err := os.RemoveAll(dir)
+			if err == nil {
+				break
+			}
+
+			if pathErr, ok := err.(*os.PathError); !ok ||
+				dir == pathErr.Path || seenErr[pathErr.Path] {
+
+				ctx.Fatalf("Error removing %s: %q\n", dir, err)
+			} else {
+				seenErr[pathErr.Path] = true
+				err = os.Chmod(filepath.Dir(pathErr.Path), 0700)
+				if err != nil {
+					ctx.Fatal(err)
+				}
+			}
 		}
 	}
 	// recreate all the directories
diff --git a/ui/build/util_test.go b/ui/build/util_test.go
index e85eada..0e0dbdf 100644
--- a/ui/build/util_test.go
+++ b/ui/build/util_test.go
@@ -14,7 +14,41 @@
 
 package build
 
-import "testing"
+import (
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"testing"
+
+	"android/soong/ui/logger"
+)
+
+func TestEnsureEmptyDirs(t *testing.T) {
+	ctx := testContext()
+	defer logger.Recover(func(err error) {
+		t.Error(err)
+	})
+
+	tmpDir, err := ioutil.TempDir("", "")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer func() {
+		err := os.RemoveAll(tmpDir)
+		if err != nil {
+			t.Errorf("Error removing tmpDir: %v", err)
+		}
+	}()
+
+	ensureEmptyDirectoriesExist(ctx, filepath.Join(tmpDir, "a/b"))
+
+	err = os.Chmod(filepath.Join(tmpDir, "a"), 0555)
+	if err != nil {
+		t.Fatalf("Failed to chown: %v", err)
+	}
+
+	ensureEmptyDirectoriesExist(ctx, filepath.Join(tmpDir, "a"))
+}
 
 func TestStripAnsiEscapes(t *testing.T) {
 	testcases := []struct {