github.com/secure-build/gitlab-runner@v12.5.0+incompatible/executors/docker/internal/volumes/parser/windows_parser.go (about)

     1  // +build windows
     2  
     3  package parser
     4  
     5  import (
     6  	"regexp"
     7  
     8  	"gitlab.com/gitlab-org/gitlab-runner/helpers/path"
     9  )
    10  
    11  // The specification of regular expression used for parsing Windows volumes
    12  // specification was taken from:
    13  //
    14  // https://github.com/docker/engine/blob/a79fabbfe84117696a19671f4aa88b82d0f64fc1/volume/mounts/windows_parser.go
    15  //
    16  // The original source is licensed under Apache License 2.0 and the copyright for it
    17  // goes to Docker, Inc.
    18  
    19  const (
    20  	// Spec should be in the format [source:]destination[:mode]
    21  	//
    22  	// Examples: c:\foo bar:d:rw
    23  	//           c:\foo:d:\bar
    24  	//           myname:d:
    25  	//           d:\
    26  	//
    27  	// Explanation of this regex! Thanks @thaJeztah on IRC and gist for help. See
    28  	// https://gist.github.com/thaJeztah/6185659e4978789fb2b2. A good place to
    29  	// test is https://regex-golang.appspot.com/assets/html/index.html
    30  	//
    31  	// Useful link for referencing named capturing groups:
    32  	// http://stackoverflow.com/questions/20750843/using-named-matches-from-go-regex
    33  	//
    34  	// There are three match groups: source, destination and mode.
    35  	//
    36  
    37  	// windowsHostDir is the first option of a source
    38  	windowsHostDir = `(?:\\\\\?\\)?[a-z]:[\\/](?:[^\\/:*?"<>|\r\n]+[\\/]?)*`
    39  	// windowsVolumeName is the second option of a source
    40  	windowsVolumeName = `[^\\/:*?"<>|\r\n]+`
    41  	// windowsPipe is a named path pipe (starts with `\\.\pipe\`, possibly with / instead of \)
    42  	windowsPipe = `[/\\]{2}.[/\\]pipe[/\\][^:*?"<>|\r\n]+`
    43  	// windowsSource is the combined possibilities for a source
    44  	windowsSource = `((?P<source>((` + windowsHostDir + `)|(` + windowsVolumeName + `)|(` + windowsPipe + `))):)?`
    45  
    46  	// Source. Can be either a host directory, a name, or omitted:
    47  	//  HostDir:
    48  	//    -  Essentially using the folder solution from
    49  	//       https://www.safaribooksonline.com/library/view/regular-expressions-cookbook/9781449327453/ch08s18.html
    50  	//       but adding case insensitivity.
    51  	//    -  Must be an absolute path such as c:\path
    52  	//    -  Can include spaces such as `c:\program files`
    53  	//    -  And then followed by a colon which is not in the capture group
    54  	//    -  And can be optional
    55  	//  Name:
    56  	//    -  Must not contain invalid NTFS filename characters (https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx)
    57  	//    -  And then followed by a colon which is not in the capture group
    58  	//    -  And can be optional
    59  
    60  	// windowsDestination is the regex expression for the mount destination
    61  	windowsDestination = `(?P<destination>((?:\\\\\?\\)?([a-z]):((?:[\\/][^\\/:*?"<>\r\n]+)*[\\/]?))|(` + windowsPipe + `))`
    62  
    63  	// windowsMode is the regex expression for the mode of the mount
    64  	// Mode (optional):
    65  	//    -  Hopefully self explanatory in comparison to above regex's.
    66  	//    -  Colon is not in the capture group
    67  	windowsMode = `(:(?P<mode>(?i)ro|rw))?`
    68  )
    69  
    70  type windowsParser struct {
    71  	baseParser
    72  }
    73  
    74  func NewWindowsParser() Parser {
    75  	return &windowsParser{
    76  		baseParser: baseParser{
    77  			path: path.NewWindowsPath(),
    78  		},
    79  	}
    80  }
    81  
    82  func (p *windowsParser) ParseVolume(spec string) (*Volume, error) {
    83  	specExp := regexp.MustCompile(`(?i)^` + windowsSource + windowsDestination + windowsMode + `$`)
    84  
    85  	parts, err := p.matchesToVolumeSpecParts(spec, specExp)
    86  	if err != nil {
    87  		return nil, err
    88  	}
    89  
    90  	return newVolume(parts["source"], parts["destination"], parts["mode"], ""), nil
    91  }