FileSystemHelpers.ps1

using System;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.AccessControl;
using System.Security.Principal;
using System.Text.RegularExpressions;

namespace GenXdev.Helpers
{
    public static class FileSystemHelpers
    {
        [Flags]
        internal enum MoveFileFlags
        {
            None = 0,
            ReplaceExisting = 1,
            CopyAllowed = 2,
            DelayUntilReboot = 4,
            WriteThrough = 8,
            CreateHardlink = 16,
            FailIfNotTrackable = 32,
        }

        internal static class NativeMethods
        {
            [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
            public static extern bool MoveFileEx(
                string lpExistingFileName,
                string lpNewFileName,
                MoveFileFlags dwFlags);
        }

        public static bool FileNameFitsMask(string filename, string filemask)
        {
            filename = Path.GetFileName(filename);
            try
            {
                Regex mask = new Regex(filemask.Replace(".", "[.]").Replace("*", ".*").Replace("?", "."));

                return mask.IsMatch(filename);
            }
            catch
            {
                return false;
            }
        }

        public static bool ForciblyMoveFile(ref string sourceFilePath, string targetFilePath, bool deleteDirIfEmpty)
        {
            if (ForciblyMoveFile(sourceFilePath, targetFilePath, deleteDirIfEmpty))
            {
                sourceFilePath = targetFilePath;
                return true;
            }

            return false;
        }

        public static bool ForciblyMoveFile(string sourceFilePath, string targetFilePath, bool deleteDirIfEmpty)
        {
            ForciblyPrepareTargetFilePath(targetFilePath);

            try
            {
                try
                {
                    File.Move(sourceFilePath, targetFilePath);
                    return true;
                }
                catch
                {
                    TakeOwnership(sourceFilePath);
                }

                ForciblyPrepareTargetFilePath(targetFilePath);
                File.Move(sourceFilePath, targetFilePath);

                return true;
            }
            catch
            {
                return false;
            }
            finally
            {
                if (deleteDirIfEmpty)
                {
                    DeleteDirectoryIfEmpty(sourceFilePath);
                }
            }
        }

        public static void ForciblyPrepareTargetFilePath(string targetFilePath, bool deleteIfExists = true)
        {
            // create directory?
            ForciblyPrepareTargetDirectory(Path.GetDirectoryName(targetFilePath));

            // delete?
            if (deleteIfExists && File.Exists(targetFilePath))
            {
                try
                {
                    ForciblyDeleteFile(targetFilePath, false);
                }
                catch { }
            }
        }

        public static void ForciblyPrepareTargetDirectory(string targetDirectory)
        {
            if (String.IsNullOrWhiteSpace(targetDirectory))
                return;
            if (!Directory.Exists(targetDirectory))
            {
                try
                {
                    Directory.CreateDirectory(targetDirectory);
                }
                catch { }
            }
            else
            {
                TakeOwnership(targetDirectory);
            }
        }

        public static string GetTempFileName(string directory = null)
        {
            if (String.IsNullOrWhiteSpace(directory))
            {
                directory = Path.GetTempPath();
            }

            var result = Path.Combine(directory, "." + Path.GetRandomFileName() + ".tmp");

            ForciblyPrepareTargetFilePath(result);

            return result;
        }

        public static FileStream GetTempFileStream(FileOptions fileOptions = FileOptions.None, string directory = null)
        {
            var filePath = GetTempFileName(directory);
            var fileInfo = new FileInfo(filePath);
            var stream =
                new FileStream(
                    filePath,
                    FileMode.Create,
                    FileAccess.Write,
                    FileShare.None,
                    4096,
                    fileOptions
                );

            if ((fileOptions & (FileOptions.DeleteOnClose | FileOptions.RandomAccess)) == (FileOptions.DeleteOnClose | FileOptions.RandomAccess))
            {
                // Set the Attribute property of this file to Temporary. 
                // Although this is not completely necessary, the .NET Framework is able 
                // to optimize the use of Temporary files by keeping them cached in memory.
                fileInfo.Attributes = FileAttributes.Temporary;
            }

            return stream;
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", MessageId = "0"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass"), DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
        static extern bool GetDiskFreeSpaceEx(string lpDirectoryName,
       out ulong lpFreeBytesAvailable,
       out ulong lpTotalNumberOfBytes,
       out ulong lpTotalNumberOfFreeBytes);

        public static bool DriveFreeBytes(string folderName, out ulong freespace)
        {
            freespace = 0;
            if (string.IsNullOrEmpty(folderName))
            {
                throw new ArgumentNullException("folderName");
            }

            if (!folderName.EndsWith("\\"))
            {
                folderName += '\\';
            }

            ulong free = 0, dummy1 = 0, dummy2 = 0;

            if (GetDiskFreeSpaceEx(folderName, out free, out dummy1, out dummy2))
            {
                freespace = free;
                return true;
            }
            else
            {
                return false;
            }
        }

