mirror of
https://github.com/golang/go.git
synced 2026-01-29 23:22:06 +03:00
Compare commits
46 Commits
dev.garbag
...
go1.7.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6b36535cf3 | ||
|
|
0ad8bf4122 | ||
|
|
26741a15f7 | ||
|
|
fab76f07f5 | ||
|
|
4f7363cd72 | ||
|
|
6759eff8eb | ||
|
|
75f4f703eb | ||
|
|
2f6557233c | ||
|
|
4de7b10483 | ||
|
|
3b6f4b04ba | ||
|
|
740dfbadbd | ||
|
|
edecc650ec | ||
|
|
2e150a0aa7 | ||
|
|
f0377a2851 | ||
|
|
2287d95e9b | ||
|
|
a2f37b7fe1 | ||
|
|
ca0b97e80a | ||
|
|
230c3918a8 | ||
|
|
b67902fee7 | ||
|
|
5a589904a3 | ||
|
|
f75aafdf56 | ||
|
|
b261730e56 | ||
|
|
40712a9625 | ||
|
|
24f46bd34f | ||
|
|
c24b5d43a6 | ||
|
|
dc3612e0d1 | ||
|
|
6f12826a86 | ||
|
|
3129c67db7 | ||
|
|
bb8706890b | ||
|
|
287be1e42d | ||
|
|
308bdd0256 | ||
|
|
9b4e323e88 | ||
|
|
a5add8c726 | ||
|
|
e464c08bef | ||
|
|
c0f5de1ad2 | ||
|
|
1861ac159e | ||
|
|
759c2c48ea | ||
|
|
09fa0b8e95 | ||
|
|
0d81858868 | ||
|
|
681a667ced | ||
|
|
806a84d3f1 | ||
|
|
87d4bd1997 | ||
|
|
1e933ed7c0 | ||
|
|
78d024a588 | ||
|
|
09fc3cc5df | ||
|
|
17a48e0a00 |
10
.github/ISSUE_TEMPLATE
vendored
10
.github/ISSUE_TEMPLATE
vendored
@@ -1,20 +1,20 @@
|
||||
Please answer these questions before submitting your issue. Thanks!
|
||||
|
||||
### What version of Go are you using (`go version`)?
|
||||
1. What version of Go are you using (`go version`)?
|
||||
|
||||
|
||||
### What operating system and processor architecture are you using (`go env`)?
|
||||
2. What operating system and processor architecture are you using (`go env`)?
|
||||
|
||||
|
||||
### What did you do?
|
||||
3. What did you do?
|
||||
If possible, provide a recipe for reproducing the error.
|
||||
A complete runnable program is good.
|
||||
A link on play.golang.org is best.
|
||||
|
||||
|
||||
### What did you expect to see?
|
||||
4. What did you expect to see?
|
||||
|
||||
|
||||
### What did you see instead?
|
||||
5. What did you see instead?
|
||||
|
||||
|
||||
|
||||
48
.gitignore
vendored
48
.gitignore
vendored
@@ -18,28 +18,28 @@ _cgo_*
|
||||
_obj
|
||||
_test
|
||||
_testmain.go
|
||||
build.out
|
||||
test.out
|
||||
doc/articles/wiki/*.bin
|
||||
misc/cgo/life/run.out
|
||||
misc/cgo/stdio/run.out
|
||||
misc/cgo/testso/main
|
||||
src/cmd/cgo/zdefaultcc.go
|
||||
src/cmd/go/zdefaultcc.go
|
||||
src/cmd/go/zosarch.go
|
||||
src/cmd/internal/obj/zbootstrap.go
|
||||
src/go/build/zcgo.go
|
||||
src/go/doc/headscan
|
||||
src/runtime/internal/sys/zversion.go
|
||||
src/unicode/maketables
|
||||
src/*.*/
|
||||
test/pass.out
|
||||
test/run.out
|
||||
test/times.out
|
||||
test/garbage/*.out
|
||||
goinstall.log
|
||||
last-change
|
||||
VERSION.cache
|
||||
|
||||
/VERSION.cache
|
||||
/bin/
|
||||
/build.out
|
||||
/doc/articles/wiki/*.bin
|
||||
/goinstall.log
|
||||
/last-change
|
||||
/misc/cgo/life/run.out
|
||||
/misc/cgo/stdio/run.out
|
||||
/misc/cgo/testso/main
|
||||
/pkg/
|
||||
/src/*.*/
|
||||
/src/cmd/cgo/zdefaultcc.go
|
||||
/src/cmd/go/zdefaultcc.go
|
||||
/src/cmd/go/zosarch.go
|
||||
/src/cmd/internal/obj/zbootstrap.go
|
||||
/src/go/build/zcgo.go
|
||||
/src/go/doc/headscan
|
||||
/src/runtime/internal/sys/zversion.go
|
||||
/src/unicode/maketables
|
||||
/test.out
|
||||
/test/garbage/*.out
|
||||
/test/pass.out
|
||||
/test/run.out
|
||||
/test/times.out
|
||||
bin/
|
||||
pkg/
|
||||
|
||||
114
AUTHORS
114
AUTHORS
@@ -27,27 +27,20 @@ Ainar Garipov <gugl.zadolbal@gmail.com>
|
||||
Akihiro Suda <suda.kyoto@gmail.com>
|
||||
Akshat Kumar <seed@mail.nanosouffle.net>
|
||||
Alan Shreve <alan@inconshreveable.com>
|
||||
Albert Nigmatzianov <albertnigma@gmail.com>
|
||||
Albert Strasheim <fullung@gmail.com>
|
||||
Albert Yu <yukinying@gmail.com>
|
||||
Alberto Bertogli <albertito@blitiri.com.ar>
|
||||
Alberto Donizetti <alb.donizetti@gmail.com>
|
||||
Alberto García Hierro <alberto@garciahierro.com> <alberto.garcia.hierro@gmail.com>
|
||||
Aleksandar Dezelin <dezelin@gmail.com>
|
||||
Alessandro Arzilli <alessandro.arzilli@gmail.com>
|
||||
Alessandro Baffa <alessandro.baffa@gmail.com>
|
||||
Alex A Skinner <alex@lx.lc>
|
||||
Alex Brainman <alex.brainman@gmail.com>
|
||||
Alex Browne <stephenalexbrowne@gmail.com>
|
||||
Alex Carol <alex.carol.c@gmail.com>
|
||||
Alex Jin <toalexjin@gmail.com>
|
||||
Alex Plugaru <alex@plugaru.org> <alexandru.plugaru@gmail.com>
|
||||
Alex Schroeder <alex@gnu.org>
|
||||
Alex Sergeyev <abc@alexsergeyev.com>
|
||||
Alexander Demakin <alexander.demakin@gmail.com>
|
||||
Alexander Döring <email@alexd.ch>
|
||||
Alexander Larsson <alexander.larsson@gmail.com>
|
||||
Alexander Menzhinsky <amenzhinsky@gmail.com>
|
||||
Alexander Morozov <lk4d4math@gmail.com>
|
||||
Alexander Neumann <alexander@bumpern.de>
|
||||
Alexander Orlov <alexander.orlov@loxal.net>
|
||||
@@ -56,24 +49,18 @@ Alexander Surma <surma@surmair.de>
|
||||
Alexander Zhavnerchik <alex.vizor@gmail.com>
|
||||
Alexander Zolotov <goldifit@gmail.com>
|
||||
Alexandre Cesaro <alexandre.cesaro@gmail.com>
|
||||
Alexandre Fiori <fiorix@gmail.com>
|
||||
Alexandre Normand <alexandre.normand@gmail.com>
|
||||
Alexei Sholik <alcosholik@gmail.com>
|
||||
Alexey Borzenkov <snaury@gmail.com>
|
||||
Alexey Palazhchenko <alexey.palazhchenko@gmail.com>
|
||||
Aliaksandr Valialkin <valyala@gmail.com>
|
||||
Alif Rachmawadi <subosito@gmail.com>
|
||||
Allan Simon <allan.simon@supinfo.com>
|
||||
Alok Menghrajani <alok.menghrajani@gmail.com>
|
||||
Amazon.com, Inc
|
||||
Amir Mohammad Saied <amir@gluegadget.com>
|
||||
Amrut Joshi <amrut.joshi@gmail.com>
|
||||
Andre Nathan <andrenth@gmail.com>
|
||||
Andreas Auernhammer <aead@mail.de>
|
||||
Andreas Litt <andreas.litt@gmail.com>
|
||||
Andrei Korzhevskii <a.korzhevskiy@gmail.com>
|
||||
Andrei Vieru <euvieru@gmail.com>
|
||||
Andrew Austin <andrewaclt@gmail.com>
|
||||
Andrew Balholm <andybalholm@gmail.com>
|
||||
Andrew Bonventre <andybons@chromium.org>
|
||||
Andrew Bursavich <abursavich@gmail.com>
|
||||
@@ -81,7 +68,6 @@ Andrew Ekstedt <andrew.ekstedt@gmail.com>
|
||||
Andrew Etter <andrew.etter@gmail.com>
|
||||
Andrew Harding <andrew@spacemonkey.com>
|
||||
Andrew Lutomirski <andy@luto.us>
|
||||
Andrew Pogrebnoy <absourd.noise@gmail.com>
|
||||
Andrew Pritchard <awpritchard@gmail.com>
|
||||
Andrew Radev <andrey.radev@gmail.com>
|
||||
Andrew Skiba <skibaa@gmail.com>
|
||||
@@ -93,7 +79,6 @@ Andrey Petrov <andrey.petrov@shazow.net>
|
||||
Andriy Lytvynov <lytvynov.a.v@gmail.com>
|
||||
Andy Balholm <andy@balholm.com>
|
||||
Andy Davis <andy@bigandian.com>
|
||||
Andy Finkenstadt <afinkenstadt@zynga.com>
|
||||
Andy Maloney <asmaloney@gmail.com>
|
||||
Anfernee Yongkun Gui <anfernee.gui@gmail.com>
|
||||
Angelo Bulfone <mbulfone@gmail.com>
|
||||
@@ -104,8 +89,6 @@ Anthony Canino <anthony.canino1@gmail.com>
|
||||
Anthony Eufemio <anthony.eufemio@gmail.com>
|
||||
Anthony Martin <ality@pbrane.org>
|
||||
Anthony Starks <ajstarks@gmail.com>
|
||||
Anthony Woods <awoods@raintank.io>
|
||||
Antonio Bibiano <antbbn@gmail.com>
|
||||
Apisak Darakananda <pongad@gmail.com>
|
||||
Aram Hăvărneanu <aram@mgk.ro>
|
||||
Areski Belaid <areski@gmail.com>
|
||||
@@ -117,7 +100,6 @@ Arnout Engelen <arnout@bzzt.net>
|
||||
Aron Nopanen <aron.nopanen@gmail.com>
|
||||
Artyom Pervukhin <artyom.pervukhin@gmail.com>
|
||||
Arvindh Rajesh Tamilmani <art@a-30.net>
|
||||
Atin Malaviya <amalaviy@akamai.com>
|
||||
Ato Araki <ato.araki@gmail.com>
|
||||
Audrey Lim <audreylh@gmail.com>
|
||||
Augusto Roman <aroman@gmail.com>
|
||||
@@ -125,9 +107,7 @@ Aulus Egnatius Varialus <varialus@gmail.com>
|
||||
awaw fumin <awawfumin@gmail.com>
|
||||
Ayanamist Yang <ayanamist@gmail.com>
|
||||
Aymerick Jéhanne <aymerick@jehanne.org>
|
||||
Baiju Muthukadan <baiju.m.mail@gmail.com>
|
||||
Ben Burkert <ben@benburkert.com>
|
||||
Ben Lubar <ben.lubar@gmail.com>
|
||||
Ben Olive <sionide21@gmail.com>
|
||||
Benjamin Black <b@b3k.us>
|
||||
Benny Siegert <bsiegert@gmail.com>
|
||||
@@ -138,9 +118,7 @@ Bjorn Tillenius <bjorn@tillenius.me>
|
||||
Bjorn Tipling <bjorn.tipling@gmail.com>
|
||||
Blake Gentry <blakesgentry@gmail.com>
|
||||
Blake Mizerany <blake.mizerany@gmail.com>
|
||||
Blixt <me@blixt.nyc>
|
||||
Bobby Powers <bobbypowers@gmail.com>
|
||||
Bolt
|
||||
Brady Catherman <brady@gmail.com>
|
||||
Brady Sullivan <brady@bsull.com>
|
||||
Brendan Daniel Tracey <tracey.brendan@gmail.com>
|
||||
@@ -148,15 +126,12 @@ Brett Cannon <bcannon@gmail.com>
|
||||
Brian Dellisanti <briandellisanti@gmail.com>
|
||||
Brian G. Merrell <bgmerrell@gmail.com>
|
||||
Brian Gitonga Marete <marete@toshnix.com> <bgmarete@gmail.com>
|
||||
Brian Kennedy <btkennedy@gmail.com>
|
||||
Brian Ketelsen <bketelsen@gmail.com>
|
||||
Brian Smith <ohohvi@gmail.com>
|
||||
Bryan Alexander <Kozical@msn.com>
|
||||
Bryan Ford <brynosaurus@gmail.com>
|
||||
Caine Tighe <arctanofyourface@gmail.com>
|
||||
Caleb Spare <cespare@gmail.com>
|
||||
Carl Chatfield <carlchatfield@gmail.com>
|
||||
Carl Johnson <me@carlmjohnson.net>
|
||||
Carlos Castillo <cookieo9@gmail.com>
|
||||
Carlos Cirello <uldericofilho@gmail.com>
|
||||
Case Nelson <case.nelson@gmail.com>
|
||||
@@ -173,7 +148,6 @@ Chris Jones <chris@cjones.org>
|
||||
Chris Kastorff <encryptio@gmail.com>
|
||||
Chris Lennert <calennert@gmail.com>
|
||||
Chris McGee <sirnewton_01@yahoo.ca> <newton688@gmail.com>
|
||||
Chris Stockton <chrisstocktonaz@gmail.com>
|
||||
Christian Couder <chriscool@tuxfamily.org>
|
||||
Christian Himpel <chressie@googlemail.com>
|
||||
Christine Hansmann <chhansmann@gmail.com>
|
||||
@@ -196,7 +170,6 @@ CoreOS, Inc.
|
||||
Corey Thomasson <cthom.lists@gmail.com>
|
||||
Cristian Staretu <unclejacksons@gmail.com>
|
||||
Currant
|
||||
Cyrill Schumacher <cyrill@schumacher.fm>
|
||||
Damian Gryski <dgryski@gmail.com>
|
||||
Dan Caddigan <goldcaddy77@gmail.com>
|
||||
Dan Callahan <dan.callahan@gmail.com>
|
||||
@@ -207,7 +180,6 @@ Daniel Johansson <dajo2002@gmail.com>
|
||||
Daniel Kerwin <d.kerwin@gini.net>
|
||||
Daniel Krech <eikeon@eikeon.com>
|
||||
Daniel Lidén <daniel.liden.87@gmail.com>
|
||||
Daniel Martí <mvdan@mvdan.cc>
|
||||
Daniel Morsing <daniel.morsing@gmail.com>
|
||||
Daniel Ortiz Pereira da Silva <daniel.particular@gmail.com>
|
||||
Daniel Skinner <daniel@dasa.cc>
|
||||
@@ -227,12 +199,10 @@ David Jakob Fritz <david.jakob.fritz@gmail.com>
|
||||
David Leon Gil <coruus@gmail.com>
|
||||
David R. Jenni <david.r.jenni@gmail.com>
|
||||
David Sansome <me@davidsansome.com>
|
||||
David Stainton <dstainton415@gmail.com>
|
||||
David Thomas <davidthomas426@gmail.com>
|
||||
David Titarenco <david.titarenco@gmail.com>
|
||||
Davies Liu <davies.liu@gmail.com>
|
||||
Dean Prichard <dean.prichard@gmail.com>
|
||||
Deepak Jois <deepak.jois@gmail.com>
|
||||
Denis Bernard <db047h@gmail.com>
|
||||
Denis Brandolini <denis.brandolini@gmail.com>
|
||||
Denys Honsiorovskyi <honsiorovskyi@gmail.com>
|
||||
@@ -241,13 +211,11 @@ Derek Parker <parkerderek86@gmail.com>
|
||||
Derek Shockey <derek.shockey@gmail.com>
|
||||
Develer SRL
|
||||
Devon H. O'Dell <devon.odell@gmail.com>
|
||||
Dhaivat Pandit <dhaivatpandit@gmail.com>
|
||||
Dhiru Kholia <dhiru.kholia@gmail.com>
|
||||
Didier Spezia <didier.06@gmail.com>
|
||||
Dimitri Tcaciuc <dtcaciuc@gmail.com>
|
||||
Dirk Gadsden <dirk@esherido.com>
|
||||
Diwaker Gupta <diwakergupta@gmail.com>
|
||||
Dmitri Popov <operator@cv.dp-net.com>
|
||||
Dmitri Shuralyov <shurcooL@gmail.com>
|
||||
Dmitriy Dudkin <dudkin.dmitriy@gmail.com>
|
||||
Dmitriy Shelenin <deemok@googlemail.com> <deemok@gmail.com>
|
||||
@@ -269,7 +237,6 @@ Egon Elbre <egonelbre@gmail.com>
|
||||
Ehren Kret <ehren.kret@gmail.com>
|
||||
Eivind Uggedal <eivind@uggedal.com>
|
||||
Elias Naur <elias.naur@gmail.com>
|
||||
Elliot Morrison-Reed <elliotmr@gmail.com>
|
||||
Emil Hessman <c.emil.hessman@gmail.com> <emil@hessman.se>
|
||||
Emmanuel Odeke <emm.odeke@gmail.com> <odeke@ualberta.ca>
|
||||
Empirical Interfaces Inc.
|
||||
@@ -285,18 +252,15 @@ Erik St. Martin <alakriti@gmail.com>
|
||||
Erik Westrup <erik.westrup@gmail.com>
|
||||
Ernest Chiang <ernest_chiang@htc.com>
|
||||
Esko Luontola <esko.luontola@gmail.com>
|
||||
Euan Kemp <euank@euank.com>
|
||||
Evan Phoenix <evan@phx.io>
|
||||
Evan Shaw <chickencha@gmail.com>
|
||||
Ewan Chou <coocood@gmail.com>
|
||||
Fabian Wickborn <fabian@wickborn.net>
|
||||
Fabrizio Milo <mistobaan@gmail.com>
|
||||
Faiyaz Ahmed <ahmedf@vmware.com>
|
||||
Fan Hongjian <fan.howard@gmail.com>
|
||||
Fastly, Inc.
|
||||
Fatih Arslan <fatih@arslan.io>
|
||||
Fazlul Shahriar <fshahriar@gmail.com>
|
||||
Fedor Indutny <fedor@indutny.com>
|
||||
Felix Geisendörfer <haimuiba@gmail.com>
|
||||
Filippo Valsorda <hi@filippo.io>
|
||||
Firmansyah Adiputra <frm.adiputra@gmail.com>
|
||||
@@ -311,20 +275,16 @@ Fredrik Enestad <fredrik.enestad@soundtrackyourbrand.com>
|
||||
Frithjof Schulze <schulze@math.uni-hannover.de> <sfrithjof@gmail.com>
|
||||
Frits van Bommel <fvbommel@gmail.com>
|
||||
Gabriel Aszalos <gabriel.aszalos@gmail.com>
|
||||
Gabriel Russell <gabriel.russell@gmail.com>
|
||||
Gareth Paul Jones <gpj@foursquare.com>
|
||||
Gary Burd <gary@beagledreams.com>
|
||||
Gaurish Sharma <contact@gaurishsharma.com>
|
||||
Gautham Thambidorai <gautham.dorai@gmail.com>
|
||||
Geert-Johan Riemer <gjr19912@gmail.com>
|
||||
Geoffroy Lorieux <lorieux.g@gmail.com>
|
||||
Georg Reinke <guelfey@gmail.com>
|
||||
George Shammas <george@shamm.as> <georgyo@gmail.com>
|
||||
Gerasimos Dimitriadis <gedimitr@gmail.com>
|
||||
Gideon Jan-Wessel Redelinghuys <gjredelinghuys@gmail.com>
|
||||
Giles Lean <giles.lean@pobox.com>
|
||||
Giulio Iotti <dullgiulio@gmail.com>
|
||||
Gleb Stepanov <glebstepanov1992@gmail.com>
|
||||
Google Inc.
|
||||
Gordon Klaus <gordon.klaus@gmail.com>
|
||||
Graham King <graham4king@gmail.com>
|
||||
@@ -341,14 +301,12 @@ Hajime Hoshi <hajimehoshi@gmail.com>
|
||||
Hari haran <hariharan.uno@gmail.com>
|
||||
Hariharan Srinath <srinathh@gmail.com>
|
||||
Harley Laue <losinggeneration@gmail.com>
|
||||
Harry Moreno <morenoh149@gmail.com>
|
||||
Harshavardhana <hrshvardhana@gmail.com>
|
||||
Håvard Haugen <havard.haugen@gmail.com>
|
||||
Hector Chu <hectorchu@gmail.com>
|
||||
Hector Martin Cantero <hector@marcansoft.com>
|
||||
Henning Schmiedehausen <henning@schmiedehausen.org>
|
||||
Henrik Edwards <henrik.edwards@gmail.com>
|
||||
Henrik Hodne <henrik@hodne.io>
|
||||
Herbert Georg Fischer <herbert.fischer@gmail.com>
|
||||
Hironao OTSUBO <motemen@gmail.com>
|
||||
Hiroshi Ioka <hirochachacha@gmail.com>
|
||||
@@ -369,14 +327,12 @@ Ingo Oeser <nightlyone@googlemail.com>
|
||||
Intel Corporation
|
||||
Irieda Noboru <irieda@gmail.com>
|
||||
Isaac Wagner <ibw@isaacwagner.me>
|
||||
Ivan Babrou <ivan@cloudflare.com>
|
||||
Ivan Ukhov <ivan.ukhov@gmail.com>
|
||||
Jacob Hoffman-Andrews <github@hoffman-andrews.com>
|
||||
Jae Kwon <jae@tendermint.com>
|
||||
Jakob Borg <jakob@nym.se>
|
||||
Jakub Ryszard Czarnowicz <j.czarnowicz@gmail.com>
|
||||
James Bardin <j.bardin@gmail.com>
|
||||
James Clarke <jrtc27@jrtc27.com>
|
||||
James David Chalfant <james.chalfant@gmail.com>
|
||||
James Fysh <james.fysh@gmail.com>
|
||||
James Gray <james@james4k.com>
|
||||
@@ -386,7 +342,6 @@ James Schofield <james@shoeboxapp.com>
|
||||
James Sweet <james.sweet88@googlemail.com>
|
||||
James Toy <nil@opensesame.st>
|
||||
James Whitehead <jnwhiteh@gmail.com>
|
||||
Jamie Beverly <jamie.r.beverly@gmail.com>
|
||||
Jamil Djadala <djadala@gmail.com>
|
||||
Jan H. Hosang <jan.hosang@gmail.com>
|
||||
Jan Mercl <0xjnml@gmail.com>
|
||||
@@ -397,26 +352,21 @@ Jani Monoses <jani.monoses@ubuntu.com>
|
||||
Jaroslavas Počepko <jp@webmaster.ms>
|
||||
Jason Barnett <jason.w.barnett@gmail.com>
|
||||
Jason Del Ponte <delpontej@gmail.com>
|
||||
Jason Smale <jsmale@zendesk.com>
|
||||
Jason Travis <infomaniac7@gmail.com>
|
||||
Jay Weisskopf <jay@jayschwa.net>
|
||||
Jean-Nicolas Moal <jn.moal@gmail.com>
|
||||
Jeff Hodges <jeff@somethingsimilar.com>
|
||||
Jeff R. Allen <jra@nella.org>
|
||||
Jeff Sickel <jas@corpus-callosum.com>
|
||||
Jeff Wendling <jeff@spacemonkey.com>
|
||||
Jens Frederich <jfrederich@gmail.com>
|
||||
Jeremy Jackins <jeremyjackins@gmail.com>
|
||||
Jeroen Bobbeldijk <jerbob92@gmail.com>
|
||||
Jess Frazelle <me@jessfraz.com>
|
||||
Jesse Szwedko <jesse.szwedko@gmail.com>
|
||||
Jihyun Yu <yjh0502@gmail.com>
|
||||
Jim McGrath <jimmc2@gmail.com>
|
||||
Jimmy Zelinskie <jimmyzelinskie@gmail.com>
|
||||
Jingcheng Zhang <diogin@gmail.com>
|
||||
Jingguo Yao <yaojingguo@gmail.com>
|
||||
Jiong Du <londevil@gmail.com>
|
||||
Jirka Daněk <dnk@mail.muni.cz>
|
||||
Joakim Sernbrant <serbaut@gmail.com>
|
||||
Joe Farrell <joe2farrell@gmail.com>
|
||||
Joe Harrison <joehazzers@gmail.com>
|
||||
@@ -443,13 +393,9 @@ Jonathan Mark <jhmark@xenops.com>
|
||||
Jonathan Rudenberg <jonathan@titanous.com>
|
||||
Jonathan Wills <runningwild@gmail.com>
|
||||
Jongmin Kim <atomaths@gmail.com>
|
||||
Joonas Kuorilehto <joneskoo@derbian.fi>
|
||||
Joop Kiefte <ikojba@gmail.com> <joop@kiefte.net>
|
||||
Jordan Lewis <jordanthelewis@gmail.com>
|
||||
Jose Luis Vázquez González <josvazg@gmail.com>
|
||||
Joseph Holsten <joseph@josephholsten.com>
|
||||
Josh Bleecher Snyder <josharian@gmail.com>
|
||||
Josh Chorlton <jchorlton@gmail.com>
|
||||
Josh Goebel <dreamer3@gmail.com>
|
||||
Josh Holland <jrh@joshh.co.uk>
|
||||
Joshua Chase <jcjoshuachase@gmail.com>
|
||||
@@ -460,15 +406,11 @@ Julian Kornberger <jk+github@digineo.de>
|
||||
Julian Phillips <julian@quantumfyre.co.uk>
|
||||
Julien Schmidt <google@julienschmidt.com>
|
||||
Justin Nuß <nuss.justin@gmail.com>
|
||||
Justyn Temme <justyntemme@gmail.com>
|
||||
Kai Backman <kaib@golang.org>
|
||||
Kale Blankenship <kale@lemnisys.com>
|
||||
Kamil Kisiel <kamil@kamilkisiel.net> <kamil.kisiel@gmail.com>
|
||||
Kang Hu <hukangustc@gmail.com>
|
||||
Kato Kazuyoshi <kato.kazuyoshi@gmail.com>
|
||||
Katrina Owen <katrina.owen@gmail.com>
|
||||
Kaviraj Kanagaraj <kavirajkanagaraj@gmail.com>
|
||||
Keegan Carruthers-Smith <keegan.csmith@gmail.com>
|
||||
Kei Son <hey.calmdown@gmail.com>
|
||||
Keith Ball <inflatablewoman@gmail.com>
|
||||
Keith Rarick <kr@xph.us>
|
||||
@@ -495,7 +437,6 @@ Kyle Lemons <kyle@kylelemons.net>
|
||||
L Campbell <unpantsu@gmail.com>
|
||||
Lai Jiangshan <eag0628@gmail.com>
|
||||
Larz Conwell <larzconwell@gmail.com>
|
||||
LE Manh Cuong <cuong.manhle.vn@gmail.com>
|
||||
Lee Hinman <hinman@gmail.com>
|
||||
Lee Packham <lpackham@gmail.com>
|
||||
Lewin Bormann <lewin.bormann@gmail.com>
|
||||
@@ -507,19 +448,14 @@ Luan Santos <cfcluan@gmail.com>
|
||||
Luca Greco <luca.greco@alcacoop.it>
|
||||
Lucien Stuker <lucien.stuker@gmail.com>
|
||||
Lucio De Re <lucio.dere@gmail.com>
|
||||
Luigi Riefolo <luigi.riefolo@gmail.com>
|
||||
Luit van Drongelen <luitvd@gmail.com>
|
||||
Luka Zakrajšek <tr00.g33k@gmail.com>
|
||||
Luke Curley <qpingu@gmail.com>
|
||||
Maksym Trykur <maksym.trykur@gmail.com>
|
||||
Mal Curtis <mal@mal.co.nz>
|
||||
Manfred Touron <m@42.am>
|
||||
Manu S Ajith <neo@codingarena.in>
|
||||
Manuel Mendez <mmendez534@gmail.com>
|
||||
Marc Weistroff <marc@weistroff.net>
|
||||
Marcel Edmund Franke <marcel.edmund.franke@gmail.com>
|
||||
Marco Hennings <marco.hennings@freiheit.com>
|
||||
Marin Bašić <marin.basic02@gmail.com>
|
||||
Mark Bucciarelli <mkbucc@gmail.com>
|
||||
Mark Severson <miquella@gmail.com>
|
||||
Mark Theunissen <mark.theunissen@gmail.com>
|
||||
@@ -529,9 +465,7 @@ Markover Inc. DBA Poptip
|
||||
Markus Duft <markus.duft@salomon.at>
|
||||
Markus Sonderegger <marraison@gmail.com>
|
||||
Markus Zimmermann <zimmski@gmail.com>
|
||||
Martin Bertschler <mbertschler@gmail.com>
|
||||
Martin Garton <garton@gmail.com>
|
||||
Martin Hamrle <martin.hamrle@gmail.com>
|
||||
Martin Möhrmann <martisch@uos.de>
|
||||
Martin Neubauer <m.ne@gmx.net>
|
||||
Martin Olsson <martin@minimum.se>
|
||||
@@ -553,15 +487,10 @@ Matt T. Proud <matt.proud@gmail.com>
|
||||
Matt Williams <gh@mattyw.net>
|
||||
Matthew Brennan <matty.brennan@gmail.com>
|
||||
Matthew Cottingham <mattcottingham@gmail.com>
|
||||
Matthew Denton <mdenton@skyportsystems.com>
|
||||
Matthew Holt <Matthew.Holt+git@gmail.com>
|
||||
Matthew Horsnell <matthew.horsnell@gmail.com>
|
||||
Matthieu Hauglustaine <matt.hauglustaine@gmail.com>
|
||||
Matthieu Olivier <olivier.matthieu@gmail.com>
|
||||
Max Riveiro <kavu13@gmail.com>
|
||||
Maxim Khitrov <max@mxcrypt.com>
|
||||
Maxwell Krohn <themax@gmail.com>
|
||||
MediaMath, Inc
|
||||
Meir Fischer <meirfischer@gmail.com>
|
||||
Meng Zhuo <mengzhuo1203@gmail.com>
|
||||
Meteor Development Group
|
||||
@@ -588,8 +517,6 @@ Miguel Mendez <stxmendez@gmail.com>
|
||||
Mihai Borobocea <MihaiBorobocea@gmail.com>
|
||||
Mikael Tillenius <mikti42@gmail.com>
|
||||
Mike Andrews <mra@xoba.com>
|
||||
Mike Appleby <mike@app.leby.org>
|
||||
Mike Houston <mike@kothar.net>
|
||||
Mike Rosset <mike.rosset@gmail.com>
|
||||
Mikhail Gusarov <dottedmag@dottedmag.net>
|
||||
Mikhail Panchenko <m@mihasya.com>
|
||||
@@ -597,9 +524,7 @@ Miki Tebeka <miki.tebeka@gmail.com>
|
||||
Mikio Hara <mikioh.mikioh@gmail.com>
|
||||
Mikkel Krautz <mikkel@krautz.dk>
|
||||
Miquel Sabaté Solà <mikisabate@gmail.com>
|
||||
Miroslav Genov <mgenov@gmail.com>
|
||||
Mohit Agarwal <mohit@sdf.org>
|
||||
Momchil Velikov <momchil.velikov@gmail.com>
|
||||
Monty Taylor <mordred@inaugust.com>
|
||||
Moov Corporation
|
||||
Moriyoshi Koizumi <mozo@mozo.jp>
|
||||
@@ -623,7 +548,6 @@ Nicholas Presta <nick@nickpresta.ca> <nick1presta@gmail.com>
|
||||
Nicholas Sullivan <nicholas.sullivan@gmail.com>
|
||||
Nicholas Waples <nwaples@gmail.com>
|
||||
Nick Craig-Wood <nick@craig-wood.com> <nickcw@gmail.com>
|
||||
Nick Leli <nicholasleli@gmail.com>
|
||||
Nick Patavalis <nick.patavalis@gmail.com>
|
||||
Nick Petroni <npetroni@cs.umd.edu>
|
||||
Nicolas Kaiser <nikai@nikai.net>
|
||||
@@ -631,13 +555,10 @@ Nicolas Owens <mischief@offblast.org>
|
||||
Nicolas S. Dade <nic.dade@gmail.com>
|
||||
Niels Widger <niels.widger@gmail.com>
|
||||
Nigel Kerr <nigel.kerr@gmail.com>
|
||||
Nik Nyby <nnyby@columbia.edu>
|
||||
Niko Dziemba <niko@dziemba.com>
|
||||
Nikolay Turpitko <nikolay@turpitko.com>
|
||||
Noah Campbell <noahcampbell@gmail.com>
|
||||
Norberto Lopes <nlopes.ml@gmail.com>
|
||||
Odin Ugedal <odin@ugedal.com>
|
||||
Oleg Vakheta <helginet@gmail.com>
|
||||
Oleku Konko <oleku.konko@gmail.com>
|
||||
Oling Cat <olingcat@gmail.com>
|
||||
Oliver Hookins <ohookins@gmail.com>
|
||||
@@ -652,12 +573,10 @@ Padraig Kitterick <padraigkitterick@gmail.com>
|
||||
Palm Stone Games
|
||||
Paolo Giarrusso <p.giarrusso@gmail.com>
|
||||
Paolo Martini <mrtnpaolo@gmail.com>
|
||||
Parker Moore <parkrmoore@gmail.com>
|
||||
Pascal S. de Kloe <pascal@quies.net>
|
||||
Patrick Crosby <patrick@stathat.com>
|
||||
Patrick Gavlin <pgavlin@gmail.com>
|
||||
Patrick Higgins <patrick.allen.higgins@gmail.com>
|
||||
Patrick Lee <pattyshack101@gmail.com>
|
||||
Patrick Mézard <patrick@mezard.eu>
|
||||
Patrick Mylund Nielsen <patrick@patrickmn.com>
|
||||
Patrick Smith <pat42smith@gmail.com>
|
||||
@@ -700,12 +619,9 @@ Quan Yong Zhai <qyzhai@gmail.com>
|
||||
Quentin Perez <qperez@ocs.online.net>
|
||||
Quoc-Viet Nguyen <afelion@gmail.com>
|
||||
RackTop Systems Inc.
|
||||
Radu Berinde <radu@cockroachlabs.com>
|
||||
Rafal Jeczalik <rjeczalik@gmail.com>
|
||||
Raif S. Naffah <go@naffah-raif.name>
|
||||
Rajat Goel <rajat.goel2010@gmail.com>
|
||||
Ralph Corderoy <ralph@inputplus.co.uk>
|
||||
Raphael Geronimi <raphael.geronimi@gmail.com>
|
||||
Red Hat, Inc.
|
||||
Reinaldo de Souza Jr <juniorz@gmail.com>
|
||||
Rémy Oudompheng <oudomphe@phare.normalesup.org>
|
||||
@@ -713,7 +629,6 @@ Ricardo Padilha <ricardospadilha@gmail.com>
|
||||
Richard Barnes <rlb@ipv.sx>
|
||||
Richard Crowley <r@rcrowley.org>
|
||||
Richard Eric Gavaletz <gavaletz@gmail.com>
|
||||
Richard Gibson <richard.gibson@gmail.com>
|
||||
Richard Miller <miller.research@gmail.com>
|
||||
Richard Musiol <mail@richard-musiol.de>
|
||||
Rick Arnold <rickarnoldjr@gmail.com>
|
||||
@@ -736,24 +651,20 @@ Ron Minnich <rminnich@gmail.com>
|
||||
Ross Light <rlight2@gmail.com>
|
||||
Rowan Worth <sqweek@gmail.com>
|
||||
Russell Haering <russellhaering@gmail.com>
|
||||
Ryan Bagwell <ryanbagwell@outlook.com>
|
||||
Ryan Hitchman <hitchmanr@gmail.com>
|
||||
Ryan Lower <rpjlower@gmail.com>
|
||||
Ryan Seys <ryan@ryanseys.com>
|
||||
Ryan Slade <ryanslade@gmail.com>
|
||||
Ryuzo Yamamoto <ryuzo.yamamoto@gmail.com>
|
||||
S.Çağlar Onur <caglar@10ur.org>
|
||||
Salmān Aljammāz <s@0x65.net>
|
||||
Sam Hug <samuel.b.hug@gmail.com>
|
||||
Sam Whited <sam@samwhited.com>
|
||||
Samuele Pedroni <pedronis@lucediurna.net>
|
||||
Sanjay Menakuru <balasanjay@gmail.com>
|
||||
Sasha Sobol <sasha@scaledinference.com>
|
||||
Scott Barron <scott.barron@github.com>
|
||||
Scott Bell <scott@sctsm.com>
|
||||
Scott Ferguson <scottwferg@gmail.com>
|
||||
Scott Lawrence <bytbox@gmail.com>
|
||||
Sean Rees <sean@erifax.org>
|
||||
Sebastien Binet <seb.binet@gmail.com>
|
||||
Sébastien Paolacci <sebastien.paolacci@gmail.com>
|
||||
Sergei Skorobogatov <skorobo@rambler.ru>
|
||||
@@ -770,13 +681,9 @@ Shinji Tanaka <shinji.tanaka@gmail.com>
|
||||
Shivakumar GN <shivakumar.gn@gmail.com>
|
||||
Silvan Jegen <s.jegen@gmail.com>
|
||||
Simon Jefford <simon.jefford@gmail.com>
|
||||
Simon Rawet <simon@rawet.se>
|
||||
Simon Thulbourn <simon+github@thulbourn.com>
|
||||
Simon Whitehead <chemnova@gmail.com>
|
||||
Sina Siadat <siadat@gmail.com>
|
||||
Sokolov Yura <funny.falcon@gmail.com>
|
||||
Song Gao <song@gao.io>
|
||||
Sourcegraph Inc
|
||||
Spencer Nelson <s@spenczar.com>
|
||||
Spring Mc <heresy.mc@gmail.com>
|
||||
Square, Inc.
|
||||
@@ -793,32 +700,25 @@ Steve Streeting <steve@stevestreeting.com>
|
||||
Steven Elliot Harris <seharris@gmail.com>
|
||||
Steven Hartland <steven.hartland@multiplay.co.uk>
|
||||
Stripe, Inc.
|
||||
Suyash <dextrous93@gmail.com>
|
||||
Sven Almgren <sven@tras.se>
|
||||
Syohei YOSHIDA <syohex@gmail.com>
|
||||
Szabolcs Nagy <nsz@port70.net>
|
||||
Tad Glines <tad.glines@gmail.com>
|
||||
Taj Khattra <taj.khattra@gmail.com>
|
||||
Takeshi YAMANASHI <9.nashi@gmail.com>
|
||||
Takuya Ueda <uedatakuya@gmail.com>
|
||||
Tal Shprecher <tshprecher@gmail.com>
|
||||
Tamir Duberstein <tamird@gmail.com>
|
||||
Tarmigan Casebolt <tarmigan@gmail.com>
|
||||
Taru Karttunen <taruti@taruti.net>
|
||||
Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
|
||||
Terrel Shumway <gopher@shumway.us>
|
||||
Tetsuo Kiso <tetsuokiso9@gmail.com>
|
||||
Thiago Fransosi Farina <thiago.farina@gmail.com>
|
||||
Thomas Alan Copeland <talan.copeland@gmail.com>
|
||||
Thomas de Zeeuw <thomasdezeeuw@gmail.com>
|
||||
Thomas Desrosiers <thomasdesr@gmail.com>
|
||||
Thomas Kappler <tkappler@gmail.com>
|
||||
Thorben Krueger <thorben.krueger@gmail.com>
|
||||
Thordur Bjornsson <thorduri@secnorth.net>
|
||||
Tilman Dilo <tilman.dilo@gmail.com>
|
||||
Tim Cooijmans <timcooijmans@gmail.com>
|
||||
Tim Ebringer <tim.ebringer@gmail.com>
|
||||
Tim Henderson <tim.tadh@gmail.com>
|
||||
Timo Savola <timo.savola@gmail.com>
|
||||
Timo Truyts <alkaloid.btx@gmail.com>
|
||||
Timothy Studd <tim@timstudd.com>
|
||||
@@ -831,12 +731,8 @@ Tor Andersson <tor.andersson@gmail.com>
|
||||
Tormod Erevik Lea <tormodlea@gmail.com>
|
||||
Totoro W <tw19881113@gmail.com>
|
||||
Travis Cline <travis.cline@gmail.com>
|
||||
Trey Lawrence <lawrence.trey@gmail.com>
|
||||
Trey Tacon <ttacon@gmail.com>
|
||||
Tristan Colgate <tcolgate@gmail.com>
|
||||
Tristan Ooohry <ooohry@gmail.com>
|
||||
Tudor Golubenco <tudor.g@gmail.com>
|
||||
Tuo Shan <sturbo89@gmail.com>
|
||||
Tyler Bunnell <tylerbunnell@gmail.com>
|
||||
Tyler Treat <ttreat31@gmail.com>
|
||||
Ugorji Nwoke <ugorji@gmail.com>
|
||||
@@ -846,18 +742,13 @@ Upthere, Inc.
|
||||
Uriel Mangado <uriel@berlinblue.org>
|
||||
Vadim Grek <vadimprog@gmail.com>
|
||||
Vadim Vygonets <unixdj@gmail.com>
|
||||
Vendasta
|
||||
Vincent Ambo <tazjin@googlemail.com>
|
||||
Vincent Batts <vbatts@hashbangbash.com> <vbatts@gmail.com>
|
||||
Vincent Vanackere <vincent.vanackere@gmail.com>
|
||||
Vinu Rajashekhar <vinutheraj@gmail.com>
|
||||
Vishvananda Ishaya <vishvananda@gmail.com>
|
||||
Vitor De Mario <vitordemario@gmail.com>
|
||||
Vladimir Mihailenco <vladimir.webdev@gmail.com>
|
||||
Vladimir Nikishenko <vova616@gmail.com>
|
||||
Vladimir Stefanovic <vladimir.stefanovic@imgtec.com>
|
||||
Volker Dobler <dr.volker.dobler@gmail.com>
|
||||
Weaveworks
|
||||
Wei Guangjing <vcc.163@gmail.com>
|
||||
Willem van der Schyff <willemvds@gmail.com>
|
||||
William Josephson <wjosephson@gmail.com>
|
||||
@@ -866,7 +757,6 @@ Wisdom Omuya <deafgoat@gmail.com>
|
||||
Xia Bin <snyh@snyh.org>
|
||||
Xing Xing <mikespook@gmail.com>
|
||||
Xudong Zhang <felixmelon@gmail.com>
|
||||
Xuyang Kang <xuyangkang@gmail.com>
|
||||
Yahoo Inc.
|
||||
Yann Kerhervé <yann.kerherve@gmail.com>
|
||||
Yao Zhang <lunaria21@gmail.com>
|
||||
@@ -876,15 +766,11 @@ Yesudeep Mangalapilly <yesudeep@google.com>
|
||||
Yissakhar Z. Beck <yissakhar.beck@gmail.com>
|
||||
Yo-An Lin <yoanlin93@gmail.com>
|
||||
Yongjian Xu <i3dmaster@gmail.com>
|
||||
Yorman Arias <cixtords@gmail.com>
|
||||
Yoshiyuki Kanno <nekotaroh@gmail.com> <yoshiyuki.kanno@stoic.co.jp>
|
||||
Yusuke Kagiwada <block.rxckin.beats@gmail.com>
|
||||
Yuusei Kuwana <kuwana@kumama.org>
|
||||
Yuval Pavel Zholkover <paulzhol@gmail.com>
|
||||
Zac Bergquist <zbergquist99@gmail.com>
|
||||
Zemanta d.o.o.
|
||||
Zev Goldstein <zev.goldstein@gmail.com>
|
||||
Ziad Hatahet <hatahet@gmail.com>
|
||||
Zorion Arrizabalaga <zorionk@gmail.com>
|
||||
Фахриддин Балтаев <faxriddinjon@gmail.com>
|
||||
申习之 <bronze1man@gmail.com>
|
||||
|
||||
@@ -7,11 +7,6 @@ It is the work of hundreds of contributors. We appreciate your help!
|
||||
|
||||
## Filing issues
|
||||
|
||||
General questions should go to the
|
||||
[golang-nuts mailing list](https://groups.google.com/group/golang-nuts) or
|
||||
[other forum](https://golang.org/wiki/Questions) instead of the issue tracker.
|
||||
The gophers there will answer or ask you to file an issue if you've tripped over a bug.
|
||||
|
||||
When filing an issue, make sure to answer these five questions:
|
||||
|
||||
1. What version of Go are you using (`go version`)?
|
||||
@@ -20,7 +15,8 @@ When filing an issue, make sure to answer these five questions:
|
||||
4. What did you expect to see?
|
||||
5. What did you see instead?
|
||||
|
||||
For change proposals, see [Proposing Changes To Go](https://github.com/golang/proposal/).
|
||||
General questions should go to the [golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead of the issue tracker.
|
||||
The gophers there will answer or ask you to file an issue if you've tripped over a bug.
|
||||
|
||||
Sensitive security-related issues should be reported to [security@golang.org](mailto:security@golang.org).
|
||||
|
||||
@@ -32,7 +28,6 @@ before sending patches.
|
||||
**We do not accept GitHub pull requests**
|
||||
(we use [an instance](https://go-review.googlesource.com/) of the
|
||||
[Gerrit](https://www.gerritcodereview.com/) code review system instead).
|
||||
Also, please do not post patches on the issue tracker.
|
||||
|
||||
Unless otherwise noted, the Go source files are distributed under
|
||||
the BSD-style license found in the LICENSE file.
|
||||
|
||||
147
CONTRIBUTORS
147
CONTRIBUTORS
@@ -53,29 +53,22 @@ Akihiro Suda <suda.kyoto@gmail.com>
|
||||
Akshat Kumar <seed@mail.nanosouffle.net>
|
||||
Alan Donovan <adonovan@google.com>
|
||||
Alan Shreve <alan@inconshreveable.com>
|
||||
Albert Nigmatzianov <albertnigma@gmail.com>
|
||||
Albert Strasheim <fullung@gmail.com>
|
||||
Albert Yu <yukinying@gmail.com>
|
||||
Alberto Bertogli <albertito@blitiri.com.ar>
|
||||
Alberto Donizetti <alb.donizetti@gmail.com>
|
||||
Alberto García Hierro <alberto@garciahierro.com> <alberto.garcia.hierro@gmail.com>
|
||||
Aleksandar Dezelin <dezelin@gmail.com>
|
||||
Alessandro Arzilli <alessandro.arzilli@gmail.com>
|
||||
Alessandro Baffa <alessandro.baffa@gmail.com>
|
||||
Alex A Skinner <alex@lx.lc>
|
||||
Alex Brainman <alex.brainman@gmail.com>
|
||||
Alex Bramley <abramley@google.com>
|
||||
Alex Browne <stephenalexbrowne@gmail.com>
|
||||
Alex Carol <alex.carol.c@gmail.com>
|
||||
Alex Jin <toalexjin@gmail.com>
|
||||
Alex Plugaru <alex@plugaru.org> <alexandru.plugaru@gmail.com>
|
||||
Alex Schroeder <alex@gnu.org>
|
||||
Alex Sergeyev <abc@alexsergeyev.com>
|
||||
Alex Vaghin <crhyme@google.com>
|
||||
Alexander Demakin <alexander.demakin@gmail.com>
|
||||
Alexander Döring <email@alexd.ch>
|
||||
Alexander Larsson <alexander.larsson@gmail.com>
|
||||
Alexander Menzhinsky <amenzhinsky@gmail.com>
|
||||
Alexander Morozov <lk4d4math@gmail.com>
|
||||
Alexander Neumann <alexander@bumpern.de>
|
||||
Alexander Orlov <alexander.orlov@loxal.net>
|
||||
@@ -84,7 +77,6 @@ Alexander Surma <surma@surmair.de>
|
||||
Alexander Zhavnerchik <alex.vizor@gmail.com>
|
||||
Alexander Zolotov <goldifit@gmail.com>
|
||||
Alexandre Cesaro <alexandre.cesaro@gmail.com>
|
||||
Alexandre Fiori <fiorix@gmail.com>
|
||||
Alexandre Normand <alexandre.normand@gmail.com>
|
||||
Alexandru Moșoi <brtzsnr@gmail.com>
|
||||
Alexei Sholik <alcosholik@gmail.com>
|
||||
@@ -93,19 +85,14 @@ Alexey Palazhchenko <alexey.palazhchenko@gmail.com>
|
||||
Alexis Imperial-Legrand <ail@google.com>
|
||||
Aliaksandr Valialkin <valyala@gmail.com>
|
||||
Alif Rachmawadi <subosito@gmail.com>
|
||||
Allan Simon <allan.simon@supinfo.com>
|
||||
Alok Menghrajani <alok.menghrajani@gmail.com>
|
||||
Amir Mohammad Saied <amir@gluegadget.com>
|
||||
Amrut Joshi <amrut.joshi@gmail.com>
|
||||
Andre Nathan <andrenth@gmail.com>
|
||||
Andrea Spadaccini <spadaccio@google.com>
|
||||
Andreas Auernhammer <aead@mail.de>
|
||||
Andreas Jellinghaus <andreas@ionisiert.de> <anj@google.com>
|
||||
Andreas Litt <andreas.litt@gmail.com>
|
||||
Andrei Korzhevskii <a.korzhevskiy@gmail.com>
|
||||
Andrei Vieru <euvieru@gmail.com>
|
||||
Andres Erbsen <andreser@google.com>
|
||||
Andrew Austin <andrewaclt@gmail.com>
|
||||
Andrew Balholm <andybalholm@gmail.com>
|
||||
Andrew Bonventre <andybons@chromium.org>
|
||||
Andrew Bursavich <abursavich@gmail.com>
|
||||
@@ -115,7 +102,6 @@ Andrew Gerrand <adg@golang.org>
|
||||
Andrew Harding <andrew@spacemonkey.com>
|
||||
Andrew Lutomirski <andy@luto.us>
|
||||
Andrew Pilloud <andrewpilloud@igneoussystems.com>
|
||||
Andrew Pogrebnoy <absourd.noise@gmail.com>
|
||||
Andrew Pritchard <awpritchard@gmail.com>
|
||||
Andrew Radev <andrey.radev@gmail.com>
|
||||
Andrew Skiba <skibaa@gmail.com>
|
||||
@@ -128,7 +114,6 @@ Andrey Petrov <andrey.petrov@shazow.net>
|
||||
Andriy Lytvynov <lytvynov.a.v@gmail.com>
|
||||
Andy Balholm <andy@balholm.com>
|
||||
Andy Davis <andy@bigandian.com>
|
||||
Andy Finkenstadt <afinkenstadt@zynga.com>
|
||||
Andy Maloney <asmaloney@gmail.com>
|
||||
Anfernee Yongkun Gui <anfernee.gui@gmail.com>
|
||||
Angelo Bulfone <mbulfone@gmail.com>
|
||||
@@ -139,9 +124,6 @@ Anthony Canino <anthony.canino1@gmail.com>
|
||||
Anthony Eufemio <anthony.eufemio@gmail.com>
|
||||
Anthony Martin <ality@pbrane.org>
|
||||
Anthony Starks <ajstarks@gmail.com>
|
||||
Anthony Woods <awoods@raintank.io>
|
||||
Antonio Bibiano <antbbn@gmail.com>
|
||||
Antonio Murdaca <runcom@redhat.com>
|
||||
Apisak Darakananda <pongad@gmail.com>
|
||||
Aram Hăvărneanu <aram@mgk.ro>
|
||||
Areski Belaid <areski@gmail.com>
|
||||
@@ -154,7 +136,6 @@ Aron Nopanen <aron.nopanen@gmail.com>
|
||||
Artyom Pervukhin <artyom.pervukhin@gmail.com>
|
||||
Arvindh Rajesh Tamilmani <art@a-30.net>
|
||||
Asim Shankar <asimshankar@gmail.com>
|
||||
Atin Malaviya <amalaviy@akamai.com>
|
||||
Ato Araki <ato.araki@gmail.com>
|
||||
Audrey Lim <audreylh@gmail.com>
|
||||
Augusto Roman <aroman@gmail.com>
|
||||
@@ -163,12 +144,10 @@ Austin Clements <austin@google.com> <aclements@csail.mit.edu>
|
||||
awaw fumin <awawfumin@gmail.com>
|
||||
Ayanamist Yang <ayanamist@gmail.com>
|
||||
Aymerick Jéhanne <aymerick@jehanne.org>
|
||||
Baiju Muthukadan <baiju.m.mail@gmail.com>
|
||||
Balazs Lecz <leczb@google.com>
|
||||
Ben Burkert <ben@benburkert.com>
|
||||
Ben Eitzen <eitzenb@golang.org>
|
||||
Ben Fried <ben.fried@gmail.com>
|
||||
Ben Lubar <ben.lubar@gmail.com>
|
||||
Ben Lynn <benlynn@gmail.com>
|
||||
Ben Olive <sionide21@gmail.com>
|
||||
Benjamin Black <b@b3k.us>
|
||||
@@ -181,17 +160,13 @@ Bill Neubauer <wcn@golang.org> <wcn@google.com> <bill.neubauer@gmail.com>
|
||||
Bill O'Farrell <billo@ca.ibm.com>
|
||||
Bill Thiede <couchmoney@gmail.com>
|
||||
Billie Harold Cleek <bhcleek@gmail.com>
|
||||
Billy Lynch <wlynch@google.com>
|
||||
Bjorn Tillenius <bjorn@tillenius.me>
|
||||
Bjorn Tipling <bjorn.tipling@gmail.com>
|
||||
Blake Gentry <blakesgentry@gmail.com>
|
||||
Blake Mizerany <blake.mizerany@gmail.com>
|
||||
Blixt <me@blixt.nyc>
|
||||
Bobby Powers <bobbypowers@gmail.com>
|
||||
Boris Nagaev <nagaev@google.com>
|
||||
Brad Fitzpatrick <bradfitz@golang.org> <bradfitz@gmail.com>
|
||||
Brad Garcia <bgarcia@golang.org>
|
||||
Braden Bassingthwaite <bbassingthwaite@vendasta.com>
|
||||
Brady Catherman <brady@gmail.com>
|
||||
Brady Sullivan <brady@bsull.com>
|
||||
Brandon Gilmore <varz@google.com>
|
||||
@@ -201,11 +176,9 @@ Brett Cannon <bcannon@gmail.com>
|
||||
Brian Dellisanti <briandellisanti@gmail.com>
|
||||
Brian G. Merrell <bgmerrell@gmail.com>
|
||||
Brian Gitonga Marete <marete@toshnix.com> <bgmarete@gmail.com> <bgm@google.com>
|
||||
Brian Kennedy <btkennedy@gmail.com>
|
||||
Brian Ketelsen <bketelsen@gmail.com>
|
||||
Brian Slesinsky <skybrian@google.com>
|
||||
Brian Smith <ohohvi@gmail.com>
|
||||
Bryan Alexander <Kozical@msn.com>
|
||||
Bryan C. Mills <bcmills@google.com>
|
||||
Bryan Chan <bryan.chan@ca.ibm.com>
|
||||
Bryan Ford <brynosaurus@gmail.com>
|
||||
@@ -214,12 +187,10 @@ Caio Marcelo de Oliveira Filho <caio.oliveira@intel.com>
|
||||
Caleb Spare <cespare@gmail.com>
|
||||
Carl Chatfield <carlchatfield@gmail.com>
|
||||
Carl Jackson <carl@stripe.com>
|
||||
Carl Johnson <me@carlmjohnson.net>
|
||||
Carl Mastrangelo <notcarl@google.com>
|
||||
Carl Shapiro <cshapiro@google.com> <cshapiro@golang.org>
|
||||
Carlos Castillo <cookieo9@gmail.com>
|
||||
Carlos Cirello <uldericofilho@gmail.com>
|
||||
Carlos Eduardo Seo <cseo@linux.vnet.ibm.com>
|
||||
Cary Hull <chull@google.com>
|
||||
Case Nelson <case.nelson@gmail.com>
|
||||
Casey Marshall <casey.marshall@gmail.com>
|
||||
@@ -243,7 +214,6 @@ Chris Kastorff <encryptio@gmail.com>
|
||||
Chris Lennert <calennert@gmail.com>
|
||||
Chris Manghane <cmang@golang.org>
|
||||
Chris McGee <sirnewton_01@yahoo.ca> <newton688@gmail.com>
|
||||
Chris Stockton <chrisstocktonaz@gmail.com>
|
||||
Chris Zou <chriszou@ca.ibm.com>
|
||||
Christian Couder <chriscool@tuxfamily.org>
|
||||
Christian Himpel <chressie@googlemail.com> <chressie@gmail.com>
|
||||
@@ -270,12 +240,10 @@ Corey Thomasson <cthom.lists@gmail.com>
|
||||
Cosmos Nicolaou <cnicolaou@google.com>
|
||||
Cristian Staretu <unclejacksons@gmail.com>
|
||||
Cuihtlauac ALVARADO <cuihtlauac.alvarado@orange.com>
|
||||
Cyrill Schumacher <cyrill@schumacher.fm>
|
||||
Damian Gryski <dgryski@gmail.com>
|
||||
Damien Neil <dneil@google.com>
|
||||
Dan Caddigan <goldcaddy77@gmail.com>
|
||||
Dan Callahan <dan.callahan@gmail.com>
|
||||
Dan Harrington <harringtond@google.com>
|
||||
Dan Jacques <dnj@google.com>
|
||||
Dan Peterson <dpiddy@gmail.com>
|
||||
Dan Pupius <dan@medium.com>
|
||||
@@ -285,14 +253,12 @@ Daniel Johansson <dajo2002@gmail.com>
|
||||
Daniel Kerwin <d.kerwin@gini.net>
|
||||
Daniel Krech <eikeon@eikeon.com>
|
||||
Daniel Lidén <daniel.liden.87@gmail.com>
|
||||
Daniel Martí <mvdan@mvdan.cc>
|
||||
Daniel Morsing <daniel.morsing@gmail.com>
|
||||
Daniel Nadasi <dnadasi@google.com>
|
||||
Daniel Ortiz Pereira da Silva <daniel.particular@gmail.com>
|
||||
Daniel Skinner <daniel@dasa.cc>
|
||||
Daniel Speichert <daniel@speichert.pl>
|
||||
Daniel Theophanes <kardianos@gmail.com>
|
||||
Daria Kolistratova <daria.kolistratova@intel.com>
|
||||
Darren Elwood <darren@textnode.com>
|
||||
Datong Sun <dndx@idndx.com>
|
||||
Dave Borowitz <dborowitz@google.com>
|
||||
@@ -314,38 +280,30 @@ David Forsythe <dforsythe@gmail.com>
|
||||
David G. Andersen <dave.andersen@gmail.com>
|
||||
David Glasser <glasser@meteor.com>
|
||||
David Howden <dhowden@gmail.com>
|
||||
David Hubbard <dsp@google.com>
|
||||
David Jakob Fritz <david.jakob.fritz@gmail.com>
|
||||
David Lazar <lazard@golang.org>
|
||||
David Leon Gil <coruus@gmail.com>
|
||||
David McLeish <davemc@google.com>
|
||||
David Presotto <presotto@gmail.com>
|
||||
David R. Jenni <david.r.jenni@gmail.com>
|
||||
David Sansome <me@davidsansome.com>
|
||||
David Stainton <dstainton415@gmail.com>
|
||||
David Symonds <dsymonds@golang.org>
|
||||
David Thomas <davidthomas426@gmail.com>
|
||||
David Titarenco <david.titarenco@gmail.com>
|
||||
Davies Liu <davies.liu@gmail.com>
|
||||
Dean Prichard <dean.prichard@gmail.com>
|
||||
Deepak Jois <deepak.jois@gmail.com>
|
||||
Denis Bernard <db047h@gmail.com>
|
||||
Denis Brandolini <denis.brandolini@gmail.com>
|
||||
Denis Nagorny <denis.nagorny@intel.com>
|
||||
Denys Honsiorovskyi <honsiorovskyi@gmail.com>
|
||||
Derek Buitenhuis <derek.buitenhuis@gmail.com>
|
||||
Derek Che <drc@yahoo-inc.com>
|
||||
Derek Parker <parkerderek86@gmail.com>
|
||||
Derek Shockey <derek.shockey@gmail.com>
|
||||
Devon H. O'Dell <devon.odell@gmail.com>
|
||||
Dhaivat Pandit <dhaivatpandit@gmail.com>
|
||||
Dhananjay Nakrani <dhananjayn@google.com>
|
||||
Dhiru Kholia <dhiru.kholia@gmail.com>
|
||||
Didier Spezia <didier.06@gmail.com>
|
||||
Dimitri Tcaciuc <dtcaciuc@gmail.com>
|
||||
Dirk Gadsden <dirk@esherido.com>
|
||||
Diwaker Gupta <diwakergupta@gmail.com>
|
||||
Dmitri Popov <operator@cv.dp-net.com>
|
||||
Dmitri Shuralyov <shurcooL@gmail.com>
|
||||
Dmitriy Dudkin <dudkin.dmitriy@gmail.com>
|
||||
Dmitriy Shelenin <deemok@googlemail.com> <deemok@gmail.com>
|
||||
@@ -372,7 +330,6 @@ Egon Elbre <egonelbre@gmail.com>
|
||||
Ehren Kret <ehren.kret@gmail.com>
|
||||
Eivind Uggedal <eivind@uggedal.com>
|
||||
Elias Naur <elias.naur@gmail.com>
|
||||
Elliot Morrison-Reed <elliotmr@gmail.com>
|
||||
Emil Hessman <c.emil.hessman@gmail.com> <emil@hessman.se>
|
||||
Emmanuel Odeke <emm.odeke@gmail.com> <odeke@ualberta.ca>
|
||||
Eoghan Sherry <ejsherry@gmail.com>
|
||||
@@ -386,13 +343,10 @@ Eric Roshan-Eisner <eric.d.eisner@gmail.com>
|
||||
Erik Aigner <aigner.erik@gmail.com>
|
||||
Erik Dubbelboer <erik@dubbelboer.com>
|
||||
Erik St. Martin <alakriti@gmail.com>
|
||||
Erik Staab <estaab@google.com>
|
||||
Erik Westrup <erik.westrup@gmail.com>
|
||||
Ernest Chiang <ernest_chiang@htc.com>
|
||||
Esko Luontola <esko.luontola@gmail.com>
|
||||
Ethan Burns <eaburns@google.com>
|
||||
Ethan Miller <eamiller@us.ibm.com>
|
||||
Euan Kemp <euank@euank.com>
|
||||
Evan Broder <evan@stripe.com>
|
||||
Evan Brown <evanbrown@google.com>
|
||||
Evan Kroske <evankroske@google.com>
|
||||
@@ -402,12 +356,10 @@ Evan Shaw <chickencha@gmail.com>
|
||||
Ewan Chou <coocood@gmail.com>
|
||||
Fabian Wickborn <fabian@wickborn.net>
|
||||
Fabrizio Milo <mistobaan@gmail.com>
|
||||
Faiyaz Ahmed <ahmedf@vmware.com>
|
||||
Fan Hongjian <fan.howard@gmail.com>
|
||||
Fatih Arslan <fatih@arslan.io>
|
||||
Fazlul Shahriar <fshahriar@gmail.com>
|
||||
Federico Simoncelli <fsimonce@redhat.com>
|
||||
Fedor Indutny <fedor@indutny.com>
|
||||
Felix Geisendörfer <haimuiba@gmail.com>
|
||||
Filippo Valsorda <hi@filippo.io>
|
||||
Firmansyah Adiputra <frm.adiputra@gmail.com>
|
||||
@@ -426,15 +378,12 @@ Frits van Bommel <fvbommel@gmail.com>
|
||||
Fumitoshi Ukai <ukai@google.com>
|
||||
Gaal Yahas <gaal@google.com>
|
||||
Gabriel Aszalos <gabriel.aszalos@gmail.com>
|
||||
Gabriel Russell <gabriel.russell@gmail.com>
|
||||
Gareth Paul Jones <gpj@foursquare.com>
|
||||
Garrick Evans <garrick@google.com>
|
||||
Gary Burd <gary@beagledreams.com> <gary.burd@gmail.com>
|
||||
Gary Elliott <garyelliott@google.com>
|
||||
Gaurish Sharma <contact@gaurishsharma.com>
|
||||
Gautham Thambidorai <gautham.dorai@gmail.com>
|
||||
Geert-Johan Riemer <gjr19912@gmail.com>
|
||||
Geoffroy Lorieux <lorieux.g@gmail.com>
|
||||
Georg Reinke <guelfey@gmail.com>
|
||||
George Shammas <george@shamm.as> <georgyo@gmail.com>
|
||||
Gerasimos Dimitriadis <gedimitr@gmail.com>
|
||||
@@ -442,7 +391,6 @@ Gideon Jan-Wessel Redelinghuys <gjredelinghuys@gmail.com>
|
||||
Giles Lean <giles.lean@pobox.com>
|
||||
Giovanni Bajo <rasky@develer.com>
|
||||
Giulio Iotti <dullgiulio@gmail.com>
|
||||
Gleb Stepanov <glebstepanov1992@gmail.com>
|
||||
Glenn Brown <glennb@google.com>
|
||||
Glenn Lewis <gmlewis@google.com>
|
||||
Gordon Klaus <gordon.klaus@gmail.com>
|
||||
@@ -463,14 +411,12 @@ Han-Wen Nienhuys <hanwen@google.com>
|
||||
Hari haran <hariharan.uno@gmail.com>
|
||||
Hariharan Srinath <srinathh@gmail.com>
|
||||
Harley Laue <losinggeneration@gmail.com>
|
||||
Harry Moreno <morenoh149@gmail.com>
|
||||
Harshavardhana <hrshvardhana@gmail.com>
|
||||
Håvard Haugen <havard.haugen@gmail.com>
|
||||
Hector Chu <hectorchu@gmail.com>
|
||||
Hector Martin Cantero <hector@marcansoft.com>
|
||||
Henning Schmiedehausen <henning@schmiedehausen.org>
|
||||
Henrik Edwards <henrik.edwards@gmail.com>
|
||||
Henrik Hodne <henrik@hodne.io>
|
||||
Herbert Georg Fischer <herbert.fischer@gmail.com>
|
||||
Hironao OTSUBO <motemen@gmail.com>
|
||||
Hiroshi Ioka <hirochachacha@gmail.com>
|
||||
@@ -485,7 +431,6 @@ Ian Gudger <ian@loosescre.ws>
|
||||
Ian Lance Taylor <iant@golang.org>
|
||||
Icarus Sparry <golang@icarus.freeuk.com>
|
||||
Idora Shinatose <idora.shinatose@gmail.com>
|
||||
Igor Bernstein <igorbernstein@google.com>
|
||||
Igor Dolzhikov <bluesriverz@gmail.com>
|
||||
Ilya Tocar <ilya.tocar@intel.com>
|
||||
INADA Naoki <songofacandy@gmail.com>
|
||||
@@ -493,11 +438,9 @@ Ingo Krabbe <ikrabbe.ask@gmail.com>
|
||||
Ingo Oeser <nightlyone@googlemail.com> <nightlyone@gmail.com>
|
||||
Irieda Noboru <irieda@gmail.com>
|
||||
Isaac Wagner <ibw@isaacwagner.me>
|
||||
Ivan Babrou <ivan@cloudflare.com>
|
||||
Ivan Krasin <krasin@golang.org>
|
||||
Ivan Ukhov <ivan.ukhov@gmail.com>
|
||||
Jaana Burcu Dogan <jbd@google.com> <jbd@golang.org> <burcujdogan@gmail.com>
|
||||
Jack Lindamood <jlindamo@justin.tv>
|
||||
Jacob Baskin <jbaskin@google.com>
|
||||
Jacob H. Haven <jacob@cloudflare.com>
|
||||
Jacob Hoffman-Andrews <github@hoffman-andrews.com>
|
||||
@@ -508,7 +451,6 @@ Jakub Ryszard Czarnowicz <j.czarnowicz@gmail.com>
|
||||
James Aguilar <jaguilar@google.com>
|
||||
James Bardin <j.bardin@gmail.com>
|
||||
James Chacon <jchacon@google.com>
|
||||
James Clarke <jrtc27@jrtc27.com>
|
||||
James David Chalfant <james.chalfant@gmail.com>
|
||||
James Fysh <james.fysh@gmail.com>
|
||||
James Gray <james@james4k.com>
|
||||
@@ -520,7 +462,6 @@ James Sweet <james.sweet88@googlemail.com>
|
||||
James Toy <nil@opensesame.st>
|
||||
James Tucker <raggi@google.com>
|
||||
James Whitehead <jnwhiteh@gmail.com>
|
||||
Jamie Beverly <jamie.r.beverly@gmail.com>
|
||||
Jamie Gennis <jgennis@google.com> <jgennis@gmail.com>
|
||||
Jamie Turner <jamwt@dropbox.com>
|
||||
Jamie Wilkinson <jaq@spacepants.org>
|
||||
@@ -534,14 +475,11 @@ Jan Ziak <0xe2.0x9a.0x9b@gmail.com>
|
||||
Jani Monoses <jani.monoses@ubuntu.com> <jani.monoses@gmail.com>
|
||||
Jaroslavas Počepko <jp@webmaster.ms>
|
||||
Jason Barnett <jason.w.barnett@gmail.com>
|
||||
Jason Buberel <jbuberel@google.com>
|
||||
Jason Del Ponte <delpontej@gmail.com>
|
||||
Jason Hall <jasonhall@google.com>
|
||||
Jason Smale <jsmale@zendesk.com>
|
||||
Jason Travis <infomaniac7@gmail.com>
|
||||
Jay Weisskopf <jay@jayschwa.net>
|
||||
Jean-Marc Eurin <jmeurin@google.com>
|
||||
Jean-Nicolas Moal <jn.moal@gmail.com>
|
||||
Jed Denlea <jed@fastly.com>
|
||||
Jeff Craig <jeffcraig@google.com>
|
||||
Jeff Hodges <jeff@somethingsimilar.com>
|
||||
@@ -552,18 +490,14 @@ Jens Frederich <jfrederich@gmail.com>
|
||||
Jeremiah Harmsen <jeremiah@google.com>
|
||||
Jeremy Jackins <jeremyjackins@gmail.com>
|
||||
Jeremy Schlatter <jeremy.schlatter@gmail.com>
|
||||
Jeroen Bobbeldijk <jerbob92@gmail.com>
|
||||
Jess Frazelle <me@jessfraz.com>
|
||||
Jesse Szwedko <jesse.szwedko@gmail.com>
|
||||
Jihyun Yu <yjh0502@gmail.com>
|
||||
Jim Cote <jfcote87@gmail.com>
|
||||
Jim Kingdon <jim@bolt.me>
|
||||
Jim McGrath <jimmc2@gmail.com>
|
||||
Jimmy Zelinskie <jimmyzelinskie@gmail.com>
|
||||
Jingcheng Zhang <diogin@gmail.com>
|
||||
Jingguo Yao <yaojingguo@gmail.com>
|
||||
Jiong Du <londevil@gmail.com>
|
||||
Jirka Daněk <dnk@mail.muni.cz>
|
||||
Joakim Sernbrant <serbaut@gmail.com>
|
||||
Joe Farrell <joe2farrell@gmail.com>
|
||||
Joe Harrison <joehazzers@gmail.com>
|
||||
@@ -590,7 +524,6 @@ John Potocny <johnp@vividcortex.com>
|
||||
John Schnake <schnake.john@gmail.com>
|
||||
John Shahid <jvshahid@gmail.com>
|
||||
John Tuley <john@tuley.org>
|
||||
Jon Chen <jchen@justin.tv>
|
||||
Jonathan Allie <jonallie@google.com>
|
||||
Jonathan Amsterdam <jba@google.com>
|
||||
Jonathan Boulle <jonathanboulle@gmail.com>
|
||||
@@ -603,19 +536,14 @@ Jonathan Pittman <jmpittman@google.com> <jonathan.mark.pittman@gmail.com>
|
||||
Jonathan Rudenberg <jonathan@titanous.com>
|
||||
Jonathan Wills <runningwild@gmail.com>
|
||||
Jongmin Kim <atomaths@gmail.com>
|
||||
Joonas Kuorilehto <joneskoo@derbian.fi>
|
||||
Joop Kiefte <ikojba@gmail.com> <joop@kiefte.net>
|
||||
Jordan Lewis <jordanthelewis@gmail.com>
|
||||
Jos Visser <josv@google.com>
|
||||
Jose Luis Vázquez González <josvazg@gmail.com>
|
||||
Joseph Bonneau <jcb@google.com>
|
||||
Joseph Holsten <joseph@josephholsten.com>
|
||||
Josh Bleecher Snyder <josharian@gmail.com>
|
||||
Josh Chorlton <jchorlton@gmail.com>
|
||||
Josh Goebel <dreamer3@gmail.com>
|
||||
Josh Hoak <jhoak@google.com>
|
||||
Josh Holland <jrh@joshh.co.uk>
|
||||
Joshua Boelter <joshua.boelter@intel.com>
|
||||
Joshua Chase <jcjoshuachase@gmail.com>
|
||||
Jostein Stuhaug <js@solidsystem.no>
|
||||
JP Sugarbroad <jpsugar@google.com>
|
||||
@@ -628,19 +556,15 @@ Julien Schmidt <google@julienschmidt.com>
|
||||
Jungho Ahn <jhahn@google.com>
|
||||
Jure Ham <jure.ham@zemanta.com>
|
||||
Justin Nuß <nuss.justin@gmail.com>
|
||||
Justyn Temme <justyntemme@gmail.com>
|
||||
Kai Backman <kaib@golang.org>
|
||||
Kale Blankenship <kale@lemnisys.com>
|
||||
Kamal Aboul-Hosn <aboulhosn@google.com>
|
||||
Kamil Kisiel <kamil@kamilkisiel.net> <kamil.kisiel@gmail.com>
|
||||
Kang Hu <hukangustc@gmail.com>
|
||||
Karan Dhiman <karandhi@ca.ibm.com>
|
||||
Kato Kazuyoshi <kato.kazuyoshi@gmail.com>
|
||||
Katrina Owen <katrina.owen@gmail.com>
|
||||
Kaviraj Kanagaraj <kavirajkanagaraj@gmail.com>
|
||||
Kay Zhu <kayzhu@google.com>
|
||||
KB Sriram <kbsriram@google.com>
|
||||
Keegan Carruthers-Smith <keegan.csmith@gmail.com>
|
||||
Kei Son <hey.calmdown@gmail.com>
|
||||
Keith Ball <inflatablewoman@gmail.com>
|
||||
Keith Randall <khr@golang.org>
|
||||
@@ -674,7 +598,6 @@ L Campbell <unpantsu@gmail.com>
|
||||
Lai Jiangshan <eag0628@gmail.com>
|
||||
Larry Hosken <lahosken@golang.org>
|
||||
Larz Conwell <larzconwell@gmail.com>
|
||||
LE Manh Cuong <cuong.manhle.vn@gmail.com>
|
||||
Lee Hinman <hinman@gmail.com>
|
||||
Lee Packham <lpackham@gmail.com>
|
||||
Lewin Bormann <lewin.bormann@gmail.com>
|
||||
@@ -685,27 +608,22 @@ Luan Santos <cfcluan@gmail.com>
|
||||
Luca Greco <luca.greco@alcacoop.it>
|
||||
Lucien Stuker <lucien.stuker@gmail.com>
|
||||
Lucio De Re <lucio.dere@gmail.com>
|
||||
Luigi Riefolo <luigi.riefolo@gmail.com>
|
||||
Luit van Drongelen <luitvd@gmail.com>
|
||||
Luka Zakrajšek <tr00.g33k@gmail.com>
|
||||
Luke Curley <qpingu@gmail.com>
|
||||
Luna Duclos <luna.duclos@palmstonegames.com>
|
||||
Luuk van Dijk <lvd@golang.org> <lvd@google.com>
|
||||
Lynn Boger <laboger@linux.vnet.ibm.com>
|
||||
Maksym Trykur <maksym.trykur@gmail.com>
|
||||
Mal Curtis <mal@mal.co.nz>
|
||||
Manfred Touron <m@42.am>
|
||||
Manoj Dayaram <platform-dev@moovweb.com> <manoj.dayaram@moovweb.com>
|
||||
Manu Garg <manugarg@google.com>
|
||||
Manu S Ajith <neo@codingarena.in>
|
||||
Manuel Mendez <mmendez534@gmail.com>
|
||||
Marc Weistroff <marc@weistroff.net>
|
||||
Marc-Antoine Ruel <maruel@chromium.org>
|
||||
Marcel Edmund Franke <marcel.edmund.franke@gmail.com>
|
||||
Marcel van Lohuizen <mpvl@golang.org>
|
||||
Marco Hennings <marco.hennings@freiheit.com>
|
||||
Marga Manterola <marga@google.com>
|
||||
Marin Bašić <marin.basic02@gmail.com>
|
||||
Marius Nuennerich <mnu@google.com>
|
||||
Mark Bucciarelli <mkbucc@gmail.com>
|
||||
Mark Severson <miquella@gmail.com>
|
||||
@@ -717,11 +635,8 @@ Marko Tiikkaja <marko@joh.to>
|
||||
Markus Duft <markus.duft@salomon.at>
|
||||
Markus Sonderegger <marraison@gmail.com>
|
||||
Markus Zimmermann <zimmski@gmail.com>
|
||||
Martin Bertschler <mbertschler@gmail.com>
|
||||
Martin Garton <garton@gmail.com>
|
||||
Martin Hamrle <martin.hamrle@gmail.com>
|
||||
Martin Kreichgauer <martinkr@google.com>
|
||||
Martin Möhrmann <moehrmann@google.com> <martisch@uos.de>
|
||||
Martin Möhrmann <martisch@uos.de>
|
||||
Martin Neubauer <m.ne@gmx.net>
|
||||
Martin Olsson <martin@minimum.se>
|
||||
Marvin Stenger <marvin.stenger94@gmail.com>
|
||||
@@ -745,12 +660,8 @@ Matt Williams <gh@mattyw.net> <mattyjwilliams@gmail.com>
|
||||
Matthew Brennan <matty.brennan@gmail.com>
|
||||
Matthew Cottingham <mattcottingham@gmail.com>
|
||||
Matthew Dempsky <mdempsky@google.com>
|
||||
Matthew Denton <mdenton@skyportsystems.com>
|
||||
Matthew Holt <Matthew.Holt+git@gmail.com>
|
||||
Matthew Horsnell <matthew.horsnell@gmail.com>
|
||||
Matthieu Hauglustaine <matt.hauglustaine@gmail.com>
|
||||
Matthieu Olivier <olivier.matthieu@gmail.com>
|
||||
Max Riveiro <kavu13@gmail.com>
|
||||
Maxim Khitrov <max@mxcrypt.com>
|
||||
Maxim Pimenov <mpimenov@google.com>
|
||||
Maxim Ushakov <ushakov@google.com>
|
||||
@@ -760,7 +671,6 @@ Meng Zhuo <mengzhuo1203@gmail.com>
|
||||
Mhd Sulhan <m.shulhan@gmail.com>
|
||||
Micah Stetson <micah.stetson@gmail.com>
|
||||
Michael Chaten <mchaten@gmail.com>
|
||||
Michael Darakananda <pongad@google.com>
|
||||
Michael Elkins <michael.elkins@gmail.com>
|
||||
Michael Fraenkel <michael.fraenkel@gmail.com>
|
||||
Michael Gehring <mg@ebfe.org> <gnirheg.leahcim@gmail.com>
|
||||
@@ -794,22 +704,17 @@ Miguel Mendez <stxmendez@gmail.com>
|
||||
Mihai Borobocea <MihaiBorobocea@gmail.com>
|
||||
Mikael Tillenius <mikti42@gmail.com>
|
||||
Mike Andrews <mra@xoba.com>
|
||||
Mike Appleby <mike@app.leby.org>
|
||||
Mike Danese <mikedanese@google.com>
|
||||
Mike Houston <mike@kothar.net>
|
||||
Mike Rosset <mike.rosset@gmail.com>
|
||||
Mike Samuel <mikesamuel@gmail.com>
|
||||
Mike Solomon <msolo@gmail.com>
|
||||
Mike Strosaker <strosake@us.ibm.com>
|
||||
Mikhail Gusarov <dottedmag@dottedmag.net>
|
||||
Mikhail Panchenko <m@mihasya.com>
|
||||
Miki Tebeka <miki.tebeka@gmail.com>
|
||||
Mikio Hara <mikioh.mikioh@gmail.com>
|
||||
Mikkel Krautz <mikkel@krautz.dk> <krautz@gmail.com>
|
||||
Miquel Sabaté Solà <mikisabate@gmail.com>
|
||||
Miroslav Genov <mgenov@gmail.com>
|
||||
Mohit Agarwal <mohit@sdf.org>
|
||||
Momchil Velikov <momchil.velikov@gmail.com>
|
||||
Monty Taylor <mordred@inaugust.com>
|
||||
Moriyoshi Koizumi <mozo@mozo.jp>
|
||||
Morten Siebuhr <sbhr@sbhr.dk>
|
||||
@@ -833,8 +738,6 @@ Nicholas Sullivan <nicholas.sullivan@gmail.com>
|
||||
Nicholas Waples <nwaples@gmail.com>
|
||||
Nick Cooper <nmvc@google.com>
|
||||
Nick Craig-Wood <nick@craig-wood.com> <nickcw@gmail.com>
|
||||
Nick Harper <nharper@google.com>
|
||||
Nick Leli <nicholasleli@gmail.com>
|
||||
Nick Patavalis <nick.patavalis@gmail.com>
|
||||
Nick Petroni <npetroni@cs.umd.edu>
|
||||
Nicolas Kaiser <nikai@nikai.net>
|
||||
@@ -843,14 +746,11 @@ Nicolas S. Dade <nic.dade@gmail.com>
|
||||
Niels Widger <niels.widger@gmail.com>
|
||||
Nigel Kerr <nigel.kerr@gmail.com>
|
||||
Nigel Tao <nigeltao@golang.org>
|
||||
Nik Nyby <nnyby@columbia.edu>
|
||||
Niko Dziemba <niko@dziemba.com>
|
||||
Nikolay Turpitko <nikolay@turpitko.com>
|
||||
Noah Campbell <noahcampbell@gmail.com>
|
||||
Nodir Turakulov <nodir@google.com>
|
||||
Norberto Lopes <nlopes.ml@gmail.com>
|
||||
Odin Ugedal <odin@ugedal.com>
|
||||
Oleg Vakheta <helginet@gmail.com>
|
||||
Oleku Konko <oleku.konko@gmail.com>
|
||||
Oling Cat <olingcat@gmail.com>
|
||||
Oliver Hookins <ohookins@gmail.com>
|
||||
@@ -863,12 +763,10 @@ Omar Jarjur <ojarjur@google.com>
|
||||
Padraig Kitterick <padraigkitterick@gmail.com>
|
||||
Paolo Giarrusso <p.giarrusso@gmail.com>
|
||||
Paolo Martini <mrtnpaolo@gmail.com>
|
||||
Parker Moore <parkrmoore@gmail.com>
|
||||
Pascal S. de Kloe <pascal@quies.net>
|
||||
Patrick Crosby <patrick@stathat.com>
|
||||
Patrick Gavlin <pgavlin@gmail.com>
|
||||
Patrick Higgins <patrick.allen.higgins@gmail.com>
|
||||
Patrick Lee <pattyshack101@gmail.com>
|
||||
Patrick Mézard <patrick@mezard.eu>
|
||||
Patrick Mylund Nielsen <patrick@patrickmn.com>
|
||||
Patrick Riley <pfr@google.com>
|
||||
@@ -919,26 +817,19 @@ Pierre Durand <pierredurand@gmail.com>
|
||||
Pierre Roullon <pierre.roullon@gmail.com>
|
||||
Pieter Droogendijk <pieter@binky.org.uk>
|
||||
Pietro Gagliardi <pietro10@mac.com>
|
||||
Prasanna Swaminathan <prasanna@mediamath.com>
|
||||
Prashant Varanasi <prashant@prashantv.com>
|
||||
Preetam Jinka <pj@preet.am>
|
||||
Quan Tran <qeed.quan@gmail.com>
|
||||
Quan Yong Zhai <qyzhai@gmail.com>
|
||||
Quentin Perez <qperez@ocs.online.net>
|
||||
Quentin Smith <quentin@golang.org>
|
||||
Quinn Slack <sqs@sourcegraph.com>
|
||||
Quoc-Viet Nguyen <afelion@gmail.com>
|
||||
Radu Berinde <radu@cockroachlabs.com>
|
||||
Rafal Jeczalik <rjeczalik@gmail.com>
|
||||
Rahul Chaudhry <rahulchaudhry@chromium.org>
|
||||
Raif S. Naffah <go@naffah-raif.name>
|
||||
Rajat Goel <rajat.goel2010@gmail.com>
|
||||
Ralph Corderoy <ralph@inputplus.co.uk>
|
||||
Ramesh Dharan <dharan@google.com>
|
||||
Raph Levien <raph@google.com>
|
||||
Raphael Geronimi <raphael.geronimi@gmail.com>
|
||||
Raul Silvera <rsilvera@google.com>
|
||||
Rebecca Stambler <rstambler@golang.org>
|
||||
Reinaldo de Souza Jr <juniorz@gmail.com>
|
||||
Rémy Oudompheng <oudomphe@phare.normalesup.org> <remyoudompheng@gmail.com>
|
||||
Rhys Hiltner <rhys@justin.tv>
|
||||
@@ -946,7 +837,6 @@ Ricardo Padilha <ricardospadilha@gmail.com>
|
||||
Richard Barnes <rlb@ipv.sx>
|
||||
Richard Crowley <r@rcrowley.org>
|
||||
Richard Eric Gavaletz <gavaletz@gmail.com>
|
||||
Richard Gibson <richard.gibson@gmail.com>
|
||||
Richard Miller <miller.research@gmail.com>
|
||||
Richard Musiol <mail@richard-musiol.de> <neelance@gmail.com>
|
||||
Rick Arnold <rickarnoldjr@gmail.com>
|
||||
@@ -979,14 +869,12 @@ Rowan Worth <sqweek@gmail.com>
|
||||
Rui Ueyama <ruiu@google.com>
|
||||
Russ Cox <rsc@golang.org>
|
||||
Russell Haering <russellhaering@gmail.com>
|
||||
Ryan Bagwell <ryanbagwell@outlook.com>
|
||||
Ryan Barrett <ryanb@google.com>
|
||||
Ryan Brown <ribrdb@google.com>
|
||||
Ryan Hitchman <hitchmanr@gmail.com>
|
||||
Ryan Lower <rpjlower@gmail.com>
|
||||
Ryan Seys <ryan@ryanseys.com>
|
||||
Ryan Slade <ryanslade@gmail.com>
|
||||
Ryuzo Yamamoto <ryuzo.yamamoto@gmail.com>
|
||||
S.Çağlar Onur <caglar@10ur.org>
|
||||
Sai Cheemalapati <saicheems@google.com>
|
||||
Salmān Aljammāz <s@0x65.net>
|
||||
@@ -996,10 +884,7 @@ Sam Thorogood <thorogood@google.com> <sam.thorogood@gmail.com>
|
||||
Sam Whited <sam@samwhited.com>
|
||||
Sameer Ajmani <sameer@golang.org> <ajmani@gmail.com>
|
||||
Sami Commerot <samic@google.com>
|
||||
Samuel Tan <samueltan@google.com>
|
||||
Samuele Pedroni <pedronis@lucediurna.net>
|
||||
Sanjay Menakuru <balasanjay@gmail.com>
|
||||
Sarah Adams <shadams@google.com>
|
||||
Sasha Lionheart <lionhearts@google.com>
|
||||
Sasha Sobol <sasha@scaledinference.com>
|
||||
Scott Barron <scott.barron@github.com>
|
||||
@@ -1012,7 +897,6 @@ Scott Van Woudenberg <scottvw@google.com>
|
||||
Sean Burford <sburford@google.com>
|
||||
Sean Dolphin <Sean.Dolphin@kpcompass.com>
|
||||
Sean Harger <sharger@google.com>
|
||||
Sean Rees <sean@erifax.org>
|
||||
Sebastien Binet <seb.binet@gmail.com>
|
||||
Sébastien Paolacci <sebastien.paolacci@gmail.com>
|
||||
Sergei Skorobogatov <skorobo@rambler.ru>
|
||||
@@ -1033,12 +917,9 @@ Shivakumar GN <shivakumar.gn@gmail.com>
|
||||
Shun Fan <sfan@google.com>
|
||||
Silvan Jegen <s.jegen@gmail.com>
|
||||
Simon Jefford <simon.jefford@gmail.com>
|
||||
Simon Rawet <simon@rawet.se>
|
||||
Simon Thulbourn <simon+github@thulbourn.com>
|
||||
Simon Whitehead <chemnova@gmail.com>
|
||||
Sina Siadat <siadat@gmail.com>
|
||||
Sokolov Yura <funny.falcon@gmail.com>
|
||||
Song Gao <song@gao.io>
|
||||
Spencer Nelson <s@spenczar.com>
|
||||
Spring Mc <heresy.mc@gmail.com>
|
||||
Srdjan Petrovic <spetrovic@google.com>
|
||||
@@ -1050,7 +931,6 @@ Stéphane Travostino <stephane.travostino@gmail.com>
|
||||
Stephen Ma <stephenm@golang.org>
|
||||
Stephen McQuay <stephen@mcquay.me>
|
||||
Stephen Weinberg <stephen@q5comm.com>
|
||||
Steve Francia <spf@golang.org>
|
||||
Steve McCoy <mccoyst@gmail.com>
|
||||
Steve Newman <snewman@google.com>
|
||||
Steve Phillips <elimisteve@gmail.com>
|
||||
@@ -1059,36 +939,27 @@ Steven Elliot Harris <seharris@gmail.com>
|
||||
Steven Hartland <steven.hartland@multiplay.co.uk>
|
||||
Sugu Sougoumarane <ssougou@gmail.com>
|
||||
Suharsh Sivakumar <suharshs@google.com>
|
||||
Suyash <dextrous93@gmail.com>
|
||||
Sven Almgren <sven@tras.se>
|
||||
Sven Blumenstein <svbl@google.com>
|
||||
Syohei YOSHIDA <syohex@gmail.com>
|
||||
Szabolcs Nagy <nsz@port70.net>
|
||||
Tad Glines <tad.glines@gmail.com>
|
||||
Taj Khattra <taj.khattra@gmail.com>
|
||||
Takashi Matsuo <tmatsuo@google.com>
|
||||
Takeshi YAMANASHI <9.nashi@gmail.com>
|
||||
Takuya Ueda <uedatakuya@gmail.com>
|
||||
Tal Shprecher <tshprecher@gmail.com>
|
||||
Tamir Duberstein <tamird@gmail.com>
|
||||
Tarmigan Casebolt <tarmigan@gmail.com>
|
||||
Taru Karttunen <taruti@taruti.net>
|
||||
Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
|
||||
Terrel Shumway <gopher@shumway.us>
|
||||
Tetsuo Kiso <tetsuokiso9@gmail.com>
|
||||
Than McIntosh <thanm@google.com>
|
||||
Thiago Fransosi Farina <thiago.farina@gmail.com> <tfarina@chromium.org>
|
||||
Thomas Alan Copeland <talan.copeland@gmail.com>
|
||||
Thomas de Zeeuw <thomasdezeeuw@gmail.com>
|
||||
Thomas Desrosiers <thomasdesr@gmail.com>
|
||||
Thomas Habets <habets@google.com>
|
||||
Thomas Kappler <tkappler@gmail.com>
|
||||
Thorben Krueger <thorben.krueger@gmail.com>
|
||||
Thordur Bjornsson <thorduri@secnorth.net>
|
||||
Tilman Dilo <tilman.dilo@gmail.com>
|
||||
Tim Cooijmans <timcooijmans@gmail.com>
|
||||
Tim Ebringer <tim.ebringer@gmail.com>
|
||||
Tim Henderson <tim.tadh@gmail.com>
|
||||
Tim Hockin <thockin@google.com>
|
||||
Tim Swast <swast@google.com>
|
||||
Timo Savola <timo.savola@gmail.com>
|
||||
@@ -1103,20 +974,15 @@ Tom Bergan <tombergan@google.com>
|
||||
Tom Heng <zhm20070928@gmail.com>
|
||||
Tom Linford <tomlinford@gmail.com>
|
||||
Tom Szymanski <tgs@google.com>
|
||||
Tom Wilkie <tom@weave.works>
|
||||
Tommy Schaefer <tommy.schaefer@teecom.com>
|
||||
Tor Andersson <tor.andersson@gmail.com>
|
||||
Tormod Erevik Lea <tormodlea@gmail.com>
|
||||
Totoro W <tw19881113@gmail.com>
|
||||
Travis Cline <travis.cline@gmail.com>
|
||||
Trevor Strohman <trevor.strohman@gmail.com>
|
||||
Trey Lawrence <lawrence.trey@gmail.com>
|
||||
Trey Tacon <ttacon@gmail.com>
|
||||
Tristan Amini <tamini01@ca.ibm.com>
|
||||
Tristan Colgate <tcolgate@gmail.com>
|
||||
Tristan Ooohry <ooohry@gmail.com>
|
||||
Tudor Golubenco <tudor.g@gmail.com>
|
||||
Tuo Shan <sturbo89@gmail.com> <shantuo@google.com>
|
||||
Tyler Bunnell <tylerbunnell@gmail.com>
|
||||
Tyler Treat <ttreat31@gmail.com>
|
||||
Tzu-Jung Lee <roylee17@currant.com>
|
||||
@@ -1128,21 +994,15 @@ Uttam C Pawar <uttam.c.pawar@intel.com>
|
||||
Vadim Grek <vadimprog@gmail.com>
|
||||
Vadim Vygonets <unixdj@gmail.com>
|
||||
Vega Garcia Luis Alfonso <vegacom@gmail.com>
|
||||
Victor Chudnovsky <vchudnov@google.com>
|
||||
Vincent Ambo <tazjin@googlemail.com>
|
||||
Vincent Batts <vbatts@hashbangbash.com> <vbatts@gmail.com>
|
||||
Vincent Vanackere <vincent.vanackere@gmail.com>
|
||||
Vinu Rajashekhar <vinutheraj@gmail.com>
|
||||
Vish Subramanian <vish@google.com>
|
||||
Vishvananda Ishaya <vishvananda@gmail.com>
|
||||
Vitor De Mario <vitordemario@gmail.com>
|
||||
Vlad Krasnov <vlad@cloudflare.com>
|
||||
Vladimir Mihailenco <vladimir.webdev@gmail.com>
|
||||
Vladimir Nikishenko <vova616@gmail.com>
|
||||
Vladimir Stefanovic <vladimir.stefanovic@imgtec.com>
|
||||
Volker Dobler <dr.volker.dobler@gmail.com>
|
||||
Volodymyr Paprotski <vpaprots@ca.ibm.com>
|
||||
Walter Poupore <wpoupore@google.com>
|
||||
Wedson Almeida Filho <wedsonaf@google.com>
|
||||
Wei Guangjing <vcc.163@gmail.com>
|
||||
Will Chan <willchan@google.com>
|
||||
@@ -1155,7 +1015,6 @@ Wisdom Omuya <deafgoat@gmail.com>
|
||||
Xia Bin <snyh@snyh.org>
|
||||
Xing Xing <mikespook@gmail.com>
|
||||
Xudong Zhang <felixmelon@gmail.com>
|
||||
Xuyang Kang <xuyangkang@gmail.com>
|
||||
Yan Zou <yzou@google.com>
|
||||
Yann Kerhervé <yann.kerherve@gmail.com>
|
||||
Yao Zhang <lunaria21@gmail.com>
|
||||
@@ -1165,7 +1024,6 @@ Yesudeep Mangalapilly <yesudeep@google.com>
|
||||
Yissakhar Z. Beck <yissakhar.beck@gmail.com>
|
||||
Yo-An Lin <yoanlin93@gmail.com>
|
||||
Yongjian Xu <i3dmaster@gmail.com>
|
||||
Yorman Arias <cixtords@gmail.com>
|
||||
Yoshiyuki Kanno <nekotaroh@gmail.com> <yoshiyuki.kanno@stoic.co.jp>
|
||||
Yu Heng Zhang <annita.zhang@cn.ibm.com>
|
||||
Yu Xuan Zhang <zyxsh@cn.ibm.com>
|
||||
@@ -1174,10 +1032,7 @@ Yusuke Kagiwada <block.rxckin.beats@gmail.com>
|
||||
Yuusei Kuwana <kuwana@kumama.org>
|
||||
Yuval Pavel Zholkover <paulzhol@gmail.com>
|
||||
Yves Junqueira <yvesj@google.com> <yves.junqueira@gmail.com>
|
||||
Zac Bergquist <zbergquist99@gmail.com>
|
||||
Zev Goldstein <zev.goldstein@gmail.com>
|
||||
Zhongwei Yao <zhongwei.yao@arm.com>
|
||||
Ziad Hatahet <hatahet@gmail.com>
|
||||
Zorion Arrizabalaga <zorionk@gmail.com>
|
||||
Фахриддин Балтаев <faxriddinjon@gmail.com>
|
||||
申习之 <bronze1man@gmail.com>
|
||||
|
||||
198
api/except.txt
198
api/except.txt
@@ -1,107 +1,23 @@
|
||||
pkg encoding/json, method (*RawMessage) MarshalJSON() ([]uint8, error)
|
||||
pkg net, func ListenUnixgram(string, *UnixAddr) (*UDPConn, error)
|
||||
pkg syscall (darwin-386), func Fchflags(string, int) error
|
||||
pkg syscall (darwin-386-cgo), func Fchflags(string, int) error
|
||||
pkg syscall (darwin-amd64), func Fchflags(string, int) error
|
||||
pkg syscall (darwin-amd64-cgo), func Fchflags(string, int) error
|
||||
pkg syscall (freebsd-386), func Fchflags(string, int) error
|
||||
pkg syscall (freebsd-amd64), func Fchflags(string, int) error
|
||||
pkg syscall (freebsd-arm), func Fchflags(string, int) error
|
||||
pkg syscall (freebsd-arm-cgo), func Fchflags(string, int) error
|
||||
pkg syscall (netbsd-arm), func Fchflags(string, int) error
|
||||
pkg syscall (netbsd-arm-cgo), func Fchflags(string, int) error
|
||||
pkg testing, func RegisterCover(Cover)
|
||||
pkg text/template/parse, type DotNode bool
|
||||
pkg text/template/parse, type Node interface { Copy, String, Type }
|
||||
pkg os (linux-arm), const O_SYNC = 4096
|
||||
pkg os (linux-arm-cgo), const O_SYNC = 4096
|
||||
pkg syscall (darwin-386), const ImplementsGetwd = false
|
||||
pkg syscall (darwin-386), func Fchflags(string, int) error
|
||||
pkg syscall (darwin-386-cgo), const ImplementsGetwd = false
|
||||
pkg syscall (darwin-386-cgo), func Fchflags(string, int) error
|
||||
pkg syscall (darwin-amd64), const ImplementsGetwd = false
|
||||
pkg syscall (darwin-amd64), func Fchflags(string, int) error
|
||||
pkg syscall (darwin-amd64-cgo), const ImplementsGetwd = false
|
||||
pkg syscall (darwin-amd64-cgo), func Fchflags(string, int) error
|
||||
pkg syscall (freebsd-386), const AF_MAX = 38
|
||||
pkg syscall (freebsd-386), const DLT_MATCHING_MAX = 242
|
||||
pkg syscall (freebsd-386), const ELAST = 94
|
||||
pkg syscall (freebsd-386), const O_CLOEXEC = 0
|
||||
pkg syscall (freebsd-386), func Fchflags(string, int) error
|
||||
pkg syscall (freebsd-386-cgo), const AF_MAX = 38
|
||||
pkg syscall (freebsd-386-cgo), const DLT_MATCHING_MAX = 242
|
||||
pkg syscall (freebsd-386-cgo), const ELAST = 94
|
||||
pkg syscall (freebsd-386-cgo), const O_CLOEXEC = 0
|
||||
pkg syscall (freebsd-amd64), const AF_MAX = 38
|
||||
pkg syscall (freebsd-amd64), const DLT_MATCHING_MAX = 242
|
||||
pkg syscall (freebsd-amd64), const ELAST = 94
|
||||
pkg syscall (freebsd-amd64), const O_CLOEXEC = 0
|
||||
pkg syscall (freebsd-amd64), func Fchflags(string, int) error
|
||||
pkg syscall (freebsd-amd64-cgo), const AF_MAX = 38
|
||||
pkg syscall (freebsd-amd64-cgo), const DLT_MATCHING_MAX = 242
|
||||
pkg syscall (freebsd-amd64-cgo), const ELAST = 94
|
||||
pkg syscall (freebsd-amd64-cgo), const O_CLOEXEC = 0
|
||||
pkg syscall (freebsd-arm), const AF_MAX = 38
|
||||
pkg syscall (freebsd-arm), const BIOCGRTIMEOUT = 1074545262
|
||||
pkg syscall (freebsd-arm), const BIOCSRTIMEOUT = 2148287085
|
||||
pkg syscall (freebsd-arm), const ELAST = 94
|
||||
pkg syscall (freebsd-arm), const O_CLOEXEC = 0
|
||||
pkg syscall (freebsd-arm), const SIOCAIFADDR = 2151967019
|
||||
pkg syscall (freebsd-arm), const SIOCGIFSTATUS = 3274991931
|
||||
pkg syscall (freebsd-arm), const SIOCSIFPHYADDR = 2151967046
|
||||
pkg syscall (freebsd-arm), const SYS_CAP_FCNTLS_GET = 537
|
||||
pkg syscall (freebsd-arm), const SYS_CAP_FCNTLS_GET ideal-int
|
||||
pkg syscall (freebsd-arm), const SYS_CAP_FCNTLS_LIMIT = 536
|
||||
pkg syscall (freebsd-arm), const SYS_CAP_FCNTLS_LIMIT ideal-int
|
||||
pkg syscall (freebsd-arm), const SYS_CAP_IOCTLS_GET = 535
|
||||
pkg syscall (freebsd-arm), const SYS_CAP_IOCTLS_GET ideal-int
|
||||
pkg syscall (freebsd-arm), const SYS_CAP_IOCTLS_LIMIT = 534
|
||||
pkg syscall (freebsd-arm), const SYS_CAP_IOCTLS_LIMIT ideal-int
|
||||
pkg syscall (freebsd-arm), const SYS_CAP_RIGHTS_GET = 515
|
||||
pkg syscall (freebsd-arm), const SYS_CAP_RIGHTS_GET ideal-int
|
||||
pkg syscall (freebsd-arm), const SYS_CAP_RIGHTS_LIMIT = 533
|
||||
pkg syscall (freebsd-arm), const SYS_CAP_RIGHTS_LIMIT ideal-int
|
||||
pkg syscall (freebsd-arm), const SizeofBpfHdr = 24
|
||||
pkg syscall (freebsd-arm), const SizeofIfData = 88
|
||||
pkg syscall (freebsd-arm), const SizeofIfMsghdr = 104
|
||||
pkg syscall (freebsd-arm), const SizeofSockaddrDatalink = 56
|
||||
pkg syscall (freebsd-arm), const SizeofSockaddrUnix = 108
|
||||
pkg syscall (freebsd-arm), const TIOCTIMESTAMP = 1074558041
|
||||
pkg syscall (freebsd-arm), func Fchflags(string, int) error
|
||||
pkg syscall (freebsd-arm), type BpfHdr struct, Pad_cgo_0 [2]uint8
|
||||
pkg syscall (freebsd-arm), type RawSockaddrDatalink struct, Pad_cgo_0 [2]uint8
|
||||
pkg syscall (freebsd-arm), type RawSockaddrUnix struct, Pad_cgo_0 [2]uint8
|
||||
pkg syscall (freebsd-arm), type Stat_t struct, Pad_cgo_0 [4]uint8
|
||||
pkg syscall (freebsd-arm-cgo), const AF_MAX = 38
|
||||
pkg syscall (freebsd-arm-cgo), const BIOCGRTIMEOUT = 1074545262
|
||||
pkg syscall (freebsd-arm-cgo), const BIOCSRTIMEOUT = 2148287085
|
||||
pkg syscall (freebsd-arm-cgo), const ELAST = 94
|
||||
pkg syscall (freebsd-arm-cgo), const O_CLOEXEC = 0
|
||||
pkg syscall (freebsd-arm-cgo), const SIOCAIFADDR = 2151967019
|
||||
pkg syscall (freebsd-arm-cgo), const SIOCGIFSTATUS = 3274991931
|
||||
pkg syscall (freebsd-arm-cgo), const SIOCSIFPHYADDR = 2151967046
|
||||
pkg syscall (freebsd-arm-cgo), const SYS_CAP_FCNTLS_GET = 537
|
||||
pkg syscall (freebsd-arm-cgo), const SYS_CAP_FCNTLS_GET ideal-int
|
||||
pkg syscall (freebsd-arm-cgo), const SYS_CAP_FCNTLS_LIMIT = 536
|
||||
pkg syscall (freebsd-arm-cgo), const SYS_CAP_FCNTLS_LIMIT ideal-int
|
||||
pkg syscall (freebsd-arm-cgo), const SYS_CAP_IOCTLS_GET = 535
|
||||
pkg syscall (freebsd-arm-cgo), const SYS_CAP_IOCTLS_GET ideal-int
|
||||
pkg syscall (freebsd-arm-cgo), const SYS_CAP_IOCTLS_LIMIT = 534
|
||||
pkg syscall (freebsd-arm-cgo), const SYS_CAP_IOCTLS_LIMIT ideal-int
|
||||
pkg syscall (freebsd-arm-cgo), const SYS_CAP_RIGHTS_GET = 515
|
||||
pkg syscall (freebsd-arm-cgo), const SYS_CAP_RIGHTS_GET ideal-int
|
||||
pkg syscall (freebsd-arm-cgo), const SYS_CAP_RIGHTS_LIMIT = 533
|
||||
pkg syscall (freebsd-arm-cgo), const SYS_CAP_RIGHTS_LIMIT ideal-int
|
||||
pkg syscall (freebsd-arm-cgo), const SizeofBpfHdr = 24
|
||||
pkg syscall (freebsd-arm-cgo), const SizeofIfData = 88
|
||||
pkg syscall (freebsd-arm-cgo), const SizeofIfMsghdr = 104
|
||||
pkg syscall (freebsd-arm-cgo), const SizeofSockaddrDatalink = 56
|
||||
pkg syscall (freebsd-arm-cgo), const SizeofSockaddrUnix = 108
|
||||
pkg syscall (freebsd-arm-cgo), const TIOCTIMESTAMP = 1074558041
|
||||
pkg syscall (freebsd-arm-cgo), func Fchflags(string, int) error
|
||||
pkg syscall (freebsd-arm-cgo), type BpfHdr struct, Pad_cgo_0 [2]uint8
|
||||
pkg syscall (freebsd-arm-cgo), type RawSockaddrDatalink struct, Pad_cgo_0 [2]uint8
|
||||
pkg syscall (freebsd-arm-cgo), type RawSockaddrUnix struct, Pad_cgo_0 [2]uint8
|
||||
pkg syscall (freebsd-arm-cgo), type Stat_t struct, Pad_cgo_0 [4]uint8
|
||||
pkg syscall (linux-386), type Cmsghdr struct, X__cmsg_data [0]uint8
|
||||
pkg syscall (linux-386-cgo), type Cmsghdr struct, X__cmsg_data [0]uint8
|
||||
pkg syscall (linux-amd64), type Cmsghdr struct, X__cmsg_data [0]uint8
|
||||
pkg syscall (linux-amd64-cgo), type Cmsghdr struct, X__cmsg_data [0]uint8
|
||||
pkg syscall (linux-arm), type Cmsghdr struct, X__cmsg_data [0]uint8
|
||||
pkg syscall (linux-arm-cgo), type Cmsghdr struct, X__cmsg_data [0]uint8
|
||||
pkg syscall (netbsd-arm), const SizeofIfData = 132
|
||||
pkg syscall (netbsd-arm), func Fchflags(string, int) error
|
||||
pkg syscall (netbsd-arm), type IfMsghdr struct, Pad_cgo_1 [4]uint8
|
||||
pkg syscall (netbsd-arm-cgo), const SizeofIfData = 132
|
||||
pkg syscall (netbsd-arm-cgo), func Fchflags(string, int) error
|
||||
pkg syscall (netbsd-arm-cgo), type IfMsghdr struct, Pad_cgo_1 [4]uint8
|
||||
pkg syscall (openbsd-386), const BIOCGRTIMEOUT = 1074283118
|
||||
pkg syscall (openbsd-386), const BIOCSRTIMEOUT = 2148024941
|
||||
pkg syscall (openbsd-386), const RTF_FMASK = 63496
|
||||
@@ -330,15 +246,87 @@ pkg syscall (openbsd-amd64-cgo), type Statfs_t struct, F_spare [3]uint32
|
||||
pkg syscall (openbsd-amd64-cgo), type Statfs_t struct, Pad_cgo_1 [4]uint8
|
||||
pkg syscall (openbsd-amd64-cgo), type Timespec struct, Pad_cgo_0 [4]uint8
|
||||
pkg syscall (openbsd-amd64-cgo), type Timespec struct, Sec int32
|
||||
pkg testing, func RegisterCover(Cover)
|
||||
pkg testing, func MainStart(func(string, string) (bool, error), []InternalTest, []InternalBenchmark, []InternalExample) *M
|
||||
pkg text/template/parse, type DotNode bool
|
||||
pkg text/template/parse, type Node interface { Copy, String, Type }
|
||||
pkg unicode, const Version = "6.2.0"
|
||||
pkg syscall (freebsd-386), const AF_MAX = 38
|
||||
pkg syscall (freebsd-386), const DLT_MATCHING_MAX = 242
|
||||
pkg syscall (freebsd-386), const ELAST = 94
|
||||
pkg syscall (freebsd-386), const O_CLOEXEC = 0
|
||||
pkg syscall (freebsd-386-cgo), const AF_MAX = 38
|
||||
pkg syscall (freebsd-386-cgo), const DLT_MATCHING_MAX = 242
|
||||
pkg syscall (freebsd-386-cgo), const ELAST = 94
|
||||
pkg syscall (freebsd-386-cgo), const O_CLOEXEC = 0
|
||||
pkg syscall (freebsd-amd64), const AF_MAX = 38
|
||||
pkg syscall (freebsd-amd64), const DLT_MATCHING_MAX = 242
|
||||
pkg syscall (freebsd-amd64), const ELAST = 94
|
||||
pkg syscall (freebsd-amd64), const O_CLOEXEC = 0
|
||||
pkg syscall (freebsd-amd64-cgo), const AF_MAX = 38
|
||||
pkg syscall (freebsd-amd64-cgo), const DLT_MATCHING_MAX = 242
|
||||
pkg syscall (freebsd-amd64-cgo), const ELAST = 94
|
||||
pkg syscall (freebsd-amd64-cgo), const O_CLOEXEC = 0
|
||||
pkg syscall (freebsd-arm), const AF_MAX = 38
|
||||
pkg syscall (freebsd-arm), const BIOCGRTIMEOUT = 1074545262
|
||||
pkg syscall (freebsd-arm), const BIOCSRTIMEOUT = 2148287085
|
||||
pkg syscall (freebsd-arm), const ELAST = 94
|
||||
pkg syscall (freebsd-arm), const O_CLOEXEC = 0
|
||||
pkg syscall (freebsd-arm), const SIOCAIFADDR = 2151967019
|
||||
pkg syscall (freebsd-arm), const SIOCGIFSTATUS = 3274991931
|
||||
pkg syscall (freebsd-arm), const SIOCSIFPHYADDR = 2151967046
|
||||
pkg syscall (freebsd-arm), const SYS_CAP_FCNTLS_GET = 537
|
||||
pkg syscall (freebsd-arm), const SYS_CAP_FCNTLS_GET ideal-int
|
||||
pkg syscall (freebsd-arm), const SYS_CAP_FCNTLS_LIMIT = 536
|
||||
pkg syscall (freebsd-arm), const SYS_CAP_FCNTLS_LIMIT ideal-int
|
||||
pkg syscall (freebsd-arm), const SYS_CAP_IOCTLS_GET = 535
|
||||
pkg syscall (freebsd-arm), const SYS_CAP_IOCTLS_GET ideal-int
|
||||
pkg syscall (freebsd-arm), const SYS_CAP_IOCTLS_LIMIT = 534
|
||||
pkg syscall (freebsd-arm), const SYS_CAP_IOCTLS_LIMIT ideal-int
|
||||
pkg syscall (freebsd-arm), const SYS_CAP_RIGHTS_GET = 515
|
||||
pkg syscall (freebsd-arm), const SYS_CAP_RIGHTS_GET ideal-int
|
||||
pkg syscall (freebsd-arm), const SYS_CAP_RIGHTS_LIMIT = 533
|
||||
pkg syscall (freebsd-arm), const SYS_CAP_RIGHTS_LIMIT ideal-int
|
||||
pkg syscall (freebsd-arm), const SizeofBpfHdr = 24
|
||||
pkg syscall (freebsd-arm), const SizeofIfData = 88
|
||||
pkg syscall (freebsd-arm), const SizeofIfMsghdr = 104
|
||||
pkg syscall (freebsd-arm), const SizeofSockaddrDatalink = 56
|
||||
pkg syscall (freebsd-arm), const SizeofSockaddrUnix = 108
|
||||
pkg syscall (freebsd-arm), const TIOCTIMESTAMP = 1074558041
|
||||
pkg syscall (freebsd-arm), type BpfHdr struct, Pad_cgo_0 [2]uint8
|
||||
pkg syscall (freebsd-arm), type RawSockaddrDatalink struct, Pad_cgo_0 [2]uint8
|
||||
pkg syscall (freebsd-arm), type RawSockaddrUnix struct, Pad_cgo_0 [2]uint8
|
||||
pkg syscall (freebsd-arm), type Stat_t struct, Pad_cgo_0 [4]uint8
|
||||
pkg syscall (freebsd-arm-cgo), const AF_MAX = 38
|
||||
pkg syscall (freebsd-arm-cgo), const BIOCGRTIMEOUT = 1074545262
|
||||
pkg syscall (freebsd-arm-cgo), const BIOCSRTIMEOUT = 2148287085
|
||||
pkg syscall (freebsd-arm-cgo), const ELAST = 94
|
||||
pkg syscall (freebsd-arm-cgo), const O_CLOEXEC = 0
|
||||
pkg syscall (freebsd-arm-cgo), const SIOCAIFADDR = 2151967019
|
||||
pkg syscall (freebsd-arm-cgo), const SIOCGIFSTATUS = 3274991931
|
||||
pkg syscall (freebsd-arm-cgo), const SIOCSIFPHYADDR = 2151967046
|
||||
pkg syscall (freebsd-arm-cgo), const SYS_CAP_FCNTLS_GET = 537
|
||||
pkg syscall (freebsd-arm-cgo), const SYS_CAP_FCNTLS_GET ideal-int
|
||||
pkg syscall (freebsd-arm-cgo), const SYS_CAP_FCNTLS_LIMIT = 536
|
||||
pkg syscall (freebsd-arm-cgo), const SYS_CAP_FCNTLS_LIMIT ideal-int
|
||||
pkg syscall (freebsd-arm-cgo), const SYS_CAP_IOCTLS_GET = 535
|
||||
pkg syscall (freebsd-arm-cgo), const SYS_CAP_IOCTLS_GET ideal-int
|
||||
pkg syscall (freebsd-arm-cgo), const SYS_CAP_IOCTLS_LIMIT = 534
|
||||
pkg syscall (freebsd-arm-cgo), const SYS_CAP_IOCTLS_LIMIT ideal-int
|
||||
pkg syscall (freebsd-arm-cgo), const SYS_CAP_RIGHTS_GET = 515
|
||||
pkg syscall (freebsd-arm-cgo), const SYS_CAP_RIGHTS_GET ideal-int
|
||||
pkg syscall (freebsd-arm-cgo), const SYS_CAP_RIGHTS_LIMIT = 533
|
||||
pkg syscall (freebsd-arm-cgo), const SYS_CAP_RIGHTS_LIMIT ideal-int
|
||||
pkg syscall (freebsd-arm-cgo), const SizeofBpfHdr = 24
|
||||
pkg syscall (freebsd-arm-cgo), const SizeofIfData = 88
|
||||
pkg syscall (freebsd-arm-cgo), const SizeofIfMsghdr = 104
|
||||
pkg syscall (freebsd-arm-cgo), const SizeofSockaddrDatalink = 56
|
||||
pkg syscall (freebsd-arm-cgo), const SizeofSockaddrUnix = 108
|
||||
pkg syscall (freebsd-arm-cgo), const TIOCTIMESTAMP = 1074558041
|
||||
pkg syscall (freebsd-arm-cgo), type BpfHdr struct, Pad_cgo_0 [2]uint8
|
||||
pkg syscall (freebsd-arm-cgo), type RawSockaddrDatalink struct, Pad_cgo_0 [2]uint8
|
||||
pkg syscall (freebsd-arm-cgo), type RawSockaddrUnix struct, Pad_cgo_0 [2]uint8
|
||||
pkg syscall (freebsd-arm-cgo), type Stat_t struct, Pad_cgo_0 [4]uint8
|
||||
pkg syscall (netbsd-arm), const SizeofIfData = 132
|
||||
pkg syscall (netbsd-arm), type IfMsghdr struct, Pad_cgo_1 [4]uint8
|
||||
pkg syscall (netbsd-arm-cgo), const SizeofIfData = 132
|
||||
pkg syscall (netbsd-arm-cgo), type IfMsghdr struct, Pad_cgo_1 [4]uint8
|
||||
pkg unicode, const Version = "6.3.0"
|
||||
pkg unicode, const Version = "7.0.0"
|
||||
pkg unicode, const Version = "8.0.0"
|
||||
pkg syscall (openbsd-386), const SYS_KILL = 37
|
||||
pkg syscall (openbsd-386-cgo), const SYS_KILL = 37
|
||||
pkg syscall (openbsd-amd64), const SYS_KILL = 37
|
||||
pkg syscall (openbsd-amd64-cgo), const SYS_KILL = 37
|
||||
|
||||
261
api/go1.8.txt
261
api/go1.8.txt
@@ -1,261 +0,0 @@
|
||||
pkg compress/gzip, const HuffmanOnly = -2
|
||||
pkg compress/gzip, const HuffmanOnly ideal-int
|
||||
pkg compress/zlib, const HuffmanOnly = -2
|
||||
pkg compress/zlib, const HuffmanOnly ideal-int
|
||||
pkg crypto/tls, const ECDSAWithP256AndSHA256 = 1027
|
||||
pkg crypto/tls, const ECDSAWithP256AndSHA256 SignatureScheme
|
||||
pkg crypto/tls, const ECDSAWithP384AndSHA384 = 1283
|
||||
pkg crypto/tls, const ECDSAWithP384AndSHA384 SignatureScheme
|
||||
pkg crypto/tls, const ECDSAWithP521AndSHA512 = 1539
|
||||
pkg crypto/tls, const ECDSAWithP521AndSHA512 SignatureScheme
|
||||
pkg crypto/tls, const PKCS1WithSHA1 = 513
|
||||
pkg crypto/tls, const PKCS1WithSHA1 SignatureScheme
|
||||
pkg crypto/tls, const PKCS1WithSHA256 = 1025
|
||||
pkg crypto/tls, const PKCS1WithSHA256 SignatureScheme
|
||||
pkg crypto/tls, const PKCS1WithSHA384 = 1281
|
||||
pkg crypto/tls, const PKCS1WithSHA384 SignatureScheme
|
||||
pkg crypto/tls, const PKCS1WithSHA512 = 1537
|
||||
pkg crypto/tls, const PKCS1WithSHA512 SignatureScheme
|
||||
pkg crypto/tls, const PSSWithSHA256 = 2052
|
||||
pkg crypto/tls, const PSSWithSHA256 SignatureScheme
|
||||
pkg crypto/tls, const PSSWithSHA384 = 2053
|
||||
pkg crypto/tls, const PSSWithSHA384 SignatureScheme
|
||||
pkg crypto/tls, const PSSWithSHA512 = 2054
|
||||
pkg crypto/tls, const PSSWithSHA512 SignatureScheme
|
||||
pkg crypto/tls, const TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = 49187
|
||||
pkg crypto/tls, const TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 uint16
|
||||
pkg crypto/tls, const TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 = 52393
|
||||
pkg crypto/tls, const TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 uint16
|
||||
pkg crypto/tls, const TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = 49191
|
||||
pkg crypto/tls, const TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 uint16
|
||||
pkg crypto/tls, const TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 = 52392
|
||||
pkg crypto/tls, const TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 uint16
|
||||
pkg crypto/tls, const TLS_RSA_WITH_AES_128_CBC_SHA256 = 60
|
||||
pkg crypto/tls, const TLS_RSA_WITH_AES_128_CBC_SHA256 uint16
|
||||
pkg crypto/tls, const X25519 = 29
|
||||
pkg crypto/tls, const X25519 CurveID
|
||||
pkg crypto/tls, method (*Config) Clone() *Config
|
||||
pkg crypto/tls, method (*Conn) CloseWrite() error
|
||||
pkg crypto/tls, type CertificateRequestInfo struct
|
||||
pkg crypto/tls, type CertificateRequestInfo struct, AcceptableCAs [][]uint8
|
||||
pkg crypto/tls, type CertificateRequestInfo struct, SignatureSchemes []SignatureScheme
|
||||
pkg crypto/tls, type ClientHelloInfo struct, Conn net.Conn
|
||||
pkg crypto/tls, type ClientHelloInfo struct, SignatureSchemes []SignatureScheme
|
||||
pkg crypto/tls, type ClientHelloInfo struct, SupportedProtos []string
|
||||
pkg crypto/tls, type ClientHelloInfo struct, SupportedVersions []uint16
|
||||
pkg crypto/tls, type Config struct, GetClientCertificate func(*CertificateRequestInfo) (*Certificate, error)
|
||||
pkg crypto/tls, type Config struct, GetConfigForClient func(*ClientHelloInfo) (*Config, error)
|
||||
pkg crypto/tls, type Config struct, KeyLogWriter io.Writer
|
||||
pkg crypto/tls, type Config struct, VerifyPeerCertificate func([][]uint8, [][]*x509.Certificate) error
|
||||
pkg crypto/tls, type SignatureScheme uint16
|
||||
pkg crypto/x509, const NameMismatch = 5
|
||||
pkg crypto/x509, const NameMismatch InvalidReason
|
||||
pkg crypto/x509, const SHA256WithRSAPSS = 13
|
||||
pkg crypto/x509, const SHA256WithRSAPSS SignatureAlgorithm
|
||||
pkg crypto/x509, const SHA384WithRSAPSS = 14
|
||||
pkg crypto/x509, const SHA384WithRSAPSS SignatureAlgorithm
|
||||
pkg crypto/x509, const SHA512WithRSAPSS = 15
|
||||
pkg crypto/x509, const SHA512WithRSAPSS SignatureAlgorithm
|
||||
pkg crypto/x509, type UnknownAuthorityError struct, Cert *Certificate
|
||||
pkg database/sql, const LevelDefault = 0
|
||||
pkg database/sql, const LevelDefault IsolationLevel
|
||||
pkg database/sql, const LevelLinearizable = 7
|
||||
pkg database/sql, const LevelLinearizable IsolationLevel
|
||||
pkg database/sql, const LevelReadCommitted = 2
|
||||
pkg database/sql, const LevelReadCommitted IsolationLevel
|
||||
pkg database/sql, const LevelReadUncommitted = 1
|
||||
pkg database/sql, const LevelReadUncommitted IsolationLevel
|
||||
pkg database/sql, const LevelRepeatableRead = 4
|
||||
pkg database/sql, const LevelRepeatableRead IsolationLevel
|
||||
pkg database/sql, const LevelSerializable = 6
|
||||
pkg database/sql, const LevelSerializable IsolationLevel
|
||||
pkg database/sql, const LevelSnapshot = 5
|
||||
pkg database/sql, const LevelSnapshot IsolationLevel
|
||||
pkg database/sql, const LevelWriteCommitted = 3
|
||||
pkg database/sql, const LevelWriteCommitted IsolationLevel
|
||||
pkg database/sql/driver, type ConnBeginTx interface { BeginTx }
|
||||
pkg database/sql/driver, type ConnBeginTx interface, BeginTx(context.Context, TxOptions) (Tx, error)
|
||||
pkg database/sql/driver, type ConnPrepareContext interface { PrepareContext }
|
||||
pkg database/sql/driver, type ConnPrepareContext interface, PrepareContext(context.Context, string) (Stmt, error)
|
||||
pkg database/sql/driver, type ExecerContext interface { ExecContext }
|
||||
pkg database/sql/driver, type ExecerContext interface, ExecContext(context.Context, string, []NamedValue) (Result, error)
|
||||
pkg database/sql/driver, type IsolationLevel int
|
||||
pkg database/sql/driver, type NamedValue struct
|
||||
pkg database/sql/driver, type NamedValue struct, Name string
|
||||
pkg database/sql/driver, type NamedValue struct, Ordinal int
|
||||
pkg database/sql/driver, type NamedValue struct, Value Value
|
||||
pkg database/sql/driver, type Pinger interface { Ping }
|
||||
pkg database/sql/driver, type Pinger interface, Ping(context.Context) error
|
||||
pkg database/sql/driver, type QueryerContext interface { QueryContext }
|
||||
pkg database/sql/driver, type QueryerContext interface, QueryContext(context.Context, string, []NamedValue) (Rows, error)
|
||||
pkg database/sql/driver, type RowsColumnTypeDatabaseTypeName interface { Close, ColumnTypeDatabaseTypeName, Columns, Next }
|
||||
pkg database/sql/driver, type RowsColumnTypeDatabaseTypeName interface, Close() error
|
||||
pkg database/sql/driver, type RowsColumnTypeDatabaseTypeName interface, Columns() []string
|
||||
pkg database/sql/driver, type RowsColumnTypeDatabaseTypeName interface, ColumnTypeDatabaseTypeName(int) string
|
||||
pkg database/sql/driver, type RowsColumnTypeDatabaseTypeName interface, Next([]Value) error
|
||||
pkg database/sql/driver, type RowsColumnTypeLength interface { Close, ColumnTypeLength, Columns, Next }
|
||||
pkg database/sql/driver, type RowsColumnTypeLength interface, Close() error
|
||||
pkg database/sql/driver, type RowsColumnTypeLength interface, Columns() []string
|
||||
pkg database/sql/driver, type RowsColumnTypeLength interface, ColumnTypeLength(int) (int64, bool)
|
||||
pkg database/sql/driver, type RowsColumnTypeLength interface, Next([]Value) error
|
||||
pkg database/sql/driver, type RowsColumnTypeNullable interface { Close, ColumnTypeNullable, Columns, Next }
|
||||
pkg database/sql/driver, type RowsColumnTypeNullable interface, Close() error
|
||||
pkg database/sql/driver, type RowsColumnTypeNullable interface, Columns() []string
|
||||
pkg database/sql/driver, type RowsColumnTypeNullable interface, ColumnTypeNullable(int) (bool, bool)
|
||||
pkg database/sql/driver, type RowsColumnTypeNullable interface, Next([]Value) error
|
||||
pkg database/sql/driver, type RowsColumnTypePrecisionScale interface { Close, ColumnTypePrecisionScale, Columns, Next }
|
||||
pkg database/sql/driver, type RowsColumnTypePrecisionScale interface, Close() error
|
||||
pkg database/sql/driver, type RowsColumnTypePrecisionScale interface, Columns() []string
|
||||
pkg database/sql/driver, type RowsColumnTypePrecisionScale interface, ColumnTypePrecisionScale(int) (int64, int64, bool)
|
||||
pkg database/sql/driver, type RowsColumnTypePrecisionScale interface, Next([]Value) error
|
||||
pkg database/sql/driver, type RowsColumnTypeScanType interface { Close, ColumnTypeScanType, Columns, Next }
|
||||
pkg database/sql/driver, type RowsColumnTypeScanType interface, Close() error
|
||||
pkg database/sql/driver, type RowsColumnTypeScanType interface, Columns() []string
|
||||
pkg database/sql/driver, type RowsColumnTypeScanType interface, ColumnTypeScanType(int) reflect.Type
|
||||
pkg database/sql/driver, type RowsColumnTypeScanType interface, Next([]Value) error
|
||||
pkg database/sql/driver, type RowsNextResultSet interface { Close, Columns, HasNextResultSet, Next, NextResultSet }
|
||||
pkg database/sql/driver, type RowsNextResultSet interface, Close() error
|
||||
pkg database/sql/driver, type RowsNextResultSet interface, Columns() []string
|
||||
pkg database/sql/driver, type RowsNextResultSet interface, HasNextResultSet() bool
|
||||
pkg database/sql/driver, type RowsNextResultSet interface, NextResultSet() error
|
||||
pkg database/sql/driver, type RowsNextResultSet interface, Next([]Value) error
|
||||
pkg database/sql/driver, type StmtExecContext interface { ExecContext }
|
||||
pkg database/sql/driver, type StmtExecContext interface, ExecContext(context.Context, []NamedValue) (Result, error)
|
||||
pkg database/sql/driver, type StmtQueryContext interface { QueryContext }
|
||||
pkg database/sql/driver, type StmtQueryContext interface, QueryContext(context.Context, []NamedValue) (Rows, error)
|
||||
pkg database/sql/driver, type TxOptions struct
|
||||
pkg database/sql/driver, type TxOptions struct, Isolation IsolationLevel
|
||||
pkg database/sql/driver, type TxOptions struct, ReadOnly bool
|
||||
pkg database/sql, func Named(string, interface{}) NamedArg
|
||||
pkg database/sql, method (*ColumnType) DatabaseTypeName() string
|
||||
pkg database/sql, method (*ColumnType) DecimalSize() (int64, int64, bool)
|
||||
pkg database/sql, method (*ColumnType) Length() (int64, bool)
|
||||
pkg database/sql, method (*ColumnType) Name() string
|
||||
pkg database/sql, method (*ColumnType) Nullable() (bool, bool)
|
||||
pkg database/sql, method (*ColumnType) ScanType() reflect.Type
|
||||
pkg database/sql, method (*DB) BeginTx(context.Context, *TxOptions) (*Tx, error)
|
||||
pkg database/sql, method (*DB) ExecContext(context.Context, string, ...interface{}) (Result, error)
|
||||
pkg database/sql, method (*DB) PingContext(context.Context) error
|
||||
pkg database/sql, method (*DB) PrepareContext(context.Context, string) (*Stmt, error)
|
||||
pkg database/sql, method (*DB) QueryContext(context.Context, string, ...interface{}) (*Rows, error)
|
||||
pkg database/sql, method (*DB) QueryRowContext(context.Context, string, ...interface{}) *Row
|
||||
pkg database/sql, method (*Rows) ColumnTypes() ([]*ColumnType, error)
|
||||
pkg database/sql, method (*Rows) NextResultSet() bool
|
||||
pkg database/sql, method (*Stmt) ExecContext(context.Context, ...interface{}) (Result, error)
|
||||
pkg database/sql, method (*Stmt) QueryContext(context.Context, ...interface{}) (*Rows, error)
|
||||
pkg database/sql, method (*Stmt) QueryRowContext(context.Context, ...interface{}) *Row
|
||||
pkg database/sql, method (*Tx) ExecContext(context.Context, string, ...interface{}) (Result, error)
|
||||
pkg database/sql, method (*Tx) PrepareContext(context.Context, string) (*Stmt, error)
|
||||
pkg database/sql, method (*Tx) QueryContext(context.Context, string, ...interface{}) (*Rows, error)
|
||||
pkg database/sql, method (*Tx) QueryRowContext(context.Context, string, ...interface{}) *Row
|
||||
pkg database/sql, method (*Tx) StmtContext(context.Context, *Stmt) *Stmt
|
||||
pkg database/sql, type ColumnType struct
|
||||
pkg database/sql, type IsolationLevel int
|
||||
pkg database/sql, type NamedArg struct
|
||||
pkg database/sql, type NamedArg struct, Name string
|
||||
pkg database/sql, type NamedArg struct, Value interface{}
|
||||
pkg database/sql, type TxOptions struct
|
||||
pkg database/sql, type TxOptions struct, Isolation IsolationLevel
|
||||
pkg database/sql, type TxOptions struct, ReadOnly bool
|
||||
pkg debug/pe, method (*COFFSymbol) FullName(StringTable) (string, error)
|
||||
pkg debug/pe, method (StringTable) String(uint32) (string, error)
|
||||
pkg debug/pe, type File struct, COFFSymbols []COFFSymbol
|
||||
pkg debug/pe, type File struct, StringTable StringTable
|
||||
pkg debug/pe, type Reloc struct
|
||||
pkg debug/pe, type Reloc struct, SymbolTableIndex uint32
|
||||
pkg debug/pe, type Reloc struct, Type uint16
|
||||
pkg debug/pe, type Reloc struct, VirtualAddress uint32
|
||||
pkg debug/pe, type Section struct, Relocs []Reloc
|
||||
pkg debug/pe, type StringTable []uint8
|
||||
pkg encoding/base64, method (Encoding) Strict() *Encoding
|
||||
pkg encoding/json, method (RawMessage) MarshalJSON() ([]uint8, error)
|
||||
pkg encoding/json, type UnmarshalTypeError struct, Field string
|
||||
pkg encoding/json, type UnmarshalTypeError struct, Struct string
|
||||
pkg expvar, func Handler() http.Handler
|
||||
pkg expvar, method (*Float) Value() float64
|
||||
pkg expvar, method (Func) Value() interface{}
|
||||
pkg expvar, method (*Int) Value() int64
|
||||
pkg expvar, method (*String) Value() string
|
||||
pkg go/doc, func IsPredeclared(string) bool
|
||||
pkg go/types, func Default(Type) Type
|
||||
pkg go/types, func IdenticalIgnoreTags(Type, Type) bool
|
||||
pkg math/big, method (*Float) Scan(fmt.ScanState, int32) error
|
||||
pkg math/big, method (*Int) Sqrt(*Int) *Int
|
||||
pkg math/rand, func Uint64() uint64
|
||||
pkg math/rand, method (*Rand) Uint64() uint64
|
||||
pkg math/rand, type Source64 interface, Int63() int64
|
||||
pkg math/rand, type Source64 interface { Int63, Seed, Uint64 }
|
||||
pkg math/rand, type Source64 interface, Seed(int64)
|
||||
pkg math/rand, type Source64 interface, Uint64() uint64
|
||||
pkg net/http, const TrailerPrefix ideal-string
|
||||
pkg net/http, const TrailerPrefix = "Trailer:"
|
||||
pkg net/http/httptrace, type ClientTrace struct, TLSHandshakeDone func(tls.ConnectionState, error)
|
||||
pkg net/http/httptrace, type ClientTrace struct, TLSHandshakeStart func()
|
||||
pkg net/http/httputil, type ReverseProxy struct, ModifyResponse func(*http.Response) error
|
||||
pkg net/http, method (*Server) Close() error
|
||||
pkg net/http, method (*Server) Shutdown(context.Context) error
|
||||
pkg net/http, type Pusher interface { Push }
|
||||
pkg net/http, type Pusher interface, Push(string, *PushOptions) error
|
||||
pkg net/http, type PushOptions struct
|
||||
pkg net/http, type PushOptions struct, Header Header
|
||||
pkg net/http, type PushOptions struct, Method string
|
||||
pkg net/http, type Request struct, GetBody func() (io.ReadCloser, error)
|
||||
pkg net/http, type Server struct, IdleTimeout time.Duration
|
||||
pkg net/http, type Server struct, ReadHeaderTimeout time.Duration
|
||||
pkg net/http, type Transport struct, ProxyConnectHeader Header
|
||||
pkg net/http, var ErrAbortHandler error
|
||||
pkg net/http, var ErrServerClosed error
|
||||
pkg net/http, var NoBody noBody
|
||||
pkg net/mail, func ParseDate(string) (time.Time, error)
|
||||
pkg net, method (*Buffers) Read([]uint8) (int, error)
|
||||
pkg net, method (*Buffers) WriteTo(io.Writer) (int64, error)
|
||||
pkg net, method (*Resolver) LookupAddr(context.Context, string) ([]string, error)
|
||||
pkg net, method (*Resolver) LookupCNAME(context.Context, string) (string, error)
|
||||
pkg net, method (*Resolver) LookupHost(context.Context, string) ([]string, error)
|
||||
pkg net, method (*Resolver) LookupIPAddr(context.Context, string) ([]IPAddr, error)
|
||||
pkg net, method (*Resolver) LookupMX(context.Context, string) ([]*MX, error)
|
||||
pkg net, method (*Resolver) LookupNS(context.Context, string) ([]*NS, error)
|
||||
pkg net, method (*Resolver) LookupPort(context.Context, string, string) (int, error)
|
||||
pkg net, method (*Resolver) LookupSRV(context.Context, string, string, string) (string, []*SRV, error)
|
||||
pkg net, method (*Resolver) LookupTXT(context.Context, string) ([]string, error)
|
||||
pkg net, method (*UnixListener) SetUnlinkOnClose(bool)
|
||||
pkg net, type Buffers [][]uint8
|
||||
pkg net, type Dialer struct, Resolver *Resolver
|
||||
pkg net, type Resolver struct
|
||||
pkg net, type Resolver struct, PreferGo bool
|
||||
pkg net/url, func PathEscape(string) string
|
||||
pkg net/url, func PathUnescape(string) (string, error)
|
||||
pkg net/url, method (*URL) Hostname() string
|
||||
pkg net/url, method (*URL) MarshalBinary() ([]uint8, error)
|
||||
pkg net/url, method (*URL) Port() string
|
||||
pkg net/url, method (*URL) UnmarshalBinary([]uint8) error
|
||||
pkg net, var DefaultResolver *Resolver
|
||||
pkg os, func Executable() (string, error)
|
||||
pkg os, var ErrClosed error
|
||||
pkg plugin, func Open(string) (*Plugin, error)
|
||||
pkg plugin, method (*Plugin) Lookup(string) (Symbol, error)
|
||||
pkg plugin, type Plugin struct
|
||||
pkg plugin, type Symbol interface {}
|
||||
pkg reflect, func Swapper(interface{}) func(int, int)
|
||||
pkg runtime, func MutexProfile([]BlockProfileRecord) (int, bool)
|
||||
pkg runtime, func SetMutexProfileFraction(int) int
|
||||
pkg runtime, type MemStats struct, NumForcedGC uint32
|
||||
pkg sort, func Slice(interface{}, func(int, int) bool)
|
||||
pkg sort, func SliceIsSorted(interface{}, func(int, int) bool) bool
|
||||
pkg sort, func SliceStable(interface{}, func(int, int) bool)
|
||||
pkg syscall (linux-arm-cgo), func TimevalToNsec(Timeval) int64
|
||||
pkg syscall (linux-arm), func TimevalToNsec(Timeval) int64
|
||||
pkg syscall (openbsd-386), const SYS_KILL = 122
|
||||
pkg syscall (openbsd-386-cgo), const SYS_KILL = 122
|
||||
pkg syscall (openbsd-amd64), const SYS_KILL = 122
|
||||
pkg syscall (openbsd-amd64-cgo), const SYS_KILL = 122
|
||||
pkg syscall (windows-386), const ERROR_DIR_NOT_EMPTY = 145
|
||||
pkg syscall (windows-386), const ERROR_DIR_NOT_EMPTY Errno
|
||||
pkg syscall (windows-amd64), const ERROR_DIR_NOT_EMPTY = 145
|
||||
pkg syscall (windows-amd64), const ERROR_DIR_NOT_EMPTY Errno
|
||||
pkg testing, func CoverMode() string
|
||||
pkg testing, func MainStart(testDeps, []InternalTest, []InternalBenchmark, []InternalExample) *M
|
||||
pkg testing, method (*B) Name() string
|
||||
pkg testing, method (*T) Name() string
|
||||
pkg testing, type TB interface, Name() string
|
||||
pkg time, func Until(Time) Duration
|
||||
@@ -97,14 +97,13 @@ a tool like the go command to look at an unfamiliar import path and
|
||||
deduce where to obtain the source code.</p>
|
||||
|
||||
<p>Second, the place to store sources in the local file system is derived
|
||||
in a known way from the import path, specifically
|
||||
<code>$GOPATH/src/<import-path></code>.
|
||||
If unset, <code>$GOPATH</code> defaults to a subdirectory
|
||||
named <code>go</code> in the user's home directory.
|
||||
in a known way from the import path. Specifically, the first choice
|
||||
is <code>$GOPATH/src/<import-path></code>. If <code>$GOPATH</code> is
|
||||
unset, the go command will fall back to storing source code alongside the
|
||||
standard Go packages, in <code>$GOROOT/src/<import-path></code>.
|
||||
If <code>$GOPATH</code> is set to a list of paths, the go command tries
|
||||
<code><dir>/src/<import-path></code> for each of the directories in
|
||||
that list.
|
||||
</p>
|
||||
that list.</p>
|
||||
|
||||
<p>Each of those trees contains, by convention, a top-level directory named
|
||||
"<code>bin</code>", for holding compiled executables, and a top-level directory
|
||||
@@ -138,26 +137,41 @@ to the use of a specific tool chain.</p>
|
||||
|
||||
<h2>Getting started with the go command</h2>
|
||||
|
||||
<p>Finally, a quick tour of how to use the go command.
|
||||
As mentioned above, the default <code>$GOPATH</code> on Unix is <code>$HOME/go</code>.
|
||||
We'll store our programs there.
|
||||
To use a different location, you can set <code>$GOPATH</code>;
|
||||
see <a href="/doc/code.html">How to Write Go Code</a> for details.
|
||||
<p>Finally, a quick tour of how to use the go command, to supplement
|
||||
the information in <a href="/doc/code.html">How to Write Go Code</a>,
|
||||
which you might want to read first. Assuming you want
|
||||
to keep your source code separate from the Go distribution source
|
||||
tree, the first step is to set <code>$GOPATH</code>, the one piece of global
|
||||
configuration that the go command needs. The <code>$GOPATH</code> can be a
|
||||
list of directories, but by far the most common usage should be to set it to a
|
||||
single directory. In particular, you do not need a separate entry in
|
||||
<code>$GOPATH</code> for each of your projects. One <code>$GOPATH</code> can
|
||||
support many projects.</p>
|
||||
|
||||
<p>We first add some source code. Suppose we want to use
|
||||
<p>Here’s an example. Let’s say we decide to keep our Go code in the directory
|
||||
<code>$HOME/mygo</code>. We need to create that directory and set
|
||||
<code>$GOPATH</code> accordingly.</p>
|
||||
|
||||
<pre>
|
||||
$ mkdir $HOME/mygo
|
||||
$ export GOPATH=$HOME/mygo
|
||||
$
|
||||
</pre>
|
||||
|
||||
<p>Into this directory, we now add some source code. Suppose we want to use
|
||||
the indexing library from the codesearch project along with a left-leaning
|
||||
red-black tree. We can install both with the "<code>go get</code>"
|
||||
subcommand:</p>
|
||||
|
||||
<pre>
|
||||
$ go get github.com/google/codesearch/index
|
||||
$ go get code.google.com/p/codesearch/index
|
||||
$ go get github.com/petar/GoLLRB/llrb
|
||||
$
|
||||
</pre>
|
||||
|
||||
<p>Both of these projects are now downloaded and installed into <code>$HOME/go</code>,
|
||||
which contains the two directories
|
||||
<code>src/github.com/google/codesearch/index/</code> and
|
||||
<p>Both of these projects are now downloaded and installed into our
|
||||
<code>$GOPATH</code> directory. The one tree now contains the two directories
|
||||
<code>src/code.google.com/p/codesearch/index/</code> and
|
||||
<code>src/github.com/petar/GoLLRB/llrb/</code>, along with the compiled
|
||||
packages (in <code>pkg/</code>) for those libraries and their dependencies.</p>
|
||||
|
||||
@@ -170,14 +184,13 @@ the pattern "<code>./...</code>" means start in the current directory
|
||||
("<code>...</code>"):</p>
|
||||
|
||||
<pre>
|
||||
$ cd $HOME/go/src
|
||||
$ go list ./...
|
||||
github.com/google/codesearch/cmd/cgrep
|
||||
github.com/google/codesearch/cmd/cindex
|
||||
github.com/google/codesearch/cmd/csearch
|
||||
github.com/google/codesearch/index
|
||||
github.com/google/codesearch/regexp
|
||||
github.com/google/codesearch/sparse
|
||||
code.google.com/p/codesearch/cmd/cgrep
|
||||
code.google.com/p/codesearch/cmd/cindex
|
||||
code.google.com/p/codesearch/cmd/csearch
|
||||
code.google.com/p/codesearch/index
|
||||
code.google.com/p/codesearch/regexp
|
||||
code.google.com/p/codesearch/sparse
|
||||
github.com/petar/GoLLRB/example
|
||||
github.com/petar/GoLLRB/llrb
|
||||
$
|
||||
@@ -187,12 +200,12 @@ $
|
||||
|
||||
<pre>
|
||||
$ go test ./...
|
||||
? github.com/google/codesearch/cmd/cgrep [no test files]
|
||||
? github.com/google/codesearch/cmd/cindex [no test files]
|
||||
? github.com/google/codesearch/cmd/csearch [no test files]
|
||||
ok github.com/google/codesearch/index 0.203s
|
||||
ok github.com/google/codesearch/regexp 0.017s
|
||||
? github.com/google/codesearch/sparse [no test files]
|
||||
? code.google.com/p/codesearch/cmd/cgrep [no test files]
|
||||
? code.google.com/p/codesearch/cmd/cindex [no test files]
|
||||
? code.google.com/p/codesearch/cmd/csearch [no test files]
|
||||
ok code.google.com/p/codesearch/index 0.239s
|
||||
ok code.google.com/p/codesearch/regexp 0.021s
|
||||
? code.google.com/p/codesearch/sparse [no test files]
|
||||
? github.com/petar/GoLLRB/example [no test files]
|
||||
ok github.com/petar/GoLLRB/llrb 0.231s
|
||||
$
|
||||
@@ -202,18 +215,18 @@ $
|
||||
current directory:</p>
|
||||
|
||||
<pre>
|
||||
$ cd github.com/google/codesearch/regexp
|
||||
$ cd $GOPATH/src/code.google.com/p/codesearch/regexp
|
||||
$ go list
|
||||
github.com/google/codesearch/regexp
|
||||
code.google.com/p/codesearch/regexp
|
||||
$ go test -v
|
||||
=== RUN TestNstateEnc
|
||||
--- PASS: TestNstateEnc (0.00s)
|
||||
=== RUN TestMatch
|
||||
--- PASS: TestMatch (0.00s)
|
||||
=== RUN TestGrep
|
||||
--- PASS: TestGrep (0.00s)
|
||||
=== RUN TestNstateEnc
|
||||
--- PASS: TestNstateEnc (0.00 seconds)
|
||||
=== RUN TestMatch
|
||||
--- PASS: TestMatch (0.01 seconds)
|
||||
=== RUN TestGrep
|
||||
--- PASS: TestGrep (0.00 seconds)
|
||||
PASS
|
||||
ok github.com/google/codesearch/regexp 0.018s
|
||||
ok code.google.com/p/codesearch/regexp 0.021s
|
||||
$ go install
|
||||
$
|
||||
</pre>
|
||||
@@ -231,6 +244,9 @@ pick such a long name, but that ability would require additional configuration
|
||||
and complexity in the tool. Typing an extra directory name or two is a small
|
||||
price to pay for the increased simplicity and power.</p>
|
||||
|
||||
<p>As the example shows, it’s fine to work with packages from many different
|
||||
projects at once within a single <code>$GOPATH</code> root directory.</p>
|
||||
|
||||
<h2>Limitations</h2>
|
||||
|
||||
<p>As mentioned above, the go command is not a general-purpose build
|
||||
@@ -239,7 +255,8 @@ In particular, it does not have any facility for generating Go
|
||||
source files <em>during</em> a build, although it does provide
|
||||
<a href="/cmd/go/#hdr-Generate_Go_files_by_processing_source"><code>go</code>
|
||||
<code>generate</code></a>,
|
||||
which can automate the creation of Go files <em>before</em> the build.
|
||||
which can automate the creation of Go files <em>before</em>
|
||||
the build, such as by running <code>yacc</code>.
|
||||
For more advanced build setups, you may need to write a
|
||||
makefile (or a configuration file for the build tool of your choice)
|
||||
to run whatever tool creates the Go files and then check those generated source files
|
||||
|
||||
38
doc/asm.html
38
doc/asm.html
@@ -838,44 +838,6 @@ It is a scaled mode as on the x86, but the only scale allowed is <code>1</code>.
|
||||
|
||||
</ul>
|
||||
|
||||
<h3 id="mips">MIPS, MIPS64</h3>
|
||||
|
||||
<p>
|
||||
General purpose registers are named <code>R0</code> through <code>R31</code>,
|
||||
floating point registers are <code>F0</code> through <code>F31</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<code>R30</code> is reserved to point to <code>g</code>.
|
||||
<code>R23</code> is used as a temporary register.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In a <code>TEXT</code> directive, the frame size <code>$-4</code> for MIPS or
|
||||
<code>$-8</code> for MIPS64 instructs the linker not to save <code>LR</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<code>SP</code> refers to the virtual stack pointer.
|
||||
For the hardware register, use <code>R29</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Addressing modes:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
<code>16(R1)</code>: The location at <code>R1</code> plus 16.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<code>(R1)</code>: Alias for <code>0(R1)</code>.
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<h3 id="unsupported_opcodes">Unsupported opcodes</h3>
|
||||
|
||||
<p>
|
||||
|
||||
@@ -120,53 +120,36 @@ We will discuss the distinction <a href="#PackageNames">later</a>.
|
||||
|
||||
<p>
|
||||
The <code>GOPATH</code> environment variable specifies the location of your
|
||||
workspace. It defaults to a directory named <code>go</code> inside your home directory,
|
||||
so <code>$HOME/go</code> on Unix,
|
||||
<code>$home/go</code> on Plan 9,
|
||||
and <code>%USERPROFILE%\go</code> (usually <code>C:\Users\YourName\go</code>) on Windows.
|
||||
If you would like to work in a different location, you will need to set
|
||||
<code>GOPATH</code> to the path to that directory.
|
||||
(Another common setup is to set <code>GOPATH=$HOME</code>.)
|
||||
Note that <code>GOPATH</code> must <b>not</b> be the
|
||||
same path as your Go installation.
|
||||
workspace. It is likely the only environment variable you'll need to set
|
||||
when developing Go code.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The command <code>go</code> <code>env</code> <code>GOPATH</code>
|
||||
prints the effective current <code>GOPATH</code>;
|
||||
it prints the default location if the environment variable is unset.
|
||||
To get started, create a workspace directory and set <code>GOPATH</code>
|
||||
accordingly. Your workspace can be located wherever you like, but we'll use
|
||||
<code>$HOME/work</code> in this document. Note that this must <b>not</b> be the
|
||||
same path as your Go installation.
|
||||
(Another common setup is to set <code>GOPATH=$HOME</code>.)
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ <b>mkdir $HOME/work</b>
|
||||
$ <b>export GOPATH=$HOME/work</b>
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
For convenience, add the workspace's <code>bin</code> subdirectory
|
||||
to your <code>PATH</code>:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ <b>export PATH=$PATH:$(go env GOPATH)/bin</b>
|
||||
$ <b>export PATH=$PATH:$GOPATH/bin</b>
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The scripts in the rest of this document use <code>$GOPATH</code>
|
||||
instead of <code>$(go env GOPATH)</code> for brevity.
|
||||
To make the scripts run as written
|
||||
if you have not set GOPATH,
|
||||
you can substitute $HOME/go in those commands
|
||||
or else run:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ <b>export GOPATH=$(go env GOPATH)</b>
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
To learn more about the <code>GOPATH</code> environment variable, see
|
||||
<a href="/cmd/go/#hdr-GOPATH_environment_variable"><code>'go help gopath'</code></a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To use a custom workspace location,
|
||||
<a href="https://golang.org/wiki/SettingGOPATH">set the <code>GOPATH</code> environment variable</a>.
|
||||
To learn more about setting up the <code>GOPATH</code> environment variable,
|
||||
please see
|
||||
<a href="/cmd/go/#hdr-GOPATH_environment_variable"><code>go help gopath</code></a>
|
||||
</p>
|
||||
|
||||
<h3 id="ImportPaths">Import paths</h3>
|
||||
|
||||
@@ -20,8 +20,8 @@ ul ul {
|
||||
<p>
|
||||
Online communities include people from many different backgrounds.
|
||||
The Go contributors are committed to providing a friendly, safe and welcoming
|
||||
environment for all, regardless of age, disability, gender, nationality,
|
||||
ethnicity, religion, sexuality, or similar personal characteristic.
|
||||
environment for all, regardless of age, disability, gender, nationality, race,
|
||||
religion, sexuality, or similar personal characteristic.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
@@ -67,6 +67,7 @@ official forums operated by the Go project (“Go spaces”):
|
||||
<li>The <a href="https://groups.google.com/group/golang-nuts">golang-nuts</a> and
|
||||
<a href="https://groups.google.com/group/golang-dev">golang-dev</a> mailing lists.
|
||||
<li>The #go-nuts IRC channel on Freenode.
|
||||
<li>The <a href="https://reddit.com/r/golang">/r/golang subreddit</a>.
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
|
||||
@@ -519,7 +519,7 @@ Other changes:
|
||||
fix FreeBSD signal handling around thread creation (thanks Devon H. O'Dell),
|
||||
goroutine profile, stack dumps,
|
||||
implement runtime.osyield on FreeBSD 386, amd64 (thanks Devon H. O'Dell),
|
||||
permit default behavior of SIGTSTP, SIGTTIN, SIGTTOU,
|
||||
permit default behaviour of SIGTSTP, SIGTTIN, SIGTTOU,
|
||||
release unused memory to the OS (thanks Sébastien Paolacci),
|
||||
remove an obsolete file (thanks Mikio Hara).
|
||||
* spec: make all comparison results untyped bool,
|
||||
@@ -2450,7 +2450,7 @@ The http package's URL parsing and query escaping code (such as ParseURL and
|
||||
URLEscape) has been moved to the new url package, with several simplifications
|
||||
to the names. Client code can be updated automatically with gofix.
|
||||
|
||||
* asn1: support unmarshaling structs with int32 members (thanks Dave Cheney).
|
||||
* asn1: support unmarshalling structs with int32 members (thanks Dave Cheney).
|
||||
* build: allow builds without cgo or hg,
|
||||
support versioning without hg (thanks Gustavo Niemeyer).
|
||||
* builtin: add documentation for builtins.
|
||||
@@ -3030,7 +3030,7 @@ Other changes:
|
||||
* 5g: alignment fixes.
|
||||
* 6l, 8l: fix Mach-O binaries with many dynamic libraries.
|
||||
* 8l: emit resources (.rsrc) in Windows PE. (thanks Wei Guangjing).
|
||||
* asn1: fix marshaling of empty optional RawValues (thanks Mikkel Krautz).
|
||||
* asn1: fix marshalling of empty optional RawValues (thanks Mikkel Krautz).
|
||||
* big: make Int and Rat implement fmt.Scanner (thanks Evan Shaw),
|
||||
~8x faster number scanning,
|
||||
remove some unnecessary conversions.
|
||||
@@ -4157,7 +4157,7 @@ Other changes in this release:
|
||||
* suffixarray: use binary search for both ends of Lookup (thanks Eric Eisner).
|
||||
* syscall: add missing network interface constants (thanks Mikio Hara).
|
||||
* template: treat map keys as zero, not non-existent (thanks Roger Peppe).
|
||||
* time: allow canceling of After events (thanks Roger Peppe),
|
||||
* time: allow cancelling of After events (thanks Roger Peppe),
|
||||
support Solaris zoneinfo directory.
|
||||
* token/position: added SetLinesForContent.
|
||||
* unicode: update to unicode 6.0.0.
|
||||
@@ -4238,7 +4238,7 @@ example: http://golang.org/pkg/xml/
|
||||
<pre>
|
||||
The json, gob, and template packages have changed, and code that uses them
|
||||
may need to be updated after this release. They will no longer read or write
|
||||
unexported struct fields. When marshaling a struct with json or gob the
|
||||
unexported struct fields. When marshalling a struct with json or gob the
|
||||
unexported fields will be silently ignored. Attempting to unmarshal json or
|
||||
gob data into an unexported field will generate an error. Accessing an
|
||||
unexported field from a template will cause the Execute function to return
|
||||
@@ -5682,7 +5682,7 @@ Other changes:
|
||||
pidigits ~10% performance win by using adds instead of shifts.
|
||||
* time: remove incorrect time.ISO8601 and add time.RFC3339 (thanks Micah Stetson).
|
||||
* utf16: add DecodeRune, EncodeRune.
|
||||
* xml: add support for XML marshaling embedded structs (thanks Raif S. Naffah),
|
||||
* xml: add support for XML marshalling embedded structs (thanks Raif S. Naffah),
|
||||
new "innerxml" tag to collect inner XML.
|
||||
</pre>
|
||||
|
||||
@@ -5696,7 +5696,7 @@ This release contains many changes:
|
||||
* cmath: new complex math library (thanks Charles L. Dorian).
|
||||
* docs: update to match current coding style (thanks Christopher Wedgwood).
|
||||
* exp/eval: fix example and add target to Makefile (thanks Evan Shaw).
|
||||
* fmt: change behavior of format verb %b to match %x when negative (thanks Andrei Vieru).
|
||||
* fmt: change behaviour of format verb %b to match %x when negative (thanks Andrei Vieru).
|
||||
* gc: compile s == "" as len(s) == 0,
|
||||
distinguish fatal compiler bug from error+exit,
|
||||
fix alignment on non-amd64,
|
||||
@@ -5925,10 +5925,10 @@ Other changes and fixes:
|
||||
* 8a/8l: Added CMOVcc instructions (thanks Evan Shaw)
|
||||
* 8l: pe executable building code changed to include import table for kernel32.dll functions (thanks Alex Brainman)
|
||||
* 5g/6g/8g: bug fixes
|
||||
* asn1: bug fixes and additions (incl marshaling)
|
||||
* asn1: bug fixes and additions (incl marshalling)
|
||||
* build: fix build for Native Client, Linux/ARM
|
||||
* dashboard: show benchmarks, add garbage collector benchmarks
|
||||
* encoding/pem: add marshaling support
|
||||
* encoding/pem: add marshalling support
|
||||
* exp/draw: fast paths for a nil mask
|
||||
* godoc: support for directories outside $GOROOT
|
||||
* http: sort header keys when writing Response or Request to wire (thanks Petar Maymounkov)
|
||||
|
||||
@@ -40,13 +40,7 @@ The first section covers basic syntax and data structures; the second discusses
|
||||
methods and interfaces; and the third introduces Go's concurrency primitives.
|
||||
Each section concludes with a few exercises so you can practice what you've
|
||||
learned. You can <a href="//tour.golang.org/">take the tour online</a> or
|
||||
install it locally with:
|
||||
</p>
|
||||
<p>
|
||||
<pre>
|
||||
$ go get golang.org/x/tour/gotour
|
||||
</pre>
|
||||
This will place the <code>gotour</code> binary in your workspace's <code>bin</code> directory.
|
||||
<a href="//code.google.com/p/go-tour/">install it locally</a>.
|
||||
</p>
|
||||
|
||||
<h3 id="code"><a href="code.html">How to write Go code</a></h3>
|
||||
|
||||
@@ -245,15 +245,15 @@ func Compile(str string) (*Regexp, error) {
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
If every doc comment begins with the name of the item it describes,
|
||||
the output of <code>godoc</code> can usefully be run through <code>grep</code>.
|
||||
If the name always begins the comment, the output of <code>godoc</code>
|
||||
can usefully be run through <code>grep</code>.
|
||||
Imagine you couldn't remember the name "Compile" but were looking for
|
||||
the parsing function for regular expressions, so you ran
|
||||
the command,
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ godoc regexp | grep -i parse
|
||||
$ godoc regexp | grep parse
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
@@ -2409,7 +2409,7 @@ The <code>http</code> package contains this code:
|
||||
// Handler object that calls f.
|
||||
type HandlerFunc func(ResponseWriter, *Request)
|
||||
|
||||
// ServeHTTP calls f(w, req).
|
||||
// ServeHTTP calls f(c, req).
|
||||
func (f HandlerFunc) ServeHTTP(w ResponseWriter, req *Request) {
|
||||
f(w, req)
|
||||
}
|
||||
@@ -2447,7 +2447,7 @@ the handler installed at that page has value <code>ArgServer</code>
|
||||
and type <code>HandlerFunc</code>.
|
||||
The HTTP server will invoke the method <code>ServeHTTP</code>
|
||||
of that type, with <code>ArgServer</code> as the receiver, which will in turn call
|
||||
<code>ArgServer</code> (via the invocation <code>f(w, req)</code>
|
||||
<code>ArgServer</code> (via the invocation <code>f(c, req)</code>
|
||||
inside <code>HandlerFunc.ServeHTTP</code>).
|
||||
The arguments will then be displayed.
|
||||
</p>
|
||||
|
||||
@@ -12,7 +12,7 @@ information on building gccgo for yourself,
|
||||
see <a href="/doc/gccgo_install.html">Setting up and using gccgo</a>.
|
||||
For more of the gritty details on the process of doing development
|
||||
with the gccgo frontend,
|
||||
see <a href="https://go.googlesource.com/gofrontend/+/master/HACKING">the
|
||||
see <a href="https://code.google.com/p/gofrontend/source/browse/HACKING">the
|
||||
file HACKING</a> in the gofrontend repository.
|
||||
</p>
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ includes the <a href="#context">context package</a>, promoted from the
|
||||
and now used in the standard library;
|
||||
and <a href="#testing">adds support in the testing package</a> for
|
||||
creating hierarchies of tests and benchmarks.
|
||||
The release also <a href="#cmd_go">finalizes the vendoring support</a>
|
||||
The release also <a href="#cmd/go">finalizes the vendoring support</a>
|
||||
started in Go 1.5, making it a standard feature.
|
||||
</p>
|
||||
|
||||
@@ -357,7 +357,7 @@ the code generation changes alone typically reduce program CPU time by 5-35%.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<!-- git log -''-grep '-[0-9][0-9]\.[0-9][0-9]%' go1.6.. -->
|
||||
<!-- git log --grep '-[0-9][0-9]\.[0-9][0-9]%' go1.6.. -->
|
||||
There have been significant optimizations bringing more than 10% improvements
|
||||
to implementations in the
|
||||
<a href="/pkg/crypto/sha1/"><code>crypto/sha1</code></a>,
|
||||
@@ -394,9 +394,9 @@ This allows the use of contexts for cancelation, timeouts, and passing
|
||||
request-scoped data in other standard library packages,
|
||||
including
|
||||
<a href="#net">net</a>,
|
||||
<a href="#net_http">net/http</a>,
|
||||
<a href="#net/http">net/http</a>,
|
||||
and
|
||||
<a href="#os_exec">os/exec</a>,
|
||||
<a href="#os/exec">os/exec</a>,
|
||||
as noted below.
|
||||
</p>
|
||||
|
||||
@@ -552,9 +552,10 @@ The
|
||||
|
||||
<dd>
|
||||
<p>
|
||||
There are many performance optimizations throughout the package.
|
||||
As noted above,
|
||||
there are significant performance optimizations throughout the package.
|
||||
Decompression speed is improved by about 10%,
|
||||
while compression for <code>DefaultCompression</code> is twice as fast.
|
||||
while compression speed for <code>DefaultCompression</code> is roughly doubled.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
||||
1663
doc/go1.8.html
1663
doc/go1.8.html
File diff suppressed because it is too large
Load Diff
@@ -1,55 +0,0 @@
|
||||
This file lists things yet to be moved into go1.8.html or deemed too
|
||||
minor to mention. Either way, delete from here when done.
|
||||
|
||||
Tools:
|
||||
|
||||
go: -buildmode=c-archive now builds PIC on ELF (CL 24180)
|
||||
go: mobile pkg dir change, recommend using go list in scripts (CL 24930, CL 27929)
|
||||
go, dist: can set default pkg-config tool using PKG_CONFIG env var (CL 29991)
|
||||
go: can set secure/insecure GIT schemes using GIT_ALLOW_PROTOCOL env var (CL 30135)
|
||||
|
||||
API additions and behavior changes:
|
||||
|
||||
cmd/compile, runtime, etc: get rid of constant FP registers (CL 28095)
|
||||
cmd/compile, runtime: add go:yeswritebarrierrec pragma (CL 30938)
|
||||
cmd/compile/internal/gc: enable new parser by default (CL 27203)
|
||||
cmd/compile/internal/syntax: fast Go syntax trees, initial commit (CL 27195)
|
||||
cmd/compile: add compiler phase timing (CL 24462)
|
||||
cmd/compile: add inline explainer (CL 22782)
|
||||
cmd/compile: enable flag-specified dump of specific phase+function (CL 23044)
|
||||
|
||||
cmd/internal/obj, cmd/link: darwin dynlink support (CL 29393)
|
||||
cmd/internal/objfile: add ppc64/ppc64le disassembler support (CL 9682)
|
||||
cmd/link, cmd/go: delay linking of mingwex and mingw32 until very end (CL 26670)
|
||||
cmd/link: R_ADDR dynamic relocs for internal PIE (CL 29118)
|
||||
cmd/link: add trampolines for too far calls in ppc64x (CL 30850)
|
||||
cmd/link: allow internal PIE linking (CL 28543)
|
||||
cmd/link: fix -X importpath.name=value when import path needs escaping (CL 31970)
|
||||
cmd/link: fix -buildmode=pie / -linkshared combination (CL 28996)
|
||||
cmd/link: for -buildmode=exe pass -no-pie to external linker (CL 33106)
|
||||
cmd/link: insert trampolines for too-far jumps on ARM (CL 29397)
|
||||
cmd/link: non-executable stack support for Solaris (CL 24142)
|
||||
cmd/link: put text at address 0x1000000 on darwin/amd64 (CL 32185)
|
||||
cmd/link: remove the -shared flag (CL 28852)
|
||||
cmd/link: split large elf text sections on ppc64x (CL 27790)
|
||||
cmd/link: trampoline support for external linking on ARM (CL 31143)
|
||||
cmd/objdump: implement objdump of .o files (CL 24818)
|
||||
|
||||
go/build: allow % in ${SRCDIR} expansion for Jenkins (CL 31611)
|
||||
go/build: do not record go:binary-only-package if build tags not satisfied (CL 31577)
|
||||
go/build: implement default GOPATH (CL 32019)
|
||||
|
||||
runtime/race: update race runtime (CL 32160)
|
||||
runtime: assume 64kB physical pages on ARM (CL 25021)
|
||||
runtime: disable stack rescanning by default (CL 31766)
|
||||
runtime: don't call cgocallback from signal handler (CL 30218)
|
||||
runtime: fix check for vacuous page boundary rounding (CL 27230)
|
||||
runtime: fix map iterator concurrent map check (CL 24749)
|
||||
runtime: fix newextram PC passed to race detector (CL 29712)
|
||||
runtime: implement unconditional hybrid barrier (CL 31765)
|
||||
runtime: include pre-panic/throw logs in core dumps (CL 32013)
|
||||
runtime: limit the number of map overflow buckets (CL 25049)
|
||||
runtime: pass windows float syscall args via XMM (CL 32173)
|
||||
runtime: print sigcode on signal crash (CL 32183)
|
||||
runtime: record current PC for SIGPROF on non-Go thread (CL 30252)
|
||||
runtime: sleep on CLOCK_MONOTONIC in futexsleep1 on freebsd (CL 30154)
|
||||
@@ -271,27 +271,6 @@ you will need to abide by the guidelines at
|
||||
|
||||
<h2 id="Design">Design</h2>
|
||||
|
||||
<h3 id="runtime">
|
||||
Does Go have a runtime?</h3>
|
||||
|
||||
<p>
|
||||
Go does have an extensive library, called the <em>runtime</em>,
|
||||
that is part of every Go program.
|
||||
The runtime library implements garbage collection, concurrency,
|
||||
stack management, and other critical features of the Go language.
|
||||
Although it is more central to the language, Go's runtime is analogous
|
||||
to <code>libc</code>, the C library.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
It is important to understand, however, that Go's runtime does not
|
||||
include a virtual machine, such as is provided by the Java runtime.
|
||||
Go programs are compiled ahead of time to native machine code.
|
||||
Thus, although the term is often used to describe the virtual
|
||||
environment in which a program runs, in Go the word “runtime”
|
||||
is just the name given to the library providing critical language services.
|
||||
</p>
|
||||
|
||||
<h3 id="unicode_identifiers">
|
||||
What's up with Unicode identifiers?</h3>
|
||||
|
||||
@@ -769,29 +748,6 @@ for i, v := range t {
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h3 id="convert_slice_with_same_underlying_type">
|
||||
Can I convert []T1 to []T2 if T1 and T2 have the same underlying type?</h3>
|
||||
|
||||
This last line of this code sample does not compile.
|
||||
|
||||
<pre>
|
||||
type T1 int
|
||||
type T2 int
|
||||
var t1 T1
|
||||
var x = T2(t1) // OK
|
||||
var st1 []T1
|
||||
var sx = ([]T2)(st1) // NOT OK
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
In Go, types are closely tied to methods, in that every named type has
|
||||
a (possibly empty) method set.
|
||||
The general rule is that you can change the name of the type being
|
||||
converted (and thus possibly change its method set) but you can't
|
||||
change the name (and method set) of elements of a composite type.
|
||||
Go requires you to be explicit about type conversions.
|
||||
</p>
|
||||
|
||||
<h3 id="nil_error">
|
||||
Why is my nil error value not equal to nil?
|
||||
</h3>
|
||||
@@ -912,7 +868,6 @@ Why does Go not have covariant result types?</h3>
|
||||
|
||||
<p>
|
||||
Covariant result types would mean that an interface like
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
type Copyable interface {
|
||||
@@ -920,15 +875,13 @@ type Copyable interface {
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
would be satisfied by the method
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
func (v Value) Copy() Value
|
||||
</pre>
|
||||
|
||||
<p>because <code>Value</code> implements the empty interface.
|
||||
because <code>Value</code> implements the empty interface.
|
||||
In Go method types must match exactly, so <code>Value</code> does not
|
||||
implement <code>Copyable</code>.
|
||||
Go separates the notion of what a
|
||||
@@ -1094,7 +1047,7 @@ it's easy to work around this. For GitHub, try one of these solutions:
|
||||
<ul>
|
||||
<li>Manually clone the repository in the expected package directory:
|
||||
<pre>
|
||||
$ cd src/github.com/username
|
||||
$ cd $GOPATH/src/github.com/username
|
||||
$ git clone git@github.com:username/package.git
|
||||
</pre>
|
||||
</li>
|
||||
@@ -1174,12 +1127,6 @@ struct. If the interface value holds a pointer, copying the interface value
|
||||
makes a copy of the pointer, but again not the data it points to.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Note that this discussion is about the semantics of the operations.
|
||||
Actual implementations may apply optimizations to avoid copying
|
||||
as long as the optimizations do not change the semantics.
|
||||
</p>
|
||||
|
||||
<h3 id="pointer_to_interface">
|
||||
When should I use a pointer to an interface?</h3>
|
||||
|
||||
@@ -1315,26 +1262,11 @@ size of value should use an explicitly sized type, like <code>int64</code>.
|
||||
Prior to Go 1.1, the 64-bit Go compilers (both gc and gccgo) used
|
||||
a 32-bit representation for <code>int</code>. As of Go 1.1 they use
|
||||
a 64-bit representation.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
On the other hand, floating-point scalars and complex
|
||||
types are always sized (there are no <code>float</code> or <code>complex</code> basic types),
|
||||
because programmers should be aware of precision when using floating-point numbers.
|
||||
The default type used for an (untyped) floating-point constant is <code>float64</code>.
|
||||
Thus <code>foo</code> <code>:=</code> <code>3.0</code> declares a variable <code>foo</code>
|
||||
of type <code>float64</code>.
|
||||
For a <code>float32</code> variable initialized by an (untyped) constant, the variable type
|
||||
must be specified explicitly in the variable declaration:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
var foo float32 = 3.0
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Alternatively, the constant must be given a type with a conversion as in
|
||||
<code>foo := float32(3.0)</code>.
|
||||
numbers are always sized: <code>float32</code>, <code>complex64</code>,
|
||||
etc., because programmers should be aware of precision when using
|
||||
floating-point numbers.
|
||||
The default size of a floating-point constant is <code>float64</code>.
|
||||
</p>
|
||||
|
||||
<h3 id="stack_or_heap">
|
||||
@@ -1738,7 +1670,8 @@ What compiler technology is used to build the compilers?</h3>
|
||||
|
||||
<p>
|
||||
<code>Gccgo</code> has a front end written in C++, with a recursive descent parser coupled to the
|
||||
standard GCC back end. <code>Gc</code> is written in Go with a recursive descent parser
|
||||
standard GCC back end. <code>Gc</code> is written in Go using
|
||||
<code>yacc</code>/<code>bison</code> for the parser
|
||||
and uses a custom loader, also written in Go but
|
||||
based on the Plan 9 loader, to generate ELF/Mach-O/PE binaries.
|
||||
</p>
|
||||
@@ -1799,7 +1732,7 @@ A simple C "hello, world" program compiled and linked statically using gcc
|
||||
on Linux is around 750 kB,
|
||||
including an implementation of <code>printf</code>.
|
||||
An equivalent Go program using <code>fmt.Printf</code>
|
||||
is around 1.5 MB, but
|
||||
is around 2.3 MB, but
|
||||
that includes more powerful run-time support and type information.
|
||||
</p>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!--{
|
||||
"Title": "The Go Programming Language Specification",
|
||||
"Subtitle": "Version of November 18, 2016",
|
||||
"Subtitle": "Version of May 31, 2016",
|
||||
"Path": "/ref/spec"
|
||||
}-->
|
||||
|
||||
@@ -605,7 +605,7 @@ implementation must:
|
||||
|
||||
<li>Represent floating-point constants, including the parts of
|
||||
a complex constant, with a mantissa of at least 256 bits
|
||||
and a signed binary exponent of at least 16 bits.</li>
|
||||
and a signed exponent of at least 32 bits.</li>
|
||||
|
||||
<li>Give an error if unable to represent an integer constant
|
||||
precisely.</li>
|
||||
@@ -2006,7 +2006,7 @@ _, y, _ := coord(p) // coord() returns three values; only interested in y coord
|
||||
<p>
|
||||
Unlike regular variable declarations, a short variable declaration may <i>redeclare</i>
|
||||
variables provided they were originally declared earlier in the same block
|
||||
(or the parameter lists if the block is the function body) with the same type,
|
||||
(or the parameter lists if the block is the function body) with the same type,
|
||||
and at least one of the non-<a href="#Blank_identifier">blank</a> variables is new.
|
||||
As a consequence, redeclaration can only appear in a multi-variable short declaration.
|
||||
Redeclaration does not introduce a new variable; it just assigns a new value to the original.
|
||||
@@ -2286,10 +2286,8 @@ For array and slice literals the following rules apply:
|
||||
<li>Each element has an associated integer index marking
|
||||
its position in the array.
|
||||
</li>
|
||||
<li>An element with a key uses the key as its index. The
|
||||
key must be a non-negative constant representable by
|
||||
a value of type <code>int</code>; and if it is typed
|
||||
it must be of integer type.
|
||||
<li>An element with a key uses the key as its index; the
|
||||
key must be a constant integer expression.
|
||||
</li>
|
||||
<li>An element without a key uses the previous element's index plus one.
|
||||
If the first element has no key, its index is zero.
|
||||
@@ -2322,7 +2320,7 @@ days := [...]string{"Sat", "Sun"} // len(days) == 2
|
||||
|
||||
<p>
|
||||
A slice literal describes the entire underlying array literal.
|
||||
Thus the length and capacity of a slice literal are the maximum
|
||||
Thus, the length and capacity of a slice literal are the maximum
|
||||
element index plus one. A slice literal has the form
|
||||
</p>
|
||||
|
||||
@@ -2352,11 +2350,10 @@ the <code>&T</code> when the element or key type is <code>*T</code>.
|
||||
[][]int{{1, 2, 3}, {4, 5}} // same as [][]int{[]int{1, 2, 3}, []int{4, 5}}
|
||||
[][]Point{{{0, 1}, {1, 2}}} // same as [][]Point{[]Point{Point{0, 1}, Point{1, 2}}}
|
||||
map[string]Point{"orig": {0, 0}} // same as map[string]Point{"orig": Point{0, 0}}
|
||||
map[Point]string{{0, 0}: "orig"} // same as map[Point]string{Point{0, 0}: "orig"}
|
||||
|
||||
type PPoint *Point
|
||||
[2]*Point{{1.5, -3.5}, {}} // same as [2]*Point{&Point{1.5, -3.5}, &Point{}}
|
||||
[2]PPoint{{1.5, -3.5}, {}} // same as [2]PPoint{PPoint(&Point{1.5, -3.5}), PPoint(&Point{})}
|
||||
[...]*Point{{1.5, -3.5}, {0, 0}} // same as [...]*Point{&Point{1.5, -3.5}, &Point{0, 0}}
|
||||
|
||||
map[Point]string{{0, 0}: "orig"} // same as map[Point]string{Point{0, 0}: "orig"}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
@@ -2936,7 +2933,6 @@ used in an <a href="#Assignments">assignment</a> or initialization of the specia
|
||||
v, ok = a[x]
|
||||
v, ok := a[x]
|
||||
var v, ok = a[x]
|
||||
var v, ok T = a[x]
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
@@ -3117,16 +3113,13 @@ known to be <code>T</code> in a correct program.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
var x interface{} = 7 // x has dynamic type int and value 7
|
||||
i := x.(int) // i has type int and value 7
|
||||
var x interface{} = 7 // x has dynamic type int and value 7
|
||||
i := x.(int) // i has type int and value 7
|
||||
|
||||
type I interface { m() }
|
||||
|
||||
func f(y I) {
|
||||
s := y.(string) // illegal: string does not implement I (missing method m)
|
||||
r := y.(io.Reader) // r has type io.Reader and the dynamic type of y must implement both I and io.Reader
|
||||
…
|
||||
}
|
||||
var y I
|
||||
s := y.(string) // illegal: string does not implement I (missing method m)
|
||||
r := y.(io.Reader) // r has type io.Reader and y must implement both I and io.Reader
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
@@ -3137,7 +3130,6 @@ A type assertion used in an <a href="#Assignments">assignment</a> or initializat
|
||||
v, ok = x.(T)
|
||||
v, ok := x.(T)
|
||||
var v, ok = x.(T)
|
||||
var v, ok T1 = x.(T)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
@@ -3745,7 +3737,6 @@ A receive expression used in an <a href="#Assignments">assignment</a> or initial
|
||||
x, ok = <-ch
|
||||
x, ok := <-ch
|
||||
var x, ok = <-ch
|
||||
var x, ok T = <-ch
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
@@ -3843,12 +3834,10 @@ in any of these cases:
|
||||
to <code>T</code>.
|
||||
</li>
|
||||
<li>
|
||||
ignoring struct tags (see below),
|
||||
<code>x</code>'s type and <code>T</code> have <a href="#Type_identity">identical</a>
|
||||
<code>x</code>'s type and <code>T</code> have identical
|
||||
<a href="#Types">underlying types</a>.
|
||||
</li>
|
||||
<li>
|
||||
ignoring struct tags (see below),
|
||||
<code>x</code>'s type and <code>T</code> are unnamed pointer types
|
||||
and their pointer base types have identical underlying types.
|
||||
</li>
|
||||
@@ -3868,31 +3857,6 @@ in any of these cases:
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
<a href="#Struct_types">Struct tags</a> are ignored when comparing struct types
|
||||
for identity for the purpose of conversion:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
type Person struct {
|
||||
Name string
|
||||
Address *struct {
|
||||
Street string
|
||||
City string
|
||||
}
|
||||
}
|
||||
|
||||
var data *struct {
|
||||
Name string `json:"name"`
|
||||
Address *struct {
|
||||
Street string `json:"street"`
|
||||
City string `json:"city"`
|
||||
} `json:"address"`
|
||||
}
|
||||
|
||||
var person = (*Person)(data) // ignoring tags, the underlying types are identical
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Specific rules apply to (non-constant) conversions between numeric types or
|
||||
to and from a string type.
|
||||
@@ -4723,8 +4687,8 @@ TypeList = Type { "," Type } .
|
||||
<p>
|
||||
The TypeSwitchGuard may include a
|
||||
<a href="#Short_variable_declarations">short variable declaration</a>.
|
||||
When that form is used, the variable is declared at the end of the
|
||||
TypeSwitchCase in the <a href="#Blocks">implicit block</a> of each clause.
|
||||
When that form is used, the variable is declared at the beginning of
|
||||
the <a href="#Blocks">implicit block</a> in each clause.
|
||||
In clauses with a case listing exactly one type, the variable
|
||||
has that type; otherwise, the variable has the type of the expression
|
||||
in the TypeSwitchGuard.
|
||||
@@ -4799,8 +4763,8 @@ The "fallthrough" statement is not permitted in a type switch.
|
||||
<h3 id="For_statements">For statements</h3>
|
||||
|
||||
<p>
|
||||
A "for" statement specifies repeated execution of a block. There are three forms:
|
||||
The iteration may be controlled by a single condition, a "for" clause, or a "range" clause.
|
||||
A "for" statement specifies repeated execution of a block. The iteration is
|
||||
controlled by a condition, a "for" clause, or a "range" clause.
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
@@ -4808,8 +4772,6 @@ ForStmt = "for" [ Condition | ForClause | RangeClause ] Block .
|
||||
Condition = Expression .
|
||||
</pre>
|
||||
|
||||
<h4 id="For_condition">For statements with single condition</h4>
|
||||
|
||||
<p>
|
||||
In its simplest form, a "for" statement specifies the repeated execution of
|
||||
a block as long as a boolean condition evaluates to true.
|
||||
@@ -4824,8 +4786,6 @@ for a < b {
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h4 id="For_clause">For statements with <code>for</code> clause</h4>
|
||||
|
||||
<p>
|
||||
A "for" statement with a ForClause is also controlled by its condition, but
|
||||
additionally it may specify an <i>init</i>
|
||||
@@ -4864,8 +4824,6 @@ for cond { S() } is the same as for ; cond ; { S() }
|
||||
for { S() } is the same as for true { S() }
|
||||
</pre>
|
||||
|
||||
<h4 id="For_range">For statements with <code>range</code> clause</h4>
|
||||
|
||||
<p>
|
||||
A "for" statement with a "range" clause
|
||||
iterates through all entries of an array, slice, string or map,
|
||||
@@ -5765,12 +5723,12 @@ var a = complex(2, -2) // complex128
|
||||
const b = complex(1.0, -1.4) // untyped complex constant 1 - 1.4i
|
||||
x := float32(math.Cos(math.Pi/2)) // float32
|
||||
var c64 = complex(5, -x) // complex64
|
||||
var s uint = complex(1, 0) // untyped complex constant 1 + 0i can be converted to uint
|
||||
_ = complex(1, 2<<s) // illegal: 2 assumes floating-point type, cannot shift
|
||||
const s uint = complex(1, 0) // untyped complex constant 1 + 0i can be converted to uint
|
||||
_ = complex(1, 2<<s) // illegal: 2 has floating-point type, cannot shift
|
||||
var rl = real(c64) // float32
|
||||
var im = imag(a) // float64
|
||||
const c = imag(b) // untyped constant -1.4
|
||||
_ = imag(3 << s) // illegal: 3 assumes complex type, cannot shift
|
||||
_ = imag(3 << s) // illegal: 3 has complex type, cannot shift
|
||||
</pre>
|
||||
|
||||
<h3 id="Handling_panics">Handling panics</h3>
|
||||
@@ -6201,10 +6159,9 @@ func init() { … }
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Multiple such functions may be defined per package, even within a single
|
||||
source file. In the package block, the <code>init</code> identifier can
|
||||
be used only to declare <code>init</code> functions, yet the identifier
|
||||
itself is not <a href="#Declarations_and_scope">declared</a>. Thus
|
||||
Multiple such functions may be defined, even within a single
|
||||
source file. The <code>init</code> identifier is not
|
||||
<a href="#Declarations_and_scope">declared</a> and thus
|
||||
<code>init</code> functions cannot be referred to from anywhere
|
||||
in a program.
|
||||
</p>
|
||||
|
||||
@@ -11,9 +11,6 @@
|
||||
|
||||
<h3 id="mailinglist"><a href="https://groups.google.com/group/golang-nuts">Go Nuts Mailing List</a></h3>
|
||||
<p>
|
||||
Get help from Go users, and share your work on the official mailing list.
|
||||
</p>
|
||||
<p>
|
||||
Search the <a href="https://groups.google.com/group/golang-nuts">golang-nuts</a>
|
||||
archives and consult the <a href="/doc/go_faq.html">FAQ</a> and
|
||||
<a href="//golang.org/wiki">wiki</a> before posting.
|
||||
@@ -21,12 +18,12 @@ archives and consult the <a href="/doc/go_faq.html">FAQ</a> and
|
||||
|
||||
<h3 id="forum"><a href="https://forum.golangbridge.org/">Go Forum</a></h3>
|
||||
<p>
|
||||
The <a href="https://forum.golangbridge.org/">Go Forum</a> is a discussion
|
||||
The <a href="https://forum.golangbridge.org/">Go Forum</a> is an alternate discussion
|
||||
forum for Go programmers.
|
||||
</p>
|
||||
|
||||
<h3 id="slack"><a href="https://blog.gopheracademy.com/gophers-slack-community/">Gopher Slack</a></h3>
|
||||
<p>Get live support from other users in the Go slack channel.</p>
|
||||
<p>Get live support from the official Go slack channel.</p>
|
||||
|
||||
<h3 id="irc"><a href="irc:irc.freenode.net/go-nuts">Go IRC Channel</a></h3>
|
||||
<p>Get live support at <b>#go-nuts</b> on <b>irc.freenode.net</b>, the official
|
||||
|
||||
@@ -33,7 +33,7 @@ compiler using the GCC back end, see
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The Go compilers support eight instruction sets.
|
||||
The Go compilers support seven instruction sets.
|
||||
There are important differences in the quality of the compilers for the different
|
||||
architectures.
|
||||
</p>
|
||||
@@ -43,19 +43,23 @@ architectures.
|
||||
<code>amd64</code> (also known as <code>x86-64</code>)
|
||||
</dt>
|
||||
<dd>
|
||||
A mature implementation.
|
||||
A mature implementation. New in 1.7 is its SSA-based back end
|
||||
that generates compact, efficient code.
|
||||
</dd>
|
||||
<dt>
|
||||
<code>386</code> (<code>x86</code> or <code>x86-32</code>)
|
||||
</dt>
|
||||
<dd>
|
||||
Comparable to the <code>amd64</code> port.
|
||||
Comparable to the <code>amd64</code> port, but does
|
||||
not yet use the SSA-based back end. It has an effective
|
||||
optimizer (registerizer) and generates good code (although
|
||||
<code>gccgo</code> can do noticeably better sometimes).
|
||||
</dd>
|
||||
<dt>
|
||||
<code>arm</code> (<code>ARM</code>)
|
||||
</dt>
|
||||
<dd>
|
||||
Supports Linux, FreeBSD, NetBSD, OpenBSD and Darwin binaries. Less widely used than the other ports.
|
||||
Supports Linux, FreeBSD, NetBSD and Darwin binaries. Less widely used than the other ports.
|
||||
</dd>
|
||||
<dt>
|
||||
<code>arm64</code> (<code>AArch64</code>)
|
||||
@@ -69,12 +73,6 @@ architectures.
|
||||
<dd>
|
||||
Supports Linux binaries. New in 1.5 and not as well exercised as other ports.
|
||||
</dd>
|
||||
<dt>
|
||||
<code>mips, mipsle</code> (32-bit MIPS big- and little-endian)
|
||||
</dt>
|
||||
<dd>
|
||||
Supports Linux binaries. New in 1.8 and not as well exercised as other ports.
|
||||
</dd>
|
||||
<dt>
|
||||
<code>mips64, mips64le</code> (64-bit MIPS big- and little-endian)
|
||||
</dt>
|
||||
@@ -218,7 +216,7 @@ To build without <code>cgo</code>, set the environment variable
|
||||
Change to the directory that will be its parent
|
||||
and make sure the <code>go</code> directory does not exist.
|
||||
Then clone the repository and check out the latest release tag
|
||||
(<code class="versionTag">go1.7.4</code>, for example):</p>
|
||||
(<code class="versionTag">go1.7.2</code>, for example):</p>
|
||||
|
||||
<pre>
|
||||
$ git clone https://go.googlesource.com/go
|
||||
@@ -335,7 +333,7 @@ You just need to do a little more setup.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <a href="/doc/code.html">How to Write Go Code</a> document
|
||||
The <a href="/doc/code.html">How to Write Go Code</a> document
|
||||
provides <b>essential setup instructions</b> for using the Go tools.
|
||||
</p>
|
||||
|
||||
@@ -361,7 +359,7 @@ $ go get golang.org/x/tools/cmd/godoc
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
To install these tools, the <code>go</code> <code>get</code> command requires
|
||||
To install these tools, the <code>go</code> <code>get</code> command requires
|
||||
that <a href="#git">Git</a> be installed locally.
|
||||
</p>
|
||||
|
||||
@@ -406,7 +404,7 @@ New releases are announced on the
|
||||
<a href="//groups.google.com/group/golang-announce">golang-announce</a>
|
||||
mailing list.
|
||||
Each announcement mentions the latest release tag, for instance,
|
||||
<code class="versionTag">go1.7.4</code>.
|
||||
<code class="versionTag">go1.7.2</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
@@ -436,7 +434,7 @@ to override the defaults.
|
||||
<ul>
|
||||
<li><code>$GOROOT</code>
|
||||
<p>
|
||||
The root of the Go tree, often <code>$HOME/go1.X</code>.
|
||||
The root of the Go tree, often <code>$HOME/go</code>.
|
||||
Its value is built into the tree when it is compiled, and
|
||||
defaults to the parent of the directory where <code>all.bash</code> was run.
|
||||
There is no need to set this unless you want to switch between multiple
|
||||
@@ -449,7 +447,7 @@ The value assumed by installed binaries and scripts when
|
||||
<code>$GOROOT</code> is not set explicitly.
|
||||
It defaults to the value of <code>$GOROOT</code>.
|
||||
If you want to build the Go tree in one location
|
||||
but move it elsewhere after the build, set
|
||||
but move it elsewhere after the build, set
|
||||
<code>$GOROOT_FINAL</code> to the eventual location.
|
||||
</p>
|
||||
|
||||
@@ -461,7 +459,7 @@ These default to the values of <code>$GOHOSTOS</code> and
|
||||
|
||||
<p>
|
||||
Choices for <code>$GOOS</code> are
|
||||
<code>darwin</code> (Mac OS X 10.8 and above and iOS), <code>dragonfly</code>, <code>freebsd</code>,
|
||||
<code>darwin</code> (Mac OS X 10.7 and above and iOS), <code>dragonfly</code>, <code>freebsd</code>,
|
||||
<code>linux</code>, <code>netbsd</code>, <code>openbsd</code>,
|
||||
<code>plan9</code>, <code>solaris</code> and <code>windows</code>.
|
||||
Choices for <code>$GOARCH</code> are
|
||||
@@ -469,7 +467,6 @@ Choices for <code>$GOARCH</code> are
|
||||
<code>386</code> (32-bit x86), <code>arm</code> (32-bit ARM), <code>arm64</code> (64-bit ARM),
|
||||
<code>ppc64le</code> (PowerPC 64-bit, little-endian), <code>ppc64</code> (PowerPC 64-bit, big-endian),
|
||||
<code>mips64le</code> (MIPS 64-bit, little-endian), and <code>mips64</code> (MIPS 64-bit, big-endian).
|
||||
<code>mipsle</code> (MIPS 32-bit, little-endian), and <code>mips</code> (MIPS 32-bit, big-endian).
|
||||
The valid combinations of <code>$GOOS</code> and <code>$GOARCH</code> are:
|
||||
<table cellpadding="0">
|
||||
<tr>
|
||||
@@ -521,12 +518,6 @@ The valid combinations of <code>$GOOS</code> and <code>$GOARCH</code> are:
|
||||
<td></td><td><code>linux</code></td> <td><code>ppc64le</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td><td><code>linux</code></td> <td><code>mips</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td><td><code>linux</code></td> <td><code>mipsle</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td><td><code>linux</code></td> <td><code>mips64</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -579,7 +570,7 @@ architecture.
|
||||
Valid choices are the same as for <code>$GOOS</code> and
|
||||
<code>$GOARCH</code>, listed above.
|
||||
The specified values must be compatible with the local system.
|
||||
For example, you should not set <code>$GOHOSTARCH</code> to
|
||||
For example, you should not set <code>$GOHOSTARCH</code> to
|
||||
<code>arm</code> on an x86 system.
|
||||
</p>
|
||||
|
||||
@@ -640,12 +631,12 @@ not <code>amd64</code>.
|
||||
<p>
|
||||
If you choose to override the defaults,
|
||||
set these variables in your shell profile (<code>$HOME/.bashrc</code>,
|
||||
<code>$HOME/.profile</code>, or equivalent). The settings might look
|
||||
<code>$HOME/.profile</code>, or equivalent). The settings might look
|
||||
something like this:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
export GOROOT=$HOME/go1.X
|
||||
export GOROOT=$HOME/go
|
||||
export GOARCH=amd64
|
||||
export GOOS=linux
|
||||
</pre>
|
||||
|
||||
@@ -47,14 +47,14 @@ If your OS or architecture is not on the list, you may be able to
|
||||
<th align="center">Notes</th>
|
||||
</tr>
|
||||
<tr><td colspan="3"><hr></td></tr>
|
||||
<tr><td>FreeBSD 8-STABLE or later</td> <td>amd64, 386</td> <td>Debian GNU/kFreeBSD not supported</td></tr>
|
||||
<tr><td>Linux 2.6.23 or later with glibc</td> <td>amd64, 386, arm, s390x, ppc64le</td> <td>CentOS/RHEL 5.x not supported</td></tr>
|
||||
<tr><td>Mac OS X 10.8 or later</td> <td>amd64</td> <td>use the clang or gcc<sup>†</sup> that comes with Xcode<sup>‡</sup> for <code>cgo</code> support</td></tr>
|
||||
<tr><td>FreeBSD 8-STABLE or later</td> <td>amd64</td> <td>Debian GNU/kFreeBSD not supported</td></tr>
|
||||
<tr><td>Linux 2.6.23 or later with glibc</td> <td>amd64, 386, arm</td> <td>CentOS/RHEL 5.x not supported</td></tr>
|
||||
<tr><td>Mac OS X 10.7 or later</td> <td>amd64</td> <td>use the clang or gcc<sup>†</sup> that comes with Xcode<sup>‡</sup> for <code>cgo</code> support</td></tr>
|
||||
<tr><td>Windows XP or later</td> <td>amd64, 386</td> <td>use MinGW gcc<sup>†</sup>. No need for cygwin or msys.</td></tr>
|
||||
</table>
|
||||
|
||||
<p>
|
||||
<sup>†</sup>A C compiler is required only if you plan to use
|
||||
<sup>†</sup><code>gcc</code> is required only if you plan to use
|
||||
<a href="/cmd/cgo">cgo</a>.<br/>
|
||||
<sup>‡</sup>You only need to install the command line tools for
|
||||
<a href="http://developer.apple.com/Xcode/">Xcode</a>. If you have already
|
||||
@@ -117,12 +117,12 @@ to point to the directory in which it was installed.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For example, if you installed Go to your home directory you should add
|
||||
commands like the following to <code>$HOME/.profile</code>:
|
||||
For example, if you installed Go to your home directory you should add the
|
||||
following commands to <code>$HOME/.profile</code>:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
export GOROOT=$HOME/go1.X
|
||||
export GOROOT=$HOME/go
|
||||
export PATH=$PATH:$GOROOT/bin
|
||||
</pre>
|
||||
|
||||
@@ -219,16 +219,37 @@ and building a simple program, as follows.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Create your <a href="code.html#Workspaces">workspace</a> directory,
|
||||
<code class="testUnix">$HOME/go</code><code class="testWindows">%USERPROFILE%\go</code>.
|
||||
(If you'd like to use a different directory,
|
||||
you will need to set the <code>GOPATH</code> environment variable;
|
||||
see <a href="code.html#Workspaces">How to Write Go Code</a> for details.)
|
||||
Create a directory to contain your <a href="code.html#Workspaces">workspace</a>,
|
||||
<code class="testUnix">$HOME/work</code>
|
||||
<code class="testWindows" style="display: none">C:\work</code>
|
||||
for example, and set the <code>GOPATH</code> environment
|
||||
variable to point to that location.
|
||||
</p>
|
||||
|
||||
<pre class="testUnix">
|
||||
$ <b>export GOPATH=$HOME/work</b>
|
||||
</pre>
|
||||
|
||||
<pre class="testWindows" style="display: none">
|
||||
C:\> <b>set GOPATH=C:\work</b>
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
<span class="testUnix">
|
||||
You should put the above command in your shell startup script
|
||||
(<code>$HOME/.profile</code> for example).
|
||||
</span>
|
||||
<span class="testWindows">
|
||||
On Windows, follow the <a href="#windows_env">instructions above</a> to set the
|
||||
<code>GOPATH</code> environment variable on your system.
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Next, make the directory <code>src/hello</code> inside your workspace,
|
||||
and in that directory create a file named <code>hello.go</code> that looks like:
|
||||
Next, make the directories <code>src/github.com/user/hello</code> inside your
|
||||
workspace (if you use GitHub, substitute your user name for <code>user</code>),
|
||||
and inside the <code>hello</code> directory create a file named <code>hello.go</code>
|
||||
with the following contents:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
@@ -242,33 +263,30 @@ func main() {
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Then build it with the <code>go</code> tool:
|
||||
Then compile it with the <code>go</code> tool:
|
||||
</p>
|
||||
|
||||
<pre class="testUnix">
|
||||
$ <b>cd $HOME/go/src/hello</b>
|
||||
$ <b>go build</b>
|
||||
$ <b>go install github.com/user/hello</b>
|
||||
</pre>
|
||||
|
||||
<pre class="testWindows" style="display: none">
|
||||
C:\> <b>cd %USERPROFILE%\go\src\hello</b>
|
||||
C:\Users\Gopher\go\src\hello> <b>go build</b>
|
||||
C:\> <b>go install github.com/user/hello</b>
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The command above will build an executable named
|
||||
<code class="testUnix">hello</code><code class="testWindows">hello.exe</code>
|
||||
in the directory alongside your source code.
|
||||
Execute it to see the greeting:
|
||||
The command above will put an executable command named <code>hello</code>
|
||||
(or <code>hello.exe</code>) inside the <code>bin</code> directory of your workspace.
|
||||
Execute the command to see the greeting:
|
||||
</p>
|
||||
|
||||
<pre class="testUnix">
|
||||
$ <b>./hello</b>
|
||||
$ <b>$GOPATH/bin/hello</b>
|
||||
hello, world
|
||||
</pre>
|
||||
|
||||
<pre class="testWindows" style="display: none">
|
||||
C:\Users\Gopher\go\src\hello> <b>hello</b>
|
||||
C:\> <b>%GOPATH%\bin\hello</b>
|
||||
hello, world
|
||||
</pre>
|
||||
|
||||
@@ -276,12 +294,6 @@ hello, world
|
||||
If you see the "hello, world" message then your Go installation is working.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You can run <code>go</code> <code>install</code> to install the binary into
|
||||
your workspace's <code>bin</code> directory
|
||||
or <code>go</code> <code>clean</code> to remove it.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Before rushing off to write Go code please read the
|
||||
<a href="/doc/code.html">How to Write Go Code</a> document,
|
||||
@@ -313,10 +325,16 @@ environment variables under Windows</a>.
|
||||
<h2 id="help">Getting help</h2>
|
||||
|
||||
<p>
|
||||
For help, see the <a href="/help/">list of Go mailing lists, forums, and places to chat</a>.
|
||||
For real-time help, ask the helpful gophers in <code>#go-nuts</code> on the
|
||||
<a href="http://freenode.net/">Freenode</a> IRC server.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Report bugs either by running “<b><code>go</code> <code>bug</code></b>”, or
|
||||
manually at the <a href="https://golang.org/issue">Go issue tracker</a>.
|
||||
The official mailing list for discussion of the Go language is
|
||||
<a href="//groups.google.com/group/golang-nuts">Go Nuts</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Report bugs using the
|
||||
<a href="//golang.org/issue">Go issue tracker</a>.
|
||||
</p>
|
||||
|
||||
@@ -28,7 +28,7 @@ func Encode() {
|
||||
|
||||
expected := []byte(`{"Name":"Alice","Body":"Hello","Time":1294706395881547000}`)
|
||||
if !reflect.DeepEqual(b, expected) {
|
||||
log.Panicf("Error marshaling %q, expected %q, got %q.", m, expected, b)
|
||||
log.Panicf("Error marshalling %q, expected %q, got %q.", m, expected, b)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -49,7 +49,7 @@ func Decode() {
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(m, expected) {
|
||||
log.Panicf("Error unmarshaling %q, expected %q, got %q.", b, expected, m)
|
||||
log.Panicf("Error unmarshalling %q, expected %q, got %q.", b, expected, m)
|
||||
}
|
||||
|
||||
m = Message{
|
||||
@@ -77,7 +77,7 @@ func PartialDecode() {
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(expected, m) {
|
||||
log.Panicf("Error unmarshaling %q, expected %q, got %q.", b, expected, m)
|
||||
log.Panicf("Error unmarshalling %q, expected %q, got %q.", b, expected, m)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ func Decode() {
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(f, expected) {
|
||||
log.Panicf("Error unmarshaling %q, expected %q, got %q", b, expected, f)
|
||||
log.Panicf("Error unmarshalling %q, expected %q, got %q", b, expected, f)
|
||||
}
|
||||
|
||||
f = map[string]interface{}{
|
||||
|
||||
@@ -36,7 +36,7 @@ func Decode() {
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(expected, m) {
|
||||
log.Panicf("Error unmarshaling %q, expected %q, got %q", b, expected, m)
|
||||
log.Panicf("Error unmarshalling %q, expected %q, got %q", b, expected, m)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
# Consult http://www.iana.org/time-zones for the latest versions.
|
||||
|
||||
# Versions to use.
|
||||
CODE=2016j
|
||||
DATA=2016j
|
||||
CODE=2016f
|
||||
DATA=2016f
|
||||
|
||||
set -e
|
||||
rm -rf work
|
||||
|
||||
Binary file not shown.
@@ -1,17 +0,0 @@
|
||||
// Copyright 2016 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.
|
||||
|
||||
// Issue 16591: Test that we detect an invalid call that was being
|
||||
// hidden by a type conversion inserted by cgo checking.
|
||||
|
||||
package p
|
||||
|
||||
// void f(int** p) { }
|
||||
import "C"
|
||||
|
||||
type x *C.int
|
||||
|
||||
func F(p *x) {
|
||||
C.f(p) // ERROR HERE
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
// Copyright 2016 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.
|
||||
|
||||
// Test that C.malloc does not return nil.
|
||||
|
||||
package main
|
||||
|
||||
// #include <stdlib.h>
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var size C.size_t
|
||||
size--
|
||||
|
||||
// The Dragonfly libc succeeds when asked to allocate
|
||||
// 0xffffffffffffffff bytes, so pass a different value that
|
||||
// causes it to fail.
|
||||
if runtime.GOOS == "dragonfly" {
|
||||
size = C.size_t(0x7fffffff << (32 * (^uintptr(0) >> 63)))
|
||||
}
|
||||
|
||||
p := C.malloc(size)
|
||||
if p == nil {
|
||||
fmt.Println("malloc: C.malloc returned nil")
|
||||
// Just exit normally--the test script expects this
|
||||
// program to crash, so exiting normally indicates failure.
|
||||
}
|
||||
}
|
||||
@@ -322,27 +322,6 @@ var ptrTests = []ptrTest{
|
||||
body: `p := &C.s{}; defer C.f(p); p.p = new(C.int)`,
|
||||
fail: true,
|
||||
},
|
||||
{
|
||||
// Check a pointer to a union if the union has any
|
||||
// pointer fields.
|
||||
name: "union1",
|
||||
c: `typedef union { char **p; unsigned long i; } u; void f(u *pu) {}`,
|
||||
imports: []string{"unsafe"},
|
||||
body: `var b C.char; p := &b; C.f((*C.u)(unsafe.Pointer(&p)))`,
|
||||
fail: true,
|
||||
},
|
||||
{
|
||||
// Don't check a pointer to a union if the union does
|
||||
// not have any pointer fields.
|
||||
// Like ptrdata1 above, the uintptr represents an
|
||||
// integer that happens to have the same
|
||||
// representation as a pointer.
|
||||
name: "union2",
|
||||
c: `typedef union { unsigned long i; } u; void f(u *pu) {}`,
|
||||
imports: []string{"unsafe"},
|
||||
body: `var b C.char; p := &b; C.f((*C.u)(unsafe.Pointer(&p)))`,
|
||||
fail: false,
|
||||
},
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
@@ -46,7 +46,6 @@ check issue13423.go
|
||||
expect issue13635.go C.uchar C.schar C.ushort C.uint C.ulong C.longlong C.ulonglong C.complexfloat C.complexdouble
|
||||
check issue13830.go
|
||||
check issue16116.go
|
||||
check issue16591.go
|
||||
|
||||
if ! go build issue14669.go; then
|
||||
exit 1
|
||||
@@ -59,15 +58,5 @@ if ! go run ptr.go; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# The malloc.go test should crash.
|
||||
rm -f malloc.out
|
||||
if go run malloc.go >malloc.out 2>&1; then
|
||||
echo '`go run malloc.go` succeeded unexpectedly'
|
||||
cat malloc.out
|
||||
rm -f malloc.out
|
||||
exit 1
|
||||
fi
|
||||
rm -f malloc.out
|
||||
|
||||
rm -rf errs _obj
|
||||
exit 0
|
||||
|
||||
@@ -7,11 +7,6 @@
|
||||
package cgotest
|
||||
|
||||
// #include <stdlib.h>
|
||||
//
|
||||
// // Test for issue 17723.
|
||||
// typedef char *cstring_pointer;
|
||||
// static void cstring_pointer_fun(cstring_pointer dummy) { }
|
||||
//
|
||||
// const char *api_hello = "hello!";
|
||||
import "C"
|
||||
import "unsafe"
|
||||
@@ -26,5 +21,4 @@ func testAPI() {
|
||||
var b []byte
|
||||
b = C.GoBytes(unsafe.Pointer(C.api_hello), C.int(6))
|
||||
_, _ = s, b
|
||||
C.cstring_pointer_fun(nil)
|
||||
}
|
||||
|
||||
@@ -162,6 +162,3 @@ func testUnsignedInt(t *testing.T) {
|
||||
func sliceOperands(array [2000]int) {
|
||||
_ = array[C.KILO:C.KILO:C.KILO] // no type error
|
||||
}
|
||||
|
||||
// set in cgo_thread_lock.go init
|
||||
var testThreadLockFunc = func(*testing.T) {}
|
||||
|
||||
@@ -186,7 +186,6 @@ func testCallbackCallers(t *testing.T) {
|
||||
"runtime.asmcgocall",
|
||||
"runtime.cgocall",
|
||||
"test._Cfunc_callback",
|
||||
"test.nestedCall.func1",
|
||||
"test.nestedCall",
|
||||
"test.testCallbackCallers",
|
||||
"test.TestCallbackCallers",
|
||||
|
||||
@@ -70,11 +70,5 @@ func Test12030(t *testing.T) { test12030(t) }
|
||||
func TestGCC68255(t *testing.T) { testGCC68255(t) }
|
||||
func TestCallGoWithString(t *testing.T) { testCallGoWithString(t) }
|
||||
func Test14838(t *testing.T) { test14838(t) }
|
||||
func Test8756(t *testing.T) { test8756(t) }
|
||||
func Test17065(t *testing.T) { test17065(t) }
|
||||
func TestThreadLock(t *testing.T) { testThreadLockFunc(t) }
|
||||
func TestCheckConst(t *testing.T) { testCheckConst(t) }
|
||||
func Test17537(t *testing.T) { test17537(t) }
|
||||
func Test18126(t *testing.T) { test18126(t) }
|
||||
|
||||
func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build linux,freebsd,openbsd
|
||||
|
||||
package cgotest
|
||||
|
||||
/*
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
void Gosched(void);
|
||||
static int Ctid(void) { Gosched(); return syscall(SYS_gettid); }
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
//export Gosched
|
||||
func Gosched() {
|
||||
runtime.Gosched()
|
||||
}
|
||||
|
||||
func init() {
|
||||
testThreadLockFunc = testThreadLock
|
||||
}
|
||||
|
||||
func testThreadLock(t *testing.T) {
|
||||
stop := make(chan int)
|
||||
go func() {
|
||||
// We need the G continue running,
|
||||
// so the M has a chance to run this G.
|
||||
for {
|
||||
select {
|
||||
case <-stop:
|
||||
return
|
||||
case <-time.After(time.Millisecond * 100):
|
||||
}
|
||||
}
|
||||
}()
|
||||
defer close(stop)
|
||||
|
||||
for i := 0; i < 1000; i++ {
|
||||
if C.int(syscall.Gettid()) != C.Ctid() {
|
||||
t.Fatalf("cgo has not locked OS thread")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,4 +10,3 @@ import "testing"
|
||||
|
||||
func TestSigaltstack(t *testing.T) { testSigaltstack(t) }
|
||||
func TestSigprocmask(t *testing.T) { testSigprocmask(t) }
|
||||
func Test18146(t *testing.T) { test18146(t) }
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
// Copyright 2016 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.
|
||||
|
||||
// Test a constant in conjunction with pointer checking.
|
||||
|
||||
package cgotest
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
|
||||
#define CheckConstVal 0
|
||||
|
||||
typedef struct {
|
||||
int *p;
|
||||
} CheckConstStruct;
|
||||
|
||||
static void CheckConstFunc(CheckConstStruct *p, int e) {
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func testCheckConst(t *testing.T) {
|
||||
// The test is that this compiles successfully.
|
||||
p := C.malloc(C.size_t(unsafe.Sizeof(C.int(0))))
|
||||
defer C.free(p)
|
||||
C.CheckConstFunc(&C.CheckConstStruct{(*C.int)(p)}, C.CheckConstVal)
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
// Copyright 2016 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 cgotest
|
||||
|
||||
/*
|
||||
struct {
|
||||
float x;
|
||||
_Complex float y;
|
||||
} cplxAlign = { 3.14, 2.17 };
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestComplexAlign(t *testing.T) {
|
||||
if C.cplxAlign.x != 3.14 {
|
||||
t.Errorf("got %v, expected 3.14", C.cplxAlign.x)
|
||||
}
|
||||
if C.cplxAlign.y != 2.17 {
|
||||
t.Errorf("got %v, expected 2.17", C.cplxAlign.y)
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
// Copyright 2016 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 cgotest
|
||||
|
||||
/*
|
||||
// Test that C symbols larger than a page play nicely with the race detector.
|
||||
// See issue 17065.
|
||||
|
||||
int ii[65537];
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var sink C.int
|
||||
|
||||
func test17065(t *testing.T) {
|
||||
if runtime.GOOS == "darwin" {
|
||||
t.Skip("broken on darwin; issue 17065")
|
||||
}
|
||||
for i := range C.ii {
|
||||
sink = C.ii[i]
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
// Copyright 2016 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.
|
||||
|
||||
// Issue 17537. The void* cast introduced by cgo to avoid problems
|
||||
// with const/volatile qualifiers breaks C preprocessor macros that
|
||||
// emulate functions.
|
||||
|
||||
package cgotest
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct {
|
||||
int i;
|
||||
} S17537;
|
||||
|
||||
int I17537(S17537 *p);
|
||||
|
||||
#define I17537(p) ((p)->i)
|
||||
|
||||
// Calling this function used to fail without the cast.
|
||||
const int F17537(const char **p) {
|
||||
return **p;
|
||||
}
|
||||
|
||||
// Calling this function used to trigger an error from the C compiler
|
||||
// (issue 18298).
|
||||
void F18298(const void *const *p) {
|
||||
}
|
||||
|
||||
// Test that conversions between typedefs work as they used to.
|
||||
typedef const void *T18298_1;
|
||||
struct S18298 { int i; };
|
||||
typedef const struct S18298 *T18298_2;
|
||||
void G18298(T18298_1 t) {
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import "testing"
|
||||
|
||||
func test17537(t *testing.T) {
|
||||
v := C.S17537{i: 17537}
|
||||
if got, want := C.I17537(&v), C.int(17537); got != want {
|
||||
t.Errorf("got %d, want %d", got, want)
|
||||
}
|
||||
|
||||
p := (*C.char)(C.malloc(1))
|
||||
*p = 17
|
||||
if got, want := C.F17537(&p), C.int(17); got != want {
|
||||
t.Errorf("got %d, want %d", got, want)
|
||||
}
|
||||
|
||||
C.F18298(nil)
|
||||
var v18298 C.T18298_2
|
||||
C.G18298(C.T18298_1(v18298))
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
// Copyright 2016 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.
|
||||
|
||||
// Issue 18126: cgo check of void function returning errno.
|
||||
|
||||
package cgotest
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
|
||||
void Issue18126C(void **p) {
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func test18126(t *testing.T) {
|
||||
p := C.malloc(1)
|
||||
_, err := C.Issue18126C(&p)
|
||||
C.free(p)
|
||||
_ = err
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !windows
|
||||
|
||||
// Issue 18146: pthread_create failure during syscall.Exec.
|
||||
|
||||
package cgotest
|
||||
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/md5"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func test18146(t *testing.T) {
|
||||
if runtime.GOOS == "darwin" {
|
||||
t.Skipf("skipping flaky test on %s; see golang.org/issue/18202", runtime.GOOS)
|
||||
}
|
||||
|
||||
if runtime.GOARCH == "mips" || runtime.GOARCH == "mips64" {
|
||||
t.Skipf("skipping on %s", runtime.GOARCH)
|
||||
}
|
||||
|
||||
attempts := 1000
|
||||
threads := 4
|
||||
|
||||
if testing.Short() {
|
||||
attempts = 100
|
||||
}
|
||||
|
||||
// Restrict the number of attempts based on RLIMIT_NPROC.
|
||||
// Tediously, RLIMIT_NPROC was left out of the syscall package,
|
||||
// probably because it is not in POSIX.1, so we define it here.
|
||||
// It is not defined on Solaris.
|
||||
var nproc int
|
||||
setNproc := true
|
||||
switch runtime.GOOS {
|
||||
default:
|
||||
setNproc = false
|
||||
case "linux":
|
||||
nproc = 6
|
||||
case "darwin", "dragonfly", "freebsd", "netbsd", "openbsd":
|
||||
nproc = 7
|
||||
}
|
||||
if setNproc {
|
||||
var rlim syscall.Rlimit
|
||||
if syscall.Getrlimit(nproc, &rlim) == nil {
|
||||
max := int(rlim.Cur) / (threads + 5)
|
||||
if attempts > max {
|
||||
t.Logf("lowering attempts from %d to %d for RLIMIT_NPROC", attempts, max)
|
||||
attempts = max
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if os.Getenv("test18146") == "exec" {
|
||||
runtime.GOMAXPROCS(1)
|
||||
for n := threads; n > 0; n-- {
|
||||
go func() {
|
||||
for {
|
||||
_ = md5.Sum([]byte("Hello, !"))
|
||||
}
|
||||
}()
|
||||
}
|
||||
runtime.GOMAXPROCS(threads)
|
||||
argv := append(os.Args, "-test.run=NoSuchTestExists")
|
||||
if err := syscall.Exec(os.Args[0], argv, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
var cmds []*exec.Cmd
|
||||
defer func() {
|
||||
for _, cmd := range cmds {
|
||||
cmd.Process.Kill()
|
||||
}
|
||||
}()
|
||||
|
||||
args := append(append([]string(nil), os.Args[1:]...), "-test.run=Test18146")
|
||||
for n := attempts; n > 0; n-- {
|
||||
cmd := exec.Command(os.Args[0], args...)
|
||||
cmd.Env = append(os.Environ(), "test18146=exec")
|
||||
buf := bytes.NewBuffer(nil)
|
||||
cmd.Stdout = buf
|
||||
cmd.Stderr = buf
|
||||
if err := cmd.Start(); err != nil {
|
||||
// We are starting so many processes that on
|
||||
// some systems (problem seen on Darwin,
|
||||
// Dragonfly, OpenBSD) the fork call will fail
|
||||
// with EAGAIN.
|
||||
if pe, ok := err.(*os.PathError); ok {
|
||||
err = pe.Err
|
||||
}
|
||||
if se, ok := err.(syscall.Errno); ok && (se == syscall.EAGAIN || se == syscall.EMFILE) {
|
||||
time.Sleep(time.Millisecond)
|
||||
continue
|
||||
}
|
||||
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
cmds = append(cmds, cmd)
|
||||
}
|
||||
|
||||
failures := 0
|
||||
for _, cmd := range cmds {
|
||||
err := cmd.Wait()
|
||||
if err == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
t.Errorf("syscall.Exec failed: %v\n%s", err, cmd.Stdout)
|
||||
failures++
|
||||
}
|
||||
|
||||
if failures > 0 {
|
||||
t.Logf("Failed %v of %v attempts.", failures, len(cmds))
|
||||
}
|
||||
}
|
||||
@@ -88,20 +88,9 @@ func issue7978wait(store uint32, wait uint32) {
|
||||
|
||||
//export issue7978cb
|
||||
func issue7978cb() {
|
||||
// Force a stack growth from the callback to put extra
|
||||
// pressure on the runtime. See issue #17785.
|
||||
growStack(64)
|
||||
issue7978wait(3, 4)
|
||||
}
|
||||
|
||||
func growStack(n int) int {
|
||||
var buf [128]int
|
||||
if n == 0 {
|
||||
return 0
|
||||
}
|
||||
return buf[growStack(n-1)]
|
||||
}
|
||||
|
||||
func issue7978go() {
|
||||
C.issue7978c((*C.uint32_t)(&issue7978sync))
|
||||
issue7978wait(7, 8)
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
package cgotest
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -lm
|
||||
#include <math.h>
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"./issue8756"
|
||||
)
|
||||
|
||||
func test8756(t *testing.T) {
|
||||
issue8756.Pow()
|
||||
C.pow(1, 2)
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package issue8756
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -lm
|
||||
#include <math.h>
|
||||
*/
|
||||
import "C"
|
||||
|
||||
func Pow() {
|
||||
C.pow(1, 2)
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build mips mipsle
|
||||
// +build !gccgo
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
TEXT ·RewindAndSetgid(SB),NOSPLIT,$-4-0
|
||||
// Rewind stack pointer so anything that happens on the stack
|
||||
// will clobber the test pattern created by the caller
|
||||
ADDU $(1024*8), R29
|
||||
|
||||
// Ask signaller to setgid
|
||||
MOVW $1, R1
|
||||
SYNC
|
||||
MOVW R1, ·Baton(SB)
|
||||
SYNC
|
||||
|
||||
// Wait for setgid completion
|
||||
loop:
|
||||
SYNC
|
||||
MOVW ·Baton(SB), R1
|
||||
OR R2, R2, R2 // hint that we're in a spin loop
|
||||
BNE R1, loop
|
||||
SYNC
|
||||
|
||||
// Restore stack
|
||||
ADDU $(-1024*8), R29
|
||||
RET
|
||||
@@ -6,7 +6,6 @@ package carchive_test
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"debug/elf"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
@@ -35,9 +34,13 @@ var GOOS, GOARCH string
|
||||
var libgodir string
|
||||
|
||||
func init() {
|
||||
bin = []string{"./testp"}
|
||||
GOOS = goEnv("GOOS")
|
||||
GOARCH = goEnv("GOARCH")
|
||||
bin = cmdToRun("./testp")
|
||||
execScript := "go_" + GOOS + "_" + GOARCH + "_exec"
|
||||
if executor, err := exec.LookPath(execScript); err == nil {
|
||||
bin = []string{executor, "./testp"}
|
||||
}
|
||||
|
||||
ccOut := goEnv("CC")
|
||||
cc = []string{string(ccOut)}
|
||||
@@ -81,13 +84,8 @@ func init() {
|
||||
cc = append(cc, []string{"-framework", "CoreFoundation", "-framework", "Foundation"}...)
|
||||
}
|
||||
libgodir = GOOS + "_" + GOARCH
|
||||
switch GOOS {
|
||||
case "darwin":
|
||||
if GOARCH == "arm" || GOARCH == "arm64" {
|
||||
libgodir += "_shared"
|
||||
}
|
||||
case "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris":
|
||||
libgodir += "_shared"
|
||||
if GOOS == "darwin" && (GOARCH == "arm" || GOARCH == "arm64") {
|
||||
libgodir = GOOS + "_" + GOARCH + "_shared"
|
||||
}
|
||||
cc = append(cc, "-I", filepath.Join("pkg", libgodir))
|
||||
|
||||
@@ -122,62 +120,81 @@ func goEnv(key string) string {
|
||||
return strings.TrimSpace(string(out))
|
||||
}
|
||||
|
||||
func cmdToRun(name string) []string {
|
||||
execScript := "go_" + goEnv("GOOS") + "_" + goEnv("GOARCH") + "_exec"
|
||||
executor, err := exec.LookPath(execScript)
|
||||
if err != nil {
|
||||
return []string{name}
|
||||
}
|
||||
return []string{executor, name}
|
||||
}
|
||||
|
||||
func testInstall(t *testing.T, exe, libgoa, libgoh string, buildcmd ...string) {
|
||||
cmd := exec.Command(buildcmd[0], buildcmd[1:]...)
|
||||
cmd.Env = gopathEnv
|
||||
if out, err := cmd.CombinedOutput(); err != nil {
|
||||
t.Logf("%s", out)
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
os.Remove(libgoa)
|
||||
os.Remove(libgoh)
|
||||
}()
|
||||
|
||||
ccArgs := append(cc, "-o", exe, "main.c")
|
||||
func compilemain(t *testing.T, libgo string) {
|
||||
ccArgs := append(cc, "-o", "testp"+exeSuffix, "main.c")
|
||||
if GOOS == "windows" {
|
||||
ccArgs = append(ccArgs, "main_windows.c", libgoa, "-lntdll", "-lws2_32", "-lwinmm")
|
||||
ccArgs = append(ccArgs, "main_windows.c", libgo, "-lntdll", "-lws2_32", "-lwinmm")
|
||||
} else {
|
||||
ccArgs = append(ccArgs, "main_unix.c", libgoa)
|
||||
ccArgs = append(ccArgs, "main_unix.c", libgo)
|
||||
}
|
||||
t.Log(ccArgs)
|
||||
if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
|
||||
t.Logf("%s", out)
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Remove(exe)
|
||||
|
||||
binArgs := append(cmdToRun(exe), "arg1", "arg2")
|
||||
if out, err := exec.Command(binArgs[0], binArgs[1:]...).CombinedOutput(); err != nil {
|
||||
if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
|
||||
t.Logf("%s", out)
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInstall(t *testing.T) {
|
||||
defer os.RemoveAll("pkg")
|
||||
defer func() {
|
||||
os.Remove("libgo.a")
|
||||
os.Remove("libgo.h")
|
||||
os.Remove("testp")
|
||||
os.RemoveAll("pkg")
|
||||
}()
|
||||
|
||||
testInstall(t, "./testp1"+exeSuffix,
|
||||
filepath.Join("pkg", libgodir, "libgo.a"),
|
||||
filepath.Join("pkg", libgodir, "libgo.h"),
|
||||
"go", "install", "-buildmode=c-archive", "libgo")
|
||||
cmd := exec.Command("go", "install", "-buildmode=c-archive", "libgo")
|
||||
cmd.Env = gopathEnv
|
||||
if out, err := cmd.CombinedOutput(); err != nil {
|
||||
t.Logf("%s", out)
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
compilemain(t, filepath.Join("pkg", libgodir, "libgo.a"))
|
||||
|
||||
binArgs := append(bin, "arg1", "arg2")
|
||||
if out, err := exec.Command(binArgs[0], binArgs[1:]...).CombinedOutput(); err != nil {
|
||||
t.Logf("%s", out)
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
os.Remove("libgo.a")
|
||||
os.Remove("libgo.h")
|
||||
os.Remove("testp")
|
||||
|
||||
// Test building libgo other than installing it.
|
||||
// Header files are now present.
|
||||
testInstall(t, "./testp2"+exeSuffix, "libgo.a", "libgo.h",
|
||||
"go", "build", "-buildmode=c-archive", filepath.Join("src", "libgo", "libgo.go"))
|
||||
cmd = exec.Command("go", "build", "-buildmode=c-archive", filepath.Join("src", "libgo", "libgo.go"))
|
||||
cmd.Env = gopathEnv
|
||||
if out, err := cmd.CombinedOutput(); err != nil {
|
||||
t.Logf("%s", out)
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
testInstall(t, "./testp3"+exeSuffix, "libgo.a", "libgo.h",
|
||||
"go", "build", "-buildmode=c-archive", "-o", "libgo.a", "libgo")
|
||||
compilemain(t, "libgo.a")
|
||||
|
||||
if out, err := exec.Command(binArgs[0], binArgs[1:]...).CombinedOutput(); err != nil {
|
||||
t.Logf("%s", out)
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
os.Remove("libgo.a")
|
||||
os.Remove("libgo.h")
|
||||
os.Remove("testp")
|
||||
|
||||
cmd = exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo.a", "libgo")
|
||||
cmd.Env = gopathEnv
|
||||
if out, err := cmd.CombinedOutput(); err != nil {
|
||||
t.Logf("%s", out)
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
compilemain(t, "libgo.a")
|
||||
|
||||
if out, err := exec.Command(binArgs[0], binArgs[1:]...).CombinedOutput(); err != nil {
|
||||
t.Logf("%s", out)
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEarlySignalHandler(t *testing.T) {
|
||||
@@ -470,71 +487,3 @@ func TestExtar(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPIE(t *testing.T) {
|
||||
switch GOOS {
|
||||
case "windows", "darwin", "plan9":
|
||||
t.Skipf("skipping PIE test on %s", GOOS)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
os.Remove("testp" + exeSuffix)
|
||||
os.RemoveAll("pkg")
|
||||
}()
|
||||
|
||||
cmd := exec.Command("go", "install", "-buildmode=c-archive", "libgo")
|
||||
cmd.Env = gopathEnv
|
||||
if out, err := cmd.CombinedOutput(); err != nil {
|
||||
t.Logf("%s", out)
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ccArgs := append(cc, "-fPIE", "-pie", "-o", "testp"+exeSuffix, "main.c", "main_unix.c", filepath.Join("pkg", libgodir, "libgo.a"))
|
||||
if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
|
||||
t.Logf("%s", out)
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
binArgs := append(bin, "arg1", "arg2")
|
||||
if out, err := exec.Command(binArgs[0], binArgs[1:]...).CombinedOutput(); err != nil {
|
||||
t.Logf("%s", out)
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
f, err := elf.Open("testp" + exeSuffix)
|
||||
if err != nil {
|
||||
t.Fatal("elf.Open failed: ", err)
|
||||
}
|
||||
defer f.Close()
|
||||
if hasDynTag(t, f, elf.DT_TEXTREL) {
|
||||
t.Errorf("%s has DT_TEXTREL flag", "testp"+exeSuffix)
|
||||
}
|
||||
}
|
||||
|
||||
func hasDynTag(t *testing.T, f *elf.File, tag elf.DynTag) bool {
|
||||
ds := f.SectionByType(elf.SHT_DYNAMIC)
|
||||
if ds == nil {
|
||||
t.Error("no SHT_DYNAMIC section")
|
||||
return false
|
||||
}
|
||||
d, err := ds.Data()
|
||||
if err != nil {
|
||||
t.Errorf("can't read SHT_DYNAMIC contents: %v", err)
|
||||
return false
|
||||
}
|
||||
for len(d) > 0 {
|
||||
var t elf.DynTag
|
||||
switch f.Class {
|
||||
case elf.ELFCLASS32:
|
||||
t = elf.DynTag(f.ByteOrder.Uint32(d[:4]))
|
||||
d = d[8:]
|
||||
case elf.ELFCLASS64:
|
||||
t = elf.DynTag(f.ByteOrder.Uint64(d[:8]))
|
||||
d = d[16:]
|
||||
}
|
||||
if t == tag {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -7,10 +7,8 @@
|
||||
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
@@ -48,22 +46,11 @@ static void ioHandler(int signo, siginfo_t* info, void* ctxt) {
|
||||
static jmp_buf jmp;
|
||||
static char* nullPointer;
|
||||
|
||||
// An arbitrary function which requires proper stack alignment; see
|
||||
// http://golang.org/issue/17641.
|
||||
static void callWithVarargs(void* dummy, ...) {
|
||||
va_list args;
|
||||
va_start(args, dummy);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
// Signal handler for SIGSEGV on a C thread.
|
||||
static void segvHandler(int signo, siginfo_t* info, void* ctxt) {
|
||||
sigset_t mask;
|
||||
int i;
|
||||
|
||||
// Call an arbitrary function that requires the stack to be properly aligned.
|
||||
callWithVarargs("dummy arg", 3.1415);
|
||||
|
||||
if (sigemptyset(&mask) < 0) {
|
||||
die("sigemptyset");
|
||||
}
|
||||
@@ -112,7 +99,6 @@ int main(int argc, char** argv) {
|
||||
int verbose;
|
||||
sigset_t mask;
|
||||
int i;
|
||||
struct timespec ts;
|
||||
|
||||
verbose = argc > 1;
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
@@ -162,11 +148,11 @@ int main(int argc, char** argv) {
|
||||
// Wait until the signal has been delivered.
|
||||
i = 0;
|
||||
while (!sigioSeen) {
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 1000000;
|
||||
nanosleep(&ts, NULL);
|
||||
if (sched_yield() < 0) {
|
||||
perror("sched_yield");
|
||||
}
|
||||
i++;
|
||||
if (i > 5000) {
|
||||
if (i > 100000) {
|
||||
fprintf(stderr, "looping too long waiting for signal\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sched.h>
|
||||
|
||||
#include "libgo3.h"
|
||||
@@ -29,7 +28,6 @@ int main(int argc, char** argv) {
|
||||
int verbose;
|
||||
struct sigaction sa;
|
||||
int i;
|
||||
struct timespec ts;
|
||||
|
||||
verbose = argc > 2;
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
@@ -66,11 +64,11 @@ int main(int argc, char** argv) {
|
||||
// Wait until the signal has been delivered.
|
||||
i = 0;
|
||||
while (!sigioSeen) {
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 1000000;
|
||||
nanosleep(&ts, NULL);
|
||||
if (sched_yield() < 0) {
|
||||
perror("sched_yield");
|
||||
}
|
||||
i++;
|
||||
if (i > 5000) {
|
||||
if (i > 100000) {
|
||||
fprintf(stderr, "looping too long waiting for signal\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@@ -140,11 +138,11 @@ int main(int argc, char** argv) {
|
||||
// Wait until the signal has been delivered.
|
||||
i = 0;
|
||||
while (!sigioSeen) {
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 1000000;
|
||||
nanosleep(&ts, NULL);
|
||||
if (sched_yield() < 0) {
|
||||
perror("sched_yield");
|
||||
}
|
||||
i++;
|
||||
if (i > 5000) {
|
||||
if (i > 100000) {
|
||||
fprintf(stderr, "looping too long waiting for signal\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sched.h>
|
||||
#include <pthread.h>
|
||||
|
||||
@@ -49,7 +48,6 @@ static void* thread1(void* arg __attribute__ ((unused))) {
|
||||
stack_t ss;
|
||||
int i;
|
||||
stack_t nss;
|
||||
struct timespec ts;
|
||||
|
||||
// Set up an alternate signal stack for this thread.
|
||||
memset(&ss, 0, sizeof ss);
|
||||
@@ -75,11 +73,11 @@ static void* thread1(void* arg __attribute__ ((unused))) {
|
||||
// Wait until the signal has been delivered.
|
||||
i = 0;
|
||||
while (SIGIOCount() == 0) {
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 1000000;
|
||||
nanosleep(&ts, NULL);
|
||||
if (sched_yield() < 0) {
|
||||
perror("sched_yield");
|
||||
}
|
||||
i++;
|
||||
if (i > 5000) {
|
||||
if (i > 100000) {
|
||||
fprintf(stderr, "looping too long waiting for signal\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@@ -107,7 +105,6 @@ static void* thread2(void* arg __attribute__ ((unused))) {
|
||||
int i;
|
||||
int oldcount;
|
||||
pthread_t tid;
|
||||
struct timespec ts;
|
||||
stack_t nss;
|
||||
|
||||
// Set up an alternate signal stack for this thread.
|
||||
@@ -132,11 +129,11 @@ static void* thread2(void* arg __attribute__ ((unused))) {
|
||||
// Wait until the signal has been delivered.
|
||||
i = 0;
|
||||
while (SIGIOCount() == oldcount) {
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 1000000;
|
||||
nanosleep(&ts, NULL);
|
||||
if (sched_yield() < 0) {
|
||||
perror("sched_yield");
|
||||
}
|
||||
i++;
|
||||
if (i > 5000) {
|
||||
if (i > 100000) {
|
||||
fprintf(stderr, "looping too long waiting for signal\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ int main(void) {
|
||||
|
||||
// The descriptor will be initialized in a thread, so we have to
|
||||
// give a chance to get opened.
|
||||
for (i = 0; i < 1000; i++) {
|
||||
for (i = 0; i < 100; i++) {
|
||||
n = read(fd, buf, sizeof buf);
|
||||
if (n >= 0)
|
||||
break;
|
||||
|
||||
@@ -77,7 +77,6 @@ int main(int argc, char** argv) {
|
||||
void (*fn)(void);
|
||||
sigset_t mask;
|
||||
int i;
|
||||
struct timespec ts;
|
||||
|
||||
verbose = argc > 2;
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
@@ -167,11 +166,11 @@ int main(int argc, char** argv) {
|
||||
// Wait until the signal has been delivered.
|
||||
i = 0;
|
||||
while (!sigioSeen) {
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 1000000;
|
||||
nanosleep(&ts, NULL);
|
||||
if (sched_yield() < 0) {
|
||||
perror("sched_yield");
|
||||
}
|
||||
i++;
|
||||
if (i > 5000) {
|
||||
if (i > 100000) {
|
||||
fprintf(stderr, "looping too long waiting for signal\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sched.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
@@ -32,7 +31,6 @@ int main(int argc, char** argv) {
|
||||
void (*fn1)(void);
|
||||
int (*sawSIGIO)(void);
|
||||
int i;
|
||||
struct timespec ts;
|
||||
|
||||
verbose = argc > 2;
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
@@ -79,11 +77,11 @@ int main(int argc, char** argv) {
|
||||
// Wait until the signal has been delivered.
|
||||
i = 0;
|
||||
while (!sigioSeen) {
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 1000000;
|
||||
nanosleep(&ts, NULL);
|
||||
if (sched_yield() < 0) {
|
||||
perror("sched_yield");
|
||||
}
|
||||
i++;
|
||||
if (i > 5000) {
|
||||
if (i > 100000) {
|
||||
fprintf(stderr, "looping too long waiting for signal\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@@ -184,11 +182,11 @@ int main(int argc, char** argv) {
|
||||
// Wait until the signal has been delivered.
|
||||
i = 0;
|
||||
while (!sigioSeen) {
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 1000000;
|
||||
nanosleep(&ts, NULL);
|
||||
if (sched_yield() < 0) {
|
||||
perror("sched_yield");
|
||||
}
|
||||
i++;
|
||||
if (i > 5000) {
|
||||
if (i > 100000) {
|
||||
fprintf(stderr, "looping too long waiting for signal\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ status=0
|
||||
|
||||
# test0: exported symbols in shared lib are accessible.
|
||||
# TODO(iant): using _shared here shouldn't really be necessary.
|
||||
$(go env CC) ${GOGCCFLAGS} -I ${installdir} -o testp main0.c ./libgo.$libext
|
||||
$(go env CC) ${GOGCCFLAGS} -I ${installdir} -o testp main0.c libgo.$libext
|
||||
binpush testp
|
||||
|
||||
output=$(run LD_LIBRARY_PATH=. ./testp)
|
||||
|
||||
@@ -12,7 +12,7 @@ FILE_PREFIXES="anonunion issue8478"
|
||||
RM=
|
||||
for FP in $FILE_PREFIXES
|
||||
do
|
||||
go tool cgo -godefs -srcdir . ${FP}.go > ${FP}_defs.go
|
||||
go tool cgo -godefs ${FP}.go > ${FP}_defs.go
|
||||
RM="${RM} ${FP}_defs.go"
|
||||
done
|
||||
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
// Copyright 2016 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 common
|
||||
|
||||
var X int
|
||||
|
||||
func init() {
|
||||
X = 4
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
// Copyright 2016 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 main
|
||||
|
||||
// // No C code required.
|
||||
import "C"
|
||||
|
||||
// The common package imported here does not match the common package
|
||||
// imported by plugin1. A program that attempts to load plugin1 and
|
||||
// plugin-mismatch should produce an error.
|
||||
import "common"
|
||||
|
||||
func ReadCommonX() int {
|
||||
return common.X
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
// Copyright 2016 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 common
|
||||
|
||||
var X int
|
||||
|
||||
func init() {
|
||||
X = 3
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
// Copyright 2016 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 main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"path/filepath"
|
||||
"plugin"
|
||||
"strings"
|
||||
|
||||
"common"
|
||||
)
|
||||
|
||||
func init() {
|
||||
common.X *= 5
|
||||
}
|
||||
|
||||
// testUnnamed tests that two plugins built with .go files passed on
|
||||
// the command line do not have overlapping symbols. That is,
|
||||
// unnamed1.so/FuncInt and unnamed2.so/FuncInt should be distinct functions.
|
||||
func testUnnamed() {
|
||||
p, err := plugin.Open("unnamed1.so")
|
||||
if err != nil {
|
||||
log.Fatalf(`plugin.Open("unnamed1.so"): %v`, err)
|
||||
}
|
||||
fn, err := p.Lookup("FuncInt")
|
||||
if err != nil {
|
||||
log.Fatalf(`unnamed1.so: Lookup("FuncInt") failed: %v`, err)
|
||||
}
|
||||
if got, want := fn.(func() int)(), 1; got != want {
|
||||
log.Fatalf("unnamed1.so: FuncInt()=%d, want %d", got, want)
|
||||
}
|
||||
|
||||
p, err = plugin.Open("unnamed2.so")
|
||||
if err != nil {
|
||||
log.Fatalf(`plugin.Open("unnamed2.so"): %v`, err)
|
||||
}
|
||||
fn, err = p.Lookup("FuncInt")
|
||||
if err != nil {
|
||||
log.Fatalf(`unnamed2.so: Lookup("FuncInt") failed: %v`, err)
|
||||
}
|
||||
if got, want := fn.(func() int)(), 2; got != want {
|
||||
log.Fatalf("unnamed2.so: FuncInt()=%d, want %d", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
if got, want := common.X, 3*5; got != want {
|
||||
log.Fatalf("before plugin load common.X=%d, want %d", got, want)
|
||||
}
|
||||
|
||||
p, err := plugin.Open("plugin1.so")
|
||||
if err != nil {
|
||||
log.Fatalf("plugin.Open failed: %v", err)
|
||||
}
|
||||
|
||||
const wantX = 3 * 5 * 7
|
||||
if got := common.X; got != wantX {
|
||||
log.Fatalf("after plugin load common.X=%d, want %d", got, wantX)
|
||||
}
|
||||
|
||||
seven, err := p.Lookup("Seven")
|
||||
if err != nil {
|
||||
log.Fatalf(`Lookup("Seven") failed: %v`, err)
|
||||
}
|
||||
if got, want := *seven.(*int), 7; got != want {
|
||||
log.Fatalf("plugin1.Seven=%d, want %d", got, want)
|
||||
}
|
||||
|
||||
readFunc, err := p.Lookup("ReadCommonX")
|
||||
if err != nil {
|
||||
log.Fatalf(`plugin1.Lookup("ReadCommonX") failed: %v`, err)
|
||||
}
|
||||
if got := readFunc.(func() int)(); got != wantX {
|
||||
log.Fatalf("plugin1.ReadCommonX()=%d, want %d", got, wantX)
|
||||
}
|
||||
|
||||
// sub/plugin1.so is a different plugin with the same name as
|
||||
// the already loaded plugin. It also depends on common. Test
|
||||
// that we can load the different plugin, it is actually
|
||||
// different, and that it sees the same common package.
|
||||
subpPath, err := filepath.Abs("sub/plugin1.so")
|
||||
if err != nil {
|
||||
log.Fatalf("filepath.Abs(%q) failed: %v", subpPath, err)
|
||||
}
|
||||
subp, err := plugin.Open(subpPath)
|
||||
if err != nil {
|
||||
log.Fatalf("plugin.Open(%q) failed: %v", subpPath, err)
|
||||
}
|
||||
|
||||
funcVar, err := subp.Lookup("FuncVar")
|
||||
if err != nil {
|
||||
log.Fatalf(`sub/plugin1.Lookup("FuncVar") failed: %v`, err)
|
||||
}
|
||||
called := false
|
||||
*funcVar.(*func()) = func() {
|
||||
called = true
|
||||
}
|
||||
|
||||
readFunc, err = subp.Lookup("ReadCommonX")
|
||||
if err != nil {
|
||||
log.Fatalf(`sub/plugin1.Lookup("ReadCommonX") failed: %v`, err)
|
||||
}
|
||||
if got := readFunc.(func() int)(); got != wantX {
|
||||
log.Fatalf("sub/plugin1.ReadCommonX()=%d, want %d", got, wantX)
|
||||
}
|
||||
if !called {
|
||||
log.Fatal("calling ReadCommonX did not call FuncVar")
|
||||
}
|
||||
|
||||
subf, err := subp.Lookup("F")
|
||||
if err != nil {
|
||||
log.Fatalf(`sub/plugin1.Lookup("F") failed: %v`, err)
|
||||
}
|
||||
if gotf := subf.(func() int)(); gotf != 17 {
|
||||
log.Fatalf(`sub/plugin1.F()=%d, want 17`, gotf)
|
||||
}
|
||||
f, err := p.Lookup("F")
|
||||
if err != nil {
|
||||
log.Fatalf(`plugin1.Lookup("F") failed: %v`, err)
|
||||
}
|
||||
if gotf := f.(func() int)(); gotf != 3 {
|
||||
log.Fatalf(`plugin1.F()=%d, want 17`, gotf)
|
||||
}
|
||||
|
||||
// plugin2 has no exported symbols, only an init function.
|
||||
if _, err := plugin.Open("plugin2.so"); err != nil {
|
||||
log.Fatalf("plugin.Open failed: %v", err)
|
||||
}
|
||||
if got, want := common.X, 2; got != want {
|
||||
log.Fatalf("after loading plugin2, common.X=%d, want %d", got, want)
|
||||
}
|
||||
|
||||
_, err = plugin.Open("plugin-mismatch.so")
|
||||
if err == nil {
|
||||
log.Fatal(`plugin.Open("plugin-mismatch.so"): should have failed`)
|
||||
}
|
||||
if s := err.Error(); !strings.Contains(s, "different version") {
|
||||
log.Fatalf(`plugin.Open("plugin-mismatch.so"): error does not mention "different version": %v`, s)
|
||||
}
|
||||
|
||||
testUnnamed()
|
||||
|
||||
fmt.Println("PASS")
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
// Copyright 2016 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 main
|
||||
|
||||
// // No C code required.
|
||||
import "C"
|
||||
|
||||
import "common"
|
||||
|
||||
func F() int {
|
||||
_ = make([]byte, 1<<21) // trigger stack unwind, Issue #18190.
|
||||
return 3
|
||||
}
|
||||
|
||||
func ReadCommonX() int {
|
||||
return common.X
|
||||
}
|
||||
|
||||
var Seven int
|
||||
|
||||
func call(fn func()) {
|
||||
fn()
|
||||
}
|
||||
|
||||
func g() {
|
||||
common.X *= Seven
|
||||
}
|
||||
|
||||
func init() {
|
||||
Seven = 7
|
||||
call(g)
|
||||
}
|
||||
|
||||
func main() {
|
||||
panic("plugin1.main called")
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
// Copyright 2016 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 main
|
||||
|
||||
//#include <errno.h>
|
||||
//#include <string.h>
|
||||
import "C"
|
||||
|
||||
// #include
|
||||
// void cfunc() {} // uses cgo_topofstack
|
||||
|
||||
import (
|
||||
"common"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func init() {
|
||||
_ = strings.NewReplacer() // trigger stack unwind, Issue #18190.
|
||||
C.strerror(C.EIO) // uses cgo_topofstack
|
||||
common.X = 2
|
||||
}
|
||||
|
||||
func main() {
|
||||
panic("plugin1.main called")
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
// Copyright 2016 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 main
|
||||
|
||||
// // No C code required.
|
||||
import "C"
|
||||
|
||||
import "common"
|
||||
|
||||
func F() int { return 17 }
|
||||
|
||||
var FuncVar = func() {}
|
||||
|
||||
func ReadCommonX() int {
|
||||
FuncVar()
|
||||
return common.X
|
||||
}
|
||||
|
||||
func main() {
|
||||
panic("plugin1.main called")
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Copyright 2016 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.
|
||||
|
||||
set -e
|
||||
|
||||
if [ ! -f src/host/host.go ]; then
|
||||
cwd=$(pwd)
|
||||
echo "misc/cgo/testplugin/test.bash is running in $cwd" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
goos=$(go env GOOS)
|
||||
goarch=$(go env GOARCH)
|
||||
|
||||
function cleanup() {
|
||||
rm -f plugin*.so unnamed*.so
|
||||
rm -rf host pkg sub
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
rm -rf pkg sub
|
||||
mkdir sub
|
||||
|
||||
GOPATH=$(pwd) go build -buildmode=plugin plugin1
|
||||
GOPATH=$(pwd) go build -buildmode=plugin plugin2
|
||||
GOPATH=$(pwd)/altpath go build -buildmode=plugin plugin-mismatch
|
||||
GOPATH=$(pwd) go build -buildmode=plugin -o=sub/plugin1.so sub/plugin1
|
||||
GOPATH=$(pwd) go build -buildmode=plugin unnamed1.go
|
||||
GOPATH=$(pwd) go build -buildmode=plugin unnamed2.go
|
||||
GOPATH=$(pwd) go build host
|
||||
|
||||
LD_LIBRARY_PATH=$(pwd) ./host
|
||||
@@ -1,12 +0,0 @@
|
||||
// Copyright 2016 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 main
|
||||
|
||||
// // No C code required.
|
||||
import "C"
|
||||
|
||||
func FuncInt() int { return 1 }
|
||||
|
||||
func main() {}
|
||||
@@ -1,12 +0,0 @@
|
||||
// Copyright 2016 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 main
|
||||
|
||||
// // No C code required.
|
||||
import "C"
|
||||
|
||||
func FuncInt() int { return 2 }
|
||||
|
||||
func main() {}
|
||||
@@ -1,57 +0,0 @@
|
||||
// Copyright 2016 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 main
|
||||
|
||||
// Using reflect to set a value was not seen by msan.
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
|
||||
extern void Go1(int*);
|
||||
extern void Go2(char*);
|
||||
|
||||
// Use weak as a hack to permit defining a function even though we use export.
|
||||
void C1() __attribute__ ((weak));
|
||||
void C2() __attribute__ ((weak));
|
||||
|
||||
void C1() {
|
||||
int i;
|
||||
Go1(&i);
|
||||
if (i != 42) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void C2() {
|
||||
char a[2];
|
||||
a[1] = 42;
|
||||
Go2(a);
|
||||
if (a[0] != 42) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
//export Go1
|
||||
func Go1(p *C.int) {
|
||||
reflect.ValueOf(p).Elem().Set(reflect.ValueOf(C.int(42)))
|
||||
}
|
||||
|
||||
//export Go2
|
||||
func Go2(p *C.char) {
|
||||
a := (*[2]byte)(unsafe.Pointer(p))
|
||||
reflect.Copy(reflect.ValueOf(a[:1]), reflect.ValueOf(a[1:]))
|
||||
}
|
||||
|
||||
func main() {
|
||||
C.C1()
|
||||
C.C2()
|
||||
}
|
||||
@@ -15,23 +15,12 @@ if test -x "$(type -p clang)"; then
|
||||
fi
|
||||
export CC
|
||||
|
||||
if [ "$(sysctl -n vm.overcommit_memory)" = 2 ]; then
|
||||
echo "skipping msan/tsan tests: vm.overcommit_memory=2" >&2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
msan=yes
|
||||
|
||||
TMPDIR=${TMPDIR:-/tmp}
|
||||
echo 'int main() { return 0; }' > ${TMPDIR}/testsanitizers$$.c
|
||||
if $CC -fsanitize=memory -o ${TMPDIR}/testsanitizers$$ ${TMPDIR}/testsanitizers$$.c 2>&1 | grep "unrecognized" >& /dev/null; then
|
||||
echo "skipping msan tests: $CC -fsanitize=memory not supported"
|
||||
msan=no
|
||||
elif ! test -x ${TMPDIR}/testsanitizers$$; then
|
||||
echo "skipping msan tests: $CC -fsanitize-memory did not generate an executable"
|
||||
msan=no
|
||||
elif ! ${TMPDIR}/testsanitizers$$ >/dev/null 2>&1; then
|
||||
echo "skipping msan tests: $CC -fsanitize-memory generates broken executable"
|
||||
if $CC -fsanitize=memory -c ${TMPDIR}/testsanitizers$$.c -o ${TMPDIR}/testsanitizers$$.o 2>&1 | grep "unrecognized" >& /dev/null; then
|
||||
echo "skipping msan tests: -fsanitize=memory not supported"
|
||||
msan=no
|
||||
fi
|
||||
rm -f ${TMPDIR}/testsanitizers$$.*
|
||||
@@ -99,11 +88,6 @@ if test "$msan" = "yes"; then
|
||||
status=1
|
||||
fi
|
||||
|
||||
if ! go run -msan msan5.go; then
|
||||
echo "FAIL: msan5"
|
||||
status=1
|
||||
fi
|
||||
|
||||
if go run -msan msan_fail.go 2>/dev/null; then
|
||||
echo "FAIL: msan_fail"
|
||||
status=1
|
||||
@@ -150,8 +134,6 @@ if test "$tsan" = "yes"; then
|
||||
testtsan tsan2.go
|
||||
testtsan tsan3.go
|
||||
testtsan tsan4.go
|
||||
testtsan tsan8.go
|
||||
testtsan tsan9.go
|
||||
|
||||
# These tests are only reliable using clang or GCC version 7 or later.
|
||||
# Otherwise runtime/cgo/libcgo.h can't tell whether TSAN is in use.
|
||||
@@ -174,9 +156,6 @@ if test "$tsan" = "yes"; then
|
||||
|
||||
# This test requires rebuilding runtime/cgo with -fsanitize=thread.
|
||||
testtsan tsan6.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
|
||||
|
||||
# This test requires rebuilding runtime/cgo with -fsanitize=thread.
|
||||
testtsan tsan7.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
// Copyright 2016 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 main
|
||||
|
||||
// Setting an environment variable in a cgo program changes the C
|
||||
// environment. Test that this does not confuse the race detector.
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -fsanitize=thread
|
||||
#cgo LDFLAGS: -fsanitize=thread
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var wg sync.WaitGroup
|
||||
var mu sync.Mutex
|
||||
f := func() {
|
||||
defer wg.Done()
|
||||
for i := 0; i < 100; i++ {
|
||||
time.Sleep(time.Microsecond)
|
||||
mu.Lock()
|
||||
s := fmt.Sprint(i)
|
||||
os.Setenv("TSAN_TEST"+s, s)
|
||||
mu.Unlock()
|
||||
}
|
||||
}
|
||||
wg.Add(2)
|
||||
go f()
|
||||
go f()
|
||||
wg.Wait()
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
// Copyright 2016 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 main
|
||||
|
||||
// This program failed when run under the C/C++ ThreadSanitizer. The TSAN
|
||||
// sigaction function interceptor returned SIG_DFL instead of the Go runtime's
|
||||
// handler in registerSegvForwarder.
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -fsanitize=thread
|
||||
#cgo LDFLAGS: -fsanitize=thread
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct sigaction prev_sa;
|
||||
|
||||
void forwardSignal(int signo, siginfo_t *info, void *context) {
|
||||
// One of sa_sigaction and/or sa_handler
|
||||
if ((prev_sa.sa_flags&SA_SIGINFO) != 0) {
|
||||
prev_sa.sa_sigaction(signo, info, context);
|
||||
return;
|
||||
}
|
||||
if (prev_sa.sa_handler != SIG_IGN && prev_sa.sa_handler != SIG_DFL) {
|
||||
prev_sa.sa_handler(signo);
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(stderr, "No Go handler to forward to!\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
void registerSegvFowarder() {
|
||||
struct sigaction sa;
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
|
||||
sa.sa_sigaction = forwardSignal;
|
||||
|
||||
if (sigaction(SIGSEGV, &sa, &prev_sa) != 0) {
|
||||
perror("failed to register SEGV forwarder");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
func main() {
|
||||
C.registerSegvFowarder()
|
||||
|
||||
defer func() {
|
||||
recover()
|
||||
}()
|
||||
var nilp *int
|
||||
*nilp = 42
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
// Copyright 2016 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 main
|
||||
|
||||
// This program failed when run under the C/C++ ThreadSanitizer. The
|
||||
// TSAN library was not keeping track of whether signals should be
|
||||
// delivered on the alternate signal stack, and the Go signal handler
|
||||
// was not preserving callee-saved registers from C callers.
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -g -fsanitize=thread
|
||||
#cgo LDFLAGS: -g -fsanitize=thread
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
void spin() {
|
||||
size_t n;
|
||||
struct timeval tvstart, tvnow;
|
||||
int diff;
|
||||
void *prev = NULL, *cur;
|
||||
|
||||
gettimeofday(&tvstart, NULL);
|
||||
for (n = 0; n < 1<<20; n++) {
|
||||
cur = malloc(n);
|
||||
free(prev);
|
||||
prev = cur;
|
||||
|
||||
gettimeofday(&tvnow, NULL);
|
||||
diff = (tvnow.tv_sec - tvstart.tv_sec) * 1000 * 1000 + (tvnow.tv_usec - tvstart.tv_usec);
|
||||
|
||||
// Profile frequency is 100Hz so we should definitely
|
||||
// get a signal in 50 milliseconds.
|
||||
if (diff > 50 * 1000) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(prev);
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"runtime/pprof"
|
||||
"time"
|
||||
)
|
||||
|
||||
func goSpin() {
|
||||
start := time.Now()
|
||||
for n := 0; n < 1<<20; n++ {
|
||||
_ = make([]byte, n)
|
||||
if time.Since(start) > 50*time.Millisecond {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
pprof.StartCPUProfile(ioutil.Discard)
|
||||
go C.spin()
|
||||
goSpin()
|
||||
pprof.StopCPUProfile()
|
||||
}
|
||||
@@ -43,7 +43,7 @@ func run(t *testing.T, msg string, args ...string) {
|
||||
}
|
||||
|
||||
// goCmd invokes the go tool with the installsuffix set up by TestMain. It calls
|
||||
// t.Fatalf if the command fails.
|
||||
// t.Errorf if the command fails.
|
||||
func goCmd(t *testing.T, args ...string) {
|
||||
newargs := []string{args[0], "-installsuffix=" + suffix}
|
||||
if testing.Verbose() {
|
||||
@@ -63,7 +63,7 @@ func goCmd(t *testing.T, args ...string) {
|
||||
}
|
||||
if err != nil {
|
||||
if t != nil {
|
||||
t.Fatalf("executing %s failed %v:\n%s", strings.Join(c.Args, " "), err, output)
|
||||
t.Errorf("executing %s failed %v:\n%s", strings.Join(c.Args, " "), err, output)
|
||||
} else {
|
||||
log.Fatalf("executing %s failed %v:\n%s", strings.Join(c.Args, " "), err, output)
|
||||
}
|
||||
@@ -97,9 +97,6 @@ func testMain(m *testing.M) (int, error) {
|
||||
if gorootInstallDir == "" {
|
||||
return 0, errors.New("could not create temporary directory after 10000 tries")
|
||||
}
|
||||
if testing.Verbose() {
|
||||
fmt.Printf("+ mkdir -p %s\n", gorootInstallDir)
|
||||
}
|
||||
defer os.RemoveAll(gorootInstallDir)
|
||||
|
||||
// Some tests need to edit the source in GOPATH, so copy this directory to a
|
||||
@@ -108,9 +105,6 @@ func testMain(m *testing.M) (int, error) {
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("TempDir failed: %v", err)
|
||||
}
|
||||
if testing.Verbose() {
|
||||
fmt.Printf("+ mkdir -p %s\n", scratchDir)
|
||||
}
|
||||
defer os.RemoveAll(scratchDir)
|
||||
err = filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
|
||||
scratchPath := filepath.Join(scratchDir, path)
|
||||
@@ -118,18 +112,12 @@ func testMain(m *testing.M) (int, error) {
|
||||
if path == "." {
|
||||
return nil
|
||||
}
|
||||
if testing.Verbose() {
|
||||
fmt.Printf("+ mkdir -p %s\n", scratchPath)
|
||||
}
|
||||
return os.Mkdir(scratchPath, info.Mode())
|
||||
} else {
|
||||
fromBytes, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if testing.Verbose() {
|
||||
fmt.Printf("+ cp %s %s\n", path, scratchPath)
|
||||
}
|
||||
return ioutil.WriteFile(scratchPath, fromBytes, info.Mode())
|
||||
}
|
||||
})
|
||||
@@ -137,13 +125,7 @@ func testMain(m *testing.M) (int, error) {
|
||||
return 0, fmt.Errorf("walk failed: %v", err)
|
||||
}
|
||||
os.Setenv("GOPATH", scratchDir)
|
||||
if testing.Verbose() {
|
||||
fmt.Printf("+ export GOPATH=%s\n", scratchDir)
|
||||
}
|
||||
myContext.GOPATH = scratchDir
|
||||
if testing.Verbose() {
|
||||
fmt.Printf("+ cd %s\n", scratchDir)
|
||||
}
|
||||
os.Chdir(scratchDir)
|
||||
|
||||
// All tests depend on runtime being built into a shared library. Because
|
||||
@@ -394,14 +376,6 @@ func TestTrivialExecutable(t *testing.T) {
|
||||
AssertHasRPath(t, "./bin/trivial", gorootInstallDir)
|
||||
}
|
||||
|
||||
// Build a trivial program in PIE mode that links against the shared runtime and check it runs.
|
||||
func TestTrivialExecutablePIE(t *testing.T) {
|
||||
goCmd(t, "build", "-buildmode=pie", "-o", "trivial.pie", "-linkshared", "trivial")
|
||||
run(t, "trivial executable", "./trivial.pie")
|
||||
AssertIsLinkedTo(t, "./trivial.pie", soname)
|
||||
AssertHasRPath(t, "./trivial.pie", gorootInstallDir)
|
||||
}
|
||||
|
||||
// Build an executable that uses cgo linked against the shared runtime and check it
|
||||
// runs.
|
||||
func TestCgoExecutable(t *testing.T) {
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
package depBase
|
||||
|
||||
import (
|
||||
"os"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
var V int = 1
|
||||
|
||||
var HasMask []string = []string{"hi"}
|
||||
@@ -18,10 +13,6 @@ type Dep struct {
|
||||
}
|
||||
|
||||
func (d *Dep) Method() int {
|
||||
// This code below causes various go.itab.* symbols to be generated in
|
||||
// the shared library. Similar code in ../exe/exe.go results in
|
||||
// exercising https://github.com/golang/go/issues/17594
|
||||
reflect.TypeOf(os.Stdout).Elem()
|
||||
return 10
|
||||
}
|
||||
|
||||
|
||||
@@ -2,34 +2,11 @@ package main
|
||||
|
||||
import (
|
||||
"depBase"
|
||||
"os"
|
||||
"reflect"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// Having a function declared in the main package triggered
|
||||
// golang.org/issue/18250
|
||||
func DeclaredInMain() {
|
||||
}
|
||||
|
||||
type C struct {
|
||||
}
|
||||
|
||||
func F() *C {
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
defer depBase.ImplementedInAsm()
|
||||
// This code below causes various go.itab.* symbols to be generated in
|
||||
// the executable. Similar code in ../depBase/dep.go results in
|
||||
// exercising https://github.com/golang/go/issues/17594
|
||||
reflect.TypeOf(os.Stdout).Elem()
|
||||
runtime.GC()
|
||||
depBase.V = depBase.F() + 1
|
||||
|
||||
var c *C
|
||||
if reflect.TypeOf(F).Out(0) != reflect.TypeOf(c) {
|
||||
panic("bad reflection results, see golang.org/issue/18252")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,6 @@ static void iohandler(int signum) {
|
||||
|
||||
static void* sigioThread(void* arg __attribute__ ((unused))) {
|
||||
raise(SIGIO);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void sigioOnThread() {
|
||||
|
||||
@@ -17,4 +17,4 @@ else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exec $CLANG -arch $CLANGARCH -isysroot $SDK_PATH -mios-version-min=6.0 "$@"
|
||||
exec $CLANG -arch $CLANGARCH -isysroot $SDK_PATH "$@"
|
||||
|
||||
@@ -18,10 +18,6 @@ go src=..
|
||||
asm
|
||||
testdata
|
||||
+
|
||||
compile
|
||||
internal
|
||||
syntax
|
||||
parser.go
|
||||
doc
|
||||
main.go
|
||||
pkg.go
|
||||
@@ -48,10 +44,6 @@ go src=..
|
||||
x86asm
|
||||
testdata
|
||||
+
|
||||
ppc64
|
||||
ppc64asm
|
||||
testdata
|
||||
+
|
||||
archive
|
||||
tar
|
||||
testdata
|
||||
|
||||
@@ -30,10 +30,6 @@ if [ "$GOARM" != "7" ]; then
|
||||
echo "android only supports GOARM=7, got GOARM=$GOARM" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
if [ "$GOARCH" = "" ]; then
|
||||
echo "GOARCH must be set" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export CGO_ENABLED=1
|
||||
unset GOBIN
|
||||
@@ -47,12 +43,6 @@ GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH go build \
|
||||
-o ../bin/go_android_${GOARCH}_exec \
|
||||
../misc/android/go_android_exec.go
|
||||
|
||||
export pkgdir=$(dirname $(go list -f '{{.Target}}' runtime))
|
||||
if [ "$pkgdir" = "" ]; then
|
||||
echo "could not find android pkg dir" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export ANDROID_TEST_DIR=/tmp/androidtest-$$
|
||||
|
||||
function cleanup() {
|
||||
@@ -74,7 +64,15 @@ mkdir -p $FAKE_GOROOT/pkg
|
||||
cp -a "${GOROOT}/src" "${FAKE_GOROOT}/"
|
||||
cp -a "${GOROOT}/test" "${FAKE_GOROOT}/"
|
||||
cp -a "${GOROOT}/lib" "${FAKE_GOROOT}/"
|
||||
cp -a "${pkgdir}" "${FAKE_GOROOT}/pkg/"
|
||||
|
||||
# For android, the go tool will install the compiled package in
|
||||
# pkg/android_${GOARCH}_shared directory by default, not in
|
||||
# the usual pkg/${GOOS}_${GOARCH}. Some tests in src/go/* assume
|
||||
# the compiled packages were installed in the usual places.
|
||||
# Instead of reflecting this exception into the go/* packages,
|
||||
# we copy the compiled packages into the usual places.
|
||||
cp -a "${GOROOT}/pkg/android_${GOARCH}_shared" "${FAKE_GOROOT}/pkg/"
|
||||
mv "${FAKE_GOROOT}/pkg/android_${GOARCH}_shared" "${FAKE_GOROOT}/pkg/android_${GOARCH}"
|
||||
|
||||
echo '# Syncing test files to android device'
|
||||
adb shell mkdir -p /data/local/tmp/goroot
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
package tar
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
@@ -20,10 +21,6 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// BUG: Use of the Uid and Gid fields in Header could overflow on 32-bit
|
||||
// architectures. If a large value is encountered when decoding, the result
|
||||
// stored in Header will be the truncated version.
|
||||
|
||||
// Header type flags.
|
||||
const (
|
||||
TypeReg = '0' // regular file
|
||||
@@ -274,6 +271,28 @@ func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) {
|
||||
return h, nil
|
||||
}
|
||||
|
||||
func isASCII(s string) bool {
|
||||
for _, c := range s {
|
||||
if c >= 0x80 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func toASCII(s string) string {
|
||||
if isASCII(s) {
|
||||
return s
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
for _, c := range s {
|
||||
if c < 0x80 {
|
||||
buf.WriteByte(byte(c))
|
||||
}
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// isHeaderOnlyType checks if the given type flag is of the type that has no
|
||||
// data section even if a size is specified.
|
||||
func isHeaderOnlyType(flag byte) bool {
|
||||
|
||||
@@ -22,20 +22,22 @@ var (
|
||||
ErrHeader = errors.New("archive/tar: invalid tar header")
|
||||
)
|
||||
|
||||
const maxNanoSecondIntSize = 9
|
||||
|
||||
// A Reader provides sequential access to the contents of a tar archive.
|
||||
// A tar archive consists of a sequence of files.
|
||||
// The Next method advances to the next file in the archive (including the first),
|
||||
// and then it can be treated as an io.Reader to access the file's data.
|
||||
type Reader struct {
|
||||
r io.Reader
|
||||
err error
|
||||
pad int64 // amount of padding (ignored) after current file entry
|
||||
curr numBytesReader // reader for current file entry
|
||||
blk block // buffer to use as temporary local storage
|
||||
}
|
||||
|
||||
// err is a persistent error.
|
||||
// It is only the responsibility of every exported method of Reader to
|
||||
// ensure that this error is sticky.
|
||||
err error
|
||||
type parser struct {
|
||||
err error // Last error seen
|
||||
}
|
||||
|
||||
// A numBytesReader is an io.Reader with a numBytes method, returning the number
|
||||
@@ -106,12 +108,8 @@ func (tr *Reader) Next() (*Header, error) {
|
||||
if tr.err != nil {
|
||||
return nil, tr.err
|
||||
}
|
||||
hdr, err := tr.next()
|
||||
tr.err = err
|
||||
return hdr, err
|
||||
}
|
||||
|
||||
func (tr *Reader) next() (*Header, error) {
|
||||
var hdr *Header
|
||||
var extHdrs map[string]string
|
||||
|
||||
// Externally, Next iterates through the tar archive as if it is a series of
|
||||
@@ -121,29 +119,29 @@ func (tr *Reader) next() (*Header, error) {
|
||||
// one or more "header files" until it finds a "normal file".
|
||||
loop:
|
||||
for {
|
||||
if err := tr.skipUnread(); err != nil {
|
||||
return nil, err
|
||||
tr.err = tr.skipUnread()
|
||||
if tr.err != nil {
|
||||
return nil, tr.err
|
||||
}
|
||||
hdr, rawHdr, err := tr.readHeader()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := tr.handleRegularFile(hdr); err != nil {
|
||||
return nil, err
|
||||
|
||||
hdr = tr.readHeader()
|
||||
if tr.err != nil {
|
||||
return nil, tr.err
|
||||
}
|
||||
|
||||
// Check for PAX/GNU special headers and files.
|
||||
switch hdr.Typeflag {
|
||||
case TypeXHeader:
|
||||
extHdrs, err = parsePAX(tr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
extHdrs, tr.err = parsePAX(tr)
|
||||
if tr.err != nil {
|
||||
return nil, tr.err
|
||||
}
|
||||
continue loop // This is a meta header affecting the next header
|
||||
case TypeGNULongName, TypeGNULongLink:
|
||||
realname, err := ioutil.ReadAll(tr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
var realname []byte
|
||||
realname, tr.err = ioutil.ReadAll(tr)
|
||||
if tr.err != nil {
|
||||
return nil, tr.err
|
||||
}
|
||||
|
||||
// Convert GNU extensions to use PAX headers.
|
||||
@@ -158,73 +156,31 @@ loop:
|
||||
extHdrs[paxLinkpath] = p.parseString(realname)
|
||||
}
|
||||
if p.err != nil {
|
||||
return nil, p.err
|
||||
tr.err = p.err
|
||||
return nil, tr.err
|
||||
}
|
||||
continue loop // This is a meta header affecting the next header
|
||||
default:
|
||||
// The old GNU sparse format is handled here since it is technically
|
||||
// just a regular file with additional attributes.
|
||||
mergePAX(hdr, extHdrs)
|
||||
|
||||
if err := mergePAX(hdr, extHdrs); err != nil {
|
||||
// Check for a PAX format sparse file
|
||||
sp, err := tr.checkForGNUSparsePAXHeaders(hdr, extHdrs)
|
||||
if err != nil {
|
||||
tr.err = err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// The extended headers may have updated the size.
|
||||
// Thus, setup the regFileReader again after merging PAX headers.
|
||||
if err := tr.handleRegularFile(hdr); err != nil {
|
||||
return nil, err
|
||||
if sp != nil {
|
||||
// Current file is a PAX format GNU sparse file.
|
||||
// Set the current file reader to a sparse file reader.
|
||||
tr.curr, tr.err = newSparseFileReader(tr.curr, sp, hdr.Size)
|
||||
if tr.err != nil {
|
||||
return nil, tr.err
|
||||
}
|
||||
}
|
||||
|
||||
// Sparse formats rely on being able to read from the logical data
|
||||
// section; there must be a preceding call to handleRegularFile.
|
||||
if err := tr.handleSparseFile(hdr, rawHdr, extHdrs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return hdr, nil // This is a file, so stop
|
||||
break loop // This is a file, so stop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// handleRegularFile sets up the current file reader and padding such that it
|
||||
// can only read the following logical data section. It will properly handle
|
||||
// special headers that contain no data section.
|
||||
func (tr *Reader) handleRegularFile(hdr *Header) error {
|
||||
nb := hdr.Size
|
||||
if isHeaderOnlyType(hdr.Typeflag) {
|
||||
nb = 0
|
||||
}
|
||||
if nb < 0 {
|
||||
return ErrHeader
|
||||
}
|
||||
|
||||
tr.pad = -nb & (blockSize - 1) // blockSize is a power of two
|
||||
tr.curr = ®FileReader{r: tr.r, nb: nb}
|
||||
return nil
|
||||
}
|
||||
|
||||
// handleSparseFile checks if the current file is a sparse format of any type
|
||||
// and sets the curr reader appropriately.
|
||||
func (tr *Reader) handleSparseFile(hdr *Header, rawHdr *block, extHdrs map[string]string) error {
|
||||
var sp []sparseEntry
|
||||
var err error
|
||||
if hdr.Typeflag == TypeGNUSparse {
|
||||
sp, err = tr.readOldGNUSparseMap(hdr, rawHdr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
sp, err = tr.checkForGNUSparsePAXHeaders(hdr, extHdrs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// If sp is non-nil, then this is a sparse file.
|
||||
// Note that it is possible for len(sp) to be zero.
|
||||
if sp != nil {
|
||||
tr.curr, err = newSparseFileReader(tr.curr, sp, hdr.Size)
|
||||
}
|
||||
return err
|
||||
return hdr, nil
|
||||
}
|
||||
|
||||
// checkForGNUSparsePAXHeaders checks the PAX headers for GNU sparse headers. If they are found, then
|
||||
@@ -263,13 +219,13 @@ func (tr *Reader) checkForGNUSparsePAXHeaders(hdr *Header, headers map[string]st
|
||||
hdr.Name = sparseName
|
||||
}
|
||||
if sparseSizeOk {
|
||||
realSize, err := strconv.ParseInt(sparseSize, 10, 64)
|
||||
realSize, err := strconv.ParseInt(sparseSize, 10, 0)
|
||||
if err != nil {
|
||||
return nil, ErrHeader
|
||||
}
|
||||
hdr.Size = realSize
|
||||
} else if sparseRealSizeOk {
|
||||
realSize, err := strconv.ParseInt(sparseRealSize, 10, 64)
|
||||
realSize, err := strconv.ParseInt(sparseRealSize, 10, 0)
|
||||
if err != nil {
|
||||
return nil, ErrHeader
|
||||
}
|
||||
@@ -293,32 +249,53 @@ func (tr *Reader) checkForGNUSparsePAXHeaders(hdr *Header, headers map[string]st
|
||||
// in the header struct overwrite those found in the header
|
||||
// struct with higher precision or longer values. Esp. useful
|
||||
// for name and linkname fields.
|
||||
func mergePAX(hdr *Header, headers map[string]string) (err error) {
|
||||
var id64 int64
|
||||
func mergePAX(hdr *Header, headers map[string]string) error {
|
||||
for k, v := range headers {
|
||||
switch k {
|
||||
case paxPath:
|
||||
hdr.Name = v
|
||||
case paxLinkpath:
|
||||
hdr.Linkname = v
|
||||
case paxUname:
|
||||
hdr.Uname = v
|
||||
case paxGname:
|
||||
hdr.Gname = v
|
||||
case paxUname:
|
||||
hdr.Uname = v
|
||||
case paxUid:
|
||||
id64, err = strconv.ParseInt(v, 10, 64)
|
||||
hdr.Uid = int(id64) // Integer overflow possible
|
||||
uid, err := strconv.ParseInt(v, 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hdr.Uid = int(uid)
|
||||
case paxGid:
|
||||
id64, err = strconv.ParseInt(v, 10, 64)
|
||||
hdr.Gid = int(id64) // Integer overflow possible
|
||||
gid, err := strconv.ParseInt(v, 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hdr.Gid = int(gid)
|
||||
case paxAtime:
|
||||
hdr.AccessTime, err = parsePAXTime(v)
|
||||
t, err := parsePAXTime(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hdr.AccessTime = t
|
||||
case paxMtime:
|
||||
hdr.ModTime, err = parsePAXTime(v)
|
||||
t, err := parsePAXTime(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hdr.ModTime = t
|
||||
case paxCtime:
|
||||
hdr.ChangeTime, err = parsePAXTime(v)
|
||||
t, err := parsePAXTime(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hdr.ChangeTime = t
|
||||
case paxSize:
|
||||
hdr.Size, err = strconv.ParseInt(v, 10, 64)
|
||||
size, err := strconv.ParseInt(v, 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hdr.Size = size
|
||||
default:
|
||||
if strings.HasPrefix(k, paxXattr) {
|
||||
if hdr.Xattrs == nil {
|
||||
@@ -327,13 +304,46 @@ func mergePAX(hdr *Header, headers map[string]string) (err error) {
|
||||
hdr.Xattrs[k[len(paxXattr):]] = v
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return ErrHeader
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// parsePAXTime takes a string of the form %d.%d as described in
|
||||
// the PAX specification.
|
||||
func parsePAXTime(t string) (time.Time, error) {
|
||||
buf := []byte(t)
|
||||
pos := bytes.IndexByte(buf, '.')
|
||||
var seconds, nanoseconds int64
|
||||
var err error
|
||||
if pos == -1 {
|
||||
seconds, err = strconv.ParseInt(t, 10, 0)
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
} else {
|
||||
seconds, err = strconv.ParseInt(string(buf[:pos]), 10, 0)
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
nanoBuf := string(buf[pos+1:])
|
||||
// Pad as needed before converting to a decimal.
|
||||
// For example .030 -> .030000000 -> 30000000 nanoseconds
|
||||
if len(nanoBuf) < maxNanoSecondIntSize {
|
||||
// Right pad
|
||||
nanoBuf += strings.Repeat("0", maxNanoSecondIntSize-len(nanoBuf))
|
||||
} else if len(nanoBuf) > maxNanoSecondIntSize {
|
||||
// Right truncate
|
||||
nanoBuf = nanoBuf[:maxNanoSecondIntSize]
|
||||
}
|
||||
nanoseconds, err = strconv.ParseInt(nanoBuf, 10, 0)
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
}
|
||||
ts := time.Unix(seconds, nanoseconds)
|
||||
return ts, nil
|
||||
}
|
||||
|
||||
// parsePAX parses PAX headers.
|
||||
// If an extended header (type 'x') is invalid, ErrHeader is returned
|
||||
func parsePAX(r io.Reader) (map[string]string, error) {
|
||||
@@ -344,11 +354,12 @@ func parsePAX(r io.Reader) (map[string]string, error) {
|
||||
sbuf := string(buf)
|
||||
|
||||
// For GNU PAX sparse format 0.0 support.
|
||||
// This function transforms the sparse format 0.0 headers into format 0.1
|
||||
// headers since 0.0 headers were not PAX compliant.
|
||||
var sparseMap []string
|
||||
// This function transforms the sparse format 0.0 headers into sparse format 0.1 headers.
|
||||
var sparseMap bytes.Buffer
|
||||
|
||||
extHdrs := make(map[string]string)
|
||||
headers := make(map[string]string)
|
||||
// Each record is constructed as
|
||||
// "%d %s=%s\n", length, keyword, value
|
||||
for len(sbuf) > 0 {
|
||||
key, value, residual, err := parsePAXRecord(sbuf)
|
||||
if err != nil {
|
||||
@@ -356,29 +367,127 @@ func parsePAX(r io.Reader) (map[string]string, error) {
|
||||
}
|
||||
sbuf = residual
|
||||
|
||||
switch key {
|
||||
case paxGNUSparseOffset, paxGNUSparseNumBytes:
|
||||
// Validate sparse header order and value.
|
||||
if (len(sparseMap)%2 == 0 && key != paxGNUSparseOffset) ||
|
||||
(len(sparseMap)%2 == 1 && key != paxGNUSparseNumBytes) ||
|
||||
strings.Contains(value, ",") {
|
||||
return nil, ErrHeader
|
||||
}
|
||||
sparseMap = append(sparseMap, value)
|
||||
default:
|
||||
// According to PAX specification, a value is stored only if it is
|
||||
// non-empty. Otherwise, the key is deleted.
|
||||
if len(value) > 0 {
|
||||
extHdrs[key] = value
|
||||
} else {
|
||||
delete(extHdrs, key)
|
||||
}
|
||||
keyStr := key
|
||||
if keyStr == paxGNUSparseOffset || keyStr == paxGNUSparseNumBytes {
|
||||
// GNU sparse format 0.0 special key. Write to sparseMap instead of using the headers map.
|
||||
sparseMap.WriteString(value)
|
||||
sparseMap.Write([]byte{','})
|
||||
} else {
|
||||
// Normal key. Set the value in the headers map.
|
||||
headers[keyStr] = value
|
||||
}
|
||||
}
|
||||
if len(sparseMap) > 0 {
|
||||
extHdrs[paxGNUSparseMap] = strings.Join(sparseMap, ",")
|
||||
if sparseMap.Len() != 0 {
|
||||
// Add sparse info to headers, chopping off the extra comma
|
||||
sparseMap.Truncate(sparseMap.Len() - 1)
|
||||
headers[paxGNUSparseMap] = sparseMap.String()
|
||||
}
|
||||
return extHdrs, nil
|
||||
return headers, nil
|
||||
}
|
||||
|
||||
// parsePAXRecord parses the input PAX record string into a key-value pair.
|
||||
// If parsing is successful, it will slice off the currently read record and
|
||||
// return the remainder as r.
|
||||
//
|
||||
// A PAX record is of the following form:
|
||||
// "%d %s=%s\n" % (size, key, value)
|
||||
func parsePAXRecord(s string) (k, v, r string, err error) {
|
||||
// The size field ends at the first space.
|
||||
sp := strings.IndexByte(s, ' ')
|
||||
if sp == -1 {
|
||||
return "", "", s, ErrHeader
|
||||
}
|
||||
|
||||
// Parse the first token as a decimal integer.
|
||||
n, perr := strconv.ParseInt(s[:sp], 10, 0) // Intentionally parse as native int
|
||||
if perr != nil || n < 5 || int64(len(s)) < n {
|
||||
return "", "", s, ErrHeader
|
||||
}
|
||||
|
||||
// Extract everything between the space and the final newline.
|
||||
rec, nl, rem := s[sp+1:n-1], s[n-1:n], s[n:]
|
||||
if nl != "\n" {
|
||||
return "", "", s, ErrHeader
|
||||
}
|
||||
|
||||
// The first equals separates the key from the value.
|
||||
eq := strings.IndexByte(rec, '=')
|
||||
if eq == -1 {
|
||||
return "", "", s, ErrHeader
|
||||
}
|
||||
return rec[:eq], rec[eq+1:], rem, nil
|
||||
}
|
||||
|
||||
// parseString parses bytes as a NUL-terminated C-style string.
|
||||
// If a NUL byte is not found then the whole slice is returned as a string.
|
||||
func (*parser) parseString(b []byte) string {
|
||||
n := 0
|
||||
for n < len(b) && b[n] != 0 {
|
||||
n++
|
||||
}
|
||||
return string(b[0:n])
|
||||
}
|
||||
|
||||
// parseNumeric parses the input as being encoded in either base-256 or octal.
|
||||
// This function may return negative numbers.
|
||||
// If parsing fails or an integer overflow occurs, err will be set.
|
||||
func (p *parser) parseNumeric(b []byte) int64 {
|
||||
// Check for base-256 (binary) format first.
|
||||
// If the first bit is set, then all following bits constitute a two's
|
||||
// complement encoded number in big-endian byte order.
|
||||
if len(b) > 0 && b[0]&0x80 != 0 {
|
||||
// Handling negative numbers relies on the following identity:
|
||||
// -a-1 == ^a
|
||||
//
|
||||
// If the number is negative, we use an inversion mask to invert the
|
||||
// data bytes and treat the value as an unsigned number.
|
||||
var inv byte // 0x00 if positive or zero, 0xff if negative
|
||||
if b[0]&0x40 != 0 {
|
||||
inv = 0xff
|
||||
}
|
||||
|
||||
var x uint64
|
||||
for i, c := range b {
|
||||
c ^= inv // Inverts c only if inv is 0xff, otherwise does nothing
|
||||
if i == 0 {
|
||||
c &= 0x7f // Ignore signal bit in first byte
|
||||
}
|
||||
if (x >> 56) > 0 {
|
||||
p.err = ErrHeader // Integer overflow
|
||||
return 0
|
||||
}
|
||||
x = x<<8 | uint64(c)
|
||||
}
|
||||
if (x >> 63) > 0 {
|
||||
p.err = ErrHeader // Integer overflow
|
||||
return 0
|
||||
}
|
||||
if inv == 0xff {
|
||||
return ^int64(x)
|
||||
}
|
||||
return int64(x)
|
||||
}
|
||||
|
||||
// Normal case is base-8 (octal) format.
|
||||
return p.parseOctal(b)
|
||||
}
|
||||
|
||||
func (p *parser) parseOctal(b []byte) int64 {
|
||||
// Because unused fields are filled with NULs, we need
|
||||
// to skip leading NULs. Fields may also be padded with
|
||||
// spaces or NULs.
|
||||
// So we remove leading and trailing NULs and spaces to
|
||||
// be sure.
|
||||
b = bytes.Trim(b, " \x00")
|
||||
|
||||
if len(b) == 0 {
|
||||
return 0
|
||||
}
|
||||
x, perr := strconv.ParseUint(p.parseString(b), 8, 64)
|
||||
if perr != nil {
|
||||
p.err = ErrHeader
|
||||
}
|
||||
return int64(x)
|
||||
}
|
||||
|
||||
// skipUnread skips any unread bytes in the existing file entry, as well as any
|
||||
@@ -407,46 +516,51 @@ func (tr *Reader) skipUnread() error {
|
||||
// Seek seems supported, so perform the real Seek.
|
||||
pos2, err := sr.Seek(dataSkip-1, io.SeekCurrent)
|
||||
if err != nil {
|
||||
return err
|
||||
tr.err = err
|
||||
return tr.err
|
||||
}
|
||||
seekSkipped = pos2 - pos1
|
||||
}
|
||||
}
|
||||
|
||||
copySkipped, err := io.CopyN(ioutil.Discard, tr.r, totalSkip-seekSkipped)
|
||||
if err == io.EOF && seekSkipped+copySkipped < dataSkip {
|
||||
err = io.ErrUnexpectedEOF
|
||||
var copySkipped int64 // Number of bytes skipped via CopyN
|
||||
copySkipped, tr.err = io.CopyN(ioutil.Discard, tr.r, totalSkip-seekSkipped)
|
||||
if tr.err == io.EOF && seekSkipped+copySkipped < dataSkip {
|
||||
tr.err = io.ErrUnexpectedEOF
|
||||
}
|
||||
return err
|
||||
return tr.err
|
||||
}
|
||||
|
||||
// readHeader reads the next block header and assumes that the underlying reader
|
||||
// is already aligned to a block boundary. It returns the raw block of the
|
||||
// header in case further processing is required.
|
||||
// is already aligned to a block boundary.
|
||||
//
|
||||
// The err will be set to io.EOF only when one of the following occurs:
|
||||
// * Exactly 0 bytes are read and EOF is hit.
|
||||
// * Exactly 1 block of zeros is read and EOF is hit.
|
||||
// * At least 2 blocks of zeros are read.
|
||||
func (tr *Reader) readHeader() (*Header, *block, error) {
|
||||
// Two blocks of zero bytes marks the end of the archive.
|
||||
if _, err := io.ReadFull(tr.r, tr.blk[:]); err != nil {
|
||||
return nil, nil, err // EOF is okay here; exactly 0 bytes read
|
||||
func (tr *Reader) readHeader() *Header {
|
||||
if _, tr.err = io.ReadFull(tr.r, tr.blk[:]); tr.err != nil {
|
||||
return nil // io.EOF is okay here
|
||||
}
|
||||
|
||||
// Two blocks of zero bytes marks the end of the archive.
|
||||
if bytes.Equal(tr.blk[:], zeroBlock[:]) {
|
||||
if _, err := io.ReadFull(tr.r, tr.blk[:]); err != nil {
|
||||
return nil, nil, err // EOF is okay here; exactly 1 block of zeros read
|
||||
if _, tr.err = io.ReadFull(tr.r, tr.blk[:]); tr.err != nil {
|
||||
return nil // io.EOF is okay here
|
||||
}
|
||||
if bytes.Equal(tr.blk[:], zeroBlock[:]) {
|
||||
return nil, nil, io.EOF // normal EOF; exactly 2 block of zeros read
|
||||
tr.err = io.EOF
|
||||
} else {
|
||||
tr.err = ErrHeader // zero block and then non-zero block
|
||||
}
|
||||
return nil, nil, ErrHeader // Zero block and then non-zero block
|
||||
return nil
|
||||
}
|
||||
|
||||
// Verify the header matches a known format.
|
||||
format := tr.blk.GetFormat()
|
||||
if format == formatUnknown {
|
||||
return nil, nil, ErrHeader
|
||||
tr.err = ErrHeader
|
||||
return nil
|
||||
}
|
||||
|
||||
var p parser
|
||||
@@ -463,26 +577,6 @@ func (tr *Reader) readHeader() (*Header, *block, error) {
|
||||
hdr.Typeflag = v7.TypeFlag()[0]
|
||||
hdr.Linkname = p.parseString(v7.LinkName())
|
||||
|
||||
// The atime and ctime fields are often left unused. Some versions of Go
|
||||
// had a bug in the tar.Writer where it would output an invalid tar file
|
||||
// in certain rare situations because the logic incorrectly believed that
|
||||
// the old GNU format had a prefix field. This is wrong and leads to
|
||||
// an outputted file that actually mangles the atime and ctime fields.
|
||||
//
|
||||
// In order to continue reading tar files created by a buggy writer, we
|
||||
// try to parse the atime and ctime fields, but just return the zero value
|
||||
// of time.Time when we cannot parse them.
|
||||
//
|
||||
// See https://golang.org/issues/12594
|
||||
tryParseTime := func(b []byte) time.Time {
|
||||
var p parser
|
||||
n := p.parseNumeric(b)
|
||||
if b[0] != 0x00 && p.err == nil {
|
||||
return time.Unix(n, 0)
|
||||
}
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
// Unpack format specific fields.
|
||||
if format > formatV7 {
|
||||
ustar := tr.blk.USTAR()
|
||||
@@ -495,7 +589,9 @@ func (tr *Reader) readHeader() (*Header, *block, error) {
|
||||
|
||||
var prefix string
|
||||
switch format {
|
||||
case formatUSTAR:
|
||||
case formatUSTAR, formatGNU:
|
||||
// TODO(dsnet): Do not use the prefix field for the GNU format!
|
||||
// See golang.org/issues/12594
|
||||
ustar := tr.blk.USTAR()
|
||||
prefix = p.parseString(ustar.Prefix())
|
||||
case formatSTAR:
|
||||
@@ -503,68 +599,97 @@ func (tr *Reader) readHeader() (*Header, *block, error) {
|
||||
prefix = p.parseString(star.Prefix())
|
||||
hdr.AccessTime = time.Unix(p.parseNumeric(star.AccessTime()), 0)
|
||||
hdr.ChangeTime = time.Unix(p.parseNumeric(star.ChangeTime()), 0)
|
||||
case formatGNU:
|
||||
gnu := tr.blk.GNU()
|
||||
hdr.AccessTime = tryParseTime(gnu.AccessTime())
|
||||
hdr.ChangeTime = tryParseTime(gnu.ChangeTime())
|
||||
}
|
||||
if len(prefix) > 0 {
|
||||
hdr.Name = prefix + "/" + hdr.Name
|
||||
}
|
||||
}
|
||||
return hdr, &tr.blk, p.err
|
||||
|
||||
nb := hdr.Size
|
||||
if isHeaderOnlyType(hdr.Typeflag) {
|
||||
nb = 0
|
||||
}
|
||||
if nb < 0 {
|
||||
tr.err = ErrHeader
|
||||
return nil
|
||||
}
|
||||
|
||||
// Set the current file reader.
|
||||
tr.pad = -nb & (blockSize - 1) // blockSize is a power of two
|
||||
tr.curr = ®FileReader{r: tr.r, nb: nb}
|
||||
|
||||
// Check for old GNU sparse format entry.
|
||||
if hdr.Typeflag == TypeGNUSparse {
|
||||
// Get the real size of the file.
|
||||
hdr.Size = p.parseNumeric(tr.blk.GNU().RealSize())
|
||||
if p.err != nil {
|
||||
tr.err = p.err
|
||||
return nil
|
||||
}
|
||||
|
||||
// Read the sparse map.
|
||||
sp := tr.readOldGNUSparseMap(&tr.blk)
|
||||
if tr.err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Current file is a GNU sparse file. Update the current file reader.
|
||||
tr.curr, tr.err = newSparseFileReader(tr.curr, sp, hdr.Size)
|
||||
if tr.err != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if p.err != nil {
|
||||
tr.err = p.err
|
||||
return nil
|
||||
}
|
||||
|
||||
return hdr
|
||||
}
|
||||
|
||||
// readOldGNUSparseMap reads the sparse map from the old GNU sparse format.
|
||||
// The sparse map is stored in the tar header if it's small enough.
|
||||
// If it's larger than four entries, then one or more extension headers are used
|
||||
// to store the rest of the sparse map.
|
||||
//
|
||||
// The Header.Size does not reflect the size of any extended headers used.
|
||||
// Thus, this function will read from the raw io.Reader to fetch extra headers.
|
||||
// This method mutates blk in the process.
|
||||
func (tr *Reader) readOldGNUSparseMap(hdr *Header, blk *block) ([]sparseEntry, error) {
|
||||
// Make sure that the input format is GNU.
|
||||
// Unfortunately, the STAR format also has a sparse header format that uses
|
||||
// the same type flag but has a completely different layout.
|
||||
if blk.GetFormat() != formatGNU {
|
||||
return nil, ErrHeader
|
||||
}
|
||||
|
||||
// readOldGNUSparseMap reads the sparse map as stored in the old GNU sparse format.
|
||||
// The sparse map is stored in the tar header if it's small enough. If it's larger than four entries,
|
||||
// then one or more extension headers are used to store the rest of the sparse map.
|
||||
func (tr *Reader) readOldGNUSparseMap(blk *block) []sparseEntry {
|
||||
var p parser
|
||||
hdr.Size = p.parseNumeric(blk.GNU().RealSize())
|
||||
if p.err != nil {
|
||||
return nil, p.err
|
||||
}
|
||||
var s sparseArray = blk.GNU().Sparse()
|
||||
var sp = make([]sparseEntry, 0, s.MaxEntries())
|
||||
for {
|
||||
for i := 0; i < s.MaxEntries(); i++ {
|
||||
offset := p.parseOctal(s.Entry(i).Offset())
|
||||
numBytes := p.parseOctal(s.Entry(i).NumBytes())
|
||||
if p.err != nil {
|
||||
tr.err = p.err
|
||||
return nil
|
||||
}
|
||||
if offset == 0 && numBytes == 0 {
|
||||
break
|
||||
}
|
||||
sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
|
||||
}
|
||||
|
||||
for s.IsExtended()[0] > 0 {
|
||||
// There are more entries. Read an extension header and parse its entries.
|
||||
var blk block
|
||||
if _, tr.err = io.ReadFull(tr.r, blk[:]); tr.err != nil {
|
||||
return nil
|
||||
}
|
||||
s = blk.Sparse()
|
||||
|
||||
for i := 0; i < s.MaxEntries(); i++ {
|
||||
// This termination condition is identical to GNU and BSD tar.
|
||||
if s.Entry(i).Offset()[0] == 0x00 {
|
||||
break // Don't return, need to process extended headers (even if empty)
|
||||
}
|
||||
offset := p.parseNumeric(s.Entry(i).Offset())
|
||||
numBytes := p.parseNumeric(s.Entry(i).NumBytes())
|
||||
offset := p.parseOctal(s.Entry(i).Offset())
|
||||
numBytes := p.parseOctal(s.Entry(i).NumBytes())
|
||||
if p.err != nil {
|
||||
return nil, p.err
|
||||
tr.err = p.err
|
||||
return nil
|
||||
}
|
||||
if offset == 0 && numBytes == 0 {
|
||||
break
|
||||
}
|
||||
sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
|
||||
}
|
||||
|
||||
if s.IsExtended()[0] > 0 {
|
||||
// There are more entries. Read an extension header and parse its entries.
|
||||
if _, err := io.ReadFull(tr.r, blk[:]); err != nil {
|
||||
if err == io.EOF {
|
||||
err = io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
s = blk.Sparse()
|
||||
continue
|
||||
}
|
||||
return sp, nil // Done
|
||||
}
|
||||
return sp
|
||||
}
|
||||
|
||||
// readGNUSparseMap1x0 reads the sparse map as stored in GNU's PAX sparse format
|
||||
@@ -692,7 +817,7 @@ func (tr *Reader) numBytes() int64 {
|
||||
// Calling Read on special types like TypeLink, TypeSymLink, TypeChar,
|
||||
// TypeBlock, TypeDir, and TypeFifo returns 0, io.EOF regardless of what
|
||||
// the Header.Size claims.
|
||||
func (tr *Reader) Read(b []byte) (int, error) {
|
||||
func (tr *Reader) Read(b []byte) (n int, err error) {
|
||||
if tr.err != nil {
|
||||
return 0, tr.err
|
||||
}
|
||||
@@ -700,11 +825,11 @@ func (tr *Reader) Read(b []byte) (int, error) {
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
n, err := tr.curr.Read(b)
|
||||
n, err = tr.curr.Read(b)
|
||||
if err != nil && err != io.EOF {
|
||||
tr.err = err
|
||||
}
|
||||
return n, err
|
||||
return
|
||||
}
|
||||
|
||||
func (rfr *regFileReader) Read(b []byte) (n int, err error) {
|
||||
|
||||
@@ -18,15 +18,17 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestReader(t *testing.T) {
|
||||
vectors := []struct {
|
||||
file string // Test input file
|
||||
headers []*Header // Expected output headers
|
||||
chksums []string // MD5 checksum of files, leave as nil if not checked
|
||||
err error // Expected error to occur
|
||||
}{{
|
||||
file: "testdata/gnu.tar",
|
||||
headers: []*Header{{
|
||||
type untarTest struct {
|
||||
file string // Test input file
|
||||
headers []*Header // Expected output headers
|
||||
chksums []string // MD5 checksum of files, leave as nil if not checked
|
||||
err error // Expected error to occur
|
||||
}
|
||||
|
||||
var gnuTarTest = &untarTest{
|
||||
file: "testdata/gnu.tar",
|
||||
headers: []*Header{
|
||||
{
|
||||
Name: "small.txt",
|
||||
Mode: 0640,
|
||||
Uid: 73025,
|
||||
@@ -36,7 +38,8 @@ func TestReader(t *testing.T) {
|
||||
Typeflag: '0',
|
||||
Uname: "dsymonds",
|
||||
Gname: "eng",
|
||||
}, {
|
||||
},
|
||||
{
|
||||
Name: "small2.txt",
|
||||
Mode: 0640,
|
||||
Uid: 73025,
|
||||
@@ -46,14 +49,18 @@ func TestReader(t *testing.T) {
|
||||
Typeflag: '0',
|
||||
Uname: "dsymonds",
|
||||
Gname: "eng",
|
||||
}},
|
||||
chksums: []string{
|
||||
"e38b27eaccb4391bdec553a7f3ae6b2f",
|
||||
"c65bd2e50a56a2138bf1716f2fd56fe9",
|
||||
},
|
||||
}, {
|
||||
file: "testdata/sparse-formats.tar",
|
||||
headers: []*Header{{
|
||||
},
|
||||
chksums: []string{
|
||||
"e38b27eaccb4391bdec553a7f3ae6b2f",
|
||||
"c65bd2e50a56a2138bf1716f2fd56fe9",
|
||||
},
|
||||
}
|
||||
|
||||
var sparseTarTest = &untarTest{
|
||||
file: "testdata/sparse-formats.tar",
|
||||
headers: []*Header{
|
||||
{
|
||||
Name: "sparse-gnu",
|
||||
Mode: 420,
|
||||
Uid: 1000,
|
||||
@@ -66,7 +73,8 @@ func TestReader(t *testing.T) {
|
||||
Gname: "david",
|
||||
Devmajor: 0,
|
||||
Devminor: 0,
|
||||
}, {
|
||||
},
|
||||
{
|
||||
Name: "sparse-posix-0.0",
|
||||
Mode: 420,
|
||||
Uid: 1000,
|
||||
@@ -79,7 +87,8 @@ func TestReader(t *testing.T) {
|
||||
Gname: "david",
|
||||
Devmajor: 0,
|
||||
Devminor: 0,
|
||||
}, {
|
||||
},
|
||||
{
|
||||
Name: "sparse-posix-0.1",
|
||||
Mode: 420,
|
||||
Uid: 1000,
|
||||
@@ -92,7 +101,8 @@ func TestReader(t *testing.T) {
|
||||
Gname: "david",
|
||||
Devmajor: 0,
|
||||
Devminor: 0,
|
||||
}, {
|
||||
},
|
||||
{
|
||||
Name: "sparse-posix-1.0",
|
||||
Mode: 420,
|
||||
Uid: 1000,
|
||||
@@ -105,7 +115,8 @@ func TestReader(t *testing.T) {
|
||||
Gname: "david",
|
||||
Devmajor: 0,
|
||||
Devminor: 0,
|
||||
}, {
|
||||
},
|
||||
{
|
||||
Name: "end",
|
||||
Mode: 420,
|
||||
Uid: 1000,
|
||||
@@ -118,237 +129,209 @@ func TestReader(t *testing.T) {
|
||||
Gname: "david",
|
||||
Devmajor: 0,
|
||||
Devminor: 0,
|
||||
}},
|
||||
chksums: []string{
|
||||
"6f53234398c2449fe67c1812d993012f",
|
||||
"6f53234398c2449fe67c1812d993012f",
|
||||
"6f53234398c2449fe67c1812d993012f",
|
||||
"6f53234398c2449fe67c1812d993012f",
|
||||
"b0061974914468de549a2af8ced10316",
|
||||
},
|
||||
}, {
|
||||
},
|
||||
chksums: []string{
|
||||
"6f53234398c2449fe67c1812d993012f",
|
||||
"6f53234398c2449fe67c1812d993012f",
|
||||
"6f53234398c2449fe67c1812d993012f",
|
||||
"6f53234398c2449fe67c1812d993012f",
|
||||
"b0061974914468de549a2af8ced10316",
|
||||
},
|
||||
}
|
||||
|
||||
var untarTests = []*untarTest{
|
||||
gnuTarTest,
|
||||
sparseTarTest,
|
||||
{
|
||||
file: "testdata/star.tar",
|
||||
headers: []*Header{{
|
||||
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),
|
||||
}, {
|
||||
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),
|
||||
}},
|
||||
}, {
|
||||
file: "testdata/v7.tar",
|
||||
headers: []*Header{{
|
||||
Name: "small.txt",
|
||||
Mode: 0444,
|
||||
Uid: 73025,
|
||||
Gid: 5000,
|
||||
Size: 5,
|
||||
ModTime: time.Unix(1244593104, 0),
|
||||
Typeflag: '\x00',
|
||||
}, {
|
||||
Name: "small2.txt",
|
||||
Mode: 0444,
|
||||
Uid: 73025,
|
||||
Gid: 5000,
|
||||
Size: 11,
|
||||
ModTime: time.Unix(1244593104, 0),
|
||||
Typeflag: '\x00',
|
||||
}},
|
||||
}, {
|
||||
file: "testdata/pax.tar",
|
||||
headers: []*Header{{
|
||||
Name: "a/123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100",
|
||||
Mode: 0664,
|
||||
Uid: 1000,
|
||||
Gid: 1000,
|
||||
Uname: "shane",
|
||||
Gname: "shane",
|
||||
Size: 7,
|
||||
ModTime: time.Unix(1350244992, 23960108),
|
||||
ChangeTime: time.Unix(1350244992, 23960108),
|
||||
AccessTime: time.Unix(1350244992, 23960108),
|
||||
Typeflag: TypeReg,
|
||||
}, {
|
||||
Name: "a/b",
|
||||
Mode: 0777,
|
||||
Uid: 1000,
|
||||
Gid: 1000,
|
||||
Uname: "shane",
|
||||
Gname: "shane",
|
||||
Size: 0,
|
||||
ModTime: time.Unix(1350266320, 910238425),
|
||||
ChangeTime: time.Unix(1350266320, 910238425),
|
||||
AccessTime: time.Unix(1350266320, 910238425),
|
||||
Typeflag: TypeSymlink,
|
||||
Linkname: "123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100",
|
||||
}},
|
||||
}, {
|
||||
file: "testdata/pax-bad-hdr-file.tar",
|
||||
err: ErrHeader,
|
||||
}, {
|
||||
file: "testdata/pax-bad-mtime-file.tar",
|
||||
err: ErrHeader,
|
||||
}, {
|
||||
file: "testdata/pax-pos-size-file.tar",
|
||||
headers: []*Header{{
|
||||
Name: "foo",
|
||||
Mode: 0640,
|
||||
Uid: 319973,
|
||||
Gid: 5000,
|
||||
Size: 999,
|
||||
ModTime: time.Unix(1442282516, 0),
|
||||
Typeflag: '0',
|
||||
Uname: "joetsai",
|
||||
Gname: "eng",
|
||||
}},
|
||||
chksums: []string{
|
||||
"0afb597b283fe61b5d4879669a350556",
|
||||
headers: []*Header{
|
||||
{
|
||||
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),
|
||||
},
|
||||
{
|
||||
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),
|
||||
},
|
||||
},
|
||||
}, {
|
||||
},
|
||||
{
|
||||
file: "testdata/v7.tar",
|
||||
headers: []*Header{
|
||||
{
|
||||
Name: "small.txt",
|
||||
Mode: 0444,
|
||||
Uid: 73025,
|
||||
Gid: 5000,
|
||||
Size: 5,
|
||||
ModTime: time.Unix(1244593104, 0),
|
||||
Typeflag: '\x00',
|
||||
},
|
||||
{
|
||||
Name: "small2.txt",
|
||||
Mode: 0444,
|
||||
Uid: 73025,
|
||||
Gid: 5000,
|
||||
Size: 11,
|
||||
ModTime: time.Unix(1244593104, 0),
|
||||
Typeflag: '\x00',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
file: "testdata/pax.tar",
|
||||
headers: []*Header{
|
||||
{
|
||||
Name: "a/123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100",
|
||||
Mode: 0664,
|
||||
Uid: 1000,
|
||||
Gid: 1000,
|
||||
Uname: "shane",
|
||||
Gname: "shane",
|
||||
Size: 7,
|
||||
ModTime: time.Unix(1350244992, 23960108),
|
||||
ChangeTime: time.Unix(1350244992, 23960108),
|
||||
AccessTime: time.Unix(1350244992, 23960108),
|
||||
Typeflag: TypeReg,
|
||||
},
|
||||
{
|
||||
Name: "a/b",
|
||||
Mode: 0777,
|
||||
Uid: 1000,
|
||||
Gid: 1000,
|
||||
Uname: "shane",
|
||||
Gname: "shane",
|
||||
Size: 0,
|
||||
ModTime: time.Unix(1350266320, 910238425),
|
||||
ChangeTime: time.Unix(1350266320, 910238425),
|
||||
AccessTime: time.Unix(1350266320, 910238425),
|
||||
Typeflag: TypeSymlink,
|
||||
Linkname: "123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
file: "testdata/nil-uid.tar", // golang.org/issue/5290
|
||||
headers: []*Header{{
|
||||
Name: "P1050238.JPG.log",
|
||||
Mode: 0664,
|
||||
Uid: 0,
|
||||
Gid: 0,
|
||||
Size: 14,
|
||||
ModTime: time.Unix(1365454838, 0),
|
||||
Typeflag: TypeReg,
|
||||
Linkname: "",
|
||||
Uname: "eyefi",
|
||||
Gname: "eyefi",
|
||||
Devmajor: 0,
|
||||
Devminor: 0,
|
||||
}},
|
||||
}, {
|
||||
headers: []*Header{
|
||||
{
|
||||
Name: "P1050238.JPG.log",
|
||||
Mode: 0664,
|
||||
Uid: 0,
|
||||
Gid: 0,
|
||||
Size: 14,
|
||||
ModTime: time.Unix(1365454838, 0),
|
||||
Typeflag: TypeReg,
|
||||
Linkname: "",
|
||||
Uname: "eyefi",
|
||||
Gname: "eyefi",
|
||||
Devmajor: 0,
|
||||
Devminor: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
file: "testdata/xattrs.tar",
|
||||
headers: []*Header{{
|
||||
Name: "small.txt",
|
||||
Mode: 0644,
|
||||
Uid: 1000,
|
||||
Gid: 10,
|
||||
Size: 5,
|
||||
ModTime: time.Unix(1386065770, 448252320),
|
||||
Typeflag: '0',
|
||||
Uname: "alex",
|
||||
Gname: "wheel",
|
||||
AccessTime: time.Unix(1389782991, 419875220),
|
||||
ChangeTime: time.Unix(1389782956, 794414986),
|
||||
Xattrs: map[string]string{
|
||||
"user.key": "value",
|
||||
"user.key2": "value2",
|
||||
// Interestingly, selinux encodes the terminating null inside the xattr
|
||||
"security.selinux": "unconfined_u:object_r:default_t:s0\x00",
|
||||
headers: []*Header{
|
||||
{
|
||||
Name: "small.txt",
|
||||
Mode: 0644,
|
||||
Uid: 1000,
|
||||
Gid: 10,
|
||||
Size: 5,
|
||||
ModTime: time.Unix(1386065770, 448252320),
|
||||
Typeflag: '0',
|
||||
Uname: "alex",
|
||||
Gname: "wheel",
|
||||
AccessTime: time.Unix(1389782991, 419875220),
|
||||
ChangeTime: time.Unix(1389782956, 794414986),
|
||||
Xattrs: map[string]string{
|
||||
"user.key": "value",
|
||||
"user.key2": "value2",
|
||||
// Interestingly, selinux encodes the terminating null inside the xattr
|
||||
"security.selinux": "unconfined_u:object_r:default_t:s0\x00",
|
||||
},
|
||||
},
|
||||
}, {
|
||||
Name: "small2.txt",
|
||||
Mode: 0644,
|
||||
Uid: 1000,
|
||||
Gid: 10,
|
||||
Size: 11,
|
||||
ModTime: time.Unix(1386065770, 449252304),
|
||||
Typeflag: '0',
|
||||
Uname: "alex",
|
||||
Gname: "wheel",
|
||||
AccessTime: time.Unix(1389782991, 419875220),
|
||||
ChangeTime: time.Unix(1386065770, 449252304),
|
||||
Xattrs: map[string]string{
|
||||
"security.selinux": "unconfined_u:object_r:default_t:s0\x00",
|
||||
{
|
||||
Name: "small2.txt",
|
||||
Mode: 0644,
|
||||
Uid: 1000,
|
||||
Gid: 10,
|
||||
Size: 11,
|
||||
ModTime: time.Unix(1386065770, 449252304),
|
||||
Typeflag: '0',
|
||||
Uname: "alex",
|
||||
Gname: "wheel",
|
||||
AccessTime: time.Unix(1389782991, 419875220),
|
||||
ChangeTime: time.Unix(1386065770, 449252304),
|
||||
Xattrs: map[string]string{
|
||||
"security.selinux": "unconfined_u:object_r:default_t:s0\x00",
|
||||
},
|
||||
},
|
||||
}},
|
||||
}, {
|
||||
},
|
||||
},
|
||||
{
|
||||
// Matches the behavior of GNU, BSD, and STAR tar utilities.
|
||||
file: "testdata/gnu-multi-hdrs.tar",
|
||||
headers: []*Header{{
|
||||
Name: "GNU2/GNU2/long-path-name",
|
||||
Linkname: "GNU4/GNU4/long-linkpath-name",
|
||||
ModTime: time.Unix(0, 0),
|
||||
Typeflag: '2',
|
||||
}},
|
||||
}, {
|
||||
// GNU tar file with atime and ctime fields set.
|
||||
// Created with the GNU tar v1.27.1.
|
||||
// tar --incremental -S -cvf gnu-incremental.tar test2
|
||||
file: "testdata/gnu-incremental.tar",
|
||||
headers: []*Header{{
|
||||
Name: "test2/",
|
||||
Mode: 16877,
|
||||
Uid: 1000,
|
||||
Gid: 1000,
|
||||
Size: 14,
|
||||
ModTime: time.Unix(1441973427, 0),
|
||||
Typeflag: 'D',
|
||||
Uname: "rawr",
|
||||
Gname: "dsnet",
|
||||
AccessTime: time.Unix(1441974501, 0),
|
||||
ChangeTime: time.Unix(1441973436, 0),
|
||||
}, {
|
||||
Name: "test2/foo",
|
||||
Mode: 33188,
|
||||
Uid: 1000,
|
||||
Gid: 1000,
|
||||
Size: 64,
|
||||
ModTime: time.Unix(1441973363, 0),
|
||||
Typeflag: '0',
|
||||
Uname: "rawr",
|
||||
Gname: "dsnet",
|
||||
AccessTime: time.Unix(1441974501, 0),
|
||||
ChangeTime: time.Unix(1441973436, 0),
|
||||
}, {
|
||||
Name: "test2/sparse",
|
||||
Mode: 33188,
|
||||
Uid: 1000,
|
||||
Gid: 1000,
|
||||
Size: 536870912,
|
||||
ModTime: time.Unix(1441973427, 0),
|
||||
Typeflag: 'S',
|
||||
Uname: "rawr",
|
||||
Gname: "dsnet",
|
||||
AccessTime: time.Unix(1441991948, 0),
|
||||
ChangeTime: time.Unix(1441973436, 0),
|
||||
}},
|
||||
}, {
|
||||
headers: []*Header{
|
||||
{
|
||||
Name: "GNU2/GNU2/long-path-name",
|
||||
Linkname: "GNU4/GNU4/long-linkpath-name",
|
||||
ModTime: time.Unix(0, 0),
|
||||
Typeflag: '2',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// Matches the behavior of GNU and BSD tar utilities.
|
||||
file: "testdata/pax-multi-hdrs.tar",
|
||||
headers: []*Header{{
|
||||
Name: "bar",
|
||||
Linkname: "PAX4/PAX4/long-linkpath-name",
|
||||
ModTime: time.Unix(0, 0),
|
||||
Typeflag: '2',
|
||||
}},
|
||||
}, {
|
||||
headers: []*Header{
|
||||
{
|
||||
Name: "bar",
|
||||
Linkname: "PAX4/PAX4/long-linkpath-name",
|
||||
ModTime: time.Unix(0, 0),
|
||||
Typeflag: '2',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
file: "testdata/neg-size.tar",
|
||||
err: ErrHeader,
|
||||
}, {
|
||||
},
|
||||
{
|
||||
file: "testdata/issue10968.tar",
|
||||
err: ErrHeader,
|
||||
}, {
|
||||
},
|
||||
{
|
||||
file: "testdata/issue11169.tar",
|
||||
err: ErrHeader,
|
||||
}, {
|
||||
},
|
||||
{
|
||||
file: "testdata/issue12435.tar",
|
||||
err: ErrHeader,
|
||||
}}
|
||||
},
|
||||
}
|
||||
|
||||
for i, v := range vectors {
|
||||
func TestReader(t *testing.T) {
|
||||
for i, v := range untarTests {
|
||||
f, err := os.Open(v.file)
|
||||
if err != nil {
|
||||
t.Errorf("file %s, test %d: unexpected error: %v", v.file, i, err)
|
||||
@@ -457,8 +440,83 @@ func TestPartialRead(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestParsePAXHeader(t *testing.T) {
|
||||
paxTests := [][3]string{
|
||||
{"a", "a=name", "10 a=name\n"}, // Test case involving multiple acceptable lengths
|
||||
{"a", "a=name", "9 a=name\n"}, // Test case involving multiple acceptable length
|
||||
{"mtime", "mtime=1350244992.023960108", "30 mtime=1350244992.023960108\n"}}
|
||||
for _, test := range paxTests {
|
||||
key, expected, raw := test[0], test[1], test[2]
|
||||
reader := bytes.NewReader([]byte(raw))
|
||||
headers, err := parsePAX(reader)
|
||||
if err != nil {
|
||||
t.Errorf("Couldn't parse correctly formatted headers: %v", err)
|
||||
continue
|
||||
}
|
||||
if strings.EqualFold(headers[key], expected) {
|
||||
t.Errorf("mtime header incorrectly parsed: got %s, wanted %s", headers[key], expected)
|
||||
continue
|
||||
}
|
||||
trailer := make([]byte, 100)
|
||||
n, err := reader.Read(trailer)
|
||||
if err != io.EOF || n != 0 {
|
||||
t.Error("Buffer wasn't consumed")
|
||||
}
|
||||
}
|
||||
badHeaderTests := [][]byte{
|
||||
[]byte("3 somelongkey=\n"),
|
||||
[]byte("50 tooshort=\n"),
|
||||
}
|
||||
for _, test := range badHeaderTests {
|
||||
if _, err := parsePAX(bytes.NewReader(test)); err != ErrHeader {
|
||||
t.Fatal("Unexpected success when parsing bad header")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParsePAXTime(t *testing.T) {
|
||||
// Some valid PAX time values
|
||||
timestamps := map[string]time.Time{
|
||||
"1350244992.023960108": time.Unix(1350244992, 23960108), // The common case
|
||||
"1350244992.02396010": time.Unix(1350244992, 23960100), // Lower precision value
|
||||
"1350244992.0239601089": time.Unix(1350244992, 23960108), // Higher precision value
|
||||
"1350244992": time.Unix(1350244992, 0), // Low precision value
|
||||
}
|
||||
for input, expected := range timestamps {
|
||||
ts, err := parsePAXTime(input)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !ts.Equal(expected) {
|
||||
t.Fatalf("Time parsing failure %s %s", ts, expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMergePAX(t *testing.T) {
|
||||
hdr := new(Header)
|
||||
// Test a string, integer, and time based value.
|
||||
headers := map[string]string{
|
||||
"path": "a/b/c",
|
||||
"uid": "1000",
|
||||
"mtime": "1350244992.023960108",
|
||||
}
|
||||
err := mergePAX(hdr, headers)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
want := &Header{
|
||||
Name: "a/b/c",
|
||||
Uid: 1000,
|
||||
ModTime: time.Unix(1350244992, 23960108),
|
||||
}
|
||||
if !reflect.DeepEqual(hdr, want) {
|
||||
t.Errorf("incorrect merge: got %+v, want %+v", hdr, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSparseFileReader(t *testing.T) {
|
||||
vectors := []struct {
|
||||
var vectors = []struct {
|
||||
realSize int64 // Real size of the output file
|
||||
sparseMap []sparseEntry // Input sparse map
|
||||
sparseData string // Input compact data
|
||||
@@ -581,11 +639,9 @@ func TestSparseFileReader(t *testing.T) {
|
||||
r := bytes.NewReader([]byte(v.sparseData))
|
||||
rfr := ®FileReader{r: r, nb: int64(len(v.sparseData))}
|
||||
|
||||
var (
|
||||
sfr *sparseFileReader
|
||||
err error
|
||||
buf []byte
|
||||
)
|
||||
var sfr *sparseFileReader
|
||||
var err error
|
||||
var buf []byte
|
||||
|
||||
sfr, err = newSparseFileReader(rfr, v.sparseMap, v.realSize)
|
||||
if err != nil {
|
||||
@@ -612,64 +668,6 @@ func TestSparseFileReader(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadOldGNUSparseMap(t *testing.T) {
|
||||
const (
|
||||
t00 = "00000000000\x0000000000000\x00"
|
||||
t11 = "00000000001\x0000000000001\x00"
|
||||
t12 = "00000000001\x0000000000002\x00"
|
||||
t21 = "00000000002\x0000000000001\x00"
|
||||
)
|
||||
|
||||
mkBlk := func(size, sp0, sp1, sp2, sp3, ext string, format int) *block {
|
||||
var blk block
|
||||
copy(blk.GNU().RealSize(), size)
|
||||
copy(blk.GNU().Sparse().Entry(0), sp0)
|
||||
copy(blk.GNU().Sparse().Entry(1), sp1)
|
||||
copy(blk.GNU().Sparse().Entry(2), sp2)
|
||||
copy(blk.GNU().Sparse().Entry(3), sp3)
|
||||
copy(blk.GNU().Sparse().IsExtended(), ext)
|
||||
if format != formatUnknown {
|
||||
blk.SetFormat(format)
|
||||
}
|
||||
return &blk
|
||||
}
|
||||
|
||||
vectors := []struct {
|
||||
data string // Input data
|
||||
rawHdr *block // Input raw header
|
||||
want []sparseEntry // Expected sparse entries to be outputted
|
||||
err error // Expected error to be returned
|
||||
}{
|
||||
{"", mkBlk("", "", "", "", "", "", formatUnknown), nil, ErrHeader},
|
||||
{"", mkBlk("1234", "fewa", "", "", "", "", formatGNU), nil, ErrHeader},
|
||||
{"", mkBlk("0031", "", "", "", "", "", formatGNU), nil, nil},
|
||||
{"", mkBlk("1234", t00, t11, "", "", "", formatGNU),
|
||||
[]sparseEntry{{0, 0}, {1, 1}}, nil},
|
||||
{"", mkBlk("1234", t11, t12, t21, t11, "", formatGNU),
|
||||
[]sparseEntry{{1, 1}, {1, 2}, {2, 1}, {1, 1}}, nil},
|
||||
{"", mkBlk("1234", t11, t12, t21, t11, "\x80", formatGNU),
|
||||
[]sparseEntry{}, io.ErrUnexpectedEOF},
|
||||
{t11 + t11,
|
||||
mkBlk("1234", t11, t12, t21, t11, "\x80", formatGNU),
|
||||
[]sparseEntry{}, io.ErrUnexpectedEOF},
|
||||
{t11 + t21 + strings.Repeat("\x00", 512),
|
||||
mkBlk("1234", t11, t12, t21, t11, "\x80", formatGNU),
|
||||
[]sparseEntry{{1, 1}, {1, 2}, {2, 1}, {1, 1}, {1, 1}, {2, 1}}, nil},
|
||||
}
|
||||
|
||||
for i, v := range vectors {
|
||||
tr := Reader{r: strings.NewReader(v.data)}
|
||||
hdr := new(Header)
|
||||
got, err := tr.readOldGNUSparseMap(hdr, v.rawHdr)
|
||||
if !reflect.DeepEqual(got, v.want) && !(len(got) == 0 && len(v.want) == 0) {
|
||||
t.Errorf("test %d, readOldGNUSparseMap(...): got %v, want %v", i, got, v.want)
|
||||
}
|
||||
if err != v.err {
|
||||
t.Errorf("test %d, unexpected error: got %v, want %v", i, err, v.err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadGNUSparseMap0x1(t *testing.T) {
|
||||
const (
|
||||
maxUint = ^uint(0)
|
||||
@@ -681,7 +679,7 @@ func TestReadGNUSparseMap0x1(t *testing.T) {
|
||||
big3 = fmt.Sprintf("%d", (int64(maxInt) / 3))
|
||||
)
|
||||
|
||||
vectors := []struct {
|
||||
var vectors = []struct {
|
||||
extHdrs map[string]string // Input data
|
||||
sparseMap []sparseEntry // Expected sparse entries to be outputted
|
||||
err error // Expected errors that may be raised
|
||||
@@ -747,12 +745,12 @@ func TestReadGNUSparseMap0x1(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestReadGNUSparseMap1x0(t *testing.T) {
|
||||
sp := []sparseEntry{{1, 2}, {3, 4}}
|
||||
var sp = []sparseEntry{{1, 2}, {3, 4}}
|
||||
for i := 0; i < 98; i++ {
|
||||
sp = append(sp, sparseEntry{54321, 12345})
|
||||
}
|
||||
|
||||
vectors := []struct {
|
||||
var vectors = []struct {
|
||||
input string // Input data
|
||||
sparseMap []sparseEntry // Expected sparse entries to be outputted
|
||||
cnt int // Expected number of bytes read
|
||||
@@ -827,7 +825,8 @@ func TestReadGNUSparseMap1x0(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestUninitializedRead(t *testing.T) {
|
||||
f, err := os.Open("testdata/gnu.tar")
|
||||
test := gnuTarTest
|
||||
f, err := os.Open(test.file)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
@@ -869,7 +868,7 @@ func TestReadTruncation(t *testing.T) {
|
||||
data2 += strings.Repeat("\x00", 10*512)
|
||||
trash := strings.Repeat("garbage ", 64) // Exactly 512 bytes
|
||||
|
||||
vectors := []struct {
|
||||
var vectors = []struct {
|
||||
input string // Input stream
|
||||
cnt int // Expected number of headers read
|
||||
err error // Expected error outcome
|
||||
@@ -905,7 +904,8 @@ func TestReadTruncation(t *testing.T) {
|
||||
{pax + trash[:1], 0, io.ErrUnexpectedEOF},
|
||||
{pax + trash[:511], 0, io.ErrUnexpectedEOF},
|
||||
{sparse[:511], 0, io.ErrUnexpectedEOF},
|
||||
{sparse[:512], 0, io.ErrUnexpectedEOF},
|
||||
// TODO(dsnet): This should pass, but currently fails.
|
||||
// {sparse[:512], 0, io.ErrUnexpectedEOF},
|
||||
{sparse[:3584], 1, io.EOF},
|
||||
{sparse[:9200], 1, io.EOF}, // Terminate in padding of sparse header
|
||||
{sparse[:9216], 1, io.EOF},
|
||||
@@ -1002,7 +1002,7 @@ func TestReadHeaderOnly(t *testing.T) {
|
||||
t.Fatalf("len(hdrs): got %d, want %d", len(hdrs), 16)
|
||||
}
|
||||
for i := 0; i < 8; i++ {
|
||||
hdr1, hdr2 := hdrs[i+0], hdrs[i+8]
|
||||
var hdr1, hdr2 = hdrs[i+0], hdrs[i+8]
|
||||
hdr1.Size, hdr2.Size = 0, 0
|
||||
if !reflect.DeepEqual(*hdr1, *hdr2) {
|
||||
t.Errorf("incorrect header:\ngot %+v\nwant %+v", *hdr1, *hdr2)
|
||||
@@ -1010,87 +1010,116 @@ func TestReadHeaderOnly(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMergePAX(t *testing.T) {
|
||||
vectors := []struct {
|
||||
in map[string]string
|
||||
want *Header
|
||||
ok bool
|
||||
}{{
|
||||
in: map[string]string{
|
||||
"path": "a/b/c",
|
||||
"uid": "1000",
|
||||
"mtime": "1350244992.023960108",
|
||||
},
|
||||
want: &Header{
|
||||
Name: "a/b/c",
|
||||
Uid: 1000,
|
||||
ModTime: time.Unix(1350244992, 23960108),
|
||||
},
|
||||
ok: true,
|
||||
}, {
|
||||
in: map[string]string{
|
||||
"gid": "gtgergergersagersgers",
|
||||
},
|
||||
}, {
|
||||
in: map[string]string{
|
||||
"missing": "missing",
|
||||
"SCHILY.xattr.key": "value",
|
||||
},
|
||||
want: &Header{
|
||||
Xattrs: map[string]string{"key": "value"},
|
||||
},
|
||||
ok: true,
|
||||
}}
|
||||
func TestParsePAXRecord(t *testing.T) {
|
||||
var medName = strings.Repeat("CD", 50)
|
||||
var longName = strings.Repeat("AB", 100)
|
||||
|
||||
for i, v := range vectors {
|
||||
got := new(Header)
|
||||
err := mergePAX(got, v.in)
|
||||
if v.ok && !reflect.DeepEqual(*got, *v.want) {
|
||||
t.Errorf("test %d, mergePAX(...):\ngot %+v\nwant %+v", i, *got, *v.want)
|
||||
}
|
||||
if ok := err == nil; ok != v.ok {
|
||||
t.Errorf("test %d, mergePAX(...): got %v, want %v", i, ok, v.ok)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParsePAX(t *testing.T) {
|
||||
vectors := []struct {
|
||||
in string
|
||||
want map[string]string
|
||||
ok bool
|
||||
var vectors = []struct {
|
||||
input string
|
||||
residual string
|
||||
outputKey string
|
||||
outputVal string
|
||||
ok bool
|
||||
}{
|
||||
{"", nil, true},
|
||||
{"6 k=1\n", map[string]string{"k": "1"}, true},
|
||||
{"10 a=name\n", map[string]string{"a": "name"}, true},
|
||||
{"9 a=name\n", map[string]string{"a": "name"}, true},
|
||||
{"30 mtime=1350244992.023960108\n", map[string]string{"mtime": "1350244992.023960108"}, true},
|
||||
{"3 somelongkey=\n", nil, false},
|
||||
{"50 tooshort=\n", nil, false},
|
||||
{"13 key1=haha\n13 key2=nana\n13 key3=kaka\n",
|
||||
map[string]string{"key1": "haha", "key2": "nana", "key3": "kaka"}, true},
|
||||
{"13 key1=val1\n13 key2=val2\n8 key1=\n",
|
||||
map[string]string{"key2": "val2"}, true},
|
||||
{"22 GNU.sparse.size=10\n26 GNU.sparse.numblocks=2\n" +
|
||||
"23 GNU.sparse.offset=1\n25 GNU.sparse.numbytes=2\n" +
|
||||
"23 GNU.sparse.offset=3\n25 GNU.sparse.numbytes=4\n",
|
||||
map[string]string{paxGNUSparseSize: "10", paxGNUSparseNumBlocks: "2", paxGNUSparseMap: "1,2,3,4"}, true},
|
||||
{"22 GNU.sparse.size=10\n26 GNU.sparse.numblocks=1\n" +
|
||||
"25 GNU.sparse.numbytes=2\n23 GNU.sparse.offset=1\n",
|
||||
nil, false},
|
||||
{"22 GNU.sparse.size=10\n26 GNU.sparse.numblocks=1\n" +
|
||||
"25 GNU.sparse.offset=1,2\n25 GNU.sparse.numbytes=2\n",
|
||||
nil, false},
|
||||
{"6 k=v\n\n", "\n", "k", "v", true},
|
||||
{"19 path=/etc/hosts\n", "", "path", "/etc/hosts", true},
|
||||
{"210 path=" + longName + "\nabc", "abc", "path", longName, true},
|
||||
{"110 path=" + medName + "\n", "", "path", medName, true},
|
||||
{"9 foo=ba\n", "", "foo", "ba", true},
|
||||
{"11 foo=bar\n\x00", "\x00", "foo", "bar", true},
|
||||
{"18 foo=b=\nar=\n==\x00\n", "", "foo", "b=\nar=\n==\x00", true},
|
||||
{"27 foo=hello9 foo=ba\nworld\n", "", "foo", "hello9 foo=ba\nworld", true},
|
||||
{"27 ☺☻☹=日a本b語ç\nmeow mix", "meow mix", "☺☻☹", "日a本b語ç", true},
|
||||
{"17 \x00hello=\x00world\n", "", "\x00hello", "\x00world", true},
|
||||
{"1 k=1\n", "1 k=1\n", "", "", false},
|
||||
{"6 k~1\n", "6 k~1\n", "", "", false},
|
||||
{"6_k=1\n", "6_k=1\n", "", "", false},
|
||||
{"6 k=1 ", "6 k=1 ", "", "", false},
|
||||
{"632 k=1\n", "632 k=1\n", "", "", false},
|
||||
{"16 longkeyname=hahaha\n", "16 longkeyname=hahaha\n", "", "", false},
|
||||
{"3 somelongkey=\n", "3 somelongkey=\n", "", "", false},
|
||||
{"50 tooshort=\n", "50 tooshort=\n", "", "", false},
|
||||
}
|
||||
|
||||
for i, v := range vectors {
|
||||
r := strings.NewReader(v.in)
|
||||
got, err := parsePAX(r)
|
||||
if !reflect.DeepEqual(got, v.want) && !(len(got) == 0 && len(v.want) == 0) {
|
||||
t.Errorf("test %d, parsePAX(...):\ngot %v\nwant %v", i, got, v.want)
|
||||
for _, v := range vectors {
|
||||
key, val, res, err := parsePAXRecord(v.input)
|
||||
ok := (err == nil)
|
||||
if v.ok != ok {
|
||||
if v.ok {
|
||||
t.Errorf("parsePAXRecord(%q): got parsing failure, want success", v.input)
|
||||
} else {
|
||||
t.Errorf("parsePAXRecord(%q): got parsing success, want failure", v.input)
|
||||
}
|
||||
}
|
||||
if ok := err == nil; ok != v.ok {
|
||||
t.Errorf("test %d, parsePAX(...): got %v, want %v", i, ok, v.ok)
|
||||
if ok && (key != v.outputKey || val != v.outputVal) {
|
||||
t.Errorf("parsePAXRecord(%q): got (%q: %q), want (%q: %q)",
|
||||
v.input, key, val, v.outputKey, v.outputVal)
|
||||
}
|
||||
if res != v.residual {
|
||||
t.Errorf("parsePAXRecord(%q): got residual %q, want residual %q",
|
||||
v.input, res, v.residual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseNumeric(t *testing.T) {
|
||||
var vectors = []struct {
|
||||
input string
|
||||
output int64
|
||||
ok bool
|
||||
}{
|
||||
// Test base-256 (binary) encoded values.
|
||||
{"", 0, true},
|
||||
{"\x80", 0, true},
|
||||
{"\x80\x00", 0, true},
|
||||
{"\x80\x00\x00", 0, true},
|
||||
{"\xbf", (1 << 6) - 1, true},
|
||||
{"\xbf\xff", (1 << 14) - 1, true},
|
||||
{"\xbf\xff\xff", (1 << 22) - 1, true},
|
||||
{"\xff", -1, true},
|
||||
{"\xff\xff", -1, true},
|
||||
{"\xff\xff\xff", -1, true},
|
||||
{"\xc0", -1 * (1 << 6), true},
|
||||
{"\xc0\x00", -1 * (1 << 14), true},
|
||||
{"\xc0\x00\x00", -1 * (1 << 22), true},
|
||||
{"\x87\x76\xa2\x22\xeb\x8a\x72\x61", 537795476381659745, true},
|
||||
{"\x80\x00\x00\x00\x07\x76\xa2\x22\xeb\x8a\x72\x61", 537795476381659745, true},
|
||||
{"\xf7\x76\xa2\x22\xeb\x8a\x72\x61", -615126028225187231, true},
|
||||
{"\xff\xff\xff\xff\xf7\x76\xa2\x22\xeb\x8a\x72\x61", -615126028225187231, true},
|
||||
{"\x80\x7f\xff\xff\xff\xff\xff\xff\xff", math.MaxInt64, true},
|
||||
{"\x80\x80\x00\x00\x00\x00\x00\x00\x00", 0, false},
|
||||
{"\xff\x80\x00\x00\x00\x00\x00\x00\x00", math.MinInt64, true},
|
||||
{"\xff\x7f\xff\xff\xff\xff\xff\xff\xff", 0, false},
|
||||
{"\xf5\xec\xd1\xc7\x7e\x5f\x26\x48\x81\x9f\x8f\x9b", 0, false},
|
||||
|
||||
// Test base-8 (octal) encoded values.
|
||||
{"0000000\x00", 0, true},
|
||||
{" \x0000000\x00", 0, true},
|
||||
{" \x0000003\x00", 3, true},
|
||||
{"00000000227\x00", 0227, true},
|
||||
{"032033\x00 ", 032033, true},
|
||||
{"320330\x00 ", 0320330, true},
|
||||
{"0000660\x00 ", 0660, true},
|
||||
{"\x00 0000660\x00 ", 0660, true},
|
||||
{"0123456789abcdef", 0, false},
|
||||
{"0123456789\x00abcdef", 0, false},
|
||||
{"01234567\x0089abcdef", 342391, true},
|
||||
{"0123\x7e\x5f\x264123", 0, false},
|
||||
}
|
||||
|
||||
for _, v := range vectors {
|
||||
var p parser
|
||||
num := p.parseNumeric([]byte(v.input))
|
||||
ok := (p.err == nil)
|
||||
if v.ok != ok {
|
||||
if v.ok {
|
||||
t.Errorf("parseNumeric(%q): got parsing failure, want success", v.input)
|
||||
} else {
|
||||
t.Errorf("parseNumeric(%q): got parsing success, want failure", v.input)
|
||||
}
|
||||
}
|
||||
if ok && num != v.output {
|
||||
t.Errorf("parseNumeric(%q): got %d, want %d", v.input, num, v.output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,252 +0,0 @@
|
||||
// Copyright 2016 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 tar
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func isASCII(s string) bool {
|
||||
for _, c := range s {
|
||||
if c >= 0x80 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func toASCII(s string) string {
|
||||
if isASCII(s) {
|
||||
return s
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
for _, c := range s {
|
||||
if c < 0x80 {
|
||||
buf.WriteByte(byte(c))
|
||||
}
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
type parser struct {
|
||||
err error // Last error seen
|
||||
}
|
||||
|
||||
type formatter struct {
|
||||
err error // Last error seen
|
||||
}
|
||||
|
||||
// parseString parses bytes as a NUL-terminated C-style string.
|
||||
// If a NUL byte is not found then the whole slice is returned as a string.
|
||||
func (*parser) parseString(b []byte) string {
|
||||
n := 0
|
||||
for n < len(b) && b[n] != 0 {
|
||||
n++
|
||||
}
|
||||
return string(b[0:n])
|
||||
}
|
||||
|
||||
// Write s into b, terminating it with a NUL if there is room.
|
||||
func (f *formatter) formatString(b []byte, s string) {
|
||||
if len(s) > len(b) {
|
||||
f.err = ErrFieldTooLong
|
||||
return
|
||||
}
|
||||
ascii := toASCII(s)
|
||||
copy(b, ascii)
|
||||
if len(ascii) < len(b) {
|
||||
b[len(ascii)] = 0
|
||||
}
|
||||
}
|
||||
|
||||
// fitsInBase256 reports whether x can be encoded into n bytes using base-256
|
||||
// encoding. Unlike octal encoding, base-256 encoding does not require that the
|
||||
// string ends with a NUL character. Thus, all n bytes are available for output.
|
||||
//
|
||||
// If operating in binary mode, this assumes strict GNU binary mode; which means
|
||||
// that the first byte can only be either 0x80 or 0xff. Thus, the first byte is
|
||||
// equivalent to the sign bit in two's complement form.
|
||||
func fitsInBase256(n int, x int64) bool {
|
||||
var binBits = uint(n-1) * 8
|
||||
return n >= 9 || (x >= -1<<binBits && x < 1<<binBits)
|
||||
}
|
||||
|
||||
// parseNumeric parses the input as being encoded in either base-256 or octal.
|
||||
// This function may return negative numbers.
|
||||
// If parsing fails or an integer overflow occurs, err will be set.
|
||||
func (p *parser) parseNumeric(b []byte) int64 {
|
||||
// Check for base-256 (binary) format first.
|
||||
// If the first bit is set, then all following bits constitute a two's
|
||||
// complement encoded number in big-endian byte order.
|
||||
if len(b) > 0 && b[0]&0x80 != 0 {
|
||||
// Handling negative numbers relies on the following identity:
|
||||
// -a-1 == ^a
|
||||
//
|
||||
// If the number is negative, we use an inversion mask to invert the
|
||||
// data bytes and treat the value as an unsigned number.
|
||||
var inv byte // 0x00 if positive or zero, 0xff if negative
|
||||
if b[0]&0x40 != 0 {
|
||||
inv = 0xff
|
||||
}
|
||||
|
||||
var x uint64
|
||||
for i, c := range b {
|
||||
c ^= inv // Inverts c only if inv is 0xff, otherwise does nothing
|
||||
if i == 0 {
|
||||
c &= 0x7f // Ignore signal bit in first byte
|
||||
}
|
||||
if (x >> 56) > 0 {
|
||||
p.err = ErrHeader // Integer overflow
|
||||
return 0
|
||||
}
|
||||
x = x<<8 | uint64(c)
|
||||
}
|
||||
if (x >> 63) > 0 {
|
||||
p.err = ErrHeader // Integer overflow
|
||||
return 0
|
||||
}
|
||||
if inv == 0xff {
|
||||
return ^int64(x)
|
||||
}
|
||||
return int64(x)
|
||||
}
|
||||
|
||||
// Normal case is base-8 (octal) format.
|
||||
return p.parseOctal(b)
|
||||
}
|
||||
|
||||
// Write x into b, as binary (GNUtar/star extension).
|
||||
func (f *formatter) formatNumeric(b []byte, x int64) {
|
||||
if fitsInBase256(len(b), x) {
|
||||
for i := len(b) - 1; i >= 0; i-- {
|
||||
b[i] = byte(x)
|
||||
x >>= 8
|
||||
}
|
||||
b[0] |= 0x80 // Highest bit indicates binary format
|
||||
return
|
||||
}
|
||||
|
||||
f.formatOctal(b, 0) // Last resort, just write zero
|
||||
f.err = ErrFieldTooLong
|
||||
}
|
||||
|
||||
func (p *parser) parseOctal(b []byte) int64 {
|
||||
// Because unused fields are filled with NULs, we need
|
||||
// to skip leading NULs. Fields may also be padded with
|
||||
// spaces or NULs.
|
||||
// So we remove leading and trailing NULs and spaces to
|
||||
// be sure.
|
||||
b = bytes.Trim(b, " \x00")
|
||||
|
||||
if len(b) == 0 {
|
||||
return 0
|
||||
}
|
||||
x, perr := strconv.ParseUint(p.parseString(b), 8, 64)
|
||||
if perr != nil {
|
||||
p.err = ErrHeader
|
||||
}
|
||||
return int64(x)
|
||||
}
|
||||
|
||||
func (f *formatter) formatOctal(b []byte, x int64) {
|
||||
s := strconv.FormatInt(x, 8)
|
||||
// Add leading zeros, but leave room for a NUL.
|
||||
if n := len(b) - len(s) - 1; n > 0 {
|
||||
s = strings.Repeat("0", n) + s
|
||||
}
|
||||
f.formatString(b, s)
|
||||
}
|
||||
|
||||
// parsePAXTime takes a string of the form %d.%d as described in the PAX
|
||||
// specification. Note that this implementation allows for negative timestamps,
|
||||
// which is allowed for by the PAX specification, but not always portable.
|
||||
func parsePAXTime(s string) (time.Time, error) {
|
||||
const maxNanoSecondDigits = 9
|
||||
|
||||
// Split string into seconds and sub-seconds parts.
|
||||
ss, sn := s, ""
|
||||
if pos := strings.IndexByte(s, '.'); pos >= 0 {
|
||||
ss, sn = s[:pos], s[pos+1:]
|
||||
}
|
||||
|
||||
// Parse the seconds.
|
||||
secs, err := strconv.ParseInt(ss, 10, 64)
|
||||
if err != nil {
|
||||
return time.Time{}, ErrHeader
|
||||
}
|
||||
if len(sn) == 0 {
|
||||
return time.Unix(secs, 0), nil // No sub-second values
|
||||
}
|
||||
|
||||
// Parse the nanoseconds.
|
||||
if strings.Trim(sn, "0123456789") != "" {
|
||||
return time.Time{}, ErrHeader
|
||||
}
|
||||
if len(sn) < maxNanoSecondDigits {
|
||||
sn += strings.Repeat("0", maxNanoSecondDigits-len(sn)) // Right pad
|
||||
} else {
|
||||
sn = sn[:maxNanoSecondDigits] // Right truncate
|
||||
}
|
||||
nsecs, _ := strconv.ParseInt(sn, 10, 64) // Must succeed
|
||||
if len(ss) > 0 && ss[0] == '-' {
|
||||
return time.Unix(secs, -1*int64(nsecs)), nil // Negative correction
|
||||
}
|
||||
return time.Unix(secs, int64(nsecs)), nil
|
||||
}
|
||||
|
||||
// TODO(dsnet): Implement formatPAXTime.
|
||||
|
||||
// parsePAXRecord parses the input PAX record string into a key-value pair.
|
||||
// If parsing is successful, it will slice off the currently read record and
|
||||
// return the remainder as r.
|
||||
//
|
||||
// A PAX record is of the following form:
|
||||
// "%d %s=%s\n" % (size, key, value)
|
||||
func parsePAXRecord(s string) (k, v, r string, err error) {
|
||||
// The size field ends at the first space.
|
||||
sp := strings.IndexByte(s, ' ')
|
||||
if sp == -1 {
|
||||
return "", "", s, ErrHeader
|
||||
}
|
||||
|
||||
// Parse the first token as a decimal integer.
|
||||
n, perr := strconv.ParseInt(s[:sp], 10, 0) // Intentionally parse as native int
|
||||
if perr != nil || n < 5 || int64(len(s)) < n {
|
||||
return "", "", s, ErrHeader
|
||||
}
|
||||
|
||||
// Extract everything between the space and the final newline.
|
||||
rec, nl, rem := s[sp+1:n-1], s[n-1:n], s[n:]
|
||||
if nl != "\n" {
|
||||
return "", "", s, ErrHeader
|
||||
}
|
||||
|
||||
// The first equals separates the key from the value.
|
||||
eq := strings.IndexByte(rec, '=')
|
||||
if eq == -1 {
|
||||
return "", "", s, ErrHeader
|
||||
}
|
||||
return rec[:eq], rec[eq+1:], rem, nil
|
||||
}
|
||||
|
||||
// formatPAXRecord formats a single PAX record, prefixing it with the
|
||||
// appropriate length.
|
||||
func formatPAXRecord(k, v string) string {
|
||||
const padding = 3 // Extra padding for ' ', '=', and '\n'
|
||||
size := len(k) + len(v) + padding
|
||||
size += len(strconv.Itoa(size))
|
||||
record := fmt.Sprintf("%d %s=%s\n", size, k, v)
|
||||
|
||||
// Final adjustment if adding size field increased the record size.
|
||||
if len(record) != size {
|
||||
size = len(record)
|
||||
record = fmt.Sprintf("%d %s=%s\n", size, k, v)
|
||||
}
|
||||
return record
|
||||
}
|
||||
@@ -1,319 +0,0 @@
|
||||
// Copyright 2016 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 tar
|
||||
|
||||
import (
|
||||
"math"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestFitsInBase256(t *testing.T) {
|
||||
vectors := []struct {
|
||||
in int64
|
||||
width int
|
||||
ok bool
|
||||
}{
|
||||
{+1, 8, true},
|
||||
{0, 8, true},
|
||||
{-1, 8, true},
|
||||
{1 << 56, 8, false},
|
||||
{(1 << 56) - 1, 8, true},
|
||||
{-1 << 56, 8, true},
|
||||
{(-1 << 56) - 1, 8, false},
|
||||
{121654, 8, true},
|
||||
{-9849849, 8, true},
|
||||
{math.MaxInt64, 9, true},
|
||||
{0, 9, true},
|
||||
{math.MinInt64, 9, true},
|
||||
{math.MaxInt64, 12, true},
|
||||
{0, 12, true},
|
||||
{math.MinInt64, 12, true},
|
||||
}
|
||||
|
||||
for _, v := range vectors {
|
||||
ok := fitsInBase256(v.width, v.in)
|
||||
if ok != v.ok {
|
||||
t.Errorf("fitsInBase256(%d, %d): got %v, want %v", v.in, v.width, ok, v.ok)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseNumeric(t *testing.T) {
|
||||
vectors := []struct {
|
||||
in string
|
||||
want int64
|
||||
ok bool
|
||||
}{
|
||||
// Test base-256 (binary) encoded values.
|
||||
{"", 0, true},
|
||||
{"\x80", 0, true},
|
||||
{"\x80\x00", 0, true},
|
||||
{"\x80\x00\x00", 0, true},
|
||||
{"\xbf", (1 << 6) - 1, true},
|
||||
{"\xbf\xff", (1 << 14) - 1, true},
|
||||
{"\xbf\xff\xff", (1 << 22) - 1, true},
|
||||
{"\xff", -1, true},
|
||||
{"\xff\xff", -1, true},
|
||||
{"\xff\xff\xff", -1, true},
|
||||
{"\xc0", -1 * (1 << 6), true},
|
||||
{"\xc0\x00", -1 * (1 << 14), true},
|
||||
{"\xc0\x00\x00", -1 * (1 << 22), true},
|
||||
{"\x87\x76\xa2\x22\xeb\x8a\x72\x61", 537795476381659745, true},
|
||||
{"\x80\x00\x00\x00\x07\x76\xa2\x22\xeb\x8a\x72\x61", 537795476381659745, true},
|
||||
{"\xf7\x76\xa2\x22\xeb\x8a\x72\x61", -615126028225187231, true},
|
||||
{"\xff\xff\xff\xff\xf7\x76\xa2\x22\xeb\x8a\x72\x61", -615126028225187231, true},
|
||||
{"\x80\x7f\xff\xff\xff\xff\xff\xff\xff", math.MaxInt64, true},
|
||||
{"\x80\x80\x00\x00\x00\x00\x00\x00\x00", 0, false},
|
||||
{"\xff\x80\x00\x00\x00\x00\x00\x00\x00", math.MinInt64, true},
|
||||
{"\xff\x7f\xff\xff\xff\xff\xff\xff\xff", 0, false},
|
||||
{"\xf5\xec\xd1\xc7\x7e\x5f\x26\x48\x81\x9f\x8f\x9b", 0, false},
|
||||
|
||||
// Test base-8 (octal) encoded values.
|
||||
{"0000000\x00", 0, true},
|
||||
{" \x0000000\x00", 0, true},
|
||||
{" \x0000003\x00", 3, true},
|
||||
{"00000000227\x00", 0227, true},
|
||||
{"032033\x00 ", 032033, true},
|
||||
{"320330\x00 ", 0320330, true},
|
||||
{"0000660\x00 ", 0660, true},
|
||||
{"\x00 0000660\x00 ", 0660, true},
|
||||
{"0123456789abcdef", 0, false},
|
||||
{"0123456789\x00abcdef", 0, false},
|
||||
{"01234567\x0089abcdef", 342391, true},
|
||||
{"0123\x7e\x5f\x264123", 0, false},
|
||||
}
|
||||
|
||||
for _, v := range vectors {
|
||||
var p parser
|
||||
got := p.parseNumeric([]byte(v.in))
|
||||
ok := (p.err == nil)
|
||||
if ok != v.ok {
|
||||
if v.ok {
|
||||
t.Errorf("parseNumeric(%q): got parsing failure, want success", v.in)
|
||||
} else {
|
||||
t.Errorf("parseNumeric(%q): got parsing success, want failure", v.in)
|
||||
}
|
||||
}
|
||||
if ok && got != v.want {
|
||||
t.Errorf("parseNumeric(%q): got %d, want %d", v.in, got, v.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatNumeric(t *testing.T) {
|
||||
vectors := []struct {
|
||||
in int64
|
||||
want string
|
||||
ok bool
|
||||
}{
|
||||
// Test base-256 (binary) encoded values.
|
||||
{-1, "\xff", true},
|
||||
{-1, "\xff\xff", true},
|
||||
{-1, "\xff\xff\xff", true},
|
||||
{(1 << 0), "0", false},
|
||||
{(1 << 8) - 1, "\x80\xff", true},
|
||||
{(1 << 8), "0\x00", false},
|
||||
{(1 << 16) - 1, "\x80\xff\xff", true},
|
||||
{(1 << 16), "00\x00", false},
|
||||
{-1 * (1 << 0), "\xff", true},
|
||||
{-1*(1<<0) - 1, "0", false},
|
||||
{-1 * (1 << 8), "\xff\x00", true},
|
||||
{-1*(1<<8) - 1, "0\x00", false},
|
||||
{-1 * (1 << 16), "\xff\x00\x00", true},
|
||||
{-1*(1<<16) - 1, "00\x00", false},
|
||||
{537795476381659745, "0000000\x00", false},
|
||||
{537795476381659745, "\x80\x00\x00\x00\x07\x76\xa2\x22\xeb\x8a\x72\x61", true},
|
||||
{-615126028225187231, "0000000\x00", false},
|
||||
{-615126028225187231, "\xff\xff\xff\xff\xf7\x76\xa2\x22\xeb\x8a\x72\x61", true},
|
||||
{math.MaxInt64, "0000000\x00", false},
|
||||
{math.MaxInt64, "\x80\x00\x00\x00\x7f\xff\xff\xff\xff\xff\xff\xff", true},
|
||||
{math.MinInt64, "0000000\x00", false},
|
||||
{math.MinInt64, "\xff\xff\xff\xff\x80\x00\x00\x00\x00\x00\x00\x00", true},
|
||||
{math.MaxInt64, "\x80\x7f\xff\xff\xff\xff\xff\xff\xff", true},
|
||||
{math.MinInt64, "\xff\x80\x00\x00\x00\x00\x00\x00\x00", true},
|
||||
}
|
||||
|
||||
for _, v := range vectors {
|
||||
var f formatter
|
||||
got := make([]byte, len(v.want))
|
||||
f.formatNumeric(got, v.in)
|
||||
ok := (f.err == nil)
|
||||
if ok != v.ok {
|
||||
if v.ok {
|
||||
t.Errorf("formatNumeric(%d): got formatting failure, want success", v.in)
|
||||
} else {
|
||||
t.Errorf("formatNumeric(%d): got formatting success, want failure", v.in)
|
||||
}
|
||||
}
|
||||
if string(got) != v.want {
|
||||
t.Errorf("formatNumeric(%d): got %q, want %q", v.in, got, v.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParsePAXTime(t *testing.T) {
|
||||
vectors := []struct {
|
||||
in string
|
||||
want time.Time
|
||||
ok bool
|
||||
}{
|
||||
{"1350244992.023960108", time.Unix(1350244992, 23960108), true},
|
||||
{"1350244992.02396010", time.Unix(1350244992, 23960100), true},
|
||||
{"1350244992.0239601089", time.Unix(1350244992, 23960108), true},
|
||||
{"1350244992.3", time.Unix(1350244992, 300000000), true},
|
||||
{"1350244992", time.Unix(1350244992, 0), true},
|
||||
{"-1.000000001", time.Unix(-1, -1e0+0e0), true},
|
||||
{"-1.000001", time.Unix(-1, -1e3+0e0), true},
|
||||
{"-1.001000", time.Unix(-1, -1e6+0e0), true},
|
||||
{"-1", time.Unix(-1, -0e0+0e0), true},
|
||||
{"-1.999000", time.Unix(-1, -1e9+1e6), true},
|
||||
{"-1.999999", time.Unix(-1, -1e9+1e3), true},
|
||||
{"-1.999999999", time.Unix(-1, -1e9+1e0), true},
|
||||
{"0.000000001", time.Unix(0, 1e0+0e0), true},
|
||||
{"0.000001", time.Unix(0, 1e3+0e0), true},
|
||||
{"0.001000", time.Unix(0, 1e6+0e0), true},
|
||||
{"0", time.Unix(0, 0e0), true},
|
||||
{"0.999000", time.Unix(0, 1e9-1e6), true},
|
||||
{"0.999999", time.Unix(0, 1e9-1e3), true},
|
||||
{"0.999999999", time.Unix(0, 1e9-1e0), true},
|
||||
{"1.000000001", time.Unix(+1, +1e0-0e0), true},
|
||||
{"1.000001", time.Unix(+1, +1e3-0e0), true},
|
||||
{"1.001000", time.Unix(+1, +1e6-0e0), true},
|
||||
{"1", time.Unix(+1, +0e0-0e0), true},
|
||||
{"1.999000", time.Unix(+1, +1e9-1e6), true},
|
||||
{"1.999999", time.Unix(+1, +1e9-1e3), true},
|
||||
{"1.999999999", time.Unix(+1, +1e9-1e0), true},
|
||||
{"-1350244992.023960108", time.Unix(-1350244992, -23960108), true},
|
||||
{"-1350244992.02396010", time.Unix(-1350244992, -23960100), true},
|
||||
{"-1350244992.0239601089", time.Unix(-1350244992, -23960108), true},
|
||||
{"-1350244992.3", time.Unix(-1350244992, -300000000), true},
|
||||
{"-1350244992", time.Unix(-1350244992, 0), true},
|
||||
{"", time.Time{}, false},
|
||||
{"0", time.Unix(0, 0), true},
|
||||
{"1.", time.Unix(1, 0), true},
|
||||
{"0.0", time.Unix(0, 0), true},
|
||||
{".5", time.Time{}, false},
|
||||
{"-1.3", time.Unix(-1, -3e8), true},
|
||||
{"-1.0", time.Unix(-1, -0e0), true},
|
||||
{"-0.0", time.Unix(-0, -0e0), true},
|
||||
{"-0.1", time.Unix(-0, -1e8), true},
|
||||
{"-0.01", time.Unix(-0, -1e7), true},
|
||||
{"-0.99", time.Unix(-0, -99e7), true},
|
||||
{"-0.98", time.Unix(-0, -98e7), true},
|
||||
{"-1.1", time.Unix(-1, -1e8), true},
|
||||
{"-1.01", time.Unix(-1, -1e7), true},
|
||||
{"-2.99", time.Unix(-2, -99e7), true},
|
||||
{"-5.98", time.Unix(-5, -98e7), true},
|
||||
{"-", time.Time{}, false},
|
||||
{"+", time.Time{}, false},
|
||||
{"-1.-1", time.Time{}, false},
|
||||
{"99999999999999999999999999999999999999999999999", time.Time{}, false},
|
||||
{"0.123456789abcdef", time.Time{}, false},
|
||||
{"foo", time.Time{}, false},
|
||||
{"\x00", time.Time{}, false},
|
||||
{"𝟵𝟴𝟳𝟲𝟱.𝟰𝟯𝟮𝟭𝟬", time.Time{}, false}, // Unicode numbers (U+1D7EC to U+1D7F5)
|
||||
{"98765﹒43210", time.Time{}, false}, // Unicode period (U+FE52)
|
||||
}
|
||||
|
||||
for _, v := range vectors {
|
||||
ts, err := parsePAXTime(v.in)
|
||||
ok := (err == nil)
|
||||
if v.ok != ok {
|
||||
if v.ok {
|
||||
t.Errorf("parsePAXTime(%q): got parsing failure, want success", v.in)
|
||||
} else {
|
||||
t.Errorf("parsePAXTime(%q): got parsing success, want failure", v.in)
|
||||
}
|
||||
}
|
||||
if ok && !ts.Equal(v.want) {
|
||||
t.Errorf("parsePAXTime(%q): got (%ds %dns), want (%ds %dns)",
|
||||
v.in, ts.Unix(), ts.Nanosecond(), v.want.Unix(), v.want.Nanosecond())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParsePAXRecord(t *testing.T) {
|
||||
medName := strings.Repeat("CD", 50)
|
||||
longName := strings.Repeat("AB", 100)
|
||||
|
||||
vectors := []struct {
|
||||
in string
|
||||
wantRes string
|
||||
wantKey string
|
||||
wantVal string
|
||||
ok bool
|
||||
}{
|
||||
{"6 k=v\n\n", "\n", "k", "v", true},
|
||||
{"19 path=/etc/hosts\n", "", "path", "/etc/hosts", true},
|
||||
{"210 path=" + longName + "\nabc", "abc", "path", longName, true},
|
||||
{"110 path=" + medName + "\n", "", "path", medName, true},
|
||||
{"9 foo=ba\n", "", "foo", "ba", true},
|
||||
{"11 foo=bar\n\x00", "\x00", "foo", "bar", true},
|
||||
{"18 foo=b=\nar=\n==\x00\n", "", "foo", "b=\nar=\n==\x00", true},
|
||||
{"27 foo=hello9 foo=ba\nworld\n", "", "foo", "hello9 foo=ba\nworld", true},
|
||||
{"27 ☺☻☹=日a本b語ç\nmeow mix", "meow mix", "☺☻☹", "日a本b語ç", true},
|
||||
{"17 \x00hello=\x00world\n", "", "\x00hello", "\x00world", true},
|
||||
{"1 k=1\n", "1 k=1\n", "", "", false},
|
||||
{"6 k~1\n", "6 k~1\n", "", "", false},
|
||||
{"6_k=1\n", "6_k=1\n", "", "", false},
|
||||
{"6 k=1 ", "6 k=1 ", "", "", false},
|
||||
{"632 k=1\n", "632 k=1\n", "", "", false},
|
||||
{"16 longkeyname=hahaha\n", "16 longkeyname=hahaha\n", "", "", false},
|
||||
{"3 somelongkey=\n", "3 somelongkey=\n", "", "", false},
|
||||
{"50 tooshort=\n", "50 tooshort=\n", "", "", false},
|
||||
}
|
||||
|
||||
for _, v := range vectors {
|
||||
key, val, res, err := parsePAXRecord(v.in)
|
||||
ok := (err == nil)
|
||||
if ok != v.ok {
|
||||
if v.ok {
|
||||
t.Errorf("parsePAXRecord(%q): got parsing failure, want success", v.in)
|
||||
} else {
|
||||
t.Errorf("parsePAXRecord(%q): got parsing success, want failure", v.in)
|
||||
}
|
||||
}
|
||||
if v.ok && (key != v.wantKey || val != v.wantVal) {
|
||||
t.Errorf("parsePAXRecord(%q): got (%q: %q), want (%q: %q)",
|
||||
v.in, key, val, v.wantKey, v.wantVal)
|
||||
}
|
||||
if res != v.wantRes {
|
||||
t.Errorf("parsePAXRecord(%q): got residual %q, want residual %q",
|
||||
v.in, res, v.wantRes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatPAXRecord(t *testing.T) {
|
||||
medName := strings.Repeat("CD", 50)
|
||||
longName := strings.Repeat("AB", 100)
|
||||
|
||||
vectors := []struct {
|
||||
inKey string
|
||||
inVal string
|
||||
want string
|
||||
}{
|
||||
{"k", "v", "6 k=v\n"},
|
||||
{"path", "/etc/hosts", "19 path=/etc/hosts\n"},
|
||||
{"path", longName, "210 path=" + longName + "\n"},
|
||||
{"path", medName, "110 path=" + medName + "\n"},
|
||||
{"foo", "ba", "9 foo=ba\n"},
|
||||
{"foo", "bar", "11 foo=bar\n"},
|
||||
{"foo", "b=\nar=\n==\x00", "18 foo=b=\nar=\n==\x00\n"},
|
||||
{"foo", "hello9 foo=ba\nworld", "27 foo=hello9 foo=ba\nworld\n"},
|
||||
{"☺☻☹", "日a本b語ç", "27 ☺☻☹=日a本b語ç\n"},
|
||||
{"\x00hello", "\x00world", "17 \x00hello=\x00world\n"},
|
||||
}
|
||||
|
||||
for _, v := range vectors {
|
||||
got := formatPAXRecord(v.inKey, v.inVal)
|
||||
if got != v.want {
|
||||
t.Errorf("formatPAXRecord(%q, %q): got %q, want %q",
|
||||
v.inKey, v.inVal, got, v.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -135,178 +135,190 @@ type headerRoundTripTest struct {
|
||||
}
|
||||
|
||||
func TestHeaderRoundTrip(t *testing.T) {
|
||||
vectors := []headerRoundTripTest{{
|
||||
golden := []headerRoundTripTest{
|
||||
// regular file.
|
||||
h: &Header{
|
||||
Name: "test.txt",
|
||||
Mode: 0644 | c_ISREG,
|
||||
Size: 12,
|
||||
ModTime: time.Unix(1360600916, 0),
|
||||
Typeflag: TypeReg,
|
||||
{
|
||||
h: &Header{
|
||||
Name: "test.txt",
|
||||
Mode: 0644 | c_ISREG,
|
||||
Size: 12,
|
||||
ModTime: time.Unix(1360600916, 0),
|
||||
Typeflag: TypeReg,
|
||||
},
|
||||
fm: 0644,
|
||||
},
|
||||
fm: 0644,
|
||||
}, {
|
||||
// symbolic link.
|
||||
h: &Header{
|
||||
Name: "link.txt",
|
||||
Mode: 0777 | c_ISLNK,
|
||||
Size: 0,
|
||||
ModTime: time.Unix(1360600852, 0),
|
||||
Typeflag: TypeSymlink,
|
||||
{
|
||||
h: &Header{
|
||||
Name: "link.txt",
|
||||
Mode: 0777 | c_ISLNK,
|
||||
Size: 0,
|
||||
ModTime: time.Unix(1360600852, 0),
|
||||
Typeflag: TypeSymlink,
|
||||
},
|
||||
fm: 0777 | os.ModeSymlink,
|
||||
},
|
||||
fm: 0777 | os.ModeSymlink,
|
||||
}, {
|
||||
// character device node.
|
||||
h: &Header{
|
||||
Name: "dev/null",
|
||||
Mode: 0666 | c_ISCHR,
|
||||
Size: 0,
|
||||
ModTime: time.Unix(1360578951, 0),
|
||||
Typeflag: TypeChar,
|
||||
{
|
||||
h: &Header{
|
||||
Name: "dev/null",
|
||||
Mode: 0666 | c_ISCHR,
|
||||
Size: 0,
|
||||
ModTime: time.Unix(1360578951, 0),
|
||||
Typeflag: TypeChar,
|
||||
},
|
||||
fm: 0666 | os.ModeDevice | os.ModeCharDevice,
|
||||
},
|
||||
fm: 0666 | os.ModeDevice | os.ModeCharDevice,
|
||||
}, {
|
||||
// block device node.
|
||||
h: &Header{
|
||||
Name: "dev/sda",
|
||||
Mode: 0660 | c_ISBLK,
|
||||
Size: 0,
|
||||
ModTime: time.Unix(1360578954, 0),
|
||||
Typeflag: TypeBlock,
|
||||
{
|
||||
h: &Header{
|
||||
Name: "dev/sda",
|
||||
Mode: 0660 | c_ISBLK,
|
||||
Size: 0,
|
||||
ModTime: time.Unix(1360578954, 0),
|
||||
Typeflag: TypeBlock,
|
||||
},
|
||||
fm: 0660 | os.ModeDevice,
|
||||
},
|
||||
fm: 0660 | os.ModeDevice,
|
||||
}, {
|
||||
// directory.
|
||||
h: &Header{
|
||||
Name: "dir/",
|
||||
Mode: 0755 | c_ISDIR,
|
||||
Size: 0,
|
||||
ModTime: time.Unix(1360601116, 0),
|
||||
Typeflag: TypeDir,
|
||||
{
|
||||
h: &Header{
|
||||
Name: "dir/",
|
||||
Mode: 0755 | c_ISDIR,
|
||||
Size: 0,
|
||||
ModTime: time.Unix(1360601116, 0),
|
||||
Typeflag: TypeDir,
|
||||
},
|
||||
fm: 0755 | os.ModeDir,
|
||||
},
|
||||
fm: 0755 | os.ModeDir,
|
||||
}, {
|
||||
// fifo node.
|
||||
h: &Header{
|
||||
Name: "dev/initctl",
|
||||
Mode: 0600 | c_ISFIFO,
|
||||
Size: 0,
|
||||
ModTime: time.Unix(1360578949, 0),
|
||||
Typeflag: TypeFifo,
|
||||
{
|
||||
h: &Header{
|
||||
Name: "dev/initctl",
|
||||
Mode: 0600 | c_ISFIFO,
|
||||
Size: 0,
|
||||
ModTime: time.Unix(1360578949, 0),
|
||||
Typeflag: TypeFifo,
|
||||
},
|
||||
fm: 0600 | os.ModeNamedPipe,
|
||||
},
|
||||
fm: 0600 | os.ModeNamedPipe,
|
||||
}, {
|
||||
// setuid.
|
||||
h: &Header{
|
||||
Name: "bin/su",
|
||||
Mode: 0755 | c_ISREG | c_ISUID,
|
||||
Size: 23232,
|
||||
ModTime: time.Unix(1355405093, 0),
|
||||
Typeflag: TypeReg,
|
||||
{
|
||||
h: &Header{
|
||||
Name: "bin/su",
|
||||
Mode: 0755 | c_ISREG | c_ISUID,
|
||||
Size: 23232,
|
||||
ModTime: time.Unix(1355405093, 0),
|
||||
Typeflag: TypeReg,
|
||||
},
|
||||
fm: 0755 | os.ModeSetuid,
|
||||
},
|
||||
fm: 0755 | os.ModeSetuid,
|
||||
}, {
|
||||
// setguid.
|
||||
h: &Header{
|
||||
Name: "group.txt",
|
||||
Mode: 0750 | c_ISREG | c_ISGID,
|
||||
Size: 0,
|
||||
ModTime: time.Unix(1360602346, 0),
|
||||
Typeflag: TypeReg,
|
||||
{
|
||||
h: &Header{
|
||||
Name: "group.txt",
|
||||
Mode: 0750 | c_ISREG | c_ISGID,
|
||||
Size: 0,
|
||||
ModTime: time.Unix(1360602346, 0),
|
||||
Typeflag: TypeReg,
|
||||
},
|
||||
fm: 0750 | os.ModeSetgid,
|
||||
},
|
||||
fm: 0750 | os.ModeSetgid,
|
||||
}, {
|
||||
// sticky.
|
||||
h: &Header{
|
||||
Name: "sticky.txt",
|
||||
Mode: 0600 | c_ISREG | c_ISVTX,
|
||||
Size: 7,
|
||||
ModTime: time.Unix(1360602540, 0),
|
||||
Typeflag: TypeReg,
|
||||
{
|
||||
h: &Header{
|
||||
Name: "sticky.txt",
|
||||
Mode: 0600 | c_ISREG | c_ISVTX,
|
||||
Size: 7,
|
||||
ModTime: time.Unix(1360602540, 0),
|
||||
Typeflag: TypeReg,
|
||||
},
|
||||
fm: 0600 | os.ModeSticky,
|
||||
},
|
||||
fm: 0600 | os.ModeSticky,
|
||||
}, {
|
||||
// hard link.
|
||||
h: &Header{
|
||||
Name: "hard.txt",
|
||||
Mode: 0644 | c_ISREG,
|
||||
Size: 0,
|
||||
Linkname: "file.txt",
|
||||
ModTime: time.Unix(1360600916, 0),
|
||||
Typeflag: TypeLink,
|
||||
{
|
||||
h: &Header{
|
||||
Name: "hard.txt",
|
||||
Mode: 0644 | c_ISREG,
|
||||
Size: 0,
|
||||
Linkname: "file.txt",
|
||||
ModTime: time.Unix(1360600916, 0),
|
||||
Typeflag: TypeLink,
|
||||
},
|
||||
fm: 0644,
|
||||
},
|
||||
fm: 0644,
|
||||
}, {
|
||||
// More information.
|
||||
h: &Header{
|
||||
Name: "info.txt",
|
||||
Mode: 0600 | c_ISREG,
|
||||
Size: 0,
|
||||
Uid: 1000,
|
||||
Gid: 1000,
|
||||
ModTime: time.Unix(1360602540, 0),
|
||||
Uname: "slartibartfast",
|
||||
Gname: "users",
|
||||
Typeflag: TypeReg,
|
||||
{
|
||||
h: &Header{
|
||||
Name: "info.txt",
|
||||
Mode: 0600 | c_ISREG,
|
||||
Size: 0,
|
||||
Uid: 1000,
|
||||
Gid: 1000,
|
||||
ModTime: time.Unix(1360602540, 0),
|
||||
Uname: "slartibartfast",
|
||||
Gname: "users",
|
||||
Typeflag: TypeReg,
|
||||
},
|
||||
fm: 0600,
|
||||
},
|
||||
fm: 0600,
|
||||
}}
|
||||
}
|
||||
|
||||
for i, v := range vectors {
|
||||
fi := v.h.FileInfo()
|
||||
for i, g := range golden {
|
||||
fi := g.h.FileInfo()
|
||||
h2, err := FileInfoHeader(fi, "")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
if strings.Contains(fi.Name(), "/") {
|
||||
t.Errorf("FileInfo of %q contains slash: %q", v.h.Name, fi.Name())
|
||||
t.Errorf("FileInfo of %q contains slash: %q", g.h.Name, fi.Name())
|
||||
}
|
||||
name := path.Base(v.h.Name)
|
||||
name := path.Base(g.h.Name)
|
||||
if fi.IsDir() {
|
||||
name += "/"
|
||||
}
|
||||
if got, want := h2.Name, name; got != want {
|
||||
t.Errorf("i=%d: Name: got %v, want %v", i, got, want)
|
||||
}
|
||||
if got, want := h2.Size, v.h.Size; got != want {
|
||||
if got, want := h2.Size, g.h.Size; got != want {
|
||||
t.Errorf("i=%d: Size: got %v, want %v", i, got, want)
|
||||
}
|
||||
if got, want := h2.Uid, v.h.Uid; got != want {
|
||||
if got, want := h2.Uid, g.h.Uid; got != want {
|
||||
t.Errorf("i=%d: Uid: got %d, want %d", i, got, want)
|
||||
}
|
||||
if got, want := h2.Gid, v.h.Gid; got != want {
|
||||
if got, want := h2.Gid, g.h.Gid; got != want {
|
||||
t.Errorf("i=%d: Gid: got %d, want %d", i, got, want)
|
||||
}
|
||||
if got, want := h2.Uname, v.h.Uname; got != want {
|
||||
if got, want := h2.Uname, g.h.Uname; got != want {
|
||||
t.Errorf("i=%d: Uname: got %q, want %q", i, got, want)
|
||||
}
|
||||
if got, want := h2.Gname, v.h.Gname; got != want {
|
||||
if got, want := h2.Gname, g.h.Gname; got != want {
|
||||
t.Errorf("i=%d: Gname: got %q, want %q", i, got, want)
|
||||
}
|
||||
if got, want := h2.Linkname, v.h.Linkname; got != want {
|
||||
if got, want := h2.Linkname, g.h.Linkname; got != want {
|
||||
t.Errorf("i=%d: Linkname: got %v, want %v", i, got, want)
|
||||
}
|
||||
if got, want := h2.Typeflag, v.h.Typeflag; got != want {
|
||||
t.Logf("%#v %#v", v.h, fi.Sys())
|
||||
if got, want := h2.Typeflag, g.h.Typeflag; got != want {
|
||||
t.Logf("%#v %#v", g.h, fi.Sys())
|
||||
t.Errorf("i=%d: Typeflag: got %q, want %q", i, got, want)
|
||||
}
|
||||
if got, want := h2.Mode, v.h.Mode; got != want {
|
||||
if got, want := h2.Mode, g.h.Mode; got != want {
|
||||
t.Errorf("i=%d: Mode: got %o, want %o", i, got, want)
|
||||
}
|
||||
if got, want := fi.Mode(), v.fm; got != want {
|
||||
if got, want := fi.Mode(), g.fm; got != want {
|
||||
t.Errorf("i=%d: fi.Mode: got %o, want %o", i, got, want)
|
||||
}
|
||||
if got, want := h2.AccessTime, v.h.AccessTime; got != want {
|
||||
if got, want := h2.AccessTime, g.h.AccessTime; got != want {
|
||||
t.Errorf("i=%d: AccessTime: got %v, want %v", i, got, want)
|
||||
}
|
||||
if got, want := h2.ChangeTime, v.h.ChangeTime; got != want {
|
||||
if got, want := h2.ChangeTime, g.h.ChangeTime; got != want {
|
||||
t.Errorf("i=%d: ChangeTime: got %v, want %v", i, got, want)
|
||||
}
|
||||
if got, want := h2.ModTime, v.h.ModTime; got != want {
|
||||
if got, want := h2.ModTime, g.h.ModTime; got != want {
|
||||
t.Errorf("i=%d: ModTime: got %v, want %v", i, got, want)
|
||||
}
|
||||
if sysh, ok := fi.Sys().(*Header); !ok || sysh != v.h {
|
||||
if sysh, ok := fi.Sys().(*Header); !ok || sysh != g.h {
|
||||
t.Errorf("i=%d: Sys didn't return original *Header", i)
|
||||
}
|
||||
}
|
||||
|
||||
BIN
src/archive/tar/testdata/gnu-incremental.tar
vendored
BIN
src/archive/tar/testdata/gnu-incremental.tar
vendored
Binary file not shown.
BIN
src/archive/tar/testdata/pax-bad-hdr-file.tar
vendored
BIN
src/archive/tar/testdata/pax-bad-hdr-file.tar
vendored
Binary file not shown.
BIN
src/archive/tar/testdata/pax-bad-mtime-file.tar
vendored
BIN
src/archive/tar/testdata/pax-bad-mtime-file.tar
vendored
Binary file not shown.
BIN
src/archive/tar/testdata/pax-pos-size-file.tar
vendored
BIN
src/archive/tar/testdata/pax-pos-size-file.tar
vendored
Binary file not shown.
BIN
src/archive/tar/testdata/ustar.issue12594.tar
vendored
BIN
src/archive/tar/testdata/ustar.issue12594.tar
vendored
Binary file not shown.
BIN
src/archive/tar/testdata/writer-big-long.tar
vendored
BIN
src/archive/tar/testdata/writer-big-long.tar
vendored
Binary file not shown.
@@ -42,6 +42,10 @@ type Writer struct {
|
||||
paxHdrBuff block // buffer to use in writeHeader when writing a PAX header
|
||||
}
|
||||
|
||||
type formatter struct {
|
||||
err error // Last error seen
|
||||
}
|
||||
|
||||
// NewWriter creates a new Writer writing to w.
|
||||
func NewWriter(w io.Writer) *Writer { return &Writer{w: w} }
|
||||
|
||||
@@ -67,6 +71,56 @@ func (tw *Writer) Flush() error {
|
||||
return tw.err
|
||||
}
|
||||
|
||||
// Write s into b, terminating it with a NUL if there is room.
|
||||
func (f *formatter) formatString(b []byte, s string) {
|
||||
if len(s) > len(b) {
|
||||
f.err = ErrFieldTooLong
|
||||
return
|
||||
}
|
||||
ascii := toASCII(s)
|
||||
copy(b, ascii)
|
||||
if len(ascii) < len(b) {
|
||||
b[len(ascii)] = 0
|
||||
}
|
||||
}
|
||||
|
||||
// Encode x as an octal ASCII string and write it into b with leading zeros.
|
||||
func (f *formatter) formatOctal(b []byte, x int64) {
|
||||
s := strconv.FormatInt(x, 8)
|
||||
// leading zeros, but leave room for a NUL.
|
||||
for len(s)+1 < len(b) {
|
||||
s = "0" + s
|
||||
}
|
||||
f.formatString(b, s)
|
||||
}
|
||||
|
||||
// fitsInBase256 reports whether x can be encoded into n bytes using base-256
|
||||
// encoding. Unlike octal encoding, base-256 encoding does not require that the
|
||||
// string ends with a NUL character. Thus, all n bytes are available for output.
|
||||
//
|
||||
// If operating in binary mode, this assumes strict GNU binary mode; which means
|
||||
// that the first byte can only be either 0x80 or 0xff. Thus, the first byte is
|
||||
// equivalent to the sign bit in two's complement form.
|
||||
func fitsInBase256(n int, x int64) bool {
|
||||
var binBits = uint(n-1) * 8
|
||||
return n >= 9 || (x >= -1<<binBits && x < 1<<binBits)
|
||||
}
|
||||
|
||||
// Write x into b, as binary (GNUtar/star extension).
|
||||
func (f *formatter) formatNumeric(b []byte, x int64) {
|
||||
if fitsInBase256(len(b), x) {
|
||||
for i := len(b) - 1; i >= 0; i-- {
|
||||
b[i] = byte(x)
|
||||
x >>= 8
|
||||
}
|
||||
b[0] |= 0x80 // Highest bit indicates binary format
|
||||
return
|
||||
}
|
||||
|
||||
f.formatOctal(b, 0) // Last resort, just write zero
|
||||
f.err = ErrFieldTooLong
|
||||
}
|
||||
|
||||
var (
|
||||
minTime = time.Unix(0, 0)
|
||||
// There is room for 11 octal digits (33 bits) of mtime.
|
||||
@@ -170,41 +224,9 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
|
||||
formatNumeric(ustar.DevMajor(), hdr.Devmajor, paxNone)
|
||||
formatNumeric(ustar.DevMinor(), hdr.Devminor, paxNone)
|
||||
|
||||
// TODO(dsnet): The logic surrounding the prefix field is broken when trying
|
||||
// to encode the header as GNU format. The challenge with the current logic
|
||||
// is that we are unsure what format we are using at any given moment until
|
||||
// we have processed *all* of the fields. The problem is that by the time
|
||||
// all fields have been processed, some work has already been done to handle
|
||||
// each field under the assumption that it is for one given format or
|
||||
// another. In some situations, this causes the Writer to be confused and
|
||||
// encode a prefix field when the format being used is GNU. Thus, producing
|
||||
// an invalid tar file.
|
||||
//
|
||||
// As a short-term fix, we disable the logic to use the prefix field, which
|
||||
// will force the badly generated GNU files to become encoded as being
|
||||
// the PAX format.
|
||||
//
|
||||
// As an alternative fix, we could hard-code preferPax to be true. However,
|
||||
// this is problematic for the following reasons:
|
||||
// * The preferPax functionality is not tested at all.
|
||||
// * This can result in headers that try to use both the GNU and PAX
|
||||
// features at the same time, which is also wrong.
|
||||
//
|
||||
// The proper fix for this is to use a two-pass method:
|
||||
// * The first pass simply determines what set of formats can possibly
|
||||
// encode the given header.
|
||||
// * The second pass actually encodes the header as that given format
|
||||
// without worrying about violating the format.
|
||||
//
|
||||
// See the following:
|
||||
// https://golang.org/issue/12594
|
||||
// https://golang.org/issue/17630
|
||||
// https://golang.org/issue/9683
|
||||
const usePrefix = false
|
||||
|
||||
// try to use a ustar header when only the name is too long
|
||||
_, paxPathUsed := paxHeaders[paxPath]
|
||||
if usePrefix && !tw.preferPax && len(paxHeaders) == 1 && paxPathUsed {
|
||||
if !tw.preferPax && len(paxHeaders) == 1 && paxPathUsed {
|
||||
prefix, suffix, ok := splitUSTARPath(hdr.Name)
|
||||
if ok {
|
||||
// Since we can encode in USTAR format, disable PAX header.
|
||||
@@ -295,7 +317,7 @@ func (tw *Writer) writePAXHeader(hdr *Header, paxHeaders map[string]string) erro
|
||||
var buf bytes.Buffer
|
||||
|
||||
// Keys are sorted before writing to body to allow deterministic output.
|
||||
keys := make([]string, 0, len(paxHeaders))
|
||||
var keys []string
|
||||
for k := range paxHeaders {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
@@ -318,6 +340,22 @@ func (tw *Writer) writePAXHeader(hdr *Header, paxHeaders map[string]string) erro
|
||||
return nil
|
||||
}
|
||||
|
||||
// formatPAXRecord formats a single PAX record, prefixing it with the
|
||||
// appropriate length.
|
||||
func formatPAXRecord(k, v string) string {
|
||||
const padding = 3 // Extra padding for ' ', '=', and '\n'
|
||||
size := len(k) + len(v) + padding
|
||||
size += len(strconv.Itoa(size))
|
||||
record := fmt.Sprintf("%d %s=%s\n", size, k, v)
|
||||
|
||||
// Final adjustment if adding size field increased the record size.
|
||||
if len(record) != size {
|
||||
size = len(record)
|
||||
record = fmt.Sprintf("%d %s=%s\n", size, k, v)
|
||||
}
|
||||
return record
|
||||
}
|
||||
|
||||
// Write writes to the current entry in the tar archive.
|
||||
// Write returns the error ErrWriteTooLong if more than
|
||||
// hdr.Size bytes are written after WriteHeader.
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"os"
|
||||
"reflect"
|
||||
"sort"
|
||||
@@ -18,6 +19,176 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type writerTestEntry struct {
|
||||
header *Header
|
||||
contents string
|
||||
}
|
||||
|
||||
type writerTest struct {
|
||||
file string // filename of expected output
|
||||
entries []*writerTestEntry
|
||||
}
|
||||
|
||||
var writerTests = []*writerTest{
|
||||
// The writer test file was produced with this command:
|
||||
// tar (GNU tar) 1.26
|
||||
// ln -s small.txt link.txt
|
||||
// tar -b 1 --format=ustar -c -f writer.tar small.txt small2.txt link.txt
|
||||
{
|
||||
file: "testdata/writer.tar",
|
||||
entries: []*writerTestEntry{
|
||||
{
|
||||
header: &Header{
|
||||
Name: "small.txt",
|
||||
Mode: 0640,
|
||||
Uid: 73025,
|
||||
Gid: 5000,
|
||||
Size: 5,
|
||||
ModTime: time.Unix(1246508266, 0),
|
||||
Typeflag: '0',
|
||||
Uname: "dsymonds",
|
||||
Gname: "eng",
|
||||
},
|
||||
contents: "Kilts",
|
||||
},
|
||||
{
|
||||
header: &Header{
|
||||
Name: "small2.txt",
|
||||
Mode: 0640,
|
||||
Uid: 73025,
|
||||
Gid: 5000,
|
||||
Size: 11,
|
||||
ModTime: time.Unix(1245217492, 0),
|
||||
Typeflag: '0',
|
||||
Uname: "dsymonds",
|
||||
Gname: "eng",
|
||||
},
|
||||
contents: "Google.com\n",
|
||||
},
|
||||
{
|
||||
header: &Header{
|
||||
Name: "link.txt",
|
||||
Mode: 0777,
|
||||
Uid: 1000,
|
||||
Gid: 1000,
|
||||
Size: 0,
|
||||
ModTime: time.Unix(1314603082, 0),
|
||||
Typeflag: '2',
|
||||
Linkname: "small.txt",
|
||||
Uname: "strings",
|
||||
Gname: "strings",
|
||||
},
|
||||
// no contents
|
||||
},
|
||||
},
|
||||
},
|
||||
// The truncated test file was produced using these commands:
|
||||
// dd if=/dev/zero bs=1048576 count=16384 > /tmp/16gig.txt
|
||||
// tar -b 1 -c -f- /tmp/16gig.txt | dd bs=512 count=8 > writer-big.tar
|
||||
{
|
||||
file: "testdata/writer-big.tar",
|
||||
entries: []*writerTestEntry{
|
||||
{
|
||||
header: &Header{
|
||||
Name: "tmp/16gig.txt",
|
||||
Mode: 0640,
|
||||
Uid: 73025,
|
||||
Gid: 5000,
|
||||
Size: 16 << 30,
|
||||
ModTime: time.Unix(1254699560, 0),
|
||||
Typeflag: '0',
|
||||
Uname: "dsymonds",
|
||||
Gname: "eng",
|
||||
},
|
||||
// fake contents
|
||||
contents: strings.Repeat("\x00", 4<<10),
|
||||
},
|
||||
},
|
||||
},
|
||||
// The truncated test file was produced using these commands:
|
||||
// dd if=/dev/zero bs=1048576 count=16384 > (longname/)*15 /16gig.txt
|
||||
// tar -b 1 -c -f- (longname/)*15 /16gig.txt | dd bs=512 count=8 > writer-big-long.tar
|
||||
{
|
||||
file: "testdata/writer-big-long.tar",
|
||||
entries: []*writerTestEntry{
|
||||
{
|
||||
header: &Header{
|
||||
Name: strings.Repeat("longname/", 15) + "16gig.txt",
|
||||
Mode: 0644,
|
||||
Uid: 1000,
|
||||
Gid: 1000,
|
||||
Size: 16 << 30,
|
||||
ModTime: time.Unix(1399583047, 0),
|
||||
Typeflag: '0',
|
||||
Uname: "guillaume",
|
||||
Gname: "guillaume",
|
||||
},
|
||||
// fake contents
|
||||
contents: strings.Repeat("\x00", 4<<10),
|
||||
},
|
||||
},
|
||||
},
|
||||
// This file was produced using gnu tar 1.17
|
||||
// gnutar -b 4 --format=ustar (longname/)*15 + file.txt
|
||||
{
|
||||
file: "testdata/ustar.tar",
|
||||
entries: []*writerTestEntry{
|
||||
{
|
||||
header: &Header{
|
||||
Name: strings.Repeat("longname/", 15) + "file.txt",
|
||||
Mode: 0644,
|
||||
Uid: 0765,
|
||||
Gid: 024,
|
||||
Size: 06,
|
||||
ModTime: time.Unix(1360135598, 0),
|
||||
Typeflag: '0',
|
||||
Uname: "shane",
|
||||
Gname: "staff",
|
||||
},
|
||||
contents: "hello\n",
|
||||
},
|
||||
},
|
||||
},
|
||||
// This file was produced using gnu tar 1.26
|
||||
// echo "Slartibartfast" > file.txt
|
||||
// ln file.txt hard.txt
|
||||
// tar -b 1 --format=ustar -c -f hardlink.tar file.txt hard.txt
|
||||
{
|
||||
file: "testdata/hardlink.tar",
|
||||
entries: []*writerTestEntry{
|
||||
{
|
||||
header: &Header{
|
||||
Name: "file.txt",
|
||||
Mode: 0644,
|
||||
Uid: 1000,
|
||||
Gid: 100,
|
||||
Size: 15,
|
||||
ModTime: time.Unix(1425484303, 0),
|
||||
Typeflag: '0',
|
||||
Uname: "vbatts",
|
||||
Gname: "users",
|
||||
},
|
||||
contents: "Slartibartfast\n",
|
||||
},
|
||||
{
|
||||
header: &Header{
|
||||
Name: "hard.txt",
|
||||
Mode: 0644,
|
||||
Uid: 1000,
|
||||
Gid: 100,
|
||||
Size: 0,
|
||||
ModTime: time.Unix(1425484303, 0),
|
||||
Typeflag: '1',
|
||||
Linkname: "file.txt",
|
||||
Uname: "vbatts",
|
||||
Gname: "users",
|
||||
},
|
||||
// no contents
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Render byte array in a two-character hexadecimal string, spaced for easy visual inspection.
|
||||
func bytestr(offset int, b []byte) string {
|
||||
const rowLen = 32
|
||||
@@ -57,168 +228,9 @@ func bytediff(a []byte, b []byte) string {
|
||||
}
|
||||
|
||||
func TestWriter(t *testing.T) {
|
||||
type entry struct {
|
||||
header *Header
|
||||
contents string
|
||||
}
|
||||
|
||||
vectors := []struct {
|
||||
file string // filename of expected output
|
||||
entries []*entry
|
||||
}{{
|
||||
// The writer test file was produced with this command:
|
||||
// tar (GNU tar) 1.26
|
||||
// ln -s small.txt link.txt
|
||||
// tar -b 1 --format=ustar -c -f writer.tar small.txt small2.txt link.txt
|
||||
file: "testdata/writer.tar",
|
||||
entries: []*entry{{
|
||||
header: &Header{
|
||||
Name: "small.txt",
|
||||
Mode: 0640,
|
||||
Uid: 73025,
|
||||
Gid: 5000,
|
||||
Size: 5,
|
||||
ModTime: time.Unix(1246508266, 0),
|
||||
Typeflag: '0',
|
||||
Uname: "dsymonds",
|
||||
Gname: "eng",
|
||||
},
|
||||
contents: "Kilts",
|
||||
}, {
|
||||
header: &Header{
|
||||
Name: "small2.txt",
|
||||
Mode: 0640,
|
||||
Uid: 73025,
|
||||
Gid: 5000,
|
||||
Size: 11,
|
||||
ModTime: time.Unix(1245217492, 0),
|
||||
Typeflag: '0',
|
||||
Uname: "dsymonds",
|
||||
Gname: "eng",
|
||||
},
|
||||
contents: "Google.com\n",
|
||||
}, {
|
||||
header: &Header{
|
||||
Name: "link.txt",
|
||||
Mode: 0777,
|
||||
Uid: 1000,
|
||||
Gid: 1000,
|
||||
Size: 0,
|
||||
ModTime: time.Unix(1314603082, 0),
|
||||
Typeflag: '2',
|
||||
Linkname: "small.txt",
|
||||
Uname: "strings",
|
||||
Gname: "strings",
|
||||
},
|
||||
// no contents
|
||||
}},
|
||||
}, {
|
||||
// The truncated test file was produced using these commands:
|
||||
// dd if=/dev/zero bs=1048576 count=16384 > /tmp/16gig.txt
|
||||
// tar -b 1 -c -f- /tmp/16gig.txt | dd bs=512 count=8 > writer-big.tar
|
||||
file: "testdata/writer-big.tar",
|
||||
entries: []*entry{{
|
||||
header: &Header{
|
||||
Name: "tmp/16gig.txt",
|
||||
Mode: 0640,
|
||||
Uid: 73025,
|
||||
Gid: 5000,
|
||||
Size: 16 << 30,
|
||||
ModTime: time.Unix(1254699560, 0),
|
||||
Typeflag: '0',
|
||||
Uname: "dsymonds",
|
||||
Gname: "eng",
|
||||
},
|
||||
// fake contents
|
||||
contents: strings.Repeat("\x00", 4<<10),
|
||||
}},
|
||||
}, {
|
||||
// This truncated file was produced using this library.
|
||||
// It was verified to work with GNU tar 1.27.1 and BSD tar 3.1.2.
|
||||
// dd if=/dev/zero bs=1G count=16 >> writer-big-long.tar
|
||||
// gnutar -xvf writer-big-long.tar
|
||||
// bsdtar -xvf writer-big-long.tar
|
||||
//
|
||||
// This file is in PAX format.
|
||||
file: "testdata/writer-big-long.tar",
|
||||
entries: []*entry{{
|
||||
header: &Header{
|
||||
Name: strings.Repeat("longname/", 15) + "16gig.txt",
|
||||
Mode: 0644,
|
||||
Uid: 1000,
|
||||
Gid: 1000,
|
||||
Size: 16 << 30,
|
||||
ModTime: time.Unix(1399583047, 0),
|
||||
Typeflag: '0',
|
||||
Uname: "guillaume",
|
||||
Gname: "guillaume",
|
||||
},
|
||||
// fake contents
|
||||
contents: strings.Repeat("\x00", 4<<10),
|
||||
}},
|
||||
}, {
|
||||
// TODO(dsnet): The Writer output should match the following file.
|
||||
// To fix an issue (see https://golang.org/issue/12594), we disabled
|
||||
// prefix support, which alters the generated output.
|
||||
/*
|
||||
// This file was produced using gnu tar 1.17
|
||||
// gnutar -b 4 --format=ustar (longname/)*15 + file.txt
|
||||
file: "testdata/ustar.tar"
|
||||
*/
|
||||
file: "testdata/ustar.issue12594.tar", // This is a valid tar file, but not expected
|
||||
entries: []*entry{{
|
||||
header: &Header{
|
||||
Name: strings.Repeat("longname/", 15) + "file.txt",
|
||||
Mode: 0644,
|
||||
Uid: 0765,
|
||||
Gid: 024,
|
||||
Size: 06,
|
||||
ModTime: time.Unix(1360135598, 0),
|
||||
Typeflag: '0',
|
||||
Uname: "shane",
|
||||
Gname: "staff",
|
||||
},
|
||||
contents: "hello\n",
|
||||
}},
|
||||
}, {
|
||||
// This file was produced using gnu tar 1.26
|
||||
// echo "Slartibartfast" > file.txt
|
||||
// ln file.txt hard.txt
|
||||
// tar -b 1 --format=ustar -c -f hardlink.tar file.txt hard.txt
|
||||
file: "testdata/hardlink.tar",
|
||||
entries: []*entry{{
|
||||
header: &Header{
|
||||
Name: "file.txt",
|
||||
Mode: 0644,
|
||||
Uid: 1000,
|
||||
Gid: 100,
|
||||
Size: 15,
|
||||
ModTime: time.Unix(1425484303, 0),
|
||||
Typeflag: '0',
|
||||
Uname: "vbatts",
|
||||
Gname: "users",
|
||||
},
|
||||
contents: "Slartibartfast\n",
|
||||
}, {
|
||||
header: &Header{
|
||||
Name: "hard.txt",
|
||||
Mode: 0644,
|
||||
Uid: 1000,
|
||||
Gid: 100,
|
||||
Size: 0,
|
||||
ModTime: time.Unix(1425484303, 0),
|
||||
Typeflag: '1',
|
||||
Linkname: "file.txt",
|
||||
Uname: "vbatts",
|
||||
Gname: "users",
|
||||
},
|
||||
// no contents
|
||||
}},
|
||||
}}
|
||||
|
||||
testLoop:
|
||||
for i, v := range vectors {
|
||||
expected, err := ioutil.ReadFile(v.file)
|
||||
for i, test := range writerTests {
|
||||
expected, err := ioutil.ReadFile(test.file)
|
||||
if err != nil {
|
||||
t.Errorf("test %d: Unexpected error: %v", i, err)
|
||||
continue
|
||||
@@ -227,7 +239,7 @@ testLoop:
|
||||
buf := new(bytes.Buffer)
|
||||
tw := NewWriter(iotest.TruncateWriter(buf, 4<<10)) // only catch the first 4 KB
|
||||
big := false
|
||||
for j, entry := range v.entries {
|
||||
for j, entry := range test.entries {
|
||||
big = big || entry.header.Size > 1<<10
|
||||
if err := tw.WriteHeader(entry.header); err != nil {
|
||||
t.Errorf("test %d, entry %d: Failed writing header: %v", i, j, err)
|
||||
@@ -564,9 +576,9 @@ func TestWriteAfterClose(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSplitUSTARPath(t *testing.T) {
|
||||
sr := strings.Repeat
|
||||
var sr = strings.Repeat
|
||||
|
||||
vectors := []struct {
|
||||
var vectors = []struct {
|
||||
input string // Input path
|
||||
prefix string // Expected output prefix
|
||||
suffix string // Expected output suffix
|
||||
@@ -597,51 +609,114 @@ func TestSplitUSTARPath(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestIssue12594 tests that the Writer does not attempt to populate the prefix
|
||||
// field when encoding a header in the GNU format. The prefix field is valid
|
||||
// in USTAR and PAX, but not GNU.
|
||||
func TestIssue12594(t *testing.T) {
|
||||
names := []string{
|
||||
"0/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/file.txt",
|
||||
"0/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/31/32/33/file.txt",
|
||||
"0/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/31/32/333/file.txt",
|
||||
"0/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/31/32/33/34/35/36/37/38/39/40/file.txt",
|
||||
"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000/file.txt",
|
||||
"/home/support/.openoffice.org/3/user/uno_packages/cache/registry/com.sun.star.comp.deployment.executable.PackageRegistryBackend",
|
||||
func TestFormatPAXRecord(t *testing.T) {
|
||||
var medName = strings.Repeat("CD", 50)
|
||||
var longName = strings.Repeat("AB", 100)
|
||||
|
||||
var vectors = []struct {
|
||||
inputKey string
|
||||
inputVal string
|
||||
output string
|
||||
}{
|
||||
{"k", "v", "6 k=v\n"},
|
||||
{"path", "/etc/hosts", "19 path=/etc/hosts\n"},
|
||||
{"path", longName, "210 path=" + longName + "\n"},
|
||||
{"path", medName, "110 path=" + medName + "\n"},
|
||||
{"foo", "ba", "9 foo=ba\n"},
|
||||
{"foo", "bar", "11 foo=bar\n"},
|
||||
{"foo", "b=\nar=\n==\x00", "18 foo=b=\nar=\n==\x00\n"},
|
||||
{"foo", "hello9 foo=ba\nworld", "27 foo=hello9 foo=ba\nworld\n"},
|
||||
{"☺☻☹", "日a本b語ç", "27 ☺☻☹=日a本b語ç\n"},
|
||||
{"\x00hello", "\x00world", "17 \x00hello=\x00world\n"},
|
||||
}
|
||||
|
||||
for i, name := range names {
|
||||
var b bytes.Buffer
|
||||
|
||||
tw := NewWriter(&b)
|
||||
if err := tw.WriteHeader(&Header{
|
||||
Name: name,
|
||||
Uid: 1 << 25, // Prevent USTAR format
|
||||
}); err != nil {
|
||||
t.Errorf("test %d, unexpected WriteHeader error: %v", i, err)
|
||||
}
|
||||
if err := tw.Close(); err != nil {
|
||||
t.Errorf("test %d, unexpected Close error: %v", i, err)
|
||||
}
|
||||
|
||||
// The prefix field should never appear in the GNU format.
|
||||
var blk block
|
||||
copy(blk[:], b.Bytes())
|
||||
prefix := string(blk.USTAR().Prefix())
|
||||
if i := strings.IndexByte(prefix, 0); i >= 0 {
|
||||
prefix = prefix[:i] // Truncate at the NUL terminator
|
||||
}
|
||||
if blk.GetFormat() == formatGNU && len(prefix) > 0 && strings.HasPrefix(name, prefix) {
|
||||
t.Errorf("test %d, found prefix in GNU format: %s", i, prefix)
|
||||
}
|
||||
|
||||
tr := NewReader(&b)
|
||||
hdr, err := tr.Next()
|
||||
if err != nil {
|
||||
t.Errorf("test %d, unexpected Next error: %v", i, err)
|
||||
}
|
||||
if hdr.Name != name {
|
||||
t.Errorf("test %d, hdr.Name = %s, want %s", i, hdr.Name, name)
|
||||
for _, v := range vectors {
|
||||
output := formatPAXRecord(v.inputKey, v.inputVal)
|
||||
if output != v.output {
|
||||
t.Errorf("formatPAXRecord(%q, %q): got %q, want %q",
|
||||
v.inputKey, v.inputVal, output, v.output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFitsInBase256(t *testing.T) {
|
||||
var vectors = []struct {
|
||||
input int64
|
||||
width int
|
||||
ok bool
|
||||
}{
|
||||
{+1, 8, true},
|
||||
{0, 8, true},
|
||||
{-1, 8, true},
|
||||
{1 << 56, 8, false},
|
||||
{(1 << 56) - 1, 8, true},
|
||||
{-1 << 56, 8, true},
|
||||
{(-1 << 56) - 1, 8, false},
|
||||
{121654, 8, true},
|
||||
{-9849849, 8, true},
|
||||
{math.MaxInt64, 9, true},
|
||||
{0, 9, true},
|
||||
{math.MinInt64, 9, true},
|
||||
{math.MaxInt64, 12, true},
|
||||
{0, 12, true},
|
||||
{math.MinInt64, 12, true},
|
||||
}
|
||||
|
||||
for _, v := range vectors {
|
||||
ok := fitsInBase256(v.width, v.input)
|
||||
if ok != v.ok {
|
||||
t.Errorf("checkNumeric(%d, %d): got %v, want %v", v.input, v.width, ok, v.ok)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatNumeric(t *testing.T) {
|
||||
var vectors = []struct {
|
||||
input int64
|
||||
output string
|
||||
ok bool
|
||||
}{
|
||||
// Test base-256 (binary) encoded values.
|
||||
{-1, "\xff", true},
|
||||
{-1, "\xff\xff", true},
|
||||
{-1, "\xff\xff\xff", true},
|
||||
{(1 << 0), "0", false},
|
||||
{(1 << 8) - 1, "\x80\xff", true},
|
||||
{(1 << 8), "0\x00", false},
|
||||
{(1 << 16) - 1, "\x80\xff\xff", true},
|
||||
{(1 << 16), "00\x00", false},
|
||||
{-1 * (1 << 0), "\xff", true},
|
||||
{-1*(1<<0) - 1, "0", false},
|
||||
{-1 * (1 << 8), "\xff\x00", true},
|
||||
{-1*(1<<8) - 1, "0\x00", false},
|
||||
{-1 * (1 << 16), "\xff\x00\x00", true},
|
||||
{-1*(1<<16) - 1, "00\x00", false},
|
||||
{537795476381659745, "0000000\x00", false},
|
||||
{537795476381659745, "\x80\x00\x00\x00\x07\x76\xa2\x22\xeb\x8a\x72\x61", true},
|
||||
{-615126028225187231, "0000000\x00", false},
|
||||
{-615126028225187231, "\xff\xff\xff\xff\xf7\x76\xa2\x22\xeb\x8a\x72\x61", true},
|
||||
{math.MaxInt64, "0000000\x00", false},
|
||||
{math.MaxInt64, "\x80\x00\x00\x00\x7f\xff\xff\xff\xff\xff\xff\xff", true},
|
||||
{math.MinInt64, "0000000\x00", false},
|
||||
{math.MinInt64, "\xff\xff\xff\xff\x80\x00\x00\x00\x00\x00\x00\x00", true},
|
||||
{math.MaxInt64, "\x80\x7f\xff\xff\xff\xff\xff\xff\xff", true},
|
||||
{math.MinInt64, "\xff\x80\x00\x00\x00\x00\x00\x00\x00", true},
|
||||
}
|
||||
|
||||
for _, v := range vectors {
|
||||
var f formatter
|
||||
output := make([]byte, len(v.output))
|
||||
f.formatNumeric(output, v.input)
|
||||
ok := (f.err == nil)
|
||||
if ok != v.ok {
|
||||
if v.ok {
|
||||
t.Errorf("formatNumeric(%d): got formatting failure, want success", v.input)
|
||||
} else {
|
||||
t.Errorf("formatNumeric(%d): got formatting success, want failure", v.input)
|
||||
}
|
||||
}
|
||||
if string(output) != v.output {
|
||||
t.Errorf("formatNumeric(%d): got %q, want %q", v.input, output, v.output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,10 +22,6 @@ type Writer struct {
|
||||
last *fileWriter
|
||||
closed bool
|
||||
compressors map[uint16]Compressor
|
||||
|
||||
// testHookCloseSizeOffset if non-nil is called with the size
|
||||
// of offset of the central directory at Close.
|
||||
testHookCloseSizeOffset func(size, offset uint64)
|
||||
}
|
||||
|
||||
type header struct {
|
||||
@@ -102,7 +98,6 @@ func (w *Writer) Close() error {
|
||||
b.uint32(h.CompressedSize)
|
||||
b.uint32(h.UncompressedSize)
|
||||
}
|
||||
|
||||
b.uint16(uint16(len(h.Name)))
|
||||
b.uint16(uint16(len(h.Extra)))
|
||||
b.uint16(uint16(len(h.Comment)))
|
||||
@@ -132,11 +127,7 @@ func (w *Writer) Close() error {
|
||||
size := uint64(end - start)
|
||||
offset := uint64(start)
|
||||
|
||||
if f := w.testHookCloseSizeOffset; f != nil {
|
||||
f(size, offset)
|
||||
}
|
||||
|
||||
if records >= uint16max || size >= uint32max || offset >= uint32max {
|
||||
if records > uint16max || size > uint32max || offset > uint32max {
|
||||
var buf [directory64EndLen + directory64LocLen]byte
|
||||
b := writeBuf(buf[:])
|
||||
|
||||
|
||||
@@ -8,10 +8,8 @@ package zip
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash"
|
||||
"internal/race"
|
||||
"internal/testenv"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
@@ -234,7 +232,6 @@ func TestZip64(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("slow test; skipping")
|
||||
}
|
||||
t.Parallel()
|
||||
const size = 1 << 32 // before the "END\n" part
|
||||
buf := testZip64(t, size)
|
||||
testZip64DirectoryRecordLength(buf, t)
|
||||
@@ -244,7 +241,6 @@ func TestZip64EdgeCase(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("slow test; skipping")
|
||||
}
|
||||
t.Parallel()
|
||||
// Test a zip file with uncompressed size 0xFFFFFFFF.
|
||||
// That's the magic marker for a 64-bit file, so even though
|
||||
// it fits in a 32-bit field we must use the 64-bit field.
|
||||
@@ -255,256 +251,6 @@ func TestZip64EdgeCase(t *testing.T) {
|
||||
testZip64DirectoryRecordLength(buf, t)
|
||||
}
|
||||
|
||||
// Tests that we generate a zip64 file if the the directory at offset
|
||||
// 0xFFFFFFFF, but not before.
|
||||
func TestZip64DirectoryOffset(t *testing.T) {
|
||||
if testing.Short() && race.Enabled {
|
||||
t.Skip("skipping in short mode")
|
||||
}
|
||||
t.Parallel()
|
||||
const filename = "huge.txt"
|
||||
gen := func(wantOff uint64) func(*Writer) {
|
||||
return func(w *Writer) {
|
||||
w.testHookCloseSizeOffset = func(size, off uint64) {
|
||||
if off != wantOff {
|
||||
t.Errorf("central directory offset = %d (%x); want %d", off, off, wantOff)
|
||||
}
|
||||
}
|
||||
f, err := w.CreateHeader(&FileHeader{
|
||||
Name: filename,
|
||||
Method: Store,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
f.(*fileWriter).crc32 = fakeHash32{}
|
||||
size := wantOff - fileHeaderLen - uint64(len(filename)) - dataDescriptorLen
|
||||
if _, err := io.CopyN(f, zeros{}, int64(size)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := w.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
t.Run("uint32max-2_NoZip64", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
if generatesZip64(t, gen(0xfffffffe)) {
|
||||
t.Error("unexpected zip64")
|
||||
}
|
||||
})
|
||||
t.Run("uint32max-1_Zip64", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !generatesZip64(t, gen(0xffffffff)) {
|
||||
t.Error("expected zip64")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// At 16k records, we need to generate a zip64 file.
|
||||
func TestZip64ManyRecords(t *testing.T) {
|
||||
if testing.Short() && race.Enabled {
|
||||
t.Skip("skipping in short mode")
|
||||
}
|
||||
t.Parallel()
|
||||
gen := func(numRec int) func(*Writer) {
|
||||
return func(w *Writer) {
|
||||
for i := 0; i < numRec; i++ {
|
||||
_, err := w.CreateHeader(&FileHeader{
|
||||
Name: "a.txt",
|
||||
Method: Store,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
if err := w.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
// 16k-1 records shouldn't make a zip64:
|
||||
t.Run("uint16max-1_NoZip64", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
if generatesZip64(t, gen(0xfffe)) {
|
||||
t.Error("unexpected zip64")
|
||||
}
|
||||
})
|
||||
// 16k records should make a zip64:
|
||||
t.Run("uint16max_Zip64", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !generatesZip64(t, gen(0xffff)) {
|
||||
t.Error("expected zip64")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// suffixSaver is an io.Writer & io.ReaderAt that remembers the last 0
|
||||
// to 'keep' bytes of data written to it. Call Suffix to get the
|
||||
// suffix bytes.
|
||||
type suffixSaver struct {
|
||||
keep int
|
||||
buf []byte
|
||||
start int
|
||||
size int64
|
||||
}
|
||||
|
||||
func (ss *suffixSaver) Size() int64 { return ss.size }
|
||||
|
||||
var errDiscardedBytes = errors.New("ReadAt of discarded bytes")
|
||||
|
||||
func (ss *suffixSaver) ReadAt(p []byte, off int64) (n int, err error) {
|
||||
back := ss.size - off
|
||||
if back > int64(ss.keep) {
|
||||
return 0, errDiscardedBytes
|
||||
}
|
||||
suf := ss.Suffix()
|
||||
n = copy(p, suf[len(suf)-int(back):])
|
||||
if n != len(p) {
|
||||
err = io.EOF
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (ss *suffixSaver) Suffix() []byte {
|
||||
if len(ss.buf) < ss.keep {
|
||||
return ss.buf
|
||||
}
|
||||
buf := make([]byte, ss.keep)
|
||||
n := copy(buf, ss.buf[ss.start:])
|
||||
copy(buf[n:], ss.buf[:])
|
||||
return buf
|
||||
}
|
||||
|
||||
func (ss *suffixSaver) Write(p []byte) (n int, err error) {
|
||||
n = len(p)
|
||||
ss.size += int64(len(p))
|
||||
if len(ss.buf) < ss.keep {
|
||||
space := ss.keep - len(ss.buf)
|
||||
add := len(p)
|
||||
if add > space {
|
||||
add = space
|
||||
}
|
||||
ss.buf = append(ss.buf, p[:add]...)
|
||||
p = p[add:]
|
||||
}
|
||||
for len(p) > 0 {
|
||||
n := copy(ss.buf[ss.start:], p)
|
||||
p = p[n:]
|
||||
ss.start += n
|
||||
if ss.start == ss.keep {
|
||||
ss.start = 0
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// generatesZip64 reports whether f wrote a zip64 file.
|
||||
// f is also responsible for closing w.
|
||||
func generatesZip64(t *testing.T, f func(w *Writer)) bool {
|
||||
ss := &suffixSaver{keep: 10 << 20}
|
||||
w := NewWriter(ss)
|
||||
f(w)
|
||||
return suffixIsZip64(t, ss)
|
||||
}
|
||||
|
||||
type sizedReaderAt interface {
|
||||
io.ReaderAt
|
||||
Size() int64
|
||||
}
|
||||
|
||||
func suffixIsZip64(t *testing.T, zip sizedReaderAt) bool {
|
||||
d := make([]byte, 1024)
|
||||
if _, err := zip.ReadAt(d, zip.Size()-int64(len(d))); err != nil {
|
||||
t.Fatalf("ReadAt: %v", err)
|
||||
}
|
||||
|
||||
sigOff := findSignatureInBlock(d)
|
||||
if sigOff == -1 {
|
||||
t.Errorf("failed to find signature in block")
|
||||
return false
|
||||
}
|
||||
|
||||
dirOff, err := findDirectory64End(zip, zip.Size()-int64(len(d))+int64(sigOff))
|
||||
if err != nil {
|
||||
t.Fatalf("findDirectory64End: %v", err)
|
||||
}
|
||||
if dirOff == -1 {
|
||||
return false
|
||||
}
|
||||
|
||||
d = make([]byte, directory64EndLen)
|
||||
if _, err := zip.ReadAt(d, dirOff); err != nil {
|
||||
t.Fatalf("ReadAt(off=%d): %v", dirOff, err)
|
||||
}
|
||||
|
||||
b := readBuf(d)
|
||||
if sig := b.uint32(); sig != directory64EndSignature {
|
||||
return false
|
||||
}
|
||||
|
||||
size := b.uint64()
|
||||
if size != directory64EndLen-12 {
|
||||
t.Errorf("expected length of %d, got %d", directory64EndLen-12, size)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Zip64 is required if the total size of the records is uint32max.
|
||||
func TestZip64LargeDirectory(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping in short mode")
|
||||
}
|
||||
t.Parallel()
|
||||
// gen returns a func that writes a zip with a wantLen bytes
|
||||
// of central directory.
|
||||
gen := func(wantLen int64) func(*Writer) {
|
||||
return func(w *Writer) {
|
||||
w.testHookCloseSizeOffset = func(size, off uint64) {
|
||||
if size != uint64(wantLen) {
|
||||
t.Errorf("Close central directory size = %d; want %d", size, wantLen)
|
||||
}
|
||||
}
|
||||
|
||||
uint16string := strings.Repeat(".", uint16max)
|
||||
remain := wantLen
|
||||
for remain > 0 {
|
||||
commentLen := int(uint16max) - directoryHeaderLen - 1
|
||||
thisRecLen := directoryHeaderLen + int(uint16max) + commentLen
|
||||
if int64(thisRecLen) > remain {
|
||||
remove := thisRecLen - int(remain)
|
||||
commentLen -= remove
|
||||
thisRecLen -= remove
|
||||
}
|
||||
remain -= int64(thisRecLen)
|
||||
f, err := w.CreateHeader(&FileHeader{
|
||||
Name: uint16string,
|
||||
Comment: uint16string[:commentLen],
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("CreateHeader: %v", err)
|
||||
}
|
||||
f.(*fileWriter).crc32 = fakeHash32{}
|
||||
}
|
||||
if err := w.Close(); err != nil {
|
||||
t.Fatalf("Close: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
t.Run("uint32max-1_NoZip64", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
if generatesZip64(t, gen(uint32max-1)) {
|
||||
t.Error("unexpected zip64")
|
||||
}
|
||||
})
|
||||
t.Run("uint32max_HasZip64", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !generatesZip64(t, gen(uint32max)) {
|
||||
t.Error("expected zip64")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func testZip64(t testing.TB, size int64) *rleBuffer {
|
||||
const chunkSize = 1024
|
||||
chunks := int(size / chunkSize)
|
||||
@@ -593,8 +339,30 @@ func testZip64(t testing.TB, size int64) *rleBuffer {
|
||||
|
||||
// Issue 9857
|
||||
func testZip64DirectoryRecordLength(buf *rleBuffer, t *testing.T) {
|
||||
if !suffixIsZip64(t, buf) {
|
||||
t.Fatal("not a zip64")
|
||||
d := make([]byte, 1024)
|
||||
if _, err := buf.ReadAt(d, buf.Size()-int64(len(d))); err != nil {
|
||||
t.Fatal("read:", err)
|
||||
}
|
||||
|
||||
sigOff := findSignatureInBlock(d)
|
||||
dirOff, err := findDirectory64End(buf, buf.Size()-int64(len(d))+int64(sigOff))
|
||||
if err != nil {
|
||||
t.Fatal("findDirectory64End:", err)
|
||||
}
|
||||
|
||||
d = make([]byte, directory64EndLen)
|
||||
if _, err := buf.ReadAt(d, dirOff); err != nil {
|
||||
t.Fatal("read:", err)
|
||||
}
|
||||
|
||||
b := readBuf(d)
|
||||
if sig := b.uint32(); sig != directory64EndSignature {
|
||||
t.Fatalf("Expected directory64EndSignature (%d), got %d", directory64EndSignature, sig)
|
||||
}
|
||||
|
||||
size := b.uint64()
|
||||
if size != directory64EndLen-12 {
|
||||
t.Fatalf("Expected length of %d, got %d", directory64EndLen-12, size)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -680,47 +448,3 @@ func BenchmarkZip64Test(b *testing.B) {
|
||||
testZip64(b, 1<<26)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSuffixSaver(t *testing.T) {
|
||||
const keep = 10
|
||||
ss := &suffixSaver{keep: keep}
|
||||
ss.Write([]byte("abc"))
|
||||
if got := string(ss.Suffix()); got != "abc" {
|
||||
t.Errorf("got = %q; want abc", got)
|
||||
}
|
||||
ss.Write([]byte("defghijklmno"))
|
||||
if got := string(ss.Suffix()); got != "fghijklmno" {
|
||||
t.Errorf("got = %q; want fghijklmno", got)
|
||||
}
|
||||
if got, want := ss.Size(), int64(len("abc")+len("defghijklmno")); got != want {
|
||||
t.Errorf("Size = %d; want %d", got, want)
|
||||
}
|
||||
buf := make([]byte, ss.Size())
|
||||
for off := int64(0); off < ss.Size(); off++ {
|
||||
for size := 1; size <= int(ss.Size()-off); size++ {
|
||||
readBuf := buf[:size]
|
||||
n, err := ss.ReadAt(readBuf, off)
|
||||
if off < ss.Size()-keep {
|
||||
if err != errDiscardedBytes {
|
||||
t.Errorf("off %d, size %d = %v, %v (%q); want errDiscardedBytes", off, size, n, err, readBuf[:n])
|
||||
}
|
||||
continue
|
||||
}
|
||||
want := "abcdefghijklmno"[off : off+int64(size)]
|
||||
got := string(readBuf[:n])
|
||||
if err != nil || got != want {
|
||||
t.Errorf("off %d, size %d = %v, %v (%q); want %q", off, size, n, err, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type zeros struct{}
|
||||
|
||||
func (zeros) Read(p []byte) (int, error) {
|
||||
for i := range p {
|
||||
p[i] = 0
|
||||
}
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
@@ -206,18 +206,10 @@ func (b *Reader) Read(p []byte) (n int, err error) {
|
||||
}
|
||||
return n, b.readErr()
|
||||
}
|
||||
// One read.
|
||||
// Do not use b.fill, which will loop.
|
||||
b.r = 0
|
||||
b.w = 0
|
||||
n, b.err = b.rd.Read(b.buf)
|
||||
if n < 0 {
|
||||
panic(errNegativeRead)
|
||||
}
|
||||
if n == 0 {
|
||||
b.fill() // buffer is empty
|
||||
if b.r == b.w {
|
||||
return 0, b.readErr()
|
||||
}
|
||||
b.w += n
|
||||
}
|
||||
|
||||
// copy as much as we can
|
||||
@@ -557,6 +549,11 @@ func (b *Writer) Reset(w io.Writer) {
|
||||
|
||||
// Flush writes any buffered data to the underlying io.Writer.
|
||||
func (b *Writer) Flush() error {
|
||||
err := b.flush()
|
||||
return err
|
||||
}
|
||||
|
||||
func (b *Writer) flush() error {
|
||||
if b.err != nil {
|
||||
return b.err
|
||||
}
|
||||
@@ -599,7 +596,7 @@ func (b *Writer) Write(p []byte) (nn int, err error) {
|
||||
} else {
|
||||
n = copy(b.buf[b.n:], p)
|
||||
b.n += n
|
||||
b.Flush()
|
||||
b.flush()
|
||||
}
|
||||
nn += n
|
||||
p = p[n:]
|
||||
@@ -618,7 +615,7 @@ func (b *Writer) WriteByte(c byte) error {
|
||||
if b.err != nil {
|
||||
return b.err
|
||||
}
|
||||
if b.Available() <= 0 && b.Flush() != nil {
|
||||
if b.Available() <= 0 && b.flush() != nil {
|
||||
return b.err
|
||||
}
|
||||
b.buf[b.n] = c
|
||||
@@ -641,7 +638,7 @@ func (b *Writer) WriteRune(r rune) (size int, err error) {
|
||||
}
|
||||
n := b.Available()
|
||||
if n < utf8.UTFMax {
|
||||
if b.Flush(); b.err != nil {
|
||||
if b.flush(); b.err != nil {
|
||||
return 0, b.err
|
||||
}
|
||||
n = b.Available()
|
||||
@@ -666,7 +663,7 @@ func (b *Writer) WriteString(s string) (int, error) {
|
||||
b.n += n
|
||||
nn += n
|
||||
s = s[n:]
|
||||
b.Flush()
|
||||
b.flush()
|
||||
}
|
||||
if b.err != nil {
|
||||
return nn, b.err
|
||||
@@ -687,7 +684,7 @@ func (b *Writer) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
var m int
|
||||
for {
|
||||
if b.Available() == 0 {
|
||||
if err1 := b.Flush(); err1 != nil {
|
||||
if err1 := b.flush(); err1 != nil {
|
||||
return n, err1
|
||||
}
|
||||
}
|
||||
@@ -711,7 +708,7 @@ func (b *Writer) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
if err == io.EOF {
|
||||
// If we filled the buffer exactly, flush preemptively.
|
||||
if b.Available() == 0 {
|
||||
err = b.Flush()
|
||||
err = b.flush()
|
||||
} else {
|
||||
err = nil
|
||||
}
|
||||
|
||||
@@ -1236,27 +1236,6 @@ func TestWriterReadFromErrNoProgress(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadZero(t *testing.T) {
|
||||
for _, size := range []int{100, 2} {
|
||||
t.Run(fmt.Sprintf("bufsize=%d", size), func(t *testing.T) {
|
||||
r := io.MultiReader(strings.NewReader("abc"), &emptyThenNonEmptyReader{r: strings.NewReader("def"), n: 1})
|
||||
br := NewReaderSize(r, size)
|
||||
want := func(s string, wantErr error) {
|
||||
p := make([]byte, 50)
|
||||
n, err := br.Read(p)
|
||||
if err != wantErr || n != len(s) || string(p[:n]) != s {
|
||||
t.Fatalf("read(%d) = %q, %v, want %q, %v", len(p), string(p[:n]), err, s, wantErr)
|
||||
}
|
||||
t.Logf("read(%d) = %q, %v", len(p), string(p[:n]), err)
|
||||
}
|
||||
want("abc", nil)
|
||||
want("", nil)
|
||||
want("def", nil)
|
||||
want("", io.EOF)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestReaderReset(t *testing.T) {
|
||||
r := NewReader(strings.NewReader("foo foo"))
|
||||
buf := make([]byte, 3)
|
||||
|
||||
@@ -199,6 +199,7 @@ func (s *Scanner) Scan() bool {
|
||||
s.buf = newBuf
|
||||
s.end -= s.start
|
||||
s.start = 0
|
||||
continue
|
||||
}
|
||||
// Finally we can read some input. Make sure we don't get stuck with
|
||||
// a misbehaving Reader. Officially we don't need to do this, but let's
|
||||
|
||||
@@ -173,8 +173,8 @@ func cap(v Type) int
|
||||
// specify a different capacity; it must be no smaller than the
|
||||
// length, so make([]int, 0, 10) allocates a slice of length 0 and
|
||||
// capacity 10.
|
||||
// Map: An empty map is allocated with enough space to hold the
|
||||
// specified number of elements. The size may be omitted, in which case
|
||||
// Map: An initial allocation is made according to the size but the
|
||||
// resulting map has length 0. The size may be omitted, in which case
|
||||
// a small starting size is allocated.
|
||||
// Channel: The channel's buffer is initialized with the specified
|
||||
// buffer capacity. If zero, or the size is omitted, the channel is
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user