time, and can't be modified by changing the `GODEBUG` environment variable
after the program starts.
+Go 1.25 added a new `embedfollowsymlinks` setting that controls whether the
+Go command will follow symlinks to regular files embedding files.
+The default value `embedfollowsymlinks=0` does not allow following
+symlinks. `embedfollowsymlinks=1` will allow following symlinks.
+
### Go 1.24
Go 1.24 added a new `fips140` setting that controls whether the Go
"go/build"
"go/scanner"
"go/token"
+ "internal/godebug"
"internal/platform"
"io/fs"
"os"
return files, err
}
+var embedfollowsymlinks = godebug.New("embedfollowsymlinks")
+
// resolveEmbed resolves //go:embed patterns to precise file lists.
// It sets files to the list of unique files matched (for go list),
// and it sets pmap to the more precise mapping from
list = append(list, rel)
}
+ // If the embedfollowsymlinks GODEBUG is set to 1, allow the leaf file to be a
+ // symlink (#59924). We don't allow directories to be symlinks and have already
+ // checked that none of the parent directories of the file are symlinks in the
+ // loop above. The file pointed to by the symlink must be a regular file.
+ case embedfollowsymlinks.Value() == "1" && info.Mode()&fs.ModeType == fs.ModeSymlink:
+ info, err := fsys.Stat(file)
+ if err != nil {
+ return nil, nil, err
+ }
+ if !info.Mode().IsRegular() {
+ return nil, nil, fmt.Errorf("cannot embed irregular file %s", rel)
+ }
+ if have[rel] != pid {
+ embedfollowsymlinks.IncNonDefault()
+ have[rel] = pid
+ list = append(list, rel)
+ }
+
case info.IsDir():
// Gather all files in the named directory, stopping at module boundaries
// and ignoring files that wouldn't be packaged into a module.
stderr '^x.go:5:12: pattern [*]t: cannot embed file [.]git: invalid name [.]git$'
rm .git
-# build rejects symlinks
+# build rejects symlinks by default
[symlink] symlink x.tzt -> x.txt
[symlink] ! go build -x
[symlink] stderr 'pattern [*]t: cannot embed irregular file x.tzt'
+# with GODEBUG embedfollowsymlinks=1, build allows symlinks of leaf files
+[symlink] env 'GODEBUG=embedfollowsymlinks=1'
+[symlink] go build -x
+[symlink] stderr 'x.tzt'
[symlink] rm x.tzt
+[symlink] env 'GODEBUG='
# build rejects empty directories
mkdir t
cp x.txt t/_x.txt
go build -x
+# build disallows symlinks of directories
+[symlink] symlink symdir -> symdirdst
+[symlink] cp x.go4 x.go
+[symlink] ! go build -x
+[symlink] stderr 'x.go:5:12: pattern symdir/[*]: cannot embed file symdir[\\/]x.txt: in non-directory symdir'
+[symlink] cp x.go5 x.go
+[symlink] ! go build -x
+[symlink] stderr 'x.go:5:12: pattern symdir/x.txt: cannot embed file symdir[\\/]x.txt: in non-directory symdir'
+# even with GODEBUG=embedfollowsymlinks=1
+[symlink] env 'GODEBUG=embedfollowsymlinks=1'
+[symlink] cp x.go4 x.go
+[symlink] ! go build -x
+[symlink] stderr 'x.go:5:12: pattern symdir/[*]: cannot embed file symdir[\\/]x.txt: in non-directory symdir'
+[symlink] cp x.go5 x.go
+[symlink] ! go build -x
+[symlink] stderr 'x.go:5:12: pattern symdir/x.txt: cannot embed file symdir[\\/]x.txt: in non-directory symdir'
+[symlink] env 'GODEBUG='
+
-- x.go --
package p
//go:embed all:t
var X embed.FS
+-- x.go4 --
+package p
+
+import "embed"
+
+//go:embed symdir/*
+var X embed.FS
+-- x.go5 --
+package p
+
+import "embed"
+
+//go:embed symdir/x.txt
+var Z string
-- x.txt --
hello
package use
import _ "m"
+-- symdirdst/x.txt --
-- go.mod --
module m
{Name: "asynctimerchan", Package: "time", Changed: 23, Old: "1"},
{Name: "dataindependenttiming", Package: "crypto/subtle", Opaque: true},
{Name: "decoratemappings", Package: "runtime", Opaque: true, Changed: 25, Old: "0"},
+ {Name: "embedfollowsymlinks", Package: "cmd/go"},
{Name: "execerrdot", Package: "os/exec"},
{Name: "fips140", Package: "crypto/fips140", Opaque: true},
{Name: "gocachehash", Package: "cmd/go"},
The number of non-default behaviors executed by the time package
due to a non-default GODEBUG=asynctimerchan=... setting.
+ /godebug/non-default-behavior/embedfollowsymlinks:events
+ The number of non-default behaviors executed by the cmd/go
+ package due to a non-default GODEBUG=embedfollowsymlinks=...
+ setting.
+
/godebug/non-default-behavior/execerrdot:events
The number of non-default behaviors executed by the os/exec
package due to a non-default GODEBUG=execerrdot=... setting.