Go version
go version go1.24.5 linux/amd64
Output of go env in your module/workspace:
AR='ar'
CC='gcc'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_ENABLED='1'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
CXX='g++'
GCCGO='gccgo'
GO111MODULE=''
GOAMD64='v1'
GOARCH='amd64'
GOAUTH='netrc'
GOBIN='/home/jono/.local/bin'
GOCACHE='/home/jono/.cache/go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/home/jono/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build3907116877=/tmp/go-build -gno-record-gcc-switches'
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMOD='/home/jono/code/example/go.mod'
GOMODCACHE='/home/jono/.cache/go/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/jono/.local/share/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/snap/go/10927'
GOSUMDB='sum.golang.org'
GOTELEMETRY='local'
GOTELEMETRYDIR='/home/jono/.config/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/snap/go/10927/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.24.5'
GOWORK=''
PKG_CONFIG='pkg-config'
What did you do?
I was just looking at the os.MkdirTemp code and noticed one of the error messages looked off. It's virtually impossible to trigger the error normally, since it requires the RNG to collide with existing directories 10000 times.
Instead I copied the code into this standalone file, and modified it to build properly (mostly just adding os. prefixes). Then I swapped out os.Mkdir with a stub which always returns os.ErrExist:
package main
import (
"errors"
"math/rand/v2"
"os"
"strconv"
"strings"
)
func Mkdir(name string, perm os.FileMode) error {
return os.ErrExist
}
func nextRandom() string {
return strconv.FormatUint(uint64(rand.Uint32()), 10)
}
func MkdirTemp(dir, pattern string) (string, error) {
if dir == "" {
dir = os.TempDir()
}
prefix, suffix, err := prefixAndSuffix(pattern)
if err != nil {
return "", &os.PathError{Op: "mkdirtemp", Path: pattern, Err: err}
}
prefix = joinPath(dir, prefix)
try := 0
for {
name := prefix + nextRandom() + suffix
err := Mkdir(name, 0700)
if err == nil {
return name, nil
}
if os.IsExist(err) {
if try++; try < 10000 {
continue
}
return "", &os.PathError{Op: "mkdirtemp", Path: dir + string(os.PathSeparator) + prefix + "*" + suffix, Err: os.ErrExist}
}
if os.IsNotExist(err) {
if _, err := os.Stat(dir); os.IsNotExist(err) {
return "", err
}
}
return "", err
}
}
var errPatternHasSeparator = errors.New("pattern contains path separator")
// prefixAndSuffix splits pattern by the last wildcard "*", if applicable,
// returning prefix as the part before "*" and suffix as the part after "*".
func prefixAndSuffix(pattern string) (prefix, suffix string, err error) {
for i := 0; i < len(pattern); i++ {
if os.IsPathSeparator(pattern[i]) {
return "", "", errPatternHasSeparator
}
}
if pos := strings.LastIndexByte(pattern, '*'); pos != -1 {
prefix, suffix = pattern[:pos], pattern[pos+1:]
} else {
prefix = pattern
}
return prefix, suffix, nil
}
func joinPath(dir, name string) string {
if len(dir) > 0 && os.IsPathSeparator(dir[len(dir)-1]) {
return dir + name
}
return dir + string(os.PathSeparator) + name
}
func main() {
if _, err := MkdirTemp("", "foo"); err != nil {
println(err.Error())
}
}
What did you see happen?
$ go run .
mkdirtemp /tmp//tmp/foo*: file already exists
What did you expect to see?
$ go run .
mkdirtemp /tmp/foo*: file already exists
Comment From: gabyhelp
Related Issues
- go test about mkdir #33053 (closed)
- os: TempDir() returns path without validation #19695 (closed)
- os: document that OpenFile Create do not create file if directory do not exist #69836 (closed)
- os: MkdirAll error has junk characters on Plan 9 #24921 (closed)
- os: MkdirAll fails when a parent folder contains trailing spaces #54040
- testing: `T.TempDir` does not clean illegal characters correctly on Go 1.16.13 #50644 (closed)
- testing: TempDir fails when TMPDIR is a relative directory and os.Chdir() is called #67954 (closed)
- io/ioutil: TempDir should support patterns like TempFile does #33805 (closed)
Related Code Changes
Related Documentation
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)
Comment From: seankhliao
feel free to send a CL.
Comment From: gopherbot
Change https://go.dev/cl/696715 mentions this issue: os: fix path in MkdirTemp error message