filename used for testing disambiguate testfn for parallel testing while letting it remain a valid module name testfnunicode is a nonascii filename in mac os x s vfs api file names are by definition canonically decomposed unicode encoded using utf8 see qa1173 http developer apple commaclibraryqaqa2001qa1173 html testfnunencodable is a filename str type that should not be able to be encoded by the filesystem encoding in strict mode it can be none if we cannot generate such filename skip win32s 0 or windows 9xme 1 different kinds of characters from various languages to minimize the probability that the whole name is encodable to mbcs issue 9819 macos and emscripten deny unencodable filenames invalid utf8 ascii and utf8 cannot encode the byte 0xff 0xff will be encoded using the surrogate character udcff file system encoding eg iso8859 encodings can encode the byte 0xff skip some unicode filename tests fsnonascii nonascii character encodable by os fsencode or an empty string if there is no such character first try printable and common characters to have a readable filename for each character the encoding list are just example of encodings able to encode the character the list is not exhaustive u00e6 latin small letter ae cp1252 iso88591 u0130 latin capital letter i with dot above cp1254 iso88593 u0141 latin capital letter l with stroke cp1250 cp1257 u03c6 greek small letter phi cp1253 u041a cyrillic capital letter ka cp1251 u05d0 hebrew letter alef encodable to cp424 u060c arabic comma cp864 cp1006 iso88596 macarabic u062a arabic letter teh cp720 u0e01 thai character ko kai cp874 then try more special characters special because they may be interpreted or displayed differently depending on the exact locale encoding and the font u00a0 nobreak space u20ac euro sign if python is set up to use the legacy mbcs in windows replace error mode is used and encode returns b for characters missing in the ansi codepage save the initial cwd testfnundecodable is a filename bytes type that should not be able to be decoded from the filesystem encoding in strict mode it can be none if we cannot generate such filename ex the latin1 encoding can decode any byte sequence on unix testfnundecodable can be decoded by os fsdecode thanks to the surrogateescape error handler pep 383 but not from the filesystem encoding in strict mode b xff is not decodable by os fsdecode with code page 932 windows accepts it to create a file or a directory or don t accept to enter to such directory when the bytes name is used so test b xe7 first it is not decodable from cp932 undecodable from ascii utf8 undecodable from iso88593 iso88596 iso88597 cp424 iso88598 cp856 and cp857 undecodable from utf8 unix and mac os x undecodable from shiftjis cp869 cp874 cp932 cp1250 cp1251 cp1252 cp1253 cp1254 cp1255 cp1257 cp1258 create an invalid file descriptor by opening and closing a file and return its fd wasi wasmtime prevents symlinks with absolute paths see man openat22 resolvebeneath almost all symlink tests use absolute paths skip symlink tests on wasi for now skip decorator for tests that require functional symlink ok cansymlink msg requires functional symlink implementation return test if ok else unittest skipmsgtest canxattr none def canxattr import tempfile global canxattr if canxattr is not none return canxattr if not hasattros setxattr can false else import platform tmpdir tempfile mkdtemp tmpfp tmpname tempfile mkstempdirtmpdir try with opentestfn wb as fp try testfn tempfile may use different file systems with different capabilities os setxattrtmpfp buser test b os setxattrtmpname btrusted foo b42 os setxattrfp fileno buser test b kernels 2 6 39 don t respect setxattr flags kernelversion platform release m re matchr2 6 d1 2 kernelversion can m is none or intm group1 39 except oserror can false finally unlinktestfn unlinktmpname rmdirtmpdir canxattr can return can def skipunlessxattrtest skip tests that require working os chmod wasi sdk 15 0 cannot change file mode bits check whether the current effective user has the capability to override dac discretionary access control typically user root is able to bypass file read write and execute permission checks the capability is independent of the effective user see capabilities7 perform the operation now setup the wait loop check for pathname to be removed from the filesystem the exponential backoff of the timeout amounts to a total of 1 second after which the deletion is probably an error anyway testing on an i74 3ghz shows that usually only 1 iteration is required when contention occurs note we are only testing for the existence of the files in the contents of the directory regardless of any security or access rights if we have made it this far we have sufficient permissions to do that much using python s equivalent of the windows api findfirstfile other windows apis can fail or give incorrect results when dealing with files that are pending deletion increase the timeout and try again no ctypes means we can t expands paths return a context manager that creates a temporary directory arguments path the directory to create temporarily if omitted or none defaults to creating a temporary directory using tempfile mkdtemp quiet if false the default the context manager raises an exception on error otherwise if the path is specified and cannot be created only a warning is issued in case the process forks let only the parent remove the directory the child has a different process id bpo30028 return a context manager that changes the current working directory arguments path the directory to use as the temporary current working directory quiet if false the default the context manager raises an exception on error otherwise it issues only a warning and keeps the current working directory the same context manager that temporarily creates and changes the cwd the function temporarily changes the current working directory after creating a temporary directory in the current directory with name name if name is none the temporary directory is created using tempfile mkdtemp if quiet is false default and it is not possible to create or change the cwd an error is raised if quiet is true only a warning is raised and the original cwd is used create an empty file if the file already exists truncate it fd os openfilename os owronly os ocreat os otrunc os closefd contextlib contextmanager def opendirfdpath detects if the file system for the specified directory is caseinsensitive import tempfile with tempfile namedtemporaryfiledirdirectory as base basepath base name casepath basepath upper if casepath basepath casepath basepath lower try return os path samefilebasepath casepath except filenotfounderror return false class fakepath def initself path self path path def reprself return f fakepath self path r def fspathself if isinstanceself path baseexception or isinstanceself path type and issubclassself path baseexception raise self path else return self path def fdcount if sys platform startswith linux freebsd emscripten try names os listdirprocselffd subtract one because listdir internally opens a file descriptor to list the content of the procselffd directory return lennames 1 except filenotfounderror pass maxfd 256 if hasattros sysconf try maxfd os sysconfscopenmax except oserror pass oldmodes none if sys platform win32 bpo25306 bpo31009 call crtsetreportmode to not kill the process on invalid file descriptor if python is compiled in debug mode try import msvcrt msvcrt crtsetreportmode except attributeerror importerror no msvcrt or a release build pass else oldmodes for reporttype in msvcrt crtwarn msvcrt crterror msvcrt crtassert oldmodesreporttype msvcrt crtsetreportmodereporttype 0 try count 0 for fd in rangemaxfd try prefer dup over fstat fstat can require inputoutput whereas dup doesn t fd2 os dupfd except oserror as e if e errno errno ebadf raise else os closefd2 count 1 finally if oldmodes is not none for reporttype in msvcrt crtwarn msvcrt crterror msvcrt crtassert msvcrt crtsetreportmodereporttype oldmodesreporttype return count if hasattros umask contextlib contextmanager def tempumaskumask noop on platforms without umask yield class environmentvarguardcollections abc mutablemapping remember the initial value on the first access remember the initial value on the first access we do what os environ copy does temporarily yield a substitute drive for a given path for c in reversedstring asciiuppercase drive f c if not kernel32 querydosdevicewdrive none 0 and ctypes getlasterror errorfilenotfound break else raise unittest skiptest no available logical drive if not kernel32 definedosdevicew dddnobroadcastsystem drive path raise ctypes winerrorctypes getlasterror try yield drive finally if not kernel32 definedosdevicew dddremovedefinition dddexactmatchonremove drive path raise ctypes winerrorctypes getlasterror filename used for testing disambiguate testfn for parallel testing while letting it remain a valid module name testfn_unicode is a non ascii filename in mac os x s vfs api file names are by definition canonically decomposed unicode encoded using utf 8 see qa1173 http developer apple com mac library qa qa2001 qa1173 html testfn_unencodable is a filename str type that should not be able to be encoded by the filesystem encoding in strict mode it can be none if we cannot generate such filename skip win32s 0 or windows 9x me 1 different kinds of characters from various languages to minimize the probability that the whole name is encodable to mbcs issue 9819 macos and emscripten deny unencodable filenames invalid utf 8 ascii and utf 8 cannot encode the byte 0xff 0xff will be encoded using the surrogate character u dcff file system encoding eg iso 8859 encodings can encode the byte 0xff skip some unicode filename tests fs_nonascii non ascii character encodable by os fsencode or an empty string if there is no such character first try printable and common characters to have a readable filename for each character the encoding list are just example of encodings able to encode the character the list is not exhaustive u 00e6 latin small letter ae cp1252 iso 8859 1 u 0130 latin capital letter i with dot above cp1254 iso8859_3 u 0141 latin capital letter l with stroke cp1250 cp1257 u 03c6 greek small letter phi cp1253 u 041a cyrillic capital letter ka cp1251 u 05d0 hebrew letter alef encodable to cp424 u 060c arabic comma cp864 cp1006 iso8859_6 mac_arabic u 062a arabic letter teh cp720 u 0e01 thai character ko kai cp874 then try more special characters special because they may be interpreted or displayed differently depending on the exact locale encoding and the font u 00a0 no break space u 20ac euro sign if python is set up to use the legacy mbcs in windows replace error mode is used and encode returns b for characters missing in the ansi codepage save the initial cwd testfn_undecodable is a filename bytes type that should not be able to be decoded from the filesystem encoding in strict mode it can be none if we cannot generate such filename ex the latin1 encoding can decode any byte sequence on unix testfn_undecodable can be decoded by os fsdecode thanks to the surrogateescape error handler pep 383 but not from the filesystem encoding in strict mode b xff is not decodable by os fsdecode with code page 932 windows accepts it to create a file or a directory or don t accept to enter to such directory when the bytes name is used so test b xe7 first it is not decodable from cp932 undecodable from ascii utf 8 undecodable from iso8859 3 iso8859 6 iso8859 7 cp424 iso8859 8 cp856 and cp857 undecodable from utf 8 unix and mac os x undecodable from shift_jis cp869 cp874 cp932 cp1250 cp1251 cp1252 cp1253 cp1254 cp1255 cp1257 cp1258 create an invalid file descriptor by opening and closing a file and return its fd wasi wasmtime prevents symlinks with absolute paths see man openat2 2 resolve_beneath almost all symlink tests use absolute paths skip symlink tests on wasi for now skip decorator for tests that require functional symlink testfn tempfile may use different file systems with different capabilities kernels 2 6 39 don t respect setxattr flags skip decorator for tests that require functional extended attributes skip tests that require working os chmod wasi sdk 15 0 cannot change file mode bits check whether the current effective user has the capability to override dac discretionary access control typically user root is able to bypass file read write and execute permission checks the capability is independent of the effective user see capabilities 7 perform the operation now setup the wait loop check for pathname to be removed from the filesystem the exponential backoff of the timeout amounts to a total of 1 second after which the deletion is probably an error anyway testing on an i7 4 3ghz shows that usually only 1 iteration is required when contention occurs note we are only testing for the existence of the file s in the contents of the directory regardless of any security or access rights if we have made it this far we have sufficient permissions to do that much using python s equivalent of the windows api findfirstfile other windows apis can fail or give incorrect results when dealing with files that are pending deletion increase the timeout and try again no ctypes means we can t expands paths return a context manager that creates a temporary directory arguments path the directory to create temporarily if omitted or none defaults to creating a temporary directory using tempfile mkdtemp quiet if false the default the context manager raises an exception on error otherwise if the path is specified and cannot be created only a warning is issued in case the process forks let only the parent remove the directory the child has a different process id bpo 30028 return a context manager that changes the current working directory arguments path the directory to use as the temporary current working directory quiet if false the default the context manager raises an exception on error otherwise it issues only a warning and keeps the current working directory the same context manager that temporarily creates and changes the cwd the function temporarily changes the current working directory after creating a temporary directory in the current directory with name name if name is none the temporary directory is created using tempfile mkdtemp if quiet is false default and it is not possible to create or change the cwd an error is raised if quiet is true only a warning is raised and the original cwd is used create an empty file if the file already exists truncate it open a file descriptor to a directory detects if the file system for the specified directory is case insensitive simple implementation of the path protocol count the number of open file descriptors subtract one because listdir internally opens a file descriptor to list the content of the proc self fd directory bpo 25306 bpo 31009 call crtsetreportmode to not kill the process on invalid file descriptor if python is compiled in debug mode no msvcrt or a release build prefer dup over fstat fstat can require input output whereas dup doesn t context manager that temporarily sets the process umask no op on platforms without umask class to help protect the environment variable properly can be used as a context manager remember the initial value on the first access remember the initial value on the first access we do what os environ copy does temporarily yield a substitute drive for a given path
import collections.abc
import contextlib
import errno
import os
import re
import stat
import string
import sys
import time
import unittest
import warnings

