summaryrefslogtreecommitdiff
path: root/libgo/go/os/getwd.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/os/getwd.go')
-rw-r--r--libgo/go/os/getwd.go92
1 files changed, 92 insertions, 0 deletions
diff --git a/libgo/go/os/getwd.go b/libgo/go/os/getwd.go
new file mode 100644
index 000000000..49aaea865
--- /dev/null
+++ b/libgo/go/os/getwd.go
@@ -0,0 +1,92 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import (
+ "syscall"
+)
+
+// Getwd returns a rooted path name corresponding to the
+// current directory. If the current directory can be
+// reached via multiple paths (due to symbolic links),
+// Getwd may return any one of them.
+func Getwd() (string, Error) {
+ // If the operating system provides a Getwd call, use it.
+ if syscall.ImplementsGetwd {
+ s, e := syscall.Getwd()
+ return s, NewSyscallError("getwd", e)
+ }
+
+ // Otherwise, we're trying to find our way back to ".".
+ dot, err := Stat(".")
+ if err != nil {
+ return "", err
+ }
+
+ // Clumsy but widespread kludge:
+ // if $PWD is set and matches ".", use it.
+ pwd := Getenv("PWD")
+ if len(pwd) > 0 && pwd[0] == '/' {
+ d, err := Stat(pwd)
+ if err == nil && d.Dev == dot.Dev && d.Ino == dot.Ino {
+ return pwd, nil
+ }
+ }
+
+ // Root is a special case because it has no parent
+ // and ends in a slash.
+ root, err := Stat("/")
+ if err != nil {
+ // Can't stat root - no hope.
+ return "", err
+ }
+ if root.Dev == dot.Dev && root.Ino == dot.Ino {
+ return "/", nil
+ }
+
+ // General algorithm: find name in parent
+ // and then find name of parent. Each iteration
+ // adds /name to the beginning of pwd.
+ pwd = ""
+ for parent := ".."; ; parent = "../" + parent {
+ if len(parent) >= 1024 { // Sanity check
+ return "", ENAMETOOLONG
+ }
+ fd, err := Open(parent, O_RDONLY, 0)
+ if err != nil {
+ return "", err
+ }
+
+ for {
+ names, err := fd.Readdirnames(100)
+ if err != nil {
+ fd.Close()
+ return "", err
+ }
+ for _, name := range names {
+ d, _ := Lstat(parent + "/" + name)
+ if d.Dev == dot.Dev && d.Ino == dot.Ino {
+ pwd = "/" + name + pwd
+ goto Found
+ }
+ }
+ }
+ fd.Close()
+ return "", ENOENT
+
+ Found:
+ pd, err := fd.Stat()
+ if err != nil {
+ return "", err
+ }
+ fd.Close()
+ if pd.Dev == root.Dev && pd.Ino == root.Ino {
+ break
+ }
+ // Set up for next round.
+ dot = pd
+ }
+ return pwd, nil
+}