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