Source file src/pkg/os/getwd.go
1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package os 6 7 import ( 8 "syscall" 9 ) 10 11 // Getwd returns a rooted path name corresponding to the 12 // current directory. If the current directory can be 13 // reached via multiple paths (due to symbolic links), 14 // Getwd may return any one of them. 15 func Getwd() (pwd string, err error) { 16 // If the operating system provides a Getwd call, use it. 17 if syscall.ImplementsGetwd { 18 s, e := syscall.Getwd() 19 return s, NewSyscallError("getwd", e) 20 } 21 22 // Otherwise, we're trying to find our way back to ".". 23 dot, err := Stat(".") 24 if err != nil { 25 return "", err 26 } 27 28 // Clumsy but widespread kludge: 29 // if $PWD is set and matches ".", use it. 30 pwd = Getenv("PWD") 31 if len(pwd) > 0 && pwd[0] == '/' { 32 d, err := Stat(pwd) 33 if err == nil && SameFile(dot, d) { 34 return pwd, nil 35 } 36 } 37 38 // Root is a special case because it has no parent 39 // and ends in a slash. 40 root, err := Stat("/") 41 if err != nil { 42 // Can't stat root - no hope. 43 return "", err 44 } 45 if SameFile(root, dot) { 46 return "/", nil 47 } 48 49 // General algorithm: find name in parent 50 // and then find name of parent. Each iteration 51 // adds /name to the beginning of pwd. 52 pwd = "" 53 for parent := ".."; ; parent = "../" + parent { 54 if len(parent) >= 1024 { // Sanity check 55 return "", syscall.ENAMETOOLONG 56 } 57 fd, err := Open(parent) 58 if err != nil { 59 return "", err 60 } 61 62 for { 63 names, err := fd.Readdirnames(100) 64 if err != nil { 65 fd.Close() 66 return "", err 67 } 68 for _, name := range names { 69 d, _ := Lstat(parent + "/" + name) 70 if SameFile(d, dot) { 71 pwd = "/" + name + pwd 72 goto Found 73 } 74 } 75 } 76 fd.Close() 77 return "", ErrNotExist 78 79 Found: 80 pd, err := fd.Stat() 81 if err != nil { 82 return "", err 83 } 84 fd.Close() 85 if SameFile(pd, root) { 86 break 87 } 88 // Set up for next round. 89 dot = pd 90 } 91 return pwd, nil 92 }