Build and install from GOPATH

* Rename 'vendor/src' -> 'vendor'
  * Ignore vendor/ instead of vendor/src/ for lint
* Rename 'cmd/client' -> 'cmd/ocic' to make it 'go install'able
* Rename 'cmd/server' -> 'cmd/ocid' to make it 'go install'able
* Update Makefile to build and install from GOPATH
* Update tests to locate ocid/ocic in GOPATH/bin
* Search for binaries in GOPATH/bin instead of PATH
* Install tools using `go get -u`, so they are updated on each run

Signed-off-by: Jonathan Yu <jawnsy@redhat.com>
This commit is contained in:
Jonathan Yu 2017-01-17 11:57:35 -08:00
parent 9da2882d49
commit 6c9628cdb1
No known key found for this signature in database
GPG key ID: F3C2F688A21CB648
1111 changed files with 70 additions and 61 deletions

View file

@ -0,0 +1,52 @@
package system
import (
"os"
"syscall"
"time"
"unsafe"
)
var (
maxTime time.Time
)
func init() {
if unsafe.Sizeof(syscall.Timespec{}.Nsec) == 8 {
// This is a 64 bit timespec
// os.Chtimes limits time to the following
maxTime = time.Unix(0, 1<<63-1)
} else {
// This is a 32 bit timespec
maxTime = time.Unix(1<<31-1, 0)
}
}
// Chtimes changes the access time and modified time of a file at the given path
func Chtimes(name string, atime time.Time, mtime time.Time) error {
unixMinTime := time.Unix(0, 0)
unixMaxTime := maxTime
// If the modified time is prior to the Unix Epoch, or after the
// end of Unix Time, os.Chtimes has undefined behavior
// default to Unix Epoch in this case, just in case
if atime.Before(unixMinTime) || atime.After(unixMaxTime) {
atime = unixMinTime
}
if mtime.Before(unixMinTime) || mtime.After(unixMaxTime) {
mtime = unixMinTime
}
if err := os.Chtimes(name, atime, mtime); err != nil {
return err
}
// Take platform specific action for setting create time.
if err := setCTime(name, mtime); err != nil {
return err
}
return nil
}

View file

@ -0,0 +1,14 @@
// +build !windows
package system
import (
"time"
)
//setCTime will set the create time on a file. On Unix, the create
//time is updated as a side effect of setting the modified time, so
//no action is required.
func setCTime(path string, ctime time.Time) error {
return nil
}

View file

@ -0,0 +1,27 @@
// +build windows
package system
import (
"syscall"
"time"
)
//setCTime will set the create time on a file. On Windows, this requires
//calling SetFileTime and explicitly including the create time.
func setCTime(path string, ctime time.Time) error {
ctimespec := syscall.NsecToTimespec(ctime.UnixNano())
pathp, e := syscall.UTF16PtrFromString(path)
if e != nil {
return e
}
h, e := syscall.CreateFile(pathp,
syscall.FILE_WRITE_ATTRIBUTES, syscall.FILE_SHARE_WRITE, nil,
syscall.OPEN_EXISTING, syscall.FILE_FLAG_BACKUP_SEMANTICS, 0)
if e != nil {
return e
}
defer syscall.Close(h)
c := syscall.NsecToFiletime(syscall.TimespecToNsec(ctimespec))
return syscall.SetFileTime(h, &c, nil, nil)
}

View file

@ -0,0 +1,10 @@
package system
import (
"errors"
)
var (
// ErrNotSupportedPlatform means the platform is not supported.
ErrNotSupportedPlatform = errors.New("platform and architecture is not supported")
)

View file

@ -0,0 +1,83 @@
package system
// This file implements syscalls for Win32 events which are not implemented
// in golang.
import (
"syscall"
"unsafe"
)
var (
procCreateEvent = modkernel32.NewProc("CreateEventW")
procOpenEvent = modkernel32.NewProc("OpenEventW")
procSetEvent = modkernel32.NewProc("SetEvent")
procResetEvent = modkernel32.NewProc("ResetEvent")
procPulseEvent = modkernel32.NewProc("PulseEvent")
)
// CreateEvent implements win32 CreateEventW func in golang. It will create an event object.
func CreateEvent(eventAttributes *syscall.SecurityAttributes, manualReset bool, initialState bool, name string) (handle syscall.Handle, err error) {
namep, _ := syscall.UTF16PtrFromString(name)
var _p1 uint32
if manualReset {
_p1 = 1
}
var _p2 uint32
if initialState {
_p2 = 1
}
r0, _, e1 := procCreateEvent.Call(uintptr(unsafe.Pointer(eventAttributes)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(namep)))
use(unsafe.Pointer(namep))
handle = syscall.Handle(r0)
if handle == syscall.InvalidHandle {
err = e1
}
return
}
// OpenEvent implements win32 OpenEventW func in golang. It opens an event object.
func OpenEvent(desiredAccess uint32, inheritHandle bool, name string) (handle syscall.Handle, err error) {
namep, _ := syscall.UTF16PtrFromString(name)
var _p1 uint32
if inheritHandle {
_p1 = 1
}
r0, _, e1 := procOpenEvent.Call(uintptr(desiredAccess), uintptr(_p1), uintptr(unsafe.Pointer(namep)))
use(unsafe.Pointer(namep))
handle = syscall.Handle(r0)
if handle == syscall.InvalidHandle {
err = e1
}
return
}
// SetEvent implements win32 SetEvent func in golang.
func SetEvent(handle syscall.Handle) (err error) {
return setResetPulse(handle, procSetEvent)
}
// ResetEvent implements win32 ResetEvent func in golang.
func ResetEvent(handle syscall.Handle) (err error) {
return setResetPulse(handle, procResetEvent)
}
// PulseEvent implements win32 PulseEvent func in golang.
func PulseEvent(handle syscall.Handle) (err error) {
return setResetPulse(handle, procPulseEvent)
}
func setResetPulse(handle syscall.Handle, proc *syscall.LazyProc) (err error) {
r0, _, _ := proc.Call(uintptr(handle))
if r0 != 0 {
err = syscall.Errno(r0)
}
return
}
var temp unsafe.Pointer
// use ensures a variable is kept alive without the GC freeing while still needed
func use(p unsafe.Pointer) {
temp = p
}

View file

@ -0,0 +1,19 @@
// +build !windows
package system
import (
"os"
"path/filepath"
)
// MkdirAll creates a directory named path along with any necessary parents,
// with permission specified by attribute perm for all dir created.
func MkdirAll(path string, perm os.FileMode) error {
return os.MkdirAll(path, perm)
}
// IsAbs is a platform-specific wrapper for filepath.IsAbs.
func IsAbs(path string) bool {
return filepath.IsAbs(path)
}

View file

@ -0,0 +1,82 @@
// +build windows
package system
import (
"os"
"path/filepath"
"regexp"
"strings"
"syscall"
)
// MkdirAll implementation that is volume path aware for Windows.
func MkdirAll(path string, perm os.FileMode) error {
if re := regexp.MustCompile(`^\\\\\?\\Volume{[a-z0-9-]+}$`); re.MatchString(path) {
return nil
}
// The rest of this method is copied from os.MkdirAll and should be kept
// as-is to ensure compatibility.
// Fast path: if we can tell whether path is a directory or file, stop with success or error.
dir, err := os.Stat(path)
if err == nil {
if dir.IsDir() {
return nil
}
return &os.PathError{
Op: "mkdir",
Path: path,
Err: syscall.ENOTDIR,
}
}
// Slow path: make sure parent exists and then call Mkdir for path.
i := len(path)
for i > 0 && os.IsPathSeparator(path[i-1]) { // Skip trailing path separator.
i--
}
j := i
for j > 0 && !os.IsPathSeparator(path[j-1]) { // Scan backward over element.
j--
}
if j > 1 {
// Create parent
err = MkdirAll(path[0:j-1], perm)
if err != nil {
return err
}
}
// Parent now exists; invoke Mkdir and use its result.
err = os.Mkdir(path, perm)
if err != nil {
// Handle arguments like "foo/." by
// double-checking that directory doesn't exist.
dir, err1 := os.Lstat(path)
if err1 == nil && dir.IsDir() {
return nil
}
return err
}
return nil
}
// IsAbs is a platform-specific wrapper for filepath.IsAbs. On Windows,
// golang filepath.IsAbs does not consider a path \windows\system32 as absolute
// as it doesn't start with a drive-letter/colon combination. However, in
// docker we need to verify things such as WORKDIR /windows/system32 in
// a Dockerfile (which gets translated to \windows\system32 when being processed
// by the daemon. This SHOULD be treated as absolute from a docker processing
// perspective.
func IsAbs(path string) bool {
if !filepath.IsAbs(path) {
if !strings.HasPrefix(path, string(os.PathSeparator)) {
return false
}
}
return true
}

