1 // Copyright 2015 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // The working directory in Plan 9 is effectively per P, so different 6 // goroutines and even the same goroutine as it's rescheduled on 7 // different Ps can see different working directories. 8 // 9 // Instead, track a Go process-wide intent of the current working directory, 10 // and switch to it at important points. 11 12 package syscall 13 14 import "sync" 15 16 var ( 17 wdmu sync.Mutex // guards following 18 wdSet bool 19 wdStr string 20 ) 21 22 func Fixwd() { 23 wdmu.Lock() 24 defer wdmu.Unlock() 25 fixwdLocked() 26 } 27 28 func fixwdLocked() { 29 if !wdSet { 30 return 31 } 32 // always call chdir when getwd returns an error 33 wd, _ := getwd() 34 if wd == wdStr { 35 return 36 } 37 if err := chdir(wdStr); err != nil { 38 return 39 } 40 } 41 42 // goroutine-specific getwd 43 func getwd() (wd string, err error) { 44 fd, err := open(".", O_RDONLY) 45 if err != nil { 46 return "", err 47 } 48 defer Close(fd) 49 return Fd2path(fd) 50 } 51 52 func Getwd() (wd string, err error) { 53 wdmu.Lock() 54 defer wdmu.Unlock() 55 56 if wdSet { 57 return wdStr, nil 58 } 59 wd, err = getwd() 60 if err != nil { 61 return 62 } 63 wdSet = true 64 wdStr = wd 65 return wd, nil 66 } 67 68 func Chdir(path string) error { 69 wdmu.Lock() 70 defer wdmu.Unlock() 71 72 if err := chdir(path); err != nil { 73 return err 74 } 75 76 wd, err := getwd() 77 if err != nil { 78 return err 79 } 80 wdSet = true 81 wdStr = wd 82 return nil 83 } 84