// 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 } } func fixwd(paths ...string) { for _, path := range paths { if path != "" && path[0] != '/' && path[0] != '#' { Fixwd() 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 { fixwd(path) 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 }