from test import support



TESTFN_ASCII = '@test'



TESTFN_ASCII = "{}_{}_tmp".format(TESTFN_ASCII, os.getpid())


TESTFN_UNICODE = TESTFN_ASCII + "-\xe0\xf2\u0258\u0141\u011f"
if sys.platform == 'darwin':
    
    
    
    import unicodedata
    TESTFN_UNICODE = unicodedata.normalize('NFD', TESTFN_UNICODE)




TESTFN_UNENCODABLE = None
if os.name == 'nt':
    
    if sys.getwindowsversion().platform >= 2:
        
        
        TESTFN_UNENCODABLE = TESTFN_ASCII + "-\u5171\u0141\u2661\u0363\uDC80"
        try:
            TESTFN_UNENCODABLE.encode(sys.getfilesystemencoding())
        except UnicodeEncodeError:
            pass
        else:
            print('WARNING: The filename %r CAN be encoded by the filesystem '
                  'encoding (%s). Unicode filename tests may not be effective'
                  % (TESTFN_UNENCODABLE, sys.getfilesystemencoding()))
            TESTFN_UNENCODABLE = None

elif sys.platform not in {'darwin', 'emscripten', 'wasi'}:
    try:
        
        b'\xff'.decode(sys.getfilesystemencoding())
    except UnicodeDecodeError:
        
        TESTFN_UNENCODABLE = TESTFN_ASCII \
            + b'-\xff'.decode(sys.getfilesystemencoding(), 'surrogateescape')
    else:
        
        
        pass



