ronantakizawa/codereview-bench huggingface dataset:
Repository: containerd/containerd
File: plugins/snapshots/erofs/erofs.go (Go)

Code before:

type snapshotter struct {
	root            string
	ms              *storage.MetaStore
	ovlOptions      []string
	enableFsverity  bool
	setImmutable    bool
	defaultWritable int64
	blockMode       bool
}

// NewSnapshotter returns a Snapshotter which uses EROFS+OverlayFS. The layers
// are stored under the provided root. A metadata file is stored under the root.
func NewSnapshotter(root string, opts ...Opt) (snapshots.Snapshotter, error) {
	config := SnapshotterConfig{
		defaultSize: defaultWritableSize,
	}
	for _, opt := range opts {
		opt(&config)
	}

	if err := os.MkdirAll(root, 0700); err != nil {
		return nil, err
	}

	if err := checkCompatibility(root, config.defaultSize > 0); err != nil {
		return nil, err
	}

	// Check fsverity support if enabled
	if config.enableFsverity {
		// TODO: Call specific function here
		supported, err := fsverity.IsSupported(root)
		if err != nil {
			return nil, fmt.Errorf("failed to check fsverity support on %q: %w", root, err)
		}
		if !supported {
			return nil, fmt.Errorf("fsverity is not supported on the filesystem of %q", root)
		}
	}

	if config.setImmutable && runtime.GOOS != "linux" {
		return nil, fmt.Errorf("setting IMMUTABLE_FL is only supported on Linux")
	}

	ms, err := storage.NewMetaStore(filepath.Join(root, "metadata.db"))
	if err != nil {
		return nil, err
	}

	if err := os.Mkdir(filepath.Join(root, "snapshots"), 0700); err != nil && !os.IsExist(err) {

Review comment (suggestion):
maybe we don't need to change checkCompatibility function. it's like

```go
if config.defaultSize > 0 {
        if err := checkCompatibility(root); err != nil {
                return nil, err
         }
} 
```

Code after:

type snapshotter struct {
	root            string
	ms              *storage.MetaStore
	ovlOptions      []string
	enableFsverity  bool
	setImmutable    bool
	defaultWritable int64
	blockMode       bool
}

// NewSnapshotter returns a Snapshotter which uses EROFS+OverlayFS. The layers
// are stored under the provided root. A metadata file is stored under the root.
func NewSnapshotter(root string, opts ...Opt) (snapshots.Snapshotter, error) {
	config := SnapshotterConfig{
		defaultSize: defaultWritableSize,
	}
	for _, opt := range opts {
		opt(&config)
	}

	if err := os.MkdirAll(root, 0700); err != nil {
		return nil, err
	}

	if config.defaultSize == 0 {
		// If not block mode, check root compatibility
		if err := checkCompatibility(root); err != nil {
			return nil, err
		}
	}

	// Check fsverity support if enabled
	if config.enableFsverity {
		// TODO: Call specific function here
		supported, err := fsverity.IsSupported(root)
		if err != nil {
			return nil, fmt.Errorf("failed to check fsverity support on %q: %w", root, err)
		}
		if !supported {
			return nil, fmt.Errorf("fsverity is not supported on the filesystem of %q", root)
		}
	}

	if config.setImmutable && runtime.GOOS != "linux" {
		return nil, fmt.Errorf("setting IMMUTABLE_FL is only supported on Linux")
	}

	ms, err := storage.NewMetaStore(filepath.Join(root, "metadata.db"))
	if err != nil {
		return nil, err
Repository: containerd/containerd
File: core/mount/losetup_linux_test.go (Go)

Code before:
func TestAttachDetachLoopDevice(t *testing.T) {
	testutil.RequiresRoot(t)

	path := createTempFile(t)

	dev, err := AttachLoopDevice(path)
	require.NoError(t, err)

	err = DetachLoopDevice(dev)
	require.NoError(t, err)
}

func TestAutoclearTrueLoop(t *testing.T) {
	testutil.RequiresRoot(t)

	dev := func() string {
		backingFile := createTempFile(t)

		file, err := SetupLoop(backingFile, LoopParams{Autoclear: true})
		require.NoError(t, err)
		dev := file.Name()
		file.Close()
		return dev
	}()
	for range 10 {
		if err := removeLoop(dev); err != nil {
			// Expected to fail as Autoclear should have already removed the loop device
			return
		}
		time.Sleep(20 * time.Millisecond)
	}
	t.Fatalf("removeLoop should fail if Autoclear is true")
}

func TestAutoclearFalseLoop(t *testing.T) {
	testutil.RequiresRoot(t)

	dev := func() string {
		backingFile := createTempFile(t)

		file, err := SetupLoop(backingFile, LoopParams{Autoclear: false})
		require.NoError(t, err)
		dev := file.Name()
		file.Close()
		return dev
	}()
	time.Sleep(100 * time.Millisecond)
	err := removeLoop(dev)
	require.NoError(t, err)
}


Review comment (suggestion):
yeah, that can introduce a race since another loop user could reuse it after loop fd is closed with autoclear on.

Code after:
		t.Fatal(err)
	}
}

func TestAttachDetachLoopDevice(t *testing.T) {
	testutil.RequiresRoot(t)

	path := createTempFile(t)

	dev, err := AttachLoopDevice(path)
	require.NoError(t, err)

	err = DetachLoopDevice(dev)
	require.NoError(t, err)
}

func TestAutoclearTrueLoop(t *testing.T) {
	testutil.RequiresRoot(t)

	backingFile := createTempFile(t)
	bInfo, err := os.Stat(backingFile)
	require.NoError(t, err)
	bInode := bInfo.Sys().(*syscall.Stat_t).Ino

	file, err := SetupLoop(backingFile, LoopParams{Autoclear: true})
	require.NoError(t, err)
	dev := file.Name()
	file.Close()

	var checkFn = func(loopDev string, expectedInode uint64) (_shouldRetry bool, _ error) {
		loop, err := os.Open(loopDev)
		if err != nil {
			if os.IsNotExist(err) {
				return false, nil
			}
			return false, fmt.Errorf("failed to open loop device: %w", err)
		}
		info, err := unix.IoctlLoopGetStatus64(int(loop.Fd()))
		loop.Close()
		if err != nil {
			if errors.Is(err, unix.ENXIO) {
				return false, nil
			}
			return false, fmt.Errorf("failed to get loop device info: %w", err)
		}

		if info.Inode != expectedInode {
			return false, nil
		}

		t.Logf("loop device %s still present with backing inode %d", loopDev, expectedInode)
Repository: containerd/containerd
File: plugins/snapshots/erofs/erofs_linux.go (Go)

Code before:
)

// defaultWritableSize is set to 0 for Linux to match the default behavior of
// other snapshotters available on Linux.
const defaultWritableSize = 0

// check if EROFS kernel filesystem is registered or not
func findErofs() bool {
	fs, err := os.ReadFile("/proc/filesystems")
	if err != nil {
		return false
	}
	return bytes.Contains(fs, []byte("\terofs\n"))
}

func checkCompatibility(root string) error {
	supportsDType, err := fs.SupportsDType(root)
	if err != nil {
		return err
	}
	if !supportsDType {
		return fmt.Errorf("%s does not support d_type. If the backing filesystem is xfs, please reformat with ftype=1 to enable d_type support", root)
	}

	if !findErofs() {
		return fmt.Errorf("erofs unsupported, please `modprobe erofs`: %w", plugin.ErrSkipPlugin)
	}

	return nil
}

func setImmutable(path string, enable bool) error {
	//nolint:revive,staticcheck	// silence "don't use ALL_CAPS in Go names; use CamelCase"
	const (
		FS_IMMUTABLE_FL = 0x10
	)
	f, err := os.Open(path)
	if err != nil {
		return fmt.Errorf("failed to open: %w", err)
	}
	defer f.Close()

	oldattr, err := unix.IoctlGetInt(int(f.Fd()), unix.FS_IOC_GETFLAGS)
	if err != nil {
		return fmt.Errorf("error getting inode flags: %w", err)
	}
	newattr := oldattr | FS_IMMUTABLE_FL
	if !enable {
		newattr ^= FS_IMMUTABLE_FL
	}
	if newattr == oldattr {

Review comment (suggestion):
honestly, `EROFS` is the preferred name, like `EXT4` and `XFS`...

Code after:
)

// defaultWritableSize is set to 0 for Linux to match the default behavior of
// other snapshotters available on Linux.
const defaultWritableSize = 0

// check if EROFS kernel filesystem is registered or not
func findErofs() bool {
	fs, err := os.ReadFile("/proc/filesystems")
	if err != nil {
		return false
	}
	return bytes.Contains(fs, []byte("\terofs\n"))
}

func checkCompatibility(root string) error {
	supportsDType, err := fs.SupportsDType(root)
	if err != nil {
		return err
	}
	if !supportsDType {
		return fmt.Errorf("%s does not support d_type. If the backing filesystem is xfs, please reformat with ftype=1 to enable d_type support", root)
	}

	if !findErofs() {
		return fmt.Errorf("EROFS unsupported, please `modprobe erofs`: %w", plugin.ErrSkipPlugin)
	}

	return nil
}

func setImmutable(path string, enable bool) error {
	//nolint:revive,staticcheck	// silence "don't use ALL_CAPS in Go names; use CamelCase"
	const (
		FS_IMMUTABLE_FL = 0x10
	)
	f, err := os.Open(path)
	if err != nil {
		return fmt.Errorf("failed to open: %w", err)
	}
	defer f.Close()

	oldattr, err := unix.IoctlGetInt(int(f.Fd()), unix.FS_IOC_GETFLAGS)
	if err != nil {
		return fmt.Errorf("error getting inode flags: %w", err)
	}
	newattr := oldattr | FS_IMMUTABLE_FL
	if !enable {
		newattr ^= FS_IMMUTABLE_FL
	}
	if newattr == oldattr {
Repository: containerd/containerd
File: internal/registrar/registrar.go (Go)

Code before:

package registrar

import (
	"fmt"
	"sync"
)

// Registrar stores one-to-one name<->key mappings.
// Names and keys must be unique.
// Registrar is safe for concurrent access.
type Registrar struct {
	lock      sync.Mutex
	nameToKey map[string]string
	keyToName map[string]string
}

// NewRegistrar creates a new Registrar with the empty indexes.
func NewRegistrar() *Registrar {
	return &Registrar{
		nameToKey: make(map[string]string),
		keyToName: make(map[string]string),
	}
}

type ReservedErr struct {
	Field string
	Name  string
	Key   string
}

func (e *ReservedErr) Error() string {
	switch e.Field {
	case "name":
		return fmt.Sprintf("name %q is reserved for %q", e.Name, e.Key)
	case "key":
		return fmt.Sprintf("key %q is reserved for %q", e.Key, e.Name)
	}
	return fmt.Sprintf("name %q is reserved for %q", e.Name, e.Key)

}

// Reserve registers a name<->key mapping, name or key must not
// be empty.
// Reserve is idempotent.
// Attempting to reserve a conflict key<->name mapping results
// in an error.
// A name<->key reservation is globally unique.
func (r *Registrar) Reserve(name, key string) error {
	r.lock.Lock()
	defer r.lock.Unlock()

Review comment (suggestion):
If this error is getting returned all the way through the API, it should Unwrap to an `errdefs` error or can implement one of the interface methods. This allows the error translation to set the appropriate grpc error code so it doesn't get treated as internal or unknown error.

If its a "conflict" error, it can be marked as such by implementing 
`Conflict() {}`
or 
`Unwrap() error { return errdefs.ErrConflict }`

Code after:

package registrar

import (
	"fmt"
	"sync"
)

// Registrar stores one-to-one name<->key mappings.
// Names and keys must be unique.
// Registrar is safe for concurrent access.
type Registrar struct {
	lock      sync.Mutex
	nameToKey map[string]string
	keyToName map[string]string
}

// NewRegistrar creates a new Registrar with the empty indexes.
func NewRegistrar() *Registrar {
	return &Registrar{
		nameToKey: make(map[string]string),
		keyToName: make(map[string]string),
	}
}

type ReservedErr struct {
	Field string
	Name  string
	Key   string
}

func (e *ReservedErr) Error() string {
	switch e.Field {
	case "name":
		return fmt.Sprintf("name %q is reserved for %q", e.Name, e.Key)
	case "key":
		return fmt.Sprintf("key %q is reserved for %q", e.Key, e.Name)
	}
	return fmt.Sprintf("name %q is reserved for %q", e.Name, e.Key)
}

func (e *ReservedErr) Conflict() {}

// Reserve registers a name<->key mapping, name or key must not
// be empty.
// Reserve is idempotent.
// Attempting to reserve a conflict key<->name mapping results
// in an error.
// A name<->key reservation is globally unique.
func (r *Registrar) Reserve(name, key string) error {
	r.lock.Lock()
Repository: containerd/containerd
File: pkg/tracing/helpers_spanopts.go (Go)

Code before:
   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package tracing

import (
	"context"

	"github.com/containerd/containerd/v2/pkg/namespaces"
	"go.opentelemetry.io/otel/trace"
)

// WithNamespace adds containerd namespace attribute to spans when available.
// It is best-effort: if namespace is not present in the context, it does nothing.
func WithNamespace(ctx context.Context) SpanOpt {
	return func(config *StartConfig) {
		ns, err := namespaces.NamespaceRequired(ctx)
		if err != nil {
			return
		}
		config.spanOpts = append(config.spanOpts,
			trace.WithAttributes(Attribute("containerd.namespace", ns)),
		)
	}
}


Review comment (suggestion):
```suggestion
			trace.WithAttributes(Attribute("namespace", ns)),
```

Code after:
   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package tracing

import (
	"context"

	"github.com/containerd/containerd/v2/pkg/namespaces"
	"go.opentelemetry.io/otel/trace"
)

// WithNamespace adds containerd namespace attribute to spans when available.
// It is best-effort: if namespace is not present in the context, it does nothing.
func WithNamespace(ctx context.Context) SpanOpt {
	return func(config *StartConfig) {
		ns, err := namespaces.NamespaceRequired(ctx)
		if err != nil {
			return
		}
		config.spanOpts = append(config.spanOpts,
			trace.WithAttributes(Attribute("namespace", ns)),
		)
	}
}
Repository: containerd/containerd
File: internal/cri/server/sandbox_run.go (Go)

Code before:
	)
	defer span.End()
	defer func() {
		if retErr != nil {
			span.RecordError(retErr)
		}
	}()

	var (
		id        = sandbox.ID
		config    = sandbox.Config
		path      = sandbox.NetNSPath
		netPlugin = c.getNetworkPlugin(sandbox.RuntimeHandler)
		err       error
		result    *cni.Result
	)

	// Add tracing attributes
	span.SetAttributes(
		tracing.Attribute("sandbox.id", id),
		tracing.Attribute("netns.path", path),
		tracing.Attribute("runtime.handler", sandbox.RuntimeHandler),
	)

	if netPlugin == nil {
		retErr = errors.New("cni config not initialized")
		return
	}

	if c.config.UseInternalLoopback {
		err := c.bringUpLoopback(path)
		if err != nil {
			retErr = fmt.Errorf("unable to set lo to up: %w", err)
			return
		}
	}

	opts, err := cniNamespaceOpts(id, config)
	if err != nil {
		retErr = fmt.Errorf("get cni namespace options: %w", err)
		return
	}

	log.G(ctx).WithField("podsandboxid", id).Debugf("begin cni setup")
	netStart := time.Now()

	span.AddEvent("cni.setup.start")
	if c.config.CniConfig.NetworkPluginSetupSerially {
		result, err = netPlugin.SetupSerially(ctx, id, path, opts...)
	} else {
		result, err = netPlugin.Setup(ctx, id, path, opts...)

Review comment (suggestion):
you don't need to assign error to retErr. the `retErr` will be the error we return.

Code after:
	defer func() {
		if retErr != nil {
			span.RecordError(retErr)
		}
	}()

	var (
		id        = sandbox.ID
		config    = sandbox.Config
		path      = sandbox.NetNSPath
		netPlugin = c.getNetworkPlugin(sandbox.RuntimeHandler)
		err       error
		result    *cni.Result
	)

	// Add tracing attributes
	span.SetAttributes(
		tracing.Attribute("sandbox.id", id),
		tracing.Attribute("netns.path", path),
		tracing.Attribute("runtime.handler", sandbox.RuntimeHandler),
	)

	if netPlugin == nil {
		return errors.New("cni config not initialized")
	}
	if c.config.UseInternalLoopback {
		err := c.bringUpLoopback(path)
		if err != nil {
			return fmt.Errorf("unable to set lo to up: %w", err)
		}
	}
	opts, err := cniNamespaceOpts(id, config)
	if err != nil {
		return fmt.Errorf("get cni namespace options: %w", err)
	}
	log.G(ctx).WithField("podsandboxid", id).Debugf("begin cni setup")
	netStart := time.Now()

	span.AddEvent("cni.setup.start")
	if c.config.CniConfig.NetworkPluginSetupSerially {
		result, err = netPlugin.SetupSerially(ctx, id, path, opts...)
	} else {
		result, err = netPlugin.Setup(ctx, id, path, opts...)
	}
	networkPluginOperations.WithValues(networkSetUpOp).Inc()
	networkPluginOperationsLatency.WithValues(networkSetUpOp).UpdateSince(netStart)
	if err != nil {
		networkPluginOperationsErrors.WithValues(networkSetUpOp).Inc()
		return err
	}
Repository: containerd/containerd
File: plugins/gc/scheduler_test.go (Go)

Code before:
	gcWait := make(chan struct{})
	go func() {
		stats, err = scheduler.ScheduleAndWait(ctx)
		close(gcWait)
	}()

	select {
	case <-gcWait:
	case <-time.After(time.Millisecond * 10):
		t.Fatal("GC wait timed out")
	}

	if err != nil {
		t.Fatalf("GC failed: %#v", err)
	}

	assert.Equal(t, tc.d, stats.Elapsed())

	if c := tc.runCount(); c != 1 {
		t.Fatalf("unexpected gc run count %d, expected 1", c)
	}
}

func TestStartupDelay(t *testing.T) {
	var (
		startupDelay = time.Millisecond * 20
		cfg          = &config{
			// Prevent GC from scheduling again before check
			PauseThreshold: 0.001,
			StartupDelay:   tomlext.Duration(startupDelay),
		}
		tc = &testCollector{
			d: time.Second,
		}
		ctx, cancel = context.WithCancel(context.Background())
		scheduler   = newScheduler(tc, cfg)
	)
	defer cancel()

	t1 := time.Now()
	go scheduler.run(ctx)
	_, err := scheduler.wait(ctx, false)
	if err != nil {
		t.Fatalf("gc failed with error: %s", err)
	}
	d := time.Since(t1)

	if c := tc.runCount(); c != 1 {
		t.Fatalf("unexpected gc run count %d, expected 1", c)
	}


Review comment (suggestion):
```suggestion
		ctx, cancel = context.WithCancel(t.Context())
```

Code after:
	case <-gcWait:
	case <-time.After(time.Millisecond * 10):
		t.Fatal("GC wait timed out")
	}

	if err != nil {
		t.Fatalf("GC failed: %#v", err)
	}

	assert.Equal(t, tc.d, stats.Elapsed())

	if c := tc.runCount(); c != 1 {
		t.Fatalf("unexpected gc run count %d, expected 1", c)
	}
}

func TestStartupDelay(t *testing.T) {
	var (
		startupDelay = time.Millisecond * 20
		cfg          = &config{
			// Prevent GC from scheduling again before check
			PauseThreshold: 0.001,
			StartupDelay:   tomlext.Duration(startupDelay),
		}
		tc        = &testCollector{d: time.Second}
		ctx       = t.Context()
		scheduler = newScheduler(tc, cfg)
	)

	t1 := time.Now()
	go scheduler.run(ctx)
	_, err := scheduler.wait(ctx, false)
	if err != nil {
		t.Fatalf("gc failed with error: %s", err)
	}
	d := time.Since(t1)

	if c := tc.runCount(); c != 1 {
		t.Fatalf("unexpected gc run count %d, expected 1", c)
	}

	if d < startupDelay {
		t.Fatalf("expected startup delay to be longer than %s, actual %s", startupDelay, d)
	}

}

type testCollector struct {
	d  time.Duration
	gc int
	m  sync.Mutex
Repository: containerd/containerd
File: internal/cri/server/container_image_mount_linux_test.go (Go)

Code before:

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	runtime "k8s.io/cri-api/pkg/apis/runtime/v1"
)

func TestGetImageVolumeSnapshotOpts(t *testing.T) {
	ctx := context.Background()

	for _, test := range []struct {
		name        string
		mount       *runtime.Mount
		expectOpts  bool
		expectError bool
	}{
		{
			name: "with user namespace mappings",
			mount: &runtime.Mount{
				ContainerPath: "/test",
				UidMappings: []*runtime.IDMapping{
					{
						ContainerId: 0,
						HostId:      65536,
						Length:      65536,
					},
				},
				GidMappings: []*runtime.IDMapping{
					{
						ContainerId: 0,
						HostId:      65536,
						Length:      65536,
					},
				},
			},
			expectOpts:  true,
			expectError: false,
		},
		{
			name: "without mappings",
			mount: &runtime.Mount{
				ContainerPath: "/test",
			},
			expectOpts:  false,
			expectError: false,
		},
		{
			name: "with empty mappings",
			mount: &runtime.Mount{
				ContainerPath: "/test",
				UidMappings:   []*runtime.IDMapping{},
				GidMappings:   []*runtime.IDMapping{},

Review comment (refactor):
You can move this to a var just before the for, like `mappings := []*runtime.IDMapiing{ ... `. And the assign it here for uidMappings and GidMappings, and all the other test cases.

Code after:
	"context"
	"testing"

	containerd "github.com/containerd/containerd/v2/client"
	"github.com/containerd/containerd/v2/core/snapshots"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	runtime "k8s.io/cri-api/pkg/apis/runtime/v1"
)

func TestGetImageVolumeSnapshotOpts(t *testing.T) {
	ctx := context.Background()

	mappings := []*runtime.IDMapping{
		{
			ContainerId: 0,
			HostId:      65536,
			Length:      65536,
		},
	}

	expectedOpts := optsToInfo(t, containerd.WithRemapperLabels(0, 65536, 0, 65536, 65536))

	for _, test := range []struct {
		name        string
		mount       *runtime.Mount
		expectInfo  *snapshots.Info
		expectError bool
	}{
		{
			name: "with user namespace mappings",
			mount: &runtime.Mount{
				ContainerPath: "/test",
				UidMappings:   mappings,
				GidMappings:   mappings,
			},
			expectInfo: expectedOpts,
		},
		{
			name: "without mappings",
			mount: &runtime.Mount{
				ContainerPath: "/test",
			},
		},
		{
			name: "with empty mappings",
			mount: &runtime.Mount{
				ContainerPath: "/test",
				UidMappings:   []*runtime.IDMapping{},
				GidMappings:   []*runtime.IDMapping{},
			},
Repository: containerd/containerd
File: internal/cri/server/container_image_mount_other.go (Go)

Code before:
	// no-op
	return mounts
}

// ensureImageVolumeMounted ensures target volume is mounted.
func ensureImageVolumeMounted(target string) (bool, error) {
	_, err := os.Stat(target)
	if err != nil {
		if os.IsNotExist(err) {
			return false, nil
		}
		return false, fmt.Errorf("failed to stat %s: %w", target, err)
	}
	return true, nil
}

// getImageVolumeSnapshotOpts is no-op on non-linux platforms.
func (c *criService) getImageVolumeSnapshotOpts(ctx context.Context, mount *runtime.Mount) ([]snapshots.Opt, error) {
	// User namespaces are only supported on Linux
	return nil, nil
}

// clearImageVolumeMountMappings is no-op on non-linux platforms.
func clearImageVolumeMountMappings(mount *runtime.Mount) {
	// User namespaces are only supported on Linux
}


Review comment (suggestion):
We can also delete this function entirely here. This was never needed, we need to add thingshere for  functions called from the non-platform specific files (like container_image_mount.go). It's not needed for functions called inside container_image_mount_linux.go, as it was the case here.


```suggestion

```

Code after:
//go:build !linux

/*
   Copyright The containerd Authors.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package server

import (
	"context"
	"fmt"
	"os"

	"github.com/containerd/containerd/v2/core/mount"
	"github.com/containerd/containerd/v2/core/snapshots"
	runtime "k8s.io/cri-api/pkg/apis/runtime/v1"
)

// addVolatileOptionOnImageVolumeMount is no-op on non-linux platforms.
func addVolatileOptionOnImageVolumeMount(mounts []mount.Mount) []mount.Mount {
	// no-op
	return mounts
}

// ensureImageVolumeMounted ensures target volume is mounted.
func ensureImageVolumeMounted(target string) (bool, error) {
	_, err := os.Stat(target)
	if err != nil {
		if os.IsNotExist(err) {
			return false, nil
		}
		return false, fmt.Errorf("failed to stat %s: %w", target, err)
	}
	return true, nil
}

func (c *criService) getImageVolumeSnapshotOpts(ctx context.Context, mount *runtime.Mount) ([]snapshots.Opt, error) {
	return nil, nil
}