"\n" +
"Abraham Lincoln, November 19, 1863, Gettysburg, Pennsylvania\n"
-
func main() {
m := md5.New()
io.WriteString(m, data)
- hash := fmt.Sprintf("%x", m.Sum())
+ hash := fmt.Sprintf("%x", m.Sum(nil))
if hash != "525f06bc62a65017cd2217d7584e5920" {
println("BUG a", hash)
return
m = md5.New()
io.WriteString(m, gettysburg)
- hash = fmt.Sprintf("%x", m.Sum())
+ hash = fmt.Sprintf("%x", m.Sum(nil))
if hash != "d7ec5d9d47a4d166091e8d9ebd7ea0aa" {
println("BUG gettysburg", hash)
println(len(gettysburg))
func init() {
go f()
- time.Nanoseconds()
+ time.Now()
}
func main() {
}
-
-b4a91b693374
+0beb796b4ef8
The first line of this file holds the Mercurial revision number of the
last merge done from the master library sources.
toolexeclibgoexp_DATA = \
exp/ebnf.gox \
- exp/gui.gox \
$(exp_inotify_gox) \
exp/norm.gox \
exp/spdy.gox \
exp/terminal.gox \
exp/types.gox
-toolexeclibgoexpguidir = $(toolexeclibgoexpdir)/gui
-
-toolexeclibgoexpgui_DATA = \
- exp/gui/x11.gox
-
toolexeclibgoexpsqldir = $(toolexeclibgoexpdir)/sql
toolexeclibgoexpsql_DATA = \
runtime/go-map-len.c \
runtime/go-map-range.c \
runtime/go-nanotime.c \
+ runtime/go-now.c \
runtime/go-new-map.c \
runtime/go-new.c \
runtime/go-panic.c \
go_html_files = \
go/html/const.go \
go/html/doc.go \
+ go/html/doctype.go \
go/html/entity.go \
go/html/escape.go \
go/html/node.go \
go/time/sys_unix.go \
go/time/tick.go \
go/time/time.go \
- go/time/zoneinfo_posix.go \
+ go/time/zoneinfo.go \
go/time/zoneinfo_unix.go
go_unicode_files = \
go_crypto_x509_files = \
go/crypto/x509/cert_pool.go \
go/crypto/x509/pkcs1.go \
+ go/crypto/x509/pkcs8.go \
go/crypto/x509/verify.go \
go/crypto/x509/x509.go
go_crypto_xtea_files = \
go_exp_ebnf_files = \
go/exp/ebnf/ebnf.go \
go/exp/ebnf/parser.go
-go_exp_gui_files = \
- go/exp/gui/gui.go
go_exp_inotify_files = \
go/exp/inotify/inotify_linux.go
go_exp_norm_files = \
go/exp/types/types.go \
go/exp/types/universe.go
-go_exp_gui_x11_files = \
- go/exp/gui/x11/auth.go \
- go/exp/gui/x11/conn.go
-
go_exp_sql_driver_files = \
go/exp/sql/driver/driver.go \
go/exp/sql/driver/types.go
go/text/template/exec.go \
go/text/template/funcs.go \
go/text/template/helper.go \
- go/text/template/parse.go \
- go/text/template/set.go
+ go/text/template/template.go
go_text_template_parse_files = \
go/text/template/parse/lex.go \
go/text/template/parse/node.go \
- go/text/template/parse/parse.go \
- go/text/template/parse/set.go
+ go/text/template/parse/parse.go
go_sync_atomic_files = \
go/sync/atomic/doc.go
encoding/pem.lo \
encoding/xml.lo \
exp/ebnf.lo \
- exp/gui.lo \
exp/norm.lo \
exp/spdy.lo \
exp/sql.lo \
exp/ssh.lo \
exp/terminal.lo \
exp/types.lo \
- exp/gui/x11.lo \
exp/sql/driver.lo \
html/template.lo \
go/ast.lo \
@$(CHECK)
.PHONY: exp/ebnf/check
-@go_include@ exp/gui.lo.dep
-exp/gui.lo.dep: $(go_exp_gui_files)
- $(BUILDDEPS)
-exp/gui.lo: $(go_exp_gui_files)
- $(BUILDPACKAGE)
-exp/gui/check: $(CHECK_DEPS)
- @$(MKDIR_P) exp/gui
- @$(CHECK)
-.PHONY: exp/gui/check
-
@go_include@ exp/norm.lo.dep
exp/norm.lo.dep: $(go_exp_norm_files)
$(BUILDDEPS)
@$(CHECK)
.PHONY: exp/types/check
-@go_include@ exp/gui/x11.lo.dep
-exp/gui/x11.lo.dep: $(go_exp_gui_x11_files)
- $(BUILDDEPS)
-exp/gui/x11.lo: $(go_exp_gui_x11_files)
- $(BUILDPACKAGE)
-exp/gui/x11/check: $(CHECK_DEPS)
- @$(MKDIR_P) exp/gui/x11
- @$(CHECK)
-.PHONY: exp/gui/x11/check
-
@go_include@ exp/inotify.lo.dep
exp/inotify.lo.dep: $(go_exp_inotify_files)
$(BUILDDEPS)
exp/ebnf.gox: exp/ebnf.lo
$(BUILDGOX)
-exp/gui.gox: exp/gui.lo
- $(BUILDGOX)
exp/inotify.gox: exp/inotify.lo
$(BUILDGOX)
exp/norm.gox: exp/norm.lo
exp/types.gox: exp/types.lo
$(BUILDGOX)
-exp/gui/x11.gox: exp/gui/x11.lo
- $(BUILDGOX)
-
exp/sql/driver.gox: exp/sql/driver.lo
$(BUILDGOX)
html/template/check \
go/ast/check \
$(go_build_check_omitted_since_it_calls_6g) \
+ go/doc/check \
go/parser/check \
go/printer/check \
go/scanner/check \
"$(DESTDIR)$(toolexeclibgodebugdir)" \
"$(DESTDIR)$(toolexeclibgoencodingdir)" \
"$(DESTDIR)$(toolexeclibgoexpdir)" \
- "$(DESTDIR)$(toolexeclibgoexpguidir)" \
"$(DESTDIR)$(toolexeclibgoexpsqldir)" \
"$(DESTDIR)$(toolexeclibgogodir)" \
"$(DESTDIR)$(toolexeclibgohashdir)" \
encoding/base64.lo encoding/binary.lo encoding/csv.lo \
encoding/git85.lo encoding/gob.lo encoding/hex.lo \
encoding/json.lo encoding/pem.lo encoding/xml.lo exp/ebnf.lo \
- exp/gui.lo exp/norm.lo exp/spdy.lo exp/sql.lo exp/ssh.lo \
- exp/terminal.lo exp/types.lo exp/gui/x11.lo exp/sql/driver.lo \
- html/template.lo go/ast.lo go/build.lo go/doc.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/fcgi.lo net/http/httptest.lo net/http/httputil.lo \
- net/http/pprof.lo image/bmp.lo image/color.lo image/draw.lo \
- image/gif.lo image/jpeg.lo image/png.lo image/tiff.lo \
- image/ycbcr.lo index/suffixarray.lo io/ioutil.lo log/syslog.lo \
+ exp/norm.lo exp/spdy.lo exp/sql.lo exp/ssh.lo exp/terminal.lo \
+ exp/types.lo exp/sql/driver.lo html/template.lo go/ast.lo \
+ go/build.lo go/doc.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/fcgi.lo \
+ net/http/httptest.lo net/http/httputil.lo net/http/pprof.lo \
+ image/bmp.lo image/color.lo image/draw.lo image/gif.lo \
+ image/jpeg.lo image/png.lo image/tiff.lo image/ycbcr.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/mime.lo mime/multipart.lo net/dict.lo net/http.lo \
net/mail.lo net/rpc.lo net/smtp.lo net/textproto.lo net/url.lo \
runtime/go-interface-val-compare.c runtime/go-make-slice.c \
runtime/go-map-delete.c runtime/go-map-index.c \
runtime/go-map-len.c runtime/go-map-range.c \
- runtime/go-nanotime.c runtime/go-new-map.c runtime/go-new.c \
- runtime/go-panic.c runtime/go-print.c runtime/go-recover.c \
- runtime/go-reflect.c runtime/go-reflect-call.c \
- runtime/go-reflect-map.c runtime/go-rune.c \
- runtime/go-runtime-error.c runtime/go-setenv.c \
- runtime/go-signal.c runtime/go-strcmp.c \
+ runtime/go-nanotime.c runtime/go-now.c runtime/go-new-map.c \
+ runtime/go-new.c runtime/go-panic.c runtime/go-print.c \
+ runtime/go-recover.c runtime/go-reflect.c \
+ runtime/go-reflect-call.c runtime/go-reflect-map.c \
+ runtime/go-rune.c runtime/go-runtime-error.c \
+ runtime/go-setenv.c runtime/go-signal.c runtime/go-strcmp.c \
runtime/go-string-to-byte-array.c \
runtime/go-string-to-int-array.c runtime/go-strplus.c \
runtime/go-strslice.c runtime/go-trampoline.c \
go-interface-compare.lo go-interface-eface-compare.lo \
go-interface-val-compare.lo go-make-slice.lo go-map-delete.lo \
go-map-index.lo go-map-len.lo go-map-range.lo go-nanotime.lo \
- go-new-map.lo go-new.lo go-panic.lo go-print.lo go-recover.lo \
- go-reflect.lo go-reflect-call.lo go-reflect-map.lo go-rune.lo \
- go-runtime-error.lo go-setenv.lo go-signal.lo go-strcmp.lo \
- go-string-to-byte-array.lo go-string-to-int-array.lo \
- go-strplus.lo go-strslice.lo go-trampoline.lo go-type-eface.lo \
- go-type-error.lo go-type-identity.lo go-type-interface.lo \
- go-type-string.lo go-typedesc-equal.lo go-typestring.lo \
- go-unreflect.lo go-unsafe-new.lo go-unsafe-newarray.lo \
- go-unsafe-pointer.lo go-unwind.lo chan.lo cpuprof.lo \
- $(am__objects_1) mcache.lo mcentral.lo $(am__objects_2) \
- mfinal.lo mfixalloc.lo mgc0.lo mheap.lo msize.lo proc.lo \
- runtime.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
+ go-now.lo go-new-map.lo go-new.lo go-panic.lo go-print.lo \
+ go-recover.lo go-reflect.lo go-reflect-call.lo \
+ go-reflect-map.lo go-rune.lo go-runtime-error.lo go-setenv.lo \
+ go-signal.lo go-strcmp.lo go-string-to-byte-array.lo \
+ go-string-to-int-array.lo go-strplus.lo go-strslice.lo \
+ go-trampoline.lo go-type-eface.lo go-type-error.lo \
+ go-type-identity.lo go-type-interface.lo go-type-string.lo \
+ go-typedesc-equal.lo go-typestring.lo go-unreflect.lo \
+ go-unsafe-new.lo go-unsafe-newarray.lo go-unsafe-pointer.lo \
+ go-unwind.lo chan.lo cpuprof.lo $(am__objects_1) mcache.lo \
+ mcentral.lo $(am__objects_2) mfinal.lo mfixalloc.lo mgc0.lo \
+ mheap.lo msize.lo proc.lo runtime.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_libgo_la_OBJECTS = $(am__objects_4)
libgo_la_OBJECTS = $(am_libgo_la_OBJECTS)
libgo_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
$(toolexeclibgocrypto_DATA) $(toolexeclibgocryptoopenpgp_DATA) \
$(toolexeclibgocryptox509_DATA) $(toolexeclibgodebug_DATA) \
$(toolexeclibgoencoding_DATA) $(toolexeclibgoexp_DATA) \
- $(toolexeclibgoexpgui_DATA) $(toolexeclibgoexpsql_DATA) \
- $(toolexeclibgogo_DATA) $(toolexeclibgohash_DATA) \
- $(toolexeclibgohtml_DATA) $(toolexeclibgoimage_DATA) \
- $(toolexeclibgoindex_DATA) $(toolexeclibgoio_DATA) \
- $(toolexeclibgolog_DATA) $(toolexeclibgomath_DATA) \
- $(toolexeclibgomime_DATA) $(toolexeclibgonet_DATA) \
- $(toolexeclibgonethttp_DATA) $(toolexeclibgonetrpc_DATA) \
- $(toolexeclibgoold_DATA) $(toolexeclibgoos_DATA) \
- $(toolexeclibgopath_DATA) $(toolexeclibgoregexp_DATA) \
- $(toolexeclibgoruntime_DATA) $(toolexeclibgosync_DATA) \
- $(toolexeclibgotesting_DATA) $(toolexeclibgotext_DATA) \
- $(toolexeclibgotexttemplate_DATA) $(toolexeclibgounicode_DATA)
+ $(toolexeclibgoexpsql_DATA) $(toolexeclibgogo_DATA) \
+ $(toolexeclibgohash_DATA) $(toolexeclibgohtml_DATA) \
+ $(toolexeclibgoimage_DATA) $(toolexeclibgoindex_DATA) \
+ $(toolexeclibgoio_DATA) $(toolexeclibgolog_DATA) \
+ $(toolexeclibgomath_DATA) $(toolexeclibgomime_DATA) \
+ $(toolexeclibgonet_DATA) $(toolexeclibgonethttp_DATA) \
+ $(toolexeclibgonetrpc_DATA) $(toolexeclibgoold_DATA) \
+ $(toolexeclibgoos_DATA) $(toolexeclibgopath_DATA) \
+ $(toolexeclibgoregexp_DATA) $(toolexeclibgoruntime_DATA) \
+ $(toolexeclibgosync_DATA) $(toolexeclibgotesting_DATA) \
+ $(toolexeclibgotext_DATA) $(toolexeclibgotexttemplate_DATA) \
+ $(toolexeclibgounicode_DATA)
RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
distclean-recursive maintainer-clean-recursive
AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
toolexeclibgoexpdir = $(toolexeclibgodir)/exp
toolexeclibgoexp_DATA = \
exp/ebnf.gox \
- exp/gui.gox \
$(exp_inotify_gox) \
exp/norm.gox \
exp/spdy.gox \
exp/terminal.gox \
exp/types.gox
-toolexeclibgoexpguidir = $(toolexeclibgoexpdir)/gui
-toolexeclibgoexpgui_DATA = \
- exp/gui/x11.gox
-
toolexeclibgoexpsqldir = $(toolexeclibgoexpdir)/sql
toolexeclibgoexpsql_DATA = \
exp/sql/driver.gox
runtime/go-map-len.c \
runtime/go-map-range.c \
runtime/go-nanotime.c \
+ runtime/go-now.c \
runtime/go-new-map.c \
runtime/go-new.c \
runtime/go-panic.c \
go_html_files = \
go/html/const.go \
go/html/doc.go \
+ go/html/doctype.go \
go/html/entity.go \
go/html/escape.go \
go/html/node.go \
go/time/sys_unix.go \
go/time/tick.go \
go/time/time.go \
- go/time/zoneinfo_posix.go \
+ go/time/zoneinfo.go \
go/time/zoneinfo_unix.go
go_unicode_files = \
go_crypto_x509_files = \
go/crypto/x509/cert_pool.go \
go/crypto/x509/pkcs1.go \
+ go/crypto/x509/pkcs8.go \
go/crypto/x509/verify.go \
go/crypto/x509/x509.go
go/exp/ebnf/ebnf.go \
go/exp/ebnf/parser.go
-go_exp_gui_files = \
- go/exp/gui/gui.go
-
go_exp_inotify_files = \
go/exp/inotify/inotify_linux.go
go/exp/types/types.go \
go/exp/types/universe.go
-go_exp_gui_x11_files = \
- go/exp/gui/x11/auth.go \
- go/exp/gui/x11/conn.go
-
go_exp_sql_driver_files = \
go/exp/sql/driver/driver.go \
go/exp/sql/driver/types.go
go/text/template/exec.go \
go/text/template/funcs.go \
go/text/template/helper.go \
- go/text/template/parse.go \
- go/text/template/set.go
+ go/text/template/template.go
go_text_template_parse_files = \
go/text/template/parse/lex.go \
go/text/template/parse/node.go \
- go/text/template/parse/parse.go \
- go/text/template/parse/set.go
+ go/text/template/parse/parse.go
go_sync_atomic_files = \
go/sync/atomic/doc.go
encoding/pem.lo \
encoding/xml.lo \
exp/ebnf.lo \
- exp/gui.lo \
exp/norm.lo \
exp/spdy.lo \
exp/sql.lo \
exp/ssh.lo \
exp/terminal.lo \
exp/types.lo \
- exp/gui/x11.lo \
exp/sql/driver.lo \
html/template.lo \
go/ast.lo \
html/template/check \
go/ast/check \
$(go_build_check_omitted_since_it_calls_6g) \
+ go/doc/check \
go/parser/check \
go/printer/check \
go/scanner/check \
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-nanotime.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-new-map.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-new.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-now.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-panic.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-print.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-recover.Plo@am__quote@
@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 go-nanotime.lo `test -f 'runtime/go-nanotime.c' || echo '$(srcdir)/'`runtime/go-nanotime.c
+go-now.lo: runtime/go-now.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-now.lo -MD -MP -MF $(DEPDIR)/go-now.Tpo -c -o go-now.lo `test -f 'runtime/go-now.c' || echo '$(srcdir)/'`runtime/go-now.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-now.Tpo $(DEPDIR)/go-now.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-now.c' object='go-now.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 go-now.lo `test -f 'runtime/go-now.c' || echo '$(srcdir)/'`runtime/go-now.c
+
go-new-map.lo: runtime/go-new-map.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-new-map.lo -MD -MP -MF $(DEPDIR)/go-new-map.Tpo -c -o go-new-map.lo `test -f 'runtime/go-new-map.c' || echo '$(srcdir)/'`runtime/go-new-map.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-new-map.Tpo $(DEPDIR)/go-new-map.Plo
test -n "$$files" || exit 0; \
echo " ( cd '$(DESTDIR)$(toolexeclibgoexpdir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(toolexeclibgoexpdir)" && rm -f $$files
-install-toolexeclibgoexpguiDATA: $(toolexeclibgoexpgui_DATA)
- @$(NORMAL_INSTALL)
- test -z "$(toolexeclibgoexpguidir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgoexpguidir)"
- @list='$(toolexeclibgoexpgui_DATA)'; test -n "$(toolexeclibgoexpguidir)" || 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)$(toolexeclibgoexpguidir)'"; \
- $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgoexpguidir)" || exit $$?; \
- done
-
-uninstall-toolexeclibgoexpguiDATA:
- @$(NORMAL_UNINSTALL)
- @list='$(toolexeclibgoexpgui_DATA)'; test -n "$(toolexeclibgoexpguidir)" || list=; \
- files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
- test -n "$$files" || exit 0; \
- echo " ( cd '$(DESTDIR)$(toolexeclibgoexpguidir)' && rm -f" $$files ")"; \
- cd "$(DESTDIR)$(toolexeclibgoexpguidir)" && rm -f $$files
install-toolexeclibgoexpsqlDATA: $(toolexeclibgoexpsql_DATA)
@$(NORMAL_INSTALL)
test -z "$(toolexeclibgoexpsqldir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgoexpsqldir)"
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)$(toolexeclibgocryptoopenpgpdir)" "$(DESTDIR)$(toolexeclibgocryptox509dir)" "$(DESTDIR)$(toolexeclibgodebugdir)" "$(DESTDIR)$(toolexeclibgoencodingdir)" "$(DESTDIR)$(toolexeclibgoexpdir)" "$(DESTDIR)$(toolexeclibgoexpguidir)" "$(DESTDIR)$(toolexeclibgoexpsqldir)" "$(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)$(toolexeclibgocryptoopenpgpdir)" "$(DESTDIR)$(toolexeclibgocryptox509dir)" "$(DESTDIR)$(toolexeclibgodebugdir)" "$(DESTDIR)$(toolexeclibgoencodingdir)" "$(DESTDIR)$(toolexeclibgoexpdir)" "$(DESTDIR)$(toolexeclibgoexpsqldir)" "$(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
install-toolexeclibgocryptox509DATA \
install-toolexeclibgodebugDATA \
install-toolexeclibgoencodingDATA install-toolexeclibgoexpDATA \
- install-toolexeclibgoexpguiDATA \
install-toolexeclibgoexpsqlDATA install-toolexeclibgogoDATA \
install-toolexeclibgohashDATA install-toolexeclibgohtmlDATA \
install-toolexeclibgoimageDATA install-toolexeclibgoindexDATA \
uninstall-toolexeclibgodebugDATA \
uninstall-toolexeclibgoencodingDATA \
uninstall-toolexeclibgoexpDATA \
- uninstall-toolexeclibgoexpguiDATA \
uninstall-toolexeclibgoexpsqlDATA \
uninstall-toolexeclibgogoDATA uninstall-toolexeclibgohashDATA \
uninstall-toolexeclibgohtmlDATA \
install-toolexeclibgocryptox509DATA \
install-toolexeclibgodebugDATA \
install-toolexeclibgoencodingDATA install-toolexeclibgoexpDATA \
- install-toolexeclibgoexpguiDATA \
install-toolexeclibgoexpsqlDATA install-toolexeclibgogoDATA \
install-toolexeclibgohashDATA install-toolexeclibgohtmlDATA \
install-toolexeclibgoimageDATA install-toolexeclibgoindexDATA \
uninstall-toolexeclibgodebugDATA \
uninstall-toolexeclibgoencodingDATA \
uninstall-toolexeclibgoexpDATA \
- uninstall-toolexeclibgoexpguiDATA \
uninstall-toolexeclibgoexpsqlDATA \
uninstall-toolexeclibgogoDATA uninstall-toolexeclibgohashDATA \
uninstall-toolexeclibgohtmlDATA \
@$(CHECK)
.PHONY: exp/ebnf/check
-@go_include@ exp/gui.lo.dep
-exp/gui.lo.dep: $(go_exp_gui_files)
- $(BUILDDEPS)
-exp/gui.lo: $(go_exp_gui_files)
- $(BUILDPACKAGE)
-exp/gui/check: $(CHECK_DEPS)
- @$(MKDIR_P) exp/gui
- @$(CHECK)
-.PHONY: exp/gui/check
-
@go_include@ exp/norm.lo.dep
exp/norm.lo.dep: $(go_exp_norm_files)
$(BUILDDEPS)
@$(CHECK)
.PHONY: exp/types/check
-@go_include@ exp/gui/x11.lo.dep
-exp/gui/x11.lo.dep: $(go_exp_gui_x11_files)
- $(BUILDDEPS)
-exp/gui/x11.lo: $(go_exp_gui_x11_files)
- $(BUILDPACKAGE)
-exp/gui/x11/check: $(CHECK_DEPS)
- @$(MKDIR_P) exp/gui/x11
- @$(CHECK)
-.PHONY: exp/gui/x11/check
-
@go_include@ exp/inotify.lo.dep
exp/inotify.lo.dep: $(go_exp_inotify_files)
$(BUILDDEPS)
exp/ebnf.gox: exp/ebnf.lo
$(BUILDGOX)
-exp/gui.gox: exp/gui.lo
- $(BUILDGOX)
exp/inotify.gox: exp/inotify.lo
$(BUILDGOX)
exp/norm.gox: exp/norm.lo
exp/types.gox: exp/types.lo
$(BUILDGOX)
-exp/gui/x11.gox: exp/gui/x11.lo
- $(BUILDGOX)
-
exp/sql/driver.gox: exp/sql/driver.lo
$(BUILDGOX)
// http://www.gnu.org/software/tar/manual/html_node/Standard.html
package tar
+import "time"
+
const (
blockSize = 512
// Types
- TypeReg = '0' // regular file.
- TypeRegA = '\x00' // regular file.
- TypeLink = '1' // hard link.
- TypeSymlink = '2' // symbolic link.
- TypeChar = '3' // character device node.
- TypeBlock = '4' // block device node.
- TypeDir = '5' // directory.
- TypeFifo = '6' // fifo node.
- TypeCont = '7' // reserved.
- TypeXHeader = 'x' // extended header.
- TypeXGlobalHeader = 'g' // global extended header.
+ TypeReg = '0' // regular file
+ TypeRegA = '\x00' // regular file
+ TypeLink = '1' // hard link
+ TypeSymlink = '2' // symbolic link
+ TypeChar = '3' // character device node
+ TypeBlock = '4' // block device node
+ TypeDir = '5' // directory
+ TypeFifo = '6' // fifo node
+ TypeCont = '7' // reserved
+ TypeXHeader = 'x' // extended header
+ TypeXGlobalHeader = 'g' // global extended header
)
// A Header represents a single header in a tar archive.
// Some fields may not be populated.
type Header struct {
- Name string // name of header file entry.
- Mode int64 // permission and mode bits.
- Uid int // user id of owner.
- Gid int // group id of owner.
- Size int64 // length in bytes.
- Mtime int64 // modified time; seconds since epoch.
- Typeflag byte // type of header entry.
- Linkname string // target name of link.
- Uname string // user name of owner.
- Gname string // group name of owner.
- Devmajor int64 // major number of character or block device.
- Devminor int64 // minor number of character or block device.
- Atime int64 // access time; seconds since epoch.
- Ctime int64 // status change time; seconds since epoch.
-
+ Name string // name of header file entry
+ Mode int64 // permission and mode bits
+ Uid int // user id of owner
+ Gid int // group id of owner
+ Size int64 // length in bytes
+ ModTime time.Time // modified time
+ Typeflag byte // type of header entry
+ Linkname string // target name of link
+ Uname string // user name of owner
+ Gname string // group name of owner
+ Devmajor int64 // major number of character or block device
+ Devminor int64 // minor number of character or block device
+ AccessTime time.Time // access time
+ ChangeTime time.Time // status change time
}
var zeroBlock = make([]byte, blockSize)
"io/ioutil"
"os"
"strconv"
+ "time"
)
var (
hdr.Uid = int(tr.octal(s.next(8)))
hdr.Gid = int(tr.octal(s.next(8)))
hdr.Size = tr.octal(s.next(12))
- hdr.Mtime = tr.octal(s.next(12))
+ hdr.ModTime = time.Unix(tr.octal(s.next(12)), 0)
s.next(8) // chksum
hdr.Typeflag = s.next(1)[0]
hdr.Linkname = cString(s.next(100))
prefix = cString(s.next(155))
case "star":
prefix = cString(s.next(131))
- hdr.Atime = tr.octal(s.next(12))
- hdr.Ctime = tr.octal(s.next(12))
+ hdr.AccessTime = time.Unix(tr.octal(s.next(12)), 0)
+ hdr.ChangeTime = time.Unix(tr.octal(s.next(12)), 0)
}
if len(prefix) > 0 {
hdr.Name = prefix + "/" + hdr.Name
"os"
"reflect"
"testing"
+ "time"
)
type untarTest struct {
Uid: 73025,
Gid: 5000,
Size: 5,
- Mtime: 1244428340,
+ ModTime: time.Unix(1244428340, 0),
Typeflag: '0',
Uname: "dsymonds",
Gname: "eng",
Uid: 73025,
Gid: 5000,
Size: 11,
- Mtime: 1244436044,
+ ModTime: time.Unix(1244436044, 0),
Typeflag: '0',
Uname: "dsymonds",
Gname: "eng",
file: "testdata/star.tar",
headers: []*Header{
&Header{
- Name: "small.txt",
- Mode: 0640,
- Uid: 73025,
- Gid: 5000,
- Size: 5,
- Mtime: 1244592783,
- Typeflag: '0',
- Uname: "dsymonds",
- Gname: "eng",
- Atime: 1244592783,
- Ctime: 1244592783,
+ Name: "small.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 5,
+ ModTime: time.Unix(1244592783, 0),
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ AccessTime: time.Unix(1244592783, 0),
+ ChangeTime: time.Unix(1244592783, 0),
},
&Header{
- Name: "small2.txt",
- Mode: 0640,
- Uid: 73025,
- Gid: 5000,
- Size: 11,
- Mtime: 1244592783,
- Typeflag: '0',
- Uname: "dsymonds",
- Gname: "eng",
- Atime: 1244592783,
- Ctime: 1244592783,
+ Name: "small2.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 11,
+ ModTime: time.Unix(1244592783, 0),
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ AccessTime: time.Unix(1244592783, 0),
+ ChangeTime: time.Unix(1244592783, 0),
},
},
},
Uid: 73025,
Gid: 5000,
Size: 5,
- Mtime: 1244593104,
+ ModTime: time.Unix(1244593104, 0),
Typeflag: '\x00',
},
&Header{
Uid: 73025,
Gid: 5000,
Size: 11,
- Mtime: 1244593104,
+ ModTime: time.Unix(1244593104, 0),
Typeflag: '\x00',
},
},
h.Write(rdbuf[0:nr])
}
// verify checksum
- have := fmt.Sprintf("%x", h.Sum())
+ have := fmt.Sprintf("%x", h.Sum(nil))
want := cksums[nread]
if want != have {
t.Errorf("Bad checksum on file %s:\nhave %+v\nwant %+v", hdr.Name, have, want)
// TODO(dsymonds): handle names longer than 100 chars
copy(s.next(100), []byte(hdr.Name))
- tw.octal(s.next(8), hdr.Mode) // 100:108
- tw.numeric(s.next(8), int64(hdr.Uid)) // 108:116
- tw.numeric(s.next(8), int64(hdr.Gid)) // 116:124
- tw.numeric(s.next(12), hdr.Size) // 124:136
- tw.numeric(s.next(12), hdr.Mtime) // 136:148
- s.next(8) // chksum (148:156)
- s.next(1)[0] = hdr.Typeflag // 156:157
- tw.cString(s.next(100), hdr.Linkname) // linkname (157:257)
- copy(s.next(8), []byte("ustar\x0000")) // 257:265
- tw.cString(s.next(32), hdr.Uname) // 265:297
- 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.octal(s.next(8), hdr.Mode) // 100:108
+ tw.numeric(s.next(8), int64(hdr.Uid)) // 108:116
+ tw.numeric(s.next(8), int64(hdr.Gid)) // 116:124
+ tw.numeric(s.next(12), hdr.Size) // 124:136
+ tw.numeric(s.next(12), hdr.ModTime.Unix()) // 136:148
+ s.next(8) // chksum (148:156)
+ s.next(1)[0] = hdr.Typeflag // 156:157
+ tw.cString(s.next(100), hdr.Linkname) // linkname (157:257)
+ copy(s.next(8), []byte("ustar\x0000")) // 257:265
+ tw.cString(s.next(32), hdr.Uname) // 265:297
+ 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
// Use the GNU magic instead of POSIX magic if we used any GNU extensions.
if tw.usedBinary {
"io/ioutil"
"testing"
"testing/iotest"
+ "time"
)
type writerTestEntry struct {
Uid: 73025,
Gid: 5000,
Size: 5,
- Mtime: 1246508266,
+ ModTime: time.Unix(1246508266, 0),
Typeflag: '0',
Uname: "dsymonds",
Gname: "eng",
Uid: 73025,
Gid: 5000,
Size: 11,
- Mtime: 1245217492,
+ ModTime: time.Unix(1245217492, 0),
Typeflag: '0',
Uname: "dsymonds",
Gname: "eng",
Uid: 1000,
Gid: 1000,
Size: 0,
- Mtime: 1314603082,
+ ModTime: time.Unix(1314603082, 0),
Typeflag: '2',
Linkname: "small.txt",
Uname: "strings",
Uid: 73025,
Gid: 5000,
Size: 16 << 30,
- Mtime: 1254699560,
+ ModTime: time.Unix(1254699560, 0),
Typeflag: '0',
Uname: "dsymonds",
Gname: "eng",
return nil, err
}
r := new(ReadCloser)
- if err := r.init(f, fi.Size); err != nil {
+ if err := r.init(f, fi.Size()); err != nil {
f.Close()
return nil, err
}
t.Error(err)
return
}
- if got, want := f.Mtime_ns()/1e9, mtime.Seconds(); got != want {
- t.Errorf("%s: mtime=%s (%d); want %s (%d)", f.Name, time.SecondsToUTC(got), got, mtime, want)
+ if ft := f.ModTime(); !ft.Equal(mtime) {
+ t.Errorf("%s: mtime=%s, want %s", f.Name, ft, mtime)
}
testFileMode(t, f, ft.Mode)
*/
package zip
-import "errors"
-import "time"
+import (
+ "errors"
+ "time"
+)
// Compression methods.
const (
// The resolution is 2s.
// See: http://msdn.microsoft.com/en-us/library/ms724247(v=VS.85).aspx
func msDosTimeToTime(dosDate, dosTime uint16) time.Time {
- return time.Time{
+ return time.Date(
// date bits 0-4: day of month; 5-8: month; 9-15: years since 1980
- Year: int64(dosDate>>9 + 1980),
- Month: int(dosDate >> 5 & 0xf),
- Day: int(dosDate & 0x1f),
+ int(dosDate>>9+1980),
+ time.Month(dosDate>>5&0xf),
+ int(dosDate&0x1f),
// time bits 0-4: second/2; 5-10: minute; 11-15: hour
- Hour: int(dosTime >> 11),
- Minute: int(dosTime >> 5 & 0x3f),
- Second: int(dosTime & 0x1f * 2),
- }
+ int(dosTime>>11),
+ int(dosTime>>5&0x3f),
+ int(dosTime&0x1f*2),
+ 0, // nanoseconds
+
+ time.UTC,
+ )
}
-// Mtime_ns returns the modified time in ns since epoch.
+// ModTime returns the modification time.
// The resolution is 2s.
-func (h *FileHeader) Mtime_ns() int64 {
- t := msDosTimeToTime(h.ModifiedDate, h.ModifiedTime)
- return t.Seconds() * 1e9
+func (h *FileHeader) ModTime() time.Time {
+ return msDosTimeToTime(h.ModifiedDate, h.ModifiedTime)
}
// Mode returns the permission and mode bits for the FileHeader.
case "TrimRight":
f = TrimRight
default:
- t.Error("Undefined trim function %s", name)
+ t.Errorf("Undefined trim function %s", name)
}
actual := string(f([]byte(tc.in), tc.cutset))
if actual != tc.out {
"hash"
"hash/crc32"
"io"
+ "time"
)
// BUG(nigeltao): Comments and Names don't properly map UTF-8 character codes outside of
// The gzip file stores a header giving metadata about the compressed file.
// That header is exposed as the fields of the Compressor and Decompressor structs.
type Header struct {
- Comment string // comment
- Extra []byte // "extra data"
- Mtime uint32 // modification time (seconds since January 1, 1970)
- Name string // file name
- OS byte // operating system type
+ Comment string // comment
+ Extra []byte // "extra data"
+ ModTime time.Time // modification time
+ Name string // file name
+ OS byte // operating system type
}
// An Decompressor is an io.Reader that can be read to retrieve
}
z.flg = z.buf[3]
if save {
- z.Mtime = get4(z.buf[4:8])
+ z.ModTime = time.Unix(int64(get4(z.buf[4:8])), 0)
// z.buf[8] is xfl, ignored
z.OS = z.buf[9]
}
if z.Comment != "" {
z.buf[3] |= 0x10
}
- put4(z.buf[4:8], z.Mtime)
+ put4(z.buf[4:8], uint32(z.ModTime.Unix()))
if z.level == BestCompression {
z.buf[8] = 2
} else if z.level == BestSpeed {
"io"
"io/ioutil"
"testing"
+ "time"
)
// pipe creates two ends of a pipe that gzip and gunzip, and runs dfunc at the
func(compressor *Compressor) {
compressor.Comment = "comment"
compressor.Extra = []byte("extra")
- compressor.Mtime = 1e8
+ compressor.ModTime = time.Unix(1e8, 0)
compressor.Name = "name"
_, err := compressor.Write([]byte("payload"))
if err != nil {
if string(decompressor.Extra) != "extra" {
t.Fatalf("extra is %q, want %q", decompressor.Extra, "extra")
}
- if decompressor.Mtime != 1e8 {
- t.Fatalf("mtime is %d, want %d", decompressor.Mtime, uint32(1e8))
+ if decompressor.ModTime.Unix() != 1e8 {
+ t.Fatalf("mtime is %d, want %d", decompressor.ModTime.Unix(), uint32(1e8))
}
if decompressor.Name != "name" {
t.Fatalf("name is %q, want %q", decompressor.Name, "name")
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package bcrypt implements Provos and Mazières's bcrypt adapative hashing
+// Package bcrypt implements Provos and Mazières's bcrypt adaptive hashing
// algorithm. See http://www.usenix.org/event/usenix99/provos/provos.pdf
package bcrypt
msg, _ := hex.DecodeString(test.msg)
sha.Reset()
sha.Write(msg)
- hashed := sha.Sum()
+ hashed := sha.Sum(nil)
r := fromHex(test.r)
s := fromHex(test.s)
if Verify(&pub, hashed, r, s) != test.ok {
}
}
-func (h *hmac) Sum() []byte {
- sum := h.inner.Sum()
+func (h *hmac) Sum(in []byte) []byte {
+ sum := h.inner.Sum(nil)
h.tmpPad(0x5c)
for i, b := range sum {
h.tmp[padSize+i] = b
}
h.outer.Reset()
h.outer.Write(h.tmp)
- return h.outer.Sum()
+ return h.outer.Sum(in)
}
func (h *hmac) Write(p []byte) (n int, err error) {
if len(key) > padSize {
// If key is too big, hash it.
hm.outer.Write(key)
- key = hm.outer.Sum()
+ key = hm.outer.Sum(nil)
}
hm.key = make([]byte, len(key))
copy(hm.key, key)
// Repetitive Sum() calls should return the same value
for k := 0; k < 2; k++ {
- sum := fmt.Sprintf("%x", h.Sum())
+ sum := fmt.Sprintf("%x", h.Sum(nil))
if sum != tt.out {
t.Errorf("test %d.%d.%d: have %s want %s\n", i, j, k, sum, tt.out)
}
return
}
-func (d0 *digest) Sum() []byte {
+func (d0 *digest) Sum(in []byte) []byte {
// Make a copy of d0, so that caller can keep writing and summing.
d := new(digest)
*d = *d0
panic("d.nx != 0")
}
- p := make([]byte, 16)
- j := 0
for _, s := range d.s {
- p[j+0] = byte(s >> 0)
- p[j+1] = byte(s >> 8)
- p[j+2] = byte(s >> 16)
- p[j+3] = byte(s >> 24)
- j += 4
+ in = append(in, byte(s>>0))
+ in = append(in, byte(s>>8))
+ in = append(in, byte(s>>16))
+ in = append(in, byte(s>>24))
}
- return p
+ return in
}
io.WriteString(c, g.in)
} else {
io.WriteString(c, g.in[0:len(g.in)/2])
- c.Sum()
+ c.Sum(nil)
io.WriteString(c, g.in[len(g.in)/2:])
}
- s := fmt.Sprintf("%x", c.Sum())
+ s := fmt.Sprintf("%x", c.Sum(nil))
if s != g.out {
t.Fatalf("md4[%d](%s) = %s want %s", j, g.in, s, g.out)
}
return
}
-func (d0 *digest) Sum() []byte {
+func (d0 *digest) Sum(in []byte) []byte {
// Make a copy of d0 so that caller can keep writing and summing.
d := new(digest)
*d = *d0
panic("d.nx != 0")
}
- p := make([]byte, 16)
- j := 0
for _, s := range d.s {
- p[j+0] = byte(s >> 0)
- p[j+1] = byte(s >> 8)
- p[j+2] = byte(s >> 16)
- p[j+3] = byte(s >> 24)
- j += 4
+ in = append(in, byte(s>>0))
+ in = append(in, byte(s>>8))
+ in = append(in, byte(s>>16))
+ in = append(in, byte(s>>24))
}
- return p
+ return in
}
io.WriteString(c, g.in)
} else {
io.WriteString(c, g.in[0:len(g.in)/2])
- c.Sum()
+ c.Sum(nil)
io.WriteString(c, g.in[len(g.in)/2:])
}
- s := fmt.Sprintf("%x", c.Sum())
+ s := fmt.Sprintf("%x", c.Sum(nil))
if s != g.out {
t.Fatalf("md5[%d](%s) = %s want %s", j, g.in, s, g.out)
}
Version int `asn1:"optional,default:1,explicit,tag:0"`
RequestorName pkix.RDNSequence `asn1:"optional,explicit,tag:1"`
KeyHash []byte `asn1:"optional,explicit,tag:2"`
- ProducedAt *time.Time
+ ProducedAt time.Time
Responses []singleResponse
}
Good asn1.Flag `asn1:"explicit,tag:0,optional"`
Revoked revokedInfo `asn1:"explicit,tag:1,optional"`
Unknown asn1.Flag `asn1:"explicit,tag:2,optional"`
- ThisUpdate *time.Time
- NextUpdate *time.Time `asn1:"explicit,tag:0,optional"`
+ ThisUpdate time.Time
+ NextUpdate time.Time `asn1:"explicit,tag:0,optional"`
}
type revokedInfo struct {
- RevocationTime *time.Time
+ RevocationTime time.Time
Reason int `asn1:"explicit,tag:0,optional"`
}
// Status is one of {Good, Revoked, Unknown, ServerFailed}
Status int
SerialNumber []byte
- ProducedAt, ThisUpdate, NextUpdate, RevokedAt *time.Time
+ ProducedAt, ThisUpdate, NextUpdate, RevokedAt time.Time
RevocationReason int
Certificate *x509.Certificate
}
pub := ret.Certificate.PublicKey.(*rsa.PublicKey)
h.Write(basicResp.TBSResponseData.Raw)
- digest := h.Sum()
+ digest := h.Sum(nil)
signature := basicResp.Signature.RightAlign()
if rsa.VerifyPKCS1v15(pub, hashType, digest, signature) != nil {
t.Error(err)
}
- expected := Response{Status: 0, SerialNumber: []byte{0x1, 0xd0, 0xfa}, RevocationReason: 0, ThisUpdate: &time.Time{Year: 2010, Month: 7, Day: 7, Hour: 15, Minute: 1, Second: 5, ZoneOffset: 0, Zone: "UTC"}, NextUpdate: &time.Time{Year: 2010, Month: 7, Day: 7, Hour: 18, Minute: 35, Second: 17, ZoneOffset: 0, Zone: "UTC"}}
+ expected := Response{
+ Status: 0,
+ SerialNumber: []byte{0x1, 0xd0, 0xfa},
+ RevocationReason: 0,
+ ThisUpdate: time.Date(2010, 7, 7, 15, 1, 5, 0, time.UTC),
+ NextUpdate: time.Date(2010, 7, 7, 18, 35, 17, 0, time.UTC),
+ }
if !reflect.DeepEqual(resp.ThisUpdate, resp.ThisUpdate) {
t.Errorf("resp.ThisUpdate: got %d, want %d", resp.ThisUpdate, expected.ThisUpdate)
return len(buf), nil
}
-func (cth *canonicalTextHash) Sum() []byte {
- return cth.h.Sum()
+func (cth *canonicalTextHash) Sum(in []byte) []byte {
+ return cth.h.Sum(in)
}
func (cth *canonicalTextHash) Reset() {
return r.buf.Write(b)
}
-func (r recordingHash) Sum() []byte {
- return r.buf.Bytes()
+func (r recordingHash) Sum(in []byte) []byte {
+ return append(in, r.buf.Bytes()...)
}
func (r recordingHash) Reset() {
r := recordingHash{bytes.NewBuffer(nil)}
c := NewCanonicalTextHash(r)
c.Write([]byte(input))
- result := c.Sum()
+ result := c.Sum(nil)
if expected != string(result) {
t.Errorf("input: %x got: %x want: %x", input, result, expected)
}
// NewEntity returns an Entity that contains a fresh RSA/RSA keypair with a
// single identity composed of the given full name, comment and email, any of
// which may be empty but must not contain any of "()<>\x00".
-func NewEntity(rand io.Reader, currentTimeSecs int64, name, comment, email string) (*Entity, error) {
+func NewEntity(rand io.Reader, currentTime time.Time, name, comment, email string) (*Entity, error) {
uid := packet.NewUserId(name, comment, email)
if uid == nil {
return nil, error_.InvalidArgumentError("user id field contained invalid characters")
return nil, err
}
- t := uint32(currentTimeSecs)
-
e := &Entity{
- PrimaryKey: packet.NewRSAPublicKey(t, &signingPriv.PublicKey, false /* not a subkey */ ),
- PrivateKey: packet.NewRSAPrivateKey(t, signingPriv, false /* not a subkey */ ),
+ PrimaryKey: packet.NewRSAPublicKey(currentTime, &signingPriv.PublicKey, false /* not a subkey */ ),
+ PrivateKey: packet.NewRSAPrivateKey(currentTime, signingPriv, false /* not a subkey */ ),
Identities: make(map[string]*Identity),
}
isPrimaryId := true
Name: uid.Name,
UserId: uid,
SelfSignature: &packet.Signature{
- CreationTime: t,
+ CreationTime: currentTime,
SigType: packet.SigTypePositiveCert,
PubKeyAlgo: packet.PubKeyAlgoRSA,
Hash: crypto.SHA256,
e.Subkeys = make([]Subkey, 1)
e.Subkeys[0] = Subkey{
- PublicKey: packet.NewRSAPublicKey(t, &encryptingPriv.PublicKey, true /* is a subkey */ ),
- PrivateKey: packet.NewRSAPrivateKey(t, encryptingPriv, true /* is a subkey */ ),
+ PublicKey: packet.NewRSAPublicKey(currentTime, &encryptingPriv.PublicKey, true /* is a subkey */ ),
+ PrivateKey: packet.NewRSAPrivateKey(currentTime, encryptingPriv, true /* is a subkey */ ),
Sig: &packet.Signature{
- CreationTime: t,
+ CreationTime: currentTime,
SigType: packet.SigTypeSubkeyBinding,
PubKeyAlgo: packet.PubKeyAlgoRSA,
Hash: crypto.SHA256,
SigType: packet.SigTypeGenericCert,
PubKeyAlgo: signer.PrivateKey.PubKeyAlgo,
Hash: crypto.SHA256,
- CreationTime: uint32(time.Seconds()),
+ CreationTime: time.Now(),
IssuerKeyId: &signer.PrivateKey.KeyId,
}
if err := sig.SignKey(e.PrimaryKey, signer.PrivateKey); err != nil {
"io/ioutil"
"math/big"
"strconv"
+ "time"
)
// PrivateKey represents a possibly encrypted private key. See RFC 4880,
iv []byte
}
-func NewRSAPrivateKey(currentTimeSecs uint32, priv *rsa.PrivateKey, isSubkey bool) *PrivateKey {
+func NewRSAPrivateKey(currentTime time.Time, priv *rsa.PrivateKey, isSubkey bool) *PrivateKey {
pk := new(PrivateKey)
- pk.PublicKey = *NewRSAPublicKey(currentTimeSecs, &priv.PublicKey, isSubkey)
+ pk.PublicKey = *NewRSAPublicKey(currentTime, &priv.PublicKey, isSubkey)
pk.PrivateKey = priv
return pk
}
}
func mod64kHash(d []byte) uint16 {
- h := uint16(0)
- for i := 0; i < len(d); i += 2 {
- v := uint16(d[i]) << 8
- if i+1 < len(d) {
- v += uint16(d[i+1])
- }
- h += v
+ var h uint16
+ for _, b := range d {
+ h += uint16(b)
}
return h
}
}
h := sha1.New()
h.Write(data[:len(data)-sha1.Size])
- sum := h.Sum()
+ sum := h.Sum(nil)
if !bytes.Equal(sum, data[len(data)-sha1.Size:]) {
return error_.StructuralError("private key checksum failure")
}
import (
"testing"
+ "time"
)
var privateKeyTests = []struct {
privateKeyHex string
- creationTime uint32
+ creationTime time.Time
}{
{
privKeyRSAHex,
- 0x4cc349a8,
+ time.Unix(0x4cc349a8, 0),
},
{
privKeyElGamalHex,
- 0x4df9ee1a,
+ time.Unix(0x4df9ee1a, 0),
},
}
continue
}
- if privKey.CreationTime != test.creationTime || privKey.Encrypted {
+ if !privKey.CreationTime.Equal(test.creationTime) || privKey.Encrypted {
t.Errorf("#%d: bad result, got: %#v", i, privKey)
}
}
"io"
"math/big"
"strconv"
+ "time"
)
// PublicKey represents an OpenPGP public key. See RFC 4880, section 5.5.2.
type PublicKey struct {
- CreationTime uint32 // seconds since the epoch
+ CreationTime time.Time
PubKeyAlgo PublicKeyAlgorithm
PublicKey interface{} // Either a *rsa.PublicKey or *dsa.PublicKey
Fingerprint [20]byte
}
// NewRSAPublicKey returns a PublicKey that wraps the given rsa.PublicKey.
-func NewRSAPublicKey(creationTimeSecs uint32, pub *rsa.PublicKey, isSubkey bool) *PublicKey {
+func NewRSAPublicKey(creationTime time.Time, pub *rsa.PublicKey, isSubkey bool) *PublicKey {
pk := &PublicKey{
- CreationTime: creationTimeSecs,
+ CreationTime: creationTime,
PubKeyAlgo: PubKeyAlgoRSA,
PublicKey: pub,
IsSubkey: isSubkey,
if buf[0] != 4 {
return error_.UnsupportedError("public key version")
}
- pk.CreationTime = uint32(buf[1])<<24 | uint32(buf[2])<<16 | uint32(buf[3])<<8 | uint32(buf[4])
+ pk.CreationTime = time.Unix(int64(uint32(buf[1])<<24|uint32(buf[2])<<16|uint32(buf[3])<<8|uint32(buf[4])), 0)
pk.PubKeyAlgo = PublicKeyAlgorithm(buf[5])
switch pk.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
fingerPrint := sha1.New()
pk.SerializeSignaturePrefix(fingerPrint)
pk.serializeWithoutHeaders(fingerPrint)
- copy(pk.Fingerprint[:], fingerPrint.Sum())
+ copy(pk.Fingerprint[:], fingerPrint.Sum(nil))
pk.KeyId = binary.BigEndian.Uint64(pk.Fingerprint[12:20])
}
func (pk *PublicKey) serializeWithoutHeaders(w io.Writer) (err error) {
var buf [6]byte
buf[0] = 4
- buf[1] = byte(pk.CreationTime >> 24)
- buf[2] = byte(pk.CreationTime >> 16)
- buf[3] = byte(pk.CreationTime >> 8)
- buf[4] = byte(pk.CreationTime)
+ t := uint32(pk.CreationTime.Unix())
+ buf[1] = byte(t >> 24)
+ buf[2] = byte(t >> 16)
+ buf[3] = byte(t >> 8)
+ buf[4] = byte(t)
buf[5] = byte(pk.PubKeyAlgo)
_, err = w.Write(buf[:])
}
signed.Write(sig.HashSuffix)
- hashBytes := signed.Sum()
+ hashBytes := signed.Sum(nil)
if hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1] {
return error_.SignatureError("hash tag doesn't match")
"bytes"
"encoding/hex"
"testing"
+ "time"
)
var pubKeyTests = []struct {
hexData string
hexFingerprint string
- creationTime uint32
+ creationTime time.Time
pubKeyAlgo PublicKeyAlgorithm
keyId uint64
keyIdString string
keyIdShort string
}{
- {rsaPkDataHex, rsaFingerprintHex, 0x4d3c5c10, PubKeyAlgoRSA, 0xa34d7e18c20c31bb, "A34D7E18C20C31BB", "C20C31BB"},
- {dsaPkDataHex, dsaFingerprintHex, 0x4d432f89, PubKeyAlgoDSA, 0x8e8fbe54062f19ed, "8E8FBE54062F19ED", "062F19ED"},
+ {rsaPkDataHex, rsaFingerprintHex, time.Unix(0x4d3c5c10, 0), PubKeyAlgoRSA, 0xa34d7e18c20c31bb, "A34D7E18C20C31BB", "C20C31BB"},
+ {dsaPkDataHex, dsaFingerprintHex, time.Unix(0x4d432f89, 0), PubKeyAlgoDSA, 0x8e8fbe54062f19ed, "8E8FBE54062F19ED", "062F19ED"},
}
func TestPublicKeyRead(t *testing.T) {
if pk.PubKeyAlgo != test.pubKeyAlgo {
t.Errorf("#%d: bad public key algorithm got:%x want:%x", i, pk.PubKeyAlgo, test.pubKeyAlgo)
}
- if pk.CreationTime != test.creationTime {
- t.Errorf("#%d: bad creation time got:%x want:%x", i, pk.CreationTime, test.creationTime)
+ if !pk.CreationTime.Equal(test.creationTime) {
+ t.Errorf("#%d: bad creation time got:%v want:%v", i, pk.CreationTime, test.creationTime)
}
expectedFingerprint, _ := hex.DecodeString(test.hexFingerprint)
if !bytes.Equal(expectedFingerprint, pk.Fingerprint[:]) {
"hash"
"io"
"strconv"
+ "time"
)
// Signature represents a signature. See RFC 4880, section 5.2.
// HashTag contains the first two bytes of the hash for fast rejection
// of bad signed data.
HashTag [2]byte
- CreationTime uint32 // Unix epoch time
+ CreationTime time.Time
RSASignature parsedMPI
DSASigR, DSASigS parsedMPI
}
}
- if sig.CreationTime == 0 {
+ if sig.CreationTime.IsZero() {
err = error_.StructuralError("no creation time in signature")
}
err = error_.StructuralError("signature creation time not four bytes")
return
}
- sig.CreationTime = binary.BigEndian.Uint32(subpacket)
+ t := binary.BigEndian.Uint32(subpacket)
+ if t == 0 {
+ sig.CreationTime = time.Time{}
+ } else {
+ sig.CreationTime = time.Unix(int64(t), 0)
+ }
case signatureExpirationSubpacket:
// Signature expiration time, section 5.2.3.10
if !isHashed {
}
h.Write(sig.HashSuffix)
- digest = h.Sum()
+ digest = h.Sum(nil)
copy(sig.HashTag[:], digest)
return
}
func (sig *Signature) buildSubpackets() (subpackets []outputSubpacket) {
creationTime := make([]byte, 4)
- creationTime[0] = byte(sig.CreationTime >> 24)
- creationTime[1] = byte(sig.CreationTime >> 16)
- creationTime[2] = byte(sig.CreationTime >> 8)
- creationTime[3] = byte(sig.CreationTime)
+ binary.BigEndian.PutUint32(creationTime, uint32(sig.CreationTime.Unix()))
subpackets = append(subpackets, outputSubpacket{true, creationTimeSubpacket, false, creationTime})
if sig.IssuerKeyId != nil {
}
ser.h.Write(ser.trailer[:2])
- final := ser.h.Sum()
+ final := ser.h.Sum(nil)
if subtle.ConstantTimeCompare(final, ser.trailer[2:]) != 1 {
return error_.SignatureError("hash mismatch")
}
buf[0] = mdcPacketTagByte
buf[1] = sha1.Size
w.h.Write(buf[:2])
- digest := w.h.Sum()
+ digest := w.h.Sum(nil)
copy(buf[2:], digest)
_, err = w.w.Write(buf[:])
}
h.Write(salt)
h.Write(in)
- n := copy(out[done:], h.Sum())
+ n := copy(out[done:], h.Sum(nil))
done += n
}
}
written += len(combined)
}
}
- n := copy(out[done:], h.Sum())
+ n := copy(out[done:], h.Sum(nil))
done += n
}
}
sig.SigType = sigType
sig.PubKeyAlgo = signer.PrivateKey.PubKeyAlgo
sig.Hash = crypto.SHA256
- sig.CreationTime = uint32(time.Seconds())
+ sig.CreationTime = time.Now()
sig.IssuerKeyId = &signer.PrivateKey.KeyId
h, wrappedHash, err := hashForSignature(sig.Hash, sig.SigType)
// file should not be written to disk. It may be equal to "_CONSOLE" to
// suggest the data should not be written to disk.
FileName string
- // EpochSeconds contains the modification time of the file, or 0 if not applicable.
- EpochSeconds uint32
+ // ModTime contains the modification time of the file, or the zero time if not applicable.
+ ModTime time.Time
}
// SymmetricallyEncrypt acts like gpg -c: it encrypts a file with a passphrase.
if err != nil {
return
}
- return packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, hints.EpochSeconds)
+ var epochSeconds uint32
+ if !hints.ModTime.IsZero() {
+ epochSeconds = uint32(hints.ModTime.Unix())
+ }
+ return packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, epochSeconds)
}
// intersectPreferences mutates and returns a prefix of a that contains only
w = noOpCloser{encryptedData}
}
- literalData, err := packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, hints.EpochSeconds)
+ var epochSeconds uint32
+ if !hints.ModTime.IsZero() {
+ epochSeconds = uint32(hints.ModTime.Unix())
+ }
+ literalData, err := packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, epochSeconds)
if err != nil {
return nil, err
}
SigType: packet.SigTypeBinary,
PubKeyAlgo: s.signer.PubKeyAlgo,
Hash: s.hashType,
- CreationTime: uint32(time.Seconds()),
+ CreationTime: time.Now(),
IssuerKeyId: &s.signer.KeyId,
}
return
}
- e, err := NewEntity(rand.Reader, time.Seconds(), "Test User", "test", "test@example.com")
+ e, err := NewEntity(rand.Reader, time.Now(), "Test User", "test", "test@example.com")
if err != nil {
t.Errorf("failed to create entity: %s", err)
return
// t = encrypt(time)
// dst = encrypt(t^seed)
// seed = encrypt(t^dst)
- ns := time.Nanoseconds()
+ ns := time.Now().UnixNano()
r.time[0] = byte(ns >> 56)
r.time[1] = byte(ns >> 48)
r.time[2] = byte(ns >> 40)
return
}
-func (d0 *digest) Sum() []byte {
+func (d0 *digest) Sum(in []byte) []byte {
// Make a copy of d0 so that caller can keep writing and summing.
d := new(digest)
*d = *d0
panic("d.nx != 0")
}
- p := make([]byte, 20)
- j := 0
for _, s := range d.s {
- p[j], p[j+1], p[j+2], p[j+3] = byte(s), byte(s>>8), byte(s>>16), byte(s>>24)
- j += 4
+ in = append(in, byte(s))
+ in = append(in, byte(s>>8))
+ in = append(in, byte(s>>16))
+ in = append(in, byte(s>>24))
}
- return p
+ return in
}
io.WriteString(md, tv.in)
} else {
io.WriteString(md, tv.in[0:len(tv.in)/2])
- md.Sum()
+ md.Sum(nil)
io.WriteString(md, tv.in[len(tv.in)/2:])
}
- s := fmt.Sprintf("%x", md.Sum())
+ s := fmt.Sprintf("%x", md.Sum(nil))
if s != tv.out {
t.Fatalf("RIPEMD-160[%d](%s) = %s, expected %s", j, tv.in, s, tv.out)
}
io.WriteString(md, "aaaaaaaaaa")
}
out := "52783243c1697bdbe16d37f97f68f08325dc1528"
- s := fmt.Sprintf("%x", md.Sum())
+ s := fmt.Sprintf("%x", md.Sum(nil))
if s != out {
t.Fatalf("RIPEMD-160 (1 million 'a') = %s, expected %s", s, out)
}
for i, test := range signPKCS1v15Tests {
h := sha1.New()
h.Write([]byte(test.in))
- digest := h.Sum()
+ digest := h.Sum(nil)
s, err := SignPKCS1v15(nil, rsaPrivateKey, crypto.SHA1, digest)
if err != nil {
for i, test := range signPKCS1v15Tests {
h := sha1.New()
h.Write([]byte(test.in))
- digest := h.Sum()
+ digest := h.Sum(nil)
sig, _ := hex.DecodeString(test.out)
for done < len(out) {
hash.Write(seed)
hash.Write(counter[0:4])
- digest := hash.Sum()
+ digest := hash.Sum(nil)
hash.Reset()
for i := 0; i < len(digest) && done < len(out); i++ {
}
hash.Write(label)
- lHash := hash.Sum()
+ lHash := hash.Sum(nil)
hash.Reset()
em := make([]byte, k)
}
hash.Write(label)
- lHash := hash.Sum()
+ lHash := hash.Sum(nil)
hash.Reset()
// Converting the plaintext number to bytes will strip any
return
}
-func (d0 *digest) Sum() []byte {
+func (d0 *digest) Sum(in []byte) []byte {
// Make a copy of d0 so that caller can keep writing and summing.
d := new(digest)
*d = *d0
panic("d.nx != 0")
}
- p := make([]byte, 20)
- j := 0
for _, s := range d.h {
- p[j+0] = byte(s >> 24)
- p[j+1] = byte(s >> 16)
- p[j+2] = byte(s >> 8)
- p[j+3] = byte(s >> 0)
- j += 4
+ in = append(in, byte(s>>24))
+ in = append(in, byte(s>>16))
+ in = append(in, byte(s>>8))
+ in = append(in, byte(s))
}
- return p
+ return in
}
io.WriteString(c, g.in)
} else {
io.WriteString(c, g.in[0:len(g.in)/2])
- c.Sum()
+ c.Sum(nil)
io.WriteString(c, g.in[len(g.in)/2:])
}
- s := fmt.Sprintf("%x", c.Sum())
+ s := fmt.Sprintf("%x", c.Sum(nil))
if s != g.out {
t.Fatalf("sha1[%d](%s) = %s want %s", j, g.in, s, g.out)
}
return
}
-func (d0 *digest) Sum() []byte {
+func (d0 *digest) Sum(in []byte) []byte {
// Make a copy of d0 so that caller can keep writing and summing.
d := new(digest)
*d = *d0
panic("d.nx != 0")
}
- p := make([]byte, 32)
- j := 0
- for _, s := range d.h {
- p[j+0] = byte(s >> 24)
- p[j+1] = byte(s >> 16)
- p[j+2] = byte(s >> 8)
- p[j+3] = byte(s >> 0)
- j += 4
- }
+ h := d.h[:]
if d.is224 {
- return p[0:28]
+ h = d.h[:7]
+ }
+ for _, s := range h {
+ in = append(in, byte(s>>24))
+ in = append(in, byte(s>>16))
+ in = append(in, byte(s>>8))
+ in = append(in, byte(s))
}
- return p
+ return in
}
io.WriteString(c, g.in)
} else {
io.WriteString(c, g.in[0:len(g.in)/2])
- c.Sum()
+ c.Sum(nil)
io.WriteString(c, g.in[len(g.in)/2:])
}
- s := fmt.Sprintf("%x", c.Sum())
+ s := fmt.Sprintf("%x", c.Sum(nil))
if s != g.out {
t.Fatalf("sha256[%d](%s) = %s want %s", j, g.in, s, g.out)
}
io.WriteString(c, g.in)
} else {
io.WriteString(c, g.in[0:len(g.in)/2])
- c.Sum()
+ c.Sum(nil)
io.WriteString(c, g.in[len(g.in)/2:])
}
- s := fmt.Sprintf("%x", c.Sum())
+ s := fmt.Sprintf("%x", c.Sum(nil))
if s != g.out {
t.Fatalf("sha224[%d](%s) = %s want %s", j, g.in, s, g.out)
}
return
}
-func (d0 *digest) Sum() []byte {
+func (d0 *digest) Sum(in []byte) []byte {
// Make a copy of d0 so that caller can keep writing and summing.
d := new(digest)
*d = *d0
panic("d.nx != 0")
}
- p := make([]byte, 64)
- j := 0
- for _, s := range d.h {
- p[j+0] = byte(s >> 56)
- p[j+1] = byte(s >> 48)
- p[j+2] = byte(s >> 40)
- p[j+3] = byte(s >> 32)
- p[j+4] = byte(s >> 24)
- p[j+5] = byte(s >> 16)
- p[j+6] = byte(s >> 8)
- p[j+7] = byte(s >> 0)
- j += 8
- }
+ h := d.h[:]
if d.is384 {
- return p[0:48]
+ h = d.h[:6]
+ }
+ for _, s := range h {
+ in = append(in, byte(s>>56))
+ in = append(in, byte(s>>48))
+ in = append(in, byte(s>>40))
+ in = append(in, byte(s>>32))
+ in = append(in, byte(s>>24))
+ in = append(in, byte(s>>16))
+ in = append(in, byte(s>>8))
+ in = append(in, byte(s))
}
- return p
+ return in
}
io.WriteString(c, g.in)
} else {
io.WriteString(c, g.in[0:len(g.in)/2])
- c.Sum()
+ c.Sum(nil)
io.WriteString(c, g.in[len(g.in)/2:])
}
- s := fmt.Sprintf("%x", c.Sum())
+ s := fmt.Sprintf("%x", c.Sum(nil))
if s != g.out {
t.Fatalf("sha512[%d](%s) = %s want %s", j, g.in, s, g.out)
}
io.WriteString(c, g.in)
} else {
io.WriteString(c, g.in[0:len(g.in)/2])
- c.Sum()
+ c.Sum(nil)
io.WriteString(c, g.in[len(g.in)/2:])
}
- s := fmt.Sprintf("%x", c.Sum())
+ s := fmt.Sprintf("%x", c.Sum(nil))
if s != g.out {
t.Fatalf("sha384[%d](%s) = %s want %s", j, g.in, s, g.out)
}
// A cipherSuite is a specific combination of key agreement, cipher and MAC
// function. All cipher suites currently assume RSA key agreement.
type cipherSuite struct {
+ id uint16
// the lengths, in bytes, of the key material needed for each component.
keyLen int
macLen int
mac func(version uint16, macKey []byte) macFunction
}
-var cipherSuites = map[uint16]*cipherSuite{
- TLS_RSA_WITH_RC4_128_SHA: &cipherSuite{16, 20, 0, rsaKA, false, cipherRC4, macSHA1},
- TLS_RSA_WITH_3DES_EDE_CBC_SHA: &cipherSuite{24, 20, 8, rsaKA, false, cipher3DES, macSHA1},
- TLS_RSA_WITH_AES_128_CBC_SHA: &cipherSuite{16, 20, 16, rsaKA, false, cipherAES, macSHA1},
- TLS_ECDHE_RSA_WITH_RC4_128_SHA: &cipherSuite{16, 20, 0, ecdheRSAKA, true, cipherRC4, macSHA1},
- TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: &cipherSuite{24, 20, 8, ecdheRSAKA, true, cipher3DES, macSHA1},
- TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: &cipherSuite{16, 20, 16, ecdheRSAKA, true, cipherAES, macSHA1},
+var cipherSuites = []*cipherSuite{
+ &cipherSuite{TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, false, cipherRC4, macSHA1},
+ &cipherSuite{TLS_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, rsaKA, false, cipher3DES, macSHA1},
+ &cipherSuite{TLS_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, rsaKA, false, cipherAES, macSHA1},
+ &cipherSuite{TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, true, cipherRC4, macSHA1},
+ &cipherSuite{TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, true, cipher3DES, macSHA1},
+ &cipherSuite{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheRSAKA, true, cipherAES, macSHA1},
}
func cipherRC4(key, iv []byte, isRead bool) interface{} {
s.h.Write(record[:1])
s.h.Write(record[3:5])
s.h.Write(record[recordHeaderLen:])
- digest := s.h.Sum()
+ digest := s.h.Sum(nil)
s.h.Reset()
s.h.Write(s.key)
s.h.Write(ssl30Pad2[:padLength])
s.h.Write(digest)
- return s.h.Sum()
+ return s.h.Sum(nil)
}
// tls10MAC implements the TLS 1.0 MAC function. RFC 2246, section 6.2.3.
s.h.Reset()
s.h.Write(seq)
s.h.Write(record)
- return s.h.Sum()
+ return s.h.Sum(nil)
}
func rsaKA() keyAgreement {
return new(ecdheRSAKeyAgreement)
}
-// mutualCipherSuite returns a cipherSuite and its id given a list of supported
+// mutualCipherSuite returns a cipherSuite given a list of supported
// ciphersuites and the id requested by the peer.
-func mutualCipherSuite(have []uint16, want uint16) (suite *cipherSuite, id uint16) {
+func mutualCipherSuite(have []uint16, want uint16) *cipherSuite {
for _, id := range have {
if id == want {
- return cipherSuites[id], id
+ for _, suite := range cipherSuites {
+ if suite.id == want {
+ return suite
+ }
+ }
+ return nil
}
}
- return
+ return nil
}
// A list of the possible cipher suite ids. Taken from
// Time returns the current time as the number of seconds since the epoch.
// If Time is nil, TLS uses the system time.Seconds.
- Time func() int64
+ Time func() time.Time
// Certificates contains one or more certificate chains
// to present to the other side of the connection.
return r
}
-func (c *Config) time() int64 {
+func (c *Config) time() time.Time {
t := c.Time
if t == nil {
- t = time.Seconds
+ t = time.Now
}
return t()
}
func initDefaultCipherSuites() {
varDefaultCipherSuites = make([]uint16, len(cipherSuites))
- i := 0
- for id := range cipherSuites {
- varDefaultCipherSuites[i] = id
- i++
+ for i, suite := range cipherSuites {
+ varDefaultCipherSuites[i] = suite.id
}
}
nextProtoNeg: len(c.config.NextProtos) > 0,
}
- t := uint32(c.config.time())
+ t := uint32(c.config.time().Unix())
hello.random[0] = byte(t >> 24)
hello.random[1] = byte(t >> 16)
hello.random[2] = byte(t >> 8)
return errors.New("server advertised unrequested NPN")
}
- suite, suiteId := mutualCipherSuite(c.config.cipherSuites(), serverHello.cipherSuite)
+ suite := mutualCipherSuite(c.config.cipherSuites(), serverHello.cipherSuite)
if suite == nil {
return c.sendAlert(alertHandshakeFailure)
}
if cert != nil {
certVerify := new(certificateVerifyMsg)
var digest [36]byte
- copy(digest[0:16], finishedHash.serverMD5.Sum())
- copy(digest[16:36], finishedHash.serverSHA1.Sum())
+ copy(digest[0:16], finishedHash.serverMD5.Sum(nil))
+ copy(digest[16:36], finishedHash.serverSHA1.Sum(nil))
signed, err := rsa.SignPKCS1v15(c.config.rand(), c.config.Certificates[0].PrivateKey, crypto.MD5SHA1, digest[0:])
if err != nil {
return c.sendAlert(alertInternalError)
}
c.handshakeComplete = true
- c.cipherSuite = suiteId
+ c.cipherSuite = suite.id
return nil
}
ellipticOk := supportedCurve && supportedPointFormat
var suite *cipherSuite
- var suiteId uint16
FindCipherSuite:
for _, id := range clientHello.cipherSuites {
for _, supported := range config.cipherSuites() {
if id == supported {
- suite = cipherSuites[id]
+ suite = nil
+ for _, s := range cipherSuites {
+ if s.id == id {
+ suite = s
+ break
+ }
+ }
+ if suite == nil {
+ continue
+ }
// Don't select a ciphersuite which we can't
// support for this client.
if suite.elliptic && !ellipticOk {
continue
}
- suiteId = id
break FindCipherSuite
}
}
}
hello.vers = vers
- hello.cipherSuite = suiteId
- t := uint32(config.time())
+ hello.cipherSuite = suite.id
+ t := uint32(config.time().Unix())
hello.random = make([]byte, 32)
hello.random[0] = byte(t >> 24)
hello.random[1] = byte(t >> 16)
}
digest := make([]byte, 36)
- copy(digest[0:16], finishedHash.serverMD5.Sum())
- copy(digest[16:36], finishedHash.serverSHA1.Sum())
+ copy(digest[0:16], finishedHash.serverMD5.Sum(nil))
+ copy(digest[16:36], finishedHash.serverSHA1.Sum(nil))
err = rsa.VerifyPKCS1v15(pub, crypto.MD5SHA1, digest, certVerify.signature)
if err != nil {
c.sendAlert(alertBadCertificate)
c.writeRecord(recordTypeHandshake, finished.marshal())
c.handshakeComplete = true
- c.cipherSuite = suiteId
+ c.cipherSuite = suite.id
return nil
}
"strconv"
"strings"
"testing"
+ "time"
)
type zeroSource struct{}
func init() {
testConfig = new(Config)
- testConfig.Time = func() int64 { return 0 }
+ testConfig.Time = func() time.Time { return time.Unix(0, 0) }
testConfig.Rand = zeroSource{}
testConfig.Certificates = make([]Certificate, 1)
testConfig.Certificates[0].Certificate = [][]byte{testCertificate}
for _, slice := range slices {
hmd5.Write(slice)
}
- copy(md5sha1, hmd5.Sum())
+ copy(md5sha1, hmd5.Sum(nil))
hsha1 := sha1.New()
for _, slice := range slices {
hsha1.Write(slice)
}
- copy(md5sha1[md5.Size:], hsha1.Sum())
+ copy(md5sha1[md5.Size:], hsha1.Sum(nil))
return md5sha1
}
func pHash(result, secret, seed []byte, hash func() hash.Hash) {
h := hmac.New(hash, secret)
h.Write(seed)
- a := h.Sum()
+ a := h.Sum(nil)
j := 0
for j < len(result) {
h.Reset()
h.Write(a)
h.Write(seed)
- b := h.Sum()
+ b := h.Sum(nil)
todo := len(b)
if j+todo > len(result) {
todo = len(result) - j
h.Reset()
h.Write(a)
- a = h.Sum()
+ a = h.Sum(nil)
}
}
hashSHA1.Write(b[:i+1])
hashSHA1.Write(secret)
hashSHA1.Write(seed)
- digest := hashSHA1.Sum()
+ digest := hashSHA1.Sum(nil)
hashMD5.Reset()
hashMD5.Write(secret)
hashMD5.Write(digest)
- done += copy(result[done:], hashMD5.Sum())
+ done += copy(result[done:], hashMD5.Sum(nil))
i++
}
}
md5.Write(magic[:])
md5.Write(masterSecret)
md5.Write(ssl30Pad1[:])
- md5Digest := md5.Sum()
+ md5Digest := md5.Sum(nil)
md5.Reset()
md5.Write(masterSecret)
md5.Write(ssl30Pad2[:])
md5.Write(md5Digest)
- md5Digest = md5.Sum()
+ md5Digest = md5.Sum(nil)
sha1.Write(magic[:])
sha1.Write(masterSecret)
sha1.Write(ssl30Pad1[:40])
- sha1Digest := sha1.Sum()
+ sha1Digest := sha1.Sum(nil)
sha1.Reset()
sha1.Write(masterSecret)
sha1.Write(ssl30Pad2[:40])
sha1.Write(sha1Digest)
- sha1Digest = sha1.Sum()
+ sha1Digest = sha1.Sum(nil)
ret := make([]byte, len(md5Digest)+len(sha1Digest))
copy(ret, md5Digest)
return finishedSum30(h.clientMD5, h.clientSHA1, masterSecret, ssl3ClientFinishedMagic)
}
- md5 := h.clientMD5.Sum()
- sha1 := h.clientSHA1.Sum()
+ md5 := h.clientMD5.Sum(nil)
+ sha1 := h.clientSHA1.Sum(nil)
return finishedSum10(md5, sha1, clientFinishedLabel, masterSecret)
}
return finishedSum30(h.serverMD5, h.serverSHA1, masterSecret, ssl3ServerFinishedMagic)
}
- md5 := h.serverMD5.Sum()
- sha1 := h.serverSHA1.Sum()
+ md5 := h.serverMD5.Sum(nil)
+ sha1 := h.serverSHA1.Sum(nil)
return finishedSum10(md5, sha1, serverFinishedLabel, masterSecret)
}
"/etc/ssl/certs/ca-certificates.crt", // Linux etc
"/etc/pki/tls/certs/ca-bundle.crt", // Fedora/RHEL
"/etc/ssl/ca-bundle.pem", // OpenSUSE
+ "/etc/ssl/cert.pem", // OpenBSD
}
func initDefaultRoots() {
import (
"crypto/x509"
- "reflect"
"syscall"
"unsafe"
)
if err != nil {
return
}
+ defer syscall.CertCloseStore(store, 0)
var cert *syscall.CertContext
for {
- cert = syscall.CertEnumCertificatesInStore(store, cert)
- if cert == nil {
- break
+ cert, err = syscall.CertEnumCertificatesInStore(store, cert)
+ if err != nil {
+ return
}
- var asn1Slice []byte
- hdrp := (*reflect.SliceHeader)(unsafe.Pointer(&asn1Slice))
- hdrp.Data = cert.EncodedCert
- hdrp.Len = int(cert.Length)
- hdrp.Cap = int(cert.Length)
-
- buf := make([]byte, len(asn1Slice))
- copy(buf, asn1Slice)
-
- if cert, err := x509.ParseCertificate(buf); err == nil {
- roots.AddCert(cert)
+ buf := (*[1 << 20]byte)(unsafe.Pointer(cert.EncodedCert))[:]
+ // ParseCertificate requires its own copy of certificate data to keep.
+ buf2 := make([]byte, cert.Length)
+ copy(buf2, buf)
+ if c, err := x509.ParseCertificate(buf2); err == nil {
+ roots.AddCert(c)
}
}
-
- syscall.CertCloseStore(store, 0)
}
func initDefaultRoots() {
return
}
- key, err := x509.ParsePKCS1PrivateKey(keyDERBlock.Bytes)
- if err != nil {
- err = errors.New("crypto/tls: failed to parse key: " + err.Error())
- return
+ // OpenSSL 0.9.8 generates PKCS#1 private keys by default, while
+ // OpenSSL 1.0.0 generates PKCS#8 keys. We try both.
+ var key *rsa.PrivateKey
+ if key, err = x509.ParsePKCS1PrivateKey(keyDERBlock.Bytes); err != nil {
+ var privKey interface{}
+ if privKey, err = x509.ParsePKCS8PrivateKey(keyDERBlock.Bytes); err != nil {
+ err = errors.New("crypto/tls: failed to parse key: " + err.Error())
+ return
+ }
+
+ var ok bool
+ if key, ok = privKey.(*rsa.PrivateKey); !ok {
+ err = errors.New("crypto/tls: found non-RSA private key in PKCS#8 wrapping")
+ return
+ }
}
cert.PrivateKey = key
"encoding/pem"
)
-// Roots is a set of certificates.
+// CertPool is a set of certificates.
type CertPool struct {
bySubjectKeyId map[string][]int
byName map[string][]int
s.byName[name] = append(s.byName[name], n)
}
-// AppendCertsFromPEM attempts to parse a series of PEM encoded root
-// certificates. It appends any certificates found to s and returns true if any
-// certificates were successfully parsed.
+// AppendCertsFromPEM attempts to parse a series of PEM encoded certificates.
+// It appends any certificates found to s and returns true if any certificates
+// were successfully parsed.
//
-// On many Linux systems, /etc/ssl/cert.pem will contains the system wide set
+// On many Linux systems, /etc/ssl/cert.pem will contain the system wide set
// of root CAs in a format suitable for this function.
func (s *CertPool) AppendCertsFromPEM(pemCerts []byte) (ok bool) {
for len(pemCerts) > 0 {
--- /dev/null
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import (
+ "crypto/x509/pkix"
+ "encoding/asn1"
+ "errors"
+ "fmt"
+)
+
+// pkcs8 reflects an ASN.1, PKCS#8 PrivateKey. See
+// ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-8/pkcs-8v1_2.asn.
+type pkcs8 struct {
+ Version int
+ Algo pkix.AlgorithmIdentifier
+ PrivateKey []byte
+ // optional attributes omitted.
+}
+
+// ParsePKCS8PrivateKey parses an unencrypted, PKCS#8 private key. See
+// http://www.rsa.com/rsalabs/node.asp?id=2130
+func ParsePKCS8PrivateKey(der []byte) (key interface{}, err error) {
+ var privKey pkcs8
+ if _, err := asn1.Unmarshal(der, &privKey); err != nil {
+ return nil, err
+ }
+ switch {
+ case privKey.Algo.Algorithm.Equal(oidRSA):
+ key, err = ParsePKCS1PrivateKey(privKey.PrivateKey)
+ if err != nil {
+ return nil, errors.New("crypto/x509: failed to parse RSA private key embedded in PKCS#8: " + err.Error())
+ }
+ return key, nil
+ default:
+ return nil, fmt.Errorf("crypto/x509: PKCS#8 wrapping contained private key with unknown algorithm: %v", privKey.Algo.Algorithm)
+ }
+
+ panic("unreachable")
+}
--- /dev/null
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import (
+ "encoding/hex"
+ "testing"
+)
+
+var pkcs8PrivateKeyHex = `30820278020100300d06092a864886f70d0101010500048202623082025e02010002818100cfb1b5bf9685ffa97b4f99df4ff122b70e59ac9b992f3bc2b3dde17d53c1a34928719b02e8fd17839499bfbd515bd6ef99c7a1c47a239718fe36bfd824c0d96060084b5f67f0273443007a24dfaf5634f7772c9346e10eb294c2306671a5a5e719ae24b4de467291bc571014b0e02dec04534d66a9bb171d644b66b091780e8d020301000102818100b595778383c4afdbab95d2bfed12b3f93bb0a73a7ad952f44d7185fd9ec6c34de8f03a48770f2009c8580bcd275e9632714e9a5e3f32f29dc55474b2329ff0ebc08b3ffcb35bc96e6516b483df80a4a59cceb71918cbabf91564e64a39d7e35dce21cb3031824fdbc845dba6458852ec16af5dddf51a8397a8797ae0337b1439024100ea0eb1b914158c70db39031dd8904d6f18f408c85fbbc592d7d20dee7986969efbda081fdf8bc40e1b1336d6b638110c836bfdc3f314560d2e49cd4fbde1e20b024100e32a4e793b574c9c4a94c8803db5152141e72d03de64e54ef2c8ed104988ca780cd11397bc359630d01b97ebd87067c5451ba777cf045ca23f5912f1031308c702406dfcdbbd5a57c9f85abc4edf9e9e29153507b07ce0a7ef6f52e60dcfebe1b8341babd8b789a837485da6c8d55b29bbb142ace3c24a1f5b54b454d01b51e2ad03024100bd6a2b60dee01e1b3bfcef6a2f09ed027c273cdbbaf6ba55a80f6dcc64e4509ee560f84b4f3e076bd03b11e42fe71a3fdd2dffe7e0902c8584f8cad877cdc945024100aa512fa4ada69881f1d8bb8ad6614f192b83200aef5edf4811313d5ef30a86cbd0a90f7b025c71ea06ec6b34db6306c86b1040670fd8654ad7291d066d06d031`
+
+func TestPKCS8(t *testing.T) {
+ derBytes, _ := hex.DecodeString(pkcs8PrivateKeyHex)
+ _, err := ParsePKCS8PrivateKey(derBytes)
+ if err != nil {
+ t.Errorf("failed to decode PKCS8 key: %s", err)
+ }
+}
SignatureValue asn1.BitString
}
-// HasExpired returns true iff currentTimeSeconds is past the expiry time of
-// certList.
-func (certList *CertificateList) HasExpired(currentTimeSeconds int64) bool {
- return certList.TBSCertList.NextUpdate.Seconds() <= currentTimeSeconds
+// HasExpired returns true iff now is past the expiry time of certList.
+func (certList *CertificateList) HasExpired(now time.Time) bool {
+ return now.After(certList.TBSCertList.NextUpdate)
}
// TBSCertificateList represents the ASN.1 structure of the same name. See RFC
Version int `asn1:"optional,default:2"`
Signature AlgorithmIdentifier
Issuer RDNSequence
- ThisUpdate *time.Time
- NextUpdate *time.Time
+ ThisUpdate time.Time
+ NextUpdate time.Time
RevokedCertificates []RevokedCertificate `asn1:"optional"`
Extensions []Extension `asn1:"tag:0,optional,explicit"`
}
// 5280, section 5.1.
type RevokedCertificate struct {
SerialNumber *big.Int
- RevocationTime *time.Time
+ RevocationTime time.Time
Extensions []Extension `asn1:"optional"`
}
DNSName string
Intermediates *CertPool
Roots *CertPool
- CurrentTime int64 // if 0, the current system time is used.
+ CurrentTime time.Time // if zero, the current time is used
}
const (
// isValid performs validity checks on the c.
func (c *Certificate) isValid(certType int, opts *VerifyOptions) error {
- if opts.CurrentTime < c.NotBefore.Seconds() ||
- opts.CurrentTime > c.NotAfter.Seconds() {
+ now := opts.CurrentTime
+ if now.IsZero() {
+ now = time.Now()
+ }
+ if now.Before(c.NotBefore) || now.After(c.NotAfter) {
return CertificateInvalidError{c, Expired}
}
//
// WARNING: this doesn't do any revocation checking.
func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) {
- if opts.CurrentTime == 0 {
- opts.CurrentTime = time.Seconds()
- }
err = c.isValid(leafCertificate, &opts)
if err != nil {
return
"errors"
"strings"
"testing"
+ "time"
)
type verifyTest struct {
Roots: NewCertPool(),
Intermediates: NewCertPool(),
DNSName: test.dnsName,
- CurrentTime: test.currentTime,
+ CurrentTime: time.Unix(test.currentTime, 0),
}
for j, root := range test.roots {
}
type validity struct {
- NotBefore, NotAfter *time.Time
+ NotBefore, NotAfter time.Time
}
type publicKeyInfo struct {
SerialNumber *big.Int
Issuer pkix.Name
Subject pkix.Name
- NotBefore, NotAfter *time.Time // Validity bounds.
+ NotBefore, NotAfter time.Time // Validity bounds.
KeyUsage KeyUsage
ExtKeyUsage []ExtKeyUsage // Sequence of extended key usages.
}
h.Write(signed)
- digest := h.Sum()
+ digest := h.Sum(nil)
switch pub := c.PublicKey.(type) {
case *rsa.PublicKey:
oidRSA = []int{1, 2, 840, 113549, 1, 1, 1}
)
-// CreateSelfSignedCertificate creates a new certificate based on
-// a template. The following members of template are used: SerialNumber,
-// Subject, NotBefore, NotAfter, KeyUsage, BasicConstraintsValid, IsCA,
-// MaxPathLen, SubjectKeyId, DNSNames, PermittedDNSDomainsCritical,
-// PermittedDNSDomains.
+// CreateCertificate creates a new certificate based on a template. The
+// following members of template are used: SerialNumber, Subject, NotBefore,
+// NotAfter, KeyUsage, BasicConstraintsValid, IsCA, MaxPathLen, SubjectKeyId,
+// DNSNames, PermittedDNSDomainsCritical, PermittedDNSDomains.
//
// The certificate is signed by parent. If parent is equal to template then the
// certificate is self-signed. The parameter pub is the public key of the
h := sha1.New()
h.Write(tbsCertContents)
- digest := h.Sum()
+ digest := h.Sum(nil)
signature, err := rsa.SignPKCS1v15(rand, priv, crypto.SHA1, digest)
if err != nil {
// CreateCRL returns a DER encoded CRL, signed by this Certificate, that
// contains the given list of revoked certificates.
-func (c *Certificate) CreateCRL(rand io.Reader, priv *rsa.PrivateKey, revokedCerts []pkix.RevokedCertificate, now, expiry *time.Time) (crlBytes []byte, err error) {
+func (c *Certificate) CreateCRL(rand io.Reader, priv *rsa.PrivateKey, revokedCerts []pkix.RevokedCertificate, now, expiry time.Time) (crlBytes []byte, err error) {
tbsCertList := pkix.TBSCertificateList{
Version: 2,
Signature: pkix.AlgorithmIdentifier{
h := sha1.New()
h.Write(tbsCertListContents)
- digest := h.Sum()
+ digest := h.Sum(nil)
signature, err := rsa.SignPKCS1v15(rand, priv, crypto.SHA1, digest)
if err != nil {
CommonName: commonName,
Organization: []string{"Acme Co"},
},
- NotBefore: time.SecondsToUTC(1000),
- NotAfter: time.SecondsToUTC(100000),
+ NotBefore: time.Unix(1000, 0),
+ NotAfter: time.Unix(100000, 0),
SubjectKeyId: []byte{1, 2, 3, 4},
KeyUsage: KeyUsageCertSign,
block, _ = pem.Decode([]byte(pemCertificate))
cert, _ := ParseCertificate(block.Bytes)
- now := time.SecondsToUTC(1000)
- expiry := time.SecondsToUTC(10000)
+ now := time.Unix(1000, 0)
+ expiry := time.Unix(10000, 0)
revokedCerts := []pkix.RevokedCertificate{
{
t.Errorf("bad number of revoked certificates. got: %d want: %d", numCerts, expected)
}
- if certList.HasExpired(1302517272) {
+ if certList.HasExpired(time.Unix(1302517272, 0)) {
t.Errorf("CRL has expired (but shouldn't have)")
}
t.Errorf("bad number of revoked certificates. got: %d want: %d", numCerts, expected)
}
- if certList.HasExpired(1302517272) {
+ if certList.HasExpired(time.Unix(1302517272, 0)) {
t.Errorf("CRL has expired (but shouldn't have)")
}
// UTCTime
-func parseUTCTime(bytes []byte) (ret *time.Time, err error) {
+func parseUTCTime(bytes []byte) (ret time.Time, err error) {
s := string(bytes)
ret, err = time.Parse("0601021504Z0700", s)
if err == nil {
// parseGeneralizedTime parses the GeneralizedTime from the given byte slice
// and returns the resulting time.
-func parseGeneralizedTime(bytes []byte) (ret *time.Time, err error) {
+func parseGeneralizedTime(bytes []byte) (ret time.Time, err error) {
return time.Parse("20060102150405Z0700", string(bytes))
}
objectIdentifierType = reflect.TypeOf(ObjectIdentifier{})
enumeratedType = reflect.TypeOf(Enumerated(0))
flagType = reflect.TypeOf(Flag(false))
- timeType = reflect.TypeOf(&time.Time{})
+ timeType = reflect.TypeOf(time.Time{})
rawValueType = reflect.TypeOf(RawValue{})
rawContentsType = reflect.TypeOf(RawContent(nil))
bigIntType = reflect.TypeOf(new(big.Int))
err = err1
return
case timeType:
- var time *time.Time
+ var time time.Time
var err1 error
if universalTag == tagUTCTime {
time, err1 = parseUTCTime(innerBytes)
//
// An ASN.1 ENUMERATED can be written to an Enumerated.
//
-// An ASN.1 UTCTIME or GENERALIZEDTIME can be written to a *time.Time.
+// An ASN.1 UTCTIME or GENERALIZEDTIME can be written to a time.Time.
//
// An ASN.1 PrintableString or IA5String can be written to a string.
//
type timeTest struct {
in string
ok bool
- out *time.Time
+ out time.Time
}
var utcTestData = []timeTest{
- {"910506164540-0700", true, &time.Time{1991, 05, 06, 16, 45, 40, 0, -7 * 60 * 60, ""}},
- {"910506164540+0730", true, &time.Time{1991, 05, 06, 16, 45, 40, 0, 7*60*60 + 30*60, ""}},
- {"910506234540Z", true, &time.Time{1991, 05, 06, 23, 45, 40, 0, 0, "UTC"}},
- {"9105062345Z", true, &time.Time{1991, 05, 06, 23, 45, 0, 0, 0, "UTC"}},
- {"a10506234540Z", false, nil},
- {"91a506234540Z", false, nil},
- {"9105a6234540Z", false, nil},
- {"910506a34540Z", false, nil},
- {"910506334a40Z", false, nil},
- {"91050633444aZ", false, nil},
- {"910506334461Z", false, nil},
- {"910506334400Za", false, nil},
+ {"910506164540-0700", true, time.Date(1991, 05, 06, 16, 45, 40, 0, time.FixedZone("", -7*60*60))},
+ {"910506164540+0730", true, time.Date(1991, 05, 06, 16, 45, 40, 0, time.FixedZone("", 7*60*60+30*60))},
+ {"910506234540Z", true, time.Date(1991, 05, 06, 23, 45, 40, 0, time.UTC)},
+ {"9105062345Z", true, time.Date(1991, 05, 06, 23, 45, 0, 0, time.UTC)},
+ {"a10506234540Z", false, time.Time{}},
+ {"91a506234540Z", false, time.Time{}},
+ {"9105a6234540Z", false, time.Time{}},
+ {"910506a34540Z", false, time.Time{}},
+ {"910506334a40Z", false, time.Time{}},
+ {"91050633444aZ", false, time.Time{}},
+ {"910506334461Z", false, time.Time{}},
+ {"910506334400Za", false, time.Time{}},
}
func TestUTCTime(t *testing.T) {
for i, test := range utcTestData {
ret, err := parseUTCTime([]byte(test.in))
- if (err == nil) != test.ok {
- t.Errorf("#%d: Incorrect error result (did fail? %v, expected: %v)", i, err == nil, test.ok)
- }
- if err == nil {
- if !reflect.DeepEqual(test.out, ret) {
- t.Errorf("#%d: Bad result: %v (expected %v)", i, ret, test.out)
+ if err != nil {
+ if test.ok {
+ t.Errorf("#%d: parseUTCTime(%q) = error %v", i, err)
}
+ continue
+ }
+ if !test.ok {
+ t.Errorf("#%d: parseUTCTime(%q) succeeded, should have failed", i)
+ continue
+ }
+ const format = "Jan _2 15:04:05 -0700 2006" // ignore zone name, just offset
+ have := ret.Format(format)
+ want := test.out.Format(format)
+ if have != want {
+ t.Errorf("#%d: parseUTCTime(%q) = %s, want %s", test.in, have, want)
}
}
}
var generalizedTimeTestData = []timeTest{
- {"20100102030405Z", true, &time.Time{2010, 01, 02, 03, 04, 05, 0, 0, "UTC"}},
- {"20100102030405", false, nil},
- {"20100102030405+0607", true, &time.Time{2010, 01, 02, 03, 04, 05, 0, 6*60*60 + 7*60, ""}},
- {"20100102030405-0607", true, &time.Time{2010, 01, 02, 03, 04, 05, 0, -6*60*60 - 7*60, ""}},
+ {"20100102030405Z", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.UTC)},
+ {"20100102030405", false, time.Time{}},
+ {"20100102030405+0607", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.FixedZone("", 6*60*60+7*60))},
+ {"20100102030405-0607", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.FixedZone("", -6*60*60-7*60))},
}
func TestGeneralizedTime(t *testing.T) {
}
type Validity struct {
- NotBefore, NotAfter *time.Time
+ NotBefore, NotAfter time.Time
}
type PublicKeyInfo struct {
RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 3}, Value: "false.example.com"}},
RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}, Value: "false@example.com"}},
},
- Validity: Validity{NotBefore: &time.Time{Year: 2009, Month: 10, Day: 8, Hour: 0, Minute: 25, Second: 53, ZoneOffset: 0, Zone: "UTC"}, NotAfter: &time.Time{Year: 2010, Month: 10, Day: 8, Hour: 0, Minute: 25, Second: 53, ZoneOffset: 0, Zone: "UTC"}},
+ Validity: Validity{
+ NotBefore: time.Date(2009, 10, 8, 00, 25, 53, 0, time.UTC),
+ NotAfter: time.Date(2010, 10, 8, 00, 25, 53, 0, time.UTC),
+ },
Subject: RDNSequence{
RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 6}, Value: "XX"}},
RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 8}, Value: "Some-State"}},
return out.WriteByte(byte('0' + v%10))
}
-func marshalUTCTime(out *forkableWriter, t *time.Time) (err error) {
+func marshalUTCTime(out *forkableWriter, t time.Time) (err error) {
+ utc := t.UTC()
+ year, month, day := utc.Date()
+
switch {
- case 1950 <= t.Year && t.Year < 2000:
- err = marshalTwoDigits(out, int(t.Year-1900))
- case 2000 <= t.Year && t.Year < 2050:
- err = marshalTwoDigits(out, int(t.Year-2000))
+ case 1950 <= year && year < 2000:
+ err = marshalTwoDigits(out, int(year-1900))
+ case 2000 <= year && year < 2050:
+ err = marshalTwoDigits(out, int(year-2000))
default:
return StructuralError{"Cannot represent time as UTCTime"}
}
-
if err != nil {
return
}
- err = marshalTwoDigits(out, t.Month)
+ err = marshalTwoDigits(out, int(month))
if err != nil {
return
}
- err = marshalTwoDigits(out, t.Day)
+ err = marshalTwoDigits(out, day)
if err != nil {
return
}
- err = marshalTwoDigits(out, t.Hour)
+ hour, min, sec := utc.Clock()
+
+ err = marshalTwoDigits(out, hour)
if err != nil {
return
}
- err = marshalTwoDigits(out, t.Minute)
+ err = marshalTwoDigits(out, min)
if err != nil {
return
}
- err = marshalTwoDigits(out, t.Second)
+ err = marshalTwoDigits(out, sec)
if err != nil {
return
}
+ _, offset := t.Zone()
+
switch {
- case t.ZoneOffset/60 == 0:
+ case offset/60 == 0:
err = out.WriteByte('Z')
return
- case t.ZoneOffset > 0:
+ case offset > 0:
err = out.WriteByte('+')
- case t.ZoneOffset < 0:
+ case offset < 0:
err = out.WriteByte('-')
}
return
}
- offsetMinutes := t.ZoneOffset / 60
+ offsetMinutes := offset / 60
if offsetMinutes < 0 {
offsetMinutes = -offsetMinutes
}
func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameters) (err error) {
switch value.Type() {
case timeType:
- return marshalUTCTime(out, value.Interface().(*time.Time))
+ return marshalUTCTime(out, value.Interface().(time.Time))
case bitStringType:
return marshalBitString(out, value.Interface().(BitString))
case objectIdentifierType:
type testSET []int
-func setPST(t *time.Time) *time.Time {
- t.ZoneOffset = -28800
- return t
-}
+var PST = time.FixedZone("PST", -8*60*60)
type marshalTest struct {
in interface{}
{[]byte{1, 2, 3}, "0403010203"},
{implicitTagTest{64}, "3003850140"},
{explicitTagTest{64}, "3005a503020140"},
- {time.SecondsToUTC(0), "170d3730303130313030303030305a"},
- {time.SecondsToUTC(1258325776), "170d3039313131353232353631365a"},
- {setPST(time.SecondsToUTC(1258325776)), "17113039313131353232353631362d30383030"},
+ {time.Unix(0, 0).UTC(), "170d3730303130313030303030305a"},
+ {time.Unix(1258325776, 0).UTC(), "170d3039313131353232353631365a"},
+ {time.Unix(1258325776, 0).In(PST), "17113039313131353232353631362d30383030"},
{BitString{[]byte{0x80}, 1}, "03020780"},
{BitString{[]byte{0x81, 0xf0}, 12}, "03030481f0"},
{ObjectIdentifier([]int{1, 2, 3, 4}), "06032a0304"},
}
out, _ := hex.DecodeString(test.out)
if bytes.Compare(out, data) != 0 {
- t.Errorf("#%d got: %x want %x", i, data, out)
+ t.Errorf("#%d got: %x want %x\n\t%q\n\t%q", i, data, out, data, out)
+
}
}
}
"runtime"
"sort"
"strconv"
+ "sync"
"unicode"
"unicode/utf8"
)
case reflect.Struct:
e.WriteByte('{')
- t := v.Type()
- n := v.NumField()
first := true
- for i := 0; i < n; i++ {
- f := t.Field(i)
- if f.PkgPath != "" {
- continue
- }
- tag, omitEmpty, quoted := f.Name, false, false
- if tv := f.Tag.Get("json"); tv != "" {
- if tv == "-" {
- continue
- }
- name, opts := parseTag(tv)
- if isValidTag(name) {
- tag = name
- }
- omitEmpty = opts.Contains("omitempty")
- quoted = opts.Contains("string")
- }
- fieldValue := v.Field(i)
- if omitEmpty && isEmptyValue(fieldValue) {
+ for _, ef := range encodeFields(v.Type()) {
+ fieldValue := v.Field(ef.i)
+ if ef.omitEmpty && isEmptyValue(fieldValue) {
continue
}
if first {
} else {
e.WriteByte(',')
}
- e.string(tag)
+ e.string(ef.tag)
e.WriteByte(':')
- e.reflectValueQuoted(fieldValue, quoted)
+ e.reflectValueQuoted(fieldValue, ef.quoted)
}
e.WriteByte('}')
e.WriteByte('"')
return e.Len() - len0, nil
}
+
+// encodeField contains information about how to encode a field of a
+// struct.
+type encodeField struct {
+ i int // field index in struct
+ tag string
+ quoted bool
+ omitEmpty bool
+}
+
+var (
+ typeCacheLock sync.RWMutex
+ encodeFieldsCache = make(map[reflect.Type][]encodeField)
+)
+
+// encodeFields returns a slice of encodeField for a given
+// struct type.
+func encodeFields(t reflect.Type) []encodeField {
+ typeCacheLock.RLock()
+ fs, ok := encodeFieldsCache[t]
+ typeCacheLock.RUnlock()
+ if ok {
+ return fs
+ }
+
+ typeCacheLock.Lock()
+ defer typeCacheLock.Unlock()
+ fs, ok = encodeFieldsCache[t]
+ if ok {
+ return fs
+ }
+
+ v := reflect.Zero(t)
+ n := v.NumField()
+ for i := 0; i < n; i++ {
+ f := t.Field(i)
+ if f.PkgPath != "" {
+ continue
+ }
+ var ef encodeField
+ ef.i = i
+ ef.tag = f.Name
+
+ tv := f.Tag.Get("json")
+ if tv != "" {
+ if tv == "-" {
+ continue
+ }
+ name, opts := parseTag(tv)
+ if isValidTag(name) {
+ ef.tag = name
+ }
+ ef.omitEmpty = opts.Contains("omitempty")
+ ef.quoted = opts.Contains("string")
+ }
+ fs = append(fs, ef)
+ }
+ encodeFieldsCache[t] = fs
+ return fs
+}
func (e StartElement) Copy() StartElement {
attrs := make([]Attr, len(e.Attr))
- copy(e.Attr, attrs)
+ copy(attrs, e.Attr)
e.Attr = attrs
return e
}
</body><!-- missing final newline -->`
var rawTokens = []Token{
- CharData([]byte("\n")),
+ CharData("\n"),
ProcInst{"xml", []byte(`version="1.0" encoding="UTF-8"`)},
- CharData([]byte("\n")),
- Directive([]byte(`DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ CharData("\n"),
+ Directive(`DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"`),
- ),
- CharData([]byte("\n")),
+ CharData("\n"),
StartElement{Name{"", "body"}, []Attr{{Name{"xmlns", "foo"}, "ns1"}, {Name{"", "xmlns"}, "ns2"}, {Name{"xmlns", "tag"}, "ns3"}}},
- CharData([]byte("\n ")),
+ CharData("\n "),
StartElement{Name{"", "hello"}, []Attr{{Name{"", "lang"}, "en"}}},
- CharData([]byte("World <>'\" 白鵬翔")),
+ CharData("World <>'\" 白鵬翔"),
EndElement{Name{"", "hello"}},
- CharData([]byte("\n ")),
+ CharData("\n "),
StartElement{Name{"", "goodbye"}, []Attr{}},
EndElement{Name{"", "goodbye"}},
- CharData([]byte("\n ")),
+ CharData("\n "),
StartElement{Name{"", "outer"}, []Attr{{Name{"foo", "attr"}, "value"}, {Name{"xmlns", "tag"}, "ns4"}}},
- CharData([]byte("\n ")),
+ CharData("\n "),
StartElement{Name{"", "inner"}, []Attr{}},
EndElement{Name{"", "inner"}},
- CharData([]byte("\n ")),
+ CharData("\n "),
EndElement{Name{"", "outer"}},
- CharData([]byte("\n ")),
+ CharData("\n "),
StartElement{Name{"tag", "name"}, []Attr{}},
- CharData([]byte("\n ")),
- CharData([]byte("Some text here.")),
- CharData([]byte("\n ")),
+ CharData("\n "),
+ CharData("Some text here."),
+ CharData("\n "),
EndElement{Name{"tag", "name"}},
- CharData([]byte("\n")),
+ CharData("\n"),
EndElement{Name{"", "body"}},
- Comment([]byte(" missing final newline ")),
+ Comment(" missing final newline "),
}
var cookedTokens = []Token{
- CharData([]byte("\n")),
+ CharData("\n"),
ProcInst{"xml", []byte(`version="1.0" encoding="UTF-8"`)},
- CharData([]byte("\n")),
- Directive([]byte(`DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ CharData("\n"),
+ Directive(`DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"`),
- ),
- CharData([]byte("\n")),
+ CharData("\n"),
StartElement{Name{"ns2", "body"}, []Attr{{Name{"xmlns", "foo"}, "ns1"}, {Name{"", "xmlns"}, "ns2"}, {Name{"xmlns", "tag"}, "ns3"}}},
- CharData([]byte("\n ")),
+ CharData("\n "),
StartElement{Name{"ns2", "hello"}, []Attr{{Name{"", "lang"}, "en"}}},
- CharData([]byte("World <>'\" 白鵬翔")),
+ CharData("World <>'\" 白鵬翔"),
EndElement{Name{"ns2", "hello"}},
- CharData([]byte("\n ")),
+ CharData("\n "),
StartElement{Name{"ns2", "goodbye"}, []Attr{}},
EndElement{Name{"ns2", "goodbye"}},
- CharData([]byte("\n ")),
+ CharData("\n "),
StartElement{Name{"ns2", "outer"}, []Attr{{Name{"ns1", "attr"}, "value"}, {Name{"xmlns", "tag"}, "ns4"}}},
- CharData([]byte("\n ")),
+ CharData("\n "),
StartElement{Name{"ns2", "inner"}, []Attr{}},
EndElement{Name{"ns2", "inner"}},
- CharData([]byte("\n ")),
+ CharData("\n "),
EndElement{Name{"ns2", "outer"}},
- CharData([]byte("\n ")),
+ CharData("\n "),
StartElement{Name{"ns3", "name"}, []Attr{}},
- CharData([]byte("\n ")),
- CharData([]byte("Some text here.")),
- CharData([]byte("\n ")),
+ CharData("\n "),
+ CharData("Some text here."),
+ CharData("\n "),
EndElement{Name{"ns3", "name"}},
- CharData([]byte("\n")),
+ CharData("\n"),
EndElement{Name{"ns2", "body"}},
- Comment([]byte(" missing final newline ")),
+ Comment(" missing final newline "),
}
const testInputAltEncoding = `
<TAG>VALUE</TAG>`
var rawTokensAltEncoding = []Token{
- CharData([]byte("\n")),
+ CharData("\n"),
ProcInst{"xml", []byte(`version="1.0" encoding="x-testing-uppercase"`)},
- CharData([]byte("\n")),
+ CharData("\n"),
StartElement{Name{"", "tag"}, []Attr{}},
- CharData([]byte("value")),
+ CharData("value"),
EndElement{Name{"", "tag"}},
}
`
var nestedDirectivesTokens = []Token{
- CharData([]byte("\n")),
- Directive([]byte(`DOCTYPE [<!ENTITY rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#">]`)),
- CharData([]byte("\n")),
- Directive([]byte(`DOCTYPE [<!ENTITY xlt ">">]`)),
- CharData([]byte("\n")),
- Directive([]byte(`DOCTYPE [<!ENTITY xlt "<">]`)),
- CharData([]byte("\n")),
- Directive([]byte(`DOCTYPE [<!ENTITY xlt '>'>]`)),
- CharData([]byte("\n")),
- Directive([]byte(`DOCTYPE [<!ENTITY xlt '<'>]`)),
- CharData([]byte("\n")),
- Directive([]byte(`DOCTYPE [<!ENTITY xlt '">'>]`)),
- CharData([]byte("\n")),
- Directive([]byte(`DOCTYPE [<!ENTITY xlt "'<">]`)),
- CharData([]byte("\n")),
+ CharData("\n"),
+ Directive(`DOCTYPE [<!ENTITY rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#">]`),
+ CharData("\n"),
+ Directive(`DOCTYPE [<!ENTITY xlt ">">]`),
+ CharData("\n"),
+ Directive(`DOCTYPE [<!ENTITY xlt "<">]`),
+ CharData("\n"),
+ Directive(`DOCTYPE [<!ENTITY xlt '>'>]`),
+ CharData("\n"),
+ Directive(`DOCTYPE [<!ENTITY xlt '<'>]`),
+ CharData("\n"),
+ Directive(`DOCTYPE [<!ENTITY xlt '">'>]`),
+ CharData("\n"),
+ Directive(`DOCTYPE [<!ENTITY xlt "'<">]`),
+ CharData("\n"),
}
func TestNestedDirectives(t *testing.T) {
elt := StartElement{Name{"", "hello"}, []Attr{{Name{"", "lang"}, "en"}}}
var tok1 Token = elt
tok2 := CopyToken(tok1)
+ if tok1.(StartElement).Attr[0].Value != "en" {
+ t.Error("CopyToken overwrote Attr[0]")
+ }
if !reflect.DeepEqual(tok1, tok2) {
t.Error("CopyToken(StartElement) != StartElement")
}
- elt.Attr[0] = Attr{Name{"", "lang"}, "de"}
+ tok1.(StartElement).Attr[0] = Attr{Name{"", "lang"}, "de"}
if reflect.DeepEqual(tok1, tok2) {
t.Error("CopyToken(CharData) uses same buffer.")
}
switch info, err := os.Stat(filename); {
case err != nil:
report(err)
- case info.IsRegular():
- if allFiles || isGoFilename(info.Name) {
- filenames[i] = filename
- i++
- }
- case info.IsDirectory():
+ case info.IsDir():
if allFiles || *recursive {
processDirectory(filename)
}
+ default:
+ if allFiles || isGoFilename(info.Name()) {
+ filenames[i] = filename
+ i++
+ }
}
}
fset := token.NewFileSet()
+++ /dev/null
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package gui defines a basic graphical user interface programming model.
-package gui
-
-import (
- "image"
- "image/draw"
-)
-
-// A Window represents a single graphics window.
-type Window interface {
- // Screen returns an editable Image for the window.
- Screen() draw.Image
- // FlushImage flushes changes made to Screen() back to screen.
- FlushImage()
- // EventChan returns a channel carrying UI events such as key presses,
- // mouse movements and window resizes.
- EventChan() <-chan interface{}
- // Close closes the window.
- Close() error
-}
-
-// A KeyEvent is sent for a key press or release.
-type KeyEvent struct {
- // The value k represents key k being pressed.
- // The value -k represents key k being released.
- // The specific set of key values is not specified,
- // but ordinary characters represent themselves.
- Key int
-}
-
-// A MouseEvent is sent for a button press or release or for a mouse movement.
-type MouseEvent struct {
- // Buttons is a bit mask of buttons: 1<<0 is left, 1<<1 middle, 1<<2 right.
- // It represents button state and not necessarily the state delta: bit 0
- // being on means that the left mouse button is down, but does not imply
- // that the same button was up in the previous MouseEvent.
- Buttons int
- // Loc is the location of the cursor.
- Loc image.Point
- // Nsec is the event's timestamp.
- Nsec int64
-}
-
-// A ConfigEvent is sent each time the window's color model or size changes.
-// The client should respond by calling Window.Screen to obtain a new image.
-type ConfigEvent struct {
- Config image.Config
-}
-
-// An ErrEvent is sent when an error occurs.
-type ErrEvent struct {
- Err error
-}
+++ /dev/null
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package x11
-
-import (
- "bufio"
- "errors"
- "io"
- "os"
-)
-
-// readU16BE reads a big-endian uint16 from r, using b as a scratch buffer.
-func readU16BE(r io.Reader, b []byte) (uint16, error) {
- _, err := io.ReadFull(r, b[0:2])
- if err != nil {
- return 0, err
- }
- return uint16(b[0])<<8 + uint16(b[1]), nil
-}
-
-// readStr reads a length-prefixed string from r, using b as a scratch buffer.
-func readStr(r io.Reader, b []byte) (string, error) {
- n, err := readU16BE(r, b)
- if err != nil {
- return "", err
- }
- if int(n) > len(b) {
- return "", errors.New("Xauthority entry too long for buffer")
- }
- _, err = io.ReadFull(r, b[0:n])
- if err != nil {
- return "", err
- }
- return string(b[0:n]), nil
-}
-
-// readAuth reads the X authority file and returns the name/data pair for the display.
-// displayStr is the "12" out of a $DISPLAY like ":12.0".
-func readAuth(displayStr string) (name, data string, err error) {
- // b is a scratch buffer to use and should be at least 256 bytes long
- // (i.e. it should be able to hold a hostname).
- var b [256]byte
- // As per /usr/include/X11/Xauth.h.
- const familyLocal = 256
-
- fn := os.Getenv("XAUTHORITY")
- if fn == "" {
- home := os.Getenv("HOME")
- if home == "" {
- err = errors.New("Xauthority not found: $XAUTHORITY, $HOME not set")
- return
- }
- fn = home + "/.Xauthority"
- }
- r, err := os.Open(fn)
- if err != nil {
- return
- }
- defer r.Close()
- br := bufio.NewReader(r)
-
- hostname, err := os.Hostname()
- if err != nil {
- return
- }
- for {
- var family uint16
- var addr, disp, name0, data0 string
- family, err = readU16BE(br, b[0:2])
- if err != nil {
- return
- }
- addr, err = readStr(br, b[0:])
- if err != nil {
- return
- }
- disp, err = readStr(br, b[0:])
- if err != nil {
- return
- }
- name0, err = readStr(br, b[0:])
- if err != nil {
- return
- }
- data0, err = readStr(br, b[0:])
- if err != nil {
- return
- }
- if family == familyLocal && addr == hostname && disp == displayStr {
- return name0, data0, nil
- }
- }
- panic("unreachable")
-}
+++ /dev/null
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package x11 implements an X11 backend for the exp/gui package.
-//
-// The X protocol specification is at ftp://ftp.x.org/pub/X11R7.0/doc/PDF/proto.pdf.
-// A summary of the wire format can be found in XCB's xproto.xml.
-package x11
-
-import (
- "bufio"
- "errors"
- "exp/gui"
- "image"
- "image/draw"
- "io"
- "log"
- "net"
- "os"
- "strconv"
- "strings"
- "time"
-)
-
-type resID uint32 // X resource IDs.
-
-// TODO(nigeltao): Handle window resizes.
-const (
- windowHeight = 600
- windowWidth = 800
-)
-
-const (
- keymapLo = 8
- keymapHi = 255
-)
-
-type conn struct {
- c io.Closer
- r *bufio.Reader
- w *bufio.Writer
-
- gc, window, root, visual resID
-
- img *image.RGBA
- eventc chan interface{}
- mouseState gui.MouseEvent
-
- buf [256]byte // General purpose scratch buffer.
-
- flush chan bool
- flushBuf0 [24]byte
- flushBuf1 [4 * 1024]byte
-}
-
-// writeSocket runs in its own goroutine, serving both FlushImage calls
-// directly from the exp/gui client and indirectly from X expose events.
-// It paints c.img to the X server via PutImage requests.
-func (c *conn) writeSocket() {
- defer c.c.Close()
- for _ = range c.flush {
- b := c.img.Bounds()
- if b.Empty() {
- continue
- }
- // Each X request has a 16-bit length (in terms of 4-byte units). To avoid going over
- // this limit, we send PutImage for each row of the image, rather than trying to paint
- // the entire image in one X request. This approach could easily be optimized (or the
- // X protocol may have an escape sequence to delimit very large requests).
- // TODO(nigeltao): See what XCB's xcb_put_image does in this situation.
- units := 6 + b.Dx()
- if units > 0xffff || b.Dy() > 0xffff {
- log.Print("x11: window is too large for PutImage")
- return
- }
-
- c.flushBuf0[0] = 0x48 // PutImage opcode.
- c.flushBuf0[1] = 0x02 // XCB_IMAGE_FORMAT_Z_PIXMAP.
- c.flushBuf0[2] = uint8(units)
- c.flushBuf0[3] = uint8(units >> 8)
- setU32LE(c.flushBuf0[4:8], uint32(c.window))
- setU32LE(c.flushBuf0[8:12], uint32(c.gc))
- setU32LE(c.flushBuf0[12:16], 1<<16|uint32(b.Dx()))
- c.flushBuf0[21] = 0x18 // depth = 24 bits.
-
- for y := b.Min.Y; y < b.Max.Y; y++ {
- setU32LE(c.flushBuf0[16:20], uint32(y<<16))
- if _, err := c.w.Write(c.flushBuf0[:24]); err != nil {
- if err != io.EOF {
- log.Println("x11:", err)
- }
- return
- }
- p := c.img.Pix[(y-b.Min.Y)*c.img.Stride:]
- for x, dx := 0, 4*b.Dx(); x < dx; {
- nx := dx - x
- if nx > len(c.flushBuf1) {
- nx = len(c.flushBuf1) &^ 3
- }
- for i := 0; i < nx; i += 4 {
- // X11's order is BGRX, not RGBA.
- c.flushBuf1[i+0] = p[x+i+2]
- c.flushBuf1[i+1] = p[x+i+1]
- c.flushBuf1[i+2] = p[x+i+0]
- }
- x += nx
- if _, err := c.w.Write(c.flushBuf1[:nx]); err != nil {
- if err != io.EOF {
- log.Println("x11:", err)
- }
- return
- }
- }
- }
- if err := c.w.Flush(); err != nil {
- if err != io.EOF {
- log.Println("x11:", err)
- }
- return
- }
- }
-}
-
-func (c *conn) Screen() draw.Image { return c.img }
-
-func (c *conn) FlushImage() {
- select {
- case c.flush <- false:
- // Flush notification sent.
- default:
- // Could not send.
- // Flush notification must be pending already.
- }
-}
-
-func (c *conn) Close() error {
- // Shut down the writeSocket goroutine. This will close the socket to the
- // X11 server, which will cause c.eventc to close.
- close(c.flush)
- for _ = range c.eventc {
- // Drain the channel to allow the readSocket goroutine to shut down.
- }
- return nil
-}
-
-func (c *conn) EventChan() <-chan interface{} { return c.eventc }
-
-// readSocket runs in its own goroutine, reading X events and sending gui
-// events on c's EventChan.
-func (c *conn) readSocket() {
- var (
- keymap [256][]int
- keysymsPerKeycode int
- )
- defer close(c.eventc)
- for {
- // X events are always 32 bytes long.
- if _, err := io.ReadFull(c.r, c.buf[:32]); err != nil {
- if err != io.EOF {
- c.eventc <- gui.ErrEvent{err}
- }
- return
- }
- switch c.buf[0] {
- case 0x01: // Reply from a request (e.g. GetKeyboardMapping).
- cookie := int(c.buf[3])<<8 | int(c.buf[2])
- if cookie != 1 {
- // We issued only one request (GetKeyboardMapping) with a cookie of 1,
- // so we shouldn't get any other reply from the X server.
- c.eventc <- gui.ErrEvent{errors.New("x11: unexpected cookie")}
- return
- }
- keysymsPerKeycode = int(c.buf[1])
- b := make([]int, 256*keysymsPerKeycode)
- for i := range keymap {
- keymap[i] = b[i*keysymsPerKeycode : (i+1)*keysymsPerKeycode]
- }
- for i := keymapLo; i <= keymapHi; i++ {
- m := keymap[i]
- for j := range m {
- u, err := readU32LE(c.r, c.buf[:4])
- if err != nil {
- if err != io.EOF {
- c.eventc <- gui.ErrEvent{err}
- }
- return
- }
- m[j] = int(u)
- }
- }
- case 0x02, 0x03: // Key press, key release.
- // X Keyboard Encoding is documented at http://tronche.com/gui/x/xlib/input/keyboard-encoding.html
- // TODO(nigeltao): Do we need to implement the "MODE SWITCH / group modifier" feature
- // or is that some no-longer-used X construct?
- if keysymsPerKeycode < 2 {
- // Either we haven't yet received the GetKeyboardMapping reply or
- // the X server has sent one that's too short.
- continue
- }
- keycode := int(c.buf[1])
- shift := int(c.buf[28]) & 0x01
- keysym := keymap[keycode][shift]
- if keysym == 0 {
- keysym = keymap[keycode][0]
- }
- // TODO(nigeltao): Should we send KeyEvents for Shift/Ctrl/Alt? Should Shift-A send
- // the same int down the channel as the sent on just the A key?
- // TODO(nigeltao): How should IME events (e.g. key presses that should generate CJK text) work? Or
- // is that outside the scope of the gui.Window interface?
- if c.buf[0] == 0x03 {
- keysym = -keysym
- }
- c.eventc <- gui.KeyEvent{keysym}
- case 0x04, 0x05: // Button press, button release.
- mask := 1 << (c.buf[1] - 1)
- if c.buf[0] == 0x04 {
- c.mouseState.Buttons |= mask
- } else {
- c.mouseState.Buttons &^= mask
- }
- c.mouseState.Nsec = time.Nanoseconds()
- c.eventc <- c.mouseState
- case 0x06: // Motion notify.
- c.mouseState.Loc.X = int(int16(c.buf[25])<<8 | int16(c.buf[24]))
- c.mouseState.Loc.Y = int(int16(c.buf[27])<<8 | int16(c.buf[26]))
- c.mouseState.Nsec = time.Nanoseconds()
- c.eventc <- c.mouseState
- case 0x0c: // Expose.
- // A single user action could trigger multiple expose events (e.g. if moving another
- // window with XShape'd rounded corners over our window). In that case, the X server will
- // send a uint16 count (in bytes 16-17) of the number of additional expose events coming.
- // We could parse each event for the (x, y, width, height) and maintain a minimal dirty
- // rectangle, but for now, the simplest approach is to paint the entire window, when
- // receiving the final event in the series.
- if c.buf[17] == 0 && c.buf[16] == 0 {
- // TODO(nigeltao): Should we ignore the very first expose event? A freshly mapped window
- // will trigger expose, but until the first c.FlushImage call, there's probably nothing to
- // paint but black. For an 800x600 window, at 4 bytes per pixel, each repaint writes about
- // 2MB over the socket.
- c.FlushImage()
- }
- // TODO(nigeltao): Should we listen to DestroyNotify (0x11) and ResizeRequest (0x19) events?
- // What about EnterNotify (0x07) and LeaveNotify (0x08)?
- }
- }
-}
-
-// connect connects to the X server given by the full X11 display name (e.g.
-// ":12.0") and returns the connection as well as the portion of the full name
-// that is the display number (e.g. "12").
-// Examples:
-// connect(":1") // calls net.Dial("unix", "", "/tmp/.X11-unix/X1"), displayStr="1"
-// connect("/tmp/launch-123/:0") // calls net.Dial("unix", "", "/tmp/launch-123/:0"), displayStr="0"
-// connect("hostname:2.1") // calls net.Dial("tcp", "", "hostname:6002"), displayStr="2"
-// connect("tcp/hostname:1.0") // calls net.Dial("tcp", "", "hostname:6001"), displayStr="1"
-func connect(display string) (conn net.Conn, displayStr string, err error) {
- colonIdx := strings.LastIndex(display, ":")
- if colonIdx < 0 {
- return nil, "", errors.New("bad display: " + display)
- }
- // Parse the section before the colon.
- var protocol, host, socket string
- if display[0] == '/' {
- socket = display[:colonIdx]
- } else {
- if i := strings.LastIndex(display, "/"); i < 0 {
- // The default protocol is TCP.
- protocol = "tcp"
- host = display[:colonIdx]
- } else {
- protocol = display[:i]
- host = display[i+1 : colonIdx]
- }
- }
- // Parse the section after the colon.
- after := display[colonIdx+1:]
- if after == "" {
- return nil, "", errors.New("bad display: " + display)
- }
- if i := strings.LastIndex(after, "."); i < 0 {
- displayStr = after
- } else {
- displayStr = after[:i]
- }
- displayInt, err := strconv.Atoi(displayStr)
- if err != nil || displayInt < 0 {
- return nil, "", errors.New("bad display: " + display)
- }
- // Make the connection.
- if socket != "" {
- conn, err = net.Dial("unix", socket+":"+displayStr)
- } else if host != "" {
- conn, err = net.Dial(protocol, host+":"+strconv.Itoa(6000+displayInt))
- } else {
- conn, err = net.Dial("unix", "/tmp/.X11-unix/X"+displayStr)
- }
- if err != nil {
- return nil, "", errors.New("cannot connect to " + display + ": " + err.Error())
- }
- return
-}
-
-// authenticate authenticates ourselves with the X server.
-// displayStr is the "12" out of ":12.0".
-func authenticate(w *bufio.Writer, displayStr string) error {
- key, value, err := readAuth(displayStr)
- if err != nil {
- return err
- }
- // Assume that the authentication protocol is "MIT-MAGIC-COOKIE-1".
- if len(key) != 18 || len(value) != 16 {
- return errors.New("unsupported Xauth")
- }
- // 0x006c means little-endian. 0x000b, 0x0000 means X major version 11, minor version 0.
- // 0x0012 and 0x0010 means the auth key and value have lengths 18 and 16.
- // The final 0x0000 is padding, so that the string length is a multiple of 4.
- _, err = io.WriteString(w, "\x6c\x00\x0b\x00\x00\x00\x12\x00\x10\x00\x00\x00")
- if err != nil {
- return err
- }
- _, err = io.WriteString(w, key)
- if err != nil {
- return err
- }
- // Again, the 0x0000 is padding.
- _, err = io.WriteString(w, "\x00\x00")
- if err != nil {
- return err
- }
- _, err = io.WriteString(w, value)
- if err != nil {
- return err
- }
- err = w.Flush()
- if err != nil {
- return err
- }
- return nil
-}
-
-// readU8 reads a uint8 from r, using b as a scratch buffer.
-func readU8(r io.Reader, b []byte) (uint8, error) {
- _, err := io.ReadFull(r, b[:1])
- if err != nil {
- return 0, err
- }
- return uint8(b[0]), nil
-}
-
-// readU16LE reads a little-endian uint16 from r, using b as a scratch buffer.
-func readU16LE(r io.Reader, b []byte) (uint16, error) {
- _, err := io.ReadFull(r, b[:2])
- if err != nil {
- return 0, err
- }
- return uint16(b[0]) | uint16(b[1])<<8, nil
-}
-
-// readU32LE reads a little-endian uint32 from r, using b as a scratch buffer.
-func readU32LE(r io.Reader, b []byte) (uint32, error) {
- _, err := io.ReadFull(r, b[:4])
- if err != nil {
- return 0, err
- }
- return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24, nil
-}
-
-// setU32LE sets b[:4] to be the little-endian representation of u.
-func setU32LE(b []byte, u uint32) {
- b[0] = byte((u >> 0) & 0xff)
- b[1] = byte((u >> 8) & 0xff)
- b[2] = byte((u >> 16) & 0xff)
- b[3] = byte((u >> 24) & 0xff)
-}
-
-// checkPixmapFormats checks that we have an agreeable X pixmap Format.
-func checkPixmapFormats(r io.Reader, b []byte, n int) (agree bool, err error) {
- for i := 0; i < n; i++ {
- _, err = io.ReadFull(r, b[:8])
- if err != nil {
- return
- }
- // Byte 0 is depth, byte 1 is bits-per-pixel, byte 2 is scanline-pad, the rest (5) is padding.
- if b[0] == 24 && b[1] == 32 {
- agree = true
- }
- }
- return
-}
-
-// checkDepths checks that we have an agreeable X Depth (i.e. one that has an agreeable X VisualType).
-func checkDepths(r io.Reader, b []byte, n int, visual uint32) (agree bool, err error) {
- for i := 0; i < n; i++ {
- var depth, visualsLen uint16
- depth, err = readU16LE(r, b)
- if err != nil {
- return
- }
- depth &= 0xff
- visualsLen, err = readU16LE(r, b)
- if err != nil {
- return
- }
- // Ignore 4 bytes of padding.
- _, err = io.ReadFull(r, b[:4])
- if err != nil {
- return
- }
- for j := 0; j < int(visualsLen); j++ {
- // Read 24 bytes: visual(4), class(1), bits per rgb value(1), colormap entries(2),
- // red mask(4), green mask(4), blue mask(4), padding(4).
- v, _ := readU32LE(r, b)
- _, _ = readU32LE(r, b)
- rm, _ := readU32LE(r, b)
- gm, _ := readU32LE(r, b)
- bm, _ := readU32LE(r, b)
- _, err = readU32LE(r, b)
- if err != nil {
- return
- }
- if v == visual && rm == 0xff0000 && gm == 0xff00 && bm == 0xff && depth == 24 {
- agree = true
- }
- }
- }
- return
-}
-
-// checkScreens checks that we have an agreeable X Screen.
-func checkScreens(r io.Reader, b []byte, n int) (root, visual uint32, err error) {
- for i := 0; i < n; i++ {
- var root0, visual0, x uint32
- root0, err = readU32LE(r, b)
- if err != nil {
- return
- }
- // Ignore the next 7x4 bytes, which is: colormap, whitepixel, blackpixel, current input masks,
- // width and height (pixels), width and height (mm), min and max installed maps.
- _, err = io.ReadFull(r, b[:28])
- if err != nil {
- return
- }
- visual0, err = readU32LE(r, b)
- if err != nil {
- return
- }
- // Next 4 bytes: backing stores, save unders, root depth, allowed depths length.
- x, err = readU32LE(r, b)
- if err != nil {
- return
- }
- nDepths := int(x >> 24)
- var agree bool
- agree, err = checkDepths(r, b, nDepths, visual0)
- if err != nil {
- return
- }
- if agree && root == 0 {
- root = root0
- visual = visual0
- }
- }
- return
-}
-
-// handshake performs the protocol handshake with the X server, and ensures
-// that the server provides a compatible Screen, Depth, etc.
-func (c *conn) handshake() error {
- _, err := io.ReadFull(c.r, c.buf[:8])
- if err != nil {
- return err
- }
- // Byte 0 should be 1 (success), bytes 2:6 should be 0xb0000000 (major/minor version 11.0).
- if c.buf[0] != 1 || c.buf[2] != 11 || c.buf[3] != 0 || c.buf[4] != 0 || c.buf[5] != 0 {
- return errors.New("unsupported X version")
- }
- // Ignore the release number.
- _, err = io.ReadFull(c.r, c.buf[:4])
- if err != nil {
- return err
- }
- // Read the resource ID base.
- resourceIdBase, err := readU32LE(c.r, c.buf[:4])
- if err != nil {
- return err
- }
- // Read the resource ID mask.
- resourceIdMask, err := readU32LE(c.r, c.buf[:4])
- if err != nil {
- return err
- }
- if resourceIdMask < 256 {
- return errors.New("X resource ID mask is too small")
- }
- // Ignore the motion buffer size.
- _, err = io.ReadFull(c.r, c.buf[:4])
- if err != nil {
- return err
- }
- // Read the vendor length and round it up to a multiple of 4,
- // for X11 protocol alignment reasons.
- vendorLen, err := readU16LE(c.r, c.buf[:2])
- if err != nil {
- return err
- }
- vendorLen = (vendorLen + 3) &^ 3
- // Read the maximum request length.
- maxReqLen, err := readU16LE(c.r, c.buf[:2])
- if err != nil {
- return err
- }
- if maxReqLen != 0xffff {
- return errors.New("unsupported X maximum request length")
- }
- // Read the roots length.
- rootsLen, err := readU8(c.r, c.buf[:1])
- if err != nil {
- return err
- }
- // Read the pixmap formats length.
- pixmapFormatsLen, err := readU8(c.r, c.buf[:1])
- if err != nil {
- return err
- }
- // Ignore some things that we don't care about (totaling 10 + vendorLen bytes):
- // imageByteOrder(1), bitmapFormatBitOrder(1), bitmapFormatScanlineUnit(1) bitmapFormatScanlinePad(1),
- // minKeycode(1), maxKeycode(1), padding(4), vendor (vendorLen).
- if 10+int(vendorLen) > cap(c.buf) {
- return errors.New("unsupported X vendor")
- }
- _, err = io.ReadFull(c.r, c.buf[:10+int(vendorLen)])
- if err != nil {
- return err
- }
- // Check that we have an agreeable pixmap format.
- agree, err := checkPixmapFormats(c.r, c.buf[:8], int(pixmapFormatsLen))
- if err != nil {
- return err
- }
- if !agree {
- return errors.New("unsupported X pixmap formats")
- }
- // Check that we have an agreeable screen.
- root, visual, err := checkScreens(c.r, c.buf[:24], int(rootsLen))
- if err != nil {
- return err
- }
- if root == 0 || visual == 0 {
- return errors.New("unsupported X screen")
- }
- c.gc = resID(resourceIdBase)
- c.window = resID(resourceIdBase + 1)
- c.root = resID(root)
- c.visual = resID(visual)
- return nil
-}
-
-// NewWindow calls NewWindowDisplay with $DISPLAY.
-func NewWindow() (gui.Window, error) {
- display := os.Getenv("DISPLAY")
- if len(display) == 0 {
- return nil, errors.New("$DISPLAY not set")
- }
- return NewWindowDisplay(display)
-}
-
-// NewWindowDisplay returns a new gui.Window, backed by a newly created and
-// mapped X11 window. The X server to connect to is specified by the display
-// string, such as ":1".
-func NewWindowDisplay(display string) (gui.Window, error) {
- socket, displayStr, err := connect(display)
- if err != nil {
- return nil, err
- }
- c := new(conn)
- c.c = socket
- c.r = bufio.NewReader(socket)
- c.w = bufio.NewWriter(socket)
- err = authenticate(c.w, displayStr)
- if err != nil {
- return nil, err
- }
- err = c.handshake()
- if err != nil {
- return nil, err
- }
-
- // Now that we're connected, show a window, via three X protocol messages.
- // First, issue a GetKeyboardMapping request. This is the first request, and
- // will be associated with a cookie of 1.
- setU32LE(c.buf[0:4], 0x00020065) // 0x65 is the GetKeyboardMapping opcode, and the message is 2 x 4 bytes long.
- setU32LE(c.buf[4:8], uint32((keymapHi-keymapLo+1)<<8|keymapLo))
- // Second, create a graphics context (GC).
- setU32LE(c.buf[8:12], 0x00060037) // 0x37 is the CreateGC opcode, and the message is 6 x 4 bytes long.
- setU32LE(c.buf[12:16], uint32(c.gc))
- setU32LE(c.buf[16:20], uint32(c.root))
- setU32LE(c.buf[20:24], 0x00010004) // Bit 2 is XCB_GC_FOREGROUND, bit 16 is XCB_GC_GRAPHICS_EXPOSURES.
- setU32LE(c.buf[24:28], 0x00000000) // The Foreground is black.
- setU32LE(c.buf[28:32], 0x00000000) // GraphicsExposures' value is unused.
- // Third, create the window.
- setU32LE(c.buf[32:36], 0x000a0001) // 0x01 is the CreateWindow opcode, and the message is 10 x 4 bytes long.
- setU32LE(c.buf[36:40], uint32(c.window))
- setU32LE(c.buf[40:44], uint32(c.root))
- setU32LE(c.buf[44:48], 0x00000000) // Initial (x, y) is (0, 0).
- setU32LE(c.buf[48:52], windowHeight<<16|windowWidth)
- setU32LE(c.buf[52:56], 0x00010000) // Border width is 0, XCB_WINDOW_CLASS_INPUT_OUTPUT is 1.
- setU32LE(c.buf[56:60], uint32(c.visual))
- setU32LE(c.buf[60:64], 0x00000802) // Bit 1 is XCB_CW_BACK_PIXEL, bit 11 is XCB_CW_EVENT_MASK.
- setU32LE(c.buf[64:68], 0x00000000) // The Back-Pixel is black.
- setU32LE(c.buf[68:72], 0x0000804f) // Key/button press and release, pointer motion, and expose event masks.
- // Fourth, map the window.
- setU32LE(c.buf[72:76], 0x00020008) // 0x08 is the MapWindow opcode, and the message is 2 x 4 bytes long.
- setU32LE(c.buf[76:80], uint32(c.window))
- // Write the bytes.
- _, err = c.w.Write(c.buf[:80])
- if err != nil {
- return nil, err
- }
- err = c.w.Flush()
- if err != nil {
- return nil, err
- }
-
- c.img = image.NewRGBA(image.Rect(0, 0, windowWidth, windowHeight))
- c.eventc = make(chan interface{}, 16)
- c.flush = make(chan bool, 1)
- go c.readSocket()
- go c.writeSocket()
- return c, nil
-}
//
// Code simply using databases should use package sql.
//
-// Drivers only need to be aware of a subset of Go's types. The db package
+// Drivers only need to be aware of a subset of Go's types. The sql package
// will convert all types into one of the following:
//
// int64
// used by multiple goroutines concurrently.
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.
Close() error
// NumInput returns the number of placeholder parameters.
- // -1 means the driver doesn't know how to count the number of
- // placeholders, so we won't sanity check input here and instead let the
- // driver deal with errors.
+ //
+ // If NumInput returns >= 0, the sql package will sanity check
+ // argument counts from callers and return errors to the caller
+ // before the statement's Exec or Query methods are called.
+ //
+ // NumInput may also return -1, if the driver doesn't know
+ // its number of placeholders. In that case, the sql package
+ // will not sanity check Exec or Query argument counts.
NumInput() int
// Exec executes a query that doesn't return rows, such
cmd string
table string
+ closed bool
+
colName []string // used by CREATE, INSERT, SELECT (selected columns)
colType []string // used by CREATE
colValue []interface{} // used by INSERT (mix of strings and "?" for bound params)
stmt.table = parts[0]
stmt.colName = strings.Split(parts[1], ",")
for n, colspec := range strings.Split(parts[2], ",") {
+ if colspec == "" {
+ continue
+ }
nameVal := strings.Split(colspec, "=")
if len(nameVal) != 2 {
return nil, errf("SELECT on table %q has invalid column spec of %q (index %d)", stmt.table, colspec, n)
}
func (s *fakeStmt) Close() error {
+ s.closed = true
return nil
}
+var errClosed = errors.New("fakedb: statement has been closed")
+
func (s *fakeStmt) Exec(args []interface{}) (driver.Result, error) {
+ if s.closed {
+ return nil, errClosed
+ }
err := checkSubsetTypes(args)
if err != nil {
return nil, err
}
func (s *fakeStmt) Query(args []interface{}) (driver.Rows, error) {
+ if s.closed {
+ return nil, errClosed
+ }
err := checkSubsetTypes(args)
if err != nil {
return nil, err
return tx.txi.Rollback()
}
-// Prepare creates a prepared statement.
+// Prepare creates a prepared statement for use within a transaction.
//
-// The statement is only valid within the scope of this transaction.
+// The returned statement operates within the transaction and can no longer
+// be used once the transaction has been committed or rolled back.
+//
+// To use an existing prepared statement on this transaction, see Tx.Stmt.
func (tx *Tx) Prepare(query string) (*Stmt, error) {
- // TODO(bradfitz): the restriction that the returned statement
- // is only valid for this Transaction is lame and negates a
- // lot of the benefit of prepared statements. We could be
- // more efficient here and either provide a method to take an
- // existing Stmt (created on perhaps a different Conn), and
- // re-create it on this Conn if necessary. Or, better: keep a
- // map in DB of query string to Stmts, and have Stmt.Execute
- // do the right thing and re-prepare if the Conn in use
- // doesn't have that prepared statement. But we'll want to
- // avoid caching the statement in the case where we only call
- // conn.Prepare implicitly (such as in db.Exec or tx.Exec),
- // but the caller package can't be holding a reference to the
- // returned statement. Perhaps just looking at the reference
- // count (by noting Stmt.Close) would be enough. We might also
- // want a finalizer on Stmt to drop the reference count.
+ // TODO(bradfitz): We could be more efficient here and either
+ // provide a method to take an existing Stmt (created on
+ // perhaps a different Conn), and re-create it on this Conn if
+ // necessary. Or, better: keep a map in DB of query string to
+ // Stmts, and have Stmt.Execute do the right thing and
+ // re-prepare if the Conn in use doesn't have that prepared
+ // statement. But we'll want to avoid caching the statement
+ // in the case where we only call conn.Prepare implicitly
+ // (such as in db.Exec or tx.Exec), but the caller package
+ // can't be holding a reference to the returned statement.
+ // Perhaps just looking at the reference count (by noting
+ // Stmt.Close) would be enough. We might also want a finalizer
+ // on Stmt to drop the reference count.
ci, err := tx.grabConn()
if err != nil {
return nil, err
return stmt, nil
}
+// Stmt returns a transaction-specific prepared statement from
+// an existing statement.
+//
+// Example:
+// updateMoney, err := db.Prepare("UPDATE balance SET money=money+? WHERE id=?")
+// ...
+// tx, err := db.Begin()
+// ...
+// res, err := tx.Stmt(updateMoney).Exec(123.45, 98293203)
+func (tx *Tx) Stmt(stmt *Stmt) *Stmt {
+ // TODO(bradfitz): optimize this. Currently this re-prepares
+ // each time. This is fine for now to illustrate the API but
+ // we should really cache already-prepared statements
+ // per-Conn. See also the big comment in Tx.Prepare.
+
+ if tx.db != stmt.db {
+ return &Stmt{stickyErr: errors.New("sql: Tx.Stmt: statement from different database used")}
+ }
+ ci, err := tx.grabConn()
+ if err != nil {
+ return &Stmt{stickyErr: err}
+ }
+ defer tx.releaseConn()
+ si, err := ci.Prepare(stmt.query)
+ return &Stmt{
+ db: tx.db,
+ tx: tx,
+ txsi: si,
+ query: stmt.query,
+ stickyErr: err,
+ }
+}
+
// Exec executes a query that doesn't return rows.
// For example: an INSERT and UPDATE.
func (tx *Tx) Exec(query string, args ...interface{}) (Result, error) {
// Stmt is a prepared statement. Stmt is safe for concurrent use by multiple goroutines.
type Stmt struct {
// Immutable:
- db *DB // where we came from
- query string // that created the Sttm
+ db *DB // where we came from
+ query string // that created the Stmt
+ stickyErr error // if non-nil, this error is returned for all operations
// If in a transaction, else both nil:
tx *Tx
// statement, a function to call to release the connection, and a
// statement bound to that connection.
func (s *Stmt) connStmt() (ci driver.Conn, releaseConn func(), si driver.Stmt, err error) {
+ if s.stickyErr != nil {
+ return nil, nil, nil, s.stickyErr
+ }
s.mu.Lock()
if s.closed {
s.mu.Unlock()
// Close closes the statement.
func (s *Stmt) Close() error {
+ if s.stickyErr != nil {
+ return s.stickyErr
+ }
s.mu.Lock()
defer s.mu.Unlock()
if s.closed {
package sql
import (
+ "reflect"
"strings"
"testing"
)
exec(t, db, "INSERT|people|name=Alice,age=?", 1)
exec(t, db, "INSERT|people|name=Bob,age=?", 2)
exec(t, db, "INSERT|people|name=Chris,age=?", 3)
-
}
return db
}
func TestQuery(t *testing.T) {
db := newTestDB(t, "people")
defer closeDB(t, db)
+ rows, err := db.Query("SELECT|people|age,name|")
+ if err != nil {
+ t.Fatalf("Query: %v", err)
+ }
+ type row struct {
+ age int
+ name string
+ }
+ got := []row{}
+ for rows.Next() {
+ var r row
+ err = rows.Scan(&r.age, &r.name)
+ if err != nil {
+ t.Fatalf("Scan: %v", err)
+ }
+ got = append(got, r)
+ }
+ err = rows.Err()
+ if err != nil {
+ t.Fatalf("Err: %v", err)
+ }
+ want := []row{
+ {age: 1, name: "Alice"},
+ {age: 2, name: "Bob"},
+ {age: 3, name: "Chris"},
+ }
+ if !reflect.DeepEqual(got, want) {
+ t.Logf(" got: %#v\nwant: %#v", got, want)
+ }
+}
+
+func TestQueryRow(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
var name string
var age int
}
}
+func TestStatementErrorAfterClose(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)
+ }
+ err = stmt.Close()
+ if err != nil {
+ t.Fatalf("Close: %v", err)
+ }
+ var name string
+ err = stmt.QueryRow("foo").Scan(&name)
+ if err == nil {
+ t.Errorf("expected error from QueryRow.Scan after Stmt.Close")
+ }
+}
+
func TestStatementQueryRow(t *testing.T) {
db := newTestDB(t, "people")
defer closeDB(t, db)
}
}
-func TestDb(t *testing.T) {
+func TestExec(t *testing.T) {
db := newTestDB(t, "foo")
defer closeDB(t, db)
exec(t, db, "CREATE|t1|name=string,age=int32,dead=bool")
}
}
}
+
+func TestTxStmt(t *testing.T) {
+ db := newTestDB(t, "")
+ defer closeDB(t, db)
+ exec(t, db, "CREATE|t1|name=string,age=int32,dead=bool")
+ stmt, err := db.Prepare("INSERT|t1|name=?,age=?")
+ if err != nil {
+ t.Fatalf("Stmt, err = %v, %v", stmt, err)
+ }
+ tx, err := db.Begin()
+ if err != nil {
+ t.Fatalf("Begin = %v", err)
+ }
+ _, err = tx.Stmt(stmt).Exec("Bobby", 7)
+ if err != nil {
+ t.Fatalf("Exec = %v", err)
+ }
+ err = tx.Commit()
+ if err != nil {
+ t.Fatalf("Commit = %v", err)
+ }
+}
packet := make([]byte, 1+4+4+len(todo))
packet[0] = msgChannelData
- packet[1] = byte(c.theirId) >> 24
- packet[2] = byte(c.theirId) >> 16
- packet[3] = byte(c.theirId) >> 8
+ packet[1] = byte(c.theirId >> 24)
+ packet[2] = byte(c.theirId >> 16)
+ packet[3] = byte(c.theirId >> 8)
packet[4] = byte(c.theirId)
- packet[5] = byte(len(todo)) >> 24
- packet[6] = byte(len(todo)) >> 16
- packet[7] = byte(len(todo)) >> 8
+ packet[5] = byte(len(todo) >> 24)
+ packet[6] = byte(len(todo) >> 16)
+ packet[7] = byte(len(todo) >> 8)
packet[8] = byte(len(todo))
copy(packet[9:], todo)
marshalInt(K, kInt)
h.Write(K)
- H := h.Sum()
+ H := h.Sum(nil)
return H, K, nil
}
-// openChan opens a new client channel. The most common session type is "session".
-// The full set of valid session types are listed in RFC 4250 4.9.1.
-func (c *ClientConn) openChan(typ string) (*clientChan, error) {
- ch := c.newChan(c.transport)
- if err := c.writePacket(marshal(msgChannelOpen, channelOpenMsg{
- ChanType: typ,
- PeersId: ch.id,
- PeersWindow: 1 << 14,
- MaxPacketSize: 1 << 15, // RFC 4253 6.1
- })); err != nil {
- c.chanlist.remove(ch.id)
- return nil, err
- }
- // wait for response
- switch msg := (<-ch.msg).(type) {
- case *channelOpenConfirmMsg:
- ch.peersId = msg.MyId
- ch.win <- int(msg.MyWindow)
- case *channelOpenFailureMsg:
- c.chanlist.remove(ch.id)
- return nil, errors.New(msg.Message)
- default:
- c.chanlist.remove(ch.id)
- return nil, errors.New("Unexpected packet")
- }
- return ch, nil
-}
-
-// mainloop reads incoming messages and routes channel messages
+// mainLoop reads incoming messages and routes channel messages
// to their respective ClientChans.
func (c *ClientConn) mainLoop() {
// TODO(dfc) signal the underlying close to all channels
case *windowAdjustMsg:
c.getChan(msg.PeersId).win <- int(msg.AdditionalBytes)
default:
- fmt.Printf("mainLoop: unhandled %#v\n", msg)
+ fmt.Printf("mainLoop: unhandled message %T: %v\n", msg, msg)
}
}
}
// Close closes the channel. This does not close the underlying connection.
func (c *clientChan) Close() error {
return c.writePacket(marshal(msgChannelClose, channelCloseMsg{
- PeersId: c.id,
+ PeersId: c.peersId,
}))
}
-func (c *clientChan) sendChanReq(req channelRequestMsg) error {
- if err := c.writePacket(marshal(msgChannelRequest, req)); err != nil {
- return err
- }
- msg := <-c.msg
- if _, ok := msg.(*channelRequestSuccessMsg); ok {
- return nil
- }
- return fmt.Errorf("failed to complete request: %s, %#v", req.Request, msg)
-}
-
// Thread safe channel list.
type chanlist struct {
// protects concurrent access to chans
sync.Mutex
// chans are indexed by the local id of the channel, clientChan.id.
- // The PeersId value of messages received by ClientConn.mainloop is
+ // The PeersId value of messages received by ClientConn.mainLoop is
// used to locate the right local clientChan in this slice.
chans []*clientChan
}
// A chanWriter represents the stdin of a remote process.
type chanWriter struct {
win chan int // receives window adjustments
- id uint32 // this channel's id
+ peersId uint32 // the peer's id
rwin int // current rwin size
packetWriter // for sending channelDataMsg
}
n = len(data)
packet := make([]byte, 0, 9+n)
packet = append(packet, msgChannelData,
- byte(w.id)>>24, byte(w.id)>>16, byte(w.id)>>8, byte(w.id),
- byte(n)>>24, byte(n)>>16, byte(n)>>8, byte(n))
+ byte(w.peersId>>24), byte(w.peersId>>16), byte(w.peersId>>8), byte(w.peersId),
+ byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
err = w.writePacket(append(packet, data...))
w.rwin -= n
return
}
func (w *chanWriter) Close() error {
- return w.writePacket(marshal(msgChannelEOF, channelEOFMsg{w.id}))
+ return w.writePacket(marshal(msgChannelEOF, channelEOFMsg{w.peersId}))
}
// A chanReader represents stdout or stderr of a remote process.
// If writes to this channel block, they will block mainLoop, making
// it unable to receive new messages from the remote side.
data chan []byte // receives data from remote
- id uint32
- packetWriter // for sending windowAdjustMsg
+ peersId uint32 // the peer's id
+ packetWriter // for sending windowAdjustMsg
buf []byte
}
n := copy(data, r.buf)
r.buf = r.buf[n:]
msg := windowAdjustMsg{
- PeersId: r.id,
+ PeersId: r.peersId,
AdditionalBytes: uint32(n),
}
return n, r.writePacket(marshal(msgChannelWindowAdjust, msg))
}
panic("unreachable")
}
-
-func (r *chanReader) Close() error {
- return r.writePacket(marshal(msgChannelEOF, channelEOFMsg{r.id}))
-}
hashFunc := crypto.SHA1
h := hashFunc.New()
h.Write(data)
- digest := h.Sum()
+ digest := h.Sum(nil)
return rsa.SignPKCS1v15(rand, k.keys[i], hashFunc, digest)
}
r = marshalString(r, pubKey)
return ret
}
+
+// safeString sanitises s according to RFC 4251, section 9.2.
+// All control characters except tab, carriage return and newline are
+// replaced by 0x20.
+func safeString(s string) string {
+ out := []byte(s)
+ for i, c := range out {
+ if c < 0x20 && c != 0xd && c != 0xa && c != 0x9 {
+ out[i] = 0x20
+ }
+ }
+ return string(out)
+}
--- /dev/null
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+ "testing"
+)
+
+var strings = map[string]string{
+ "\x20\x0d\x0a": "\x20\x0d\x0a",
+ "flibble": "flibble",
+ "new\x20line": "new\x20line",
+ "123456\x07789": "123456 789",
+ "\t\t\x10\r\n": "\t\t \r\n",
+}
+
+func TestSafeString(t *testing.T) {
+ for s, expected := range strings {
+ actual := safeString(s)
+ if expected != actual {
+ t.Errorf("expected: %v, actual: %v", []byte(expected), []byte(actual))
+ }
+ }
+}
session, err := client.NewSession()
Once a Session is created, you can execute a single command on the remote side
-using the Exec method.
+using the Run method.
- if err := session.Exec("/usr/bin/whoami"); err != nil {
+ if err := session.Run("/usr/bin/whoami"); err != nil {
panic("Failed to exec: " + err.String())
}
reader := bufio.NewReader(session.Stdin)
marshalInt(K, kInt)
h.Write(K)
- H = h.Sum()
+ H = h.Sum(nil)
h.Reset()
h.Write(H)
- hh := h.Sum()
+ hh := h.Sum(nil)
var sig []byte
switch hostKeyAlgo {
hashFunc := crypto.SHA1
h := hashFunc.New()
h.Write(signedData)
- digest := h.Sum()
+ digest := h.Sum(nil)
rsaKey, ok := parseRSA(pubKey)
if !ok {
return ParseError{msgUserAuthRequest}
// "RFC 4254, section 6".
import (
- "encoding/binary"
+ "bytes"
"errors"
+ "fmt"
"io"
+ "io/ioutil"
+)
+
+type Signal string
+
+// POSIX signals as listed in RFC 4254 Section 6.10.
+const (
+ SIGABRT Signal = "ABRT"
+ SIGALRM Signal = "ALRM"
+ SIGFPE Signal = "FPE"
+ SIGHUP Signal = "HUP"
+ SIGILL Signal = "ILL"
+ SIGINT Signal = "INT"
+ SIGKILL Signal = "KILL"
+ SIGPIPE Signal = "PIPE"
+ SIGQUIT Signal = "QUIT"
+ SIGSEGV Signal = "SEGV"
+ SIGTERM Signal = "TERM"
+ SIGUSR1 Signal = "USR1"
+ SIGUSR2 Signal = "USR2"
)
// A Session represents a connection to a remote command or shell.
type Session struct {
- // Writes to Stdin are made available to the remote command's standard input.
- // Closing Stdin causes the command to observe an EOF on its standard input.
- Stdin io.WriteCloser
-
- // Reads from Stdout and Stderr consume from the remote command's standard
- // output and error streams, respectively.
- // There is a fixed amount of buffering that is shared for the two streams.
- // Failing to read from either may eventually cause the command to block.
- // Closing Stdout unblocks such writes and causes them to return errors.
- Stdout io.ReadCloser
- Stderr io.Reader
+ // Stdin specifies the remote process's standard input.
+ // If Stdin is nil, the remote process reads from an empty
+ // bytes.Buffer.
+ Stdin io.Reader
+
+ // Stdout and Stderr specify the remote process's standard
+ // output and error.
+ //
+ // If either is nil, Run connects the corresponding file
+ // descriptor to an instance of ioutil.Discard. There is a
+ // fixed amount of buffering that is shared for the two streams.
+ // If either blocks it may eventually cause the remote
+ // command to block.
+ Stdout io.Writer
+ Stderr io.Writer
*clientChan // the channel backing this session
- started bool // started is set to true once a Shell or Exec is invoked.
+ started bool // true once Start, Run or Shell is invoked.
+ closeAfterWait []io.Closer
+ copyFuncs []func() error
+ errch chan error // one send per copyFunc
+}
+
+// RFC 4254 Section 6.4.
+type setenvRequest struct {
+ PeersId uint32
+ Request string
+ WantReply bool
+ Name string
+ Value string
}
// Setenv sets an environment variable that will be applied to any
-// command executed by Shell or Exec.
+// command executed by Shell or Run.
func (s *Session) Setenv(name, value string) error {
- n, v := []byte(name), []byte(value)
- nlen, vlen := stringLength(n), stringLength(v)
- payload := make([]byte, nlen+vlen)
- marshalString(payload[:nlen], n)
- marshalString(payload[nlen:], v)
-
- return s.sendChanReq(channelRequestMsg{
- PeersId: s.id,
- Request: "env",
- WantReply: true,
- RequestSpecificData: payload,
- })
+ req := setenvRequest{
+ PeersId: s.peersId,
+ Request: "env",
+ WantReply: true,
+ Name: name,
+ Value: value,
+ }