FS_NONASCII = ''
for character in (
    
    
    

    
    '\u00E6',
    
    '\u0130',
    
    '\u0141',
    
    '\u03C6',
    
    '\u041A',
    
    '\u05D0',
    
    '\u060C',
    
    '\u062A',
    
    '\u0E01',

    
    
    

    
    '\u00A0',
    
    '\u20AC',
):
    try:
        
        
        
        if os.fsdecode(os.fsencode(character)) != character:
            raise UnicodeError
    except UnicodeError:
        pass
    else:
        FS_NONASCII = character
        break


SAVEDCWD = os.getcwd()







TESTFN_UNDECODABLE = None
for name in (
    
    
    
    
    b'\xe7w\xf0',
    
    b'\xff',
    
    
    b'\xae\xd5'
    
    b'\xed\xb2\x80', b'\xed\xb4\x80',
    
    
    b'\x81\x98',
):
    try:
        name.decode(sys.getfilesystemencoding())
    except UnicodeDecodeError:
        try:
            name.decode(sys.getfilesystemencoding(),
                        sys.getfilesystemencodeerrors())
        except UnicodeDecodeError:
            continue
        TESTFN_UNDECODABLE = os.fsencode(TESTFN_ASCII) + name
        break

if FS_NONASCII:
    TESTFN_NONASCII = TESTFN_ASCII + FS_NONASCII
