Repository: pytest-dev/pyfakefs (language: python)

Issue:
shutil.rmtree failing in OSType.WINDOWS with PermissionError
**Describe the bug**

I expect this to succeed, and not fail.

```
Traceback (most recent call last):
  File "/private/var/folders/qk/hmjj9_lx2cg3_4v3vx3y7y_w0000gn/T/tmp.L4ZwvgaUdy/test.py", line 12, in <module>
    shutil.rmtree("C:\\test.checkout\\LayoutTests\\imported\\w3c")
  File "/opt/homebrew/Cellar/python@3.12/3.12.2_1/Frameworks/Python.framework/Versions/3.12/lib/python3.12/shutil.py", line 781, in rmtree
    onexc(os.open, path, err)
  File "/opt/homebrew/Cellar/python@3.12/3.12.2_1/Frameworks/Python.framework/Versions/3.12/lib/python3.12/shutil.py", line 778, in rmtree
    fd = os.open(path, os.O_RDONLY, dir_fd=dir_fd)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/private/var/folders/qk/hmjj9_lx2cg3_4v3vx3y7y_w0000gn/T/tmp.L4ZwvgaUdy/venv/lib/python3.12/site-packages/pyfakefs/fake_os.py", line 1353, in wrapped
    return f(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^
  File "/private/var/folders/qk/hmjj9_lx2cg3_4v3vx3y7y_w0000gn/T/tmp.L4ZwvgaUdy/venv/lib/python3.12/site-packages/pyfakefs/fake_os.py", line 290, in open
    fake_file = FakeFileOpen(
                ^^^^^^^^^^^^^
  File "/private/var/folders/qk/hmjj9_lx2cg3_4v3vx3y7y_w0000gn/T/tmp.L4ZwvgaUdy/venv/lib/python3.12/site-packages/pyfakefs/fake_open.py", line 97, in __call__
    return self.call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/private/var/folders/qk/hmjj9_lx2cg3_4v3vx3y7y_w0000gn/T/tmp.L4ZwvgaUdy/venv/lib/python3.12/site-packages/pyfakefs/fake_open.py", line 205, in call
    self.filesystem.raise_os_error(errno.EACCES, file_path)
  File "/private/var/folders/qk/hmjj9_lx2cg3_4v3vx3y7y_w0000gn/T/tmp.L4ZwvgaUdy/venv/lib/python3.12/site-packages/pyfakefs/fake_filesystem.py", line 427, in raise_os_error
    raise OSError(err_no, message, filename)
PermissionError: [Errno 13] Permission denied in the fake filesystem: 'C:\\test.checkout\\LayoutTests\\imported\\w3c'
```

**How To Reproduce**
```python
import os
import shutil

from pyfakefs.fake_filesystem import OSType
from pyfakefs.fake_filesystem_unittest import Patcher

with Patcher() as patcher:
    fs = patcher.fs
    fs.os = OSType.WINDOWS

    os.makedirs("C:\\test.checkout\\LayoutTests\\imported\\w3c\\resources")
    shutil.rmtree("C:\\test.checkout\\LayoutTests\\imported\\w3c")
```

**Your environment**
```bash
% python -c "import platform; print(platform.platform())"
python -c "import sys; print('Python', sys.version)"
python -c "from pyfakefs import __version__; print('pyfakefs', __version__)"
python -c "import pytest; print('pytest', pytest.__version__)"
macOS-14.4-arm64-arm-64bit
Python 3.12.2 (main, Feb  6 2024, 20:19:44) [Clang 15.0.0 (clang-1500.1.0.2.5)]
pyfakefs 5.3.5
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ModuleNotFoundError: No module named 'pytest'
```



Discussion / hints:
Thanks for the report! 


Fix patch:
diff --git a/CHANGES.md b/CHANGES.md
index f0366160..ca96be64 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -23,6 +23,8 @@ The released versions correspond to PyPI releases.
 * fixed handling of `dirfd` in `os.symlink` (see [#968](../../issues/968))
 * add missing `follow_symlink` argument to `os.link` (see [#973](../../issues/973))
 * fixed handling of missing attribute in `os.getxattr` (see [#971](../../issues/971))
+* fixed permission problem with `shutil.rmtree` if emulating Windows under POSIX
+  (see [#979](../../issues/979))
 
 ### Enhancements
 * added support for `O_NOFOLLOW` and `O_DIRECTORY` flags in `os.open`


Test patch:
diff --git a/pyfakefs/fake_filesystem_unittest.py b/pyfakefs/fake_filesystem_unittest.py
index f7fb6e74..231e2075 100644
--- a/pyfakefs/fake_filesystem_unittest.py
+++ b/pyfakefs/fake_filesystem_unittest.py
@@ -919,6 +919,10 @@ def setUp(self, doctester: Any = None) -> None:
         if self.has_fcopy_file:
             shutil._HAS_FCOPYFILE = False  # type: ignore[attr-defined]
 
+        # do not use the fd functions, as they may not be available in the target OS
+        if hasattr(shutil, "_use_fd_functions"):
+            shutil._use_fd_functions = False  # type: ignore[module-attr]
+
         with warnings.catch_warnings():
             # ignore warnings, see #542 and #614
             warnings.filterwarnings("ignore")
diff --git a/pyfakefs/tests/fake_filesystem_shutil_test.py b/pyfakefs/tests/fake_filesystem_shutil_test.py
index 9043b8dd..5516415d 100644
--- a/pyfakefs/tests/fake_filesystem_shutil_test.py
+++ b/pyfakefs/tests/fake_filesystem_shutil_test.py
@@ -192,6 +192,15 @@ def error_handler(_, path, _error_info):
         self.assertFalse(NonLocal.errorHandled)
         self.assertEqual(NonLocal.errorPath, "")
 
+    def test_rmtree_in_windows(self):
+        # regression test for #979
+        self.check_windows_only()
+        base_path = self.make_path("foo", "bar")
+        self.os.makedirs(self.os.path.join(base_path, "res"))
+        self.assertTrue(self.os.path.exists(base_path))
+        shutil.rmtree(base_path)
+        self.assertFalse(self.os.path.exists(base_path))
+
     def test_copy(self):
         src_file = self.make_path("xyzzy")
         dst_file = self.make_path("xyzzy_copy")