remove unused files
[platform/upstream/gcc48.git] / libgo / go / os / getwd.go
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.
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 // Getwd returns a rooted path name corresponding to the
18 // current directory.  If the current directory can be
19 // reached via multiple paths (due to symbolic links),
20 // Getwd may return any one of them.
21 func Getwd() (pwd string, err error) {
22         // If the operating system provides a Getwd call, use it.
23         if syscall.ImplementsGetwd {
24                 s, e := syscall.Getwd()
25                 return s, NewSyscallError("getwd", e)
26         }
27
28         // Otherwise, we're trying to find our way back to ".".
29         dot, err := Stat(".")
30         if err != nil {
31                 return "", err
32         }
33
34         // Clumsy but widespread kludge:
35         // if $PWD is set and matches ".", use it.
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         // Apply same kludge but to cached dir instead of $PWD.
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         // Root is a special case because it has no parent
56         // and ends in a slash.
57         root, err := Stat("/")
58         if err != nil {
59                 // Can't stat root - no hope.
60                 return "", err
61         }
62         if SameFile(root, dot) {
63                 return "/", nil
64         }
65
66         // General algorithm: find name in parent
67         // and then find name of parent.  Each iteration
68         // adds /name to the beginning of pwd.
69         pwd = ""
70         for parent := ".."; ; parent = "../" + parent {
71                 if len(parent) >= 1024 { // Sanity check
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                 // Set up for next round.
104                 dot = pd
105         }
106
107         // Save answer as hint to avoid the expensive path next time.
108         getwdCache.Lock()
109         getwdCache.dir = pwd
110         getwdCache.Unlock()
111
112         return pwd, nil
113 }