else:
    TESTFN_NONASCII = None
TESTFN = TESTFN_NONASCII or TESTFN_ASCII


def make_bad_fd():
    
    file = open(TESTFN, "wb")
    try:
        return file.fileno()
    finally:
        file.close()
        unlink(TESTFN)


_can_symlink = None


def can_symlink():
    global _can_symlink
    if _can_symlink is not None:
        return _can_symlink
    
    
    
    src = os.path.abspath(TESTFN)
    symlink_path = src + "can_symlink"
    try:
        os.symlink(src, symlink_path)
        can = True
    except (OSError, NotImplementedError, AttributeError):
        can = False
    else:
        os.remove(symlink_path)
    _can_symlink = can
    return can


def skip_unless_symlink(test):
    
    ok = can_symlink()
    msg = "Requires functional symlink implementation"
    return test if ok else unittest.skip(msg)(test)


_can_xattr = None


def can_xattr():
    import tempfile
    global _can_xattr
    if _can_xattr is not None:
        return _can_xattr
    if not hasattr(os, "setxattr"):
        can = False
    else:
        import platform
        tmp_dir = tempfile.mkdtemp()
        tmp_fp, tmp_name = tempfile.mkstemp(dir=tmp_dir)
        try:
            with open(TESTFN, "wb") as fp:
                try:
                    
                    
                    os.setxattr(tmp_fp, b"user.test", b"")
                    os.setxattr(tmp_name, b"trusted.foo", b"42")
                    os.setxattr(fp.fileno(), b"user.test", b"")
                    
                    kernel_version = platform.release()
                    m = re.match(r"2.6.(\d{1,2})", kernel_version)
                    can = m is None or int(m.group(1)) >= 39
                except OSError:
                    can = False
        finally:
            unlink(TESTFN)
            unlink(tmp_name)
            rmdir(tmp_dir)
    _can_xattr = can
    return can


