diff options
author | Ian Lance Taylor <iant@golang.org> | 2018-09-24 21:46:21 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2018-09-24 21:46:21 +0000 |
commit | dd931d9b48647e898dc80927c532ae93cc09e192 (patch) | |
tree | 71be2295cd79b8a182f6130611658db8628772d5 /libgo/go/syscall | |
parent | 779d8a5ad09b01428726ea5a0e6c87bd9ac3c0e4 (diff) | |
download | gcc-dd931d9b48647e898dc80927c532ae93cc09e192.zip gcc-dd931d9b48647e898dc80927c532ae93cc09e192.tar.gz gcc-dd931d9b48647e898dc80927c532ae93cc09e192.tar.bz2 |
libgo: update to Go 1.11
Reviewed-on: https://go-review.googlesource.com/136435
gotools/:
* Makefile.am (mostlyclean-local): Run chmod on check-go-dir to
make sure it is writable.
(check-go-tools): Likewise.
(check-vet): Copy internal/objabi to check-vet-dir.
* Makefile.in: Rebuild.
From-SVN: r264546
Diffstat (limited to 'libgo/go/syscall')
31 files changed, 2676 insertions, 30 deletions
diff --git a/libgo/go/syscall/dirent.go b/libgo/go/syscall/dirent.go index a09bf05..5c7af42 100644 --- a/libgo/go/syscall/dirent.go +++ b/libgo/go/syscall/dirent.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build aix darwin dragonfly freebsd linux nacl netbsd openbsd solaris +// +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris package syscall diff --git a/libgo/go/syscall/endian_little.go b/libgo/go/syscall/endian_little.go index a5d32ae..0cd2d75 100644 --- a/libgo/go/syscall/endian_little.go +++ b/libgo/go/syscall/endian_little.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // -// +build 386 alpha amd64 amd64p32 arm arm64 ia64 mips64le mipsle mips64p32le nios2 ppc64le riscv64 sh +// +build 386 alpha amd64 amd64p32 arm arm64 ia64 mips64le mipsle mips64p32le nios2 ppc64le riscv64 sh wasm package syscall diff --git a/libgo/go/syscall/env_unix.go b/libgo/go/syscall/env_unix.go index eb93e2e..0b6b711 100644 --- a/libgo/go/syscall/env_unix.go +++ b/libgo/go/syscall/env_unix.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build aix darwin dragonfly freebsd linux nacl netbsd openbsd solaris +// +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris // Unix environment variables. diff --git a/libgo/go/syscall/env_windows.go b/libgo/go/syscall/env_windows.go index 1606b42..74b154e 100644 --- a/libgo/go/syscall/env_windows.go +++ b/libgo/go/syscall/env_windows.go @@ -57,7 +57,7 @@ func Clearenv() { for _, s := range Environ() { // Environment variables can begin with = // so start looking for the separator = at j=1. - // http://blogs.msdn.com/b/oldnewthing/archive/2010/05/06/10008132.aspx + // https://blogs.msdn.com/b/oldnewthing/archive/2010/05/06/10008132.aspx for j := 1; j < len(s); j++ { if s[j] == '=' { Unsetenv(s[0:j]) diff --git a/libgo/go/syscall/exec_linux_test.go b/libgo/go/syscall/exec_linux_test.go index 17df8f4..f551e87 100644 --- a/libgo/go/syscall/exec_linux_test.go +++ b/libgo/go/syscall/exec_linux_test.go @@ -84,6 +84,15 @@ func checkUserNS(t *testing.T) { t.Skip("kernel doesn't support user namespaces") } } + + // On Centos 7.5+, user namespaces are disabled if user.max_user_namespaces = 0 + if _, err := os.Stat("/proc/sys/user/max_user_namespaces"); err == nil { + buf, errRead := ioutil.ReadFile("/proc/sys/user/max_user_namespaces") + if errRead == nil && buf[0] == '0' { + t.Skip("kernel doesn't support user namespaces") + } + } + // When running under the Go continuous build, skip tests for // now when under Kubernetes. (where things are root but not quite) // Both of these are our own environment variables. diff --git a/libgo/go/syscall/exec_windows.go b/libgo/go/syscall/exec_windows.go index 91b0e84..c78bad8 100644 --- a/libgo/go/syscall/exec_windows.go +++ b/libgo/go/syscall/exec_windows.go @@ -15,7 +15,7 @@ import ( var ForkLock sync.RWMutex // EscapeArg rewrites command line argument s as prescribed -// in http://msdn.microsoft.com/en-us/library/ms880421. +// in https://msdn.microsoft.com/en-us/library/ms880421. // This function returns "" (2 double quotes) if s is empty. // Alternatively, these transformations are done: // - every back slash (\) is doubled, but only if immediately diff --git a/libgo/go/syscall/export_linux_test.go b/libgo/go/syscall/export_linux_test.go new file mode 100644 index 0000000..274849e --- /dev/null +++ b/libgo/go/syscall/export_linux_test.go @@ -0,0 +1,9 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package syscall + +var RawSyscallNoError = rawSyscallNoError + +const Sys_GETEUID = sys_GETEUID diff --git a/libgo/go/syscall/forkpipe_bsd.go b/libgo/go/syscall/forkpipe.go index d479284..71890a2 100644 --- a/libgo/go/syscall/forkpipe_bsd.go +++ b/libgo/go/syscall/forkpipe.go @@ -2,10 +2,11 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build aix darwin dragonfly netbsd openbsd solaris +// +build darwin dragonfly solaris package syscall +// Try to open a pipe with O_CLOEXEC set on both file descriptors. func forkExecPipe(p []int) error { err := Pipe(p) if err != nil { diff --git a/libgo/go/syscall/exec_freebsd.go b/libgo/go/syscall/forkpipe2.go index 1654b4b..c9a0c49 100644 --- a/libgo/go/syscall/exec_freebsd.go +++ b/libgo/go/syscall/forkpipe2.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// +build freebsd netbsd openbsd + package syscall func forkExecPipe(p []int) error { diff --git a/libgo/go/syscall/fs_js.go b/libgo/go/syscall/fs_js.go new file mode 100644 index 0000000..00d6c76 --- /dev/null +++ b/libgo/go/syscall/fs_js.go @@ -0,0 +1,501 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build js,wasm + +package syscall + +import ( + "errors" + "io" + "sync" + "syscall/js" +) + +// Provided by package runtime. +func now() (sec int64, nsec int32) + +var jsProcess = js.Global().Get("process") +var jsFS = js.Global().Get("fs") +var constants = jsFS.Get("constants") + +var ( + nodeWRONLY = constants.Get("O_WRONLY").Int() + nodeRDWR = constants.Get("O_RDWR").Int() + nodeCREATE = constants.Get("O_CREAT").Int() + nodeTRUNC = constants.Get("O_TRUNC").Int() + nodeAPPEND = constants.Get("O_APPEND").Int() + nodeEXCL = constants.Get("O_EXCL").Int() +) + +type jsFile struct { + path string + entries []string + pos int64 + seeked bool +} + +var filesMu sync.Mutex +var files = map[int]*jsFile{ + 0: &jsFile{}, + 1: &jsFile{}, + 2: &jsFile{}, +} + +func fdToFile(fd int) (*jsFile, error) { + filesMu.Lock() + f, ok := files[fd] + filesMu.Unlock() + if !ok { + return nil, EBADF + } + return f, nil +} + +func Open(path string, openmode int, perm uint32) (int, error) { + if err := checkPath(path); err != nil { + return 0, err + } + + flags := 0 + if openmode&O_WRONLY != 0 { + flags |= nodeWRONLY + } + if openmode&O_RDWR != 0 { + flags |= nodeRDWR + } + if openmode&O_CREATE != 0 { + flags |= nodeCREATE + } + if openmode&O_TRUNC != 0 { + flags |= nodeTRUNC + } + if openmode&O_APPEND != 0 { + flags |= nodeAPPEND + } + if openmode&O_EXCL != 0 { + flags |= nodeEXCL + } + if openmode&O_SYNC != 0 { + return 0, errors.New("syscall.Open: O_SYNC is not supported by js/wasm") + } + + jsFD, err := fsCall("openSync", path, flags, perm) + if err != nil { + return 0, err + } + fd := jsFD.Int() + + var entries []string + if stat, err := fsCall("fstatSync", fd); err == nil && stat.Call("isDirectory").Bool() { + dir, err := fsCall("readdirSync", path) + if err != nil { + return 0, err + } + entries = make([]string, dir.Length()) + for i := range entries { + entries[i] = dir.Index(i).String() + } + } + + f := &jsFile{ + path: path, + entries: entries, + } + filesMu.Lock() + files[fd] = f + filesMu.Unlock() + return fd, nil +} + +func Close(fd int) error { + filesMu.Lock() + delete(files, fd) + filesMu.Unlock() + _, err := fsCall("closeSync", fd) + return err +} + +func CloseOnExec(fd int) { + // nothing to do - no exec +} + +func Mkdir(path string, perm uint32) error { + if err := checkPath(path); err != nil { + return err + } + _, err := fsCall("mkdirSync", path, perm) + return err +} + +func ReadDirent(fd int, buf []byte) (int, error) { + f, err := fdToFile(fd) + if err != nil { + return 0, err + } + if f.entries == nil { + return 0, EINVAL + } + + n := 0 + for len(f.entries) > 0 { + entry := f.entries[0] + l := 2 + len(entry) + if l > len(buf) { + break + } + buf[0] = byte(l) + buf[1] = byte(l >> 8) + copy(buf[2:], entry) + buf = buf[l:] + n += l + f.entries = f.entries[1:] + } + + return n, nil +} + +func setStat(st *Stat_t, jsSt js.Value) { + st.Dev = int64(jsSt.Get("dev").Int()) + st.Ino = uint64(jsSt.Get("ino").Int()) + st.Mode = uint32(jsSt.Get("mode").Int()) + st.Nlink = uint32(jsSt.Get("nlink").Int()) + st.Uid = uint32(jsSt.Get("uid").Int()) + st.Gid = uint32(jsSt.Get("gid").Int()) + st.Rdev = int64(jsSt.Get("rdev").Int()) + st.Size = int64(jsSt.Get("size").Int()) + st.Blksize = int32(jsSt.Get("blksize").Int()) + st.Blocks = int32(jsSt.Get("blocks").Int()) + atime := int64(jsSt.Get("atimeMs").Int()) + st.Atime = atime / 1000 + st.AtimeNsec = (atime % 1000) * 1000000 + mtime := int64(jsSt.Get("mtimeMs").Int()) + st.Mtime = mtime / 1000 + st.MtimeNsec = (mtime % 1000) * 1000000 + ctime := int64(jsSt.Get("ctimeMs").Int()) + st.Ctime = ctime / 1000 + st.CtimeNsec = (ctime % 1000) * 1000000 +} + +func Stat(path string, st *Stat_t) error { + if err := checkPath(path); err != nil { + return err + } + jsSt, err := fsCall("statSync", path) + if err != nil { + return err + } + setStat(st, jsSt) + return nil +} + +func Lstat(path string, st *Stat_t) error { + if err := checkPath(path); err != nil { + return err + } + jsSt, err := fsCall("lstatSync", path) + if err != nil { + return err + } + setStat(st, jsSt) + return nil +} + +func Fstat(fd int, st *Stat_t) error { + jsSt, err := fsCall("fstatSync", fd) + if err != nil { + return err + } + setStat(st, jsSt) + return nil +} + +func Unlink(path string) error { + if err := checkPath(path); err != nil { + return err + } + _, err := fsCall("unlinkSync", path) + return err +} + +func Rmdir(path string) error { + if err := checkPath(path); err != nil { + return err + } + _, err := fsCall("rmdirSync", path) + return err +} + +func Chmod(path string, mode uint32) error { + if err := checkPath(path); err != nil { + return err + } + _, err := fsCall("chmodSync", path, mode) + return err +} + +func Fchmod(fd int, mode uint32) error { + _, err := fsCall("fchmodSync", fd, mode) + return err +} + +func Chown(path string, uid, gid int) error { + if err := checkPath(path); err != nil { + return err + } + return ENOSYS +} + +func Fchown(fd int, uid, gid int) error { + return ENOSYS +} + +func Lchown(path string, uid, gid int) error { + if err := checkPath(path); err != nil { + return err + } + return ENOSYS +} + +func UtimesNano(path string, ts []Timespec) error { + if err := checkPath(path); err != nil { + return err + } + if len(ts) != 2 { + return EINVAL + } + atime := ts[0].Sec + mtime := ts[1].Sec + _, err := fsCall("utimesSync", path, atime, mtime) + return err +} + +func Rename(from, to string) error { + if err := checkPath(from); err != nil { + return err + } + if err := checkPath(to); err != nil { + return err + } + _, err := fsCall("renameSync", from, to) + return err +} + +func Truncate(path string, length int64) error { + if err := checkPath(path); err != nil { + return err + } + _, err := fsCall("truncateSync", path, length) + return err +} + +func Ftruncate(fd int, length int64) error { + _, err := fsCall("ftruncateSync", fd, length) + return err +} + +func Getcwd(buf []byte) (n int, err error) { + defer recoverErr(&err) + cwd := jsProcess.Call("cwd").String() + n = copy(buf, cwd) + return n, nil +} + +func Chdir(path string) (err error) { + if err := checkPath(path); err != nil { + return err + } + defer recoverErr(&err) + jsProcess.Call("chdir", path) + return +} + +func Fchdir(fd int) error { + f, err := fdToFile(fd) + if err != nil { + return err + } + return Chdir(f.path) +} + +func Readlink(path string, buf []byte) (n int, err error) { + if err := checkPath(path); err != nil { + return 0, err + } + dst, err := fsCall("readlinkSync", path) + if err != nil { + return 0, err + } + n = copy(buf, dst.String()) + return n, nil +} + +func Link(path, link string) error { + if err := checkPath(path); err != nil { + return err + } + if err := checkPath(link); err != nil { + return err + } + _, err := fsCall("linkSync", path, link) + return err +} + +func Symlink(path, link string) error { + if err := checkPath(path); err != nil { + return err + } + if err := checkPath(link); err != nil { + return err + } + _, err := fsCall("symlinkSync", path, link) + return err +} + +func Fsync(fd int) error { + _, err := fsCall("fsyncSync", fd) + return err +} + +func Read(fd int, b []byte) (int, error) { + f, err := fdToFile(fd) + if err != nil { + return 0, err + } + + if f.seeked { + n, err := Pread(fd, b, f.pos) + f.pos += int64(n) + return n, err + } + + a := js.TypedArrayOf(b) + n, err := fsCall("readSync", fd, a, 0, len(b)) + a.Release() + if err != nil { + return 0, err + } + n2 := n.Int() + f.pos += int64(n2) + return n2, err +} + +func Write(fd int, b []byte) (int, error) { + f, err := fdToFile(fd) + if err != nil { + return 0, err + } + + if f.seeked { + n, err := Pwrite(fd, b, f.pos) + f.pos += int64(n) + return n, err + } + + a := js.TypedArrayOf(b) + n, err := fsCall("writeSync", fd, a, 0, len(b)) + a.Release() + if err != nil { + return 0, err + } + n2 := n.Int() + f.pos += int64(n2) + return n2, err +} + +func Pread(fd int, b []byte, offset int64) (int, error) { + a := js.TypedArrayOf(b) + n, err := fsCall("readSync", fd, a, 0, len(b), offset) + a.Release() + if err != nil { + return 0, err + } + return n.Int(), nil +} + +func Pwrite(fd int, b []byte, offset int64) (int, error) { + a := js.TypedArrayOf(b) + n, err := fsCall("writeSync", fd, a, 0, len(b), offset) + a.Release() + if err != nil { + return 0, err + } + return n.Int(), nil +} + +func Seek(fd int, offset int64, whence int) (int64, error) { + f, err := fdToFile(fd) + if err != nil { + return 0, err + } + + var newPos int64 + switch whence { + case io.SeekStart: + newPos = offset + case io.SeekCurrent: + newPos = f.pos + offset + case io.SeekEnd: + var st Stat_t + if err := Fstat(fd, &st); err != nil { + return 0, err + } + newPos = st.Size + offset + default: + return 0, errnoErr(EINVAL) + } + + if newPos < 0 { + return 0, errnoErr(EINVAL) + } + + f.seeked = true + f.pos = newPos + return newPos, nil +} + +func Dup(fd int) (int, error) { + return 0, ENOSYS +} + +func Dup2(fd, newfd int) error { + return ENOSYS +} + +func Pipe(fd []int) error { + return ENOSYS +} + +func fsCall(name string, args ...interface{}) (res js.Value, err error) { + defer recoverErr(&err) + res = jsFS.Call(name, args...) + return +} + +// checkPath checks that the path is not empty and that it contains no null characters. +func checkPath(path string) error { + if path == "" { + return EINVAL + } + for i := 0; i < len(path); i++ { + if path[i] == '\x00' { + return EINVAL + } + } + return nil +} + +func recoverErr(errPtr *error) { + if err := recover(); err != nil { + jsErr, ok := err.(js.Error) + if !ok { + panic(err) + } + errno, ok := errnoByCode[jsErr.Get("code").String()] + if !ok { + panic(err) + } + *errPtr = errnoErr(Errno(errno)) + } +} diff --git a/libgo/go/syscall/js/callback.go b/libgo/go/syscall/js/callback.go new file mode 100644 index 0000000..9d57307 --- /dev/null +++ b/libgo/go/syscall/js/callback.go @@ -0,0 +1,122 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build js,wasm + +package js + +import "sync" + +var ( + pendingCallbacks = Global().Get("Array").New() + makeCallbackHelper = Global().Get("Go").Get("_makeCallbackHelper") + makeEventCallbackHelper = Global().Get("Go").Get("_makeEventCallbackHelper") +) + +var ( + callbacksMu sync.Mutex + callbacks = make(map[uint32]func([]Value)) + nextCallbackID uint32 = 1 +) + +// Callback is a Go function that got wrapped for use as a JavaScript callback. +type Callback struct { + Value // the JavaScript function that queues the callback for execution + id uint32 +} + +// NewCallback returns a wrapped callback function. +// +// Invoking the callback in JavaScript will queue the Go function fn for execution. +// This execution happens asynchronously on a special goroutine that handles all callbacks and preserves +// the order in which the callbacks got called. +// As a consequence, if one callback blocks this goroutine, other callbacks will not be processed. +// A blocking callback should therefore explicitly start a new goroutine. +// +// Callback.Release must be called to free up resources when the callback will not be used any more. +func NewCallback(fn func(args []Value)) Callback { + callbackLoopOnce.Do(func() { + go callbackLoop() + }) + + callbacksMu.Lock() + id := nextCallbackID + nextCallbackID++ + callbacks[id] = fn + callbacksMu.Unlock() + return Callback{ + Value: makeCallbackHelper.Invoke(id, pendingCallbacks, jsGo), + id: id, + } +} + +type EventCallbackFlag int + +const ( + // PreventDefault can be used with NewEventCallback to call event.preventDefault synchronously. + PreventDefault EventCallbackFlag = 1 << iota + // StopPropagation can be used with NewEventCallback to call event.stopPropagation synchronously. + StopPropagation + // StopImmediatePropagation can be used with NewEventCallback to call event.stopImmediatePropagation synchronously. + StopImmediatePropagation +) + +// NewEventCallback returns a wrapped callback function, just like NewCallback, but the callback expects to have +// exactly one argument, the event. Depending on flags, it will synchronously call event.preventDefault, +// event.stopPropagation and/or event.stopImmediatePropagation before queuing the Go function fn for execution. +func NewEventCallback(flags EventCallbackFlag, fn func(event Value)) Callback { + c := NewCallback(func(args []Value) { + fn(args[0]) + }) + return Callback{ + Value: makeEventCallbackHelper.Invoke( + flags&PreventDefault != 0, + flags&StopPropagation != 0, + flags&StopImmediatePropagation != 0, + c, + ), + id: c.id, + } +} + +// Release frees up resources allocated for the callback. +// The callback must not be invoked after calling Release. +func (c Callback) Release() { + callbacksMu.Lock() + delete(callbacks, c.id) + callbacksMu.Unlock() +} + +var callbackLoopOnce sync.Once + +func callbackLoop() { + for !jsGo.Get("_callbackShutdown").Bool() { + sleepUntilCallback() + for { + cb := pendingCallbacks.Call("shift") + if cb == Undefined() { + break + } + + id := uint32(cb.Get("id").Int()) + callbacksMu.Lock() + f, ok := callbacks[id] + callbacksMu.Unlock() + if !ok { + Global().Get("console").Call("error", "call to closed callback") + continue + } + + argsObj := cb.Get("args") + args := make([]Value, argsObj.Length()) + for i := range args { + args[i] = argsObj.Index(i) + } + f(args) + } + } +} + +// sleepUntilCallback is defined in the runtime package +func sleepUntilCallback() diff --git a/libgo/go/syscall/js/js.go b/libgo/go/syscall/js/js.go new file mode 100644 index 0000000..336586ca --- /dev/null +++ b/libgo/go/syscall/js/js.go @@ -0,0 +1,382 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build js,wasm + +// Package js gives access to the WebAssembly host environment when using the js/wasm architecture. +// Its API is based on JavaScript semantics. +// +// This package is EXPERIMENTAL. Its current scope is only to allow tests to run, but not yet to provide a +// comprehensive API for users. It is exempt from the Go compatibility promise. +package js + +import ( + "unsafe" +) + +// ref is used to identify a JavaScript value, since the value itself can not be passed to WebAssembly. +// A JavaScript number (64-bit float, except NaN) is represented by its IEEE 754 binary representation. +// All other values are represented as an IEEE 754 binary representation of NaN with bits 0-31 used as +// an ID and bits 32-33 used to differentiate between string, symbol, function and object. +type ref uint64 + +// nanHead are the upper 32 bits of a ref which are set if the value is not a JavaScript number or NaN itself. +const nanHead = 0x7FF80000 + +// Value represents a JavaScript value. +type Value struct { + ref ref +} + +func makeValue(v ref) Value { + return Value{ref: v} +} + +func predefValue(id uint32) Value { + return Value{ref: nanHead<<32 | ref(id)} +} + +func floatValue(f float64) Value { + if f != f { + return valueNaN + } + return Value{ref: *(*ref)(unsafe.Pointer(&f))} +} + +// Error wraps a JavaScript error. +type Error struct { + // Value is the underlying JavaScript error value. + Value +} + +// Error implements the error interface. +func (e Error) Error() string { + return "JavaScript error: " + e.Get("message").String() +} + +var ( + valueNaN = predefValue(0) + valueUndefined = predefValue(1) + valueNull = predefValue(2) + valueTrue = predefValue(3) + valueFalse = predefValue(4) + valueGlobal = predefValue(5) + memory = predefValue(6) // WebAssembly linear memory + jsGo = predefValue(7) // instance of the Go class in JavaScript + + objectConstructor = valueGlobal.Get("Object") + arrayConstructor = valueGlobal.Get("Array") +) + +// Undefined returns the JavaScript value "undefined". +func Undefined() Value { + return valueUndefined +} + +// Null returns the JavaScript value "null". +func Null() Value { + return valueNull +} + +// Global returns the JavaScript global object, usually "window" or "global". +func Global() Value { + return valueGlobal +} + +// ValueOf returns x as a JavaScript value: +// +// | Go | JavaScript | +// | ---------------------- | ---------------------- | +// | js.Value | [its value] | +// | js.TypedArray | typed array | +// | js.Callback | function | +// | nil | null | +// | bool | boolean | +// | integers and floats | number | +// | string | string | +// | []interface{} | new array | +// | map[string]interface{} | new object | +func ValueOf(x interface{}) Value { + switch x := x.(type) { + case Value: + return x + case TypedArray: + return x.Value + case Callback: + return x.Value + case nil: + return valueNull + case bool: + if x { + return valueTrue + } else { + return valueFalse + } + case int: + return floatValue(float64(x)) + case int8: + return floatValue(float64(x)) + case int16: + return floatValue(float64(x)) + case int32: + return floatValue(float64(x)) + case int64: + return floatValue(float64(x)) + case uint: + return floatValue(float64(x)) + case uint8: + return floatValue(float64(x)) + case uint16: + return floatValue(float64(x)) + case uint32: + return floatValue(float64(x)) + case uint64: + return floatValue(float64(x)) + case uintptr: + return floatValue(float64(x)) + case unsafe.Pointer: + return floatValue(float64(uintptr(x))) + case float32: + return floatValue(float64(x)) + case float64: + return floatValue(x) + case string: + return makeValue(stringVal(x)) + case []interface{}: + a := arrayConstructor.New(len(x)) + for i, s := range x { + a.SetIndex(i, s) + } + return a + case map[string]interface{}: + o := objectConstructor.New() + for k, v := range x { + o.Set(k, v) + } + return o + default: + panic("ValueOf: invalid value") + } +} + +func stringVal(x string) ref + +// Type represents the JavaScript type of a Value. +type Type int + +const ( + TypeUndefined Type = iota + TypeNull + TypeBoolean + TypeNumber + TypeString + TypeSymbol + TypeObject + TypeFunction +) + +func (t Type) String() string { + switch t { + case TypeUndefined: + return "undefined" + case TypeNull: + return "null" + case TypeBoolean: + return "boolean" + case TypeNumber: + return "number" + case TypeString: + return "string" + case TypeSymbol: + return "symbol" + case TypeObject: + return "object" + case TypeFunction: + return "function" + default: + panic("bad type") + } +} + +// Type returns the JavaScript type of the value v. It is similar to JavaScript's typeof operator, +// except that it returns TypeNull instead of TypeObject for null. +func (v Value) Type() Type { + switch v.ref { + case valueUndefined.ref: + return TypeUndefined + case valueNull.ref: + return TypeNull + case valueTrue.ref, valueFalse.ref: + return TypeBoolean + } + if v.isNumber() { + return TypeNumber + } + typeFlag := v.ref >> 32 & 3 + switch typeFlag { + case 1: + return TypeString + case 2: + return TypeSymbol + case 3: + return TypeFunction + default: + return TypeObject + } +} + +// Get returns the JavaScript property p of value v. +func (v Value) Get(p string) Value { + return makeValue(valueGet(v.ref, p)) +} + +func valueGet(v ref, p string) ref + +// Set sets the JavaScript property p of value v to ValueOf(x). +func (v Value) Set(p string, x interface{}) { + valueSet(v.ref, p, ValueOf(x).ref) +} + +func valueSet(v ref, p string, x ref) + +// Index returns JavaScript index i of value v. +func (v Value) Index(i int) Value { + return makeValue(valueIndex(v.ref, i)) +} + +func valueIndex(v ref, i int) ref + +// SetIndex sets the JavaScript index i of value v to ValueOf(x). +func (v Value) SetIndex(i int, x interface{}) { + valueSetIndex(v.ref, i, ValueOf(x).ref) +} + +func valueSetIndex(v ref, i int, x ref) + +func makeArgs(args []interface{}) []ref { + argVals := make([]ref, len(args)) + for i, arg := range args { + argVals[i] = ValueOf(arg).ref + } + return argVals +} + +// Length returns the JavaScript property "length" of v. +func (v Value) Length() int { + return valueLength(v.ref) +} + +func valueLength(v ref) int + +// Call does a JavaScript call to the method m of value v with the given arguments. +// It panics if v has no method m. +// The arguments get mapped to JavaScript values according to the ValueOf function. +func (v Value) Call(m string, args ...interface{}) Value { + res, ok := valueCall(v.ref, m, makeArgs(args)) + if !ok { + if vType := v.Type(); vType != TypeObject && vType != TypeFunction { // check here to avoid overhead in success case + panic(&ValueError{"Value.Call", vType}) + } + if propType := v.Get(m).Type(); propType != TypeFunction { + panic("syscall/js: Value.Call: property " + m + " is not a function, got " + propType.String()) + } + panic(Error{makeValue(res)}) + } + return makeValue(res) +} + +func valueCall(v ref, m string, args []ref) (ref, bool) + +// Invoke does a JavaScript call of the value v with the given arguments. +// It panics if v is not a function. +// The arguments get mapped to JavaScript values according to the ValueOf function. +func (v Value) Invoke(args ...interface{}) Value { + res, ok := valueInvoke(v.ref, makeArgs(args)) + if !ok { + if vType := v.Type(); vType != TypeFunction { // check here to avoid overhead in success case + panic(&ValueError{"Value.Invoke", vType}) + } + panic(Error{makeValue(res)}) + } + return makeValue(res) +} + +func valueInvoke(v ref, args []ref) (ref, bool) + +// New uses JavaScript's "new" operator with value v as constructor and the given arguments. +// It panics if v is not a function. +// The arguments get mapped to JavaScript values according to the ValueOf function. +func (v Value) New(args ...interface{}) Value { + res, ok := valueNew(v.ref, makeArgs(args)) + if !ok { + panic(Error{makeValue(res)}) + } + return makeValue(res) +} + +func valueNew(v ref, args []ref) (ref, bool) + +func (v Value) isNumber() bool { + return v.ref>>32&nanHead != nanHead || v.ref == valueNaN.ref +} + +func (v Value) float(method string) float64 { + if !v.isNumber() { + panic(&ValueError{method, v.Type()}) + } + return *(*float64)(unsafe.Pointer(&v.ref)) +} + +// Float returns the value v as a float64. It panics if v is not a JavaScript number. +func (v Value) Float() float64 { + return v.float("Value.Float") +} + +// Int returns the value v truncated to an int. It panics if v is not a JavaScript number. +func (v Value) Int() int { + return int(v.float("Value.Int")) +} + +// Bool returns the value v as a bool. It panics if v is not a JavaScript boolean. +func (v Value) Bool() bool { + switch v.ref { + case valueTrue.ref: + return true + case valueFalse.ref: + return false + default: + panic(&ValueError{"Value.Bool", v.Type()}) + } +} + +// String returns the value v converted to string according to JavaScript type conversions. +func (v Value) String() string { + str, length := valuePrepareString(v.ref) + b := make([]byte, length) + valueLoadString(str, b) + return string(b) +} + +func valuePrepareString(v ref) (ref, int) + +func valueLoadString(v ref, b []byte) + +// InstanceOf reports whether v is an instance of type t according to JavaScript's instanceof operator. +func (v Value) InstanceOf(t Value) bool { + return valueInstanceOf(v.ref, t.ref) +} + +func valueInstanceOf(v ref, t ref) bool + +// A ValueError occurs when a Value method is invoked on +// a Value that does not support it. Such cases are documented +// in the description of each method. +type ValueError struct { + Method string + Type Type +} + +func (e *ValueError) Error() string { + return "syscall/js: call of " + e.Method + " on " + e.Type.String() +} diff --git a/libgo/go/syscall/js/js_test.go b/libgo/go/syscall/js/js_test.go new file mode 100644 index 0000000..9cc931a --- /dev/null +++ b/libgo/go/syscall/js/js_test.go @@ -0,0 +1,319 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build js,wasm + +package js_test + +import ( + "fmt" + "math" + "syscall/js" + "testing" +) + +var dummys = js.Global().Call("eval", `({ + someBool: true, + someString: "abc\u1234", + someInt: 42, + someFloat: 42.123, + someArray: [41, 42, 43], + add: function(a, b) { + return a + b; + }, + NaN: NaN, +})`) + +func TestBool(t *testing.T) { + want := true + o := dummys.Get("someBool") + if got := o.Bool(); got != want { + t.Errorf("got %#v, want %#v", got, want) + } + dummys.Set("otherBool", want) + if got := dummys.Get("otherBool").Bool(); got != want { + t.Errorf("got %#v, want %#v", got, want) + } + if dummys.Get("someBool") != dummys.Get("someBool") { + t.Errorf("same value not equal") + } +} + +func TestString(t *testing.T) { + want := "abc\u1234" + o := dummys.Get("someString") + if got := o.String(); got != want { + t.Errorf("got %#v, want %#v", got, want) + } + dummys.Set("otherString", want) + if got := dummys.Get("otherString").String(); got != want { + t.Errorf("got %#v, want %#v", got, want) + } + if dummys.Get("someString") != dummys.Get("someString") { + t.Errorf("same value not equal") + } + + wantInt := "42" + o = dummys.Get("someInt") + if got := o.String(); got != wantInt { + t.Errorf("got %#v, want %#v", got, wantInt) + } +} + +func TestInt(t *testing.T) { + want := 42 + o := dummys.Get("someInt") + if got := o.Int(); got != want { + t.Errorf("got %#v, want %#v", got, want) + } + dummys.Set("otherInt", want) + if got := dummys.Get("otherInt").Int(); got != want { + t.Errorf("got %#v, want %#v", got, want) + } + if dummys.Get("someInt") != dummys.Get("someInt") { + t.Errorf("same value not equal") + } +} + +func TestIntConversion(t *testing.T) { + testIntConversion(t, 0) + testIntConversion(t, 1) + testIntConversion(t, -1) + testIntConversion(t, 1<<20) + testIntConversion(t, -1<<20) + testIntConversion(t, 1<<40) + testIntConversion(t, -1<<40) + testIntConversion(t, 1<<60) + testIntConversion(t, -1<<60) +} + +func testIntConversion(t *testing.T, want int) { + if got := js.ValueOf(want).Int(); got != want { + t.Errorf("got %#v, want %#v", got, want) + } +} + +func TestFloat(t *testing.T) { + want := 42.123 + o := dummys.Get("someFloat") + if got := o.Float(); got != want { + t.Errorf("got %#v, want %#v", got, want) + } + dummys.Set("otherFloat", want) + if got := dummys.Get("otherFloat").Float(); got != want { + t.Errorf("got %#v, want %#v", got, want) + } + if dummys.Get("someFloat") != dummys.Get("someFloat") { + t.Errorf("same value not equal") + } +} + +func TestObject(t *testing.T) { + if dummys.Get("someArray") != dummys.Get("someArray") { + t.Errorf("same value not equal") + } + + // An object and its prototype should not be equal. + proto := js.Global().Get("Object").Get("prototype") + o := js.Global().Call("eval", "new Object()") + if proto == o { + t.Errorf("object equals to its prototype") + } +} + +func TestFrozenObject(t *testing.T) { + o := js.Global().Call("eval", "(function () { let o = new Object(); o.field = 5; Object.freeze(o); return o; })()") + want := 5 + if got := o.Get("field").Int(); want != got { + t.Errorf("got %#v, want %#v", got, want) + } +} + +func TestTypedArrayOf(t *testing.T) { + testTypedArrayOf(t, "[]int8", []int8{0, -42, 0}, -42) + testTypedArrayOf(t, "[]int16", []int16{0, -42, 0}, -42) + testTypedArrayOf(t, "[]int32", []int32{0, -42, 0}, -42) + testTypedArrayOf(t, "[]uint8", []uint8{0, 42, 0}, 42) + testTypedArrayOf(t, "[]uint16", []uint16{0, 42, 0}, 42) + testTypedArrayOf(t, "[]uint32", []uint32{0, 42, 0}, 42) + testTypedArrayOf(t, "[]float32", []float32{0, -42.5, 0}, -42.5) + testTypedArrayOf(t, "[]float64", []float64{0, -42.5, 0}, -42.5) +} + +func testTypedArrayOf(t *testing.T, name string, slice interface{}, want float64) { + t.Run(name, func(t *testing.T) { + a := js.TypedArrayOf(slice) + got := a.Index(1).Float() + a.Release() + if got != want { + t.Errorf("got %#v, want %#v", got, want) + } + }) +} + +func TestNaN(t *testing.T) { + want := js.ValueOf(math.NaN()) + got := dummys.Get("NaN") + if got != want { + t.Errorf("got %#v, want %#v", got, want) + } +} + +func TestUndefined(t *testing.T) { + dummys.Set("test", js.Undefined()) + if dummys == js.Undefined() || dummys.Get("test") != js.Undefined() || dummys.Get("xyz") != js.Undefined() { + t.Errorf("js.Undefined expected") + } +} + +func TestNull(t *testing.T) { + dummys.Set("test1", nil) + dummys.Set("test2", js.Null()) + if dummys == js.Null() || dummys.Get("test1") != js.Null() || dummys.Get("test2") != js.Null() { + t.Errorf("js.Null expected") + } +} + +func TestLength(t *testing.T) { + if got := dummys.Get("someArray").Length(); got != 3 { + t.Errorf("got %#v, want %#v", got, 3) + } +} + +func TestIndex(t *testing.T) { + if got := dummys.Get("someArray").Index(1).Int(); got != 42 { + t.Errorf("got %#v, want %#v", got, 42) + } +} + +func TestSetIndex(t *testing.T) { + dummys.Get("someArray").SetIndex(2, 99) + if got := dummys.Get("someArray").Index(2).Int(); got != 99 { + t.Errorf("got %#v, want %#v", got, 99) + } +} + +func TestCall(t *testing.T) { + var i int64 = 40 + if got := dummys.Call("add", i, 2).Int(); got != 42 { + t.Errorf("got %#v, want %#v", got, 42) + } + if got := dummys.Call("add", js.Global().Call("eval", "40"), 2).Int(); got != 42 { + t.Errorf("got %#v, want %#v", got, 42) + } +} + +func TestInvoke(t *testing.T) { + var i int64 = 40 + if got := dummys.Get("add").Invoke(i, 2).Int(); got != 42 { + t.Errorf("got %#v, want %#v", got, 42) + } +} + +func TestNew(t *testing.T) { + if got := js.Global().Get("Array").New(42).Length(); got != 42 { + t.Errorf("got %#v, want %#v", got, 42) + } +} + +func TestInstanceOf(t *testing.T) { + someArray := js.Global().Get("Array").New() + if got, want := someArray.InstanceOf(js.Global().Get("Array")), true; got != want { + t.Errorf("got %#v, want %#v", got, want) + } + if got, want := someArray.InstanceOf(js.Global().Get("Function")), false; got != want { + t.Errorf("got %#v, want %#v", got, want) + } +} + +func TestType(t *testing.T) { + if got, want := js.Undefined().Type(), js.TypeUndefined; got != want { + t.Errorf("got %s, want %s", got, want) + } + if got, want := js.Null().Type(), js.TypeNull; got != want { + t.Errorf("got %s, want %s", got, want) + } + if got, want := js.ValueOf(true).Type(), js.TypeBoolean; got != want { + t.Errorf("got %s, want %s", got, want) + } + if got, want := js.ValueOf(42).Type(), js.TypeNumber; got != want { + t.Errorf("got %s, want %s", got, want) + } + if got, want := js.ValueOf("test").Type(), js.TypeString; got != want { + t.Errorf("got %s, want %s", got, want) + } + if got, want := js.Global().Get("Symbol").Invoke("test").Type(), js.TypeSymbol; got != want { + t.Errorf("got %s, want %s", got, want) + } + if got, want := js.Global().Get("Array").New().Type(), js.TypeObject; got != want { + t.Errorf("got %s, want %s", got, want) + } + if got, want := js.Global().Get("Array").Type(), js.TypeFunction; got != want { + t.Errorf("got %s, want %s", got, want) + } +} + +type object = map[string]interface{} +type array = []interface{} + +func TestValueOf(t *testing.T) { + a := js.ValueOf(array{0, array{0, 42, 0}, 0}) + if got := a.Index(1).Index(1).Int(); got != 42 { + t.Errorf("got %v, want %v", got, 42) + } + + o := js.ValueOf(object{"x": object{"y": 42}}) + if got := o.Get("x").Get("y").Int(); got != 42 { + t.Errorf("got %v, want %v", got, 42) + } +} + +func TestCallback(t *testing.T) { + c := make(chan struct{}) + cb := js.NewCallback(func(args []js.Value) { + if got := args[0].Int(); got != 42 { + t.Errorf("got %#v, want %#v", got, 42) + } + c <- struct{}{} + }) + defer cb.Release() + js.Global().Call("setTimeout", cb, 0, 42) + <-c +} + +func TestEventCallback(t *testing.T) { + for _, name := range []string{"preventDefault", "stopPropagation", "stopImmediatePropagation"} { + c := make(chan struct{}) + var flags js.EventCallbackFlag + switch name { + case "preventDefault": + flags = js.PreventDefault + case "stopPropagation": + flags = js.StopPropagation + case "stopImmediatePropagation": + flags = js.StopImmediatePropagation + } + cb := js.NewEventCallback(flags, func(event js.Value) { + c <- struct{}{} + }) + defer cb.Release() + + event := js.Global().Call("eval", fmt.Sprintf("({ called: false, %s: function() { this.called = true; } })", name)) + cb.Invoke(event) + if !event.Get("called").Bool() { + t.Errorf("%s not called", name) + } + + <-c + } +} + +func ExampleNewCallback() { + var cb js.Callback + cb = js.NewCallback(func(args []js.Value) { + fmt.Println("button clicked") + cb.Release() // release the callback if the button will not be clicked again + }) + js.Global().Get("document").Call("getElementById", "myButton").Call("addEventListener", "click", cb) +} diff --git a/libgo/go/syscall/js/typedarray.go b/libgo/go/syscall/js/typedarray.go new file mode 100644 index 0000000..afa1548 --- /dev/null +++ b/libgo/go/syscall/js/typedarray.go @@ -0,0 +1,102 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build js,wasm + +package js + +import ( + "sync" + "unsafe" +) + +var ( + int8Array = Global().Get("Int8Array") + int16Array = Global().Get("Int16Array") + int32Array = Global().Get("Int32Array") + uint8Array = Global().Get("Uint8Array") + uint16Array = Global().Get("Uint16Array") + uint32Array = Global().Get("Uint32Array") + float32Array = Global().Get("Float32Array") + float64Array = Global().Get("Float64Array") +) + +// TypedArray represents a JavaScript typed array. +type TypedArray struct { + Value +} + +// Release frees up resources allocated for the typed array. +// The typed array and its buffer must not be accessed after calling Release. +func (a TypedArray) Release() { + openTypedArraysMutex.Lock() + delete(openTypedArrays, a) + openTypedArraysMutex.Unlock() +} + +var ( + openTypedArraysMutex sync.Mutex + openTypedArrays = make(map[TypedArray]interface{}) +) + +// TypedArrayOf returns a JavaScript typed array backed by the slice's underlying array. +// +// The supported types are []int8, []int16, []int32, []uint8, []uint16, []uint32, []float32 and []float64. +// Passing an unsupported value causes a panic. +// +// TypedArray.Release must be called to free up resources when the typed array will not be used any more. +func TypedArrayOf(slice interface{}) TypedArray { + a := TypedArray{typedArrayOf(slice)} + openTypedArraysMutex.Lock() + openTypedArrays[a] = slice + openTypedArraysMutex.Unlock() + return a +} + +func typedArrayOf(slice interface{}) Value { + switch slice := slice.(type) { + case []int8: + if len(slice) == 0 { + return int8Array.New(memory.Get("buffer"), 0, 0) + } + return int8Array.New(memory.Get("buffer"), unsafe.Pointer(&slice[0]), len(slice)) + case []int16: + if len(slice) == 0 { + return int16Array.New(memory.Get("buffer"), 0, 0) + } + return int16Array.New(memory.Get("buffer"), unsafe.Pointer(&slice[0]), len(slice)) + case []int32: + if len(slice) == 0 { + return int32Array.New(memory.Get("buffer"), 0, 0) + } + return int32Array.New(memory.Get("buffer"), unsafe.Pointer(&slice[0]), len(slice)) + case []uint8: + if len(slice) == 0 { + return uint8Array.New(memory.Get("buffer"), 0, 0) + } + return uint8Array.New(memory.Get("buffer"), unsafe.Pointer(&slice[0]), len(slice)) + case []uint16: + if len(slice) == 0 { + return uint16Array.New(memory.Get("buffer"), 0, 0) + } + return uint16Array.New(memory.Get("buffer"), unsafe.Pointer(&slice[0]), len(slice)) + case []uint32: + if len(slice) == 0 { + return uint32Array.New(memory.Get("buffer"), 0, 0) + } + return uint32Array.New(memory.Get("buffer"), unsafe.Pointer(&slice[0]), len(slice)) + case []float32: + if len(slice) == 0 { + return float32Array.New(memory.Get("buffer"), 0, 0) + } + return float32Array.New(memory.Get("buffer"), unsafe.Pointer(&slice[0]), len(slice)) + case []float64: + if len(slice) == 0 { + return float64Array.New(memory.Get("buffer"), 0, 0) + } + return float64Array.New(memory.Get("buffer"), unsafe.Pointer(&slice[0]), len(slice)) + default: + panic("TypedArrayOf: not a supported slice") + } +} diff --git a/libgo/go/syscall/libcall_linux.go b/libgo/go/syscall/libcall_linux.go index 5f47784..7903328 100644 --- a/libgo/go/syscall/libcall_linux.go +++ b/libgo/go/syscall/libcall_linux.go @@ -238,15 +238,6 @@ func Getdents(fd int, buf []byte) (n int, err error) { return } -func clen(n []byte) int { - for i := 0; i < len(n); i++ { - if n[i] == 0 { - return i - } - } - return len(n) -} - func ReadDirent(fd int, buf []byte) (n int, err error) { return Getdents(fd, buf) } diff --git a/libgo/go/syscall/net_js.go b/libgo/go/syscall/net_js.go new file mode 100644 index 0000000..d5bf1f4 --- /dev/null +++ b/libgo/go/syscall/net_js.go @@ -0,0 +1,128 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// js/wasm uses fake networking directly implemented in the net package. +// This file only exists to make the compiler happy. + +// +build js,wasm + +package syscall + +const ( + AF_UNSPEC = iota + AF_UNIX + AF_INET + AF_INET6 +) + +const ( + SOCK_STREAM = 1 + iota + SOCK_DGRAM + SOCK_RAW + SOCK_SEQPACKET +) + +const ( + IPPROTO_IP = 0 + IPPROTO_IPV4 = 4 + IPPROTO_IPV6 = 0x29 + IPPROTO_TCP = 6 + IPPROTO_UDP = 0x11 +) + +const ( + _ = iota + IPV6_V6ONLY + SOMAXCONN + SO_ERROR +) + +// Misc constants expected by package net but not supported. +const ( + _ = iota + F_DUPFD_CLOEXEC + SYS_FCNTL = 500 // unsupported; same value as net_nacl.go +) + +type Sockaddr interface { +} + +type SockaddrInet4 struct { + Port int + Addr [4]byte +} + +type SockaddrInet6 struct { + Port int + ZoneId uint32 + Addr [16]byte +} + +type SockaddrUnix struct { + Name string +} + +func Socket(proto, sotype, unused int) (fd int, err error) { + return 0, ENOSYS +} + +func Bind(fd int, sa Sockaddr) error { + return ENOSYS +} + +func StopIO(fd int) error { + return ENOSYS +} + +func Listen(fd int, backlog int) error { + return ENOSYS +} + +func Accept(fd int) (newfd int, sa Sockaddr, err error) { + return 0, nil, ENOSYS +} + +func Connect(fd int, sa Sockaddr) error { + return ENOSYS +} + +func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, err error) { + return 0, nil, ENOSYS +} + +func Sendto(fd int, p []byte, flags int, to Sockaddr) error { + return ENOSYS +} + +func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn, recvflags int, from Sockaddr, err error) { + return 0, 0, 0, nil, ENOSYS +} + +func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) { + return 0, ENOSYS +} + +func GetsockoptInt(fd, level, opt int) (value int, err error) { + return 0, ENOSYS +} + +func SetsockoptInt(fd, level, opt int, value int) error { + return nil +} + +func SetReadDeadline(fd int, t int64) error { + return ENOSYS +} + +func SetWriteDeadline(fd int, t int64) error { + return ENOSYS +} + +func Shutdown(fd int, how int) error { + return ENOSYS +} + +func SetNonblock(fd int, nonblocking bool) error { + return nil +} diff --git a/libgo/go/syscall/pwd_plan9.go b/libgo/go/syscall/pwd_plan9.go index 1248613..1deeaa9 100644 --- a/libgo/go/syscall/pwd_plan9.go +++ b/libgo/go/syscall/pwd_plan9.go @@ -39,6 +39,15 @@ func fixwdLocked() { } } +func fixwd(paths ...string) { + for _, path := range paths { + if path != "" && path[0] != '/' && path[0] != '#' { + Fixwd() + return + } + } +} + // goroutine-specific getwd func getwd() (wd string, err error) { fd, err := open(".", O_RDONLY) @@ -66,6 +75,7 @@ func Getwd() (wd string, err error) { } func Chdir(path string) error { + fixwd(path) wdmu.Lock() defer wdmu.Unlock() diff --git a/libgo/go/syscall/route_freebsd_32bit.go b/libgo/go/syscall/route_freebsd_32bit.go index 5c10b05..ec6f6b7 100644 --- a/libgo/go/syscall/route_freebsd_32bit.go +++ b/libgo/go/syscall/route_freebsd_32bit.go @@ -21,7 +21,7 @@ func (any *anyMessage) parseInterfaceMessage(b []byte) *InterfaceMessage { p := (*InterfaceMessage)(unsafe.Pointer(any)) // FreeBSD 10 and beyond have a restructured mbuf // packet header view. - // See http://svnweb.freebsd.org/base?view=revision&revision=254804. + // See https://svnweb.freebsd.org/base?view=revision&revision=254804. if freebsdVersion >= 1000000 { m := (*ifMsghdr)(unsafe.Pointer(any)) p.Header.Data.Hwassist = uint32(m.Data.Hwassist) diff --git a/libgo/go/syscall/security_windows.go b/libgo/go/syscall/security_windows.go index e2a9dc5..ae8b3a1 100644 --- a/libgo/go/syscall/security_windows.go +++ b/libgo/go/syscall/security_windows.go @@ -30,7 +30,7 @@ const ( ) // This function returns 1 byte BOOLEAN rather than the 4 byte BOOL. -// http://blogs.msdn.com/b/drnick/archive/2007/12/19/windows-and-upn-format-credentials.aspx +// https://blogs.msdn.com/b/drnick/archive/2007/12/19/windows-and-upn-format-credentials.aspx //sys TranslateName(accName *uint16, accNameFormat uint32, desiredNameFormat uint32, translatedName *uint16, nSize *uint32) (err error) [failretval&0xff==0] = secur32.TranslateNameW //sys GetUserNameEx(nameFormat uint32, nameBuffre *uint16, nSize *uint32) (err error) [failretval&0xff==0] = secur32.GetUserNameExW @@ -221,6 +221,7 @@ const ( TOKEN_ADJUST_PRIVILEGES TOKEN_ADJUST_GROUPS TOKEN_ADJUST_DEFAULT + TOKEN_ADJUST_SESSIONID TOKEN_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY | @@ -230,7 +231,8 @@ const ( TOKEN_QUERY_SOURCE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | - TOKEN_ADJUST_DEFAULT + TOKEN_ADJUST_DEFAULT | + TOKEN_ADJUST_SESSIONID TOKEN_READ = STANDARD_RIGHTS_READ | TOKEN_QUERY TOKEN_WRITE = STANDARD_RIGHTS_WRITE | TOKEN_ADJUST_PRIVILEGES | diff --git a/libgo/go/syscall/setuidgid_32_linux.go b/libgo/go/syscall/setuidgid_32_linux.go index 182f5d2..1fe7120 100644 --- a/libgo/go/syscall/setuidgid_32_linux.go +++ b/libgo/go/syscall/setuidgid_32_linux.go @@ -8,6 +8,8 @@ package syscall const ( + sys_GETEUID = SYS_GETEUID32 + sys_SETGID = SYS_SETGID32 sys_SETUID = SYS_SETUID32 ) diff --git a/libgo/go/syscall/setuidgid_linux.go b/libgo/go/syscall/setuidgid_linux.go index bf40d2d..22fa334 100644 --- a/libgo/go/syscall/setuidgid_linux.go +++ b/libgo/go/syscall/setuidgid_linux.go @@ -8,6 +8,8 @@ package syscall const ( + sys_GETEUID = SYS_GETEUID + sys_SETGID = SYS_SETGID sys_SETUID = SYS_SETUID ) diff --git a/libgo/go/syscall/syscall.go b/libgo/go/syscall/syscall.go index 8e785dd..9b74afe 100644 --- a/libgo/go/syscall/syscall.go +++ b/libgo/go/syscall/syscall.go @@ -18,14 +18,11 @@ // err is an operating system error describing the failure. // On most systems, that error has type syscall.Errno. // -// NOTE: This package is locked down. Code outside the standard -// Go repository should be migrated to use the corresponding -// package in the golang.org/x/sys repository. That is also where updates -// required by new systems or versions should be applied. -// Signal, Errno and SysProcAttr are not yet available in -// golang.org/x/sys and must still be referenced from the -// syscall package. See https://golang.org/s/go1.4-syscall -// for more information. +// Deprecated: this package is locked down. Callers should use the +// corresponding package in the golang.org/x/sys repository instead. +// That is also where updates required by new systems or versions +// should be applied. See https://golang.org/s/go1.4-syscall for more +// information. // package syscall diff --git a/libgo/go/syscall/syscall_errno.go b/libgo/go/syscall/syscall_errno.go index 01618d1..810572f 100644 --- a/libgo/go/syscall/syscall_errno.go +++ b/libgo/go/syscall/syscall_errno.go @@ -18,7 +18,7 @@ func (e Errno) Error() string { } func (e Errno) Temporary() bool { - return e == EINTR || e == EMFILE || e == ECONNRESET || e == ECONNABORTED || e.Timeout() + return e == EINTR || e == EMFILE || e.Timeout() } func (e Errno) Timeout() bool { diff --git a/libgo/go/syscall/syscall_js.go b/libgo/go/syscall/syscall_js.go new file mode 100644 index 0000000..6822eec --- /dev/null +++ b/libgo/go/syscall/syscall_js.go @@ -0,0 +1,307 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build js,wasm + +package syscall + +import ( + "sync" + "unsafe" +) + +const direntSize = 8 + 8 + 2 + 256 + +type Dirent struct { + Reclen uint16 + Name [256]byte +} + +func direntIno(buf []byte) (uint64, bool) { + return 1, true +} + +func direntReclen(buf []byte) (uint64, bool) { + return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen)) +} + +func direntNamlen(buf []byte) (uint64, bool) { + reclen, ok := direntReclen(buf) + if !ok { + return 0, false + } + return reclen - uint64(unsafe.Offsetof(Dirent{}.Name)), true +} + +const PathMax = 256 + +// An Errno is an unsigned number describing an error condition. +// It implements the error interface. The zero Errno is by convention +// a non-error, so code to convert from Errno to error should use: +// err = nil +// if errno != 0 { +// err = errno +// } +type Errno uintptr + +func (e Errno) Error() string { + if 0 <= int(e) && int(e) < len(errorstr) { + s := errorstr[e] + if s != "" { + return s + } + } + return "errno " + itoa(int(e)) +} + +func (e Errno) Temporary() bool { + return e == EINTR || e == EMFILE || e.Timeout() +} + +func (e Errno) Timeout() bool { + return e == EAGAIN || e == EWOULDBLOCK || e == ETIMEDOUT +} + +// A Signal is a number describing a process signal. +// It implements the os.Signal interface. +type Signal int + +const ( + _ Signal = iota + SIGCHLD + SIGINT + SIGKILL + SIGTRAP + SIGQUIT +) + +func (s Signal) Signal() {} + +func (s Signal) String() string { + if 0 <= s && int(s) < len(signals) { + str := signals[s] + if str != "" { + return str + } + } + return "signal " + itoa(int(s)) +} + +var signals = [...]string{} + +// File system + +const ( + Stdin = 0 + Stdout = 1 + Stderr = 2 +) + +const ( + O_RDONLY = 0 + O_WRONLY = 1 + O_RDWR = 2 + + O_CREAT = 0100 + O_CREATE = O_CREAT + O_TRUNC = 01000 + O_APPEND = 02000 + O_EXCL = 0200 + O_SYNC = 010000 + + O_CLOEXEC = 0 +) + +const ( + F_DUPFD = 0 + F_GETFD = 1 + F_SETFD = 2 + F_GETFL = 3 + F_SETFL = 4 + F_GETOWN = 5 + F_SETOWN = 6 + F_GETLK = 7 + F_SETLK = 8 + F_SETLKW = 9 + F_RGETLK = 10 + F_RSETLK = 11 + F_CNVT = 12 + F_RSETLKW = 13 + + F_RDLCK = 1 + F_WRLCK = 2 + F_UNLCK = 3 + F_UNLKSYS = 4 +) + +const ( + S_IFMT = 0000370000 + S_IFSHM_SYSV = 0000300000 + S_IFSEMA = 0000270000 + S_IFCOND = 0000260000 + S_IFMUTEX = 0000250000 + S_IFSHM = 0000240000 + S_IFBOUNDSOCK = 0000230000 + S_IFSOCKADDR = 0000220000 + S_IFDSOCK = 0000210000 + + S_IFSOCK = 0000140000 + S_IFLNK = 0000120000 + S_IFREG = 0000100000 + S_IFBLK = 0000060000 + S_IFDIR = 0000040000 + S_IFCHR = 0000020000 + S_IFIFO = 0000010000 + + S_UNSUP = 0000370000 + + S_ISUID = 0004000 + S_ISGID = 0002000 + S_ISVTX = 0001000 + + S_IREAD = 0400 + S_IWRITE = 0200 + S_IEXEC = 0100 + + S_IRWXU = 0700 + S_IRUSR = 0400 + S_IWUSR = 0200 + S_IXUSR = 0100 + + S_IRWXG = 070 + S_IRGRP = 040 + S_IWGRP = 020 + S_IXGRP = 010 + + S_IRWXO = 07 + S_IROTH = 04 + S_IWOTH = 02 + S_IXOTH = 01 +) + +type Stat_t struct { + Dev int64 + Ino uint64 + Mode uint32 + Nlink uint32 + Uid uint32 + Gid uint32 + Rdev int64 + Size int64 + Blksize int32 + Blocks int32 + Atime int64 + AtimeNsec int64 + Mtime int64 + MtimeNsec int64 + Ctime int64 + CtimeNsec int64 +} + +// Processes +// Not supported - just enough for package os. + +var ForkLock sync.RWMutex + +type WaitStatus uint32 + +func (w WaitStatus) Exited() bool { return false } +func (w WaitStatus) ExitStatus() int { return 0 } +func (w WaitStatus) Signaled() bool { return false } +func (w WaitStatus) Signal() Signal { return 0 } +func (w WaitStatus) CoreDump() bool { return false } +func (w WaitStatus) Stopped() bool { return false } +func (w WaitStatus) Continued() bool { return false } +func (w WaitStatus) StopSignal() Signal { return 0 } +func (w WaitStatus) TrapCause() int { return 0 } + +// XXX made up +type Rusage struct { + Utime Timeval + Stime Timeval +} + +// XXX made up +type ProcAttr struct { + Dir string + Env []string + Files []uintptr + Sys *SysProcAttr +} + +type SysProcAttr struct { +} + +func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) { + return 0, 0, ENOSYS +} + +func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) { + return 0, 0, ENOSYS +} + +func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) { + return 0, 0, ENOSYS +} + +func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) { + return 0, 0, ENOSYS +} + +func Sysctl(key string) (string, error) { + if key == "kern.hostname" { + return "js", nil + } + return "", ENOSYS +} + +const ImplementsGetwd = true + +func Getwd() (wd string, err error) { + var buf [PathMax]byte + n, err := Getcwd(buf[0:]) + if err != nil { + return "", err + } + return string(buf[:n]), nil +} + +func Getegid() int { return 1 } +func Geteuid() int { return 1 } +func Getgid() int { return 1 } +func Getgroups() ([]int, error) { return []int{1}, nil } +func Getppid() int { return 2 } +func Getpid() int { return 3 } +func Gettimeofday(tv *Timeval) error { return ENOSYS } +func Getuid() int { return 1 } +func Kill(pid int, signum Signal) error { return ENOSYS } +func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { + return 0, ENOSYS +} +func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) { + return 0, 0, ENOSYS +} +func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, err error) { + return 0, ENOSYS +} + +type Iovec struct{} // dummy + +type Timespec struct { + Sec int64 + Nsec int64 +} + +type Timeval struct { + Sec int64 + Usec int64 +} + +func setTimespec(sec, nsec int64) Timespec { + return Timespec{Sec: sec, Nsec: nsec} +} + +func setTimeval(sec, usec int64) Timeval { + return Timeval{Sec: sec, Usec: usec} +} diff --git a/libgo/go/syscall/syscall_linux.go b/libgo/go/syscall/syscall_linux.go index 338a971..d2d49c3 100644 --- a/libgo/go/syscall/syscall_linux.go +++ b/libgo/go/syscall/syscall_linux.go @@ -6,6 +6,11 @@ package syscall import "unsafe" +func rawSyscallNoError(trap, a1, a2, a3 uintptr) (r1, r2 uintptr) { + r1, r2, _ = RawSyscall(trap, a1, a2, a3) + return +} + func direntIno(buf []byte) (uint64, bool) { return readInt(buf, unsafe.Offsetof(Dirent{}.Ino), unsafe.Sizeof(Dirent{}.Ino)) } diff --git a/libgo/go/syscall/syscall_linux_test.go b/libgo/go/syscall/syscall_linux_test.go index 2c4d953..99de6eb 100644 --- a/libgo/go/syscall/syscall_linux_test.go +++ b/libgo/go/syscall/syscall_linux_test.go @@ -13,16 +13,139 @@ import ( "os/exec" "os/signal" "path/filepath" + "runtime" + "strconv" + "strings" "syscall" "testing" "time" ) +// chtmpdir changes the working directory to a new temporary directory and +// provides a cleanup function. Used when PWD is read-only. +func chtmpdir(t *testing.T) func() { + oldwd, err := os.Getwd() + if err != nil { + t.Fatalf("chtmpdir: %v", err) + } + d, err := ioutil.TempDir("", "test") + if err != nil { + t.Fatalf("chtmpdir: %v", err) + } + if err := os.Chdir(d); err != nil { + t.Fatalf("chtmpdir: %v", err) + } + return func() { + if err := os.Chdir(oldwd); err != nil { + t.Fatalf("chtmpdir: %v", err) + } + os.RemoveAll(d) + } +} + +func touch(t *testing.T, name string) { + f, err := os.Create(name) + if err != nil { + t.Fatal(err) + } + if err := f.Close(); err != nil { + t.Fatal(err) + } +} + +const ( + _AT_SYMLINK_NOFOLLOW = 0x100 + _AT_FDCWD = -0x64 + _AT_EACCESS = 0x200 + _F_OK = 0 + _R_OK = 4 +) + +func TestFaccessat(t *testing.T) { + defer chtmpdir(t)() + touch(t, "file1") + + err := syscall.Faccessat(_AT_FDCWD, "file1", _R_OK, 0) + if err != nil { + t.Errorf("Faccessat: unexpected error: %v", err) + } + + err = syscall.Faccessat(_AT_FDCWD, "file1", _R_OK, 2) + if err != syscall.EINVAL { + t.Errorf("Faccessat: unexpected error: %v, want EINVAL", err) + } + + err = syscall.Faccessat(_AT_FDCWD, "file1", _R_OK, _AT_EACCESS) + if err != nil { + t.Errorf("Faccessat: unexpected error: %v", err) + } + + err = os.Symlink("file1", "symlink1") + if err != nil { + t.Fatal(err) + } + + err = syscall.Faccessat(_AT_FDCWD, "symlink1", _R_OK, _AT_SYMLINK_NOFOLLOW) + if err != nil { + t.Errorf("Faccessat SYMLINK_NOFOLLOW: unexpected error %v", err) + } + + // We can't really test _AT_SYMLINK_NOFOLLOW, because there + // doesn't seem to be any way to change the mode of a symlink. + // We don't test _AT_EACCESS because such tests are only + // meaningful if run as root. + + err = syscall.Fchmodat(_AT_FDCWD, "file1", 0, 0) + if err != nil { + t.Errorf("Fchmodat: unexpected error %v", err) + } + + err = syscall.Faccessat(_AT_FDCWD, "file1", _F_OK, _AT_SYMLINK_NOFOLLOW) + if err != nil { + t.Errorf("Faccessat: unexpected error: %v", err) + } + + err = syscall.Faccessat(_AT_FDCWD, "file1", _R_OK, _AT_SYMLINK_NOFOLLOW) + if err != syscall.EACCES { + if syscall.Getuid() != 0 { + t.Errorf("Faccessat: unexpected error: %v, want EACCES", err) + } + } +} + +func TestFchmodat(t *testing.T) { + defer chtmpdir(t)() + + touch(t, "file1") + os.Symlink("file1", "symlink1") + + err := syscall.Fchmodat(_AT_FDCWD, "symlink1", 0444, 0) + if err != nil { + t.Fatalf("Fchmodat: unexpected error: %v", err) + } + + fi, err := os.Stat("file1") + if err != nil { + t.Fatal(err) + } + + if fi.Mode() != 0444 { + t.Errorf("Fchmodat: failed to change mode: expected %v, got %v", 0444, fi.Mode()) + } + + err = syscall.Fchmodat(_AT_FDCWD, "symlink1", 0444, _AT_SYMLINK_NOFOLLOW) + if err != syscall.EOPNOTSUPP { + t.Fatalf("Fchmodat: unexpected error: %v, expected EOPNOTSUPP", err) + } +} + func TestMain(m *testing.M) { if os.Getenv("GO_DEATHSIG_PARENT") == "1" { deathSignalParent() } else if os.Getenv("GO_DEATHSIG_CHILD") == "1" { deathSignalChild() + } else if os.Getenv("GO_SYSCALL_NOERROR") == "1" { + syscallNoError() } os.Exit(m.Run()) @@ -166,3 +289,82 @@ func TestParseNetlinkMessage(t *testing.T) { } } } + +func TestSyscallNoError(t *testing.T) { + // On Linux there are currently no syscalls which don't fail and return + // a value larger than 0xfffffffffffff001 so we could test RawSyscall + // vs. RawSyscallNoError on 64bit architectures. + if runtime.GOARCH != "386" && runtime.GOARCH != "arm" { + t.Skip("skipping on non-32bit architecture") + } + + if os.Getuid() != 0 { + t.Skip("skipping root only test") + } + + // Copy the test binary to a location that a non-root user can read/execute + // after we drop privileges + tempDir, err := ioutil.TempDir("", "TestSyscallNoError") + if err != nil { + t.Fatalf("cannot create temporary directory: %v", err) + } + defer os.RemoveAll(tempDir) + os.Chmod(tempDir, 0755) + + tmpBinary := filepath.Join(tempDir, filepath.Base(os.Args[0])) + + src, err := os.Open(os.Args[0]) + if err != nil { + t.Fatalf("cannot open binary %q, %v", os.Args[0], err) + } + defer src.Close() + + dst, err := os.OpenFile(tmpBinary, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755) + if err != nil { + t.Fatalf("cannot create temporary binary %q, %v", tmpBinary, err) + } + if _, err := io.Copy(dst, src); err != nil { + t.Fatalf("failed to copy test binary to %q, %v", tmpBinary, err) + } + err = dst.Close() + if err != nil { + t.Fatalf("failed to close test binary %q, %v", tmpBinary, err) + } + + uid := uint32(0xfffffffe) + err = os.Chown(tmpBinary, int(uid), -1) + if err != nil { + t.Fatalf("failed to chown test binary %q, %v", tmpBinary, err) + } + + err = os.Chmod(tmpBinary, 0755|os.ModeSetuid) + if err != nil { + t.Fatalf("failed to set setuid bit on test binary %q, %v", tmpBinary, err) + } + + cmd := exec.Command(tmpBinary) + cmd.Env = []string{"GO_SYSCALL_NOERROR=1"} + + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("failed to start first child process: %v", err) + } + + got := strings.TrimSpace(string(out)) + want := strconv.FormatUint(uint64(uid)+1, 10) + " / " + + strconv.FormatUint(uint64(-uid), 10) + " / " + + strconv.FormatUint(uint64(uid), 10) + if got != want { + t.Errorf("expected %s, got %s", want, got) + } +} + +func syscallNoError() { + // Test that the return value from SYS_GETEUID32 (which cannot fail) + // doesn't get treated as an error (see https://golang.org/issue/22924) + euid1, _, e := syscall.RawSyscall(syscall.Sys_GETEUID, 0, 0, 0) + euid2, _ := syscall.RawSyscallNoError(syscall.Sys_GETEUID, 0, 0, 0) + + fmt.Println(uintptr(euid1), "/", int(e), "/", uintptr(euid2)) + os.Exit(0) +} diff --git a/libgo/go/syscall/syscall_plan9_test.go b/libgo/go/syscall/syscall_plan9_test.go new file mode 100644 index 0000000..c0b3af5 --- /dev/null +++ b/libgo/go/syscall/syscall_plan9_test.go @@ -0,0 +1,53 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package syscall_test + +import ( + "syscall" + "testing" +) + +// testalias checks for aliasing of error strings returned by sys1 and sys2, +// which both call the function named fn in package syscall +func testalias(t *testing.T, fn string, sys1, sys2 func() error) { + err := sys1().Error() + errcopy := string([]byte(err)) + sys2() + if err != errcopy { + t.Errorf("syscall.%s error string changed from %q to %q\n", fn, errcopy, err) + } +} + +// issue 13770: errors cannot be nested in Plan 9 + +func TestPlan9Syserr(t *testing.T) { + testalias(t, + "Syscall", + func() error { + return syscall.Mkdir("/", 0) + }, + func() error { + return syscall.Mkdir("#", 0) + }) + testalias(t, + "Syscall6", + func() error { + return syscall.Mount(0, 0, "", 0, "") + }, + func() error { + return syscall.Mount(-1, 0, "", 0, "") + }) + // originally failed only on plan9_arm + testalias(t, + "seek", + func() error { + _, err := syscall.Seek(0, 0, -1) + return err + }, + func() error { + _, err := syscall.Seek(-1, 0, 0) + return err + }) +} diff --git a/libgo/go/syscall/syscall_test.go b/libgo/go/syscall/syscall_test.go index c3fffda..2a9d90e 100644 --- a/libgo/go/syscall/syscall_test.go +++ b/libgo/go/syscall/syscall_test.go @@ -62,8 +62,8 @@ func TestExecErrPermutedFds(t *testing.T) { } func TestGettimeofday(t *testing.T) { - if runtime.GOOS == "nacl" { - t.Skip("not implemented on nacl") + if runtime.GOOS == "nacl" || runtime.GOOS == "js" { + t.Skip("not implemented on " + runtime.GOOS) } tv := &syscall.Timeval{} if err := syscall.Gettimeofday(tv); err != nil { diff --git a/libgo/go/syscall/syscall_unix.go b/libgo/go/syscall/syscall_unix.go index 61aa1c4..9455c3f 100644 --- a/libgo/go/syscall/syscall_unix.go +++ b/libgo/go/syscall/syscall_unix.go @@ -99,6 +99,16 @@ func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errn return r, 0, err } +// clen returns the index of the first NULL byte in n or len(n) if n contains no NULL byte. +func clen(n []byte) int { + for i := 0; i < len(n); i++ { + if n[i] == 0 { + return i + } + } + return len(n) +} + // Mmap manager, for use by operating system-specific implementations. // Gccgo only has one implementation but we do this to correspond to gc. diff --git a/libgo/go/syscall/tables_nacljs.go b/libgo/go/syscall/tables_nacljs.go new file mode 100644 index 0000000..1c265f2 --- /dev/null +++ b/libgo/go/syscall/tables_nacljs.go @@ -0,0 +1,490 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build nacl js,wasm + +package syscall + +import "runtime" + +// TODO: generate with runtime/mknacl.sh, allow override with IRT. +const ( + sys_null = 1 + sys_nameservice = 2 + sys_dup = 8 + sys_dup2 = 9 + sys_open = 10 + sys_close = 11 + sys_read = 12 + sys_write = 13 + sys_lseek = 14 + sys_stat = 16 + sys_fstat = 17 + sys_chmod = 18 + sys_isatty = 19 + sys_brk = 20 + sys_mmap = 21 + sys_munmap = 22 + sys_getdents = 23 + sys_mprotect = 24 + sys_list_mappings = 25 + sys_exit = 30 + sys_getpid = 31 + sys_sched_yield = 32 + sys_sysconf = 33 + sys_gettimeofday = 40 + sys_clock = 41 + sys_nanosleep = 42 + sys_clock_getres = 43 + sys_clock_gettime = 44 + sys_mkdir = 45 + sys_rmdir = 46 + sys_chdir = 47 + sys_getcwd = 48 + sys_unlink = 49 + sys_imc_makeboundsock = 60 + sys_imc_accept = 61 + sys_imc_connect = 62 + sys_imc_sendmsg = 63 + sys_imc_recvmsg = 64 + sys_imc_mem_obj_create = 65 + sys_imc_socketpair = 66 + sys_mutex_create = 70 + sys_mutex_lock = 71 + sys_mutex_trylock = 72 + sys_mutex_unlock = 73 + sys_cond_create = 74 + sys_cond_wait = 75 + sys_cond_signal = 76 + sys_cond_broadcast = 77 + sys_cond_timed_wait_abs = 79 + sys_thread_create = 80 + sys_thread_exit = 81 + sys_tls_init = 82 + sys_thread_nice = 83 + sys_tls_get = 84 + sys_second_tls_set = 85 + sys_second_tls_get = 86 + sys_exception_handler = 87 + sys_exception_stack = 88 + sys_exception_clear_flag = 89 + sys_sem_create = 100 + sys_sem_wait = 101 + sys_sem_post = 102 + sys_sem_get_value = 103 + sys_dyncode_create = 104 + sys_dyncode_modify = 105 + sys_dyncode_delete = 106 + sys_test_infoleak = 109 + sys_test_crash = 110 + sys_test_syscall_1 = 111 + sys_test_syscall_2 = 112 + sys_futex_wait_abs = 120 + sys_futex_wake = 121 + sys_pread = 130 + sys_pwrite = 131 + sys_truncate = 140 + sys_lstat = 141 + sys_link = 142 + sys_rename = 143 + sys_symlink = 144 + sys_access = 145 + sys_readlink = 146 + sys_utimes = 147 + sys_get_random_bytes = 150 +) + +// TODO: Auto-generate some day. (Hard-coded in binaries so not likely to change.) +const ( + // native_client/src/trusted/service_runtime/include/sys/errno.h + // The errors are mainly copied from Linux. + EPERM Errno = 1 /* Operation not permitted */ + ENOENT Errno = 2 /* No such file or directory */ + ESRCH Errno = 3 /* No such process */ + EINTR Errno = 4 /* Interrupted system call */ + EIO Errno = 5 /* I/O error */ + ENXIO Errno = 6 /* No such device or address */ + E2BIG Errno = 7 /* Argument list too long */ + ENOEXEC Errno = 8 /* Exec format error */ + EBADF Errno = 9 /* Bad file number */ + ECHILD Errno = 10 /* No child processes */ + EAGAIN Errno = 11 /* Try again */ + ENOMEM Errno = 12 /* Out of memory */ + EACCES Errno = 13 /* Permission denied */ + EFAULT Errno = 14 /* Bad address */ + EBUSY Errno = 16 /* Device or resource busy */ + EEXIST Errno = 17 /* File exists */ + EXDEV Errno = 18 /* Cross-device link */ + ENODEV Errno = 19 /* No such device */ + ENOTDIR Errno = 20 /* Not a directory */ + EISDIR Errno = 21 /* Is a directory */ + EINVAL Errno = 22 /* Invalid argument */ + ENFILE Errno = 23 /* File table overflow */ + EMFILE Errno = 24 /* Too many open files */ + ENOTTY Errno = 25 /* Not a typewriter */ + EFBIG Errno = 27 /* File too large */ + ENOSPC Errno = 28 /* No space left on device */ + ESPIPE Errno = 29 /* Illegal seek */ + EROFS Errno = 30 /* Read-only file system */ + EMLINK Errno = 31 /* Too many links */ + EPIPE Errno = 32 /* Broken pipe */ + ENAMETOOLONG Errno = 36 /* File name too long */ + ENOSYS Errno = 38 /* Function not implemented */ + EDQUOT Errno = 122 /* Quota exceeded */ + EDOM Errno = 33 /* Math arg out of domain of func */ + ERANGE Errno = 34 /* Math result not representable */ + EDEADLK Errno = 35 /* Deadlock condition */ + ENOLCK Errno = 37 /* No record locks available */ + ENOTEMPTY Errno = 39 /* Directory not empty */ + ELOOP Errno = 40 /* Too many symbolic links */ + ENOMSG Errno = 42 /* No message of desired type */ + EIDRM Errno = 43 /* Identifier removed */ + ECHRNG Errno = 44 /* Channel number out of range */ + EL2NSYNC Errno = 45 /* Level 2 not synchronized */ + EL3HLT Errno = 46 /* Level 3 halted */ + EL3RST Errno = 47 /* Level 3 reset */ + ELNRNG Errno = 48 /* Link number out of range */ + EUNATCH Errno = 49 /* Protocol driver not attached */ + ENOCSI Errno = 50 /* No CSI structure available */ + EL2HLT Errno = 51 /* Level 2 halted */ + EBADE Errno = 52 /* Invalid exchange */ + EBADR Errno = 53 /* Invalid request descriptor */ + EXFULL Errno = 54 /* Exchange full */ + ENOANO Errno = 55 /* No anode */ + EBADRQC Errno = 56 /* Invalid request code */ + EBADSLT Errno = 57 /* Invalid slot */ + EDEADLOCK Errno = EDEADLK /* File locking deadlock error */ + EBFONT Errno = 59 /* Bad font file fmt */ + ENOSTR Errno = 60 /* Device not a stream */ + ENODATA Errno = 61 /* No data (for no delay io) */ + ETIME Errno = 62 /* Timer expired */ + ENOSR Errno = 63 /* Out of streams resources */ + ENONET Errno = 64 /* Machine is not on the network */ + ENOPKG Errno = 65 /* Package not installed */ + EREMOTE Errno = 66 /* The object is remote */ + ENOLINK Errno = 67 /* The link has been severed */ + EADV Errno = 68 /* Advertise error */ + ESRMNT Errno = 69 /* Srmount error */ + ECOMM Errno = 70 /* Communication error on send */ + EPROTO Errno = 71 /* Protocol error */ + EMULTIHOP Errno = 72 /* Multihop attempted */ + EDOTDOT Errno = 73 /* Cross mount point (not really error) */ + EBADMSG Errno = 74 /* Trying to read unreadable message */ + EOVERFLOW Errno = 75 /* Value too large for defined data type */ + ENOTUNIQ Errno = 76 /* Given log. name not unique */ + EBADFD Errno = 77 /* f.d. invalid for this operation */ + EREMCHG Errno = 78 /* Remote address changed */ + ELIBACC Errno = 79 /* Can't access a needed shared lib */ + ELIBBAD Errno = 80 /* Accessing a corrupted shared lib */ + ELIBSCN Errno = 81 /* .lib section in a.out corrupted */ + ELIBMAX Errno = 82 /* Attempting to link in too many libs */ + ELIBEXEC Errno = 83 /* Attempting to exec a shared library */ + EILSEQ Errno = 84 + EUSERS Errno = 87 + ENOTSOCK Errno = 88 /* Socket operation on non-socket */ + EDESTADDRREQ Errno = 89 /* Destination address required */ + EMSGSIZE Errno = 90 /* Message too long */ + EPROTOTYPE Errno = 91 /* Protocol wrong type for socket */ + ENOPROTOOPT Errno = 92 /* Protocol not available */ + EPROTONOSUPPORT Errno = 93 /* Unknown protocol */ + ESOCKTNOSUPPORT Errno = 94 /* Socket type not supported */ + EOPNOTSUPP Errno = 95 /* Operation not supported on transport endpoint */ + EPFNOSUPPORT Errno = 96 /* Protocol family not supported */ + EAFNOSUPPORT Errno = 97 /* Address family not supported by protocol family */ + EADDRINUSE Errno = 98 /* Address already in use */ + EADDRNOTAVAIL Errno = 99 /* Address not available */ + ENETDOWN Errno = 100 /* Network interface is not configured */ + ENETUNREACH Errno = 101 /* Network is unreachable */ + ENETRESET Errno = 102 + ECONNABORTED Errno = 103 /* Connection aborted */ + ECONNRESET Errno = 104 /* Connection reset by peer */ + ENOBUFS Errno = 105 /* No buffer space available */ + EISCONN Errno = 106 /* Socket is already connected */ + ENOTCONN Errno = 107 /* Socket is not connected */ + ESHUTDOWN Errno = 108 /* Can't send after socket shutdown */ + ETOOMANYREFS Errno = 109 + ETIMEDOUT Errno = 110 /* Connection timed out */ + ECONNREFUSED Errno = 111 /* Connection refused */ + EHOSTDOWN Errno = 112 /* Host is down */ + EHOSTUNREACH Errno = 113 /* Host is unreachable */ + EALREADY Errno = 114 /* Socket already connected */ + EINPROGRESS Errno = 115 /* Connection already in progress */ + ESTALE Errno = 116 + ENOTSUP Errno = EOPNOTSUPP /* Not supported */ + ENOMEDIUM Errno = 123 /* No medium (in tape drive) */ + ECANCELED Errno = 125 /* Operation canceled. */ + ELBIN Errno = 2048 /* Inode is remote (not really error) */ + EFTYPE Errno = 2049 /* Inappropriate file type or format */ + ENMFILE Errno = 2050 /* No more files */ + EPROCLIM Errno = 2051 + ENOSHARE Errno = 2052 /* No such host or network path */ + ECASECLASH Errno = 2053 /* Filename exists with different case */ + EWOULDBLOCK Errno = EAGAIN /* Operation would block */ +) + +// TODO: Auto-generate some day. (Hard-coded in binaries so not likely to change.) +var errorstr = [...]string{ + EPERM: "Operation not permitted", + ENOENT: "No such file or directory", + ESRCH: "No such process", + EINTR: "Interrupted system call", + EIO: "I/O error", + ENXIO: "No such device or address", + E2BIG: "Argument list too long", + ENOEXEC: "Exec format error", + EBADF: "Bad file number", + ECHILD: "No child processes", + EAGAIN: "Try again", + ENOMEM: "Out of memory", + EACCES: "Permission denied", + EFAULT: "Bad address", + EBUSY: "Device or resource busy", + EEXIST: "File exists", + EXDEV: "Cross-device link", + ENODEV: "No such device", + ENOTDIR: "Not a directory", + EISDIR: "Is a directory", + EINVAL: "Invalid argument", + ENFILE: "File table overflow", + EMFILE: "Too many open files", + ENOTTY: "Not a typewriter", + EFBIG: "File too large", + ENOSPC: "No space left on device", + ESPIPE: "Illegal seek", + EROFS: "Read-only file system", + EMLINK: "Too many links", + EPIPE: "Broken pipe", + ENAMETOOLONG: "File name too long", + ENOSYS: "not implemented on " + runtime.GOOS, + EDQUOT: "Quota exceeded", + EDOM: "Math arg out of domain of func", + ERANGE: "Math result not representable", + EDEADLK: "Deadlock condition", + ENOLCK: "No record locks available", + ENOTEMPTY: "Directory not empty", + ELOOP: "Too many symbolic links", + ENOMSG: "No message of desired type", + EIDRM: "Identifier removed", + ECHRNG: "Channel number out of range", + EL2NSYNC: "Level 2 not synchronized", + EL3HLT: "Level 3 halted", + EL3RST: "Level 3 reset", + ELNRNG: "Link number out of range", + EUNATCH: "Protocol driver not attached", + ENOCSI: "No CSI structure available", + EL2HLT: "Level 2 halted", + EBADE: "Invalid exchange", + EBADR: "Invalid request descriptor", + EXFULL: "Exchange full", + ENOANO: "No anode", + EBADRQC: "Invalid request code", + EBADSLT: "Invalid slot", + EBFONT: "Bad font file fmt", + ENOSTR: "Device not a stream", + ENODATA: "No data (for no delay io)", + ETIME: "Timer expired", + ENOSR: "Out of streams resources", + ENONET: "Machine is not on the network", + ENOPKG: "Package not installed", + EREMOTE: "The object is remote", + ENOLINK: "The link has been severed", + EADV: "Advertise error", + ESRMNT: "Srmount error", + ECOMM: "Communication error on send", + EPROTO: "Protocol error", + EMULTIHOP: "Multihop attempted", + EDOTDOT: "Cross mount point (not really error)", + EBADMSG: "Trying to read unreadable message", + EOVERFLOW: "Value too large for defined data type", + ENOTUNIQ: "Given log. name not unique", + EBADFD: "f.d. invalid for this operation", + EREMCHG: "Remote address changed", + ELIBACC: "Can't access a needed shared lib", + ELIBBAD: "Accessing a corrupted shared lib", + ELIBSCN: ".lib section in a.out corrupted", + ELIBMAX: "Attempting to link in too many libs", + ELIBEXEC: "Attempting to exec a shared library", + ENOTSOCK: "Socket operation on non-socket", + EDESTADDRREQ: "Destination address required", + EMSGSIZE: "Message too long", + EPROTOTYPE: "Protocol wrong type for socket", + ENOPROTOOPT: "Protocol not available", + EPROTONOSUPPORT: "Unknown protocol", + ESOCKTNOSUPPORT: "Socket type not supported", + EOPNOTSUPP: "Operation not supported on transport endpoint", + EPFNOSUPPORT: "Protocol family not supported", + EAFNOSUPPORT: "Address family not supported by protocol family", + EADDRINUSE: "Address already in use", + EADDRNOTAVAIL: "Address not available", + ENETDOWN: "Network interface is not configured", + ENETUNREACH: "Network is unreachable", + ECONNABORTED: "Connection aborted", + ECONNRESET: "Connection reset by peer", + ENOBUFS: "No buffer space available", + EISCONN: "Socket is already connected", + ENOTCONN: "Socket is not connected", + ESHUTDOWN: "Can't send after socket shutdown", + ETIMEDOUT: "Connection timed out", + ECONNREFUSED: "Connection refused", + EHOSTDOWN: "Host is down", + EHOSTUNREACH: "Host is unreachable", + EALREADY: "Socket already connected", + EINPROGRESS: "Connection already in progress", + ENOMEDIUM: "No medium (in tape drive)", + ECANCELED: "Operation canceled.", + ELBIN: "Inode is remote (not really error)", + EFTYPE: "Inappropriate file type or format", + ENMFILE: "No more files", + ENOSHARE: "No such host or network path", + ECASECLASH: "Filename exists with different case", +} + +// Do the interface allocations only once for common +// Errno values. +var ( + errEAGAIN error = EAGAIN + errEINVAL error = EINVAL + errENOENT error = ENOENT +) + +// errnoErr returns common boxed Errno values, to prevent +// allocations at runtime. +func errnoErr(e Errno) error { + switch e { + case 0: + return nil + case EAGAIN: + return errEAGAIN + case EINVAL: + return errEINVAL + case ENOENT: + return errENOENT + } + return e +} + +var errnoByCode = map[string]Errno{ + "EPERM": EPERM, + "ENOENT": ENOENT, + "ESRCH": ESRCH, + "EINTR": EINTR, + "EIO": EIO, + "ENXIO": ENXIO, + "E2BIG": E2BIG, + "ENOEXEC": ENOEXEC, + "EBADF": EBADF, + "ECHILD": ECHILD, + "EAGAIN": EAGAIN, + "ENOMEM": ENOMEM, + "EACCES": EACCES, + "EFAULT": EFAULT, + "EBUSY": EBUSY, + "EEXIST": EEXIST, + "EXDEV": EXDEV, + "ENODEV": ENODEV, + "ENOTDIR": ENOTDIR, + "EISDIR": EISDIR, + "EINVAL": EINVAL, + "ENFILE": ENFILE, + "EMFILE": EMFILE, + "ENOTTY": ENOTTY, + "EFBIG": EFBIG, + "ENOSPC": ENOSPC, + "ESPIPE": ESPIPE, + "EROFS": EROFS, + "EMLINK": EMLINK, + "EPIPE": EPIPE, + "ENAMETOOLONG": ENAMETOOLONG, + "ENOSYS": ENOSYS, + "EDQUOT": EDQUOT, + "EDOM": EDOM, + "ERANGE": ERANGE, + "EDEADLK": EDEADLK, + "ENOLCK": ENOLCK, + "ENOTEMPTY": ENOTEMPTY, + "ELOOP": ELOOP, + "ENOMSG": ENOMSG, + "EIDRM": EIDRM, + "ECHRNG": ECHRNG, + "EL2NSYNC": EL2NSYNC, + "EL3HLT": EL3HLT, + "EL3RST": EL3RST, + "ELNRNG": ELNRNG, + "EUNATCH": EUNATCH, + "ENOCSI": ENOCSI, + "EL2HLT": EL2HLT, + "EBADE": EBADE, + "EBADR": EBADR, + "EXFULL": EXFULL, + "ENOANO": ENOANO, + "EBADRQC": EBADRQC, + "EBADSLT": EBADSLT, + "EDEADLOCK": EDEADLOCK, + "EBFONT": EBFONT, + "ENOSTR": ENOSTR, + "ENODATA": ENODATA, + "ETIME": ETIME, + "ENOSR": ENOSR, + "ENONET": ENONET, + "ENOPKG": ENOPKG, + "EREMOTE": EREMOTE, + "ENOLINK": ENOLINK, + "EADV": EADV, + "ESRMNT": ESRMNT, + "ECOMM": ECOMM, + "EPROTO": EPROTO, + "EMULTIHOP": EMULTIHOP, + "EDOTDOT": EDOTDOT, + "EBADMSG": EBADMSG, + "EOVERFLOW": EOVERFLOW, + "ENOTUNIQ": ENOTUNIQ, + "EBADFD": EBADFD, + "EREMCHG": EREMCHG, + "ELIBACC": ELIBACC, + "ELIBBAD": ELIBBAD, + "ELIBSCN": ELIBSCN, + "ELIBMAX": ELIBMAX, + "ELIBEXEC": ELIBEXEC, + "EILSEQ": EILSEQ, + "EUSERS": EUSERS, + "ENOTSOCK": ENOTSOCK, + "EDESTADDRREQ": EDESTADDRREQ, + "EMSGSIZE": EMSGSIZE, + "EPROTOTYPE": EPROTOTYPE, + "ENOPROTOOPT": ENOPROTOOPT, + "EPROTONOSUPPORT": EPROTONOSUPPORT, + "ESOCKTNOSUPPORT": ESOCKTNOSUPPORT, + "EOPNOTSUPP": EOPNOTSUPP, + "EPFNOSUPPORT": EPFNOSUPPORT, + "EAFNOSUPPORT": EAFNOSUPPORT, + "EADDRINUSE": EADDRINUSE, + "EADDRNOTAVAIL": EADDRNOTAVAIL, + "ENETDOWN": ENETDOWN, + "ENETUNREACH": ENETUNREACH, + "ENETRESET": ENETRESET, + "ECONNABORTED": ECONNABORTED, + "ECONNRESET": ECONNRESET, + "ENOBUFS": ENOBUFS, + "EISCONN": EISCONN, + "ENOTCONN": ENOTCONN, + "ESHUTDOWN": ESHUTDOWN, + "ETOOMANYREFS": ETOOMANYREFS, + "ETIMEDOUT": ETIMEDOUT, + "ECONNREFUSED": ECONNREFUSED, + "EHOSTDOWN": EHOSTDOWN, + "EHOSTUNREACH": EHOSTUNREACH, + "EALREADY": EALREADY, + "EINPROGRESS": EINPROGRESS, + "ESTALE": ESTALE, + "ENOTSUP": ENOTSUP, + "ENOMEDIUM": ENOMEDIUM, + "ECANCELED": ECANCELED, + "ELBIN": ELBIN, + "EFTYPE": EFTYPE, + "ENMFILE": ENMFILE, + "EPROCLIM": EPROCLIM, + "ENOSHARE": ENOSHARE, + "ECASECLASH": ECASECLASH, + "EWOULDBLOCK": EWOULDBLOCK, +} diff --git a/libgo/go/syscall/timestruct.go b/libgo/go/syscall/timestruct.go index 6ece338..d17811c 100644 --- a/libgo/go/syscall/timestruct.go +++ b/libgo/go/syscall/timestruct.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build aix darwin dragonfly freebsd linux nacl netbsd openbsd solaris +// +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris package syscall |