libgo: Update to Go 1.1.1.

From-SVN: r200974
This commit is contained in:
Ian Lance Taylor 2013-07-16 06:54:42 +00:00
parent efb30cdeb0
commit be47d6ecef
620 changed files with 23931 additions and 122692 deletions

View File

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

View File

@ -211,40 +211,11 @@ toolexeclibgoencoding_DATA = \
encoding/pem.gox \
encoding/xml.gox
if LIBGO_IS_LINUX
# exp_inotify_gox = exp/inotify.gox
exp_inotify_gox =
else
exp_inotify_gox =
endif
toolexeclibgoexpdir = $(toolexeclibgodir)/exp
toolexeclibgoexp_DATA = \
exp/cookiejar.gox \
exp/ebnf.gox \
exp/html.gox \
$(exp_inotify_gox) \
exp/norm.gox \
exp/proxy.gox \
exp/ssa.gox \
exp/terminal.gox \
exp/utf8string.gox
toolexeclibgoexphtmldir = $(toolexeclibgoexpdir)/html
toolexeclibgoexphtml_DATA = \
exp/html/atom.gox
toolexeclibgoexplocaledir = $(toolexeclibgoexpdir)/locale
toolexeclibgoexplocale_DATA = \
exp/locale/collate.gox
toolexeclibgoexplocalecollatedir = $(toolexeclibgoexplocaledir)/collate
toolexeclibgoexplocalecollate_DATA = \
exp/locale/collate/build.gox
exp/terminal.gox
toolexeclibgogodir = $(toolexeclibgodir)/go
@ -256,8 +227,7 @@ toolexeclibgogo_DATA = \
go/parser.gox \
go/printer.gox \
go/scanner.gox \
go/token.gox \
go/types.gox
go/token.gox
toolexeclibgohashdir = $(toolexeclibgodir)/hash
@ -322,6 +292,7 @@ toolexeclibgonethttpdir = $(toolexeclibgonetdir)/http
toolexeclibgonethttp_DATA = \
net/http/cgi.gox \
net/http/cookiejar.gox \
net/http/fcgi.gox \
net/http/httptest.gox \
net/http/httputil.gox \
@ -335,7 +306,6 @@ toolexeclibgonetrpc_DATA = \
toolexeclibgoolddir = $(toolexeclibgodir)/old
toolexeclibgoold_DATA = \
old/netchan.gox \
old/regexp.gox \
old/template.gox
@ -435,6 +405,16 @@ endif
endif
endif
if LIBGO_IS_LINUX
runtime_netpoll_files = netpoll.c runtime/netpoll_epoll.c
else
if LIBGO_IS_DARWIN
runtime_netpoll_files = netpoll.c runtime/netpoll_kqueue.c
else
runtime_netpoll_files = runtime/netpoll_stub.c
endif
endif
runtime_files = \
runtime/go-append.c \
runtime/go-assert.c \
@ -513,6 +493,7 @@ runtime_files = \
runtime/mgc0.c \
runtime/mheap.c \
runtime/msize.c \
$(runtime_netpoll_files) \
runtime/panic.c \
runtime/parfor.c \
runtime/print.c \
@ -548,6 +529,10 @@ mprof.c: $(srcdir)/runtime/mprof.goc goc2c
./goc2c $< > $@.tmp
mv -f $@.tmp $@
netpoll.c: $(srcdir)/runtime/netpoll.goc goc2c
./goc2c $< > $@.tmp
mv -f $@.tmp $@
reflect.c: $(srcdir)/runtime/reflect.goc goc2c
./goc2c $< > $@.tmp
mv -f $@.tmp $@
@ -573,7 +558,8 @@ time.c: $(srcdir)/runtime/time.goc goc2c
mv -f $@.tmp $@
go_bufio_files = \
go/bufio/bufio.go
go/bufio/bufio.go \
go/bufio/scan.go
go_bytes_files = \
go/bytes/buffer.go \
@ -678,17 +664,17 @@ go_net_fd_os_file = go/net/fd_select.go
go_net_newpollserver_file = go/net/newpollserver_rtems.go
else # !LIBGO_IS_RTEMS
if LIBGO_IS_LINUX
go_net_fd_os_file = go/net/fd_linux.go
go_net_newpollserver_file = go/net/newpollserver_unix.go
go_net_fd_os_file =
go_net_newpollserver_file =
else # !LIBGO_IS_LINUX && !LIBGO_IS_RTEMS
if LIBGO_IS_NETBSD
go_net_fd_os_file = go/net/fd_bsd.go
go_net_newpollserver_file = go/net/newpollserver_unix.go
go_net_newpollserver_file =
else # !LIBGO_IS_NETBSD && !LIBGO_IS_LINUX && !LIBGO_IS_RTEMS
# By default use select with pipes. Most systems should have
# something better.
go_net_fd_os_file = go/net/fd_select.go
go_net_newpollserver_file = go/net/newpollserver_unix.go
go_net_newpollserver_file =
endif # !LIBGO_IS_NETBSD
endif # !LIBGO_IS_LINUX
endif # !LIBGO_IS_RTEMS
@ -759,6 +745,16 @@ else
go_net_cloexec_file = go/net/sys_cloexec.go
endif
if LIBGO_IS_LINUX
go_net_poll_file = go/net/fd_poll_runtime.go
else
if LIBGO_IS_DARWIN
go_net_poll_file = go/net/fd_poll_runtime.go
else
go_net_poll_file = go/net/fd_poll_unix.go
endif
endif
go_net_files = \
go/net/cgo_unix.go \
$(go_net_cgo_file) \
@ -786,10 +782,12 @@ go_net_files = \
go/net/net.go \
go/net/parse.go \
go/net/pipe.go \
$(go_net_poll_file) \
go/net/port.go \
go/net/port_unix.go \
$(go_net_sendfile_file) \
go/net/sock_posix.go \
go/net/sock_unix.go \
$(go_net_sock_file) \
go/net/sockopt_posix.go \
$(go_net_sockopt_file) \
@ -890,7 +888,8 @@ go_os_files = \
$(go_os_stat_file) \
go/os/str.go \
$(go_os_sys_file) \
go/os/types.go
go/os/types.go \
go/os/types_notwin.go
go_path_files = \
go/path/match.go \
@ -979,6 +978,7 @@ go_syslog_c_files = \
go/log/syslog/syslog_c.c
go_testing_files = \
go/testing/allocs.go \
go/testing/benchmark.go \
go/testing/example.go \
go/testing/testing.go
@ -1101,7 +1101,8 @@ go_crypto_rand_files = \
go/crypto/rand/rand_unix.go \
go/crypto/rand/util.go
go_crypto_rc4_files = \
go/crypto/rc4/rc4.go
go/crypto/rc4/rc4.go \
go/crypto/rc4/rc4_ref.go
go_crypto_rsa_files = \
go/crypto/rsa/pkcs1v15.go \
go/crypto/rsa/rsa.go
@ -1212,73 +1213,14 @@ go_encoding_xml_files = \
go/encoding/xml/typeinfo.go \
go/encoding/xml/xml.go
go_exp_cookiejar_files = \
go/exp/cookiejar/jar.go \
go/exp/cookiejar/storage.go
go_exp_ebnf_files = \
go/exp/ebnf/ebnf.go \
go/exp/ebnf/parser.go
go_exp_html_files = \
go/exp/html/const.go \
go/exp/html/doc.go \
go/exp/html/doctype.go \
go/exp/html/entity.go \
go/exp/html/escape.go \
go/exp/html/foreign.go \
go/exp/html/node.go \
go/exp/html/parse.go \
go/exp/html/render.go \
go/exp/html/token.go
go_exp_html_atom_files = \
go/exp/html/atom/atom.go \
go/exp/html/atom/table.go
go_exp_inotify_files = \
go/exp/inotify/inotify_linux.go
go_exp_locale_collate_files = \
go/exp/locale/collate/colelem.go \
go/exp/locale/collate/collate.go \
go/exp/locale/collate/colltab.go \
go/exp/locale/collate/contract.go \
go/exp/locale/collate/export.go \
go/exp/locale/collate/sort.go \
go/exp/locale/collate/table.go \
go/exp/locale/collate/tables.go \
go/exp/locale/collate/trie.go
go_exp_locale_collate_build_files = \
go/exp/locale/collate/build/builder.go \
go/exp/locale/collate/build/colelem.go \
go/exp/locale/collate/build/contract.go \
go/exp/locale/collate/build/order.go \
go/exp/locale/collate/build/table.go \
go/exp/locale/collate/build/trie.go
go_exp_norm_files = \
go/exp/norm/composition.go \
go/exp/norm/forminfo.go \
go/exp/norm/input.go \
go/exp/norm/iter.go \
go/exp/norm/normalize.go \
go/exp/norm/readwriter.go \
go/exp/norm/tables.go \
go/exp/norm/trie.go
go_exp_proxy_files = \
go/exp/proxy/direct.go \
go/exp/proxy/per_host.go \
go/exp/proxy/proxy.go \
go/exp/proxy/socks5.go
go_exp_ssa_files = \
go/exp/ssa/blockopt.go \
go/exp/ssa/doc.go \
go/exp/ssa/func.go \
go/exp/ssa/sanity.go \
go/exp/ssa/ssa.go \
go/exp/ssa/literal.go \
go/exp/ssa/print.go \
go/exp/ssa/util.go
go_exp_terminal_files = \
go/exp/terminal/terminal.go \
go/exp/terminal/util.go
go_exp_utf8string_files = \
go/exp/utf8string/string.go
go_go_ast_files = \
go/go/ast/ast.go \
@ -1317,24 +1259,6 @@ go_go_token_files = \
go/go/token/position.go \
go/go/token/serialize.go \
go/go/token/token.go
go_go_types_files = \
go/go/types/api.go \
go/go/types/builtins.go \
go/go/types/check.go \
go/go/types/const.go \
go/go/types/conversions.go \
go/go/types/errors.go \
go/go/types/exportdata.go \
go/go/types/expr.go \
go/go/types/gcimporter.go \
go/go/types/objects.go \
go/go/types/operand.go \
go/go/types/predicates.go \
go/go/types/resolve.go \
go/go/types/scope.go \
go/go/types/stmt.go \
go/go/types/types.go \
go/go/types/universe.go
go_hash_adler32_files = \
go/hash/adler32/adler32.go
@ -1458,6 +1382,9 @@ go_net_url_files = \
go_net_http_cgi_files = \
go/net/http/cgi/child.go \
go/net/http/cgi/host.go
go_net_http_cookiejar_files = \
go/net/http/cookiejar/jar.go \
go/net/http/cookiejar/punycode.go
go_net_http_fcgi_files = \
go/net/http/fcgi/child.go \
go/net/http/fcgi/fcgi.go
@ -1473,10 +1400,6 @@ go_net_http_httputil_files = \
go/net/http/httputil/reverseproxy.go
go_old_netchan_files = \
go/old/netchan/common.go \
go/old/netchan/export.go \
go/old/netchan/import.go
go_old_regexp_files = \
go/old/regexp/regexp.go
go_old_template_files = \
@ -1518,6 +1441,7 @@ go_net_rpc_jsonrpc_files = \
go/net/rpc/jsonrpc/server.go
go_runtime_debug_files = \
go/runtime/debug/garbage.go \
go/runtime/debug/stack.go
go_runtime_pprof_files = \
go/runtime/pprof/pprof.go
@ -1896,17 +1820,8 @@ libgo_go_objs = \
encoding/json.lo \
encoding/pem.lo \
encoding/xml.lo \
exp/cookiejar.lo \
exp/ebnf.lo \
exp/html.lo \
exp/html/atom.lo \
exp/locale/collate.lo \
exp/locale/collate/build.lo \
exp/norm.lo \
exp/proxy.lo \
exp/ssa.lo \
exp/terminal.lo \
exp/utf8string.lo \
html/template.lo \
go/ast.lo \
go/build.lo \
@ -1916,12 +1831,12 @@ libgo_go_objs = \
go/printer.lo \
go/scanner.lo \
go/token.lo \
go/types.lo \
hash/adler32.lo \
hash/crc32.lo \
hash/crc64.lo \
hash/fnv.lo \
net/http/cgi.lo \
net/http/cookiejar.lo \
net/http/fcgi.lo \
net/http/httptest.lo \
net/http/httputil.lo \
@ -1945,7 +1860,6 @@ libgo_go_objs = \
net/smtp.lo \
net/textproto.lo \
net/url.lo \
old/netchan.lo \
old/regexp.lo \
old/template.lo \
os/exec.lo \
@ -2730,69 +2644,6 @@ encoding/xml/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: encoding/xml/check
@go_include@ exp/cookiejar.lo.dep
exp/cookiejar.lo.dep: $(go_exp_cookiejar_files)
$(BUILDDEPS)
exp/cookiejar.lo: $(go_exp_cookiejar_files)
$(BUILDPACKAGE)
exp/cookiejar/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: exp/cookiejar/check
@go_include@ exp/ebnf.lo.dep
exp/ebnf.lo.dep: $(go_exp_ebnf_files)
$(BUILDDEPS)
exp/ebnf.lo: $(go_exp_ebnf_files)
$(BUILDPACKAGE)
exp/ebnf/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: exp/ebnf/check
@go_include@ exp/html.lo.dep
exp/html.lo.dep: $(go_exp_html_files)
$(BUILDDEPS)
exp/html.lo: $(go_exp_html_files)
$(BUILDPACKAGE)
exp/html/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: exp/html/check
@go_include@ exp/html/atom.lo.dep
exp/html/atom.lo.dep: $(go_exp_html_atom_files)
$(BUILDDEPS)
exp/html/atom.lo: $(go_exp_html_atom_files)
$(BUILDPACKAGE)
exp/html/atom/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: exp/html/atom/check
@go_include@ exp/locale/collate.lo.dep
exp/locale/collate.lo.dep: $(go_exp_locale_collate_files)
$(BUILDDEPS)
exp/locale/collate.lo: $(go_exp_locale_collate_files)
$(BUILDPACKAGE)
exp/locale/collate/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: exp/locale/collate/check
@go_include@ exp/locale/collate/build.lo.dep
exp/locale/collate/build.lo.dep: $(go_exp_locale_collate_build_files)
$(BUILDDEPS)
exp/locale/collate/build.lo: $(go_exp_locale_collate_build_files)
$(BUILDPACKAGE)
exp/locale/collate/build/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: exp/locale/collate/build/check
@go_include@ exp/norm.lo.dep
exp/norm.lo.dep: $(go_exp_norm_files)
$(BUILDDEPS)
exp/norm.lo: $(go_exp_norm_files)
$(BUILDPACKAGE)
exp/norm/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: exp/norm/check
@go_include@ exp/proxy.lo.dep
exp/proxy.lo.dep: $(go_exp_proxy_files)
$(BUILDDEPS)
@ -2802,15 +2653,6 @@ exp/proxy/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: exp/proxy/check
@go_include@ exp/ssa.lo.dep
exp/ssa.lo.dep: $(go_exp_ssa_files)
$(BUILDDEPS)
exp/ssa.lo: $(go_exp_ssa_files)
$(BUILDPACKAGE)
exp/ssa/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: exp/ssa/check
@go_include@ exp/terminal.lo.dep
exp/terminal.lo.dep: $(go_exp_terminal_files)
$(BUILDDEPS)
@ -2820,24 +2662,6 @@ exp/terminal/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: exp/terminal/check
@go_include@ exp/utf8string.lo.dep
exp/utf8string.lo.dep: $(go_exp_utf8string_files)
$(BUILDDEPS)
exp/utf8string.lo: $(go_exp_utf8string_files)
$(BUILDPACKAGE)
exp/utf8string/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: exp/utf8string/check
@go_include@ exp/inotify.lo.dep
exp/inotify.lo.dep: $(go_exp_inotify_files)
$(BUILDDEPS)
exp/inotify.lo: $(go_exp_inotify_files)
$(BUILDPACKAGE)
exp/inotify/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: exp/inotify/check
@go_include@ html/template.lo.dep
html/template.lo.dep: $(go_html_template_files)
$(BUILDDEPS)
@ -2928,15 +2752,6 @@ go/token/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: go/token/check
@go_include@ go/types.lo.dep
go/types.lo.dep: $(go_go_types_files)
$(BUILDDEPS)
go/types.lo: $(go_go_types_files)
$(BUILDPACKAGE)
go/types/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: go/types/check
@go_include@ hash/adler32.lo.dep
hash/adler32.lo.dep: $(go_hash_adler32_files)
$(BUILDDEPS)
@ -3147,6 +2962,15 @@ net/http/cgi/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: net/http/cgi/check
@go_include@ net/http/cookiejar.lo.dep
net/http/cookiejar.lo.dep: $(go_net_http_cookiejar_files)
$(BUILDDEPS)
net/http/cookiejar.lo: $(go_net_http_cookiejar_files)
$(BUILDPACKAGE)
net/http/cookiejar/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: net/http/cookiejar/check
@go_include@ net/http/fcgi.lo.dep
net/http/fcgi.lo.dep: $(go_net_http_fcgi_files)
$(BUILDDEPS)
@ -3192,15 +3016,6 @@ net/rpc/jsonrpc/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: net/rpc/jsonrpc/check
@go_include@ old/netchan.lo.dep
old/netchan.lo.dep: $(go_old_netchan_files)
$(BUILDDEPS)
old/netchan.lo: $(go_old_netchan_files)
$(BUILDPACKAGE)
old/netchan/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: old/netchan/check
@go_include@ old/regexp.lo.dep
old/regexp.lo.dep: $(go_old_regexp_files)
$(BUILDDEPS)
@ -3549,30 +3364,10 @@ encoding/pem.gox: encoding/pem.lo
encoding/xml.gox: encoding/xml.lo
$(BUILDGOX)
exp/cookiejar.gox: exp/cookiejar.lo
$(BUILDGOX)
exp/ebnf.gox: exp/ebnf.lo
$(BUILDGOX)
exp/html.gox: exp/html.lo
$(BUILDGOX)
exp/html/atom.gox: exp/html/atom.lo
$(BUILDGOX)
exp/inotify.gox: exp/inotify.lo
$(BUILDGOX)
exp/locale/collate.gox: exp/locale/collate.lo
$(BUILDGOX)
exp/locale/collate/build.gox: exp/locale/collate/build.lo
$(BUILDGOX)
exp/norm.gox: exp/norm.lo
$(BUILDGOX)
exp/proxy.gox: exp/proxy.lo
$(BUILDGOX)
exp/ssa.gox: exp/ssa.lo
$(BUILDGOX)
exp/terminal.gox: exp/terminal.lo
$(BUILDGOX)
exp/utf8string.gox: exp/utf8string.lo
$(BUILDGOX)
html/template.gox: html/template.lo
$(BUILDGOX)
@ -3593,8 +3388,6 @@ go/scanner.gox: go/scanner.lo
$(BUILDGOX)
go/token.gox: go/token.lo
$(BUILDGOX)
go/types.gox: go/types.lo
$(BUILDGOX)
hash/adler32.gox: hash/adler32.lo
$(BUILDGOX)
@ -3650,6 +3443,8 @@ net/url.gox: net/url.lo
net/http/cgi.gox: net/http/cgi.lo
$(BUILDGOX)
net/http/cookiejar.gox: net/http/cookiejar.lo
$(BUILDGOX)
net/http/fcgi.gox: net/http/fcgi.lo
$(BUILDGOX)
net/http/httptest.gox: net/http/httptest.lo
@ -3662,8 +3457,6 @@ net/http/pprof.gox: net/http/pprof.lo
net/rpc/jsonrpc.gox: net/rpc/jsonrpc.lo
$(BUILDGOX)
old/netchan.gox: old/netchan.lo
$(BUILDGOX)
old/regexp.gox: old/regexp.lo
$(BUILDGOX)
old/template.gox: old/template.lo
@ -3709,13 +3502,6 @@ unicode/utf16.gox: unicode/utf16.lo
unicode/utf8.gox: unicode/utf8.lo
$(BUILDGOX)
if LIBGO_IS_LINUX
# exp_inotify_check = exp/inotify/check
exp_inotify_check =
else
exp_inotify_check =
endif
TEST_PACKAGES = \
bufio/check \
bytes/check \
@ -3786,17 +3572,8 @@ TEST_PACKAGES = \
encoding/json/check \
encoding/pem/check \
encoding/xml/check \
exp/cookiejar/check \
exp/ebnf/check \
exp/html/check \
exp/html/atom/check \
$(exp_inotify_check) \
exp/locale/collate/check \
exp/locale/collate/build/check \
exp/norm/check \
exp/proxy/check \
exp/terminal/check \
exp/utf8string/check \
html/template/check \
go/ast/check \
$(go_build_check_omitted_since_it_calls_6g) \
@ -3806,7 +3583,6 @@ TEST_PACKAGES = \
go/printer/check \
go/scanner/check \
go/token/check \
go/types/check \
hash/adler32/check \
hash/crc32/check \
hash/crc64/check \
@ -3824,6 +3600,7 @@ TEST_PACKAGES = \
mime/multipart/check \
net/http/check \
net/http/cgi/check \
net/http/cookiejar/check \
net/http/fcgi/check \
net/http/httptest/check \
net/http/httputil/check \
@ -3833,7 +3610,6 @@ TEST_PACKAGES = \
net/textproto/check \
net/url/check \
net/rpc/jsonrpc/check \
old/netchan/check \
old/regexp/check \
old/template/check \
os/exec/check \

View File