def skip_unless_xattr(test):
    
    ok = can_xattr()
    msg = "no non-broken extended attribute support"
    return test if ok else unittest.skip(msg)(test)


_can_chmod = None

def can_chmod():
    global _can_chmod
    if _can_chmod is not None:
        return _can_chmod
    if not hasattr(os, "chown"):
        _can_chmod = False
        return _can_chmod
    try:
        with open(TESTFN, "wb") as f:
            try:
                os.chmod(TESTFN, 0o777)
                mode1 = os.stat(TESTFN).st_mode
                os.chmod(TESTFN, 0o666)
                mode2 = os.stat(TESTFN).st_mode
            except OSError as e:
                can = False
            else:
                can = stat.S_IMODE(mode1) != stat.S_IMODE(mode2)
    finally:
        unlink(TESTFN)
    _can_chmod = can
    return can


def skip_unless_working_chmod(test):
    
    ok = can_chmod()
    msg = "requires working os.chmod()"
    return test if ok else unittest.skip(msg)(test)






_can_dac_override = None

def can_dac_override():
    global _can_dac_override

    if not can_chmod():
        _can_dac_override = False
    if _can_dac_override is not None:
        return _can_dac_override

    try:
        with open(TESTFN, "wb") as f:
            os.chmod(TESTFN, 0o400)
            try:
                with open(TESTFN, "wb"):
                    pass
            except OSError:
                _can_dac_override = False
            else:
                _can_dac_override = True
    finally:
        unlink(TESTFN)

    return _can_dac_override


def skip_if_dac_override(test):
    ok = not can_dac_override()
    msg = "incompatible with CAP_DAC_OVERRIDE"
    return test if ok else unittest.skip(msg)(test)


def skip_unless_dac_override(test):
    ok = can_dac_override()
    msg = "requires CAP_DAC_OVERRIDE"
    return test if ok else unittest.skip(msg)(test)


def unlink(filename):
    try:
        _unlink(filename)
    except (FileNotFoundError, NotADirectoryError):
        pass


if sys.platform.startswith("win"):
    def _waitfor(func, pathname, waitall=False):
        
        func(pathname)
        
        if waitall:
            dirname = pathname
        else:
            dirname, name = os.path.split(pathname)
            dirname = dirname or '.'
        
        
        
        
        
        
        timeout = 0.001
        while timeout < 1.0:
            
            
            
            
            
            
            
            L = os.listdir(dirname)
            if not (L if waitall else name in L):
                return
            
            time.sleep(timeout)
            timeout *= 2
        warnings.warn('tests may fail, delete still pending for ' + pathname,
                      RuntimeWarning, stacklevel=4)

    def _unlink(filename):
        _waitfor(os.unlink, filename)

    def _rmdir(dirname):
        _waitfor(os.rmdir, dirname)

    def _rmtree(path):
        from test.support import _force_run

        def _rmtree_inner(path):
            for name in _force_run(path, os.listdir, path):
                fullname = os.path.join(path, name)
                try:
                    mode = os.lstat(fullname).st_mode
                except OSError as exc:
                    print("support.rmtree(): os.lstat(%r) failed with %s"
                          % (fullname, exc),
                          file=sys.__stderr__)
                    mode = 0
                if stat.S_ISDIR(mode):
                    _waitfor(_rmtree_inner, fullname, waitall=True)
                    _force_run(fullname, os.rmdir, fullname)
                else:
                    _force_run(fullname, os.unlink, fullname)
        _waitfor(_rmtree_inner, path, waitall=True)
        _waitfor(lambda p: _force_run(p, os.rmdir, p), path)

    def _longpath(path):
        try:
            import ctypes
        except ImportError:
            
            pass
        else:
            buffer = ctypes.create_unicode_buffer(len(path) * 2)
            length = ctypes.windll.kernel32.GetLongPathNameW(path, buffer,
                                                             len(buffer))
            if length:
                return buffer[:length]
        return path
