package syscall
-import "sync"
+import (
+ "runtime"
+ "sync"
+)
var (
wdmu sync.Mutex // guards following
wdStr string
)
+// Ensure current working directory seen by this goroutine matches
+// the most recent Chdir called in any goroutine. It's called internally
+// before executing any syscall which uses a relative pathname. Must
+// be called with the goroutine locked to the OS thread, to prevent
+// rescheduling on a different thread (potentially with a different
+// working directory) before the syscall is executed.
func Fixwd() {
wdmu.Lock()
defer wdmu.Unlock()
}
}
-func fixwd(paths ...string) {
+// If any of the paths is relative, call Fixwd and return true
+// (locked to OS thread). Otherwise return false.
+func fixwd(paths ...string) bool {
for _, path := range paths {
if path != "" && path[0] != '/' && path[0] != '#' {
+ runtime.LockOSThread()
Fixwd()
- return
+ return true
}
}
+ return false
}
// goroutine-specific getwd
}
func Chdir(path string) error {
- fixwd(path)
+ // If Chdir is to a relative path, sync working dir first
+ if fixwd(path) {
+ defer runtime.UnlockOSThread()
+ }
wdmu.Lock()
defer wdmu.Unlock()
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
if err := chdir(path); err != nil {
return err
}
import (
"internal/oserror"
+ "runtime"
"unsafe"
)
}
func Unmount(name, old string) (err error) {
- fixwd(name, old)
+ if fixwd(name, old) {
+ defer runtime.UnlockOSThread()
+ }
oldp, err := BytePtrFromString(old)
if err != nil {
return err
//sys open(path string, mode int) (fd int, err error)
func Open(path string, mode int) (fd int, err error) {
- fixwd(path)
+ if fixwd(path) {
+ defer runtime.UnlockOSThread()
+ }
return open(path, mode)
}
//sys create(path string, mode int, perm uint32) (fd int, err error)
func Create(path string, mode int, perm uint32) (fd int, err error) {
- fixwd(path)
+ if fixwd(path) {
+ defer runtime.UnlockOSThread()
+ }
return create(path, mode, perm)
}
//sys remove(path string) (err error)
func Remove(path string) error {
- fixwd(path)
+ if fixwd(path) {
+ defer runtime.UnlockOSThread()
+ }
return remove(path)
}
//sys stat(path string, edir []byte) (n int, err error)
func Stat(path string, edir []byte) (n int, err error) {
- fixwd(path)
+ if fixwd(path) {
+ defer runtime.UnlockOSThread()
+ }
return stat(path, edir)
}
//sys bind(name string, old string, flag int) (err error)
func Bind(name string, old string, flag int) (err error) {
- fixwd(name, old)
+ if fixwd(name, old) {
+ defer runtime.UnlockOSThread()
+ }
return bind(name, old, flag)
}
//sys mount(fd int, afd int, old string, flag int, aname string) (err error)
func Mount(fd int, afd int, old string, flag int, aname string) (err error) {
- fixwd(old)
+ if fixwd(old) {
+ defer runtime.UnlockOSThread()
+ }
return mount(fd, afd, old, flag, aname)
}
//sys wstat(path string, edir []byte) (err error)
func Wstat(path string, edir []byte) (err error) {
- fixwd(path)
+ if fixwd(path) {
+ defer runtime.UnlockOSThread()
+ }
return wstat(path, edir)
}