github.com/opencontainers/runtime-tools@v0.9.0/filepath/clean.go (about) 1 package filepath 2 3 import ( 4 "fmt" 5 "strings" 6 ) 7 8 // Clean is an explicit-OS version of path/filepath's Clean. 9 func Clean(os, path string) string { 10 abs := IsAbs(os, path) 11 sep := Separator(os) 12 elements := strings.Split(path, string(sep)) 13 14 // Replace multiple Separator elements with a single one. 15 for i := 0; i < len(elements); i++ { 16 if len(elements[i]) == 0 { 17 elements = append(elements[:i], elements[i+1:]...) 18 i-- 19 } 20 } 21 22 // Eliminate each . path name element (the current directory). 23 for i := 0; i < len(elements); i++ { 24 if elements[i] == "." && len(elements) > 1 { 25 elements = append(elements[:i], elements[i+1:]...) 26 i-- 27 } 28 } 29 30 // Eliminate each inner .. path name element (the parent directory) 31 // along with the non-.. element that precedes it. 32 for i := 1; i < len(elements); i++ { 33 if i == 1 && abs && sep == '\\' { 34 continue 35 } 36 if i > 0 && elements[i] == ".." { 37 elements = append(elements[:i-1], elements[i+1:]...) 38 i -= 2 39 } 40 } 41 42 // Eliminate .. elements that begin a rooted path: 43 // that is, replace "/.." by "/" at the beginning of a path, 44 // assuming Separator is '/'. 45 offset := 0 46 if sep == '\\' { 47 offset = 1 48 } 49 if abs { 50 for len(elements) > offset && elements[offset] == ".." { 51 elements = append(elements[:offset], elements[offset+1:]...) 52 } 53 } 54 55 cleaned := strings.Join(elements, string(sep)) 56 if abs { 57 if sep == '/' { 58 cleaned = fmt.Sprintf("%c%s", sep, cleaned) 59 } else if len(elements) == 1 { 60 cleaned = fmt.Sprintf("%s%c", cleaned, sep) 61 } 62 } 63 64 // If the result of this process is an empty string, Clean returns 65 // the string ".". 66 if len(cleaned) == 0 { 67 cleaned = "." 68 } 69 70 if cleaned == path { 71 return path 72 } 73 return Clean(os, cleaned) 74 }