GetExceptionForLastWin32Error() static private méthode

Converts, resetting it, the last Win32 error into a corresponding Exception object.
static private GetExceptionForLastWin32Error ( ) : Exception
Résultat System.Exception
Exemple #1
0
        public static string[] GetLogicalDrives()
        {
            int drives = Interop.Kernel32.GetLogicalDrives();

            if (drives == 0)
            {
                throw Win32Marshal.GetExceptionForLastWin32Error();
            }

            // GetLogicalDrives returns a bitmask starting from
            // position 0 "A" indicating whether a drive is present.
            // Loop over each bit, creating a string for each one
            // that is set.

            uint d     = (uint)drives;
            int  count = 0;

            while (d != 0)
            {
                if (((int)d & 1) != 0)
                {
                    count++;
                }
                d >>= 1;
            }

            string[]    result = new string[count];
            Span <char> root   = stackalloc char[] { 'A', ':', '\\' };

            d     = (uint)drives;
            count = 0;
            while (d != 0)
            {
                if (((int)d & 1) != 0)
                {
                    result[count++] = root.ToString();
                }
                d >>= 1;
                root[0]++;
            }
            return(result);
        }
    }
Exemple #2
0
        public static DriveInfo[] GetDrives()
        {
            int drives = Interop.mincore.GetLogicalDrives();

            if (drives == 0)
            {
                throw Win32Marshal.GetExceptionForLastWin32Error();
            }

            // GetLogicalDrives returns a bitmask starting from
            // position 0 "A" indicating whether a drive is present.
            // Loop over each bit, creating a DriveInfo for each one
            // that is set.

            uint d     = (uint)drives;
            int  count = 0;

            while (d != 0)
            {
                if (((int)d & 1) != 0)
                {
                    count++;
                }
                d >>= 1;
            }

            DriveInfo[] result = new DriveInfo[count];
            char[]      root   = new char[] { 'A', ':', '\\' };
            d     = (uint)drives;
            count = 0;
            while (d != 0)
            {
                if (((int)d & 1) != 0)
                {
                    result[count++] = new DriveInfo(new String(root));
                }
                d >>= 1;
                root[0]++;
            }
            return(result);
        }
Exemple #3
0
        public override string GetCurrentDirectory()
        {
            StringBuilder sb = StringBuilderCache.Acquire(Interop.mincore.MAX_PATH + 1);

            if (Interop.mincore.GetCurrentDirectory(sb.Capacity, sb) == 0)
            {
                throw Win32Marshal.GetExceptionForLastWin32Error();
            }
            String currentDirectory = sb.ToString();

            // Note that if we have somehow put our command prompt into short
            // file name mode (ie, by running edlin or a DOS grep, etc), then
            // this will return a short file name.
            if (currentDirectory.IndexOf('~') >= 0)
            {
                int r = Interop.mincore.GetLongPathName(currentDirectory, sb, sb.Capacity);
                if (r == 0 || r >= Interop.mincore.MAX_PATH)
                {
                    int errorCode = Marshal.GetLastWin32Error();
                    if (r >= Interop.mincore.MAX_PATH)
                    {
                        errorCode = Interop.mincore.Errors.ERROR_FILENAME_EXCED_RANGE;
                    }
                    if (errorCode != Interop.mincore.Errors.ERROR_FILE_NOT_FOUND &&
                        errorCode != Interop.mincore.Errors.ERROR_PATH_NOT_FOUND &&
                        errorCode != Interop.mincore.Errors.ERROR_INVALID_FUNCTION &&  // by design - enough said.
                        errorCode != Interop.mincore.Errors.ERROR_ACCESS_DENIED)
                    {
                        throw Win32Marshal.GetExceptionForWin32Error(errorCode);
                    }
                }
                currentDirectory = sb.ToString();
            }
            StringBuilderCache.Release(sb);

            return(currentDirectory);
        }
