11

Under some circumstances, the rm command in Git-Bash deletes files that can't be deleted in explorer, cmd prompt, PowerShell, or using C++ standard library calls.

Why?

This is perplexing to me because I know there is no magic here and I assume that they are all using the same Win32 API.

For example, I have database snapshots that remain open and cannot be deleted using the other methods described, but are successfully deleted by Git-Bash rm:

Explorer delete: "The action cannot be completed because the file is open."

cmd: del <path> : "Access is denied"

PS: Remove-Item -Force -Path <path> : "Cannot remove item. Access to the path is denied."

C++ remove() : returns -1

C++ unlink() : returns -1

C++ _unlink() : returns -1

git-bash rm <path> : success

The above can be performed repeatedly on different files.

There are other locked files that git-bash rm deletes successfully as well (I have used it in the past, not recently and I don't have other specific examples).

However it doesn't always work: In a test application I opened a text file using fopen() and none of the methods, including Git-Bash rm, could successfully delete it.

So, how does Git-Bash rm work?

Clijsters
  • 4,031
  • 1
  • 27
  • 37
apamburn
  • 191
  • 1
  • 8
  • I ma not sure mingw always considered Windows lock status though: https://stackoverflow.com/a/39159518/6309 – VonC Jan 23 '18 at 05:33
  • 1
    Probably because the file is locked by git or something related to git-bash? – user202729 Jan 23 '18 at 07:01
  • i would think that git-bash itself is locking the file – 4c74356b41 Jan 23 '18 at 08:15
  • In the cases I have seen, git bash is not locking the file. Specifically in the database example provided, the snapshots are locked by the database process and I can delete the snapshots "out from under" the process when logged in as an administrator user that does not own the database process. – apamburn Jan 23 '18 at 15:09
  • @vonc right: I can only assume that git-bash "rm" is omitting a permissions or lock check that the other applications do not. But how? I have looked at both mingw and git-bash repositories and I haven't been able to find the implementation of "rm" and even the win32 API calls to remove(), unlink(), and _unlink() don't work... – apamburn Jan 23 '18 at 15:17
  • @apamburn Agreed. You can have a look at https://github.com/git/git/commit/05d1ed6148305d299693000856e4971e9f642662#diff-2d323e09cb6c177bad72feb74df05c8b, and https://github.com/git/git/blob/05d1ed6148305d299693000856e4971e9f642662/tempfile.c#L300-L310 for example. – VonC Jan 23 '18 at 15:51
  • I appreciate the links, but none of them quite seem to get at the original question: How can git-bash for windows `rm ` close files opened by a different process that has an open file handle for the files in question, when other windows tools can't? (**not `git rm `, just `rm ` on the git-bash terminal**). The commits linked appear to refer to opening files with mingw in such a way that they can be later closed, and closing those files. – apamburn Jan 23 '18 at 18:41

1 Answers1

7

I was able to figure out how this works.

Interestingly, I used Git-Bash's strace utility on it's rm command.

It turns out that Git Bash uses CygWin, and the delete routine is found in the CygWin syscalls.cc file which tries to delete a file in a few different ways.

Eventually it tries to move the file to the Recycle Bin, where it deletes the locked file by opening it with the Windows Driver call NtOpenFile() with a FILE_DELETE_ON_CLOSE flag, then closing it using NtClose().

Not sure if it would be proper to copy CygWin's code into the response here, but details on all of the above can be found in the link provided.

apamburn
  • 191
  • 1
  • 8