else:
    _unlink = os.unlink
    _rmdir = os.rmdir

    def _rmtree(path):
        import shutil
        try:
            shutil.rmtree(path)
            return
        except OSError:
            pass

        def _rmtree_inner(path):
            from test.support import _force_run
            for name in _force_run(path, os.listdir, path):
                fullname = os.path.join(path, name)
                try:
                    mode = os.lstat(fullname).st_mode
                except OSError:
                    mode = 0
                if stat.S_ISDIR(mode):
                    _rmtree_inner(fullname)
                    _force_run(path, os.rmdir, fullname)
                else:
                    _force_run(path, os.unlink, fullname)
        _rmtree_inner(path)
        os.rmdir(path)

    def _longpath(path):
        return path


def rmdir(dirname):
    try:
        _rmdir(dirname)
    except FileNotFoundError:
        pass


def rmtree(path):
    try:
        _rmtree(path)
    except FileNotFoundError:
        pass


@contextlib.contextmanager
def temp_dir(path=None, quiet=False):
    
    import tempfile
    dir_created = False
    if path is None:
        path = tempfile.mkdtemp()
        dir_created = True
        path = os.path.realpath(path)
    else:
        try:
            os.mkdir(path)
            dir_created = True
        except OSError as exc:
            if not quiet:
                raise
            warnings.warn(f'tests may fail, unable to create '
                          f'temporary directory {path!r}: {exc}',
                          RuntimeWarning, stacklevel=3)
    if dir_created:
        pid = os.getpid()
    try:
        yield path
    finally:
        
        
        if dir_created and pid == os.getpid():
            rmtree(path)


@contextlib.contextmanager
def change_cwd(path, quiet=False):
    
    saved_dir = os.getcwd()
    try:
        os.chdir(os.path.realpath(path))
    except OSError as exc:
        if not quiet:
            raise
        warnings.warn(f'tests may fail, unable to change the current working '
                      f'directory to {path!r}: {exc}',
                      RuntimeWarning, stacklevel=3)
    try:
        yield os.getcwd()
    finally:
        os.chdir(saved_dir)


@contextlib.contextmanager
def temp_cwd(name='tempcwd', quiet=False):
    
    with temp_dir(path=name, quiet=quiet) as temp_path:
        with change_cwd(temp_path, quiet=quiet) as cwd_dir:
            yield cwd_dir


def create_empty_file(filename):
    
    fd = os.open(filename, os.O_WRONLY | os.O_CREAT | os.O_TRUNC)
    os.close(fd)


@contextlib.contextmanager
def open_dir_fd(path):
    
    assert os.path.isdir(path)
    flags = os.O_RDONLY
    if hasattr(os, "O_DIRECTORY"):
        flags |= os.O_DIRECTORY
    dir_fd = os.open(path, flags)
    try:
        yield dir_fd
    finally:
        os.close(dir_fd)


def fs_is_case_insensitive(directory):
    
    import tempfile
    with tempfile.NamedTemporaryFile(dir=directory) as base:
        base_path = base.name
        case_path = base_path.upper()
        if case_path == base_path:
            case_path = base_path.lower()
        try:
            return os.path.samefile(base_path, case_path)
        except FileNotFoundError:
            return False


class FakePath:
    
    def __init__(self, path):
        self.path = path

    def __repr__(self):
        return f'<FakePath {self.path!r}>'

    def __fspath__(self):
        if (isinstance(self.path, BaseException) or
            isinstance(self.path, type) and
                issubclass(self.path, BaseException)):
            raise self.path
        else:
            return self.path


