1 // Copyright 2009 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.
13 var getwdCache
struct {
18 // Getwd returns a rooted path name corresponding to the
19 // current directory. If the current directory can be
20 // reached via multiple paths (due to symbolic links),
21 // Getwd may return any one of them.
22 func Getwd() (dir
string, err error
) {
23 if runtime
.GOOS
== "windows" || runtime
.GOOS
== "plan9" {
24 return syscall
.Getwd()
27 // Clumsy but widespread kludge:
28 // if $PWD is set and matches ".", use it.
29 dot
, err
:= statNolog(".")
34 if len(dir
) > 0 && dir
[0] == '/' {
35 d
, err
:= statNolog(dir
)
36 if err
== nil && SameFile(dot
, d
) {
41 // If the operating system provides a Getwd call, use it.
42 // Otherwise, we're trying to find our way back to ".".
43 if syscall
.ImplementsGetwd
{
49 s
, e
= syscall
.Getwd()
50 if e
!= syscall
.EINTR
{
54 return s
, NewSyscallError("getwd", e
)
57 // Apply same kludge but to cached dir instead of $PWD.
62 d
, err
:= statNolog(dir
)
63 if err
== nil && SameFile(dot
, d
) {
68 // Root is a special case because it has no parent
69 // and ends in a slash.
70 root
, err
:= statNolog("/")
72 // Can't stat root - no hope.
75 if SameFile(root
, dot
) {
79 // General algorithm: find name in parent
80 // and then find name of parent. Each iteration
81 // adds /name to the beginning of dir.
83 for parent
:= ".."; ; parent
= "../" + parent
{
84 if len(parent
) >= 1024 { // Sanity check
85 return "", syscall
.ENAMETOOLONG
87 fd
, err
:= openFileNolog(parent
, O_RDONLY
, 0)
93 names
, err
:= fd
.Readdirnames(100)
98 for _
, name
:= range names
{
99 d
, _
:= lstatNolog(parent
+ "/" + name
)
100 if SameFile(d
, dot
) {
101 dir
= "/" + name
+ dir
113 if SameFile(pd
, root
) {
116 // Set up for next round.
120 // Save answer as hint to avoid the expensive path next time.