Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deleting a symlink actually deletes the target file #401

Closed
mheinzler opened this issue Oct 25, 2021 · 4 comments
Closed

Deleting a symlink actually deletes the target file #401

mheinzler opened this issue Oct 25, 2021 · 4 comments

Comments

@mheinzler
Copy link

Bug Report

When deleting a symlink in a WinFsp filesystem with Windows Explorer the symlink target is deleted instead. Deleting the link with other tools (cmd, etc.) works correctly. I first noticed this in my filesystem but it can also be reproduced with MEMFS.

I attached log files and traces from Process Monitor of the deletion process here: logs.zip

The files memfs-delete-symlink* are about the bug, the memfs-delete-file* ones are only for comparison and show the deletion of a normal file. The logs have separators (********) to highlight the actual deletion parts.

How to Reproduce

  1. Mount a simple MEMFS filesystem: memfs-x64.exe -m Y:
  2. Create a test file: "New Text Document.txt"
  3. Create a symlink to the test file: "New Text Document - SymbolicLink.txt"
  4. Delete the symlink with Windows Explorer
  5. The symlink is still there but broken and the original file was deleted instead

Behaviors

From what I have seen yet, my best guess is that it has to do with Windows Explorer using CreateFile with a Delete On Close option to delete a file. It then sees that the file is a symlink and tries the same thing again with the target file which results in the wrong file being deleted. In most cases this will probably result in data loss.

Environment

  • OS version and build: Windows 10 20H2 / 19042.1288
  • WinFsp version and build: 2021 / 1.9.21096.0
@billziss-gh
Copy link
Collaborator

Thanks for the report. Looking at this now.

@billziss-gh
Copy link
Collaborator

billziss-gh commented Oct 31, 2021

Able to Reproduce

I am able to reproduce your findings using the following steps:

  • Create a file named \file from Command Prompt: echo file > file
  • Create a link named \link from Command Prompt: mklink link file
  • Delete the link named \link from Explorer.

By following these steps the file named \file gets deleted instead of the link named \link.

Analysis

I ran the file system using the command line memfs-x64.exe -d -1 -D memfs.log -m Y:. I used FileSpy to look at the file system traffic, which is my tool of choice to diagnose such problems.

Below is an excerpt from the FileSpy log.

364	explorer.exe	IRP_MJ_DIRECTORY_CONTROL/IRP_MN_QUERY_DIRECTORY	\Device\Volume{a18be7f7-39b7-11ec-9b0d-58961d948059}	STATUS_SUCCESS	FileIdBothDirectoryInformation FileMask: link
...
367	explorer.exe	IRP_MJ_CREATE	\Device\Volume{a18be7f7-39b7-11ec-9b0d-58961d948059}\link	STATUS_REPARSE	FILE_OPEN CreOpts: 00001040 Access: 00010000 Share:  00000004 Attrib: 0
368	explorer.exe	IRP_MJ_CREATE	\Device\Volume{a18be7f7-39b7-11ec-9b0d-58961d948059}\file	STATUS_SUCCESS	FILE_OPEN CreOpts: 00001040 Access: 00010000 Share:  00000004 Attrib: 0 Result: FILE_OPENED
370	explorer.exe	IRP_MJ_CLEANUP	\Device\Volume{a18be7f7-39b7-11ec-9b0d-58961d948059}\file	STATUS_SUCCESS	

Log analysis:

  • Line 367 shows \link being opened with options 0x1040 == FILE_NON_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE. The result is STATUS_REPARSE. The kernel follows up by attempting to open the pointed \file as described in line 368.
  • Line 368 shows \file being opened with options 0x1040 == FILE_NON_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE. The result is STATUS_SUCCESS.
  • Line 370 shows \file being cleaned up (and deleted).

According to the CreateFileW Symbolic Link Behavior documentation:

  • If FILE_FLAG_OPEN_REPARSE_POINT is not specified:
    • If an existing file is opened and it is a symbolic link, the handle returned is a handle to the target.
    • If CREATE_ALWAYS, TRUNCATE_EXISTING, or FILE_FLAG_DELETE_ON_CLOSE are specified, the file affected is the target.

Based on this documentation it looks like WinFsp/MEMFS interpret the instruction specified in line 367 correctly. If Explorer wants to delete \link instead of \file it should send FILE_NON_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT | FILE_DELETE_ON_CLOSE.

Possible Resolution

The question then becomes: why does Explorer send the wrong CreateOptions?

I do not know the reason for certain, but I have a suspicion. Notice that in line 364 Explorer sent us a QueryDirectory with FileIdBothDirectoryInformation. In a recent investigation (see #380) it was discovered that the EaSize field in FILE_ID_BOTH_DIR_INFORMATION is also used to pass reparse tag information for reparse points. My suspicion is that when Explorer sees EaSize==0 (which it interprets as reparse tag) it blindly assumes that the file is not a reparse point (despite the fact that the FileAttributes field reports FILE_ATTRIBUTE_REPARSE_POINT) and fails to open \link with FILE_OPEN_REPARSE_POINT.

While fixing issue #380 I added commit 3e66082. I suspect that the same commit may fix our problem as well.

@billziss-gh
Copy link
Collaborator

I can confirm that the upcoming release 2021.1 Beta3 (due for release later today) fixes this problem.

Closing. Please reopen if you find that the problem is not fixed after trying release 2021.1 Beta3.

@mheinzler
Copy link
Author

I can also no longer reproduce the issue.

Thanks a lot for the quick fix!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants