...

Source file src/internal/syscall/windows/registry/value.go

     1	// Copyright 2015 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	// +build windows
     6	
     7	package registry
     8	
     9	import (
    10		"errors"
    11		"io"
    12		"syscall"
    13		"unicode/utf16"
    14		"unsafe"
    15	)
    16	
    17	const (
    18		// Registry value types.
    19		NONE                       = 0
    20		SZ                         = 1
    21		EXPAND_SZ                  = 2
    22		BINARY                     = 3
    23		DWORD                      = 4
    24		DWORD_BIG_ENDIAN           = 5
    25		LINK                       = 6
    26		MULTI_SZ                   = 7
    27		RESOURCE_LIST              = 8
    28		FULL_RESOURCE_DESCRIPTOR   = 9
    29		RESOURCE_REQUIREMENTS_LIST = 10
    30		QWORD                      = 11
    31	)
    32	
    33	var (
    34		// ErrShortBuffer is returned when the buffer was too short for the operation.
    35		ErrShortBuffer = syscall.ERROR_MORE_DATA
    36	
    37		// ErrNotExist is returned when a registry key or value does not exist.
    38		ErrNotExist = syscall.ERROR_FILE_NOT_FOUND
    39	
    40		// ErrUnexpectedType is returned by Get*Value when the value's type was unexpected.
    41		ErrUnexpectedType = errors.New("unexpected key value type")
    42	)
    43	
    44	// GetValue retrieves the type and data for the specified value associated
    45	// with an open key k. It fills up buffer buf and returns the retrieved
    46	// byte count n. If buf is too small to fit the stored value it returns
    47	// ErrShortBuffer error along with the required buffer size n.
    48	// If no buffer is provided, it returns true and actual buffer size n.
    49	// If no buffer is provided, GetValue returns the value's type only.
    50	// If the value does not exist, the error returned is ErrNotExist.
    51	//
    52	// GetValue is a low level function. If value's type is known, use the appropriate
    53	// Get*Value function instead.
    54	func (k Key) GetValue(name string, buf []byte) (n int, valtype uint32, err error) {
    55		pname, err := syscall.UTF16PtrFromString(name)
    56		if err != nil {
    57			return 0, 0, err
    58		}
    59		var pbuf *byte
    60		if len(buf) > 0 {
    61			pbuf = (*byte)(unsafe.Pointer(&buf[0]))
    62		}
    63		l := uint32(len(buf))
    64		err = syscall.RegQueryValueEx(syscall.Handle(k), pname, nil, &valtype, pbuf, &l)
    65		if err != nil {
    66			return int(l), valtype, err
    67		}
    68		return int(l), valtype, nil
    69	}
    70	
    71	func (k Key) getValue(name string, buf []byte) (date []byte, valtype uint32, err error) {
    72		p, err := syscall.UTF16PtrFromString(name)
    73		if err != nil {
    74			return nil, 0, err
    75		}
    76		var t uint32
    77		n := uint32(len(buf))
    78		for {
    79			err = syscall.RegQueryValueEx(syscall.Handle(k), p, nil, &t, (*byte)(unsafe.Pointer(&buf[0])), &n)
    80			if err == nil {
    81				return buf[:n], t, nil
    82			}
    83			if err != syscall.ERROR_MORE_DATA {
    84				return nil, 0, err
    85			}
    86			if n <= uint32(len(buf)) {
    87				return nil, 0, err
    88			}
    89			buf = make([]byte, n)
    90		}
    91	}
    92	
    93	// GetStringValue retrieves the string value for the specified
    94	// value name associated with an open key k. It also returns the value's type.
    95	// If value does not exist, GetStringValue returns ErrNotExist.
    96	// If value is not SZ or EXPAND_SZ, it will return the correct value
    97	// type and ErrUnexpectedType.
    98	func (k Key) GetStringValue(name string) (val string, valtype uint32, err error) {
    99		data, typ, err2 := k.getValue(name, make([]byte, 64))
   100		if err2 != nil {
   101			return "", typ, err2
   102		}
   103		switch typ {
   104		case SZ, EXPAND_SZ:
   105		default:
   106			return "", typ, ErrUnexpectedType
   107		}
   108		if len(data) == 0 {
   109			return "", typ, nil
   110		}
   111		u := (*[1 << 29]uint16)(unsafe.Pointer(&data[0]))[:]
   112		return syscall.UTF16ToString(u), typ, nil
   113	}
   114	
   115	// GetMUIStringValue retrieves the localized string value for
   116	// the specified value name associated with an open key k.
   117	// If the value name doesn't exist or the localized string value
   118	// can't be resolved, GetMUIStringValue returns ErrNotExist.
   119	// GetMUIStringValue panics if the system doesn't support
   120	// regLoadMUIString; use LoadRegLoadMUIString to check if
   121	// regLoadMUIString is supported before calling this function.
   122	func (k Key) GetMUIStringValue(name string) (string, error) {
   123		pname, err := syscall.UTF16PtrFromString(name)
   124		if err != nil {
   125			return "", err
   126		}
   127	
   128		buf := make([]uint16, 1024)
   129		var buflen uint32
   130		var pdir *uint16
   131	
   132		err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir)
   133		if err == syscall.ERROR_FILE_NOT_FOUND { // Try fallback path
   134	
   135			// Try to resolve the string value using the system directory as
   136			// a DLL search path; this assumes the string value is of the form
   137			// @[path]\dllname,-strID but with no path given, e.g. @tzres.dll,-320.
   138	
   139			// This approach works with tzres.dll but may have to be revised
   140			// in the future to allow callers to provide custom search paths.
   141	
   142			var s string
   143			s, err = ExpandString("%SystemRoot%\\system32\\")
   144			if err != nil {
   145				return "", err
   146			}
   147			pdir, err = syscall.UTF16PtrFromString(s)
   148			if err != nil {
   149				return "", err
   150			}
   151	
   152			err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir)
   153		}
   154	
   155		for err == syscall.ERROR_MORE_DATA { // Grow buffer if needed
   156			if buflen <= uint32(len(buf)) {
   157				break // Buffer not growing, assume race; break
   158			}
   159			buf = make([]uint16, buflen)
   160			err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir)
   161		}
   162	
   163		if err != nil {
   164			return "", err
   165		}
   166	
   167		return syscall.UTF16ToString(buf), nil
   168	}
   169	
   170	// ExpandString expands environment-variable strings and replaces
   171	// them with the values defined for the current user.
   172	// Use ExpandString to expand EXPAND_SZ strings.
   173	func ExpandString(value string) (string, error) {
   174		if value == "" {
   175			return "", nil
   176		}
   177		p, err := syscall.UTF16PtrFromString(value)
   178		if err != nil {
   179			return "", err
   180		}
   181		r := make([]uint16, 100)
   182		for {
   183			n, err := expandEnvironmentStrings(p, &r[0], uint32(len(r)))
   184			if err != nil {
   185				return "", err
   186			}
   187			if n <= uint32(len(r)) {
   188				u := (*[1 << 29]uint16)(unsafe.Pointer(&r[0]))[:]
   189				return syscall.UTF16ToString(u), nil
   190			}
   191			r = make([]uint16, n)
   192		}
   193	}
   194	
   195	// GetStringsValue retrieves the []string value for the specified
   196	// value name associated with an open key k. It also returns the value's type.
   197	// If value does not exist, GetStringsValue returns ErrNotExist.
   198	// If value is not MULTI_SZ, it will return the correct value
   199	// type and ErrUnexpectedType.
   200	func (k Key) GetStringsValue(name string) (val []string, valtype uint32, err error) {
   201		data, typ, err2 := k.getValue(name, make([]byte, 64))
   202		if err2 != nil {
   203			return nil, typ, err2
   204		}
   205		if typ != MULTI_SZ {
   206			return nil, typ, ErrUnexpectedType
   207		}
   208		if len(data) == 0 {
   209			return nil, typ, nil
   210		}
   211		p := (*[1 << 29]uint16)(unsafe.Pointer(&data[0]))[:len(data)/2]
   212		if len(p) == 0 {
   213			return nil, typ, nil
   214		}
   215		if p[len(p)-1] == 0 {
   216			p = p[:len(p)-1] // remove terminating null
   217		}
   218		val = make([]string, 0, 5)
   219		from := 0
   220		for i, c := range p {
   221			if c == 0 {
   222				val = append(val, string(utf16.Decode(p[from:i])))
   223				from = i + 1
   224			}
   225		}
   226		return val, typ, nil
   227	}
   228	
   229	// GetIntegerValue retrieves the integer value for the specified
   230	// value name associated with an open key k. It also returns the value's type.
   231	// If value does not exist, GetIntegerValue returns ErrNotExist.
   232	// If value is not DWORD or QWORD, it will return the correct value
   233	// type and ErrUnexpectedType.
   234	func (k Key) GetIntegerValue(name string) (val uint64, valtype uint32, err error) {
   235		data, typ, err2 := k.getValue(name, make([]byte, 8))
   236		if err2 != nil {
   237			return 0, typ, err2
   238		}
   239		switch typ {
   240		case DWORD:
   241			if len(data) != 4 {
   242				return 0, typ, errors.New("DWORD value is not 4 bytes long")
   243			}
   244			return uint64(*(*uint32)(unsafe.Pointer(&data[0]))), DWORD, nil
   245		case QWORD:
   246			if len(data) != 8 {
   247				return 0, typ, errors.New("QWORD value is not 8 bytes long")
   248			}
   249			return uint64(*(*uint64)(unsafe.Pointer(&data[0]))), QWORD, nil
   250		default:
   251			return 0, typ, ErrUnexpectedType
   252		}
   253	}
   254	
   255	// GetBinaryValue retrieves the binary value for the specified
   256	// value name associated with an open key k. It also returns the value's type.
   257	// If value does not exist, GetBinaryValue returns ErrNotExist.
   258	// If value is not BINARY, it will return the correct value
   259	// type and ErrUnexpectedType.
   260	func (k Key) GetBinaryValue(name string) (val []byte, valtype uint32, err error) {
   261		data, typ, err2 := k.getValue(name, make([]byte, 64))
   262		if err2 != nil {
   263			return nil, typ, err2
   264		}
   265		if typ != BINARY {
   266			return nil, typ, ErrUnexpectedType
   267		}
   268		return data, typ, nil
   269	}
   270	
   271	func (k Key) setValue(name string, valtype uint32, data []byte) error {
   272		p, err := syscall.UTF16PtrFromString(name)
   273		if err != nil {
   274			return err
   275		}
   276		if len(data) == 0 {
   277			return regSetValueEx(syscall.Handle(k), p, 0, valtype, nil, 0)
   278		}
   279		return regSetValueEx(syscall.Handle(k), p, 0, valtype, &data[0], uint32(len(data)))
   280	}
   281	
   282	// SetDWordValue sets the data and type of a name value
   283	// under key k to value and DWORD.
   284	func (k Key) SetDWordValue(name string, value uint32) error {
   285		return k.setValue(name, DWORD, (*[4]byte)(unsafe.Pointer(&value))[:])
   286	}
   287	
   288	// SetQWordValue sets the data and type of a name value
   289	// under key k to value and QWORD.
   290	func (k Key) SetQWordValue(name string, value uint64) error {
   291		return k.setValue(name, QWORD, (*[8]byte)(unsafe.Pointer(&value))[:])
   292	}
   293	
   294	func (k Key) setStringValue(name string, valtype uint32, value string) error {
   295		v, err := syscall.UTF16FromString(value)
   296		if err != nil {
   297			return err
   298		}
   299		buf := (*[1 << 29]byte)(unsafe.Pointer(&v[0]))[:len(v)*2]
   300		return k.setValue(name, valtype, buf)
   301	}
   302	
   303	// SetStringValue sets the data and type of a name value
   304	// under key k to value and SZ. The value must not contain a zero byte.
   305	func (k Key) SetStringValue(name, value string) error {
   306		return k.setStringValue(name, SZ, value)
   307	}
   308	
   309	// SetExpandStringValue sets the data and type of a name value
   310	// under key k to value and EXPAND_SZ. The value must not contain a zero byte.
   311	func (k Key) SetExpandStringValue(name, value string) error {
   312		return k.setStringValue(name, EXPAND_SZ, value)
   313	}
   314	
   315	// SetStringsValue sets the data and type of a name value
   316	// under key k to value and MULTI_SZ. The value strings
   317	// must not contain a zero byte.
   318	func (k Key) SetStringsValue(name string, value []string) error {
   319		ss := ""
   320		for _, s := range value {
   321			for i := 0; i < len(s); i++ {
   322				if s[i] == 0 {
   323					return errors.New("string cannot have 0 inside")
   324				}
   325			}
   326			ss += s + "\x00"
   327		}
   328		v := utf16.Encode([]rune(ss + "\x00"))
   329		buf := (*[1 << 29]byte)(unsafe.Pointer(&v[0]))[:len(v)*2]
   330		return k.setValue(name, MULTI_SZ, buf)
   331	}
   332	
   333	// SetBinaryValue sets the data and type of a name value
   334	// under key k to value and BINARY.
   335	func (k Key) SetBinaryValue(name string, value []byte) error {
   336		return k.setValue(name, BINARY, value)
   337	}
   338	
   339	// DeleteValue removes a named value from the key k.
   340	func (k Key) DeleteValue(name string) error {
   341		return regDeleteValue(syscall.Handle(k), syscall.StringToUTF16Ptr(name))
   342	}
   343	
   344	// ReadValueNames returns the value names of key k.
   345	// The parameter n controls the number of returned names,
   346	// analogous to the way os.File.Readdirnames works.
   347	func (k Key) ReadValueNames(n int) ([]string, error) {
   348		ki, err := k.Stat()
   349		if err != nil {
   350			return nil, err
   351		}
   352		names := make([]string, 0, ki.ValueCount)
   353		buf := make([]uint16, ki.MaxValueNameLen+1) // extra room for terminating null character
   354	loopItems:
   355		for i := uint32(0); ; i++ {
   356			if n > 0 {
   357				if len(names) == n {
   358					return names, nil
   359				}
   360			}
   361			l := uint32(len(buf))
   362			for {
   363				err := regEnumValue(syscall.Handle(k), i, &buf[0], &l, nil, nil, nil, nil)
   364				if err == nil {
   365					break
   366				}
   367				if err == syscall.ERROR_MORE_DATA {
   368					// Double buffer size and try again.
   369					l = uint32(2 * len(buf))
   370					buf = make([]uint16, l)
   371					continue
   372				}
   373				if err == _ERROR_NO_MORE_ITEMS {
   374					break loopItems
   375				}
   376				return names, err
   377			}
   378			names = append(names, syscall.UTF16ToString(buf[:l]))
   379		}
   380		if n > len(names) {
   381			return names, io.EOF
   382		}
   383		return names, nil
   384	}
   385	

View as plain text