@@ -19,16 +19,17 @@ package oci
1919import (
2020 "context"
2121 "io"
22+ "io/fs"
2223 "os"
2324 "path/filepath"
2425 "runtime"
2526 "testing"
2627
27- "github.com/opencontainers/runtime-spec/specs-go"
28-
2928 "github.com/containerd/containerd/v2/core/containers"
3029 "github.com/containerd/containerd/v2/pkg/namespaces"
3130 "github.com/containerd/containerd/v2/pkg/testutil"
31+ "github.com/containerd/continuity/fs/fstest"
32+ "github.com/opencontainers/runtime-spec/specs-go"
3233)
3334
3435func TestGenerateSpec (t * testing.T ) {
@@ -330,24 +331,35 @@ func TestWithPrivileged(t *testing.T) {
330331}
331332
332333func TestOpenUserFile_AbsoluteSymlink (t * testing.T ) {
333- tmpDir := t .TempDir ()
334-
335- targetName := "passwd"
336- targetPath := filepath .Join (tmpDir , targetName )
337- expectedContent := []byte ("root:x:0:0:root:/root:/bin/bash" )
338- if err := os .WriteFile (targetPath , expectedContent , 0644 ); err != nil {
339- t .Fatal (err )
334+ if runtime .GOOS == "windows" {
335+ t .Skip ("absolute symlink handling is only supported on non-Windows platforms" )
340336 }
341337
342- linkName := "abs_link"
343- linkPath := filepath .Join (tmpDir , linkName )
344- if err := os .Symlink (targetPath , linkPath ); err != nil {
338+ expectedContent := []byte ("root:x:0:0:root:/root:/bin/bash" + t .Name ())
339+
340+ root := t .TempDir ()
341+ // Use 'continuity' library to create a directory structure simulating NixOS
342+ if err := fstest .Apply (
343+ fstest .CreateDir ("/etc" , 0o755 ),
344+ fstest .CreateDir ("/nix/store/abcd" , 0o755 ),
345+ fstest .CreateFile ("/nix/store/abcd/passwd" , expectedContent , 0o644 ),
346+ // /etc/passwd -> /nix/store/abcd/passwd (absolute symlink)
347+ fstest .Symlink ("/nix/store/abcd/passwd" , "/etc/passwd" ),
348+ ).Apply (root ); err != nil {
345349 t .Fatal (err )
346350 }
347351
348- rootFS := os .DirFS (tmpDir )
352+ rootFS := os .DirFS (root )
353+
354+ // Ensure the FS implements the ReadLink interface.
355+ // If the native os.DirFS doesn't implement it (depending on Go version),
356+ // wrap it in our readLinkFS helper.
357+ if _ , ok := rootFS .(readLinker ); ! ok {
358+ t .Logf ("os.DirFS does not implement ReadLink; wrapping to use ReadLink" )
359+ rootFS = readLinkFS {root : root , fs : rootFS }
360+ }
349361
350- f , err := openUserFile (rootFS , linkName )
362+ f , err := openUserFile (rootFS , "etc/passwd" )
351363 if err != nil {
352364 t .Fatalf ("openUserFile failed on absolute symlink: %v" , err )
353365 }
@@ -361,3 +373,18 @@ func TestOpenUserFile_AbsoluteSymlink(t *testing.T) {
361373 t .Errorf ("expected content %q, got %q" , string (expectedContent ), string (content ))
362374 }
363375}
376+
377+ // Helpers for testing ReadLink support
378+ type readLinkFS struct {
379+ root string
380+ fs fs.FS
381+ }
382+
383+ func (r readLinkFS ) Open (name string ) (fs.File , error ) {
384+ return r .fs .Open (name )
385+ }
386+
387+ func (r readLinkFS ) ReadLink (name string ) (string , error ) {
388+ // Force link reading using the actual path on disk
389+ return os .Readlink (filepath .Join (r .root , filepath .FromSlash (name )))
390+ }
0 commit comments