mirror of
https://github.com/rwinkhart/sys.git
synced 2026-08-27 20:36:31 -04:00
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
This commit is contained in:
@@ -1,43 +0,0 @@
|
||||
// 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
|
||||
@@ -1,41 +0,0 @@
|
||||
// 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
|
||||
@@ -1,43 +0,0 @@
|
||||
// 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
|
||||
+1
-1
@@ -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.
|
||||
|
||||
|
||||
-326
@@ -1,326 +0,0 @@
|
||||
// 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
|
||||
}
|
||||
-832
@@ -1,832 +0,0 @@
|
||||
// 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.
|
||||
|
||||
@@ -1,912 +0,0 @@
|
||||
// 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 }
|
||||
@@ -1,822 +0,0 @@
|
||||
// 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
|
||||
}
|
||||
@@ -1,311 +0,0 @@
|
||||
// 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 }
|
||||
@@ -1,32 +0,0 @@
|
||||
// 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
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
// 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
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
// 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
|
||||
}
|
||||
@@ -1,324 +0,0 @@
|
||||
// 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",
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
// 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)
|
||||
@@ -1,11 +0,0 @@
|
||||
// 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)
|
||||
@@ -1,11 +0,0 @@
|
||||
// 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)
|
||||
@@ -1,685 +0,0 @@
|
||||
// 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,
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
// 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
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
// 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
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
// 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
|
||||
}
|
||||
Reference in New Issue
Block a user