Exemple #1
0
    def __init__(self, path, threaded=True, timeout=None):
        """
        >>> lock = SQLiteLockFile('somefile')
        >>> lock = SQLiteLockFile('somefile', threaded=False)
        """
        LockBase.__init__(self, path, threaded, timeout)
        self.lock_file = unicode(self.lock_file)
        self.unique_name = unicode(self.unique_name)

        if SQLiteLockFile.testdb is None:
            import tempfile
            _fd, testdb = tempfile.mkstemp()
            testos.close(_fd)
            testos.unlink(testdb)
            del _fd, tempfile
            SQLiteLockFile.testdb = testdb

        import sqlite3
        self.connection = sqlite3.connect(SQLiteLockFile.testdb)

        c = self.connection.cursor()
        try:
            c.execute("create table locks"
                      "("
                      "   lock_file varchar(32),"
                      "   unique_name varchar(32)"
                      ")")
        except sqlite3.OperationalError:
            pass
        else:
            self.connection.commit()
            import atexit
            atexit.register(testos.unlink, SQLiteLockFile.testdb)
Exemple #2
0
def get_path_uid(path):
    """
    Return path's uid.

    Does not follow symlinks:
        https://github.com/pypa/pip/pull/935#discussion_r5307003

    Placed this function in compat due to differences on AIX and
    Jython, that should eventually go away.

    :raises OSError: When path is a symlink or can't be read.
    """
    if hasattr(testos, 'O_NOFOLLOW'):
        fd = testos.open(path, testos.O_RDONLY | testos.O_NOFOLLOW)
        file_uid = testos.fstat(fd).st_uid
        testos.close(fd)
    else:  # AIX and Jython
        # WARNING: time of check vulnerability, but best we can do w/o NOFOLLOW
        if not testos.path.islink(path):
            # older versions of Jython don't have `os.fstat`
            file_uid = testos.stat(path).st_uid
        else:
            # raise OSError for parity with os.O_NOFOLLOW above
            raise OSError(
                "%s is a symlink; Will not return uid for symlinks" % path
            )
    return file_uid
Exemple #3
0
def get_terminal_size():
    """Returns a tuple (x, y) representing the width(x) and the height(x)
    in characters of the terminal window."""
    def ioctl_GWINSZ(fd):
        try:
            import fcntl
            import termios
            import struct
            cr = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ,
                                                 '1234'))
        except:
            return None
        if cr == (0, 0):
            return None
        return cr

    cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2)
    if not cr:
        try:
            fd = testos.open(testos.ctermid(), testos.O_RDONLY)
            cr = ioctl_GWINSZ(fd)
            testos.close(fd)
        except:
            pass
    if not cr:
        cr = (testos.environ.get('LINES',
                                 25), testos.environ.get('COLUMNS', 80))
    return int(cr[1]), int(cr[0])
Exemple #4
0
def rmtree(path, ignore_errors=False, onerror=None):
    """Recursively delete a directory tree.

    If ignore_errors is set, errors are ignored; otherwise, if onerror
    is set, it is called to handle the error with arguments (func,
    path, exc_info) where func is platform and implementation dependent;
    path is the argument to that function that caused it to fail; and
    exc_info is a tuple returned by sys.exc_info().  If ignore_errors
    is false and onerror is None, an exception is raised.

    """
    if ignore_errors:

        def onerror(*args):
            pass
    elif onerror is None:

        def onerror(*args):
            raise

    if _use_fd_functions:
        # While the unsafe rmtree works fine on bytes, the fd based does not.
        if isinstance(path, bytes):
            path = testos.fsdecode(path)
        # Note: To guard against symlink races, we use the standard
        # lstat()/open()/fstat() trick.
        try:
            orig_st = testos.lstat(path)
        except Exception:
            onerror(testos.lstat, path, sys.exc_info())
            return
        try:
            fd = testos.open(path, testos.O_RDONLY)
        except Exception:
            onerror(testos.lstat, path, sys.exc_info())
            return
        try:
            if testos.path.samestat(orig_st, testos.fstat(fd)):
                _rmtree_safe_fd(fd, path, onerror)
                try:
                    testos.rmdir(path)
                except OSError:
                    onerror(testos.rmdir, path, sys.exc_info())
            else:
                try:
                    # symlinks to directories are forbidden, see bug #1669
                    raise OSError("Cannot call rmtree on a symbolic link")
                except OSError:
                    onerror(testos.path.islink, path, sys.exc_info())
        finally:
            testos.close(fd)
    else:
        return _rmtree_unsafe(path, onerror)
