public T Get <T>()
        {
            using (new NativeMethods.ChangeErrorMode(NativeMethods.ErrorMode.FailCriticalErrors))
            {
                NativeMethods.WIN32_FIND_DATA win32FindData;


                // Not explicitly set to be a folder.

                if (!IsDirectory)
                {
                    using (var handle = FindFirstFile(InputPath, out win32FindData))

                        return(null == handle

                     ? (T)(object)null

                     : NewFileSystemEntryType <T>((win32FindData.dwFileAttributes & FileAttributes.Directory) != 0, null, null, InputPath, win32FindData));
                }


                using (var handle = FindFirstFile(InputPath, out win32FindData, true))
                {
                    if (null == handle)
                    {
                        // InputPath might be a logical drive such as: "C:\", "D:\".

                        var attrs = new NativeMethods.WIN32_FILE_ATTRIBUTE_DATA();

                        var lastError = File.FillAttributeInfoCore(Transaction, Path.GetRegularPathCore(InputPath, GetFullPathOptions.None, false), ref attrs, false, true);
                        if (lastError != Win32Errors.NO_ERROR)
                        {
                            if (!ContinueOnException)
                            {
                                switch ((uint)lastError)
                                {
                                case Win32Errors.ERROR_FILE_NOT_FOUND: // FileNotFoundException.
                                case Win32Errors.ERROR_PATH_NOT_FOUND: // DirectoryNotFoundException.
                                case Win32Errors.ERROR_NOT_READY:      // DeviceNotReadyException: Floppy device or network drive not ready.
                                case Win32Errors.ERROR_BAD_NET_NAME:

                                    Directory.ExistsDriveOrFolderOrFile(Transaction, InputPath, IsDirectory, lastError, true, true);
                                    break;
                                }

                                ThrowPossibleException((uint)lastError, InputPath);
                            }

                            return((T)(object)null);
                        }


                        win32FindData = new NativeMethods.WIN32_FIND_DATA
                        {
                            cFileName        = Path.CurrentDirectoryPrefix,
                            dwFileAttributes = attrs.dwFileAttributes,
                            ftCreationTime   = attrs.ftCreationTime,
                            ftLastAccessTime = attrs.ftLastAccessTime,
                            ftLastWriteTime  = attrs.ftLastWriteTime,
                            nFileSizeHigh    = attrs.nFileSizeHigh,
                            nFileSizeLow     = attrs.nFileSizeLow
                        };
                    }


                    VerifyInstanceType(win32FindData);
                }


                return(NewFileSystemEntryType <T>((win32FindData.dwFileAttributes & FileAttributes.Directory) != 0, null, null, InputPath, win32FindData));
            }
        }
