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