Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
_os.py531 linesDownload Raw Back to pathlib
1"""2Low-level OS functionality wrappers used by pathlib.3"""4 5from errno import *6from io import TextIOWrapper, text_encoding7from stat import S_ISDIR, S_ISREG, S_ISLNK, S_IMODE8import os9import sys10try:11    import fcntl12except ImportError:13    fcntl = None14try:15    import posix16except ImportError:17    posix = None18try:19    import _winapi20except ImportError:21    _winapi = None22 23 24def _get_copy_blocksize(infd):25    """Determine blocksize for fastcopying on Linux.26    Hopefully the whole file will be copied in a single call.27    The copying itself should be performed in a loop 'till EOF is28    reached (0 return) so a blocksize smaller or bigger than the actual29    file size should not make any difference, also in case the file30    content changes while being copied.31    """32    try:33        blocksize = max(os.fstat(infd).st_size, 2 ** 23)  # min 8 MiB34    except OSError:35        blocksize = 2 ** 27  # 128 MiB36    # On 32-bit architectures truncate to 1 GiB to avoid OverflowError,37    # see gh-82500.38    if sys.maxsize < 2 ** 32:39        blocksize = min(blocksize, 2 ** 30)40    return blocksize41 42 43if fcntl and hasattr(fcntl, 'FICLONE'):44    def _ficlone(source_fd, target_fd):45        """46        Perform a lightweight copy of two files, where the data blocks are47        copied only when modified. This is known as Copy on Write (CoW),48        instantaneous copy or reflink.49        """50        fcntl.ioctl(target_fd, fcntl.FICLONE, source_fd)51else:52    _ficlone = None53 54 55if posix and hasattr(posix, '_fcopyfile'):56    def _fcopyfile(source_fd, target_fd):57        """58        Copy a regular file content using high-performance fcopyfile(3)59        syscall (macOS).60        """61        posix._fcopyfile(source_fd, target_fd, posix._COPYFILE_DATA)62else:63    _fcopyfile = None64 65 66if hasattr(os, 'copy_file_range'):67    def _copy_file_range(source_fd, target_fd):68        """69        Copy data from one regular mmap-like fd to another by using a70        high-performance copy_file_range(2) syscall that gives filesystems71        an opportunity to implement the use of reflinks or server-side72        copy.73        This should work on Linux >= 4.5 only.74        """75        blocksize = _get_copy_blocksize(source_fd)76        offset = 077        while True:78            sent = os.copy_file_range(source_fd, target_fd, blocksize,79                                      offset_dst=offset)80            if sent == 0:81                break  # EOF82            offset += sent83else:84    _copy_file_range = None85 86 87if hasattr(os, 'sendfile'):88    def _sendfile(source_fd, target_fd):89        """Copy data from one regular mmap-like fd to another by using90        high-performance sendfile(2) syscall.91        This should work on Linux >= 2.6.33 only.92        """93        blocksize = _get_copy_blocksize(source_fd)94        offset = 095        while True:96            sent = os.sendfile(target_fd, source_fd, offset, blocksize)97            if sent == 0:98                break  # EOF99            offset += sent100else:101    _sendfile = None102 103 104if _winapi and hasattr(_winapi, 'CopyFile2'):105    def copyfile2(source, target):106        """107        Copy from one file to another using CopyFile2 (Windows only).108        """109        _winapi.CopyFile2(source, target, 0)110else:111    copyfile2 = None112 113 114def copyfileobj(source_f, target_f):115    """116    Copy data from file-like object source_f to file-like object target_f.117    """118    try:119        source_fd = source_f.fileno()120        target_fd = target_f.fileno()121    except Exception:122        pass  # Fall through to generic code.123    else:124        try:125            # Use OS copy-on-write where available.126            if _ficlone:127                try:128                    _ficlone(source_fd, target_fd)129                    return130                except OSError as err:131                    if err.errno not in (EBADF, EOPNOTSUPP, ETXTBSY, EXDEV):132                        raise err133 134            # Use OS copy where available.135            if _fcopyfile:136                try:137                    _fcopyfile(source_fd, target_fd)138                    return139                except OSError as err:140                    if err.errno not in (EINVAL, ENOTSUP):141                        raise err142            if _copy_file_range:143                try:144                    _copy_file_range(source_fd, target_fd)145                    return146                except OSError as err:147                    if err.errno not in (ETXTBSY, EXDEV):148                        raise err149            if _sendfile:150                try:151                    _sendfile(source_fd, target_fd)152                    return153                except OSError as err:154                    if err.errno != ENOTSOCK:155                        raise err156        except OSError as err:157            # Produce more useful error messages.158            err.filename = source_f.name159            err.filename2 = target_f.name160            raise err161 162    # Last resort: copy with fileobj read() and write().163    read_source = source_f.read164    write_target = target_f.write165    while buf := read_source(1024 * 1024):166        write_target(buf)167 168 169def magic_open(path, mode='r', buffering=-1, encoding=None, errors=None,170               newline=None):171    """172    Open the file pointed to by this path and return a file object, as173    the built-in open() function does.174    """175    text = 'b' not in mode176    if text:177        # Call io.text_encoding() here to ensure any warning is raised at an178        # appropriate stack level.179        encoding = text_encoding(encoding)180    try:181        return open(path, mode, buffering, encoding, errors, newline)182    except TypeError:183        pass184    cls = type(path)185    mode = ''.join(sorted(c for c in mode if c not in 'bt'))186    if text:187        try:188            attr = getattr(cls, f'__open_{mode}__')189        except AttributeError:190            pass191        else:192            return attr(path, buffering, encoding, errors, newline)193    elif encoding is not None:194        raise ValueError("binary mode doesn't take an encoding argument")195    elif errors is not None:196        raise ValueError("binary mode doesn't take an errors argument")197    elif newline is not None:198        raise ValueError("binary mode doesn't take a newline argument")199 200    try:201        attr = getattr(cls, f'__open_{mode}b__')202    except AttributeError:203        pass204    else:205        stream = attr(path, buffering)206        if text:207            stream = TextIOWrapper(stream, encoding, errors, newline)208        return stream209 210    raise TypeError(f"{cls.__name__} can't be opened with mode {mode!r}")211 212 213def ensure_distinct_paths(source, target):214    """215    Raise OSError(EINVAL) if the other path is within this path.216    """217    # Note: there is no straightforward, foolproof algorithm to determine218    # if one directory is within another (a particularly perverse example219    # would be a single network share mounted in one location via NFS, and220    # in another location via CIFS), so we simply checks whether the221    # other path is lexically equal to, or within, this path.222    if source == target:223        err = OSError(EINVAL, "Source and target are the same path")224    elif source in target.parents:225        err = OSError(EINVAL, "Source path is a parent of target path")226    else:227        return228    err.filename = str(source)229    err.filename2 = str(target)230    raise err231 232 233def ensure_different_files(source, target):234    """235    Raise OSError(EINVAL) if both paths refer to the same file.236    """237    try:238        source_file_id = source.info._file_id239        target_file_id = target.info._file_id240    except AttributeError:241        if source != target:242            return243    else:244        try:245            if source_file_id() != target_file_id():246                return247        except (OSError, ValueError):248            return249    err = OSError(EINVAL, "Source and target are the same file")250    err.filename = str(source)251    err.filename2 = str(target)252    raise err253 254 255def copy_info(info, target, follow_symlinks=True):256    """Copy metadata from the given PathInfo to the given local path."""257    copy_times_ns = (258        hasattr(info, '_access_time_ns') and259        hasattr(info, '_mod_time_ns') and260        (follow_symlinks or os.utime in os.supports_follow_symlinks))261    if copy_times_ns:262        t0 = info._access_time_ns(follow_symlinks=follow_symlinks)263        t1 = info._mod_time_ns(follow_symlinks=follow_symlinks)264        os.utime(target, ns=(t0, t1), follow_symlinks=follow_symlinks)265 266    # We must copy extended attributes before the file is (potentially)267    # chmod()'ed read-only, otherwise setxattr() will error with -EACCES.268    copy_xattrs = (269        hasattr(info, '_xattrs') and270        hasattr(os, 'setxattr') and271        (follow_symlinks or os.setxattr in os.supports_follow_symlinks))272    if copy_xattrs:273        xattrs = info._xattrs(follow_symlinks=follow_symlinks)274        for attr, value in xattrs:275            try:276                os.setxattr(target, attr, value, follow_symlinks=follow_symlinks)277            except OSError as e:278                if e.errno not in (EPERM, ENOTSUP, ENODATA, EINVAL, EACCES):279                    raise280 281    copy_posix_permissions = (282        hasattr(info, '_posix_permissions') and283        (follow_symlinks or os.chmod in os.supports_follow_symlinks))284    if copy_posix_permissions:285        posix_permissions = info._posix_permissions(follow_symlinks=follow_symlinks)286        try:287            os.chmod(target, posix_permissions, follow_symlinks=follow_symlinks)288        except NotImplementedError:289            # if we got a NotImplementedError, it's because290            #   * follow_symlinks=False,291            #   * lchown() is unavailable, and292            #   * either293            #       * fchownat() is unavailable or294            #       * fchownat() doesn't implement AT_SYMLINK_NOFOLLOW.295            #         (it returned ENOSUP.)296            # therefore we're out of options--we simply cannot chown the297            # symlink.  give up, suppress the error.298            # (which is what shutil always did in this circumstance.)299            pass300 301    copy_bsd_flags = (302        hasattr(info, '_bsd_flags') and303        hasattr(os, 'chflags') and304        (follow_symlinks or os.chflags in os.supports_follow_symlinks))305    if copy_bsd_flags:306        bsd_flags = info._bsd_flags(follow_symlinks=follow_symlinks)307        try:308            os.chflags(target, bsd_flags, follow_symlinks=follow_symlinks)309        except OSError as why:310            if why.errno not in (EOPNOTSUPP, ENOTSUP):311                raise312 313 314class _PathInfoBase:315    __slots__ = ('_path', '_stat_result', '_lstat_result')316 317    def __init__(self, path):318        self._path = str(path)319 320    def __repr__(self):321        path_type = "WindowsPath" if os.name == "nt" else "PosixPath"322        return f"<{path_type}.info>"323 324    def _stat(self, *, follow_symlinks=True, ignore_errors=False):325        """Return the status as an os.stat_result, or None if stat() fails and326        ignore_errors is true."""327        if follow_symlinks:328            try:329                result = self._stat_result330            except AttributeError:331                pass332            else:333                if ignore_errors or result is not None:334                    return result335            try:336                self._stat_result = os.stat(self._path)337            except (OSError, ValueError):338                self._stat_result = None339                if not ignore_errors:340                    raise341            return self._stat_result342        else:343            try:344                result = self._lstat_result345            except AttributeError:346                pass347            else:348                if ignore_errors or result is not None:349                    return result350            try:351                self._lstat_result = os.lstat(self._path)352            except (OSError, ValueError):353                self._lstat_result = None354                if not ignore_errors:355                    raise356            return self._lstat_result357 358    def _posix_permissions(self, *, follow_symlinks=True):359        """Return the POSIX file permissions."""360        return S_IMODE(self._stat(follow_symlinks=follow_symlinks).st_mode)361 362    def _file_id(self, *, follow_symlinks=True):363        """Returns the identifier of the file."""364        st = self._stat(follow_symlinks=follow_symlinks)365        return st.st_dev, st.st_ino366 367    def _access_time_ns(self, *, follow_symlinks=True):368        """Return the access time in nanoseconds."""369        return self._stat(follow_symlinks=follow_symlinks).st_atime_ns370 371    def _mod_time_ns(self, *, follow_symlinks=True):372        """Return the modify time in nanoseconds."""373        return self._stat(follow_symlinks=follow_symlinks).st_mtime_ns374 375    if hasattr(os.stat_result, 'st_flags'):376        def _bsd_flags(self, *, follow_symlinks=True):377            """Return the flags."""378            return self._stat(follow_symlinks=follow_symlinks).st_flags379 380    if hasattr(os, 'listxattr'):381        def _xattrs(self, *, follow_symlinks=True):382            """Return the xattrs as a list of (attr, value) pairs, or an empty383            list if extended attributes aren't supported."""384            try:385                return [386                    (attr, os.getxattr(self._path, attr, follow_symlinks=follow_symlinks))387                    for attr in os.listxattr(self._path, follow_symlinks=follow_symlinks)]388            except OSError as err:389                if err.errno not in (EPERM, ENOTSUP, ENODATA, EINVAL, EACCES):390                    raise391                return []392 393 394class _WindowsPathInfo(_PathInfoBase):395    """Implementation of pathlib.types.PathInfo that provides status396    information for Windows paths. Don't try to construct it yourself."""397    __slots__ = ('_exists', '_is_dir', '_is_file', '_is_symlink')398 399    def exists(self, *, follow_symlinks=True):400        """Whether this path exists."""401        if not follow_symlinks and self.is_symlink():402            return True403        try:404            return self._exists405        except AttributeError:406            if os.path.exists(self._path):407                self._exists = True408                return True409            else:410                self._exists = self._is_dir = self._is_file = False411                return False412 413    def is_dir(self, *, follow_symlinks=True):414        """Whether this path is a directory."""415        if not follow_symlinks and self.is_symlink():416            return False417        try:418            return self._is_dir419        except AttributeError:420            if os.path.isdir(self._path):421                self._is_dir = self._exists = True422                return True423            else:424                self._is_dir = False425                return False426 427    def is_file(self, *, follow_symlinks=True):428        """Whether this path is a regular file."""429        if not follow_symlinks and self.is_symlink():430            return False431        try:432            return self._is_file433        except AttributeError:434            if os.path.isfile(self._path):435                self._is_file = self._exists = True436                return True437            else:438                self._is_file = False439                return False440 441    def is_symlink(self):442        """Whether this path is a symbolic link."""443        try:444            return self._is_symlink445        except AttributeError:446            self._is_symlink = os.path.islink(self._path)447            return self._is_symlink448 449 450class _PosixPathInfo(_PathInfoBase):451    """Implementation of pathlib.types.PathInfo that provides status452    information for POSIX paths. Don't try to construct it yourself."""453    __slots__ = ()454 455    def exists(self, *, follow_symlinks=True):456        """Whether this path exists."""457        st = self._stat(follow_symlinks=follow_symlinks, ignore_errors=True)458        if st is None:459            return False460        return True461 462    def is_dir(self, *, follow_symlinks=True):463        """Whether this path is a directory."""464        st = self._stat(follow_symlinks=follow_symlinks, ignore_errors=True)465        if st is None:466            return False467        return S_ISDIR(st.st_mode)468 469    def is_file(self, *, follow_symlinks=True):470        """Whether this path is a regular file."""471        st = self._stat(follow_symlinks=follow_symlinks, ignore_errors=True)472        if st is None:473            return False474        return S_ISREG(st.st_mode)475 476    def is_symlink(self):477        """Whether this path is a symbolic link."""478        st = self._stat(follow_symlinks=False, ignore_errors=True)479        if st is None:480            return False481        return S_ISLNK(st.st_mode)482 483 484PathInfo = _WindowsPathInfo if os.name == 'nt' else _PosixPathInfo485 486 487class DirEntryInfo(_PathInfoBase):488    """Implementation of pathlib.types.PathInfo that provides status489    information by querying a wrapped os.DirEntry object. Don't try to490    construct it yourself."""491    __slots__ = ('_entry',)492 493    def __init__(self, entry):494        super().__init__(entry.path)495        self._entry = entry496 497    def _stat(self, *, follow_symlinks=True, ignore_errors=False):498        try:499            return self._entry.stat(follow_symlinks=follow_symlinks)500        except OSError:501            if not ignore_errors:502                raise503            return None504 505    def exists(self, *, follow_symlinks=True):506        """Whether this path exists."""507        if not follow_symlinks:508            return True509        return self._stat(ignore_errors=True) is not None510 511    def is_dir(self, *, follow_symlinks=True):512        """Whether this path is a directory."""513        try:514            return self._entry.is_dir(follow_symlinks=follow_symlinks)515        except OSError:516            return False517 518    def is_file(self, *, follow_symlinks=True):519        """Whether this path is a regular file."""520        try:521            return self._entry.is_file(follow_symlinks=follow_symlinks)522        except OSError:523            return False524 525    def is_symlink(self):526        """Whether this path is a symbolic link."""527        try:528            return self._entry.is_symlink()529        except OSError:530            return False531 
codekingpro/portable-devtools · Team Ai