Beispiel #2
0
        internal static void DeleteFileCore(KernelTransaction transaction, string path, bool ignoreReadOnly, PathFormat pathFormat)
        {
            if (null == path)
            {
                throw new ArgumentNullException("path");
            }

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

            var pathLp = Path.GetExtendedLengthPathCore(transaction, path, pathFormat, GetFullPathOptions.TrimEnd | GetFullPathOptions.RemoveTrailingDirectorySeparator);

            // If the path points to a symbolic link, the symbolic link is deleted, not the target.


startDeleteFile:

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

                  // DeleteFile() / DeleteFileTransacted()
                  // 2013-01-13: MSDN confirms LongPath usage.

            ? NativeMethods.DeleteFile(pathLp)
            : NativeMethods.DeleteFileTransacted(pathLp, transaction.SafeHandle)))
            {
                var lastError = Marshal.GetLastWin32Error();
                switch ((uint)lastError)
                {
                case Win32Errors.ERROR_FILE_NOT_FOUND:
                    // MSDN: .NET 3.5+: If the file to be deleted does not exist, no exception is thrown.
                    return;

                case Win32Errors.ERROR_PATH_NOT_FOUND:
                    // MSDN: .NET 3.5+: DirectoryNotFoundException: The specified path is invalid (for example, it is on an unmapped drive).
                    NativeError.ThrowException(lastError, pathLp);
                    return;

                case Win32Errors.ERROR_SHARING_VIOLATION:
                    // MSDN: .NET 3.5+: IOException: The specified file is in use or there is an open handle on the file.
                    NativeError.ThrowException(lastError, pathLp);
                    break;

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


                    if (IsDirectory(attrs.dwFileAttributes))
                    {
                        // MSDN: .NET 3.5+: UnauthorizedAccessException: Path is a directory.
                        throw new UnauthorizedAccessException(string.Format(CultureInfo.InvariantCulture, "({0}) {1}",
                                                                            Win32Errors.ERROR_INVALID_PARAMETER, string.Format(CultureInfo.InvariantCulture, Resources.Target_File_Is_A_Directory, pathLp)));
                    }


                    if (IsReadOnly(attrs.dwFileAttributes))
                    {
                        if (ignoreReadOnly)
                        {
                            // Reset file attributes to Normal.
                            SetAttributesCore(transaction, false, pathLp, FileAttributes.Normal, PathFormat.LongFullPath);

                            goto startDeleteFile;
                        }


                        // MSDN: .NET 3.5+: UnauthorizedAccessException: Path specified a read-only file.
                        throw new FileReadOnlyException(pathLp);
                    }


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

                    break;
                }

                // MSDN: .NET 3.5+: IOException:
                // The specified file is in use.
                // There is an open handle on the file, and the operating system is Windows XP or earlier.

                NativeError.ThrowException(lastError, pathLp);
            }
        }
