public void DeleteDirectoryContents()
        {
            string rootDir = GetFullPath("Directory");

            Directory.CreateDirectory(rootDir);
            Directory.CreateDirectory(Path.Combine(rootDir, "subdir1"));
            Directory.CreateDirectory(Path.Combine(rootDir, "subdir2"));

            // Create a readonly file
            string nestedFile = Path.Combine(rootDir, "subdir1", "File.txt");

            File.WriteAllText(nestedFile, "asdf");
            File.SetAttributes(nestedFile, FileAttributes.ReadOnly);

            // And a normal file
            File.WriteAllText(Path.Combine(rootDir, "File.txt"), "asdf");

            string exeLink = Path.Combine(rootDir, "hardlink");

            XAssert.IsTrue(CreateHardLinkIfSupported(link: exeLink, linkTarget: DummyWaiter.GetDummyWaiterExeLocation()));

            // Add a hardlink
            using (var waiter = DummyWaiter.RunAndWait())
            {
                FileUtilities.DeleteDirectoryContents(rootDir);
            }

            XAssert.AreEqual(0, Directory.GetFileSystemEntries(rootDir).Length);
        }
        public void TrivialDeleteFailsForLinkToRunningExecutable()
        {
            string exeLink = GetFullPath("DummyWaiterLink");

            XAssert.IsTrue(CreateHardLinkIfSupported(link: exeLink, linkTarget: DummyWaiter.GetDummyWaiterExeLocation()));

            using (var waiter = DummyWaiter.RunAndWait())
            {
                try
                {
                    File.Delete(exeLink);
                    XAssert.Fail("Expected deletion to fail due to the executable being loaded and running.");
                }
                catch (UnauthorizedAccessException)
                {
                    // expected.
                }
                catch (IOException)
                {
                    // expected.
                }
            }

            // Should succeed when the executable is no longer running.
            File.Delete(exeLink);
        }
        public void CanDeleteRunningExecutableLink()
        {
            string exeLink = GetFullPath("DummyWaiterLink");

            XAssert.IsTrue(CreateHardLinkIfSupported(link: exeLink, linkTarget: DummyWaiter.GetDummyWaiterExeLocation()));

            using (var waiter = DummyWaiter.RunAndWait())
            {
                XAssert.IsTrue(File.Exists(exeLink));
                FileUtilities.DeleteFile(exeLink);
                XAssert.IsFalse(File.Exists(exeLink));
            }
        }
        public void CreateReplacementFileCanReplaceRunningExecutableLink()
        {
            string exeLink = GetFullPath("DummyWaiterLink");

            XAssert.IsTrue(CreateHardLinkIfSupported(link: exeLink, linkTarget: DummyWaiter.GetDummyWaiterExeLocation()));

            using (var waiter = DummyWaiter.RunAndWait())
            {
                using (FileStream fs = FileUtilities.CreateReplacementFile(exeLink, FileShare.Delete))
                {
                    XAssert.AreEqual(0, fs.Length);
                }
            }
        }
        public void MoveTempDeletionCanReplaceRunningExecutable()
        {
            // Make a copy of DummyWaiter.exe to use as the test subject for deleting a running executable.
            // Keep the copy in the same directory as the original since it will need runtime dlls
            string dummyWaiterLocation = DummyWaiter.GetDummyWaiterExeLocation();
            string exeCopy             = dummyWaiterLocation + ".copy.exe";

            File.Copy(dummyWaiterLocation, exeCopy);

            using (var waiter = DummyWaiter.RunAndWait(exeCopy))
            {
                BuildXLException caughtException = null;
                try
                {
                    FileUtilities.DeleteFile(exeCopy);
                }
                catch (BuildXLException ex)
                {
                    caughtException = ex;
                }

                XAssert.IsNotNull(caughtException, "Expected deletion without a tempCleaner to fail");
                XAssert.IsTrue(File.Exists(exeCopy));

                caughtException = null;


                try
                {
                    FileUtilities.DeleteFile(exeCopy, tempDirectoryCleaner: MoveDeleteCleaner);
                }
                catch (BuildXLException ex)
                {
                    caughtException = ex;
                }

                XAssert.IsNull(caughtException, "Expected deletion with a MoveDeleteCleaner to succeed");
                XAssert.IsFalse(File.Exists(exeCopy));
            }
        }
        public void DeleteDirectoryContentsLongPath()
        {
            string originalRoot = GetFullPath("testRoot");

            // Create a directory with a path that's too long to normally delete
            StringBuilder sb = new StringBuilder();

            for (int i = 0; i < 100; i++)
            {
                sb.Append("a");
            }

            string rootDir = @"\\?\" + originalRoot;

            XAssert.IsTrue(CreateDirectoryW(rootDir, IntPtr.Zero));
            rootDir = rootDir + "\\" + sb.ToString();
            XAssert.IsTrue(CreateDirectoryW(rootDir, IntPtr.Zero));
            rootDir = rootDir + "\\" + sb.ToString();
            XAssert.IsTrue(CreateDirectoryW(rootDir, IntPtr.Zero));

            // Write some files in the directory. Set their attributes as readonly to exercise the related logic in DeleteFile
            string shorterPath = Path.Combine(originalRoot, "myFile.txt");

            File.WriteAllText(shorterPath, "foo");
            File.SetAttributes(shorterPath, FileAttributes.ReadOnly);

            // And a file with a filename longer than maxpath
            string         longerPath = rootDir + @"\myFile.txt";
            SafeFileHandle fileHandle;
            var            result = FileUtilities.TryCreateOrOpenFile(
                longerPath,
                FileDesiredAccess.GenericWrite,
                FileShare.Delete,
                FileMode.Create,
                FileFlagsAndAttributes.FileAttributeNormal,
                out fileHandle);

            XAssert.IsTrue(result.Succeeded);
            using (FileStream stream = new FileStream(fileHandle, FileAccess.Write))
            {
                stream.WriteByte(255);
            }

            FileUtilities.SetFileAttributes(longerPath, FileAttributes.ReadOnly);

            string exeLink = Path.Combine(rootDir, "hardlink");

            XAssert.IsTrue(CreateHardLinkIfSupported(link: exeLink, linkTarget: DummyWaiter.GetDummyWaiterExeLocation()));

            // Add a hardlink. Perform deletion attempts while the hardlink target is in use
            using (var waiter = DummyWaiter.RunAndWait())
            {
                // Attempt to delete with the managed API. This should fail because it contains nested paths that are too long
                bool isPathTooLong = false;
                try
                {
                    Directory.Delete(rootDir, recursive: true);
                }
                catch (PathTooLongException)
                {
                    isPathTooLong = true;
                }

                XAssert.IsTrue(isPathTooLong, "Expected to encounter a PathTooLongException. If no exception is thrown by the System.IO method, this test isn't validating anything");

                // Now use the native API. This should succeed
                FileUtilities.DeleteDirectoryContents(originalRoot);
            }

            XAssert.IsTrue(Directory.Exists(originalRoot));
            XAssert.AreEqual(0, Directory.GetFileSystemEntries(originalRoot).Length);
        }