...
Source file src/pkg/os/getwd.go
1
2
3
4
5 package os
6
7 import (
8 "runtime"
9 "sync"
10 "syscall"
11 )
12
13 var getwdCache struct {
14 sync.Mutex
15 dir string
16 }
17
18
19
20 var useSyscallwd = func(error) bool { return true }
21
22
23
24
25
26 func Getwd() (dir string, err error) {
27 if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
28 return syscall.Getwd()
29 }
30
31
32
33 dot, err := statNolog(".")
34 if err != nil {
35 return "", err
36 }
37 dir = Getenv("PWD")
38 if len(dir) > 0 && dir[0] == '/' {
39 d, err := statNolog(dir)
40 if err == nil && SameFile(dot, d) {
41 return dir, nil
42 }
43 }
44
45
46
47 if syscall.ImplementsGetwd {
48 s, e := syscall.Getwd()
49 if useSyscallwd(e) {
50 return s, NewSyscallError("getwd", e)
51 }
52 }
53
54
55 getwdCache.Lock()
56 dir = getwdCache.dir
57 getwdCache.Unlock()
58 if len(dir) > 0 {
59 d, err := statNolog(dir)
60 if err == nil && SameFile(dot, d) {
61 return dir, nil
62 }
63 }
64
65
66
67 root, err := statNolog("/")
68 if err != nil {
69
70 return "", err
71 }
72 if SameFile(root, dot) {
73 return "/", nil
74 }
75
76
77
78
79 dir = ""
80 for parent := ".."; ; parent = "../" + parent {
81 if len(parent) >= 1024 {
82 return "", syscall.ENAMETOOLONG
83 }
84 fd, err := openFileNolog(parent, O_RDONLY, 0)
85 if err != nil {
86 return "", err
87 }
88
89 for {
90 names, err := fd.Readdirnames(100)
91 if err != nil {
92 fd.Close()
93 return "", err
94 }
95 for _, name := range names {
96 d, _ := lstatNolog(parent + "/" + name)
97 if SameFile(d, dot) {
98 dir = "/" + name + dir
99 goto Found
100 }
101 }
102 }
103
104 Found:
105 pd, err := fd.Stat()
106 if err != nil {
107 return "", err
108 }
109 fd.Close()
110 if SameFile(pd, root) {
111 break
112 }
113
114 dot = pd
115 }
116
117
118 getwdCache.Lock()
119 getwdCache.dir = dir
120 getwdCache.Unlock()
121
122 return dir, nil
123 }
124
View as plain text