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