github.com/fjballest/golang@v0.0.0-20151209143359-e4c5fe594ca8/src/path/filepath/symlink_windows.go (about)

     1  // Copyright 2012 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 filepath
     6  
     7  import (
     8  	"syscall"
     9  )
    10  
    11  func toShort(path string) (string, error) {
    12  	p, err := syscall.UTF16FromString(path)
    13  	if err != nil {
    14  		return "", err
    15  	}
    16  	b := p // GetShortPathName says we can reuse buffer
    17  	n := uint32(len(b))
    18  	for {
    19  		n, err = syscall.GetShortPathName(&p[0], &b[0], uint32(len(b)))
    20  		if err != nil {
    21  			return "", err
    22  		}
    23  		if n <= uint32(len(b)) {
    24  			return syscall.UTF16ToString(b[:n]), nil
    25  		}
    26  		b = make([]uint16, n)
    27  	}
    28  }
    29  
    30  func toLong(path string) (string, error) {
    31  	p, err := syscall.UTF16FromString(path)
    32  	if err != nil {
    33  		return "", err
    34  	}
    35  	b := p // GetLongPathName says we can reuse buffer
    36  	n := uint32(len(b))
    37  	for {
    38  		n, err = syscall.GetLongPathName(&p[0], &b[0], uint32(len(b)))
    39  		if err != nil {
    40  			return "", err
    41  		}
    42  		if n <= uint32(len(b)) {
    43  			return syscall.UTF16ToString(b[:n]), nil
    44  		}
    45  		b = make([]uint16, n)
    46  	}
    47  }
    48  
    49  func evalSymlinks(path string) (string, error) {
    50  	newpath, err := walkSymlinks(path)
    51  	if err != nil {
    52  		return "", err
    53  	}
    54  	// discard the walk if path is "." and link destination is relative path (just like unix does)
    55  	if path != "." || IsAbs(newpath) {
    56  		path = newpath
    57  	}
    58  
    59  	p, err := toShort(path)
    60  	if err != nil {
    61  		return "", err
    62  	}
    63  	p, err = toLong(p)
    64  	if err != nil {
    65  		return "", err
    66  	}
    67  	// syscall.GetLongPathName does not change the case of the drive letter,
    68  	// but the result of EvalSymlinks must be unique, so we have
    69  	// EvalSymlinks(`c:\a`) == EvalSymlinks(`C:\a`).
    70  	// Make drive letter upper case.
    71  	if len(p) >= 2 && p[1] == ':' && 'a' <= p[0] && p[0] <= 'z' {
    72  		p = string(p[0]+'A'-'a') + p[1:]
    73  	}
    74  	return Clean(p), nil
    75  }