forked from buildpacks/pack
-
Notifications
You must be signed in to change notification settings - Fork 0
/
paths.go
144 lines (120 loc) · 3.26 KB
/
paths.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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package paths
import (
"net/url"
"os"
"path/filepath"
"regexp"
"runtime"
"strings"
)
var schemeRegexp = regexp.MustCompile(`^.+://.*`)
func IsURI(ref string) bool {
return schemeRegexp.MatchString(ref)
}
func IsDir(p string) (bool, error) {
fileInfo, err := os.Stat(p)
if err != nil {
return false, err
}
return fileInfo.IsDir(), nil
}
func FilePathToURI(p string) (string, error) {
var err error
if !filepath.IsAbs(p) {
p, err = filepath.Abs(p)
if err != nil {
return "", err
}
}
if runtime.GOOS == "windows" {
if strings.HasPrefix(p, `\\`) {
return "file://" + filepath.ToSlash(strings.TrimPrefix(p, `\\`)), nil
}
return "file:///" + filepath.ToSlash(p), nil
}
return "file://" + p, nil
}
// examples:
//
// - unix file: file://laptop/some%20dir/file.tgz
//
// - windows drive: file:///C:/Documents%20and%20Settings/file.tgz
//
// - windows share: file://laptop/My%20Documents/file.tgz
//
func URIToFilePath(uri string) (string, error) {
var (
osPath string
err error
)
osPath = filepath.FromSlash(strings.TrimPrefix(uri, "file://"))
if osPath, err = url.PathUnescape(osPath); err != nil {
return "", nil
}
if runtime.GOOS == "windows" {
if strings.HasPrefix(osPath, `\`) {
return strings.TrimPrefix(osPath, `\`), nil
}
return `\\` + osPath, nil
}
return osPath, nil
}
func ToAbsolute(uri, relativeTo string) (string, error) {
parsed, err := url.Parse(uri)
if err != nil {
return "", err
}
if parsed.Scheme == "" {
if !filepath.IsAbs(parsed.Path) {
absPath := filepath.Join(relativeTo, parsed.Path)
return FilePathToURI(absPath)
}
}
return uri, nil
}
func FilterReservedNames(p string) string {
// The following keys are reserved on Windows
// https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file?redirectedfrom=MSDN#win32-file-namespaces
reservedNameConversions := map[string]string{
"aux": "a_u_x",
"com": "c_o_m",
"con": "c_o_n",
"lpt": "l_p_t",
"nul": "n_u_l",
"prn": "p_r_n",
}
for k, v := range reservedNameConversions {
p = strings.Replace(p, k, v, -1)
}
return p
}
//WindowsDir is equivalent to path.Dir or filepath.Dir but always for Windows paths
//reproduced because Windows implementation is not exported
func WindowsDir(p string) string {
pathElements := strings.Split(p, `\`)
dirName := strings.Join(pathElements[:len(pathElements)-1], `\`)
return dirName
}
//WindowsBasename is equivalent to path.Basename or filepath.Basename but always for Windows paths
//reproduced because Windows implementation is not exported
func WindowsBasename(p string) string {
pathElements := strings.Split(p, `\`)
return pathElements[len(pathElements)-1]
}
//WindowsToSlash is equivalent to path.ToSlash or filepath.ToSlash but always for Windows paths
//reproduced because Windows implementation is not exported
func WindowsToSlash(p string) string {
slashPath := strings.ReplaceAll(p, `\`, "/") // convert slashes
if len(slashPath) < 2 {
return ""
}
return slashPath[2:] // strip volume
}
//WindowsPathSID returns the appropriate SID for a given UID and GID
//This the basic logic for path permissions in Pack and Lifecycle
func WindowsPathSID(uid, gid int) string {
if uid == 0 && gid == 0 {
return "S-1-5-32-544" // BUILTIN\Administrators
}
return "S-1-5-32-545" // BUILTIN\Users
}