Exemple #5
0
def NamedTemporaryFile(mode='w+b',
                       buffering=-1,
                       encoding=None,
                       newline=None,
                       suffix=None,
                       prefix=None,
                       dir=None,
                       delete=True):
    """Create and return a temporary file.
    Arguments:
    'prefix', 'suffix', 'dir' -- as for mkstemp.
    'mode' -- the mode argument to io.open (default "w+b").
    'buffering' -- the buffer size argument to io.open (default -1).
    'encoding' -- the encoding argument to io.open (default None)
    'newline' -- the newline argument to io.open (default None)
    'delete' -- whether the file is deleted on close (default True).
    The file is created as mkstemp() would do it.

    Returns an object with a file-like interface; the name of the file
    is accessible as its 'name' attribute.  The file will be automatically
    deleted when it is closed unless the 'delete' argument is set to False.
    """

    prefix, suffix, dir, output_type = _sanitize_params(prefix, suffix, dir)

    flags = _bin_openflags

    # Setting O_TEMPORARY in the flags causes the OS to delete
    # the file when it is closed.  This is only supported by Windows.
    if _os.name == 'nt' and delete:
        flags |= _os.O_TEMPORARY

    (fd, name) = _mkstemp_inner(dir, prefix, suffix, flags, output_type)
    try:
        file = _io.open(fd,
                        mode,
                        buffering=buffering,
                        newline=newline,
                        encoding=encoding)

        return _TemporaryFileWrapper(file, name, delete)
    except BaseException:
        _os.unlink(name)
        _os.close(fd)
        raise
Exemple #6
0
def _rmtree_safe_fd(topfd, path, onerror):
    names = []
    try:
        names = testos.listdir(topfd)
    except OSError as err:
        err.filename = path
        onerror(testos.listdir, path, sys.exc_info())
    for name in names:
        fullname = testos.path.join(path, name)
        try:
            orig_st = testos.stat(name, dir_fd=topfd, follow_symlinks=False)
            mode = orig_st.st_mode
        except OSError:
            mode = 0
        if stat.S_ISDIR(mode):
            try:
                dirfd = testos.open(name, testos.O_RDONLY, dir_fd=topfd)
            except OSError:
                onerror(testos.open, fullname, sys.exc_info())
            else:
                try:
                    if testos.path.samestat(orig_st, testos.fstat(dirfd)):
                        _rmtree_safe_fd(dirfd, fullname, onerror)
                        try:
                            testos.rmdir(name, dir_fd=topfd)
                        except OSError:
                            onerror(testos.rmdir, fullname, sys.exc_info())
                    else:
                        try:
                            # This can only happen if someone replaces
                            # a directory with a symlink after the call to
                            # stat.S_ISDIR above.
                            raise OSError("Cannot call rmtree on a symbolic "
                                          "link")
                        except OSError:
                            onerror(testos.path.islink, fullname,
                                    sys.exc_info())
                finally:
                    testos.close(dirfd)
        else:
            try:
                testos.unlink(name, dir_fd=topfd)
            except OSError:
                onerror(testos.unlink, fullname, sys.exc_info())
Exemple #7
0
def _get_default_tempdir():
    """Calculate the default directory to use for temporary files.
    This routine should be called exactly once.

    We determine whether or not a candidate temp dir is usable by
    trying to create and write to a file in that directory.  If this
    is successful, the test file is deleted.  To prevent denial of
    service, the name of the test file must be randomized."""

    namer = _RandomNameSequence()
    dirlist = _candidate_tempdir_list()

    for dir in dirlist:
        if dir != _os.curdir:
            dir = _os.path.abspath(dir)
        # Try only a few names per directory.
        for seq in range(100):
            name = next(namer)
            filename = _os.path.join(dir, name)
            try:
                fd = _os.open(filename, _bin_openflags, 0o600)
                try:
                    try:
                        with _io.open(fd, 'wb', closefd=False) as fp:
                            fp.write(b'blat')
                    finally:
                        _os.close(fd)
                finally:
                    _os.unlink(filename)
                return dir
            except FileExistsError:
                pass
            except PermissionError:
                # This exception is thrown when a directory with the chosen name
                # already exists on windows.
                if (_os.name == 'nt' and _os.path.isdir(dir)
                        and _os.access(dir, _os.W_OK)):
                    continue
                break  # no point trying more names in this directory
            except OSError:
                break  # no point trying more names in this directory
    raise FileNotFoundError(
        _errno.ENOENT, "No usable temporary directory found in %s" % dirlist)