View file

@ -0,0 +1,19 @@
// +build !windows
package system
import (
"syscall"
)
// Lstat takes a path to a file and returns
// a system.StatT type pertaining to that file.
//
// Throws an error if the file does not exist
func Lstat(path string) (*StatT, error) {
s := &syscall.Stat_t{}
if err := syscall.Lstat(path, s); err != nil {
return nil, err
}
return fromStatT(s)
}

View file

@ -0,0 +1,25 @@
// +build windows
package system
import (
"os"
)
// Lstat calls os.Lstat to get a fileinfo interface back.
// This is then copied into our own locally defined structure.
// Note the Linux version uses fromStatT to do the copy back,
// but that not strictly necessary when already in an OS specific module.
func Lstat(path string) (*StatT, error) {
fi, err := os.Lstat(path)
if err != nil {
return nil, err
}
return &StatT{
name: fi.Name(),
size: fi.Size(),
mode: fi.Mode(),
modTime: fi.ModTime(),
isDir: fi.IsDir()}, nil
}

View file

@ -0,0 +1,17 @@
package system
// MemInfo contains memory statistics of the host system.
type MemInfo struct {
// Total usable RAM (i.e. physical RAM minus a few reserved bits and the
// kernel binary code).
MemTotal int64
// Amount of free memory.
MemFree int64
// Total amount of swap space available.
SwapTotal int64
// Amount of swap space that is currently unused.
SwapFree int64
}

View file

@ -0,0 +1,65 @@
package system
import (
"bufio"
"io"
"os"
"strconv"
"strings"
"github.com/docker/go-units"
)
// ReadMemInfo retrieves memory statistics of the host system and returns a
// MemInfo type.
func ReadMemInfo() (*MemInfo, error) {
file, err := os.Open("/proc/meminfo")
if err != nil {
return nil, err
}
defer file.Close()
return parseMemInfo(file)
}
// parseMemInfo parses the /proc/meminfo file into
// a MemInfo object given an io.Reader to the file.
// Throws error if there are problems reading from the file
func parseMemInfo(reader io.Reader) (*MemInfo, error) {
meminfo := &MemInfo{}
scanner := bufio.NewScanner(reader)
for scanner.Scan() {
// Expected format: ["MemTotal:", "1234", "kB"]
parts := strings.Fields(scanner.Text())
// Sanity checks: Skip malformed entries.
if len(parts) < 3 || parts[2] != "kB" {
continue
}
// Convert to bytes.
size, err := strconv.Atoi(parts[1])
if err != nil {
continue
}
bytes := int64(size) * units.KiB
switch parts[0] {
case "MemTotal:":
meminfo.MemTotal = bytes
case "MemFree:":
meminfo.MemFree = bytes
case "SwapTotal:":
meminfo.SwapTotal = bytes
case "SwapFree:":
meminfo.SwapFree = bytes
}
}
// Handle errors that may have occurred during the reading of the file.
if err := scanner.Err(); err != nil {
return nil, err
}
return meminfo, nil
}

View file

