ronantakizawa/codereview-bench huggingface dataset:
Repository: containerd/containerd
File: core/remotes/docker/fetcher.go (Go)

Code before:
						} else {
							if err := r.Acquire(ctx, 1); err != nil {
								_ = writers[i].CloseWithError(err)
								return err
							}
							defer r.Release(1)
							reqClone := req.clone()
							reqClone.setOffset(offset + i*chunkSize)
							nresp, err := reqClone.doWithRetries(ctx, lastHost, withErrorCheck)
							if err != nil {
								_ = writers[i].CloseWithError(err)
								return err
							}
							body = nresp.Body
						}
						_, err := io.Copy(writers[i], io.LimitReader(body, chunkSize))
						_ = body.Close()
						_ = writers[i].CloseWithError(err)
						if err != nil && err != io.EOF {
							return err
						}
						return nil
					}
					if err := copy(); err != nil {
						return err
					}
				}
				return nil
			})
		}
		body = &fnOnClose{
			BeforeClose: func() {
				if err := eg.Wait(); err != nil {
					log.G(ctx).WithError(err).Warn("parallel fetch failed")
				}
			},
			ReadCloser: io.NopCloser(io.MultiReader(readers...)),
		}
	}

	for i := len(encoding) - 1; i >= 0; i-- {
		algorithm := strings.ToLower(encoding[i])
		switch algorithm {
		case "zstd":
			r, err := zstd.NewReader(body.ReadCloser,
				zstd.WithDecoderLowmem(false),
			)
			if err != nil {
				return nil, 0, err
			}
			body.ReadCloser = r.IOReadCloser()

Review comment (suggestion):
I think we should close the rest of writers for all `j` where `j > i` before returning the error. This will ensure the readers do not block.

Code after:
							body = ibody
						} else {
							if err := r.Acquire(ctx, 1); err != nil {
								_ = writers[i].CloseWithError(err)
								return err
							}
							defer r.Release(1)
							reqClone := req.clone()
							reqClone.setOffset(offset + i*chunkSize)
							nresp, err := reqClone.doWithRetries(ctx, lastHost, withErrorCheck)
							if err != nil {
								_ = writers[i].CloseWithError(err)
								return err
							}
							body = nresp.Body
						}
						_, err := io.Copy(writers[i], io.LimitReader(body, chunkSize))
						_ = body.Close()
						_ = writers[i].CloseWithError(err)
						if err != nil && err != io.EOF {
							return err
						}
						return nil
					}
					if err := copy(); err != nil {
						return err
					}
				}
				return nil
			})
		}
		body = &fnOnClose{
			BeforeClose: func() {
				cancel()
				if err := eg.Wait(); err != nil {
					log.G(ctx).WithError(err).Warn("parallel fetch failed")
				}
			},
			ReadCloser: io.NopCloser(io.MultiReader(readers...)),
		}
	}

	for i := len(encoding) - 1; i >= 0; i-- {
		algorithm := strings.ToLower(encoding[i])
		switch algorithm {
		case "zstd":
			r, err := zstd.NewReader(body.ReadCloser,
				zstd.WithDecoderLowmem(false),
			)
			if err != nil {
				return nil, 0, err
Repository: containerd/containerd
File: core/remotes/docker/fetcher.go (Go)

Code before:
		case "identity", "":
			// no content-encoding applied, use raw body
		default:
			return nil, 0, errors.New("unsupported Content-Encoding algorithm: " + algorithm)
		}
	}

	return body, remaining, nil
}

type readFunc func(p []byte) (n int, err error)

func (f readFunc) Read(p []byte) (n int, err error) {
	return f(p)
}

func copyWithContext(ctx context.Context, dst io.Writer, src io.Reader) (written int64, err error) {
	// If the reader has a WriteTo method, use it to do the copy.
	// Avoids an allocation and a copy.
	if wt, ok := src.(io.WriterTo); ok {
		return wt.WriteTo(dst)
	}
	// Similarly, if the writer has a ReadFrom method, use it to do the copy.
	if rf, ok := dst.(io.ReaderFrom); ok {
		return rf.ReadFrom(src)
	}
	readFn := readFunc(func(p []byte) (n int, err error) {
		select {
		case <-ctx.Done():
			return 0, ctx.Err()
		default:
			return src.Read(p)
		}
	})
	return io.Copy(dst, readFn)
}

type fnOnClose struct {
	BeforeClose func()
	io.ReadCloser
}

