github.com/YousefHaggyHeroku/pack@v1.5.5/internal/paths/paths.go (about) 1 package paths 2 3 import ( 4 "net/url" 5 "os" 6 "path/filepath" 7 "regexp" 8 "runtime" 9 "strings" 10 ) 11 12 var schemeRegexp = regexp.MustCompile(`^.+://.*`) 13 14 func IsURI(ref string) bool { 15 return schemeRegexp.MatchString(ref) 16 } 17 18 func IsDir(p string) (bool, error) { 19 fileInfo, err := os.Stat(p) 20 if err != nil { 21 return false, err 22 } 23 24 return fileInfo.IsDir(), nil 25 } 26 27 func FilePathToURI(p string) (string, error) { 28 var err error 29 if !filepath.IsAbs(p) { 30 p, err = filepath.Abs(p) 31 if err != nil { 32 return "", err 33 } 34 } 35 36 if runtime.GOOS == "windows" { 37 if strings.HasPrefix(p, `\\`) { 38 return "file://" + filepath.ToSlash(strings.TrimPrefix(p, `\\`)), nil 39 } 40 return "file:///" + filepath.ToSlash(p), nil 41 } 42 return "file://" + p, nil 43 } 44 45 // examples: 46 // 47 // - unix file: file://laptop/some%20dir/file.tgz 48 // 49 // - windows drive: file:///C:/Documents%20and%20Settings/file.tgz 50 // 51 // - windows share: file://laptop/My%20Documents/file.tgz 52 // 53 func URIToFilePath(uri string) (string, error) { 54 var ( 55 osPath string 56 err error 57 ) 58 59 osPath = filepath.FromSlash(strings.TrimPrefix(uri, "file://")) 60 61 if osPath, err = url.PathUnescape(osPath); err != nil { 62 return "", nil 63 } 64 65 if runtime.GOOS == "windows" { 66 if strings.HasPrefix(osPath, `\`) { 67 return strings.TrimPrefix(osPath, `\`), nil 68 } 69 return `\\` + osPath, nil 70 } 71 return osPath, nil 72 } 73 74 func ToAbsolute(uri, relativeTo string) (string, error) { 75 parsed, err := url.Parse(uri) 76 if err != nil { 77 return "", err 78 } 79 80 if parsed.Scheme == "" { 81 if !filepath.IsAbs(parsed.Path) { 82 absPath := filepath.Join(relativeTo, parsed.Path) 83 return FilePathToURI(absPath) 84 } 85 } 86 87 return uri, nil 88 } 89 90 func FilterReservedNames(p string) string { 91 // The following keys are reserved on Windows 92 // https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file?redirectedfrom=MSDN#win32-file-namespaces 93 reservedNameConversions := map[string]string{ 94 "aux": "a_u_x", 95 "com": "c_o_m", 96 "con": "c_o_n", 97 "lpt": "l_p_t", 98 "nul": "n_u_l", 99 "prn": "p_r_n", 100 } 101 for k, v := range reservedNameConversions { 102 p = strings.Replace(p, k, v, -1) 103 } 104 105 return p 106 } 107 108 //WindowsDir is equivalent to path.Dir or filepath.Dir but always for Windows paths 109 //reproduced because Windows implementation is not exported 110 func WindowsDir(p string) string { 111 pathElements := strings.Split(p, `\`) 112 113 dirName := strings.Join(pathElements[:len(pathElements)-1], `\`) 114 115 return dirName 116 } 117 118 //WindowsBasename is equivalent to path.Basename or filepath.Basename but always for Windows paths 119 //reproduced because Windows implementation is not exported 120 func WindowsBasename(p string) string { 121 pathElements := strings.Split(p, `\`) 122 123 return pathElements[len(pathElements)-1] 124 } 125 126 //WindowsToSlash is equivalent to path.ToSlash or filepath.ToSlash but always for Windows paths 127 //reproduced because Windows implementation is not exported 128 func WindowsToSlash(p string) string { 129 slashPath := strings.ReplaceAll(p, `\`, "/") // convert slashes 130 if len(slashPath) < 2 { 131 return "" 132 } 133 134 return slashPath[2:] // strip volume 135 } 136 137 //WindowsPathSID returns the appropriate SID for a given UID and GID 138 //This the basic logic for path permissions in Pack and Lifecycle 139 func WindowsPathSID(uid, gid int) string { 140 if uid == 0 && gid == 0 { 141 return "S-1-5-32-544" // BUILTIN\Administrators 142 } 143 return "S-1-5-32-545" // BUILTIN\Users 144 }