@ -0,0 +1,128 @@
// +build solaris,cgo
package system
import (
"fmt"
"unsafe"
)
// #cgo LDFLAGS: -lkstat
// #include <unistd.h>
// #include <stdlib.h>
// #include <stdio.h>
// #include <kstat.h>
// #include <sys/swap.h>
// #include <sys/param.h>
// struct swaptable *allocSwaptable(int num) {
// struct swaptable *st;
// struct swapent *swapent;
// st = (struct swaptable *)malloc(num * sizeof(swapent_t) + sizeof (int));
// swapent = st->swt_ent;
// for (int i = 0; i < num; i++,swapent++) {
// swapent->ste_path = (char *)malloc(MAXPATHLEN * sizeof (char));
// }
// st->swt_n = num;
// return st;
//}
// void freeSwaptable (struct swaptable *st) {
// struct swapent *swapent = st->swt_ent;
// for (int i = 0; i < st->swt_n; i++,swapent++) {
// free(swapent->ste_path);
// }
// free(st);
// }
// swapent_t getSwapEnt(swapent_t *ent, int i) {
// return ent[i];
// }
// int64_t getPpKernel() {
// int64_t pp_kernel = 0;
// kstat_ctl_t *ksc;
// kstat_t *ks;
// kstat_named_t *knp;
// kid_t kid;
//
// if ((ksc = kstat_open()) == NULL) {
// return -1;
// }
// if ((ks = kstat_lookup(ksc, "unix", 0, "system_pages")) == NULL) {
// return -1;
// }
// if (((kid = kstat_read(ksc, ks, NULL)) == -1) ||
// ((knp = kstat_data_lookup(ks, "pp_kernel")) == NULL)) {
// return -1;
// }
// switch (knp->data_type) {
// case KSTAT_DATA_UINT64:
// pp_kernel = knp->value.ui64;
// break;
// case KSTAT_DATA_UINT32:
// pp_kernel = knp->value.ui32;
// break;
// }
// pp_kernel *= sysconf(_SC_PAGESIZE);
// return (pp_kernel > 0 ? pp_kernel : -1);
// }
import "C"
// Get the system memory info using sysconf same as prtconf
func getTotalMem() int64 {
pagesize := C.sysconf(C._SC_PAGESIZE)
npages := C.sysconf(C._SC_PHYS_PAGES)
return int64(pagesize * npages)
}
func getFreeMem() int64 {
pagesize := C.sysconf(C._SC_PAGESIZE)
npages := C.sysconf(C._SC_AVPHYS_PAGES)
return int64(pagesize * npages)
}
// ReadMemInfo retrieves memory statistics of the host system and returns a
// MemInfo type.
func ReadMemInfo() (*MemInfo, error) {
ppKernel := C.getPpKernel()
MemTotal := getTotalMem()
MemFree := getFreeMem()
SwapTotal, SwapFree, err := getSysSwap()
if ppKernel < 0 || MemTotal < 0 || MemFree < 0 || SwapTotal < 0 ||
SwapFree < 0 {
return nil, fmt.Errorf("Error getting system memory info %v\n", err)
}
meminfo := &MemInfo{}
// Total memory is total physical memory less than memory locked by kernel
meminfo.MemTotal = MemTotal - int64(ppKernel)
meminfo.MemFree = MemFree
meminfo.SwapTotal = SwapTotal
meminfo.SwapFree = SwapFree
return meminfo, nil
}
func getSysSwap() (int64, int64, error) {
var tSwap int64
var fSwap int64
var diskblksPerPage int64
num, err := C.swapctl(C.SC_GETNSWP, nil)
if err != nil {
return -1, -1, err
}
st := C.allocSwaptable(num)
_, err = C.swapctl(C.SC_LIST, unsafe.Pointer(st))
if err != nil {
C.freeSwaptable(st)
return -1, -1, err
}
diskblksPerPage = int64(C.sysconf(C._SC_PAGESIZE) >> C.DEV_BSHIFT)
for i := 0; i < int(num); i++ {
swapent := C.getSwapEnt(&st.swt_ent[0], C.int(i))
tSwap += int64(swapent.ste_pages) * diskblksPerPage
fSwap += int64(swapent.ste_free) * diskblksPerPage
}
C.freeSwaptable(st)
return tSwap, fSwap, nil
}

View file

@ -0,0 +1,8 @@
// +build !linux,!windows,!solaris
package system
// ReadMemInfo is not supported on platforms other than linux and windows.
func ReadMemInfo() (*MemInfo, error) {
return nil, ErrNotSupportedPlatform
}

View file

@ -0,0 +1,44 @@
package system
import (
"syscall"
"unsafe"
)
var (
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
procGlobalMemoryStatusEx = modkernel32.NewProc("GlobalMemoryStatusEx")
)
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa366589(v=vs.85).aspx
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa366770(v=vs.85).aspx
type memorystatusex struct {
dwLength uint32
dwMemoryLoad uint32
ullTotalPhys uint64
ullAvailPhys uint64
ullTotalPageFile uint64
ullAvailPageFile uint64
ullTotalVirtual uint64
ullAvailVirtual uint64
ullAvailExtendedVirtual uint64
}
// ReadMemInfo retrieves memory statistics of the host system and returns a
// MemInfo type.
func ReadMemInfo() (*MemInfo, error) {
msi := &memorystatusex{
dwLength: 64,
}
r1, _, _ := procGlobalMemoryStatusEx.Call(uintptr(unsafe.Pointer(msi)))
if r1 == 0 {
return &MemInfo{}, nil
}
return &MemInfo{
MemTotal: int64(msi.ullTotalPhys),
MemFree: int64(msi.ullAvailPhys),
SwapTotal: int64(msi.ullTotalPageFile),
SwapFree: int64(msi.ullAvailPageFile),
}, nil
}