        public static void ForciblyDeleteAllEmptySubDirectories(string rootDirectory)
        {
            try
            {
                if (Directory.Exists(rootDirectory))
                    foreach (var directory in Directory.GetDirectories(rootDirectory, "*", SearchOption.TopDirectoryOnly))
                    {
                        ForciblyDeleteAllEmptySubDirectories(directory);

                        try
                        {
                            Directory.Delete(directory, false);
                        }
                        catch
                        {
                            // not empty
                        }
                    }
            }
            catch
            {
                // ignore
            }
        }

        public static bool TakeOwnership(string filepath)
        {
            try
            {
                //Get Currently Applied Access Control
                FileSecurity fileS = File.GetAccessControl(filepath);

                //Update it, Grant Current User Full Control
                SecurityIdentifier cu = WindowsIdentity.GetCurrent().User;
                try
                {
                    fileS.SetOwner(cu);
                }
                catch { }
                try
                {
                    fileS.SetAccessRule(new FileSystemAccessRule(cu, FileSystemRights.FullControl, AccessControlType.Allow));
                }
                catch { }

                //Update the Access Control on the File
                File.SetAccessControl(filepath, fileS);

                return true;
            }
            catch { }

            return false;
        }

        public static bool ForciblyDeleteFile(string filepath, bool DeleteDirIfEmpty)
        {
            if (!File.Exists(filepath))
                return true;

            try
            {
                try
                {
                    File.Delete(filepath);

                    return true;
                }
                catch
                {
                    TakeOwnership(filepath);
                }

                try
                {
                    File.Delete(filepath);

                    return true;
                }
                catch
                {
                }

                try
                {
                    Microsoft.VisualBasic.FileIO.FileSystem.DeleteFile(
                        filepath,
                        0,
                        Microsoft.VisualBasic.FileIO.RecycleOption.SendToRecycleBin,
                        Microsoft.VisualBasic.FileIO.UICancelOption.ThrowException
                        );

                    if (!File.Exists(filepath))
                        return true;
                }
                catch
                {
                }

                try
                {
                    if (filepath.ToLowerInvariant().EndsWith(".deleted_-"))
                    {
                        var parts = filepath.Split('.').ToList<string>();

                        parts.RemoveAt(parts.Count - 1);
                        parts.RemoveAt(parts.Count - 1);

                        filepath = string.Join(".", parts.ToArray<string>());
                    }

                    var destination = filepath + "." +
                        Guid.NewGuid().ToString().Replace("-", "").ToLowerInvariant() +
                        ".deleted_-";

                    if (ForciblyMoveFile(filepath, destination, false))
                    {
                        NativeMethods.MoveFileEx(destination, null, MoveFileFlags.DelayUntilReboot);
                    }

                    if (!File.Exists(filepath))
                        return true;
                }
                catch
                {
                }

                return !File.Exists(filepath);
            }
            catch
            {
                return !File.Exists(filepath);
            }
            finally
            {
                if (DeleteDirIfEmpty)
                {
                    var dir = Path.GetDirectoryName(filepath);

                    ForciblyDeleteDirIfEmpty(dir);
                }
            }
        }

        public static void ForciblyDeleteDirIfEmpty(string dir)
        {
            ForciblyDeleteAllEmptySubDirectories(dir);

            DeleteDirectoryIfEmpty(dir);
        }

        public static void DeleteDirectoryIfEmpty(string path)
        {
            try
            {
                if (File.Exists(path))
                {
                    path = Path.GetDirectoryName(path);
                }

                if (Directory.Exists(path))
                {
                    Directory.Delete(path);
                }
            }
            catch { }
        }


        public static bool FileIsInUse(string fullPath)
        {
            if (!File.Exists(fullPath))
                return false;

            if (Directory.Exists(fullPath))
                return false;

            try
            {
                (new FileStream(fullPath, FileMode.Open, FileAccess.ReadWrite, FileShare.None)).Close();

                return false;
            }
            catch
            {
                return true;
            }
        }

        public static bool FileNameFitsMasks(string filename, string[] filemasks)
        {
            foreach (var mask in filemasks)
                if (FileNameFitsMask(filename, mask))
                    return true;

            return false;
        }

        public static bool ForciblyDeleteDirectory(string path)
        {
            if (!Directory.Exists(path))
                return true;

            try
            {
                try
                {
                    Directory.Delete(path, true);
                }
                catch
                {
                    TakeOwnership(path);
                }

                Directory.Delete(path, true);

                return true;
            }
            catch
            {
                return false;
            }
        }
    }
}