/
name_encoding.go
94 lines (80 loc) · 2.77 KB
/
name_encoding.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
// Copyright 2021 Keybase Inc. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.
package libkb
import (
"fmt"
"strings"
)
const escapeSacrificeForWindows = '‰'
const disallowedRunesOnWindows = "<>:\"/\\|?*"
var kbfsNameToWindowsReplaceSequence [][2]string
var windowsNameToKbfsReplaceSequence [][2]string
func init() {
makeEscapePair := func(r rune) [2]string {
return [2]string{string(r), fmt.Sprintf("‰%x", r)}
}
makeUnescapePairs := func(r rune) [][2]string {
lower := fmt.Sprintf("‰%x", r)
upper := fmt.Sprintf("‰%X", r)
if lower == upper {
return [][2]string{
{lower, string(r)},
}
}
return [][2]string{
{lower, string(r)},
{upper, string(r)},
}
}
kbfsNameToWindowsReplaceSequence = nil
windowsNameToKbfsReplaceSequence = nil
kbfsNameToWindowsReplaceSequence = append(kbfsNameToWindowsReplaceSequence,
makeEscapePair(escapeSacrificeForWindows),
)
for _, r := range disallowedRunesOnWindows {
kbfsNameToWindowsReplaceSequence = append(
kbfsNameToWindowsReplaceSequence, makeEscapePair(r))
windowsNameToKbfsReplaceSequence = append(
windowsNameToKbfsReplaceSequence, makeUnescapePairs(r)...)
}
windowsNameToKbfsReplaceSequence = append(windowsNameToKbfsReplaceSequence,
makeUnescapePairs(escapeSacrificeForWindows)...)
}
// EncodeKbfsNameForWindows encodes a KBFS path element for Windows by
// escaping disallowed characters.
func EncodeKbfsNameForWindows(kbfsName string) (windowsName string) {
// fast path for names that don't have characters that need escaping
if !strings.ContainsAny(kbfsName, disallowedRunesOnWindows) &&
!strings.ContainsRune(kbfsName, escapeSacrificeForWindows) {
return kbfsName
}
windowsName = kbfsName
for _, replacement := range kbfsNameToWindowsReplaceSequence {
windowsName = strings.ReplaceAll(windowsName, replacement[0], replacement[1])
}
return windowsName
}
// InvalidWindowsNameError is the error returned when an invalid path name is
// passed in.
type InvalidWindowsNameError struct{}
// Error implements the error interface.
func (InvalidWindowsNameError) Error() string {
return "invalid windows path name"
}
// DecodeWindowsNameForKbfs decodes a path element encoded by
// EncodeKbfsNameForWindows.
func DecodeWindowsNameForKbfs(windowsName string) (kbfsName string, err error) {
if strings.ContainsAny(windowsName, disallowedRunesOnWindows) {
return "", InvalidWindowsNameError{}
}
// fast path for names that don't have escaped characters
if !strings.ContainsRune(windowsName, escapeSacrificeForWindows) {
return windowsName, nil
}
kbfsName = windowsName
for _, replacement := range windowsNameToKbfsReplaceSequence {
kbfsName = strings.ReplaceAll(kbfsName, replacement[0], replacement[1])
}
return kbfsName, nil
}