@ -101,9 +101,6 @@ am__installdirs = "$(DESTDIR)$(toolexeclibdir)" \
"$(DESTDIR)$(toolexeclibgodebugdir)" \
"$(DESTDIR)$(toolexeclibgoencodingdir)" \
"$(DESTDIR)$(toolexeclibgoexpdir)" \
"$(DESTDIR)$(toolexeclibgoexphtmldir)" \
"$(DESTDIR)$(toolexeclibgoexplocaledir)" \
"$(DESTDIR)$(toolexeclibgoexplocalecollatedir)" \
"$(DESTDIR)$(toolexeclibgogodir)" \
"$(DESTDIR)$(toolexeclibgohashdir)" \
"$(DESTDIR)$(toolexeclibgohtmldir)" \
@ -153,22 +150,20 @@ am__DEPENDENCIES_2 = bufio.lo bytes.lo bytes/index.lo crypto.lo \
debug/pe.lo encoding/ascii85.lo encoding/asn1.lo \
encoding/base32.lo encoding/base64.lo encoding/binary.lo \
encoding/csv.lo encoding/gob.lo encoding/hex.lo \
encoding/json.lo encoding/pem.lo encoding/xml.lo \
exp/cookiejar.lo exp/ebnf.lo exp/html.lo exp/html/atom.lo \
exp/locale/collate.lo exp/locale/collate/build.lo exp/norm.lo \
exp/proxy.lo exp/ssa.lo exp/terminal.lo exp/utf8string.lo \
html/template.lo go/ast.lo go/build.lo go/doc.lo go/format.lo \
go/parser.lo go/printer.lo go/scanner.lo go/token.lo \
go/types.lo hash/adler32.lo hash/crc32.lo hash/crc64.lo \
hash/fnv.lo net/http/cgi.lo net/http/fcgi.lo \
net/http/httptest.lo net/http/httputil.lo net/http/pprof.lo \
image/color.lo image/draw.lo image/gif.lo image/jpeg.lo \
image/png.lo index/suffixarray.lo io/ioutil.lo log/syslog.lo \
encoding/json.lo encoding/pem.lo encoding/xml.lo exp/proxy.lo \
exp/terminal.lo html/template.lo go/ast.lo go/build.lo \
go/doc.lo go/format.lo go/parser.lo go/printer.lo \
go/scanner.lo go/token.lo hash/adler32.lo hash/crc32.lo \
hash/crc64.lo hash/fnv.lo net/http/cgi.lo \
net/http/cookiejar.lo net/http/fcgi.lo net/http/httptest.lo \
net/http/httputil.lo net/http/pprof.lo image/color.lo \
image/draw.lo image/gif.lo image/jpeg.lo image/png.lo \
index/suffixarray.lo io/ioutil.lo log/syslog.lo \
log/syslog/syslog_c.lo math/big.lo math/cmplx.lo math/rand.lo \
mime/multipart.lo net/http.lo net/mail.lo net/rpc.lo \
net/smtp.lo net/textproto.lo net/url.lo old/netchan.lo \
old/regexp.lo old/template.lo os/exec.lo $(am__DEPENDENCIES_1) \
os/signal.lo os/user.lo path/filepath.lo regexp/syntax.lo \
net/smtp.lo net/textproto.lo net/url.lo old/regexp.lo \
old/template.lo os/exec.lo $(am__DEPENDENCIES_1) os/signal.lo \
os/user.lo path/filepath.lo regexp/syntax.lo \
net/rpc/jsonrpc.lo runtime/debug.lo runtime/pprof.lo \
sync/atomic.lo sync/atomic_c.lo text/scanner.lo \
text/tabwriter.lo text/template.lo text/template/parse.lo \
@ -183,16 +178,22 @@ libgo_la_DEPENDENCIES = $(am__DEPENDENCIES_2) \
@LIBGO_IS_LINUX_TRUE@am__objects_1 = lock_futex.lo thread-linux.lo
@HAVE_SYS_MMAN_H_FALSE@am__objects_2 = mem_posix_memalign.lo
@HAVE_SYS_MMAN_H_TRUE@am__objects_2 = mem.lo
@LIBGO_IS_RTEMS_TRUE@am__objects_3 = rtems-task-variable-add.lo
@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@am__objects_4 = getncpu-none.lo
@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_SOLARIS_FALSE@am__objects_4 = getncpu-bsd.lo
@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@am__objects_4 = getncpu-bsd.lo
@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@am__objects_4 = getncpu-solaris.lo
@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_IRIX_TRUE@@LIBGO_IS_LINUX_FALSE@am__objects_4 = getncpu-irix.lo
@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_LINUX_FALSE@am__objects_4 = \
@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_LINUX_FALSE@am__objects_3 = \
@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_LINUX_FALSE@ netpoll_stub.lo
@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_LINUX_FALSE@am__objects_3 = \
@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_LINUX_FALSE@ netpoll.lo \
@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_LINUX_FALSE@ netpoll_kqueue.lo
@LIBGO_IS_LINUX_TRUE@am__objects_3 = netpoll.lo netpoll_epoll.lo
@LIBGO_IS_RTEMS_TRUE@am__objects_4 = rtems-task-variable-add.lo
@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@am__objects_5 = getncpu-none.lo
@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_SOLARIS_FALSE@am__objects_5 = getncpu-bsd.lo
@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@am__objects_5 = getncpu-bsd.lo
@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@am__objects_5 = getncpu-solaris.lo
@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_IRIX_TRUE@@LIBGO_IS_LINUX_FALSE@am__objects_5 = getncpu-irix.lo
@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_LINUX_FALSE@am__objects_5 = \
@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_LINUX_FALSE@ getncpu-bsd.lo
@LIBGO_IS_LINUX_TRUE@am__objects_4 = getncpu-linux.lo
am__objects_5 = go-append.lo go-assert.lo go-assert-interface.lo \
@LIBGO_IS_LINUX_TRUE@am__objects_5 = getncpu-linux.lo
am__objects_6 = go-append.lo go-assert.lo go-assert-interface.lo \
go-byte-array-to-string.lo go-breakpoint.lo go-caller.lo \
go-callers.lo go-can-convert-interface.lo go-cgo.lo \
go-check-interface.lo go-construct-map.lo \
@ -215,12 +216,12 @@ am__objects_5 = go-append.lo go-assert.lo go-assert-interface.lo \
go-unsafe-new.lo go-unsafe-newarray.lo go-unsafe-pointer.lo \
go-unwind.lo chan.lo cpuprof.lo env_posix.lo lfstack.lo \
$(am__objects_1) mcache.lo mcentral.lo $(am__objects_2) \
mfinal.lo mfixalloc.lo mgc0.lo mheap.lo msize.lo panic.lo \
parfor.lo print.lo proc.lo runtime.lo signal_unix.lo thread.lo \
yield.lo $(am__objects_3) iface.lo malloc.lo map.lo mprof.lo \
reflect.lo runtime1.lo sema.lo sigqueue.lo string.lo time.lo \
$(am__objects_4)
am_libgo_la_OBJECTS = $(am__objects_5)
mfinal.lo mfixalloc.lo mgc0.lo mheap.lo msize.lo \
$(am__objects_3) panic.lo parfor.lo print.lo proc.lo \
runtime.lo signal_unix.lo thread.lo yield.lo $(am__objects_4) \
iface.lo malloc.lo map.lo mprof.lo reflect.lo runtime1.lo \
sema.lo sigqueue.lo string.lo time.lo $(am__objects_5)
am_libgo_la_OBJECTS = $(am__objects_6)
libgo_la_OBJECTS = $(am_libgo_la_OBJECTS)
libgo_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(libgo_la_LDFLAGS) \
@ -257,9 +258,7 @@ DATA = $(toolexeclibgo_DATA) $(toolexeclibgoarchive_DATA) \
$(toolexeclibgocrypto_DATA) $(toolexeclibgocryptox509_DATA) \
$(toolexeclibgodatabase_DATA) $(toolexeclibgodatabasesql_DATA) \
$(toolexeclibgodebug_DATA) $(toolexeclibgoencoding_DATA) \
$(toolexeclibgoexp_DATA) $(toolexeclibgoexphtml_DATA) \
$(toolexeclibgoexplocale_DATA) \
$(toolexeclibgoexplocalecollate_DATA) $(toolexeclibgogo_DATA) \
$(toolexeclibgoexp_DATA) $(toolexeclibgogo_DATA) \
$(toolexeclibgohash_DATA) $(toolexeclibgohtml_DATA) \
$(toolexeclibgoimage_DATA) $(toolexeclibgoindex_DATA) \
$(toolexeclibgoio_DATA) $(toolexeclibgolog_DATA) \
@ -606,33 +605,10 @@ toolexeclibgoencoding_DATA = \
encoding/pem.gox \
encoding/xml.gox
@LIBGO_IS_LINUX_FALSE@exp_inotify_gox =
# exp_inotify_gox = exp/inotify.gox
@LIBGO_IS_LINUX_TRUE@exp_inotify_gox =
toolexeclibgoexpdir = $(toolexeclibgodir)/exp
toolexeclibgoexp_DATA = \
exp/cookiejar.gox \
exp/ebnf.gox \
exp/html.gox \
$(exp_inotify_gox) \
exp/norm.gox \
exp/proxy.gox \
exp/ssa.gox \
exp/terminal.gox \
exp/utf8string.gox
toolexeclibgoexphtmldir = $(toolexeclibgoexpdir)/html
toolexeclibgoexphtml_DATA = \
exp/html/atom.gox
toolexeclibgoexplocaledir = $(toolexeclibgoexpdir)/locale
toolexeclibgoexplocale_DATA = \
exp/locale/collate.gox
toolexeclibgoexplocalecollatedir = $(toolexeclibgoexplocaledir)/collate
toolexeclibgoexplocalecollate_DATA = \
exp/locale/collate/build.gox
exp/terminal.gox
toolexeclibgogodir = $(toolexeclibgodir)/go
toolexeclibgogo_DATA = \
@ -643,8 +619,7 @@ toolexeclibgogo_DATA = \
go/parser.gox \
go/printer.gox \
go/scanner.gox \
go/token.gox \
go/types.gox
go/token.gox
toolexeclibgohashdir = $(toolexeclibgodir)/hash
toolexeclibgohash_DATA = \
@ -699,6 +674,7 @@ toolexeclibgonet_DATA = \
toolexeclibgonethttpdir = $(toolexeclibgonetdir)/http
toolexeclibgonethttp_DATA = \
net/http/cgi.gox \
net/http/cookiejar.gox \
net/http/fcgi.gox \
net/http/httptest.gox \
net/http/httputil.gox \
@ -710,7 +686,6 @@ toolexeclibgonetrpc_DATA = \
toolexeclibgoolddir = $(toolexeclibgodir)/old
toolexeclibgoold_DATA = \
old/netchan.gox \
old/regexp.gox \
old/template.gox
@ -770,6 +745,9 @@ toolexeclibgounicode_DATA = \
@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_IRIX_TRUE@@LIBGO_IS_LINUX_FALSE@runtime_getncpu_file = runtime/getncpu-irix.c
@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_LINUX_FALSE@runtime_getncpu_file = runtime/getncpu-bsd.c
@LIBGO_IS_LINUX_TRUE@runtime_getncpu_file = runtime/getncpu-linux.c
@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_LINUX_FALSE@runtime_netpoll_files = runtime/netpoll_stub.c
@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_LINUX_FALSE@runtime_netpoll_files = netpoll.c runtime/netpoll_kqueue.c
@LIBGO_IS_LINUX_TRUE@runtime_netpoll_files = netpoll.c runtime/netpoll_epoll.c
runtime_files = \
runtime/go-append.c \
runtime/go-assert.c \
@ -848,6 +826,7 @@ runtime_files = \
runtime/mgc0.c \
runtime/mheap.c \
runtime/msize.c \
$(runtime_netpoll_files) \
runtime/panic.c \
runtime/parfor.c \
runtime/print.c \
@ -870,7 +849,8 @@ runtime_files = \
$(runtime_getncpu_file)
go_bufio_files = \
go/bufio/bufio.go
go/bufio/bufio.go \
go/bufio/scan.go
go_bytes_files = \
go/bytes/buffer.go \
@ -975,11 +955,11 @@ go_mime_files = \
# something better.
@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_RTEMS_FALSE@go_net_fd_os_file = go/net/fd_select.go
@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_RTEMS_FALSE@go_net_fd_os_file = go/net/fd_bsd.go
@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_RTEMS_FALSE@go_net_fd_os_file = go/net/fd_linux.go
@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_RTEMS_FALSE@go_net_fd_os_file =
@LIBGO_IS_RTEMS_TRUE@go_net_fd_os_file = go/net/fd_select.go
@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_RTEMS_FALSE@go_net_newpollserver_file = go/net/newpollserver_unix.go
@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_RTEMS_FALSE@go_net_newpollserver_file = go/net/newpollserver_unix.go
@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_RTEMS_FALSE@go_net_newpollserver_file = go/net/newpollserver_unix.go
@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_RTEMS_FALSE@go_net_newpollserver_file =
@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_RTEMS_FALSE@go_net_newpollserver_file =
@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_RTEMS_FALSE@go_net_newpollserver_file =
@LIBGO_IS_RTEMS_TRUE@go_net_newpollserver_file = go/net/newpollserver_rtems.go
@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_cgo_file = go/net/cgo_bsd.go
@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_SOLARIS_FALSE@go_net_cgo_file = go/net/cgo_netbsd.go
@ -1013,6 +993,9 @@ go_mime_files = \
@LIBGO_IS_LINUX_TRUE@go_net_interface_file = go/net/interface_linux.go
@LIBGO_IS_LINUX_FALSE@go_net_cloexec_file = go/net/sys_cloexec.go
@LIBGO_IS_LINUX_TRUE@go_net_cloexec_file = go/net/sock_cloexec.go
@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_LINUX_FALSE@go_net_poll_file = go/net/fd_poll_unix.go
@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_LINUX_FALSE@go_net_poll_file = go/net/fd_poll_runtime.go
@LIBGO_IS_LINUX_TRUE@go_net_poll_file = go/net/fd_poll_runtime.go
go_net_files = \
go/net/cgo_unix.go \
$(go_net_cgo_file) \
@ -1040,10 +1023,12 @@ go_net_files = \
go/net/net.go \
go/net/parse.go \
go/net/pipe.go \
$(go_net_poll_file) \
go/net/port.go \
go/net/port_unix.go \
$(go_net_sendfile_file) \
go/net/sock_posix.go \
go/net/sock_unix.go \
$(go_net_sock_file) \
go/net/sockopt_posix.go \
$(go_net_sockopt_file) \
@ -1095,7 +1080,8 @@ go_os_files = \
$(go_os_stat_file) \
go/os/str.go \
$(go_os_sys_file) \
go/os/types.go
go/os/types.go \
go/os/types_notwin.go
go_path_files = \
go/path/match.go \
@ -1167,6 +1153,7 @@ go_syslog_c_files = \
go/log/syslog/syslog_c.c
go_testing_files = \
go/testing/allocs.go \
go/testing/benchmark.go \
go/testing/example.go \
go/testing/testing.go
@ -1285,7 +1272,8 @@ go_crypto_rand_files = \
go/crypto/rand/util.go
go_crypto_rc4_files = \
go/crypto/rc4/rc4.go
go/crypto/rc4/rc4.go \
go/crypto/rc4/rc4_ref.go
go_crypto_rsa_files = \
go/crypto/rsa/pkcs1v15.go \
@ -1417,85 +1405,16 @@ go_encoding_xml_files = \
go/encoding/xml/typeinfo.go \
go/encoding/xml/xml.go
go_exp_cookiejar_files = \
go/exp/cookiejar/jar.go \
go/exp/cookiejar/storage.go
go_exp_ebnf_files = \
go/exp/ebnf/ebnf.go \
go/exp/ebnf/parser.go
go_exp_html_files = \
go/exp/html/const.go \
go/exp/html/doc.go \
go/exp/html/doctype.go \
go/exp/html/entity.go \
go/exp/html/escape.go \
go/exp/html/foreign.go \
go/exp/html/node.go \
go/exp/html/parse.go \
go/exp/html/render.go \
go/exp/html/token.go
go_exp_html_atom_files = \
go/exp/html/atom/atom.go \
go/exp/html/atom/table.go
go_exp_inotify_files = \
go/exp/inotify/inotify_linux.go
go_exp_locale_collate_files = \
go/exp/locale/collate/colelem.go \
go/exp/locale/collate/collate.go \
go/exp/locale/collate/colltab.go \
go/exp/locale/collate/contract.go \
go/exp/locale/collate/export.go \
go/exp/locale/collate/sort.go \
go/exp/locale/collate/table.go \
go/exp/locale/collate/tables.go \
go/exp/locale/collate/trie.go
go_exp_locale_collate_build_files = \
go/exp/locale/collate/build/builder.go \
go/exp/locale/collate/build/colelem.go \
go/exp/locale/collate/build/contract.go \
go/exp/locale/collate/build/order.go \
go/exp/locale/collate/build/table.go \
go/exp/locale/collate/build/trie.go
go_exp_norm_files = \
go/exp/norm/composition.go \
go/exp/norm/forminfo.go \
go/exp/norm/input.go \
go/exp/norm/iter.go \
go/exp/norm/normalize.go \
go/exp/norm/readwriter.go \
go/exp/norm/tables.go \
go/exp/norm/trie.go
go_exp_proxy_files = \
go/exp/proxy/direct.go \
go/exp/proxy/per_host.go \
go/exp/proxy/proxy.go \
go/exp/proxy/socks5.go
go_exp_ssa_files = \
go/exp/ssa/blockopt.go \
go/exp/ssa/doc.go \
go/exp/ssa/func.go \
go/exp/ssa/sanity.go \
go/exp/ssa/ssa.go \
go/exp/ssa/literal.go \
go/exp/ssa/print.go \
go/exp/ssa/util.go
go_exp_terminal_files = \
go/exp/terminal/terminal.go \
go/exp/terminal/util.go
go_exp_utf8string_files = \
go/exp/utf8string/string.go
go_go_ast_files = \
go/go/ast/ast.go \
go/go/ast/commentmap.go \
@ -1541,25 +1460,6 @@ go_go_token_files = \
go/go/token/serialize.go \
go/go/token/token.go
go_go_types_files = \
go/go/types/api.go \
go/go/types/builtins.go \
go/go/types/check.go \
go/go/types/const.go \
go/go/types/conversions.go \
go/go/types/errors.go \
go/go/types/exportdata.go \
go/go/types/expr.go \
go/go/types/gcimporter.go \
go/go/types/objects.go \
go/go/types/operand.go \
go/go/types/predicates.go \
go/go/types/resolve.go \
go/go/types/scope.go \
go/go/types/stmt.go \
go/go/types/types.go \
go/go/types/universe.go
go_hash_adler32_files = \
go/hash/adler32/adler32.go
@ -1692,6 +1592,10 @@ go_net_http_cgi_files = \
go/net/http/cgi/child.go \
go/net/http/cgi/host.go
go_net_http_cookiejar_files = \
go/net/http/cookiejar/jar.go \
go/net/http/cookiejar/punycode.go
go_net_http_fcgi_files = \
go/net/http/fcgi/child.go \
go/net/http/fcgi/fcgi.go
@ -1709,11 +1613,6 @@ go_net_http_httputil_files = \
go/net/http/httputil/persist.go \
go/net/http/httputil/reverseproxy.go
go_old_netchan_files = \
go/old/netchan/common.go \
go/old/netchan/export.go \
go/old/netchan/import.go
go_old_regexp_files = \
go/old/regexp/regexp.go
@ -1756,6 +1655,7 @@ go_net_rpc_jsonrpc_files = \
go/net/rpc/jsonrpc/server.go
go_runtime_debug_files = \
go/runtime/debug/garbage.go \
go/runtime/debug/stack.go
go_runtime_pprof_files = \
@ -2005,17 +1905,8 @@ libgo_go_objs = \
encoding/json.lo \
encoding/pem.lo \
encoding/xml.lo \
exp/cookiejar.lo \
exp/ebnf.lo \
exp/html.lo \
exp/html/atom.lo \
exp/locale/collate.lo \
exp/locale/collate/build.lo \
exp/norm.lo \
exp/proxy.lo \
exp/ssa.lo \
exp/terminal.lo \
exp/utf8string.lo \
html/template.lo \
go/ast.lo \
go/build.lo \
@ -2025,12 +1916,12 @@ libgo_go_objs = \
go/printer.lo \
go/scanner.lo \
go/token.lo \
go/types.lo \
hash/adler32.lo \
hash/crc32.lo \
hash/crc64.lo \
hash/fnv.lo \
net/http/cgi.lo \
net/http/cookiejar.lo \
net/http/fcgi.lo \
net/http/httptest.lo \
net/http/httputil.lo \
@ -2054,7 +1945,6 @@ libgo_go_objs = \
net/smtp.lo \
net/textproto.lo \
net/url.lo \
old/netchan.lo \
old/regexp.lo \
old/template.lo \
os/exec.lo \
@ -2185,10 +2075,6 @@ BUILDGOX = \
f=`echo $< | sed -e 's/.lo$$/.o/'`; \
$(OBJCOPY) -j .go_export $$f $@.tmp && mv -f $@.tmp $@
@LIBGO_IS_LINUX_FALSE@exp_inotify_check =
# exp_inotify_check = exp/inotify/check
@LIBGO_IS_LINUX_TRUE@exp_inotify_check =
TEST_PACKAGES = \
bufio/check \
bytes/check \
@ -2259,17 +2145,8 @@ TEST_PACKAGES = \
encoding/json/check \
encoding/pem/check \
encoding/xml/check \
exp/cookiejar/check \
exp/ebnf/check \
exp/html/check \
exp/html/atom/check \
$(exp_inotify_check) \
exp/locale/collate/check \
exp/locale/collate/build/check \
exp/norm/check \
exp/proxy/check \
exp/terminal/check \
exp/utf8string/check \
html/template/check \
go/ast/check \
$(go_build_check_omitted_since_it_calls_6g) \
@ -2279,7 +2156,6 @@ TEST_PACKAGES = \
go/printer/check \
go/scanner/check \
go/token/check \
go/types/check \
hash/adler32/check \
hash/crc32/check \
hash/crc64/check \
@ -2297,6 +2173,7 @@ TEST_PACKAGES = \
mime/multipart/check \
net/http/check \
net/http/cgi/check \
net/http/cookiejar/check \
net/http/fcgi/check \
net/http/httptest/check \
net/http/httputil/check \
@ -2306,7 +2183,6 @@ TEST_PACKAGES = \
net/textproto/check \
net/url/check \
net/rpc/jsonrpc/check \
old/netchan/check \
old/regexp/check \
old/template/check \
os/exec/check \
@ -2547,6 +2423,10 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mheap.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mprof.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/msize.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netpoll.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netpoll_epoll.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netpoll_kqueue.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netpoll_stub.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/panic.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parfor.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/print.Plo@am__quote@
@ -3167,6 +3047,27 @@ msize.lo: runtime/msize.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o msize.lo `test -f 'runtime/msize.c' || echo '$(srcdir)/'`runtime/msize.c
netpoll_stub.lo: runtime/netpoll_stub.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT netpoll_stub.lo -MD -MP -MF $(DEPDIR)/netpoll_stub.Tpo -c -o netpoll_stub.lo `test -f 'runtime/netpoll_stub.c' || echo '$(srcdir)/'`runtime/netpoll_stub.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/netpoll_stub.Tpo $(DEPDIR)/netpoll_stub.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/netpoll_stub.c' object='netpoll_stub.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o netpoll_stub.lo `test -f 'runtime/netpoll_stub.c' || echo '$(srcdir)/'`runtime/netpoll_stub.c
netpoll_kqueue.lo: runtime/netpoll_kqueue.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT netpoll_kqueue.lo -MD -MP -MF $(DEPDIR)/netpoll_kqueue.Tpo -c -o netpoll_kqueue.lo `test -f 'runtime/netpoll_kqueue.c' || echo '$(srcdir)/'`runtime/netpoll_kqueue.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/netpoll_kqueue.Tpo $(DEPDIR)/netpoll_kqueue.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/netpoll_kqueue.c' object='netpoll_kqueue.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o netpoll_kqueue.lo `test -f 'runtime/netpoll_kqueue.c' || echo '$(srcdir)/'`runtime/netpoll_kqueue.c
netpoll_epoll.lo: runtime/netpoll_epoll.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT netpoll_epoll.lo -MD -MP -MF $(DEPDIR)/netpoll_epoll.Tpo -c -o netpoll_epoll.lo `test -f 'runtime/netpoll_epoll.c' || echo '$(srcdir)/'`runtime/netpoll_epoll.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/netpoll_epoll.Tpo $(DEPDIR)/netpoll_epoll.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/netpoll_epoll.c' object='netpoll_epoll.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o netpoll_epoll.lo `test -f 'runtime/netpoll_epoll.c' || echo '$(srcdir)/'`runtime/netpoll_epoll.c
panic.lo: runtime/panic.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT panic.lo -MD -MP -MF $(DEPDIR)/panic.Tpo -c -o panic.lo `test -f 'runtime/panic.c' || echo '$(srcdir)/'`runtime/panic.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/panic.Tpo $(DEPDIR)/panic.Plo
@ -3510,66 +3411,6 @@ uninstall-toolexeclibgoexpDATA:
test -n "$$files" || exit 0; \
echo " ( cd '$(DESTDIR)$(toolexeclibgoexpdir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(toolexeclibgoexpdir)" && rm -f $$files
install-toolexeclibgoexphtmlDATA: $(toolexeclibgoexphtml_DATA)
@$(NORMAL_INSTALL)
test -z "$(toolexeclibgoexphtmldir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgoexphtmldir)"
@list='$(toolexeclibgoexphtml_DATA)'; test -n "$(toolexeclibgoexphtmldir)" || list=; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
done | $(am__base_list) | \
while read files; do \
echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(toolexeclibgoexphtmldir)'"; \
$(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgoexphtmldir)" || exit $$?; \
done
uninstall-toolexeclibgoexphtmlDATA:
@$(NORMAL_UNINSTALL)
@list='$(toolexeclibgoexphtml_DATA)'; test -n "$(toolexeclibgoexphtmldir)" || list=; \
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
test -n "$$files" || exit 0; \
echo " ( cd '$(DESTDIR)$(toolexeclibgoexphtmldir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(toolexeclibgoexphtmldir)" && rm -f $$files
install-toolexeclibgoexplocaleDATA: $(toolexeclibgoexplocale_DATA)
@$(NORMAL_INSTALL)
test -z "$(toolexeclibgoexplocaledir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgoexplocaledir)"
@list='$(toolexeclibgoexplocale_DATA)'; test -n "$(toolexeclibgoexplocaledir)" || list=; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
done | $(am__base_list) | \
while read files; do \
echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(toolexeclibgoexplocaledir)'"; \
$(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgoexplocaledir)" || exit $$?; \
done
uninstall-toolexeclibgoexplocaleDATA:
@$(NORMAL_UNINSTALL)
@list='$(toolexeclibgoexplocale_DATA)'; test -n "$(toolexeclibgoexplocaledir)" || list=; \
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
test -n "$$files" || exit 0; \
echo " ( cd '$(DESTDIR)$(toolexeclibgoexplocaledir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(toolexeclibgoexplocaledir)" && rm -f $$files
install-toolexeclibgoexplocalecollateDATA: $(toolexeclibgoexplocalecollate_DATA)
@$(NORMAL_INSTALL)
test -z "$(toolexeclibgoexplocalecollatedir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgoexplocalecollatedir)"
@list='$(toolexeclibgoexplocalecollate_DATA)'; test -n "$(toolexeclibgoexplocalecollatedir)" || list=; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
done | $(am__base_list) | \
while read files; do \
echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(toolexeclibgoexplocalecollatedir)'"; \
$(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgoexplocalecollatedir)" || exit $$?; \
done
uninstall-toolexeclibgoexplocalecollateDATA:
@$(NORMAL_UNINSTALL)
@list='$(toolexeclibgoexplocalecollate_DATA)'; test -n "$(toolexeclibgoexplocalecollatedir)" || list=; \
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
test -n "$$files" || exit 0; \
echo " ( cd '$(DESTDIR)$(toolexeclibgoexplocalecollatedir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(toolexeclibgoexplocalecollatedir)" && rm -f $$files
install-toolexeclibgogoDATA: $(toolexeclibgogo_DATA)
@$(NORMAL_INSTALL)
test -z "$(toolexeclibgogodir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgogodir)"
@ -4151,7 +3992,7 @@ all-am: Makefile $(LIBRARIES) $(LTLIBRARIES) all-multi $(DATA) \
config.h
installdirs: installdirs-recursive
installdirs-am:
for dir in "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibgodir)" "$(DESTDIR)$(toolexeclibgoarchivedir)" "$(DESTDIR)$(toolexeclibgocompressdir)" "$(DESTDIR)$(toolexeclibgocontainerdir)" "$(DESTDIR)$(toolexeclibgocryptodir)" "$(DESTDIR)$(toolexeclibgocryptox509dir)" "$(DESTDIR)$(toolexeclibgodatabasedir)" "$(DESTDIR)$(toolexeclibgodatabasesqldir)" "$(DESTDIR)$(toolexeclibgodebugdir)" "$(DESTDIR)$(toolexeclibgoencodingdir)" "$(DESTDIR)$(toolexeclibgoexpdir)" "$(DESTDIR)$(toolexeclibgoexphtmldir)" "$(DESTDIR)$(toolexeclibgoexplocaledir)" "$(DESTDIR)$(toolexeclibgoexplocalecollatedir)" "$(DESTDIR)$(toolexeclibgogodir)" "$(DESTDIR)$(toolexeclibgohashdir)" "$(DESTDIR)$(toolexeclibgohtmldir)" "$(DESTDIR)$(toolexeclibgoimagedir)" "$(DESTDIR)$(toolexeclibgoindexdir)" "$(DESTDIR)$(toolexeclibgoiodir)" "$(DESTDIR)$(toolexeclibgologdir)" "$(DESTDIR)$(toolexeclibgomathdir)" "$(DESTDIR)$(toolexeclibgomimedir)" "$(DESTDIR)$(toolexeclibgonetdir)" "$(DESTDIR)$(toolexeclibgonethttpdir)" "$(DESTDIR)$(toolexeclibgonetrpcdir)" "$(DESTDIR)$(toolexeclibgoolddir)" "$(DESTDIR)$(toolexeclibgoosdir)" "$(DESTDIR)$(toolexeclibgopathdir)" "$(DESTDIR)$(toolexeclibgoregexpdir)" "$(DESTDIR)$(toolexeclibgoruntimedir)" "$(DESTDIR)$(toolexeclibgosyncdir)" "$(DESTDIR)$(toolexeclibgotestingdir)" "$(DESTDIR)$(toolexeclibgotextdir)" "$(DESTDIR)$(toolexeclibgotexttemplatedir)" "$(DESTDIR)$(toolexeclibgounicodedir)"; do \
for dir in "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibgodir)" "$(DESTDIR)$(toolexeclibgoarchivedir)" "$(DESTDIR)$(toolexeclibgocompressdir)" "$(DESTDIR)$(toolexeclibgocontainerdir)" "$(DESTDIR)$(toolexeclibgocryptodir)" "$(DESTDIR)$(toolexeclibgocryptox509dir)" "$(DESTDIR)$(toolexeclibgodatabasedir)" "$(DESTDIR)$(toolexeclibgodatabasesqldir)" "$(DESTDIR)$(toolexeclibgodebugdir)" "$(DESTDIR)$(toolexeclibgoencodingdir)" "$(DESTDIR)$(toolexeclibgoexpdir)" "$(DESTDIR)$(toolexeclibgogodir)" "$(DESTDIR)$(toolexeclibgohashdir)" "$(DESTDIR)$(toolexeclibgohtmldir)" "$(DESTDIR)$(toolexeclibgoimagedir)" "$(DESTDIR)$(toolexeclibgoindexdir)" "$(DESTDIR)$(toolexeclibgoiodir)" "$(DESTDIR)$(toolexeclibgologdir)" "$(DESTDIR)$(toolexeclibgomathdir)" "$(DESTDIR)$(toolexeclibgomimedir)" "$(DESTDIR)$(toolexeclibgonetdir)" "$(DESTDIR)$(toolexeclibgonethttpdir)" "$(DESTDIR)$(toolexeclibgonetrpcdir)" "$(DESTDIR)$(toolexeclibgoolddir)" "$(DESTDIR)$(toolexeclibgoosdir)" "$(DESTDIR)$(toolexeclibgopathdir)" "$(DESTDIR)$(toolexeclibgoregexpdir)" "$(DESTDIR)$(toolexeclibgoruntimedir)" "$(DESTDIR)$(toolexeclibgosyncdir)" "$(DESTDIR)$(toolexeclibgotestingdir)" "$(DESTDIR)$(toolexeclibgotextdir)" "$(DESTDIR)$(toolexeclibgotexttemplatedir)" "$(DESTDIR)$(toolexeclibgounicodedir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-recursive
@ -4222,9 +4063,6 @@ install-exec-am: install-multi install-toolexeclibLIBRARIES \
install-toolexeclibgodatabasesqlDATA \
install-toolexeclibgodebugDATA \
install-toolexeclibgoencodingDATA install-toolexeclibgoexpDATA \
install-toolexeclibgoexphtmlDATA \
install-toolexeclibgoexplocaleDATA \
install-toolexeclibgoexplocalecollateDATA \
install-toolexeclibgogoDATA install-toolexeclibgohashDATA \
install-toolexeclibgohtmlDATA install-toolexeclibgoimageDATA \
install-toolexeclibgoindexDATA install-toolexeclibgoioDATA \
@ -4290,11 +4128,8 @@ uninstall-am: uninstall-toolexeclibLIBRARIES \
uninstall-toolexeclibgodatabasesqlDATA \
uninstall-toolexeclibgodebugDATA \
uninstall-toolexeclibgoencodingDATA \
uninstall-toolexeclibgoexpDATA \
uninstall-toolexeclibgoexphtmlDATA \
uninstall-toolexeclibgoexplocaleDATA \
uninstall-toolexeclibgoexplocalecollateDATA \
uninstall-toolexeclibgogoDATA uninstall-toolexeclibgohashDATA \
uninstall-toolexeclibgoexpDATA uninstall-toolexeclibgogoDATA \
uninstall-toolexeclibgohashDATA \
uninstall-toolexeclibgohtmlDATA \
uninstall-toolexeclibgoimageDATA \
uninstall-toolexeclibgoindexDATA uninstall-toolexeclibgoioDATA \
@ -4339,9 +4174,6 @@ uninstall-am: uninstall-toolexeclibLIBRARIES \
install-toolexeclibgodatabasesqlDATA \
install-toolexeclibgodebugDATA \
install-toolexeclibgoencodingDATA install-toolexeclibgoexpDATA \
install-toolexeclibgoexphtmlDATA \
install-toolexeclibgoexplocaleDATA \
install-toolexeclibgoexplocalecollateDATA \
install-toolexeclibgogoDATA install-toolexeclibgohashDATA \
install-toolexeclibgohtmlDATA install-toolexeclibgoimageDATA \
install-toolexeclibgoindexDATA install-toolexeclibgoioDATA \
@ -4371,11 +4203,8 @@ uninstall-am: uninstall-toolexeclibLIBRARIES \
uninstall-toolexeclibgodatabasesqlDATA \
uninstall-toolexeclibgodebugDATA \
uninstall-toolexeclibgoencodingDATA \
uninstall-toolexeclibgoexpDATA \
uninstall-toolexeclibgoexphtmlDATA \
uninstall-toolexeclibgoexplocaleDATA \
uninstall-toolexeclibgoexplocalecollateDATA \
uninstall-toolexeclibgogoDATA uninstall-toolexeclibgohashDATA \
uninstall-toolexeclibgoexpDATA uninstall-toolexeclibgogoDATA \
uninstall-toolexeclibgohashDATA \
uninstall-toolexeclibgohtmlDATA \
uninstall-toolexeclibgoimageDATA \
uninstall-toolexeclibgoindexDATA uninstall-toolexeclibgoioDATA \
@ -4408,6 +4237,10 @@ mprof.c: $(srcdir)/runtime/mprof.goc goc2c
./goc2c $< > $@.tmp
mv -f $@.tmp $@
netpoll.c: $(srcdir)/runtime/netpoll.goc goc2c
./goc2c $< > $@.tmp
mv -f $@.tmp $@
reflect.c: $(srcdir)/runtime/reflect.goc goc2c
./goc2c $< > $@.tmp
mv -f $@.tmp $@
@ -5163,69 +4996,6 @@ encoding/xml/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: encoding/xml/check
@go_include@ exp/cookiejar.lo.dep
exp/cookiejar.lo.dep: $(go_exp_cookiejar_files)
$(BUILDDEPS)
exp/cookiejar.lo: $(go_exp_cookiejar_files)
$(BUILDPACKAGE)
exp/cookiejar/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: exp/cookiejar/check
@go_include@ exp/ebnf.lo.dep
exp/ebnf.lo.dep: $(go_exp_ebnf_files)
$(BUILDDEPS)
exp/ebnf.lo: $(go_exp_ebnf_files)
$(BUILDPACKAGE)
exp/ebnf/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: exp/ebnf/check
@go_include@ exp/html.lo.dep
exp/html.lo.dep: $(go_exp_html_files)
$(BUILDDEPS)
exp/html.lo: $(go_exp_html_files)
$(BUILDPACKAGE)
exp/html/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: exp/html/check
@go_include@ exp/html/atom.lo.dep
exp/html/atom.lo.dep: $(go_exp_html_atom_files)
$(BUILDDEPS)
exp/html/atom.lo: $(go_exp_html_atom_files)
$(BUILDPACKAGE)
exp/html/atom/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: exp/html/atom/check
@go_include@ exp/locale/collate.lo.dep
exp/locale/collate.lo.dep: $(go_exp_locale_collate_files)
$(BUILDDEPS)
exp/locale/collate.lo: $(go_exp_locale_collate_files)
$(BUILDPACKAGE)
exp/locale/collate/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: exp/locale/collate/check
@go_include@ exp/locale/collate/build.lo.dep
exp/locale/collate/build.lo.dep: $(go_exp_locale_collate_build_files)
$(BUILDDEPS)
exp/locale/collate/build.lo: $(go_exp_locale_collate_build_files)
$(BUILDPACKAGE)
exp/locale/collate/build/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: exp/locale/collate/build/check
@go_include@ exp/norm.lo.dep
exp/norm.lo.dep: $(go_exp_norm_files)
$(BUILDDEPS)
exp/norm.lo: $(go_exp_norm_files)
$(BUILDPACKAGE)
exp/norm/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: exp/norm/check
@go_include@ exp/proxy.lo.dep
exp/proxy.lo.dep: $(go_exp_proxy_files)
$(BUILDDEPS)
@ -5235,15 +5005,6 @@ exp/proxy/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: exp/proxy/check
@go_include@ exp/ssa.lo.dep
exp/ssa.lo.dep: $(go_exp_ssa_files)
$(BUILDDEPS)
exp/ssa.lo: $(go_exp_ssa_files)
$(BUILDPACKAGE)
exp/ssa/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: exp/ssa/check
@go_include@ exp/terminal.lo.dep
exp/terminal.lo.dep: $(go_exp_terminal_files)
$(BUILDDEPS)
@ -5253,24 +5014,6 @@ exp/terminal/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: exp/terminal/check
@go_include@ exp/utf8string.lo.dep
exp/utf8string.lo.dep: $(go_exp_utf8string_files)
$(BUILDDEPS)
exp/utf8string.lo: $(go_exp_utf8string_files)
$(BUILDPACKAGE)
exp/utf8string/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: exp/utf8string/check
@go_include@ exp/inotify.lo.dep
exp/inotify.lo.dep: $(go_exp_inotify_files)
$(BUILDDEPS)
exp/inotify.lo: $(go_exp_inotify_files)
$(BUILDPACKAGE)
exp/inotify/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: exp/inotify/check
@go_include@ html/template.lo.dep
html/template.lo.dep: $(go_html_template_files)
$(BUILDDEPS)
@ -5361,15 +5104,6 @@ go/token/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: go/token/check
@go_include@ go/types.lo.dep
go/types.lo.dep: $(go_go_types_files)
$(BUILDDEPS)
go/types.lo: $(go_go_types_files)
$(BUILDPACKAGE)
go/types/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: go/types/check
@go_include@ hash/adler32.lo.dep
hash/adler32.lo.dep: $(go_hash_adler32_files)
$(BUILDDEPS)
@ -5580,6 +5314,15 @@ net/http/cgi/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: net/http/cgi/check
@go_include@ net/http/cookiejar.lo.dep
net/http/cookiejar.lo.dep: $(go_net_http_cookiejar_files)
$(BUILDDEPS)
net/http/cookiejar.lo: $(go_net_http_cookiejar_files)
$(BUILDPACKAGE)
net/http/cookiejar/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: net/http/cookiejar/check
@go_include@ net/http/fcgi.lo.dep
net/http/fcgi.lo.dep: $(go_net_http_fcgi_files)
$(BUILDDEPS)
@ -5625,15 +5368,6 @@ net/rpc/jsonrpc/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: net/rpc/jsonrpc/check
@go_include@ old/netchan.lo.dep
old/netchan.lo.dep: $(go_old_netchan_files)
$(BUILDDEPS)
old/netchan.lo: $(go_old_netchan_files)
$(BUILDPACKAGE)
old/netchan/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: old/netchan/check
@go_include@ old/regexp.lo.dep
old/regexp.lo.dep: $(go_old_regexp_files)
$(BUILDDEPS)
@ -5974,30 +5708,10 @@ encoding/pem.gox: encoding/pem.lo
encoding/xml.gox: encoding/xml.lo
$(BUILDGOX)
exp/cookiejar.gox: exp/cookiejar.lo
$(BUILDGOX)
exp/ebnf.gox: exp/ebnf.lo
$(BUILDGOX)
exp/html.gox: exp/html.lo
$(BUILDGOX)
exp/html/atom.gox: exp/html/atom.lo
$(BUILDGOX)
exp/inotify.gox: exp/inotify.lo
$(BUILDGOX)
exp/locale/collate.gox: exp/locale/collate.lo
$(BUILDGOX)
exp/locale/collate/build.gox: exp/locale/collate/build.lo
$(BUILDGOX)
exp/norm.gox: exp/norm.lo
$(BUILDGOX)
exp/proxy.gox: exp/proxy.lo
$(BUILDGOX)
exp/ssa.gox: exp/ssa.lo
$(BUILDGOX)
exp/terminal.gox: exp/terminal.lo
$(BUILDGOX)
exp/utf8string.gox: exp/utf8string.lo
$(BUILDGOX)
html/template.gox: html/template.lo
$(BUILDGOX)
@ -6018,8 +5732,6 @@ go/scanner.gox: go/scanner.lo
$(BUILDGOX)
go/token.gox: go/token.lo
$(BUILDGOX)
go/types.gox: go/types.lo
$(BUILDGOX)
hash/adler32.gox: hash/adler32.lo
$(BUILDGOX)
@ -6075,6 +5787,8 @@ net/url.gox: net/url.lo
net/http/cgi.gox: net/http/cgi.lo
$(BUILDGOX)
net/http/cookiejar.gox: net/http/cookiejar.lo
$(BUILDGOX)
net/http/fcgi.gox: net/http/fcgi.lo
$(BUILDGOX)
net/http/httptest.gox: net/http/httptest.lo
@ -6087,8 +5801,6 @@ net/http/pprof.gox: net/http/pprof.lo
net/rpc/jsonrpc.gox: net/rpc/jsonrpc.lo
$(BUILDGOX)
old/netchan.gox: old/netchan.lo
$(BUILDGOX)
old/regexp.gox: old/regexp.lo
$(BUILDGOX)
old/template.gox: old/template.lo

View File

