Home | History | Annotate | Download | only in filepath
      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 	path, err := walkSymlinks(path)
     51 	if err != nil {
     52 		return "", err
     53 	}
     54 
     55 	p, err := toShort(path)
     56 	if err != nil {
     57 		return "", err
     58 	}
     59 	p, err = toLong(p)
     60 	if err != nil {
     61 		return "", err
     62 	}
     63 	// syscall.GetLongPathName does not change the case of the drive letter,
     64 	// but the result of EvalSymlinks must be unique, so we have
     65 	// EvalSymlinks(`c:\a`) == EvalSymlinks(`C:\a`).
     66 	// Make drive letter upper case.
     67 	if len(p) >= 2 && p[1] == ':' && 'a' <= p[0] && p[0] <= 'z' {
     68 		p = string(p[0]+'A'-'a') + p[1:]
     69 	}
     70 	return Clean(p), nil
     71 }
     72