// Copyright 2026 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build linux

package unix

import (
	
	
)

func ( int,  string,  uint32,  int) error {
	// On Linux, the fchmodat syscall silently ignores the AT_SYMLINK_NOFOLLOW flag.
	// We need to use fchmodat2 instead.
	// syscall.Fchmodat handles this.
	if  := syscall.Fchmodat(, , , );  != syscall.EOPNOTSUPP {
		return 
	}

	// This kernel doesn't appear to support fchmodat2 (added in Linux 6.6).
	// We can't fall back to Fchmod, because it requires write permissions on the file.
	// Instead, use the same workaround as GNU libc and musl, which is to open the file
	// and then fchmodat the FD in /proc/self/fd.
	// See: https://lwn.net/Articles/939217/
	,  := Openat(, , O_PATH|syscall.O_NOFOLLOW|syscall.O_CLOEXEC, 0)
	if  != nil {
		return 
	}
	defer syscall.Close()
	 := "/proc/self/fd/" + strconv.Itoa()

	// Check to see if this file is a symlink.
	// (We passed O_NOFOLLOW above, but O_PATH|O_NOFOLLOW will open a symlink.)
	var  syscall.Stat_t
	if  := syscall.Stat(, &);  != nil {
		if  == syscall.ENOENT {
			// /proc has probably not been mounted. Give up.
			return syscall.EOPNOTSUPP
		}
		return 
	}
	if .Mode&syscall.S_IFMT == syscall.S_IFLNK {
		// fchmodat on the proc FD for a symlink apparently gives inconsistent
		// results, so just refuse to try.
		return syscall.EOPNOTSUPP
	}

	return syscall.Fchmodat(AT_FDCWD, , , &^AT_SYMLINK_NOFOLLOW)
}