libgo: Update to current Go library.

From-SVN: r172106
This commit is contained in:
Ian Lance Taylor 2011-04-07 17:09:10 +00:00
parent a751005d50
commit 405ca10418
110 changed files with 4608 additions and 3136 deletions

View File

@ -1,4 +1,4 @@
342e3b11f21a
f618e5e0991d
The first line of this file holds the Mercurial revision number of the
last merge done from the master library sources.

View File

@ -177,10 +177,10 @@ toolexeclibgocryptodir = $(toolexeclibgodir)/crypto
toolexeclibgocrypto_DATA = \
crypto/aes.gox \
crypto/block.gox \
crypto/blowfish.gox \
crypto/cast5.gox \
crypto/cipher.gox \
crypto/des.gox \
crypto/dsa.gox \
crypto/ecdsa.gox \
crypto/elliptic.gox \
@ -727,9 +727,12 @@ go_os_files = \
go/os/env.go \
go/os/env_unix.go \
go/os/error.go \
go/os/error_posix.go \
go/os/exec.go \
go/os/exec_posix.go \
go/os/exec_unix.go \
go/os/file.go \
go/os/file_posix.go \
go/os/file_unix.go \
go/os/getwd.go \
go/os/path.go \
@ -932,16 +935,6 @@ go_crypto_aes_files = \
go/crypto/aes/block.go \
go/crypto/aes/cipher.go \
go/crypto/aes/const.go
go_crypto_block_files = \
go/crypto/block/cbc.go \
go/crypto/block/cfb.go \
go/crypto/block/cmac.go \
go/crypto/block/cipher.go \
go/crypto/block/ctr.go \
go/crypto/block/eax.go \
go/crypto/block/ecb.go \
go/crypto/block/ofb.go \
go/crypto/block/xor.go
go_crypto_blowfish_files = \
go/crypto/blowfish/block.go \
go/crypto/blowfish/const.go \
@ -956,6 +949,10 @@ go_crypto_cipher_files = \
go/crypto/cipher/io.go \
go/crypto/cipher/ocfb.go \
go/crypto/cipher/ofb.go
go_crypto_des_files = \
go/crypto/des/block.go \
go/crypto/des/cipher.go \
go/crypto/des/const.go
go_crypto_dsa_files = \
go/crypto/dsa/dsa.go
go_crypto_ecdsa_files = \
@ -1428,10 +1425,10 @@ libgo_go_objs = \
container/ring.lo \
container/vector.lo \
crypto/aes.lo \
crypto/block.lo \
crypto/blowfish.lo \
crypto/cast5.lo \
crypto/cipher.lo \
crypto/des.lo \
crypto/dsa.lo \
crypto/ecdsa.lo \
crypto/elliptic.lo \
@ -2026,13 +2023,6 @@ crypto/aes/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: crypto/aes/check
crypto/block.lo: $(go_crypto_block_files) fmt.gox io.gox os.gox strconv.gox
$(BUILDPACKAGE)
crypto/block/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/block
@$(CHECK)
.PHONY: crypto/block/check
crypto/blowfish.lo: $(go_crypto_blowfish_files) os.gox strconv.gox
$(BUILDPACKAGE)
crypto/blowfish/check: $(CHECK_DEPS)
@ -2054,6 +2044,13 @@ crypto/cipher/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: crypto/cipher/check
crypto/des.lo: $(go_crypto_des_files) encoding/binary.gox os.gox strconv.gox
$(BUILDPACKAGE)
crypto/des/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/des
@$(CHECK)
.PHONY: crypto/des/check
crypto/dsa.lo: $(go_crypto_dsa_files) big.gox io.gox os.gox
$(BUILDPACKAGE)
crypto/dsa/check: $(CHECK_DEPS)
@ -2139,7 +2136,8 @@ crypto/ripemd160/check: $(CHECK_DEPS)
.PHONY: crypto/ripemd160/check
crypto/rsa.lo: $(go_crypto_rsa_files) big.gox crypto.gox crypto/sha1.gox \
crypto/subtle.gox encoding/hex.gox hash.gox io.gox os.gox
crypto/subtle.gox encoding/hex.gox hash.gox io.gox os.gox \
sync.gox
$(BUILDPACKAGE)
crypto/rsa/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/rsa
@ -2475,8 +2473,8 @@ http/cgi/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: http/cgi/check
http/httptest.lo: $(go_http_httptest_files) bytes.gox fmt.gox http.gox \
net.gox os.gox
http/httptest.lo: $(go_http_httptest_files) bytes.gox crypto/rand.gox \
crypto/tls.gox fmt.gox http.gox net.gox os.gox time.gox
$(BUILDPACKAGE)
http/httptest/check: $(CHECK_DEPS)
@$(MKDIR_P) http/httptest
@ -2767,14 +2765,14 @@ container/vector.gox: container/vector.lo
crypto/aes.gox: crypto/aes.lo
$(BUILDGOX)
crypto/block.gox: crypto/block.lo
$(BUILDGOX)
crypto/blowfish.gox: crypto/blowfish.lo
$(BUILDGOX)
crypto/cast5.gox: crypto/cast5.lo
$(BUILDGOX)
crypto/cipher.gox: crypto/cipher.lo
$(BUILDGOX)
crypto/des.gox: crypto/des.lo
$(BUILDGOX)
crypto/dsa.gox: crypto/dsa.lo
$(BUILDGOX)
crypto/ecdsa.gox: crypto/ecdsa.lo
@ -3002,10 +3000,10 @@ TEST_PACKAGES = \
container/ring/check \
container/vector/check \
crypto/aes/check \
crypto/block/check \
crypto/blowfish/check \
crypto/cast5/check \
crypto/cipher/check \
crypto/des/check \
crypto/dsa/check \
crypto/ecdsa/check \
crypto/elliptic/check \

View File

@ -140,31 +140,30 @@ am__DEPENDENCIES_2 = asn1/asn1.lo big/big.lo bufio/bufio.lo \
archive/zip.lo compress/bzip2.lo compress/flate.lo \
compress/gzip.lo compress/lzw.lo compress/zlib.lo \
container/heap.lo container/list.lo container/ring.lo \
container/vector.lo crypto/aes.lo crypto/block.lo \
crypto/blowfish.lo crypto/cast5.lo crypto/cipher.lo \
crypto/dsa.lo crypto/ecdsa.lo crypto/elliptic.lo \
crypto/hmac.lo crypto/md4.lo crypto/md5.lo crypto/ocsp.lo \
crypto/openpgp.lo crypto/rand.lo crypto/rc4.lo \
crypto/ripemd160.lo crypto/rsa.lo crypto/sha1.lo \
crypto/sha256.lo crypto/sha512.lo crypto/subtle.lo \
crypto/tls.lo crypto/twofish.lo crypto/x509.lo crypto/xtea.lo \
crypto/openpgp/armor.lo crypto/openpgp/error.lo \
crypto/openpgp/packet.lo crypto/openpgp/s2k.lo debug/dwarf.lo \
debug/elf.lo debug/gosym.lo debug/macho.lo debug/pe.lo \
debug/proc.lo encoding/ascii85.lo encoding/base32.lo \
encoding/base64.lo encoding/binary.lo encoding/git85.lo \
encoding/hex.lo encoding/line.lo encoding/pem.lo \
exp/datafmt.lo exp/draw.lo exp/eval.lo go/ast.lo go/doc.lo \
go/parser.lo go/printer.lo go/scanner.lo go/token.lo \
go/typechecker.lo hash/adler32.lo hash/crc32.lo hash/crc64.lo \
hash/fnv.lo http/cgi.lo http/httptest.lo http/pprof.lo \
image/jpeg.lo image/png.lo index/suffixarray.lo io/ioutil.lo \
mime/multipart.lo net/dict.lo net/textproto.lo \
$(am__DEPENDENCIES_1) os/signal.lo path/filepath.lo \
rpc/jsonrpc.lo runtime/debug.lo runtime/pprof.lo \
sync/atomic.lo sync/atomic_c.lo syscalls/syscall.lo \
syscalls/errno.lo testing/testing.lo testing/iotest.lo \
testing/quick.lo testing/script.lo
container/vector.lo crypto/aes.lo crypto/blowfish.lo \
crypto/cast5.lo crypto/cipher.lo crypto/des.lo crypto/dsa.lo \
crypto/ecdsa.lo crypto/elliptic.lo crypto/hmac.lo \
crypto/md4.lo crypto/md5.lo crypto/ocsp.lo crypto/openpgp.lo \
crypto/rand.lo crypto/rc4.lo crypto/ripemd160.lo crypto/rsa.lo \
crypto/sha1.lo crypto/sha256.lo crypto/sha512.lo \
crypto/subtle.lo crypto/tls.lo crypto/twofish.lo \
crypto/x509.lo crypto/xtea.lo crypto/openpgp/armor.lo \
crypto/openpgp/error.lo crypto/openpgp/packet.lo \
crypto/openpgp/s2k.lo debug/dwarf.lo debug/elf.lo \
debug/gosym.lo debug/macho.lo debug/pe.lo debug/proc.lo \
encoding/ascii85.lo encoding/base32.lo encoding/base64.lo \
encoding/binary.lo encoding/git85.lo encoding/hex.lo \
encoding/line.lo encoding/pem.lo exp/datafmt.lo exp/draw.lo \
exp/eval.lo go/ast.lo go/doc.lo go/parser.lo go/printer.lo \
go/scanner.lo go/token.lo go/typechecker.lo hash/adler32.lo \
hash/crc32.lo hash/crc64.lo hash/fnv.lo http/cgi.lo \
http/httptest.lo http/pprof.lo image/jpeg.lo image/png.lo \
index/suffixarray.lo io/ioutil.lo mime/multipart.lo \
net/dict.lo net/textproto.lo $(am__DEPENDENCIES_1) \
os/signal.lo path/filepath.lo rpc/jsonrpc.lo runtime/debug.lo \
runtime/pprof.lo sync/atomic.lo sync/atomic_c.lo \
syscalls/syscall.lo syscalls/errno.lo testing/testing.lo \
testing/iotest.lo testing/quick.lo testing/script.lo
libgo_la_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1)
@ -624,10 +623,10 @@ toolexeclibgocontainer_DATA = \
toolexeclibgocryptodir = $(toolexeclibgodir)/crypto
toolexeclibgocrypto_DATA = \
crypto/aes.gox \
crypto/block.gox \
crypto/blowfish.gox \
crypto/cast5.gox \
crypto/cipher.gox \
crypto/des.gox \
crypto/dsa.gox \
crypto/ecdsa.gox \
crypto/elliptic.gox \
@ -1087,9 +1086,12 @@ go_os_files = \
go/os/env.go \
go/os/env_unix.go \
go/os/error.go \
go/os/error_posix.go \
go/os/exec.go \
go/os/exec_posix.go \
go/os/exec_unix.go \
go/os/file.go \
go/os/file_posix.go \
go/os/file_unix.go \
go/os/getwd.go \
go/os/path.go \
@ -1279,17 +1281,6 @@ go_crypto_aes_files = \
go/crypto/aes/cipher.go \
go/crypto/aes/const.go
go_crypto_block_files = \
go/crypto/block/cbc.go \
go/crypto/block/cfb.go \
go/crypto/block/cmac.go \
go/crypto/block/cipher.go \
go/crypto/block/ctr.go \
go/crypto/block/eax.go \
go/crypto/block/ecb.go \
go/crypto/block/ofb.go \
go/crypto/block/xor.go
go_crypto_blowfish_files = \
go/crypto/blowfish/block.go \
go/crypto/blowfish/const.go \
@ -1307,6 +1298,11 @@ go_crypto_cipher_files = \
go/crypto/cipher/ocfb.go \
go/crypto/cipher/ofb.go
go_crypto_des_files = \
go/crypto/des/block.go \
go/crypto/des/cipher.go \
go/crypto/des/const.go
go_crypto_dsa_files = \
go/crypto/dsa/dsa.go
@ -1766,10 +1762,10 @@ libgo_go_objs = \
container/ring.lo \
container/vector.lo \
crypto/aes.lo \
crypto/block.lo \
crypto/blowfish.lo \
crypto/cast5.lo \
crypto/cipher.lo \
crypto/des.lo \
crypto/dsa.lo \
crypto/ecdsa.lo \
crypto/elliptic.lo \
@ -2008,10 +2004,10 @@ TEST_PACKAGES = \
container/ring/check \
container/vector/check \
crypto/aes/check \
crypto/block/check \
crypto/blowfish/check \
crypto/cast5/check \
crypto/cipher/check \
crypto/des/check \
crypto/dsa/check \
crypto/ecdsa/check \
crypto/elliptic/check \
@ -4436,13 +4432,6 @@ crypto/aes/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: crypto/aes/check
crypto/block.lo: $(go_crypto_block_files) fmt.gox io.gox os.gox strconv.gox
$(BUILDPACKAGE)
crypto/block/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/block
@$(CHECK)
.PHONY: crypto/block/check
crypto/blowfish.lo: $(go_crypto_blowfish_files) os.gox strconv.gox
$(BUILDPACKAGE)
crypto/blowfish/check: $(CHECK_DEPS)
@ -4464,6 +4453,13 @@ crypto/cipher/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: crypto/cipher/check
crypto/des.lo: $(go_crypto_des_files) encoding/binary.gox os.gox strconv.gox
$(BUILDPACKAGE)
crypto/des/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/des
@$(CHECK)
.PHONY: crypto/des/check
crypto/dsa.lo: $(go_crypto_dsa_files) big.gox io.gox os.gox
$(BUILDPACKAGE)
crypto/dsa/check: $(CHECK_DEPS)
@ -4549,7 +4545,8 @@ crypto/ripemd160/check: $(CHECK_DEPS)
.PHONY: crypto/ripemd160/check
crypto/rsa.lo: $(go_crypto_rsa_files) big.gox crypto.gox crypto/sha1.gox \
crypto/subtle.gox encoding/hex.gox hash.gox io.gox os.gox
crypto/subtle.gox encoding/hex.gox hash.gox io.gox os.gox \
sync.gox
$(BUILDPACKAGE)
crypto/rsa/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/rsa
@ -4885,8 +4882,8 @@ http/cgi/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: http/cgi/check
http/httptest.lo: $(go_http_httptest_files) bytes.gox fmt.gox http.gox \
net.gox os.gox
http/httptest.lo: $(go_http_httptest_files) bytes.gox crypto/rand.gox \
crypto/tls.gox fmt.gox http.gox net.gox os.gox time.gox
$(BUILDPACKAGE)
http/httptest/check: $(CHECK_DEPS)
@$(MKDIR_P) http/httptest
@ -5172,14 +5169,14 @@ container/vector.gox: container/vector.lo
crypto/aes.gox: crypto/aes.lo
$(BUILDGOX)
crypto/block.gox: crypto/block.lo
$(BUILDGOX)
crypto/blowfish.gox: crypto/blowfish.lo
$(BUILDGOX)
crypto/cast5.gox: crypto/cast5.lo
$(BUILDGOX)
crypto/cipher.gox: crypto/cipher.lo
$(BUILDGOX)
crypto/des.gox: crypto/des.lo
$(BUILDGOX)
crypto/dsa.gox: crypto/dsa.lo
$(BUILDGOX)
crypto/ecdsa.gox: crypto/ecdsa.lo

View File

