Source file
src/os/path_windows.go
1
2
3
4
5 package os
6
7 import (
8 "internal/syscall/windows"
9 "syscall"
10 )
11
12 const (
13 PathSeparator = '\\'
14 PathListSeparator = ';'
15 )
16
17
18 func IsPathSeparator(c uint8) bool {
19
20 return c == '\\' || c == '/'
21 }
22
23
24
25 func basename(name string) string {
26
27 if len(name) == 2 && name[1] == ':' {
28 name = "."
29 } else if len(name) > 2 && name[1] == ':' {
30 name = name[2:]
31 }
32 i := len(name) - 1
33
34 for ; i > 0 && (name[i] == '/' || name[i] == '\\'); i-- {
35 name = name[:i]
36 }
37
38 for i--; i >= 0; i-- {
39 if name[i] == '/' || name[i] == '\\' {
40 name = name[i+1:]
41 break
42 }
43 }
44 return name
45 }
46
47 func isAbs(path string) (b bool) {
48 v := volumeName(path)
49 if v == "" {
50 return false
51 }
52 path = path[len(v):]
53 if path == "" {
54 return false
55 }
56 return IsPathSeparator(path[0])
57 }
58
59 func volumeName(path string) (v string) {
60 if len(path) < 2 {
61 return ""
62 }
63
64 c := path[0]
65 if path[1] == ':' &&
66 ('0' <= c && c <= '9' || 'a' <= c && c <= 'z' ||
67 'A' <= c && c <= 'Z') {
68 return path[:2]
69 }
70
71 if l := len(path); l >= 5 && IsPathSeparator(path[0]) && IsPathSeparator(path[1]) &&
72 !IsPathSeparator(path[2]) && path[2] != '.' {
73
74 for n := 3; n < l-1; n++ {
75
76 if IsPathSeparator(path[n]) {
77 n++
78
79 if !IsPathSeparator(path[n]) {
80 if path[n] == '.' {
81 break
82 }
83 for ; n < l; n++ {
84 if IsPathSeparator(path[n]) {
85 break
86 }
87 }
88 return path[:n]
89 }
90 break
91 }
92 }
93 }
94 return ""
95 }
96
97 func fromSlash(path string) string {
98
99 var pathbuf []byte
100 var lastSlash int
101 for i, b := range path {
102 if b == '/' {
103 if pathbuf == nil {
104 pathbuf = make([]byte, len(path))
105 }
106 copy(pathbuf[lastSlash:], path[lastSlash:i])
107 pathbuf[i] = '\\'
108 lastSlash = i + 1
109 }
110 }
111 if pathbuf == nil {
112 return path
113 }
114
115 copy(pathbuf[lastSlash:], path[lastSlash:])
116 return string(pathbuf)
117 }
118
119 func dirname(path string) string {
120 vol := volumeName(path)
121 i := len(path) - 1
122 for i >= len(vol) && !IsPathSeparator(path[i]) {
123 i--
124 }
125 dir := path[len(vol) : i+1]
126 last := len(dir) - 1
127 if last > 0 && IsPathSeparator(dir[last]) {
128 dir = dir[:last]
129 }
130 if dir == "" {
131 dir = "."
132 }
133 return vol + dir
134 }
135
136
137
138
139
140
141
142
143
144
145 func fixLongPath(path string) string {
146 if windows.CanUseLongPaths {
147 return path
148 }
149 return addExtendedPrefix(path)
150 }
151
152
153 func addExtendedPrefix(path string) string {
154 if len(path) >= 4 {
155 if path[:4] == `\??\` {
156
157 return path
158 }
159 if IsPathSeparator(path[0]) && IsPathSeparator(path[1]) && path[2] == '?' && IsPathSeparator(path[3]) {
160
161 return path
162 }
163 }
164
165
166
167
168
169
170
171
172
173
174
175
176 pathLength := len(path)
177 if !isAbs(path) {
178
179
180
181
182
183
184
185 getwdCache.Lock()
186 if getwdCache.dir == "" {
187
188 getwdCache.dir, _ = syscall.Getwd()
189 }
190 pathLength += len(getwdCache.dir) + 1
191 getwdCache.Unlock()
192 }
193
194 if pathLength < 248 {
195
196
197 return path
198 }
199
200 var isUNC, isDevice bool
201 if len(path) >= 2 && IsPathSeparator(path[0]) && IsPathSeparator(path[1]) {
202 if len(path) >= 4 && path[2] == '.' && IsPathSeparator(path[3]) {
203
204 isDevice = true
205 } else {
206
207 isUNC = true
208 }
209 }
210 var prefix []uint16
211 if isUNC {
212
213 prefix = []uint16{'\\', '\\', '?', '\\', 'U', 'N', 'C', '\\'}
214 } else if isDevice {
215
216
217 } else {
218 prefix = []uint16{'\\', '\\', '?', '\\'}
219 }
220
221 p, err := syscall.UTF16FromString(path)
222 if err != nil {
223 return path
224 }
225
226
227
228 n := uint32(pathLength) + 1
229 var buf []uint16
230 for {
231 buf = make([]uint16, n+uint32(len(prefix)))
232 n, err = syscall.GetFullPathName(&p[0], n, &buf[len(prefix)], nil)
233 if err != nil {
234 return path
235 }
236 if n <= uint32(len(buf)-len(prefix)) {
237 buf = buf[:n+uint32(len(prefix))]
238 break
239 } else {
240 continue
241 }
242 }
243 if isUNC {
244
245 buf = buf[2:]
246 }
247 copy(buf, prefix)
248 return syscall.UTF16ToString(buf)
249 }
250
View as plain text