Commit 55e2a233 authored by Rob Pike's avatar Rob Pike

go.sys/unix: delete nacl

It's a peculiar environment that probably doesn't belong here.
We can bring it back easily if we need it.

LGTM=dave, rsc
R=rsc, dave
CC=golang-codereviews
https://golang.org/cl/128110043
parent 8768103c
// 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.
#include "textflag.h"
#include "../runtime/syscall_nacl.h" // TODO: how to refer to this?
//
// System call support for 386, Native Client
//
#define NACL_SYSCALL(code) \
MOVL $(0x10000 + ((code)<<5)), AX; CALL AX
#define NACL_SYSJMP(code) \
MOVL $(0x10000 + ((code)<<5)), AX; JMP AX
TEXT unix·Syscall(SB),NOSPLIT,$12-28
CALL runtime·entersyscall(SB)
MOVL trap+0(FP), AX
MOVL a1+4(FP), BX
MOVL BX, 0(SP)
MOVL a2+8(FP), BX
MOVL BX, 4(SP)
MOVL a3+12(FP), BX
MOVL BX, 8(SP)
SHLL $5, AX
ADDL $0x10000, AX
CALL AX
CMPL AX, $0
JGE ok
MOVL $-1, r1+16(FP)
MOVL $-1, r2+20(FP)
NEGL AX
MOVL AX, err+24(FP)
CALL runtime·exitsyscall(SB)
RET
ok:
MOVL AX, r1+16(FP)
MOVL DX, r2+20(FP)
MOVL $0, err+24(FP)
CALL runtime·exitsyscall(SB)
RET
// 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.
#include "textflag.h"
#include "../runtime/syscall_nacl.h" // TODO: how to refer to this?
//
// System call support for amd64, Native Client
//
#define NACL_SYSCALL(code) \
MOVL $(0x10000 + ((code)<<5)), AX; CALL AX
#define NACL_SYSJMP(code) \
MOVL $(0x10000 + ((code)<<5)), AX; JMP AX
TEXT unix·Syscall(SB),NOSPLIT,$0-28
CALL runtime·entersyscall(SB)
MOVL trap+0(FP), AX
MOVL a1+4(FP), DI
MOVL a2+8(FP), SI
MOVL a3+12(FP), DX
// more args would use CX, R8, R9
SHLL $5, AX
ADDL $0x10000, AX
CALL AX
CMPL AX, $0
JGE ok
MOVL $-1, r1+16(FP)
MOVL $-1, r2+20(FP)
NEGL AX
MOVL AX, err+24(FP)
CALL runtime·exitsyscall(SB)
RET
ok:
MOVL AX, r1+16(FP)
MOVL DX, r2+20(FP)
MOVL $0, err+24(FP)
CALL runtime·exitsyscall(SB)
RET
// Copyright 2014 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.
#include "textflag.h"
#include "../runtime/syscall_nacl.h" // TODO: how to refer to this?
//
// System call support for ARM, Native Client
//
#define NACL_SYSCALL(code) \
MOVW $(0x10000 + ((code)<<5)), R8; BL (R8)
#define NACL_SYSJMP(code) \
MOVW $(0x10000 + ((code)<<5)), R8; B (R8)
TEXT unix·Syscall(SB),NOSPLIT,$0-28
BL runtime·entersyscall(SB)
MOVW trap+0(FP), R8
MOVW a1+4(FP), R0
MOVW a2+8(FP), R1
MOVW a3+12(FP), R2
// more args would use R3, and then stack.
MOVW $0x10000, R7
ADD R8<<5, R7
BL (R7)
CMP $0, R0
BGE ok
MOVW $-1, R1
MOVW R1, r1+16(FP)
MOVW R1, r2+20(FP)
RSB $0, R0
MOVW R0, err+24(FP)
BL runtime·exitsyscall(SB)
RET
ok:
MOVW R0, r1+16(FP)
MOVW R1, r2+20(FP)
MOVW $0, R2
MOVW R2, err+24(FP)
BL runtime·exitsyscall(SB)
RET
......@@ -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 darwin dragonfly freebsd linux nacl netbsd openbsd solaris
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
// Unix environment variables.
......
// 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.
// File descriptor support for Native Client.
// We want to provide access to a broader range of (simulated) files than
// Native Client allows, so we maintain our own file descriptor table exposed
// to higher-level packages.
package unix
import (
"sync"
)
// files is the table indexed by a file descriptor.
var files struct {
sync.RWMutex
tab []*file
}
// A file is an open file, something with a file descriptor.
// A particular *file may appear in files multiple times, due to use of Dup or Dup2.
type file struct {
fdref int // uses in files.tab
impl fileImpl // underlying implementation
}
// A fileImpl is the implementation of something that can be a file.
type fileImpl interface {
// Standard operations.
// These can be called concurrently from multiple goroutines.
stat(*Stat_t) error
read([]byte) (int, error)
write([]byte) (int, error)
seek(int64, int) (int64, error)
pread([]byte, int64) (int, error)
pwrite([]byte, int64) (int, error)
// Close is called when the last reference to a *file is removed
// from the file descriptor table. It may be called concurrently
// with active operations such as blocked read or write calls.
close() error
}
// newFD adds impl to the file descriptor table,
// returning the new file descriptor.
// Like Unix, it uses the lowest available descriptor.
func newFD(impl fileImpl) int {
files.Lock()
defer files.Unlock()
f := &file{impl: impl, fdref: 1}
for fd, oldf := range files.tab {
if oldf == nil {
files.tab[fd] = f
return fd
}
}
fd := len(files.tab)
files.tab = append(files.tab, f)
return fd
}
// Install Native Client stdin, stdout, stderr.
func init() {
newFD(&naclFile{naclFD: 0})
newFD(&naclFile{naclFD: 1})
newFD(&naclFile{naclFD: 2})
}
// fdToFile retrieves the *file corresponding to a file descriptor.
func fdToFile(fd int) (*file, error) {
files.Lock()
defer files.Unlock()
if fd < 0 || fd >= len(files.tab) || files.tab[fd] == nil {
return nil, EBADF
}
return files.tab[fd], nil
}
func Close(fd int) error {
files.Lock()
if fd < 0 || fd >= len(files.tab) || files.tab[fd] == nil {
files.Unlock()
return EBADF
}
f := files.tab[fd]
files.tab[fd] = nil
f.fdref--
fdref := f.fdref
files.Unlock()
if fdref > 0 {
return nil
}
return f.impl.close()
}
func CloseOnExec(fd int) {
// nothing to do - no exec
}
func Dup(fd int) (int, error) {
files.Lock()
defer files.Unlock()
if fd < 0 || fd >= len(files.tab) || files.tab[fd] == nil {
return -1, EBADF
}
f := files.tab[fd]
f.fdref++
for newfd, oldf := range files.tab {
if oldf == nil {
files.tab[newfd] = f
return newfd, nil
}
}
newfd := len(files.tab)
files.tab = append(files.tab, f)
return newfd, nil
}
func Dup2(fd, newfd int) error {
files.Lock()
defer files.Unlock()
if fd < 0 || fd >= len(files.tab) || files.tab[fd] == nil || newfd < 0 || newfd >= len(files.tab)+100 {
files.Unlock()
return EBADF
}
f := files.tab[fd]
f.fdref++
for cap(files.tab) <= newfd {
files.tab = append(files.tab[:cap(files.tab)], nil)
}
oldf := files.tab[newfd]
var oldfdref int
if oldf != nil {
oldf.fdref--
oldfdref = oldf.fdref
}
files.tab[newfd] = f
files.Unlock()
if oldf != nil {
if oldfdref == 0 {
oldf.impl.close()
}
}
return nil
}
func Fstat(fd int, st *Stat_t) error {
f, err := fdToFile(fd)
if err != nil {
return err
}
return f.impl.stat(st)
}
func Read(fd int, b []byte) (int, error) {
f, err := fdToFile(fd)
if err != nil {
return 0, err
}
return f.impl.read(b)
}
var zerobuf [0]byte
func Write(fd int, b []byte) (int, error) {
if b == nil {
// avoid nil in syscalls; nacl doesn't like that.
b = zerobuf[:]
}
f, err := fdToFile(fd)
if err != nil {
return 0, err
}
return f.impl.write(b)
}
func Pread(fd int, b []byte, offset int64) (int, error) {
f, err := fdToFile(fd)
if err != nil {
return 0, err
}
return f.impl.pread(b, offset)
}
func Pwrite(fd int, b []byte, offset int64) (int, error) {
f, err := fdToFile(fd)
if err != nil {
return 0, err
}
return f.impl.pwrite(b, offset)
}
func Seek(fd int, offset int64, whence int) (int64, error) {
f, err := fdToFile(fd)
if err != nil {
return 0, err
}
return f.impl.seek(offset, whence)
}
// defaulFileImpl implements fileImpl.
// It can be embedded to complete a partial fileImpl implementation.
type defaultFileImpl struct{}
func (*defaultFileImpl) close() error { return nil }
func (*defaultFileImpl) stat(*Stat_t) error { return ENOSYS }
func (*defaultFileImpl) read([]byte) (int, error) { return 0, ENOSYS }
func (*defaultFileImpl) write([]byte) (int, error) { return 0, ENOSYS }
func (*defaultFileImpl) seek(int64, int) (int64, error) { return 0, ENOSYS }
func (*defaultFileImpl) pread([]byte, int64) (int, error) { return 0, ENOSYS }
func (*defaultFileImpl) pwrite([]byte, int64) (int, error) { return 0, ENOSYS }
// naclFile is the fileImpl implementation for a Native Client file descriptor.
type naclFile struct {
defaultFileImpl
naclFD int
}
func (f *naclFile) stat(st *Stat_t) error {
return naclFstat(f.naclFD, st)
}
func (f *naclFile) read(b []byte) (int, error) {
n, err := naclRead(f.naclFD, b)
if err != nil {
n = 0
}
return n, err
}
// implemented in package runtime, to add time header on playground
func naclWrite(fd int, b []byte) int
func (f *naclFile) write(b []byte) (int, error) {
n := naclWrite(f.naclFD, b)
if n < 0 {
return 0, Errno(-n)
}
return n, nil
}
func (f *naclFile) seek(off int64, whence int) (int64, error) {
old := off
err := naclSeek(f.naclFD, &off, whence)
if err != nil {
return old, err
}
return off, nil
}
func (f *naclFile) prw(b []byte, offset int64, rw func([]byte) (int, error)) (int, error) {
// NaCl has no pread; simulate with seek and hope for no races.
old, err := f.seek(0, 1)
if err != nil {
return 0, err
}
if _, err := f.seek(offset, 0); err != nil {
return 0, err
}
n, err := rw(b)
f.seek(old, 0)
return n, err
}
func (f *naclFile) pread(b []byte, offset int64) (int, error) {
return f.prw(b, offset, f.read)
}
func (f *naclFile) pwrite(b []byte, offset int64) (int, error) {
return f.prw(b, offset, f.write)
}
func (f *naclFile) close() error {
err := naclClose(f.naclFD)
f.naclFD = -1
return err
}
// A pipeFile is an in-memory implementation of a pipe.
// The byteq implementation is in net_nacl.go.
type pipeFile struct {
defaultFileImpl
rd *byteq
wr *byteq
}
func (f *pipeFile) close() error {
if f.rd != nil {
f.rd.close()
}
if f.wr != nil {
f.wr.close()
}
return nil
}
func (f *pipeFile) read(b []byte) (int, error) {
if f.rd == nil {
return 0, EINVAL
}
n, err := f.rd.read(b, 0)
if err == EAGAIN {
err = nil
}
return n, err
}
func (f *pipeFile) write(b []byte) (int, error) {
if f.wr == nil {
return 0, EINVAL
}
n, err := f.wr.write(b, 0)
if err == EAGAIN {
err = EPIPE
}
return n, err
}
func Pipe(fd []int) error {
q := newByteq()
fd[0] = newFD(&pipeFile{rd: q})
fd[1] = newFD(&pipeFile{wr: q})
return nil
}
// 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.
// A simulated Unix-like file system for use within NaCl.
//
// The simulation is not particularly tied to NaCl other than the reuse
// of NaCl's definition for the Stat_t structure.
//
// The file system need never be written to disk, so it is represented as
// in-memory Go data structures, never in a serialized form.
//
// TODO: Perhaps support symlinks, although they muck everything up.
package unix
import (
"sync"
"unsafe"
)
// Provided by package runtime.
func now() (sec int64, nsec int32)
// An fsys is a file system.
// Since there is no I/O (everything is in memory),
// the global lock mu protects the whole file system state,
// and that's okay.
type fsys struct {
mu sync.Mutex
root *inode // root directory
cwd *inode // process current directory
inum uint64 // number of inodes created
dev []func() (devFile, error) // table for opening devices
}
// A devFile is the implementation required of device files
// like /dev/null or /dev/random.
type devFile interface {
pread([]byte, int64) (int, error)
pwrite([]byte, int64) (int, error)
}
// An inode is a (possibly special) file in the file system.
type inode struct {
Stat_t
data []byte
dir []dirent
}
// A dirent describes a single directory entry.
type dirent struct {
name string
inode *inode
}
// An fsysFile is the fileImpl implementation backed by the file system.
type fsysFile struct {
defaultFileImpl
fsys *fsys
inode *inode
openmode int
offset int64
dev devFile
}
// newFsys creates a new file system.
func newFsys() *fsys {
fs := &fsys{}
fs.mu.Lock()
defer fs.mu.Unlock()
ip := fs.newInode()
ip.Mode = 0555 | S_IFDIR
fs.dirlink(ip, ".", ip)
fs.dirlink(ip, "..", ip)
fs.cwd = ip
fs.root = ip
return fs
}
var fs = newFsys()
var fsinit = func() {}
func init() {
// do not trigger loading of zipped file system here
oldFsinit := fsinit
defer func() { fsinit = oldFsinit }()
fsinit = func() {}
Mkdir("/dev", 0555)
Mkdir("/tmp", 0777)
mkdev("/dev/null", 0666, openNull)
mkdev("/dev/random", 0444, openRandom)
mkdev("/dev/urandom", 0444, openRandom)
mkdev("/dev/zero", 0666, openZero)
chdirEnv()
}
func chdirEnv() {
pwd, ok := Getenv("NACLPWD")
if ok {
chdir(pwd)
}
}
// Except where indicated otherwise, unexported methods on fsys
// expect fs.mu to have been locked by the caller.
// newInode creates a new inode.
func (fs *fsys) newInode() *inode {
fs.inum++
ip := &inode{
Stat_t: Stat_t{
Ino: fs.inum,
Blksize: 512,
},
}
return ip
}
// atime sets ip.Atime to the current time.
func (fs *fsys) atime(ip *inode) {
sec, nsec := now()
ip.Atime, ip.AtimeNsec = sec, int64(nsec)
}
// mtime sets ip.Mtime to the current time.
func (fs *fsys) mtime(ip *inode) {
sec, nsec := now()
ip.Mtime, ip.MtimeNsec = sec, int64(nsec)
}
// dirlookup looks for an entry in the directory dp with the given name.
// It returns the directory entry and its index within the directory.
func (fs *fsys) dirlookup(dp *inode, name string) (de *dirent, index int, err error) {
fs.atime(dp)
for i := range dp.dir {
de := &dp.dir[i]
if de.name == name {
fs.atime(de.inode)
return de, i, nil
}
}
return nil, 0, ENOENT
}
// dirlink adds to the directory dp an entry for name pointing at the inode ip.
// If dp already contains an entry for name, that entry is overwritten.
func (fs *fsys) dirlink(dp *inode, name string, ip *inode) {
fs.mtime(dp)
fs.atime(ip)
ip.Nlink++
for i := range dp.dir {
if dp.dir[i].name == name {
dp.dir[i] = dirent{name, ip}
return
}
}
dp.dir = append(dp.dir, dirent{name, ip})
dp.dirSize()
}
func (dp *inode) dirSize() {
dp.Size = int64(len(dp.dir)) * (8 + 8 + 2 + 256) // Dirent
}
// skipelem splits path into the first element and the remainder.
// the returned first element contains no slashes, and the returned
// remainder does not begin with a slash.
func skipelem(path string) (elem, rest string) {
for len(path) > 0 && path[0] == '/' {
path = path[1:]
}
if len(path) == 0 {
return "", ""
}
i := 0
for i < len(path) && path[i] != '/' {
i++
}
elem, path = path[:i], path[i:]
for len(path) > 0 && path[0] == '/' {
path = path[1:]
}
return elem, path
}
// namei translates a file system path name into an inode.
// If parent is false, the returned ip corresponds to the given name, and elem is the empty string.
// If parent is true, the walk stops at the next-to-last element in the name,
// so that ip is the parent directory and elem is the final element in the path.
func (fs *fsys) namei(path string, parent bool) (ip *inode, elem string, err error) {
// Reject NUL in name.
for i := 0; i < len(path); i++ {
if path[i] == '\x00' {
return nil, "", EINVAL
}
}
// Reject empty name.
if path == "" {
return nil, "", EINVAL
}
if path[0] == '/' {
ip = fs.root
} else {
ip = fs.cwd
}
for len(path) > 0 && path[len(path)-1] == '/' {
path = path[:len(path)-1]
}
for {
elem, rest := skipelem(path)
if elem == "" {
if parent && ip.Mode&S_IFMT == S_IFDIR {
return ip, ".", nil
}
break
}
if ip.Mode&S_IFMT != S_IFDIR {
return nil, "", ENOTDIR
}
if len(elem) >= 256 {
return nil, "", ENAMETOOLONG
}
if parent && rest == "" {
// Stop one level early.
return ip, elem, nil
}
de, _, err := fs.dirlookup(ip, elem)
if err != nil {
return nil, "", err
}
ip = de.inode
path = rest
}
if parent {
return nil, "", ENOTDIR
}
return ip, "", nil
}
// open opens or creates a file with the given name, open mode,
// and permission mode bits.
func (fs *fsys) open(name string, openmode int, mode uint32) (fileImpl, error) {
dp, elem, err := fs.namei(name, true)
if err != nil {
return nil, err
}
var (
ip *inode
dev devFile
)
de, _, err := fs.dirlookup(dp, elem)
if err != nil {
if openmode&O_CREATE == 0 {
return nil, err
}
ip = fs.newInode()
ip.Mode = mode
fs.dirlink(dp, elem, ip)
if ip.Mode&S_IFMT == S_IFDIR {
fs.dirlink(ip, ".", ip)
fs.dirlink(ip, "..", dp)
}
} else {
ip = de.inode
if openmode&(O_CREATE|O_EXCL) == O_CREATE|O_EXCL {
return nil, EEXIST
}
if openmode&O_TRUNC != 0 {
if ip.Mode&S_IFMT == S_IFDIR {
return nil, EISDIR
}
ip.data = nil
}
if ip.Mode&S_IFMT == S_IFCHR {
if ip.Rdev < 0 || ip.Rdev >= int64(len(fs.dev)) || fs.dev[ip.Rdev] == nil {
return nil, ENODEV
}
dev, err = fs.dev[ip.Rdev]()
if err != nil {
return nil, err
}
}
}
switch openmode & O_ACCMODE {
case O_WRONLY, O_RDWR:
if ip.Mode&S_IFMT == S_IFDIR {
return nil, EISDIR
}
}
switch ip.Mode & S_IFMT {
case S_IFDIR:
if openmode&O_ACCMODE != O_RDONLY {
return nil, EISDIR
}
case S_IFREG:
// ok
case S_IFCHR:
// handled above
default:
// TODO: some kind of special file
return nil, EPERM
}
f := &fsysFile{
fsys: fs,
inode: ip,
openmode: openmode,
dev: dev,
}
if openmode&O_APPEND != 0 {
f.offset = ip.Size
}
return f, nil
}
// fsysFile methods to implement fileImpl.
func (f *fsysFile) stat(st *Stat_t) error {
f.fsys.mu.Lock()
defer f.fsys.mu.Unlock()
*st = f.inode.Stat_t
return nil
}
func (f *fsysFile) read(b []byte) (int, error) {
f.fsys.mu.Lock()
defer f.fsys.mu.Unlock()
n, err := f.preadLocked(b, f.offset)
f.offset += int64(n)
return n, err
}
func ReadDirent(fd int, buf []byte) (int, error) {
f, err := fdToFsysFile(fd)
if err != nil {
return 0, err
}
f.fsys.mu.Lock()
defer f.fsys.mu.Unlock()
if f.inode.Mode&S_IFMT != S_IFDIR {
return 0, EINVAL
}
n, err := f.preadLocked(buf, f.offset)
f.offset += int64(n)
return n, err
}
func (f *fsysFile) write(b []byte) (int, error) {
f.fsys.mu.Lock()
defer f.fsys.mu.Unlock()
n, err := f.pwriteLocked(b, f.offset)
f.offset += int64(n)
return n, err
}
func (f *fsysFile) seek(offset int64, whence int) (int64, error) {
f.fsys.mu.Lock()
defer f.fsys.mu.Unlock()
switch whence {
case 1:
offset += f.offset
case 2:
offset += f.inode.Size
}
if offset < 0 {
return 0, EINVAL
}
if offset > f.inode.Size {
return 0, EINVAL
}
f.offset = offset
return offset, nil
}
func (f *fsysFile) pread(b []byte, offset int64) (int, error) {
f.fsys.mu.Lock()
defer f.fsys.mu.Unlock()
return f.preadLocked(b, offset)
}
func (f *fsysFile) pwrite(b []byte, offset int64) (int, error) {
f.fsys.mu.Lock()
defer f.fsys.mu.Unlock()
return f.pwriteLocked(b, offset)
}
func (f *fsysFile) preadLocked(b []byte, offset int64) (int, error) {
if f.openmode&O_ACCMODE == O_WRONLY {
return 0, EINVAL
}
if offset < 0 {
return 0, EINVAL
}
if f.dev != nil {
f.fsys.atime(f.inode)
f.fsys.mu.Unlock()
defer f.fsys.mu.Lock()
return f.dev.pread(b, offset)
}
if offset > f.inode.Size {
return 0, nil
}
if int64(len(b)) > f.inode.Size-offset {
b = b[:f.inode.Size-offset]
}
if f.inode.Mode&S_IFMT == S_IFDIR {
if offset%direntSize != 0 || len(b) != 0 && len(b) < direntSize {
return 0, EINVAL
}
fs.atime(f.inode)
n := 0
for len(b) >= direntSize {
src := f.inode.dir[int(offset/direntSize)]
dst := (*Dirent)(unsafe.Pointer(&b[0]))
dst.Ino = int64(src.inode.Ino)
dst.Off = offset
dst.Reclen = direntSize
for i := range dst.Name {
dst.Name[i] = 0
}
copy(dst.Name[:], src.name)
n += direntSize
offset += direntSize
b = b[direntSize:]
}
return n, nil
}
fs.atime(f.inode)
n := copy(b, f.inode.data[offset:])
return n, nil
}
func (f *fsysFile) pwriteLocked(b []byte, offset int64) (int, error) {
if f.openmode&O_ACCMODE == O_RDONLY {
return 0, EINVAL
}
if offset < 0 {
return 0, EINVAL
}
if f.dev != nil {
f.fsys.atime(f.inode)
f.fsys.mu.Unlock()
defer f.fsys.mu.Lock()
return f.dev.pwrite(b, offset)
}
if offset > f.inode.Size {
return 0, EINVAL
}
f.fsys.mtime(f.inode)
n := copy(f.inode.data[offset:], b)
if n < len(b) {
f.inode.data = append(f.inode.data, b[n:]...)
f.inode.Size = int64(len(f.inode.data))
}
return len(b), nil
}
// Standard Unix system calls.
func Open(path string, openmode int, perm uint32) (fd int, err error) {
fsinit()
fs.mu.Lock()
defer fs.mu.Unlock()
f, err := fs.open(path, openmode, perm&0777|S_IFREG)
if err != nil {
return -1, err
}
return newFD(f), nil
}
func Mkdir(path string, perm uint32) error {
fs.mu.Lock()
defer fs.mu.Unlock()
_, err := fs.open(path, O_CREATE|O_EXCL, perm&0777|S_IFDIR)
return err
}
func Getcwd(buf []byte) (n int, err error) {
// Force package os to default to the old algorithm using .. and directory reads.
return 0, ENOSYS
}
func Stat(path string, st *Stat_t) error {
fsinit()
fs.mu.Lock()
defer fs.mu.Unlock()
ip, _, err := fs.namei(path, false)
if err != nil {
return err
}
*st = ip.Stat_t
return nil
}
func Lstat(path string, st *Stat_t) error {
return Stat(path, st)
}
func unlink(path string, isdir bool) error {
fsinit()
fs.mu.Lock()
defer fs.mu.Unlock()
dp, elem, err := fs.namei(path, true)
if err != nil {
return err
}
if elem == "." || elem == ".." {
return EINVAL
}
de, _, err := fs.dirlookup(dp, elem)
if err != nil {
return err
}
if isdir {
if de.inode.Mode&S_IFMT != S_IFDIR {
return ENOTDIR
}
if len(de.inode.dir) != 2 {
return ENOTEMPTY
}
} else {
if de.inode.Mode&S_IFMT == S_IFDIR {
return EISDIR
}
}
de.inode.Nlink--
*de = dp.dir[len(dp.dir)-1]
dp.dir = dp.dir[:len(dp.dir)-1]
dp.dirSize()
return nil
}
func Unlink(path string) error {
return unlink(path, false)
}
func Rmdir(path string) error {
return unlink(path, true)
}
func Chmod(path string, mode uint32) error {
fsinit()
fs.mu.Lock()
defer fs.mu.Unlock()
ip, _, err := fs.namei(path, false)
if err != nil {
return err
}
ip.Mode = ip.Mode&^0777 | mode&0777
return nil
}
func Fchmod(fd int, mode uint32) error {
f, err := fdToFsysFile(fd)
if err != nil {
return err
}
f.fsys.mu.Lock()
defer f.fsys.mu.Unlock()
f.inode.Mode = f.inode.Mode&^0777 | mode&0777
return nil
}
func Chown(path string, uid, gid int) error {
fsinit()
fs.mu.Lock()
defer fs.mu.Unlock()
ip, _, err := fs.namei(path, false)
if err != nil {
return err
}
ip.Uid = uint32(uid)
ip.Gid = uint32(gid)
return nil
}
func Fchown(fd int, uid, gid int) error {
fs.mu.Lock()
defer fs.mu.Unlock()
f, err := fdToFsysFile(fd)
if err != nil {
return err
}
f.fsys.mu.Lock()
defer f.fsys.mu.Unlock()
f.inode.Uid = uint32(uid)
f.inode.Gid = uint32(gid)
return nil
}
func Lchown(path string, uid, gid int) error {
return Chown(path, uid, gid)
}
func UtimesNano(path string, ts []Timespec) error {
if len(ts) != 2 {
return EINVAL
}
fsinit()
fs.mu.Lock()
defer fs.mu.Unlock()
ip, _, err := fs.namei(path, false)
if err != nil {
return err
}
ip.Atime = ts[0].Sec
ip.AtimeNsec = int64(ts[0].Nsec)
ip.Mtime = ts[1].Sec
ip.MtimeNsec = int64(ts[1].Nsec)
return nil
}
func Link(path, link string) error {
fsinit()
ip, _, err := fs.namei(path, false)
if err != nil {
return err
}
dp, elem, err := fs.namei(link, true)
if err != nil {
return err
}
if ip.Mode&S_IFMT == S_IFDIR {
return EPERM
}
fs.dirlink(dp, elem, ip)
return nil
}
func Rename(from, to string) error {
fsinit()
fdp, felem, err := fs.namei(from, true)
if err != nil {
return err
}
fde, _, err := fs.dirlookup(fdp, felem)
if err != nil {
return err
}
tdp, telem, err := fs.namei(to, true)
if err != nil {
return err
}
fs.dirlink(tdp, telem, fde.inode)
fde.inode.Nlink--
*fde = fdp.dir[len(fdp.dir)-1]
fdp.dir = fdp.dir[:len(fdp.dir)-1]
fdp.dirSize()
return nil
}
func (fs *fsys) truncate(ip *inode, length int64) error {
if length > 1e9 || ip.Mode&S_IFMT != S_IFREG {
return EINVAL
}
if length < int64(len(ip.data)) {
ip.data = ip.data[:length]
} else {
data := make([]byte, length)
copy(data, ip.data)
ip.data = data
}
ip.Size = int64(len(ip.data))
return nil
}
func Truncate(path string, length int64) error {
fsinit()
fs.mu.Lock()
defer fs.mu.Unlock()
ip, _, err := fs.namei(path, false)
if err != nil {
return err
}
return fs.truncate(ip, length)
}
func Ftruncate(fd int, length int64) error {
f, err := fdToFsysFile(fd)
if err != nil {
return err
}
f.fsys.mu.Lock()
defer f.fsys.mu.Unlock()
return f.fsys.truncate(f.inode, length)
}
func Chdir(path string) error {
fsinit()
return chdir(path)
}
func chdir(path string) error {
fs.mu.Lock()
defer fs.mu.Unlock()
ip, _, err := fs.namei(path, false)
if err != nil {
return err
}
fs.cwd = ip
return nil
}
func Fchdir(fd int) error {
f, err := fdToFsysFile(fd)
if err != nil {
return err
}
f.fsys.mu.Lock()
defer f.fsys.mu.Unlock()
if f.inode.Mode&S_IFMT != S_IFDIR {
return ENOTDIR
}
fs.cwd = f.inode
return nil
}
func Readlink(path string, buf []byte) (n int, err error) {
return 0, ENOSYS
}
func Symlink(path, link string) error {
return ENOSYS
}
func Fsync(fd int) error {
return nil
}
// Special devices.
func mkdev(path string, mode uint32, open func() (devFile, error)) error {
f, err := fs.open(path, O_CREATE|O_RDONLY|O_EXCL, S_IFCHR|mode)
if err != nil {
return err
}
ip := f.(*fsysFile).inode
ip.Rdev = int64(len(fs.dev))
fs.dev = append(fs.dev, open)
return nil
}
type nullFile struct{}
func openNull() (devFile, error) { return &nullFile{}, nil }
func (f *nullFile) close() error { return nil }
func (f *nullFile) pread(b []byte, offset int64) (int, error) { return 0, nil }
func (f *nullFile) pwrite(b []byte, offset int64) (int, error) { return len(b), nil }
type zeroFile struct{}
func openZero() (devFile, error) { return &zeroFile{}, nil }
func (f *zeroFile) close() error { return nil }
func (f *zeroFile) pwrite(b []byte, offset int64) (int, error) { return len(b), nil }
func (f *zeroFile) pread(b []byte, offset int64) (int, error) {
for i := range b {
b[i] = 0
}
return len(b), nil
}
type randomFile struct {
naclFD int
}
func openRandom() (devFile, error) {
fd, err := openNamedService("SecureRandom", O_RDONLY)
if err != nil {
return nil, err
}
return &randomFile{naclFD: fd}, nil
}
func (f *randomFile) close() error {
naclClose(f.naclFD)
f.naclFD = -1
return nil
}
func (f *randomFile) pread(b []byte, offset int64) (int, error) {
return naclRead(f.naclFD, b)
}
func (f *randomFile) pwrite(b []byte, offset int64) (int, error) {
return 0, EPERM
}
func fdToFsysFile(fd int) (*fsysFile, error) {
f, err := fdToFile(fd)
if err != nil {
return nil, err
}
impl := f.impl
fsysf, ok := impl.(*fsysFile)
if !ok {
return nil, EINVAL
}
return fsysf, nil
}
// create creates a file in the file system with the given name, mode, time, and data.
// It is meant to be called when initializing the file system image.
func create(name string, mode uint32, sec int64, data []byte) error {
fs.mu.Lock()
fs.mu.Unlock()
f, err := fs.open(name, O_CREATE|O_EXCL, mode)
if err != nil {
return err
}
ip := f.(*fsysFile).inode
ip.Atime = sec
ip.Mtime = sec
ip.Ctime = sec
if len(data) > 0 {
ip.Size = int64(len(data))
ip.data = data
}
return nil
}
......@@ -176,18 +176,6 @@ linux_arm)
mksysnum="curl -s 'http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/plain/arch/arm/include/uapi/asm/unistd.h' | ./mksysnum_linux.pl"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
nacl_386)
mkerrors=""
mksyscall="./mksyscall.pl -l32 -nacl"
mksysnum=""
mktypes=""
;;
nacl_amd64p32)
mkerrors=""
mksyscall="./mksyscall.pl -nacl"
mksysnum=""
mktypes=""
;;
netbsd_386)
mkerrors="$mkerrors -m32"
mksyscall="./mksyscall.pl -l32 -netbsd"
......
......@@ -28,7 +28,6 @@ my $plan9 = 0;
my $openbsd = 0;
my $netbsd = 0;
my $dragonfly = 0;
my $nacl = 0;
my $arm = 0; # 64-bit value should use (even, odd)-pair
if($ARGV[0] eq "-b32") {
......@@ -54,10 +53,6 @@ if($ARGV[0] eq "-dragonfly") {
$dragonfly = 1;
shift;
}
if($ARGV[0] eq "-nacl") {
$nacl = 1;
shift;
}
if($ARGV[0] eq "-arm") {
$arm = 1;
shift;
......@@ -224,9 +219,6 @@ while(<>) {
$sysname = "SYS_$func";
$sysname =~ s/([a-z])([A-Z])/${1}_$2/g; # turn FooBar into Foo_Bar
$sysname =~ y/a-z/A-Z/;
if($nacl) {
$sysname =~ y/A-Z/a-z/;
}
}
# Actual call.
......
// 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.
// A simulated network for use within NaCl.
// The simulation is not particularly tied to NaCl,
// but other systems have real networks.
package unix
import (
"sync"
"sync/atomic"
)
// Interface to timers implemented in package runtime.
// Must be in sync with ../runtime/runtime.h:/^struct.Timer$
// Really for use by package time, but we cannot import time here.
type runtimeTimer struct {
i int32
when int64
period int64
f func(int64, interface{}) // NOTE: must not be closure
arg interface{}
}
func startTimer(*runtimeTimer)
func stopTimer(*runtimeTimer) bool
type timer struct {
expired bool
q *queue
r runtimeTimer
}
func (t *timer) start(q *queue, deadline int64) {
if deadline == 0 {
return
}
t.q = q
t.r.when = deadline
t.r.f = timerExpired
t.r.arg = t
startTimer(&t.r)
}
func (t *timer) stop() {
stopTimer(&t.r)
}
func timerExpired(now int64, i interface{}) {
t := i.(*timer)
go func() {
t.q.Lock()
defer t.q.Unlock()
t.expired = true
t.q.canRead.Broadcast()
t.q.canWrite.Broadcast()
}()
}
// Network constants and data structures. These match the traditional values.
const (
AF_UNSPEC = iota
AF_UNIX
AF_INET
AF_INET6
)
const (
SHUT_RD = iota
SHUT_WR
SHUT_RDWR
)
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
)
// Misc constants expected by package net but not supported.
const (
_ = iota
SOL_SOCKET
SO_TYPE
NET_RT_IFLIST
IFNAMSIZ
IFF_UP
IFF_BROADCAST
IFF_LOOPBACK
IFF_POINTOPOINT
IFF_MULTICAST
IPV6_V6ONLY
SOMAXCONN
F_DUPFD_CLOEXEC
SO_BROADCAST
SO_REUSEADDR
SO_REUSEPORT
SO_RCVBUF
SO_SNDBUF
SO_KEEPALIVE
SO_LINGER
SO_ERROR
IP_PORTRANGE
IP_PORTRANGE_DEFAULT
IP_PORTRANGE_LOW
IP_PORTRANGE_HIGH
IP_MULTICAST_IF
IP_MULTICAST_LOOP
IP_ADD_MEMBERSHIP
IPV6_PORTRANGE
IPV6_PORTRANGE_DEFAULT
IPV6_PORTRANGE_LOW
IPV6_PORTRANGE_HIGH
IPV6_MULTICAST_IF
IPV6_MULTICAST_LOOP
IPV6_JOIN_GROUP
TCP_NODELAY
TCP_KEEPINTVL
TCP_KEEPIDLE
SYS_FCNTL = 500 // unsupported
)
var SocketDisableIPv6 bool
// A Sockaddr is one of the SockaddrXxx structs.
type Sockaddr interface {
// copy returns a copy of the underlying data.
copy() Sockaddr
// key returns the value of the underlying data,
// for comparison as a map key.
key() interface{}
}
type SockaddrInet4 struct {
Port int
Addr [4]byte
}
func (sa *SockaddrInet4) copy() Sockaddr {
sa1 := *sa
return &sa1
}
func (sa *SockaddrInet4) key() interface{} { return *sa }
type SockaddrInet6 struct {
Port int
ZoneId uint32
Addr [16]byte
}
func (sa *SockaddrInet6) copy() Sockaddr {
sa1 := *sa
return &sa1
}
func (sa *SockaddrInet6) key() interface{} { return *sa }
type SockaddrUnix struct {
Name string
}
func (sa *SockaddrUnix) copy() Sockaddr {
sa1 := *sa
return &sa1
}
func (sa *SockaddrUnix) key() interface{} { return *sa }
type SockaddrDatalink struct {
Len uint8
Family uint8
Index uint16
Type uint8
Nlen uint8
Alen uint8
Slen uint8
Data [12]int8
}
func (sa *SockaddrDatalink) copy() Sockaddr {
sa1 := *sa
return &sa1
}
func (sa *SockaddrDatalink) key() interface{} { return *sa }
// RoutingMessage represents a routing message.
type RoutingMessage interface {
unimplemented()
}
type IPMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
type IPv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Interface uint32
}
type Linger struct {
Onoff int32
Linger int32
}
type ICMPv6Filter struct {
Filt [8]uint32
}
// A queue is the bookkeeping for a synchronized buffered queue.
// We do not use channels because we need to be able to handle
// writes after and during close, and because a chan byte would
// require too many send and receive operations in real use.
type queue struct {
sync.Mutex
canRead sync.Cond
canWrite sync.Cond
r int // total read index
w int // total write index
m int // index mask
closed bool
}
func (q *queue) init(size int) {
if size&(size-1) != 0 {
panic("invalid queue size - must be power of two")
}
q.canRead.L = &q.Mutex
q.canWrite.L = &q.Mutex
q.m = size - 1
}
func past(deadline int64) bool {
sec, nsec := now()
return deadline > 0 && deadline < sec*1e9+int64(nsec)
}
func (q *queue) waitRead(n int, deadline int64) (int, error) {
if past(deadline) {
return 0, EAGAIN
}
var t timer
t.start(q, deadline)
for q.w-q.r == 0 && !q.closed && !t.expired {
q.canRead.Wait()
}
t.stop()
m := q.w - q.r
if m == 0 && t.expired {
return 0, EAGAIN
}
if m > n {
m = n
q.canRead.Signal() // wake up next reader too
}
q.canWrite.Signal()
return m, nil
}
func (q *queue) waitWrite(n int, deadline int64) (int, error) {
if past(deadline) {
return 0, EAGAIN
}
var t timer
t.start(q, deadline)
for q.w-q.r > q.m && !q.closed && !t.expired {
q.canWrite.Wait()
}
t.stop()
m := q.m + 1 - (q.w - q.r)
if m == 0 && t.expired {
return 0, EAGAIN
}
if m == 0 {
return 0, EAGAIN
}
if m > n {
m = n
q.canWrite.Signal() // wake up next writer too
}
q.canRead.Signal()
return m, nil
}
func (q *queue) close() {
q.Lock()
defer q.Unlock()
q.closed = true
q.canRead.Broadcast()
q.canWrite.Broadcast()
}
// A byteq is a byte queue.
type byteq struct {
queue
data []byte
}
func newByteq() *byteq {
q := &byteq{
data: make([]byte, 4096),
}
q.init(len(q.data))
return q
}
func (q *byteq) read(b []byte, deadline int64) (int, error) {
q.Lock()
defer q.Unlock()
n, err := q.waitRead(len(b), deadline)
if err != nil {
return 0, err
}
b = b[:n]
for len(b) > 0 {
m := copy(b, q.data[q.r&q.m:])
q.r += m
b = b[m:]
}
return n, nil
}
func (q *byteq) write(b []byte, deadline int64) (n int, err error) {
q.Lock()
defer q.Unlock()
for n < len(b) {
nn, err := q.waitWrite(len(b[n:]), deadline)
if err != nil {
return n, err
}
bb := b[n : n+nn]
n += nn
for len(bb) > 0 {
m := copy(q.data[q.w&q.m:], bb)
q.w += m
bb = bb[m:]
}
}
return n, nil
}
// A msgq is a queue of messages.
type msgq struct {
queue
data []interface{}
}
func newMsgq() *msgq {
q := &msgq{
data: make([]interface{}, 32),
}
q.init(len(q.data))
return q
}
func (q *msgq) read(deadline int64) (interface{}, error) {
q.Lock()
defer q.Unlock()
n, err := q.waitRead(1, deadline)
if err != nil {
return nil, err
}
if n == 0 {
return nil, nil
}
m := q.data[q.r&q.m]
q.r++
return m, nil
}
func (q *msgq) write(m interface{}, deadline int64) error {
q.Lock()
defer q.Unlock()
_, err := q.waitWrite(1, deadline)
if err != nil {
return err
}
q.data[q.w&q.m] = m
q.w++
return nil
}
// An addr is a sequence of bytes uniquely identifying a network address.
// It is not human-readable.
type addr string
// A conn is one side of a stream-based network connection.
// That is, a stream-based network connection is a pair of cross-connected conns.
type conn struct {
rd *byteq
wr *byteq
local addr
remote addr
}
// A pktconn is one side of a packet-based network connection.
// That is, a packet-based network connection is a pair of cross-connected pktconns.
type pktconn struct {
rd *msgq
wr *msgq
local addr
remote addr
}
// A listener accepts incoming stream-based network connections.
type listener struct {
rd *msgq
local addr
}
// A netFile is an open network file.
type netFile struct {
defaultFileImpl
proto *netproto
sotype int
listener *msgq
packet *msgq
rd *byteq
wr *byteq
rddeadline int64
wrdeadline int64
addr Sockaddr
raddr Sockaddr
}
// A netAddr is a network address in the global listener map.
// All the fields must have defined == operations.
type netAddr struct {
proto *netproto
sotype int
addr interface{}
}
// net records the state of the network.
// It maps a network address to the listener on that address.
var net = struct {
sync.Mutex
listener map[netAddr]*netFile
}{
listener: make(map[netAddr]*netFile),
}
// TODO(rsc): Some day, do a better job with port allocation.
// For playground programs, incrementing is fine.
var nextport = 2
// A netproto contains protocol-specific functionality
// (one for AF_INET, one for AF_INET6 and so on).
// It is a struct instead of an interface because the
// implementation needs no state, and I expect to
// add some data fields at some point.
type netproto struct {
bind func(*netFile, Sockaddr) error
}
var netprotoAF_INET = &netproto{
bind: func(f *netFile, sa Sockaddr) error {
if sa == nil {
f.addr = &SockaddrInet4{
Port: nextport,
Addr: [4]byte{127, 0, 0, 1},
}
nextport++
return nil
}
addr, ok := sa.(*SockaddrInet4)
if !ok {
return EINVAL
}
addr = addr.copy().(*SockaddrInet4)
if addr.Port == 0 {
addr.Port = nextport
nextport++
}
f.addr = addr
return nil
},
}
var netprotos = map[int]*netproto{
AF_INET: netprotoAF_INET,
}
// These functions implement the usual BSD socket operations.
func (f *netFile) bind(sa Sockaddr) error {
if f.addr != nil {
return EISCONN
}
if err := f.proto.bind(f, sa); err != nil {
return err
}
if f.sotype == SOCK_DGRAM {
_, ok := net.listener[netAddr{f.proto, f.sotype, f.addr.key()}]
if ok {
f.addr = nil
return EADDRINUSE
}
net.listener[netAddr{f.proto, f.sotype, f.addr.key()}] = f
f.packet = newMsgq()
}
return nil
}
func (f *netFile) listen(backlog int) error {
net.Lock()
defer net.Unlock()
if f.listener != nil {
return EINVAL
}
_, ok := net.listener[netAddr{f.proto, f.sotype, f.addr.key()}]
if ok {
return EADDRINUSE
}
net.listener[netAddr{f.proto, f.sotype, f.addr.key()}] = f
f.listener = newMsgq()
return nil
}
func (f *netFile) accept() (fd int, sa Sockaddr, err error) {
msg, err := f.listener.read(f.readDeadline())
if err != nil {
return -1, nil, err
}
newf, ok := msg.(*netFile)
if !ok {
// must be eof
return -1, nil, EAGAIN
}
return newFD(newf), newf.raddr.copy(), nil
}
func (f *netFile) connect(sa Sockaddr) error {
if past(f.writeDeadline()) {
return EAGAIN
}
if f.addr == nil {
if err := f.bind(nil); err != nil {
return err
}
}
net.Lock()
if sa == nil {
net.Unlock()
return EINVAL
}
sa = sa.copy()
if f.raddr != nil {
net.Unlock()
return EISCONN
}
if f.sotype == SOCK_DGRAM {
net.Unlock()
f.raddr = sa
return nil
}
if f.listener != nil {
net.Unlock()
return EISCONN
}
l, ok := net.listener[netAddr{f.proto, f.sotype, sa.key()}]
if !ok {
net.Unlock()
return ECONNREFUSED
}
f.raddr = sa
f.rd = newByteq()
f.wr = newByteq()
newf := &netFile{
proto: f.proto,
sotype: f.sotype,
addr: f.raddr,
raddr: f.addr,
rd: f.wr,
wr: f.rd,
}
net.Unlock()
l.listener.write(newf, f.writeDeadline())
return nil
}
func (f *netFile) read(b []byte) (int, error) {
if f.rd == nil {
if f.raddr != nil {
n, _, err := f.recvfrom(b, 0)
return n, err
}
return 0, ENOTCONN
}
return f.rd.read(b, f.readDeadline())
}
func (f *netFile) write(b []byte) (int, error) {
if f.wr == nil {
if f.raddr != nil {
err := f.sendto(b, 0, f.raddr)
var n int
if err == nil {
n = len(b)
}
return n, err
}
return 0, ENOTCONN
}
return f.wr.write(b, f.writeDeadline())
}
type pktmsg struct {
buf []byte
addr Sockaddr
}
func (f *netFile) recvfrom(p []byte, flags int) (n int, from Sockaddr, err error) {
if f.sotype != SOCK_DGRAM {
return 0, nil, EINVAL
}
if f.packet == nil {
return 0, nil, ENOTCONN
}
msg1, err := f.packet.read(f.readDeadline())
if err != nil {
return 0, nil, err
}
msg, ok := msg1.(*pktmsg)
if !ok {
return 0, nil, EAGAIN
}
return copy(p, msg.buf), msg.addr, nil
}
func (f *netFile) sendto(p []byte, flags int, to Sockaddr) error {
if f.sotype != SOCK_DGRAM {
return EINVAL
}
if f.packet == nil {
if err := f.bind(nil); err != nil {
return err
}
}
net.Lock()
if to == nil {
net.Unlock()
return EINVAL
}
to = to.copy()
l, ok := net.listener[netAddr{f.proto, f.sotype, to.key()}]
if !ok || l.packet == nil {
net.Unlock()
return ECONNREFUSED
}
net.Unlock()
msg := &pktmsg{
buf: make([]byte, len(p)),
addr: f.addr,
}
copy(msg.buf, p)
l.packet.write(msg, f.writeDeadline())
return nil
}
func (f *netFile) close() error {
if f.listener != nil {
f.listener.close()
}
if f.packet != nil {
f.packet.close()
}
if f.rd != nil {
f.rd.close()
}
if f.wr != nil {
f.wr.close()
}
return nil
}
func fdToNetFile(fd int) (*netFile, error) {
f, err := fdToFile(fd)
if err != nil {
return nil, err
}
impl := f.impl
netf, ok := impl.(*netFile)
if !ok {
return nil, EINVAL
}
return netf, nil
}
func Socket(proto, sotype, unused int) (fd int, err error) {
p := netprotos[proto]
if p == nil {
return -1, EPROTONOSUPPORT
}
if sotype != SOCK_STREAM && sotype != SOCK_DGRAM {
return -1, ESOCKTNOSUPPORT
}
f := &netFile{
proto: p,
sotype: sotype,
}
return newFD(f), nil
}
func Bind(fd int, sa Sockaddr) error {
f, err := fdToNetFile(fd)
if err != nil {
return err
}
return f.bind(sa)
}
func StopIO(fd int) error {
f, err := fdToNetFile(fd)
if err != nil {
return err
}
f.close()
return nil
}
func Listen(fd int, backlog int) error {
f, err := fdToNetFile(fd)
if err != nil {
return err
}
return f.listen(backlog)
}
func Accept(fd int) (newfd int, sa Sockaddr, err error) {
f, err := fdToNetFile(fd)
if err != nil {
return 0, nil, err
}
return f.accept()
}
func Getsockname(fd int) (sa Sockaddr, err error) {
f, err := fdToNetFile(fd)
if err != nil {
return nil, err
}
if f.addr == nil {
return nil, ENOTCONN
}
return f.addr.copy(), nil
}
func Getpeername(fd int) (sa Sockaddr, err error) {
f, err := fdToNetFile(fd)
if err != nil {
return nil, err
}
if f.raddr == nil {
return nil, ENOTCONN
}
return f.raddr.copy(), nil
}
func Connect(fd int, sa Sockaddr) error {
f, err := fdToNetFile(fd)
if err != nil {
return err
}
return f.connect(sa)
}
func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, err error) {
f, err := fdToNetFile(fd)
if err != nil {
return 0, nil, err
}
return f.recvfrom(p, flags)
}
func Sendto(fd int, p []byte, flags int, to Sockaddr) error {
f, err := fdToNetFile(fd)
if err != nil {
return err
}
return f.sendto(p, flags, to)
}
func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn, recvflags int, from Sockaddr, err error) {
f, err := fdToNetFile(fd)
if err != nil {
return
}
n, from, err = f.recvfrom(p, flags)
return
}
func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) error {
_, err := SendmsgN(fd, p, oob, to, flags)
return err
}
func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) {
f, err := fdToNetFile(fd)
if err != nil {
return 0, err
}
switch f.sotype {
case SOCK_STREAM:
n, err = f.write(p)
case SOCK_DGRAM:
n = len(p)
err = f.sendto(p, flags, to)
}
if err != nil {
return 0, err
}
return n, nil
}
func GetsockoptInt(fd, level, opt int) (value int, err error) {
f, err := fdToNetFile(fd)
if err != nil {
return 0, err
}
switch {
case level == SOL_SOCKET && opt == SO_TYPE:
return f.sotype, nil
}
return 0, ENOTSUP
}
func SetsockoptInt(fd, level, opt int, value int) error {
return nil
}
func SetsockoptByte(fd, level, opt int, value byte) error {
_, err := fdToNetFile(fd)
if err != nil {
return err
}
return ENOTSUP
}
func SetsockoptLinger(fd, level, opt int, l *Linger) error {
return nil
}
func SetReadDeadline(fd int, t int64) error {
f, err := fdToNetFile(fd)
if err != nil {
return err
}
atomic.StoreInt64(&f.rddeadline, t)
return nil
}
func (f *netFile) readDeadline() int64 {
return atomic.LoadInt64(&f.rddeadline)
}
func SetWriteDeadline(fd int, t int64) error {
f, err := fdToNetFile(fd)
if err != nil {
return err
}
atomic.StoreInt64(&f.wrdeadline, t)
return nil
}
func (f *netFile) writeDeadline() int64 {
return atomic.LoadInt64(&f.wrdeadline)
}
func Shutdown(fd int, how int) error {
f, err := fdToNetFile(fd)
if err != nil {
return err
}
switch how {
case SHUT_RD:
f.rd.close()
case SHUT_WR:
f.wr.close()
case SHUT_RDWR:
f.rd.close()
f.wr.close()
}
return nil
}
func SetsockoptICMPv6Filter(fd, level, opt int, filter *ICMPv6Filter) error { panic("SetsockoptICMPv") }
func SetsockoptIPMreq(fd, level, opt int, mreq *IPMreq) error { panic("SetsockoptIPMreq") }
func SetsockoptIPv6Mreq(fd, level, opt int, mreq *IPv6Mreq) error { panic("SetsockoptIPv") }
func SetsockoptInet4Addr(fd, level, opt int, value [4]byte) error { panic("SetsockoptInet") }
func SetsockoptString(fd, level, opt int, s string) error { panic("SetsockoptString") }
func SetsockoptTimeval(fd, level, opt int, tv *Timeval) error { panic("SetsockoptTimeval") }
func Socketpair(domain, typ, proto int) (fd [2]int, err error) { panic("Socketpair") }
func SetNonblock(fd int, nonblocking bool) error { return nil }
// 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.
// Native Client SRPC message passing.
// This code is needed to invoke SecureRandom, the NaCl equivalent of /dev/random.
package unix
import (
"errors"
"sync"
"unsafe"
)
// An srpcClient represents the client side of an SRPC connection.
type srpcClient struct {
fd int // to server
r msgReceiver
s msgSender
service map[string]srpcService // services by name
outMu sync.Mutex // protects writing to connection
mu sync.Mutex // protects following fields
muxer bool // is someone reading and muxing responses
pending map[uint32]*srpc
idGen uint32 // generator for request IDs
}
// An srpcService is a single method that the server offers.
type srpcService struct {
num uint32 // method number
fmt string // argument format; see "parsing of RPC messages" below
}
// An srpc represents a single srpc issued by a client.
type srpc struct {
Ret []interface{}
Done chan *srpc
Err error
c *srpcClient
id uint32
}
// newClient allocates a new SRPC client using the file descriptor fd.
func newClient(fd int) (*srpcClient, error) {
c := new(srpcClient)
c.fd = fd
c.r.fd = fd
c.s.fd = fd
c.service = make(map[string]srpcService)
c.pending = make(map[uint32]*srpc)
// service discovery request
m := &msg{
isRequest: 1,
template: []interface{}{[]byte(nil)},
size: []int{4000}, // max size to accept for returned byte slice
}
if err := m.pack(); err != nil {
return nil, errors.New("Native Client SRPC service_discovery: preparing request: " + err.Error())
}
c.s.send(m)
m, err := c.r.recv()
if err != nil {
return nil, err
}
m.unpack()
if m.status != uint32(srpcOK) {
return nil, errors.New("Native Client SRPC service_discovery: " + srpcErrno(m.status).Error())
}
list := m.value[0].([]byte)
var n uint32
for len(list) > 0 {
var line []byte
i := byteIndex(list, '\n')
if i < 0 {
line, list = list, nil
} else {
line, list = list[:i], list[i+1:]
}
i = byteIndex(line, ':')
if i >= 0 {
c.service[string(line)] = srpcService{n, string(line[i+1:])}
}
n++
}
return c, nil
}
func byteIndex(b []byte, c byte) int {
for i, bi := range b {
if bi == c {
return i
}
}
return -1
}
var yourTurn srpc
func (c *srpcClient) wait(r *srpc) {
var rx *srpc
for rx = range r.Done {
if rx != &yourTurn {
break
}
c.input()
}
return
}
func (c *srpcClient) input() {
// read message
m, err := c.r.recv()
if err != nil {
println("Native Client SRPC receive error:", err.Error())
return
}
if m.unpack(); m.status != uint32(srpcOK) {
println("Native Client SRPC receive error: invalid message: ", srpcErrno(m.status).Error())
return
}
// deliver to intended recipient
c.mu.Lock()
rpc, ok := c.pending[m.id]
if ok {
delete(c.pending, m.id)
}
// wake a new muxer if there are more RPCs to read
c.muxer = false
for _, rpc := range c.pending {
c.muxer = true
rpc.Done <- &yourTurn
break
}
c.mu.Unlock()
if !ok {
println("Native Client: unexpected response for ID", m.id)
return
}
rpc.Ret = m.value
rpc.Done <- rpc
}
// Wait blocks until the RPC has finished.
func (r *srpc) Wait() {
r.c.wait(r)
}
// Start issues an RPC request for method name with the given arguments.
// The RPC r must not be in use for another pending request.
// To wait for the RPC to finish, receive from r.Done and then
// inspect r.Ret and r.Errno.
func (r *srpc) Start(name string, arg []interface{}) {
r.Err = nil
r.c.mu.Lock()
srv, ok := r.c.service[name]
if !ok {
r.c.mu.Unlock()
r.Err = srpcErrBadRPCNumber
r.Done <- r
return
}
r.c.pending[r.id] = r
if !r.c.muxer {
r.c.muxer = true
r.Done <- &yourTurn
}
r.c.mu.Unlock()
var m msg
m.id = r.id
m.isRequest = 1
m.rpc = srv.num
m.value = arg
// Fill in the return values and sizes to generate
// the right type chars. We'll take most any size.
// Skip over input arguments.
// We could check them against arg, but the server
// will do that anyway.
i := 0
for srv.fmt[i] != ':' {
i++
}
format := srv.fmt[i+1:]
// Now the return prototypes.
m.template = make([]interface{}, len(format))
m.size = make([]int, len(format))
for i := 0; i < len(format); i++ {
switch format[i] {
default:
println("Native Client SRPC: unexpected service type " + string(format[i]))
r.Err = srpcErrBadRPCNumber
r.Done <- r
return
case 'b':
m.template[i] = false
case 'C':
m.template[i] = []byte(nil)
m.size[i] = 1 << 30
case 'd':
m.template[i] = float64(0)
case 'D':
m.template[i] = []float64(nil)
m.size[i] = 1 << 30
case 'h':
m.template[i] = int(-1)
case 'i':
m.template[i] = int32(0)
case 'I':
m.template[i] = []int32(nil)
m.size[i] = 1 << 30
case 's':
m.template[i] = ""
m.size[i] = 1 << 30
}
}
if err := m.pack(); err != nil {
r.Err = errors.New("Native Client RPC Start " + name + ": preparing request: " + err.Error())
r.Done <- r
return
}
r.c.outMu.Lock()
r.c.s.send(&m)
r.c.outMu.Unlock()
}
// Call is a convenience wrapper that starts the RPC request,
// waits for it to finish, and then returns the results.
// Its implementation is:
//
// r.Start(name, arg)
// r.Wait()
// return r.Ret, r.Errno
//
func (c *srpcClient) Call(name string, arg ...interface{}) (ret []interface{}, err error) {
r := c.NewRPC(nil)
r.Start(name, arg)
r.Wait()
return r.Ret, r.Err
}
// NewRPC creates a new RPC on the client connection.
func (c *srpcClient) NewRPC(done chan *srpc) *srpc {
if done == nil {
done = make(chan *srpc, 1)
}
c.mu.Lock()
id := c.idGen
c.idGen++
c.mu.Unlock()
return &srpc{Done: done, c: c, id: id}
}
// The current protocol number.
// Kind of useless, since there have been backwards-incompatible changes
// to the wire protocol that did not update the protocol number.
// At this point it's really just a sanity check.
const protocol = 0xc0da0002
// An srpcErrno is an SRPC status code.
type srpcErrno uint32
const (
srpcOK srpcErrno = 256 + iota
srpcErrBreak
srpcErrMessageTruncated
srpcErrNoMemory
srpcErrProtocolMismatch
srpcErrBadRPCNumber
srpcErrBadArgType
srpcErrTooFewArgs
srpcErrTooManyArgs
srpcErrInArgTypeMismatch
srpcErrOutArgTypeMismatch
srpcErrInternalError
srpcErrAppError
)
var srpcErrstr = [...]string{
srpcOK - srpcOK: "ok",
srpcErrBreak - srpcOK: "break",
srpcErrMessageTruncated - srpcOK: "message truncated",
srpcErrNoMemory - srpcOK: "out of memory",
srpcErrProtocolMismatch - srpcOK: "protocol mismatch",
srpcErrBadRPCNumber - srpcOK: "invalid RPC method number",
srpcErrBadArgType - srpcOK: "unexpected argument type",
srpcErrTooFewArgs - srpcOK: "too few arguments",
srpcErrTooManyArgs - srpcOK: "too many arguments",
srpcErrInArgTypeMismatch - srpcOK: "input argument type mismatch",
srpcErrOutArgTypeMismatch - srpcOK: "output argument type mismatch",
srpcErrInternalError - srpcOK: "internal error",
srpcErrAppError - srpcOK: "application error",
}
func (e srpcErrno) Error() string {
if e < srpcOK || int(e-srpcOK) >= len(srpcErrstr) {
return "srpcErrno(" + itoa(int(e)) + ")"
}
return srpcErrstr[e-srpcOK]
}
// A msgHdr is the data argument to the imc_recvmsg
// and imc_sendmsg system calls.
type msgHdr struct {
iov *iov
niov int32
desc *int32
ndesc int32
flags uint32
}
// A single region for I/O.
type iov struct {
base *byte
len int32
}
const maxMsgSize = 1<<16 - 4*4
// A msgReceiver receives messages from a file descriptor.
type msgReceiver struct {
fd int
data [maxMsgSize]byte
desc [8]int32
hdr msgHdr
iov iov
}
func (r *msgReceiver) recv() (*msg, error) {
// Init pointers to buffers where syscall recvmsg can write.
r.iov.base = &r.data[0]
r.iov.len = int32(len(r.data))
r.hdr.iov = &r.iov
r.hdr.niov = 1
r.hdr.desc = &r.desc[0]
r.hdr.ndesc = int32(len(r.desc))
n, _, e := Syscall(sys_imc_recvmsg, uintptr(r.fd), uintptr(unsafe.Pointer(&r.hdr)), 0)
if e != 0 {
println("Native Client imc_recvmsg: ", e.Error())
return nil, e
}
// Make a copy of the data so that the next recvmsg doesn't
// smash it. The system call did not update r.iov.len. Instead it
// returned the total byte count as n.
m := new(msg)
m.data = make([]byte, n)
copy(m.data, r.data[0:])
// Make a copy of the desc too.
// The system call *did* update r.hdr.ndesc.
if r.hdr.ndesc > 0 {
m.desc = make([]int32, r.hdr.ndesc)
copy(m.desc, r.desc[:])
}
return m, nil
}
// A msgSender sends messages on a file descriptor.
type msgSender struct {
fd int
hdr msgHdr
iov iov
}
func (s *msgSender) send(m *msg) error {
if len(m.data) > 0 {
s.iov.base = &m.data[0]
}
s.iov.len = int32(len(m.data))
s.hdr.iov = &s.iov
s.hdr.niov = 1
s.hdr.desc = nil
s.hdr.ndesc = 0
_, _, e := Syscall(sys_imc_sendmsg, uintptr(s.fd), uintptr(unsafe.Pointer(&s.hdr)), 0)
if e != 0 {
println("Native Client imc_sendmsg: ", e.Error())
return e
}
return nil
}
// A msg is the Go representation of an SRPC message.
type msg struct {
data []byte // message data
desc []int32 // message file descriptors
// parsed version of message
id uint32
isRequest uint32
rpc uint32
status uint32
value []interface{}
template []interface{}
size []int
format string
broken bool
}
// reading from a msg
func (m *msg) uint32() uint32 {
if m.broken {
return 0
}
if len(m.data) < 4 {
m.broken = true
return 0
}
b := m.data[:4]
x := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
m.data = m.data[4:]
return x
}
func (m *msg) uint64() uint64 {
x := uint64(m.uint32()) | uint64(m.uint32())<<32
if m.broken {
return 0
}
return x
}
func (m *msg) bytes(n int) []byte {
if m.broken {
return nil
}
if len(m.data) < n {
m.broken = true
return nil
}
x := m.data[0:n]
m.data = m.data[n:]
return x
}
// writing to a msg
func (m *msg) wuint32(x uint32) {
m.data = append(m.data, byte(x), byte(x>>8), byte(x>>16), byte(x>>24))
}
func (m *msg) wuint64(x uint64) {
lo := uint32(x)
hi := uint32(x >> 32)
m.data = append(m.data, byte(lo), byte(lo>>8), byte(lo>>16), byte(lo>>24), byte(hi), byte(hi>>8), byte(hi>>16), byte(hi>>24))
}
func (m *msg) wbytes(p []byte) {
m.data = append(m.data, p...)
}
func (m *msg) wstring(s string) {
m.data = append(m.data, s...)
}
// Parsing of RPC messages.
//
// Each message begins with
// total_size uint32
// total_descs uint32
// fragment_size uint32
// fragment_descs uint32
//
// If fragment_size < total_size or fragment_descs < total_descs, the actual
// message is broken up in multiple messages; follow-up messages omit
// the "total" fields and begin with the "fragment" fields.
// We do not support putting fragmented messages back together.
// To do this we would need to change the message receiver.
//
// After that size information, the message header follows:
// protocol uint32
// requestID uint32
// isRequest uint32
// rpcNumber uint32
// status uint32
// numValue uint32
// numTemplate uint32
//
// After the header come numTemplate fixed-size arguments,
// numValue fixed-size arguments, and then the variable-sized
// part of the values. The templates describe the expected results
// and have no associated variable sized data in the request.
//
// Each fixed-size argument has the form:
// tag uint32 // really a char, like 'b' or 'C'
// pad uint32 // unused
// val1 uint32
// val2 uint32
//
// The tags are:
// 'b': bool; val1 == 0 or 1
// 'C': []byte; val1 == len, data in variable-sized section
// 'd': float64; (val1, val2) is data
// 'D': []float64; val1 == len, data in variable-sized section
// 'h': int; val1 == file descriptor
// 'i': int32; descriptor in next entry in m.desc
// 'I': []int; val1 == len, data in variable-sized section
// 's': string; val1 == len, data in variable-sized section
//
func (m *msg) pack() error {
m.data = m.data[:0]
m.desc = m.desc[:0]
// sizes, to fill in later
m.wuint32(0)
m.wuint32(0)
m.wuint32(0)
m.wuint32(0)
// message header
m.wuint32(protocol)
m.wuint32(m.id)
m.wuint32(m.isRequest)
m.wuint32(m.rpc)
m.wuint32(m.status)
m.wuint32(uint32(len(m.value)))
m.wuint32(uint32(len(m.template)))
// fixed-size templates
for i, x := range m.template {
var tag, val1, val2 uint32
switch x.(type) {
default:
return errors.New("unexpected template type")
case bool:
tag = 'b'
case []byte:
tag = 'C'
val1 = uint32(m.size[i])
case float64:
tag = 'd'
case []float64:
tag = 'D'
val1 = uint32(m.size[i])
case int:
tag = 'h'
case int32:
tag = 'i'
case []int32:
tag = 'I'
val1 = uint32(m.size[i])
case string:
tag = 's'
val1 = uint32(m.size[i])
}
m.wuint32(tag)
m.wuint32(0)
m.wuint32(val1)
m.wuint32(val2)
}
// fixed-size values
for _, x := range m.value {
var tag, val1, val2 uint32
switch x := x.(type) {
default:
return errors.New("unexpected value type")
case bool:
tag = 'b'
if x {
val1 = 1
}
case []byte:
tag = 'C'
val1 = uint32(len(x))
case float64:
tag = 'd'
v := float64bits(x)
val1 = uint32(v)
val2 = uint32(v >> 32)
case []float64:
tag = 'D'
val1 = uint32(len(x))
case int32:
tag = 'i'
m.desc = append(m.desc, x)
case []int32:
tag = 'I'
val1 = uint32(len(x))
case string:
tag = 's'
val1 = uint32(len(x) + 1)
}
m.wuint32(tag)
m.wuint32(0)
m.wuint32(val1)
m.wuint32(val2)
}
// variable-length data for values
for _, x := range m.value {
switch x := x.(type) {
case []byte:
m.wbytes(x)
case []float64:
for _, f := range x {
m.wuint64(float64bits(f))
}
case []int32:
for _, j := range x {
m.wuint32(uint32(j))
}
case string:
m.wstring(x)
m.wstring("\x00")
}
}
// fill in sizes
data := m.data
m.data = m.data[:0]
m.wuint32(uint32(len(data)))
m.wuint32(uint32(len(m.desc)))
m.wuint32(uint32(len(data)))
m.wuint32(uint32(len(m.desc)))
m.data = data
return nil
}
func (m *msg) unpack() error {
totalSize := m.uint32()
totalDesc := m.uint32()
fragSize := m.uint32()
fragDesc := m.uint32()
if totalSize != fragSize || totalDesc != fragDesc {
return errors.New("Native Client: fragmented RPC messages not supported")
}
if m.uint32() != protocol {
return errors.New("Native Client: RPC protocol mismatch")
}
// message header
m.id = m.uint32()
m.isRequest = m.uint32()
m.rpc = m.uint32()
m.status = m.uint32()
m.value = make([]interface{}, m.uint32())
m.template = make([]interface{}, m.uint32())
m.size = make([]int, len(m.template))
if m.broken {
return errors.New("Native Client: malformed message")
}
// fixed-size templates
for i := range m.template {
tag := m.uint32()
m.uint32() // padding
val1 := m.uint32()
m.uint32() // val2
switch tag {
default:
return errors.New("Native Client: unexpected template type " + string(rune(tag)))
case 'b':
m.template[i] = false
case 'C':
m.template[i] = []byte(nil)
m.size[i] = int(val1)
case 'd':
m.template[i] = float64(0)
case 'D':
m.template[i] = []float64(nil)
m.size[i] = int(val1)
case 'i':
m.template[i] = int32(0)
case 'I':
m.template[i] = []int32(nil)
m.size[i] = int(val1)
case 'h':
m.template[i] = int(0)
case 's':
m.template[i] = ""
m.size[i] = int(val1)
}
}
// fixed-size values
var (
strsize []uint32
d int
)
for i := range m.value {
tag := m.uint32()
m.uint32() // padding
val1 := m.uint32()
val2 := m.uint32()
switch tag {
default:
return errors.New("Native Client: unexpected value type " + string(rune(tag)))
case 'b':
m.value[i] = val1 > 0
case 'C':
m.value[i] = []byte(nil)
strsize = append(strsize, val1)
case 'd':
m.value[i] = float64frombits(uint64(val1) | uint64(val2)<<32)
case 'D':
m.value[i] = make([]float64, val1)
case 'i':
m.value[i] = int32(val1)
case 'I':
m.value[i] = make([]int32, val1)
case 'h':
m.value[i] = int(m.desc[d])
d++
case 's':
m.value[i] = ""
strsize = append(strsize, val1)
}
}
// variable-sized parts of values
for i, x := range m.value {
switch x := x.(type) {
case []byte:
m.value[i] = m.bytes(int(strsize[0]))
strsize = strsize[1:]
case []float64:
for i := range x {
x[i] = float64frombits(m.uint64())
}
case []int32:
for i := range x {
x[i] = int32(m.uint32())
}
case string:
m.value[i] = string(m.bytes(int(strsize[0])))
strsize = strsize[1:]
}
}
if len(m.data) > 0 {
return errors.New("Native Client: junk at end of message")
}
return nil
}
func float64bits(x float64) uint64 {
return *(*uint64)(unsafe.Pointer(&x))
}
func float64frombits(x uint64) float64 {
return *(*float64)(unsafe.Pointer(&x))
}
// At startup, connect to the name service.
var nsClient = nsConnect()
func nsConnect() *srpcClient {
var ns int32 = -1
_, _, errno := Syscall(sys_nameservice, uintptr(unsafe.Pointer(&ns)), 0, 0)
if errno != 0 {
println("Native Client nameservice:", errno.Error())
return nil
}
sock, _, errno := Syscall(sys_imc_connect, uintptr(ns), 0, 0)
if errno != 0 {
println("Native Client nameservice connect:", errno.Error())
return nil
}
c, err := newClient(int(sock))
if err != nil {
println("Native Client nameservice init:", err.Error())
return nil
}
return c
}
const (
nsSuccess = 0
nsNameNotFound = 1
nsDuplicateName = 2
nsInsufficientResources = 3
nsPermissionDenied = 4
nsInvalidArgument = 5
)
func openNamedService(name string, mode int32) (fd int, err error) {
if nsClient == nil {
return 0, errors.New("no name service")
}
ret, err := nsClient.Call("lookup:si:ih", name, int32(mode))
if err != nil {
return 0, err
}
status := ret[0].(int32)
fd = ret[1].(int)
switch status {
case nsSuccess:
// ok
case nsNameNotFound:
return -1, ENOENT
case nsDuplicateName:
return -1, EEXIST
case nsInsufficientResources:
return -1, EWOULDBLOCK
case nsPermissionDenied:
return -1, EPERM
case nsInvalidArgument:
return -1, EINVAL
default:
return -1, EINVAL
}
return fd, nil
}
// 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.
package unix
import (
"sync"
"unsafe"
)
//sys naclClose(fd int) (err error) = sys_close
//sys Exit(code int) (err error)
//sys naclFstat(fd int, stat *Stat_t) (err error) = sys_fstat
//sys naclRead(fd int, b []byte) (n int, err error) = sys_read
//sys naclSeek(fd int, off *int64, whence int) (err error) = sys_lseek
const direntSize = 8 + 8 + 2 + 256
// native_client/src/trusted/service_runtime/include/sys/dirent.h
type Dirent struct {
Ino int64
Off int64
Reclen uint16
Name [256]byte
}
func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
origlen := len(buf)
count = 0
for max != 0 && len(buf) > 0 {
dirent := (*Dirent)(unsafe.Pointer(&buf[0]))
buf = buf[dirent.Reclen:]
if dirent.Ino == 0 { // File absent in directory.
continue
}
bytes := (*[512 + PathMax]byte)(unsafe.Pointer(&dirent.Name[0]))
var name = string(bytes[0:clen(bytes[:])])
if name == "." || name == ".." { // Useless names
continue
}
max--
count++
names = append(names, name)
}
return origlen - len(buf), count, names
}
func clen(n []byte) int {
for i := 0; i < len(n); i++ {
if n[i] == 0 {
return i
}
}
return len(n)
}
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
)
// native_client/src/trusted/service_runtime/include/sys/fcntl.h
const (
O_RDONLY = 0
O_WRONLY = 1
O_RDWR = 2
O_ACCMODE = 3
O_CREAT = 0100
O_CREATE = O_CREAT // for ken
O_TRUNC = 01000
O_APPEND = 02000
O_EXCL = 0200
O_NONBLOCK = 04000
O_NDELAY = O_NONBLOCK
O_SYNC = 010000
O_FSYNC = O_SYNC
O_ASYNC = 020000
O_CLOEXEC = 0
FD_CLOEXEC = 1
)
// native_client/src/trusted/service_runtime/include/sys/fcntl.h
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
)
// native_client/src/trusted/service_runtime/include/bits/stat.h
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
)
// native_client/src/trusted/service_runtime/include/sys/stat.h
// native_client/src/trusted/service_runtime/include/machine/_types.h
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 on NaCl - 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 {
}
// System
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
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 "naclbox", nil
}
return "", ENOSYS
}
// Unimplemented Unix midden heap.
const ImplementsGetwd = false
func Getwd() (wd string, err error) { return "", ENOSYS }
func Getegid() int { return 1 }
func Geteuid() int { return 1 }
func Getgid() int { return 1 }
func Getgroups() ([]int, error) { return []int{1}, nil }
func Getpagesize() int { return 65536 }
func Getppid() int { return 2 }
func Getpid() int { return 3 }
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
}
func RouteRIB(facility, param int) ([]byte, error) { return nil, ENOSYS }
func ParseRoutingMessage(b []byte) ([]RoutingMessage, error) { return nil, ENOSYS }
func ParseRoutingSockaddr(msg RoutingMessage) ([]Sockaddr, error) { return nil, ENOSYS }
func SysctlUint32(name string) (value uint32, err error) { return 0, ENOSYS }
// 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.
package unix
type Timespec struct {
Sec int64
Nsec int32
}
type Timeval struct {
Sec int64
Usec int32
}
func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
func NsecToTimespec(nsec int64) (ts Timespec) {
ts.Sec = int64(nsec / 1e9)
ts.Nsec = int32(nsec % 1e9)
return
}
func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
func NsecToTimeval(nsec int64) (tv Timeval) {
nsec += 999 // round up to microsecond
tv.Usec = int32(nsec % 1e9 / 1e3)
tv.Sec = int64(nsec / 1e9)
return
}
// 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.
package unix
type Timespec struct {
Sec int64
Nsec int32
}
type Timeval struct {
Sec int64
Usec int32
}
func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
func NsecToTimespec(nsec int64) (ts Timespec) {
ts.Sec = int64(nsec / 1e9)
ts.Nsec = int32(nsec % 1e9)
return
}
func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
func NsecToTimeval(nsec int64) (tv Timeval) {
nsec += 999 // round up to microsecond
tv.Usec = int32(nsec % 1e9 / 1e3)
tv.Sec = int64(nsec / 1e9)
return
}
// Copyright 2014 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 unix
type Timespec struct {
Sec int64
Nsec int32
}
type Timeval struct {
Sec int64
Usec int32
}
func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
func NsecToTimespec(nsec int64) (ts Timespec) {
ts.Sec = int64(nsec / 1e9)
ts.Nsec = int32(nsec % 1e9)
return
}
func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
func NsecToTimeval(nsec int64) (tv Timeval) {
nsec += 999 // round up to microsecond
tv.Usec = int32(nsec % 1e9 / 1e3)
tv.Sec = int64(nsec / 1e9)
return
}
// 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.
package unix
// 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_ioctl = 15
sys_stat = 16
sys_fstat = 17
sys_chmod = 18
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
)
// 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 Native Client",
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",
}
// 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.
#include "textflag.h"
TEXT ·startTimer(SB),NOSPLIT,$0
JMP time·startTimer(SB)
TEXT ·stopTimer(SB),NOSPLIT,$0
JMP time·stopTimer(SB)
// 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.
#include "textflag.h"
TEXT ·startTimer(SB),NOSPLIT,$0
JMP time·startTimer(SB)
TEXT ·stopTimer(SB),NOSPLIT,$0
JMP time·stopTimer(SB)
// Copyright 2014 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.
#include "textflag.h"
TEXT ·startTimer(SB),NOSPLIT,$0
B time·startTimer(SB)
TEXT ·stopTimer(SB),NOSPLIT,$0
B time·stopTimer(SB)
// Copyright 2009 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.
// Small in-memory unzip implementation.
// A simplified copy of the pre-Go 1 compress/flate/inflate.go
// and a modified copy of the zip reader in package time.
// (The one in package time does not support decompression; this one does.)
package unix
const (
maxCodeLen = 16 // max length of Huffman code
maxHist = 32768 // max history required
maxLit = 286
maxDist = 32
numCodes = 19 // number of codes in Huffman meta-code
)
type decompressor struct {
in string // compressed input
out []byte // uncompressed output
b uint32 // input bits, at top of b
nb uint
err bool // invalid input
eof bool // reached EOF
h1, h2 huffmanDecoder // decoders for literal/length, distance
bits [maxLit + maxDist]int // lengths defining Huffman codes
codebits [numCodes]int
}
func (f *decompressor) nextBlock() {
for f.nb < 1+2 {
if f.moreBits(); f.err {
return
}
}
f.eof = f.b&1 == 1
f.b >>= 1
typ := f.b & 3
f.b >>= 2
f.nb -= 1 + 2
switch typ {
case 0:
f.dataBlock()
case 1:
// compressed, fixed Huffman tables
f.huffmanBlock(&fixedHuffmanDecoder, nil)
case 2:
// compressed, dynamic Huffman tables
if f.readHuffman(); f.err {
break
}
f.huffmanBlock(&f.h1, &f.h2)
default:
// 3 is reserved.
f.err = true
}
}
// RFC 1951 section 3.2.7.
// Compression with dynamic Huffman codes
var codeOrder = [...]int{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}
func (f *decompressor) readHuffman() {
// HLIT[5], HDIST[5], HCLEN[4].
for f.nb < 5+5+4 {
if f.moreBits(); f.err {
return
}
}
nlit := int(f.b&0x1F) + 257
f.b >>= 5
ndist := int(f.b&0x1F) + 1
f.b >>= 5
nclen := int(f.b&0xF) + 4
f.b >>= 4
f.nb -= 5 + 5 + 4
// (HCLEN+4)*3 bits: code lengths in the magic codeOrder order.
for i := 0; i < nclen; i++ {
for f.nb < 3 {
if f.moreBits(); f.err {
return
}
}
f.codebits[codeOrder[i]] = int(f.b & 0x7)
f.b >>= 3
f.nb -= 3
}
for i := nclen; i < len(codeOrder); i++ {
f.codebits[codeOrder[i]] = 0
}
if !f.h1.init(f.codebits[0:]) {
f.err = true
return
}
// HLIT + 257 code lengths, HDIST + 1 code lengths,
// using the code length Huffman code.
for i, n := 0, nlit+ndist; i < n; {
x := f.huffSym(&f.h1)
if f.err {
return
}
if x < 16 {
// Actual length.
f.bits[i] = x
i++
continue
}
// Repeat previous length or zero.
var rep int
var nb uint
var b int
switch x {
default:
f.err = true
return
case 16:
rep = 3
nb = 2
if i == 0 {
f.err = true
return
}
b = f.bits[i-1]
case 17:
rep = 3
nb = 3
b = 0
case 18:
rep = 11
nb = 7
b = 0
}
for f.nb < nb {
if f.moreBits(); f.err {
return
}
}
rep += int(f.b & uint32(1<<nb-1))
f.b >>= nb
f.nb -= nb
if i+rep > n {
f.err = true
return
}
for j := 0; j < rep; j++ {
f.bits[i] = b
i++
}
}
if !f.h1.init(f.bits[0:nlit]) || !f.h2.init(f.bits[nlit:nlit+ndist]) {
f.err = true
return
}
}
// Decode a single Huffman block from f.
// hl and hd are the Huffman states for the lit/length values
// and the distance values, respectively. If hd == nil, using the
// fixed distance encoding associated with fixed Huffman blocks.
func (f *decompressor) huffmanBlock(hl, hd *huffmanDecoder) {
for {
v := f.huffSym(hl)
if f.err {
return
}
var n uint // number of bits extra
var length int
switch {
case v < 256:
f.out = append(f.out, byte(v))
continue
case v == 256:
// Done with huffman block; read next block.
return
// otherwise, reference to older data
case v < 265:
length = v - (257 - 3)
n = 0
case v < 269:
length = v*2 - (265*2 - 11)
n = 1
case v < 273:
length = v*4 - (269*4 - 19)
n = 2
case v < 277:
length = v*8 - (273*8 - 35)
n = 3
case v < 281:
length = v*16 - (277*16 - 67)
n = 4
case v < 285:
length = v*32 - (281*32 - 131)
n = 5
default:
length = 258
n = 0
}
if n > 0 {
for f.nb < n {
if f.moreBits(); f.err {
return
}
}
length += int(f.b & uint32(1<<n-1))
f.b >>= n
f.nb -= n
}
var dist int
if hd == nil {
for f.nb < 5 {
if f.moreBits(); f.err {
return
}
}
dist = int(reverseByte[(f.b&0x1F)<<3])
f.b >>= 5
f.nb -= 5
} else {
if dist = f.huffSym(hd); f.err {
return
}
}
switch {
case dist < 4:
dist++
case dist >= 30:
f.err = true
return
default:
nb := uint(dist-2) >> 1
// have 1 bit in bottom of dist, need nb more.
extra := (dist & 1) << nb
for f.nb < nb {
if f.moreBits(); f.err {
return
}
}
extra |= int(f.b & uint32(1<<nb-1))
f.b >>= nb
f.nb -= nb
dist = 1<<(nb+1) + 1 + extra
}
// Copy [-dist:-dist+length] into output.
// Encoding can be prescient, so no check on length.
if dist > len(f.out) {
f.err = true
return
}
p := len(f.out) - dist
for i := 0; i < length; i++ {
f.out = append(f.out, f.out[p])
p++
}
}
}
// Copy a single uncompressed data block from input to output.
func (f *decompressor) dataBlock() {
// Uncompressed.
// Discard current half-byte.
f.nb = 0
f.b = 0
if len(f.in) < 4 {
f.err = true
return
}
buf := f.in[:4]
f.in = f.in[4:]
n := int(buf[0]) | int(buf[1])<<8
nn := int(buf[2]) | int(buf[3])<<8
if uint16(nn) != uint16(^n) {
f.err = true
return
}
if len(f.in) < n {
f.err = true
return
}
f.out = append(f.out, f.in[:n]...)
f.in = f.in[n:]
}
func (f *decompressor) moreBits() {
if len(f.in) == 0 {
f.err = true
return
}
c := f.in[0]
f.in = f.in[1:]
f.b |= uint32(c) << f.nb
f.nb += 8
}
// Read the next Huffman-encoded symbol from f according to h.
func (f *decompressor) huffSym(h *huffmanDecoder) int {
for n := uint(h.min); n <= uint(h.max); n++ {
lim := h.limit[n]
if lim == -1 {
continue
}
for f.nb < n {
if f.moreBits(); f.err {
return 0
}
}
v := int(f.b & uint32(1<<n-1))
v <<= 16 - n
v = int(reverseByte[v>>8]) | int(reverseByte[v&0xFF])<<8 // reverse bits
if v <= lim {
f.b >>= n
f.nb -= n
return h.codes[v-h.base[n]]
}
}
f.err = true
return 0
}
var reverseByte = [256]byte{
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
}
// Hard-coded Huffman tables for DEFLATE algorithm.
// See RFC 1951, section 3.2.6.
var fixedHuffmanDecoder = huffmanDecoder{
7, 9,
[maxCodeLen + 1]int{7: 23, 199, 511},
[maxCodeLen + 1]int{7: 0, 24, 224},
[]int{
// length 7: 256-279
256, 257, 258, 259, 260, 261, 262,
263, 264, 265, 266, 267, 268, 269,
270, 271, 272, 273, 274, 275, 276,
277, 278, 279,
// length 8: 0-143
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
82, 83, 84, 85, 86, 87, 88, 89, 90, 91,
92, 93, 94, 95, 96, 97, 98, 99, 100,
101, 102, 103, 104, 105, 106, 107, 108,
109, 110, 111, 112, 113, 114, 115, 116,
117, 118, 119, 120, 121, 122, 123, 124,
125, 126, 127, 128, 129, 130, 131, 132,
133, 134, 135, 136, 137, 138, 139, 140,
141, 142, 143,
// length 8: 280-287
280, 281, 282, 283, 284, 285, 286, 287,
// length 9: 144-255
144, 145, 146, 147, 148, 149, 150, 151,
152, 153, 154, 155, 156, 157, 158, 159,
160, 161, 162, 163, 164, 165, 166, 167,
168, 169, 170, 171, 172, 173, 174, 175,
176, 177, 178, 179, 180, 181, 182, 183,
184, 185, 186, 187, 188, 189, 190, 191,
192, 193, 194, 195, 196, 197, 198, 199,
200, 201, 202, 203, 204, 205, 206, 207,
208, 209, 210, 211, 212, 213, 214, 215,
216, 217, 218, 219, 220, 221, 222, 223,
224, 225, 226, 227, 228, 229, 230, 231,
232, 233, 234, 235, 236, 237, 238, 239,
240, 241, 242, 243, 244, 245, 246, 247,
248, 249, 250, 251, 252, 253, 254, 255,
},
}
// Huffman decoder is based on
// J. Brian Connell, ``A Huffman-Shannon-Fano Code,''
// Proceedings of the IEEE, 61(7) (July 1973), pp 1046-1047.
type huffmanDecoder struct {
// min, max code length
min, max int
// limit[i] = largest code word of length i
// Given code v of length n,
// need more bits if v > limit[n].
limit [maxCodeLen + 1]int
// base[i] = smallest code word of length i - seq number
base [maxCodeLen + 1]int
// codes[seq number] = output code.
// Given code v of length n, value is
// codes[v - base[n]].
codes []int
}
// Initialize Huffman decoding tables from array of code lengths.
func (h *huffmanDecoder) init(bits []int) bool {
// Count number of codes of each length,
// compute min and max length.
var count [maxCodeLen + 1]int
var min, max int
for _, n := range bits {
if n == 0 {
continue
}
if min == 0 || n < min {
min = n
}
if n > max {
max = n
}
count[n]++
}
if max == 0 {
return false
}
h.min = min
h.max = max
// For each code range, compute
// nextcode (first code of that length),
// limit (last code of that length), and
// base (offset from first code to sequence number).
code := 0
seq := 0
var nextcode [maxCodeLen]int
for i := min; i <= max; i++ {
n := count[i]
nextcode[i] = code
h.base[i] = code - seq
code += n
seq += n
h.limit[i] = code - 1
code <<= 1
}
// Make array mapping sequence numbers to codes.
if len(h.codes) < len(bits) {
h.codes = make([]int, len(bits))
}
for i, n := range bits {
if n == 0 {
continue
}
code := nextcode[n]
nextcode[n]++
seq := code - h.base[n]
h.codes[seq] = i
}
return true
}
func inflate(in string) (out []byte) {
var d decompressor
d.in = in
for !d.err && !d.eof {
d.nextBlock()
}
if len(d.in) != 0 {
println("fs unzip: junk at end of compressed data")
return nil
}
return d.out
}
// get4 returns the little-endian 32-bit value in b.
func zget4(b string) int {
if len(b) < 4 {
return 0
}
return int(b[0]) | int(b[1])<<8 | int(b[2])<<16 | int(b[3])<<24
}
// get2 returns the little-endian 16-bit value in b.
func zget2(b string) int {
if len(b) < 2 {
return 0
}
return int(b[0]) | int(b[1])<<8
}
func unzip(data string) {
const (
zecheader = 0x06054b50
zcheader = 0x02014b50
ztailsize = 22
zheadersize = 30
zheader = 0x04034b50
)
buf := data[len(data)-ztailsize:]
n := zget2(buf[10:])
size := zget4(buf[12:])
off := zget4(buf[16:])
hdr := data[off : off+size]
for i := 0; i < n; i++ {
// zip entry layout:
// 0 magic[4]
// 4 madevers[1]
// 5 madeos[1]
// 6 extvers[1]
// 7 extos[1]
// 8 flags[2]
// 10 meth[2]
// 12 modtime[2]
// 14 moddate[2]
// 16 crc[4]
// 20 csize[4]
// 24 uncsize[4]
// 28 namelen[2]
// 30 xlen[2]
// 32 fclen[2]
// 34 disknum[2]
// 36 iattr[2]
// 38 eattr[4]
// 42 off[4]
// 46 name[namelen]
// 46+namelen+xlen+fclen - next header
//
if zget4(hdr) != zcheader {
println("fs unzip: bad magic")
break
}
meth := zget2(hdr[10:])
mtime := zget2(hdr[12:])
mdate := zget2(hdr[14:])
csize := zget4(hdr[20:])
size := zget4(hdr[24:])
namelen := zget2(hdr[28:])
xlen := zget2(hdr[30:])
fclen := zget2(hdr[32:])
xattr := uint32(zget4(hdr[38:])) >> 16
off := zget4(hdr[42:])
name := hdr[46 : 46+namelen]
hdr = hdr[46+namelen+xlen+fclen:]
// zip per-file header layout:
// 0 magic[4]
// 4 extvers[1]
// 5 extos[1]
// 6 flags[2]
// 8 meth[2]
// 10 modtime[2]
// 12 moddate[2]
// 14 crc[4]
// 18 csize[4]
// 22 uncsize[4]
// 26 namelen[2]
// 28 xlen[2]
// 30 name[namelen]
// 30+namelen+xlen - file data
//
buf := data[off : off+zheadersize+namelen]
if zget4(buf) != zheader ||
zget2(buf[8:]) != meth ||
zget2(buf[26:]) != namelen ||
buf[30:30+namelen] != name {
println("fs unzip: inconsistent zip file")
return
}
xlen = zget2(buf[28:])
off += zheadersize + namelen + xlen
var fdata []byte
switch meth {
case 0:
// buf is uncompressed
buf = data[off : off+size]
fdata = []byte(buf)
case 8:
// buf is deflate-compressed
buf = data[off : off+csize]
fdata = inflate(buf)
if len(fdata) != size {
println("fs unzip: inconsistent size in zip file")
return
}
}
if xattr&S_IFMT == 0 {
if xattr&0777 == 0 {
xattr |= 0666
}
if len(name) > 0 && name[len(name)-1] == '/' {
xattr |= S_IFDIR
xattr |= 0111
} else {
xattr |= S_IFREG
}
}
if err := create(name, xattr, zipToTime(mdate, mtime), fdata); err != nil {
print("fs unzip: create ", name, ": ", err.Error(), "\n")
}
}
chdirEnv()
}
func zipToTime(date, time int) int64 {
dd := date & 0x1f
mm := date >> 5 & 0xf
yy := date >> 9 // since 1980
sec := int64(315532800) // jan 1 1980
sec += int64(yy) * 365 * 86400
sec += int64(yy) / 4 * 86400
if yy%4 > 0 || mm >= 3 {
sec += 86400
}
sec += int64(daysBeforeMonth[mm]) * 86400
sec += int64(dd-1) * 86400
h := time >> 11
m := time >> 5 & 0x3F
s := time & 0x1f * 2
sec += int64(h*3600 + m*60 + s)
return sec
}
var daysBeforeMonth = [...]int32{
0,
0,
31,
31 + 28,
31 + 28 + 31,
31 + 28 + 31 + 30,
31 + 28 + 31 + 30 + 31,
31 + 28 + 31 + 30 + 31 + 30,
31 + 28 + 31 + 30 + 31 + 30 + 31,
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31,
}
// mkunix.pl -l32 -nacl syscall_nacl.go syscall_nacl_386.go
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
package unix
import "unsafe"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func naclClose(fd int) (err error) {
_, _, e1 := Syscall(sys_close, uintptr(fd), 0, 0)
if e1 != 0 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Exit(code int) (err error) {
_, _, e1 := Syscall(sys_exit, uintptr(code), 0, 0)
if e1 != 0 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func naclFstat(fd int, stat *Stat_t) (err error) {
_, _, e1 := Syscall(sys_fstat, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
if e1 != 0 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func naclRead(fd int, b []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(b) > 0 {
_p0 = unsafe.Pointer(&b[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(sys_read, uintptr(fd), uintptr(_p0), uintptr(len(b)))
n = int(r0)
if e1 != 0 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func naclSeek(fd int, off *int64, whence int) (err error) {
_, _, e1 := Syscall(sys_lseek, uintptr(fd), uintptr(unsafe.Pointer(off)), uintptr(whence))
if e1 != 0 {
err = e1
}
return
}
// mkunix.pl -nacl syscall_nacl.go syscall_nacl_amd64p32.go
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
package unix
import "unsafe"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func naclClose(fd int) (err error) {
_, _, e1 := Syscall(sys_close, uintptr(fd), 0, 0)
if e1 != 0 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Exit(code int) (err error) {
_, _, e1 := Syscall(sys_exit, uintptr(code), 0, 0)
if e1 != 0 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func naclFstat(fd int, stat *Stat_t) (err error) {
_, _, e1 := Syscall(sys_fstat, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
if e1 != 0 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func naclRead(fd int, b []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(b) > 0 {
_p0 = unsafe.Pointer(&b[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(sys_read, uintptr(fd), uintptr(_p0), uintptr(len(b)))
n = int(r0)
if e1 != 0 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func naclSeek(fd int, off *int64, whence int) (err error) {
_, _, e1 := Syscall(sys_lseek, uintptr(fd), uintptr(unsafe.Pointer(off)), uintptr(whence))
if e1 != 0 {
err = e1
}
return
}
// mkunix.pl -l32 -nacl -arm syscall_nacl.go syscall_nacl_arm.go
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
package unix
import "unsafe"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func naclClose(fd int) (err error) {
_, _, e1 := Syscall(sys_close, uintptr(fd), 0, 0)
if e1 != 0 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Exit(code int) (err error) {
_, _, e1 := Syscall(sys_exit, uintptr(code), 0, 0)
if e1 != 0 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func naclFstat(fd int, stat *Stat_t) (err error) {
_, _, e1 := Syscall(sys_fstat, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
if e1 != 0 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func naclRead(fd int, b []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(b) > 0 {
_p0 = unsafe.Pointer(&b[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(sys_read, uintptr(fd), uintptr(_p0), uintptr(len(b)))
n = int(r0)
if e1 != 0 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func naclSeek(fd int, off *int64, whence int) (err error) {
_, _, e1 := Syscall(sys_lseek, uintptr(fd), uintptr(unsafe.Pointer(off)), uintptr(whence))
if e1 != 0 {
err = e1
}
return
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment