|
| 1 | +/* |
| 2 | + Copyright 2020 The Compose Specification Authors. |
| 3 | +
|
| 4 | + Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | + you may not use this file except in compliance with the License. |
| 6 | + You may obtain a copy of the License at |
| 7 | +
|
| 8 | + http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | +
|
| 10 | + Unless required by applicable law or agreed to in writing, software |
| 11 | + distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | + See the License for the specific language governing permissions and |
| 14 | + limitations under the License. |
| 15 | +*/ |
| 16 | + |
| 17 | +package utils |
| 18 | + |
| 19 | +import ( |
| 20 | + "os" |
| 21 | + "path/filepath" |
| 22 | + "strings" |
| 23 | +) |
| 24 | + |
| 25 | +// ResolveSymbolicLink converts the section of an absolute path if it is a |
| 26 | +// symbolic link |
| 27 | +// |
| 28 | +// Parameters: |
| 29 | +// - path: an absolute path |
| 30 | +// |
| 31 | +// Returns: |
| 32 | +// - converted path if it has a symbolic link or the same path if there is |
| 33 | +// no symbolic link |
| 34 | +func ResolveSymbolicLink(path string) (string, error) { |
| 35 | + sym, part, err := getSymbolinkLink(path) |
| 36 | + if err != nil { |
| 37 | + return "", err |
| 38 | + } |
| 39 | + if sym == "" && part == "" { |
| 40 | + // no symbolic link detected |
| 41 | + return path, nil |
| 42 | + } |
| 43 | + return strings.Replace(path, part, sym, 1), nil |
| 44 | + |
| 45 | +} |
| 46 | + |
| 47 | +// getSymbolinkLink parses all parts of the path and returns the |
| 48 | +// the symbolic link part as well as the correspondent original part |
| 49 | +// Parameters: |
| 50 | +// - path: an absolute path |
| 51 | +// |
| 52 | +// Returns: |
| 53 | +// - string section of the path that is a symbolic link |
| 54 | +// - string correspondent path section of the symbolic link |
| 55 | +// - An error |
| 56 | +func getSymbolinkLink(path string) (string, string, error) { |
| 57 | + parts := strings.Split(path, string(os.PathSeparator)) |
| 58 | + |
| 59 | + // Reconstruct the path step by step, checking each component |
| 60 | + var currentPath string |
| 61 | + if filepath.IsAbs(path) { |
| 62 | + currentPath = string(os.PathSeparator) |
| 63 | + } |
| 64 | + |
| 65 | + for _, part := range parts { |
| 66 | + if part == "" { |
| 67 | + continue |
| 68 | + } |
| 69 | + currentPath = filepath.Join(currentPath, part) |
| 70 | + |
| 71 | + if isSymLink := isSymbolicLink(currentPath); isSymLink { |
| 72 | + // return symbolic link, and correspondent part |
| 73 | + target, err := filepath.EvalSymlinks(currentPath) |
| 74 | + if err != nil { |
| 75 | + return "", "", err |
| 76 | + } |
| 77 | + return target, currentPath, nil |
| 78 | + } |
| 79 | + } |
| 80 | + return "", "", nil // no symbolic link |
| 81 | +} |
| 82 | + |
| 83 | +// isSymbolicLink validates if the path is a symbolic link |
| 84 | +func isSymbolicLink(path string) bool { |
| 85 | + info, err := os.Lstat(path) |
| 86 | + if err != nil { |
| 87 | + return false |
| 88 | + } |
| 89 | + |
| 90 | + // Check if the file mode indicates a symbolic link |
| 91 | + return info.Mode()&os.ModeSymlink != 0 |
| 92 | +} |
0 commit comments