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