// 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 osimport ()var getwdCache struct {sync.Mutex dir string}// Getwd returns an absolute 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.//// On Unix platforms, if the environment variable PWD// provides an absolute name, and it is a name of the// current directory, it is returned.func () ( string, error) {ifruntime.GOOS == "windows" || runtime.GOOS == "plan9" {// Use syscall.Getwd directly for // - plan9: see reasons in CL 89575; // - windows: syscall implementation is sufficient, // and we should not rely on $PWD. , = syscall.Getwd()return , NewSyscallError("getwd", ) }// Clumsy but widespread kludge: // if $PWD is set and matches ".", use it.varFileInfo = Getenv("PWD")iflen() > 0 && [0] == '/' { , = statNolog(".")if != nil {return"", } , := statNolog()if == nil && SameFile(, ) {return , nil }// If err is ENAMETOOLONG here, the syscall.Getwd below will // fail with the same error, too, but let's give it a try // anyway as the fallback code is much slower. }// If the operating system provides a Getwd call, use it.ifsyscall.ImplementsGetwd { , = ignoringEINTR2(syscall.Getwd)// Linux returns ENAMETOOLONG if the result is too long. // Some BSD systems appear to return EINVAL. // FreeBSD systems appear to use ENOMEM // Solaris appears to use ERANGE.if != syscall.ENAMETOOLONG && != syscall.EINVAL && != errERANGE && != errENOMEM {return , NewSyscallError("getwd", ) } }// We're trying to find our way back to ".".if == nil { , = statNolog(".")if != nil {return"", } }// Apply same kludge but to cached dir instead of $PWD.getwdCache.Lock() = getwdCache.dirgetwdCache.Unlock()iflen() > 0 { , := statNolog()if == nil && SameFile(, ) {return , nil } }// Root is a special case because it has no parent // and ends in a slash. , := statNolog("/")if != nil {// Can't stat root - no hope.return"", }ifSameFile(, ) {return"/", nil }// General algorithm: find name in parent // and then find name of parent. Each iteration // adds /name to the beginning of dir. = ""for := ".."; ; = "../" + {iflen() >= 1024 { // Sanity checkreturn"", NewSyscallError("getwd", syscall.ENAMETOOLONG) } , := openDirNolog()if != nil {return"", }for { , := .Readdirnames(100)if != nil { .Close()// Readdirnames can return io.EOF or other error. // In any case, we're here because syscall.Getwd // is not implemented or failed with ENAMETOOLONG, // so return the most sensible error.ifsyscall.ImplementsGetwd {return"", NewSyscallError("getwd", syscall.ENAMETOOLONG) }return"", NewSyscallError("getwd", errENOSYS) }for , := range { , := lstatNolog( + "/" + )ifSameFile(, ) { = "/" + + goto } } } : , := .Stat() .Close()if != nil {return"", }ifSameFile(, ) {break }// Set up for next round. = }// Save answer as hint to avoid the expensive path next time.getwdCache.Lock()getwdCache.dir = getwdCache.Unlock()return , nil}
The pages are generated with Goldsv0.7.3. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.