View file

@ -0,0 +1,22 @@
// +build !windows
package system
import (
"syscall"
)
// Mknod creates a filesystem node (file, device special file or named pipe) named path
// with attributes specified by mode and dev.
func Mknod(path string, mode uint32, dev int) error {
return syscall.Mknod(path, mode, dev)
}
// Mkdev is used to build the value of linux devices (in /dev/) which specifies major
// and minor number of the newly created device special file.
// Linux device nodes are a bit weird due to backwards compat with 16 bit device nodes.
// They are, from low to high: the lower 8 bits of the minor, then 12 bits of the major,
// then the top 12 bits of the minor.
func Mkdev(major int64, minor int64) uint32 {
return uint32(((minor & 0xfff00) << 12) | ((major & 0xfff) << 8) | (minor & 0xff))
}

View file

@ -0,0 +1,13 @@
// +build windows
package system
// Mknod is not implemented on Windows.
func Mknod(path string, mode uint32, dev int) error {
return ErrNotSupportedPlatform
}
// Mkdev is not implemented on Windows.
func Mkdev(major int64, minor int64) uint32 {
panic("Mkdev not implemented on Windows.")
}

View file

@ -0,0 +1,14 @@
// +build !windows
package system
// DefaultPathEnv is unix style list of directories to search for
// executables. Each directory is separated from the next by a colon
// ':' character .
const DefaultPathEnv = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
// CheckSystemDriveAndRemoveDriveLetter verifies that a path, if it includes a drive letter,
// is the system drive. This is a no-op on Linux.
func CheckSystemDriveAndRemoveDriveLetter(path string) (string, error) {
return path, nil
}

View file

@ -0,0 +1,37 @@
// +build windows
package system
import (
"fmt"
"path/filepath"
"strings"
)
// DefaultPathEnv is deliberately empty on Windows as the default path will be set by
// the container. Docker has no context of what the default path should be.
const DefaultPathEnv = ""
// CheckSystemDriveAndRemoveDriveLetter verifies and manipulates a Windows path.
// This is used, for example, when validating a user provided path in docker cp.
// If a drive letter is supplied, it must be the system drive. The drive letter
// is always removed. Also, it translates it to OS semantics (IOW / to \). We
// need the path in this syntax so that it can ultimately be contatenated with
// a Windows long-path which doesn't support drive-letters. Examples:
// C: --> Fail
// C:\ --> \
// a --> a
// /a --> \a
// d:\ --> Fail
func CheckSystemDriveAndRemoveDriveLetter(path string) (string, error) {
if len(path) == 2 && string(path[1]) == ":" {
return "", fmt.Errorf("No relative path specified in %q", path)
}
if !filepath.IsAbs(path) || len(path) < 2 {
return filepath.FromSlash(path), nil
}
if string(path[1]) == ":" && !strings.EqualFold(string(path[0]), "c") {
return "", fmt.Errorf("The specified path is not on the system drive (C:)")
}
return filepath.FromSlash(path[2:]), nil
}

View file

@ -0,0 +1,53 @@
// +build !windows
package system
import (
"syscall"
)
// StatT type contains status of a file. It contains metadata
// like permission, owner, group, size, etc about a file.
type StatT struct {
mode uint32
uid uint32
gid uint32
rdev uint64
size int64
mtim syscall.Timespec
}
// Mode returns file's permission mode.
func (s StatT) Mode() uint32 {
return s.mode
}
// UID returns file's user id of owner.
func (s StatT) UID() uint32 {
return s.uid
}
// GID returns file's group id of owner.
func (s StatT) GID() uint32 {
return s.gid
}
// Rdev returns file's device ID (if it's special file).
func (s StatT) Rdev() uint64 {
return s.rdev
}
// Size returns file's size.
func (s StatT) Size() int64 {
return s.size
}
// Mtim returns file's last modification time.
func (s StatT) Mtim() syscall.Timespec {
return s.mtim
}
// GetLastModification returns file's last modification time.
func (s StatT) GetLastModification() syscall.Timespec {
return s.Mtim()
}

