mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-13 21:01:29 +08:00
libgo: Update to current Go library.
From-SVN: r172106
This commit is contained in:
parent
a751005d50
commit
405ca10418
@ -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.
|
||||
|
@ -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 \
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
@ -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)
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
@ -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) }
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
@ -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
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
@ -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.
|
98
libgo/go/crypto/des/block.go
Normal file
98
libgo/go/crypto/des/block.go
Normal 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[:])
|
||||
}
|
||||
}
|
103
libgo/go/crypto/des/cipher.go
Normal file
103
libgo/go/crypto/des/cipher.go
Normal 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()
|
||||
}
|
139
libgo/go/crypto/des/const.go
Normal file
139
libgo/go/crypto/des/const.go
Normal 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}
|
1497
libgo/go/crypto/des/des_test.go
Normal file
1497
libgo/go/crypto/des/des_test.go
Normal file
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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")
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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"},
|
||||
|
@ -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 + "`"
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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-----
|
||||
`)
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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")
|
||||
|
@ -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]
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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.
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
300
libgo/go/os/dir_plan9.go
Normal 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
54
libgo/go/os/dir_unix.go
Normal 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
91
libgo/go/os/env_plan9.go
Normal 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"
|
||||
}
|
@ -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)}
|
||||
}
|
||||
|
57
libgo/go/os/error_plan9.go
Normal file
57
libgo/go/os/error_plan9.go
Normal 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 }
|
90
libgo/go/os/error_posix.go
Normal file
90
libgo/go/os/error_posix.go
Normal 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
|
||||
}
|
@ -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
114
libgo/go/os/exec_plan9.go
Normal 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
127
libgo/go/os/exec_posix.go
Normal 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
|
||||
}
|
@ -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
233
libgo/go/os/file_plan9.go
Normal 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
246
libgo/go/os/file_posix.go
Normal 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
|
||||
}
|
@ -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)}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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
84
libgo/go/os/stat_plan9.go
Normal 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)
|
||||
}
|
@ -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
27
libgo/go/os/sys_plan9.go
Normal 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
|
||||
}
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
28
libgo/go/path/filepath/path_plan9.go
Normal file
28
libgo/go/path/filepath/path_plan9.go
Normal 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 ""
|
||||
}
|
@ -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
Loading…
x
Reference in New Issue
Block a user