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