1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
|
// Copyright 2013 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
// +build windows
package utils
import (
"fmt"
"os"
"path/filepath"
"syscall"
"unsafe"
"github.com/juju/errors"
)
const (
movefile_replace_existing = 0x1
movefile_write_through = 0x8
)
//sys moveFileEx(lpExistingFileName *uint16, lpNewFileName *uint16, dwFlags uint32) (err error) = MoveFileExW
// MoveFile atomically moves the source file to the destination, returning
// whether the file was moved successfully. If the destination already exists,
// it returns an error rather than overwrite it.
func MoveFile(source, destination string) (bool, error) {
src, err := syscall.UTF16PtrFromString(source)
if err != nil {
return false, &os.LinkError{"move", source, destination, err}
}
dest, err := syscall.UTF16PtrFromString(destination)
if err != nil {
return false, &os.LinkError{"move", source, destination, err}
}
// see http://msdn.microsoft.com/en-us/library/windows/desktop/aa365240(v=vs.85).aspx
if err := moveFileEx(src, dest, movefile_write_through); err != nil {
return false, &os.LinkError{"move", source, destination, err}
}
return true, nil
}
// ReplaceFile atomically replaces the destination file or directory with the source.
// The errors that are returned are identical to those returned by os.Rename.
func ReplaceFile(source, destination string) error {
src, err := syscall.UTF16PtrFromString(source)
if err != nil {
return &os.LinkError{"replace", source, destination, err}
}
dest, err := syscall.UTF16PtrFromString(destination)
if err != nil {
return &os.LinkError{"replace", source, destination, err}
}
// see http://msdn.microsoft.com/en-us/library/windows/desktop/aa365240(v=vs.85).aspx
if err := moveFileEx(src, dest, movefile_replace_existing|movefile_write_through); err != nil {
return &os.LinkError{"replace", source, destination, err}
}
return nil
}
// MakeFileURL returns a proper file URL for the given path/directory
func MakeFileURL(in string) string {
in = filepath.ToSlash(in)
// for windows at least should be <letter>: to be considered valid
// so we cant do anything with less than that.
if len(in) < 2 {
return in
}
if string(in[1]) != ":" {
return in
}
// since go 1.6 http client will only take this format.
return "file://" + in
}
func getUserSID(username string) (string, error) {
sid, _, _, e := syscall.LookupSID("", username)
if e != nil {
return "", e
}
sidStr, err := sid.String()
return sidStr, err
}
func readRegString(h syscall.Handle, key string) (value string, err error) {
var typ uint32
var buf uint32
// Get size of registry key
err = syscall.RegQueryValueEx(h, syscall.StringToUTF16Ptr(key), nil, &typ, nil, &buf)
if err != nil {
return value, err
}
n := make([]uint16, buf/2+1)
err = syscall.RegQueryValueEx(h, syscall.StringToUTF16Ptr(key), nil, &typ, (*byte)(unsafe.Pointer(&n[0])), &buf)
if err != nil {
return value, err
}
return syscall.UTF16ToString(n[:]), err
}
func homeFromRegistry(sid string) (string, error) {
var h syscall.Handle
// This key will exist on all platforms we support the agent on (windows server 2008 and above)
keyPath := fmt.Sprintf("Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\%s", sid)
err := syscall.RegOpenKeyEx(syscall.HKEY_LOCAL_MACHINE,
syscall.StringToUTF16Ptr(keyPath),
0, syscall.KEY_READ, &h)
if err != nil {
return "", err
}
defer syscall.RegCloseKey(h)
str, err := readRegString(h, "ProfileImagePath")
if err != nil {
return "", err
}
return str, nil
}
// homeDir returns a local user home dir on Windows
// user.Lookup() does not populate Gid and HomeDir on Windows,
// so we get it from the registry
func homeDir(user string) (string, error) {
u, err := getUserSID(user)
if err != nil {
return "", errors.NewUserNotFound(err, "no such user")
}
return homeFromRegistry(u)
}
// ChownPath is not implemented for Windows.
func ChownPath(path, username string) error {
// This only exists to allow building on Windows. User lookup and
// file ownership needs to be handled in a completely different
// way and hasn't yet been implemented.
return nil
}
// IsFileOwner is not implemented for Windows.
func IsFileOwner(path, username string) (bool, error) {
return true, nil
}
|