mirror of
https://github.com/moby/moby.git
synced 2026-08-09 01:21:37 +00:00
vendor: github.com/moby/go-archive v0.3.2 (dev)
full diff: https://github.com/moby/go-archive/compare/v0.3.1...v0.3.2 Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
2
go.mod
2
go.mod
@@ -64,7 +64,7 @@ require (
|
||||
github.com/mitchellh/copystructure v1.2.0
|
||||
github.com/moby/buildkit v0.32.0
|
||||
github.com/moby/docker-image-spec v1.3.1
|
||||
github.com/moby/go-archive v0.3.1
|
||||
github.com/moby/go-archive v0.3.2
|
||||
github.com/moby/ipvs v1.1.0
|
||||
github.com/moby/locker v1.0.1
|
||||
github.com/moby/moby/api v1.55.0
|
||||
|
||||
4
go.sum
4
go.sum
@@ -547,8 +547,8 @@ github.com/moby/buildkit v0.32.0 h1:slXarYQoMo4cp2d9x30M9t0L4R+c0CVMov+5P1hhiHY=
|
||||
github.com/moby/buildkit v0.32.0/go.mod h1:Y10FBWvqxl/Wmhdzjee1Y2wQfjifTiwxENIUdaVNdME=
|
||||
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
||||
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
||||
github.com/moby/go-archive v0.3.1 h1:AHwfS8lTrPOb4rg9IFuc3k5Xg7jCzYidPt8SimWPHLM=
|
||||
github.com/moby/go-archive v0.3.1/go.mod h1:Npdv43fFqlhZW7Xo8fbm3ZMYFvAGNviUPqX21VERbcE=
|
||||
github.com/moby/go-archive v0.3.2 h1:x893kC3zRygv2C+k4Y9kMxYRPLCj4XEJB0srbAP06Hw=
|
||||
github.com/moby/go-archive v0.3.2/go.mod h1:Npdv43fFqlhZW7Xo8fbm3ZMYFvAGNviUPqX21VERbcE=
|
||||
github.com/moby/ipvs v1.1.0 h1:ONN4pGaZQgAx+1Scz5RvWV4Q7Gb+mvfRh3NsPS+1XQQ=
|
||||
github.com/moby/ipvs v1.1.0/go.mod h1:4VJMWuf098bsUMmZEiD4Tjk/O7mOn3l1PTD3s4OoYAs=
|
||||
github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=
|
||||
|
||||
126
vendor/github.com/moby/go-archive/archive.go
generated
vendored
126
vendor/github.com/moby/go-archive/archive.go
generated
vendored
@@ -439,6 +439,82 @@ func (ta *tarAppender) addTarFile(srcPath, archivePath string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// resolveArchivePath resolves intermediate symlinks in name using chroot-like
|
||||
// semantics when os.Root cannot traverse them. The final path component is
|
||||
// intentionally preserved because archive extraction may create or replace it.
|
||||
//
|
||||
// This is a compatibility workaround rather than the preferred long-term
|
||||
// implementation. It resolves the path separately before the actual operation,
|
||||
// so a concurrent filesystem change may cause the operation to affect a
|
||||
// different path within root. The subsequent os.Root operation still confines
|
||||
// the operation to root and prevents such a change from escaping it.
|
||||
//
|
||||
// Paths with missing components are supported. Existing symlinks are resolved,
|
||||
// and any remaining nonexistent components are retained for later creation.
|
||||
//
|
||||
// This helper should eventually be replaced by handle-relative resolution and
|
||||
// operations with resolve-in-root semantics, avoiding the resolution/use race
|
||||
// and repeated path traversal.
|
||||
func resolveArchivePath(root *os.Root, name string) (string, error) {
|
||||
parent, base := filepath.Split(name)
|
||||
if parent == "" {
|
||||
return name, nil
|
||||
}
|
||||
|
||||
parent = filepath.Clean(parent)
|
||||
|
||||
// Follow the final parent component: it is an intermediate component of name,
|
||||
// and an absolute symlink there must trigger the resolve-in-root fallback.
|
||||
_, statErr := root.Stat(parent)
|
||||
switch {
|
||||
case statErr == nil:
|
||||
return name, nil
|
||||
case !os.IsNotExist(statErr) && !isPathEscapes(statErr):
|
||||
return "", statErr
|
||||
}
|
||||
|
||||
// Resolve the parent both to handle ENOENT from missing components or dangling
|
||||
// symlinks, and to determine whether an os.Root breakout was caused by an
|
||||
// absolute symlink. Relative symlink escapes preserve the original Stat error.
|
||||
resolved, err := resolveFSRootPath(root.Name(), parent)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if isPathEscapes(statErr) && (!resolved.followedAbsoluteLink || resolved.relativeEscapeBeforeAbsolute) {
|
||||
return "", statErr
|
||||
}
|
||||
|
||||
relParent, err := filepath.Rel(root.Name(), resolved.path)
|
||||
if err != nil {
|
||||
return "", breakoutError(fmt.Errorf(
|
||||
"could not make resolved parent %q relative to root %q: %w",
|
||||
resolved.path,
|
||||
root.Name(),
|
||||
err,
|
||||
))
|
||||
}
|
||||
if relParent != "." && !filepath.IsLocal(relParent) {
|
||||
return "", breakoutError(fmt.Errorf(
|
||||
"resolved parent %q escapes root %q",
|
||||
resolved.path,
|
||||
root.Name(),
|
||||
))
|
||||
}
|
||||
|
||||
return filepath.Join(relParent, base), nil
|
||||
}
|
||||
|
||||
// resolveHardlinkTarget validates a POSIX hardlink target and resolves it to
|
||||
// the native, root-relative filesystem path used for extraction.
|
||||
func resolveHardlinkTarget(root *os.Root, linkname string) (string, error) {
|
||||
cleaned := path.Clean(linkname)
|
||||
if cleaned == "." || !filepath.IsLocal(cleaned) {
|
||||
return "", breakoutError(fmt.Errorf("invalid hardlink target %q", linkname))
|
||||
}
|
||||
return resolveArchivePath(root, filepath.FromSlash(cleaned))
|
||||
}
|
||||
|
||||
// createTarFile extracts a single tar entry into the given root. dstPath is the
|
||||
// root-relative path of the entry being extracted, in native (host-separator)
|
||||
// form so it can be passed directly to os.Root methods and fsRootPath.
|
||||
@@ -462,6 +538,15 @@ func createTarFile(root *os.Root, dstPath string, hdr *tar.Header, reader io.Rea
|
||||
// so use hdrInfo.Mode() (they differ for e.g. setuid bits)
|
||||
hdrInfo := hdr.FileInfo()
|
||||
|
||||
var hardlinkTarget string
|
||||
if hdr.Typeflag == tar.TypeLink {
|
||||
var err error
|
||||
hardlinkTarget, err = resolveHardlinkTarget(root, hdr.Linkname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
switch hdr.Typeflag {
|
||||
case tar.TypeDir:
|
||||
// Create directory unless it already exists as one; merge in that case.
|
||||
@@ -511,13 +596,7 @@ func createTarFile(root *os.Root, dstPath string, hdr *tar.Header, reader io.Rea
|
||||
}
|
||||
|
||||
case tar.TypeLink:
|
||||
// Defence in depth: root.Link's containment is limited when
|
||||
// dest is a volume root.
|
||||
linkname := path.Clean(hdr.Linkname)
|
||||
if linkname == "." || !filepath.IsLocal(linkname) {
|
||||
return breakoutError(fmt.Errorf("invalid hardlink target %q", hdr.Linkname))
|
||||
}
|
||||
if err := root.Link(filepath.FromSlash(linkname), dstPath); err != nil {
|
||||
if err := root.Link(hardlinkTarget, dstPath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -593,7 +672,7 @@ func createTarFile(root *os.Root, dstPath string, hdr *tar.Header, reader io.Rea
|
||||
|
||||
// There is no LChmod, so ignore mode for symlink. Also, this
|
||||
// must happen after chown, as that can modify the file mode
|
||||
if err := handleLChmod(root, dstPath, hdr, hdrInfo); err != nil {
|
||||
if err := handleLChmod(root, dstPath, hardlinkTarget, hdr, hdrInfo); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -608,7 +687,7 @@ func createTarFile(root *os.Root, dstPath string, hdr *tar.Header, reader io.Rea
|
||||
}
|
||||
case tar.TypeLink:
|
||||
// Follow the hardlink only when its target is not itself a symlink.
|
||||
fi, err := root.Lstat(filepath.FromSlash(path.Clean(hdr.Linkname)))
|
||||
fi, err := root.Lstat(hardlinkTarget)
|
||||
if err == nil && fi.Mode()&os.ModeSymlink == 0 {
|
||||
if err := chtimes(root, dstPath, aTime, mTime); err != nil {
|
||||
return err
|
||||
@@ -931,7 +1010,10 @@ loop:
|
||||
// dstPath is the native (host-separator) form of the entry name,
|
||||
// used at all filesystem boundaries (os.Root methods, fsRootPath).
|
||||
// hdr.Name stays POSIX (forward-slash) for logical string checks.
|
||||
dstPath := filepath.FromSlash(hdr.Name)
|
||||
dstPath, err := resolveArchivePath(root, filepath.FromSlash(hdr.Name))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If dstPath exists we almost always just want to remove and replace it.
|
||||
// The only exception is when it is a directory *and* the file from
|
||||
@@ -969,7 +1051,7 @@ loop:
|
||||
//
|
||||
// This must be done before whiteoutConverter.ConvertRead, which
|
||||
// may set xattrs on the directory or create whiteout files.
|
||||
if err := createImpliedDirectories(root, hdr, options); err != nil {
|
||||
if err := createImpliedDirectories(root, dstPath, options); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1024,17 +1106,19 @@ func unrepresentableOnWindows(hdr *tar.Header) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// createImpliedDirectories will create all parent directories of the current path with default permissions, if they do
|
||||
// not already exist. This is possible as the tar format supports 'implicit' directories, where their existence is
|
||||
// defined by the paths of files in the tar, but there are no header entries for the directories themselves, and thus
|
||||
// we most both create them and choose metadata like permissions.
|
||||
// createImpliedDirectories creates all parent directories of dstPath with
|
||||
// default permissions if they do not already exist. This is necessary because
|
||||
// the tar format permits implicit directories whose existence is defined only
|
||||
// by file paths, without corresponding directory headers from which metadata
|
||||
// could be restored.
|
||||
//
|
||||
// The caller must have normalized hdr.Name (no leading ".." components).
|
||||
// All directory creation is performed via root so it is bounded within the
|
||||
// destination at the OS level (openat(2) semantics), preventing escape via
|
||||
// symlinks in the destination tree.
|
||||
func createImpliedDirectories(root *os.Root, hdr *tar.Header, options *TarOptions) error {
|
||||
parent := filepath.FromSlash(path.Dir(strings.TrimSuffix(hdr.Name, "/")))
|
||||
// The caller must pass a normalized, root-relative local path. Any archive-path
|
||||
// conversion and resolve-in-root handling must already have been applied.
|
||||
// Directory creation is performed through root, so it remains confined to the
|
||||
// extraction destination even if the destination tree changes concurrently.
|
||||
func createImpliedDirectories(root *os.Root, dstPath string, options *TarOptions) error {
|
||||
parent := filepath.Dir(dstPath)
|
||||
|
||||
// Skip when the parent is the root itself; nothing to create.
|
||||
if parent == "." || parent == "" {
|
||||
return nil
|
||||
|
||||
5
vendor/github.com/moby/go-archive/archive_unix.go
generated
vendored
5
vendor/github.com/moby/go-archive/archive_unix.go
generated
vendored
@@ -8,7 +8,6 @@ import (
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
@@ -88,7 +87,7 @@ func handleTarTypeBlockCharFifo(root *os.Root, hdr *tar.Header, dstPath string)
|
||||
// handleLChmod applies the mode from hdrInfo to dstPath within root, skipping
|
||||
// symlinks (there is no lchmod). For hardlinks, the mode is applied only when
|
||||
// the link target is itself not a symlink.
|
||||
func handleLChmod(root *os.Root, dstPath string, hdr *tar.Header, hdrInfo os.FileInfo) error {
|
||||
func handleLChmod(root *os.Root, dstPath string, hardlinkTarget string, hdr *tar.Header, hdrInfo os.FileInfo) error {
|
||||
switch hdr.Typeflag {
|
||||
case tar.TypeSymlink:
|
||||
return nil
|
||||
@@ -96,7 +95,7 @@ func handleLChmod(root *os.Root, dstPath string, hdr *tar.Header, hdrInfo os.Fil
|
||||
case tar.TypeLink:
|
||||
// If the target is a symlink, there is no way to chmod the hardlink
|
||||
// without following it.
|
||||
fi, err := root.Lstat(filepath.FromSlash(path.Clean(hdr.Linkname)))
|
||||
fi, err := root.Lstat(hardlinkTarget)
|
||||
if err != nil || fi.Mode()&os.ModeSymlink != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
2
vendor/github.com/moby/go-archive/archive_windows.go
generated
vendored
2
vendor/github.com/moby/go-archive/archive_windows.go
generated
vendored
@@ -53,7 +53,7 @@ func handleTarTypeBlockCharFifo(root *os.Root, hdr *tar.Header, path string) err
|
||||
}
|
||||
|
||||
// handleLChmod is a no-op on Windows because chmod is not supported.
|
||||
func handleLChmod(root *os.Root, path string, hdr *tar.Header, hdrInfo os.FileInfo) error {
|
||||
func handleLChmod(root *os.Root, dstPath string, hardlinkTarget string, hdr *tar.Header, hdrInfo os.FileInfo) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
36
vendor/github.com/moby/go-archive/diff.go
generated
vendored
36
vendor/github.com/moby/go-archive/diff.go
generated
vendored
@@ -29,8 +29,9 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
|
||||
tr := tar.NewReader(layer)
|
||||
|
||||
var dirs []unpackedDir
|
||||
// unpackedPaths tracks root-relative paths already written in this layer
|
||||
// so that the AUFS opaque-whiteout walk knows which paths to preserve.
|
||||
// unpackedPaths tracks resolved, native-separator, root-relative paths
|
||||
// already written in this layer so that the AUFS opaque-whiteout walk
|
||||
// knows which paths to preserve.
|
||||
unpackedPaths := make(map[string]struct{})
|
||||
|
||||
if options == nil {
|
||||
@@ -71,12 +72,6 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
|
||||
continue
|
||||
}
|
||||
|
||||
// Ensure that the parent directory exists.
|
||||
err = createImpliedDirectories(root, hdr, options)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Skip AUFS metadata dirs
|
||||
if strings.HasPrefix(hdr.Name, WhiteoutMetaPrefix) {
|
||||
// Regular files inside /.wh..wh.plnk can be used as hardlink targets
|
||||
@@ -109,10 +104,15 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
|
||||
// dstPath is the native (host-separator) form of the entry name,
|
||||
// used at all filesystem boundaries (os.Root methods, fsRootPath).
|
||||
// The tar-header name (hdr.Name) is POSIX, so convert it here.
|
||||
dstPath := filepath.FromSlash(hdr.Name)
|
||||
base := filepath.Base(dstPath)
|
||||
|
||||
if strings.HasPrefix(base, WhiteoutPrefix) {
|
||||
dstPath, err := resolveArchivePath(root, filepath.FromSlash(hdr.Name))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
// Ensure that the parent directory exists.
|
||||
if err := createImpliedDirectories(root, dstPath, options); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if base := filepath.Base(dstPath); strings.HasPrefix(base, WhiteoutPrefix) {
|
||||
dir := filepath.Dir(dstPath)
|
||||
if base == WhiteoutOpaqueDir {
|
||||
_, err := root.Lstat(dir)
|
||||
@@ -144,9 +144,9 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
|
||||
return err
|
||||
}
|
||||
|
||||
// unpackedPaths is keyed by root-relative slash paths; convert
|
||||
// filepath.WalkDir's native path before looking it up.
|
||||
if _, exists := unpackedPaths[filepath.ToSlash(rel)]; !exists {
|
||||
// unpackedPaths is keyed by resolved, native-separator,
|
||||
// root-relative paths, matching filepath.WalkDir's paths.
|
||||
if _, exists := unpackedPaths[rel]; !exists {
|
||||
return root.RemoveAll(rel)
|
||||
}
|
||||
return nil
|
||||
@@ -206,9 +206,9 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
|
||||
if hdr.Typeflag == tar.TypeDir {
|
||||
dirs = append(dirs, unpackedDir{hdr: hdr, name: dstPath})
|
||||
}
|
||||
// unpackedPaths is keyed by the POSIX (forward-slash) name so it
|
||||
// matches the ToSlash'd lookup in the opaque-whiteout walk above.
|
||||
unpackedPaths[hdr.Name] = struct{}{}
|
||||
// Record the resolved, native-separator, root-relative path so it
|
||||
// matches the paths produced by the opaque-whiteout walk.
|
||||
unpackedPaths[dstPath] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
60
vendor/github.com/moby/go-archive/rootpath.go
generated
vendored
60
vendor/github.com/moby/go-archive/rootpath.go
generated
vendored
@@ -24,31 +24,47 @@ import (
|
||||
|
||||
var errTooManyLinks = errors.New("too many links")
|
||||
|
||||
type fsRootPathResult struct {
|
||||
path string
|
||||
followedAbsoluteLink bool
|
||||
relativeEscapeBeforeAbsolute bool
|
||||
}
|
||||
|
||||
// fsRootPath joins a path with a root, evaluating and bounding any
|
||||
// symlink to the root directory.
|
||||
func fsRootPath(root, path string) (string, error) {
|
||||
result, err := resolveFSRootPath(root, path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return result.path, nil
|
||||
}
|
||||
|
||||
func resolveFSRootPath(root, path string) (fsRootPathResult, error) {
|
||||
result := fsRootPathResult{path: root}
|
||||
if path == "" {
|
||||
return root, nil
|
||||
return result, nil
|
||||
}
|
||||
var linksWalked int // to protect against cycles
|
||||
for {
|
||||
i := linksWalked
|
||||
newpath, err := walkLinks(root, path, &linksWalked)
|
||||
newpath, err := walkLinks(root, path, &linksWalked, &result)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return fsRootPathResult{}, err
|
||||
}
|
||||
path = newpath
|
||||
if i == linksWalked {
|
||||
newpath = filepath.Join(string(os.PathSeparator), newpath)
|
||||
if path == newpath {
|
||||
return filepath.Join(root, newpath), nil
|
||||
result.path = filepath.Join(root, newpath)
|
||||
return result, nil
|
||||
}
|
||||
path = newpath
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func walkLink(root, path string, linksWalked *int) (newpath string, islink bool, err error) {
|
||||
func walkLink(root, path string, linksWalked *int, result *fsRootPathResult) (newpath string, islink bool, err error) {
|
||||
if *linksWalked > 255 {
|
||||
return "", false, errTooManyLinks
|
||||
}
|
||||
@@ -74,37 +90,51 @@ func walkLink(root, path string, linksWalked *int) (newpath string, islink bool,
|
||||
if err != nil {
|
||||
return "", false, err
|
||||
}
|
||||
if filepath.IsAbs(newpath) {
|
||||
result.followedAbsoluteLink = true
|
||||
} else if !result.followedAbsoluteLink {
|
||||
// Record an escape before a later absolute link can make the original
|
||||
// os.Root error appear eligible for resolve-in-root fallback.
|
||||
relativeDir, err := filepath.Rel(string(os.PathSeparator), filepath.Dir(path))
|
||||
if err != nil {
|
||||
return "", false, err
|
||||
}
|
||||
|
||||
resolved := filepath.Join(relativeDir, newpath)
|
||||
if resolved != "." && !filepath.IsLocal(resolved) {
|
||||
result.relativeEscapeBeforeAbsolute = true
|
||||
}
|
||||
}
|
||||
|
||||
*linksWalked++
|
||||
return newpath, true, nil
|
||||
}
|
||||
|
||||
func walkLinks(root, path string, linksWalked *int) (string, error) {
|
||||
func walkLinks(root, path string, linksWalked *int, result *fsRootPathResult) (string, error) {
|
||||
switch dir, file := filepath.Split(path); {
|
||||
case dir == "":
|
||||
newpath, _, err := walkLink(root, file, linksWalked)
|
||||
newpath, _, err := walkLink(root, file, linksWalked, result)
|
||||
return newpath, err
|
||||
case file == "":
|
||||
if os.IsPathSeparator(dir[len(dir)-1]) {
|
||||
if dir == string(os.PathSeparator) {
|
||||
return dir, nil
|
||||
}
|
||||
return walkLinks(root, dir[:len(dir)-1], linksWalked)
|
||||
return walkLinks(root, dir[:len(dir)-1], linksWalked, result)
|
||||
}
|
||||
newpath, _, err := walkLink(root, dir, linksWalked)
|
||||
newpath, _, err := walkLink(root, dir, linksWalked, result)
|
||||
return newpath, err
|
||||
|
||||
default:
|
||||
newdir, err := walkLinks(root, dir, linksWalked)
|
||||
newdir, err := walkLinks(root, dir, linksWalked, result)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
newpath, islink, err := walkLink(root, filepath.Join(newdir, file), linksWalked)
|
||||
newpath, islink, err := walkLink(root, filepath.Join(newdir, file), linksWalked, result)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !islink {
|
||||
return newpath, nil
|
||||
}
|
||||
if filepath.IsAbs(newpath) {
|
||||
if !islink || filepath.IsAbs(newpath) {
|
||||
return newpath, nil
|
||||
}
|
||||
return filepath.Join(newdir, newpath), nil
|
||||
|
||||
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
@@ -1266,7 +1266,7 @@ github.com/moby/buildkit/worker/label
|
||||
# github.com/moby/docker-image-spec v1.3.1
|
||||
## explicit; go 1.18
|
||||
github.com/moby/docker-image-spec/specs-go/v1
|
||||
# github.com/moby/go-archive v0.3.1
|
||||
# github.com/moby/go-archive v0.3.2
|
||||
## explicit; go 1.25
|
||||
github.com/moby/go-archive
|
||||
github.com/moby/go-archive/chrootarchive
|
||||
|
||||
Reference in New Issue
Block a user