Beispiel #3
0
        internal static int FillAttributeInfoCore(KernelTransaction transaction, string pathLp, ref NativeMethods.WIN32_FILE_ATTRIBUTE_DATA win32AttrData, bool tryagain, bool returnErrorOnNotFound)
        {
            int dataInitialised = (int)Win32Errors.ERROR_SUCCESS;

            #region Try Again

            // Someone has a handle to the file open, or other error.
            if (tryagain)
            {
                NativeMethods.WIN32_FIND_DATA findData;

                // ChangeErrorMode is for the Win32 SetThreadErrorMode() method, used to suppress possible pop-ups.
                using (new NativeMethods.ChangeErrorMode(NativeMethods.ErrorMode.FailCriticalErrors))
                {
                    bool error = false;

                    SafeFindFileHandle handle = transaction == null || !NativeMethods.IsAtLeastWindowsVista

                                                // FindFirstFileEx() / FindFirstFileTransacted()
                                                // 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.
                                                // 2013-01-13: MSDN confirms LongPath usage.

                                                // A trailing backslash is not allowed.
                  ? NativeMethods.FindFirstFileEx(Path.RemoveTrailingDirectorySeparator(pathLp, false), NativeMethods.FindexInfoLevels, out findData, NativeMethods.FINDEX_SEARCH_OPS.SearchNameMatch, IntPtr.Zero, NativeMethods.LargeCache)
                  : NativeMethods.FindFirstFileTransacted(Path.RemoveTrailingDirectorySeparator(pathLp, false), NativeMethods.FindexInfoLevels, out findData, NativeMethods.FINDEX_SEARCH_OPS.SearchNameMatch, IntPtr.Zero, NativeMethods.LargeCache, transaction.SafeHandle);

                    try
                    {
                        if (handle != null && handle.IsInvalid)
                        {
                            error           = true;
                            dataInitialised = Marshal.GetLastWin32Error();

                            if (dataInitialised == Win32Errors.ERROR_FILE_NOT_FOUND ||
                                dataInitialised == Win32Errors.ERROR_PATH_NOT_FOUND ||
                                dataInitialised == Win32Errors.ERROR_NOT_READY) // Floppy device not ready.
                            {
                                if (!returnErrorOnNotFound)
                                {
                                    // Return default value for backward compatibility
                                    dataInitialised = (int)Win32Errors.ERROR_SUCCESS;
                                    win32AttrData.dwFileAttributes = (FileAttributes)(-1);
                                }
                            }

                            return(dataInitialised);
                        }
                    }
                    finally
                    {
                        try
                        {
                            if (handle != null)
                            {
                                handle.Close();
                            }
                        }
                        catch
                        {
                            // If we're already returning an error, don't throw another one.
                            if (!error)
                            {
                                NativeError.ThrowException(dataInitialised, pathLp);
                            }
                        }
                    }
                }

                // Copy the attribute information.
                win32AttrData = new NativeMethods.WIN32_FILE_ATTRIBUTE_DATA(findData);
            }

            #endregion // Try Again

            else
            {
                using (new NativeMethods.ChangeErrorMode(NativeMethods.ErrorMode.FailCriticalErrors))
                {
                    if (!(transaction == null || !NativeMethods.IsAtLeastWindowsVista

                          // GetFileAttributesEx() / GetFileAttributesTransacted()
                          // 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.
                          // 2013-01-13: MSDN confirms LongPath usage.

                  ? NativeMethods.GetFileAttributesEx(pathLp, NativeMethods.GetFileExInfoLevels.GetFileExInfoStandard, out win32AttrData)
                  : NativeMethods.GetFileAttributesTransacted(pathLp, NativeMethods.GetFileExInfoLevels.GetFileExInfoStandard, out win32AttrData, transaction.SafeHandle)))
                    {
                        dataInitialised = Marshal.GetLastWin32Error();

                        if (dataInitialised != Win32Errors.ERROR_FILE_NOT_FOUND &&
                            dataInitialised != Win32Errors.ERROR_PATH_NOT_FOUND &&
                            dataInitialised != Win32Errors.ERROR_NOT_READY) // Floppy device not ready.
                        {
                            // In case someone latched onto the file. Take the perf hit only for failure.
                            return(FillAttributeInfoCore(transaction, pathLp, ref win32AttrData, true, returnErrorOnNotFound));
                        }

                        if (!returnErrorOnNotFound)
                        {
                            // Return default value for backward compbatibility.
                            dataInitialised = (int)Win32Errors.ERROR_SUCCESS;
                            win32AttrData.dwFileAttributes = (FileAttributes)(-1);
                        }
                    }
                }
            }

            return(dataInitialised);
        }
        internal static void DeleteDirectoryCore(FileSystemEntryInfo fileSystemEntryInfo, KernelTransaction transaction, string path, bool recursive, bool ignoreReadOnly, 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, 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:
                    // MSDN: .NET 3.5+: IOException: The directory specified by path is not an empty directory.
                    throw new DirectoryNotEmptyException(pathLp);


                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) != 0)
                        {
                            // 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
        }
        internal static int FillAttributeInfoCore(KernelTransaction transaction, string pathLp, ref NativeMethods.WIN32_FILE_ATTRIBUTE_DATA win32AttrData, bool tryAgain, bool returnErrorOnNotFound)
        {
            var lastError = (int)Win32Errors.ERROR_SUCCESS;

            #region Try Again

            // Someone has a handle to the file open, or other error.
            if (tryAgain)
            {
                NativeMethods.WIN32_FIND_DATA win32FindData;

                using (new NativeMethods.ChangeErrorMode(NativeMethods.ErrorMode.FailCriticalErrors))
                {
                    var handle = FileSystemInfo.FindFirstFileNative(transaction, pathLp, NativeMethods.FindexInfoLevel, NativeMethods.FINDEX_SEARCH_OPS.SearchNameMatch, NativeMethods.UseLargeCache, out lastError, out win32FindData);

                    if (null == handle)
                    {
                        switch ((uint)lastError)
                        {
                        case Win32Errors.ERROR_INVALID_NAME:
                        case Win32Errors.ERROR_FILE_NOT_FOUND: // On files.
                        case Win32Errors.ERROR_PATH_NOT_FOUND: // On folders.
                        case Win32Errors.ERROR_NOT_READY:      // DeviceNotReadyException: Floppy device or network drive not ready.

                            if (!returnErrorOnNotFound)
                            {
                                // Return default value for backward compatibility.
                                lastError = (int)Win32Errors.ERROR_SUCCESS;

                                win32AttrData.dwFileAttributes = NativeMethods.InvalidFileAttributes;
                            }

                            break;
                        }

                        return(lastError);
                    }
                }

                // Copy the attribute information.
                win32AttrData = new NativeMethods.WIN32_FILE_ATTRIBUTE_DATA(win32FindData);
            }

            #endregion // Try Again

            else
            {
                using (new NativeMethods.ChangeErrorMode(NativeMethods.ErrorMode.FailCriticalErrors))
                {
                    if (!(null == transaction || !NativeMethods.IsAtLeastWindowsVista

                          // GetFileAttributesEx() / GetFileAttributesTransacted()
                          // 2013-01-13: MSDN confirms LongPath usage.

                  ? NativeMethods.GetFileAttributesEx(pathLp, NativeMethods.GET_FILEEX_INFO_LEVELS.GetFileExInfoStandard, out win32AttrData)
                  : NativeMethods.GetFileAttributesTransacted(pathLp, NativeMethods.GET_FILEEX_INFO_LEVELS.GetFileExInfoStandard, out win32AttrData, transaction.SafeHandle)))
                    {
                        lastError = Marshal.GetLastWin32Error();

                        switch ((uint)lastError)
                        {
                        case Win32Errors.ERROR_FILE_NOT_FOUND: // On files.
                        case Win32Errors.ERROR_PATH_NOT_FOUND: // On folders.
                        case Win32Errors.ERROR_NOT_READY:      // DeviceNotReadyException: Floppy device or network drive not ready.

                            // In case someone latched onto the file. Take the perf hit only for failure.
                            return(FillAttributeInfoCore(transaction, pathLp, ref win32AttrData, true, returnErrorOnNotFound));
                        }


                        if (!returnErrorOnNotFound)
                        {
                            // Return default value for backward compatibility.
                            lastError = (int)Win32Errors.ERROR_SUCCESS;

                            win32AttrData.dwFileAttributes = NativeMethods.InvalidFileAttributes;
                        }
                    }
                }
            }

            return(lastError);
        }
        internal static void TransferTimestampsCore(bool isFolder, KernelTransaction transaction, string sourcePath, string destinationPath, PathFormat pathFormat)
        {
            NativeMethods.WIN32_FILE_ATTRIBUTE_DATA attrs = GetAttributesExCore <NativeMethods.WIN32_FILE_ATTRIBUTE_DATA>(transaction, sourcePath, pathFormat, true);

            SetFsoDateTimeCore(isFolder, transaction, destinationPath, DateTime.FromFileTimeUtc(attrs.ftCreationTime), DateTime.FromFileTimeUtc(attrs.ftLastAccessTime), DateTime.FromFileTimeUtc(attrs.ftLastWriteTime), false, pathFormat);
        }
        private static void DeleteDirectoryCore(KernelTransaction transaction, string pathLp, bool ignoreReadOnly, bool continueOnNotFound)
        {
startRemoveDirectory:

            var success = transaction == null || !NativeMethods.IsAtLeastWindowsVista

                          // RemoveDirectory() / RemoveDirectoryTransacted()
                          // 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);


            var lastError = Marshal.GetLastWin32Error();

            if (!success)
            {
                switch ((uint)lastError)
                {
                case Win32Errors.ERROR_DIR_NOT_EMPTY:
                    // MSDN: .NET 3.5+: IOException: The directory specified by path is not an empty directory.
                    throw new DirectoryNotEmptyException(pathLp, true);


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


                case Win32Errors.ERROR_PATH_NOT_FOUND:
                    if (continueOnNotFound)
                    {
                        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 attrs           = new NativeMethods.WIN32_FILE_ATTRIBUTE_DATA();
                    var dataInitialised = File.FillAttributeInfoCore(transaction, pathLp, ref attrs, false, true);


                    if (File.IsReadOnly(attrs.dwFileAttributes))
                    {
                        // MSDN: .NET 3.5+: IOException: The directory specified by path is read-only.

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

                            goto startRemoveDirectory;
                        }


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


                    // MSDN: .NET 3.5+: UnauthorizedAccessException: The caller does not have the required permission.
                    if (dataInitialised == Win32Errors.ERROR_SUCCESS)
                    {
                        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);
            }
        }