Ejemplo n.º 1
0
        internal static void DeleteDirectoryCore(FileSystemEntryInfo fileSystemEntryInfo, KernelTransaction transaction, string path, bool recursive, bool ignoreReadOnly, bool requireEmpty, bool continueOnNotExist, PathFormat pathFormat)
        {
            #region Setup

            if (pathFormat == PathFormat.RelativePath)
            {
                Path.CheckSupportedPathFormat(path, true, true);
            }

            if (fileSystemEntryInfo == null)
            {
                // MSDN: .NET 3.5+: DirectoryNotFoundException:
                // Path does not exist or could not be found.
                // Path refers to a file instead of a directory.
                // The specified path is invalid (for example, it is on an unmapped drive).

                fileSystemEntryInfo = File.GetFileSystemEntryInfoCore(true, transaction,
                                                                      Path.GetExtendedLengthPathCore(transaction, path, pathFormat, GetFullPathOptions.TrimEnd | GetFullPathOptions.RemoveTrailingDirectorySeparator),
                                                                      continueOnNotExist, pathFormat);
            }

            if (fileSystemEntryInfo == null)
            {
                return;
            }

            string pathLp = fileSystemEntryInfo.LongFullPath;

            #endregion // Setup

            // Do not follow mount points nor symbolic links, but do delete the reparse point itself.

            // If directory is reparse point, disable recursion.
            if (recursive && fileSystemEntryInfo.IsReparsePoint)
            {
                recursive = false;
            }


            // Check to see if this is a mount point, and unmount it.
            if (fileSystemEntryInfo.IsMountPoint)
            {
                int lastError = Volume.DeleteVolumeMountPointCore(pathLp, true);

                if (lastError != Win32Errors.ERROR_SUCCESS && lastError != Win32Errors.ERROR_PATH_NOT_FOUND)
                {
                    NativeError.ThrowException(lastError, pathLp);
                }

                // Now it is safe to delete the actual directory.
            }


            if (recursive)
            {
                // Enumerate all file system objects.
                foreach (var fsei in EnumerateFileSystemEntryInfosCore <FileSystemEntryInfo>(transaction, pathLp, Path.WildcardStarMatchAll, DirectoryEnumerationOptions.FilesAndFolders, PathFormat.LongFullPath))
                {
                    if (fsei.IsDirectory)
                    {
                        DeleteDirectoryCore(fsei, transaction, null, true, ignoreReadOnly, requireEmpty, true, PathFormat.LongFullPath);
                    }
                    else
                    {
                        File.DeleteFileCore(transaction, fsei.LongFullPath, ignoreReadOnly, PathFormat.LongFullPath);
                    }
                }
            }

            #region Remove

startRemoveDirectory:

            if (!(transaction == null || !NativeMethods.IsAtLeastWindowsVista

                  // RemoveDirectory() / RemoveDirectoryTransacted()
                  // In the ANSI version of this function, the name is limited to MAX_PATH characters.
                  // To extend this limit to 32,767 wide characters, call the Unicode version of the function and prepend "\\?\" to the path.
                  // 2014-09-09: MSDN confirms LongPath usage.

                  // RemoveDirectory on a symbolic link will remove the link itself.

            ? NativeMethods.RemoveDirectory(pathLp)
            : NativeMethods.RemoveDirectoryTransacted(pathLp, transaction.SafeHandle)))
            {
                int lastError = Marshal.GetLastWin32Error();
                switch ((uint)lastError)
                {
                case Win32Errors.ERROR_DIR_NOT_EMPTY:
                    if (requireEmpty)
                    {
                        // MSDN: .NET 3.5+: IOException: The directory specified by path is not an empty directory.
                        throw new DirectoryNotEmptyException(pathLp);
                    }

                    goto startRemoveDirectory;


                case Win32Errors.ERROR_DIRECTORY:
                    // MSDN: .NET 3.5+: DirectoryNotFoundException: Path refers to a file instead of a directory.
                    if (File.ExistsCore(false, transaction, pathLp, PathFormat.LongFullPath))
                    {
                        throw new DirectoryNotFoundException(string.Format(CultureInfo.CurrentCulture, "({0}) {1}", Win32Errors.ERROR_INVALID_PARAMETER, string.Format(CultureInfo.CurrentCulture, Resources.Target_Directory_Is_A_File, pathLp)));
                    }
                    break;


                case Win32Errors.ERROR_PATH_NOT_FOUND:
                    if (continueOnNotExist)
                    {
                        return;
                    }
                    break;

                case Win32Errors.ERROR_SHARING_VIOLATION:
                    // MSDN: .NET 3.5+: IOException: The directory is being used by another process or there is an open handle on the directory.
                    NativeError.ThrowException(lastError, pathLp);
                    break;

                case Win32Errors.ERROR_ACCESS_DENIED:
                    var data            = new NativeMethods.WIN32_FILE_ATTRIBUTE_DATA();
                    int dataInitialised = File.FillAttributeInfoCore(transaction, pathLp, ref data, false, true);

                    if (data.dwFileAttributes != (FileAttributes)(-1))
                    {
                        if ((data.dwFileAttributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
                        {
                            // MSDN: .NET 3.5+: IOException: The directory specified by path is read-only.

                            if (ignoreReadOnly)
                            {
                                // Reset directory attributes.
                                File.SetAttributesCore(true, transaction, pathLp, FileAttributes.Normal, true, PathFormat.LongFullPath);
                                goto startRemoveDirectory;
                            }

                            // MSDN: .NET 3.5+: IOException: The directory is read-only.
                            throw new DirectoryReadOnlyException(pathLp);
                        }
                    }

                    if (dataInitialised == Win32Errors.ERROR_SUCCESS)
                    {
                        // MSDN: .NET 3.5+: UnauthorizedAccessException: The caller does not have the required permission.
                        NativeError.ThrowException(lastError, pathLp);
                    }

                    break;
                }

                // MSDN: .NET 3.5+: IOException:
                // A file with the same name and location specified by path exists.
                // The directory specified by path is read-only, or recursive is false and path is not an empty directory.
                // The directory is the application's current working directory.
                // The directory contains a read-only file.
                // The directory is being used by another process.

                NativeError.ThrowException(lastError, pathLp);
            }

            #endregion // Remove
        }
Ejemplo n.º 2
0
        internal static void DeleteDirectoryCore(FileSystemEntryInfo fsEntryInfo, KernelTransaction transaction, string path, bool recursive, bool ignoreReadOnly, bool continueOnNotFound, PathFormat pathFormat)
        {
            #region Setup

            if (fsEntryInfo == null)
            {
                // MSDN: .NET 3.5+: DirectoryNotFoundException:
                // Path does not exist or could not be found.
                // Path refers to a file instead of a directory.
                // The specified path is invalid (for example, it is on an unmapped drive).

                if (pathFormat == PathFormat.RelativePath)
                {
                    Path.CheckSupportedPathFormat(path, true, true);
                }

                fsEntryInfo = File.GetFileSystemEntryInfoCore(true, transaction, Path.GetExtendedLengthPathCore(transaction, path, pathFormat, GetFullPathOptions.TrimEnd | GetFullPathOptions.RemoveTrailingDirectorySeparator), continueOnNotFound, pathFormat);

                if (fsEntryInfo == null)
                {
                    return;
                }
            }

            #endregion // Setup


            // Do not follow mount points nor symbolic links, but do delete the reparse point itself.
            // If directory is reparse point, disable recursion.

            if (recursive && !fsEntryInfo.IsReparsePoint)
            {
                var dirs = new Stack <string>(1000);

                foreach (var fsei in EnumerateFileSystemEntryInfosCore <FileSystemEntryInfo>(transaction, fsEntryInfo.LongFullPath, Path.WildcardStarMatchAll, DirectoryEnumerationOptions.FilesAndFolders | DirectoryEnumerationOptions.Recursive, PathFormat.LongFullPath))
                {
                    if (fsei.IsDirectory)
                    {
                        // Check to see if this is a mount point, and unmount it.
                        // Now it is safe to delete the actual directory.
                        if (fsei.IsMountPoint)
                        {
                            Volume.DeleteVolumeMountPointCore(fsei.LongFullPath, false);
                        }

                        dirs.Push(fsei.LongFullPath);
                    }

                    else
                    {
                        File.DeleteFileCore(transaction, fsei.LongFullPath, ignoreReadOnly, PathFormat.LongFullPath);
                    }
                }


                while (dirs.Count > 0)
                {
                    DeleteDirectoryCore(transaction, dirs.Pop(), ignoreReadOnly, continueOnNotFound);
                }
            }


            // Check to see if this is a mount point, and unmount it.
            // Now it is safe to delete the actual directory.
            if (fsEntryInfo.IsMountPoint)
            {
                Volume.DeleteVolumeMountPointCore(fsEntryInfo.LongFullPath, false);
            }

            DeleteDirectoryCore(transaction, fsEntryInfo.LongFullPath, ignoreReadOnly, continueOnNotFound);
        }