Daily bump.
[official-gcc.git] / libgo / go / os / getwd.go
blob8c5ff7fca51a53ad64ab7e202e23d3061d095b6a
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.
5 package os
7 import (
8 "sync"
9 "syscall"
12 var getwdCache struct {
13 sync.Mutex
14 dir string
17 // useSyscallwd determines whether to use the return value of
18 // syscall.Getwd based on its error.
19 var useSyscallwd = func(error) bool { return true }
21 // Getwd returns a rooted path name corresponding to the
22 // current directory. If the current directory can be
23 // reached via multiple paths (due to symbolic links),
24 // Getwd may return any one of them.
25 func Getwd() (pwd string, err error) {
26 // If the operating system provides a Getwd call, use it.
27 if syscall.ImplementsGetwd {
28 s, e := syscall.Getwd()
29 if useSyscallwd(e) {
30 return s, NewSyscallError("getwd", e)
34 // Otherwise, we're trying to find our way back to ".".
35 dot, err := Stat(".")
36 if err != nil {
37 return "", err
40 // Clumsy but widespread kludge:
41 // if $PWD is set and matches ".", use it.
42 pwd = Getenv("PWD")
43 if len(pwd) > 0 && pwd[0] == '/' {
44 d, err := Stat(pwd)
45 if err == nil && SameFile(dot, d) {
46 return pwd, nil
50 // Apply same kludge but to cached dir instead of $PWD.
51 getwdCache.Lock()
52 pwd = getwdCache.dir
53 getwdCache.Unlock()
54 if len(pwd) > 0 {
55 d, err := Stat(pwd)
56 if err == nil && SameFile(dot, d) {
57 return pwd, nil
61 // Root is a special case because it has no parent
62 // and ends in a slash.
63 root, err := Stat("/")
64 if err != nil {
65 // Can't stat root - no hope.
66 return "", err
68 if SameFile(root, dot) {
69 return "/", nil
72 // General algorithm: find name in parent
73 // and then find name of parent. Each iteration
74 // adds /name to the beginning of pwd.
75 pwd = ""
76 for parent := ".."; ; parent = "../" + parent {
77 if len(parent) >= 1024 { // Sanity check
78 return "", syscall.ENAMETOOLONG
80 fd, err := Open(parent)
81 if err != nil {
82 return "", err
85 for {
86 names, err := fd.Readdirnames(100)
87 if err != nil {
88 fd.Close()
89 return "", err
91 for _, name := range names {
92 d, _ := Lstat(parent + "/" + name)
93 if SameFile(d, dot) {
94 pwd = "/" + name + pwd
95 goto Found
100 Found:
101 pd, err := fd.Stat()
102 if err != nil {
103 return "", err
105 fd.Close()
106 if SameFile(pd, root) {
107 break
109 // Set up for next round.
110 dot = pd
113 // Save answer as hint to avoid the expensive path next time.
114 getwdCache.Lock()
115 getwdCache.dir = pwd
116 getwdCache.Unlock()
118 return pwd, nil