Source file src/internal/syscall/unix/fchmodat_test.go

     1  // Copyright 2026 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build unix || wasip1
     6  
     7  package unix_test
     8  
     9  import (
    10  	"internal/syscall/unix"
    11  	"os"
    12  	"runtime"
    13  	"testing"
    14  )
    15  
    16  // TestFchmodAtSymlinkNofollow verifies that Fchmodat honors the AT_SYMLINK_NOFOLLOW flag.
    17  func TestFchmodatSymlinkNofollow(t *testing.T) {
    18  	if runtime.GOOS == "wasip1" {
    19  		t.Skip("wasip1 doesn't support chmod")
    20  	}
    21  
    22  	dir := t.TempDir()
    23  	filename := dir + "/file"
    24  	linkname := dir + "/symlink"
    25  	if err := os.WriteFile(filename, nil, 0o100); err != nil {
    26  		t.Fatal(err)
    27  	}
    28  	if err := os.Symlink(filename, linkname); err != nil {
    29  		t.Fatal(err)
    30  	}
    31  
    32  	parent, err := os.Open(dir)
    33  	if err != nil {
    34  		t.Fatal(err)
    35  	}
    36  	defer parent.Close()
    37  
    38  	lstatMode := func(path string) os.FileMode {
    39  		st, err := os.Lstat(path)
    40  		if err != nil {
    41  			t.Fatal(err)
    42  		}
    43  		return st.Mode()
    44  	}
    45  
    46  	// Fchmodat with no flags follows symlinks.
    47  	const mode1 = 0o200
    48  	if err := unix.Fchmodat(int(parent.Fd()), "symlink", mode1, 0); err != nil {
    49  		t.Fatal(err)
    50  	}
    51  	if got, want := lstatMode(filename), os.FileMode(mode1); got != want {
    52  		t.Errorf("after Fchmodat(parent, symlink, %v, 0); mode = %v, want %v", mode1, got, want)
    53  	}
    54  
    55  	// Fchmodat with AT_SYMLINK_NOFOLLOW does not follow symlinks.
    56  	// The Fchmodat call may fail or chmod the symlink itself, depending on the kernel version.
    57  	const mode2 = 0o400
    58  	unix.Fchmodat(int(parent.Fd()), "symlink", mode2, unix.AT_SYMLINK_NOFOLLOW)
    59  	if got, want := lstatMode(filename), os.FileMode(mode1); got != want {
    60  		t.Errorf("after Fchmodat(parent, symlink, %v, AT_SYMLINK_NOFOLLOW); mode = %v, want %v", mode1, got, want)
    61  	}
    62  }
    63  

View as plain text