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  }