View file

@ -0,0 +1,27 @@
package system
import (
"syscall"
)
// fromStatT converts a syscall.Stat_t type to a system.Stat_t type
func fromStatT(s *syscall.Stat_t) (*StatT, error) {
return &StatT{size: s.Size,
mode: uint32(s.Mode),
uid: s.Uid,
gid: s.Gid,
rdev: uint64(s.Rdev),
mtim: s.Mtimespec}, nil
}
// Stat takes a path to a file and returns
// a system.Stat_t type pertaining to that file.
//
// Throws an error if the file does not exist
func Stat(path string) (*StatT, error) {
s := &syscall.Stat_t{}
if err := syscall.Stat(path, s); err != nil {
return nil, err
}
return fromStatT(s)
}

View file

@ -0,0 +1,33 @@
package system
import (
"syscall"
)
// fromStatT converts a syscall.Stat_t type to a system.Stat_t type
func fromStatT(s *syscall.Stat_t) (*StatT, error) {
return &StatT{size: s.Size,
mode: s.Mode,
uid: s.Uid,
gid: s.Gid,
rdev: s.Rdev,
mtim: s.Mtim}, nil
}
// FromStatT exists only on linux, and loads a system.StatT from a
// syscal.Stat_t.
func FromStatT(s *syscall.Stat_t) (*StatT, error) {
return fromStatT(s)
}
// Stat takes a path to a file and returns
// a system.StatT type pertaining to that file.
//
// Throws an error if the file does not exist
func Stat(path string) (*StatT, error) {
s := &syscall.Stat_t{}
if err := syscall.Stat(path, s); err != nil {
return nil, err
}
return fromStatT(s)
}

View file

@ -0,0 +1,15 @@
package system
import (
"syscall"
)
// fromStatT creates a system.StatT type from a syscall.Stat_t type
func fromStatT(s *syscall.Stat_t) (*StatT, error) {
return &StatT{size: s.Size,
mode: uint32(s.Mode),
uid: s.Uid,
gid: s.Gid,
rdev: uint64(s.Rdev),
mtim: s.Mtim}, nil
}

View file

@ -0,0 +1,34 @@
// +build solaris
package system
import (
"syscall"
)
// fromStatT creates a system.StatT type from a syscall.Stat_t type
func fromStatT(s *syscall.Stat_t) (*StatT, error) {
return &StatT{size: s.Size,
mode: uint32(s.Mode),
uid: s.Uid,
gid: s.Gid,
rdev: uint64(s.Rdev),
mtim: s.Mtim}, nil
}
// FromStatT loads a system.StatT from a syscal.Stat_t.
func FromStatT(s *syscall.Stat_t) (*StatT, error) {
return fromStatT(s)
}
// Stat takes a path to a file and returns
// a system.StatT type pertaining to that file.
//
// Throws an error if the file does not exist
func Stat(path string) (*StatT, error) {
s := &syscall.Stat_t{}
if err := syscall.Stat(path, s); err != nil {
return nil, err
}
return fromStatT(s)
}

View file

@ -0,0 +1,17 @@
// +build !linux,!windows,!freebsd,!solaris,!openbsd
package system
import (
"syscall"
)
// fromStatT creates a system.StatT type from a syscall.Stat_t type
func fromStatT(s *syscall.Stat_t) (*StatT, error) {
return &StatT{size: s.Size,
mode: uint32(s.Mode),
uid: s.Uid,
gid: s.Gid,
rdev: uint64(s.Rdev),
mtim: s.Mtimespec}, nil
}

View file

@ -0,0 +1,43 @@
// +build windows
package system
import (
"os"
"time"
)
// StatT type contains status of a file. It contains metadata
// like name, permission, size, etc about a file.
type StatT struct {
name string
size int64
mode os.FileMode
modTime time.Time
isDir bool
}
// Name returns file's name.
func (s StatT) Name() string {
return s.name
}
// Size returns file's size.
func (s StatT) Size() int64 {
return s.size
}
// Mode returns file's permission mode.
func (s StatT) Mode() os.FileMode {
return s.mode
}
// ModTime returns file's last modification time.
func (s StatT) ModTime() time.Time {
return s.modTime
}
// IsDir returns whether file is actually a directory.
func (s StatT) IsDir() bool {
return s.isDir
}

