17db96d56Sopenharmony_ciimport fnmatch
27db96d56Sopenharmony_ciimport glob
37db96d56Sopenharmony_ciimport os
47db96d56Sopenharmony_ciimport os.path
57db96d56Sopenharmony_ciimport shutil
67db96d56Sopenharmony_ciimport stat
77db96d56Sopenharmony_ci
87db96d56Sopenharmony_cifrom .iterutil import iter_many
97db96d56Sopenharmony_ci
107db96d56Sopenharmony_ci
117db96d56Sopenharmony_ciUSE_CWD = object()
127db96d56Sopenharmony_ci
137db96d56Sopenharmony_ci
147db96d56Sopenharmony_ciC_SOURCE_SUFFIXES = ('.c', '.h')
157db96d56Sopenharmony_ci
167db96d56Sopenharmony_ci
177db96d56Sopenharmony_cidef create_backup(old, backup=None):
187db96d56Sopenharmony_ci    if isinstance(old, str):
197db96d56Sopenharmony_ci        filename = old
207db96d56Sopenharmony_ci    else:
217db96d56Sopenharmony_ci        filename = getattr(old, 'name', None)
227db96d56Sopenharmony_ci    if not filename:
237db96d56Sopenharmony_ci        return None
247db96d56Sopenharmony_ci    if not backup or backup is True:
257db96d56Sopenharmony_ci        backup = f'{filename}.bak'
267db96d56Sopenharmony_ci    try:
277db96d56Sopenharmony_ci        shutil.copyfile(filename, backup)
287db96d56Sopenharmony_ci    except FileNotFoundError as exc:
297db96d56Sopenharmony_ci        if exc.filename != filename:
307db96d56Sopenharmony_ci            raise   # re-raise
317db96d56Sopenharmony_ci        backup = None
327db96d56Sopenharmony_ci    return backup
337db96d56Sopenharmony_ci
347db96d56Sopenharmony_ci
357db96d56Sopenharmony_ci##################################
367db96d56Sopenharmony_ci# filenames
377db96d56Sopenharmony_ci
387db96d56Sopenharmony_cidef fix_filename(filename, relroot=USE_CWD, *,
397db96d56Sopenharmony_ci                 fixroot=True,
407db96d56Sopenharmony_ci                 _badprefix=f'..{os.path.sep}',
417db96d56Sopenharmony_ci                 ):
427db96d56Sopenharmony_ci    """Return a normalized, absolute-path copy of the given filename."""
437db96d56Sopenharmony_ci    if not relroot or relroot is USE_CWD:
447db96d56Sopenharmony_ci        return os.path.abspath(filename)
457db96d56Sopenharmony_ci    if fixroot:
467db96d56Sopenharmony_ci        relroot = os.path.abspath(relroot)
477db96d56Sopenharmony_ci    return _fix_filename(filename, relroot)
487db96d56Sopenharmony_ci
497db96d56Sopenharmony_ci
507db96d56Sopenharmony_cidef _fix_filename(filename, relroot, *,
517db96d56Sopenharmony_ci                  _badprefix=f'..{os.path.sep}',
527db96d56Sopenharmony_ci                  ):
537db96d56Sopenharmony_ci    orig = filename
547db96d56Sopenharmony_ci
557db96d56Sopenharmony_ci    # First we normalize.
567db96d56Sopenharmony_ci    filename = os.path.normpath(filename)
577db96d56Sopenharmony_ci    if filename.startswith(_badprefix):
587db96d56Sopenharmony_ci        raise ValueError(f'bad filename {orig!r} (resolves beyond relative root')
597db96d56Sopenharmony_ci
607db96d56Sopenharmony_ci    # Now make sure it is absolute (relative to relroot).
617db96d56Sopenharmony_ci    if not os.path.isabs(filename):
627db96d56Sopenharmony_ci        filename = os.path.join(relroot, filename)
637db96d56Sopenharmony_ci    else:
647db96d56Sopenharmony_ci        relpath = os.path.relpath(filename, relroot)
657db96d56Sopenharmony_ci        if os.path.join(relroot, relpath) != filename:
667db96d56Sopenharmony_ci            raise ValueError(f'expected {relroot!r} as lroot, got {orig!r}')
677db96d56Sopenharmony_ci
687db96d56Sopenharmony_ci    return filename
697db96d56Sopenharmony_ci
707db96d56Sopenharmony_ci
717db96d56Sopenharmony_cidef fix_filenames(filenames, relroot=USE_CWD):
727db96d56Sopenharmony_ci    if not relroot or relroot is USE_CWD:
737db96d56Sopenharmony_ci        filenames = (os.path.abspath(v) for v in filenames)
747db96d56Sopenharmony_ci    else:
757db96d56Sopenharmony_ci        relroot = os.path.abspath(relroot)
767db96d56Sopenharmony_ci        filenames = (_fix_filename(v, relroot) for v in filenames)
777db96d56Sopenharmony_ci    return filenames, relroot
787db96d56Sopenharmony_ci
797db96d56Sopenharmony_ci
807db96d56Sopenharmony_cidef format_filename(filename, relroot=USE_CWD, *,
817db96d56Sopenharmony_ci                    fixroot=True,
827db96d56Sopenharmony_ci                    normalize=True,
837db96d56Sopenharmony_ci                    _badprefix=f'..{os.path.sep}',
847db96d56Sopenharmony_ci                    ):
857db96d56Sopenharmony_ci    """Return a consistent relative-path representation of the filename."""
867db96d56Sopenharmony_ci    orig = filename
877db96d56Sopenharmony_ci    if normalize:
887db96d56Sopenharmony_ci        filename = os.path.normpath(filename)
897db96d56Sopenharmony_ci    if relroot is None:
907db96d56Sopenharmony_ci        # Otherwise leave it as-is.
917db96d56Sopenharmony_ci        return filename
927db96d56Sopenharmony_ci    elif relroot is USE_CWD:
937db96d56Sopenharmony_ci        # Make it relative to CWD.
947db96d56Sopenharmony_ci        filename = os.path.relpath(filename)
957db96d56Sopenharmony_ci    else:
967db96d56Sopenharmony_ci        # Make it relative to "relroot".
977db96d56Sopenharmony_ci        if fixroot:
987db96d56Sopenharmony_ci            relroot = os.path.abspath(relroot)
997db96d56Sopenharmony_ci        elif not relroot:
1007db96d56Sopenharmony_ci            raise ValueError('missing relroot')
1017db96d56Sopenharmony_ci        filename = os.path.relpath(filename, relroot)
1027db96d56Sopenharmony_ci    if filename.startswith(_badprefix):
1037db96d56Sopenharmony_ci        raise ValueError(f'bad filename {orig!r} (resolves beyond relative root')
1047db96d56Sopenharmony_ci    return filename
1057db96d56Sopenharmony_ci
1067db96d56Sopenharmony_ci
1077db96d56Sopenharmony_ci##################################
1087db96d56Sopenharmony_ci# find files
1097db96d56Sopenharmony_ci
1107db96d56Sopenharmony_cidef match_glob(filename, pattern):
1117db96d56Sopenharmony_ci    if fnmatch.fnmatch(filename, pattern):
1127db96d56Sopenharmony_ci        return True
1137db96d56Sopenharmony_ci
1147db96d56Sopenharmony_ci    # fnmatch doesn't handle ** quite right.  It will not match the
1157db96d56Sopenharmony_ci    # following:
1167db96d56Sopenharmony_ci    #
1177db96d56Sopenharmony_ci    #  ('x/spam.py', 'x/**/*.py')
1187db96d56Sopenharmony_ci    #  ('spam.py', '**/*.py')
1197db96d56Sopenharmony_ci    #
1207db96d56Sopenharmony_ci    # though it *will* match the following:
1217db96d56Sopenharmony_ci    #
1227db96d56Sopenharmony_ci    #  ('x/y/spam.py', 'x/**/*.py')
1237db96d56Sopenharmony_ci    #  ('x/spam.py', '**/*.py')
1247db96d56Sopenharmony_ci
1257db96d56Sopenharmony_ci    if '**/' not in pattern:
1267db96d56Sopenharmony_ci        return False
1277db96d56Sopenharmony_ci
1287db96d56Sopenharmony_ci    # We only accommodate the single-"**" case.
1297db96d56Sopenharmony_ci    return fnmatch.fnmatch(filename, pattern.replace('**/', '', 1))
1307db96d56Sopenharmony_ci
1317db96d56Sopenharmony_ci
1327db96d56Sopenharmony_cidef process_filenames(filenames, *,
1337db96d56Sopenharmony_ci                      start=None,
1347db96d56Sopenharmony_ci                      include=None,
1357db96d56Sopenharmony_ci                      exclude=None,
1367db96d56Sopenharmony_ci                      relroot=USE_CWD,
1377db96d56Sopenharmony_ci                      ):
1387db96d56Sopenharmony_ci    if relroot and relroot is not USE_CWD:
1397db96d56Sopenharmony_ci        relroot = os.path.abspath(relroot)
1407db96d56Sopenharmony_ci    if start:
1417db96d56Sopenharmony_ci        start = fix_filename(start, relroot, fixroot=False)
1427db96d56Sopenharmony_ci    if include:
1437db96d56Sopenharmony_ci        include = set(fix_filename(v, relroot, fixroot=False)
1447db96d56Sopenharmony_ci                      for v in include)
1457db96d56Sopenharmony_ci    if exclude:
1467db96d56Sopenharmony_ci        exclude = set(fix_filename(v, relroot, fixroot=False)
1477db96d56Sopenharmony_ci                      for v in exclude)
1487db96d56Sopenharmony_ci
1497db96d56Sopenharmony_ci    onempty = Exception('no filenames provided')
1507db96d56Sopenharmony_ci    for filename, solo in iter_many(filenames, onempty):
1517db96d56Sopenharmony_ci        filename = fix_filename(filename, relroot, fixroot=False)
1527db96d56Sopenharmony_ci        relfile = format_filename(filename, relroot, fixroot=False, normalize=False)
1537db96d56Sopenharmony_ci        check, start = _get_check(filename, start, include, exclude)
1547db96d56Sopenharmony_ci        yield filename, relfile, check, solo
1557db96d56Sopenharmony_ci
1567db96d56Sopenharmony_ci
1577db96d56Sopenharmony_cidef expand_filenames(filenames):
1587db96d56Sopenharmony_ci    for filename in filenames:
1597db96d56Sopenharmony_ci        # XXX Do we need to use glob.escape (a la commit 9355868458, GH-20994)?
1607db96d56Sopenharmony_ci        if '**/' in filename:
1617db96d56Sopenharmony_ci            yield from glob.glob(filename.replace('**/', ''))
1627db96d56Sopenharmony_ci        yield from glob.glob(filename)
1637db96d56Sopenharmony_ci
1647db96d56Sopenharmony_ci
1657db96d56Sopenharmony_cidef _get_check(filename, start, include, exclude):
1667db96d56Sopenharmony_ci    if start and filename != start:
1677db96d56Sopenharmony_ci        return (lambda: '<skipped>'), start
1687db96d56Sopenharmony_ci    else:
1697db96d56Sopenharmony_ci        def check():
1707db96d56Sopenharmony_ci            if _is_excluded(filename, exclude, include):
1717db96d56Sopenharmony_ci                return '<excluded>'
1727db96d56Sopenharmony_ci            return None
1737db96d56Sopenharmony_ci        return check, None
1747db96d56Sopenharmony_ci
1757db96d56Sopenharmony_ci
1767db96d56Sopenharmony_cidef _is_excluded(filename, exclude, include):
1777db96d56Sopenharmony_ci    if include:
1787db96d56Sopenharmony_ci        for included in include:
1797db96d56Sopenharmony_ci            if match_glob(filename, included):
1807db96d56Sopenharmony_ci                return False
1817db96d56Sopenharmony_ci        return True
1827db96d56Sopenharmony_ci    elif exclude:
1837db96d56Sopenharmony_ci        for excluded in exclude:
1847db96d56Sopenharmony_ci            if match_glob(filename, excluded):
1857db96d56Sopenharmony_ci                return True
1867db96d56Sopenharmony_ci        return False
1877db96d56Sopenharmony_ci    else:
1887db96d56Sopenharmony_ci        return False
1897db96d56Sopenharmony_ci
1907db96d56Sopenharmony_ci
1917db96d56Sopenharmony_cidef _walk_tree(root, *,
1927db96d56Sopenharmony_ci               _walk=os.walk,
1937db96d56Sopenharmony_ci               ):
1947db96d56Sopenharmony_ci    # A wrapper around os.walk that resolves the filenames.
1957db96d56Sopenharmony_ci    for parent, _, names in _walk(root):
1967db96d56Sopenharmony_ci        for name in names:
1977db96d56Sopenharmony_ci            yield os.path.join(parent, name)
1987db96d56Sopenharmony_ci
1997db96d56Sopenharmony_ci
2007db96d56Sopenharmony_cidef walk_tree(root, *,
2017db96d56Sopenharmony_ci              suffix=None,
2027db96d56Sopenharmony_ci              walk=_walk_tree,
2037db96d56Sopenharmony_ci              ):
2047db96d56Sopenharmony_ci    """Yield each file in the tree under the given directory name.
2057db96d56Sopenharmony_ci
2067db96d56Sopenharmony_ci    If "suffix" is provided then only files with that suffix will
2077db96d56Sopenharmony_ci    be included.
2087db96d56Sopenharmony_ci    """
2097db96d56Sopenharmony_ci    if suffix and not isinstance(suffix, str):
2107db96d56Sopenharmony_ci        raise ValueError('suffix must be a string')
2117db96d56Sopenharmony_ci
2127db96d56Sopenharmony_ci    for filename in walk(root):
2137db96d56Sopenharmony_ci        if suffix and not filename.endswith(suffix):
2147db96d56Sopenharmony_ci            continue
2157db96d56Sopenharmony_ci        yield filename
2167db96d56Sopenharmony_ci
2177db96d56Sopenharmony_ci
2187db96d56Sopenharmony_cidef glob_tree(root, *,
2197db96d56Sopenharmony_ci              suffix=None,
2207db96d56Sopenharmony_ci              _glob=glob.iglob,
2217db96d56Sopenharmony_ci              ):
2227db96d56Sopenharmony_ci    """Yield each file in the tree under the given directory name.
2237db96d56Sopenharmony_ci
2247db96d56Sopenharmony_ci    If "suffix" is provided then only files with that suffix will
2257db96d56Sopenharmony_ci    be included.
2267db96d56Sopenharmony_ci    """
2277db96d56Sopenharmony_ci    suffix = suffix or ''
2287db96d56Sopenharmony_ci    if not isinstance(suffix, str):
2297db96d56Sopenharmony_ci        raise ValueError('suffix must be a string')
2307db96d56Sopenharmony_ci
2317db96d56Sopenharmony_ci    for filename in _glob(f'{root}/*{suffix}'):
2327db96d56Sopenharmony_ci        yield filename
2337db96d56Sopenharmony_ci    for filename in _glob(f'{root}/**/*{suffix}'):
2347db96d56Sopenharmony_ci        yield filename
2357db96d56Sopenharmony_ci
2367db96d56Sopenharmony_ci
2377db96d56Sopenharmony_cidef iter_files(root, suffix=None, relparent=None, *,
2387db96d56Sopenharmony_ci               get_files=os.walk,
2397db96d56Sopenharmony_ci               _glob=glob_tree,
2407db96d56Sopenharmony_ci               _walk=walk_tree,
2417db96d56Sopenharmony_ci               ):
2427db96d56Sopenharmony_ci    """Yield each file in the tree under the given directory name.
2437db96d56Sopenharmony_ci
2447db96d56Sopenharmony_ci    If "root" is a non-string iterable then do the same for each of
2457db96d56Sopenharmony_ci    those trees.
2467db96d56Sopenharmony_ci
2477db96d56Sopenharmony_ci    If "suffix" is provided then only files with that suffix will
2487db96d56Sopenharmony_ci    be included.
2497db96d56Sopenharmony_ci
2507db96d56Sopenharmony_ci    if "relparent" is provided then it is used to resolve each
2517db96d56Sopenharmony_ci    filename as a relative path.
2527db96d56Sopenharmony_ci    """
2537db96d56Sopenharmony_ci    if not isinstance(root, str):
2547db96d56Sopenharmony_ci        roots = root
2557db96d56Sopenharmony_ci        for root in roots:
2567db96d56Sopenharmony_ci            yield from iter_files(root, suffix, relparent,
2577db96d56Sopenharmony_ci                                  get_files=get_files,
2587db96d56Sopenharmony_ci                                  _glob=_glob, _walk=_walk)
2597db96d56Sopenharmony_ci        return
2607db96d56Sopenharmony_ci
2617db96d56Sopenharmony_ci    # Use the right "walk" function.
2627db96d56Sopenharmony_ci    if get_files in (glob.glob, glob.iglob, glob_tree):
2637db96d56Sopenharmony_ci        get_files = _glob
2647db96d56Sopenharmony_ci    else:
2657db96d56Sopenharmony_ci        _files = _walk_tree if get_files in (os.walk, walk_tree) else get_files
2667db96d56Sopenharmony_ci        get_files = (lambda *a, **k: _walk(*a, walk=_files, **k))
2677db96d56Sopenharmony_ci
2687db96d56Sopenharmony_ci    # Handle a single suffix.
2697db96d56Sopenharmony_ci    if suffix and not isinstance(suffix, str):
2707db96d56Sopenharmony_ci        filenames = get_files(root)
2717db96d56Sopenharmony_ci        suffix = tuple(suffix)
2727db96d56Sopenharmony_ci    else:
2737db96d56Sopenharmony_ci        filenames = get_files(root, suffix=suffix)
2747db96d56Sopenharmony_ci        suffix = None
2757db96d56Sopenharmony_ci
2767db96d56Sopenharmony_ci    for filename in filenames:
2777db96d56Sopenharmony_ci        if suffix and not isinstance(suffix, str):  # multiple suffixes
2787db96d56Sopenharmony_ci            if not filename.endswith(suffix):
2797db96d56Sopenharmony_ci                continue
2807db96d56Sopenharmony_ci        if relparent:
2817db96d56Sopenharmony_ci            filename = os.path.relpath(filename, relparent)
2827db96d56Sopenharmony_ci        yield filename
2837db96d56Sopenharmony_ci
2847db96d56Sopenharmony_ci
2857db96d56Sopenharmony_cidef iter_files_by_suffix(root, suffixes, relparent=None, *,
2867db96d56Sopenharmony_ci                         walk=walk_tree,
2877db96d56Sopenharmony_ci                         _iter_files=iter_files,
2887db96d56Sopenharmony_ci                         ):
2897db96d56Sopenharmony_ci    """Yield each file in the tree that has the given suffixes.
2907db96d56Sopenharmony_ci
2917db96d56Sopenharmony_ci    Unlike iter_files(), the results are in the original suffix order.
2927db96d56Sopenharmony_ci    """
2937db96d56Sopenharmony_ci    if isinstance(suffixes, str):
2947db96d56Sopenharmony_ci        suffixes = [suffixes]
2957db96d56Sopenharmony_ci    # XXX Ignore repeated suffixes?
2967db96d56Sopenharmony_ci    for suffix in suffixes:
2977db96d56Sopenharmony_ci        yield from _iter_files(root, suffix, relparent)
2987db96d56Sopenharmony_ci
2997db96d56Sopenharmony_ci
3007db96d56Sopenharmony_ci##################################
3017db96d56Sopenharmony_ci# file info
3027db96d56Sopenharmony_ci
3037db96d56Sopenharmony_ci# XXX posix-only?
3047db96d56Sopenharmony_ci
3057db96d56Sopenharmony_ciS_IRANY = stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH
3067db96d56Sopenharmony_ciS_IWANY = stat.S_IWUSR | stat.S_IWGRP | stat.S_IWOTH
3077db96d56Sopenharmony_ciS_IXANY = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
3087db96d56Sopenharmony_ci
3097db96d56Sopenharmony_ci
3107db96d56Sopenharmony_cidef is_readable(file, *, user=None, check=False):
3117db96d56Sopenharmony_ci    filename, st, mode = _get_file_info(file)
3127db96d56Sopenharmony_ci    if check:
3137db96d56Sopenharmony_ci        try:
3147db96d56Sopenharmony_ci            okay = _check_file(filename, S_IRANY)
3157db96d56Sopenharmony_ci        except NotImplementedError:
3167db96d56Sopenharmony_ci            okay = NotImplemented
3177db96d56Sopenharmony_ci        if okay is not NotImplemented:
3187db96d56Sopenharmony_ci            return okay
3197db96d56Sopenharmony_ci        # Fall back to checking the mode.
3207db96d56Sopenharmony_ci    return _check_mode(st, mode, S_IRANY, user)
3217db96d56Sopenharmony_ci
3227db96d56Sopenharmony_ci
3237db96d56Sopenharmony_cidef is_writable(file, *, user=None, check=False):
3247db96d56Sopenharmony_ci    filename, st, mode = _get_file_info(file)
3257db96d56Sopenharmony_ci    if check:
3267db96d56Sopenharmony_ci        try:
3277db96d56Sopenharmony_ci            okay = _check_file(filename, S_IWANY)
3287db96d56Sopenharmony_ci        except NotImplementedError:
3297db96d56Sopenharmony_ci            okay = NotImplemented
3307db96d56Sopenharmony_ci        if okay is not NotImplemented:
3317db96d56Sopenharmony_ci            return okay
3327db96d56Sopenharmony_ci        # Fall back to checking the mode.
3337db96d56Sopenharmony_ci    return _check_mode(st, mode, S_IWANY, user)
3347db96d56Sopenharmony_ci
3357db96d56Sopenharmony_ci
3367db96d56Sopenharmony_cidef is_executable(file, *, user=None, check=False):
3377db96d56Sopenharmony_ci    filename, st, mode = _get_file_info(file)
3387db96d56Sopenharmony_ci    if check:
3397db96d56Sopenharmony_ci        try:
3407db96d56Sopenharmony_ci            okay = _check_file(filename, S_IXANY)
3417db96d56Sopenharmony_ci        except NotImplementedError:
3427db96d56Sopenharmony_ci            okay = NotImplemented
3437db96d56Sopenharmony_ci        if okay is not NotImplemented:
3447db96d56Sopenharmony_ci            return okay
3457db96d56Sopenharmony_ci        # Fall back to checking the mode.
3467db96d56Sopenharmony_ci    return _check_mode(st, mode, S_IXANY, user)
3477db96d56Sopenharmony_ci
3487db96d56Sopenharmony_ci
3497db96d56Sopenharmony_cidef _get_file_info(file):
3507db96d56Sopenharmony_ci    filename = st = mode = None
3517db96d56Sopenharmony_ci    if isinstance(file, int):
3527db96d56Sopenharmony_ci        mode = file
3537db96d56Sopenharmony_ci    elif isinstance(file, os.stat_result):
3547db96d56Sopenharmony_ci        st = file
3557db96d56Sopenharmony_ci    else:
3567db96d56Sopenharmony_ci        if isinstance(file, str):
3577db96d56Sopenharmony_ci            filename = file
3587db96d56Sopenharmony_ci        elif hasattr(file, 'name') and os.path.exists(file.name):
3597db96d56Sopenharmony_ci            filename = file.name
3607db96d56Sopenharmony_ci        else:
3617db96d56Sopenharmony_ci            raise NotImplementedError(file)
3627db96d56Sopenharmony_ci        st = os.stat(filename)
3637db96d56Sopenharmony_ci    return filename, st, mode or st.st_mode
3647db96d56Sopenharmony_ci
3657db96d56Sopenharmony_ci
3667db96d56Sopenharmony_cidef _check_file(filename, check):
3677db96d56Sopenharmony_ci    if not isinstance(filename, str):
3687db96d56Sopenharmony_ci        raise Exception(f'filename required to check file, got {filename}')
3697db96d56Sopenharmony_ci    if check & S_IRANY:
3707db96d56Sopenharmony_ci        flags = os.O_RDONLY
3717db96d56Sopenharmony_ci    elif check & S_IWANY:
3727db96d56Sopenharmony_ci        flags = os.O_WRONLY
3737db96d56Sopenharmony_ci    elif check & S_IXANY:
3747db96d56Sopenharmony_ci        # We can worry about S_IXANY later
3757db96d56Sopenharmony_ci        return NotImplemented
3767db96d56Sopenharmony_ci    else:
3777db96d56Sopenharmony_ci        raise NotImplementedError(check)
3787db96d56Sopenharmony_ci
3797db96d56Sopenharmony_ci    try:
3807db96d56Sopenharmony_ci        fd = os.open(filename, flags)
3817db96d56Sopenharmony_ci    except PermissionError:
3827db96d56Sopenharmony_ci        return False
3837db96d56Sopenharmony_ci    # We do not ignore other exceptions.
3847db96d56Sopenharmony_ci    else:
3857db96d56Sopenharmony_ci        os.close(fd)
3867db96d56Sopenharmony_ci        return True
3877db96d56Sopenharmony_ci
3887db96d56Sopenharmony_ci
3897db96d56Sopenharmony_cidef _get_user_info(user):
3907db96d56Sopenharmony_ci    import pwd
3917db96d56Sopenharmony_ci    username = uid = gid = groups = None
3927db96d56Sopenharmony_ci    if user is None:
3937db96d56Sopenharmony_ci        uid = os.geteuid()
3947db96d56Sopenharmony_ci        #username = os.getlogin()
3957db96d56Sopenharmony_ci        username = pwd.getpwuid(uid)[0]
3967db96d56Sopenharmony_ci        gid = os.getgid()
3977db96d56Sopenharmony_ci        groups = os.getgroups()
3987db96d56Sopenharmony_ci    else:
3997db96d56Sopenharmony_ci        if isinstance(user, int):
4007db96d56Sopenharmony_ci            uid = user
4017db96d56Sopenharmony_ci            entry = pwd.getpwuid(uid)
4027db96d56Sopenharmony_ci            username = entry.pw_name
4037db96d56Sopenharmony_ci        elif isinstance(user, str):
4047db96d56Sopenharmony_ci            username = user
4057db96d56Sopenharmony_ci            entry = pwd.getpwnam(username)
4067db96d56Sopenharmony_ci            uid = entry.pw_uid
4077db96d56Sopenharmony_ci        else:
4087db96d56Sopenharmony_ci            raise NotImplementedError(user)
4097db96d56Sopenharmony_ci        gid = entry.pw_gid
4107db96d56Sopenharmony_ci        os.getgrouplist(username, gid)
4117db96d56Sopenharmony_ci    return username, uid, gid, groups
4127db96d56Sopenharmony_ci
4137db96d56Sopenharmony_ci
4147db96d56Sopenharmony_cidef _check_mode(st, mode, check, user):
4157db96d56Sopenharmony_ci    orig = check
4167db96d56Sopenharmony_ci    _, uid, gid, groups = _get_user_info(user)
4177db96d56Sopenharmony_ci    if check & S_IRANY:
4187db96d56Sopenharmony_ci        check -= S_IRANY
4197db96d56Sopenharmony_ci        matched = False
4207db96d56Sopenharmony_ci        if mode & stat.S_IRUSR:
4217db96d56Sopenharmony_ci            if st.st_uid == uid:
4227db96d56Sopenharmony_ci                matched = True
4237db96d56Sopenharmony_ci        if mode & stat.S_IRGRP:
4247db96d56Sopenharmony_ci            if st.st_uid == gid or st.st_uid in groups:
4257db96d56Sopenharmony_ci                matched = True
4267db96d56Sopenharmony_ci        if mode & stat.S_IROTH:
4277db96d56Sopenharmony_ci            matched = True
4287db96d56Sopenharmony_ci        if not matched:
4297db96d56Sopenharmony_ci            return False
4307db96d56Sopenharmony_ci    if check & S_IWANY:
4317db96d56Sopenharmony_ci        check -= S_IWANY
4327db96d56Sopenharmony_ci        matched = False
4337db96d56Sopenharmony_ci        if mode & stat.S_IWUSR:
4347db96d56Sopenharmony_ci            if st.st_uid == uid:
4357db96d56Sopenharmony_ci                matched = True
4367db96d56Sopenharmony_ci        if mode & stat.S_IWGRP:
4377db96d56Sopenharmony_ci            if st.st_uid == gid or st.st_uid in groups:
4387db96d56Sopenharmony_ci                matched = True
4397db96d56Sopenharmony_ci        if mode & stat.S_IWOTH:
4407db96d56Sopenharmony_ci            matched = True
4417db96d56Sopenharmony_ci        if not matched:
4427db96d56Sopenharmony_ci            return False
4437db96d56Sopenharmony_ci    if check & S_IXANY:
4447db96d56Sopenharmony_ci        check -= S_IXANY
4457db96d56Sopenharmony_ci        matched = False
4467db96d56Sopenharmony_ci        if mode & stat.S_IXUSR:
4477db96d56Sopenharmony_ci            if st.st_uid == uid:
4487db96d56Sopenharmony_ci                matched = True
4497db96d56Sopenharmony_ci        if mode & stat.S_IXGRP:
4507db96d56Sopenharmony_ci            if st.st_uid == gid or st.st_uid in groups:
4517db96d56Sopenharmony_ci                matched = True
4527db96d56Sopenharmony_ci        if mode & stat.S_IXOTH:
4537db96d56Sopenharmony_ci            matched = True
4547db96d56Sopenharmony_ci        if not matched:
4557db96d56Sopenharmony_ci            return False
4567db96d56Sopenharmony_ci    if check:
4577db96d56Sopenharmony_ci        raise NotImplementedError((orig, check))
4587db96d56Sopenharmony_ci    return True
459