// Close calls the BeforeClose function before closing the underlying
// ReadCloser.
func (f *fnOnClose) Close() error {
	f.BeforeClose()
	return f.ReadCloser.Close()
}

var _ io.ReadCloser = &fnOnClose{}


Review comment (suggestion):
The WriteTo and ReadFrom optimizations bypass context cancellation checks. If the source implements WriterTo or destination implements ReaderFrom, the copy operation will not respect context cancellation, potentially causing goroutines to hang during cancellation. Remove these optimization paths or ensure the underlying implementations are context-aware.
```suggestion

```

Code after:
		case "deflate":
			body.ReadCloser = flate.NewReader(body.ReadCloser)
		case "identity", "":
			// no content-encoding applied, use raw body
		default:
			return nil, 0, errors.New("unsupported Content-Encoding algorithm: " + algorithm)
		}
	}

	return body, remaining, nil
}

type fnOnClose struct {
	BeforeClose func()
	io.ReadCloser
}

// Close calls the BeforeClose function before closing the underlying
// ReadCloser.
func (f *fnOnClose) Close() error {
	f.BeforeClose()
	return f.ReadCloser.Close()
}

var _ io.ReadCloser = &fnOnClose{}
Repository: containerd/containerd
File: core/remotes/docker/fetcher.go (Go)

Code before:
			body.ReadCloser = r.IOReadCloser()
		case "gzip":
			r, err := gzip.NewReader(body.ReadCloser)
			if err != nil {
				return nil, 0, err
			}
			body.ReadCloser = r
		case "deflate":
			body.ReadCloser = flate.NewReader(body.ReadCloser)
		case "identity", "":
			// no content-encoding applied, use raw body
		default:
			return nil, 0, errors.New("unsupported Content-Encoding algorithm: " + algorithm)
		}
	}

	return body, remaining, nil
}

type readFunc func(p []byte) (n int, err error)

func (f readFunc) Read(p []byte) (n int, err error) {
	return f(p)
}

func copyWithContext(ctx context.Context, dst io.Writer, src io.Reader) (written int64, err error) {
	readFn := readFunc(func(p []byte) (n int, err error) {
		select {
		case <-ctx.Done():
			return 0, ctx.Err()
		default:
			return src.Read(p)
		}
	})
	return io.Copy(dst, readFn)
}

type fnOnClose struct {
	BeforeClose func()
	io.ReadCloser
}

// Close calls the BeforeClose function before closing the underlying
// ReadCloser.
func (f *fnOnClose) Close() error {
	f.BeforeClose()
	return f.ReadCloser.Close()
}

var _ io.ReadCloser = &fnOnClose{}


Review comment (suggestion):
I am thinking if we actually need this. The body is http reader with context. If there is any cancel on that, reader will return error.

Code after:
			body.ReadCloser = r.IOReadCloser()
		case "gzip":
			r, err := gzip.NewReader(body.ReadCloser)
			if err != nil {
				return nil, 0, err
			}
			body.ReadCloser = r
		case "deflate":
			body.ReadCloser = flate.NewReader(body.ReadCloser)
		case "identity", "":
			// no content-encoding applied, use raw body
		default:
			return nil, 0, errors.New("unsupported Content-Encoding algorithm: " + algorithm)
		}
	}

	return body, remaining, nil
}

type fnOnClose struct {
	BeforeClose func()
	io.ReadCloser
}

// Close calls the BeforeClose function before closing the underlying
// ReadCloser.
func (f *fnOnClose) Close() error {
	f.BeforeClose()
	return f.ReadCloser.Close()
}

var _ io.ReadCloser = &fnOnClose{}
Repository: containerd/containerd
File: core/remotes/docker/referrers.go (Go)

Code before:

package docker

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"strings"

	"github.com/containerd/errdefs"
	"github.com/containerd/log"
	digest "github.com/opencontainers/go-digest"
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)

func (r dockerFetcher) FetchReferrers(ctx context.Context, dgst digest.Digest, artifactTypes ...string) ([]ocispec.Descriptor, error) {
	rc, size, err := r.openReferrers(ctx, dgst, artifactTypes...)
	if err != nil {
		return nil, err
	}
	defer rc.Close()

	var index ocispec.Index
	if err := json.NewDecoder(io.LimitReader(rc, size)).Decode(&index); err != nil {
		return nil, fmt.Errorf("failed to decode referrers index: %w", err)
	}
	return index.Manifests, nil
}