View file

@ -0,0 +1,17 @@
// +build linux freebsd
package system
import "syscall"
// Unmount is a platform-specific helper function to call
// the unmount syscall.
func Unmount(dest string) error {
return syscall.Unmount(dest, 0)
}
// CommandLineToArgv should not be used on Unix.
// It simply returns commandLine in the only element in the returned array.
func CommandLineToArgv(commandLine string) ([]string, error) {
return []string{commandLine}, nil
}

View file

@ -0,0 +1,103 @@
package system
import (
"syscall"
"unsafe"
"github.com/Sirupsen/logrus"
)
var (
ntuserApiset = syscall.NewLazyDLL("ext-ms-win-ntuser-window-l1-1-0")
procGetVersionExW = modkernel32.NewProc("GetVersionExW")
)
// OSVersion is a wrapper for Windows version information
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724439(v=vs.85).aspx
type OSVersion struct {
Version uint32
MajorVersion uint8
MinorVersion uint8
Build uint16
}
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724833(v=vs.85).aspx
type osVersionInfoEx struct {
OSVersionInfoSize uint32
MajorVersion uint32
MinorVersion uint32
BuildNumber uint32
PlatformID uint32
CSDVersion [128]uint16
ServicePackMajor uint16
ServicePackMinor uint16
SuiteMask uint16
ProductType byte
Reserve byte
}
// GetOSVersion gets the operating system version on Windows. Note that
// docker.exe must be manifested to get the correct version information.
func GetOSVersion() OSVersion {
var err error
osv := OSVersion{}
osv.Version, err = syscall.GetVersion()
if err != nil {
// GetVersion never fails.
panic(err)
}
osv.MajorVersion = uint8(osv.Version & 0xFF)
osv.MinorVersion = uint8(osv.Version >> 8 & 0xFF)
osv.Build = uint16(osv.Version >> 16)
return osv
}
// IsWindowsClient returns true if the SKU is client
func IsWindowsClient() bool {
osviex := &osVersionInfoEx{OSVersionInfoSize: 284}
r1, _, err := procGetVersionExW.Call(uintptr(unsafe.Pointer(osviex)))
if r1 == 0 {
logrus.Warnf("GetVersionExW failed - assuming server SKU: %v", err)
return false
}
const verNTWorkstation = 0x00000001
return osviex.ProductType == verNTWorkstation
}
// Unmount is a platform-specific helper function to call
// the unmount syscall. Not supported on Windows
func Unmount(dest string) error {
return nil
}
// CommandLineToArgv wraps the Windows syscall to turn a commandline into an argument array.
func CommandLineToArgv(commandLine string) ([]string, error) {
var argc int32
argsPtr, err := syscall.UTF16PtrFromString(commandLine)
if err != nil {
return nil, err
}
argv, err := syscall.CommandLineToArgv(argsPtr, &argc)
if err != nil {
return nil, err
}
defer syscall.LocalFree(syscall.Handle(uintptr(unsafe.Pointer(argv))))
newArgs := make([]string, argc)
for i, v := range (*argv)[:argc] {
newArgs[i] = string(syscall.UTF16ToString((*v)[:]))
}
return newArgs, nil
}
// HasWin32KSupport determines whether containers that depend on win32k can
// run on this machine. Win32k is the driver used to implement windowing.
func HasWin32KSupport() bool {
// For now, check for ntuser API support on the host. In the future, a host
// may support win32k in containers even if the host does not support ntuser
// APIs.
return ntuserApiset.Load() == nil
}

View file

@ -0,0 +1,13 @@
// +build !windows
package system
import (
"syscall"
)
// Umask sets current process's file mode creation mask to newmask
// and returns oldmask.
func Umask(newmask int) (oldmask int, err error) {
return syscall.Umask(newmask), nil
}

View file

@ -0,0 +1,9 @@
// +build windows
package system
// Umask is not supported on the windows platform.
func Umask(newmask int) (oldmask int, err error) {
// should not be called on cli code path
return 0, ErrNotSupportedPlatform
}

View file

