Exemplo n.º 1
0
        /// <summary>
        /// Combines the exception data into a single generic message string.
        /// </summary>
        /// <param name="nativeMethodName">Name of the native API method which returned the error code.</param>
        /// <param name="errorCode">Native error code of this exception.</param>
        /// <param name="errno">Value of errno.</param>
        /// <param name="errnoString">The string representation of errno.</param>
        private static string BuildExceptionMessageString(string nativeMethodName, NativeErrorCodes errorCode, long errno, string errnoString)
        {
            string prefix = $"Error in {nativeMethodName}: ";
            string functionErrnoSuffix = $"() failed with errno = {errnoString} [{errno}].";

            return(prefix + errorCode switch
            {
                NativeErrorCodes.NATIVE_ERROR_OPEN_FAILED => prefix + "open" + functionErrnoSuffix,
                NativeErrorCodes.NATIVE_ERROR_FSTAT_FAILED => prefix + "fstat" + functionErrnoSuffix,
                NativeErrorCodes.NATIVE_ERROR_GET_ACL_FAILED => prefix + "acl_get_fd" + functionErrnoSuffix,
                NativeErrorCodes.NATIVE_ERROR_GET_ACL_ENTRY_FAILED => prefix + "acl_get_entry" + functionErrnoSuffix,
                NativeErrorCodes.NATIVE_ERROR_GET_ACL_ENTRY_TAG_TYPE_FAILED => prefix + "acl_get_tag_type" + functionErrnoSuffix,
                NativeErrorCodes.NATIVE_ERROR_GET_ACL_ENTRY_QUALIFIER_FAILED => prefix + "acl_get_qualifier" + functionErrnoSuffix,
                NativeErrorCodes.NATIVE_ERROR_GET_ACL_ENTRY_PERMSET_FAILED => prefix + "acl_get_permset" + functionErrnoSuffix,
                NativeErrorCodes.NATIVE_ERROR_GET_ACL_ENTRY_PERM_FAILED => prefix + "acl_get_perm" + functionErrnoSuffix,
                NativeErrorCodes.NATIVE_ERROR_CHOWN_FAILED => prefix + "fchown" + functionErrnoSuffix,
                NativeErrorCodes.NATIVE_ERROR_CHMOD_FAILED => prefix + "fchmod" + functionErrnoSuffix,
                NativeErrorCodes.NATIVE_ERROR_INIT_ACL_FAILED => prefix + "acl_init" + functionErrnoSuffix,
                NativeErrorCodes.NATIVE_ERROR_CREATE_ACL_ENTRY_FAILED => prefix + "acl_create_entry" + functionErrnoSuffix,
                NativeErrorCodes.NATIVE_ERROR_INVALID_TAG_TYPE => prefix + "The given entry tag type was invalid.",
                NativeErrorCodes.NATIVE_ERROR_SET_ACL_ENTRY_TAG_TYPE_FAILED => prefix + "acl_set_tag_type" + functionErrnoSuffix,
                NativeErrorCodes.NATIVE_ERROR_SET_ACL_ENTRY_QUALIFIER_FAILED => prefix + "acl_set_qualifier" + functionErrnoSuffix,
                NativeErrorCodes.NATIVE_ERROR_CLEAR_ACL_ENTRY_PERMS_FAILED => prefix + "acl_clear_perms" + functionErrnoSuffix,
                NativeErrorCodes.NATIVE_ERROR_ADD_ACL_ENTRY_PERM_FAILED => prefix + "acl_add_perm" + functionErrnoSuffix,
                NativeErrorCodes.NATIVE_ERROR_VALIDATE_ACL_FAILED => prefix + "acl_valid" + functionErrnoSuffix,
                NativeErrorCodes.NATIVE_ERROR_SET_ACL_FAILED => prefix + "acl_set_file" + functionErrnoSuffix,
                _ => "Unknown native error.",
            });
Exemplo n.º 2
0
 /// <summary>
 /// Creates a new exception from the given native error code and errno value, using the given exception message.
 /// </summary>
 /// <param name="nativeFunctionName">Name of the native API method which returned the error code.</param>
 /// <param name="errorCode">Native error code of this exception.</param>
 /// <param name="errno">Value of errno (or 0, if not applicable).</param>
 /// <param name="errnoString">The string representation of errno (if applicable).</param>
 /// <param name="message">The exception message to display.</param>
 protected NativeException(string nativeMethodName, NativeErrorCodes errorCode, long errno, string errnoString, string message)
     : base(message)
 {
     NativeMethodName = nativeMethodName;
     ErrorCode        = errorCode;
     Errno            = errno;
     ErrnoString      = errnoString;
 }
        /// <inheritdoc />
        /// <exception cref="UnauthorizedAccessException">Thrown when trying to open or modify a file/directory without having sufficient access permissions.</exception>
        /// <exception cref="FileNotFoundException">Thrown when a file/directory or parts of its path cannot be found.</exception>
        /// <exception cref="ArgumentException">Thrown when the provided ACL is invalid.</exception>
        /// <exception cref="NativeException">Generic exception thrown when a native method fails, and the error was not covered by one of the other possible exceptions. This exception is also always included as the <see cref="Exception.InnerException"/>.</exception>
        public void SetPermissionData(string fileName, int setDefaultAcl, ref NativePermissionDataContainer dataContainer, AccessControlListEntry[] entries)
        {
            // Ensure exclusive access to native functions
            lock (_nativeFunctionsLock)
            {
                // Make sure the meta data object is valid
                dataContainer.AclSize = entries.Length;

                // Set permissions and ACL
                NativeErrorCodes err = SetFilePermissionDataAndAcl(fileName, setDefaultAcl, ref dataContainer, entries);
                if (err != NativeErrorCodes.NATIVE_ERROR_SUCCESS)
                {
                    // Throw suitable exceptions
                    var nativeException = RetrieveErrnoAndBuildException(nameof(SetFilePermissionDataAndAcl), err, out var _, out var errnoSymbolic);
                    switch (err)
                    {
                    // Handle certain special exception cases
                    case NativeErrorCodes.NATIVE_ERROR_OPEN_FAILED when errnoSymbolic == Errno.EACCES:
                        throw new UnauthorizedAccessException($"Could not open \"{fileName}\" for reading.", nativeException);

                    case NativeErrorCodes.NATIVE_ERROR_OPEN_FAILED when errnoSymbolic == Errno.ENOENT:
                        throw new FileNotFoundException($"Could not open \"{fileName}\" for reading.", nativeException);

                    case NativeErrorCodes.NATIVE_ERROR_CHOWN_FAILED when errnoSymbolic == Errno.EPERM:
                        throw new UnauthorizedAccessException($"Permission denied when using fchown() on \"{fileName}\".", nativeException);

                    case NativeErrorCodes.NATIVE_ERROR_CHMOD_FAILED when errnoSymbolic == Errno.EPERM:
                        throw new UnauthorizedAccessException($"Permission denied when using fchmod() on \"{fileName}\".", nativeException);

                    case NativeErrorCodes.NATIVE_ERROR_VALIDATE_ACL_FAILED when errnoSymbolic == Errno.EINVAL:
                        throw new ArgumentException($"The given ACL is invalid.", nativeException);

                    case NativeErrorCodes.NATIVE_ERROR_SET_ACL_FAILED when errnoSymbolic == Errno.EINVAL:
                        throw new ArgumentException($"Could not assign ACL to file \"{fileName}\" using acl_set_fd().", nativeException);

                    case NativeErrorCodes.NATIVE_ERROR_SET_ACL_FAILED when errnoSymbolic == Errno.EPERM:
                        throw new UnauthorizedAccessException($"Permission denied when assigning ACL using acl_set_fd() on \"{fileName}\".", nativeException);

                    // Unhandled case, just throw generic exception directly
                    default:
                        throw nativeException;
                    }
                }
            }
        }
        /// <inheritdoc />
        /// <exception cref="UnauthorizedAccessException">Thrown when trying to open a file/directory without having sufficient access permissions.</exception>
        /// <exception cref="FileNotFoundException">Thrown when a file/directory or parts of its path cannot be found.</exception>
        /// <exception cref="NativeException">Generic exception thrown when a native method fails, and the error was not covered by one of the other possible exceptions. This exception is also always included as the <see cref="Exception.InnerException"/>.</exception>
        public AccessControlListEntry[] GetPermissionData(string fileName, int loadDefaultAcl, out NativePermissionDataContainer dataContainer)
        {
            // Ensure exclusive access to native functions
            lock (_nativeFunctionsLock)
            {
                // Read permission data and retrieve ACL size
                NativeErrorCodes err = OpenFileAndReadPermissionData(fileName, loadDefaultAcl, out dataContainer);
                if (err != NativeErrorCodes.NATIVE_ERROR_SUCCESS)
                {
                    // Throw suitable exceptions
                    var nativeException = RetrieveErrnoAndBuildException(nameof(OpenFileAndReadPermissionData), err, out var _, out var errnoSymbolic);
                    switch (err)
                    {
                    // Handle certain special exception cases
                    case NativeErrorCodes.NATIVE_ERROR_OPEN_FAILED when errnoSymbolic == Errno.EACCES:
                        throw new UnauthorizedAccessException($"Could not open \"{fileName}\" for reading.", nativeException);

                    case NativeErrorCodes.NATIVE_ERROR_OPEN_FAILED when errnoSymbolic == Errno.ENOENT:
                        throw new FileNotFoundException($"Could not open \"{fileName}\" for reading.", nativeException);

                    // Unhandled case, just throw generic exception directly
                    default:
                        throw nativeException;
                    }
                }

                // Read ACL
                AccessControlListEntry[] acl = new AccessControlListEntry[dataContainer.AclSize];
                err = ReadFileAclAndClose(acl);
                if (err != NativeErrorCodes.NATIVE_ERROR_SUCCESS)
                {
                    throw RetrieveErrnoAndBuildException(nameof(ReadFileAclAndClose), err, out var _, out var _);
                }
                return(acl);
            }
        }
Exemplo n.º 5
0
 /// <summary>
 /// Creates a new exception from the given native error code and errno value.
 /// </summary>
 /// <param name="nativeFunctionName">Name of the native API method which returned the error code.</param>
 /// <param name="errorCode">Native error code of this exception.</param>
 /// <param name="errno">Value of errno (or 0, if not applicable).</param>
 /// <param name="errnoString">The string representation of errno (if applicable).</param>
 internal NativeException(string nativeMethodName, NativeErrorCodes errorCode, long errno, string errnoString)
     : this(nativeMethodName, errorCode, errno, errnoString, BuildExceptionMessageString(nativeMethodName, errorCode, errno, errnoString))
 {
 }
        /// <summary>
        /// Retrieves the error information from the native implementation and constructs a new <see cref="NativeException"/> object, that can be thrown afterwards.
        /// </summary>
        /// <param name="nativeMethodName">Name of the native API method which returned the error code.</param>
        /// <param name="errorCode">The error code returned by the native API method.</param>
        /// <param name="errnoResolvable">This will tell whether the retrieved errno could be resolved into a symbolic representation.</param>
        /// <param name="errnoSymbolic">This will hold the symbolic value of the retrieved errno; check the <paramref name="errnoResolvable"/> parameter beforehand!</param>
        private NativeException RetrieveErrnoAndBuildException(string nativeMethodName, NativeErrorCodes errorCode, out bool errnoResolvable, out Errno errnoSymbolic)
        {
            // Retrieve errno
            var  errnoStringBuffer = new StringBuilder(256);
            long errno             = GetLastErrnoValue(errnoStringBuffer, errnoStringBuffer.Capacity);

            // Try to resolve to symbolic representation
            errnoResolvable = NativeConvert.TryToErrno((int)errno, out errnoSymbolic);

            // Create native exception object
            return(new NativeException(nativeMethodName, errorCode, errno, (errnoResolvable ? errnoSymbolic.ToString() + ", " : "") + errnoStringBuffer.ToString()));
        }