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