src/pkg/os/getwd.go - The Go Programming Language

Golang

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	}