Exemplo n.º 1
0
def ar_open(root, path, flags, mode=None, create=False, truncate=False):
    """A function similar to os.open() that ensures that the path
        we're accessing resides within a specified directory subtree.

        'root' is a directory that path must reside in.

        'path' is a path that is interpreted relative to 'root'.  i.e., 'root'
        is prepended to path.  'path' can not contain any symbolic links that
        would cause an access to be redirected outside of 'root'.  If this
        happens we'll raise an OSError exception with errno set to EREMOTE

        'mode' optional permissions mask used if we create 'path'

        'create' optional flag indicating if we should create 'path'

        'truncate' optional flag indicating if we should truncate 'path' after
        opening it."""

    # all paths must be absolute
    assert os.path.isabs(root)

    # only allow read/write flags
    assert (flags & ~(os.O_WRONLY | os.O_RDONLY)) == 0

    # we can't truncate a file unless we open it for writing
    assert not truncate or (flags & os.O_WRONLY)

    # if create is true the user must supply a mode mask
    assert not create or mode != None

    # we're going to update root and path so prepare an error
    # message with the existing values now.
    eremote = _("Path outside alternate root: root={root}, "
                "path={path}").format(root=root, path=path)

    # make target into a relative path
    if os.path.isabs(path):
        path = __path_abs_to_relative(path)

    # now open the alternate root and get its path
    # done to eliminate any links/mounts/etc in the path
    root_fd = os.open(root, os.O_RDONLY)
    try:
        root = __fd_to_path(root_fd)
    except OSError as e:
        if e.errno != errno.ENOENT:
            os.close(root_fd)
            raise e
    os.close(root_fd)

    # now open the target file, get its path, and make sure it
    # lives in the alternate root
    path_fd = None
    try:
        path_tmp = os.path.join(root, path)
        path_fd = os.open(path_tmp, flags)
    except OSError as e:
        if e.errno != errno.ENOENT or not create:
            raise e

    assert path_fd or create
    if not path_fd:
        # the file doesn't exist so we should try to create it.
        # we'll do this by first opening the directory which
        # will contain the file and then using openat within
        # that directory.
        path_dir = os.path.dirname(path)
        path_file = os.path.basename(path)
        try:
            path_dir_fd = \
                ar_open(root, path_dir, os.O_RDONLY)
        except OSError as e:
            if e.errno != errno.EREMOTE:
                raise e
            raise OSError(errno.EREMOTE, eremote)

        # we opened the directory, now create the file
        try:
            path_fd = sat.openat(path_dir_fd, path_file,
                                 flags | os.O_CREAT | os.O_EXCL, mode)
        except OSError as e:
            os.close(path_dir_fd)
            raise e

        # we created the file
        assert path_fd
        os.close(path_dir_fd)

    # verify that the file we opened lives in the alternate root
    try:
        path = __fd_to_path(path_fd)
    except OSError as e:
        if e.errno != errno.ENOENT:
            os.close(path_fd)
            raise e
        path = os.path.join(root, path)

    if not path.startswith(root):
        os.close(path_fd)
        raise OSError(errno.EREMOTE, eremote)

    if truncate:
        # the user wanted us to truncate the file
        try:
            os.ftruncate(path_fd, 0)
        except OSError as e:
            os.close(path_fd)
            raise e

    return path_fd
Exemplo n.º 2
0
                # we'll do this by first opening the directory which
                # will contain the file and then using openat within
                # that directory.
                path_dir = os.path.dirname(path)
                path_file = os.path.basename(path)
                try:
                        path_dir_fd = \
                            ar_open(root, path_dir, os.O_RDONLY)
                except OSError, e:
                        if e.errno != errno.EREMOTE:
                                raise e
                        raise OSError(errno.EREMOTE, eremote)

                # we opened the directory, now create the file
                try:
                        path_fd = sat.openat(path_dir_fd, path_file,
                            flags|os.O_CREAT|os.O_EXCL, mode)
                except OSError, e:
                        os.close(path_dir_fd)
                        raise e

                # we created the file
                assert path_fd
                os.close(path_dir_fd)

        # verify that the file we opened lives in the alternate root
        try:
                path = __fd_to_path(path_fd)
        except OSError, e:
                # W0511 XXX / FIXME Comments; pylint: disable=W0511
                # XXX: __fd_to_path() can return ENOENT due to 6964121
                # pylint: enable=W0511