diff options
Diffstat (limited to 'src/lib/os/getwd.go')
-rw-r--r-- | src/lib/os/getwd.go | 94 |
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 +} |