libgo: Update to Go 1.1.1.
From-SVN: r200974
This commit is contained in:
parent
efb30cdeb0
commit
be47d6ecef
@ -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.
|
||||
|
@ -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 \
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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
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
BIN
libgo/go/archive/tar/testdata/ustar.tar
vendored
Normal file
Binary file not shown.
@ -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.
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
BIN
libgo/go/archive/zip/testdata/test-trailing-junk.zip
vendored
Normal file
BIN
libgo/go/archive/zip/testdata/test-trailing-junk.zip
vendored
Normal file
Binary file not shown.
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
74
libgo/go/bufio/example_test.go
Normal file
74
libgo/go/bufio/example_test.go
Normal 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
|
||||
}
|
27
libgo/go/bufio/export_test.go
Normal file
27
libgo/go/bufio/export_test.go
Normal 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
346
libgo/go/bufio/scan.go
Normal 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
406
libgo/go/bufio/scan_test.go
Normal 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)
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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))
|
||||
|
@ -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])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
47
libgo/go/bytes/equal_test.go
Normal file
47
libgo/go/bytes/equal_test.go
Normal 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])
|
||||
}
|
||||
}
|
@ -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!
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -158,7 +158,6 @@ func (b *syncBuffer) Read(p []byte) (n int, err error) {
|
||||
}
|
||||
<-b.ready
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
func (b *syncBuffer) signal() {
|
||||
|
@ -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.
|
||||
|
@ -99,5 +99,4 @@ func offsetCode(off uint32) uint32 {
|
||||
default:
|
||||
return offsetCodes[off>>14] + 28
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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 {
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
}
|
@ -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
|
||||
|
@ -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"
|
||||
)
|
||||
|
||||
|
@ -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++ {
|
||||
|
36
libgo/go/crypto/cipher/cipher_test.go
Normal file
36
libgo/go/crypto/cipher/cipher_test.go
Normal 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()
|
||||
}
|
@ -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)
|
||||
|
@ -144,8 +144,6 @@ GeneratePrimes:
|
||||
params.G = g
|
||||
return
|
||||
}
|
||||
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// GenerateKey generates a public&private key pair. The Parameters of the
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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())
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
// DO NOT EDIT.
|
||||
// Generate with: go run gen.go -full | gofmt >md5block.go
|
||||
|
||||
// +build !amd64,!386
|
||||
|
||||
package md5
|
||||
|
||||
import (
|
||||
|
9
libgo/go/crypto/md5/md5block_decl.go
Normal file
9
libgo/go/crypto/md5/md5block_decl.go
Normal 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)
|
@ -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
|
||||
}
|
||||
|
@ -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() {
|
||||
|
18
libgo/go/crypto/rc4/rc4_asm.go
Normal file
18
libgo/go/crypto/rc4/rc4_asm.go
Normal 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)
|
||||
}
|
20
libgo/go/crypto/rc4/rc4_ref.go
Normal file
20
libgo/go/crypto/rc4/rc4_ref.go
Normal 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
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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) {
|
||||
|
@ -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.
|
||||
|
9
libgo/go/crypto/sha1/sha1block_decl.go
Normal file
9
libgo/go/crypto/sha1/sha1block_decl.go
Normal 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)
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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-----`
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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:
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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)))
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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"}
|
||||
|
@ -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
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user