@ -95,7 +95,7 @@ func (tr *Reader) skipUnread() {
nr := tr.nb + tr.pad // number of bytes to skip
tr.nb, tr.pad = 0, 0
if sr, ok := tr.r.(io.Seeker); ok {
if _, err := sr.Seek(nr, 1); err == nil {
if _, err := sr.Seek(nr, os.SEEK_CUR); err == nil {
return
}
}

View File

@ -113,7 +113,7 @@ var untarTests = []*untarTest{
func TestReader(t *testing.T) {
testLoop:
for i, test := range untarTests {
f, err := os.Open(test.file, os.O_RDONLY, 0444)
f, err := os.Open(test.file)
if err != nil {
t.Errorf("test %d: Unexpected error: %v", i, err)
continue
@ -143,7 +143,7 @@ testLoop:
}
func TestPartialRead(t *testing.T) {
f, err := os.Open("testdata/gnu.tar", os.O_RDONLY, 0444)
f, err := os.Open("testdata/gnu.tar")
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
@ -181,7 +181,7 @@ func TestPartialRead(t *testing.T) {
func TestIncrementalRead(t *testing.T) {
test := gnuTarTest
f, err := os.Open(test.file, os.O_RDONLY, 0444)
f, err := os.Open(test.file)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
@ -235,7 +235,7 @@ func TestIncrementalRead(t *testing.T) {
func TestNonSeekable(t *testing.T) {
test := gnuTarTest
f, err := os.Open(test.file, os.O_RDONLY, 0444)
f, err := os.Open(test.file)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}

View File

@ -49,7 +49,7 @@ func (f *File) hasDataDescriptor() bool {
// OpenReader will open the Zip file specified by name and return a Reader.
func OpenReader(name string) (*Reader, os.Error) {
f, err := os.Open(name, os.O_RDONLY, 0644)
f, err := os.Open(name)
if err != nil {
return nil, err
}
@ -73,7 +73,7 @@ func NewReader(r io.ReaderAt, size int64) (*Reader, os.Error) {
Comment: end.comment,
}
rs := io.NewSectionReader(r, 0, size)
if _, err = rs.Seek(int64(end.directoryOffset), 0); err != nil {
if _, err = rs.Seek(int64(end.directoryOffset), os.SEEK_SET); err != nil {
return nil, err
}
buf := bufio.NewReader(rs)
@ -94,7 +94,7 @@ func (f *File) Open() (rc io.ReadCloser, err os.Error) {
if err = readFileHeader(f, r); err != nil {
return
}
if f.bodyOffset, err = r.Seek(0, 1); err != nil {
if f.bodyOffset, err = r.Seek(0, os.SEEK_CUR); err != nil {
return
}
}

View File

@ -415,38 +415,27 @@ func (b *Writer) Buffered() int { return b.n }
// If nn < len(p), it also returns an error explaining
// why the write is short.
func (b *Writer) Write(p []byte) (nn int, err os.Error) {
if b.err != nil {
return 0, b.err
}
nn = 0
for len(p) > 0 {
n := b.Available()
if n <= 0 {
if b.Flush(); b.err != nil {
break
}
n = b.Available()
}
if b.Buffered() == 0 && len(p) >= len(b.buf) {
for len(p) > b.Available() && b.err == nil {
var n int
if b.Buffered() == 0 {
// Large write, empty buffer.
// Write directly from p to avoid copy.
n, b.err = b.wr.Write(p)
nn += n
p = p[n:]
if b.err != nil {
break
}
continue
} else {
n = copy(b.buf[b.n:], p)
b.n += n
b.Flush()
}
if n > len(p) {
n = len(p)
}
copy(b.buf[b.n:b.n+n], p[0:n])
b.n += n
nn += n
p = p[n:]
}
return nn, b.err
if b.err != nil {
return nn, b.err
}
n := copy(b.buf[b.n:], p)
b.n += n
nn += n
return nn, nil
}
// WriteByte writes a single byte.
@ -496,24 +485,21 @@ func (b *Writer) WriteRune(rune int) (size int, err os.Error) {
// If the count is less than len(s), it also returns an error explaining
// why the write is short.
func (b *Writer) WriteString(s string) (int, os.Error) {
nn := 0
for len(s) > b.Available() && b.err == nil {
n := copy(b.buf[b.n:], s)
b.n += n
nn += n
s = s[n:]
b.Flush()
}
if b.err != nil {
return 0, b.err
return nn, b.err
}
// Common case, worth making fast.
if b.Available() >= len(s) || len(b.buf) >= len(s) && b.Flush() == nil {
for i := 0; i < len(s); i++ { // loop over bytes, not runes.
b.buf[b.n] = s[i]
b.n++
}
return len(s), nil
}
for i := 0; i < len(s); i++ { // loop over bytes, not runes.
b.WriteByte(s[i])
if b.err != nil {
return i, b.err
}
}
return len(s), nil
n := copy(b.buf[b.n:], s)
b.n += n
nn += n
return nn, nil
}
// buffered input and output

View File

@ -21,7 +21,7 @@ var filenames = []string{
// the given options yields equivalent bytes to the original file.
func testFile(t *testing.T, fn string, order Order, litWidth int) {
// Read the file, as golden output.
golden, err := os.Open(fn, os.O_RDONLY, 0400)
golden, err := os.Open(fn)
if err != nil {
t.Errorf("%s (order=%d litWidth=%d): %v", fn, order, litWidth, err)
return
@ -29,7 +29,7 @@ func testFile(t *testing.T, fn string, order Order, litWidth int) {
defer golden.Close()
// Read the file again, and push it through a pipe that compresses at the write end, and decompresses at the read end.
raw, err := os.Open(fn, os.O_RDONLY, 0400)
raw, err := os.Open(fn)
if err != nil {
t.Errorf("%s (order=%d litWidth=%d): %v", fn, order, litWidth, err)
return

View File

@ -20,7 +20,7 @@ var filenames = []string{
// yields equivalent bytes to the original file.
func testFileLevel(t *testing.T, fn string, level int) {
// Read the file, as golden output.
golden, err := os.Open(fn, os.O_RDONLY, 0444)
golden, err := os.Open(fn)
if err != nil {
t.Errorf("%s (level=%d): %v", fn, level, err)
return
@ -28,7 +28,7 @@ func testFileLevel(t *testing.T, fn string, level int) {
defer golden.Close()
// Read the file again, and push it through a pipe that compresses at the write end, and decompresses at the read end.
raw, err := os.Open(fn, os.O_RDONLY, 0444)
raw, err := os.Open(fn)
if err != nil {
t.Errorf("%s (level=%d): %v", fn, level, err)
return

View File

@ -1,71 +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.
// Cipher block chaining (CBC) mode.
// CBC provides confidentiality by xoring (chaining) each plaintext block
// with the previous ciphertext block before applying the block cipher.
// See NIST SP 800-38A, pp 10-11
package block
import (
"io"
)
type cbcCipher struct {
c Cipher
blockSize int
iv []byte
tmp []byte
}
func newCBC(c Cipher, iv []byte) *cbcCipher {
n := c.BlockSize()
x := new(cbcCipher)
x.c = c
x.blockSize = n
x.iv = dup(iv)
x.tmp = make([]byte, n)
return x
}
func (x *cbcCipher) BlockSize() int { return x.blockSize }
func (x *cbcCipher) Encrypt(dst, src []byte) {
for i := 0; i < x.blockSize; i++ {
x.iv[i] ^= src[i]
}
x.c.Encrypt(x.iv, x.iv)
for i := 0; i < x.blockSize; i++ {
dst[i] = x.iv[i]
}
}
func (x *cbcCipher) Decrypt(dst, src []byte) {
x.c.Decrypt(x.tmp, src)
for i := 0; i < x.blockSize; i++ {
x.tmp[i] ^= x.iv[i]
x.iv[i] = src[i]
dst[i] = x.tmp[i]
}
}
// NewCBCDecrypter returns a reader that reads data from r and decrypts it using c
// in cipher block chaining (CBC) mode with the initialization vector iv.
// The returned Reader does not buffer or read ahead except
// as required by the cipher's block size.
func NewCBCDecrypter(c Cipher, iv []byte, r io.Reader) io.Reader {
return NewECBDecrypter(newCBC(c, iv), r)
}
// NewCBCEncrypter returns a writer that encrypts data using c
// in cipher block chaining (CBC) mode with the initialization vector iv
// and writes the encrypted data to w.
// The returned Writer does no buffering except as required
// by the cipher's block size, so there is no need for a Flush method.
func NewCBCEncrypter(c Cipher, iv []byte, w io.Writer) io.Writer {
return NewECBEncrypter(newCBC(c, iv), w)
}

View File

@ -1,96 +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.
// Cipher feedback (CFB) mode.
// CFB provides confidentiality by feeding a fraction of
// the previous ciphertext in as the plaintext for the next
// block operation.
// See NIST SP 800-38A, pp 11-13
package block
import (
"io"
)
type cfbCipher struct {
c Cipher
blockSize int // our block size (s/8)
cipherSize int // underlying cipher block size
iv []byte
tmp []byte
}
func newCFB(c Cipher, s int, iv []byte) *cfbCipher {
if s == 0 || s%8 != 0 {
panic("crypto/block: invalid CFB mode")
}
b := c.BlockSize()
x := new(cfbCipher)
x.c = c
x.blockSize = s / 8
x.cipherSize = b
x.iv = dup(iv)
x.tmp = make([]byte, b)
return x
}
func (x *cfbCipher) BlockSize() int { return x.blockSize }
func (x *cfbCipher) Encrypt(dst, src []byte) {
// Encrypt old IV and xor prefix with src to make dst.
x.c.Encrypt(x.tmp, x.iv)
for i := 0; i < x.blockSize; i++ {
dst[i] = src[i] ^ x.tmp[i]
}
// Slide unused IV pieces down and insert dst at end.
for i := 0; i < x.cipherSize-x.blockSize; i++ {
x.iv[i] = x.iv[i+x.blockSize]
}
off := x.cipherSize - x.blockSize
for i := off; i < x.cipherSize; i++ {
x.iv[i] = dst[i-off]
}
}
func (x *cfbCipher) Decrypt(dst, src []byte) {
// Encrypt [sic] old IV and xor prefix with src to make dst.
x.c.Encrypt(x.tmp, x.iv)
for i := 0; i < x.blockSize; i++ {
dst[i] = src[i] ^ x.tmp[i]
}
// Slide unused IV pieces down and insert src at top.
for i := 0; i < x.cipherSize-x.blockSize; i++ {
x.iv[i] = x.iv[i+x.blockSize]
}
off := x.cipherSize - x.blockSize
for i := off; i < x.cipherSize; i++ {
// Reconstruct src = dst ^ x.tmp
// in case we overwrote src (src == dst).
x.iv[i] = dst[i-off] ^ x.tmp[i-off]
}
}
// NewCFBDecrypter returns a reader that reads data from r and decrypts it using c
// in s-bit cipher feedback (CFB) mode with the initialization vector iv.
// The returned Reader does not buffer or read ahead except
// as required by the cipher's block size.
// Modes for s not a multiple of 8 are unimplemented.
func NewCFBDecrypter(c Cipher, s int, iv []byte, r io.Reader) io.Reader {
return NewECBDecrypter(newCFB(c, s, iv), r)
}
// NewCFBEncrypter returns a writer that encrypts data using c
// in s-bit cipher feedback (CFB) mode with the initialization vector iv
// and writes the encrypted data to w.
// The returned Writer does no buffering except as required
// by the cipher's block size, so there is no need for a Flush method.
// Modes for s not a multiple of 8 are unimplemented.
func NewCFBEncrypter(c Cipher, s int, iv []byte, w io.Writer) io.Writer {
return NewECBEncrypter(newCFB(c, s, iv), w)
}

View File

@ -1,311 +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.
// CFB AES test vectors.
// See U.S. National Institute of Standards and Technology (NIST)
// Special Publication 800-38A, ``Recommendation for Block Cipher
// Modes of Operation,'' 2001 Edition, pp. 29-52.
package block
import (
"bytes"
"crypto/aes"
"io"
"testing"
)
type cfbTest struct {
name string
s int
key []byte
iv []byte
in []byte
out []byte
}
var cfbAESTests = []cfbTest{
{
"CFB1-AES128",
1,
commonKey128,
commonIV,
[]byte{
0<<7 | 1<<6 | 1<<5 | 0<<4 | 1<<3 | 0<<2 | 1<<1,
1<<7 | 1<<6 | 0<<5 | 0<<4 | 0<<3 | 0<<2 | 0<<1,
},
[]byte{
0<<7 | 1<<6 | 1<<5 | 0<<4 | 1<<3 | 0<<2 | 0<<1,
1<<7 | 0<<6 | 1<<5 | 1<<4 | 0<<3 | 0<<2 | 1<<1,
},
},
{
"CFB1-AES192",
1,
commonKey192,
commonIV,
[]byte{
0<<7 | 1<<6 | 1<<5 | 0<<4 | 1<<3 | 0<<2 | 1<<1,
1<<7 | 1<<6 | 0<<5 | 0<<4 | 0<<3 | 0<<2 | 0<<1,
},
[]byte{
1<<7 | 0<<6 | 0<<5 | 1<<4 | 0<<3 | 0<<2 | 1<<1,
0<<7 | 1<<6 | 0<<5 | 1<<4 | 1<<3 | 0<<2 | 0<<1,
},
},
{
"CFB1-AES256",
1,
commonKey256,
commonIV,
[]byte{
0<<7 | 1<<6 | 1<<5 | 0<<4 | 1<<3 | 0<<2 | 1<<1,
1<<7 | 1<<6 | 0<<5 | 0<<4 | 0<<3 | 0<<2 | 0<<1,
},
[]byte{
1<<7 | 0<<6 | 0<<5 | 1<<4 | 0<<3 | 0<<2 | 0<<1,
0<<7 | 0<<6 | 1<<5 | 0<<4 | 1<<3 | 0<<2 | 0<<1,
},
},
{
"CFB8-AES128",
8,
commonKey128,
commonIV,
[]byte{
0x6b,
0xc1,
0xbe,
0xe2,
0x2e,
0x40,
0x9f,
0x96,
0xe9,
0x3d,
0x7e,
0x11,
0x73,
0x93,
0x17,
0x2a,
0xae,
0x2d,
},
[]byte{
0x3b,
0x79,
0x42,
0x4c,
0x9c,
0x0d,
0xd4,
0x36,
0xba,
0xce,
0x9e,
0x0e,
0xd4,
0x58,
0x6a,
0x4f,
0x32,
0xb9,
},
},
{
"CFB8-AES192",
8,
commonKey192,
commonIV,
[]byte{
0x6b,
0xc1,
0xbe,
0xe2,
0x2e,
0x40,
0x9f,
0x96,
0xe9,
0x3d,
0x7e,
0x11,
0x73,
0x93,
0x17,
0x2a,
0xae,
0x2d,
},
[]byte{
0xcd,
0xa2,
0x52,
0x1e,
0xf0,
0xa9,
0x05,
0xca,
0x44,
0xcd,
0x05,
0x7c,
0xbf,
0x0d,
0x47,
0xa0,
0x67,
0x8a,
},
},
{
"CFB8-AES256",
8,
commonKey256,
commonIV,
[]byte{
0x6b,
0xc1,
0xbe,
0xe2,
0x2e,
0x40,
0x9f,
0x96,
0xe9,
0x3d,
0x7e,
0x11,
0x73,
0x93,
0x17,
0x2a,
0xae,
0x2d,
},
[]byte{
0xdc,
0x1f,
0x1a,
0x85,
0x20,
0xa6,
0x4d,
0xb5,
0x5f,
0xcc,
0x8a,
0xc5,
0x54,
0x84,
0x4e,
0x88,
0x97,
0x00,
},
},
{
"CFB128-AES128",
128,
commonKey128,
commonIV,
[]byte{
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
},
[]byte{
0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20, 0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a,
0xc8, 0xa6, 0x45, 0x37, 0xa0, 0xb3, 0xa9, 0x3f, 0xcd, 0xe3, 0xcd, 0xad, 0x9f, 0x1c, 0xe5, 0x8b,
0x26, 0x75, 0x1f, 0x67, 0xa3, 0xcb, 0xb1, 0x40, 0xb1, 0x80, 0x8c, 0xf1, 0x87, 0xa4, 0xf4, 0xdf,
0xc0, 0x4b, 0x05, 0x35, 0x7c, 0x5d, 0x1c, 0x0e, 0xea, 0xc4, 0xc6, 0x6f, 0x9f, 0xf7, 0xf2, 0xe6,
},
},
{
"CFB128-AES192",
128,
commonKey192,
commonIV,
[]byte{
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
},
[]byte{
0xcd, 0xc8, 0x0d, 0x6f, 0xdd, 0xf1, 0x8c, 0xab, 0x34, 0xc2, 0x59, 0x09, 0xc9, 0x9a, 0x41, 0x74,
0x67, 0xce, 0x7f, 0x7f, 0x81, 0x17, 0x36, 0x21, 0x96, 0x1a, 0x2b, 0x70, 0x17, 0x1d, 0x3d, 0x7a,
0x2e, 0x1e, 0x8a, 0x1d, 0xd5, 0x9b, 0x88, 0xb1, 0xc8, 0xe6, 0x0f, 0xed, 0x1e, 0xfa, 0xc4, 0xc9,
0xc0, 0x5f, 0x9f, 0x9c, 0xa9, 0x83, 0x4f, 0xa0, 0x42, 0xae, 0x8f, 0xba, 0x58, 0x4b, 0x09, 0xff,
},
},
{
"CFB128-AES256",
128,
commonKey256,
commonIV,
[]byte{
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
},
[]byte{
0xdc, 0x7e, 0x84, 0xbf, 0xda, 0x79, 0x16, 0x4b, 0x7e, 0xcd, 0x84, 0x86, 0x98, 0x5d, 0x38, 0x60,
0x39, 0xff, 0xed, 0x14, 0x3b, 0x28, 0xb1, 0xc8, 0x32, 0x11, 0x3c, 0x63, 0x31, 0xe5, 0x40, 0x7b,
0xdf, 0x10, 0x13, 0x24, 0x15, 0xe5, 0x4b, 0x92, 0xa1, 0x3e, 0xd0, 0xa8, 0x26, 0x7a, 0xe2, 0xf9,
0x75, 0xa3, 0x85, 0x74, 0x1a, 0xb9, 0xce, 0xf8, 0x20, 0x31, 0x62, 0x3d, 0x55, 0xb1, 0xe4, 0x71,
},
},
}
func TestCFB_AES(t *testing.T) {
for _, tt := range cfbAESTests {
test := tt.name
if tt.s == 1 {
// 1-bit CFB not implemented
continue
}
c, err := aes.NewCipher(tt.key)
if err != nil {
t.Errorf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err)
continue
}
var crypt bytes.Buffer
w := NewCFBEncrypter(c, tt.s, tt.iv, &crypt)
var r io.Reader = bytes.NewBuffer(tt.in)
n, err := io.Copy(w, r)
if n != int64(len(tt.in)) || err != nil {
t.Errorf("%s: CFBEncrypter io.Copy = %d, %v want %d, nil", test, n, err, len(tt.in))
} else if d := crypt.Bytes(); !same(tt.out, d) {
t.Errorf("%s: CFBEncrypter\nhave %x\nwant %x", test, d, tt.out)
}
var plain bytes.Buffer
r = NewCFBDecrypter(c, tt.s, tt.iv, bytes.NewBuffer(tt.out))
w = &plain
n, err = io.Copy(w, r)
if n != int64(len(tt.out)) || err != nil {
t.Errorf("%s: CFBDecrypter io.Copy = %d, %v want %d, nil", test, n, err, len(tt.out))
} else if d := plain.Bytes(); !same(tt.in, d) {
t.Errorf("%s: CFBDecrypter\nhave %x\nwant %x", test, d, tt.in)
}
if t.Failed() {
break
}
}
}

View File

@ -1,57 +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.
// The block package is deprecated, use cipher instead.
// The block package implements standard block cipher modes
// that can be wrapped around low-level block cipher implementations.
// See http://csrc.nist.gov/groups/ST/toolkit/BCM/current_modes.html
// and NIST Special Publication 800-38A.
package block
// A Cipher represents an implementation of block cipher
// using a given key. It provides the capability to encrypt
// or decrypt individual blocks. The mode implementations
// extend that capability to streams of blocks.
type Cipher interface {
// BlockSize returns the cipher's block size.
BlockSize() int
// Encrypt encrypts the first block in src into dst.
// Src and dst may point at the same memory.
Encrypt(dst, src []byte)
// Decrypt decrypts the first block in src into dst.
// Src and dst may point at the same memory.
Decrypt(dst, src []byte)
}
// Utility routines
func shift1(dst, src []byte) byte {
var b byte
for i := len(src) - 1; i >= 0; i-- {
bb := src[i] >> 7
dst[i] = src[i]<<1 | b
b = bb
}
return b
}
func same(p, q []byte) bool {
if len(p) != len(q) {
return false
}
for i := 0; i < len(p); i++ {
if p[i] != q[i] {
return false
}
}
return true
}
func dup(p []byte) []byte {
q := make([]byte, len(p))
copy(q, p)
return q
}

View File

@ -1,105 +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.
// CMAC message authentication code, defined in
// NIST Special Publication SP 800-38B.
package block
import (
"hash"
"os"
)
const (
// minimal irreducible polynomial of degree b
r64 = 0x1b
r128 = 0x87
)
type cmac struct {
k1, k2, ci, digest []byte
p int // position in ci
c Cipher
}
// TODO(rsc): Should this return an error instead of panic?
// NewCMAC returns a new instance of a CMAC message authentication code
// digest using the given Cipher.
func NewCMAC(c Cipher) hash.Hash {
var r byte
n := c.BlockSize()
switch n {
case 64 / 8:
r = r64
case 128 / 8:
r = r128
default:
panic("crypto/block: NewCMAC: invalid cipher block size")
}
d := new(cmac)
d.c = c
d.k1 = make([]byte, n)
d.k2 = make([]byte, n)
d.ci = make([]byte, n)
d.digest = make([]byte, n)
// Subkey generation, p. 7
c.Encrypt(d.k1, d.k1)
if shift1(d.k1, d.k1) != 0 {
d.k1[n-1] ^= r
}
if shift1(d.k2, d.k1) != 0 {
d.k2[n-1] ^= r
}
return d
}
// Reset clears the digest state, starting a new digest.
func (d *cmac) Reset() {
for i := range d.ci {
d.ci[i] = 0
}
d.p = 0
}
// Write adds the given data to the digest state.
func (d *cmac) Write(p []byte) (n int, err os.Error) {
// Xor input into ci.
for _, c := range p {
// If ci is full, encrypt and start over.
if d.p >= len(d.ci) {
d.c.Encrypt(d.ci, d.ci)
d.p = 0
}
d.ci[d.p] ^= c
d.p++
}
return len(p), nil
}
// Sum returns the CMAC digest, one cipher block in length,
// of the data written with Write.
func (d *cmac) Sum() []byte {
// Finish last block, mix in key, encrypt.
// Don't edit ci, in case caller wants
// to keep digesting after call to Sum.
k := d.k1
if d.p < len(d.digest) {
k = d.k2
}
for i := 0; i < len(d.ci); i++ {
d.digest[i] = d.ci[i] ^ k[i]
}
if d.p < len(d.digest) {
d.digest[d.p] ^= 0x80
}
d.c.Encrypt(d.digest, d.digest)
return d.digest
}
func (d *cmac) Size() int { return len(d.digest) }

View File

@ -1,130 +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.
// CMAC test vectors. See NIST SP 800-38B, Appendix D.
package block
import (
"crypto/aes"
"testing"
)
type cmacAESTest struct {
key []byte
in []byte
digest []byte
}
var cmacAESTests = []cmacAESTest{
{
commonKey128,
nil,
[]byte{0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28, 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46},
},
{
commonKey128,
[]byte{0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a},
[]byte{0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44, 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c},
},
{
commonKey128,
[]byte{
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
},
[]byte{0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30, 0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27},
},
{
commonKey128,
[]byte{
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
},
[]byte{0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92, 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe},
},
{
commonKey192,
nil,
[]byte{0xd1, 0x7d, 0xdf, 0x46, 0xad, 0xaa, 0xcd, 0xe5, 0x31, 0xca, 0xc4, 0x83, 0xde, 0x7a, 0x93, 0x67},
},
{
commonKey192,
[]byte{0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a},
[]byte{0x9e, 0x99, 0xa7, 0xbf, 0x31, 0xe7, 0x10, 0x90, 0x06, 0x62, 0xf6, 0x5e, 0x61, 0x7c, 0x51, 0x84},
},
{
commonKey192,
[]byte{
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
},
[]byte{0x8a, 0x1d, 0xe5, 0xbe, 0x2e, 0xb3, 0x1a, 0xad, 0x08, 0x9a, 0x82, 0xe6, 0xee, 0x90, 0x8b, 0x0e},
},
{
commonKey192,
[]byte{
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
},
[]byte{0xa1, 0xd5, 0xdf, 0x0e, 0xed, 0x79, 0x0f, 0x79, 0x4d, 0x77, 0x58, 0x96, 0x59, 0xf3, 0x9a, 0x11},
},
{
commonKey256,
nil,
[]byte{0x02, 0x89, 0x62, 0xf6, 0x1b, 0x7b, 0xf8, 0x9e, 0xfc, 0x6b, 0x55, 0x1f, 0x46, 0x67, 0xd9, 0x83},
},
{
commonKey256,
[]byte{0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a},
[]byte{0x28, 0xa7, 0x02, 0x3f, 0x45, 0x2e, 0x8f, 0x82, 0xbd, 0x4b, 0xf2, 0x8d, 0x8c, 0x37, 0xc3, 0x5c},
},
{
commonKey256,
[]byte{
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
},
[]byte{0xaa, 0xf3, 0xd8, 0xf1, 0xde, 0x56, 0x40, 0xc2, 0x32, 0xf5, 0xb1, 0x69, 0xb9, 0xc9, 0x11, 0xe6},
},
{
commonKey256,
[]byte{
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
},
[]byte{0xe1, 0x99, 0x21, 0x90, 0x54, 0x9f, 0x6e, 0xd5, 0x69, 0x6a, 0x2c, 0x05, 0x6c, 0x31, 0x54, 0x10},
},
}
func TestCMAC_AES(t *testing.T) {
for i, tt := range cmacAESTests {
c, err := aes.NewCipher(tt.key)
if err != nil {
t.Errorf("test %d: NewCipher: %s", i, err)
continue
}
d := NewCMAC(c)
n, err := d.Write(tt.in)
if err != nil || n != len(tt.in) {
t.Errorf("test %d: Write %d: %d, %s", i, len(tt.in), n, err)
continue
}
sum := d.Sum()
if !same(sum, tt.digest) {
x := d.(*cmac)
t.Errorf("test %d: digest mismatch\n\twant %x\n\thave %x\n\tk1 %x\n\tk2 %x", i, tt.digest, sum, x.k1, x.k2)
continue
}
}
}

View File

@ -1,67 +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.
// Counter (CTR) mode.
// CTR converts a block cipher into a stream cipher by
// repeatedly encrypting an incrementing counter and
// xoring the resulting stream of data with the input.
// See NIST SP 800-38A, pp 13-15
package block
import (
"io"
)
type ctrStream struct {
c Cipher
ctr []byte
out []byte
}
func newCTRStream(c Cipher, ctr []byte) *ctrStream {
x := new(ctrStream)
x.c = c
x.ctr = dup(ctr)
x.out = make([]byte, len(ctr))
return x
}
func (x *ctrStream) Next() []byte {
// Next block is encryption of counter.
x.c.Encrypt(x.out, x.ctr)
// Increment counter
for i := len(x.ctr) - 1; i >= 0; i-- {
x.ctr[i]++
if x.ctr[i] != 0 {
break
}
}
return x.out
}
// NewCTRReader returns a reader that reads data from r, decrypts (or encrypts)
// it using c in counter (CTR) mode with the initialization vector iv.
// The returned Reader does not buffer and has no block size.
// In CTR mode, encryption and decryption are the same operation:
// a CTR reader applied to an encrypted stream produces a decrypted
// stream and vice versa.
func NewCTRReader(c Cipher, iv []byte, r io.Reader) io.Reader {
return newXorReader(newCTRStream(c, iv), r)
}
// NewCTRWriter returns a writer that encrypts (or decrypts) data using c
// in counter (CTR) mode with the initialization vector iv
// and writes the encrypted data to w.
// The returned Writer does not buffer and has no block size.
// In CTR mode, encryption and decryption are the same operation:
// a CTR writer applied to an decrypted stream produces an encrypted
// stream and vice versa.
func NewCTRWriter(c Cipher, iv []byte, w io.Writer) io.Writer {
return newXorWriter(newCTRStream(c, iv), w)
}

View File

@ -1,253 +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.
// EAX mode, not a NIST standard (yet).
// EAX provides encryption and authentication.
// EAX targets the same uses as NIST's CCM mode,
// but EAX adds the ability to run in streaming mode.
// See
// http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/eax/eax-spec.pdf
// http://www.cs.ucdavis.edu/~rogaway/papers/eax.pdf
// What those papers call OMAC is now called CMAC.
package block
import (
"fmt"
"hash"
"io"
"os"
)
// An EAXTagError is returned when the message has failed to authenticate,
// because the tag at the end of the message stream (Read) does not match
// the tag computed from the message itself (Computed).
type EAXTagError struct {
Read []byte
Computed []byte
}
func (e *EAXTagError) String() string {
return fmt.Sprintf("crypto/block: EAX tag mismatch: read %x but computed %x", e.Read, e.Computed)
}
func setupEAX(c Cipher, iv, hdr []byte, tagBytes int) (ctrIV, tag []byte, cmac hash.Hash) {
n := len(iv)
if n != c.BlockSize() {
panic(fmt.Sprintln("crypto/block: EAX: iv length", n, "!=", c.BlockSize()))
}
buf := make([]byte, n) // zeroed
// tag = CMAC(0 + iv) ^ CMAC(1 + hdr) ^ CMAC(2 + data)
cmac = NewCMAC(c)
cmac.Write(buf) // 0
cmac.Write(iv)
sum := cmac.Sum()
ctrIV = dup(sum)
tag = dup(sum[0:tagBytes])
cmac.Reset()
buf[n-1] = 1
cmac.Write(buf) // 1
cmac.Write(hdr)
sum = cmac.Sum()
for i := 0; i < tagBytes; i++ {
tag[i] ^= sum[i]
}
cmac.Reset()
buf[n-1] = 2 // 2
cmac.Write(buf)
return
}
func finishEAX(tag []byte, cmac hash.Hash) {
// Finish CMAC #2 and xor into tag.
sum := cmac.Sum()
for i := range tag {
tag[i] ^= sum[i]
}
}
// Writer adapter. Tees writes into both w and cmac.
// Knows that cmac never returns write errors.
type cmacWriter struct {
w io.Writer
cmac hash.Hash
}
func (cw *cmacWriter) Write(p []byte) (n int, err os.Error) {
n, err = cw.w.Write(p)
cw.cmac.Write(p[0:n])
return
}
// An eaxEncrypter implements the EAX encryption mode.
type eaxEncrypter struct {
ctr io.Writer // CTR encrypter
cw cmacWriter // CTR's output stream
tag []byte
}
// NewEAXEncrypter creates and returns a new EAX encrypter
// using the given cipher c, initialization vector iv, associated data hdr,
// and tag length tagBytes. The encrypter's Write method encrypts
// the data it receives and writes that data to w.
// The encrypter's Close method writes a final authenticating tag to w.
func NewEAXEncrypter(c Cipher, iv []byte, hdr []byte, tagBytes int, w io.Writer) io.WriteCloser {
x := new(eaxEncrypter)
// Create new CTR instance writing to both
// w for encrypted output and cmac for digesting.
x.cw.w = w
var ctrIV []byte
ctrIV, x.tag, x.cw.cmac = setupEAX(c, iv, hdr, tagBytes)
x.ctr = NewCTRWriter(c, ctrIV, &x.cw)
return x
}
func (x *eaxEncrypter) Write(p []byte) (n int, err os.Error) {
return x.ctr.Write(p)
}
func (x *eaxEncrypter) Close() os.Error {
x.ctr = nil // crash if Write is called again
// Write tag.
finishEAX(x.tag, x.cw.cmac)
n, err := x.cw.w.Write(x.tag)
if n != len(x.tag) && err == nil {
err = io.ErrShortWrite
}
return err
}
// Reader adapter. Returns data read from r but hangs
// on to the last len(tag) bytes for itself (returns EOF len(tag)
// bytes early). Also tees all data returned from Read into
// the cmac digest. The "don't return the last t bytes"
// and the "tee into digest" functionality could be separated,
// but the latter half is trivial.
type cmacReader struct {
r io.Reader
cmac hash.Hash
tag []byte
tmp []byte
}
func (cr *cmacReader) Read(p []byte) (n int, err os.Error) {
// TODO(rsc): Maybe fall back to simpler code if
// we recognize the underlying r as a ByteBuffer
// or ByteReader. Then we can just take the last piece
// off at the start.
// First, read a tag-sized chunk.
// It's probably not the tag (unless there's no data).
tag := cr.tag
if len(tag) < cap(tag) {
nt := len(tag)
nn, err1 := io.ReadFull(cr.r, tag[nt:cap(tag)])
tag = tag[0 : nt+nn]
cr.tag = tag
if err1 != nil {
return 0, err1
}
}
tagBytes := len(tag)
if len(p) > 4*tagBytes {
// If p is big, try to read directly into p to avoid a copy.
n, err = cr.r.Read(p[tagBytes:])
if n == 0 {
goto out
}
// copy old tag into p
for i := 0; i < tagBytes; i++ {
p[i] = tag[i]
}
// copy new tag out of p
for i := 0; i < tagBytes; i++ {
tag[i] = p[n+i]
}
goto out
}
// Otherwise, read into p and then slide data
n, err = cr.r.Read(p)
if n == 0 {
goto out
}
// copy tag+p into p+tmp and then swap tmp, tag
tmp := cr.tmp
for i := n + tagBytes - 1; i >= 0; i-- {
var c byte
if i < tagBytes {
c = tag[i]
} else {
c = p[i-tagBytes]
}
if i < n {
p[i] = c
} else {
tmp[i] = c
}
}
cr.tmp, cr.tag = tag, tmp
out:
cr.cmac.Write(p[0:n])
return
}
type eaxDecrypter struct {
ctr io.Reader
cr cmacReader
tag []byte
}
// NewEAXDecrypter creates and returns a new EAX decrypter
// using the given cipher c, initialization vector iv, associated data hdr,
// and tag length tagBytes. The encrypter's Read method decrypts and
// returns data read from r. At r's EOF, the encrypter checks the final
// authenticating tag and returns an EAXTagError if the tag is invalid.
// In that case, the message should be discarded.
// Note that the data stream returned from Read cannot be
// assumed to be valid, authenticated data until Read returns
// 0, nil to signal the end of the data.
func NewEAXDecrypter(c Cipher, iv []byte, hdr []byte, tagBytes int, r io.Reader) io.Reader {
x := new(eaxDecrypter)
x.cr.r = r
x.cr.tag = make([]byte, 0, tagBytes)
x.cr.tmp = make([]byte, 0, tagBytes)
var ctrIV []byte
ctrIV, x.tag, x.cr.cmac = setupEAX(c, iv, hdr, tagBytes)
x.ctr = NewCTRReader(c, ctrIV, &x.cr)
return x
}
func (x *eaxDecrypter) checkTag() os.Error {
x.ctr = nil // crash if Read is called again
finishEAX(x.tag, x.cr.cmac)
if !same(x.tag, x.cr.tag) {
e := new(EAXTagError)
e.Computed = dup(x.tag)
e.Read = dup(x.cr.tag)
return e
}
return nil
}
func (x *eaxDecrypter) Read(p []byte) (n int, err os.Error) {
n, err = x.ctr.Read(p)
if n == 0 && err == nil {
err = x.checkTag()
}
return n, err
}

View File

@ -1,140 +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.
package block
import (
"bytes"
"crypto/aes"
"fmt"
"io"
"testing"
)
// Test vectors from http://www.cs.ucdavis.edu/~rogaway/papers/eax.pdf
type eaxAESTest struct {
msg []byte
key []byte
nonce []byte
header []byte
cipher []byte
}
var eaxAESTests = []eaxAESTest{
{
[]byte{},
[]byte{0x23, 0x39, 0x52, 0xDE, 0xE4, 0xD5, 0xED, 0x5F, 0x9B, 0x9C, 0x6D, 0x6F, 0xF8, 0x0F, 0xF4, 0x78},
[]byte{0x62, 0xEC, 0x67, 0xF9, 0xC3, 0xA4, 0xA4, 0x07, 0xFC, 0xB2, 0xA8, 0xC4, 0x90, 0x31, 0xA8, 0xB3},
[]byte{0x6B, 0xFB, 0x91, 0x4F, 0xD0, 0x7E, 0xAE, 0x6B},
[]byte{0xE0, 0x37, 0x83, 0x0E, 0x83, 0x89, 0xF2, 0x7B, 0x02, 0x5A, 0x2D, 0x65, 0x27, 0xE7, 0x9D, 0x01},
},
{
[]byte{0xF7, 0xFB},
[]byte{0x91, 0x94, 0x5D, 0x3F, 0x4D, 0xCB, 0xEE, 0x0B, 0xF4, 0x5E, 0xF5, 0x22, 0x55, 0xF0, 0x95, 0xA4},
[]byte{0xBE, 0xCA, 0xF0, 0x43, 0xB0, 0xA2, 0x3D, 0x84, 0x31, 0x94, 0xBA, 0x97, 0x2C, 0x66, 0xDE, 0xBD},
[]byte{0xFA, 0x3B, 0xFD, 0x48, 0x06, 0xEB, 0x53, 0xFA},
[]byte{0x19, 0xDD, 0x5C, 0x4C, 0x93, 0x31, 0x04, 0x9D, 0x0B, 0xDA, 0xB0, 0x27, 0x74, 0x08, 0xF6, 0x79, 0x67, 0xE5},
},
{
[]byte{0x1A, 0x47, 0xCB, 0x49, 0x33},
[]byte{0x01, 0xF7, 0x4A, 0xD6, 0x40, 0x77, 0xF2, 0xE7, 0x04, 0xC0, 0xF6, 0x0A, 0xDA, 0x3D, 0xD5, 0x23},
[]byte{0x70, 0xC3, 0xDB, 0x4F, 0x0D, 0x26, 0x36, 0x84, 0x00, 0xA1, 0x0E, 0xD0, 0x5D, 0x2B, 0xFF, 0x5E},
[]byte{0x23, 0x4A, 0x34, 0x63, 0xC1, 0x26, 0x4A, 0xC6},
[]byte{0xD8, 0x51, 0xD5, 0xBA, 0xE0, 0x3A, 0x59, 0xF2, 0x38, 0xA2, 0x3E, 0x39, 0x19, 0x9D, 0xC9, 0x26, 0x66, 0x26, 0xC4, 0x0F, 0x80},
},
{
[]byte{0x48, 0x1C, 0x9E, 0x39, 0xB1},
[]byte{0xD0, 0x7C, 0xF6, 0xCB, 0xB7, 0xF3, 0x13, 0xBD, 0xDE, 0x66, 0xB7, 0x27, 0xAF, 0xD3, 0xC5, 0xE8},
[]byte{0x84, 0x08, 0xDF, 0xFF, 0x3C, 0x1A, 0x2B, 0x12, 0x92, 0xDC, 0x19, 0x9E, 0x46, 0xB7, 0xD6, 0x17},
[]byte{0x33, 0xCC, 0xE2, 0xEA, 0xBF, 0xF5, 0xA7, 0x9D},
[]byte{0x63, 0x2A, 0x9D, 0x13, 0x1A, 0xD4, 0xC1, 0x68, 0xA4, 0x22, 0x5D, 0x8E, 0x1F, 0xF7, 0x55, 0x93, 0x99, 0x74, 0xA7, 0xBE, 0xDE},
},
{
[]byte{0x40, 0xD0, 0xC0, 0x7D, 0xA5, 0xE4},
[]byte{0x35, 0xB6, 0xD0, 0x58, 0x00, 0x05, 0xBB, 0xC1, 0x2B, 0x05, 0x87, 0x12, 0x45, 0x57, 0xD2, 0xC2},
[]byte{0xFD, 0xB6, 0xB0, 0x66, 0x76, 0xEE, 0xDC, 0x5C, 0x61, 0xD7, 0x42, 0x76, 0xE1, 0xF8, 0xE8, 0x16},
[]byte{0xAE, 0xB9, 0x6E, 0xAE, 0xBE, 0x29, 0x70, 0xE9},
[]byte{0x07, 0x1D, 0xFE, 0x16, 0xC6, 0x75, 0xCB, 0x06, 0x77, 0xE5, 0x36, 0xF7, 0x3A, 0xFE, 0x6A, 0x14, 0xB7, 0x4E, 0xE4, 0x98, 0x44, 0xDD},
},
{
[]byte{0x4D, 0xE3, 0xB3, 0x5C, 0x3F, 0xC0, 0x39, 0x24, 0x5B, 0xD1, 0xFB, 0x7D},
[]byte{0xBD, 0x8E, 0x6E, 0x11, 0x47, 0x5E, 0x60, 0xB2, 0x68, 0x78, 0x4C, 0x38, 0xC6, 0x2F, 0xEB, 0x22},
[]byte{0x6E, 0xAC, 0x5C, 0x93, 0x07, 0x2D, 0x8E, 0x85, 0x13, 0xF7, 0x50, 0x93, 0x5E, 0x46, 0xDA, 0x1B},
[]byte{0xD4, 0x48, 0x2D, 0x1C, 0xA7, 0x8D, 0xCE, 0x0F},
[]byte{0x83, 0x5B, 0xB4, 0xF1, 0x5D, 0x74, 0x3E, 0x35, 0x0E, 0x72, 0x84, 0x14, 0xAB, 0xB8, 0x64, 0x4F, 0xD6, 0xCC, 0xB8, 0x69, 0x47, 0xC5, 0xE1, 0x05, 0x90, 0x21, 0x0A, 0x4F},
},
{
[]byte{0x8B, 0x0A, 0x79, 0x30, 0x6C, 0x9C, 0xE7, 0xED, 0x99, 0xDA, 0xE4, 0xF8, 0x7F, 0x8D, 0xD6, 0x16, 0x36},
[]byte{0x7C, 0x77, 0xD6, 0xE8, 0x13, 0xBE, 0xD5, 0xAC, 0x98, 0xBA, 0xA4, 0x17, 0x47, 0x7A, 0x2E, 0x7D},
[]byte{0x1A, 0x8C, 0x98, 0xDC, 0xD7, 0x3D, 0x38, 0x39, 0x3B, 0x2B, 0xF1, 0x56, 0x9D, 0xEE, 0xFC, 0x19},
[]byte{0x65, 0xD2, 0x01, 0x79, 0x90, 0xD6, 0x25, 0x28},
[]byte{0x02, 0x08, 0x3E, 0x39, 0x79, 0xDA, 0x01, 0x48, 0x12, 0xF5, 0x9F, 0x11, 0xD5, 0x26, 0x30, 0xDA, 0x30, 0x13, 0x73, 0x27, 0xD1, 0x06, 0x49, 0xB0, 0xAA, 0x6E, 0x1C, 0x18, 0x1D, 0xB6, 0x17, 0xD7, 0xF2},
},
{
[]byte{0x1B, 0xDA, 0x12, 0x2B, 0xCE, 0x8A, 0x8D, 0xBA, 0xF1, 0x87, 0x7D, 0x96, 0x2B, 0x85, 0x92, 0xDD, 0x2D, 0x56},
[]byte{0x5F, 0xFF, 0x20, 0xCA, 0xFA, 0xB1, 0x19, 0xCA, 0x2F, 0xC7, 0x35, 0x49, 0xE2, 0x0F, 0x5B, 0x0D},
[]byte{0xDD, 0xE5, 0x9B, 0x97, 0xD7, 0x22, 0x15, 0x6D, 0x4D, 0x9A, 0xFF, 0x2B, 0xC7, 0x55, 0x98, 0x26},
[]byte{0x54, 0xB9, 0xF0, 0x4E, 0x6A, 0x09, 0x18, 0x9A},
[]byte{0x2E, 0xC4, 0x7B, 0x2C, 0x49, 0x54, 0xA4, 0x89, 0xAF, 0xC7, 0xBA, 0x48, 0x97, 0xED, 0xCD, 0xAE, 0x8C, 0xC3, 0x3B, 0x60, 0x45, 0x05, 0x99, 0xBD, 0x02, 0xC9, 0x63, 0x82, 0x90, 0x2A, 0xEF, 0x7F, 0x83, 0x2A},
},
{
[]byte{0x6C, 0xF3, 0x67, 0x20, 0x87, 0x2B, 0x85, 0x13, 0xF6, 0xEA, 0xB1, 0xA8, 0xA4, 0x44, 0x38, 0xD5, 0xEF, 0x11},
[]byte{0xA4, 0xA4, 0x78, 0x2B, 0xCF, 0xFD, 0x3E, 0xC5, 0xE7, 0xEF, 0x6D, 0x8C, 0x34, 0xA5, 0x61, 0x23},
[]byte{0xB7, 0x81, 0xFC, 0xF2, 0xF7, 0x5F, 0xA5, 0xA8, 0xDE, 0x97, 0xA9, 0xCA, 0x48, 0xE5, 0x22, 0xEC},
[]byte{0x89, 0x9A, 0x17, 0x58, 0x97, 0x56, 0x1D, 0x7E},
[]byte{0x0D, 0xE1, 0x8F, 0xD0, 0xFD, 0xD9, 0x1E, 0x7A, 0xF1, 0x9F, 0x1D, 0x8E, 0xE8, 0x73, 0x39, 0x38, 0xB1, 0xE8, 0xE7, 0xF6, 0xD2, 0x23, 0x16, 0x18, 0x10, 0x2F, 0xDB, 0x7F, 0xE5, 0x5F, 0xF1, 0x99, 0x17, 0x00},
},
{
[]byte{0xCA, 0x40, 0xD7, 0x44, 0x6E, 0x54, 0x5F, 0xFA, 0xED, 0x3B, 0xD1, 0x2A, 0x74, 0x0A, 0x65, 0x9F, 0xFB, 0xBB, 0x3C, 0xEA, 0xB7},
[]byte{0x83, 0x95, 0xFC, 0xF1, 0xE9, 0x5B, 0xEB, 0xD6, 0x97, 0xBD, 0x01, 0x0B, 0xC7, 0x66, 0xAA, 0xC3},
[]byte{0x22, 0xE7, 0xAD, 0xD9, 0x3C, 0xFC, 0x63, 0x93, 0xC5, 0x7E, 0xC0, 0xB3, 0xC1, 0x7D, 0x6B, 0x44},
[]byte{0x12, 0x67, 0x35, 0xFC, 0xC3, 0x20, 0xD2, 0x5A},
[]byte{0xCB, 0x89, 0x20, 0xF8, 0x7A, 0x6C, 0x75, 0xCF, 0xF3, 0x96, 0x27, 0xB5, 0x6E, 0x3E, 0xD1, 0x97, 0xC5, 0x52, 0xD2, 0x95, 0xA7, 0xCF, 0xC4, 0x6A, 0xFC, 0x25, 0x3B, 0x46, 0x52, 0xB1, 0xAF, 0x37, 0x95, 0xB1, 0x24, 0xAB, 0x6E},
},
}
func TestEAXEncrypt_AES(t *testing.T) {
b := new(bytes.Buffer)
for i, tt := range eaxAESTests {
test := fmt.Sprintf("test %d", i)
c, err := aes.NewCipher(tt.key)
if err != nil {
t.Fatalf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err)
}
b.Reset()
enc := NewEAXEncrypter(c, tt.nonce, tt.header, 16, b)
n, err := io.Copy(enc, bytes.NewBuffer(tt.msg))
if n != int64(len(tt.msg)) || err != nil {
t.Fatalf("%s: io.Copy into encrypter: %d, %s", test, n, err)
}
err = enc.Close()
if err != nil {
t.Fatalf("%s: enc.Close: %s", test, err)
}
if d := b.Bytes(); !same(d, tt.cipher) {
t.Fatalf("%s: got %x want %x", test, d, tt.cipher)
}
}
}
func TestEAXDecrypt_AES(t *testing.T) {
b := new(bytes.Buffer)
for i, tt := range eaxAESTests {
test := fmt.Sprintf("test %d", i)
c, err := aes.NewCipher(tt.key)
if err != nil {
t.Fatalf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err)
}
b.Reset()
dec := NewEAXDecrypter(c, tt.nonce, tt.header, 16, bytes.NewBuffer(tt.cipher))
n, err := io.Copy(b, dec)
if n != int64(len(tt.msg)) || err != nil {
t.Fatalf("%s: io.Copy into decrypter: %d, %s", test, n, err)
}
if d := b.Bytes(); !same(d, tt.msg) {
t.Fatalf("%s: got %x want %x", test, d, tt.msg)
}
}
}

View File

@ -1,270 +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.
// Electronic codebook (ECB) mode.
// ECB is a fancy name for ``encrypt and decrypt each block separately.''
// It's a pretty bad thing to do for any large amount of data (more than one block),
// because the individual blocks can still be identified, duplicated, and reordered.
// The ECB implementation exists mainly to provide buffering for
// the other modes, which wrap it by providing modified Ciphers.
// See NIST SP 800-38A, pp 9-10
package block
import (
"io"
"os"
"strconv"
)
type ecbDecrypter struct {
c Cipher
r io.Reader
blockSize int // block size
// Buffered data.
// The buffer buf is used as storage for both
// plain or crypt; at least one of those is nil at any given time.
buf []byte
plain []byte // plain text waiting to be read
crypt []byte // ciphertext waiting to be decrypted
}
// Read into x.crypt until it has a full block or EOF or an error happens.
func (x *ecbDecrypter) fillCrypt() os.Error {
var err os.Error
for len(x.crypt) < x.blockSize {
off := len(x.crypt)
var m int
m, err = x.r.Read(x.crypt[off:x.blockSize])
x.crypt = x.crypt[0 : off+m]
if m == 0 {
break
}
// If an error happened but we got enough
// data to do some decryption, we can decrypt
// first and report the error (with some data) later.
// But if we don't have enough to decrypt,
// have to stop now.
if err != nil && len(x.crypt) < x.blockSize {
break
}
}
return err
}
// Read from plain text buffer into p.
func (x *ecbDecrypter) readPlain(p []byte) int {
n := len(x.plain)
if n > len(p) {
n = len(p)
}
for i := 0; i < n; i++ {
p[i] = x.plain[i]
}
if n < len(x.plain) {
x.plain = x.plain[n:]
} else {
x.plain = nil
}
return n
}
type ecbFragmentError int
func (n ecbFragmentError) String() string {
return "crypto/block: " + strconv.Itoa(int(n)) + "-byte fragment at EOF"
}
func (x *ecbDecrypter) Read(p []byte) (n int, err os.Error) {
if len(p) == 0 {
return
}
// If there's no plaintext waiting and p is not big enough
// to hold a whole cipher block, we'll have to work in the
// cipher text buffer. Set it to non-nil so that the
// code below will fill it.
if x.plain == nil && len(p) < x.blockSize && x.crypt == nil {
x.crypt = x.buf[0:0]
}
// If there is a leftover cipher text buffer,
// try to accumulate a full block.
if x.crypt != nil {
err = x.fillCrypt()
if err != nil || len(x.crypt) == 0 {
return
}
x.c.Decrypt(x.crypt, x.crypt)
x.plain = x.crypt
x.crypt = nil
}
// If there is a leftover plain text buffer, read from it.
if x.plain != nil {
n = x.readPlain(p)
return
}
// Read and decrypt directly in caller's buffer.
n, err = io.ReadAtLeast(x.r, p, x.blockSize)
if err == os.EOF && n > 0 {
// EOF is only okay on block boundary
err = os.ErrorString("block fragment at EOF during decryption")
return
}
var i int
for i = 0; i+x.blockSize <= n; i += x.blockSize {
a := p[i : i+x.blockSize]
x.c.Decrypt(a, a)
}
// There might be an encrypted fringe remaining.
// Save it for next time.
if i < n {
p = p[i:n]
copy(x.buf, p)
x.crypt = x.buf[0:len(p)]
n = i
}
return
}
// NewECBDecrypter returns a reader that reads data from r and decrypts it using c.
// It decrypts by calling c.Decrypt on each block in sequence;
// this mode is known as electronic codebook mode, or ECB.
// The returned Reader does not buffer or read ahead except
// as required by the cipher's block size.
func NewECBDecrypter(c Cipher, r io.Reader) io.Reader {
x := new(ecbDecrypter)
x.c = c
x.r = r
x.blockSize = c.BlockSize()
x.buf = make([]byte, x.blockSize)
return x
}
type ecbEncrypter struct {
c Cipher
w io.Writer
blockSize int
// Buffered data.
// The buffer buf is used as storage for both
// plain or crypt. If both are non-nil, plain
// follows crypt in buf.
buf []byte
plain []byte // plain text waiting to be encrypted
crypt []byte // encrypted text waiting to be written
}
// Flush the x.crypt buffer to x.w.
func (x *ecbEncrypter) flushCrypt() os.Error {
if len(x.crypt) == 0 {
return nil
}
n, err := x.w.Write(x.crypt)
if n < len(x.crypt) {
x.crypt = x.crypt[n:]
if err == nil {
err = io.ErrShortWrite
}
}
if err != nil {
return err
}
x.crypt = nil
return nil
}
// Slide x.plain down to the beginning of x.buf.
// Plain is known to have less than one block of data,
// so this is cheap enough.
func (x *ecbEncrypter) slidePlain() {
if len(x.plain) == 0 {
x.plain = x.buf[0:0]
} else if cap(x.plain) < cap(x.buf) {
copy(x.buf, x.plain)
x.plain = x.buf[0:len(x.plain)]
}
}
// Fill x.plain from the data in p.
// Return the number of bytes copied.
func (x *ecbEncrypter) fillPlain(p []byte) int {
off := len(x.plain)
n := len(p)
if max := cap(x.plain) - off; n > max {
n = max
}
x.plain = x.plain[0 : off+n]
for i := 0; i < n; i++ {
x.plain[off+i] = p[i]
}
return n
}
// Encrypt x.plain; record encrypted range as x.crypt.
func (x *ecbEncrypter) encrypt() {
var i int
n := len(x.plain)
for i = 0; i+x.blockSize <= n; i += x.blockSize {
a := x.plain[i : i+x.blockSize]
x.c.Encrypt(a, a)
}
x.crypt = x.plain[0:i]
x.plain = x.plain[i:n]
}
func (x *ecbEncrypter) Write(p []byte) (n int, err os.Error) {
for {
// If there is data waiting to be written, write it.
// This can happen on the first iteration
// if a write failed in an earlier call.
if err = x.flushCrypt(); err != nil {
return
}
// Now that encrypted data is gone (flush ran),
// perhaps we need to slide the plaintext down.
x.slidePlain()
// Fill plaintext buffer from p.
m := x.fillPlain(p)
if m == 0 {
break
}
n += m
p = p[m:]
// Encrypt, adjusting crypt and plain.
x.encrypt()
// Write x.crypt.
if err = x.flushCrypt(); err != nil {
break
}
}
return
}
// NewECBEncrypter returns a writer that encrypts data using c and writes it to w.
// It encrypts by calling c.Encrypt on each block in sequence;
// this mode is known as electronic codebook mode, or ECB.
// The returned Writer does no buffering except as required
// by the cipher's block size, so there is no need for a Flush method.
func NewECBEncrypter(c Cipher, w io.Writer) io.Writer {
x := new(ecbEncrypter)
x.c = c
x.w = w
x.blockSize = c.BlockSize()
// Create a buffer that is an integral number of blocks.
x.buf = make([]byte, 8192/x.blockSize*x.blockSize)
return x
}

View File

@ -1,127 +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.
// ECB AES test vectors.
// See U.S. National Institute of Standards and Technology (NIST)
// Special Publication 800-38A, ``Recommendation for Block Cipher
// Modes of Operation,'' 2001 Edition, pp. 24-27.
package block
import (
"bytes"
"crypto/aes"
"io"
"testing"
)
type ecbTest struct {
name string
key []byte
in []byte
out []byte
}
var commonInput = []byte{
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
}
var commonKey128 = []byte{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c}
var commonKey192 = []byte{
0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5,
0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b,
}
var commonKey256 = []byte{
0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81,
0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4,
}
var commonIV = []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}
var ecbAESTests = []ecbTest{
// FIPS 197, Appendix B, C
{
"FIPS-197 Appendix B",
commonKey128,
[]byte{0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, 0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34},
[]byte{0x39, 0x25, 0x84, 0x1d, 0x02, 0xdc, 0x09, 0xfb, 0xdc, 0x11, 0x85, 0x97, 0x19, 0x6a, 0x0b, 0x32},
},
// NIST SP 800-38A pp 24-27
{
"ECB-AES128",
commonKey128,
commonInput,
[]byte{
0x3a, 0xd7, 0x7b, 0xb4, 0x0d, 0x7a, 0x36, 0x60, 0xa8, 0x9e, 0xca, 0xf3, 0x24, 0x66, 0xef, 0x97,
0xf5, 0xd3, 0xd5, 0x85, 0x03, 0xb9, 0x69, 0x9d, 0xe7, 0x85, 0x89, 0x5a, 0x96, 0xfd, 0xba, 0xaf,
0x43, 0xb1, 0xcd, 0x7f, 0x59, 0x8e, 0xce, 0x23, 0x88, 0x1b, 0x00, 0xe3, 0xed, 0x03, 0x06, 0x88,
0x7b, 0x0c, 0x78, 0x5e, 0x27, 0xe8, 0xad, 0x3f, 0x82, 0x23, 0x20, 0x71, 0x04, 0x72, 0x5d, 0xd4,
},
},
{
"ECB-AES192",
commonKey192,
commonInput,
[]byte{
0xbd, 0x33, 0x4f, 0x1d, 0x6e, 0x45, 0xf2, 0x5f, 0xf7, 0x12, 0xa2, 0x14, 0x57, 0x1f, 0xa5, 0xcc,
0x97, 0x41, 0x04, 0x84, 0x6d, 0x0a, 0xd3, 0xad, 0x77, 0x34, 0xec, 0xb3, 0xec, 0xee, 0x4e, 0xef,
0xef, 0x7a, 0xfd, 0x22, 0x70, 0xe2, 0xe6, 0x0a, 0xdc, 0xe0, 0xba, 0x2f, 0xac, 0xe6, 0x44, 0x4e,
0x9a, 0x4b, 0x41, 0xba, 0x73, 0x8d, 0x6c, 0x72, 0xfb, 0x16, 0x69, 0x16, 0x03, 0xc1, 0x8e, 0x0e,
},
},
{
"ECB-AES256",
commonKey256,
commonInput,
[]byte{
0xf3, 0xee, 0xd1, 0xbd, 0xb5, 0xd2, 0xa0, 0x3c, 0x06, 0x4b, 0x5a, 0x7e, 0x3d, 0xb1, 0x81, 0xf8,
0x59, 0x1c, 0xcb, 0x10, 0xd4, 0x10, 0xed, 0x26, 0xdc, 0x5b, 0xa7, 0x4a, 0x31, 0x36, 0x28, 0x70,
0xb6, 0xed, 0x21, 0xb9, 0x9c, 0xa6, 0xf4, 0xf9, 0xf1, 0x53, 0xe7, 0xb1, 0xbe, 0xaf, 0xed, 0x1d,
0x23, 0x30, 0x4b, 0x7a, 0x39, 0xf9, 0xf3, 0xff, 0x06, 0x7d, 0x8d, 0x8f, 0x9e, 0x24, 0xec, 0xc7,
},
},
}
func TestECB_AES(t *testing.T) {
for _, tt := range ecbAESTests {
test := tt.name
c, err := aes.NewCipher(tt.key)
if err != nil {
t.Errorf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err)
continue
}
var crypt bytes.Buffer
w := NewECBEncrypter(c, &crypt)
var r io.Reader = bytes.NewBuffer(tt.in)
n, err := io.Copy(w, r)
if n != int64(len(tt.in)) || err != nil {
t.Errorf("%s: ECBReader io.Copy = %d, %v want %d, nil", test, n, err, len(tt.in))
} else if d := crypt.Bytes(); !same(tt.out, d) {
t.Errorf("%s: ECBReader\nhave %x\nwant %x", test, d, tt.out)
}
var plain bytes.Buffer
r = NewECBDecrypter(c, bytes.NewBuffer(tt.out))
w = &plain
n, err = io.Copy(w, r)
if n != int64(len(tt.out)) || err != nil {
t.Errorf("%s: ECBWriter io.Copy = %d, %v want %d, nil", test, n, err, len(tt.out))
} else if d := plain.Bytes(); !same(tt.in, d) {
t.Errorf("%s: ECBWriter\nhave %x\nwant %x", test, d, tt.in)
}
if t.Failed() {
break
}
}
}

View File

@ -1,181 +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.
package block
import (
"bytes"
"fmt"
"io"
"testing"
"testing/iotest"
)
// Simple Cipher for testing: adds an incrementing amount
// to each byte in each
type IncCipher struct {
blockSize int
delta byte
encrypting bool
}
func (c *IncCipher) BlockSize() int { return c.blockSize }
func (c *IncCipher) Encrypt(dst, src []byte) {
if !c.encrypting {
panic("encrypt: not encrypting")
}
if len(src) != c.blockSize || len(dst) != c.blockSize {
panic(fmt.Sprintln("encrypt: wrong block size", c.blockSize, len(src), len(dst)))
}
c.delta++
for i, b := range src {
dst[i] = b + c.delta
}
}
func (c *IncCipher) Decrypt(dst, src []byte) {
if c.encrypting {
panic("decrypt: not decrypting")
}
if len(src) != c.blockSize || len(dst) != c.blockSize {
panic(fmt.Sprintln("decrypt: wrong block size ", c.blockSize, " ", len(src), " ", len(dst)))
}
c.delta--
for i, b := range src {
dst[i] = b + c.delta
}
}
func TestECBEncrypter(t *testing.T) {
var plain, crypt [256]byte
for i := 0; i < len(plain); i++ {
plain[i] = byte(i)
}
b := new(bytes.Buffer)
for block := 1; block <= 64; block *= 2 {
// compute encrypted version
delta := byte(0)
for i := 0; i < len(crypt); i++ {
if i%block == 0 {
delta++
}
crypt[i] = plain[i] + delta
}
for frag := 0; frag < 2; frag++ {
c := &IncCipher{block, 0, true}
b.Reset()
r := bytes.NewBuffer(plain[0:])
w := NewECBEncrypter(c, b)
// copy plain into w in increasingly large chunks: 1, 1, 2, 4, 8, ...
// if frag != 0, move the 1 to the end to cause fragmentation.
if frag == 0 {
_, err := io.Copyn(w, r, 1)
if err != nil {
t.Errorf("block=%d frag=0: first Copyn: %s", block, err)
continue
}
}
for n := 1; n <= len(plain)/2; n *= 2 {
_, err := io.Copyn(w, r, int64(n))
if err != nil {
t.Errorf("block=%d frag=%d: Copyn %d: %s", block, frag, n, err)
}
}
if frag != 0 {
_, err := io.Copyn(w, r, 1)
if err != nil {
t.Errorf("block=%d frag=1: last Copyn: %s", block, err)
continue
}
}
// check output
data := b.Bytes()
if len(data) != len(crypt) {
t.Errorf("block=%d frag=%d: want %d bytes, got %d", block, frag, len(crypt), len(data))
continue
}
if string(data) != string(crypt[0:]) {
t.Errorf("block=%d frag=%d: want %x got %x", block, frag, data, crypt)
}
}
}
}
func testECBDecrypter(t *testing.T, maxio int) {
var readers = []func(io.Reader) io.Reader{
func(r io.Reader) io.Reader { return r },
iotest.OneByteReader,
iotest.HalfReader,
}
var plain, crypt [256]byte
for i := 0; i < len(plain); i++ {
plain[i] = byte(255 - i)
}
b := new(bytes.Buffer)
for block := 1; block <= 64 && block <= maxio; block *= 2 {
// compute encrypted version
delta := byte(0)
for i := 0; i < len(crypt); i++ {
if i%block == 0 {
delta++
}
crypt[i] = plain[i] + delta
}
for mode := 0; mode < len(readers); mode++ {
for frag := 0; frag < 2; frag++ {
test := fmt.Sprintf("block=%d mode=%d frag=%d maxio=%d", block, mode, frag, maxio)
c := &IncCipher{block, 0, false}
b.Reset()
r := NewECBDecrypter(c, readers[mode](bytes.NewBuffer(crypt[0:maxio])))
// read from crypt in increasingly large chunks: 1, 1, 2, 4, 8, ...
// if frag == 1, move the 1 to the end to cause fragmentation.
if frag == 0 {
_, err := io.Copyn(b, r, 1)
if err != nil {
t.Errorf("%s: first Copyn: %s", test, err)
continue
}
}
for n := 1; n <= maxio/2; n *= 2 {
_, err := io.Copyn(b, r, int64(n))
if err != nil {
t.Errorf("%s: Copyn %d: %s", test, n, err)
}
}
if frag != 0 {
_, err := io.Copyn(b, r, 1)
if err != nil {
t.Errorf("%s: last Copyn: %s", test, err)
continue
}
}
// check output
data := b.Bytes()
if len(data) != maxio {
t.Errorf("%s: want %d bytes, got %d", test, maxio, len(data))
continue
}
if string(data) != string(plain[0:maxio]) {
t.Errorf("%s: input=%x want %x got %x", test, crypt[0:maxio], plain[0:maxio], data)
}
}
}
}
}
func TestECBDecrypter(t *testing.T) {
// Do shorter I/O sizes first; they're easier to debug.
for n := 1; n <= 256 && !t.Failed(); n *= 2 {
testECBDecrypter(t, n)
}
}

View File

@ -1,60 +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.
// Output feedback (OFB) mode.
// OFB converts a block cipher into a stream cipher by
// repeatedly encrypting an initialization vector and
// xoring the resulting stream of data with the input.
// See NIST SP 800-38A, pp 13-15
package block
import (
"fmt"
"io"
)
type ofbStream struct {
c Cipher
iv []byte
}
func newOFBStream(c Cipher, iv []byte) *ofbStream {
x := new(ofbStream)
x.c = c
n := len(iv)
if n != c.BlockSize() {
panic(fmt.Sprintln("crypto/block: newOFBStream: invalid iv size", n, "!=", c.BlockSize()))
}
x.iv = dup(iv)
return x
}
func (x *ofbStream) Next() []byte {
x.c.Encrypt(x.iv, x.iv)
return x.iv
}
// NewOFBReader returns a reader that reads data from r, decrypts (or encrypts)
// it using c in output feedback (OFB) mode with the initialization vector iv.
// The returned Reader does not buffer and has no block size.
// In OFB mode, encryption and decryption are the same operation:
// an OFB reader applied to an encrypted stream produces a decrypted
// stream and vice versa.
func NewOFBReader(c Cipher, iv []byte, r io.Reader) io.Reader {
return newXorReader(newOFBStream(c, iv), r)
}
// NewOFBWriter returns a writer that encrypts (or decrypts) data using c
// in cipher feedback (OFB) mode with the initialization vector iv
// and writes the encrypted data to w.
// The returned Writer does not buffer and has no block size.
// In OFB mode, encryption and decryption are the same operation:
// an OFB writer applied to an decrypted stream produces an encrypted
// stream and vice versa.
func NewOFBWriter(c Cipher, iv []byte, w io.Writer) io.Writer {
return newXorWriter(newOFBStream(c, iv), w)
}

View File

@ -1,108 +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.
// OFB AES test vectors.
// See U.S. National Institute of Standards and Technology (NIST)
// Special Publication 800-38A, ``Recommendation for Block Cipher
// Modes of Operation,'' 2001 Edition, pp. 52-55.
package block
import (
"bytes"
"crypto/aes"
"io"
"testing"
)
type ofbTest struct {
name string
key []byte
iv []byte
in []byte
out []byte
}
var ofbAESTests = []ofbTest{
// NIST SP 800-38A pp 52-55
{
"OFB-AES128",
commonKey128,
commonIV,
commonInput,
[]byte{
0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20, 0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a,
0x77, 0x89, 0x50, 0x8d, 0x16, 0x91, 0x8f, 0x03, 0xf5, 0x3c, 0x52, 0xda, 0xc5, 0x4e, 0xd8, 0x25,
0x97, 0x40, 0x05, 0x1e, 0x9c, 0x5f, 0xec, 0xf6, 0x43, 0x44, 0xf7, 0xa8, 0x22, 0x60, 0xed, 0xcc,
0x30, 0x4c, 0x65, 0x28, 0xf6, 0x59, 0xc7, 0x78, 0x66, 0xa5, 0x10, 0xd9, 0xc1, 0xd6, 0xae, 0x5e,
},
},
{
"OFB-AES192",
commonKey192,
commonIV,
commonInput,
[]byte{
0xcd, 0xc8, 0x0d, 0x6f, 0xdd, 0xf1, 0x8c, 0xab, 0x34, 0xc2, 0x59, 0x09, 0xc9, 0x9a, 0x41, 0x74,
0xfc, 0xc2, 0x8b, 0x8d, 0x4c, 0x63, 0x83, 0x7c, 0x09, 0xe8, 0x17, 0x00, 0xc1, 0x10, 0x04, 0x01,
0x8d, 0x9a, 0x9a, 0xea, 0xc0, 0xf6, 0x59, 0x6f, 0x55, 0x9c, 0x6d, 0x4d, 0xaf, 0x59, 0xa5, 0xf2,
0x6d, 0x9f, 0x20, 0x08, 0x57, 0xca, 0x6c, 0x3e, 0x9c, 0xac, 0x52, 0x4b, 0xd9, 0xac, 0xc9, 0x2a,
},
},
{
"OFB-AES256",
commonKey256,
commonIV,
commonInput,
[]byte{
0xdc, 0x7e, 0x84, 0xbf, 0xda, 0x79, 0x16, 0x4b, 0x7e, 0xcd, 0x84, 0x86, 0x98, 0x5d, 0x38, 0x60,
0x4f, 0xeb, 0xdc, 0x67, 0x40, 0xd2, 0x0b, 0x3a, 0xc8, 0x8f, 0x6a, 0xd8, 0x2a, 0x4f, 0xb0, 0x8d,
0x71, 0xab, 0x47, 0xa0, 0x86, 0xe8, 0x6e, 0xed, 0xf3, 0x9d, 0x1c, 0x5b, 0xba, 0x97, 0xc4, 0x08,
0x01, 0x26, 0x14, 0x1d, 0x67, 0xf3, 0x7b, 0xe8, 0x53, 0x8f, 0x5a, 0x8b, 0xe7, 0x40, 0xe4, 0x84,
},
},
}
func TestOFB_AES(t *testing.T) {
for _, tt := range ofbAESTests {
test := tt.name
c, err := aes.NewCipher(tt.key)
if err != nil {
t.Errorf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err)
continue
}
for j := 0; j <= 5; j += 5 {
var crypt bytes.Buffer
in := tt.in[0 : len(tt.in)-j]
w := NewOFBWriter(c, tt.iv, &crypt)
var r io.Reader = bytes.NewBuffer(in)
n, err := io.Copy(w, r)
if n != int64(len(in)) || err != nil {
t.Errorf("%s/%d: OFBWriter io.Copy = %d, %v want %d, nil", test, len(in), n, err, len(in))
} else if d, out := crypt.Bytes(), tt.out[0:len(in)]; !same(out, d) {
t.Errorf("%s/%d: OFBWriter\ninpt %x\nhave %x\nwant %x", test, len(in), in, d, out)
}
}
for j := 0; j <= 7; j += 7 {
var plain bytes.Buffer
out := tt.out[0 : len(tt.out)-j]
r := NewOFBReader(c, tt.iv, bytes.NewBuffer(out))
w := &plain
n, err := io.Copy(w, r)
if n != int64(len(out)) || err != nil {
t.Errorf("%s/%d: OFBReader io.Copy = %d, %v want %d, nil", test, len(out), n, err, len(out))
} else if d, in := plain.Bytes(), tt.in[0:len(out)]; !same(in, d) {
t.Errorf("%s/%d: OFBReader\nhave %x\nwant %x", test, len(out), d, in)
}
}
if t.Failed() {
break
}
}
}

View File

@ -1,124 +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.
// Encrypt/decrypt data by xor with a pseudo-random data stream.
package block
import (
"io"
"os"
)
// A dataStream is an interface to an unending stream of data,
// used by XorReader and XorWriter to model a pseudo-random generator.
// Calls to Next() return sequential blocks of data from the stream.
// Each call must return at least one byte: there is no EOF.
type dataStream interface {
Next() []byte
}
type xorReader struct {
r io.Reader
rand dataStream // pseudo-random
buf []byte // data available from last call to rand
}
func newXorReader(rand dataStream, r io.Reader) io.Reader {
x := new(xorReader)
x.r = r
x.rand = rand
return x
}
func (x *xorReader) Read(p []byte) (n int, err os.Error) {
n, err = x.r.Read(p)
// xor input with stream.
bp := 0
buf := x.buf
for i := 0; i < n; i++ {
if bp >= len(buf) {
buf = x.rand.Next()
bp = 0
}
p[i] ^= buf[bp]
bp++
}
x.buf = buf[bp:]
return n, err
}
type xorWriter struct {
w io.Writer
rand dataStream // pseudo-random
buf []byte // last buffer returned by rand
extra []byte // extra random data (use before buf)
work []byte // work space
}
func newXorWriter(rand dataStream, w io.Writer) io.Writer {
x := new(xorWriter)
x.w = w
x.rand = rand
x.work = make([]byte, 4096)
return x
}
func (x *xorWriter) Write(p []byte) (n int, err os.Error) {
for len(p) > 0 {
// Determine next chunk of random data
// and xor with p into x.work.
var chunk []byte
m := len(p)
if nn := len(x.extra); nn > 0 {
// extra points into work, so edit directly
if m > nn {
m = nn
}
for i := 0; i < m; i++ {
x.extra[i] ^= p[i]
}
chunk = x.extra[0:m]
} else {
// xor p ^ buf into work, refreshing buf as needed
if nn := len(x.work); m > nn {
m = nn
}
bp := 0
buf := x.buf
for i := 0; i < m; i++ {
if bp >= len(buf) {
buf = x.rand.Next()
bp = 0
}
x.work[i] = buf[bp] ^ p[i]
bp++
}
x.buf = buf[bp:]
chunk = x.work[0:m]
}
// Write chunk.
var nn int
nn, err = x.w.Write(chunk)
if nn != len(chunk) && err == nil {
err = io.ErrShortWrite
}
if nn < len(chunk) {
// Reconstruct the random bits from the unwritten
// data and save them for next time.
for i := nn; i < m; i++ {
chunk[i] ^= p[i]
}
x.extra = chunk[nn:]
}
n += nn
if err != nil {
return
}
p = p[m:]
}
return
}

View File

@ -1,168 +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.
package block
import (
"bytes"
"fmt"
"io"
"testing"
"testing/iotest"
)
// Simple "pseudo-random" stream for testing.
type incStream struct {
buf []byte
n byte
}
func newIncStream(blockSize int) *incStream {
x := new(incStream)
x.buf = make([]byte, blockSize)
return x
}
func (x *incStream) Next() []byte {
x.n++
for i := range x.buf {
x.buf[i] = x.n
x.n++
}
return x.buf
}
func testXorWriter(t *testing.T, maxio int) {
var plain, crypt [256]byte
for i := 0; i < len(plain); i++ {
plain[i] = byte(i)
}
b := new(bytes.Buffer)
for block := 1; block <= 64 && block <= maxio; block *= 2 {
// compute encrypted version
n := byte(0)
for i := 0; i < len(crypt); i++ {
if i%block == 0 {
n++
}
crypt[i] = plain[i] ^ n
n++
}
for frag := 0; frag < 2; frag++ {
test := fmt.Sprintf("block=%d frag=%d maxio=%d", block, frag, maxio)
b.Reset()
r := bytes.NewBuffer(plain[0:])
s := newIncStream(block)
w := newXorWriter(s, b)
// copy plain into w in increasingly large chunks: 1, 1, 2, 4, 8, ...
// if frag != 0, move the 1 to the end to cause fragmentation.
if frag == 0 {
_, err := io.Copyn(w, r, 1)
if err != nil {
t.Errorf("%s: first Copyn: %s", test, err)
continue
}
}
for n := 1; n <= len(plain)/2; n *= 2 {
_, err := io.Copyn(w, r, int64(n))
if err != nil {
t.Errorf("%s: Copyn %d: %s", test, n, err)
}
}
// check output
crypt := crypt[0 : len(crypt)-frag]
data := b.Bytes()
if len(data) != len(crypt) {
t.Errorf("%s: want %d bytes, got %d", test, len(crypt), len(data))
continue
}
if string(data) != string(crypt) {
t.Errorf("%s: want %x got %x", test, data, crypt)
}
}
}
}
func TestXorWriter(t *testing.T) {
// Do shorter I/O sizes first; they're easier to debug.
for n := 1; n <= 256 && !t.Failed(); n *= 2 {
testXorWriter(t, n)
}
}
func testXorReader(t *testing.T, maxio int) {
var readers = []func(io.Reader) io.Reader{
func(r io.Reader) io.Reader { return r },
iotest.OneByteReader,
iotest.HalfReader,
}
var plain, crypt [256]byte
for i := 0; i < len(plain); i++ {
plain[i] = byte(255 - i)
}
b := new(bytes.Buffer)
for block := 1; block <= 64 && block <= maxio; block *= 2 {
// compute encrypted version
n := byte(0)
for i := 0; i < len(crypt); i++ {
if i%block == 0 {
n++
}
crypt[i] = plain[i] ^ n
n++
}
for mode := 0; mode < len(readers); mode++ {
for frag := 0; frag < 2; frag++ {
test := fmt.Sprintf("block=%d mode=%d frag=%d maxio=%d", block, mode, frag, maxio)
s := newIncStream(block)
b.Reset()
r := newXorReader(s, readers[mode](bytes.NewBuffer(crypt[0:maxio])))
// read from crypt in increasingly large chunks: 1, 1, 2, 4, 8, ...
// if frag == 1, move the 1 to the end to cause fragmentation.
if frag == 0 {
_, err := io.Copyn(b, r, 1)
if err != nil {
t.Errorf("%s: first Copyn: %s", test, err)
continue
}
}
for n := 1; n <= maxio/2; n *= 2 {
_, err := io.Copyn(b, r, int64(n))
if err != nil {
t.Errorf("%s: Copyn %d: %s", test, n, err)
}
}
// check output
data := b.Bytes()
crypt := crypt[0 : maxio-frag]
plain := plain[0 : maxio-frag]
if len(data) != len(plain) {
t.Errorf("%s: want %d bytes, got %d", test, len(plain), len(data))
continue
}
if string(data) != string(plain) {
t.Errorf("%s: input=%x want %x got %x", test, crypt, plain, data)
}
}
}
}
}
func TestXorReader(t *testing.T) {
// Do shorter I/O sizes first; they're easier to debug.
for n := 1; n <= 256 && !t.Failed(); n *= 2 {
testXorReader(t, n)
}
}
// TODO(rsc): Test handling of writes after write errors.

View File

@ -0,0 +1,98 @@
// Copyright 2011 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 des
import (
"encoding/binary"
)
func cryptBlock(subkeys []uint64, dst, src []byte, decrypt bool) {
b := binary.BigEndian.Uint64(src)
b = permuteBlock(b, initialPermutation[:])
left, right := uint32(b>>32), uint32(b)
var subkey uint64
for i := 0; i < 16; i++ {
if decrypt {
subkey = subkeys[15-i]
} else {
subkey = subkeys[i]
}
left, right = right, left^feistel(right, subkey)
}
// switch left & right and perform final permutation
preOutput := (uint64(right) << 32) | uint64(left)
binary.BigEndian.PutUint64(dst, permuteBlock(preOutput, finalPermutation[:]))
}
// Encrypt one block from src into dst, using the subkeys.
func encryptBlock(subkeys []uint64, dst, src []byte) {
cryptBlock(subkeys, dst, src, false)
}
// Decrypt one block from src into dst, using the subkeys.
func decryptBlock(subkeys []uint64, dst, src []byte) {
cryptBlock(subkeys, dst, src, true)
}
// DES Feistel function
func feistel(right uint32, key uint64) (result uint32) {
sBoxLocations := key ^ permuteBlock(uint64(right), expansionFunction[:])
var sBoxResult uint32
for i := uint8(0); i < 8; i++ {
sBoxLocation := uint8(sBoxLocations>>42) & 0x3f
sBoxLocations <<= 6
// row determined by 1st and 6th bit
row := (sBoxLocation & 0x1) | ((sBoxLocation & 0x20) >> 4)
// column is middle four bits
column := (sBoxLocation >> 1) & 0xf
sBoxResult |= uint32(sBoxes[i][row][column]) << (4 * (7 - i))
}
return uint32(permuteBlock(uint64(sBoxResult), permutationFunction[:]))
}
// general purpose function to perform DES block permutations
func permuteBlock(src uint64, permutation []uint8) (block uint64) {
for position, n := range permutation {
bit := (src >> n) & 1
block |= bit << uint((len(permutation)-1)-position)
}
return
}
// creates 16 28-bit blocks rotated according
// to the rotation schedule
func ksRotate(in uint32) (out []uint32) {
out = make([]uint32, 16)
last := in
for i := 0; i < 16; i++ {
// 28-bit circular left shift
left := (last << (4 + ksRotations[i])) >> 4
right := (last << 4) >> (32 - ksRotations[i])
out[i] = left | right
last = out[i]
}
return
}
// creates 16 56-bit subkeys from the original key
func (c *Cipher) generateSubkeys(keyBytes []byte) {
// apply PC1 permutation to key
key := binary.BigEndian.Uint64(keyBytes)
permutedKey := permuteBlock(key, permutedChoice1[:])
// rotate halves of permuted key according to the rotation schedule
leftRotations := ksRotate(uint32(permutedKey >> 28))
rightRotations := ksRotate(uint32(permutedKey<<4) >> 4)
// generate subkeys
for i := 0; i < 16; i++ {
// combine halves to form 56-bit input to PC2
pc2Input := uint64(leftRotations[i])<<28 | uint64(rightRotations[i])
// apply PC2 permutation to 7 byte input
c.subkeys[i] = permuteBlock(pc2Input, permutedChoice2[:])
}
}

View File

@ -0,0 +1,103 @@
// Copyright 2011 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 des
import (
"os"
"strconv"
)
// The DES block size in bytes.
const BlockSize = 8
type KeySizeError int
func (k KeySizeError) String() string {
return "crypto/des: invalid key size " + strconv.Itoa(int(k))
}
// Cipher is an instance of DES encryption.
type Cipher struct {
subkeys [16]uint64
}
// NewCipher creates and returns a new Cipher.
func NewCipher(key []byte) (*Cipher, os.Error) {
if len(key) != 8 {
return nil, KeySizeError(len(key))
}
c := new(Cipher)
c.generateSubkeys(key)
return c, nil
}
// BlockSize returns the DES block size, 8 bytes.
func (c *Cipher) BlockSize() int { return BlockSize }
// Encrypts the 8-byte buffer src and stores the result in dst.
// Note that for amounts of data larger than a block,
// it is not safe to just call Encrypt on successive blocks;
// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go).
func (c *Cipher) Encrypt(dst, src []byte) { encryptBlock(c.subkeys[:], dst, src) }
// Decrypts the 8-byte buffer src and stores the result in dst.
func (c *Cipher) Decrypt(dst, src []byte) { decryptBlock(c.subkeys[:], dst, src) }
// Reset zeros the key data, so that it will no longer
// appear in the process's memory.
func (c *Cipher) Reset() {
for i := 0; i < len(c.subkeys); i++ {
c.subkeys[i] = 0
}
}
// A TripleDESCipher is an instance of TripleDES encryption.
type TripleDESCipher struct {
cipher1, cipher2, cipher3 Cipher
}
// NewCipher creates and returns a new Cipher.
func NewTripleDESCipher(key []byte) (*TripleDESCipher, os.Error) {
if len(key) != 24 {
return nil, KeySizeError(len(key))
}
c := new(TripleDESCipher)
c.cipher1.generateSubkeys(key[:8])
c.cipher2.generateSubkeys(key[8:16])
c.cipher3.generateSubkeys(key[16:])
return c, nil
}
// BlockSize returns the TripleDES block size, 8 bytes.
// It is necessary to satisfy the Block interface in the
// package "crypto/cipher".
func (c *TripleDESCipher) BlockSize() int { return BlockSize }
// Encrypts the 8-byte buffer src and stores the result in dst.
// Note that for amounts of data larger than a block,
// it is not safe to just call Encrypt on successive blocks;
// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go).
func (c *TripleDESCipher) Encrypt(dst, src []byte) {
c.cipher1.Encrypt(dst, src)
c.cipher2.Decrypt(dst, dst)
c.cipher3.Encrypt(dst, dst)
}
// Decrypts the 8-byte buffer src and stores the result in dst.
func (c *TripleDESCipher) Decrypt(dst, src []byte) {
c.cipher3.Decrypt(dst, src)
c.cipher2.Encrypt(dst, dst)
c.cipher1.Decrypt(dst, dst)
}
// Reset zeros the key data, so that it will no longer
// appear in the process's memory.
func (c *TripleDESCipher) Reset() {
c.cipher1.Reset()
c.cipher2.Reset()
c.cipher3.Reset()
}

View File

@ -0,0 +1,139 @@
// Copyright 2010 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 des implements the Data Encryption Standard (DES) and the
// Triple Data Encryption Algorithm (TDEA) as defined
// in U.S. Federal Information Processing Standards Publication 46-3.
package des
// Used to perform an initial permutation of a 64-bit input block.
var initialPermutation = [64]byte{
6, 14, 22, 30, 38, 46, 54, 62,
4, 12, 20, 28, 36, 44, 52, 60,
2, 10, 18, 26, 34, 42, 50, 58,
0, 8, 16, 24, 32, 40, 48, 56,
7, 15, 23, 31, 39, 47, 55, 63,
5, 13, 21, 29, 37, 45, 53, 61,
3, 11, 19, 27, 35, 43, 51, 59,
1, 9, 17, 25, 33, 41, 49, 57,
}
// Used to perform a final permutation of a 4-bit preoutput block. This is the
// inverse of initialPermutation
var finalPermutation = [64]byte{
24, 56, 16, 48, 8, 40, 0, 32,
25, 57, 17, 49, 9, 41, 1, 33,
26, 58, 18, 50, 10, 42, 2, 34,
27, 59, 19, 51, 11, 43, 3, 35,
28, 60, 20, 52, 12, 44, 4, 36,
29, 61, 21, 53, 13, 45, 5, 37,
30, 62, 22, 54, 14, 46, 6, 38,
31, 63, 23, 55, 15, 47, 7, 39,
}
// Used to expand an input block of 32 bits, producing an output block of 48
// bits.
var expansionFunction = [48]byte{
0, 31, 30, 29, 28, 27, 28, 27,
26, 25, 24, 23, 24, 23, 22, 21,
20, 19, 20, 19, 18, 17, 16, 15,
16, 15, 14, 13, 12, 11, 12, 11,
10, 9, 8, 7, 8, 7, 6, 5,
4, 3, 4, 3, 2, 1, 0, 31,
}
// Yields a 32-bit output from a 32-bit input
var permutationFunction = [32]byte{
16, 25, 12, 11, 3, 20, 4, 15,
31, 17, 9, 6, 27, 14, 1, 22,
30, 24, 8, 18, 0, 5, 29, 23,
13, 19, 2, 26, 10, 21, 28, 7,
}
// Used in the key schedule to select 56 bits
// from a 64-bit input.
var permutedChoice1 = [56]byte{
7, 15, 23, 31, 39, 47, 55, 63,
6, 14, 22, 30, 38, 46, 54, 62,
5, 13, 21, 29, 37, 45, 53, 61,
4, 12, 20, 28, 1, 9, 17, 25,
33, 41, 49, 57, 2, 10, 18, 26,
34, 42, 50, 58, 3, 11, 19, 27,
35, 43, 51, 59, 36, 44, 52, 60,
}
// Used in the key schedule to produce each subkey by selecting 48 bits from
// the 56-bit input
var permutedChoice2 = [48]byte{
42, 39, 45, 32, 55, 51, 53, 28,
41, 50, 35, 46, 33, 37, 44, 52,
30, 48, 40, 49, 29, 36, 43, 54,
15, 4, 25, 19, 9, 1, 26, 16,
5, 11, 23, 8, 12, 7, 17, 0,
22, 3, 10, 14, 6, 20, 27, 24,
}
// 8 S-boxes composed of 4 rows and 16 columns
// Used in the DES cipher function
var sBoxes = [8][4][16]uint8{
// S-box 1
{
{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7},
{0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8},
{4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0},
{15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13},
},
// S-box 2
{
{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10},
{3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5},
{0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15},
{13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9},
},
// S-box 3
{
{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8},
{13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1},
{13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7},
{1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12},
},
// S-box 4
{
{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15},
{13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9},
{10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4},
{3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14},
},
// S-box 5
{
{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9},
{14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6},
{4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14},
{11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3},
},
// S-box 6
{
{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11},
{10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8},
{9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6},
{4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13},
},
// S-box 7
{
{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1},
{13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6},
{1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2},
{6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12},
},
// S-box 8
{
{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7},
{1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2},
{7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8},
{2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11},
},
}
// Size of left rotation per round in each half of the key schedule
var ksRotations = [16]uint8{1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1}

File diff suppressed because it is too large Load Diff

View File

@ -37,7 +37,7 @@ var one = new(big.Int).SetInt64(1)
// curve using the procedure given in [NSA] A.2.1.
func randFieldElement(c *elliptic.Curve, rand io.Reader) (k *big.Int, err os.Error) {
b := make([]byte, c.BitSize/8+8)
_, err = rand.Read(b)
_, err = io.ReadFull(rand, b)
if err != nil {
return
}

View File

@ -32,7 +32,7 @@ func (r *devReader) Read(b []byte) (n int, err os.Error) {
r.mu.Lock()
defer r.mu.Unlock()
if r.f == nil {
f, err := os.Open(r.name, os.O_RDONLY, 0)
f, err := os.Open(r.name)
if f == nil {
return 0, err
}

View File

@ -127,7 +127,7 @@ func nonZeroRandomBytes(s []byte, rand io.Reader) (err os.Error) {
for i := 0; i < len(s); i++ {
for s[i] == 0 {
_, err = rand.Read(s[i : i+1])
_, err = io.ReadFull(rand, s[i:i+1])
if err != nil {
return
}

View File

@ -13,6 +13,7 @@ import (
"hash"
"io"
"os"
"sync"
)
var bigZero = big.NewInt(0)
@ -91,15 +92,21 @@ type PublicKey struct {
type PrivateKey struct {
PublicKey // public part.
D *big.Int // private exponent
P, Q *big.Int // prime factors of N
P, Q, R *big.Int // prime factors of N (R may be nil)
rwMutex sync.RWMutex // protects the following
dP, dQ, dR *big.Int // D mod (P-1) (or mod Q-1 etc)
qInv *big.Int // q^-1 mod p
pq *big.Int // P*Q
tr *big.Int // pq·tr ≡ 1 mod r
}
// Validate performs basic sanity checks on the key.
// It returns nil if the key is valid, or else an os.Error describing a problem.
func (priv PrivateKey) Validate() os.Error {
// Check that p and q are prime. Note that this is just a sanity
// check. Since the random witnesses chosen by ProbablyPrime are
func (priv *PrivateKey) Validate() os.Error {
// Check that p, q and, maybe, r are prime. Note that this is just a
// sanity check. Since the random witnesses chosen by ProbablyPrime are
// deterministic, given the candidate number, it's easy for an attack
// to generate composites that pass this test.
if !big.ProbablyPrime(priv.P, 20) {
@ -108,16 +115,26 @@ func (priv PrivateKey) Validate() os.Error {
if !big.ProbablyPrime(priv.Q, 20) {
return os.ErrorString("Q is composite")
}
if priv.R != nil && !big.ProbablyPrime(priv.R, 20) {
return os.ErrorString("R is composite")
}
// Check that p*q == n.
// Check that p*q*r == n.
modulus := new(big.Int).Mul(priv.P, priv.Q)
if priv.R != nil {
modulus.Mul(modulus, priv.R)
}
if modulus.Cmp(priv.N) != 0 {
return os.ErrorString("invalid modulus")
}
// Check that e and totient(p, q) are coprime.
// Check that e and totient(p, q, r) are coprime.
pminus1 := new(big.Int).Sub(priv.P, bigOne)
qminus1 := new(big.Int).Sub(priv.Q, bigOne)
totient := new(big.Int).Mul(pminus1, qminus1)
if priv.R != nil {
rminus1 := new(big.Int).Sub(priv.R, bigOne)
totient.Mul(totient, rminus1)
}
e := big.NewInt(int64(priv.E))
gcd := new(big.Int)
x := new(big.Int)
@ -126,7 +143,7 @@ func (priv PrivateKey) Validate() os.Error {
if gcd.Cmp(bigOne) != 0 {
return os.ErrorString("invalid public exponent E")
}
// Check that de ≡ 1 (mod totient(p, q))
// Check that de ≡ 1 (mod totient(p, q, r))
de := new(big.Int).Mul(priv.D, e)
de.Mod(de, totient)
if de.Cmp(bigOne) != 0 {
@ -135,7 +152,7 @@ func (priv PrivateKey) Validate() os.Error {
return nil
}
// GenerateKeyPair generates an RSA keypair of the given bit size.
// GenerateKey generates an RSA keypair of the given bit size.
func GenerateKey(rand io.Reader, bits int) (priv *PrivateKey, err os.Error) {
priv = new(PrivateKey)
// Smaller public exponents lead to faster public key
@ -191,6 +208,77 @@ func GenerateKey(rand io.Reader, bits int) (priv *PrivateKey, err os.Error) {
return
}
// Generate3PrimeKey generates a 3-prime RSA keypair of the given bit size, as
// suggested in [1]. Although the public keys are compatible (actually,
// indistinguishable) from the 2-prime case, the private keys are not. Thus it
// may not be possible to export 3-prime private keys in certain formats or to
// subsequently import them into other code.
//
// Table 1 in [2] suggests that size should be >= 1024 when using 3 primes.
//
// [1] US patent 4405829 (1972, expired)
// [2] http://www.cacr.math.uwaterloo.ca/techreports/2006/cacr2006-16.pdf
func Generate3PrimeKey(rand io.Reader, bits int) (priv *PrivateKey, err os.Error) {
priv = new(PrivateKey)
priv.E = 3
pminus1 := new(big.Int)
qminus1 := new(big.Int)
rminus1 := new(big.Int)
totient := new(big.Int)
for {
p, err := randomPrime(rand, bits/3)
if err != nil {
return nil, err
}
todo := bits - p.BitLen()
q, err := randomPrime(rand, todo/2)
if err != nil {
return nil, err
}
todo -= q.BitLen()
r, err := randomPrime(rand, todo)
if err != nil {
return nil, err
}
if p.Cmp(q) == 0 ||
q.Cmp(r) == 0 ||
r.Cmp(p) == 0 {
continue
}
n := new(big.Int).Mul(p, q)
n.Mul(n, r)
pminus1.Sub(p, bigOne)
qminus1.Sub(q, bigOne)
rminus1.Sub(r, bigOne)
totient.Mul(pminus1, qminus1)
totient.Mul(totient, rminus1)
g := new(big.Int)
priv.D = new(big.Int)
y := new(big.Int)
e := big.NewInt(int64(priv.E))
big.GcdInt(g, priv.D, y, e, totient)
if g.Cmp(bigOne) == 0 {
priv.D.Add(priv.D, totient)
priv.P = p
priv.Q = q
priv.R = r
priv.N = n
break
}
}
return
}
// incCounter increments a four byte, big-endian counter.
func incCounter(c *[4]byte) {
if c[3]++; c[3] != 0 {
@ -321,6 +409,26 @@ func modInverse(a, n *big.Int) (ia *big.Int, ok bool) {
return x, true
}
// precompute performs some calculations that speed up private key operations
// in the future.
func (priv *PrivateKey) precompute() {
priv.dP = new(big.Int).Sub(priv.P, bigOne)
priv.dP.Mod(priv.D, priv.dP)
priv.dQ = new(big.Int).Sub(priv.Q, bigOne)
priv.dQ.Mod(priv.D, priv.dQ)
priv.qInv = new(big.Int).ModInverse(priv.Q, priv.P)
if priv.R != nil {
priv.dR = new(big.Int).Sub(priv.R, bigOne)
priv.dR.Mod(priv.D, priv.dR)
priv.pq = new(big.Int).Mul(priv.P, priv.Q)
priv.tr = new(big.Int).ModInverse(priv.pq, priv.R)
}
}
// decrypt performs an RSA decryption, resulting in a plaintext integer. If a
// random source is given, RSA blinding is used.
func decrypt(rand io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err os.Error) {
@ -359,7 +467,48 @@ func decrypt(rand io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err os.E
c.Mod(c, priv.N)
}
m = new(big.Int).Exp(c, priv.D, priv.N)
priv.rwMutex.RLock()
if priv.dP == nil && priv.P != nil {
priv.rwMutex.RUnlock()
priv.rwMutex.Lock()
if priv.dP == nil && priv.P != nil {
priv.precompute()
}
priv.rwMutex.Unlock()
priv.rwMutex.RLock()
}
if priv.dP == nil {
m = new(big.Int).Exp(c, priv.D, priv.N)
} else {
// We have the precalculated values needed for the CRT.
m = new(big.Int).Exp(c, priv.dP, priv.P)
m2 := new(big.Int).Exp(c, priv.dQ, priv.Q)
m.Sub(m, m2)
if m.Sign() < 0 {
m.Add(m, priv.P)
}
m.Mul(m, priv.qInv)
m.Mod(m, priv.P)
m.Mul(m, priv.Q)
m.Add(m, m2)
if priv.dR != nil {
// 3-prime CRT.
m2.Exp(c, priv.dR, priv.R)
m2.Sub(m2, m)
m2.Mul(m2, priv.tr)
m2.Mod(m2, priv.R)
if m2.Sign() < 0 {
m2.Add(m2, priv.R)
}
m2.Mul(m2, priv.pq)
m.Add(m, m2)
}
}
priv.rwMutex.RUnlock()
if ir != nil {
// Unblind.

View File

@ -13,28 +13,48 @@ import (
)
func TestKeyGeneration(t *testing.T) {
random := rand.Reader
size := 1024
if testing.Short() {
size = 128
}
priv, err := GenerateKey(random, size)
priv, err := GenerateKey(rand.Reader, size)
if err != nil {
t.Errorf("failed to generate key")
}
testKeyBasics(t, priv)
}
func Test3PrimeKeyGeneration(t *testing.T) {
if testing.Short() {
return
}
size := 768
priv, err := Generate3PrimeKey(rand.Reader, size)
if err != nil {
t.Errorf("failed to generate key")
}
testKeyBasics(t, priv)
}
func testKeyBasics(t *testing.T, priv *PrivateKey) {
if err := priv.Validate(); err != nil {
t.Errorf("Validate() failed: %s", err)
}
pub := &priv.PublicKey
m := big.NewInt(42)
c := encrypt(new(big.Int), pub, m)
m2, err := decrypt(nil, priv, c)
if err != nil {
t.Errorf("error while decrypting: %s", err)
return
}
if m.Cmp(m2) != 0 {
t.Errorf("got:%v, want:%v (%s)", m2, m, priv)
t.Errorf("got:%v, want:%v (%+v)", m2, m, priv)
}
m3, err := decrypt(random, priv, c)
m3, err := decrypt(rand.Reader, priv, c)
if err != nil {
t.Errorf("error while decrypting (blind): %s", err)
}
@ -43,6 +63,57 @@ func TestKeyGeneration(t *testing.T) {
}
}
func fromBase10(base10 string) *big.Int {
i := new(big.Int)
i.SetString(base10, 10)
return i
}
func BenchmarkRSA2048Decrypt(b *testing.B) {
b.StopTimer()
priv := &PrivateKey{
PublicKey: PublicKey{
N: fromBase10("14314132931241006650998084889274020608918049032671858325988396851334124245188214251956198731333464217832226406088020736932173064754214329009979944037640912127943488972644697423190955557435910767690712778463524983667852819010259499695177313115447116110358524558307947613422897787329221478860907963827160223559690523660574329011927531289655711860504630573766609239332569210831325633840174683944553667352219670930408593321661375473885147973879086994006440025257225431977751512374815915392249179976902953721486040787792801849818254465486633791826766873076617116727073077821584676715609985777563958286637185868165868520557"),
E: 3,
},
D: fromBase10("9542755287494004433998723259516013739278699355114572217325597900889416163458809501304132487555642811888150937392013824621448709836142886006653296025093941418628992648429798282127303704957273845127141852309016655778568546006839666463451542076964744073572349705538631742281931858219480985907271975884773482372966847639853897890615456605598071088189838676728836833012254065983259638538107719766738032720239892094196108713378822882383694456030043492571063441943847195939549773271694647657549658603365629458610273821292232646334717612674519997533901052790334279661754176490593041941863932308687197618671528035670452762731"),
P: fromBase10("130903255182996722426771613606077755295583329135067340152947172868415809027537376306193179624298874215608270802054347609836776473930072411958753044562214537013874103802006369634761074377213995983876788718033850153719421695468704276694983032644416930879093914927146648402139231293035971427838068945045019075433"),
Q: fromBase10("109348945610485453577574767652527472924289229538286649661240938988020367005475727988253438647560958573506159449538793540472829815903949343191091817779240101054552748665267574271163617694640513549693841337820602726596756351006149518830932261246698766355347898158548465400674856021497190430791824869615170301029"),
}
priv.precompute()
c := fromBase10("1000")
b.StartTimer()
for i := 0; i < b.N; i++ {
decrypt(nil, priv, c)
}
}
func Benchmark3PrimeRSA2048Decrypt(b *testing.B) {
b.StopTimer()
priv := &PrivateKey{
PublicKey: PublicKey{
N: fromBase10("16346378922382193400538269749936049106320265317511766357599732575277382844051791096569333808598921852351577762718529818072849191122419410612033592401403764925096136759934497687765453905884149505175426053037420486697072448609022753683683718057795566811401938833367954642951433473337066311978821180526439641496973296037000052546108507805269279414789035461158073156772151892452251106173507240488993608650881929629163465099476849643165682709047462010581308719577053905787496296934240246311806555924593059995202856826239801816771116902778517096212527979497399966526283516447337775509777558018145573127308919204297111496233"),
E: 3,
},
D: fromBase10("10897585948254795600358846499957366070880176878341177571733155050184921896034527397712889205732614568234385175145686545381899460748279607074689061600935843283397424506622998458510302603922766336783617368686090042765718290914099334449154829375179958369993407724946186243249568928237086215759259909861748642124071874879861299389874230489928271621259294894142840428407196932444474088857746123104978617098858619445675532587787023228852383149557470077802718705420275739737958953794088728369933811184572620857678792001136676902250566845618813972833750098806496641114644760255910789397593428910198080271317419213080834885003"),
P: fromBase10("1025363189502892836833747188838978207017355117492483312747347695538428729137306368764177201532277413433182799108299960196606011786562992097313508180436744488171474690412562218914213688661311117337381958560443"),
Q: fromBase10("3467903426626310123395340254094941045497208049900750380025518552334536945536837294961497712862519984786362199788654739924501424784631315081391467293694361474867825728031147665777546570788493758372218019373"),
R: fromBase10("4597024781409332673052708605078359346966325141767460991205742124888960305710298765592730135879076084498363772408626791576005136245060321874472727132746643162385746062759369754202494417496879741537284589047"),
}
priv.precompute()
c := fromBase10("1000")
b.StartTimer()
for i := 0; i < b.N; i++ {
decrypt(nil, priv, c)
}
}
type testEncryptOAEPMessage struct {
in []byte
seed []byte
@ -85,10 +156,12 @@ func TestDecryptOAEP(t *testing.T) {
for i, test := range testEncryptOAEPData {
n.SetString(test.modulus, 16)
d.SetString(test.d, 16)
private := PrivateKey{PublicKey{n, test.e}, d, nil, nil}
private := new(PrivateKey)
private.PublicKey = PublicKey{n, test.e}
private.D = d
for j, message := range test.msgs {
out, err := DecryptOAEP(sha1, nil, &private, message.out, nil)
out, err := DecryptOAEP(sha1, nil, private, message.out, nil)
if err != nil {
t.Errorf("#%d,%d error: %s", i, j, err)
} else if bytes.Compare(out, message.in) != 0 {
@ -96,7 +169,7 @@ func TestDecryptOAEP(t *testing.T) {
}
// Decrypt with blinding.
out, err = DecryptOAEP(sha1, random, &private, message.out, nil)
out, err = DecryptOAEP(sha1, random, private, message.out, nil)
if err != nil {
t.Errorf("#%d,%d (blind) error: %s", i, j, err)
} else if bytes.Compare(out, message.in) != 0 {

View File

@ -50,7 +50,7 @@ func main() {
return
}
certOut, err := os.Open("cert.pem", os.O_WRONLY|os.O_CREAT, 0644)
certOut, err := os.Create("cert.pem")
if err != nil {
log.Fatalf("failed to open cert.pem for writing: %s", err)
return
@ -59,7 +59,7 @@ func main() {
certOut.Close()
log.Print("written cert.pem\n")
keyOut, err := os.Open("key.pem", os.O_WRONLY|os.O_CREAT, 0600)
keyOut, err := os.OpenFile("key.pem", os.O_WRONLY|os.O_CREAT|os.O_TRUNC, 0600)
if err != nil {
log.Print("failed to open key.pem for writing:", err)
return

View File

@ -124,7 +124,16 @@ func LoadX509KeyPair(certFile string, keyFile string) (cert Certificate, err os.
if err != nil {
return
}
keyPEMBlock, err := ioutil.ReadFile(keyFile)
if err != nil {
return
}
return X509KeyPair(certPEMBlock, keyPEMBlock)
}
// X509KeyPair parses a public/private key pair from a pair of
// PEM encoded data.
func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (cert Certificate, err os.Error) {
var certDERBlock *pem.Block
for {
certDERBlock, certPEMBlock = pem.Decode(certPEMBlock)
@ -141,11 +150,6 @@ func LoadX509KeyPair(certFile string, keyFile string) (cert Certificate, err os.
return
}
keyPEMBlock, err := ioutil.ReadFile(keyFile)
if err != nil {
return
}
keyDERBlock, _ := pem.Decode(keyPEMBlock)
if keyDERBlock == nil {
err = os.ErrorString("crypto/tls: failed to parse key PEM data")

View File

@ -54,20 +54,21 @@ func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err os.Error) {
return
}
key = &rsa.PrivateKey{
PublicKey: rsa.PublicKey{
E: priv.E,
N: new(big.Int).SetBytes(priv.N.Bytes),
},
D: new(big.Int).SetBytes(priv.D.Bytes),
P: new(big.Int).SetBytes(priv.P.Bytes),
Q: new(big.Int).SetBytes(priv.Q.Bytes),
key = new(rsa.PrivateKey)
key.PublicKey = rsa.PublicKey{
E: priv.E,
N: new(big.Int).SetBytes(priv.N.Bytes),
}
key.D = new(big.Int).SetBytes(priv.D.Bytes)
key.P = new(big.Int).SetBytes(priv.P.Bytes)
key.Q = new(big.Int).SetBytes(priv.Q.Bytes)
err = key.Validate()
if err != nil {
return nil, err
}
return
}

View File

@ -11,7 +11,6 @@ import (
"crypto/rsa"
"encoding/hex"
"encoding/pem"
"reflect"
"testing"
"time"
)
@ -22,7 +21,11 @@ func TestParsePKCS1PrivateKey(t *testing.T) {
if err != nil {
t.Errorf("Failed to parse private key: %s", err)
}
if !reflect.DeepEqual(priv, rsaPrivateKey) {
if priv.PublicKey.N.Cmp(rsaPrivateKey.PublicKey.N) != 0 ||
priv.PublicKey.E != rsaPrivateKey.PublicKey.E ||
priv.D.Cmp(rsaPrivateKey.D) != 0 ||
priv.P.Cmp(rsaPrivateKey.P) != 0 ||
priv.Q.Cmp(rsaPrivateKey.Q) != 0 {
t.Errorf("got:%+v want:%+v", priv, rsaPrivateKey)
}
}

View File

@ -144,7 +144,7 @@ func (e *FormatError) String() string {
// Open opens the named file using os.Open and prepares it for use as an ELF binary.
func Open(name string) (*File, os.Error) {
f, err := os.Open(name, os.O_RDONLY, 0)
f, err := os.Open(name)
if err != nil {
return nil, err
}
@ -228,7 +228,7 @@ func NewFile(r io.ReaderAt) (*File, os.Error) {
switch f.Class {
case ELFCLASS32:
hdr := new(Header32)
sr.Seek(0, 0)
sr.Seek(0, os.SEEK_SET)
if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
return nil, err
}
@ -243,7 +243,7 @@ func NewFile(r io.ReaderAt) (*File, os.Error) {
shstrndx = int(hdr.Shstrndx)
case ELFCLASS64:
hdr := new(Header64)
sr.Seek(0, 0)
sr.Seek(0, os.SEEK_SET)
if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
return nil, err
}
@ -269,7 +269,7 @@ func NewFile(r io.ReaderAt) (*File, os.Error) {
names := make([]uint32, shnum)
for i := 0; i < shnum; i++ {
off := shoff + int64(i)*int64(shentsize)
sr.Seek(off, 0)
sr.Seek(off, os.SEEK_SET)
s := new(Section)
switch f.Class {
case ELFCLASS32:

View File

@ -159,7 +159,7 @@ func (e *FormatError) String() string {
// Open opens the named file using os.Open and prepares it for use as a Mach-O binary.
func Open(name string) (*File, os.Error) {
f, err := os.Open(name, os.O_RDONLY, 0)
f, err := os.Open(name)
if err != nil {
return nil, err
}

View File

@ -87,7 +87,7 @@ func (e *FormatError) String() string {
// Open opens the named file using os.Open and prepares it for use as a PE binary.
func Open(name string) (*File, os.Error) {
f, err := os.Open(name, os.O_RDONLY, 0)
f, err := os.Open(name)
if err != nil {
return nil, err
}
@ -132,7 +132,7 @@ func NewFile(r io.ReaderAt) (*File, os.Error) {
} else {
base = int64(0)
}
sr.Seek(base, 0)
sr.Seek(base, os.SEEK_SET)
if err := binary.Read(sr, binary.LittleEndian, &f.FileHeader); err != nil {
return nil, err
}
@ -140,7 +140,7 @@ func NewFile(r io.ReaderAt) (*File, os.Error) {
return nil, os.NewError("Invalid PE File Format.")
}
// get symbol string table
sr.Seek(int64(f.FileHeader.PointerToSymbolTable+18*f.FileHeader.NumberOfSymbols), 0)
sr.Seek(int64(f.FileHeader.PointerToSymbolTable+18*f.FileHeader.NumberOfSymbols), os.SEEK_SET)
var l uint32
if err := binary.Read(sr, binary.LittleEndian, &l); err != nil {
return nil, err
@ -149,9 +149,9 @@ func NewFile(r io.ReaderAt) (*File, os.Error) {
if _, err := r.ReadAt(ss, int64(f.FileHeader.PointerToSymbolTable+18*f.FileHeader.NumberOfSymbols)); err != nil {
return nil, err
}
sr.Seek(base, 0)
sr.Seek(base, os.SEEK_SET)
binary.Read(sr, binary.LittleEndian, &f.FileHeader)
sr.Seek(int64(f.FileHeader.SizeOfOptionalHeader), 1) //Skip OptionalHeader
sr.Seek(int64(f.FileHeader.SizeOfOptionalHeader), os.SEEK_CUR) //Skip OptionalHeader
f.Sections = make([]*Section, f.FileHeader.NumberOfSections)
for i := 0; i < int(f.FileHeader.NumberOfSections); i++ {
sh := new(SectionHeader32)

View File

@ -1184,7 +1184,7 @@ func (p *process) attachThread(tid int) (*thread, os.Error) {
// attachAllThreads attaches to all threads in a process.
func (p *process) attachAllThreads() os.Error {
taskPath := "/proc/" + strconv.Itoa(p.pid) + "/task"
taskDir, err := os.Open(taskPath, os.O_RDONLY, 0)
taskDir, err := os.Open(taskPath)
if err != nil {
return err
}

View File

@ -2,9 +2,13 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// The exec package runs external commands.
// The exec package runs external commands. It wraps os.StartProcess
// to make it easier to remap stdin and stdout, connect I/O with pipes,
// and do other adjustments.
package exec
// BUG(r): This package should be made even easier to use or merged into os.
import (
"os"
"strconv"
@ -49,7 +53,7 @@ func modeToFiles(mode, fd int) (*os.File, *os.File, os.Error) {
if fd == 0 {
rw = os.O_RDONLY
}
f, err := os.Open(os.DevNull, rw, 0)
f, err := os.OpenFile(os.DevNull, rw, 0)
return f, nil, err
case PassThrough:
switch fd {

View File

@ -53,7 +53,7 @@ func readAuth(displayStr string) (name, data string, err os.Error) {
}
fn = home + "/.Xauthority"
}
r, err := os.Open(fn, os.O_RDONLY, 0444)
r, err := os.Open(fn)
if err != nil {
return
}

View File

@ -170,7 +170,7 @@ func cmdLoad(args []byte) os.Error {
}
// Get symbols
f, err := os.Open(fname, os.O_RDONLY, 0)
f, err := os.Open(fname)
if err != nil {
tproc.Detach()
return err

View File

@ -139,7 +139,17 @@ var fmttests = []struct {
{"%5s", "abc", " abc"},
{"%2s", "\u263a", " \u263a"},
{"%-5s", "abc", "abc "},
{"%-8q", "abc", `"abc" `},
{"%05s", "abc", "00abc"},
{"%08q", "abc", `000"abc"`},
{"%5s", "abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz"},
{"%.5s", "abcdefghijklmnopqrstuvwxyz", "abcde"},
{"%.5s", "日本語日本語", "日本語日本"},
{"%.5s", []byte("日本語日本語"), "日本語日本"},
{"%.5q", "abcdefghijklmnopqrstuvwxyz", `"abcde"`},
{"%.3q", "日本語日本語", `"\u65e5\u672c\u8a9e"`},
{"%.3q", []byte("日本語日本語"), `"\u65e5\u672c\u8a9e"`},
{"%10.1q", "日本語日本語", ` "\u65e5"`},
// integers
{"%d", 12345, "12345"},

View File

@ -235,13 +235,24 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
f.pad(buf[i:])
}
// fmt_s formats a string.
func (f *fmt) fmt_s(s string) {
if f.precPresent {
if f.prec < len(s) {
s = s[0:f.prec]
// truncate truncates the string to the specified precision, if present.
func (f *fmt) truncate(s string) string {
if f.precPresent && f.prec < utf8.RuneCountInString(s) {
n := f.prec
for i := range s {
if n == 0 {
s = s[:i]
break
}
n--
}
}
return s
}
// fmt_s formats a string.
func (f *fmt) fmt_s(s string) {
s = f.truncate(s)
f.padString(s)
}
@ -275,6 +286,7 @@ func (f *fmt) fmt_sX(s string) {
// fmt_q formats a string as a double-quoted, escaped Go string constant.
func (f *fmt) fmt_q(s string) {
s = f.truncate(s)
var quoted string
if f.sharp && strconv.CanBackquote(s) {
quoted = "`" + s + "`"

View File

@ -520,12 +520,14 @@ func (p *pp) fmtBytes(v []byte, verb int, goSyntax bool, depth int, value interf
}
func (p *pp) fmtPointer(field interface{}, value reflect.Value, verb int, goSyntax bool) {
v, ok := value.(uintptrGetter)
if !ok { // reflect.PtrValue is a uintptrGetter, so failure means it's not a pointer at all.
var u uintptr
switch value.(type) {
case *reflect.ChanValue, *reflect.FuncValue, *reflect.MapValue, *reflect.PtrValue, *reflect.SliceValue, *reflect.UnsafePointerValue:
u = value.(uintptrGetter).Get()
default:
p.badVerb(verb, field)
return
}
u := v.Get()
if goSyntax {
p.add('(')
p.buf.WriteString(reflect.Typeof(field).String())
@ -534,7 +536,7 @@ func (p *pp) fmtPointer(field interface{}, value reflect.Value, verb int, goSynt
if u == 0 {
p.buf.Write(nilBytes)
} else {
p.fmt0x64(uint64(v.Get()), true)
p.fmt0x64(uint64(u), true)
}
p.add(')')
} else {
@ -811,7 +813,7 @@ BigSwitch:
break
}
p.fmt0x64(uint64(v), true)
case uintptrGetter:
case *reflect.ChanValue, *reflect.FuncValue, *reflect.UnsafePointerValue:
p.fmtPointer(field, value, verb, goSyntax)
default:
p.unknownType(f)

View File

@ -183,7 +183,7 @@ func ParseFiles(fset *token.FileSet, filenames []string, mode uint) (pkgs map[st
// error are returned.
//
func ParseDir(fset *token.FileSet, path string, filter func(*os.FileInfo) bool, mode uint) (map[string]*ast.Package, os.Error) {
fd, err := os.Open(path, os.O_RDONLY, 0)
fd, err := os.Open(path)
if err != nil {
return nil, err
}

View File

@ -332,7 +332,7 @@ func (p *parser) next() {
var endline int
if p.file.Line(p.pos) == line {
// The comment is on same line as previous token; it
// The comment is on same line as the previous token; it
// cannot be a lead comment but may be a line comment.
comment, endline = p.consumeCommentGroup()
if p.file.Line(p.pos) != endline {
@ -2016,16 +2016,18 @@ func parseTypeSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
}
ident := p.parseIdent()
typ := p.parseType()
p.expectSemi() // call before accessing p.linecomment
// Go spec: The scope of a type identifier declared inside a function begins
// at the identifier in the TypeSpec and ends at the end of the innermost
// containing block.
// (Global identifiers are resolved in a separate phase after parsing.)
spec := &ast.TypeSpec{doc, ident, typ, p.lineComment}
spec := &ast.TypeSpec{doc, ident, nil, nil}
p.declare(spec, p.topScope, ast.Typ, ident)
spec.Type = p.parseType()
p.expectSemi() // call before accessing p.linecomment
spec.Comment = p.lineComment
return spec
}
@ -2207,6 +2209,9 @@ func (p *parser) parseFile() *ast.File {
// Go spec: The package clause is not a declaration;
// the package name does not appear in any scope.
ident := p.parseIdent()
if ident.Name == "_" {
p.error(p.pos, "invalid package name _")
}
p.expectSemi()
var decls []ast.Decl

View File

@ -28,7 +28,7 @@ func pipeErr(err os.Error) io.Reader {
}
func readDat(filename string, c chan io.Reader) {
f, err := os.Open("testdata/webkit/"+filename, os.O_RDONLY, 0600)
f, err := os.Open("testdata/webkit/" + filename)
if err != nil {
c <- pipeErr(err)
return

View File

@ -72,7 +72,7 @@ func serveFile(w ResponseWriter, r *Request, name string, redirect bool) {
return
}
f, err := os.Open(name, os.O_RDONLY, 0)
f, err := os.Open(name)
if err != nil {
// TODO expose actual error?
NotFound(w, r)
@ -113,7 +113,7 @@ func serveFile(w ResponseWriter, r *Request, name string, redirect bool) {
// use contents of index.html for directory, if present
if d.IsDirectory() {
index := name + filepath.FromSlash(indexPage)
ff, err := os.Open(index, os.O_RDONLY, 0)
ff, err := os.Open(index)
if err == nil {
defer ff.Close()
dd, err := ff.Stat()
@ -134,21 +134,23 @@ func serveFile(w ResponseWriter, r *Request, name string, redirect bool) {
size := d.Size
code := StatusOK
// use extension to find content type.
ext := filepath.Ext(name)
if ctype := mime.TypeByExtension(ext); ctype != "" {
w.Header().Set("Content-Type", ctype)
} else {
// read first chunk to decide between utf-8 text and binary
var buf [1024]byte
n, _ := io.ReadFull(f, buf[:])
b := buf[:n]
if isText(b) {
w.Header().Set("Content-Type", "text-plain; charset=utf-8")
} else {
w.Header().Set("Content-Type", "application/octet-stream") // generic binary
// If Content-Type isn't set, use the file's extension to find it.
if w.Header().Get("Content-Type") == "" {
ctype := mime.TypeByExtension(filepath.Ext(name))
if ctype == "" {
// read a chunk to decide between utf-8 text and binary
var buf [1024]byte
n, _ := io.ReadFull(f, buf[:])
b := buf[:n]
if isText(b) {
ctype = "text-plain; charset=utf-8"
} else {
// generic binary
ctype = "application/octet-stream"
}
f.Seek(0, os.SEEK_SET) // rewind to output whole file
}
f.Seek(0, 0) // rewind to output whole file
w.Header().Set("Content-Type", ctype)
}
// handle Content-Range header.
@ -163,7 +165,7 @@ func serveFile(w ResponseWriter, r *Request, name string, redirect bool) {
}
if len(ranges) == 1 {
ra := ranges[0]
if _, err := f.Seek(ra.start, 0); err != nil {
if _, err := f.Seek(ra.start, os.SEEK_SET); err != nil {
Error(w, err.String(), StatusRequestedRangeNotSatisfiable)
return
}

View File

@ -85,6 +85,30 @@ func TestServeFile(t *testing.T) {
}
}
func TestServeFileContentType(t *testing.T) {
const ctype = "icecream/chocolate"
override := false
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
if override {
w.Header().Set("Content-Type", ctype)
}
ServeFile(w, r, "testdata/file")
}))
defer ts.Close()
get := func(want string) {
resp, _, err := Get(ts.URL)
if err != nil {
t.Fatal(err)
}
if h := resp.Header.Get("Content-Type"); h != want {
t.Errorf("Content-Type mismatch: got %q, want %q", h, want)
}
}
get("text-plain; charset=utf-8")
override = true
get(ctype)
}
func getBody(t *testing.T, req Request) (*Response, []byte) {
r, err := DefaultClient.Do(&req)
if err != nil {

View File

@ -7,10 +7,13 @@
package httptest
import (
"crypto/rand"
"crypto/tls"
"fmt"
"http"
"os"
"net"
"os"
"time"
)
// A Server is an HTTP server listening on a system-chosen port on the
@ -18,6 +21,7 @@ import (
type Server struct {
URL string // base URL of form http://ipaddr:port with no trailing slash
Listener net.Listener
TLS *tls.Config // nil if not using using TLS
}
// historyListener keeps track of all connections that it's ever
@ -35,16 +39,21 @@ func (hs *historyListener) Accept() (c net.Conn, err os.Error) {
return
}
// NewServer starts and returns a new Server.
// The caller should call Close when finished, to shut it down.
func NewServer(handler http.Handler) *Server {
ts := new(Server)
func newLocalListener() net.Listener {
l, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
if l, err = net.Listen("tcp6", "[::1]:0"); err != nil {
panic(fmt.Sprintf("httptest: failed to listen on a port: %v", err))
}
}
return l
}
// NewServer starts and returns a new Server.
// The caller should call Close when finished, to shut it down.
func NewServer(handler http.Handler) *Server {
ts := new(Server)
l := newLocalListener()
ts.Listener = &historyListener{l, make([]net.Conn, 0)}
ts.URL = "http://" + l.Addr().String()
server := &http.Server{Handler: handler}
@ -52,6 +61,32 @@ func NewServer(handler http.Handler) *Server {
return ts
}
// NewTLSServer starts and returns a new Server using TLS.
// The caller should call Close when finished, to shut it down.
func NewTLSServer(handler http.Handler) *Server {
l := newLocalListener()
ts := new(Server)
cert, err := tls.X509KeyPair(localhostCert, localhostKey)
if err != nil {
panic(fmt.Sprintf("httptest: NewTLSServer: %v", err))
}
ts.TLS = &tls.Config{
Rand: rand.Reader,
Time: time.Seconds,
NextProtos: []string{"http/1.1"},
Certificates: []tls.Certificate{cert},
}
tlsListener := tls.NewListener(l, ts.TLS)
ts.Listener = &historyListener{tlsListener, make([]net.Conn, 0)}
ts.URL = "https://" + l.Addr().String()
server := &http.Server{Handler: handler}
go server.Serve(ts.Listener)
return ts
}
// Close shuts down the server.
func (s *Server) Close() {
s.Listener.Close()
@ -68,3 +103,34 @@ func (s *Server) CloseClientConnections() {
conn.Close()
}
}
// localhostCert is a PEM-encoded TLS cert with SAN DNS names
// "127.0.0.1" and "[::1]", expiring at the last second of 2049 (the end
// of ASN.1 time).
var localhostCert = []byte(`-----BEGIN CERTIFICATE-----
MIIBwTCCASugAwIBAgIBADALBgkqhkiG9w0BAQUwADAeFw0xMTAzMzEyMDI1MDda
Fw00OTEyMzEyMzU5NTlaMAAwggCdMAsGCSqGSIb3DQEBAQOCAIwAMIIAhwKCAIB6
oy4iT42G6qk+GGn5VL5JlnJT6ZG5cqaMNFaNGlIxNb6CPUZLKq2sM3gRaimsktIw
nNAcNwQGHpe1tZo+J/Pl04JTt71Y/TTAxy7OX27aZf1Rpt0SjdZ7vTPnFDPNsHGe
KBKvPt55l2+YKjkZmV7eRevsVbpkNvNGB+T5d4Ge/wIBA6NPME0wDgYDVR0PAQH/
BAQDAgCgMA0GA1UdDgQGBAQBAgMEMA8GA1UdIwQIMAaABAECAwQwGwYDVR0RBBQw
EoIJMTI3LjAuMC4xggVbOjoxXTALBgkqhkiG9w0BAQUDggCBAHC3gbdvc44vs+wD
g2kONiENnx8WKc0UTGg/TOXS3gaRb+CUIQtHWja65l8rAfclEovjHgZ7gx8brO0W
JuC6p3MUAKsgOssIrrRIx2rpnfcmFVMzguCmrMNVmKUAalw18Yp0F72xYAIitVQl
kJrLdIhBajcJRYu/YGltHQRaXuVt
-----END CERTIFICATE-----
`)
// localhostKey is the private key for localhostCert.
var localhostKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
MIIBkgIBAQKCAIB6oy4iT42G6qk+GGn5VL5JlnJT6ZG5cqaMNFaNGlIxNb6CPUZL
Kq2sM3gRaimsktIwnNAcNwQGHpe1tZo+J/Pl04JTt71Y/TTAxy7OX27aZf1Rpt0S
jdZ7vTPnFDPNsHGeKBKvPt55l2+YKjkZmV7eRevsVbpkNvNGB+T5d4Ge/wIBAwKC
AIBRwh7Bil5Z8cYpZZv7jdQxDvbim7Z7ocRdeDmzZuF2I9RW04QyHHPIIlALnBvI
YeF1veASz1gEFGUjzmbUGqKYSbCoTzXoev+F4bmbRxcX9sOmtslqvhMSHRSzA5NH
aDVI3Hn4wvBVD8gePu8ACWqvPGbCiql11OKCMfjlPn2uuwJAx/24/F5DjXZ6hQQ7
HxScOxKrpx5WnA9r1wZTltOTZkhRRzuLc21WJeE3M15QUdWi3zZxCKRFoth65HEs
jy9YHQJAnPueRI44tz79b5QqVbeaOMUr7ZCb1Kp0uo6G+ANPLdlfliAupwij2eIz
mHRJOWk0jBtXfRft1McH2H51CpXAyw==
-----END RSA PRIVATE KEY-----
`)

View File

@ -164,6 +164,28 @@ var respTests = []respTest{
"Body here\n",
},
// Chunked response in response to a HEAD request (the "chunked" should
// be ignored, as HEAD responses never have bodies)
{
"HTTP/1.0 200 OK\r\n" +
"Transfer-Encoding: chunked\r\n" +
"\r\n",
Response{
Status: "200 OK",
StatusCode: 200,
Proto: "HTTP/1.0",
ProtoMajor: 1,
ProtoMinor: 0,
RequestMethod: "HEAD",
Header: Header{},
Close: true,
ContentLength: 0,
},
"",
},
// Status line without a Reason-Phrase, but trailing space.
// (permitted by RFC 2616)
{

View File

@ -507,3 +507,30 @@ func TestHeadResponses(t *testing.T) {
t.Errorf("got unexpected body %q", string(body))
}
}
func TestTLSServer(t *testing.T) {
ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {
fmt.Fprintf(w, "tls=%v", r.TLS != nil)
}))
defer ts.Close()
if !strings.HasPrefix(ts.URL, "https://") {
t.Fatalf("expected test TLS server to start with https://, got %q", ts.URL)
}
res, _, err := Get(ts.URL)
if err != nil {
t.Error(err)
}
if res == nil {
t.Fatalf("got nil Response")
}
if res.Body == nil {
t.Fatalf("got nil Response.Body")
}
body, err := ioutil.ReadAll(res.Body)
if err != nil {
t.Error(err)
}
if e, g := "tls=true", string(body); e != g {
t.Errorf("expected body %q; got %q", e, g)
}
}

View File

@ -215,7 +215,7 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) {
}
// Transfer encoding, content length
t.TransferEncoding, err = fixTransferEncoding(t.Header)
t.TransferEncoding, err = fixTransferEncoding(t.RequestMethod, t.Header)
if err != nil {
return err
}
@ -289,13 +289,20 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) {
func chunked(te []string) bool { return len(te) > 0 && te[0] == "chunked" }
// Sanitize transfer encoding
func fixTransferEncoding(header Header) ([]string, os.Error) {
func fixTransferEncoding(requestMethod string, header Header) ([]string, os.Error) {
raw, present := header["Transfer-Encoding"]
if !present {
return nil, nil
}
header["Transfer-Encoding"] = nil, false
// Head responses have no bodies, so the transfer encoding
// should be ignored.
if requestMethod == "HEAD" {
return nil, nil
}
encodings := strings.Split(raw[0], ",", -1)
te := make([]string, 0, len(encodings))
// TODO: Even though we only support "identity" and "chunked"

View File

@ -24,6 +24,10 @@ import (
// environment variables.
var DefaultTransport RoundTripper = &Transport{}
// DefaultMaxIdleConnsPerHost is the default value of Transport's
// MaxIdleConnsPerHost.
const DefaultMaxIdleConnsPerHost = 2
// Transport is an implementation of RoundTripper that supports http,
// https, and http proxies (for either http or https with CONNECT).
// Transport can also cache connections for future re-use.
@ -31,11 +35,17 @@ type Transport struct {
lk sync.Mutex
idleConn map[string][]*persistConn
// TODO: tunables on max cached connections (total, per-server), duration
// TODO: tunable on global max cached connections
// TODO: tunable on timeout on cached connections
// TODO: optional pipelining
IgnoreEnvironment bool // don't look at environment variables for proxy configuration
DisableKeepAlives bool
// MaxIdleConnsPerHost, if non-zero, controls the maximum idle
// (keep-alive) to keep to keep per-host. If zero,
// DefaultMaxIdleConnsPerHost is used.
MaxIdleConnsPerHost int
}
// RoundTrip implements the RoundTripper interface.
@ -147,7 +157,7 @@ func (cm *connectMethod) proxyAuth() string {
func (t *Transport) putIdleConn(pconn *persistConn) {
t.lk.Lock()
defer t.lk.Unlock()
if t.DisableKeepAlives {
if t.DisableKeepAlives || t.MaxIdleConnsPerHost < 0 {
pconn.close()
return
}
@ -155,6 +165,14 @@ func (t *Transport) putIdleConn(pconn *persistConn) {
return
}
key := pconn.cacheKey
max := t.MaxIdleConnsPerHost
if max == 0 {
max = DefaultMaxIdleConnsPerHost
}
if len(t.idleConn[key]) >= max {
pconn.close()
return
}
t.idleConn[key] = append(t.idleConn[key], pconn)
}
@ -406,24 +424,37 @@ func (pc *persistConn) readLoop() {
rc := <-pc.reqch
resp, err := pc.cc.Read(rc.req)
if err == nil && !rc.req.Close {
pc.t.putIdleConn(pc)
}
if err == ErrPersistEOF {
// Succeeded, but we can't send any more
// persistent connections on this again. We
// hide this error to upstream callers.
alive = false
err = nil
} else if err != nil {
} else if err != nil || rc.req.Close {
alive = false
}
hasBody := resp != nil && resp.ContentLength != 0
var waitForBodyRead chan bool
if alive {
if hasBody {
waitForBodyRead = make(chan bool)
resp.Body.(*bodyEOFSignal).fn = func() {
pc.t.putIdleConn(pc)
waitForBodyRead <- true
}
} else {
pc.t.putIdleConn(pc)
}
}
rc.ch <- responseAndError{resp, err}
// Wait for the just-returned response body to be fully consumed
// before we race and peek on the underlying bufio reader.
if alive {
<-resp.Body.(*bodyEOFSignal).ch
if waitForBodyRead != nil {
<-waitForBodyRead
}
}
}
@ -494,34 +525,34 @@ func responseIsKeepAlive(res *Response) bool {
// the response body with a bodyEOFSignal-wrapped version.
func readResponseWithEOFSignal(r *bufio.Reader, requestMethod string) (resp *Response, err os.Error) {
resp, err = ReadResponse(r, requestMethod)
if err == nil {
resp.Body = &bodyEOFSignal{resp.Body, make(chan bool, 1), false}
if err == nil && resp.ContentLength != 0 {
resp.Body = &bodyEOFSignal{resp.Body, nil}
}
return
}
// bodyEOFSignal wraps a ReadCloser but sends on ch once once
// the wrapped ReadCloser is fully consumed (including on Close)
// bodyEOFSignal wraps a ReadCloser but runs fn (if non-nil) at most
// once, right before the final Read() or Close() call returns, but after
// EOF has been seen.
type bodyEOFSignal struct {
body io.ReadCloser
ch chan bool
done bool
fn func()
}
func (es *bodyEOFSignal) Read(p []byte) (n int, err os.Error) {
n, err = es.body.Read(p)
if err == os.EOF && !es.done {
es.ch <- true
es.done = true
if err == os.EOF && es.fn != nil {
es.fn()
es.fn = nil
}
return
}
func (es *bodyEOFSignal) Close() (err os.Error) {
err = es.body.Close()
if err == nil && !es.done {
es.ch <- true
es.done = true
if err == nil && es.fn != nil {
es.fn()
es.fn = nil
}
return
}

View File

@ -85,6 +85,7 @@ func TestTransportConnectionCloseOnResponse(t *testing.T) {
t.Fatalf("error in connectionClose=%v, req #%d, Do: %v", connectionClose, n, err)
}
body, err := ioutil.ReadAll(res.Body)
defer res.Body.Close()
if err != nil {
t.Fatalf("error in connectionClose=%v, req #%d, ReadAll: %v", connectionClose, n, err)
}
@ -154,9 +155,11 @@ func TestTransportIdleCacheKeys(t *testing.T) {
t.Errorf("After CloseIdleConnections expected %d idle conn cache keys; got %d", e, g)
}
if _, _, err := c.Get(ts.URL); err != nil {
resp, _, err := c.Get(ts.URL)
if err != nil {
t.Error(err)
}
ioutil.ReadAll(resp.Body)
keys := tr.IdleConnKeysForTesting()
if e, g := 1, len(keys); e != g {
@ -164,7 +167,7 @@ func TestTransportIdleCacheKeys(t *testing.T) {
}
if e := "|http|" + ts.Listener.Addr().String(); keys[0] != e {
t.Logf("Expected idle cache key %q; got %q", e, keys[0])
t.Errorf("Expected idle cache key %q; got %q", e, keys[0])
}
tr.CloseIdleConnections()
@ -173,6 +176,62 @@ func TestTransportIdleCacheKeys(t *testing.T) {
}
}
func TestTransportMaxPerHostIdleConns(t *testing.T) {
ch := make(chan string)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
fmt.Fprintf(w, "%s", <-ch)
}))
defer ts.Close()
maxIdleConns := 2
tr := &Transport{DisableKeepAlives: false, MaxIdleConnsPerHost: maxIdleConns}
c := &Client{Transport: tr}
// Start 3 outstanding requests (will hang until we write to
// ch)
donech := make(chan bool)
doReq := func() {
resp, _, err := c.Get(ts.URL)
if err != nil {
t.Error(err)
}
ioutil.ReadAll(resp.Body)
donech <- true
}
go doReq()
go doReq()
go doReq()
if e, g := 0, len(tr.IdleConnKeysForTesting()); e != g {
t.Fatalf("Before writes, expected %d idle conn cache keys; got %d", e, g)
}
ch <- "res1"
<-donech
keys := tr.IdleConnKeysForTesting()
if e, g := 1, len(keys); e != g {
t.Fatalf("after first response, expected %d idle conn cache keys; got %d", e, g)
}
cacheKey := "|http|" + ts.Listener.Addr().String()
if keys[0] != cacheKey {
t.Fatalf("Expected idle cache key %q; got %q", cacheKey, keys[0])
}
if e, g := 1, tr.IdleConnCountForTesting(cacheKey); e != g {
t.Errorf("after first response, expected %d idle conns; got %d", e, g)
}
ch <- "res2"
<-donech
if e, g := 2, tr.IdleConnCountForTesting(cacheKey); e != g {
t.Errorf("after second response, expected %d idle conns; got %d", e, g)
}
ch <- "res3"
<-donech
if e, g := maxIdleConns, tr.IdleConnCountForTesting(cacheKey); e != g {
t.Errorf("after third response, still expected %d idle conns; got %d", e, g)
}
}
func TestTransportServerClosingUnexpectedly(t *testing.T) {
ts := httptest.NewServer(hostPortHandler)
defer ts.Close()
@ -209,6 +268,63 @@ func TestTransportServerClosingUnexpectedly(t *testing.T) {
}
}
// TestTransportHeadResponses verifies that we deal with Content-Lengths
// with no bodies properly
func TestTransportHeadResponses(t *testing.T) {
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
if r.Method != "HEAD" {
panic("expected HEAD; got " + r.Method)
}
w.Header().Set("Content-Length", "123")
w.WriteHeader(200)
}))
defer ts.Close()
tr := &Transport{DisableKeepAlives: false}
c := &Client{Transport: tr}
for i := 0; i < 2; i++ {
res, err := c.Head(ts.URL)
if err != nil {
t.Errorf("error on loop %d: %v", i, err)
}
if e, g := "123", res.Header.Get("Content-Length"); e != g {
t.Errorf("loop %d: expected Content-Length header of %q, got %q", e, g)
}
if e, g := int64(0), res.ContentLength; e != g {
t.Errorf("loop %d: expected res.ContentLength of %v, got %v", e, g)
}
}
}
// TestTransportHeadChunkedResponse verifies that we ignore chunked transfer-encoding
// on responses to HEAD requests.
func TestTransportHeadChunkedResponse(t *testing.T) {
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
if r.Method != "HEAD" {
panic("expected HEAD; got " + r.Method)
}
w.Header().Set("Transfer-Encoding", "chunked") // client should ignore
w.Header().Set("x-client-ipport", r.RemoteAddr)
w.WriteHeader(200)
}))
defer ts.Close()
tr := &Transport{DisableKeepAlives: false}
c := &Client{Transport: tr}
res1, err := c.Head(ts.URL)
if err != nil {
t.Fatalf("request 1 error: %v", err)
}
res2, err := c.Head(ts.URL)
if err != nil {
t.Fatalf("request 2 error: %v", err)
}
if v1, v2 := res1.Header.Get("x-client-ipport"), res2.Header.Get("x-client-ipport"); v1 != v2 {
t.Errorf("ip/ports differed between head requests: %q vs %q", v1, v2)
}
}
func TestTransportNilURL(t *testing.T) {
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
fmt.Fprintf(w, "Hi")

View File

@ -213,8 +213,8 @@ func urlEscape(s string, mode encoding) string {
j++
case shouldEscape(c, mode):
t[j] = '%'
t[j+1] = "0123456789abcdef"[c>>4]
t[j+2] = "0123456789abcdef"[c&15]
t[j+1] = "0123456789ABCDEF"[c>>4]
t[j+2] = "0123456789ABCDEF"[c&15]
j += 3
default:
t[j] = s[i]

View File

@ -490,7 +490,7 @@ var escapeTests = []URLEscapeTest{
},
{
" ?&=#+%!<>#\"{}|\\^[]`☺\t",
"+%3f%26%3d%23%2b%25!%3c%3e%23%22%7b%7d%7c%5c%5e%5b%5d%60%e2%98%ba%09",
"+%3F%26%3D%23%2B%25!%3C%3E%23%22%7B%7D%7C%5C%5E%5B%5D%60%E2%98%BA%09",
nil,
},
}
@ -519,7 +519,7 @@ type UserinfoTest struct {
var userinfoTests = []UserinfoTest{
{"user", "password", "user:password"},
{"foo:bar", "~!@#$%^&*()_+{}|[]\\-=`:;'\"<>?,./",
"foo%3abar:~!%40%23$%25%5e&*()_+%7b%7d%7c%5b%5d%5c-=%60%3a;'%22%3c%3e?,.%2f"},
"foo%3Abar:~!%40%23$%25%5E&*()_+%7B%7D%7C%5B%5D%5C-=%60%3A;'%22%3C%3E?,.%2F"},
}
func TestEscapeUserinfo(t *testing.T) {

View File

@ -34,7 +34,7 @@ var imageTests = []imageTest{
}
func decode(filename string) (image.Image, string, os.Error) {
f, err := os.Open(filename, os.O_RDONLY, 0400)
f, err := os.Open(filename)
if err != nil {
return nil, "", err
}

View File

@ -41,7 +41,7 @@ var filenamesShort = []string{
}
func readPng(filename string) (image.Image, os.Error) {
f, err := os.Open(filename, os.O_RDONLY, 0444)
f, err := os.Open(filename)
if err != nil {
return nil, err
}
@ -191,7 +191,7 @@ func TestReader(t *testing.T) {
defer piper.Close()
// Read the .sng file.
sf, err := os.Open("testdata/pngsuite/"+fn+".sng", os.O_RDONLY, 0444)
sf, err := os.Open("testdata/pngsuite/" + fn + ".sng")
if err != nil {
t.Error(fn, err)
continue

View File

@ -28,7 +28,7 @@ func ReadAll(r io.Reader) ([]byte, os.Error) {
// ReadFile reads the file named by filename and returns the contents.
func ReadFile(filename string) ([]byte, os.Error) {
f, err := os.Open(filename, os.O_RDONLY, 0)
f, err := os.Open(filename)
if err != nil {
return nil, err
}
@ -52,7 +52,7 @@ func ReadFile(filename string) ([]byte, os.Error) {
// If the file does not exist, WriteFile creates it with permissions perm;
// otherwise WriteFile truncates it before writing.
func WriteFile(filename string, data []byte, perm uint32) os.Error {
f, err := os.Open(filename, os.O_WRONLY|os.O_CREAT|os.O_TRUNC, perm)
f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
if err != nil {
return err
}
@ -74,7 +74,7 @@ func (f fileInfoList) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
// ReadDir reads the directory named by dirname and returns
// a list of sorted directory entries.
func ReadDir(dirname string) ([]*os.FileInfo, os.Error) {
f, err := os.Open(dirname, os.O_RDONLY, 0)
f, err := os.Open(dirname)
if err != nil {
return nil, err
}

View File

@ -48,7 +48,7 @@ func TempFile(dir, prefix string) (f *os.File, err os.Error) {
nconflict := 0
for i := 0; i < 10000; i++ {
name := filepath.Join(dir, prefix+nextSuffix())
f, err = os.Open(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
f, err = os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
if pe, ok := err.(*os.PathError); ok && pe.Error == os.EEXIST {
if nconflict++; nconflict > 10 {
rand = reseed()

View File

@ -28,11 +28,12 @@ const (
// order they appear (the order listed here) or the format they present (as
// described in the comments). A colon appears after these items:
// 2009/0123 01:23:23.123123 /a/b/c/d.go:23: message
Ldate = 1 << iota // the date: 2009/0123
Ltime // the time: 01:23:23
Lmicroseconds // microsecond resolution: 01:23:23.123123. assumes Ltime.
Llongfile // full file name and line number: /a/b/c/d.go:23
Lshortfile // final file name element and line number: d.go:23. overrides Llongfile
Ldate = 1 << iota // the date: 2009/0123
Ltime // the time: 01:23:23
Lmicroseconds // microsecond resolution: 01:23:23.123123. assumes Ltime.
Llongfile // full file name and line number: /a/b/c/d.go:23
Lshortfile // final file name element and line number: d.go:23. overrides Llongfile
LstdFlags = Ldate | Ltime // initial values for the standard logger
)
// A Logger represents an active logging object that generates lines of
@ -40,10 +41,11 @@ const (
// the Writer's Write method. A Logger can be used simultaneously from
// multiple goroutines; it guarantees to serialize access to the Writer.
type Logger struct {
mu sync.Mutex // ensures atomic writes
out io.Writer // destination for output
prefix string // prefix to write at beginning of each line
flag int // properties
prefix string // prefix to write at beginning of each line
flag int // properties
mu sync.Mutex // ensures atomic writes; protects the following fields
out io.Writer // destination for output
buf bytes.Buffer // for accumulating text to write
}
// New creates a new Logger. The out variable sets the
@ -54,7 +56,7 @@ func New(out io.Writer, prefix string, flag int) *Logger {
return &Logger{out: out, prefix: prefix, flag: flag}
}
var std = New(os.Stderr, "", Ldate|Ltime)
var std = New(os.Stderr, "", LstdFlags)
// Cheap integer to fixed-width decimal ASCII. Give a negative width to avoid zero-padding.
// Knows the buffer has capacity.
@ -81,7 +83,7 @@ func itoa(buf *bytes.Buffer, i int, wid int) {
}
}
func (l *Logger) formatHeader(buf *bytes.Buffer, ns int64, calldepth int) {
func (l *Logger) formatHeader(buf *bytes.Buffer, ns int64, file string, line int) {
buf.WriteString(l.prefix)
if l.flag&(Ldate|Ltime|Lmicroseconds) != 0 {
t := time.SecondsToLocalTime(ns / 1e9)
@ -107,21 +109,15 @@ func (l *Logger) formatHeader(buf *bytes.Buffer, ns int64, calldepth int) {
}
}
if l.flag&(Lshortfile|Llongfile) != 0 {
_, file, line, ok := runtime.Caller(calldepth)
if ok {
if l.flag&Lshortfile != 0 {
short := file
for i := len(file) - 1; i > 0; i-- {
if file[i] == '/' {
short = file[i+1:]
break
}
if l.flag&Lshortfile != 0 {
short := file
for i := len(file) - 1; i > 0; i-- {
if file[i] == '/' {
short = file[i+1:]
break
}
file = short
}
} else {
file = "???"
line = 0
file = short
}
buf.WriteString(file)
buf.WriteByte(':')
@ -138,15 +134,26 @@ func (l *Logger) formatHeader(buf *bytes.Buffer, ns int64, calldepth int) {
// paths it will be 2.
func (l *Logger) Output(calldepth int, s string) os.Error {
now := time.Nanoseconds() // get this early.
buf := new(bytes.Buffer)
l.formatHeader(buf, now, calldepth+1)
buf.WriteString(s)
if len(s) > 0 && s[len(s)-1] != '\n' {
buf.WriteByte('\n')
// get caller info (if required) before locking - it's expensive.
var file string
var line int
if l.flag&(Lshortfile|Llongfile) != 0 {
var ok bool
_, file, line, ok = runtime.Caller(calldepth)
if !ok {
file = "???"
line = 0
}
}
l.mu.Lock()
defer l.mu.Unlock()
_, err := l.out.Write(buf.Bytes())
l.buf.Reset()
l.formatHeader(&l.buf, now, file, line)
l.buf.WriteString(s)
if len(s) > 0 && s[len(s)-1] != '\n' {
l.buf.WriteByte('\n')
}
_, err := l.out.Write(l.buf.Bytes())
return err
}
@ -203,19 +210,49 @@ func (l *Logger) Panicln(v ...interface{}) {
panic(s)
}
// Flags returns the output flags for the logger.
func (l *Logger) Flags() int {
return l.flag
}
// SetFlags sets the output flags for the logger.
func (l *Logger) SetFlags(flag int) {
l.flag = flag
}
// Prefix returns the output prefix for the logger.
func (l *Logger) Prefix() string {
return l.prefix
}
// SetPrefix sets the output prefix for the logger.
func (l *Logger) SetPrefix(prefix string) {
l.prefix = prefix
}
// SetOutput sets the output destination for the standard logger.
func SetOutput(w io.Writer) {
std.out = w
}
// Flags returns the output flags for the standard logger.
func Flags() int {
return std.Flags()
}
// SetFlags sets the output flags for the standard logger.
func SetFlags(flag int) {
std.flag = flag
std.SetFlags(flag)
}
// Prefix returns the output prefix for the standard logger.
func Prefix() string {
return std.Prefix()
}
// SetPrefix sets the output prefix for the standard logger.
func SetPrefix(prefix string) {
std.prefix = prefix
std.SetPrefix(prefix)
}
// These functions write to the standard logger.

View File

@ -84,3 +84,36 @@ func TestOutput(t *testing.T) {
t.Errorf("log output should match %q is %q", expect, b.String())
}
}
func TestFlagAndPrefixSetting(t *testing.T) {
var b bytes.Buffer
l := New(&b, "Test:", LstdFlags)
f := l.Flags()
if f != LstdFlags {
t.Errorf("Flags 1: expected %x got %x", LstdFlags, f)
}
l.SetFlags(f | Lmicroseconds)
f = l.Flags()
if f != LstdFlags|Lmicroseconds {
t.Errorf("Flags 2: expected %x got %x", LstdFlags|Lmicroseconds, f)
}
p := l.Prefix()
if p != "Test:" {
t.Errorf(`Prefix: expected "Test:" got %q`, p)
}
l.SetPrefix("Reality:")
p = l.Prefix()
if p != "Reality:" {
t.Errorf(`Prefix: expected "Reality:" got %q`, p)
}
// Verify a log message looks right, with our prefix and microseconds present.
l.Print("hello")
pattern := "^Reality:" + Rdate + " " + Rtime + Rmicroseconds + " hello\n"
matched, err := regexp.Match(pattern, b.Bytes())
if err != nil {
t.Fatalf("pattern %q did not compile: %s", pattern, err)
}
if !matched {
t.Error("message did not match pattern")
}
}

View File

@ -33,7 +33,7 @@ var mimeTypes = map[string]string{
var mimeLock sync.RWMutex
func loadMimeFile(filename string) {
f, err := os.Open(filename, os.O_RDONLY, 0666)
f, err := os.Open(filename)
if err != nil {
return
}

View File

@ -59,7 +59,7 @@ func readHosts() {
}
}
// lookupStaticHosts looks up the addresses for the given host from /etc/hosts.
// lookupStaticHost looks up the addresses for the given host from /etc/hosts.
func lookupStaticHost(host string) []string {
hosts.Lock()
defer hosts.Unlock()
@ -72,7 +72,7 @@ func lookupStaticHost(host string) []string {
return nil
}
// rlookupStaticHosts looks up the hosts for the given address from /etc/hosts.
// lookupStaticAddr looks up the hosts for the given address from /etc/hosts.
func lookupStaticAddr(addr string) []string {
hosts.Lock()
defer hosts.Unlock()

View File

@ -63,7 +63,7 @@ func (f *file) readLine() (s string, ok bool) {
}
func open(name string) (*file, os.Error) {
fd, err := os.Open(name, os.O_RDONLY, 0)
fd, err := os.Open(name)
if err != nil {
return nil, err
}

View File

@ -18,7 +18,7 @@ func TestReadLine(t *testing.T) {
}
filename := "/etc/services" // a nice big file
fd, err := os.Open(filename, os.O_RDONLY, 0)
fd, err := os.Open(filename)
if err != nil {
t.Fatalf("open %s: %v", filename, err)
}

View File

@ -14,26 +14,51 @@ import (
var hostentLock sync.Mutex
var serventLock sync.Mutex
func LookupHost(name string) (cname string, addrs []string, err os.Error) {
func goLookupHost(name string) (addrs []string, err os.Error) {
ips, err := goLookupIP(name)
if err != nil {
return
}
addrs = make([]string, 0, len(ips))
for _, ip := range ips {
addrs = append(addrs, ip.String())
}
return
}
func goLookupIP(name string) (addrs []IP, err os.Error) {
hostentLock.Lock()
defer hostentLock.Unlock()
h, e := syscall.GetHostByName(name)
if e != 0 {
return "", nil, os.NewSyscallError("GetHostByName", e)
return nil, os.NewSyscallError("GetHostByName", e)
}
cname = name
switch h.AddrType {
case syscall.AF_INET:
i := 0
addrs = make([]string, 100) // plenty of room to grow
addrs = make([]IP, 100) // plenty of room to grow
for p := (*[100](*[4]byte))(unsafe.Pointer(h.AddrList)); i < cap(addrs) && p[i] != nil; i++ {
addrs[i] = IPv4(p[i][0], p[i][1], p[i][2], p[i][3]).String()
addrs[i] = IPv4(p[i][0], p[i][1], p[i][2], p[i][3])
}
addrs = addrs[0:i]
default: // TODO(vcc): Implement non IPv4 address lookups.
return "", nil, os.NewSyscallError("LookupHost", syscall.EWINDOWS)
return nil, os.NewSyscallError("LookupHost", syscall.EWINDOWS)
}
return cname, addrs, nil
return addrs, nil
}
func LookupCNAME(name string) (cname string, err os.Error) {
var r *syscall.DNSRecord
e := syscall.DnsQuery(name, syscall.DNS_TYPE_CNAME, 0, nil, &r, nil)
if int(e) != 0 {
return "", os.NewSyscallError("LookupCNAME", int(e))
}
defer syscall.DnsRecordListFree(r, 1)
if r != nil && r.Type == syscall.DNS_TYPE_CNAME {
v := (*syscall.DNSPTRData)(unsafe.Pointer(&r.Data[0]))
cname = syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:]) + "."
}
return
}
type SRV struct {
@ -62,7 +87,7 @@ func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err os.
return name, addrs, nil
}
func LookupPort(network, service string) (port int, err os.Error) {
func goLookupPort(network, service string) (port int, err os.Error) {
switch network {
case "tcp4", "tcp6":
network = "tcp"

300
libgo/go/os/dir_plan9.go Normal file
View File

@ -0,0 +1,300 @@
// 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.
package os
import (
"syscall"
)
type dirInfo int
var markDirectory dirInfo = ^0
// Readdir reads the contents of the directory associated with file and
// returns an array of up to count FileInfo structures, as would be returned
// by Lstat, in directory order. Subsequent calls on the same file will yield
// further FileInfos. A negative count means to read the entire directory.
// Readdir returns the array and an Error, if any.
func (file *File) Readdir(count int) (fi []FileInfo, err Error) {
// If this file has no dirinfo, create one.
if file.dirinfo == nil {
file.dirinfo = &markDirectory
}
size := count
if size < 0 {
size = 100
}
result := make([]FileInfo, 0, size)
var buf [syscall.STATMAX]byte
for {
n, e := file.Read(buf[:])
if e != nil {
if e == EOF {
break
}
return []FileInfo{}, &PathError{"readdir", file.name, e}
}
if n < syscall.STATFIXLEN {
return []FileInfo{}, &PathError{"readdir", file.name, Eshortstat}
}
for i := 0; i < n; {
m, _ := gbit16(buf[i:])
m += 2
if m < syscall.STATFIXLEN {
return []FileInfo{}, &PathError{"readdir", file.name, Eshortstat}
}
d, e := UnmarshalDir(buf[i : i+int(m)])
if e != nil {
return []FileInfo{}, &PathError{"readdir", file.name, e}
}
var f FileInfo
fileInfoFromStat(&f, d)
result = append(result, f)
// a negative count means to read until EOF.
if count > 0 && len(result) >= count {
break
}
i += int(m)
}
}
return result, nil
}
// Readdirnames returns an array of up to count file names residing in the
// directory associated with file. A negative count will return all of them.
// Readdir returns the array and an Error, if any.
func (file *File) Readdirnames(count int) (names []string, err Error) {
fi, e := file.Readdir(count)
if e != nil {
return []string{}, e
}
names = make([]string, len(fi))
err = nil
for i, _ := range fi {
names[i] = fi[i].Name
}
return
}
type Dir struct {
// system-modified data
Type uint16 // server type
Dev uint32 // server subtype
// file data
Qid Qid // unique id from server
Mode uint32 // permissions
Atime uint32 // last read time
Mtime uint32 // last write time
Length uint64 // file length
Name string // last element of path
Uid string // owner name
Gid string // group name
Muid string // last modifier name
}
type Qid struct {
Path uint64 // the file server's unique identification for the file
Vers uint32 // version number for given Path
Type uint8 // the type of the file (syscall.QTDIR for example)
}
var nullDir = Dir{
^uint16(0),
^uint32(0),
Qid{^uint64(0), ^uint32(0), ^uint8(0)},
^uint32(0),
^uint32(0),
^uint32(0),
^uint64(0),
"",
"",
"",
"",
}
// Null assigns members of d with special "don't care" values indicating
// they should not be written by syscall.Wstat.
func (d *Dir) Null() {
*d = nullDir
}
// pdir appends a 9P Stat message based on the contents of Dir d to a byte slice b.
func pdir(b []byte, d *Dir) []byte {
n := len(b)
b = pbit16(b, 0) // length, filled in later
b = pbit16(b, d.Type)
b = pbit32(b, d.Dev)
b = pqid(b, d.Qid)
b = pbit32(b, d.Mode)
b = pbit32(b, d.Atime)
b = pbit32(b, d.Mtime)
b = pbit64(b, d.Length)
b = pstring(b, d.Name)
b = pstring(b, d.Uid)
b = pstring(b, d.Gid)
b = pstring(b, d.Muid)
pbit16(b[0:n], uint16(len(b)-(n+2)))
return b
}
// UnmarshalDir reads a 9P Stat message from a 9P protocol message strored in b,
// returning the corresponding Dir struct.
func UnmarshalDir(b []byte) (d *Dir, err Error) {
n := uint16(0)
n, b = gbit16(b)
if int(n) != len(b) {
return nil, Ebadstat
}
d = new(Dir)
d.Type, b = gbit16(b)
d.Dev, b = gbit32(b)
d.Qid, b = gqid(b)
d.Mode, b = gbit32(b)
d.Atime, b = gbit32(b)
d.Mtime, b = gbit32(b)
d.Length, b = gbit64(b)
d.Name, b = gstring(b)
d.Uid, b = gstring(b)
d.Gid, b = gstring(b)
d.Muid, b = gstring(b)
if len(b) != 0 {
return nil, Ebadstat
}
return d, nil
}
// gqid reads the qid part of a 9P Stat message from a 9P protocol message strored in b,
// returning the corresponding Qid struct and the remaining slice of b.
func gqid(b []byte) (Qid, []byte) {
var q Qid
q.Path, b = gbit64(b)
q.Vers, b = gbit32(b)
q.Type, b = gbit8(b)
return q, b
}
// pqid appends a Qid struct q to a 9P message b.
func pqid(b []byte, q Qid) []byte {
b = pbit64(b, q.Path)
b = pbit32(b, q.Vers)
b = pbit8(b, q.Type)
return b
}
// gbit8 reads a byte-sized numeric value from a 9P protocol message strored in b,
// returning the value and the remaining slice of b.
func gbit8(b []byte) (uint8, []byte) {
return uint8(b[0]), b[1:]
}
// gbit16 reads a 16-bit numeric value from a 9P protocol message strored in b,
// returning the value and the remaining slice of b.
func gbit16(b []byte) (uint16, []byte) {
return uint16(b[0]) | uint16(b[1])<<8, b[2:]
}
// gbit32 reads a 32-bit numeric value from a 9P protocol message strored in b,
// returning the value and the remaining slice of b.
func gbit32(b []byte) (uint32, []byte) {
return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24, b[4:]
}
// gbit64 reads a 64-bit numeric value from a 9P protocol message strored in b,
// returning the value and the remaining slice of b.
func gbit64(b []byte) (uint64, []byte) {
lo, b := gbit32(b)
hi, b := gbit32(b)
return uint64(hi)<<32 | uint64(lo), b
}
// gstring reads a string from a 9P protocol message strored in b,
// returning the value as a Go string and the remaining slice of b.
func gstring(b []byte) (string, []byte) {
n, b := gbit16(b)
return string(b[0:n]), b[n:]
}
// pbit8 appends a byte-sized numeric value x to a 9P message b.
func pbit8(b []byte, x uint8) []byte {
n := len(b)
if n+1 > cap(b) {
nb := make([]byte, n, 100+2*cap(b))
copy(nb, b)
b = nb
}
b = b[0 : n+1]
b[n] = x
return b
}
// pbit16 appends a 16-bit numeric value x to a 9P message b.
func pbit16(b []byte, x uint16) []byte {
n := len(b)
if n+2 > cap(b) {
nb := make([]byte, n, 100+2*cap(b))
copy(nb, b)
b = nb
}
b = b[0 : n+2]
b[n] = byte(x)
b[n+1] = byte(x >> 8)
return b
}
// pbit32 appends a 32-bit numeric value x to a 9P message b.
func pbit32(b []byte, x uint32) []byte {
n := len(b)
if n+4 > cap(b) {
nb := make([]byte, n, 100+2*cap(b))
copy(nb, b)
b = nb
}
b = b[0 : n+4]
b[n] = byte(x)
b[n+1] = byte(x >> 8)
b[n+2] = byte(x >> 16)
b[n+3] = byte(x >> 24)
return b
}
// pbit64 appends a 64-bit numeric value x to a 9P message b.
func pbit64(b []byte, x uint64) []byte {
b = pbit32(b, uint32(x))
b = pbit32(b, uint32(x>>32))
return b
}
// pstring appends a Go string s to a 9P message b.
func pstring(b []byte, s string) []byte {
if len(s) >= 1<<16 {
panic(NewError("string too long"))
}
b = pbit16(b, uint16(len(s)))
b = append(b, []byte(s)...)
return b
}

54
libgo/go/os/dir_unix.go Normal file
View File

@ -0,0 +1,54 @@
// 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.
package os
import (
"syscall"
)
const (
blockSize = 4096
)
// Readdirnames reads the contents of the directory associated with file and
// returns an array of up to count names, in directory order. Subsequent
// calls on the same file will yield further names.
// A negative count means to read until EOF.
// Readdirnames returns the array and an Error, if any.
func (file *File) Readdirnames(count int) (names []string, err Error) {
// If this file has no dirinfo, create one.
if file.dirinfo == nil {
file.dirinfo = new(dirInfo)
// The buffer must be at least a block long.
file.dirinfo.buf = make([]byte, blockSize)
}
d := file.dirinfo
size := count
if size < 0 {
size = 100
}
names = make([]string, 0, size) // Empty with room to grow.
for count != 0 {
// Refill the buffer if necessary
if d.bufp >= d.nbuf {
d.bufp = 0
var errno int
d.nbuf, errno = syscall.ReadDirent(file.fd, d.buf)
if errno != 0 {
return names, NewSyscallError("readdirent", errno)
}
if d.nbuf <= 0 {
break // EOF
}
}
// Drain the buffer
var nb, nc int
nb, nc, names = syscall.ParseDirent(d.buf[d.bufp:d.nbuf], count, names)
d.bufp += nb
count -= nc
}
return names, nil
}

91
libgo/go/os/env_plan9.go Normal file
View File

@ -0,0 +1,91 @@
// Copyright 2011 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.
// Plan 9 environment variables.
package os
import "syscall"
// ENOENV is the Error indicating that an environment variable does not exist.
var ENOENV = NewError("no such environment variable")
// Getenverror retrieves the value of the environment variable named by the key.
// It returns the value and an error, if any.
func Getenverror(key string) (value string, err Error) {
if len(key) == 0 {
return "", EINVAL
}
f, e := Open("/env/" + key)
if iserror(e) {
return "", ENOENV
}
defer f.Close()
var buf [4096]byte
n, e := f.Read(buf[:len(buf)-1])
if iserror(e) {
return "", ENOENV
}
buf[n] = 0
return string(buf[0:n]), nil
}
// Getenv retrieves the value of the environment variable named by the key.
// It returns the value, which will be empty if the variable is not present.
func Getenv(key string) string {
v, _ := Getenverror(key)
return v
}
// Setenv sets the value of the environment variable named by the key.
// It returns an Error, if any.
func Setenv(key, value string) Error {
if len(key) == 0 {
return EINVAL
}
f, e := Create("/env/" + key)
if iserror(e) {
return e
}
defer f.Close()
_, e = f.Write(syscall.StringByteSlice(value))
return nil
}
// Clearenv deletes all environment variables.
func Clearenv() {
syscall.RawSyscall(syscall.SYS_RFORK, syscall.RFCENVG, 0, 0)
}
// Environ returns an array of strings representing the environment,
// in the form "key=value".
func Environ() []string {
env := make([]string, 0, 100)
f, e := Open("/env")
if iserror(e) {
panic(e)
}
defer f.Close()
names, e := f.Readdirnames(-1)
if iserror(e) {
panic(e)
}
for _, k := range names {
if v, e := Getenverror(k); !iserror(e) {
env = append(env, k+"="+v)
}
}
return env[0:len(env)]
}
// TempDir returns the default directory to use for temporary files.
func TempDir() string {
return "/tmp"
}

View File

@ -4,8 +4,6 @@
package os
import syscall "syscall"
// An Error can represent any printable error condition.
type Error interface {
String() string
@ -26,63 +24,6 @@ func (e ErrorString) Timeout() bool { return false }
// NewError converts s to an ErrorString, which satisfies the Error interface.
func NewError(s string) Error { return ErrorString(s) }
// Errno is the Unix error number. Names such as EINVAL are simple
// wrappers to convert the error number into an Error.
type Errno int64
func (e Errno) String() string { return syscall.Errstr(int(e)) }
func (e Errno) Temporary() bool {
return e == Errno(syscall.EINTR) || e.Timeout()
}
func (e Errno) Timeout() bool {
return e == Errno(syscall.EAGAIN) || e == Errno(syscall.EWOULDBLOCK) || e == Errno(syscall.ETIMEDOUT)
}
// Commonly known Unix errors.
var (
EPERM Error = Errno(syscall.EPERM)
ENOENT Error = Errno(syscall.ENOENT)
ESRCH Error = Errno(syscall.ESRCH)
EINTR Error = Errno(syscall.EINTR)
EIO Error = Errno(syscall.EIO)
ENXIO Error = Errno(syscall.ENXIO)
E2BIG Error = Errno(syscall.E2BIG)
ENOEXEC Error = Errno(syscall.ENOEXEC)
EBADF Error = Errno(syscall.EBADF)
ECHILD Error = Errno(syscall.ECHILD)
EDEADLK Error = Errno(syscall.EDEADLK)
ENOMEM Error = Errno(syscall.ENOMEM)
EACCES Error = Errno(syscall.EACCES)
EFAULT Error = Errno(syscall.EFAULT)
EBUSY Error = Errno(syscall.EBUSY)
EEXIST Error = Errno(syscall.EEXIST)
EXDEV Error = Errno(syscall.EXDEV)
ENODEV Error = Errno(syscall.ENODEV)
ENOTDIR Error = Errno(syscall.ENOTDIR)
EISDIR Error = Errno(syscall.EISDIR)
EINVAL Error = Errno(syscall.EINVAL)
ENFILE Error = Errno(syscall.ENFILE)
EMFILE Error = Errno(syscall.EMFILE)
ENOTTY Error = Errno(syscall.ENOTTY)
EFBIG Error = Errno(syscall.EFBIG)
ENOSPC Error = Errno(syscall.ENOSPC)
ESPIPE Error = Errno(syscall.ESPIPE)
EROFS Error = Errno(syscall.EROFS)
EMLINK Error = Errno(syscall.EMLINK)
EPIPE Error = Errno(syscall.EPIPE)
EAGAIN Error = Errno(syscall.EAGAIN)
EDOM Error = Errno(syscall.EDOM)
ERANGE Error = Errno(syscall.ERANGE)
EADDRINUSE Error = Errno(syscall.EADDRINUSE)
ECONNREFUSED Error = Errno(syscall.ECONNREFUSED)
ENAMETOOLONG Error = Errno(syscall.ENAMETOOLONG)
EAFNOSUPPORT Error = Errno(syscall.EAFNOSUPPORT)
ETIMEDOUT Error = Errno(syscall.ETIMEDOUT)
ENOTCONN Error = Errno(syscall.ENOTCONN)
)
// PathError records an error and the operation and file path that caused it.
type PathError struct {
Op string
@ -91,25 +32,3 @@ type PathError struct {
}
func (e *PathError) String() string { return e.Op + " " + e.Path + ": " + e.Error.String() }
// SyscallError records an error from a specific system call.
type SyscallError struct {
Syscall string
Errno Errno
}
func (e *SyscallError) String() string { return e.Syscall + ": " + e.Errno.String() }
// Note: If the name of the function NewSyscallError changes,
// pkg/go/doc/doc.go should be adjusted since it hardwires
// this name in a heuristic.
// NewSyscallError returns, as an Error, a new SyscallError
// with the given system call name and error number.
// As a convenience, if errno is 0, NewSyscallError returns nil.
func NewSyscallError(syscall string, errno int) Error {
if errno == 0 {
return nil
}
return &SyscallError{syscall, Errno(errno)}
}

View File

@ -0,0 +1,57 @@
// Copyright 2011 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 os
import syscall "syscall"
// SyscallError records an error from a specific system call.
type SyscallError struct {
Syscall string
Err string
}
func (e *SyscallError) String() string { return e.Syscall + ": " + e.Err }
// Note: If the name of the function NewSyscallError changes,
// pkg/go/doc/doc.go should be adjusted since it hardwires
// this name in a heuristic.
// NewSyscallError returns, as an Error, a new SyscallError
// with the given system call name and error details.
// As a convenience, if err is nil, NewSyscallError returns nil.
func NewSyscallError(syscall string, err syscall.Error) Error {
if err == nil {
return nil
}
return &SyscallError{syscall, err.String()}
}
var (
Eshortstat = NewError("stat buffer too small")
Ebadstat = NewError("malformed stat buffer")
Ebadfd = NewError("fd out of range or not open")
Ebadarg = NewError("bad arg in system call")
Enotdir = NewError("not a directory")
Enonexist = NewError("file does not exist")
Eexist = NewError("file already exists")
Eio = NewError("i/o error")
EINVAL = Ebadarg
ENOTDIR = Enotdir
ENOENT = Enonexist
EEXIST = Eexist
EIO = Eio
ENAMETOOLONG = NewError("file name too long")
ERANGE = NewError("math result not representable")
EPIPE = NewError("Broken Pipe")
EPLAN9 = NewError("not supported by plan 9")
)
func iserror(err syscall.Error) bool {
return err != nil
}
func Errno(e syscall.Error) syscall.Error { return e }

View File

@ -0,0 +1,90 @@
// 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.
package os
import syscall "syscall"
// Errno is the Unix error number. Names such as EINVAL are simple
// wrappers to convert the error number into an Error.
type Errno int64
func (e Errno) String() string { return syscall.Errstr(int(e)) }
func (e Errno) Temporary() bool {
return e == Errno(syscall.EINTR) || e.Timeout()
}
func (e Errno) Timeout() bool {
return e == Errno(syscall.EAGAIN) || e == Errno(syscall.EWOULDBLOCK) || e == Errno(syscall.ETIMEDOUT)
}
// Commonly known Unix errors.
var (
EPERM Error = Errno(syscall.EPERM)
ENOENT Error = Errno(syscall.ENOENT)
ESRCH Error = Errno(syscall.ESRCH)
EINTR Error = Errno(syscall.EINTR)
EIO Error = Errno(syscall.EIO)
ENXIO Error = Errno(syscall.ENXIO)
E2BIG Error = Errno(syscall.E2BIG)
ENOEXEC Error = Errno(syscall.ENOEXEC)
EBADF Error = Errno(syscall.EBADF)
ECHILD Error = Errno(syscall.ECHILD)
EDEADLK Error = Errno(syscall.EDEADLK)
ENOMEM Error = Errno(syscall.ENOMEM)
EACCES Error = Errno(syscall.EACCES)
EFAULT Error = Errno(syscall.EFAULT)
EBUSY Error = Errno(syscall.EBUSY)
EEXIST Error = Errno(syscall.EEXIST)
EXDEV Error = Errno(syscall.EXDEV)
ENODEV Error = Errno(syscall.ENODEV)
ENOTDIR Error = Errno(syscall.ENOTDIR)
EISDIR Error = Errno(syscall.EISDIR)
EINVAL Error = Errno(syscall.EINVAL)
ENFILE Error = Errno(syscall.ENFILE)
EMFILE Error = Errno(syscall.EMFILE)
ENOTTY Error = Errno(syscall.ENOTTY)
EFBIG Error = Errno(syscall.EFBIG)
ENOSPC Error = Errno(syscall.ENOSPC)
ESPIPE Error = Errno(syscall.ESPIPE)
EROFS Error = Errno(syscall.EROFS)
EMLINK Error = Errno(syscall.EMLINK)
EPIPE Error = Errno(syscall.EPIPE)
EAGAIN Error = Errno(syscall.EAGAIN)
EDOM Error = Errno(syscall.EDOM)
ERANGE Error = Errno(syscall.ERANGE)
EADDRINUSE Error = Errno(syscall.EADDRINUSE)
ECONNREFUSED Error = Errno(syscall.ECONNREFUSED)
ENAMETOOLONG Error = Errno(syscall.ENAMETOOLONG)
EAFNOSUPPORT Error = Errno(syscall.EAFNOSUPPORT)
ETIMEDOUT Error = Errno(syscall.ETIMEDOUT)
ENOTCONN Error = Errno(syscall.ENOTCONN)
)
// SyscallError records an error from a specific system call.
type SyscallError struct {
Syscall string
Errno Errno
}
func (e *SyscallError) String() string { return e.Syscall + ": " + e.Errno.String() }
// Note: If the name of the function NewSyscallError changes,
// pkg/go/doc/doc.go should be adjusted since it hardwires
// this name in a heuristic.
// NewSyscallError returns, as an Error, a new SyscallError
// with the given system call name and error details.
// As a convenience, if errno is 0, NewSyscallError returns nil.
func NewSyscallError(syscall string, errno int) Error {
if errno == 0 {
return nil
}
return &SyscallError{syscall, Errno(errno)}
}
func iserror(errno int) bool {
return errno != 0
}

View File

@ -39,126 +39,6 @@ type ProcAttr struct {
Files []*File
}
// StartProcess starts a new process with the program, arguments and attributes
// specified by name, argv and attr.
func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err Error) {
sysattr := &syscall.ProcAttr{
Dir: attr.Dir,
Env: attr.Env,
}
if sysattr.Env == nil {
sysattr.Env = Environ()
}
// Create array of integer (system) fds.
intfd := make([]int, len(attr.Files))
for i, f := range attr.Files {
if f == nil {
intfd[i] = -1
} else {
intfd[i] = f.Fd()
}
}
sysattr.Files = intfd
pid, h, e := syscall.StartProcess(name, argv, sysattr)
if e != 0 {
return nil, &PathError{"fork/exec", name, Errno(e)}
}
return newProcess(pid, h), nil
}
// Exec replaces the current process with an execution of the
// named binary, with arguments argv and environment envv.
// If successful, Exec never returns. If it fails, it returns an Error.
// StartProcess is almost always a better way to execute a program.
func Exec(name string, argv []string, envv []string) Error {
if envv == nil {
envv = Environ()
}
e := syscall.Exec(name, argv, envv)
if e != 0 {
return &PathError{"exec", name, Errno(e)}
}
return nil
}
// TODO(rsc): Should os implement its own syscall.WaitStatus
// wrapper with the methods, or is exposing the underlying one enough?
//
// TODO(rsc): Certainly need to have Rusage struct,
// since syscall one might have different field types across
// different OS.
// Waitmsg stores the information about an exited process as reported by Wait.
type Waitmsg struct {
Pid int // The process's id.
syscall.WaitStatus // System-dependent status info.
Rusage *syscall.Rusage // System-dependent resource usage info.
}
// Wait waits for process pid to exit or stop, and then returns a
// Waitmsg describing its status and an Error, if any. The options
// (WNOHANG etc.) affect the behavior of the Wait call.
// Wait is equivalent to calling FindProcess and then Wait
// and Release on the result.
func Wait(pid int, options int) (w *Waitmsg, err Error) {
p, e := FindProcess(pid)
if e != nil {
return nil, e
}
defer p.Release()
return p.Wait(options)
}
// Convert i to decimal string.
func itod(i int) string {
if i == 0 {
return "0"
}
u := uint64(i)
if i < 0 {
u = -u
}
// Assemble decimal in reverse order.
var b [32]byte
bp := len(b)
for ; u > 0; u /= 10 {
bp--
b[bp] = byte(u%10) + '0'
}
if i < 0 {
bp--
b[bp] = '-'
}
return string(b[bp:])
}
func (w Waitmsg) String() string {
// TODO(austin) Use signal names when possible?
res := ""
switch {
case w.Exited():
res = "exit status " + itod(w.ExitStatus())
case w.Signaled():
res = "signal " + itod(w.Signal())
case w.Stopped():
res = "stop signal " + itod(w.StopSignal())
if w.StopSignal() == syscall.SIGTRAP && w.TrapCause() != 0 {
res += " (trap " + itod(w.TrapCause()) + ")"
}
case w.Continued():
res = "continued"
}
if w.CoreDump() {
res += " (core dumped)"
}
return res
}
// Getpid returns the process id of the caller.
func Getpid() int { return syscall.Getpid() }

114
libgo/go/os/exec_plan9.go Normal file
View File

@ -0,0 +1,114 @@
// 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.
package os
import (
"runtime"
"syscall"
)
// StartProcess starts a new process with the program, arguments and attributes
// specified by name, argv and attr.
func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err Error) {
sysattr := &syscall.ProcAttr{
Dir: attr.Dir,
Env: attr.Env,
}
// Create array of integer (system) fds.
intfd := make([]int, len(attr.Files))
for i, f := range attr.Files {
if f == nil {
intfd[i] = -1
} else {
intfd[i] = f.Fd()
}
}
sysattr.Files = intfd
pid, h, e := syscall.StartProcess(name, argv, sysattr)
if iserror(e) {
return nil, &PathError{"fork/exec", name, e}
}
return newProcess(pid, h), nil
}
// Exec replaces the current process with an execution of the
// named binary, with arguments argv and environment envv.
// If successful, Exec never returns. If it fails, it returns an Error.
// ForkExec is almost always a better way to execute a program.
func Exec(name string, argv []string, envv []string) Error {
e := syscall.Exec(name, argv, envv)
if iserror(e) {
return &PathError{"exec", name, e}
}
return nil
}
// Waitmsg stores the information about an exited process as reported by Wait.
type Waitmsg syscall.Waitmsg
// Wait waits for the Process to exit or stop, and then returns a
// Waitmsg describing its status and an Error, if any. The options
// (WNOHANG etc.) affect the behavior of the Wait call.
func (p *Process) Wait(options int) (w *Waitmsg, err Error) {
var waitmsg syscall.Waitmsg
if p.Pid == -1 {
return nil, EINVAL
}
for true {
err = syscall.Await(&waitmsg)
if iserror(err) {
return nil, NewSyscallError("wait", err)
}
if waitmsg.Pid == p.Pid {
break
}
}
return (*Waitmsg)(&waitmsg), nil
}
// Wait waits for process pid to exit or stop, and then returns a
// Waitmsg describing its status and an Error, if any. The options
// (WNOHANG etc.) affect the behavior of the Wait call.
// Wait is equivalent to calling FindProcess and then Wait
// and Release on the result.
func Wait(pid int, options int) (w *Waitmsg, err Error) {
p, e := FindProcess(pid)
if e != nil {
return nil, e
}
defer p.Release()
return p.Wait(options)
}
// Release releases any resources associated with the Process.
func (p *Process) Release() Error {
// NOOP for Plan 9.
p.Pid = -1
// no need for a finalizer anymore
runtime.SetFinalizer(p, nil)
return nil
}
// FindProcess looks for a running process by its pid.
// The Process it returns can be used to obtain information
// about the underlying operating system process.
func FindProcess(pid int) (p *Process, err Error) {
// NOOP for Plan 9.
return newProcess(pid, 0), nil
}
func (w Waitmsg) String() string {
return "exit status: " + w.Msg
}

127
libgo/go/os/exec_posix.go Normal file
View File

@ -0,0 +1,127 @@
// 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.
package os
import "syscall"
// StartProcess starts a new process with the program, arguments and attributes
// specified by name, argv and attr.
func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err Error) {
sysattr := &syscall.ProcAttr{
Dir: attr.Dir,
Env: attr.Env,
}
if sysattr.Env == nil {
sysattr.Env = Environ()
}
// Create array of integer (system) fds.
intfd := make([]int, len(attr.Files))
for i, f := range attr.Files {
if f == nil {
intfd[i] = -1
} else {
intfd[i] = f.Fd()
}
}
sysattr.Files = intfd
pid, h, e := syscall.StartProcess(name, argv, sysattr)
if iserror(e) {
return nil, &PathError{"fork/exec", name, Errno(e)}
}
return newProcess(pid, h), nil
}
// Exec replaces the current process with an execution of the
// named binary, with arguments argv and environment envv.
// If successful, Exec never returns. If it fails, it returns an Error.
// StartProcess is almost always a better way to execute a program.
func Exec(name string, argv []string, envv []string) Error {
if envv == nil {
envv = Environ()
}
e := syscall.Exec(name, argv, envv)
if iserror(e) {
return &PathError{"exec", name, Errno(e)}
}
return nil
}
// TODO(rsc): Should os implement its own syscall.WaitStatus
// wrapper with the methods, or is exposing the underlying one enough?
//
// TODO(rsc): Certainly need to have Rusage struct,
// since syscall one might have different field types across
// different OS.
// Waitmsg stores the information about an exited process as reported by Wait.
type Waitmsg struct {
Pid int // The process's id.
syscall.WaitStatus // System-dependent status info.
Rusage *syscall.Rusage // System-dependent resource usage info.
}
// Wait waits for process pid to exit or stop, and then returns a
// Waitmsg describing its status and an Error, if any. The options
// (WNOHANG etc.) affect the behavior of the Wait call.
// Wait is equivalent to calling FindProcess and then Wait
// and Release on the result.
func Wait(pid int, options int) (w *Waitmsg, err Error) {
p, e := FindProcess(pid)
if e != nil {
return nil, e
}
defer p.Release()
return p.Wait(options)
}
// Convert i to decimal string.
func itod(i int) string {
if i == 0 {
return "0"
}
u := uint64(i)
if i < 0 {
u = -u
}
// Assemble decimal in reverse order.
var b [32]byte
bp := len(b)
for ; u > 0; u /= 10 {
bp--
b[bp] = byte(u%10) + '0'
}
if i < 0 {
bp--
b[bp] = '-'
}
return string(b[bp:])
}
func (w Waitmsg) String() string {
// TODO(austin) Use signal names when possible?
res := ""
switch {
case w.Exited():
res = "exit status " + itod(w.ExitStatus())
case w.Signaled():
res = "signal " + itod(w.Signal())
case w.Stopped():
res = "stop signal " + itod(w.StopSignal())
if w.StopSignal() == syscall.SIGTRAP && w.TrapCause() != 0 {
res += " (trap " + itod(w.TrapCause()) + ")"
}
case w.Continued():
res = "continued"
}
if w.CoreDump() {
res += " (core dumped)"
}
return res
}

View File

@ -51,14 +51,20 @@ const (
O_RDWR int = syscall.O_RDWR // open the file read-write.
O_APPEND int = syscall.O_APPEND // append data to the file when writing.
O_ASYNC int = syscall.O_ASYNC // generate a signal when I/O is available.
O_CREAT int = syscall.O_CREAT // create a new file if none exists.
O_EXCL int = syscall.O_EXCL // used with O_CREAT, file must not exist
O_CREATE int = syscall.O_CREAT // create a new file if none exists.
O_EXCL int = syscall.O_EXCL // used with O_CREATE, file must not exist
O_NOCTTY int = syscall.O_NOCTTY // do not make file the controlling tty.
O_NONBLOCK int = syscall.O_NONBLOCK // open in non-blocking mode.
O_NDELAY int = O_NONBLOCK // synonym for O_NONBLOCK
O_SYNC int = syscall.O_SYNC // open for synchronous I/O.
O_TRUNC int = syscall.O_TRUNC // if possible, truncate file when opened.
O_CREATE int = O_CREAT // create a new file if none exists.
)
// Seek whence values.
const (
SEEK_SET int = 0 // seek relative to the origin of the file
SEEK_CUR int = 1 // seek relative to the current offset
SEEK_END int = 2 // seek relative to the end
)
type eofError int
@ -83,10 +89,10 @@ func (file *File) Read(b []byte) (n int, err Error) {
if n < 0 {
n = 0
}
if n == 0 && e == 0 {
if n == 0 && !iserror(e) {
return 0, EOF
}
if e != 0 {
if iserror(e) {
err = &PathError{"read", file.name, Errno(e)}
}
return n, err
@ -102,10 +108,10 @@ func (file *File) ReadAt(b []byte, off int64) (n int, err Error) {
}
for len(b) > 0 {
m, e := syscall.Pread(file.fd, b, off)
if m == 0 && e == 0 {
if m == 0 && !iserror(e) {
return n, EOF
}
if e != 0 {
if iserror(e) {
err = &PathError{"read", file.name, Errno(e)}
break
}
@ -127,15 +133,10 @@ func (file *File) Write(b []byte) (n int, err Error) {
if n < 0 {
n = 0
}
if e == syscall.EPIPE {
file.nepipe++
if file.nepipe >= 10 {
Exit(syscall.EPIPE)
}
} else {
file.nepipe = 0
}
if e != 0 {
epipecheck(file, e)
if iserror(e) {
err = &PathError{"write", file.name, Errno(e)}
}
return n, err
@ -150,7 +151,7 @@ func (file *File) WriteAt(b []byte, off int64) (n int, err Error) {
}
for len(b) > 0 {
m, e := syscall.Pwrite(file.fd, b, off)
if e != 0 {
if iserror(e) {
err = &PathError{"write", file.name, Errno(e)}
break
}
@ -167,10 +168,10 @@ func (file *File) WriteAt(b []byte, off int64) (n int, err Error) {
// It returns the new offset and an Error, if any.
func (file *File) Seek(offset int64, whence int) (ret int64, err Error) {
r, e := syscall.Seek(file.fd, offset, whence)
if e == 0 && file.dirinfo != nil && r != 0 {
if !iserror(e) && file.dirinfo != nil && r != 0 {
e = syscall.EISDIR
}
if e != 0 {
if iserror(e) {
return 0, &PathError{"seek", file.name, Errno(e)}
}
return r, nil
@ -187,71 +188,19 @@ func (file *File) WriteString(s string) (ret int, err Error) {
return file.Write(b)
}
// Pipe returns a connected pair of Files; reads from r return bytes written to w.
// It returns the files and an Error, if any.
func Pipe() (r *File, w *File, err Error) {
var p [2]int
// See ../syscall/exec.go for description of lock.
syscall.ForkLock.RLock()
e := syscall.Pipe(p[0:])
if e != 0 {
syscall.ForkLock.RUnlock()
return nil, nil, NewSyscallError("pipe", e)
}
syscall.CloseOnExec(p[0])
syscall.CloseOnExec(p[1])
syscall.ForkLock.RUnlock()
return NewFile(p[0], "|0"), NewFile(p[1], "|1"), nil
}
// Mkdir creates a new directory with the specified name and permission bits.
// It returns an error, if any.
func Mkdir(name string, perm uint32) Error {
e := syscall.Mkdir(name, perm)
if e != 0 {
if iserror(e) {
return &PathError{"mkdir", name, Errno(e)}
}
return nil
}
// Stat returns a FileInfo structure describing the named file and an error, if any.
// If name names a valid symbolic link, the returned FileInfo describes
// the file pointed at by the link and has fi.FollowedSymlink set to true.
// If name names an invalid symbolic link, the returned FileInfo describes
// the link itself and has fi.FollowedSymlink set to false.
func Stat(name string) (fi *FileInfo, err Error) {
var lstat, stat syscall.Stat_t
e := syscall.Lstat(name, &lstat)
if e != 0 {
return nil, &PathError{"stat", name, Errno(e)}
}
statp := &lstat
if lstat.Mode&syscall.S_IFMT == syscall.S_IFLNK {
e := syscall.Stat(name, &stat)
if e == 0 {
statp = &stat
}
}
return fileInfoFromStat(name, new(FileInfo), &lstat, statp), nil
}
// Lstat returns the FileInfo structure describing the named file and an
// error, if any. If the file is a symbolic link, the returned FileInfo
// describes the symbolic link. Lstat makes no attempt to follow the link.
func Lstat(name string) (fi *FileInfo, err Error) {
var stat syscall.Stat_t
e := syscall.Lstat(name, &stat)
if e != 0 {
return nil, &PathError{"lstat", name, Errno(e)}
}
return fileInfoFromStat(name, new(FileInfo), &stat, &stat), nil
}
// Chdir changes the current working directory to the named directory.
func Chdir(dir string) Error {
if e := syscall.Chdir(dir); e != 0 {
if e := syscall.Chdir(dir); iserror(e) {
return &PathError{"chdir", dir, Errno(e)}
}
return nil
@ -260,179 +209,25 @@ func Chdir(dir string) Error {
// Chdir changes the current working directory to the file,
// which must be a directory.
func (f *File) Chdir() Error {
if e := syscall.Fchdir(f.fd); e != 0 {
if e := syscall.Fchdir(f.fd); iserror(e) {
return &PathError{"chdir", f.name, Errno(e)}
}
return nil
}
// Remove removes the named file or directory.
func Remove(name string) Error {
// System call interface forces us to know
// whether name is a file or directory.
// Try both: it is cheaper on average than
// doing a Stat plus the right one.
e := syscall.Unlink(name)
if e == 0 {
return nil
}
e1 := syscall.Rmdir(name)
if e1 == 0 {
return nil
}
// Both failed: figure out which error to return.
// OS X and Linux differ on whether unlink(dir)
// returns EISDIR, so can't use that. However,
// both agree that rmdir(file) returns ENOTDIR,
// so we can use that to decide which error is real.
// Rmdir might also return ENOTDIR if given a bad
// file path, like /etc/passwd/foo, but in that case,
// both errors will be ENOTDIR, so it's okay to
// use the error from unlink.
// For windows syscall.ENOTDIR is set
// to syscall.ERROR_DIRECTORY, hopefully it should
// do the trick.
if e1 != syscall.ENOTDIR {
e = e1
}
return &PathError{"remove", name, Errno(e)}
// Open opens the named file for reading. If successful, methods on
// the returned file can be used for reading; the associated file
// descriptor has mode O_RDONLY.
// It returns the File and an Error, if any.
func Open(name string) (file *File, err Error) {
return OpenFile(name, O_RDONLY, 0)
}
// LinkError records an error during a link or symlink or rename
// system call and the paths that caused it.
type LinkError struct {
Op string
Old string
New string
Error Error
}
func (e *LinkError) String() string {
return e.Op + " " + e.Old + " " + e.New + ": " + e.Error.String()
}
// Link creates a hard link.
func Link(oldname, newname string) Error {
e := syscall.Link(oldname, newname)
if e != 0 {
return &LinkError{"link", oldname, newname, Errno(e)}
}
return nil
}
// Symlink creates a symbolic link.
func Symlink(oldname, newname string) Error {
e := syscall.Symlink(oldname, newname)
if e != 0 {
return &LinkError{"symlink", oldname, newname, Errno(e)}
}
return nil
}
// Readlink reads the contents of a symbolic link: the destination of
// the link. It returns the contents and an Error, if any.
func Readlink(name string) (string, Error) {
for len := 128; ; len *= 2 {
b := make([]byte, len)
n, e := syscall.Readlink(name, b)
if e != 0 {
return "", &PathError{"readlink", name, Errno(e)}
}
if n < len {
return string(b[0:n]), nil
}
}
// Silence 6g.
return "", nil
}
// Rename renames a file.
func Rename(oldname, newname string) Error {
e := syscall.Rename(oldname, newname)
if e != 0 {
return &LinkError{"rename", oldname, newname, Errno(e)}
}
return nil
}
// Chmod changes the mode of the named file to mode.
// If the file is a symbolic link, it changes the mode of the link's target.
func Chmod(name string, mode uint32) Error {
if e := syscall.Chmod(name, mode); e != 0 {
return &PathError{"chmod", name, Errno(e)}
}
return nil
}
// Chmod changes the mode of the file to mode.
func (f *File) Chmod(mode uint32) Error {
if e := syscall.Fchmod(f.fd, mode); e != 0 {
return &PathError{"chmod", f.name, Errno(e)}
}
return nil
}
// Chown changes the numeric uid and gid of the named file.
// If the file is a symbolic link, it changes the uid and gid of the link's target.
func Chown(name string, uid, gid int) Error {
if e := syscall.Chown(name, uid, gid); e != 0 {
return &PathError{"chown", name, Errno(e)}
}
return nil
}
// Lchown changes the numeric uid and gid of the named file.
// If the file is a symbolic link, it changes the uid and gid of the link itself.
func Lchown(name string, uid, gid int) Error {
if e := syscall.Lchown(name, uid, gid); e != 0 {
return &PathError{"lchown", name, Errno(e)}
}
return nil
}
// Chown changes the numeric uid and gid of the named file.
func (f *File) Chown(uid, gid int) Error {
if e := syscall.Fchown(f.fd, uid, gid); e != 0 {
return &PathError{"chown", f.name, Errno(e)}
}
return nil
}
// Truncate changes the size of the file.
// It does not change the I/O offset.
func (f *File) Truncate(size int64) Error {
if e := syscall.Ftruncate(f.fd, size); e != 0 {
return &PathError{"truncate", f.name, Errno(e)}
}
return nil
}
// Sync commits the current contents of the file to stable storage.
// Typically, this means flushing the file system's in-memory copy
// of recently written data to disk.
func (file *File) Sync() (err Error) {
if file == nil {
return EINVAL
}
if e := syscall.Fsync(file.fd); e != 0 {
return NewSyscallError("fsync", e)
}
return nil
}
// Chtimes changes the access and modification times of the named
// file, similar to the Unix utime() or utimes() functions.
//
// The argument times are in nanoseconds, although the underlying
// filesystem may truncate or round the values to a more
// coarse time unit.
func Chtimes(name string, atime_ns int64, mtime_ns int64) Error {
var utimes [2]syscall.Timeval
utimes[0] = syscall.NsecToTimeval(atime_ns)
utimes[1] = syscall.NsecToTimeval(mtime_ns)
if e := syscall.Utimes(name, utimes[0:]); e != 0 {
return &PathError{"chtimes", name, Errno(e)}
}
return nil
// Create creates the named file mode 0666 (before umask), truncating
// it if it already exists. If successful, methods on the returned
// File can be used for I/O; the associated file descriptor has mode
// O_RDWR.
// It returns the File and an Error, if any.
func Create(name string) (file *File, err Error) {
return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
}

233
libgo/go/os/file_plan9.go Normal file
View File

@ -0,0 +1,233 @@
// Copyright 2011 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 os
import (
"runtime"
"syscall"
)
func epipecheck(file *File, e syscall.Error) {
}
// DevNull is the name of the operating system's ``null device.''
// On Unix-like systems, it is "/dev/null"; on Windows, "NUL".
const DevNull = "/dev/null"
// OpenFile is the generalized open call; most users will use Open
// or Create instead. It opens the named file with specified flag
// (O_RDONLY etc.) and perm, (0666 etc.) if applicable. If successful,
// methods on the returned File can be used for I/O.
// It returns the File and an Error, if any.
func OpenFile(name string, flag int, perm uint32) (file *File, err Error) {
var fd int
var e syscall.Error
syscall.ForkLock.RLock()
if flag&O_CREATE == O_CREATE {
fd, e = syscall.Create(name, flag & ^O_CREATE, perm)
} else {
fd, e = syscall.Open(name, flag)
}
syscall.ForkLock.RUnlock()
if e != nil {
return nil, &PathError{"open", name, e}
}
return NewFile(fd, name), nil
}
// Close closes the File, rendering it unusable for I/O.
// It returns an Error, if any.
func (file *File) Close() Error {
if file == nil || file.fd < 0 {
return Ebadfd
}
var err Error
syscall.ForkLock.RLock()
if e := syscall.Close(file.fd); e != nil {
err = &PathError{"close", file.name, e}
}
syscall.ForkLock.RUnlock()
file.fd = -1 // so it can't be closed again
// no need for a finalizer anymore
runtime.SetFinalizer(file, nil)
return err
}
// Stat returns the FileInfo structure describing file.
// It returns the FileInfo and an error, if any.
func (file *File) Stat() (fi *FileInfo, err Error) {
return dirstat(file)
}
// Truncate changes the size of the file.
// It does not change the I/O offset.
func (f *File) Truncate(size int64) Error {
var d Dir
d.Null()
d.Length = uint64(size)
if e := syscall.Fwstat(f.fd, pdir(nil, &d)); iserror(e) {
return &PathError{"truncate", f.name, e}
}
return nil
}
// Chmod changes the mode of the file to mode.
func (f *File) Chmod(mode uint32) Error {
var d Dir
d.Null()
d.Mode = mode & 0777
if e := syscall.Fwstat(f.fd, pdir(nil, &d)); iserror(e) {
return &PathError{"chmod", f.name, e}
}
return nil
}
// Sync commits the current contents of the file to stable storage.
// Typically, this means flushing the file system's in-memory copy
// of recently written data to disk.
func (f *File) Sync() (err Error) {
if f == nil {
return EINVAL
}
var d Dir
d.Null()
if e := syscall.Fwstat(f.fd, pdir(nil, &d)); iserror(e) {
return NewSyscallError("fsync", e)
}
return nil
}
// Truncate changes the size of the named file.
// If the file is a symbolic link, it changes the size of the link's target.
func Truncate(name string, size int64) Error {
var d Dir
d.Null()
d.Length = uint64(size)
if e := syscall.Wstat(name, pdir(nil, &d)); iserror(e) {
return &PathError{"truncate", name, e}
}
return nil
}
// Remove removes the named file or directory.
func Remove(name string) Error {
if e := syscall.Remove(name); iserror(e) {
return &PathError{"remove", name, e}
}
return nil
}
// Rename renames a file.
func Rename(oldname, newname string) Error {
var d Dir
d.Null()
d.Name = newname
if e := syscall.Wstat(oldname, pdir(nil, &d)); iserror(e) {
return &PathError{"rename", oldname, e}
}
return nil
}
// Chmod changes the mode of the named file to mode.
func Chmod(name string, mode uint32) Error {
var d Dir
d.Null()
d.Mode = mode & 0777
if e := syscall.Wstat(name, pdir(nil, &d)); iserror(e) {
return &PathError{"chmod", name, e}
}
return nil
}
// ChownPlan9 changes the uid and gid strings of the named file.
func ChownPlan9(name, uid, gid string) Error {
var d Dir
d.Null()
d.Uid = uid
d.Gid = gid
if e := syscall.Wstat(name, pdir(nil, &d)); iserror(e) {
return &PathError{"chown_plan9", name, e}
}
return nil
}
// Chtimes changes the access and modification times of the named
// file, similar to the Unix utime() or utimes() functions.
//
// The argument times are in nanoseconds, although the underlying
// filesystem may truncate or round the values to a more
// coarse time unit.
func Chtimes(name string, atimeNs int64, mtimeNs int64) Error {
var d Dir
d.Null()
d.Atime = uint32(atimeNs / 1e9)
d.Mtime = uint32(mtimeNs / 1e9)
if e := syscall.Wstat(name, pdir(nil, &d)); iserror(e) {
return &PathError{"chtimes", name, e}
}
return nil
}
func Pipe() (r *File, w *File, err Error) {
var p [2]int
syscall.ForkLock.RLock()
if e := syscall.Pipe(p[0:]); iserror(e) {
syscall.ForkLock.RUnlock()
return nil, nil, NewSyscallError("pipe", e)
}
syscall.ForkLock.RUnlock()
return NewFile(p[0], "|0"), NewFile(p[1], "|1"), nil
}
// not supported on Plan 9
// Link creates a hard link.
func Link(oldname, newname string) Error {
return EPLAN9
}
func Symlink(oldname, newname string) Error {
return EPLAN9
}
func Readlink(name string) (string, Error) {
return "", EPLAN9
}
func Chown(name string, uid, gid int) Error {
return EPLAN9
}
func Lchown(name string, uid, gid int) Error {
return EPLAN9
}
func (f *File) Chown(uid, gid int) Error {
return EPLAN9
}

246
libgo/go/os/file_posix.go Normal file
View File

@ -0,0 +1,246 @@
// 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.
// The os package provides a platform-independent interface to operating
// system functionality. The design is Unix-like.
package os
import (
"syscall"
)
func epipecheck(file *File, e int) {
if e == syscall.EPIPE {
file.nepipe++
if file.nepipe >= 10 {
Exit(syscall.EPIPE)
}
} else {
file.nepipe = 0
}
}
// Pipe returns a connected pair of Files; reads from r return bytes written to w.
// It returns the files and an Error, if any.
func Pipe() (r *File, w *File, err Error) {
var p [2]int
// See ../syscall/exec.go for description of lock.
syscall.ForkLock.RLock()
e := syscall.Pipe(p[0:])
if iserror(e) {
syscall.ForkLock.RUnlock()
return nil, nil, NewSyscallError("pipe", e)
}
syscall.CloseOnExec(p[0])
syscall.CloseOnExec(p[1])
syscall.ForkLock.RUnlock()
return NewFile(p[0], "|0"), NewFile(p[1], "|1"), nil
}
// Stat returns a FileInfo structure describing the named file and an error, if any.
// If name names a valid symbolic link, the returned FileInfo describes
// the file pointed at by the link and has fi.FollowedSymlink set to true.
// If name names an invalid symbolic link, the returned FileInfo describes
// the link itself and has fi.FollowedSymlink set to false.
func Stat(name string) (fi *FileInfo, err Error) {
var lstat, stat syscall.Stat_t
e := syscall.Lstat(name, &lstat)
if iserror(e) {
return nil, &PathError{"stat", name, Errno(e)}
}
statp := &lstat
if lstat.Mode&syscall.S_IFMT == syscall.S_IFLNK {
e := syscall.Stat(name, &stat)
if !iserror(e) {
statp = &stat
}
}
return fileInfoFromStat(name, new(FileInfo), &lstat, statp), nil
}
// Lstat returns the FileInfo structure describing the named file and an
// error, if any. If the file is a symbolic link, the returned FileInfo
// describes the symbolic link. Lstat makes no attempt to follow the link.
func Lstat(name string) (fi *FileInfo, err Error) {
var stat syscall.Stat_t
e := syscall.Lstat(name, &stat)
if iserror(e) {
return nil, &PathError{"lstat", name, Errno(e)}
}
return fileInfoFromStat(name, new(FileInfo), &stat, &stat), nil
}
// Remove removes the named file or directory.
func Remove(name string) Error {
// System call interface forces us to know
// whether name is a file or directory.
// Try both: it is cheaper on average than
// doing a Stat plus the right one.
e := syscall.Unlink(name)
if !iserror(e) {
return nil
}
e1 := syscall.Rmdir(name)
if !iserror(e1) {
return nil
}
// Both failed: figure out which error to return.
// OS X and Linux differ on whether unlink(dir)
// returns EISDIR, so can't use that. However,
// both agree that rmdir(file) returns ENOTDIR,
// so we can use that to decide which error is real.
// Rmdir might also return ENOTDIR if given a bad
// file path, like /etc/passwd/foo, but in that case,
// both errors will be ENOTDIR, so it's okay to
// use the error from unlink.
// For windows syscall.ENOTDIR is set
// to syscall.ERROR_DIRECTORY, hopefully it should
// do the trick.
if e1 != syscall.ENOTDIR {
e = e1
}
return &PathError{"remove", name, Errno(e)}
}
// LinkError records an error during a link or symlink or rename
// system call and the paths that caused it.
type LinkError struct {
Op string
Old string
New string
Error Error
}
func (e *LinkError) String() string {
return e.Op + " " + e.Old + " " + e.New + ": " + e.Error.String()
}
// Link creates a hard link.
func Link(oldname, newname string) Error {
e := syscall.Link(oldname, newname)
if iserror(e) {
return &LinkError{"link", oldname, newname, Errno(e)}
}
return nil
}
// Symlink creates a symbolic link.
func Symlink(oldname, newname string) Error {
e := syscall.Symlink(oldname, newname)
if iserror(e) {
return &LinkError{"symlink", oldname, newname, Errno(e)}
}
return nil
}
// Readlink reads the contents of a symbolic link: the destination of
// the link. It returns the contents and an Error, if any.
func Readlink(name string) (string, Error) {
for len := 128; ; len *= 2 {
b := make([]byte, len)
n, e := syscall.Readlink(name, b)
if iserror(e) {
return "", &PathError{"readlink", name, Errno(e)}
}
if n < len {
return string(b[0:n]), nil
}
}
// Silence 6g.
return "", nil
}
// Rename renames a file.
func Rename(oldname, newname string) Error {
e := syscall.Rename(oldname, newname)
if iserror(e) {
return &LinkError{"rename", oldname, newname, Errno(e)}
}
return nil
}
// Chmod changes the mode of the named file to mode.
// If the file is a symbolic link, it changes the mode of the link's target.
func Chmod(name string, mode uint32) Error {
if e := syscall.Chmod(name, mode); iserror(e) {
return &PathError{"chmod", name, Errno(e)}
}
return nil
}
// Chmod changes the mode of the file to mode.
func (f *File) Chmod(mode uint32) Error {
if e := syscall.Fchmod(f.fd, mode); iserror(e) {
return &PathError{"chmod", f.name, Errno(e)}
}
return nil
}
// Chown changes the numeric uid and gid of the named file.
// If the file is a symbolic link, it changes the uid and gid of the link's target.
func Chown(name string, uid, gid int) Error {
if e := syscall.Chown(name, uid, gid); iserror(e) {
return &PathError{"chown", name, Errno(e)}
}
return nil
}
// Lchown changes the numeric uid and gid of the named file.
// If the file is a symbolic link, it changes the uid and gid of the link itself.
func Lchown(name string, uid, gid int) Error {
if e := syscall.Lchown(name, uid, gid); iserror(e) {
return &PathError{"lchown", name, Errno(e)}
}
return nil
}
// Chown changes the numeric uid and gid of the named file.
func (f *File) Chown(uid, gid int) Error {
if e := syscall.Fchown(f.fd, uid, gid); iserror(e) {
return &PathError{"chown", f.name, Errno(e)}
}
return nil
}
// Truncate changes the size of the file.
// It does not change the I/O offset.
func (f *File) Truncate(size int64) Error {
if e := syscall.Ftruncate(f.fd, size); iserror(e) {
return &PathError{"truncate", f.name, Errno(e)}
}
return nil
}
// Sync commits the current contents of the file to stable storage.
// Typically, this means flushing the file system's in-memory copy
// of recently written data to disk.
func (file *File) Sync() (err Error) {
if file == nil {
return EINVAL
}
if e := syscall.Fsync(file.fd); iserror(e) {
return NewSyscallError("fsync", e)
}
return nil
}
// Chtimes changes the access and modification times of the named
// file, similar to the Unix utime() or utimes() functions.
//
// The argument times are in nanoseconds, although the underlying
// filesystem may truncate or round the values to a more
// coarse time unit.
func Chtimes(name string, atime_ns int64, mtime_ns int64) Error {
var utimes [2]syscall.Timeval
utimes[0] = syscall.NsecToTimeval(atime_ns)
utimes[1] = syscall.NsecToTimeval(mtime_ns)
if e := syscall.Utimes(name, utimes[0:]); iserror(e) {
return &PathError{"chtimes", name, Errno(e)}
}
return nil
}

View File

@ -19,10 +19,12 @@ type dirInfo struct {
// On Unix-like systems, it is "/dev/null"; on Windows, "NUL".
const DevNull = "/dev/null"
// Open opens the named file with specified flag (O_RDONLY etc.) and perm, (0666 etc.)
// if applicable. If successful, methods on the returned File can be used for I/O.
// OpenFile is the generalized open call; most users will use Open
// or Create instead. It opens the named file with specified flag
// (O_RDONLY etc.) and perm, (0666 etc.) if applicable. If successful,
// methods on the returned File can be used for I/O.
// It returns the File and an Error, if any.
func Open(name string, flag int, perm uint32) (file *File, err Error) {
func OpenFile(name string, flag int, perm uint32) (file *File, err Error) {
r, e := syscall.Open(name, flag|syscall.O_CLOEXEC, perm)
if e != 0 {
return nil, &PathError{"open", name, Errno(e)}

View File

@ -54,7 +54,7 @@ func Getwd() (string, Error) {
if len(parent) >= 1024 { // Sanity check
return "", ENAMETOOLONG
}
fd, err := Open(parent, O_RDONLY, 0)
fd, err := Open(parent)
if err != nil {
return "", err
}

View File

@ -51,7 +51,7 @@ func TestInotifyEvents(t *testing.T) {
// Create a file
// This should add at least one event to the inotify event queue
_, err = os.Open(testFile, os.O_WRONLY|os.O_CREAT, 0666)
_, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
t.Fatalf("creating test file failed: %s", err)
}

View File

@ -17,6 +17,7 @@ import (
)
var dot = []string{
"dir_unix.go",
"env_unix.go",
"error.go",
"file.go",
@ -56,7 +57,7 @@ var sysdir = func() (sd *sysDir) {
}()
func size(name string, t *testing.T) int64 {
file, err := Open(name, O_RDONLY, 0)
file, err := Open(name)
defer file.Close()
if err != nil {
t.Fatal("open failed:", err)
@ -121,7 +122,7 @@ func TestStat(t *testing.T) {
func TestFstat(t *testing.T) {
path := sfdir + "/" + sfname
file, err1 := Open(path, O_RDONLY, 0)
file, err1 := Open(path)
defer file.Close()
if err1 != nil {
t.Fatal("open failed:", err1)
@ -155,7 +156,7 @@ func TestLstat(t *testing.T) {
}
func testReaddirnames(dir string, contents []string, t *testing.T) {
file, err := Open(dir, O_RDONLY, 0)
file, err := Open(dir)
defer file.Close()
if err != nil {
t.Fatalf("open %q failed: %v", dir, err)
@ -184,7 +185,7 @@ func testReaddirnames(dir string, contents []string, t *testing.T) {
}
func testReaddir(dir string, contents []string, t *testing.T) {
file, err := Open(dir, O_RDONLY, 0)
file, err := Open(dir)
defer file.Close()
if err != nil {
t.Fatalf("open %q failed: %v", dir, err)
@ -245,7 +246,7 @@ func TestReaddirnamesOneAtATime(t *testing.T) {
if syscall.OS == "windows" {
dir = Getenv("SystemRoot") + "\\system32"
}
file, err := Open(dir, O_RDONLY, 0)
file, err := Open(dir)
defer file.Close()
if err != nil {
t.Fatalf("open %q failed: %v", dir, err)
@ -254,7 +255,7 @@ func TestReaddirnamesOneAtATime(t *testing.T) {
if err1 != nil {
t.Fatalf("readdirnames %q failed: %v", dir, err1)
}
file1, err2 := Open(dir, O_RDONLY, 0)
file1, err2 := Open(dir)
if err2 != nil {
t.Fatalf("open %q failed: %v", dir, err2)
}
@ -273,7 +274,7 @@ func TestHardLink(t *testing.T) {
}
from, to := "hardlinktestfrom", "hardlinktestto"
Remove(from) // Just in case.
file, err := Open(to, O_CREAT|O_WRONLY, 0666)
file, err := Create(to)
if err != nil {
t.Fatalf("open %q failed: %v", to, err)
}
@ -306,7 +307,7 @@ func TestSymLink(t *testing.T) {
}
from, to := "symlinktestfrom", "symlinktestto"
Remove(from) // Just in case.
file, err := Open(to, O_CREAT|O_WRONLY, 0666)
file, err := Create(to)
if err != nil {
t.Fatalf("open %q failed: %v", to, err)
}
@ -354,7 +355,7 @@ func TestSymLink(t *testing.T) {
if s != to {
t.Fatalf("after symlink %q != %q", s, to)
}
file, err = Open(from, O_RDONLY, 0)
file, err = Open(from)
if err != nil {
t.Fatalf("open %q failed: %v", from, err)
}
@ -388,7 +389,7 @@ func TestLongSymlink(t *testing.T) {
func TestRename(t *testing.T) {
from, to := "renamefrom", "renameto"
Remove(to) // Just in case.
file, err := Open(from, O_CREAT|O_WRONLY, 0666)
file, err := Create(from)
if err != nil {
t.Fatalf("open %q failed: %v", to, err)
}
@ -615,7 +616,7 @@ func TestChdirAndGetwd(t *testing.T) {
if syscall.OS == "windows" {
return
}
fd, err := Open(".", O_RDONLY, 0)
fd, err := Open(".")
if err != nil {
t.Fatalf("Open .: %s", err)
}
@ -627,7 +628,7 @@ func TestChdirAndGetwd(t *testing.T) {
if mode == 0 {
err = Chdir(d)
} else {
fd1, err := Open(d, O_RDONLY, 0)
fd1, err := Open(d)
if err != nil {
t.Errorf("Open %s: %s", d, err)
continue
@ -736,7 +737,7 @@ var openErrorTests = []openErrorTest{
func TestOpenError(t *testing.T) {
for _, tt := range openErrorTests {
f, err := Open(tt.path, tt.mode, 0)
f, err := OpenFile(tt.path, tt.mode, 0)
if err == nil {
t.Errorf("Open(%q, %d) succeeded", tt.path, tt.mode)
f.Close()
@ -842,7 +843,7 @@ func TestWriteAt(t *testing.T) {
}
func writeFile(t *testing.T, fname string, flag int, text string) string {
f, err := Open(fname, flag, 0666)
f, err := OpenFile(fname, flag, 0666)
if err != nil {
t.Fatalf("Open: %v", err)
}
@ -861,7 +862,7 @@ func writeFile(t *testing.T, fname string, flag int, text string) string {
func TestAppend(t *testing.T) {
const f = "append.txt"
defer Remove(f)
s := writeFile(t, f, O_CREAT|O_TRUNC|O_RDWR, "new")
s := writeFile(t, f, O_CREATE|O_TRUNC|O_RDWR, "new")
if s != "new" {
t.Fatalf("writeFile: have %q want %q", s, "new")
}

View File

@ -33,7 +33,7 @@ func MkdirAll(path string, perm uint32) Error {
j--
}
if j > 0 {
if j > 1 {
// Create parent
err = MkdirAll(path[0:j-1], perm)
if err != nil {
@ -80,7 +80,7 @@ func RemoveAll(path string) Error {
}
// Directory.
fd, err := Open(path, O_RDONLY, 0)
fd, err := Open(path)
if err != nil {
return err
}

View File

@ -29,7 +29,7 @@ func TestMkdirAll(t *testing.T) {
// Make file.
fpath := path + "/file"
_, err = Open(fpath, O_WRONLY|O_CREAT, 0666)
_, err = Create(fpath)
if err != nil {
t.Fatalf("create %q: %s", fpath, err)
}
@ -72,7 +72,7 @@ func TestRemoveAll(t *testing.T) {
if err := MkdirAll(path, 0777); err != nil {
t.Fatalf("MkdirAll %q: %s", path, err)
}
fd, err := Open(fpath, O_WRONLY|O_CREAT, 0666)
fd, err := Create(fpath)
if err != nil {
t.Fatalf("create %q: %s", fpath, err)
}
@ -88,12 +88,12 @@ func TestRemoveAll(t *testing.T) {
if err = MkdirAll(dpath, 0777); err != nil {
t.Fatalf("MkdirAll %q: %s", dpath, err)
}
fd, err = Open(fpath, O_WRONLY|O_CREAT, 0666)
fd, err = Create(fpath)
if err != nil {
t.Fatalf("create %q: %s", fpath, err)
}
fd.Close()
fd, err = Open(dpath+"/file", O_WRONLY|O_CREAT, 0666)
fd, err = Create(dpath + "/file")
if err != nil {
t.Fatalf("create %q: %s", fpath, err)
}
@ -121,7 +121,7 @@ func TestRemoveAll(t *testing.T) {
}
for _, s := range []string{fpath, dpath + "/file1", path + "/zzz"} {
fd, err = Open(s, O_WRONLY|O_CREAT, 0666)
fd, err = Create(s)
if err != nil {
t.Fatalf("create %q: %s", s, err)
}
@ -179,3 +179,20 @@ func TestMkdirAllWithSymlink(t *testing.T) {
t.Errorf("MkdirAll %q: %s", path, err)
}
}
func TestMkdirAllAtSlash(t *testing.T) {
if runtime.GOOS == "windows" {
return
}
RemoveAll("/_go_os_test")
err := MkdirAll("/_go_os_test/dir", 0777)
if err != nil {
pathErr, ok := err.(*PathError)
// common for users not to be able to write to /
if ok && pathErr.Error == EACCES {
return
}
t.Fatalf(`MkdirAll "/_go_os_test/dir": %v`, err)
}
RemoveAll("/_go_os_test")
}

View File

@ -26,8 +26,8 @@ func Getegid() int { return syscall.Getegid() }
// Getgroups returns a list of the numeric ids of groups that the caller belongs to.
func Getgroups() ([]int, Error) {
gids, errno := syscall.Getgroups()
return gids, NewSyscallError("getgroups", errno)
gids, e := syscall.Getgroups()
return gids, NewSyscallError("getgroups", e)
}
// Exit causes the current program to exit with the given status code.

84
libgo/go/os/stat_plan9.go Normal file
View File

@ -0,0 +1,84 @@
// Copyright 2011 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 os
import "syscall"
func fileInfoFromStat(fi *FileInfo, d *Dir) *FileInfo {
fi.Dev = uint64(d.Qid.Vers) | uint64(d.Qid.Type<<32)
fi.Ino = d.Qid.Path
fi.Mode = uint32(d.Mode) & 0777
if (d.Mode & syscall.DMDIR) == syscall.DMDIR {
fi.Mode |= syscall.S_IFDIR
} else {
fi.Mode |= syscall.S_IFREG
}
fi.Size = int64(d.Length)
fi.Atime_ns = 1e9 * int64(d.Atime)
fi.Mtime_ns = 1e9 * int64(d.Mtime)
fi.Name = d.Name
fi.FollowedSymlink = false
return fi
}
// arg is an open *File or a path string.
func dirstat(arg interface{}) (fi *FileInfo, err Error) {
var name string
nd := syscall.STATFIXLEN + 16*4
for i := 0; i < 2; i++ { /* should work by the second try */
buf := make([]byte, nd)
var n int
var e syscall.Error
switch syscallArg := arg.(type) {
case *File:
name = syscallArg.name
n, e = syscall.Fstat(syscallArg.fd, buf)
case string:
name = syscallArg
n, e = syscall.Stat(name, buf)
}
if e != nil {
return nil, &PathError{"stat", name, e}
}
if n < syscall.STATFIXLEN {
return nil, &PathError{"stat", name, Eshortstat}
}
ntmp, _ := gbit16(buf)
nd = int(ntmp)
if nd <= n {
d, e := UnmarshalDir(buf[:n])
if e != nil {
return nil, &PathError{"stat", name, e}
}
return fileInfoFromStat(new(FileInfo), d), nil
}
}
return nil, &PathError{"stat", name, Ebadstat}
}
// Stat returns a FileInfo structure describing the named file and an error, if any.
func Stat(name string) (fi *FileInfo, err Error) {
return dirstat(name)
}
// Lstat returns the FileInfo structure describing the named file and an
// error, if any. If the file is a symbolic link (though Plan 9 does not have symbolic links),
// the returned FileInfo describes the symbolic link. Lstat makes no attempt to follow the link.
func Lstat(name string) (fi *FileInfo, err Error) {
return dirstat(name)
}

View File

@ -9,7 +9,7 @@ package os
// Hostname returns the host name reported by the kernel.
func Hostname() (name string, err Error) {
f, err := Open("/proc/sys/kernel/hostname", O_RDONLY, 0)
f, err := Open("/proc/sys/kernel/hostname")
if err != nil {
return "", err
}

27
libgo/go/os/sys_plan9.go Normal file
View File

@ -0,0 +1,27 @@
// Copyright 2011 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.
// Plan 9-specific
package os
func Hostname() (name string, err Error) {
f, err := Open("#c/sysname")
if err != nil {
return "", err
}
defer f.Close()
var buf [128]byte
n, err := f.Read(buf[:len(buf)-1])
if err != nil {
return "", err
}
if n > 0 {
buf[n] = 0
}
return string(buf[0:n]), nil
}

View File

@ -13,8 +13,8 @@ import "syscall"
// time is the Unix epoch.
func Time() (sec int64, nsec int64, err Error) {
var tv syscall.Timeval
if errno := syscall.Gettimeofday(&tv); errno != 0 {
return 0, 0, NewSyscallError("gettimeofday", errno)
if e := syscall.Gettimeofday(&tv); iserror(e) {
return 0, 0, NewSyscallError("gettimeofday", e)
}
return int64(tv.Sec), int64(tv.Usec) * 1000, err
}

View File

@ -32,7 +32,7 @@ var ErrBadPattern = os.NewError("syntax error in pattern")
// lo '-' hi matches character c for lo <= c <= hi
//
// Match requires pattern to match all of name, not just a substring.
// The only possible error return is when pattern is malformed.
// The only possible error return occurs when the pattern is malformed.
//
func Match(pattern, name string) (matched bool, err os.Error) {
Pattern:
@ -211,13 +211,14 @@ func getEsc(chunk string) (r int, nchunk string, err os.Error) {
// if there is no matching file. The syntax of patterns is the same
// as in Match. The pattern may describe hierarchical names such as
// /usr/*/bin/ed (assuming the Separator is '/').
// The only possible error return occurs when the pattern is malformed.
//
func Glob(pattern string) (matches []string) {
func Glob(pattern string) (matches []string, err os.Error) {
if !hasMeta(pattern) {
if _, err := os.Stat(pattern); err == nil {
return []string{pattern}
if _, err = os.Stat(pattern); err != nil {
return
}
return nil
return []string{pattern}, nil
}
dir, file := Split(pattern)
@ -230,48 +231,60 @@ func Glob(pattern string) (matches []string) {
dir = dir[0 : len(dir)-1] // chop off trailing separator
}
if hasMeta(dir) {
for _, d := range Glob(dir) {
matches = glob(d, file, matches)
}
} else {
if !hasMeta(dir) {
return glob(dir, file, nil)
}
return matches
var m []string
m, err = Glob(dir)
if err != nil {
return
}
for _, d := range m {
matches, err = glob(d, file, matches)
if err != nil {
return
}
}
return
}
// glob searches for files matching pattern in the directory dir
// and appends them to matches.
func glob(dir, pattern string, matches []string) []string {
// and appends them to matches. If the directory cannot be
// opened, it returns the existing matches. New matches are
// added in lexicographical order.
// The only possible error return occurs when the pattern is malformed.
func glob(dir, pattern string, matches []string) (m []string, e os.Error) {
m = matches
fi, err := os.Stat(dir)
if err != nil {
return nil
return
}
if !fi.IsDirectory() {
return matches
return
}
d, err := os.Open(dir, os.O_RDONLY, 0666)
d, err := os.Open(dir)
if err != nil {
return nil
return
}
defer d.Close()
names, err := d.Readdirnames(-1)
if err != nil {
return nil
return
}
sort.SortStrings(names)
for _, n := range names {
matched, err := Match(pattern, n)
if err != nil {
return matches
return m, err
}
if matched {
matches = append(matches, Join(dir, n))
m = append(m, Join(dir, n))
}
}
return matches
return
}
// hasMeta returns true if path contains any of the magic characters

View File

@ -6,7 +6,7 @@ package filepath_test
import (
"os"
"path/filepath"
. "path/filepath"
"testing"
"runtime"
)
@ -56,16 +56,16 @@ var matchTests = []MatchTest{
{"[\\-x]", "x", true, nil},
{"[\\-x]", "-", true, nil},
{"[\\-x]", "a", false, nil},
{"[]a]", "]", false, filepath.ErrBadPattern},
{"[-]", "-", false, filepath.ErrBadPattern},
{"[x-]", "x", false, filepath.ErrBadPattern},
{"[x-]", "-", false, filepath.ErrBadPattern},
{"[x-]", "z", false, filepath.ErrBadPattern},
{"[-x]", "x", false, filepath.ErrBadPattern},
{"[-x]", "-", false, filepath.ErrBadPattern},
{"[-x]", "a", false, filepath.ErrBadPattern},
{"\\", "a", false, filepath.ErrBadPattern},
{"[a-b-c]", "a", false, filepath.ErrBadPattern},
{"[]a]", "]", false, ErrBadPattern},
{"[-]", "-", false, ErrBadPattern},
{"[x-]", "x", false, ErrBadPattern},
{"[x-]", "-", false, ErrBadPattern},
{"[x-]", "z", false, ErrBadPattern},
{"[-x]", "x", false, ErrBadPattern},
{"[-x]", "-", false, ErrBadPattern},
{"[-x]", "a", false, ErrBadPattern},
{"\\", "a", false, ErrBadPattern},
{"[a-b-c]", "a", false, ErrBadPattern},
{"*x", "xxx", true, nil},
}
@ -75,7 +75,7 @@ func TestMatch(t *testing.T) {
return
}
for _, tt := range matchTests {
ok, err := filepath.Match(tt.pattern, tt.s)
ok, err := Match(tt.pattern, tt.s)
if ok != tt.match || err != tt.err {
t.Errorf("Match(%#q, %#q) = %v, %v want %v, nil", tt.pattern, tt.s, ok, err, tt.match)
}
@ -84,7 +84,7 @@ func TestMatch(t *testing.T) {
// contains returns true if vector contains the string s.
func contains(vector []string, s string) bool {
s = filepath.ToSlash(s)
s = ToSlash(s)
for _, elem := range vector {
if elem == s {
return true
@ -109,9 +109,20 @@ func TestGlob(t *testing.T) {
return
}
for _, tt := range globTests {
matches := filepath.Glob(tt.pattern)
matches, err := Glob(tt.pattern)
if err != nil {
t.Errorf("Glob error for %q: %s", tt.pattern, err)
continue
}
if !contains(matches, tt.result) {
t.Errorf("Glob(%#q) = %#v want %v", tt.pattern, matches, tt.result)
}
}
}
func TestGlobError(t *testing.T) {
_, err := Glob("[7]")
if err != nil {
t.Error("expected error for bad pattern; got none")
}
}

View File

@ -231,6 +231,21 @@ func EvalSymlinks(path string) (string, os.Error) {
return Clean(b.String()), nil
}
// Abs returns an absolute representation of path.
// If the path is not absolute it will be joined with the current
// working directory to turn it into an absolute path. The absolute
// path name for a given file is not guaranteed to be unique.
func Abs(path string) (string, os.Error) {
if IsAbs(path) {
return path, nil
}
wd, err := os.Getwd()
if err != nil {
return "", err
}
return Join(wd, path), nil
}
// Visitor methods are invoked for corresponding file tree entries
// visited by Walk. The parameter path is the full path of f relative
// to root.
@ -265,7 +280,7 @@ func walk(path string, f *os.FileInfo, v Visitor, errors chan<- os.Error) {
// a list of sorted directory entries.
// Copied from io/ioutil to avoid the circular import.
func readDir(dirname string) ([]*os.FileInfo, os.Error) {
f, err := os.Open(dirname, os.O_RDONLY, 0)
f, err := os.Open(dirname)
if err != nil {
return nil, err
}

View File

@ -0,0 +1,28 @@
// Copyright 2010 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 filepath
import "strings"
const (
Separator = '/' // OS-specific path separator
ListSeparator = 0 // OS-specific path list separator
)
// isSeparator returns true if c is a directory separator character.
func isSeparator(c uint8) bool {
return Separator == c
}
// IsAbs returns true if the path is absolute.
func IsAbs(path string) bool {
return strings.HasPrefix(path, "/") || strings.HasPrefix(path, "#")
}
// volumeName returns the leading volume name on Windows.
// It returns "" elsewhere
func volumeName(path string) string {
return ""
}

View File

@ -248,7 +248,7 @@ func walkTree(n *Node, path string, f func(path string, n *Node)) {
func makeTree(t *testing.T) {
walkTree(tree, tree.name, func(path string, n *Node) {
if n.entries == nil {
fd, err := os.Open(path, os.O_CREAT, 0660)
fd, err := os.Create(path)
if err != nil {
t.Errorf("makeTree: %v", err)
}
@ -459,9 +459,9 @@ func TestEvalSymlinks(t *testing.T) {
// relative
for _, d := range EvalSymlinksTests {
if p, err := filepath.EvalSymlinks(d.path); err != nil {
t.Errorf("EvalSymlinks(%v) error: %v", d.path, err)
t.Errorf("EvalSymlinks(%q) error: %v", d.path, err)
} else if p != d.dest {
t.Errorf("EvalSymlinks(%v)=%v, want %v", d.path, p, d.dest)
t.Errorf("EvalSymlinks(%q)=%q, want %q", d.path, p, d.dest)
}
}
// absolute
@ -477,10 +477,54 @@ func TestEvalSymlinks(t *testing.T) {
filepath.Join(testroot, d.dest),
}
if p, err := filepath.EvalSymlinks(a.path); err != nil {
t.Errorf("EvalSymlinks(%v) error: %v", a.path, err)
t.Errorf("EvalSymlinks(%q) error: %v", a.path, err)
} else if p != a.dest {
t.Errorf("EvalSymlinks(%v)=%v, want %v", a.path, p, a.dest)
t.Errorf("EvalSymlinks(%q)=%q, want %q", a.path, p, a.dest)
}
}
*/
}
/* These tests do not work in the gccgo test environment.
// Test paths relative to $GOROOT/src
var abstests = []string{
"../AUTHORS",
"pkg/../../AUTHORS",
"Make.pkg",
"pkg/Makefile",
// Already absolute
"$GOROOT/src/Make.pkg",
}
func TestAbs(t *testing.T) {
oldwd, err := os.Getwd()
if err != nil {
t.Fatal("Getwd failed: " + err.String())
}
defer os.Chdir(oldwd)
goroot := os.Getenv("GOROOT")
cwd := filepath.Join(goroot, "src")
os.Chdir(cwd)
for _, path := range abstests {
path = strings.Replace(path, "$GOROOT", goroot, -1)
abspath, err := filepath.Abs(path)
if err != nil {
t.Errorf("Abs(%q) error: %v", path, err)
}
info, err := os.Stat(path)
if err != nil {
t.Errorf("%s: %s", path, err)
}
absinfo, err := os.Stat(abspath)
if err != nil || absinfo.Ino != info.Ino {
t.Errorf("Abs(%q)=%q, not the same file", path, abspath)
}
if !filepath.IsAbs(abspath) {
t.Errorf("Abs(%q)=%q, not an absolute path", path, abspath)
}
}
}
*/

Some files were not shown because too many files have changed in this diff Show More