| // 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) |
| 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 |
| } |