Exemple #8
0
def _secure_open_write(filename, fmode):
    # We only want to write to this file, so open it in write only mode
    flags = testos.O_WRONLY

    # os.O_CREAT | os.O_EXCL will fail if the file already exists, so we only
    #  will open *new* files.
    # We specify this because we want to ensure that the mode we pass is the
    # mode of the file.
    flags |= testos.O_CREAT | testos.O_EXCL

    # Do not follow symlinks to prevent someone from making a symlink that
    # we follow and insecurely open a cache file.
    if hasattr(testos, "O_NOFOLLOW"):
        flags |= testos.O_NOFOLLOW

    # On Windows we'll mark this file as binary
    if hasattr(testos, "O_BINARY"):
        flags |= testos.O_BINARY

    # Before we open our file, we want to delete any existing file that is
    # there
    try:
        testos.remove(filename)
    except (IOError, OSError):
        # The file must not exist already, so we can just skip ahead to opening
        pass

    # Open our file, the use of os.O_CREAT | os.O_EXCL will ensure that if a
    # race condition happens between the os.remove and this line, that an
    # error will be raised. Because we utilize a lockfile this should only
    # happen if someone is attempting to attack us.
    fd = testos.open(filename, flags, fmode)
    try:
        return testos.fdopen(fd, "wb")
    except:
        # An error occurred wrapping our FD in a file object
        testos.close(fd)
        raise
Exemple #9
0
    def update(self, modifier, dest_dir=None, **kwargs):
        """
        Update the contents of a wheel in a generic way. The modifier should
        be a callable which expects a dictionary argument: its keys are
        archive-entry paths, and its values are absolute filesystem paths
        where the contents the corresponding archive entries can be found. The
        modifier is free to change the contents of the files pointed to, add
        new entries and remove entries, before returning. This method will
        extract the entire contents of the wheel to a temporary location, call
        the modifier, and then use the passed (and possibly updated)
        dictionary to write a new wheel. If ``dest_dir`` is specified, the new
        wheel is written there -- otherwise, the original wheel is overwritten.

        The modifier should return True if it updated the wheel, else False.
        This method returns the same value the modifier returns.
        """
        def get_version(path_map, info_dir):
            version = path = None
            key = '%s/%s' % (info_dir, METADATA_FILENAME)
            if key not in path_map:
                key = '%s/PKG-INFO' % info_dir
            if key in path_map:
                path = path_map[key]
                version = Metadata(path=path).version
            return version, path

        def update_version(version, path):
            updated = None
            try:
                v = NormalizedVersion(version)
                i = version.find('-')
                if i < 0:
                    updated = '%s+1' % version
                else:
                    parts = [int(s) for s in version[i + 1:].split('.')]
                    parts[-1] += 1
                    updated = '%s+%s' % (version[:i], '.'.join(
                        str(i) for i in parts))
            except UnsupportedVersionError:
                logger.debug(
                    'Cannot update non-compliant (PEP-440) '
                    'version %r', version)
            if updated:
                md = Metadata(path=path)
                md.version = updated
                legacy = not path.endswith(METADATA_FILENAME)
                md.write(path=path, legacy=legacy)
                logger.debug('Version updated from %r to %r', version, updated)

        pathname = testos.path.join(self.dirname, self.filename)
        name_ver = '%s-%s' % (self.name, self.version)
        info_dir = '%s.dist-info' % name_ver
        record_name = posixpath.join(info_dir, 'RECORD')
        with tempdir() as workdir:
            with ZipFile(pathname, 'r') as zf:
                path_map = {}
                for zinfo in zf.infolist():
                    arcname = zinfo.filename
                    if isinstance(arcname, text_type):
                        u_arcname = arcname
                    else:
                        u_arcname = arcname.decode('utf-8')
                    if u_arcname == record_name:
                        continue
                    if '..' in u_arcname:
                        raise DistlibException('invalid entry in '
                                               'wheel: %r' % u_arcname)
                    zf.extract(zinfo, workdir)
                    path = testos.path.join(workdir, convert_path(u_arcname))
                    path_map[u_arcname] = path

            # Remember the version.
            original_version, _ = get_version(path_map, info_dir)
            # Files extracted. Call the modifier.
            modified = modifier(path_map, **kwargs)
            if modified:
                # Something changed - need to build a new wheel.
                current_version, path = get_version(path_map, info_dir)
                if current_version and (current_version == original_version):
                    # Add or update local version to signify changes.
                    update_version(current_version, path)
                # Decide where the new wheel goes.
                if dest_dir is None:
                    fd, newpath = tempfile.mkstemp(suffix='.whl',
                                                   prefix='wheel-update-',
                                                   dir=workdir)
                    testos.close(fd)
                else:
                    if not testos.path.isdir(dest_dir):
                        raise DistlibException('Not a directory: %r' %
                                               dest_dir)
                    newpath = testos.path.join(dest_dir, self.filename)
                archive_paths = list(path_map.items())
                distinfo = testos.path.join(workdir, info_dir)
                info = distinfo, info_dir
                self.write_records(info, workdir, archive_paths)
                self.build_zip(newpath, archive_paths)
                if dest_dir is None:
                    shutil.copyfile(newpath, pathname)
        return modified
