mirror of
https://github.com/golang/go
synced 2024-11-06 06:36:20 -07:00
7d3f81a9f3
In Plan 9, goroutines can run in different processes, which don't share their working directory. However, Go expects the working directory to be program-wide. We use a Fixwd function to fix the working directory before calling system calls which depend on the working directory. In fixwdLocked, the working directory is not fixed when getwd returns an error. However, an error can happen is some cases, notably when the directory has been previously removed in another process. Fixes #10422. Change-Id: Ie0c36f97c4b5ebe27ff0ead360987c5b35f825e4 Reviewed-on: https://go-review.googlesource.com/8800 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
84 lines
1.4 KiB
Go
84 lines
1.4 KiB
Go
// Copyright 2015 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.
|
|
|
|
// The working directory in Plan 9 is effectively per P, so different
|
|
// goroutines and even the same goroutine as it's rescheduled on
|
|
// different Ps can see different working directories.
|
|
//
|
|
// Instead, track a Go process-wide intent of the current working directory,
|
|
// and switch to it at important points.
|
|
|
|
package syscall
|
|
|
|
import "sync"
|
|
|
|
var (
|
|
wdmu sync.Mutex // guards following
|
|
wdSet bool
|
|
wdStr string
|
|
)
|
|
|
|
func Fixwd() {
|
|
wdmu.Lock()
|
|
defer wdmu.Unlock()
|
|
fixwdLocked()
|
|
}
|
|
|
|
func fixwdLocked() {
|
|
if !wdSet {
|
|
return
|
|
}
|
|
// always call chdir when getwd returns an error
|
|
wd, _ := getwd()
|
|
if wd == wdStr {
|
|
return
|
|
}
|
|
if err := chdir(wdStr); err != nil {
|
|
return
|
|
}
|
|
}
|
|
|
|
// goroutine-specific getwd
|
|
func getwd() (wd string, err error) {
|
|
fd, err := open(".", O_RDONLY)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer Close(fd)
|
|
return Fd2path(fd)
|
|
}
|
|
|
|
func Getwd() (wd string, err error) {
|
|
wdmu.Lock()
|
|
defer wdmu.Unlock()
|
|
|
|
if wdSet {
|
|
return wdStr, nil
|
|
}
|
|
wd, err = getwd()
|
|
if err != nil {
|
|
return
|
|
}
|
|
wdSet = true
|
|
wdStr = wd
|
|
return wd, nil
|
|
}
|
|
|
|
func Chdir(path string) error {
|
|
wdmu.Lock()
|
|
defer wdmu.Unlock()
|
|
|
|
if err := chdir(path); err != nil {
|
|
return err
|
|
}
|
|
|
|
wd, err := getwd()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
wdSet = true
|
|
wdStr = wd
|
|
return nil
|
|
}
|