@ -0,0 +1,8 @@
package system
import "syscall"
// LUtimesNano is not supported by darwin platform.
func LUtimesNano(path string, ts []syscall.Timespec) error {
return ErrNotSupportedPlatform
}

View file

@ -0,0 +1,22 @@
package system
import (
"syscall"
"unsafe"
)
// LUtimesNano is used to change access and modification time of the specified path.
// It's used for symbol link file because syscall.UtimesNano doesn't support a NOFOLLOW flag atm.
func LUtimesNano(path string, ts []syscall.Timespec) error {
var _path *byte
_path, err := syscall.BytePtrFromString(path)
if err != nil {
return err
}
if _, _, err := syscall.Syscall(syscall.SYS_LUTIMES, uintptr(unsafe.Pointer(_path)), uintptr(unsafe.Pointer(&ts[0])), 0); err != 0 && err != syscall.ENOSYS {
return err
}
return nil
}

View file

@ -0,0 +1,26 @@
package system
import (
"syscall"
"unsafe"
)
// LUtimesNano is used to change access and modification time of the specified path.
// It's used for symbol link file because syscall.UtimesNano doesn't support a NOFOLLOW flag atm.
func LUtimesNano(path string, ts []syscall.Timespec) error {
// These are not currently available in syscall
atFdCwd := -100
atSymLinkNoFollow := 0x100
var _path *byte
_path, err := syscall.BytePtrFromString(path)
if err != nil {
return err
}
if _, _, err := syscall.Syscall6(syscall.SYS_UTIMENSAT, uintptr(atFdCwd), uintptr(unsafe.Pointer(_path)), uintptr(unsafe.Pointer(&ts[0])), uintptr(atSymLinkNoFollow), 0, 0); err != 0 && err != syscall.ENOSYS {
return err
}
return nil
}

View file

@ -0,0 +1,10 @@
// +build !linux,!freebsd,!darwin
package system
import "syscall"
// LUtimesNano is not supported on platforms other than linux, freebsd and darwin.
func LUtimesNano(path string, ts []syscall.Timespec) error {
return ErrNotSupportedPlatform
}

View file

@ -0,0 +1,63 @@
package system
import (
"syscall"
"unsafe"
)
// Lgetxattr retrieves the value of the extended attribute identified by attr
// and associated with the given path in the file system.
// It will returns a nil slice and nil error if the xattr is not set.
func Lgetxattr(path string, attr string) ([]byte, error) {
pathBytes, err := syscall.BytePtrFromString(path)
if err != nil {
return nil, err
}
attrBytes, err := syscall.BytePtrFromString(attr)
if err != nil {
return nil, err
}
dest := make([]byte, 128)
destBytes := unsafe.Pointer(&dest[0])
sz, _, errno := syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(destBytes), uintptr(len(dest)), 0, 0)
if errno == syscall.ENODATA {
return nil, nil
}
if errno == syscall.ERANGE {
dest = make([]byte, sz)
destBytes := unsafe.Pointer(&dest[0])
sz, _, errno = syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(destBytes), uintptr(len(dest)), 0, 0)
}
if errno != 0 {
return nil, errno
}
return dest[:sz], nil
}
var _zero uintptr
// Lsetxattr sets the value of the extended attribute identified by attr
// and associated with the given path in the file system.
func Lsetxattr(path string, attr string, data []byte, flags int) error {
pathBytes, err := syscall.BytePtrFromString(path)
if err != nil {
return err
}
attrBytes, err := syscall.BytePtrFromString(attr)
if err != nil {
return err
}
var dataBytes unsafe.Pointer
if len(data) > 0 {
dataBytes = unsafe.Pointer(&data[0])
} else {
dataBytes = unsafe.Pointer(&_zero)
}
_, _, errno := syscall.Syscall6(syscall.SYS_LSETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(dataBytes), uintptr(len(data)), uintptr(flags), 0)
if errno != 0 {
return errno
}
return nil
}

View file

@ -0,0 +1,13 @@
// +build !linux
package system
// Lgetxattr is not supported on platforms other than linux.
func Lgetxattr(path string, attr string) ([]byte, error) {
return nil, ErrNotSupportedPlatform
}
// Lsetxattr is not supported on platforms other than linux.
func Lsetxattr(path string, attr string, data []byte, flags int) error {
return ErrNotSupportedPlatform
}