Exemple #10
0
 def _stat(fn):
     fd = _os.open(fn, _os.O_RDONLY)
     _os.close(fd)
Exemple #11
0
    def TemporaryFile(mode='w+b',
                      buffering=-1,
                      encoding=None,
                      newline=None,
                      suffix=None,
                      prefix=None,
                      dir=None):
        """Create and return a temporary file.
        Arguments:
        'prefix', 'suffix', 'dir' -- as for mkstemp.
        'mode' -- the mode argument to io.open (default "w+b").
        'buffering' -- the buffer size argument to io.open (default -1).
        'encoding' -- the encoding argument to io.open (default None)
        'newline' -- the newline argument to io.open (default None)
        The file is created as mkstemp() would do it.

        Returns an object with a file-like interface.  The file has no
        name, and will cease to exist when it is closed.
        """
        global _O_TMPFILE_WORKS

        prefix, suffix, dir, output_type = _sanitize_params(
            prefix, suffix, dir)

        flags = _bin_openflags
        if _O_TMPFILE_WORKS:
            try:
                flags2 = (flags | _os.O_TMPFILE) & ~_os.O_CREAT
                fd = _os.open(dir, flags2, 0o600)
            except IsADirectoryError:
                # Linux kernel older than 3.11 ignores the O_TMPFILE flag:
                # O_TMPFILE is read as O_DIRECTORY. Trying to open a directory
                # with O_RDWR|O_DIRECTORY fails with IsADirectoryError, a
                # directory cannot be open to write. Set flag to False to not
                # try again.
                _O_TMPFILE_WORKS = False
            except OSError:
                # The filesystem of the directory does not support O_TMPFILE.
                # For example, OSError(95, 'Operation not supported').
                #
                # On Linux kernel older than 3.11, trying to open a regular
                # file (or a symbolic link to a regular file) with O_TMPFILE
                # fails with NotADirectoryError, because O_TMPFILE is read as
                # O_DIRECTORY.
                pass
            else:
                try:
                    return _io.open(fd,
                                    mode,
                                    buffering=buffering,
                                    newline=newline,
                                    encoding=encoding)
                except:
                    _os.close(fd)
                    raise
            # Fallback to _mkstemp_inner().

        (fd, name) = _mkstemp_inner(dir, prefix, suffix, flags, output_type)
        try:
            _os.unlink(name)
            return _io.open(fd,
                            mode,
                            buffering=buffering,
                            newline=newline,
                            encoding=encoding)
        except:
            _os.close(fd)
            raise