func (r dockerFetcher) openReferrers(ctx context.Context, dgst digest.Digest, artifactTypes ...string) (io.ReadCloser, int64, error) {
	mediaType := ocispec.MediaTypeImageIndex
	ctx = log.WithLogger(ctx, log.G(ctx).WithField("digest", dgst))

	hosts := r.filterHosts(HostCapabilityReferrers)
	fallbackHosts := r.filterHosts(HostCapabilityResolve)
	if len(hosts) == 0 && len(fallbackHosts) == 0 {
		return nil, 0, fmt.Errorf("no pull hosts: %w", errdefs.ErrNotFound)
	}

	ctx, err := ContextWithRepositoryScope(ctx, r.refspec, false)
	if err != nil {
		return nil, 0, err
	}

	for i, host := range hosts {
		req := r.request(host, http.MethodGet, "referrers", dgst.String())
		for _, artifactType := range artifactTypes {
			if err := req.addQuery("artifactType", artifactType); err != nil {
				return nil, 0, err

Review comment (security):
Safe usage of `json.NewDecoder` requires calling smth like

```
	if _, err := dec.Token(); !errors.Is(err, io.EOF) {
		return nil, errors.Errorf("unexpected data after JSON object")
	}
```

after `Decode`. No actual security issue in here, just potentially not validating garbage data from registry.

Code after:

package docker

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"strings"

	"github.com/containerd/errdefs"
	"github.com/containerd/log"
	digest "github.com/opencontainers/go-digest"
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)

func (r dockerFetcher) FetchReferrers(ctx context.Context, dgst digest.Digest, artifactTypes ...string) ([]ocispec.Descriptor, error) {
	rc, size, err := r.openReferrers(ctx, dgst, artifactTypes...)
	if err != nil {
		return nil, err
	}
	defer rc.Close()

	var index ocispec.Index
	dec := json.NewDecoder(io.LimitReader(rc, size))
	if err := dec.Decode(&index); err != nil {
		return nil, fmt.Errorf("failed to decode referrers index: %w", err)
	}
	if _, err := dec.Token(); !errors.Is(err, io.EOF) {
		return nil, fmt.Errorf("unexpected data after JSON object")
	}

	if len(artifactTypes) == 0 {
		return index.Manifests, nil
	}

	var referrers []ocispec.Descriptor
	tFilter := map[string]struct{}{}
	for _, t := range artifactTypes {
		tFilter[t] = struct{}{}
	}
	for _, desc := range index.Manifests {
		if _, ok := tFilter[desc.ArtifactType]; ok {
			referrers = append(referrers, desc)
		}
	}
	return referrers, nil
}
Repository: containerd/containerd
File: pkg/sys/unshare_linux.go (Go)

Code before:
		var proc *os.Process
		var restoreErrno syscall.Errno
		var workErr error
		originalEUID := os.Geteuid()

		// Lock the thread, and use setresuid() directly to only apply
		// the effective uid to this thread
		runtime.LockOSThread()

		defer func() {
			// Only unlock the thread if we restored correctly, otherwise
			// let the go runtime kill the thread since its state is bad
			if restoreErrno == 0 {
				runtime.UnlockOSThread()
			}
		}()

		if _, _, errno := syscall.RawSyscall(unix.SYS_SETRESUID, ^uintptr(0), uintptr(targetHostUID), ^uintptr(0)); errno != 0 {
			workErr = fmt.Errorf("failed to set effective UID: %w", errno)
			resultChan <- result{-1, -1, workErr}
			return
		}
		defer func() {
			_, _, restoreErrno = syscall.RawSyscall(unix.SYS_SETRESUID, ^uintptr(0), uintptr(originalEUID), ^uintptr(0))
			if restoreErrno != 0 {
				if proc != nil {
					proc.Kill()
					proc.Wait()
				}
				if pidfd != -1 {
					unix.Close(pidfd)
				}
				resultChan <- result{-1, -1, fmt.Errorf("failed to restore UID: %w", restoreErrno)}
			} else if workErr != nil {
				resultChan <- result{-1, -1, workErr}
			} else {
				resultChan <- result{proc.Pid, pidfd, nil}
			}
		}()

		proc, err := os.StartProcess("/proc/self/exe", []string{"UnshareAfterEnterUserns"}, &os.ProcAttr{
			Sys: &syscall.SysProcAttr{
				// clone new user namespace first and then unshare
				Cloneflags:   unix.CLONE_NEWUSER,
				Unshareflags: unshareFlags,
				// NOTE: It's reexec but it's not heavy because subprocess
				// be in PTRACE_TRACEME mode before performing execve.
				Ptrace:    true,
				Pdeathsig: syscall.SIGKILL,
				PidFD:     &pidfd,
			},

Review comment (refactor):
This is just too much identation to me.

A function that inside has an anonymous function, that inside has a defer function, that inside does two nested ifs. Let's simplify this.

I'm not sure we want so many defers, or maybe another function.

Code after:
		proc.Wait()
		return -1, -1, fmt.Errorf("kernel doesn't support CLONE_PIDFD")
	}

	if _, _, errno := syscall.RawSyscall(unix.SYS_SETRESUID, ^uintptr(0), uintptr(originalEUID), ^uintptr(0)); errno != 0 {
		proc.Kill()
		proc.Wait()
		unix.Close(pidfd)
		return -1, -1, fmt.Errorf("failed to restore UID: %w", errno)
	}

	return proc.Pid, pidfd, nil
}

func pidfdWaitid(pidfd int) error {
	return IgnoringEINTR(func() error {
		return unix.Waitid(unix.P_PIDFD, pidfd, nil, unix.WEXITED, nil)
	})
}

type capSnapshot struct {
	hdr  unix.CapUserHeader
	data [2]unix.CapUserData
}

func getCurrentCaps() (*capSnapshot, error) {
	caps := &capSnapshot{}
	caps.hdr.Version = unix.LINUX_CAPABILITY_VERSION_3

	err := unix.Capget(&caps.hdr, &caps.data[0])
	if err != nil {
		return nil, err
	}
	return caps, nil
}

func setCurrentCaps(caps *capSnapshot) error {
	return unix.Capset(&caps.hdr, &caps.data[0])
}
Repository: containerd/containerd
File: pkg/sys/unshare_linux.go (Go)

Code before:
		runtime.LockOSThread()

		defer func() {
			// Only unlock the thread if we restored correctly, otherwise
			// let the go runtime kill the thread since its state is bad
			if restoreErrno == 0 {
				runtime.UnlockOSThread()
			}
		}()

		if _, _, errno := syscall.RawSyscall(unix.SYS_SETRESUID, ^uintptr(0), uintptr(targetHostUID), ^uintptr(0)); errno != 0 {
			workErr = fmt.Errorf("failed to set effective UID: %w", errno)
			resultChan <- result{-1, -1, workErr}
			return
		}
		defer func() {
			_, _, restoreErrno = syscall.RawSyscall(unix.SYS_SETRESUID, ^uintptr(0), uintptr(originalEUID), ^uintptr(0))
			if restoreErrno != 0 {
				if proc != nil {
					proc.Kill()
					proc.Wait()
				}
				if pidfd != -1 {
					unix.Close(pidfd)
				}
				resultChan <- result{-1, -1, fmt.Errorf("failed to restore UID: %w", restoreErrno)}
			} else if workErr != nil {
				resultChan <- result{-1, -1, workErr}
			} else {
				resultChan <- result{proc.Pid, pidfd, nil}
			}
		}()

		proc, err := os.StartProcess("/proc/self/exe", []string{"UnshareAfterEnterUserns"}, &os.ProcAttr{
			Sys: &syscall.SysProcAttr{
				// clone new user namespace first and then unshare
				Cloneflags:   unix.CLONE_NEWUSER,
				Unshareflags: unshareFlags,
				// NOTE: It's reexec but it's not heavy because subprocess
				// be in PTRACE_TRACEME mode before performing execve.
				Ptrace:    true,
				Pdeathsig: syscall.SIGKILL,
				PidFD:     &pidfd,
			},
		})

		if err != nil {
			workErr = fmt.Errorf("failed to start noop process for unshare: %w", err)
			return
		}


Review comment (suggestion):
No one is listening to this, right? The out most function waits for only one message on this channel.

I think that way is probably a little on the complex side, I hope this can be reworked so it's not needed, instead of the caller receiving two messages.

Code after:
		unix.Close(pidfd)
		return -1, -1, fmt.Errorf("failed to restore UID: %w", errno)
	}

	return proc.Pid, pidfd, nil
}

func pidfdWaitid(pidfd int) error {
	return IgnoringEINTR(func() error {
		return unix.Waitid(unix.P_PIDFD, pidfd, nil, unix.WEXITED, nil)
	})
}

type capSnapshot struct {
	hdr  unix.CapUserHeader
	data [2]unix.CapUserData
}

func getCurrentCaps() (*capSnapshot, error) {
	caps := &capSnapshot{}
	caps.hdr.Version = unix.LINUX_CAPABILITY_VERSION_3

	err := unix.Capget(&caps.hdr, &caps.data[0])
	if err != nil {
		return nil, err
	}
	return caps, nil
}

func setCurrentCaps(caps *capSnapshot) error {
	return unix.Capset(&caps.hdr, &caps.data[0])
}
Repository: containerd/containerd
File: plugins/mount/erofs/plugin_linux.go (Go)

Code before:
	} else if err != nil {
		return mount.ActiveMount{}, err
	}

	t := time.Now()
	return mount.ActiveMount{
		Mount:      m,
		MountedAt:  &t,
		MountPoint: mp,
	}, nil
}