Exemple #4
0
        [System.Security.SecurityCritical]  // auto-generated
        private static void RemoveDirectoryHelper(string fullPath, bool recursive, bool throwOnTopLevelDirectoryNotFound)
        {
            bool      r;
            int       errorCode;
            Exception ex = null;

            // Do not recursively delete through reparse points.  Perhaps in a
            // future version we will add a new flag to control this behavior,
            // but for now we're much safer if we err on the conservative side.
            // This applies to symbolic links and mount points.
            // Note the logic to check whether fullPath is a reparse point is
            // in Delete(String, String, bool), and will set "recursive" to false.
            // Note that Win32's DeleteFile and RemoveDirectory will just delete
            // the reparse point itself.

            if (recursive)
            {
                Interop.mincore.WIN32_FIND_DATA data = new Interop.mincore.WIN32_FIND_DATA();

                // Open a Find handle
                using (SafeFindHandle hnd = Interop.mincore.FindFirstFile(Directory.EnsureTrailingDirectorySeparator(fullPath) + "*", ref data))
                {
                    if (hnd.IsInvalid)
                    {
                        throw Win32Marshal.GetExceptionForLastWin32Error(fullPath);
                    }

                    do
                    {
                        bool isDir = (0 != (data.dwFileAttributes & Interop.mincore.FileAttributes.FILE_ATTRIBUTE_DIRECTORY));
                        if (isDir)
                        {
                            // Skip ".", "..".
                            if (data.cFileName.Equals(".") || data.cFileName.Equals(".."))
                            {
                                continue;
                            }

                            // Recurse for all directories, unless they are
                            // reparse points.  Do not follow mount points nor
                            // symbolic links, but do delete the reparse point
                            // itself.
                            bool shouldRecurse = (0 == (data.dwFileAttributes & (int)FileAttributes.ReparsePoint));
                            if (shouldRecurse)
                            {
                                string newFullPath = Path.Combine(fullPath, data.cFileName);
                                try
                                {
                                    RemoveDirectoryHelper(newFullPath, recursive, false);
                                }
                                catch (Exception e)
                                {
                                    if (ex == null)
                                    {
                                        ex = e;
                                    }
                                }
                            }
                            else
                            {
                                // Check to see if this is a mount point, and
                                // unmount it.
                                if (data.dwReserved0 == Interop.mincore.IOReparseOptions.IO_REPARSE_TAG_MOUNT_POINT)
                                {
                                    // Use full path plus a trailing '\'
                                    String mountPoint = Path.Combine(fullPath, data.cFileName + PathHelpers.DirectorySeparatorCharAsString);
                                    if (!Interop.mincore.DeleteVolumeMountPoint(mountPoint))
                                    {
                                        errorCode = Marshal.GetLastWin32Error();

                                        if (errorCode != Interop.mincore.Errors.ERROR_SUCCESS &&
                                            errorCode != Interop.mincore.Errors.ERROR_PATH_NOT_FOUND)
                                        {
                                            try
                                            {
                                                throw Win32Marshal.GetExceptionForWin32Error(errorCode, data.cFileName);
                                            }
                                            catch (Exception e)
                                            {
                                                if (ex == null)
                                                {
                                                    ex = e;
                                                }
                                            }
                                        }
                                    }
                                }

                                // RemoveDirectory on a symbolic link will
                                // remove the link itself.
                                String reparsePoint = Path.Combine(fullPath, data.cFileName);
                                r = Interop.mincore.RemoveDirectory(reparsePoint);
                                if (!r)
                                {
                                    errorCode = Marshal.GetLastWin32Error();
                                    if (errorCode != Interop.mincore.Errors.ERROR_PATH_NOT_FOUND)
                                    {
                                        try
                                        {
                                            throw Win32Marshal.GetExceptionForWin32Error(errorCode, data.cFileName);
                                        }
                                        catch (Exception e)
                                        {
                                            if (ex == null)
                                            {
                                                ex = e;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        else
                        {
                            String fileName = Path.Combine(fullPath, data.cFileName);
                            r = Interop.mincore.DeleteFile(fileName);
                            if (!r)
                            {
                                errorCode = Marshal.GetLastWin32Error();
                                if (errorCode != Interop.mincore.Errors.ERROR_FILE_NOT_FOUND)
                                {
                                    try
                                    {
                                        throw Win32Marshal.GetExceptionForWin32Error(errorCode, data.cFileName);
                                    }
                                    catch (Exception e)
                                    {
                                        if (ex == null)
                                        {
                                            ex = e;
                                        }
                                    }
                                }
                            }
                        }
                    } while (Interop.mincore.FindNextFile(hnd, ref data));
                    // Make sure we quit with a sensible error.
                    errorCode = Marshal.GetLastWin32Error();
                }

                if (ex != null)
                {
                    throw ex;
                }
                if (errorCode != 0 && errorCode != Interop.mincore.Errors.ERROR_NO_MORE_FILES)
                {
                    throw Win32Marshal.GetExceptionForWin32Error(errorCode, fullPath);
                }
            }

            r = Interop.mincore.RemoveDirectory(fullPath);

            if (!r)
            {
                errorCode = Marshal.GetLastWin32Error();
                if (errorCode == Interop.mincore.Errors.ERROR_FILE_NOT_FOUND) // A dubious error code.
                {
                    errorCode = Interop.mincore.Errors.ERROR_PATH_NOT_FOUND;
                }
                // This check was originally put in for Win9x (unfortunately without special casing it to be for Win9x only). We can't change the NT codepath now for backcomp reasons.
                if (errorCode == Interop.mincore.Errors.ERROR_ACCESS_DENIED)
                {
                    throw new IOException(SR.Format(SR.UnauthorizedAccess_IODenied_Path, fullPath));
                }

                // don't throw the DirectoryNotFoundException since this is a subdir and
                // there could be a race condition between two Directory.Delete callers
                if (errorCode == Interop.mincore.Errors.ERROR_PATH_NOT_FOUND && !throwOnTopLevelDirectoryNotFound)
                {
                    return;
                }

                throw Win32Marshal.GetExceptionForWin32Error(errorCode, fullPath);
            }
        }
Exemple #5
0
        [System.Security.SecurityCritical]  // auto-generated
        internal static int FillAttributeInfo(String path, ref Interop.mincore.WIN32_FILE_ATTRIBUTE_DATA data, bool tryagain, bool returnErrorOnNotFound)
        {
            int errorCode = 0;

            if (tryagain) // someone has a handle to the file open, or other error
            {
                Interop.mincore.WIN32_FIND_DATA findData;
                findData = new Interop.mincore.WIN32_FIND_DATA();

                // Remove trialing slash since this can cause grief to FindFirstFile. You will get an invalid argument error
                String tempPath = path.TrimEnd(PathHelpers.DirectorySeparatorChars);

                // For floppy drives, normally the OS will pop up a dialog saying
                // there is no disk in drive A:, please insert one.  We don't want that.
                // SetErrorMode will let us disable this, but we should set the error
                // mode back, since this may have wide-ranging effects.
                uint oldMode = Interop.mincore.SetErrorMode(Interop.mincore.SEM_FAILCRITICALERRORS);
                try
                {
                    bool           error  = false;
                    SafeFindHandle handle = Interop.mincore.FindFirstFile(tempPath, ref findData);
                    try
                    {
                        if (handle.IsInvalid)
                        {
                            error     = true;
                            errorCode = Marshal.GetLastWin32Error();

                            if (errorCode == Interop.mincore.Errors.ERROR_FILE_NOT_FOUND ||
                                errorCode == Interop.mincore.Errors.ERROR_PATH_NOT_FOUND ||
                                errorCode == Interop.mincore.Errors.ERROR_NOT_READY)  // floppy device not ready
                            {
                                if (!returnErrorOnNotFound)
                                {
                                    // Return default value for backward compatibility
                                    errorCode           = 0;
                                    data.fileAttributes = -1;
                                }
                            }
                            return(errorCode);
                        }
                    }
                    finally
                    {
                        // Close the Win32 handle
                        try
                        {
                            handle.Dispose();
                        }
                        catch
                        {
                            // if we're already returning an error, don't throw another one.
                            if (!error)
                            {
                                throw Win32Marshal.GetExceptionForLastWin32Error();
                            }
                        }
                    }
                }
                finally
                {
                    Interop.mincore.SetErrorMode(oldMode);
                }

                // Copy the information to data
                data.PopulateFrom(ref findData);
            }
            else
            {
                // For floppy drives, normally the OS will pop up a dialog saying
                // there is no disk in drive A:, please insert one.  We don't want that.
                // SetErrorMode will let us disable this, but we should set the error
                // mode back, since this may have wide-ranging effects.
                bool success = false;
                uint oldMode = Interop.mincore.SetErrorMode(Interop.mincore.SEM_FAILCRITICALERRORS);
                try
                {
                    success = Interop.mincore.GetFileAttributesEx(path, Interop.mincore.GET_FILEEX_INFO_LEVELS.GetFileExInfoStandard, ref data);
                }
                finally
                {
                    Interop.mincore.SetErrorMode(oldMode);
                }

                if (!success)
                {
                    errorCode = Marshal.GetLastWin32Error();
                    if (errorCode != Interop.mincore.Errors.ERROR_FILE_NOT_FOUND &&
                        errorCode != Interop.mincore.Errors.ERROR_PATH_NOT_FOUND &&
                        errorCode != Interop.mincore.Errors.ERROR_NOT_READY)  // floppy device not ready
                    {
                        // In case someone latched onto the file. Take the perf hit only for failure
                        return(FillAttributeInfo(path, ref data, true, returnErrorOnNotFound));
                    }
                    else
                    {
                        if (!returnErrorOnNotFound)
                        {
                            // Return default value for backward compatibility
                            errorCode           = 0;
                            data.fileAttributes = -1;
                        }
                    }
                }
            }

            return(errorCode);
        }
Exemple #6
0
        // Returns 0 on success, otherwise a Win32 error code.  Note that
        // classes should use -1 as the uninitialized state for dataInitialized.
        internal static int FillAttributeInfo(String path, ref Win32Native.WIN32_FILE_ATTRIBUTE_DATA data, bool tryagain, bool returnErrorOnNotFound)
        {
            int dataInitialised = 0;

            if (tryagain) // someone has a handle to the file open, or other error
            {
                Win32Native.WIN32_FIND_DATA findData;
                findData = new Win32Native.WIN32_FIND_DATA();

                // Remove trialing slash since this can cause grief to FindFirstFile. You will get an invalid argument error
                String tempPath = path.TrimEnd(new char[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar });

#if !PLATFORM_UNIX
                // For floppy drives, normally the OS will pop up a dialog saying
                // there is no disk in drive A:, please insert one.  We don't want that.
                // SetThreadErrorMode will let us disable this, but we should set the error
                // mode back, since this may have wide-ranging effects.
                uint oldMode;
                bool errorModeSuccess = Interop.Kernel32.SetThreadErrorMode(Interop.Kernel32.SEM_FAILCRITICALERRORS, out oldMode);
                try
                {
#endif
                bool error            = false;
                SafeFindHandle handle = Win32Native.FindFirstFile(tempPath, findData);
                try
                {
                    if (handle.IsInvalid)
                    {
                        error           = true;
                        dataInitialised = Marshal.GetLastWin32Error();

                        if (dataInitialised == Win32Native.ERROR_FILE_NOT_FOUND ||
                            dataInitialised == Win32Native.ERROR_PATH_NOT_FOUND ||
                            dataInitialised == Win32Native.ERROR_NOT_READY)      // floppy device not ready
                        {
                            if (!returnErrorOnNotFound)
                            {
                                // Return default value for backward compatibility
                                dataInitialised     = 0;
                                data.fileAttributes = -1;
                            }
                        }
                        return(dataInitialised);
                    }
                }
                finally
                {
                    // Close the Win32 handle
                    try
                    {
                        handle.Close();
                    }
                    catch
                    {
                        // if we're already returning an error, don't throw another one.
                        if (!error)
                        {
                            Debug.Assert(false, "File::FillAttributeInfo - FindClose failed!");
                            throw Win32Marshal.GetExceptionForLastWin32Error();
                        }
                    }
                }
#if !PLATFORM_UNIX
            }
            finally
            {
                if (errorModeSuccess)
                {
                    Interop.Kernel32.SetThreadErrorMode(oldMode, out oldMode);
                }
            }
#endif

                // Copy the information to data
                data.PopulateFrom(findData);
            }
            else
            {
                bool success = false;

#if !PLATFORM_UNIX
                // For floppy drives, normally the OS will pop up a dialog saying
                // there is no disk in drive A:, please insert one.  We don't want that.
                // SetThreadErrorMode will let us disable this, but we should set the error
                // mode back, since this may have wide-ranging effects.
                uint oldMode;
                bool errorModeSuccess = Interop.Kernel32.SetThreadErrorMode(Interop.Kernel32.SEM_FAILCRITICALERRORS, out oldMode);
                try
                {
#endif
                success = Win32Native.GetFileAttributesEx(path, GetFileExInfoStandard, ref data);
#if !PLATFORM_UNIX
            }
            finally
            {
                if (errorModeSuccess)
                {
                    Interop.Kernel32.SetThreadErrorMode(oldMode, out oldMode);
                }
            }
#endif

                if (!success)
                {
                    dataInitialised = Marshal.GetLastWin32Error();
                    if (dataInitialised != Win32Native.ERROR_FILE_NOT_FOUND &&
                        dataInitialised != Win32Native.ERROR_PATH_NOT_FOUND &&
                        dataInitialised != Win32Native.ERROR_NOT_READY)  // floppy device not ready
                    {
                        // In case someone latched onto the file. Take the perf hit only for failure
                        return(FillAttributeInfo(path, ref data, true, returnErrorOnNotFound));
                    }
                    else
                    {
                        if (!returnErrorOnNotFound)
                        {
                            // Return default value for backward compbatibility
                            dataInitialised     = 0;
                            data.fileAttributes = -1;
                        }
                    }
                }
            }

            return(dataInitialised);
        }
Exemple #7
0
        private static void RemoveDirectoryRecursive(string fullPath, ref Interop.Kernel32.WIN32_FIND_DATA findData, bool topLevel)
        {
            int       errorCode;
            Exception exception = null;

            using (SafeFindHandle handle = Interop.Kernel32.FindFirstFile(Path.Join(fullPath, "*"), ref findData))
            {
                if (handle.IsInvalid)
                {
                    throw Win32Marshal.GetExceptionForLastWin32Error(fullPath);
                }

                do
                {
                    if ((findData.dwFileAttributes & Interop.Kernel32.FileAttributes.FILE_ATTRIBUTE_DIRECTORY) == 0)
                    {
                        // File
                        string fileName = findData.cFileName.GetStringFromFixedBuffer();
                        if (!Interop.Kernel32.DeleteFile(Path.Combine(fullPath, fileName)) && exception == null)
                        {
                            errorCode = Marshal.GetLastWin32Error();

                            // We don't care if something else deleted the file first
                            if (errorCode != Interop.Errors.ERROR_FILE_NOT_FOUND)
                            {
                                exception = Win32Marshal.GetExceptionForWin32Error(errorCode, fileName);
                            }
                        }
                    }
                    else
                    {
                        // Directory, skip ".", "..".
                        if (findData.cFileName.FixedBufferEqualsString(".") || findData.cFileName.FixedBufferEqualsString(".."))
                        {
                            continue;
                        }

                        string fileName = findData.cFileName.GetStringFromFixedBuffer();

                        if (!IsNameSurrogateReparsePoint(ref findData))
                        {
                            // Not a reparse point, or the reparse point isn't a name surrogate, recurse.
                            try
                            {
                                RemoveDirectoryRecursive(
                                    Path.Combine(fullPath, fileName),
                                    findData: ref findData,
                                    topLevel: false);
                            }
                            catch (Exception e)
                            {
                                if (exception == null)
                                {
                                    exception = e;
                                }
                            }
                        }
                        else
                        {
                            // Name surrogate reparse point, don't recurse, simply remove the directory.
                            // If a mount point, we have to delete the mount point first.
                            if (findData.dwReserved0 == Interop.Kernel32.IOReparseOptions.IO_REPARSE_TAG_MOUNT_POINT)
                            {
                                // Mount point. Unmount using full path plus a trailing '\'.
                                // (Note: This doesn't remove the underlying directory)
                                string mountPoint = Path.Join(fullPath, fileName, PathInternal.DirectorySeparatorCharAsString);
                                if (!Interop.Kernel32.DeleteVolumeMountPoint(mountPoint) && exception == null)
                                {
                                    errorCode = Marshal.GetLastWin32Error();
                                    if (errorCode != Interop.Errors.ERROR_SUCCESS &&
                                        errorCode != Interop.Errors.ERROR_PATH_NOT_FOUND)
                                    {
                                        exception = Win32Marshal.GetExceptionForWin32Error(errorCode, fileName);
                                    }
                                }
                            }

                            // Note that RemoveDirectory on a symbolic link will remove the link itself.
                            if (!Interop.Kernel32.RemoveDirectory(Path.Combine(fullPath, fileName)) && exception == null)
                            {
                                errorCode = Marshal.GetLastWin32Error();
                                if (errorCode != Interop.Errors.ERROR_PATH_NOT_FOUND)
                                {
                                    exception = Win32Marshal.GetExceptionForWin32Error(errorCode, fileName);
                                }
                            }
                        }
                    }
                } while (Interop.Kernel32.FindNextFile(handle, ref findData));

                if (exception != null)
                {
                    throw exception;
                }

                errorCode = Marshal.GetLastWin32Error();
                if (errorCode != Interop.Errors.ERROR_SUCCESS && errorCode != Interop.Errors.ERROR_NO_MORE_FILES)
                {
                    throw Win32Marshal.GetExceptionForWin32Error(errorCode, fullPath);
                }
            }

            // As we successfully removed all of the files we shouldn't care about the directory itself
            // not being empty. As file deletion is just a marker to remove the file when all handles
            // are closed we could still have contents hanging around.
            RemoveDirectoryInternal(fullPath, topLevel: topLevel, allowDirectoryNotEmpty: true);
        }
Exemple #8
0
        private static void RemoveDirectoryRecursive(string fullPath, ref Interop.Kernel32.WIN32_FIND_DATA findData, bool topLevel)
        {
            int       errorCode;
            Exception exception = null;

            using (SafeFindHandle handle = Interop.Kernel32.FindFirstFile(Directory.EnsureTrailingDirectorySeparator(fullPath) + "*", ref findData))
            {
                if (handle.IsInvalid)
                {
                    throw Win32Marshal.GetExceptionForLastWin32Error(fullPath);
                }

                do
                {
                    if ((findData.dwFileAttributes & Interop.Kernel32.FileAttributes.FILE_ATTRIBUTE_DIRECTORY) == 0)
                    {
                        // File
                        string fileName = findData.cFileName.GetStringFromFixedBuffer();
                        if (!Interop.Kernel32.DeleteFile(Path.Combine(fullPath, fileName)) && exception == null)
                        {
                            errorCode = Marshal.GetLastWin32Error();

                            // We don't care if something else deleted the file first
                            if (errorCode != Interop.Errors.ERROR_FILE_NOT_FOUND)
                            {
                                exception = Win32Marshal.GetExceptionForWin32Error(errorCode, fileName);
                            }
                        }
                    }
                    else
                    {
                        // Directory, skip ".", "..".
                        if (findData.cFileName.FixedBufferEqualsString(".") || findData.cFileName.FixedBufferEqualsString(".."))
                        {
                            continue;
                        }

                        string fileName = findData.cFileName.GetStringFromFixedBuffer();
                        if ((findData.dwFileAttributes & (int)FileAttributes.ReparsePoint) == 0)
                        {
                            // Not a reparse point, recurse.
                            try
                            {
                                RemoveDirectoryRecursive(
                                    Path.Combine(fullPath, fileName),
                                    findData: ref findData,
                                    topLevel: false);
                            }
                            catch (Exception e)
                            {
                                if (exception == null)
                                {
                                    exception = e;
                                }
                            }
                        }
                        else
                        {
                            // Reparse point, don't recurse, just remove. (dwReserved0 is documented for this flag)
                            if (findData.dwReserved0 == Interop.Kernel32.IOReparseOptions.IO_REPARSE_TAG_MOUNT_POINT)
                            {
                                // Mount point. Unmount using full path plus a trailing '\'.
                                // (Note: This doesn't remove the underlying directory)
                                string mountPoint = Path.Combine(fullPath, fileName + PathHelpers.DirectorySeparatorCharAsString);
                                if (!Interop.Kernel32.DeleteVolumeMountPoint(mountPoint) && exception == null)
                                {
                                    errorCode = Marshal.GetLastWin32Error();
                                    if (errorCode != Interop.Errors.ERROR_SUCCESS &&
                                        errorCode != Interop.Errors.ERROR_PATH_NOT_FOUND)
                                    {
                                        exception = Win32Marshal.GetExceptionForWin32Error(errorCode, fileName);
                                    }
                                }
                            }

                            // Note that RemoveDirectory on a symbolic link will remove the link itself.
                            if (!Interop.Kernel32.RemoveDirectory(Path.Combine(fullPath, fileName)) && exception == null)
                            {
                                errorCode = Marshal.GetLastWin32Error();
                                if (errorCode != Interop.Errors.ERROR_PATH_NOT_FOUND)
                                {
                                    exception = Win32Marshal.GetExceptionForWin32Error(errorCode, fileName);
                                }
                            }
                        }
                    }
                } while (Interop.Kernel32.FindNextFile(handle, ref findData));

                if (exception != null)
                {
                    throw exception;
                }

                errorCode = Marshal.GetLastWin32Error();
                if (errorCode != Interop.Errors.ERROR_SUCCESS && errorCode != Interop.Errors.ERROR_NO_MORE_FILES)
                {
                    throw Win32Marshal.GetExceptionForWin32Error(errorCode, fullPath);
                }
            }

            RemoveDirectoryInternal(fullPath, topLevel: topLevel);
        }
        internal unsafe int GetFullPathName()
        {
            if (useStackAlloc)
            {
                char *finalBuffer = stackalloc char[Path.MaxPath + 1];
                int   result      = Interop.mincore.GetFullPathNameW(m_arrayPtr, Path.MaxPath + 1, finalBuffer, IntPtr.Zero);

                // If success, the return buffer length does not account for the terminating null character.
                // If in-sufficient buffer, the return buffer length does account for the path + the terminating null character.
                // If failure, the return buffer length is zero
                if (result > Path.MaxPath)
                {
                    char *tempBuffer = stackalloc char[result];
                    finalBuffer = tempBuffer;
                    result      = Interop.mincore.GetFullPathNameW(m_arrayPtr, result, finalBuffer, IntPtr.Zero);
                }

                // Full path is genuinely long
                if (result >= Path.MaxPath)
                {
                    throw new PathTooLongException(SR.IO_PathTooLong);
                }

                Contract.Assert(result < Path.MaxPath, "did we accidently remove a PathTooLongException check?");
                if (result == 0 && m_arrayPtr[0] != '\0')
                {
                    throw Win32Marshal.GetExceptionForLastWin32Error();
                }

                else if (result < Path.MaxPath)
                {
                    // Null terminate explicitly (may be only needed for some cases such as empty strings)
                    // GetFullPathName return length doesn't account for null terminating char...
                    finalBuffer[result] = '\0'; // Safe to write directly as result is < Path.MaxPath
                }

                // We have expanded the paths and GetLongPathName may or may not behave differently from before.
                // We need to call it again to see:
                doNotTryExpandShortFileName = false;

                Wstrcpy(m_arrayPtr, finalBuffer, result);
                // Doesn't account for null terminating char. Think of this as the last
                // valid index into the buffer but not the length of the buffer
                Length = result;
                return(result);
            }
            else
            {
                StringBuilder finalBuffer = new StringBuilder(m_capacity + 1);
                int           result      = Interop.mincore.GetFullPathNameW(m_sb.ToString(), m_capacity + 1, finalBuffer, IntPtr.Zero);

                // If success, the return buffer length does not account for the terminating null character.
                // If in-sufficient buffer, the return buffer length does account for the path + the terminating null character.
                // If failure, the return buffer length is zero
                if (result > m_maxPath)
                {
                    finalBuffer.Length = result;
                    result             = Interop.mincore.GetFullPathNameW(m_sb.ToString(), result, finalBuffer, IntPtr.Zero);
                }

                // Fullpath is genuinely long
                if (result >= m_maxPath)
                {
                    throw new PathTooLongException(SR.IO_PathTooLong);
                }

                Contract.Assert(result < m_maxPath, "did we accidentally remove a PathTooLongException check?");
                if (result == 0 && m_sb[0] != '\0')
                {
                    if (Length >= m_maxPath)
                    {
                        throw new PathTooLongException(SR.IO_PathTooLong);
                    }
                    throw Win32Marshal.GetExceptionForLastWin32Error();
                }

                // We have expanded the paths and GetLongPathName may or may not behave differently from before.
                // We need to call it again to see:
                doNotTryExpandShortFileName = false;

                m_sb = finalBuffer;
                return(result);
            }
        }