/Code/Foundation/Windows/IO/ErrorHelper.cs

https://github.com/DavidMoore/Foundation · C# · 125 lines · 81 code · 20 blank · 24 comment · 13 complexity · b31503c860ecc1b56ba05627be919f7c MD5 · raw file

  1. using System;
  2. using System.Diagnostics.Contracts;
  3. using System.IO;
  4. using System.Runtime.InteropServices;
  5. using System.Security;
  6. using System.Security.Permissions;
  7. namespace Foundation.Windows.IO
  8. {
  9. /// <summary>
  10. /// Helper methods for throwing appropriate exceptions for a
  11. /// Win32 error code related to a file system path.
  12. /// </summary>
  13. [Pure]
  14. static class ErrorHelper
  15. {
  16. [SecuritySafeCritical]
  17. internal static void WinIoError()
  18. {
  19. WinIoError(Marshal.GetLastWin32Error(), string.Empty);
  20. }
  21. /// <summary>
  22. /// Gets the displayable path. If we don't have discovery permissions
  23. /// for the path, we will return just the file name.
  24. /// </summary>
  25. /// <param name="path">The path.</param>
  26. /// <param name="isInvalidPath"><c>true</c> if <paramref name="path"/> is invalid.</param>
  27. /// <returns></returns>
  28. /// <exception cref="FoundationException">if the path is a directory, and we don't have <see cref="FileIOPermissionAccess.PathDiscovery"/> permission to it.</exception>
  29. [SecurityCritical]
  30. static string GetDisplayablePath(string path, bool isInvalidPath)
  31. {
  32. if( string.IsNullOrWhiteSpace(path) ) return path;
  33. // Is it a fully qualified path?
  34. var isFullyQualified = false;
  35. if( path.Length < 2 ) return path;
  36. if( (PathHelperMethods.IsDirectorySeparator(path[0]) && PathHelperMethods.IsDirectorySeparator(path[1])) || path[1] == Path.VolumeSeparatorChar)
  37. {
  38. isFullyQualified = true;
  39. }
  40. if( !isFullyQualified && !isInvalidPath ) return path;
  41. try
  42. {
  43. if( !isInvalidPath )
  44. {
  45. new FileIOPermission(FileIOPermissionAccess.PathDiscovery, new[] {path}).Demand();
  46. return path;
  47. }
  48. }
  49. catch( SecurityException ) {}
  50. catch( ArgumentException )
  51. {
  52. // ? and * characters cause ArgumentException to be thrown from HasIllegalCharacters
  53. // inside FileIOPermission.AddPathList
  54. }
  55. catch( NotSupportedException )
  56. {
  57. // paths like "!Bogus\\dir:with/junk_.in it" can cause NotSupportedException to be thrown
  58. // from Security.Util.StringExpressionSet.CanonicalizePath when ':' is found in the path
  59. // beyond string index position 1.
  60. }
  61. if( PathHelperMethods.IsDirectorySeparator(path[path.Length - 1]) )
  62. {
  63. throw new FoundationException("No permission to directory name '{0}'", path);
  64. }
  65. return Path.GetFileName(path);
  66. }
  67. /// <summary>
  68. /// Takes a Win32 error code from <see cref="Marshal.GetLastWin32Error"/>, and
  69. /// a path, and throws an appropriate exception and message for the corresponding error.
  70. /// </summary>
  71. /// <param name="errorCode">The error code.</param>
  72. /// <param name="errorPath">The path related to the error.</param>
  73. [SecurityCritical]
  74. internal static void WinIoError(int errorCode, String errorPath)
  75. {
  76. var isInvalidPath = errorCode == Win32Error.ERROR_INVALID_NAME || errorCode == Win32Error.ERROR_BAD_PATHNAME;
  77. var path = GetDisplayablePath(errorPath, isInvalidPath);
  78. switch( errorCode )
  79. {
  80. case Win32Error.ERROR_FILE_NOT_FOUND:
  81. throw new FileNotFoundException("File not found", path);
  82. case Win32Error.ERROR_PATH_NOT_FOUND:
  83. throw new DirectoryNotFoundException("Path not found: " + path);
  84. case Win32Error.ERROR_ACCESS_DENIED:
  85. throw new UnauthorizedAccessException("Access denied to path: " + path);
  86. case Win32Error.ERROR_ALREADY_EXISTS:
  87. throw new IOException("Path already exists: " + path, Win32Error.MakeHRFromErrorCode(errorCode));
  88. case Win32Error.ERROR_FILENAME_EXCED_RANGE:
  89. throw new PathTooLongException("Path too long: " + path);
  90. case Win32Error.ERROR_INVALID_DRIVE:
  91. throw new DriveNotFoundException("Drive not found for path: " + path);
  92. case Win32Error.ERROR_INVALID_PARAMETER:
  93. throw new IOException(Win32Error.GetMessage(errorCode), Win32Error.MakeHRFromErrorCode(errorCode));
  94. case Win32Error.ERROR_SHARING_VIOLATION:
  95. throw new IOException("Sharing violation error for path: " + path, Win32Error.MakeHRFromErrorCode(errorCode));
  96. case Win32Error.ERROR_FILE_EXISTS:
  97. throw new IOException("File exists error for path: " + path, Win32Error.MakeHRFromErrorCode(errorCode));
  98. case Win32Error.ERROR_OPERATION_ABORTED:
  99. throw new OperationCanceledException();
  100. default:
  101. throw new IOException(Win32Error.GetMessage(errorCode), Win32Error.MakeHRFromErrorCode(errorCode));
  102. }
  103. }
  104. }
  105. }