Open Bug 1428304 Opened 2 years ago Updated 9 months ago

mozfile.remove() incorrectly removes the contents of symlinked directories on Windows

Categories

(Testing :: Mozbase, enhancement, P3)

Version 3
Unspecified
Windows
enhancement

Tracking

(Not tracked)

People

(Reporter: standard8, Unassigned)

References

Details

In another bug I was investigating issues with shutil.rmtree on Windows. I saw clobber.py's use of mozfile.remove() and attempted to use that, but it gave the same problems as rmtree. Switching to use `winrm.exe` as clobberer does, handles the issue correctly.

In this case I was testing removing the node_modules directory. In the directory, there's a couple of symlinked directories:

node_modules/eslint-plugin-mozilla
node_modules/eslint-plugin-spidermonkey-js

These point to their respective directories in tools/lint/eslint. They are symlinks that are set up by npm install.

Running mozfile.remove('/path/to/node_modules') causes the contents of:

tools/lint/eslint/eslint-plugin-mozilla
tools/lint/eslint/eslint-plugin-spidermonkey-js

to be removed as well as the entirety of node_modules when run on Windows. Running the same code on Mac works correctly.
mozfile.remove uses os.path.islink to determine if the path is a symlink. os.path.islink did not support Windows native symlinks until Python 3.2. What version of Python are you using?
Flags: needinfo?(standard8)
I'd have been using Python 2.7, since that's the standard baseline that Mozilla supports at the moment.
Flags: needinfo?(standard8)
Priority: -- → P3
The line of code referenced in comment 1 is here:
https://dxr.mozilla.org/mozilla-central/rev/c291143e24019097d087f9307e59b49facaf90cb/testing/mozbase/mozfile/mozfile/mozfile.py#214

I wrote some sample code for detecting symlinks on Windows and tested it locally:
```
import platform

INVALID_FILE_ATTRIBUTES = -1
FILE_ATTRIBUTE_REPARSE_POINT = 0x400

if platform.system() == 'Windows':
    import ctypes
    def is_link(path):
        path_buf = ctypes.create_unicode_buffer(path)
        return ctypes.windll.kernel32.GetFileAttributesW(path_buf) & FILE_ATTRIBUTE_REPARSE_POINT == FILE_ATTRIBUTE_REPARSE_POINT

else:
    import os
    is_link = os.path.islink
```

It should be straightforward to incorporate this into mozfile.
See Also: → 1321922
You need to log in before you can comment on or make changes to this bug.