@ -9,12 +9,14 @@
// References:
// http://www.freebsd.org/cgi/man.cgi?query=tar&sektion=5
// http://www.gnu.org/software/tar/manual/html_node/Standard.html
// http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html
package tar
import (
"errors"
"fmt"
"os"
"path"
"time"
)
@ -33,6 +35,8 @@ const (
TypeCont = '7' // reserved
TypeXHeader = 'x' // extended header
TypeXGlobalHeader = 'g' // global extended header
TypeGNULongName = 'L' // Next file has a long name
TypeGNULongLink = 'K' // Next file symlinks to a file w/ a long name
)
// A Header represents a single header in a tar archive.
@ -54,55 +58,172 @@ type Header struct {
ChangeTime time.Time // status change time
}
// File name constants from the tar spec.
const (
fileNameSize = 100 // Maximum number of bytes in a standard tar name.
fileNamePrefixSize = 155 // Maximum number of ustar extension bytes.
)
// FileInfo returns an os.FileInfo for the Header.
func (h *Header) FileInfo() os.FileInfo {
return headerFileInfo{h}
}
// headerFileInfo implements os.FileInfo.
type headerFileInfo struct {
h *Header
}
func (fi headerFileInfo) Size() int64 { return fi.h.Size }
func (fi headerFileInfo) IsDir() bool { return fi.Mode().IsDir() }
func (fi headerFileInfo) ModTime() time.Time { return fi.h.ModTime }
func (fi headerFileInfo) Sys() interface{} { return fi.h }
// Name returns the base name of the file.
func (fi headerFileInfo) Name() string {
if fi.IsDir() {
return path.Clean(fi.h.Name)
}
return fi.h.Name
}
// Mode returns the permission and mode bits for the headerFileInfo.
func (fi headerFileInfo) Mode() (mode os.FileMode) {
// Set file permission bits.
mode = os.FileMode(fi.h.Mode).Perm()
// Set setuid, setgid and sticky bits.
if fi.h.Mode&c_ISUID != 0 {
// setuid
mode |= os.ModeSetuid
}
if fi.h.Mode&c_ISGID != 0 {
// setgid
mode |= os.ModeSetgid
}
if fi.h.Mode&c_ISVTX != 0 {
// sticky
mode |= os.ModeSticky
}
// Set file mode bits.
// clear perm, setuid, setgid and sticky bits.
m := os.FileMode(fi.h.Mode) &^ 07777
if m == c_ISDIR {
// directory
mode |= os.ModeDir
}
if m == c_ISFIFO {
// named pipe (FIFO)
mode |= os.ModeNamedPipe
}
if m == c_ISLNK {
// symbolic link
mode |= os.ModeSymlink
}
if m == c_ISBLK {
// device file
mode |= os.ModeDevice
}
if m == c_ISCHR {
// Unix character device
mode |= os.ModeDevice
mode |= os.ModeCharDevice
}
if m == c_ISSOCK {
// Unix domain socket
mode |= os.ModeSocket
}
switch fi.h.Typeflag {
case TypeLink, TypeSymlink:
// hard link, symbolic link
mode |= os.ModeSymlink
case TypeChar:
// character device node
mode |= os.ModeDevice
mode |= os.ModeCharDevice
case TypeBlock:
// block device node
mode |= os.ModeDevice
case TypeDir:
// directory
mode |= os.ModeDir
case TypeFifo:
// fifo node
mode |= os.ModeNamedPipe
}
return mode
}
// sysStat, if non-nil, populates h from system-dependent fields of fi.
var sysStat func(fi os.FileInfo, h *Header) error
// Mode constants from the tar spec.
const (
c_ISDIR = 040000
c_ISFIFO = 010000
c_ISREG = 0100000
c_ISLNK = 0120000
c_ISBLK = 060000
c_ISCHR = 020000
c_ISSOCK = 0140000
c_ISUID = 04000 // Set uid
c_ISGID = 02000 // Set gid
c_ISVTX = 01000 // Save text (sticky bit)
c_ISDIR = 040000 // Directory
c_ISFIFO = 010000 // FIFO
c_ISREG = 0100000 // Regular file
c_ISLNK = 0120000 // Symbolic link
c_ISBLK = 060000 // Block special file
c_ISCHR = 020000 // Character special file
c_ISSOCK = 0140000 // Socket
)
// FileInfoHeader creates a partially-populated Header from fi.
// If fi describes a symlink, FileInfoHeader records link as the link target.
// If fi describes a directory, a slash is appended to the name.
func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) {
if fi == nil {
return nil, errors.New("tar: FileInfo is nil")
}
fm := fi.Mode()
h := &Header{
Name: fi.Name(),
ModTime: fi.ModTime(),
Mode: int64(fi.Mode().Perm()), // or'd with c_IS* constants later
Mode: int64(fm.Perm()), // or'd with c_IS* constants later
}
switch {
case fi.Mode()&os.ModeType == 0:
case fm.IsRegular():
h.Mode |= c_ISREG
h.Typeflag = TypeReg
h.Size = fi.Size()
case fi.IsDir():
h.Typeflag = TypeDir
h.Mode |= c_ISDIR
case fi.Mode()&os.ModeSymlink != 0:
h.Name += "/"
case fm&os.ModeSymlink != 0:
h.Typeflag = TypeSymlink
h.Mode |= c_ISLNK
h.Linkname = link
case fi.Mode()&os.ModeDevice != 0:
if fi.Mode()&os.ModeCharDevice != 0 {
case fm&os.ModeDevice != 0:
if fm&os.ModeCharDevice != 0 {
h.Mode |= c_ISCHR
h.Typeflag = TypeChar
} else {
h.Mode |= c_ISBLK
h.Typeflag = TypeBlock
}
case fi.Mode()&os.ModeSocket != 0:
case fm&os.ModeNamedPipe != 0:
h.Typeflag = TypeFifo
h.Mode |= c_ISFIFO
case fm&os.ModeSocket != 0:
h.Mode |= c_ISSOCK
default:
return nil, fmt.Errorf("archive/tar: unknown file mode %v", fi.Mode())
return nil, fmt.Errorf("archive/tar: unknown file mode %v", fm)
}
if fm&os.ModeSetuid != 0 {
h.Mode |= c_ISUID
}
if fm&os.ModeSetgid != 0 {
h.Mode |= c_ISGID
}
if fm&os.ModeSticky != 0 {
h.Mode |= c_ISVTX
}
if sysStat != nil {
return h, sysStat(fi, h)

View File

@ -14,6 +14,7 @@ import (
"io/ioutil"
"os"
"strconv"
"strings"
"time"
)
@ -21,24 +22,12 @@ var (
ErrHeader = errors.New("archive/tar: invalid tar header")
)
const maxNanoSecondIntSize = 9
// A Reader provides sequential access to the contents of a tar archive.
// A tar archive consists of a sequence of files.
// The Next method advances to the next file in the archive (including the first),
// and then it can be treated as an io.Reader to access the file's data.
//
// Example:
// tr := tar.NewReader(r)
// for {
// hdr, err := tr.Next()
// if err == io.EOF {
// // end of tar archive
// break
// }
// if err != nil {
// // handle error
// }
// io.Copy(data, tr)
// }
type Reader struct {
r io.Reader
err error
@ -55,13 +44,183 @@ func (tr *Reader) Next() (*Header, error) {
if tr.err == nil {
tr.skipUnread()
}
if tr.err == nil {
if tr.err != nil {
return hdr, tr.err
}
hdr = tr.readHeader()
if hdr == nil {
return hdr, tr.err
}
// Check for PAX/GNU header.
switch hdr.Typeflag {
case TypeXHeader:
// PAX extended header
headers, err := parsePAX(tr)
if err != nil {
return nil, err
}
// We actually read the whole file,
// but this skips alignment padding
tr.skipUnread()
hdr = tr.readHeader()
mergePAX(hdr, headers)
return hdr, nil
case TypeGNULongName:
// We have a GNU long name header. Its contents are the real file name.
realname, err := ioutil.ReadAll(tr)
if err != nil {
return nil, err
}
hdr, err := tr.Next()
hdr.Name = cString(realname)
return hdr, err
case TypeGNULongLink:
// We have a GNU long link header.
realname, err := ioutil.ReadAll(tr)
if err != nil {
return nil, err
}
hdr, err := tr.Next()
hdr.Linkname = cString(realname)
return hdr, err
}
return hdr, tr.err
}
// Parse bytes as a NUL-terminated C-style string.
// mergePAX merges well known headers according to PAX standard.
// In general headers with the same name as those found
// in the header struct overwrite those found in the header
// struct with higher precision or longer values. Esp. useful
// for name and linkname fields.
func mergePAX(hdr *Header, headers map[string]string) error {
for k, v := range headers {
switch k {
case "path":
hdr.Name = v
case "linkpath":
hdr.Linkname = v
case "gname":
hdr.Gname = v
case "uname":
hdr.Uname = v
case "uid":
uid, err := strconv.ParseInt(v, 10, 0)
if err != nil {
return err
}
hdr.Uid = int(uid)
case "gid":
gid, err := strconv.ParseInt(v, 10, 0)
if err != nil {
return err
}
hdr.Gid = int(gid)
case "atime":
t, err := parsePAXTime(v)
if err != nil {
return err
}
hdr.AccessTime = t
case "mtime":
t, err := parsePAXTime(v)
if err != nil {
return err
}
hdr.ModTime = t
case "ctime":
t, err := parsePAXTime(v)
if err != nil {
return err
}
hdr.ChangeTime = t
case "size":
size, err := strconv.ParseInt(v, 10, 0)
if err != nil {
return err
}
hdr.Size = int64(size)
}
}
return nil
}
// parsePAXTime takes a string of the form %d.%d as described in
// the PAX specification.
func parsePAXTime(t string) (time.Time, error) {
buf := []byte(t)
pos := bytes.IndexByte(buf, '.')
var seconds, nanoseconds int64
var err error
if pos == -1 {
seconds, err = strconv.ParseInt(t, 10, 0)
if err != nil {
return time.Time{}, err
}
} else {
seconds, err = strconv.ParseInt(string(buf[:pos]), 10, 0)
if err != nil {
return time.Time{}, err
}
nano_buf := string(buf[pos+1:])
// Pad as needed before converting to a decimal.
// For example .030 -> .030000000 -> 30000000 nanoseconds
if len(nano_buf) < maxNanoSecondIntSize {
// Right pad
nano_buf += strings.Repeat("0", maxNanoSecondIntSize-len(nano_buf))
} else if len(nano_buf) > maxNanoSecondIntSize {
// Right truncate
nano_buf = nano_buf[:maxNanoSecondIntSize]
}
nanoseconds, err = strconv.ParseInt(string(nano_buf), 10, 0)
if err != nil {
return time.Time{}, err
}
}
ts := time.Unix(seconds, nanoseconds)
return ts, nil
}
// parsePAX parses PAX headers.
// If an extended header (type 'x') is invalid, ErrHeader is returned
func parsePAX(r io.Reader) (map[string]string, error) {
buf, err := ioutil.ReadAll(r)
if err != nil {
return nil, err
}
headers := make(map[string]string)
// Each record is constructed as
// "%d %s=%s\n", length, keyword, value
for len(buf) > 0 {
// or the header was empty to start with.
var sp int
// The size field ends at the first space.
sp = bytes.IndexByte(buf, ' ')
if sp == -1 {
return nil, ErrHeader
}
// Parse the first token as a decimal integer.
n, err := strconv.ParseInt(string(buf[:sp]), 10, 0)
if err != nil {
return nil, ErrHeader
}
// Extract everything between the decimal and the n -1 on the
// beginning to to eat the ' ', -1 on the end to skip the newline.
var record []byte
record, buf = buf[sp+1:n-1], buf[n:]
// The first equals is guaranteed to mark the end of the key.
// Everything else is value.
eq := bytes.IndexByte(record, '=')
if eq == -1 {
return nil, ErrHeader
}
key, value := record[:eq], record[eq+1:]
headers[string(key)] = string(value)
}
return headers, nil
}
// cString parses bytes as a NUL-terminated C-style string.
// If a NUL byte is not found then the whole slice is returned as a string.
func cString(b []byte) string {
n := 0
@ -99,7 +258,7 @@ func (tr *Reader) octal(b []byte) int64 {
return int64(x)
}
// Skip any unread bytes in the existing file entry, as well as any alignment padding.
// skipUnread skips any unread bytes in the existing file entry, as well as any alignment padding.
func (tr *Reader) skipUnread() {
nr := tr.nb + tr.pad // number of bytes to skip
tr.nb, tr.pad = 0, 0

View File

@ -10,6 +10,8 @@ import (
"fmt"
"io"
"os"
"reflect"
"strings"
"testing"
"time"
)
@ -108,6 +110,38 @@ var untarTests = []*untarTest{
},
},
},
{
file: "testdata/pax.tar",
headers: []*Header{
{
Name: "a/123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100",
Mode: 0664,
Uid: 1000,
Gid: 1000,
Uname: "shane",
Gname: "shane",
Size: 7,
ModTime: time.Unix(1350244992, 23960108),
ChangeTime: time.Unix(1350244992, 23960108),
AccessTime: time.Unix(1350244992, 23960108),
Typeflag: TypeReg,
},
{
Name: "a/b",
Mode: 0777,
Uid: 1000,
Gid: 1000,
Uname: "shane",
Gname: "shane",
Size: 0,
ModTime: time.Unix(1350266320, 910238425),
ChangeTime: time.Unix(1350266320, 910238425),
AccessTime: time.Unix(1350266320, 910238425),
Typeflag: TypeSymlink,
Linkname: "123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100",
},
},
},
}
func TestReader(t *testing.T) {
@ -133,7 +167,7 @@ testLoop:
}
hdr, err := tr.Next()
if err == io.EOF {
break
continue testLoop
}
if hdr != nil || err != nil {
t.Errorf("test %d: Unexpected entry or error: hdr=%v err=%v", i, hdr, err)
@ -260,3 +294,73 @@ func TestNonSeekable(t *testing.T) {
t.Errorf("Didn't process all files\nexpected: %d\nprocessed %d\n", len(test.headers), nread)
}
}
func TestParsePAXHeader(t *testing.T) {
paxTests := [][3]string{
{"a", "a=name", "10 a=name\n"}, // Test case involving multiple acceptable lengths
{"a", "a=name", "9 a=name\n"}, // Test case involving multiple acceptable length
{"mtime", "mtime=1350244992.023960108", "30 mtime=1350244992.023960108\n"}}
for _, test := range paxTests {
key, expected, raw := test[0], test[1], test[2]
reader := bytes.NewBuffer([]byte(raw))
headers, err := parsePAX(reader)
if err != nil {
t.Errorf("Couldn't parse correctly formatted headers: %v", err)
continue
}
if strings.EqualFold(headers[key], expected) {
t.Errorf("mtime header incorrectly parsed: got %s, wanted %s", headers[key], expected)
continue
}
trailer := make([]byte, 100)
n, err := reader.Read(trailer)
if err != io.EOF || n != 0 {
t.Error("Buffer wasn't consumed")
}
}
badHeader := bytes.NewBuffer([]byte("3 somelongkey="))
if _, err := parsePAX(badHeader); err != ErrHeader {
t.Fatal("Unexpected success when parsing bad header")
}
}
func TestParsePAXTime(t *testing.T) {
// Some valid PAX time values
timestamps := map[string]time.Time{
"1350244992.023960108": time.Unix(1350244992, 23960108), // The commoon case
"1350244992.02396010": time.Unix(1350244992, 23960100), // Lower precision value
"1350244992.0239601089": time.Unix(1350244992, 23960108), // Higher precision value
"1350244992": time.Unix(1350244992, 0), // Low precision value
}
for input, expected := range timestamps {
ts, err := parsePAXTime(input)
if err != nil {
t.Fatal(err)
}
if !ts.Equal(expected) {
t.Fatalf("Time parsing failure %s %s", ts, expected)
}
}
}
func TestMergePAX(t *testing.T) {
hdr := new(Header)
// Test a string, integer, and time based value.
headers := map[string]string{
"path": "a/b/c",
"uid": "1000",
"mtime": "1350244992.023960108",
}
err := mergePAX(hdr, headers)
if err != nil {
t.Fatal(err)
}
want := &Header{
Name: "a/b/c",
Uid: 1000,
ModTime: time.Unix(1350244992, 23960108),
}
if !reflect.DeepEqual(hdr, want) {
t.Errorf("incorrect merge: got %+v, want %+v", hdr, want)
}
}

View File

@ -14,13 +14,13 @@ import (
)
func TestFileInfoHeader(t *testing.T) {
fi, err := os.Lstat("testdata/small.txt")
fi, err := os.Stat("testdata/small.txt")
if err != nil {
t.Fatal(err)
}
h, err := FileInfoHeader(fi, "")
if err != nil {
t.Fatalf("on small.txt: %v", err)
t.Fatalf("FileInfoHeader: %v", err)
}
if g, e := h.Name, "small.txt"; g != e {
t.Errorf("Name = %q; want %q", g, e)
@ -36,6 +36,30 @@ func TestFileInfoHeader(t *testing.T) {
}
}
func TestFileInfoHeaderDir(t *testing.T) {
fi, err := os.Stat("testdata")
if err != nil {
t.Fatal(err)
}
h, err := FileInfoHeader(fi, "")
if err != nil {
t.Fatalf("FileInfoHeader: %v", err)
}
if g, e := h.Name, "testdata/"; g != e {
t.Errorf("Name = %q; want %q", g, e)
}
// Ignoring c_ISGID for golang.org/issue/4867
if g, e := h.Mode&^c_ISGID, int64(fi.Mode().Perm())|c_ISDIR; g != e {
t.Errorf("Mode = %#o; want %#o", g, e)
}
if g, e := h.Size, int64(0); g != e {
t.Errorf("Size = %v; want %v", g, e)
}
if g, e := h.ModTime, fi.ModTime(); !g.Equal(e) {
t.Errorf("ModTime = %v; want %v", g, e)
}
}
func TestFileInfoHeaderSymlink(t *testing.T) {
h, err := FileInfoHeader(symlink{}, "some-target")
if err != nil {
@ -98,3 +122,150 @@ func TestRoundTrip(t *testing.T) {
t.Errorf("Data mismatch.\n got %q\nwant %q", rData, data)
}
}
type headerRoundTripTest struct {
h *Header
fm os.FileMode
}
func TestHeaderRoundTrip(t *testing.T) {
golden := []headerRoundTripTest{
// regular file.
{
h: &Header{
Name: "test.txt",
Mode: 0644 | c_ISREG,
Size: 12,
ModTime: time.Unix(1360600916, 0),
Typeflag: TypeReg,
},
fm: 0644,
},
// hard link.
{
h: &Header{
Name: "hard.txt",
Mode: 0644 | c_ISLNK,
Size: 0,
ModTime: time.Unix(1360600916, 0),
Typeflag: TypeLink,
},
fm: 0644 | os.ModeSymlink,
},
// symbolic link.
{
h: &Header{
Name: "link.txt",
Mode: 0777 | c_ISLNK,
Size: 0,
ModTime: time.Unix(1360600852, 0),
Typeflag: TypeSymlink,
},
fm: 0777 | os.ModeSymlink,
},
// character device node.
{
h: &Header{
Name: "dev/null",
Mode: 0666 | c_ISCHR,
Size: 0,
ModTime: time.Unix(1360578951, 0),
Typeflag: TypeChar,
},
fm: 0666 | os.ModeDevice | os.ModeCharDevice,
},
// block device node.
{
h: &Header{
Name: "dev/sda",
Mode: 0660 | c_ISBLK,
Size: 0,
ModTime: time.Unix(1360578954, 0),
Typeflag: TypeBlock,
},
fm: 0660 | os.ModeDevice,
},
// directory.
{
h: &Header{
Name: "dir/",
Mode: 0755 | c_ISDIR,
Size: 0,
ModTime: time.Unix(1360601116, 0),
Typeflag: TypeDir,
},
fm: 0755 | os.ModeDir,
},
// fifo node.
{
h: &Header{
Name: "dev/initctl",
Mode: 0600 | c_ISFIFO,
Size: 0,
ModTime: time.Unix(1360578949, 0),
Typeflag: TypeFifo,
},
fm: 0600 | os.ModeNamedPipe,
},
// setuid.
{
h: &Header{
Name: "bin/su",
Mode: 0755 | c_ISREG | c_ISUID,
Size: 23232,
ModTime: time.Unix(1355405093, 0),
Typeflag: TypeReg,
},
fm: 0755 | os.ModeSetuid,
},
// setguid.
{
h: &Header{
Name: "group.txt",
Mode: 0750 | c_ISREG | c_ISGID,
Size: 0,
ModTime: time.Unix(1360602346, 0),
Typeflag: TypeReg,
},
fm: 0750 | os.ModeSetgid,
},
// sticky.
{
h: &Header{
Name: "sticky.txt",
Mode: 0600 | c_ISREG | c_ISVTX,
Size: 7,
ModTime: time.Unix(1360602540, 0),
Typeflag: TypeReg,
},
fm: 0600 | os.ModeSticky,
},
}
for i, g := range golden {
fi := g.h.FileInfo()
h2, err := FileInfoHeader(fi, "")
if err != nil {
t.Error(err)
continue
}
if got, want := h2.Name, g.h.Name; got != want {
t.Errorf("i=%d: Name: got %v, want %v", i, got, want)
}
if got, want := h2.Size, g.h.Size; got != want {
t.Errorf("i=%d: Size: got %v, want %v", i, got, want)
}
if got, want := h2.Mode, g.h.Mode; got != want {
t.Errorf("i=%d: Mode: got %o, want %o", i, got, want)
}
if got, want := fi.Mode(), g.fm; got != want {
t.Errorf("i=%d: fi.Mode: got %o, want %o", i, got, want)
}
if got, want := h2.ModTime, g.h.ModTime; got != want {
t.Errorf("i=%d: ModTime: got %v, want %v", i, got, want)
}
if sysh, ok := fi.Sys().(*Header); !ok || sysh != g.h {
t.Errorf("i=%d: Sys didn't return original *Header", i)
}
}
}

BIN
libgo/go/archive/tar/testdata/pax.tar vendored Normal file

Binary file not shown.

BIN
libgo/go/archive/tar/testdata/ustar.tar vendored Normal file

Binary file not shown.

View File

@ -8,10 +8,14 @@ package tar
// - catch more errors (no first header, etc.)
import (
"bytes"
"errors"
"fmt"
"io"
"os"
"path"
"strconv"
"strings"
"time"
)
@ -19,23 +23,13 @@ var (
ErrWriteTooLong = errors.New("archive/tar: write too long")
ErrFieldTooLong = errors.New("archive/tar: header field too long")
ErrWriteAfterClose = errors.New("archive/tar: write after close")
errNameTooLong = errors.New("archive/tar: name too long")
)
// A Writer provides sequential writing of a tar archive in POSIX.1 format.
// A tar archive consists of a sequence of files.
// Call WriteHeader to begin a new file, and then call Write to supply that file's data,
// writing at most hdr.Size bytes in total.
//
// Example:
// tw := tar.NewWriter(w)
// hdr := new(tar.Header)
// hdr.Size = length of data in bytes
// // populate other hdr fields as desired
// if err := tw.WriteHeader(hdr); err != nil {
// // handle error
// }
// io.Copy(tw, data)
// tw.Close()
type Writer struct {
w io.Writer
err error
@ -130,15 +124,31 @@ func (tw *Writer) WriteHeader(hdr *Header) error {
if tw.err != nil {
return tw.err
}
// Decide whether or not to use PAX extensions
// TODO(shanemhansen): we might want to use PAX headers for
// subsecond time resolution, but for now let's just capture
// the long name/long symlink use case.
suffix := hdr.Name
prefix := ""
if len(hdr.Name) > fileNameSize || len(hdr.Linkname) > fileNameSize {
var err error
prefix, suffix, err = tw.splitUSTARLongName(hdr.Name)
// Either we were unable to pack the long name into ustar format
// or the link name is too long; use PAX headers.
if err == errNameTooLong || len(hdr.Linkname) > fileNameSize {
if err := tw.writePAXHeader(hdr); err != nil {
return err
}
} else if err != nil {
return err
}
}
tw.nb = int64(hdr.Size)
tw.pad = -tw.nb & (blockSize - 1) // blockSize is a power of two
header := make([]byte, blockSize)
s := slicer(header)
// TODO(dsymonds): handle names longer than 100 chars
copy(s.next(100), []byte(hdr.Name))
tw.cString(s.next(fileNameSize), suffix)
// Handle out of range ModTime carefully.
var modTime int64
@ -159,11 +169,15 @@ func (tw *Writer) WriteHeader(hdr *Header) error {
tw.cString(s.next(32), hdr.Gname) // 297:329
tw.numeric(s.next(8), hdr.Devmajor) // 329:337
tw.numeric(s.next(8), hdr.Devminor) // 337:345
tw.cString(s.next(155), prefix) // 345:500
// Use the GNU magic instead of POSIX magic if we used any GNU extensions.
if tw.usedBinary {
copy(header[257:265], []byte("ustar \x00"))
}
// Use the ustar magic if we used ustar long names.
if len(prefix) > 0 {
copy(header[257:265], []byte("ustar\000"))
}
// The chksum field is terminated by a NUL and a space.
// This is different from the other octal fields.
@ -181,6 +195,78 @@ func (tw *Writer) WriteHeader(hdr *Header) error {
return tw.err
}
// writeUSTARLongName splits a USTAR long name hdr.Name.
// name must be < 256 characters. errNameTooLong is returned
// if hdr.Name can't be split. The splitting heuristic
// is compatible with gnu tar.
func (tw *Writer) splitUSTARLongName(name string) (prefix, suffix string, err error) {
length := len(name)
if length > fileNamePrefixSize+1 {
length = fileNamePrefixSize + 1
} else if name[length-1] == '/' {
length--
}
i := strings.LastIndex(name[:length], "/")
nlen := length - i - 1
if i <= 0 || nlen > fileNameSize || nlen == 0 {
err = errNameTooLong
return
}
prefix, suffix = name[:i], name[i+1:]
return
}
// writePaxHeader writes an extended pax header to the
// archive.
func (tw *Writer) writePAXHeader(hdr *Header) error {
// Prepare extended header
ext := new(Header)
ext.Typeflag = TypeXHeader
// Setting ModTime is required for reader parsing to
// succeed, and seems harmless enough.
ext.ModTime = hdr.ModTime
// The spec asks that we namespace our pseudo files
// with the current pid.
pid := os.Getpid()
dir, file := path.Split(hdr.Name)
ext.Name = path.Join(dir,
fmt.Sprintf("PaxHeaders.%d", pid), file)[0:100]
// Construct the body
var buf bytes.Buffer
if len(hdr.Name) > fileNameSize {
fmt.Fprint(&buf, paxHeader("path="+hdr.Name))
}
if len(hdr.Linkname) > fileNameSize {
fmt.Fprint(&buf, paxHeader("linkpath="+hdr.Linkname))
}
ext.Size = int64(len(buf.Bytes()))
if err := tw.WriteHeader(ext); err != nil {
return err
}
if _, err := tw.Write(buf.Bytes()); err != nil {
return err
}
if err := tw.Flush(); err != nil {
return err
}
return nil
}
// paxHeader formats a single pax record, prefixing it with the appropriate length
func paxHeader(msg string) string {
const padding = 2 // Extra padding for space and newline
size := len(msg) + padding
size += len(strconv.Itoa(size))
record := fmt.Sprintf("%d %s\n", size, msg)
if len(record) != size {
// Final adjustment if adding size increased
// the number of digits in size
size = len(record)
record = fmt.Sprintf("%d %s\n", size, msg)
}
return record
}
// Write writes to the current entry in the tar archive.
// Write returns the error ErrWriteTooLong if more than
// hdr.Size bytes are written after WriteHeader.

View File

@ -9,6 +9,7 @@ import (
"fmt"
"io"
"io/ioutil"
"os"
"strings"
"testing"
"testing/iotest"
@ -101,6 +102,27 @@ var writerTests = []*writerTest{
},
},
},
// This file was produced using gnu tar 1.17
// gnutar -b 4 --format=ustar (longname/)*15 + file.txt
{
file: "testdata/ustar.tar",
entries: []*writerTestEntry{
{
header: &Header{
Name: strings.Repeat("longname/", 15) + "file.txt",
Mode: 0644,
Uid: 0765,
Gid: 024,
Size: 06,
ModTime: time.Unix(1360135598, 0),
Typeflag: '0',
Uname: "shane",
Gname: "staff",
},
contents: "hello\n",
},
},
},
}
// Render byte array in a two-character hexadecimal string, spaced for easy visual inspection.
@ -180,3 +202,61 @@ testLoop:
}
}
}
func TestPax(t *testing.T) {
// Create an archive with a large name
fileinfo, err := os.Stat("testdata/small.txt")
if err != nil {
t.Fatal(err)
}
hdr, err := FileInfoHeader(fileinfo, "")
if err != nil {
t.Fatalf("os.Stat: %v", err)
}
// Force a PAX long name to be written
longName := strings.Repeat("ab", 100)
contents := strings.Repeat(" ", int(hdr.Size))
hdr.Name = longName
var buf bytes.Buffer
writer := NewWriter(&buf)
if err := writer.WriteHeader(hdr); err != nil {
t.Fatal(err)
}
if _, err = writer.Write([]byte(contents)); err != nil {
t.Fatal(err)
}
if err := writer.Close(); err != nil {
t.Fatal(err)
}
// Simple test to make sure PAX extensions are in effect
if !bytes.Contains(buf.Bytes(), []byte("PaxHeaders.")) {
t.Fatal("Expected at least one PAX header to be written.")
}
// Test that we can get a long name back out of the archive.
reader := NewReader(&buf)
hdr, err = reader.Next()
if err != nil {
t.Fatal(err)
}
if hdr.Name != longName {
t.Fatal("Couldn't recover long file name")
}
}
func TestPAXHeader(t *testing.T) {
medName := strings.Repeat("CD", 50)
longName := strings.Repeat("AB", 100)
paxTests := [][2]string{
{"name=/etc/hosts", "19 name=/etc/hosts\n"},
{"a=b", "6 a=b\n"}, // Single digit length
{"a=names", "11 a=names\n"}, // Test case involving carries
{"name=" + longName, fmt.Sprintf("210 name=%s\n", longName)},
{"name=" + medName, fmt.Sprintf("110 name=%s\n", medName)}}
for _, test := range paxTests {
key, expected := test[0], test[1]
if result := paxHeader(key); result != expected {
t.Fatalf("paxHeader: got %s, expected %s", result, expected)
}
}
}

View File

@ -353,6 +353,11 @@ func readDirectoryEnd(r io.ReaderAt, size int64) (dir *directoryEnd, err error)
if err != nil {
return nil, err
}
// Make sure directoryOffset points to somewhere in our file.
if o := int64(d.directoryOffset); o < 0 || o >= size {
return nil, ErrFormat
}
return d, nil
}
@ -407,7 +412,7 @@ func findSignatureInBlock(b []byte) int {
if b[i] == 'P' && b[i+1] == 'K' && b[i+2] == 0x05 && b[i+3] == 0x06 {
// n is length of comment
n := int(b[i+directoryEndLen-2]) | int(b[i+directoryEndLen-1])<<8
if n+directoryEndLen+i == len(b) {
if n+directoryEndLen+i <= len(b) {
return i
}
}

View File

@ -63,6 +63,24 @@ var tests = []ZipTest{
},
},
},
{
Name: "test-trailing-junk.zip",
Comment: "This is a zipfile comment.",
File: []ZipTestFile{
{
Name: "test.txt",
Content: []byte("This is a test text file.\n"),
Mtime: "09-05-10 12:12:02",
Mode: 0644,
},
{
Name: "gophercolor16x16.png",
File: "gophercolor16x16.png",
Mtime: "09-05-10 15:52:58",
Mode: 0644,
},
},
},
{
Name: "r.zip",
Source: returnRecursiveZip,
@ -262,7 +280,7 @@ func readTestZip(t *testing.T, zt ZipTest) {
}
}
if err != zt.Error {
t.Errorf("error=%v, want %v", err, zt.Error)
t.Errorf("%s: error=%v, want %v", zt.Name, err, zt.Error)
return
}

View File

@ -64,8 +64,15 @@ const (
zip64ExtraId = 0x0001 // zip64 Extended Information Extra Field
)
// FileHeader describes a file within a zip file.
// See the zip spec for details.
type FileHeader struct {
Name string
// Name is the name of the file.
// It must be a relative path: it must not start with a drive
// letter (e.g. C:) or leading slash, and only forward slashes
// are allowed.
Name string
CreatorVersion uint16
ReaderVersion uint16
Flags uint16

Binary file not shown.

View File

@ -163,6 +163,9 @@ func (w *Writer) Close() error {
// Create adds a file to the zip file using the provided name.
// It returns a Writer to which the file contents should be written.
// The name must be a relative path: it must not start with a drive
// letter (e.g. C:) or leading slash, and only forward slashes are
// allowed.
// The file's contents must be written to the io.Writer before the next
// call to Create, CreateHeader, or Close.
func (w *Writer) Create(name string) (io.Writer, error) {

View File

@ -274,11 +274,10 @@ func (b *Reader) ReadSlice(delim byte) (line []byte, err error) {
return b.buf, ErrBufferFull
}
}
panic("not reached")
}
// ReadLine is a low-level line-reading primitive. Most callers should use
// ReadBytes('\n') or ReadString('\n') instead.
// ReadBytes('\n') or ReadString('\n') instead or use a Scanner.
//
// ReadLine tries to return a single line, not including the end-of-line bytes.
// If the line was too long for the buffer then isPrefix is set and the
@ -331,6 +330,7 @@ func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error) {
// it returns the data read before the error and the error itself (often io.EOF).
// ReadBytes returns err != nil if and only if the returned data does not end in
// delim.
// For simple uses, a Scanner may be more convenient.
func (b *Reader) ReadBytes(delim byte) (line []byte, err error) {
// Use ReadSlice to look for array,
// accumulating full buffers.
@ -378,6 +378,7 @@ func (b *Reader) ReadBytes(delim byte) (line []byte, err error) {
// it returns the data read before the error and the error itself (often io.EOF).
// ReadString returns err != nil if and only if the returned data does not end in
// delim.
// For simple uses, a Scanner may be more convenient.
func (b *Reader) ReadString(delim byte) (line string, err error) {
bytes, err := b.ReadBytes(delim)
return string(bytes), err

View File

@ -7,6 +7,7 @@ package bufio_test
import (
. "bufio"
"bytes"
"errors"
"fmt"
"io"
"io/ioutil"
@ -434,9 +435,12 @@ func TestWriteErrors(t *testing.T) {
t.Errorf("Write hello to %v: %v", w, e)
continue
}
e = buf.Flush()
if e != w.expect {
t.Errorf("Flush %v: got %v, wanted %v", w, e, w.expect)
// Two flushes, to verify the error is sticky.
for i := 0; i < 2; i++ {
e = buf.Flush()
if e != w.expect {
t.Errorf("Flush %d/2 %v: got %v, wanted %v", i+1, w, e, w.expect)
}
}
}
}
@ -953,7 +957,7 @@ func TestNegativeRead(t *testing.T) {
t.Fatal("read did not panic")
case error:
if !strings.Contains(err.Error(), "reader returned negative count from Read") {
t.Fatal("wrong panic: %v", err)
t.Fatalf("wrong panic: %v", err)
}
default:
t.Fatalf("unexpected panic value: %T(%v)", err, err)
@ -962,6 +966,43 @@ func TestNegativeRead(t *testing.T) {
b.Read(make([]byte, 100))
}
var errFake = errors.New("fake error")
type errorThenGoodReader struct {
didErr bool
nread int
}
func (r *errorThenGoodReader) Read(p []byte) (int, error) {
r.nread++
if !r.didErr {
r.didErr = true
return 0, errFake
}
return len(p), nil
}
func TestReaderClearError(t *testing.T) {
r := &errorThenGoodReader{}
b := NewReader(r)
buf := make([]byte, 1)
if _, err := b.Read(nil); err != nil {
t.Fatalf("1st nil Read = %v; want nil", err)
}
if _, err := b.Read(buf); err != errFake {
t.Fatalf("1st Read = %v; want errFake", err)
}
if _, err := b.Read(nil); err != nil {
t.Fatalf("2nd nil Read = %v; want nil", err)
}
if _, err := b.Read(buf); err != nil {
t.Fatalf("3rd Read with buffer = %v; want nil", err)
}
if r.nread != 2 {
t.Errorf("num reads = %d; want 2", r.nread)
}
}
// An onlyReader only implements io.Reader, no matter what other methods the underlying implementation may have.
type onlyReader struct {
r io.Reader

View File

@ -0,0 +1,74 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bufio_test
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
// The simplest use of a Scanner, to read standard input as a set of lines.
func ExampleScanner_lines() {
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
fmt.Println(scanner.Text()) // Println will add back the final '\n'
}
if err := scanner.Err(); err != nil {
fmt.Fprintln(os.Stderr, "reading standard input:", err)
}
}
// Use a Scanner to implement a simple word-count utility by scanning the
// input as a sequence of space-delimited tokens.
func ExampleScanner_words() {
// An artificial input source.
const input = "Now is the winter of our discontent,\nMade glorious summer by this sun of York.\n"
scanner := bufio.NewScanner(strings.NewReader(input))
// Set the split function for the scanning operation.
scanner.Split(bufio.ScanWords)
// Count the words.
count := 0
for scanner.Scan() {
count++
}
if err := scanner.Err(); err != nil {
fmt.Fprintln(os.Stderr, "reading input:", err)
}
fmt.Printf("%d\n", count)
// Output: 15
}
// Use a Scanner with a custom split function (built by wrapping ScanWords) to validate
// 32-bit decimal input.
func ExampleScanner_custom() {
// An artificial input source.
const input = "1234 5678 1234567901234567890"
scanner := bufio.NewScanner(strings.NewReader(input))
// Create a custom split function by wrapping the existing ScanWords function.
split := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
advance, token, err = bufio.ScanWords(data, atEOF)
if err == nil && token != nil {
_, err = strconv.ParseInt(string(token), 10, 32)
}
return
}
// Set the split function for the scanning operation.
scanner.Split(split)
// Validate the input
for scanner.Scan() {
fmt.Printf("%s\n", scanner.Text())
}
if err := scanner.Err(); err != nil {
fmt.Printf("Invalid input: %s", err)
}
// Output:
// 1234
// 5678
// Invalid input: strconv.ParseInt: parsing "1234567901234567890": value out of range
}

View File

@ -0,0 +1,27 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bufio
// Exported for testing only.
import (
"unicode/utf8"
)
var IsSpace = isSpace
func (s *Scanner) MaxTokenSize(n int) {
if n < utf8.UTFMax || n > 1e9 {
panic("bad max token size")
}
if n < len(s.buf) {
s.buf = make([]byte, n)
}
s.maxTokenSize = n
}
// ErrOrEOF is like Err, but returns EOF. Used to test a corner case.
func (s *Scanner) ErrOrEOF() error {
return s.err
}

346
libgo/go/bufio/scan.go Normal file
View File

@ -0,0 +1,346 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bufio
import (
"bytes"
"errors"
"io"
"unicode/utf8"
)
// Scanner provides a convenient interface for reading data such as
// a file of newline-delimited lines of text. Successive calls to
// the Scan method will step through the 'tokens' of a file, skipping
// the bytes between the tokens. The specification of a token is
// defined by a split function of type SplitFunc; the default split
// function breaks the input into lines with line termination stripped. Split
// functions are defined in this package for scanning a file into
// lines, bytes, UTF-8-encoded runes, and space-delimited words. The
// client may instead provide a custom split function.
//
// Scanning stops unrecoverably at EOF, the first I/O error, or a token too
// large to fit in the buffer. When a scan stops, the reader may have
// advanced arbitrarily far past the last token. Programs that need more
// control over error handling or large tokens, or must run sequential scans
// on a reader, should use bufio.Reader instead.
//
type Scanner struct {
r io.Reader // The reader provided by the client.
split SplitFunc // The function to split the tokens.
maxTokenSize int // Maximum size of a token; modified by tests.
token []byte // Last token returned by split.
buf []byte // Buffer used as argument to split.
start int // First non-processed byte in buf.
end int // End of data in buf.
err error // Sticky error.
}
// SplitFunc is the signature of the split function used to tokenize the
// input. The arguments are an initial substring of the remaining unprocessed
// data and a flag, atEOF, that reports whether the Reader has no more data
// to give. The return values are the number of bytes to advance the input
// and the next token to return to the user, plus an error, if any. If the
// data does not yet hold a complete token, for instance if it has no newline
// while scanning lines, SplitFunc can return (0, nil) to signal the Scanner
// to read more data into the slice and try again with a longer slice
// starting at the same point in the input.
//
// If the returned error is non-nil, scanning stops and the error
// is returned to the client.
//
// The function is never called with an empty data slice unless atEOF
// is true. If atEOF is true, however, data may be non-empty and,
// as always, holds unprocessed text.
type SplitFunc func(data []byte, atEOF bool) (advance int, token []byte, err error)
// Errors returned by Scanner.
var (
ErrTooLong = errors.New("bufio.Scanner: token too long")
ErrNegativeAdvance = errors.New("bufio.Scanner: SplitFunc returns negative advance count")
ErrAdvanceTooFar = errors.New("bufio.Scanner: SplitFunc returns advance count beyond input")
)
const (
// Maximum size used to buffer a token. The actual maximum token size
// may be smaller as the buffer may need to include, for instance, a newline.
MaxScanTokenSize = 64 * 1024
)
// NewScanner returns a new Scanner to read from r.
// The split function defaults to ScanLines.
func NewScanner(r io.Reader) *Scanner {
return &Scanner{
r: r,
split: ScanLines,
maxTokenSize: MaxScanTokenSize,
buf: make([]byte, 4096), // Plausible starting size; needn't be large.
}
}
// Err returns the first non-EOF error that was encountered by the Scanner.
func (s *Scanner) Err() error {
if s.err == io.EOF {
return nil
}
return s.err
}
// Bytes returns the most recent token generated by a call to Scan.
// The underlying array may point to data that will be overwritten
// by a subsequent call to Scan. It does no allocation.
func (s *Scanner) Bytes() []byte {
return s.token
}
// Text returns the most recent token generated by a call to Scan
// as a newly allocated string holding its bytes.
func (s *Scanner) Text() string {
return string(s.token)
}
// Scan advances the Scanner to the next token, which will then be
// available through the Bytes or Text method. It returns false when the
// scan stops, either by reaching the end of the input or an error.
// After Scan returns false, the Err method will return any error that
// occurred during scanning, except that if it was io.EOF, Err
// will return nil.
func (s *Scanner) Scan() bool {
// Loop until we have a token.
for {
// See if we can get a token with what we already have.
if s.end > s.start {
advance, token, err := s.split(s.buf[s.start:s.end], s.err != nil)
if err != nil {
s.setErr(err)
return false
}
if !s.advance(advance) {
return false
}
s.token = token
if token != nil {
return true
}
}
// We cannot generate a token with what we are holding.
// If we've already hit EOF or an I/O error, we are done.
if s.err != nil {
// Shut it down.
s.start = 0
s.end = 0
return false
}
// Must read more data.
// First, shift data to beginning of buffer if there's lots of empty space
// or space is neded.
if s.start > 0 && (s.end == len(s.buf) || s.start > len(s.buf)/2) {
copy(s.buf, s.buf[s.start:s.end])
s.end -= s.start
s.start = 0
}
// Is the buffer full? If so, resize.
if s.end == len(s.buf) {
if len(s.buf) >= s.maxTokenSize {
s.setErr(ErrTooLong)
return false
}
newSize := len(s.buf) * 2
if newSize > s.maxTokenSize {
newSize = s.maxTokenSize
}
newBuf := make([]byte, newSize)
copy(newBuf, s.buf[s.start:s.end])
s.buf = newBuf
s.end -= s.start
s.start = 0
continue
}
// Finally we can read some input. Make sure we don't get stuck with
// a misbehaving Reader. Officially we don't need to do this, but let's
// be extra careful: Scanner is for safe, simple jobs.
for loop := 0; ; {
n, err := s.r.Read(s.buf[s.end:len(s.buf)])
s.end += n
if err != nil {
s.setErr(err)
break
}
if n > 0 {
break
}
loop++
if loop > 100 {
s.setErr(io.ErrNoProgress)
break
}
}
}
}
// advance consumes n bytes of the buffer. It reports whether the advance was legal.
func (s *Scanner) advance(n int) bool {
if n < 0 {
s.setErr(ErrNegativeAdvance)
return false
}
if n > s.end-s.start {
s.setErr(ErrAdvanceTooFar)
return false
}
s.start += n
return true
}
// setErr records the first error encountered.
func (s *Scanner) setErr(err error) {
if s.err == nil || s.err == io.EOF {
s.err = err
}
}
// Split sets the split function for the Scanner. If called, it must be
// called before Scan. The default split function is ScanLines.
func (s *Scanner) Split(split SplitFunc) {
s.split = split
}
// Split functions
// ScanBytes is a split function for a Scanner that returns each byte as a token.
func ScanBytes(data []byte, atEOF bool) (advance int, token []byte, err error) {
if atEOF && len(data) == 0 {
return 0, nil, nil
}
return 1, data[0:1], nil
}
var errorRune = []byte(string(utf8.RuneError))
// ScanRunes is a split function for a Scanner that returns each
// UTF-8-encoded rune as a token. The sequence of runes returned is
// equivalent to that from a range loop over the input as a string, which
// means that erroneous UTF-8 encodings translate to U+FFFD = "\xef\xbf\xbd".
// Because of the Scan interface, this makes it impossible for the client to
// distinguish correctly encoded replacement runes from encoding errors.
func ScanRunes(data []byte, atEOF bool) (advance int, token []byte, err error) {
if atEOF && len(data) == 0 {
return 0, nil, nil
}
// Fast path 1: ASCII.
if data[0] < utf8.RuneSelf {
return 1, data[0:1], nil
}
// Fast path 2: Correct UTF-8 decode without error.
_, width := utf8.DecodeRune(data)
if width > 1 {
// It's a valid encoding. Width cannot be one for a correctly encoded
// non-ASCII rune.
return width, data[0:width], nil
}
// We know it's an error: we have width==1 and implicitly r==utf8.RuneError.
// Is the error because there wasn't a full rune to be decoded?
// FullRune distinguishes correctly between erroneous and incomplete encodings.
if !atEOF && !utf8.FullRune(data) {
// Incomplete; get more bytes.
return 0, nil, nil
}
// We have a real UTF-8 encoding error. Return a properly encoded error rune
// but advance only one byte. This matches the behavior of a range loop over
// an incorrectly encoded string.
return 1, errorRune, nil
}
// dropCR drops a terminal \r from the data.
func dropCR(data []byte) []byte {
if len(data) > 0 && data[len(data)-1] == '\r' {
return data[0 : len(data)-1]
}
return data
}
// ScanLines is a split function for a Scanner that returns each line of
// text, stripped of any trailing end-of-line marker. The returned line may
// be empty. The end-of-line marker is one optional carriage return followed
// by one mandatory newline. In regular expression notation, it is `\r?\n`.
// The last non-empty line of input will be returned even if it has no
// newline.
func ScanLines(data []byte, atEOF bool) (advance int, token []byte, err error) {
if atEOF && len(data) == 0 {
return 0, nil, nil
}
if i := bytes.IndexByte(data, '\n'); i >= 0 {
// We have a full newline-terminated line.
return i + 1, dropCR(data[0:i]), nil
}
// If we're at EOF, we have a final, non-terminated line. Return it.
if atEOF {
return len(data), dropCR(data), nil
}
// Request more data.
return 0, nil, nil
}
// isSpace returns whether the character is a Unicode white space character.
// We avoid dependency on the unicode package, but check validity of the implementation
// in the tests.
func isSpace(r rune) bool {
if r <= '\u00FF' {
// Obvious ASCII ones: \t through \r plus space. Plus two Latin-1 oddballs.
switch r {
case ' ', '\t', '\n', '\v', '\f', '\r':
return true
case '\u0085', '\u00A0':
return true
}
return false
}
// High-valued ones.
if '\u2000' <= r && r <= '\u200a' {
return true
}
switch r {
case '\u1680', '\u180e', '\u2028', '\u2029', '\u202f', '\u205f', '\u3000':
return true
}
return false
}
// ScanWords is a split function for a Scanner that returns each
// space-separated word of text, with surrounding spaces deleted. It will
// never return an empty string. The definition of space is set by
// unicode.IsSpace.
func ScanWords(data []byte, atEOF bool) (advance int, token []byte, err error) {
// Skip leading spaces.
start := 0
for width := 0; start < len(data); start += width {
var r rune
r, width = utf8.DecodeRune(data[start:])
if !isSpace(r) {
break
}
}
if atEOF && len(data) == 0 {
return 0, nil, nil
}
// Scan until space, marking end of word.
for width, i := 0, start; i < len(data); i += width {
var r rune
r, width = utf8.DecodeRune(data[i:])
if isSpace(r) {
return i + width, data[start:i], nil
}
}
// If we're at EOF, we have a final, non-empty, non-terminated word. Return it.
if atEOF && len(data) > start {
return len(data), data[start:], nil
}
// Request more data.
return 0, nil, nil
}

406
libgo/go/bufio/scan_test.go Normal file
View File

@ -0,0 +1,406 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bufio_test
import (
. "bufio"
"bytes"
"errors"
"io"
"strings"
"testing"
"unicode"
"unicode/utf8"
)
// Test white space table matches the Unicode definition.
func TestSpace(t *testing.T) {
for r := rune(0); r <= utf8.MaxRune; r++ {
if IsSpace(r) != unicode.IsSpace(r) {
t.Fatalf("white space property disagrees: %#U should be %t", r, unicode.IsSpace(r))
}
}
}
var scanTests = []string{
"",
"a",
"¼",
"☹",
"\x81", // UTF-8 error
"\uFFFD", // correctly encoded RuneError
"abcdefgh",
"abc def\n\t\tgh ",
"abc¼☹\x81\uFFFD日本語\x82abc",
}
func TestScanByte(t *testing.T) {
for n, test := range scanTests {
buf := bytes.NewBufferString(test)
s := NewScanner(buf)
s.Split(ScanBytes)
var i int
for i = 0; s.Scan(); i++ {
if b := s.Bytes(); len(b) != 1 || b[0] != test[i] {
t.Errorf("#%d: %d: expected %q got %q", n, i, test, b)
}
}
if i != len(test) {
t.Errorf("#%d: termination expected at %d; got %d", n, len(test), i)
}
err := s.Err()
if err != nil {
t.Errorf("#%d: %v", n, err)
}
}
}
// Test that the rune splitter returns same sequence of runes (not bytes) as for range string.
func TestScanRune(t *testing.T) {
for n, test := range scanTests {
buf := bytes.NewBufferString(test)
s := NewScanner(buf)
s.Split(ScanRunes)
var i, runeCount int
var expect rune
// Use a string range loop to validate the sequence of runes.
for i, expect = range string(test) {
if !s.Scan() {
break
}
runeCount++
got, _ := utf8.DecodeRune(s.Bytes())
if got != expect {
t.Errorf("#%d: %d: expected %q got %q", n, i, expect, got)
}
}
if s.Scan() {
t.Errorf("#%d: scan ran too long, got %q", n, s.Text())
}
testRuneCount := utf8.RuneCountInString(test)
if runeCount != testRuneCount {
t.Errorf("#%d: termination expected at %d; got %d", n, testRuneCount, runeCount)
}
err := s.Err()
if err != nil {
t.Errorf("#%d: %v", n, err)
}
}
}
var wordScanTests = []string{
"",
" ",
"\n",
"a",
" a ",
"abc def",
" abc def ",
" abc\tdef\nghi\rjkl\fmno\vpqr\u0085stu\u00a0\n",
}
// Test that the word splitter returns the same data as strings.Fields.
func TestScanWords(t *testing.T) {
for n, test := range wordScanTests {
buf := bytes.NewBufferString(test)
s := NewScanner(buf)
s.Split(ScanWords)
words := strings.Fields(test)
var wordCount int
for wordCount = 0; wordCount < len(words); wordCount++ {
if !s.Scan() {
break
}
got := s.Text()
if got != words[wordCount] {
t.Errorf("#%d: %d: expected %q got %q", n, wordCount, words[wordCount], got)
}
}
if s.Scan() {
t.Errorf("#%d: scan ran too long, got %q", n, s.Text())
}
if wordCount != len(words) {
t.Errorf("#%d: termination expected at %d; got %d", n, len(words), wordCount)
}
err := s.Err()
if err != nil {
t.Errorf("#%d: %v", n, err)
}
}
}
// slowReader is a reader that returns only a few bytes at a time, to test the incremental
// reads in Scanner.Scan.
type slowReader struct {
max int
buf *bytes.Buffer
}
func (sr *slowReader) Read(p []byte) (n int, err error) {
if len(p) > sr.max {
p = p[0:sr.max]
}
return sr.buf.Read(p)
}
// genLine writes to buf a predictable but non-trivial line of text of length
// n, including the terminal newline and an occasional carriage return.
// If addNewline is false, the \r and \n are not emitted.
func genLine(buf *bytes.Buffer, lineNum, n int, addNewline bool) {
buf.Reset()
doCR := lineNum%5 == 0
if doCR {
n--
}
for i := 0; i < n-1; i++ { // Stop early for \n.
c := 'a' + byte(lineNum+i)
if c == '\n' || c == '\r' { // Don't confuse us.
c = 'N'
}
buf.WriteByte(c)
}
if addNewline {
if doCR {
buf.WriteByte('\r')
}
buf.WriteByte('\n')
}
return
}
// Test the line splitter, including some carriage returns but no long lines.
func TestScanLongLines(t *testing.T) {
const smallMaxTokenSize = 256 // Much smaller for more efficient testing.
// Build a buffer of lots of line lengths up to but not exceeding smallMaxTokenSize.
tmp := new(bytes.Buffer)
buf := new(bytes.Buffer)
lineNum := 0
j := 0
for i := 0; i < 2*smallMaxTokenSize; i++ {
genLine(tmp, lineNum, j, true)
if j < smallMaxTokenSize {
j++
} else {
j--
}
buf.Write(tmp.Bytes())
lineNum++
}
s := NewScanner(&slowReader{1, buf})
s.Split(ScanLines)
s.MaxTokenSize(smallMaxTokenSize)
j = 0
for lineNum := 0; s.Scan(); lineNum++ {
genLine(tmp, lineNum, j, false)
if j < smallMaxTokenSize {
j++
} else {
j--
}
line := tmp.String() // We use the string-valued token here, for variety.
if s.Text() != line {
t.Errorf("%d: bad line: %d %d\n%.100q\n%.100q\n", lineNum, len(s.Bytes()), len(line), s.Text(), line)
}
}
err := s.Err()
if err != nil {
t.Fatal(err)
}
}
// Test that the line splitter errors out on a long line.
func TestScanLineTooLong(t *testing.T) {
const smallMaxTokenSize = 256 // Much smaller for more efficient testing.
// Build a buffer of lots of line lengths up to but not exceeding smallMaxTokenSize.
tmp := new(bytes.Buffer)
buf := new(bytes.Buffer)
lineNum := 0
j := 0
for i := 0; i < 2*smallMaxTokenSize; i++ {
genLine(tmp, lineNum, j, true)
j++
buf.Write(tmp.Bytes())
lineNum++
}
s := NewScanner(&slowReader{3, buf})
s.Split(ScanLines)
s.MaxTokenSize(smallMaxTokenSize)
j = 0
for lineNum := 0; s.Scan(); lineNum++ {
genLine(tmp, lineNum, j, false)
if j < smallMaxTokenSize {
j++
} else {
j--
}
line := tmp.Bytes()
if !bytes.Equal(s.Bytes(), line) {
t.Errorf("%d: bad line: %d %d\n%.100q\n%.100q\n", lineNum, len(s.Bytes()), len(line), s.Bytes(), line)
}
}
err := s.Err()
if err != ErrTooLong {
t.Fatalf("expected ErrTooLong; got %s", err)
}
}
// Test that the line splitter handles a final line without a newline.
func testNoNewline(text string, lines []string, t *testing.T) {
buf := bytes.NewBufferString(text)
s := NewScanner(&slowReader{7, buf})
s.Split(ScanLines)
for lineNum := 0; s.Scan(); lineNum++ {
line := lines[lineNum]
if s.Text() != line {
t.Errorf("%d: bad line: %d %d\n%.100q\n%.100q\n", lineNum, len(s.Bytes()), len(line), s.Bytes(), line)
}
}
err := s.Err()
if err != nil {
t.Fatal(err)
}
}
var noNewlineLines = []string{
"abcdefghijklmn\nopqrstuvwxyz",
}
// Test that the line splitter handles a final line without a newline.
func TestScanLineNoNewline(t *testing.T) {
const text = "abcdefghijklmn\nopqrstuvwxyz"
lines := []string{
"abcdefghijklmn",
"opqrstuvwxyz",
}
testNoNewline(text, lines, t)
}
// Test that the line splitter handles a final line with a carriage return but nonewline.
func TestScanLineReturnButNoNewline(t *testing.T) {
const text = "abcdefghijklmn\nopqrstuvwxyz\r"
lines := []string{
"abcdefghijklmn",
"opqrstuvwxyz",
}
testNoNewline(text, lines, t)
}
// Test that the line splitter handles a final empty line.
func TestScanLineEmptyFinalLine(t *testing.T) {
const text = "abcdefghijklmn\nopqrstuvwxyz\n\n"
lines := []string{
"abcdefghijklmn",
"opqrstuvwxyz",
"",
}
testNoNewline(text, lines, t)
}
// Test that the line splitter handles a final empty line with a carriage return but no newline.
func TestScanLineEmptyFinalLineWithCR(t *testing.T) {
const text = "abcdefghijklmn\nopqrstuvwxyz\n\r"
lines := []string{
"abcdefghijklmn",
"opqrstuvwxyz",
"",
}
testNoNewline(text, lines, t)
}
var testError = errors.New("testError")
// Test the correct error is returned when the split function errors out.
func TestSplitError(t *testing.T) {
// Create a split function that delivers a little data, then a predictable error.
numSplits := 0
const okCount = 7
errorSplit := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
if atEOF {
panic("didn't get enough data")
}
if numSplits >= okCount {
return 0, nil, testError
}
numSplits++
return 1, data[0:1], nil
}
// Read the data.
const text = "abcdefghijklmnopqrstuvwxyz"
buf := bytes.NewBufferString(text)
s := NewScanner(&slowReader{1, buf})
s.Split(errorSplit)
var i int
for i = 0; s.Scan(); i++ {
if len(s.Bytes()) != 1 || text[i] != s.Bytes()[0] {
t.Errorf("#%d: expected %q got %q", i, text[i], s.Bytes()[0])
}
}
// Check correct termination location and error.
if i != okCount {
t.Errorf("unexpected termination; expected %d tokens got %d", okCount, i)
}
err := s.Err()
if err != testError {
t.Fatalf("expected %q got %v", testError, err)
}
}
// Test that an EOF is overridden by a user-generated scan error.
func TestErrAtEOF(t *testing.T) {
s := NewScanner(strings.NewReader("1 2 33"))
// This spitter will fail on last entry, after s.err==EOF.
split := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
advance, token, err = ScanWords(data, atEOF)
if len(token) > 1 {
if s.ErrOrEOF() != io.EOF {
t.Fatal("not testing EOF")
}
err = testError
}
return
}
s.Split(split)
for s.Scan() {
}
if s.Err() != testError {
t.Fatal("wrong error:", s.Err())
}
}
// Test for issue 5268.
type alwaysError struct{}
func (alwaysError) Read(p []byte) (int, error) {
return 0, io.ErrUnexpectedEOF
}
func TestNonEOFWithEmptyRead(t *testing.T) {
scanner := NewScanner(alwaysError{})
for scanner.Scan() {
t.Fatal("read should fail")
}
err := scanner.Err()
if err != io.ErrUnexpectedEOF {
t.Errorf("unexpected error: %v", err)
}
}
// Test that Scan finishes if we have endless empty reads.
type endlessZeros struct{}
func (endlessZeros) Read(p []byte) (int, error) {
return 0, nil
}
func TestBadReader(t *testing.T) {
scanner := NewScanner(endlessZeros{})
for scanner.Scan() {
t.Fatal("read should fail")
}
err := scanner.Err()
if err != io.ErrNoProgress {
t.Errorf("unexpected error: %v", err)
}
}

View File

@ -13,6 +13,12 @@ package builtin
// bool is the set of boolean values, true and false.
type bool bool
// true and false are the two untyped boolean values.
const (
true = 0 == 0 // Untyped bool.
false = 0 != 0 // Untyped bool.
)
// uint8 is the set of all unsigned 8-bit integers.
// Range: 0 through 255.
type uint8 uint8
@ -85,6 +91,15 @@ type byte byte
// used, by convention, to distinguish character values from integer values.
type rune rune
// iota is a predeclared identifier representing the untyped integer ordinal
// number of the current const specification in a (usually parenthesized)
// const declaration. It is zero-indexed.
const iota = 0 // Untyped int.
// nil is a predeclared identifier representing the zero value for a
// pointer, channel, func, interface, map, or slice type.
var nil Type // Type must be a pointer, channel, func, interface, map, or slice type
// Type is here for the purposes of documentation only. It is a stand-in
// for any Go type, but represents the same type for any given function
// invocation.
@ -114,6 +129,8 @@ type ComplexType complex64
// result of append, often in the variable holding the slice itself:
// slice = append(slice, elem1, elem2)
// slice = append(slice, anotherSlice...)
// As a special case, it is legal to append a string to a byte slice, like this:
// slice = append([]byte("hello "), "world"...)
func append(slice []Type, elems ...Type) []Type
// The copy built-in function copies elements from a source slice into a

View File

@ -87,6 +87,13 @@ func (b *Buffer) grow(n int) int {
var buf []byte
if b.buf == nil && n <= len(b.bootstrap) {
buf = b.bootstrap[0:]
} else if m+n <= cap(b.buf)/2 {
// We can slide things down instead of allocating a new
// slice. We only need m+n <= cap(b.buf) to slide, but
// we instead let capacity get twice as large so we
// don't spend all our time copying.
copy(b.buf[:], b.buf[b.off:])
buf = b.buf[:m]
} else {
// not enough space anywhere
buf = makeSlice(2*cap(b.buf) + n)
@ -112,20 +119,18 @@ func (b *Buffer) Grow(n int) {
b.buf = b.buf[0:m]
}
// Write appends the contents of p to the buffer. The return
// value n is the length of p; err is always nil.
// If the buffer becomes too large, Write will panic with
// ErrTooLarge.
// Write appends the contents of p to the buffer, growing the buffer as
// needed. The return value n is the length of p; err is always nil. If the
// buffer becomes too large, Write will panic with ErrTooLarge.
func (b *Buffer) Write(p []byte) (n int, err error) {
b.lastRead = opInvalid
m := b.grow(len(p))
return copy(b.buf[m:], p), nil
}
// WriteString appends the contents of s to the buffer. The return
// value n is the length of s; err is always nil.
// If the buffer becomes too large, WriteString will panic with
// ErrTooLarge.
// WriteString appends the contents of s to the buffer, growing the buffer as
// needed. The return value n is the length of s; err is always nil. If the
// buffer becomes too large, WriteString will panic with ErrTooLarge.
func (b *Buffer) WriteString(s string) (n int, err error) {
b.lastRead = opInvalid
m := b.grow(len(s))
@ -138,12 +143,10 @@ func (b *Buffer) WriteString(s string) (n int, err error) {
// underlying buffer.
const MinRead = 512
// ReadFrom reads data from r until EOF and appends it to the buffer.
// The return value n is the number of bytes read.
// Any error except io.EOF encountered during the read
// is also returned.
// If the buffer becomes too large, ReadFrom will panic with
// ErrTooLarge.
// ReadFrom reads data from r until EOF and appends it to the buffer, growing
// the buffer as needed. The return value n is the number of bytes read. Any
// error except io.EOF encountered during the read is also returned. If the
// buffer becomes too large, ReadFrom will panic with ErrTooLarge.
func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) {
b.lastRead = opInvalid
// If buffer is empty, reset to recover space.
@ -188,10 +191,10 @@ func makeSlice(n int) []byte {
return make([]byte, n)
}
// WriteTo writes data to w until the buffer is drained or an error
// occurs. The return value n is the number of bytes written; it always
// fits into an int, but it is int64 to match the io.WriterTo interface.
// Any error encountered during the write is also returned.
// WriteTo writes data to w until the buffer is drained or an error occurs.
// The return value n is the number of bytes written; it always fits into an
// int, but it is int64 to match the io.WriterTo interface. Any error
// encountered during the write is also returned.
func (b *Buffer) WriteTo(w io.Writer) (n int64, err error) {
b.lastRead = opInvalid
if b.off < len(b.buf) {
@ -216,10 +219,9 @@ func (b *Buffer) WriteTo(w io.Writer) (n int64, err error) {
return
}
// WriteByte appends the byte c to the buffer.
// The returned error is always nil, but is included
// to match bufio.Writer's WriteByte.
// If the buffer becomes too large, WriteByte will panic with
// WriteByte appends the byte c to the buffer, growing the buffer as needed.
// The returned error is always nil, but is included to match bufio.Writer's
// WriteByte. If the buffer becomes too large, WriteByte will panic with
// ErrTooLarge.
func (b *Buffer) WriteByte(c byte) error {
b.lastRead = opInvalid
@ -228,12 +230,10 @@ func (b *Buffer) WriteByte(c byte) error {
return nil
}
// WriteRune appends the UTF-8 encoding of Unicode
// code point r to the buffer, returning its length and
// an error, which is always nil but is included
// to match bufio.Writer's WriteRune.
// If the buffer becomes too large, WriteRune will panic with
// ErrTooLarge.
// WriteRune appends the UTF-8 encoding of Unicode code point r to the
// buffer, returning its length and an error, which is always nil but is
// included to match bufio.Writer's WriteRune. The buffer is grown as needed;
// if it becomes too large, WriteRune will panic with ErrTooLarge.
func (b *Buffer) WriteRune(r rune) (n int, err error) {
if r < utf8.RuneSelf {
b.WriteByte(byte(r))

View File

@ -475,3 +475,53 @@ func TestUnreadByte(t *testing.T) {
t.Errorf("ReadByte = %q; want %q", c, 'm')
}
}
// Tests that we occasionally compact. Issue 5154.
func TestBufferGrowth(t *testing.T) {
var b Buffer
buf := make([]byte, 1024)
b.Write(buf[0:1])
var cap0 int
for i := 0; i < 5<<10; i++ {
b.Write(buf)
b.Read(buf)
if i == 0 {
cap0 = b.Cap()
}
}
cap1 := b.Cap()
// (*Buffer).grow allows for 2x capacity slop before sliding,
// so set our error threshold at 3x.
if cap1 > cap0*3 {
t.Errorf("buffer cap = %d; too big (grew from %d)", cap1, cap0)
}
}
// From Issue 5154.
func BenchmarkBufferNotEmptyWriteRead(b *testing.B) {
buf := make([]byte, 1024)
for i := 0; i < b.N; i++ {
var b Buffer
b.Write(buf[0:1])
for i := 0; i < 5<<10; i++ {
b.Write(buf)
b.Read(buf)
}
}
}
// Check that we don't compact too often. From Issue 5154.
func BenchmarkBufferFullSmallReads(b *testing.B) {
buf := make([]byte, 1024)
for i := 0; i < b.N; i++ {
var b Buffer
b.Write(buf)
for b.Len()+20 < b.Cap() {
b.Write(buf[:10])
}
for i := 0; i < 5<<10; i++ {
b.Read(buf[:1])
b.Write(buf[:1])
}
}
}

View File

@ -37,10 +37,6 @@ func Compare(a, b []byte) int {
return 0
}
// Equal returns a boolean reporting whether a == b.
// A nil argument is equivalent to an empty slice.
func Equal(a, b []byte) bool
func equalPortable(a, b []byte) bool {
if len(a) != len(b) {
return false
@ -465,10 +461,10 @@ func isSeparator(r rune) bool {
return unicode.IsSpace(r)
}
// BUG(r): The rule Title uses for word boundaries does not handle Unicode punctuation properly.
// Title returns a copy of s with all Unicode letters that begin words
// mapped to their title case.
//
// BUG: The rule Title uses for word boundaries does not handle Unicode punctuation properly.
func Title(s []byte) []byte {
// Use a closure here to remember state.
// Hackish but effective. Depends on Map scanning in order and calling
@ -515,6 +511,24 @@ func TrimFunc(s []byte, f func(r rune) bool) []byte {
return TrimRightFunc(TrimLeftFunc(s, f), f)
}
// TrimPrefix returns s without the provided leading prefix string.
// If s doesn't start with prefix, s is returned unchanged.
func TrimPrefix(s, prefix []byte) []byte {
if HasPrefix(s, prefix) {
return s[len(prefix):]
}
return s
}
// TrimSuffix returns s without the provided trailing suffix string.
// If s doesn't end with suffix, s is returned unchanged.
func TrimSuffix(s, suffix []byte) []byte {
if HasSuffix(s, suffix) {
return s[:len(s)-len(suffix)]
}
return s
}
// IndexFunc interprets s as a sequence of UTF-8-encoded Unicode code points.
// It returns the byte index in s of the first Unicode
// code point satisfying f(c), or -1 if none do.
@ -553,7 +567,10 @@ func indexFunc(s []byte, f func(r rune) bool, truth bool) int {
// inverted.
func lastIndexFunc(s []byte, f func(r rune) bool, truth bool) int {
for i := len(s); i > 0; {
r, size := utf8.DecodeLastRune(s[0:i])
r, size := rune(s[i-1]), 1
if r >= utf8.RuneSelf {
r, size = utf8.DecodeLastRune(s[0:i])
}
i -= size
if f(r) == truth {
return i

View File

@ -4,5 +4,13 @@
package bytes
//go:noescape
// IndexByte returns the index of the first instance of c in s, or -1 if c is not present in s.
func IndexByte(s []byte, c byte) int // asm_$GOARCH.s
//go:noescape
// Equal returns a boolean reporting whether a == b.
// A nil argument is equivalent to an empty slice.
func Equal(a, b []byte) bool // asm_arm.s or ../runtime/asm_{386,amd64}.s

View File

@ -61,6 +61,10 @@ var compareTests = []struct {
{[]byte("ab"), []byte("x"), -1},
{[]byte("x"), []byte("a"), 1},
{[]byte("b"), []byte("x"), -1},
// test runtime·memeq's chunked implementation
{[]byte("abcdefgh"), []byte("abcdefgh"), 0},
{[]byte("abcdefghi"), []byte("abcdefghi"), 0},
{[]byte("abcdefghi"), []byte("abcdefghj"), -1},
// nil tests
{nil, nil, 0},
{[]byte(""), nil, 0},
@ -86,6 +90,58 @@ func TestCompare(t *testing.T) {
}
}
func TestEqual(t *testing.T) {
var size = 128
if testing.Short() {
size = 32
}
a := make([]byte, size)
b := make([]byte, size)
b_init := make([]byte, size)
// randomish but deterministic data
for i := 0; i < size; i++ {
a[i] = byte(17 * i)
b_init[i] = byte(23*i + 100)
}
for len := 0; len <= size; len++ {
for x := 0; x <= size-len; x++ {
for y := 0; y <= size-len; y++ {
copy(b, b_init)
copy(b[y:y+len], a[x:x+len])
if !Equal(a[x:x+len], b[y:y+len]) || !Equal(b[y:y+len], a[x:x+len]) {
t.Errorf("Equal(%d, %d, %d) = false", len, x, y)
}
}
}
}
}
// make sure Equal returns false for minimally different strings. The data
// is all zeros except for a single one in one location.
func TestNotEqual(t *testing.T) {
var size = 128
if testing.Short() {
size = 32
}
a := make([]byte, size)
b := make([]byte, size)
for len := 0; len <= size; len++ {
for x := 0; x <= size-len; x++ {
for y := 0; y <= size-len; y++ {
for diffpos := x; diffpos < x+len; diffpos++ {
a[diffpos] = 1
if Equal(a[x:x+len], b[y:y+len]) || Equal(b[y:y+len], a[x:x+len]) {
t.Errorf("NotEqual(%d, %d, %d, %d) = true", len, x, y, diffpos)
}
a[diffpos] = 0
}
}
}
}
}
var indexTests = []BinOpTest{
{"", "", 0},
{"", "a", -1},
@ -303,10 +359,30 @@ func bmIndexByte(b *testing.B, index func([]byte, byte) int, n int) {
buf[n-1] = '\x00'
}
func BenchmarkEqual0(b *testing.B) {
var buf [4]byte
buf1 := buf[0:0]
buf2 := buf[1:1]
for i := 0; i < b.N; i++ {
eq := Equal(buf1, buf2)
if !eq {
b.Fatal("bad equal")
}
}
}
func BenchmarkEqual1(b *testing.B) { bmEqual(b, Equal, 1) }
func BenchmarkEqual6(b *testing.B) { bmEqual(b, Equal, 6) }
func BenchmarkEqual9(b *testing.B) { bmEqual(b, Equal, 9) }
func BenchmarkEqual15(b *testing.B) { bmEqual(b, Equal, 15) }
func BenchmarkEqual16(b *testing.B) { bmEqual(b, Equal, 16) }
func BenchmarkEqual20(b *testing.B) { bmEqual(b, Equal, 20) }
func BenchmarkEqual32(b *testing.B) { bmEqual(b, Equal, 32) }
func BenchmarkEqual4K(b *testing.B) { bmEqual(b, Equal, 4<<10) }
func BenchmarkEqual4M(b *testing.B) { bmEqual(b, Equal, 4<<20) }
func BenchmarkEqual64M(b *testing.B) { bmEqual(b, Equal, 64<<20) }
func BenchmarkEqualPort1(b *testing.B) { bmEqual(b, EqualPortable, 1) }
func BenchmarkEqualPort6(b *testing.B) { bmEqual(b, EqualPortable, 6) }
func BenchmarkEqualPort32(b *testing.B) { bmEqual(b, EqualPortable, 32) }
func BenchmarkEqualPort4K(b *testing.B) { bmEqual(b, EqualPortable, 4<<10) }
func BenchmarkEqualPortable4M(b *testing.B) { bmEqual(b, EqualPortable, 4<<20) }
@ -794,8 +870,8 @@ func TestRunes(t *testing.T) {
}
type TrimTest struct {
f string
in, cutset, out string
f string
in, arg, out string
}
var trimTests = []TrimTest{
@ -820,12 +896,17 @@ var trimTests = []TrimTest{
{"TrimRight", "", "123", ""},
{"TrimRight", "", "", ""},
{"TrimRight", "☺\xc0", "☺", "☺\xc0"},
{"TrimPrefix", "aabb", "a", "abb"},
{"TrimPrefix", "aabb", "b", "aabb"},
{"TrimSuffix", "aabb", "a", "aabb"},
{"TrimSuffix", "aabb", "b", "aab"},
}
func TestTrim(t *testing.T) {
for _, tc := range trimTests {
name := tc.f
var f func([]byte, string) []byte
var fb func([]byte, []byte) []byte
switch name {
case "Trim":
f = Trim
@ -833,12 +914,21 @@ func TestTrim(t *testing.T) {
f = TrimLeft
case "TrimRight":
f = TrimRight
case "TrimPrefix":
fb = TrimPrefix
case "TrimSuffix":
fb = TrimSuffix
default:
t.Errorf("Undefined trim function %s", name)
}
actual := string(f([]byte(tc.in), tc.cutset))
var actual string
if f != nil {
actual = string(f([]byte(tc.in), tc.arg))
} else {
actual = string(fb([]byte(tc.in), []byte(tc.arg)))
}
if actual != tc.out {
t.Errorf("%s(%q, %q) = %q; want %q", name, tc.in, tc.cutset, actual, tc.out)
t.Errorf("%s(%q, %q) = %q; want %q", name, tc.in, tc.arg, actual, tc.out)
}
}
}
@ -1059,3 +1149,10 @@ func BenchmarkFieldsFunc(b *testing.B) {
FieldsFunc(fieldsInput, unicode.IsSpace)
}
}
func BenchmarkTrimSpace(b *testing.B) {
s := []byte(" Some text. \n")
for i := 0; i < b.N; i++ {
TrimSpace(s)
}
}

View File

@ -0,0 +1,47 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
// +build linux
package bytes_test
import (
. "bytes"
"syscall"
"testing"
"unsafe"
)
// This file tests the situation where memeq is checking
// data very near to a page boundary. We want to make sure
// equal does not read across the boundary and cause a page
// fault where it shouldn't.
// This test runs only on linux. The code being tested is
// not OS-specific, so it does not need to be tested on all
// operating systems.
func TestEqualNearPageBoundary(t *testing.T) {
pagesize := syscall.Getpagesize()
b := make([]byte, 4*pagesize)
i := pagesize
for ; uintptr(unsafe.Pointer(&b[i]))%uintptr(pagesize) != 0; i++ {
}
syscall.Mprotect(b[i-pagesize:i], 0)
syscall.Mprotect(b[i+pagesize:i+2*pagesize], 0)
defer syscall.Mprotect(b[i-pagesize:i], syscall.PROT_READ|syscall.PROT_WRITE)
defer syscall.Mprotect(b[i+pagesize:i+2*pagesize], syscall.PROT_READ|syscall.PROT_WRITE)
// both of these should fault
//pagesize += int(b[i-1])
//pagesize += int(b[i+pagesize])
for j := 0; j < pagesize; j++ {
b[i+j] = 'A'
}
for j := 0; j <= pagesize; j++ {
Equal(b[i:i+j], b[i+pagesize-j:i+pagesize])
Equal(b[i+pagesize-j:i+pagesize], b[i:i+j])
}
}

View File

@ -66,3 +66,20 @@ func ExampleCompare_search() {
// Found it!
}
}
func ExampleTrimSuffix() {
var b = []byte("Hello, goodbye, etc!")
b = bytes.TrimSuffix(b, []byte("goodbye, etc!"))
b = bytes.TrimSuffix(b, []byte("gopher"))
b = append(b, bytes.TrimSuffix([]byte("world!"), []byte("x!"))...)
os.Stdout.Write(b)
// Output: Hello, world!
}
func ExampleTrimPrefix() {
var b = []byte("Goodbye,, world!")
b = bytes.TrimPrefix(b, []byte("Goodbye,"))
b = bytes.TrimPrefix(b, []byte("See ya,"))
fmt.Printf("Hello%s", b)
// Output: Hello, world!
}

View File

@ -7,3 +7,7 @@ package bytes
// Export func for testing
var IndexBytePortable = indexBytePortable
var EqualPortable = equalPortable
func (b *Buffer) Cap() int {
return cap(b.buf)
}

View File

@ -54,8 +54,6 @@ func (t huffmanTree) Decode(br *bitReader) (v uint16) {
nodeIndex = node.right
}
}
panic("unreachable")
}
// newHuffmanTree builds a Huffman tree from a slice containing the code

View File

@ -158,7 +158,6 @@ func (b *syncBuffer) Read(p []byte) (n int, err error) {
}
<-b.ready
}
panic("unreachable")
}
func (b *syncBuffer) signal() {

View File

@ -263,7 +263,6 @@ func (f *decompressor) Read(b []byte) (int, error) {
}
f.step(f)
}
panic("unreachable")
}
func (f *decompressor) Close() error {
@ -495,7 +494,6 @@ func (f *decompressor) huffmanBlock() {
return
}
}
panic("unreached")
}
// copyHist copies f.copyLen bytes from f.hist (f.copyDist bytes ago) to itself.
@ -642,7 +640,6 @@ func (f *decompressor) huffSym(h *huffmanDecoder) (int, error) {
return int(chunk >> huffmanValueShift), nil
}
}
return 0, CorruptInputError(f.roffset)
}
// Flush any buffered output to the underlying writer.

View File

@ -99,5 +99,4 @@ func offsetCode(off uint32) uint32 {
default:
return offsetCodes[off>>14] + 28
}
panic("unreachable")
}

View File

@ -120,7 +120,6 @@ func (z *Reader) readString() (string, error) {
return string(z.buf[0:i]), nil
}
}
panic("not reached")
}
func (z *Reader) read2() (uint32, error) {

View File

@ -28,7 +28,7 @@ type Writer struct {
Header
w io.Writer
level int
compressor io.WriteCloser
compressor *flate.Writer
digest hash.Hash32
size uint32
closed bool
@ -191,6 +191,28 @@ func (z *Writer) Write(p []byte) (int, error) {
return n, z.err
}
// Flush flushes any pending compressed data to the underlying writer.
//
// It is useful mainly in compressed network protocols, to ensure that
// a remote reader has enough data to reconstruct a packet. Flush does
// not return until the data has been written. If the underlying
// writer returns an error, Flush returns that error.
//
// In the terminology of the zlib library, Flush is equivalent to Z_SYNC_FLUSH.
func (z *Writer) Flush() error {
if z.err != nil {
return z.err
}
if z.closed {
return nil
}
if z.compressor == nil {
z.Write(nil)
}
z.err = z.compressor.Flush()
return z.err
}
// Close closes the Writer. It does not close the underlying io.Writer.
func (z *Writer) Close() error {
if z.err != nil {

View File

@ -157,3 +157,43 @@ func TestLatin1RoundTrip(t *testing.T) {
}
}
}
func TestWriterFlush(t *testing.T) {
buf := new(bytes.Buffer)
w := NewWriter(buf)
w.Comment = "comment"
w.Extra = []byte("extra")
w.ModTime = time.Unix(1e8, 0)
w.Name = "name"
n0 := buf.Len()
if n0 != 0 {
t.Fatalf("buffer size = %d before writes; want 0", n0)
}
if err := w.Flush(); err != nil {
t.Fatal(err)
}
n1 := buf.Len()
if n1 == 0 {
t.Fatal("no data after first flush")
}
w.Write([]byte("x"))
n2 := buf.Len()
if n1 != n2 {
t.Fatalf("after writing a single byte, size changed from %d to %d; want no change", n1, n2)
}
if err := w.Flush(); err != nil {
t.Fatal(err)
}
n3 := buf.Len()
if n2 == n3 {
t.Fatal("Flush didn't flush any data")
}
}

View File

@ -121,7 +121,6 @@ func (d *decoder) Read(b []byte) (int, error) {
}
d.decode()
}
panic("unreachable")
}
// decode decompresses bytes from r and leaves them in d.toRead.
@ -203,7 +202,6 @@ func (d *decoder) decode() {
return
}
}
panic("unreachable")
}
func (d *decoder) flush() {

View File

@ -1,100 +0,0 @@
// Copyright 2012 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.
// This example demonstrates a priority queue built using the heap interface.
package heap_test
import (
"container/heap"
"fmt"
)
// An Item is something we manage in a priority queue.
type Item struct {
value string // The value of the item; arbitrary.
priority int // The priority of the item in the queue.
// The index is needed by changePriority and is maintained by the heap.Interface methods.
index int // The index of the item in the heap.
}
// A PriorityQueue implements heap.Interface and holds Items.
type PriorityQueue []*Item
func (pq PriorityQueue) Len() int { return len(pq) }
func (pq PriorityQueue) Less(i, j int) bool {
// We want Pop to give us the highest, not lowest, priority so we use greater than here.
return pq[i].priority > pq[j].priority
}
func (pq PriorityQueue) Swap(i, j int) {
pq[i], pq[j] = pq[j], pq[i]
pq[i].index = i
pq[j].index = j
}
func (pq *PriorityQueue) Push(x interface{}) {
// Push and Pop use pointer receivers because they modify the slice's length,
// not just its contents.
n := len(*pq)
item := x.(*Item)
item.index = n
*pq = append(*pq, item)
}
func (pq *PriorityQueue) Pop() interface{} {
a := *pq
n := len(a)
item := a[n-1]
item.index = -1 // for safety
*pq = a[0 : n-1]
return item
}
// update is not used by the example but shows how to take the top item from
// the queue, update its priority and value, and put it back.
func (pq *PriorityQueue) update(value string, priority int) {
item := heap.Pop(pq).(*Item)
item.value = value
item.priority = priority
heap.Push(pq, item)
}
// changePriority is not used by the example but shows how to change the
// priority of an arbitrary item.
func (pq *PriorityQueue) changePriority(item *Item, priority int) {
heap.Remove(pq, item.index)
item.priority = priority
heap.Push(pq, item)
}
// This example pushes 10 items into a PriorityQueue and takes them out in
// order of priority.
func Example() {
const nItem = 10
// Random priorities for the items (a permutation of 0..9, times 11)).
priorities := [nItem]int{
77, 22, 44, 55, 11, 88, 33, 99, 00, 66,
}
values := [nItem]string{
"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
}
// Create a priority queue and put some items in it.
pq := make(PriorityQueue, 0, nItem)
for i := 0; i < cap(pq); i++ {
item := &Item{
value: values[i],
priority: priorities[i],
}
heap.Push(&pq, item)
}
// Take the items out; should arrive in decreasing priority order.
// For example, the highest priority (99) is the seventh item, so output starts with 99:"seven".
for i := 0; i < nItem; i++ {
item := heap.Pop(&pq).(*Item)
fmt.Printf("%.2d:%s ", item.priority, item.value)
}
// Output:
// 99:seven 88:five 77:zero 66:nine 55:three 44:two 33:six 22:one 11:four 00:eight
}

View File

@ -4,13 +4,13 @@
// Package heap provides heap operations for any type that implements
// heap.Interface. A heap is a tree with the property that each node is the
// highest-valued node in its subtree.
// minimum-valued node in its subtree.
//
// A heap is a common way to implement a priority queue. To build a priority
// queue, implement the Heap interface with the (negative) priority as the
// ordering for the Less method, so Push adds items while Pop removes the
// highest-priority item from the queue. The Examples include such an
// implementation; the file example_test.go has the complete source.
// implementation; the file example_pq_test.go has the complete source.
//
package heap
@ -90,7 +90,7 @@ func up(h Interface, j int) {
func down(h Interface, i, n int) {
for {
j1 := 2*i + 1
if j1 >= n {
if j1 >= n || j1 < 0 { // j1 < 0 after int overflow
break
}
j := j1 // left child

View File

@ -2,10 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package heap_test
package heap
import (
. "container/heap"
"testing"
)

View File

@ -42,6 +42,12 @@ func NewCBCEncrypter(b Block, iv []byte) BlockMode {
func (x *cbcEncrypter) BlockSize() int { return x.blockSize }
func (x *cbcEncrypter) CryptBlocks(dst, src []byte) {
if len(src)%x.blockSize != 0 {
panic("crypto/cipher: input not full blocks")
}
if len(dst) < len(src) {
panic("crypto/cipher: output smaller than input")
}
for len(src) > 0 {
for i := 0; i < x.blockSize; i++ {
x.iv[i] ^= src[i]
@ -70,6 +76,12 @@ func NewCBCDecrypter(b Block, iv []byte) BlockMode {
func (x *cbcDecrypter) BlockSize() int { return x.blockSize }
func (x *cbcDecrypter) CryptBlocks(dst, src []byte) {
if len(src)%x.blockSize != 0 {
panic("crypto/cipher: input not full blocks")
}
if len(dst) < len(src) {
panic("crypto/cipher: output smaller than input")
}
for len(src) > 0 {
x.b.Decrypt(x.tmp, src[:x.blockSize])
for i := 0; i < x.blockSize; i++ {

View File

@ -0,0 +1,36 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package cipher_test
import (
"crypto/aes"
"crypto/cipher"
"testing"
)
func TestCryptBlocks(t *testing.T) {
buf := make([]byte, 16)
block, _ := aes.NewCipher(buf)
mode := cipher.NewCBCDecrypter(block, buf)
mustPanic(t, "crypto/cipher: input not full blocks", func() { mode.CryptBlocks(buf, buf[:3]) })
mustPanic(t, "crypto/cipher: output smaller than input", func() { mode.CryptBlocks(buf[:3], buf) })
mode = cipher.NewCBCEncrypter(block, buf)
mustPanic(t, "crypto/cipher: input not full blocks", func() { mode.CryptBlocks(buf, buf[:3]) })
mustPanic(t, "crypto/cipher: output smaller than input", func() { mode.CryptBlocks(buf[:3], buf) })
}
func mustPanic(t *testing.T, msg string, f func()) {
defer func() {
err := recover()
if err == nil {
t.Errorf("function did not panic, wanted %q", msg)
} else if err != msg {
t.Errorf("got panic %v, wanted %q", err, msg)
}
}()
f()
}

View File

@ -233,7 +233,7 @@ func ExampleStreamReader() {
}
defer outFile.Close()
reader := &cipher.StreamReader{stream, inFile}
reader := &cipher.StreamReader{S: stream, R: inFile}
// Copy the input file to the output file, decrypting as we go.
if _, err := io.Copy(outFile, reader); err != nil {
panic(err)
@ -270,7 +270,7 @@ func ExampleStreamWriter() {
}
defer outFile.Close()
writer := &cipher.StreamWriter{stream, outFile, nil}
writer := &cipher.StreamWriter{S: stream, W: outFile}
// Copy the input file to the output file, encrypting as we go.
if _, err := io.Copy(writer, inFile); err != nil {
panic(err)

View File

@ -144,8 +144,6 @@ GeneratePrimes:
params.G = g
return
}
panic("unreachable")
}
// GenerateKey generates a public&private key pair. The Parameters of the

View File

@ -63,8 +63,9 @@ func testParameterGeneration(t *testing.T, sizes ParameterSizes, L, N int) {
}
func TestParameterGeneration(t *testing.T) {
// This test is too slow to run all the time.
return
if testing.Short() {
t.Skip("skipping parameter generation test in short mode")
}
testParameterGeneration(t, L1024N160, 1024, 160)
testParameterGeneration(t, L2048N224, 2048, 224)

View File

@ -49,7 +49,7 @@ func randFieldElement(c elliptic.Curve, rand io.Reader) (k *big.Int, err error)
return
}
// GenerateKey generates a public&private key pair.
// GenerateKey generates a public and private key pair.
func GenerateKey(c elliptic.Curve, rand io.Reader) (priv *PrivateKey, err error) {
k, err := randFieldElement(c, rand)
if err != nil {

View File

@ -161,6 +161,11 @@ var data = Data{
}
var program = `
// DO NOT EDIT.
// Generate with: go run gen.go{{if .Full}} -full{{end}} | gofmt >md5block.go
// +build !amd64
package md5
import (
@ -186,6 +191,16 @@ import (
}
{{end}}
const x86 = runtime.GOARCH == "amd64" || runtime.GOARCH == "386"
var littleEndian bool
func init() {
x := uint32(0x04030201)
y := [4]byte{0x1, 0x2, 0x3, 0x4}
littleEndian = *(*[4]byte)(unsafe.Pointer(&x)) == y
}
func block(dig *digest, p []byte) {
a := dig.s[0]
b := dig.s[1]
@ -197,13 +212,13 @@ func block(dig *digest, p []byte) {
aa, bb, cc, dd := a, b, c, d
// This is a constant condition - it is not evaluated on each iteration.
if runtime.GOARCH == "amd64" || runtime.GOARCH == "386" {
if x86 {
// MD5 was designed so that x86 processors can just iterate
// over the block data directly as uint32s, and we generate
// less code and run 1.3x faster if we take advantage of that.
// My apologies.
X = (*[16]uint32)(unsafe.Pointer(&p[0]))
} else if uintptr(unsafe.Pointer(&p[0]))&(unsafe.Alignof(uint32(0))-1) == 0 {
} else if littleEndian && uintptr(unsafe.Pointer(&p[0]))&(unsafe.Alignof(uint32(0))-1) == 0 {
X = (*[16]uint32)(unsafe.Pointer(&p[0]))
} else {
X = &xbuf

View File

@ -2,10 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package md5_test
package md5
import (
"crypto/md5"
"fmt"
"io"
"testing"
@ -54,7 +53,7 @@ var golden = []md5Test{
func TestGolden(t *testing.T) {
for i := 0; i < len(golden); i++ {
g := golden[i]
c := md5.New()
c := New()
buf := make([]byte, len(g.in)+4)
for j := 0; j < 3+4; j++ {
if j < 2 {
@ -79,14 +78,14 @@ func TestGolden(t *testing.T) {
}
func ExampleNew() {
h := md5.New()
h := New()
io.WriteString(h, "The fog is getting thicker!")
io.WriteString(h, "And Leon's getting laaarger!")
fmt.Printf("%x", h.Sum(nil))
// Output: e2c569be17396eca2a2e3c11578123ed
}
var bench = md5.New()
var bench = New()
var buf = make([]byte, 8192+1)
var sum = make([]byte, bench.Size())

View File

@ -1,3 +1,8 @@
// DO NOT EDIT.
// Generate with: go run gen.go -full | gofmt >md5block.go
// +build !amd64,!386
package md5
import (

View File

@ -0,0 +1,9 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build amd64 386
package md5
func block(dig *digest, p []byte)

View File

@ -98,12 +98,13 @@ func Prime(rand io.Reader, bits int) (p *big.Int, err error) {
return
}
}
return
}
// Int returns a uniform random value in [0, max).
// Int returns a uniform random value in [0, max). It panics if max <= 0.
func Int(rand io.Reader, max *big.Int) (n *big.Int, err error) {
if max.Sign() <= 0 {
panic("crypto/rand: argument to Int is <= 0")
}
k := (max.BitLen() + 7) / 8
// b is the number of bits in the most significant byte of max.
@ -130,6 +131,4 @@ func Int(rand io.Reader, max *big.Int) (n *big.Int, err error) {
return
}
}
return
}

View File

@ -13,7 +13,7 @@ import "strconv"
// A Cipher is an instance of RC4 using a particular key.
type Cipher struct {
s [256]byte
s [256]uint32
i, j uint8
}
@ -32,27 +32,16 @@ func NewCipher(key []byte) (*Cipher, error) {
}
var c Cipher
for i := 0; i < 256; i++ {
c.s[i] = uint8(i)
c.s[i] = uint32(i)
}
var j uint8 = 0
for i := 0; i < 256; i++ {
j += c.s[i] + key[i%k]
j += uint8(c.s[i]) + key[i%k]
c.s[i], c.s[j] = c.s[j], c.s[i]
}
return &c, nil
}
// XORKeyStream sets dst to the result of XORing src with the key stream.
// Dst and src may be the same slice but otherwise should not overlap.
func (c *Cipher) XORKeyStream(dst, src []byte) {
for i := range src {
c.i += 1
c.j += c.s[c.i]
c.s[c.i], c.s[c.j] = c.s[c.j], c.s[c.i]
dst[i] = src[i] ^ c.s[c.s[c.i]+c.s[c.j]]
}
}
// Reset zeros the key data so that it will no longer appear in the
// process's memory.
func (c *Cipher) Reset() {

View File

@ -0,0 +1,18 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build amd64 arm 386
package rc4
func xorKeyStream(dst, src *byte, n int, state *[256]uint32, i, j *uint8)
// XORKeyStream sets dst to the result of XORing src with the key stream.
// Dst and src may be the same slice but otherwise should not overlap.
func (c *Cipher) XORKeyStream(dst, src []byte) {
if len(src) == 0 {
return
}
xorKeyStream(&dst[0], &src[0], len(src), &c.s, &c.i, &c.j)
}

View File

@ -0,0 +1,20 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !amd64,!arm,!386
package rc4
// XORKeyStream sets dst to the result of XORing src with the key stream.
// Dst and src may be the same slice but otherwise should not overlap.
func (c *Cipher) XORKeyStream(dst, src []byte) {
i, j := c.i, c.j
for k, v := range src {
i += 1
j += uint8(c.s[i])
c.s[i], c.s[j] = c.s[j], c.s[i]
dst[k] = v ^ byte(c.s[byte(c.s[i]+c.s[j])])
}
c.i, c.j = i, j
}

View File

@ -5,6 +5,8 @@
package rc4
import (
"bytes"
"fmt"
"testing"
)
@ -37,23 +39,124 @@ var golden = []rc4Test{
[]byte{0x57, 0x69, 0x6b, 0x69},
[]byte{0x60, 0x44, 0xdb, 0x6d, 0x41, 0xb7},
},
{
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{
0xde, 0x18, 0x89, 0x41, 0xa3, 0x37, 0x5d, 0x3a,
0x8a, 0x06, 0x1e, 0x67, 0x57, 0x6e, 0x92, 0x6d,
0xc7, 0x1a, 0x7f, 0xa3, 0xf0, 0xcc, 0xeb, 0x97,
0x45, 0x2b, 0x4d, 0x32, 0x27, 0x96, 0x5f, 0x9e,
0xa8, 0xcc, 0x75, 0x07, 0x6d, 0x9f, 0xb9, 0xc5,
0x41, 0x7a, 0xa5, 0xcb, 0x30, 0xfc, 0x22, 0x19,
0x8b, 0x34, 0x98, 0x2d, 0xbb, 0x62, 0x9e, 0xc0,
0x4b, 0x4f, 0x8b, 0x05, 0xa0, 0x71, 0x08, 0x50,
0x92, 0xa0, 0xc3, 0x58, 0x4a, 0x48, 0xe4, 0xa3,
0x0a, 0x39, 0x7b, 0x8a, 0xcd, 0x1d, 0x00, 0x9e,
0xc8, 0x7d, 0x68, 0x11, 0xf2, 0x2c, 0xf4, 0x9c,
0xa3, 0xe5, 0x93, 0x54, 0xb9, 0x45, 0x15, 0x35,
0xa2, 0x18, 0x7a, 0x86, 0x42, 0x6c, 0xca, 0x7d,
0x5e, 0x82, 0x3e, 0xba, 0x00, 0x44, 0x12, 0x67,
0x12, 0x57, 0xb8, 0xd8, 0x60, 0xae, 0x4c, 0xbd,
0x4c, 0x49, 0x06, 0xbb, 0xc5, 0x35, 0xef, 0xe1,
0x58, 0x7f, 0x08, 0xdb, 0x33, 0x95, 0x5c, 0xdb,
0xcb, 0xad, 0x9b, 0x10, 0xf5, 0x3f, 0xc4, 0xe5,
0x2c, 0x59, 0x15, 0x65, 0x51, 0x84, 0x87, 0xfe,
0x08, 0x4d, 0x0e, 0x3f, 0x03, 0xde, 0xbc, 0xc9,
0xda, 0x1c, 0xe9, 0x0d, 0x08, 0x5c, 0x2d, 0x8a,
0x19, 0xd8, 0x37, 0x30, 0x86, 0x16, 0x36, 0x92,
0x14, 0x2b, 0xd8, 0xfc, 0x5d, 0x7a, 0x73, 0x49,
0x6a, 0x8e, 0x59, 0xee, 0x7e, 0xcf, 0x6b, 0x94,
0x06, 0x63, 0xf4, 0xa6, 0xbe, 0xe6, 0x5b, 0xd2,
0xc8, 0x5c, 0x46, 0x98, 0x6c, 0x1b, 0xef, 0x34,
0x90, 0xd3, 0x7b, 0x38, 0xda, 0x85, 0xd3, 0x2e,
0x97, 0x39, 0xcb, 0x23, 0x4a, 0x2b, 0xe7, 0x40,
},
},
}
func testEncrypt(t *testing.T, desc string, c *Cipher, src, expect []byte) {
dst := make([]byte, len(src))
c.XORKeyStream(dst, src)
for i, v := range dst {
if v != expect[i] {
t.Fatalf("%s: mismatch at byte %d:\nhave %x\nwant %x", desc, i, dst, expect)
}
}
}
func TestGolden(t *testing.T) {
for i := 0; i < len(golden); i++ {
g := golden[i]
c, err := NewCipher(g.key)
if err != nil {
t.Errorf("Failed to create cipher at golden index %d", i)
return
for gi, g := range golden {
data := make([]byte, len(g.keystream))
for i := range data {
data[i] = byte(i)
}
keystream := make([]byte, len(g.keystream))
c.XORKeyStream(keystream, keystream)
for j, v := range keystream {
if g.keystream[j] != v {
t.Errorf("Failed at golden index %d", i)
break
expect := make([]byte, len(g.keystream))
for i := range expect {
expect[i] = byte(i) ^ g.keystream[i]
}
for size := 1; size <= len(g.keystream); size++ {
c, err := NewCipher(g.key)
if err != nil {
t.Fatalf("#%d: NewCipher: %v", gi, err)
}
off := 0
for off < len(g.keystream) {
n := len(g.keystream) - off
if n > size {
n = size
}
desc := fmt.Sprintf("#%d@[%d:%d]", gi, off, off+n)
testEncrypt(t, desc, c, data[off:off+n], expect[off:off+n])
off += n
}
}
}
}
func TestBlock(t *testing.T) {
c1a, _ := NewCipher(golden[0].key)
c1b, _ := NewCipher(golden[1].key)
data1 := make([]byte, 1<<20)
for i := range data1 {
c1a.XORKeyStream(data1[i:i+1], data1[i:i+1])
c1b.XORKeyStream(data1[i:i+1], data1[i:i+1])
}
c2a, _ := NewCipher(golden[0].key)
c2b, _ := NewCipher(golden[1].key)
data2 := make([]byte, 1<<20)
c2a.XORKeyStream(data2, data2)
c2b.XORKeyStream(data2, data2)
if !bytes.Equal(data1, data2) {
t.Fatalf("bad block")
}
}
func benchmark(b *testing.B, size int64) {
buf := make([]byte, size)
c, err := NewCipher(golden[0].key)
if err != nil {
panic(err)
}
b.SetBytes(size)
for i := 0; i < b.N; i++ {
c.XORKeyStream(buf, buf)
}
}
func BenchmarkRC4_128(b *testing.B) {
benchmark(b, 128)
}
func BenchmarkRC4_1K(b *testing.B) {
benchmark(b, 1024)
}
func BenchmarkRC4_8K(b *testing.B) {
benchmark(b, 8096)
}

View File

@ -150,6 +150,20 @@ func GenerateMultiPrimeKey(random io.Reader, nprimes int, bits int) (priv *Priva
NextSetOfPrimes:
for {
todo := bits
// crypto/rand should set the top two bits in each prime.
// Thus each prime has the form
// p_i = 2^bitlen(p_i) × 0.11... (in base 2).
// And the product is:
// P = 2^todo × α
// where α is the product of nprimes numbers of the form 0.11...
//
// If α < 1/2 (which can happen for nprimes > 2), we need to
// shift todo to compensate for lost bits: the mean value of 0.11...
// is 7/8, so todo + shift - nprimes * log2(7/8) ~= bits - 1/2
// will give good results.
if nprimes >= 7 {
todo += (nprimes - 2) / 5
}
for i := 0; i < nprimes; i++ {
primes[i], err = rand.Prime(random, todo/(nprimes-i))
if err != nil {
@ -176,8 +190,9 @@ NextSetOfPrimes:
totient.Mul(totient, pminus1)
}
if n.BitLen() != bits {
// This should never happen because crypto/rand should
// set the top two bits in each prime.
// This should never happen for nprimes == 2 because
// crypto/rand should set the top two bits in each prime.
// For nprimes > 2 we hope it does not happen often.
continue NextSetOfPrimes
}
@ -188,7 +203,9 @@ NextSetOfPrimes:
g.GCD(priv.D, y, e, totient)
if g.Cmp(bigOne) == 0 {
priv.D.Add(priv.D, totient)
if priv.D.Sign() < 0 {
priv.D.Add(priv.D, totient)
}
priv.Primes = primes
priv.N = n

View File

@ -28,11 +28,11 @@ func TestKeyGeneration(t *testing.T) {
}
func Test3PrimeKeyGeneration(t *testing.T) {
size := 768
if testing.Short() {
return
size = 256
}
size := 768
priv, err := GenerateMultiPrimeKey(rand.Reader, 3, size)
if err != nil {
t.Errorf("failed to generate key")
@ -41,11 +41,11 @@ func Test3PrimeKeyGeneration(t *testing.T) {
}
func Test4PrimeKeyGeneration(t *testing.T) {
size := 768
if testing.Short() {
return
size = 256
}
size := 768
priv, err := GenerateMultiPrimeKey(rand.Reader, 4, size)
if err != nil {
t.Errorf("failed to generate key")
@ -53,6 +53,24 @@ func Test4PrimeKeyGeneration(t *testing.T) {
testKeyBasics(t, priv)
}
func TestNPrimeKeyGeneration(t *testing.T) {
primeSize := 64
maxN := 24
if testing.Short() {
primeSize = 16
maxN = 16
}
// Test that generation of N-prime keys works for N > 4.
for n := 5; n < maxN; n++ {
priv, err := GenerateMultiPrimeKey(rand.Reader, n, 64+n*primeSize)
if err == nil {
testKeyBasics(t, priv)
} else {
t.Errorf("failed to generate %d-prime key", n)
}
}
}
func TestGnuTLSKey(t *testing.T) {
// This is a key generated by `certtool --generate-privkey --bits 128`.
// It's such that de ≢ 1 mod φ(n), but is congruent mod the order of
@ -75,6 +93,9 @@ func testKeyBasics(t *testing.T, priv *PrivateKey) {
if err := priv.Validate(); err != nil {
t.Errorf("Validate() failed: %s", err)
}
if priv.D.Cmp(priv.N) > 0 {
t.Errorf("private exponent too large")
}
pub := &priv.PublicKey
m := big.NewInt(42)

View File

@ -4,10 +4,9 @@
// SHA1 hash algorithm. See RFC 3174.
package sha1_test
package sha1
import (
"crypto/sha1"
"fmt"
"io"
"testing"
@ -55,7 +54,7 @@ var golden = []sha1Test{
func TestGolden(t *testing.T) {
for i := 0; i < len(golden); i++ {
g := golden[i]
c := sha1.New()
c := New()
for j := 0; j < 3; j++ {
if j < 2 {
io.WriteString(c, g.in)
@ -74,13 +73,13 @@ func TestGolden(t *testing.T) {
}
func ExampleNew() {
h := sha1.New()
h := New()
io.WriteString(h, "His money is twice tainted: 'taint yours and 'taint mine.")
fmt.Printf("% x", h.Sum(nil))
// Output: 59 7f 6a 54 00 10 f9 4c 15 d7 18 06 a9 9a 2c 87 10 e7 47 bd
}
var bench = sha1.New()
var bench = New()
var buf = make([]byte, 8192)
func benchmarkSize(b *testing.B, size int) {

View File

@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !amd64,!386
// SHA1 block step.
// In its own file so that a faster assembly or C version
// can be substituted easily.

View File

@ -0,0 +1,9 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build amd64 386
package sha1
func block(dig *digest, p []byte)

View File

@ -204,7 +204,24 @@ type Config struct {
// connections using that key are compromised.
SessionTicketKey [32]byte
serverInitOnce sync.Once
serverInitOnce sync.Once // guards calling (*Config).serverInit
}
func (c *Config) serverInit() {
if c.SessionTicketsDisabled {
return
}
// If the key has already been set then we have nothing to do.
for _, b := range c.SessionTicketKey {
if b != 0 {
return
}
}
if _, err := io.ReadFull(c.rand(), c.SessionTicketKey[:]); err != nil {
c.SessionTicketsDisabled = true
}
}
func (c *Config) rand() io.Reader {

View File

@ -16,36 +16,80 @@ import (
"crypto/x509/pkix"
"encoding/pem"
"flag"
"fmt"
"log"
"math/big"
"net"
"os"
"strings"
"time"
)
var hostName *string = flag.String("host", "127.0.0.1", "Hostname to generate a certificate for")
var (
host = flag.String("host", "", "Comma-separated hostnames and IPs to generate a certificate for")
validFrom = flag.String("start-date", "", "Creation date formatted as Jan 1 15:04:05 2011")
validFor = flag.Duration("duration", 365*24*time.Hour, "Duration that certificate is valid for")
isCA = flag.Bool("ca", false, "whether this cert should be its own Certificate Authority")
rsaBits = flag.Int("rsa-bits", 1024, "Size of RSA key to generate")
)
func main() {
flag.Parse()
priv, err := rsa.GenerateKey(rand.Reader, 1024)
if len(*host) == 0 {
log.Fatalf("Missing required --host parameter")
}
priv, err := rsa.GenerateKey(rand.Reader, *rsaBits)
if err != nil {
log.Fatalf("failed to generate private key: %s", err)
return
}
now := time.Now()
var notBefore time.Time
if len(*validFrom) == 0 {
notBefore = time.Now()
} else {
notBefore, err = time.Parse("Jan 2 15:04:05 2006", *validFrom)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to parse creation date: %s\n", err)
os.Exit(1)
}
}
notAfter := notBefore.Add(*validFor)
// end of ASN.1 time
endOfTime := time.Date(2049, 12, 31, 23, 59, 59, 0, time.UTC)
if notAfter.After(endOfTime) {
notAfter = endOfTime
}
template := x509.Certificate{
SerialNumber: new(big.Int).SetInt64(0),
Subject: pkix.Name{
CommonName: *hostName,
Organization: []string{"Acme Co"},
},
NotBefore: now.Add(-5 * time.Minute).UTC(),
NotAfter: now.AddDate(1, 0, 0).UTC(), // valid for 1 year.
NotBefore: notBefore,
NotAfter: notAfter,
SubjectKeyId: []byte{1, 2, 3, 4},
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
}
hosts := strings.Split(*host, ",")
for _, h := range hosts {
if ip := net.ParseIP(h); ip != nil {
template.IPAddresses = append(template.IPAddresses, ip)
} else {
template.DNSNames = append(template.DNSNames, h)
}
}
if *isCA {
template.IsCA = true
template.KeyUsage |= x509.KeyUsageCertSign
}
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)

View File

@ -33,22 +33,7 @@ func (c *Conn) serverHandshake() error {
// If this is the first server handshake, we generate a random key to
// encrypt the tickets with.
config.serverInitOnce.Do(func() {
if config.SessionTicketsDisabled {
return
}
// If the key has already been set then we have nothing to do.
for _, b := range config.SessionTicketKey {
if b != 0 {
return
}
}
if _, err := io.ReadFull(config.rand(), config.SessionTicketKey[:]); err != nil {
config.SessionTicketsDisabled = true
}
})
config.serverInitOnce.Do(config.serverInit)
hs := serverHandshakeState{
c: c,

View File

@ -51,6 +51,4 @@ func ParsePKCS8PrivateKey(der []byte) (key interface{}, err error) {
default:
return nil, fmt.Errorf("crypto/x509: PKCS#8 wrapping contained private key with unknown algorithm: %v", privKey.Algo.Algorithm)
}
panic("unreachable")
}

View File

@ -5,6 +5,7 @@
package x509
import (
"net"
"runtime"
"strings"
"time"
@ -63,14 +64,28 @@ type HostnameError struct {
}
func (h HostnameError) Error() string {
var valid string
c := h.Certificate
if len(c.DNSNames) > 0 {
valid = strings.Join(c.DNSNames, ", ")
var valid string
if ip := net.ParseIP(h.Host); ip != nil {
// Trying to validate an IP
if len(c.IPAddresses) == 0 {
return "x509: cannot validate certificate for " + h.Host + " because it doesn't contain any IP SANs"
}
for _, san := range c.IPAddresses {
if len(valid) > 0 {
valid += ", "
}
valid += san.String()
}
} else {
valid = c.Subject.CommonName
if len(c.DNSNames) > 0 {
valid = strings.Join(c.DNSNames, ", ")
} else {
valid = c.Subject.CommonName
}
}
return "certificate is valid for " + valid + ", not " + h.Host
return "x509: certificate is valid for " + valid + ", not " + h.Host
}
// UnknownAuthorityError results when the certificate issuer is unknown
@ -334,6 +349,22 @@ func toLowerCaseASCII(in string) string {
// VerifyHostname returns nil if c is a valid certificate for the named host.
// Otherwise it returns an error describing the mismatch.
func (c *Certificate) VerifyHostname(h string) error {
// IP addresses may be written in [ ].
candidateIP := h
if len(h) >= 3 && h[0] == '[' && h[len(h)-1] == ']' {
candidateIP = h[1 : len(h)-1]
}
if ip := net.ParseIP(candidateIP); ip != nil {
// We only match IP addresses against IP SANs.
// https://tools.ietf.org/html/rfc6125#appendix-B.2
for _, candidate := range c.IPAddresses {
if ip.Equal(candidate) {
return nil
}
}
return HostnameError{c, candidateIP}
}
lowered := toLowerCaseASCII(h)
if len(c.DNSNames) > 0 {
@ -389,6 +420,14 @@ func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool {
for _, usage := range cert.ExtKeyUsage {
if requestedUsage == usage {
continue NextRequestedUsage
} else if requestedUsage == ExtKeyUsageServerAuth &&
(usage == ExtKeyUsageNetscapeServerGatedCrypto ||
usage == ExtKeyUsageMicrosoftServerGatedCrypto) {
// In order to support COMODO
// certificate chains, we have to
// accept Netscape or Microsoft SGC
// usages as equal to ServerAuth.
continue NextRequestedUsage
}
}

View File

@ -158,6 +158,19 @@ var verifyTests = []verifyTest{
{"Ryan Hurst", "GlobalSign PersonalSign 2 CA - G2"},
},
},
{
leaf: megaLeaf,
intermediates: []string{comodoIntermediate1},
roots: []string{comodoRoot},
currentTime: 1360431182,
// CryptoAPI can find alternative validation paths so we don't
// perform this test with system validation.
systemSkip: true,
expectedChains: [][]string{
{"mega.co.nz", "EssentialSSL CA", "COMODO Certification Authority"},
},
},
}
func expectHostnameError(t *testing.T, i int, err error) (ok bool) {
@ -563,3 +576,90 @@ YEvTWbWwGdPytDFPYIl3/6OqNSXSnZ7DxPcdLJq2uyiga8PB/TTIIHYkdM2+1DE0
7y3rH/7TjwDVD7SLu5/SdOfKskuMPTjOEvz3K161mymW06klVhubCIWOro/Gx1Q2
2FQOZ7/2k4uYoOdBTSlb8kTAuzZNgIE0rB2BIYCTz/P6zZIKW0ogbRSH
-----END CERTIFICATE-----`
var megaLeaf = `-----BEGIN CERTIFICATE-----
MIIFOjCCBCKgAwIBAgIQWYE8Dup170kZ+k11Lg51OjANBgkqhkiG9w0BAQUFADBy
MQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD
VQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01PRE8gQ0EgTGltaXRlZDEYMBYGA1UE
AxMPRXNzZW50aWFsU1NMIENBMB4XDTEyMTIxNDAwMDAwMFoXDTE0MTIxNDIzNTk1
OVowfzEhMB8GA1UECxMYRG9tYWluIENvbnRyb2wgVmFsaWRhdGVkMS4wLAYDVQQL
EyVIb3N0ZWQgYnkgSW5zdHJhIENvcnBvcmF0aW9uIFB0eS4gTFREMRUwEwYDVQQL
EwxFc3NlbnRpYWxTU0wxEzARBgNVBAMTCm1lZ2EuY28ubnowggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQDcxMCClae8BQIaJHBUIVttlLvhbK4XhXPk3RQ3
G5XA6tLZMBQ33l3F9knYJ0YErXtr8IdfYoulRQFmKFMJl9GtWyg4cGQi2Rcr5VN5
S5dA1vu4oyJBxE9fPELcK6Yz1vqaf+n6za+mYTiQYKggVdS8/s8hmNuXP9Zk1pIn
+q0pGsf8NAcSHMJgLqPQrTDw+zae4V03DvcYfNKjuno88d2226ld7MAmQZ7uRNsI
/CnkdelVs+akZsXf0szefSqMJlf08SY32t2jj4Ra7RApVYxOftD9nij/aLfuqOU6
ow6IgIcIG2ZvXLZwK87c5fxL7UAsTTV+M1sVv8jA33V2oKLhAgMBAAGjggG9MIIB
uTAfBgNVHSMEGDAWgBTay+qtWwhdzP/8JlTOSeVVxjj0+DAdBgNVHQ4EFgQUmP9l
6zhyrZ06Qj4zogt+6LKFk4AwDgYDVR0PAQH/BAQDAgWgMAwGA1UdEwEB/wQCMAAw
NAYDVR0lBC0wKwYIKwYBBQUHAwEGCCsGAQUFBwMCBgorBgEEAYI3CgMDBglghkgB
hvhCBAEwTwYDVR0gBEgwRjA6BgsrBgEEAbIxAQICBzArMCkGCCsGAQUFBwIBFh1o
dHRwczovL3NlY3VyZS5jb21vZG8uY29tL0NQUzAIBgZngQwBAgEwOwYDVR0fBDQw
MjAwoC6gLIYqaHR0cDovL2NybC5jb21vZG9jYS5jb20vRXNzZW50aWFsU1NMQ0Eu
Y3JsMG4GCCsGAQUFBwEBBGIwYDA4BggrBgEFBQcwAoYsaHR0cDovL2NydC5jb21v
ZG9jYS5jb20vRXNzZW50aWFsU1NMQ0FfMi5jcnQwJAYIKwYBBQUHMAGGGGh0dHA6
Ly9vY3NwLmNvbW9kb2NhLmNvbTAlBgNVHREEHjAcggptZWdhLmNvLm56gg53d3cu
bWVnYS5jby5uejANBgkqhkiG9w0BAQUFAAOCAQEAcYhrsPSvDuwihMOh0ZmRpbOE
Gw6LqKgLNTmaYUPQhzi2cyIjhUhNvugXQQlP5f0lp5j8cixmArafg1dTn4kQGgD3
ivtuhBTgKO1VYB/VRoAt6Lmswg3YqyiS7JiLDZxjoV7KoS5xdiaINfHDUaBBY4ZH
j2BUlPniNBjCqXe/HndUTVUewlxbVps9FyCmH+C4o9DWzdGBzDpCkcmo5nM+cp7q
ZhTIFTvZfo3zGuBoyu8BzuopCJcFRm3cRiXkpI7iOMUIixO1szkJS6WpL1sKdT73
UXp08U0LBqoqG130FbzEJBBV3ixbvY6BWMHoCWuaoF12KJnC5kHt2RoWAAgMXA==
-----END CERTIFICATE-----`
var comodoIntermediate1 = `-----BEGIN CERTIFICATE-----
MIIFAzCCA+ugAwIBAgIQGLLLuqME8aAPwfLzJkYqSjANBgkqhkiG9w0BAQUFADCB
gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV
BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw
MDBaFw0xOTEyMzEyMzU5NTlaMHIxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVh
dGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9E
TyBDQSBMaW1pdGVkMRgwFgYDVQQDEw9Fc3NlbnRpYWxTU0wgQ0EwggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCt8AiwcsargxIxF3CJhakgEtSYau2A1NHf
5I5ZLdOWIY120j8YC0YZYwvHIPPlC92AGvFaoL0dds23Izp0XmEbdaqb1IX04XiR
0y3hr/yYLgbSeT1awB8hLRyuIVPGOqchfr7tZ291HRqfalsGs2rjsQuqag7nbWzD
ypWMN84hHzWQfdvaGlyoiBSyD8gSIF/F03/o4Tjg27z5H6Gq1huQByH6RSRQXScq
oChBRVt9vKCiL6qbfltTxfEFFld+Edc7tNkBdtzffRDPUanlOPJ7FAB1WfnwWdsX
Pvev5gItpHnBXaIcw5rIp6gLSApqLn8tl2X2xQScRMiZln5+pN0vAgMBAAGjggGD
MIIBfzAfBgNVHSMEGDAWgBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAdBgNVHQ4EFgQU
2svqrVsIXcz//CZUzknlVcY49PgwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQI
MAYBAf8CAQAwIAYDVR0lBBkwFwYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMD4GA1Ud
IAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwczovL3NlY3VyZS5jb21v
ZG8uY29tL0NQUzBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9kb2Nh
LmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBsBggrBgEFBQcB
AQRgMF4wNgYIKwYBBQUHMAKGKmh0dHA6Ly9jcnQuY29tb2RvY2EuY29tL0NvbW9k
b1VUTlNHQ0NBLmNydDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2Eu
Y29tMA0GCSqGSIb3DQEBBQUAA4IBAQAtlzR6QDLqcJcvgTtLeRJ3rvuq1xqo2l/z
odueTZbLN3qo6u6bldudu+Ennv1F7Q5Slqz0J790qpL0pcRDAB8OtXj5isWMcL2a
ejGjKdBZa0wztSz4iw+SY1dWrCRnilsvKcKxudokxeRiDn55w/65g+onO7wdQ7Vu
F6r7yJiIatnyfKH2cboZT7g440LX8NqxwCPf3dfxp+0Jj1agq8MLy6SSgIGSH6lv
+Wwz3D5XxqfyH8wqfOQsTEZf6/Nh9yvENZ+NWPU6g0QO2JOsTGvMd/QDzczc4BxL
XSXaPV7Od4rhPsbXlM1wSTz/Dr0ISKvlUhQVnQ6cGodWaK2cCQBk
-----END CERTIFICATE-----`
var comodoRoot = `-----BEGIN CERTIFICATE-----
MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB
gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV
BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw
MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl
YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P
RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0
aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3
UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI
2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8
Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp
+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+
DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O
nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW
/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g
PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u
QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY
SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv
IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/
RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4
zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd
BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB
ZQ==
-----END CERTIFICATE-----`

View File

@ -19,6 +19,8 @@ import (
"errors"
"io"
"math/big"
"net"
"strconv"
"time"
)
@ -360,16 +362,18 @@ const (
// id-kp-timeStamping OBJECT IDENTIFIER ::= { id-kp 8 }
// id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 }
var (
oidExtKeyUsageAny = asn1.ObjectIdentifier{2, 5, 29, 37, 0}
oidExtKeyUsageServerAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 1}
oidExtKeyUsageClientAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 2}
oidExtKeyUsageCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 3}
oidExtKeyUsageEmailProtection = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 4}
oidExtKeyUsageIPSECEndSystem = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 5}
oidExtKeyUsageIPSECTunnel = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 6}
oidExtKeyUsageIPSECUser = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 7}
oidExtKeyUsageTimeStamping = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 8}
oidExtKeyUsageOCSPSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 9}
oidExtKeyUsageAny = asn1.ObjectIdentifier{2, 5, 29, 37, 0}
oidExtKeyUsageServerAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 1}
oidExtKeyUsageClientAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 2}
oidExtKeyUsageCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 3}
oidExtKeyUsageEmailProtection = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 4}
oidExtKeyUsageIPSECEndSystem = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 5}
oidExtKeyUsageIPSECTunnel = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 6}
oidExtKeyUsageIPSECUser = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 7}
oidExtKeyUsageTimeStamping = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 8}
oidExtKeyUsageOCSPSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 9}
oidExtKeyUsageMicrosoftServerGatedCrypto = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 3}
oidExtKeyUsageNetscapeServerGatedCrypto = asn1.ObjectIdentifier{2, 16, 840, 1, 113730, 4, 1}
)
// ExtKeyUsage represents an extended set of actions that are valid for a given key.
@ -387,6 +391,8 @@ const (
ExtKeyUsageIPSECUser
ExtKeyUsageTimeStamping
ExtKeyUsageOCSPSigning
ExtKeyUsageMicrosoftServerGatedCrypto
ExtKeyUsageNetscapeServerGatedCrypto
)
// extKeyUsageOIDs contains the mapping between an ExtKeyUsage and its OID.
@ -404,6 +410,8 @@ var extKeyUsageOIDs = []struct {
{ExtKeyUsageIPSECUser, oidExtKeyUsageIPSECUser},
{ExtKeyUsageTimeStamping, oidExtKeyUsageTimeStamping},
{ExtKeyUsageOCSPSigning, oidExtKeyUsageOCSPSigning},
{ExtKeyUsageMicrosoftServerGatedCrypto, oidExtKeyUsageMicrosoftServerGatedCrypto},
{ExtKeyUsageNetscapeServerGatedCrypto, oidExtKeyUsageNetscapeServerGatedCrypto},
}
func extKeyUsageFromOID(oid asn1.ObjectIdentifier) (eku ExtKeyUsage, ok bool) {
@ -458,6 +466,7 @@ type Certificate struct {
// Subject Alternate Name values
DNSNames []string
EmailAddresses []string
IPAddresses []net.IP
// Name constraints
PermittedDNSDomainsCritical bool // if true then the name constraints are marked critical.
@ -660,6 +669,13 @@ func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{
return nil, err
}
if p.N.Sign() <= 0 {
return nil, errors.New("x509: RSA modulus is not a positive number")
}
if p.E <= 0 {
return nil, errors.New("x509: RSA public exponent is not a positive number")
}
pub := &rsa.PublicKey{
E: p.E,
N: p.N,
@ -713,7 +729,6 @@ func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{
default:
return nil, nil
}
panic("unreachable")
}
func parseCertificate(in *certificate) (*Certificate, error) {
@ -828,6 +843,13 @@ func parseCertificate(in *certificate) (*Certificate, error) {
case 2:
out.DNSNames = append(out.DNSNames, string(v.Bytes))
parsedName = true
case 7:
switch len(v.Bytes) {
case net.IPv4len, net.IPv6len:
out.IPAddresses = append(out.IPAddresses, v.Bytes)
default:
return nil, errors.New("x509: certificate contained IP address of length " + strconv.Itoa(len(v.Bytes)))
}
}
}
@ -1072,11 +1094,22 @@ func buildExtensions(template *Certificate) (ret []pkix.Extension, err error) {
n++
}
if len(template.DNSNames) > 0 {
if len(template.DNSNames) > 0 || len(template.EmailAddresses) > 0 || len(template.IPAddresses) > 0 {
ret[n].Id = oidExtensionSubjectAltName
rawValues := make([]asn1.RawValue, len(template.DNSNames))
for i, name := range template.DNSNames {
rawValues[i] = asn1.RawValue{Tag: 2, Class: 2, Bytes: []byte(name)}
var rawValues []asn1.RawValue
for _, name := range template.DNSNames {
rawValues = append(rawValues, asn1.RawValue{Tag: 2, Class: 2, Bytes: []byte(name)})
}
for _, email := range template.EmailAddresses {
rawValues = append(rawValues, asn1.RawValue{Tag: 1, Class: 2, Bytes: []byte(email)})
}
for _, rawIP := range template.IPAddresses {
// If possible, we always want to encode IPv4 addresses in 4 bytes.
ip := rawIP.To4()
if ip == nil {
ip = rawIP
}
rawValues = append(rawValues, asn1.RawValue{Tag: 7, Class: 2, Bytes: ip})
}
ret[n].Value, err = asn1.Marshal(rawValues)
if err != nil {

View File

@ -19,6 +19,7 @@ import (
"encoding/hex"
"encoding/pem"
"math/big"
"net"
"reflect"
"testing"
"time"
@ -174,6 +175,49 @@ func TestMatchHostnames(t *testing.T) {
}
}
func TestMatchIP(t *testing.T) {
// Check that pattern matching is working.
c := &Certificate{
DNSNames: []string{"*.foo.bar.baz"},
Subject: pkix.Name{
CommonName: "*.foo.bar.baz",
},
}
err := c.VerifyHostname("quux.foo.bar.baz")
if err != nil {
t.Fatalf("VerifyHostname(quux.foo.bar.baz): %v", err)
}
// But check that if we change it to be matching against an IP address,
// it is rejected.
c = &Certificate{
DNSNames: []string{"*.2.3.4"},
Subject: pkix.Name{
CommonName: "*.2.3.4",
},
}
err = c.VerifyHostname("1.2.3.4")
if err == nil {
t.Fatalf("VerifyHostname(1.2.3.4) should have failed, did not")
}
c = &Certificate{
IPAddresses: []net.IP{net.ParseIP("127.0.0.1"), net.ParseIP("::1")},
}
err = c.VerifyHostname("127.0.0.1")
if err != nil {
t.Fatalf("VerifyHostname(127.0.0.1): %v", err)
}
err = c.VerifyHostname("::1")
if err != nil {
t.Fatalf("VerifyHostname(::1): %v", err)
}
err = c.VerifyHostname("[::1]")
if err != nil {
t.Fatalf("VerifyHostname([::1]): %v", err)
}
}
func TestCertificateParse(t *testing.T) {
s, _ := hex.DecodeString(certBytes)
certs, err := ParseCertificates(s)
@ -284,8 +328,11 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
UnknownExtKeyUsage: testUnknownExtKeyUsage,
BasicConstraintsValid: true,
IsCA: true,
DNSNames: []string{"test.example.com"},
IsCA: true,
DNSNames: []string{"test.example.com"},
EmailAddresses: []string{"gopher@golang.org"},
IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1).To4(), net.ParseIP("2001:4860:0:2001::68")},
PolicyIdentifiers: []asn1.ObjectIdentifier{[]int{1, 2, 3}},
PermittedDNSDomains: []string{".example.com", "example.com"},
@ -327,6 +374,18 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
t.Errorf("%s: unknown extkeyusage wasn't correctly copied from the template. Got %v, want %v", test.name, cert.UnknownExtKeyUsage, testUnknownExtKeyUsage)
}
if !reflect.DeepEqual(cert.DNSNames, template.DNSNames) {
t.Errorf("%s: SAN DNS names differ from template. Got %v, want %v", test.name, cert.DNSNames, template.DNSNames)
}
if !reflect.DeepEqual(cert.EmailAddresses, template.EmailAddresses) {
t.Errorf("%s: SAN emails differ from template. Got %v, want %v", test.name, cert.EmailAddresses, template.EmailAddresses)
}
if !reflect.DeepEqual(cert.IPAddresses, template.IPAddresses) {
t.Errorf("%s: SAN IPs differ from template. Got %v, want %v", test.name, cert.IPAddresses, template.IPAddresses)
}
if test.checkSig {
err = cert.CheckSignatureFrom(cert)
if err != nil {

View File

@ -14,12 +14,18 @@ import (
"strconv"
)
var errNilPtr = errors.New("destination pointer is nil") // embedded in descriptive error
// driverArgs converts arguments from callers of Stmt.Exec and
// Stmt.Query into driver Values.
//
// The statement si may be nil, if no statement is available.
func driverArgs(si driver.Stmt, args []interface{}) ([]driver.Value, error) {
// The statement ds may be nil, if no statement is available.
func driverArgs(ds *driverStmt, args []interface{}) ([]driver.Value, error) {
dargs := make([]driver.Value, len(args))
var si driver.Stmt
if ds != nil {
si = ds.si
}
cc, ok := si.(driver.ColumnConverter)
// Normal path, for a driver.Stmt that is not a ColumnConverter.
@ -58,7 +64,9 @@ func driverArgs(si driver.Stmt, args []interface{}) ([]driver.Value, error) {
// column before going across the network to get the
// same error.
var err error
ds.Lock()
dargs[n], err = cc.ColumnConverter(n).ConvertValue(arg)
ds.Unlock()
if err != nil {
return nil, fmt.Errorf("sql: converting argument #%d's type: %v", n, err)
}
@ -75,34 +83,68 @@ func driverArgs(si driver.Stmt, args []interface{}) ([]driver.Value, error) {
// An error is returned if the copy would result in loss of information.
// dest should be a pointer type.
func convertAssign(dest, src interface{}) error {
// Common cases, without reflect. Fall through.
// Common cases, without reflect.
switch s := src.(type) {
case string:
switch d := dest.(type) {
case *string:
if d == nil {
return errNilPtr
}
*d = s
return nil
case *[]byte:
if d == nil {
return errNilPtr
}
*d = []byte(s)
return nil
}
case []byte:
switch d := dest.(type) {
case *string:
if d == nil {
return errNilPtr
}
*d = string(s)
return nil
case *interface{}:
bcopy := make([]byte, len(s))
copy(bcopy, s)
*d = bcopy
if d == nil {
return errNilPtr
}
*d = cloneBytes(s)
return nil
case *[]byte:
if d == nil {
return errNilPtr
}
*d = cloneBytes(s)
return nil
case *RawBytes:
if d == nil {
return errNilPtr
}
*d = s
return nil
}
case nil:
switch d := dest.(type) {
case *interface{}:
if d == nil {
return errNilPtr
}
*d = nil
return nil
case *[]byte:
if d == nil {
return errNilPtr
}
*d = nil
return nil
case *RawBytes:
if d == nil {
return errNilPtr
}
*d = nil
return nil
}
@ -121,6 +163,26 @@ func convertAssign(dest, src interface{}) error {
*d = fmt.Sprintf("%v", src)
return nil
}
case *[]byte:
sv = reflect.ValueOf(src)
switch sv.Kind() {
case reflect.Bool,
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
reflect.Float32, reflect.Float64:
*d = []byte(fmt.Sprintf("%v", src))
return nil
}
case *RawBytes:
sv = reflect.ValueOf(src)
switch sv.Kind() {
case reflect.Bool,
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
reflect.Float32, reflect.Float64:
*d = RawBytes(fmt.Sprintf("%v", src))
return nil
}
case *bool:
bv, err := driver.Bool.ConvertValue(src)
if err == nil {
@ -140,6 +202,9 @@ func convertAssign(dest, src interface{}) error {
if dpv.Kind() != reflect.Ptr {
return errors.New("destination not a pointer")
}
if dpv.IsNil() {
return errNilPtr
}
if !sv.IsValid() {
sv = reflect.ValueOf(src)
@ -189,6 +254,16 @@ func convertAssign(dest, src interface{}) error {
return fmt.Errorf("unsupported driver -> Scan pair: %T -> %T", src, dest)
}
func cloneBytes(b []byte) []byte {
if b == nil {
return nil
} else {
c := make([]byte, len(b))
copy(c, b)
return c
}
}
func asString(src interface{}) string {
switch v := src.(type) {
case string:

View File

@ -22,6 +22,8 @@ type conversionTest struct {
wantint int64
wantuint uint64
wantstr string
wantbytes []byte
wantraw RawBytes
wantf32 float32
wantf64 float64
wanttime time.Time
@ -35,6 +37,8 @@ type conversionTest struct {
// Target variables for scanning into.
var (
scanstr string
scanbytes []byte
scanraw RawBytes
scanint int
scanint8 int8
scanint16 int16
@ -56,6 +60,7 @@ var conversionTests = []conversionTest{
{s: someTime, d: &scantime, wanttime: someTime},
// To strings
{s: "string", d: &scanstr, wantstr: "string"},
{s: []byte("byteslice"), d: &scanstr, wantstr: "byteslice"},
{s: 123, d: &scanstr, wantstr: "123"},
{s: int8(123), d: &scanstr, wantstr: "123"},
@ -66,6 +71,31 @@ var conversionTests = []conversionTest{
{s: uint64(123), d: &scanstr, wantstr: "123"},
{s: 1.5, d: &scanstr, wantstr: "1.5"},
// To []byte
{s: nil, d: &scanbytes, wantbytes: nil},
{s: "string", d: &scanbytes, wantbytes: []byte("string")},
{s: []byte("byteslice"), d: &scanbytes, wantbytes: []byte("byteslice")},
{s: 123, d: &scanbytes, wantbytes: []byte("123")},
{s: int8(123), d: &scanbytes, wantbytes: []byte("123")},
{s: int64(123), d: &scanbytes, wantbytes: []byte("123")},
{s: uint8(123), d: &scanbytes, wantbytes: []byte("123")},
{s: uint16(123), d: &scanbytes, wantbytes: []byte("123")},
{s: uint32(123), d: &scanbytes, wantbytes: []byte("123")},
{s: uint64(123), d: &scanbytes, wantbytes: []byte("123")},
{s: 1.5, d: &scanbytes, wantbytes: []byte("1.5")},
// To RawBytes
{s: nil, d: &scanraw, wantraw: nil},
{s: []byte("byteslice"), d: &scanraw, wantraw: RawBytes("byteslice")},
{s: 123, d: &scanraw, wantraw: RawBytes("123")},
{s: int8(123), d: &scanraw, wantraw: RawBytes("123")},
{s: int64(123), d: &scanraw, wantraw: RawBytes("123")},
{s: uint8(123), d: &scanraw, wantraw: RawBytes("123")},
{s: uint16(123), d: &scanraw, wantraw: RawBytes("123")},
{s: uint32(123), d: &scanraw, wantraw: RawBytes("123")},
{s: uint64(123), d: &scanraw, wantraw: RawBytes("123")},
{s: 1.5, d: &scanraw, wantraw: RawBytes("1.5")},
// Strings to integers
{s: "255", d: &scanuint8, wantuint: 255},
{s: "256", d: &scanuint8, wanterr: `converting string "256" to a uint8: strconv.ParseUint: parsing "256": value out of range`},
@ -113,6 +143,7 @@ var conversionTests = []conversionTest{
{s: []byte("byteslice"), d: &scaniface, wantiface: []byte("byteslice")},
{s: true, d: &scaniface, wantiface: true},
{s: nil, d: &scaniface},
{s: []byte(nil), d: &scaniface, wantiface: []byte(nil)},
}
func intPtrValue(intptr interface{}) interface{} {
@ -191,7 +222,7 @@ func TestConversions(t *testing.T) {
}
if srcBytes, ok := ct.s.([]byte); ok {
dstBytes := (*ifptr).([]byte)
if &dstBytes[0] == &srcBytes[0] {
if len(srcBytes) > 0 && &dstBytes[0] == &srcBytes[0] {
errf("copy into interface{} didn't copy []byte data")
}
}

View File

@ -10,8 +10,8 @@ package driver
import "errors"
// A driver Value is a value that drivers must be able to handle.
// A Value is either nil or an instance of one of these types:
// Value is a value that drivers must be able to handle.
// It is either nil or an instance of one of these types:
//
// int64
// float64
@ -56,7 +56,7 @@ var ErrBadConn = errors.New("driver: bad connection")
// Execer is an optional interface that may be implemented by a Conn.
//
// If a Conn does not implement Execer, the db package's DB.Exec will
// If a Conn does not implement Execer, the sql package's DB.Exec will
// first prepare a query, execute the statement, and then close the
// statement.
//
@ -65,6 +65,17 @@ type Execer interface {
Exec(query string, args []Value) (Result, error)
}
// Queryer is an optional interface that may be implemented by a Conn.
//
// If a Conn does not implement Queryer, the sql package's DB.Query will
// first prepare a query, execute the statement, and then close the
// statement.
//
// Query may return ErrSkip.
type Queryer interface {
Query(query string, args []Value) (Rows, error)
}
// Conn is a connection to a database. It is not used concurrently
// by multiple goroutines.
//
@ -104,23 +115,8 @@ type Result interface {
type Stmt interface {
// Close closes the statement.
//
// Closing a statement should not interrupt any outstanding
// query created from that statement. That is, the following
// order of operations is valid:
//
// * create a driver statement
// * call Query on statement, returning Rows
// * close the statement
// * read from Rows
//
// If closing a statement invalidates currently-running
// queries, the final step above will incorrectly fail.
//
// TODO(bradfitz): possibly remove the restriction above, if
// enough driver authors object and find it complicates their
// code too much. The sql package could be smarter about
// refcounting the statement and closing it at the appropriate
// time.
// As of Go 1.1, a Stmt will not be closed if it's in use
// by any queries.
Close() error
// NumInput returns the number of placeholder parameters.

View File

@ -13,6 +13,7 @@ import (
"strconv"
"strings"
"sync"
"testing"
"time"
)
@ -34,9 +35,10 @@ var _ = log.Printf
// When opening a fakeDriver's database, it starts empty with no
// tables. All tables and data are stored in memory only.
type fakeDriver struct {
mu sync.Mutex
openCount int
dbs map[string]*fakeDB
mu sync.Mutex // guards 3 following fields
openCount int // conn opens
closeCount int // conn closes
dbs map[string]*fakeDB
}
type fakeDB struct {
@ -229,7 +231,43 @@ func (c *fakeConn) Begin() (driver.Tx, error) {
return c.currTx, nil
}
func (c *fakeConn) Close() error {
var hookPostCloseConn struct {
sync.Mutex
fn func(*fakeConn, error)
}
func setHookpostCloseConn(fn func(*fakeConn, error)) {
hookPostCloseConn.Lock()
defer hookPostCloseConn.Unlock()
hookPostCloseConn.fn = fn
}
var testStrictClose *testing.T
// setStrictFakeConnClose sets the t to Errorf on when fakeConn.Close
// fails to close. If nil, the check is disabled.
func setStrictFakeConnClose(t *testing.T) {
testStrictClose = t
}
func (c *fakeConn) Close() (err error) {
drv := fdriver.(*fakeDriver)
defer func() {
if err != nil && testStrictClose != nil {
testStrictClose.Errorf("failed to close a test fakeConn: %v", err)
}
hookPostCloseConn.Lock()
fn := hookPostCloseConn.fn
hookPostCloseConn.Unlock()
if fn != nil {
fn(c, err)
}
if err == nil {
drv.mu.Lock()
drv.closeCount++
drv.mu.Unlock()
}
}()
if c.currTx != nil {
return errors.New("can't close fakeConn; in a Transaction")
}
@ -266,6 +304,18 @@ func (c *fakeConn) Exec(query string, args []driver.Value) (driver.Result, error
return nil, driver.ErrSkip
}
func (c *fakeConn) Query(query string, args []driver.Value) (driver.Rows, error) {
// This is an optional interface, but it's implemented here
// just to check that all the args are of the proper types.
// ErrSkip is returned so the caller acts as if we didn't
// implement this at all.
err := checkSubsetTypes(args)
if err != nil {
return nil, err
}
return nil, driver.ErrSkip
}
func errf(msg string, args ...interface{}) error {
return errors.New("fakedb: " + fmt.Sprintf(msg, args...))
}
@ -412,6 +462,12 @@ func (s *fakeStmt) ColumnConverter(idx int) driver.ValueConverter {
}
func (s *fakeStmt) Close() error {
if s.c == nil {
panic("nil conn in fakeStmt.Close")
}
if s.c.db == nil {
panic("in fakeStmt.Close, conn's db is nil (already closed)")
}
if !s.closed {
s.c.incrStat(&s.c.stmtsClosed)
s.closed = true
@ -503,6 +559,15 @@ func (s *fakeStmt) Query(args []driver.Value) (driver.Rows, error) {
if !ok {
return nil, fmt.Errorf("fakedb: table %q doesn't exist", s.table)
}
if s.table == "magicquery" {
if len(s.whereCol) == 2 && s.whereCol[0] == "op" && s.whereCol[1] == "millis" {
if args[0] == "sleep" {
time.Sleep(time.Duration(args[1].(int64)) * time.Millisecond)
}
}
}
t.mu.Lock()
defer t.mu.Unlock()

File diff suppressed because it is too large Load Diff

View File

@ -5,11 +5,11 @@
package sql
import (
"database/sql/driver"
"fmt"
"reflect"
"runtime"
"strings"
"sync"
"testing"
"time"
)
@ -17,10 +17,10 @@ import (
func init() {
type dbConn struct {
db *DB
c driver.Conn
c *driverConn
}
freedFrom := make(map[dbConn]string)
putConnHook = func(db *DB, c driver.Conn) {
putConnHook = func(db *DB, c *driverConn) {
for _, oc := range db.freeConn {
if oc == c {
// print before panic, as panic may get lost due to conflicting panic
@ -38,7 +38,15 @@ const fakeDBName = "foo"
var chrisBirthday = time.Unix(123456789, 0)
func newTestDB(t *testing.T, name string) *DB {
type testOrBench interface {
Fatalf(string, ...interface{})
Errorf(string, ...interface{})
Fatal(...interface{})
Error(...interface{})
Logf(string, ...interface{})
}
func newTestDB(t testOrBench, name string) *DB {
db, err := Open("test", fakeDBName)
if err != nil {
t.Fatalf("Open: %v", err)
@ -52,17 +60,42 @@ func newTestDB(t *testing.T, name string) *DB {
exec(t, db, "INSERT|people|name=Bob,age=?,photo=BPHOTO", 2)
exec(t, db, "INSERT|people|name=Chris,age=?,photo=CPHOTO,bdate=?", 3, chrisBirthday)
}
if name == "magicquery" {
// Magic table name and column, known by fakedb_test.go.
exec(t, db, "CREATE|magicquery|op=string,millis=int32")
exec(t, db, "INSERT|magicquery|op=sleep,millis=10")
}
return db
}
func exec(t *testing.T, db *DB, query string, args ...interface{}) {
func exec(t testOrBench, db *DB, query string, args ...interface{}) {
_, err := db.Exec(query, args...)
if err != nil {
t.Fatalf("Exec of %q: %v", query, err)
}
}
func closeDB(t *testing.T, db *DB) {
func closeDB(t testOrBench, db *DB) {
if e := recover(); e != nil {
fmt.Printf("Panic: %v\n", e)
panic(e)
}
defer setHookpostCloseConn(nil)
setHookpostCloseConn(func(_ *fakeConn, err error) {
if err != nil {
t.Errorf("Error closing fakeConn: %v", err)
}
})
for i, dc := range db.freeConn {
if n := len(dc.openStmt); n > 0 {
// Just a sanity check. This is legal in
// general, but if we make the tests clean up
// their statements first, then we can safely
// verify this is always zero here, and any
// other value is a leak.
t.Errorf("while closing db, freeConn %d/%d had %d open stmts; want 0", i, len(db.freeConn), n)
}
}
err := db.Close()
if err != nil {
t.Fatalf("error closing DB: %v", err)
@ -75,7 +108,52 @@ func numPrepares(t *testing.T, db *DB) int {
if n := len(db.freeConn); n != 1 {
t.Fatalf("free conns = %d; want 1", n)
}
return db.freeConn[0].(*fakeConn).numPrepare
return db.freeConn[0].ci.(*fakeConn).numPrepare
}
func (db *DB) numDeps() int {
db.mu.Lock()
defer db.mu.Unlock()
return len(db.dep)
}
// Dependencies are closed via a goroutine, so this polls waiting for
// numDeps to fall to want, waiting up to d.
func (db *DB) numDepsPollUntil(want int, d time.Duration) int {
deadline := time.Now().Add(d)
for {
n := db.numDeps()
if n <= want || time.Now().After(deadline) {
return n
}
time.Sleep(50 * time.Millisecond)
}
}
func (db *DB) numFreeConns() int {
db.mu.Lock()
defer db.mu.Unlock()
return len(db.freeConn)
}
func (db *DB) dumpDeps(t *testing.T) {
for fc := range db.dep {
db.dumpDep(t, 0, fc, map[finalCloser]bool{})
}
}
func (db *DB) dumpDep(t *testing.T, depth int, dep finalCloser, seen map[finalCloser]bool) {
seen[dep] = true
indent := strings.Repeat(" ", depth)
ds := db.dep[dep]
for k := range ds {
t.Logf("%s%T (%p) waiting for -> %T (%p)", indent, dep, dep, k, k)
if fc, ok := k.(finalCloser); ok {
if !seen[fc] {
db.dumpDep(t, depth+1, fc, seen)
}
}
}
}
func TestQuery(t *testing.T) {
@ -114,7 +192,7 @@ func TestQuery(t *testing.T) {
// And verify that the final rows.Next() call, which hit EOF,
// also closed the rows connection.
if n := len(db.freeConn); n != 1 {
if n := db.numFreeConns(); n != 1 {
t.Fatalf("free conns after query hitting EOF = %d; want 1", n)
}
if prepares := numPrepares(t, db) - prepares0; prepares != 1 {
@ -270,6 +348,35 @@ func TestStatementQueryRow(t *testing.T) {
}
// golang.org/issue/3734
func TestStatementQueryRowConcurrent(t *testing.T) {
db := newTestDB(t, "people")
defer closeDB(t, db)
stmt, err := db.Prepare("SELECT|people|age|name=?")
if err != nil {
t.Fatalf("Prepare: %v", err)
}
defer stmt.Close()
const n = 10
ch := make(chan error, n)
for i := 0; i < n; i++ {
go func() {
var age int
err := stmt.QueryRow("Alice").Scan(&age)
if err == nil && age != 1 {
err = fmt.Errorf("unexpected age %d", age)
}
ch <- err
}()
}
for i := 0; i < n; i++ {
if err := <-ch; err != nil {
t.Error(err)
}
}
}
// just a test of fakedb itself
func TestBogusPreboundParameters(t *testing.T) {
db := newTestDB(t, "foo")
@ -448,6 +555,30 @@ func TestIssue2542Deadlock(t *testing.T) {
}
}
// From golang.org/issue/3865
func TestCloseStmtBeforeRows(t *testing.T) {
db := newTestDB(t, "people")
defer closeDB(t, db)
s, err := db.Prepare("SELECT|people|name|")
if err != nil {
t.Fatal(err)
}
r, err := s.Query()
if err != nil {
s.Close()
t.Fatal(err)
}
err = s.Close()
if err != nil {
t.Fatal(err)
}
r.Close()
}
// Tests fix for issue 2788, that we bind nil to a []byte if the
// value in the column is sql null
func TestNullByteSlice(t *testing.T) {
@ -520,7 +651,7 @@ func TestQueryRowClosingStmt(t *testing.T) {
if len(db.freeConn) != 1 {
t.Fatalf("expected 1 free conn")
}
fakeConn := db.freeConn[0].(*fakeConn)
fakeConn := db.freeConn[0].ci.(*fakeConn)
if made, closed := fakeConn.stmtsMade, fakeConn.stmtsClosed; made != closed {
t.Errorf("statement close mismatch: made %d, closed %d", made, closed)
}
@ -641,7 +772,337 @@ func nullTestRun(t *testing.T, spec nullTestSpec) {
}
}
func stack() string {
buf := make([]byte, 1024)
return string(buf[:runtime.Stack(buf, false)])
// golang.org/issue/4859
func TestQueryRowNilScanDest(t *testing.T) {
db := newTestDB(t, "people")
defer closeDB(t, db)
var name *string // nil pointer
err := db.QueryRow("SELECT|people|name|").Scan(name)
want := "sql: Scan error on column index 0: destination pointer is nil"
if err == nil || err.Error() != want {
t.Errorf("error = %q; want %q", err.Error(), want)
}
}
func TestIssue4902(t *testing.T) {
db := newTestDB(t, "people")
defer closeDB(t, db)
driver := db.driver.(*fakeDriver)
opens0 := driver.openCount
var stmt *Stmt
var err error
for i := 0; i < 10; i++ {
stmt, err = db.Prepare("SELECT|people|name|")
if err != nil {
t.Fatal(err)
}
err = stmt.Close()
if err != nil {
t.Fatal(err)
}
}
opens := driver.openCount - opens0
if opens > 1 {
t.Errorf("opens = %d; want <= 1", opens)
t.Logf("db = %#v", db)
t.Logf("driver = %#v", driver)
t.Logf("stmt = %#v", stmt)
}
}
// Issue 3857
// This used to deadlock.
func TestSimultaneousQueries(t *testing.T) {
db := newTestDB(t, "people")
defer closeDB(t, db)
tx, err := db.Begin()
if err != nil {
t.Fatal(err)
}
defer tx.Rollback()
r1, err := tx.Query("SELECT|people|name|")
if err != nil {
t.Fatal(err)
}
defer r1.Close()
r2, err := tx.Query("SELECT|people|name|")
if err != nil {
t.Fatal(err)
}
defer r2.Close()
}
func TestMaxIdleConns(t *testing.T) {
db := newTestDB(t, "people")
defer closeDB(t, db)
tx, err := db.Begin()
if err != nil {
t.Fatal(err)
}
tx.Commit()
if got := len(db.freeConn); got != 1 {
t.Errorf("freeConns = %d; want 1", got)
}
db.SetMaxIdleConns(0)
if got := len(db.freeConn); got != 0 {
t.Errorf("freeConns after set to zero = %d; want 0", got)
}
tx, err = db.Begin()
if err != nil {
t.Fatal(err)
}
tx.Commit()
if got := len(db.freeConn); got != 0 {
t.Errorf("freeConns = %d; want 0", got)
}
}
// golang.org/issue/5323
func TestStmtCloseDeps(t *testing.T) {
if testing.Short() {
t.Skip("skipping in short mode")
}
defer setHookpostCloseConn(nil)
setHookpostCloseConn(func(_ *fakeConn, err error) {
if err != nil {
t.Errorf("Error closing fakeConn: %v", err)
}
})
db := newTestDB(t, "magicquery")
defer closeDB(t, db)
driver := db.driver.(*fakeDriver)
driver.mu.Lock()
opens0 := driver.openCount
closes0 := driver.closeCount
driver.mu.Unlock()
openDelta0 := opens0 - closes0
stmt, err := db.Prepare("SELECT|magicquery|op|op=?,millis=?")
if err != nil {
t.Fatal(err)
}
// Start 50 parallel slow queries.
const (
nquery = 50
sleepMillis = 25
nbatch = 2
)
var wg sync.WaitGroup
for batch := 0; batch < nbatch; batch++ {
for i := 0; i < nquery; i++ {
wg.Add(1)
go func() {
defer wg.Done()
var op string
if err := stmt.QueryRow("sleep", sleepMillis).Scan(&op); err != nil && err != ErrNoRows {
t.Error(err)
}
}()
}
// Sleep for twice the expected length of time for the
// batch of 50 queries above to finish before starting
// the next round.
time.Sleep(2 * sleepMillis * time.Millisecond)
}
wg.Wait()
if g, w := db.numFreeConns(), 2; g != w {
t.Errorf("free conns = %d; want %d", g, w)
}
if n := db.numDepsPollUntil(4, time.Second); n > 4 {
t.Errorf("number of dependencies = %d; expected <= 4", n)
db.dumpDeps(t)
}
driver.mu.Lock()
opens := driver.openCount - opens0
closes := driver.closeCount - closes0
driver.mu.Unlock()
openDelta := (driver.openCount - driver.closeCount) - openDelta0
if openDelta > 2 {
t.Logf("open calls = %d", opens)
t.Logf("close calls = %d", closes)
t.Logf("open delta = %d", openDelta)
t.Errorf("db connections opened = %d; want <= 2", openDelta)
db.dumpDeps(t)
}
if len(stmt.css) > nquery {
t.Errorf("len(stmt.css) = %d; want <= %d", len(stmt.css), nquery)
}
if err := stmt.Close(); err != nil {
t.Fatal(err)
}
if g, w := db.numFreeConns(), 2; g != w {
t.Errorf("free conns = %d; want %d", g, w)
}
if n := db.numDepsPollUntil(2, time.Second); n > 2 {
t.Errorf("number of dependencies = %d; expected <= 2", n)
db.dumpDeps(t)
}
db.SetMaxIdleConns(0)
if g, w := db.numFreeConns(), 0; g != w {
t.Errorf("free conns = %d; want %d", g, w)
}
if n := db.numDepsPollUntil(0, time.Second); n > 0 {
t.Errorf("number of dependencies = %d; expected 0", n)
db.dumpDeps(t)
}
}
// golang.org/issue/5046
func TestCloseConnBeforeStmts(t *testing.T) {
db := newTestDB(t, "people")
defer closeDB(t, db)
defer setHookpostCloseConn(nil)
setHookpostCloseConn(func(_ *fakeConn, err error) {
if err != nil {
t.Errorf("Error closing fakeConn: %v; from %s", err, stack())
db.dumpDeps(t)
t.Errorf("DB = %#v", db)
}
})
stmt, err := db.Prepare("SELECT|people|name|")
if err != nil {
t.Fatal(err)
}
if len(db.freeConn) != 1 {
t.Fatalf("expected 1 freeConn; got %d", len(db.freeConn))
}
dc := db.freeConn[0]
if dc.closed {
t.Errorf("conn shouldn't be closed")
}
if n := len(dc.openStmt); n != 1 {
t.Errorf("driverConn num openStmt = %d; want 1", n)
}
err = db.Close()
if err != nil {
t.Errorf("db Close = %v", err)
}
if !dc.closed {
t.Errorf("after db.Close, driverConn should be closed")
}
if n := len(dc.openStmt); n != 0 {
t.Errorf("driverConn num openStmt = %d; want 0", n)
}
err = stmt.Close()
if err != nil {
t.Errorf("Stmt close = %v", err)
}
if !dc.closed {
t.Errorf("conn should be closed")
}
if dc.ci != nil {
t.Errorf("after Stmt Close, driverConn's Conn interface should be nil")
}
}
// golang.org/issue/5283: don't release the Rows' connection in Close
// before calling Stmt.Close.
func TestRowsCloseOrder(t *testing.T) {
db := newTestDB(t, "people")
defer closeDB(t, db)
db.SetMaxIdleConns(0)
setStrictFakeConnClose(t)
defer setStrictFakeConnClose(nil)
rows, err := db.Query("SELECT|people|age,name|")
if err != nil {
t.Fatal(err)
}
err = rows.Close()
if err != nil {
t.Fatal(err)
}
}
func manyConcurrentQueries(t testOrBench) {
maxProcs, numReqs := 16, 500
if testing.Short() {
maxProcs, numReqs = 4, 50
}
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(maxProcs))
db := newTestDB(t, "people")
defer closeDB(t, db)
stmt, err := db.Prepare("SELECT|people|name|")
if err != nil {
t.Fatal(err)
}
defer stmt.Close()
var wg sync.WaitGroup
wg.Add(numReqs)
reqs := make(chan bool)
defer close(reqs)
for i := 0; i < maxProcs*2; i++ {
go func() {
for _ = range reqs {
rows, err := stmt.Query()
if err != nil {
t.Errorf("error on query: %v", err)
wg.Done()
continue
}
var name string
for rows.Next() {
rows.Scan(&name)
}
rows.Close()
wg.Done()
}
}()
}
for i := 0; i < numReqs; i++ {
reqs <- true
}
wg.Wait()
}
func TestConcurrency(t *testing.T) {
manyConcurrentQueries(t)
}
func BenchmarkConcurrency(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
manyConcurrentQueries(b)
}
}

View File

@ -13,17 +13,45 @@ import (
// Data buffer being decoded.
type buf struct {
dwarf *Data
u *unit
order binary.ByteOrder
name string
off Offset
data []byte
err error
dwarf *Data
order binary.ByteOrder
format dataFormat
name string
off Offset
data []byte
err error
}
func makeBuf(d *Data, u *unit, name string, off Offset, data []byte) buf {
return buf{d, u, d.order, name, off, data, nil}
// Data format, other than byte order. This affects the handling of
// certain field formats.
type dataFormat interface {
// DWARF version number. Zero means unknown.
version() int
// 64-bit DWARF format?
dwarf64() (dwarf64 bool, isKnown bool)
// Size of an address, in bytes. Zero means unknown.
addrsize() int
}
// Some parts of DWARF have no data format, e.g., abbrevs.
type unknownFormat struct{}
func (u unknownFormat) version() int {
return 0
}
func (u unknownFormat) dwarf64() (bool, bool) {
return false, false
}
func (u unknownFormat) addrsize() int {
return 0
}
func makeBuf(d *Data, format dataFormat, name string, off Offset, data []byte) buf {
return buf{d, d.order, format, name, off, data, nil}
}
func (b *buf) uint8() uint8 {
@ -121,17 +149,15 @@ func (b *buf) int() int64 {
// Address-sized uint.
func (b *buf) addr() uint64 {
if b.u != nil {
switch b.u.addrsize {
case 1:
return uint64(b.uint8())
case 2:
return uint64(b.uint16())
case 4:
return uint64(b.uint32())
case 8:
return uint64(b.uint64())
}
switch b.format.addrsize() {
case 1:
return uint64(b.uint8())
case 2:
return uint64(b.uint16())
case 4:
return uint64(b.uint32())
case 8:
return uint64(b.uint64())
}
b.error("unknown address size")
return 0

View File

@ -40,7 +40,7 @@ func (d *Data) parseAbbrev(off uint32) (abbrevTable, error) {
} else {
data = data[off:]
}
b := makeBuf(d, nil, "abbrev", 0, data)
b := makeBuf(d, unknownFormat{}, "abbrev", 0, data)
// Error handling is simplified by the buf getters
// returning an endless stream of 0s after an error.
@ -190,13 +190,16 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
case formFlag:
val = b.uint8() == 1
case formFlagPresent:
// The attribute is implicitly indicated as present, and no value is
// encoded in the debugging information entry itself.
val = true
// lineptr, loclistptr, macptr, rangelistptr
case formSecOffset:
if b.u == nil {
is64, known := b.format.dwarf64()
if !known {
b.error("unknown size for DW_FORM_sec_offset")
} else if b.u.dwarf64 {
} else if is64 {
val = Offset(b.uint64())
} else {
val = Offset(b.uint32())
@ -204,14 +207,20 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
// reference to other entry
case formRefAddr:
if b.u == nil {
vers := b.format.version()
if vers == 0 {
b.error("unknown version for DW_FORM_ref_addr")
} else if b.u.version == 2 {
} else if vers == 2 {
val = Offset(b.addr())
} else if b.u.dwarf64 {
val = Offset(b.uint64())
} else {
val = Offset(b.uint32())
is64, known := b.format.dwarf64()
if !known {
b.error("unknown size for DW_FORM_ref_addr")
} else if is64 {
val = Offset(b.uint64())
} else {
val = Offset(b.uint32())
}
}
case formRef1:
val = Offset(b.uint8()) + ubase
@ -234,7 +243,7 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
if b.err != nil {
return nil
}
b1 := makeBuf(b.dwarf, b.u, "str", 0, b.dwarf.str)
b1 := makeBuf(b.dwarf, unknownFormat{}, "str", 0, b.dwarf.str)
b1.skip(int(off))
val = b1.string()
if b1.err != nil {

View File

@ -112,7 +112,7 @@ func (d *Data) readUnitLine(i int, u *unit) error {
func (d *Data) readAddressRanges(off Offset, base uint64, u *unit) error {
b := makeBuf(d, u, "ranges", off, d.ranges[off:])
var highest uint64
switch u.addrsize {
switch u.addrsize() {
case 1:
highest = 0xff
case 2:

View File

@ -435,7 +435,9 @@ func (d *Data) Type(off Offset) (Type, error) {
goto Error
}
if loc, ok := kid.Val(AttrDataMemberLoc).([]byte); ok {
b := makeBuf(d, nil, "location", 0, loc)
// TODO: Should have original compilation
// unit here, not unknownFormat.
b := makeBuf(d, unknownFormat{}, "location", 0, loc)
if b.uint8() != opPlusUconst {
err = DecodeError{"info", kid.Offset, "unexpected opcode"}
goto Error

View File

@ -10,17 +10,31 @@ import "strconv"
// Each unit has its own abbreviation table and address size.
type unit struct {
base Offset // byte offset of header within the aggregate info
off Offset // byte offset of data within the aggregate info
lineoff Offset // byte offset of data within the line info
data []byte
atable abbrevTable
addrsize int
version int
dwarf64 bool // True for 64-bit DWARF format
dir string
pc []addrRange // PC ranges in this compilation unit
lines []mapLineInfo // PC -> line mapping
base Offset // byte offset of header within the aggregate info
off Offset // byte offset of data within the aggregate info
lineoff Offset // byte offset of data within the line info
data []byte
atable abbrevTable
asize int
vers int
is64 bool // True for 64-bit DWARF format
dir string
pc []addrRange // PC ranges in this compilation unit
lines []mapLineInfo // PC -> line mapping
}
// Implement the dataFormat interface.
func (u *unit) version() int {
return u.vers
}
func (u *unit) dwarf64() (bool, bool) {
return u.is64, true
}
func (u *unit) addrsize() int {
return u.asize
}
// A range is an address range.
@ -32,12 +46,12 @@ type addrRange struct {
func (d *Data) parseUnits() ([]unit, error) {
// Count units.
nunit := 0
b := makeBuf(d, nil, "info", 0, d.info)
b := makeBuf(d, unknownFormat{}, "info", 0, d.info)
for len(b.data) > 0 {
len := b.uint32()
if len == 0xffffffff {
len64 := b.uint64()
if len64 != uint64(int(len64)) {
if len64 != uint64(uint32(len64)) {
b.error("unit length overflow")
break
}
@ -51,14 +65,14 @@ func (d *Data) parseUnits() ([]unit, error) {
}
// Again, this time writing them down.
b = makeBuf(d, nil, "info", 0, d.info)
b = makeBuf(d, unknownFormat{}, "info", 0, d.info)
units := make([]unit, nunit)
for i := range units {
u := &units[i]
u.base = b.off
n := b.uint32()
if n == 0xffffffff {
u.dwarf64 = true
u.is64 = true
n = uint32(b.uint64())
}
vers := b.uint16()
@ -66,6 +80,7 @@ func (d *Data) parseUnits() ([]unit, error) {
b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
break
}
u.vers = int(vers)
atable, err := d.parseAbbrev(b.uint32())
if err != nil {
if b.err == nil {
@ -73,9 +88,8 @@ func (d *Data) parseUnits() ([]unit, error) {
}
break
}
u.version = int(vers)
u.atable = atable
u.addrsize = int(b.uint8())
u.asize = int(b.uint8())
u.off = b.off
u.data = b.bytes(int(n - (2 + 4 + 1)))
}

View File

@ -422,6 +422,10 @@ func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) {
return nil, nil, errors.New("cannot load string table section")
}
// The first entry is all zeros.
var skip [Sym32Size]byte
symtab.Read(skip[:])
symbols := make([]Symbol, symtab.Len()/Sym32Size)
i := 0
@ -461,6 +465,10 @@ func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) {
return nil, nil, errors.New("cannot load string table section")
}
// The first entry is all zeros.
var skip [Sym64Size]byte
symtab.Read(skip[:])
symbols := make([]Symbol, symtab.Len()/Sym64Size)
i := 0
@ -533,10 +541,10 @@ func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {
symNo := rela.Info >> 32
t := R_X86_64(rela.Info & 0xffff)
if symNo >= uint64(len(symbols)) {
if symNo == 0 || symNo > uint64(len(symbols)) {
continue
}
sym := &symbols[symNo]
sym := &symbols[symNo-1]
if SymType(sym.Info&0xf) != STT_SECTION {
// We don't handle non-section relocations for now.
continue
@ -597,6 +605,10 @@ func (f *File) DWARF() (*dwarf.Data, error) {
}
// Symbols returns the symbol table for f.
//
// For compatibility with Go 1.0, Symbols omits the null symbol at index 0.
// After retrieving the symbols as symtab, an externally supplied index x
// corresponds to symtab[x-1], not symtab[x].
func (f *File) Symbols() ([]Symbol, error) {
sym, _, err := f.getSymbols(SHT_SYMTAB)
return sym, err
@ -706,7 +718,7 @@ func (f *File) gnuVersionInit(str []byte) {
// which came from offset i of the symbol table.
func (f *File) gnuVersion(i int, sym *ImportedSymbol) {
// Each entry is two bytes.
i = i * 2
i = (i + 1) * 2
if i >= len(f.gnuVersym) {
return
}

View File

@ -99,31 +99,116 @@ type Table struct {
}
type sym struct {
value uint32
gotype uint32
value uint64
gotype uint64
typ byte
name []byte
}
var littleEndianSymtab = []byte{0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00}
var littleEndianSymtab = []byte{0xFD, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00}
var bigEndianSymtab = []byte{0xFF, 0xFF, 0xFF, 0xFD, 0x00, 0x00, 0x00}
var oldLittleEndianSymtab = []byte{0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00}
func walksymtab(data []byte, fn func(sym) error) error {
var order binary.ByteOrder = binary.BigEndian
if bytes.HasPrefix(data, littleEndianSymtab) {
newTable := false
switch {
case bytes.HasPrefix(data, oldLittleEndianSymtab):
// Same as Go 1.0, but little endian.
// Format was used during interim development between Go 1.0 and Go 1.1.
// Should not be widespread, but easy to support.
data = data[6:]
order = binary.LittleEndian
case bytes.HasPrefix(data, bigEndianSymtab):
newTable = true
case bytes.HasPrefix(data, littleEndianSymtab):
newTable = true
order = binary.LittleEndian
}
var ptrsz int
if newTable {
if len(data) < 8 {
return &DecodingError{len(data), "unexpected EOF", nil}
}
ptrsz = int(data[7])
if ptrsz != 4 && ptrsz != 8 {
return &DecodingError{7, "invalid pointer size", ptrsz}
}
data = data[8:]
}
var s sym
p := data
for len(p) >= 6 {
s.value = order.Uint32(p[0:4])
typ := p[4]
if typ&0x80 == 0 {
return &DecodingError{len(data) - len(p) + 4, "bad symbol type", typ}
for len(p) >= 4 {
var typ byte
if newTable {
// Symbol type, value, Go type.
typ = p[0] & 0x3F
wideValue := p[0]&0x40 != 0
goType := p[0]&0x80 != 0
if typ < 26 {
typ += 'A'
} else {
typ += 'a' - 26
}
s.typ = typ
p = p[1:]
if wideValue {
if len(p) < ptrsz {
return &DecodingError{len(data), "unexpected EOF", nil}
}
// fixed-width value
if ptrsz == 8 {
s.value = order.Uint64(p[0:8])
p = p[8:]
} else {
s.value = uint64(order.Uint32(p[0:4]))
p = p[4:]
}
} else {
// varint value
s.value = 0
shift := uint(0)
for len(p) > 0 && p[0]&0x80 != 0 {
s.value |= uint64(p[0]&0x7F) << shift
shift += 7
p = p[1:]
}
if len(p) == 0 {
return &DecodingError{len(data), "unexpected EOF", nil}
}
s.value |= uint64(p[0]) << shift
p = p[1:]
}
if goType {
if len(p) < ptrsz {
return &DecodingError{len(data), "unexpected EOF", nil}
}
// fixed-width go type
if ptrsz == 8 {
s.gotype = order.Uint64(p[0:8])
p = p[8:]
} else {
s.gotype = uint64(order.Uint32(p[0:4]))
p = p[4:]
}
}
} else {
// Value, symbol type.
s.value = uint64(order.Uint32(p[0:4]))
if len(p) < 5 {
return &DecodingError{len(data), "unexpected EOF", nil}
}
typ = p[4]
if typ&0x80 == 0 {
return &DecodingError{len(data) - len(p) + 4, "bad symbol type", typ}
}
typ &^= 0x80
s.typ = typ
p = p[5:]
}
typ &^= 0x80
s.typ = typ
p = p[5:]
// Name.
var i int
var nnul int
for i = 0; i < len(p); i++ {
@ -142,13 +227,21 @@ func walksymtab(data []byte, fn func(sym) error) error {
}
}
}
if i+nnul+4 > len(p) {
if len(p) < i+nnul {
return &DecodingError{len(data), "unexpected EOF", nil}
}
s.name = p[0:i]
i += nnul
s.gotype = order.Uint32(p[i : i+4])
p = p[i+4:]
p = p[i:]
if !newTable {
if len(p) < 4 {
return &DecodingError{len(data), "unexpected EOF", nil}
}
// Go type.
s.gotype = uint64(order.Uint32(p[:4]))
p = p[4:]
}
fn(s)
}
return nil

View File

@ -142,6 +142,8 @@ type Dysymtab struct {
* Mach-O reader
*/
// FormatError is returned by some operations if the data does
// not have the correct format for an object file.
type FormatError struct {
off int64
msg string

View File

@ -296,5 +296,4 @@ func (d *decoder) Read(p []byte) (n int, err error) {
nn, d.readErr = d.r.Read(d.buf[d.nbuf:])
d.nbuf += nn
}
panic("unreachable")
}

View File

@ -460,7 +460,6 @@ func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameter
default:
return marshalUTF8String(out, v.String())
}
return
}
return StructuralError{"unknown Go type"}

View File

@ -6,8 +6,10 @@
package base32
import (
"bytes"
"io"
"strconv"
"strings"
)
/*
@ -48,6 +50,13 @@ var StdEncoding = NewEncoding(encodeStd)
// It is typically used in DNS.
var HexEncoding = NewEncoding(encodeHex)
var removeNewlinesMapper = func(r rune) rune {
if r == '\r' || r == '\n' {
return -1
}
return r
}
/*
* Encoder
*/
@ -228,40 +237,47 @@ func (e CorruptInputError) Error() string {
// decode is like Decode but returns an additional 'end' value, which
// indicates if end-of-message padding was encountered and thus any
// additional data is an error.
// additional data is an error. This method assumes that src has been
// stripped of all supported whitespace ('\r' and '\n').
func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
osrc := src
olen := len(src)
for len(src) > 0 && !end {
// Decode quantum using the base32 alphabet
var dbuf [8]byte
dlen := 8
// do the top bytes contain any data?
for j := 0; j < 8; {
if len(src) == 0 {
return n, false, CorruptInputError(len(osrc) - len(src) - j)
return n, false, CorruptInputError(olen - len(src) - j)
}
in := src[0]
src = src[1:]
if in == '\r' || in == '\n' {
// Ignore this character.
continue
}
if in == '=' && j >= 2 && len(src) < 8 {
// We've reached the end and there's
// padding, the rest should be padded
for k := 0; k < 8-j-1; k++ {
// We've reached the end and there's padding
if len(src)+j < 8-1 {
// not enough padding
return n, false, CorruptInputError(olen)
}
for k := 0; k < 8-1-j; k++ {
if len(src) > k && src[k] != '=' {
return n, false, CorruptInputError(len(osrc) - len(src) + k - 1)
// incorrect padding
return n, false, CorruptInputError(olen - len(src) + k - 1)
}
}
dlen = j
end = true
dlen, end = j, true
// 7, 5 and 2 are not valid padding lengths, and so 1, 3 and 6 are not
// valid dlen values. See RFC 4648 Section 6 "Base 32 Encoding" listing
// the five valid padding lengths, and Section 9 "Illustrations and
// Examples" for an illustration for how the the 1st, 3rd and 6th base32
// src bytes do not yield enough information to decode a dst byte.
if dlen == 1 || dlen == 3 || dlen == 6 {
return n, false, CorruptInputError(olen - len(src) - 1)
}
break
}
dbuf[j] = enc.decodeMap[in]
if dbuf[j] == 0xFF {
return n, false, CorruptInputError(len(osrc) - len(src) - 1)
return n, false, CorruptInputError(olen - len(src) - 1)
}
j++
}
@ -269,16 +285,16 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
// Pack 8x 5-bit source blocks into 5 byte destination
// quantum
switch dlen {
case 7, 8:
case 8:
dst[4] = dbuf[6]<<5 | dbuf[7]
fallthrough
case 6, 5:
case 7:
dst[3] = dbuf[4]<<7 | dbuf[5]<<2 | dbuf[6]>>3
fallthrough
case 4:
case 5:
dst[2] = dbuf[3]<<4 | dbuf[4]>>1
fallthrough
case 3:
case 4:
dst[1] = dbuf[1]<<6 | dbuf[2]<<1 | dbuf[3]>>4
fallthrough
case 2:
@ -288,11 +304,11 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
switch dlen {
case 2:
n += 1
case 3, 4:
case 4:
n += 2
case 5:
n += 3
case 6, 7:
case 7:
n += 4
case 8:
n += 5
@ -307,12 +323,14 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
// number of bytes successfully written and CorruptInputError.
// New line characters (\r and \n) are ignored.
func (enc *Encoding) Decode(dst, src []byte) (n int, err error) {
src = bytes.Map(removeNewlinesMapper, src)
n, _, err = enc.decode(dst, src)
return
}
// DecodeString returns the bytes represented by the base32 string s.
func (enc *Encoding) DecodeString(s string) ([]byte, error) {
s = strings.Map(removeNewlinesMapper, s)
dbuf := make([]byte, enc.DecodedLen(len(s)))
n, err := enc.Decode(dbuf, []byte(s))
return dbuf[:n], err
@ -377,9 +395,34 @@ func (d *decoder) Read(p []byte) (n int, err error) {
return n, d.err
}
type newlineFilteringReader struct {
wrapped io.Reader
}
func (r *newlineFilteringReader) Read(p []byte) (int, error) {
n, err := r.wrapped.Read(p)
for n > 0 {
offset := 0
for i, b := range p[0:n] {
if b != '\r' && b != '\n' {
if i != offset {
p[offset] = b
}
offset++
}
}
if offset > 0 {
return offset, err
}
// Previous buffer entirely whitespace, read again
n, err = r.wrapped.Read(p)
}
return n, err
}
// NewDecoder constructs a new base32 stream decoder.
func NewDecoder(enc *Encoding, r io.Reader) io.Reader {
return &decoder{enc: enc, r: r}
return &decoder{enc: enc, r: &newlineFilteringReader{r}}
}
// DecodedLen returns the maximum length in bytes of the decoded data

View File

@ -8,6 +8,7 @@ import (
"bytes"
"io"
"io/ioutil"
"strings"
"testing"
)
@ -137,27 +138,48 @@ func TestDecoderBuffering(t *testing.T) {
}
func TestDecodeCorrupt(t *testing.T) {
type corrupt struct {
e string
p int
}
examples := []corrupt{
testCases := []struct {
input string
offset int // -1 means no corruption.
}{
{"", -1},
{"!!!!", 0},
{"x===", 0},
{"AA=A====", 2},
{"AAA=AAAA", 3},
{"MMMMMMMMM", 8},
{"MMMMMM", 0},
{"A=", 1},
{"AA=", 3},
{"AA==", 4},
{"AA===", 5},
{"AAAA=", 5},
{"AAAA==", 6},
{"AAAAA=", 6},
{"AAAAA==", 7},
{"A=======", 1},
{"AA======", -1},
{"AAA=====", 3},
{"AAAA====", -1},
{"AAAAA===", -1},
{"AAAAAA==", 6},
{"AAAAAAA=", -1},
{"AAAAAAAA", -1},
}
for _, e := range examples {
dbuf := make([]byte, StdEncoding.DecodedLen(len(e.e)))
_, err := StdEncoding.Decode(dbuf, []byte(e.e))
for _, tc := range testCases {
dbuf := make([]byte, StdEncoding.DecodedLen(len(tc.input)))
_, err := StdEncoding.Decode(dbuf, []byte(tc.input))
if tc.offset == -1 {
if err != nil {
t.Error("Decoder wrongly detected coruption in", tc.input)
}
continue
}
switch err := err.(type) {
case CorruptInputError:
testEqual(t, "Corruption in %q at offset %v, want %v", e.e, int(err), e.p)
testEqual(t, "Corruption in %q at offset %v, want %v", tc.input, int(err), tc.offset)
default:
t.Error("Decoder failed to detect corruption in", e)
t.Error("Decoder failed to detect corruption in", tc)
}
}
}
@ -195,20 +217,7 @@ func TestBig(t *testing.T) {
}
}
func TestNewLineCharacters(t *testing.T) {
// Each of these should decode to the string "sure", without errors.
const expected = "sure"
examples := []string{
"ON2XEZI=",
"ON2XEZI=\r",
"ON2XEZI=\n",
"ON2XEZI=\r\n",
"ON2XEZ\r\nI=",
"ON2X\rEZ\nI=",
"ON2X\nEZ\rI=",
"ON2XEZ\nI=",
"ON2XEZI\n=",
}
func testStringEncoding(t *testing.T, expected string, examples []string) {
for _, e := range examples {
buf, err := StdEncoding.DecodeString(e)
if err != nil {
@ -220,3 +229,58 @@ func TestNewLineCharacters(t *testing.T) {
}
}
}
func TestNewLineCharacters(t *testing.T) {
// Each of these should decode to the string "sure", without errors.
examples := []string{
"ON2XEZI=",
"ON2XEZI=\r",
"ON2XEZI=\n",
"ON2XEZI=\r\n",
"ON2XEZ\r\nI=",
"ON2X\rEZ\nI=",
"ON2X\nEZ\rI=",
"ON2XEZ\nI=",
"ON2XEZI\n=",
}
testStringEncoding(t, "sure", examples)
// Each of these should decode to the string "foobar", without errors.
examples = []string{
"MZXW6YTBOI======",
"MZXW6YTBOI=\r\n=====",
}
testStringEncoding(t, "foobar", examples)
}
func TestDecoderIssue4779(t *testing.T) {
encoded := `JRXXEZLNEBUXA43VNUQGI33MN5ZCA43JOQQGC3LFOQWCAY3PNZZWKY3UMV2HK4
RAMFSGS4DJONUWG2LOM4QGK3DJOQWCA43FMQQGI3YKMVUXK43NN5SCA5DFNVYG64RANFXGG2LENFSH
K3TUEB2XIIDMMFRG64TFEBSXIIDEN5WG64TFEBWWCZ3OMEQGC3DJOF2WCLRAKV2CAZLONFWQUYLEEB
WWS3TJNUQHMZLONFQW2LBAOF2WS4ZANZXXG5DSOVSCAZLYMVZGG2LUMF2GS33OEB2WY3DBNVRW6IDM
MFRG64TJOMQG42LTNEQHK5AKMFWGS4LVNFYCAZLYEBSWCIDDN5WW233EN4QGG33OONSXC5LBOQXCAR
DVNFZSAYLVORSSA2LSOVZGKIDEN5WG64RANFXAU4TFOBZGK2DFNZSGK4TJOQQGS3RAOZXWY5LQORQX
IZJAOZSWY2LUEBSXG43FEBRWS3DMOVWSAZDPNRXXEZJAMV2SAZTVM5UWC5BANZ2WY3DBBJYGC4TJMF
2HK4ROEBCXQY3FOB2GK5LSEBZWS3TUEBXWGY3BMVRWC5BAMN2XA2LEMF2GC5BANZXW4IDQOJXWSZDF
NZ2CYIDTOVXHIIDJNYFGG5LMOBQSA4LVNEQG6ZTGNFRWSYJAMRSXGZLSOVXHIIDNN5WGY2LUEBQW42
LNEBUWIIDFON2CA3DBMJXXE5LNFY==
====`
encodedShort := strings.Replace(encoded, "\n", "", -1)
dec := NewDecoder(StdEncoding, bytes.NewBufferString(encoded))
res1, err := ioutil.ReadAll(dec)
if err != nil {
t.Errorf("ReadAll failed: %v", err)
}
dec = NewDecoder(StdEncoding, bytes.NewBufferString(encodedShort))
var res2 []byte
res2, err = ioutil.ReadAll(dec)
if err != nil {
t.Errorf("ReadAll failed: %v", err)
}
if !bytes.Equal(res1, res2) {
t.Error("Decoded results not equal")
}
}

View File

@ -6,8 +6,10 @@
package base64
import (
"bytes"
"io"
"strconv"
"strings"
)
/*
@ -49,6 +51,13 @@ var StdEncoding = NewEncoding(encodeStd)
// It is typically used in URLs and file names.
var URLEncoding = NewEncoding(encodeURL)
var removeNewlinesMapper = func(r rune) rune {
if r == '\r' || r == '\n' {
return -1
}
return r
}
/*
* Encoder
*/
@ -208,9 +217,10 @@ func (e CorruptInputError) Error() string {
// decode is like Decode but returns an additional 'end' value, which
// indicates if end-of-message padding was encountered and thus any
// additional data is an error.
// additional data is an error. This method assumes that src has been
// stripped of all supported whitespace ('\r' and '\n').
func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
osrc := src
olen := len(src)
for len(src) > 0 && !end {
// Decode quantum using the base64 alphabet
var dbuf [4]byte
@ -218,32 +228,26 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
for j := 0; j < 4; {
if len(src) == 0 {
return n, false, CorruptInputError(len(osrc) - len(src) - j)
return n, false, CorruptInputError(olen - len(src) - j)
}
in := src[0]
src = src[1:]
if in == '\r' || in == '\n' {
// Ignore this character.
continue
}
if in == '=' && j >= 2 && len(src) < 4 {
// We've reached the end and there's
// padding
if len(src) == 0 && j == 2 {
// We've reached the end and there's padding
if len(src)+j < 4-1 {
// not enough padding
return n, false, CorruptInputError(len(osrc))
return n, false, CorruptInputError(olen)
}
if len(src) > 0 && src[0] != '=' {
// incorrect padding
return n, false, CorruptInputError(len(osrc) - len(src) - 1)
return n, false, CorruptInputError(olen - len(src) - 1)
}
dlen = j
end = true
dlen, end = j, true
break
}
dbuf[j] = enc.decodeMap[in]
if dbuf[j] == 0xFF {
return n, false, CorruptInputError(len(osrc) - len(src) - 1)
return n, false, CorruptInputError(olen - len(src) - 1)
}
j++
}
@ -273,12 +277,14 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
// number of bytes successfully written and CorruptInputError.
// New line characters (\r and \n) are ignored.
func (enc *Encoding) Decode(dst, src []byte) (n int, err error) {
src = bytes.Map(removeNewlinesMapper, src)
n, _, err = enc.decode(dst, src)
return
}
// DecodeString returns the bytes represented by the base64 string s.
func (enc *Encoding) DecodeString(s string) ([]byte, error) {
s = strings.Map(removeNewlinesMapper, s)
dbuf := make([]byte, enc.DecodedLen(len(s)))
n, err := enc.Decode(dbuf, []byte(s))
return dbuf[:n], err
@ -343,9 +349,34 @@ func (d *decoder) Read(p []byte) (n int, err error) {
return n, d.err
}
type newlineFilteringReader struct {
wrapped io.Reader
}
func (r *newlineFilteringReader) Read(p []byte) (int, error) {
n, err := r.wrapped.Read(p)
for n > 0 {
offset := 0
for i, b := range p[0:n] {
if b != '\r' && b != '\n' {
if i != offset {
p[offset] = b
}
offset++
}
}
if offset > 0 {
return offset, err
}
// Previous buffer entirely whitespace, read again
n, err = r.wrapped.Read(p)
}
return n, err
}
// NewDecoder constructs a new base64 stream decoder.
func NewDecoder(enc *Encoding, r io.Reader) io.Reader {
return &decoder{enc: enc, r: r}
return &decoder{enc: enc, r: &newlineFilteringReader{r}}
}
// DecodedLen returns the maximum length in bytes of the decoded data

View File

@ -9,6 +9,7 @@ import (
"errors"
"io"
"io/ioutil"
"strings"
"testing"
"time"
)
@ -142,11 +143,11 @@ func TestDecoderBuffering(t *testing.T) {
}
func TestDecodeCorrupt(t *testing.T) {
type corrupt struct {
e string
p int
}
examples := []corrupt{
testCases := []struct {
input string
offset int // -1 means no corruption.
}{
{"", -1},
{"!!!!", 0},
{"x===", 1},
{"AA=A", 2},
@ -154,18 +155,27 @@ func TestDecodeCorrupt(t *testing.T) {
{"AAAAA", 4},
{"AAAAAA", 4},
{"A=", 1},
{"A==", 1},
{"AA=", 3},
{"AA==", -1},
{"AAA=", -1},
{"AAAA", -1},
{"AAAAAA=", 7},
}
for _, e := range examples {
dbuf := make([]byte, StdEncoding.DecodedLen(len(e.e)))
_, err := StdEncoding.Decode(dbuf, []byte(e.e))
for _, tc := range testCases {
dbuf := make([]byte, StdEncoding.DecodedLen(len(tc.input)))
_, err := StdEncoding.Decode(dbuf, []byte(tc.input))
if tc.offset == -1 {
if err != nil {
t.Error("Decoder wrongly detected coruption in", tc.input)
}
continue
}
switch err := err.(type) {
case CorruptInputError:
testEqual(t, "Corruption in %q at offset %v, want %v", e.e, int(err), e.p)
testEqual(t, "Corruption in %q at offset %v, want %v", tc.input, int(err), tc.offset)
default:
t.Error("Decoder failed to detect corruption in", e)
t.Error("Decoder failed to detect corruption in", tc)
}
}
}
@ -216,6 +226,8 @@ func TestNewLineCharacters(t *testing.T) {
"c3V\nyZ\rQ==",
"c3VyZ\nQ==",
"c3VyZQ\n==",
"c3VyZQ=\n=",
"c3VyZQ=\r\n\r\n=",
}
for _, e := range examples {
buf, err := StdEncoding.DecodeString(e)
@ -257,6 +269,7 @@ func TestDecoderIssue3577(t *testing.T) {
wantErr := errors.New("my error")
next <- nextRead{5, nil}
next <- nextRead{10, wantErr}
next <- nextRead{0, wantErr}
d := NewDecoder(StdEncoding, &faultInjectReader{
source: "VHdhcyBicmlsbGlnLCBhbmQgdGhlIHNsaXRoeSB0b3Zlcw==", // twas brillig...
nextc: next,
@ -275,3 +288,40 @@ func TestDecoderIssue3577(t *testing.T) {
t.Errorf("timeout; Decoder blocked without returning an error")
}
}
func TestDecoderIssue4779(t *testing.T) {
encoded := `CP/EAT8AAAEF
AQEBAQEBAAAAAAAAAAMAAQIEBQYHCAkKCwEAAQUBAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAAB
BAEDAgQCBQcGCAUDDDMBAAIRAwQhEjEFQVFhEyJxgTIGFJGhsUIjJBVSwWIzNHKC0UMHJZJT8OHx
Y3M1FqKygyZEk1RkRcKjdDYX0lXiZfKzhMPTdePzRieUpIW0lcTU5PSltcXV5fVWZnaGlqa2xtbm
9jdHV2d3h5ent8fX5/cRAAICAQIEBAMEBQYHBwYFNQEAAhEDITESBEFRYXEiEwUygZEUobFCI8FS
0fAzJGLhcoKSQ1MVY3M08SUGFqKygwcmNcLSRJNUoxdkRVU2dGXi8rOEw9N14/NGlKSFtJXE1OT0
pbXF1eX1VmZ2hpamtsbW5vYnN0dXZ3eHl6e3x//aAAwDAQACEQMRAD8A9VSSSSUpJJJJSkkkJ+Tj
1kiy1jCJJDnAcCTykpKkuQ6p/jN6FgmxlNduXawwAzaGH+V6jn/R/wCt71zdn+N/qL3kVYFNYB4N
ji6PDVjWpKp9TSXnvTf8bFNjg3qOEa2n6VlLpj/rT/pf567DpX1i6L1hs9Py67X8mqdtg/rUWbbf
+gkp0kkkklKSSSSUpJJJJT//0PVUkkklKVLq3WMDpGI7KzrNjADtYNXvI/Mqr/Pd/q9W3vaxjnvM
NaCXE9gNSvGPrf8AWS3qmba5jjsJhoB0DAf0NDf6sevf+/lf8Hj0JJATfWT6/dV6oXU1uOLQeKKn
EQP+Hubtfe/+R7Mf/g7f5xcocp++Z11JMCJPgFBxOg7/AOuqDx8I/ikpkXkmSdU8mJIJA/O8EMAy
j+mSARB/17pKVXYWHXjsj7yIex0PadzXMO1zT5KHoNA3HT8ietoGhgjsfA+CSnvvqh/jJtqsrwOv
2b6NGNzXfTYexzJ+nU7/ALkf4P8Awv6P9KvTQQ4AgyDqCF85Pho3CTB7eHwXoH+LT65uZbX9X+o2
bqbPb06551Y4
`
encodedShort := strings.Replace(encoded, "\n", "", -1)
dec := NewDecoder(StdEncoding, bytes.NewBufferString(encoded))
res1, err := ioutil.ReadAll(dec)
if err != nil {
t.Errorf("ReadAll failed: %v", err)
}
dec = NewDecoder(StdEncoding, bytes.NewBufferString(encodedShort))
var res2 []byte
res2, err = ioutil.ReadAll(dec)
if err != nil {
t.Errorf("ReadAll failed: %v", err)
}
if !bytes.Equal(res1, res2) {
t.Error("Decoded results not equal")
}
}

View File

@ -167,9 +167,9 @@ func Read(r io.Reader, order ByteOrder, data interface{}) error {
default:
return errors.New("binary.Read: invalid type " + d.Type().String())
}
size := dataSize(v)
if size < 0 {
return errors.New("binary.Read: invalid type " + v.Type().String())
size, err := dataSize(v)
if err != nil {
return errors.New("binary.Read: " + err.Error())
}
d := &decoder{order: order, buf: make([]byte, size)}
if _, err := io.ReadFull(r, d.buf); err != nil {
@ -247,64 +247,68 @@ func Write(w io.Writer, order ByteOrder, data interface{}) error {
// Fallback to reflect-based encoding.
v := reflect.Indirect(reflect.ValueOf(data))
size := dataSize(v)
if size < 0 {
return errors.New("binary.Write: invalid type " + v.Type().String())
size, err := dataSize(v)
if err != nil {
return errors.New("binary.Write: " + err.Error())
}
buf := make([]byte, size)
e := &encoder{order: order, buf: buf}
e.value(v)
_, err := w.Write(buf)
_, err = w.Write(buf)
return err
}
// Size returns how many bytes Write would generate to encode the value v, which
// must be a fixed-size value or a slice of fixed-size values, or a pointer to such data.
func Size(v interface{}) int {
return dataSize(reflect.Indirect(reflect.ValueOf(v)))
n, err := dataSize(reflect.Indirect(reflect.ValueOf(v)))
if err != nil {
return -1
}
return n
}
// dataSize returns the number of bytes the actual data represented by v occupies in memory.
// For compound structures, it sums the sizes of the elements. Thus, for instance, for a slice
// it returns the length of the slice times the element size and does not count the memory
// occupied by the header.
func dataSize(v reflect.Value) int {
func dataSize(v reflect.Value) (int, error) {
if v.Kind() == reflect.Slice {
elem := sizeof(v.Type().Elem())
if elem < 0 {
return -1
elem, err := sizeof(v.Type().Elem())
if err != nil {
return 0, err
}
return v.Len() * elem
return v.Len() * elem, nil
}
return sizeof(v.Type())
}
func sizeof(t reflect.Type) int {
func sizeof(t reflect.Type) (int, error) {
switch t.Kind() {
case reflect.Array:
n := sizeof(t.Elem())
if n < 0 {
return -1
n, err := sizeof(t.Elem())
if err != nil {
return 0, err
}
return t.Len() * n
return t.Len() * n, nil
case reflect.Struct:
sum := 0
for i, n := 0, t.NumField(); i < n; i++ {
s := sizeof(t.Field(i).Type)
if s < 0 {
return -1
s, err := sizeof(t.Field(i).Type)
if err != nil {
return 0, err
}
sum += s
}
return sum
return sum, nil
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
return int(t.Size())
return int(t.Size()), nil
}
return -1
return 0, errors.New("invalid type " + t.String())
}
type coder struct {
@ -514,11 +518,12 @@ func (e *encoder) value(v reflect.Value) {
}
func (d *decoder) skip(v reflect.Value) {
d.buf = d.buf[dataSize(v):]
n, _ := dataSize(v)
d.buf = d.buf[n:]
}
func (e *encoder) skip(v reflect.Value) {
n := dataSize(v)
n, _ := dataSize(v)
for i := range e.buf[0:n] {
e.buf[i] = 0
}

View File

@ -9,6 +9,7 @@ import (
"io"
"math"
"reflect"
"strings"
"testing"
)
@ -149,8 +150,14 @@ func TestWriteT(t *testing.T) {
tv := reflect.Indirect(reflect.ValueOf(ts))
for i, n := 0, tv.NumField(); i < n; i++ {
typ := tv.Field(i).Type().String()
if typ == "[4]int" {
typ = "int" // the problem is int, not the [4]
}
if err := Write(buf, BigEndian, tv.Field(i).Interface()); err == nil {
t.Errorf("WriteT.%v: have err == nil, want non-nil", tv.Field(i).Type())
} else if !strings.Contains(err.Error(), typ) {
t.Errorf("WriteT: have err == %q, want it to mention %s", err, typ)
}
}
}
@ -238,7 +245,7 @@ func BenchmarkReadStruct(b *testing.B) {
bsr := &byteSliceReader{}
var buf bytes.Buffer
Write(&buf, BigEndian, &s)
n := dataSize(reflect.ValueOf(s))
n, _ := dataSize(reflect.ValueOf(s))
b.SetBytes(int64(n))
t := s
b.ResetTimer()

View File

@ -120,7 +120,6 @@ func ReadUvarint(r io.ByteReader) (uint64, error) {
x |= uint64(b&0x7f) << s
s += 7
}
panic("unreachable")
}
// ReadVarint reads an encoded signed integer from r and returns it as an int64.

View File

@ -171,7 +171,6 @@ func (r *Reader) ReadAll() (records [][]string, err error) {
}
records = append(records, record)
}
panic("unreachable")
}
// readRune reads one rune from r, folding \r\n to \n and keeping track
@ -213,7 +212,6 @@ func (r *Reader) skip(delim rune) error {
return nil
}
}
panic("unreachable")
}
// parseRecord reads and parses a single csv record from r.
@ -250,7 +248,6 @@ func (r *Reader) parseRecord() (fields []string, err error) {
return nil, err
}
}
panic("unreachable")
}
// parseField parses the next field in the record. The read field is

View File

@ -1191,10 +1191,8 @@ func TestInterface(t *testing.T) {
if v1 != nil || v2 != nil {
t.Errorf("item %d inconsistent nils", i)
}
continue
if v1.Square() != v2.Square() {
t.Errorf("item %d inconsistent values: %v %v", i, v1, v2)
}
} else if v1.Square() != v2.Square() {
t.Errorf("item %d inconsistent values: %v %v", i, v1, v2)
}
}
}

View File

@ -1066,7 +1066,6 @@ func (dec *Decoder) compatibleType(fr reflect.Type, fw typeId, inProgress map[re
case reflect.Struct:
return true
}
return true
}
// typeString returns a human-readable description of the type identified by remoteId.

View File

@ -1,4 +1,4 @@
// Copyright 20011 The Go Authors. All rights reserved.
// 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.
@ -348,7 +348,7 @@ func TestGobEncoderFieldsOfDifferentType(t *testing.T) {
t.Fatal("decode error:", err)
}
if y.G.s != "XYZ" {
t.Fatalf("expected `XYZ` got %c", y.G.s)
t.Fatalf("expected `XYZ` got %q", y.G.s)
}
}

View File

@ -50,49 +50,51 @@ func BenchmarkEndToEndByteBuffer(b *testing.B) {
}
func TestCountEncodeMallocs(t *testing.T) {
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
if runtime.GOMAXPROCS(0) > 1 {
t.Skip("skipping; GOMAXPROCS>1")
}
const N = 1000
var buf bytes.Buffer
enc := NewEncoder(&buf)
bench := &Bench{7, 3.2, "now is the time", []byte("for all good men")}
memstats := new(runtime.MemStats)
runtime.ReadMemStats(memstats)
mallocs := 0 - memstats.Mallocs
const count = 1000
for i := 0; i < count; i++ {
allocs := testing.AllocsPerRun(N, func() {
err := enc.Encode(bench)
if err != nil {
t.Fatal("encode:", err)
}
}
runtime.ReadMemStats(memstats)
mallocs += memstats.Mallocs
fmt.Printf("mallocs per encode of type Bench: %d\n", mallocs/count)
})
fmt.Printf("mallocs per encode of type Bench: %v\n", allocs)
}
func TestCountDecodeMallocs(t *testing.T) {
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
if runtime.GOMAXPROCS(0) > 1 {
t.Skip("skipping; GOMAXPROCS>1")
}
const N = 1000
var buf bytes.Buffer
enc := NewEncoder(&buf)
bench := &Bench{7, 3.2, "now is the time", []byte("for all good men")}
const count = 1000
for i := 0; i < count; i++ {
// Fill the buffer with enough to decode
testing.AllocsPerRun(N, func() {
err := enc.Encode(bench)
if err != nil {
t.Fatal("encode:", err)
}
}
})
dec := NewDecoder(&buf)
memstats := new(runtime.MemStats)
runtime.ReadMemStats(memstats)
mallocs := 0 - memstats.Mallocs
for i := 0; i < count; i++ {
allocs := testing.AllocsPerRun(N, func() {
*bench = Bench{}
err := dec.Decode(&bench)
if err != nil {
t.Fatal("decode:", err)
}
}
runtime.ReadMemStats(memstats)
mallocs += memstats.Mallocs
fmt.Printf("mallocs per decode of type Bench: %d\n", mallocs/count)
})
fmt.Printf("mallocs per decode of type Bench: %v\n", allocs)
}

View File

@ -526,7 +526,6 @@ func newTypeObject(name string, ut *userTypeInfo, rt reflect.Type) (gobType, err
default:
return nil, errors.New("gob NewTypeObject can't handle type: " + rt.String())
}
return nil, nil
}
// isExported reports whether this is an exported - upper case - name.

View File

@ -33,6 +33,10 @@ import (
// the value pointed at by the pointer. If the pointer is nil, Unmarshal
// allocates a new value for it to point to.
//
// To unmarshal JSON into a struct, Unmarshal matches incoming object
// keys to the keys used by Marshal (either the struct field name or its tag),
// preferring an exact match but also accepting a case-insensitive match.
//
// To unmarshal JSON into an interface value, Unmarshal unmarshals
// the JSON into the concrete value contained in the interface value.
// If the interface value is nil, that is, has no concrete value stored in it,
@ -51,17 +55,22 @@ import (
// If no more serious errors are encountered, Unmarshal returns
// an UnmarshalTypeError describing the earliest such error.
//
// When unmarshaling quoted strings, invalid UTF-8 or
// invalid UTF-16 surrogate pairs are not treated as an error.
// Instead, they are replaced by the Unicode replacement
// character U+FFFD.
//
func Unmarshal(data []byte, v interface{}) error {
d := new(decodeState).init(data)
// Quick check for well-formedness.
// Check for well-formedness.
// Avoids filling out half a data structure
// before discovering a JSON syntax error.
var d decodeState
err := checkValid(data, &d.scan)
if err != nil {
return err
}
d.init(data)
return d.unmarshal(v)
}
@ -252,6 +261,16 @@ func (d *decodeState) value(v reflect.Value) {
}
d.scan.step(&d.scan, '"')
d.scan.step(&d.scan, '"')
n := len(d.scan.parseState)
if n > 0 && d.scan.parseState[n-1] == parseObjectKey {
// d.scan thinks we just read an object key; finish the object
d.scan.step(&d.scan, ':')
d.scan.step(&d.scan, '"')
d.scan.step(&d.scan, '"')
d.scan.step(&d.scan, '}')
}
return
}
@ -730,6 +749,7 @@ func (d *decodeState) valueInterface() interface{} {
switch d.scanWhile(scanSkipSpace) {
default:
d.error(errPhase)
panic("unreachable")
case scanBeginArray:
return d.arrayInterface()
case scanBeginObject:
@ -737,12 +757,11 @@ func (d *decodeState) valueInterface() interface{} {
case scanBeginLiteral:
return d.literalInterface()
}
panic("unreachable")
}
// arrayInterface is like array but returns []interface{}.
func (d *decodeState) arrayInterface() []interface{} {
var v []interface{}
var v = make([]interface{}, 0)
for {
// Look ahead for ] - can only happen on first iteration.
op := d.scanWhile(scanSkipSpace)
@ -849,7 +868,6 @@ func (d *decodeState) literalInterface() interface{} {
}
return n
}
panic("unreachable")
}
// getu4 decodes \uXXXX from the beginning of s, returning the hex value,

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