dotnet / dotnet/wpf

Full temporary folder will crash cursor initialization

Open
#696 6 comments 3 reactions 0 assignees View on GitHub
Bug
Dominant language
C#
Stars
7.7k
Forks
1.3k
Avg merge
1d 11h
Merged PRs (30d)
61

Description

* .NET Core Version: 3.0 Preview5
* Windows version: windows 10 1903
* Does the bug reproduce also in WPF for .NET Framework 4.8?: Yes



**Problem description:**

The cursor will crash at initialization when the temporary folder full.

**Actual behavior:**

I set a cursor from a resource and use this code.

```
var uri = new Uri("pack://application:,,,/Foo.cur");
var resource = Application.GetResourceStream(uri);
Cursor = new Cursor(resource.Stream);
```

I can find the cursor will crash at initialization when the temporary folder full.

System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
System.IO.Directory.InternalCreateDirectory(String fullPath, String path, Object dirSecurityObj, Boolean checkHost)
System.IO.Directory.InternalCreateDirectoryHelper(String path, Boolean checkHost)
System.IO.Directory.CreateDirectory(String path)
System.IO.FileHelper.CreateAndOpenTemporaryFile(String& filePath, FileAccess fileAccess, FileOptions fileOptions, String extension, String subFolder)
System.Windows.Input.Cursor.LoadFromStream(Stream cursorStream)
System.Windows.Input.Cursor..ctor(Stream cursorStream, Boolean scaleWithDpi)
System.Windows.Input.Cursor..ctor(Stream cursorStream)
FawlalnejajerelaWhallgemcurkear.MainWindow..ctor()

**Expected behavior:**

The cursor can be set.

**Minimal repro:**

Run this code when the temporary folder full.

var uri = new Uri("pack://application:,,,/Text.cur");
var resource = Application.GetResourceStream(uri);
Cursor = new Cursor(resource.Stream);

And the other way is set a can not visit folder as the temp folder. And you can see the code in https://github.com/lindexi/lindexi_gd/tree/8e346e750fe2075e1366a2a098d63af3b50db177/FawlalnejajerelaWhallgemcurkear that I set a folder name as `D:\lindexi\不存在文件` that is an unauthorized access folder.

**Reason**

The Cursor.LegacyLoadFromStream will generate a temporary file based on the memory stream. But the [Path.GetTempFileName Method](https://docs.microsoft.com/en-us/dotnet/api/system.io.path.gettempfilename?wt.mc_id=MVP ) limit the number of the files is 65535 and it will throw IOException when overcount.

The LoadFromStream code in https://referencesource.microsoft.com/#PresentationCore/Core/CSharp/System/Windows/Input/Cursor.cs,090cb505b6310a4e

The LegacyLoadFromStream code in https://referencesource.microsoft.com/#PresentationCore/Core/CSharp/System/Windows/Input/Cursor.cs,935d59bd1efe76e4,references

Actual LoadFromStream may ignore LegacyLoadFromStream. But FileHelper.CreateAndOpenTemporaryFile will generate the file in WPF folder by default and use Path.GetRandomFileName to create a file without check access. And it also crashes when the temp folder can not write.

**solution**

1. Set the Environment Variable to the own folder that can read or write.
```
Environment.SetEnvironmentVariable("TEMP", newTempFolder);
Environment.SetEnvironmentVariable("TMP", newTempFolder);
```
Why set the environment variable is safe? Because all the process can call the `Path.GetTempFileName` that will throw IOException when the other process uses it to create and do not delete.
1. Use the `public Cursor(string cursorFile)` replace `public Cursor(Stream cursorStream)` that the first will call LoadFromFile and the LoadFromFile will load the file and do not need to copy to temp folder.

Reference

[WPF 光标初始化的时候 temp 文件夹满了无法创建](https://blog.lindexi.com/post/WPF-%E5%85%89%E6%A0%87%E5%88%9D%E5%A7%8B%E5%8C%96%E7%9A%84%E6%97%B6%E5%80%99-temp-%E6%96%87%E4%BB%B6%E5%A4%B9%E6%BB%A1%E4%BA%86%E6%97%A0%E6%B3%95%E5%88%9B%E5%BB%BA.html )

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.