libstdc++: Make std::basic_format_context non-copyable [PR114387]
[official-gcc.git] / libgo / go / os / getwd.go
blob90604cf2f4b18e57a04cdcf5f559b61a0ef0be3e
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 "runtime"
9 "sync"
10 "syscall"
13 var getwdCache struct {
14 sync.Mutex
15 dir string
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(".")
30 if err != nil {
31 return "", err
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
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 {
44 var (
45 s string
46 e error
48 for {
49 s, e = syscall.Getwd()
50 if e != syscall.EINTR {
51 break
54 return s, NewSyscallError("getwd", e)
57 // Apply same kludge but to cached dir instead of $PWD.
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
68 // Root is a special case because it has no parent
69 // and ends in a slash.
70 root, err := statNolog("/")
71 if err != nil {
72 // Can't stat root - no hope.
73 return "", err
75 if SameFile(root, dot) {
76 return "/", nil
79 // General algorithm: find name in parent
80 // and then find name of parent. Each iteration
81 // adds /name to the beginning of dir.
82 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)
88 if err != nil {
89 return "", err
92 for {
93 names, err := fd.Readdirnames(100)
94 if err != nil {
95 fd.Close()
96 return "", err
98 for _, name := range names {
99 d, _ := lstatNolog(parent + "/" + name)
100 if SameFile(d, dot) {
101 dir = "/" + name + dir
102 goto Found
107 Found:
108 pd, err := fd.Stat()
109 fd.Close()
110 if err != nil {
111 return "", err
113 if SameFile(pd, root) {
114 break
116 // Set up for next round.
117 dot = pd
120 // Save answer as hint to avoid the expensive path next time.
121 getwdCache.Lock()
122 getwdCache.dir = dir
123 getwdCache.Unlock()
125 return dir, nil