summaryrefslogtreecommitdiff
path: root/src/lib/os/getwd.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/os/getwd.go')
-rw-r--r--src/lib/os/getwd.go94
1 files changed, 94 insertions, 0 deletions
diff --git a/src/lib/os/getwd.go b/src/lib/os/getwd.go
new file mode 100644
index 000000000..2d7b754b5
--- /dev/null
+++ b/src/lib/os/getwd.go
@@ -0,0 +1,94 @@
+// 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 (
+ "os";
+ "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, ErrnoToError(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.
+ elem := make([]string, 0, 16);
+ 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 i, name := range names {
+ d, err := 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
+}