func (erofsMountHandler) Unmount(ctx context.Context, path string) error {
	return mount.Unmount(path, 0)
}

type Config struct{}

func init() {
	registry.Register(&plugin.Registration{
		Type:   plugins.MountHandlerPlugin,
		ID:     "erofs",
		Config: &Config{},
		InitFn: func(ic *plugin.InitContext) (interface{}, error) {
			p := platforms.DefaultSpec()
			p.OS = "linux"
			ic.Meta.Platforms = append(ic.Meta.Platforms, p)

			return newErofsMountHandler(), nil
		},
	})
}


Review comment (suggestion):
The file name is `_linux.go`. Just use runtime.GOOS. here

Code after:
		}
	} else if err != nil {
		return mount.ActiveMount{}, err
	}

	t := time.Now()
	return mount.ActiveMount{
		Mount:      m,
		MountedAt:  &t,
		MountPoint: mp,
	}, nil
}

func (erofsMountHandler) Unmount(ctx context.Context, path string) error {
	return mount.Unmount(path, 0)
}

type Config struct{}

func init() {
	registry.Register(&plugin.Registration{
		Type:   plugins.MountHandlerPlugin,
		ID:     "erofs",
		Config: &Config{},
		InitFn: func(ic *plugin.InitContext) (interface{}, error) {
			p := platforms.DefaultSpec()
			p.OS = runtime.GOOS
			ic.Meta.Platforms = append(ic.Meta.Platforms, p)

			return newErofsMountHandler(), nil
		},
	})
}
Repository: containerd/containerd
File: plugins/content/local/store_test.go (Go)