def fd_count():
    
    if sys.platform.startswith(('linux', 'freebsd', 'emscripten')):
        try:
            names = os.listdir("/proc/self/fd")
            
            
            return len(names) - 1
        except FileNotFoundError:
            pass

    MAXFD = 256
    if hasattr(os, 'sysconf'):
        try:
            MAXFD = os.sysconf("SC_OPEN_MAX")
        except OSError:
            pass

    old_modes = None
    if sys.platform == 'win32':
        
        
        try:
            import msvcrt
            msvcrt.CrtSetReportMode
        except (AttributeError, ImportError):
            
            pass
        else:
            old_modes = {}
            for report_type in (msvcrt.CRT_WARN,
                                msvcrt.CRT_ERROR,
                                msvcrt.CRT_ASSERT):
                old_modes[report_type] = msvcrt.CrtSetReportMode(report_type,
                                                                 0)

    try:
        count = 0
        for fd in range(MAXFD):
            try:
                
                
                fd2 = os.dup(fd)
            except OSError as e:
                if e.errno != errno.EBADF:
                    raise
            else:
                os.close(fd2)
                count += 1
    finally:
        if old_modes is not None:
            for report_type in (msvcrt.CRT_WARN,
                                msvcrt.CRT_ERROR,
                                msvcrt.CRT_ASSERT):
                msvcrt.CrtSetReportMode(report_type, old_modes[report_type])

    return count


if hasattr(os, "umask"):
    @contextlib.contextmanager
    def temp_umask(umask):
        
        oldmask = os.umask(umask)
        try:
            yield
        finally:
            os.umask(oldmask)
else:
    @contextlib.contextmanager
    def temp_umask(umask):
        
        yield


class EnvironmentVarGuard(collections.abc.MutableMapping):

    

    def __init__(self):
        self._environ = os.environ
        self._changed = {}

    def __getitem__(self, envvar):
        return self._environ[envvar]

    def __setitem__(self, envvar, value):
        
        if envvar not in self._changed:
            self._changed[envvar] = self._environ.get(envvar)
        self._environ[envvar] = value

    def __delitem__(self, envvar):
        
        if envvar not in self._changed:
            self._changed[envvar] = self._environ.get(envvar)
        if envvar in self._environ:
            del self._environ[envvar]

    def keys(self):
        return self._environ.keys()

    def __iter__(self):
        return iter(self._environ)

    def __len__(self):
        return len(self._environ)

    def set(self, envvar, value):
        self[envvar] = value

    def unset(self, envvar):
        del self[envvar]

    def copy(self):
        
        return dict(self)

    def __enter__(self):
        return self

    def __exit__(self, *ignore_exc):
        for (k, v) in self._changed.items():
            if v is None:
                if k in self._environ:
                    del self._environ[k]
            else:
                self._environ[k] = v
        os.environ = self._environ


try:
    if support.MS_WINDOWS:
        import ctypes
        kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)

        ERROR_FILE_NOT_FOUND = 2
        DDD_REMOVE_DEFINITION = 2
        DDD_EXACT_MATCH_ON_REMOVE = 4
        DDD_NO_BROADCAST_SYSTEM = 8
    else:
        raise AttributeError
except (ImportError, AttributeError):
    def subst_drive(path):
        raise unittest.SkipTest('ctypes or kernel32 is not available')
else:
    @contextlib.contextmanager
    def subst_drive(path):
        
        for c in reversed(string.ascii_uppercase):
            drive = f'{c}:'
            if (not kernel32.QueryDosDeviceW(drive, None, 0) and
                    ctypes.get_last_error() == ERROR_FILE_NOT_FOUND):
                break
        else:
            raise unittest.SkipTest('no available logical drive')
        if not kernel32.DefineDosDeviceW(
                DDD_NO_BROADCAST_SYSTEM, drive, path):
            raise ctypes.WinError(ctypes.get_last_error())
        try:
            yield drive
        finally:
            if not kernel32.DefineDosDeviceW(
                    DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE,
                    drive, path):
                raise ctypes.WinError(ctypes.get_last_error())