github.com/bir3/gocompiler@v0.3.205/src/xvendor/golang.org/x/sys/windows/exec_windows.go (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Fork, exec, wait, etc.
     6  
     7  package windows
     8  
     9  import (
    10  	errorspkg "errors"
    11  	"unsafe"
    12  )
    13  
    14  // EscapeArg rewrites command line argument s as prescribed
    15  // in http://msdn.microsoft.com/en-us/library/ms880421.
    16  // This function returns "" (2 double quotes) if s is empty.
    17  // Alternatively, these transformations are done:
    18  //   - every back slash (\) is doubled, but only if immediately
    19  //     followed by double quote (");
    20  //   - every double quote (") is escaped by back slash (\);
    21  //   - finally, s is wrapped with double quotes (arg -> "arg"),
    22  //     but only if there is space or tab inside s.
    23  func EscapeArg(s string) string {
    24  	if len(s) == 0 {
    25  		return "\"\""
    26  	}
    27  	n := len(s)
    28  	hasSpace := false
    29  	for i := 0; i < len(s); i++ {
    30  		switch s[i] {
    31  		case '"', '\\':
    32  			n++
    33  		case ' ', '\t':
    34  			hasSpace = true
    35  		}
    36  	}
    37  	if hasSpace {
    38  		n += 2
    39  	}
    40  	if n == len(s) {
    41  		return s
    42  	}
    43  
    44  	qs := make([]byte, n)
    45  	j := 0
    46  	if hasSpace {
    47  		qs[j] = '"'
    48  		j++
    49  	}
    50  	slashes := 0
    51  	for i := 0; i < len(s); i++ {
    52  		switch s[i] {
    53  		default:
    54  			slashes = 0
    55  			qs[j] = s[i]
    56  		case '\\':
    57  			slashes++
    58  			qs[j] = s[i]
    59  		case '"':
    60  			for ; slashes > 0; slashes-- {
    61  				qs[j] = '\\'
    62  				j++
    63  			}
    64  			qs[j] = '\\'
    65  			j++
    66  			qs[j] = s[i]
    67  		}
    68  		j++
    69  	}
    70  	if hasSpace {
    71  		for ; slashes > 0; slashes-- {
    72  			qs[j] = '\\'
    73  			j++
    74  		}
    75  		qs[j] = '"'
    76  		j++
    77  	}
    78  	return string(qs[:j])
    79  }
    80  
    81  // ComposeCommandLine escapes and joins the given arguments suitable for use as a Windows command line,
    82  // in CreateProcess's CommandLine argument, CreateService/ChangeServiceConfig's BinaryPathName argument,
    83  // or any program that uses CommandLineToArgv.
    84  func ComposeCommandLine(args []string) string {
    85  	var commandLine string
    86  	for i := range args {
    87  		if i > 0 {
    88  			commandLine += " "
    89  		}
    90  		commandLine += EscapeArg(args[i])
    91  	}
    92  	return commandLine
    93  }
    94  
    95  // DecomposeCommandLine breaks apart its argument command line into unescaped parts using CommandLineToArgv,
    96  // as gathered from GetCommandLine, QUERY_SERVICE_CONFIG's BinaryPathName argument, or elsewhere that
    97  // command lines are passed around.
    98  func DecomposeCommandLine(commandLine string) ([]string, error) {
    99  	if len(commandLine) == 0 {
   100  		return []string{}, nil
   101  	}
   102  	var argc int32
   103  	argv, err := CommandLineToArgv(StringToUTF16Ptr(commandLine), &argc)
   104  	if err != nil {
   105  		return nil, err
   106  	}
   107  	defer LocalFree(Handle(unsafe.Pointer(argv)))
   108  	var args []string
   109  	for _, v := range (*argv)[:argc] {
   110  		args = append(args, UTF16ToString((*v)[:]))
   111  	}
   112  	return args, nil
   113  }
   114  
   115  func CloseOnExec(fd Handle) {
   116  	SetHandleInformation(Handle(fd), HANDLE_FLAG_INHERIT, 0)
   117  }
   118  
   119  // FullPath retrieves the full path of the specified file.
   120  func FullPath(name string) (path string, err error) {
   121  	p, err := UTF16PtrFromString(name)
   122  	if err != nil {
   123  		return "", err
   124  	}
   125  	n := uint32(100)
   126  	for {
   127  		buf := make([]uint16, n)
   128  		n, err = GetFullPathName(p, uint32(len(buf)), &buf[0], nil)
   129  		if err != nil {
   130  			return "", err
   131  		}
   132  		if n <= uint32(len(buf)) {
   133  			return UTF16ToString(buf[:n]), nil
   134  		}
   135  	}
   136  }
   137  
   138  // NewProcThreadAttributeList allocates a new ProcThreadAttributeListContainer, with the requested maximum number of attributes.
   139  func NewProcThreadAttributeList(maxAttrCount uint32) (*ProcThreadAttributeListContainer, error) {
   140  	var size uintptr
   141  	err := initializeProcThreadAttributeList(nil, maxAttrCount, 0, &size)
   142  	if err != ERROR_INSUFFICIENT_BUFFER {
   143  		if err == nil {
   144  			return nil, errorspkg.New("unable to query buffer size from InitializeProcThreadAttributeList")
   145  		}
   146  		return nil, err
   147  	}
   148  	alloc, err := LocalAlloc(LMEM_FIXED, uint32(size))
   149  	if err != nil {
   150  		return nil, err
   151  	}
   152  	// size is guaranteed to be ≥1 by InitializeProcThreadAttributeList.
   153  	al := &ProcThreadAttributeListContainer{data: (*ProcThreadAttributeList)(unsafe.Pointer(alloc))}
   154  	err = initializeProcThreadAttributeList(al.data, maxAttrCount, 0, &size)
   155  	if err != nil {
   156  		return nil, err
   157  	}
   158  	return al, err
   159  }
   160  
   161  // Update modifies the ProcThreadAttributeList using UpdateProcThreadAttribute.
   162  func (al *ProcThreadAttributeListContainer) Update(attribute uintptr, value unsafe.Pointer, size uintptr) error {
   163  	al.pointers = append(al.pointers, value)
   164  	return updateProcThreadAttribute(al.data, 0, attribute, value, size, nil, nil)
   165  }
   166  
   167  // Delete frees ProcThreadAttributeList's resources.
   168  func (al *ProcThreadAttributeListContainer) Delete() {
   169  	deleteProcThreadAttributeList(al.data)
   170  	LocalFree(Handle(unsafe.Pointer(al.data)))
   171  	al.data = nil
   172  	al.pointers = nil
   173  }
   174  
   175  // List returns the actual ProcThreadAttributeList to be passed to StartupInfoEx.
   176  func (al *ProcThreadAttributeListContainer) List() *ProcThreadAttributeList {
   177  	return al.data
   178  }