Code before:
		}, nil
	})
}

func TestContentRootDir(t *testing.T) {
	// test dir exist
	dirExist := t.TempDir()
	_, err := NewLabeledStore(dirExist, newMemoryLabelStore())
	if err != nil {
		t.Fatal(err)
	}
	// test dir doesn't exist
	dir := filepath.Join(t.TempDir(), "test_dir001")
	_, err = NewLabeledStore(dir, newMemoryLabelStore())
	if err != nil {
		t.Fatal(err)
	}
	if _, err := os.Stat(dir); err != nil {
		t.Fatal(err)
	}

	// test dir permissions are invalid
	if os.Getuid() != 0 {
		t.Skip("skipping test that requires root")
	}
	dirBadPermission := t.TempDir()
	cmd := exec.Command("chattr", "+i", dirBadPermission)
	_, err = cmd.CombinedOutput()
	if err != nil {
		t.Fatal(err)
	}
	defer func() {
		cmd := exec.Command("chattr", "-i", dirBadPermission)
		_, err = cmd.CombinedOutput()
	}()
	_, err = fsverity.IsSupported(dirBadPermission)
	if err == nil {
		t.Fatal(fmt.Errorf("err can't be nil"))
	}
}

func TestContentWriter(t *testing.T) {
	ctx, tmpdir, cs, cleanup := contentStoreEnv(t)
	defer cleanup()
	defer testutil.DumpDirOnFailure(t, tmpdir)

	cw, err := cs.Writer(ctx, content.WithRef("myref"))
	if err != nil {
		t.Fatal(err)
	}
	if err := cw.Close(); err != nil {

Review comment (suggestion):
Why not directly call `ioctl(FS_IOC_SETFLAGS)` in Go


Code after:
}

func TestContentRootDir(t *testing.T) {
	// test dir exist
	dirExist := t.TempDir()
	_, err := NewLabeledStore(dirExist, newMemoryLabelStore())
	assert.NoError(t, err)
	// test dir doesn't exist
	dir := filepath.Join(t.TempDir(), "test_dir001")
	_, err = NewLabeledStore(dir, newMemoryLabelStore())
	assert.NoError(t, err)
	_, err = os.Stat(dir)
	assert.NoError(t, err)
}

func TestInvalidPermissionRootDir(t *testing.T) {
	// test dir permissions are invalid
	if os.Getuid() != 0 {
		t.Skip("skipping test that requires root")
	}
	_, err := exec.LookPath("chattr")
	if err != nil {
		t.Skip("skipping test that requires chattr command")
	}
	dirBadPermission := t.TempDir()
	cmd := exec.Command("chattr", "+i", dirBadPermission)
	_, err = cmd.CombinedOutput()
	assert.NoError(t, err)
	defer func() {
		cmd := exec.Command("chattr", "-i", dirBadPermission)
		_, err = cmd.CombinedOutput()
		assert.NoError(t, err)
	}()
	_, err = fsverity.IsSupported(dirBadPermission)
	if err == nil {
		t.Fatal(fmt.Errorf("err can't be nil"))
	}
}

func TestContentWriter(t *testing.T) {
	ctx, tmpdir, cs, cleanup := contentStoreEnv(t)
	defer cleanup()
	defer testutil.DumpDirOnFailure(t, tmpdir)

	cw, err := cs.Writer(ctx, content.WithRef("myref"))
	if err != nil {
		t.Fatal(err)
	}
	if err := cw.Close(); err != nil {
		t.Fatal(err)
	}
Repository: containerd/containerd
File: plugins/snapshots/erofs/plugin/plugin.go (Go)

Code before:
				root = config.RootPath
			}

			if len(config.OvlOptions) > 0 {
				opts = append(opts, erofs.WithOvlOptions(config.OvlOptions))
			}

			if config.EnableFsverity {
				opts = append(opts, erofs.WithFsverity())
			}

			if config.SetImmutable {
				opts = append(opts, erofs.WithImmutable())
			}

			if config.DefaultSize != "" {
				size, err := units.RAMInBytes(config.DefaultSize)
				if err != nil {
					return nil, fmt.Errorf("failed to parse default_size '%v': %w", config.DefaultSize, err)
				}
				opts = append(opts, erofs.WithDefaultSize(size))
			}

			// Don't bother supporting overlay's slow_chown, only RemapIDs
			ic.Meta.Capabilities = append(ic.Meta.Capabilities, capaOnlyRemapIDs)
			if ok, err := overlayutils.SupportsIDMappedMounts(); err == nil && ok {
				opts = append(opts, erofs.WithRemapIDs())
				ic.Meta.Capabilities = append(ic.Meta.Capabilities, capaRemapIDs)
			}

			ic.Meta.Exports[plugins.SnapshotterRootDir] = root
			ic.Meta.Capabilities = append(ic.Meta.Capabilities, "rebase")
			return erofs.NewSnapshotter(root, opts...)
		},
	})
}


Review comment (suggestion):
`fsmerge feature` can also be used as a faster chown approach later if needed, but I'm fine to leave this PR as-is.

Code after:
				root = config.RootPath
			}

			if len(config.OvlOptions) > 0 {
				opts = append(opts, erofs.WithOvlOptions(config.OvlOptions))
			}

			if config.EnableFsverity {
				opts = append(opts, erofs.WithFsverity())
			}

			if config.SetImmutable {
				opts = append(opts, erofs.WithImmutable())
			}

			if config.DefaultSize != "" {
				size, err := units.RAMInBytes(config.DefaultSize)
				if err != nil {
					return nil, fmt.Errorf("failed to parse default_size '%v': %w", config.DefaultSize, err)
				}
				opts = append(opts, erofs.WithDefaultSize(size))
			}

			if config.MaxUnmergedLayers > 0 {
				opts = append(opts, erofs.WithFsMergeThreshold(config.MaxUnmergedLayers))
			}

			// Don't bother supporting overlay's slow_chown, only RemapIDs
			ic.Meta.Capabilities = append(ic.Meta.Capabilities, capaOnlyRemapIDs)
			if ok, err := supportsIDMappedMounts(); err == nil && ok {
				opts = append(opts, erofs.WithRemapIDs())
				ic.Meta.Capabilities = append(ic.Meta.Capabilities, capaRemapIDs)
			}

			ic.Meta.Exports[plugins.SnapshotterRootDir] = root
			ic.Meta.Capabilities = append(ic.Meta.Capabilities, "rebase")
			return erofs.NewSnapshotter(root, opts...)
		},
	})
}