mirror of
https://github.com/golang/go
synced 2024-11-25 01:08:02 -07:00
use new time API
R=bradfitz, gri, r, dsymonds CC=golang-dev https://golang.org/cl/5390042
This commit is contained in:
parent
efe3d35fc5
commit
03823b881c
@ -24,9 +24,9 @@ const (
|
|||||||
codeProject = "go"
|
codeProject = "go"
|
||||||
codePyScript = "misc/dashboard/googlecode_upload.py"
|
codePyScript = "misc/dashboard/googlecode_upload.py"
|
||||||
hgUrl = "https://go.googlecode.com/hg/"
|
hgUrl = "https://go.googlecode.com/hg/"
|
||||||
waitInterval = 30e9 // time to wait before checking for new revs
|
|
||||||
mkdirPerm = 0750
|
mkdirPerm = 0750
|
||||||
pkgBuildInterval = 1e9 * 60 * 60 * 24 // rebuild packages every 24 hours
|
waitInterval = 30 * time.Second // time to wait before checking for new revs
|
||||||
|
pkgBuildInterval = 24 * time.Hour // rebuild packages every 24 hours
|
||||||
)
|
)
|
||||||
|
|
||||||
// These variables are copied from the gobuilder's environment
|
// These variables are copied from the gobuilder's environment
|
||||||
@ -131,7 +131,7 @@ func main() {
|
|||||||
// check for new commits and build them
|
// check for new commits and build them
|
||||||
for {
|
for {
|
||||||
built := false
|
built := false
|
||||||
t := time.Nanoseconds()
|
t := time.Now()
|
||||||
if *parallel {
|
if *parallel {
|
||||||
done := make(chan bool)
|
done := make(chan bool)
|
||||||
for _, b := range builders {
|
for _, b := range builders {
|
||||||
@ -152,9 +152,9 @@ func main() {
|
|||||||
time.Sleep(waitInterval)
|
time.Sleep(waitInterval)
|
||||||
}
|
}
|
||||||
// sleep if we're looping too fast.
|
// sleep if we're looping too fast.
|
||||||
t1 := time.Nanoseconds() - t
|
dt := time.Now().Sub(t)
|
||||||
if t1 < waitInterval {
|
if dt < waitInterval {
|
||||||
time.Sleep(waitInterval - t1)
|
time.Sleep(waitInterval - dt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -194,7 +194,7 @@ func NewBuilder(builder string) (*Builder, error) {
|
|||||||
// a new release tag is found.
|
// a new release tag is found.
|
||||||
func (b *Builder) buildExternal() {
|
func (b *Builder) buildExternal() {
|
||||||
var prevTag string
|
var prevTag string
|
||||||
var nextBuild int64
|
var nextBuild time.Time
|
||||||
for {
|
for {
|
||||||
time.Sleep(waitInterval)
|
time.Sleep(waitInterval)
|
||||||
err := run(nil, goroot, "hg", "pull", "-u")
|
err := run(nil, goroot, "hg", "pull", "-u")
|
||||||
@ -213,7 +213,7 @@ func (b *Builder) buildExternal() {
|
|||||||
// don't rebuild if there's no new release
|
// don't rebuild if there's no new release
|
||||||
// and it's been less than pkgBuildInterval
|
// and it's been less than pkgBuildInterval
|
||||||
// nanoseconds since the last build.
|
// nanoseconds since the last build.
|
||||||
if tag == prevTag && time.Nanoseconds() < nextBuild {
|
if tag == prevTag && time.Now().Before(nextBuild) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// build will also build the packages
|
// build will also build the packages
|
||||||
@ -222,7 +222,7 @@ func (b *Builder) buildExternal() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
prevTag = tag
|
prevTag = tag
|
||||||
nextBuild = time.Nanoseconds() + pkgBuildInterval
|
nextBuild = time.Now().Add(pkgBuildInterval)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,13 +13,14 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// The FileInfo interface provides access to file information.
|
// The FileInfo interface provides access to file information.
|
||||||
type FileInfo interface {
|
type FileInfo interface {
|
||||||
Name() string
|
Name() string
|
||||||
Size() int64
|
Size() int64
|
||||||
Mtime_ns() int64
|
ModTime() time.Time
|
||||||
IsRegular() bool
|
IsRegular() bool
|
||||||
IsDirectory() bool
|
IsDirectory() bool
|
||||||
}
|
}
|
||||||
@ -64,8 +65,8 @@ func (fi osFI) Size() int64 {
|
|||||||
return fi.FileInfo.Size
|
return fi.FileInfo.Size
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fi osFI) Mtime_ns() int64 {
|
func (fi osFI) ModTime() time.Time {
|
||||||
return fi.FileInfo.Mtime_ns
|
return fi.FileInfo.ModTime
|
||||||
}
|
}
|
||||||
|
|
||||||
// osFS is the OS-specific implementation of FileSystem
|
// osFS is the OS-specific implementation of FileSystem
|
||||||
|
@ -35,9 +35,9 @@ type delayTime struct {
|
|||||||
RWValue
|
RWValue
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dt *delayTime) backoff(max int) {
|
func (dt *delayTime) backoff(max time.Duration) {
|
||||||
dt.mutex.Lock()
|
dt.mutex.Lock()
|
||||||
v := dt.value.(int) * 2
|
v := dt.value.(time.Duration) * 2
|
||||||
if v > max {
|
if v > max {
|
||||||
v = max
|
v = max
|
||||||
}
|
}
|
||||||
@ -207,7 +207,7 @@ func updateFilterFile() {
|
|||||||
// update filter file
|
// update filter file
|
||||||
if err := writeFileAtomically(*filter, buf.Bytes()); err != nil {
|
if err := writeFileAtomically(*filter, buf.Bytes()); err != nil {
|
||||||
log.Printf("writeFileAtomically(%s): %s", *filter, err)
|
log.Printf("writeFileAtomically(%s): %s", *filter, err)
|
||||||
filterDelay.backoff(24 * 60) // back off exponentially, but try at least once a day
|
filterDelay.backoff(24 * time.Hour) // back off exponentially, but try at least once a day
|
||||||
} else {
|
} else {
|
||||||
filterDelay.set(*filterMin) // revert to regular filter update schedule
|
filterDelay.set(*filterMin) // revert to regular filter update schedule
|
||||||
}
|
}
|
||||||
@ -230,7 +230,7 @@ func initDirTrees() {
|
|||||||
|
|
||||||
// start filter update goroutine, if enabled.
|
// start filter update goroutine, if enabled.
|
||||||
if *filter != "" && *filterMin > 0 {
|
if *filter != "" && *filterMin > 0 {
|
||||||
filterDelay.set(*filterMin) // initial filter update delay
|
filterDelay.set(time.Duration(*filterMin) * time.Minute) // initial filter update delay
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
if *verbose {
|
if *verbose {
|
||||||
@ -238,10 +238,11 @@ func initDirTrees() {
|
|||||||
}
|
}
|
||||||
updateFilterFile()
|
updateFilterFile()
|
||||||
delay, _ := filterDelay.get()
|
delay, _ := filterDelay.get()
|
||||||
|
dt := delay.(time.Duration)
|
||||||
if *verbose {
|
if *verbose {
|
||||||
log.Printf("next filter update in %dmin", delay.(int))
|
log.Printf("next filter update in %s", dt)
|
||||||
}
|
}
|
||||||
time.Sleep(int64(delay.(int)) * 60e9)
|
time.Sleep(dt)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
@ -389,8 +390,8 @@ func fileInfoNameFunc(fi FileInfo) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func fileInfoTimeFunc(fi FileInfo) string {
|
func fileInfoTimeFunc(fi FileInfo) string {
|
||||||
if t := fi.Mtime_ns(); t != 0 {
|
if t := fi.ModTime(); t.Unix() != 0 {
|
||||||
return time.SecondsToLocalTime(t / 1e9).String()
|
return t.Local().String()
|
||||||
}
|
}
|
||||||
return "" // don't return epoch if time is obviously not set
|
return "" // don't return epoch if time is obviously not set
|
||||||
}
|
}
|
||||||
@ -876,7 +877,7 @@ type PageInfo struct {
|
|||||||
PDoc *doc.PackageDoc // nil if no single package documentation
|
PDoc *doc.PackageDoc // nil if no single package documentation
|
||||||
Examples []*doc.Example // nil if no example code
|
Examples []*doc.Example // nil if no example code
|
||||||
Dirs *DirList // nil if no directory information
|
Dirs *DirList // nil if no directory information
|
||||||
DirTime int64 // directory time stamp in seconds since epoch
|
DirTime time.Time // directory time stamp
|
||||||
DirFlat bool // if set, show directory in a flat (non-indented) manner
|
DirFlat bool // if set, show directory in a flat (non-indented) manner
|
||||||
IsPkg bool // false if this is not documenting a real package
|
IsPkg bool // false if this is not documenting a real package
|
||||||
Err error // I/O error or nil
|
Err error // I/O error or nil
|
||||||
@ -906,7 +907,7 @@ func fsReadDir(dir string) ([]*os.FileInfo, error) {
|
|||||||
if f.IsDirectory() {
|
if f.IsDirectory() {
|
||||||
mode = S_IFDIR
|
mode = S_IFDIR
|
||||||
}
|
}
|
||||||
osfi[i] = &os.FileInfo{Name: f.Name(), Size: f.Size(), Mtime_ns: f.Mtime_ns(), Mode: mode}
|
osfi[i] = &os.FileInfo{Name: f.Name(), Size: f.Size(), ModTime: f.ModTime(), Mode: mode}
|
||||||
}
|
}
|
||||||
return osfi, nil
|
return osfi, nil
|
||||||
}
|
}
|
||||||
@ -1075,7 +1076,7 @@ func (h *httpHandler) getPageInfo(abspath, relpath, pkgname string, mode PageInf
|
|||||||
|
|
||||||
// get directory information
|
// get directory information
|
||||||
var dir *Directory
|
var dir *Directory
|
||||||
var timestamp int64
|
var timestamp time.Time
|
||||||
if tree, ts := fsTree.get(); tree != nil && tree.(*Directory) != nil {
|
if tree, ts := fsTree.get(); tree != nil && tree.(*Directory) != nil {
|
||||||
// directory tree is present; lookup respective directory
|
// directory tree is present; lookup respective directory
|
||||||
// (may still fail if the file system was updated and the
|
// (may still fail if the file system was updated and the
|
||||||
@ -1112,7 +1113,7 @@ func (h *httpHandler) getPageInfo(abspath, relpath, pkgname string, mode PageInf
|
|||||||
// note: cannot use path filter here because in general
|
// note: cannot use path filter here because in general
|
||||||
// it doesn't contain the fsTree path
|
// it doesn't contain the fsTree path
|
||||||
dir = newDirectory(abspath, nil, 1)
|
dir = newDirectory(abspath, nil, 1)
|
||||||
timestamp = time.Seconds()
|
timestamp = time.Now()
|
||||||
}
|
}
|
||||||
|
|
||||||
return PageInfo{
|
return PageInfo{
|
||||||
@ -1172,7 +1173,7 @@ func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
default:
|
default:
|
||||||
title = "Directory " + relativeURL(info.Dirname)
|
title = "Directory " + relativeURL(info.Dirname)
|
||||||
if *showTimestamps {
|
if *showTimestamps {
|
||||||
subtitle = "Last update: " + time.SecondsToLocalTime(info.DirTime).String()
|
subtitle = "Last update: " + info.DirTime.String()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1238,7 +1239,7 @@ func lookup(query string) (result SearchResult) {
|
|||||||
|
|
||||||
// is the result accurate?
|
// is the result accurate?
|
||||||
if *indexEnabled {
|
if *indexEnabled {
|
||||||
if _, ts := fsModified.get(); timestamp < ts {
|
if _, ts := fsModified.get(); timestamp.Before(ts) {
|
||||||
// The index is older than the latest file system change under godoc's observation.
|
// The index is older than the latest file system change under godoc's observation.
|
||||||
result.Alert = "Indexing in progress: result may be inaccurate"
|
result.Alert = "Indexing in progress: result may be inaccurate"
|
||||||
}
|
}
|
||||||
@ -1286,7 +1287,7 @@ func invalidateIndex() {
|
|||||||
func indexUpToDate() bool {
|
func indexUpToDate() bool {
|
||||||
_, fsTime := fsModified.get()
|
_, fsTime := fsModified.get()
|
||||||
_, siTime := searchIndex.get()
|
_, siTime := searchIndex.get()
|
||||||
return fsTime <= siTime
|
return !fsTime.After(siTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
// feedDirnames feeds the directory names of all directories
|
// feedDirnames feeds the directory names of all directories
|
||||||
@ -1343,12 +1344,12 @@ func updateIndex() {
|
|||||||
if *verbose {
|
if *verbose {
|
||||||
log.Printf("updating index...")
|
log.Printf("updating index...")
|
||||||
}
|
}
|
||||||
start := time.Nanoseconds()
|
start := time.Now()
|
||||||
index := NewIndex(fsDirnames(), *maxResults > 0, *indexThrottle)
|
index := NewIndex(fsDirnames(), *maxResults > 0, *indexThrottle)
|
||||||
stop := time.Nanoseconds()
|
stop := time.Now()
|
||||||
searchIndex.set(index)
|
searchIndex.set(index)
|
||||||
if *verbose {
|
if *verbose {
|
||||||
secs := float64((stop-start)/1e6) / 1e3
|
secs := stop.Sub(start).Seconds()
|
||||||
stats := index.Stats()
|
stats := index.Stats()
|
||||||
log.Printf("index updated (%gs, %d bytes of source, %d files, %d lines, %d unique words, %d spots)",
|
log.Printf("index updated (%gs, %d bytes of source, %d files, %d lines, %d unique words, %d spots)",
|
||||||
secs, stats.Bytes, stats.Files, stats.Lines, stats.Words, stats.Spots)
|
secs, stats.Bytes, stats.Files, stats.Lines, stats.Words, stats.Spots)
|
||||||
@ -1372,10 +1373,10 @@ func indexer() {
|
|||||||
// index possibly out of date - make a new one
|
// index possibly out of date - make a new one
|
||||||
updateIndex()
|
updateIndex()
|
||||||
}
|
}
|
||||||
var delay int64 = 60 * 1e9 // by default, try every 60s
|
delay := 60 * time.Second // by default, try every 60s
|
||||||
if *testDir != "" {
|
if *testDir != "" {
|
||||||
// in test mode, try once a second for fast startup
|
// in test mode, try once a second for fast startup
|
||||||
delay = 1 * 1e9
|
delay = 1 * time.Second
|
||||||
}
|
}
|
||||||
time.Sleep(delay)
|
time.Sleep(delay)
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// We cannot import syscall on app engine.
|
// We cannot import syscall on app engine.
|
||||||
@ -77,17 +78,18 @@ func (f *httpZipFile) Readdir(count int) ([]os.FileInfo, error) {
|
|||||||
}
|
}
|
||||||
name := e.Name[len(dirname):] // local name
|
name := e.Name[len(dirname):] // local name
|
||||||
var mode uint32
|
var mode uint32
|
||||||
var size, mtime_ns int64
|
var size int64
|
||||||
|
var mtime time.Time
|
||||||
if i := strings.IndexRune(name, '/'); i >= 0 {
|
if i := strings.IndexRune(name, '/'); i >= 0 {
|
||||||
// We infer directories from files in subdirectories.
|
// We infer directories from files in subdirectories.
|
||||||
// If we have x/y, return a directory entry for x.
|
// If we have x/y, return a directory entry for x.
|
||||||
name = name[0:i] // keep local directory name only
|
name = name[0:i] // keep local directory name only
|
||||||
mode = S_IFDIR
|
mode = S_IFDIR
|
||||||
// no size or mtime_ns for directories
|
// no size or mtime for directories
|
||||||
} else {
|
} else {
|
||||||
mode = S_IFREG
|
mode = S_IFREG
|
||||||
size = int64(e.UncompressedSize)
|
size = int64(e.UncompressedSize)
|
||||||
mtime_ns = e.Mtime_ns()
|
mtime = e.ModTime()
|
||||||
}
|
}
|
||||||
// If we have x/y and x/z, don't return two directory entries for x.
|
// If we have x/y and x/z, don't return two directory entries for x.
|
||||||
// TODO(gri): It should be possible to do this more efficiently
|
// TODO(gri): It should be possible to do this more efficiently
|
||||||
@ -95,10 +97,10 @@ func (f *httpZipFile) Readdir(count int) ([]os.FileInfo, error) {
|
|||||||
// (via two binary searches).
|
// (via two binary searches).
|
||||||
if name != prevname {
|
if name != prevname {
|
||||||
list = append(list, os.FileInfo{
|
list = append(list, os.FileInfo{
|
||||||
Name: name,
|
Name: name,
|
||||||
Mode: mode,
|
Mode: mode,
|
||||||
Size: size,
|
Size: size,
|
||||||
Mtime_ns: mtime_ns,
|
ModTime: mtime,
|
||||||
})
|
})
|
||||||
prevname = name
|
prevname = name
|
||||||
count--
|
count--
|
||||||
@ -142,10 +144,10 @@ func (fs *httpZipFS) Open(name string) (http.File, error) {
|
|||||||
return &httpZipFile{
|
return &httpZipFile{
|
||||||
path,
|
path,
|
||||||
os.FileInfo{
|
os.FileInfo{
|
||||||
Name: name,
|
Name: name,
|
||||||
Mode: S_IFREG,
|
Mode: S_IFREG,
|
||||||
Size: int64(f.UncompressedSize),
|
Size: int64(f.UncompressedSize),
|
||||||
Mtime_ns: f.Mtime_ns(),
|
ModTime: f.ModTime(),
|
||||||
},
|
},
|
||||||
rc,
|
rc,
|
||||||
nil,
|
nil,
|
||||||
@ -158,7 +160,7 @@ func (fs *httpZipFS) Open(name string) (http.File, error) {
|
|||||||
os.FileInfo{
|
os.FileInfo{
|
||||||
Name: name,
|
Name: name,
|
||||||
Mode: S_IFDIR,
|
Mode: S_IFDIR,
|
||||||
// no size or mtime_ns for directories
|
// no size or mtime for directories
|
||||||
},
|
},
|
||||||
nil,
|
nil,
|
||||||
fs.list[index:],
|
fs.list[index:],
|
||||||
|
@ -141,10 +141,10 @@ func dosync(w http.ResponseWriter, r *http.Request) {
|
|||||||
case 1:
|
case 1:
|
||||||
// sync failed because no files changed;
|
// sync failed because no files changed;
|
||||||
// don't change the package tree
|
// don't change the package tree
|
||||||
syncDelay.set(*syncMin) // revert to regular sync schedule
|
syncDelay.set(time.Duration(*syncMin) * time.Minute) // revert to regular sync schedule
|
||||||
default:
|
default:
|
||||||
// sync failed because of an error - back off exponentially, but try at least once a day
|
// sync failed because of an error - back off exponentially, but try at least once a day
|
||||||
syncDelay.backoff(24 * 60)
|
syncDelay.backoff(24 * time.Hour)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -328,10 +328,11 @@ func main() {
|
|||||||
for {
|
for {
|
||||||
dosync(nil, nil)
|
dosync(nil, nil)
|
||||||
delay, _ := syncDelay.get()
|
delay, _ := syncDelay.get()
|
||||||
|
dt := delay.(time.Duration)
|
||||||
if *verbose {
|
if *verbose {
|
||||||
log.Printf("next sync in %dmin", delay.(int))
|
log.Printf("next sync in %s", dt)
|
||||||
}
|
}
|
||||||
time.Sleep(int64(delay.(int)) * 60e9)
|
time.Sleep(dt)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
@ -10,15 +10,15 @@ import "time"
|
|||||||
// calling the Throttle method repeatedly.
|
// calling the Throttle method repeatedly.
|
||||||
//
|
//
|
||||||
type Throttle struct {
|
type Throttle struct {
|
||||||
f float64 // f = (1-r)/r for 0 < r < 1
|
f float64 // f = (1-r)/r for 0 < r < 1
|
||||||
tm int64 // minimum run time slice; >= 0
|
dt time.Duration // minimum run time slice; >= 0
|
||||||
tr int64 // accumulated time running
|
tr time.Duration // accumulated time running
|
||||||
ts int64 // accumulated time stopped
|
ts time.Duration // accumulated time stopped
|
||||||
tt int64 // earliest throttle time (= time Throttle returned + tm)
|
tt time.Time // earliest throttle time (= time Throttle returned + tm)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewThrottle creates a new Throttle with a throttle value r and
|
// NewThrottle creates a new Throttle with a throttle value r and
|
||||||
// a minimum allocated run time slice of tm nanoseconds:
|
// a minimum allocated run time slice of dt:
|
||||||
//
|
//
|
||||||
// r == 0: "empty" throttle; the goroutine is always sleeping
|
// r == 0: "empty" throttle; the goroutine is always sleeping
|
||||||
// r == 1: full throttle; the goroutine is never sleeping
|
// r == 1: full throttle; the goroutine is never sleeping
|
||||||
@ -26,9 +26,9 @@ type Throttle struct {
|
|||||||
// A value of r == 0.6 throttles a goroutine such that it runs
|
// A value of r == 0.6 throttles a goroutine such that it runs
|
||||||
// approx. 60% of the time, and sleeps approx. 40% of the time.
|
// approx. 60% of the time, and sleeps approx. 40% of the time.
|
||||||
// Values of r < 0 or r > 1 are clamped down to values between 0 and 1.
|
// Values of r < 0 or r > 1 are clamped down to values between 0 and 1.
|
||||||
// Values of tm < 0 are set to 0.
|
// Values of dt < 0 are set to 0.
|
||||||
//
|
//
|
||||||
func NewThrottle(r float64, tm int64) *Throttle {
|
func NewThrottle(r float64, dt time.Duration) *Throttle {
|
||||||
var f float64
|
var f float64
|
||||||
switch {
|
switch {
|
||||||
case r <= 0:
|
case r <= 0:
|
||||||
@ -39,10 +39,10 @@ func NewThrottle(r float64, tm int64) *Throttle {
|
|||||||
// 0 < r < 1
|
// 0 < r < 1
|
||||||
f = (1 - r) / r
|
f = (1 - r) / r
|
||||||
}
|
}
|
||||||
if tm < 0 {
|
if dt < 0 {
|
||||||
tm = 0
|
dt = 0
|
||||||
}
|
}
|
||||||
return &Throttle{f: f, tm: tm, tt: time.Nanoseconds() + tm}
|
return &Throttle{f: f, dt: dt, tt: time.Now().Add(dt)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Throttle calls time.Sleep such that over time the ratio tr/ts between
|
// Throttle calls time.Sleep such that over time the ratio tr/ts between
|
||||||
@ -55,13 +55,13 @@ func (p *Throttle) Throttle() {
|
|||||||
select {} // always sleep
|
select {} // always sleep
|
||||||
}
|
}
|
||||||
|
|
||||||
t0 := time.Nanoseconds()
|
t0 := time.Now()
|
||||||
if t0 < p.tt {
|
if t0.Before(p.tt) {
|
||||||
return // keep running (minimum time slice not exhausted yet)
|
return // keep running (minimum time slice not exhausted yet)
|
||||||
}
|
}
|
||||||
|
|
||||||
// accumulate running time
|
// accumulate running time
|
||||||
p.tr += t0 - (p.tt - p.tm)
|
p.tr += t0.Sub(p.tt) + p.dt
|
||||||
|
|
||||||
// compute sleep time
|
// compute sleep time
|
||||||
// Over time we want:
|
// Over time we want:
|
||||||
@ -75,14 +75,14 @@ func (p *Throttle) Throttle() {
|
|||||||
// After some incremental run time δr added to the total run time
|
// After some incremental run time δr added to the total run time
|
||||||
// tr, the incremental sleep-time δs to get to the same ratio again
|
// tr, the incremental sleep-time δs to get to the same ratio again
|
||||||
// after waking up from time.Sleep is:
|
// after waking up from time.Sleep is:
|
||||||
if δs := int64(float64(p.tr)*p.f) - p.ts; δs > 0 {
|
if δs := time.Duration(float64(p.tr)*p.f) - p.ts; δs > 0 {
|
||||||
time.Sleep(δs)
|
time.Sleep(δs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// accumulate (actual) sleep time
|
// accumulate (actual) sleep time
|
||||||
t1 := time.Nanoseconds()
|
t1 := time.Now()
|
||||||
p.ts += t1 - t0
|
p.ts += t1.Sub(t0)
|
||||||
|
|
||||||
// set earliest next throttle time
|
// set earliest next throttle time
|
||||||
p.tt = t1 + p.tm
|
p.tt = t1.Add(p.dt)
|
||||||
}
|
}
|
||||||
|
@ -24,17 +24,17 @@ import (
|
|||||||
type RWValue struct {
|
type RWValue struct {
|
||||||
mutex sync.RWMutex
|
mutex sync.RWMutex
|
||||||
value interface{}
|
value interface{}
|
||||||
timestamp int64 // time of last set(), in seconds since epoch
|
timestamp time.Time // time of last set()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *RWValue) set(value interface{}) {
|
func (v *RWValue) set(value interface{}) {
|
||||||
v.mutex.Lock()
|
v.mutex.Lock()
|
||||||
v.value = value
|
v.value = value
|
||||||
v.timestamp = time.Seconds()
|
v.timestamp = time.Now()
|
||||||
v.mutex.Unlock()
|
v.mutex.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *RWValue) get() (interface{}, int64) {
|
func (v *RWValue) get() (interface{}, time.Time) {
|
||||||
v.mutex.RLock()
|
v.mutex.RLock()
|
||||||
defer v.mutex.RUnlock()
|
defer v.mutex.RUnlock()
|
||||||
return v.value, v.timestamp
|
return v.value, v.timestamp
|
||||||
|
@ -25,6 +25,7 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// zipFI is the zip-file based implementation of FileInfo
|
// zipFI is the zip-file based implementation of FileInfo
|
||||||
@ -44,11 +45,11 @@ func (fi zipFI) Size() int64 {
|
|||||||
return 0 // directory
|
return 0 // directory
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fi zipFI) Mtime_ns() int64 {
|
func (fi zipFI) ModTime() time.Time {
|
||||||
if f := fi.file; f != nil {
|
if f := fi.file; f != nil {
|
||||||
return f.Mtime_ns()
|
return f.ModTime()
|
||||||
}
|
}
|
||||||
return 0 // directory has no modified time entry
|
return time.Time{} // directory has no modified time entry
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fi zipFI) IsDirectory() bool {
|
func (fi zipFI) IsDirectory() bool {
|
||||||
|
@ -56,10 +56,10 @@ var (
|
|||||||
|
|
||||||
// elapsed returns the number of seconds since gotest started.
|
// elapsed returns the number of seconds since gotest started.
|
||||||
func elapsed() float64 {
|
func elapsed() float64 {
|
||||||
return float64(time.Nanoseconds()-start) / 1e9
|
return time.Now().Sub(start).Seconds()
|
||||||
}
|
}
|
||||||
|
|
||||||
var start = time.Nanoseconds()
|
var start = time.Now()
|
||||||
|
|
||||||
// File represents a file that contains tests.
|
// File represents a file that contains tests.
|
||||||
type File struct {
|
type File struct {
|
||||||
@ -293,10 +293,10 @@ func runTestWithArgs(binary string) {
|
|||||||
func doRun(argv []string, returnStdout bool) string {
|
func doRun(argv []string, returnStdout bool) string {
|
||||||
if xFlag {
|
if xFlag {
|
||||||
fmt.Printf("gotest %.2fs: %s\n", elapsed(), strings.Join(argv, " "))
|
fmt.Printf("gotest %.2fs: %s\n", elapsed(), strings.Join(argv, " "))
|
||||||
t := -time.Nanoseconds()
|
start := time.Now()
|
||||||
defer func() {
|
defer func() {
|
||||||
t += time.Nanoseconds()
|
t := time.Now().Sub(start)
|
||||||
fmt.Printf(" [+%.2fs]\n", float64(t)/1e9)
|
fmt.Printf(" [+%.2fs]\n", t.Seconds())
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
command := argv[0]
|
command := argv[0]
|
||||||
|
@ -11,41 +11,42 @@
|
|||||||
// http://www.gnu.org/software/tar/manual/html_node/Standard.html
|
// http://www.gnu.org/software/tar/manual/html_node/Standard.html
|
||||||
package tar
|
package tar
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
blockSize = 512
|
blockSize = 512
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
TypeReg = '0' // regular file.
|
TypeReg = '0' // regular file
|
||||||
TypeRegA = '\x00' // regular file.
|
TypeRegA = '\x00' // regular file
|
||||||
TypeLink = '1' // hard link.
|
TypeLink = '1' // hard link
|
||||||
TypeSymlink = '2' // symbolic link.
|
TypeSymlink = '2' // symbolic link
|
||||||
TypeChar = '3' // character device node.
|
TypeChar = '3' // character device node
|
||||||
TypeBlock = '4' // block device node.
|
TypeBlock = '4' // block device node
|
||||||
TypeDir = '5' // directory.
|
TypeDir = '5' // directory
|
||||||
TypeFifo = '6' // fifo node.
|
TypeFifo = '6' // fifo node
|
||||||
TypeCont = '7' // reserved.
|
TypeCont = '7' // reserved
|
||||||
TypeXHeader = 'x' // extended header.
|
TypeXHeader = 'x' // extended header
|
||||||
TypeXGlobalHeader = 'g' // global extended header.
|
TypeXGlobalHeader = 'g' // global extended header
|
||||||
)
|
)
|
||||||
|
|
||||||
// A Header represents a single header in a tar archive.
|
// A Header represents a single header in a tar archive.
|
||||||
// Some fields may not be populated.
|
// Some fields may not be populated.
|
||||||
type Header struct {
|
type Header struct {
|
||||||
Name string // name of header file entry.
|
Name string // name of header file entry
|
||||||
Mode int64 // permission and mode bits.
|
Mode int64 // permission and mode bits
|
||||||
Uid int // user id of owner.
|
Uid int // user id of owner
|
||||||
Gid int // group id of owner.
|
Gid int // group id of owner
|
||||||
Size int64 // length in bytes.
|
Size int64 // length in bytes
|
||||||
Mtime int64 // modified time; seconds since epoch.
|
ModTime time.Time // modified time
|
||||||
Typeflag byte // type of header entry.
|
Typeflag byte // type of header entry
|
||||||
Linkname string // target name of link.
|
Linkname string // target name of link
|
||||||
Uname string // user name of owner.
|
Uname string // user name of owner
|
||||||
Gname string // group name of owner.
|
Gname string // group name of owner
|
||||||
Devmajor int64 // major number of character or block device.
|
Devmajor int64 // major number of character or block device
|
||||||
Devminor int64 // minor number of character or block device.
|
Devminor int64 // minor number of character or block device
|
||||||
Atime int64 // access time; seconds since epoch.
|
AccessTime time.Time // access time
|
||||||
Ctime int64 // status change time; seconds since epoch.
|
ChangeTime time.Time // status change time
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var zeroBlock = make([]byte, blockSize)
|
var zeroBlock = make([]byte, blockSize)
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -141,7 +142,7 @@ func (tr *Reader) readHeader() *Header {
|
|||||||
hdr.Uid = int(tr.octal(s.next(8)))
|
hdr.Uid = int(tr.octal(s.next(8)))
|
||||||
hdr.Gid = int(tr.octal(s.next(8)))
|
hdr.Gid = int(tr.octal(s.next(8)))
|
||||||
hdr.Size = tr.octal(s.next(12))
|
hdr.Size = tr.octal(s.next(12))
|
||||||
hdr.Mtime = tr.octal(s.next(12))
|
hdr.ModTime = time.Unix(tr.octal(s.next(12)), 0)
|
||||||
s.next(8) // chksum
|
s.next(8) // chksum
|
||||||
hdr.Typeflag = s.next(1)[0]
|
hdr.Typeflag = s.next(1)[0]
|
||||||
hdr.Linkname = cString(s.next(100))
|
hdr.Linkname = cString(s.next(100))
|
||||||
@ -178,8 +179,8 @@ func (tr *Reader) readHeader() *Header {
|
|||||||
prefix = cString(s.next(155))
|
prefix = cString(s.next(155))
|
||||||
case "star":
|
case "star":
|
||||||
prefix = cString(s.next(131))
|
prefix = cString(s.next(131))
|
||||||
hdr.Atime = tr.octal(s.next(12))
|
hdr.AccessTime = time.Unix(tr.octal(s.next(12)), 0)
|
||||||
hdr.Ctime = tr.octal(s.next(12))
|
hdr.ChangeTime = time.Unix(tr.octal(s.next(12)), 0)
|
||||||
}
|
}
|
||||||
if len(prefix) > 0 {
|
if len(prefix) > 0 {
|
||||||
hdr.Name = prefix + "/" + hdr.Name
|
hdr.Name = prefix + "/" + hdr.Name
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type untarTest struct {
|
type untarTest struct {
|
||||||
@ -29,7 +30,7 @@ var gnuTarTest = &untarTest{
|
|||||||
Uid: 73025,
|
Uid: 73025,
|
||||||
Gid: 5000,
|
Gid: 5000,
|
||||||
Size: 5,
|
Size: 5,
|
||||||
Mtime: 1244428340,
|
ModTime: time.Unix(1244428340, 0),
|
||||||
Typeflag: '0',
|
Typeflag: '0',
|
||||||
Uname: "dsymonds",
|
Uname: "dsymonds",
|
||||||
Gname: "eng",
|
Gname: "eng",
|
||||||
@ -40,7 +41,7 @@ var gnuTarTest = &untarTest{
|
|||||||
Uid: 73025,
|
Uid: 73025,
|
||||||
Gid: 5000,
|
Gid: 5000,
|
||||||
Size: 11,
|
Size: 11,
|
||||||
Mtime: 1244436044,
|
ModTime: time.Unix(1244436044, 0),
|
||||||
Typeflag: '0',
|
Typeflag: '0',
|
||||||
Uname: "dsymonds",
|
Uname: "dsymonds",
|
||||||
Gname: "eng",
|
Gname: "eng",
|
||||||
@ -58,30 +59,30 @@ var untarTests = []*untarTest{
|
|||||||
file: "testdata/star.tar",
|
file: "testdata/star.tar",
|
||||||
headers: []*Header{
|
headers: []*Header{
|
||||||
&Header{
|
&Header{
|
||||||
Name: "small.txt",
|
Name: "small.txt",
|
||||||
Mode: 0640,
|
Mode: 0640,
|
||||||
Uid: 73025,
|
Uid: 73025,
|
||||||
Gid: 5000,
|
Gid: 5000,
|
||||||
Size: 5,
|
Size: 5,
|
||||||
Mtime: 1244592783,
|
ModTime: time.Unix(1244592783, 0),
|
||||||
Typeflag: '0',
|
Typeflag: '0',
|
||||||
Uname: "dsymonds",
|
Uname: "dsymonds",
|
||||||
Gname: "eng",
|
Gname: "eng",
|
||||||
Atime: 1244592783,
|
AccessTime: time.Unix(1244592783, 0),
|
||||||
Ctime: 1244592783,
|
ChangeTime: time.Unix(1244592783, 0),
|
||||||
},
|
},
|
||||||
&Header{
|
&Header{
|
||||||
Name: "small2.txt",
|
Name: "small2.txt",
|
||||||
Mode: 0640,
|
Mode: 0640,
|
||||||
Uid: 73025,
|
Uid: 73025,
|
||||||
Gid: 5000,
|
Gid: 5000,
|
||||||
Size: 11,
|
Size: 11,
|
||||||
Mtime: 1244592783,
|
ModTime: time.Unix(1244592783, 0),
|
||||||
Typeflag: '0',
|
Typeflag: '0',
|
||||||
Uname: "dsymonds",
|
Uname: "dsymonds",
|
||||||
Gname: "eng",
|
Gname: "eng",
|
||||||
Atime: 1244592783,
|
AccessTime: time.Unix(1244592783, 0),
|
||||||
Ctime: 1244592783,
|
ChangeTime: time.Unix(1244592783, 0),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -94,7 +95,7 @@ var untarTests = []*untarTest{
|
|||||||
Uid: 73025,
|
Uid: 73025,
|
||||||
Gid: 5000,
|
Gid: 5000,
|
||||||
Size: 5,
|
Size: 5,
|
||||||
Mtime: 1244593104,
|
ModTime: time.Unix(1244593104, 0),
|
||||||
Typeflag: '\x00',
|
Typeflag: '\x00',
|
||||||
},
|
},
|
||||||
&Header{
|
&Header{
|
||||||
@ -103,7 +104,7 @@ var untarTests = []*untarTest{
|
|||||||
Uid: 73025,
|
Uid: 73025,
|
||||||
Gid: 5000,
|
Gid: 5000,
|
||||||
Size: 11,
|
Size: 11,
|
||||||
Mtime: 1244593104,
|
ModTime: time.Unix(1244593104, 0),
|
||||||
Typeflag: '\x00',
|
Typeflag: '\x00',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -127,19 +127,19 @@ func (tw *Writer) WriteHeader(hdr *Header) error {
|
|||||||
// TODO(dsymonds): handle names longer than 100 chars
|
// TODO(dsymonds): handle names longer than 100 chars
|
||||||
copy(s.next(100), []byte(hdr.Name))
|
copy(s.next(100), []byte(hdr.Name))
|
||||||
|
|
||||||
tw.octal(s.next(8), hdr.Mode) // 100:108
|
tw.octal(s.next(8), hdr.Mode) // 100:108
|
||||||
tw.numeric(s.next(8), int64(hdr.Uid)) // 108:116
|
tw.numeric(s.next(8), int64(hdr.Uid)) // 108:116
|
||||||
tw.numeric(s.next(8), int64(hdr.Gid)) // 116:124
|
tw.numeric(s.next(8), int64(hdr.Gid)) // 116:124
|
||||||
tw.numeric(s.next(12), hdr.Size) // 124:136
|
tw.numeric(s.next(12), hdr.Size) // 124:136
|
||||||
tw.numeric(s.next(12), hdr.Mtime) // 136:148
|
tw.numeric(s.next(12), hdr.ModTime.Unix()) // 136:148
|
||||||
s.next(8) // chksum (148:156)
|
s.next(8) // chksum (148:156)
|
||||||
s.next(1)[0] = hdr.Typeflag // 156:157
|
s.next(1)[0] = hdr.Typeflag // 156:157
|
||||||
tw.cString(s.next(100), hdr.Linkname) // linkname (157:257)
|
tw.cString(s.next(100), hdr.Linkname) // linkname (157:257)
|
||||||
copy(s.next(8), []byte("ustar\x0000")) // 257:265
|
copy(s.next(8), []byte("ustar\x0000")) // 257:265
|
||||||
tw.cString(s.next(32), hdr.Uname) // 265:297
|
tw.cString(s.next(32), hdr.Uname) // 265:297
|
||||||
tw.cString(s.next(32), hdr.Gname) // 297:329
|
tw.cString(s.next(32), hdr.Gname) // 297:329
|
||||||
tw.numeric(s.next(8), hdr.Devmajor) // 329:337
|
tw.numeric(s.next(8), hdr.Devmajor) // 329:337
|
||||||
tw.numeric(s.next(8), hdr.Devminor) // 337:345
|
tw.numeric(s.next(8), hdr.Devminor) // 337:345
|
||||||
|
|
||||||
// Use the GNU magic instead of POSIX magic if we used any GNU extensions.
|
// Use the GNU magic instead of POSIX magic if we used any GNU extensions.
|
||||||
if tw.usedBinary {
|
if tw.usedBinary {
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"testing"
|
"testing"
|
||||||
"testing/iotest"
|
"testing/iotest"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type writerTestEntry struct {
|
type writerTestEntry struct {
|
||||||
@ -38,7 +39,7 @@ var writerTests = []*writerTest{
|
|||||||
Uid: 73025,
|
Uid: 73025,
|
||||||
Gid: 5000,
|
Gid: 5000,
|
||||||
Size: 5,
|
Size: 5,
|
||||||
Mtime: 1246508266,
|
ModTime: time.Unix(1246508266, 0),
|
||||||
Typeflag: '0',
|
Typeflag: '0',
|
||||||
Uname: "dsymonds",
|
Uname: "dsymonds",
|
||||||
Gname: "eng",
|
Gname: "eng",
|
||||||
@ -52,7 +53,7 @@ var writerTests = []*writerTest{
|
|||||||
Uid: 73025,
|
Uid: 73025,
|
||||||
Gid: 5000,
|
Gid: 5000,
|
||||||
Size: 11,
|
Size: 11,
|
||||||
Mtime: 1245217492,
|
ModTime: time.Unix(1245217492, 0),
|
||||||
Typeflag: '0',
|
Typeflag: '0',
|
||||||
Uname: "dsymonds",
|
Uname: "dsymonds",
|
||||||
Gname: "eng",
|
Gname: "eng",
|
||||||
@ -66,7 +67,7 @@ var writerTests = []*writerTest{
|
|||||||
Uid: 1000,
|
Uid: 1000,
|
||||||
Gid: 1000,
|
Gid: 1000,
|
||||||
Size: 0,
|
Size: 0,
|
||||||
Mtime: 1314603082,
|
ModTime: time.Unix(1314603082, 0),
|
||||||
Typeflag: '2',
|
Typeflag: '2',
|
||||||
Linkname: "small.txt",
|
Linkname: "small.txt",
|
||||||
Uname: "strings",
|
Uname: "strings",
|
||||||
@ -89,7 +90,7 @@ var writerTests = []*writerTest{
|
|||||||
Uid: 73025,
|
Uid: 73025,
|
||||||
Gid: 5000,
|
Gid: 5000,
|
||||||
Size: 16 << 30,
|
Size: 16 << 30,
|
||||||
Mtime: 1254699560,
|
ModTime: time.Unix(1254699560, 0),
|
||||||
Typeflag: '0',
|
Typeflag: '0',
|
||||||
Uname: "dsymonds",
|
Uname: "dsymonds",
|
||||||
Gname: "eng",
|
Gname: "eng",
|
||||||
|
@ -164,8 +164,8 @@ func readTestFile(t *testing.T, ft ZipTestFile, f *File) {
|
|||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if got, want := f.Mtime_ns()/1e9, mtime.Seconds(); got != want {
|
if ft := f.ModTime(); !ft.Equal(mtime) {
|
||||||
t.Errorf("%s: mtime=%s (%d); want %s (%d)", f.Name, time.SecondsToUTC(got), got, mtime, want)
|
t.Errorf("%s: mtime=%s, want %s", f.Name, ft, mtime)
|
||||||
}
|
}
|
||||||
|
|
||||||
testFileMode(t, f, ft.Mode)
|
testFileMode(t, f, ft.Mode)
|
||||||
|
@ -11,8 +11,10 @@ This package does not support ZIP64 or disk spanning.
|
|||||||
*/
|
*/
|
||||||
package zip
|
package zip
|
||||||
|
|
||||||
import "errors"
|
import (
|
||||||
import "time"
|
"errors"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
// Compression methods.
|
// Compression methods.
|
||||||
const (
|
const (
|
||||||
@ -74,24 +76,26 @@ func recoverError(errp *error) {
|
|||||||
// The resolution is 2s.
|
// The resolution is 2s.
|
||||||
// See: http://msdn.microsoft.com/en-us/library/ms724247(v=VS.85).aspx
|
// See: http://msdn.microsoft.com/en-us/library/ms724247(v=VS.85).aspx
|
||||||
func msDosTimeToTime(dosDate, dosTime uint16) time.Time {
|
func msDosTimeToTime(dosDate, dosTime uint16) time.Time {
|
||||||
return time.Time{
|
return time.Date(
|
||||||
// date bits 0-4: day of month; 5-8: month; 9-15: years since 1980
|
// date bits 0-4: day of month; 5-8: month; 9-15: years since 1980
|
||||||
Year: int64(dosDate>>9 + 1980),
|
int(dosDate>>9+1980),
|
||||||
Month: int(dosDate >> 5 & 0xf),
|
time.Month(dosDate>>5&0xf),
|
||||||
Day: int(dosDate & 0x1f),
|
int(dosDate&0x1f),
|
||||||
|
|
||||||
// time bits 0-4: second/2; 5-10: minute; 11-15: hour
|
// time bits 0-4: second/2; 5-10: minute; 11-15: hour
|
||||||
Hour: int(dosTime >> 11),
|
int(dosTime>>11),
|
||||||
Minute: int(dosTime >> 5 & 0x3f),
|
int(dosTime>>5&0x3f),
|
||||||
Second: int(dosTime & 0x1f * 2),
|
int(dosTime&0x1f*2),
|
||||||
}
|
0, // nanoseconds
|
||||||
|
|
||||||
|
time.UTC,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mtime_ns returns the modified time in ns since epoch.
|
// ModTime returns the modification time.
|
||||||
// The resolution is 2s.
|
// The resolution is 2s.
|
||||||
func (h *FileHeader) Mtime_ns() int64 {
|
func (h *FileHeader) ModTime() time.Time {
|
||||||
t := msDosTimeToTime(h.ModifiedDate, h.ModifiedTime)
|
return msDosTimeToTime(h.ModifiedDate, h.ModifiedTime)
|
||||||
return t.Seconds() * 1e9
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mode returns the permission and mode bits for the FileHeader.
|
// Mode returns the permission and mode bits for the FileHeader.
|
||||||
|
@ -13,6 +13,7 @@ import (
|
|||||||
"hash"
|
"hash"
|
||||||
"hash/crc32"
|
"hash/crc32"
|
||||||
"io"
|
"io"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BUG(nigeltao): Comments and Names don't properly map UTF-8 character codes outside of
|
// BUG(nigeltao): Comments and Names don't properly map UTF-8 character codes outside of
|
||||||
@ -42,11 +43,11 @@ var ChecksumError = errors.New("gzip checksum error")
|
|||||||
// The gzip file stores a header giving metadata about the compressed file.
|
// The gzip file stores a header giving metadata about the compressed file.
|
||||||
// That header is exposed as the fields of the Compressor and Decompressor structs.
|
// That header is exposed as the fields of the Compressor and Decompressor structs.
|
||||||
type Header struct {
|
type Header struct {
|
||||||
Comment string // comment
|
Comment string // comment
|
||||||
Extra []byte // "extra data"
|
Extra []byte // "extra data"
|
||||||
Mtime uint32 // modification time (seconds since January 1, 1970)
|
ModTime time.Time // modification time
|
||||||
Name string // file name
|
Name string // file name
|
||||||
OS byte // operating system type
|
OS byte // operating system type
|
||||||
}
|
}
|
||||||
|
|
||||||
// An Decompressor is an io.Reader that can be read to retrieve
|
// An Decompressor is an io.Reader that can be read to retrieve
|
||||||
@ -130,7 +131,7 @@ func (z *Decompressor) readHeader(save bool) error {
|
|||||||
}
|
}
|
||||||
z.flg = z.buf[3]
|
z.flg = z.buf[3]
|
||||||
if save {
|
if save {
|
||||||
z.Mtime = get4(z.buf[4:8])
|
z.ModTime = time.Unix(int64(get4(z.buf[4:8])), 0)
|
||||||
// z.buf[8] is xfl, ignored
|
// z.buf[8] is xfl, ignored
|
||||||
z.OS = z.buf[9]
|
z.OS = z.buf[9]
|
||||||
}
|
}
|
||||||
|
@ -122,7 +122,7 @@ func (z *Compressor) Write(p []byte) (int, error) {
|
|||||||
if z.Comment != "" {
|
if z.Comment != "" {
|
||||||
z.buf[3] |= 0x10
|
z.buf[3] |= 0x10
|
||||||
}
|
}
|
||||||
put4(z.buf[4:8], z.Mtime)
|
put4(z.buf[4:8], uint32(z.ModTime.Unix()))
|
||||||
if z.level == BestCompression {
|
if z.level == BestCompression {
|
||||||
z.buf[8] = 2
|
z.buf[8] = 2
|
||||||
} else if z.level == BestSpeed {
|
} else if z.level == BestSpeed {
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// pipe creates two ends of a pipe that gzip and gunzip, and runs dfunc at the
|
// pipe creates two ends of a pipe that gzip and gunzip, and runs dfunc at the
|
||||||
@ -53,7 +54,7 @@ func TestWriter(t *testing.T) {
|
|||||||
func(compressor *Compressor) {
|
func(compressor *Compressor) {
|
||||||
compressor.Comment = "comment"
|
compressor.Comment = "comment"
|
||||||
compressor.Extra = []byte("extra")
|
compressor.Extra = []byte("extra")
|
||||||
compressor.Mtime = 1e8
|
compressor.ModTime = time.Unix(1e8, 0)
|
||||||
compressor.Name = "name"
|
compressor.Name = "name"
|
||||||
_, err := compressor.Write([]byte("payload"))
|
_, err := compressor.Write([]byte("payload"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -74,8 +75,8 @@ func TestWriter(t *testing.T) {
|
|||||||
if string(decompressor.Extra) != "extra" {
|
if string(decompressor.Extra) != "extra" {
|
||||||
t.Fatalf("extra is %q, want %q", decompressor.Extra, "extra")
|
t.Fatalf("extra is %q, want %q", decompressor.Extra, "extra")
|
||||||
}
|
}
|
||||||
if decompressor.Mtime != 1e8 {
|
if decompressor.ModTime.Unix() != 1e8 {
|
||||||
t.Fatalf("mtime is %d, want %d", decompressor.Mtime, uint32(1e8))
|
t.Fatalf("mtime is %d, want %d", decompressor.ModTime.Unix(), uint32(1e8))
|
||||||
}
|
}
|
||||||
if decompressor.Name != "name" {
|
if decompressor.Name != "name" {
|
||||||
t.Fatalf("name is %q, want %q", decompressor.Name, "name")
|
t.Fatalf("name is %q, want %q", decompressor.Name, "name")
|
||||||
|
@ -61,7 +61,7 @@ type responseData struct {
|
|||||||
Version int `asn1:"optional,default:1,explicit,tag:0"`
|
Version int `asn1:"optional,default:1,explicit,tag:0"`
|
||||||
RequestorName pkix.RDNSequence `asn1:"optional,explicit,tag:1"`
|
RequestorName pkix.RDNSequence `asn1:"optional,explicit,tag:1"`
|
||||||
KeyHash []byte `asn1:"optional,explicit,tag:2"`
|
KeyHash []byte `asn1:"optional,explicit,tag:2"`
|
||||||
ProducedAt *time.Time
|
ProducedAt time.Time
|
||||||
Responses []singleResponse
|
Responses []singleResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,12 +70,12 @@ type singleResponse struct {
|
|||||||
Good asn1.Flag `asn1:"explicit,tag:0,optional"`
|
Good asn1.Flag `asn1:"explicit,tag:0,optional"`
|
||||||
Revoked revokedInfo `asn1:"explicit,tag:1,optional"`
|
Revoked revokedInfo `asn1:"explicit,tag:1,optional"`
|
||||||
Unknown asn1.Flag `asn1:"explicit,tag:2,optional"`
|
Unknown asn1.Flag `asn1:"explicit,tag:2,optional"`
|
||||||
ThisUpdate *time.Time
|
ThisUpdate time.Time
|
||||||
NextUpdate *time.Time `asn1:"explicit,tag:0,optional"`
|
NextUpdate time.Time `asn1:"explicit,tag:0,optional"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type revokedInfo struct {
|
type revokedInfo struct {
|
||||||
RevocationTime *time.Time
|
RevocationTime time.Time
|
||||||
Reason int `asn1:"explicit,tag:0,optional"`
|
Reason int `asn1:"explicit,tag:0,optional"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,7 +97,7 @@ type Response struct {
|
|||||||
// Status is one of {Good, Revoked, Unknown, ServerFailed}
|
// Status is one of {Good, Revoked, Unknown, ServerFailed}
|
||||||
Status int
|
Status int
|
||||||
SerialNumber []byte
|
SerialNumber []byte
|
||||||
ProducedAt, ThisUpdate, NextUpdate, RevokedAt *time.Time
|
ProducedAt, ThisUpdate, NextUpdate, RevokedAt time.Time
|
||||||
RevocationReason int
|
RevocationReason int
|
||||||
Certificate *x509.Certificate
|
Certificate *x509.Certificate
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,13 @@ func TestOCSPDecode(t *testing.T) {
|
|||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := Response{Status: 0, SerialNumber: []byte{0x1, 0xd0, 0xfa}, RevocationReason: 0, ThisUpdate: &time.Time{Year: 2010, Month: 7, Day: 7, Hour: 15, Minute: 1, Second: 5, ZoneOffset: 0, Zone: "UTC"}, NextUpdate: &time.Time{Year: 2010, Month: 7, Day: 7, Hour: 18, Minute: 35, Second: 17, ZoneOffset: 0, Zone: "UTC"}}
|
expected := Response{
|
||||||
|
Status: 0,
|
||||||
|
SerialNumber: []byte{0x1, 0xd0, 0xfa},
|
||||||
|
RevocationReason: 0,
|
||||||
|
ThisUpdate: time.Date(2010, 7, 7, 15, 1, 5, 0, time.UTC),
|
||||||
|
NextUpdate: time.Date(2010, 7, 7, 18, 35, 17, 0, time.UTC),
|
||||||
|
}
|
||||||
|
|
||||||
if !reflect.DeepEqual(resp.ThisUpdate, resp.ThisUpdate) {
|
if !reflect.DeepEqual(resp.ThisUpdate, resp.ThisUpdate) {
|
||||||
t.Errorf("resp.ThisUpdate: got %d, want %d", resp.ThisUpdate, expected.ThisUpdate)
|
t.Errorf("resp.ThisUpdate: got %d, want %d", resp.ThisUpdate, expected.ThisUpdate)
|
||||||
|
@ -381,7 +381,7 @@ const defaultRSAKeyBits = 2048
|
|||||||
// NewEntity returns an Entity that contains a fresh RSA/RSA keypair with a
|
// NewEntity returns an Entity that contains a fresh RSA/RSA keypair with a
|
||||||
// single identity composed of the given full name, comment and email, any of
|
// single identity composed of the given full name, comment and email, any of
|
||||||
// which may be empty but must not contain any of "()<>\x00".
|
// which may be empty but must not contain any of "()<>\x00".
|
||||||
func NewEntity(rand io.Reader, currentTimeSecs int64, name, comment, email string) (*Entity, error) {
|
func NewEntity(rand io.Reader, currentTime time.Time, name, comment, email string) (*Entity, error) {
|
||||||
uid := packet.NewUserId(name, comment, email)
|
uid := packet.NewUserId(name, comment, email)
|
||||||
if uid == nil {
|
if uid == nil {
|
||||||
return nil, error_.InvalidArgumentError("user id field contained invalid characters")
|
return nil, error_.InvalidArgumentError("user id field contained invalid characters")
|
||||||
@ -395,11 +395,9 @@ func NewEntity(rand io.Reader, currentTimeSecs int64, name, comment, email strin
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
t := uint32(currentTimeSecs)
|
|
||||||
|
|
||||||
e := &Entity{
|
e := &Entity{
|
||||||
PrimaryKey: packet.NewRSAPublicKey(t, &signingPriv.PublicKey, false /* not a subkey */ ),
|
PrimaryKey: packet.NewRSAPublicKey(currentTime, &signingPriv.PublicKey, false /* not a subkey */ ),
|
||||||
PrivateKey: packet.NewRSAPrivateKey(t, signingPriv, false /* not a subkey */ ),
|
PrivateKey: packet.NewRSAPrivateKey(currentTime, signingPriv, false /* not a subkey */ ),
|
||||||
Identities: make(map[string]*Identity),
|
Identities: make(map[string]*Identity),
|
||||||
}
|
}
|
||||||
isPrimaryId := true
|
isPrimaryId := true
|
||||||
@ -407,7 +405,7 @@ func NewEntity(rand io.Reader, currentTimeSecs int64, name, comment, email strin
|
|||||||
Name: uid.Name,
|
Name: uid.Name,
|
||||||
UserId: uid,
|
UserId: uid,
|
||||||
SelfSignature: &packet.Signature{
|
SelfSignature: &packet.Signature{
|
||||||
CreationTime: t,
|
CreationTime: currentTime,
|
||||||
SigType: packet.SigTypePositiveCert,
|
SigType: packet.SigTypePositiveCert,
|
||||||
PubKeyAlgo: packet.PubKeyAlgoRSA,
|
PubKeyAlgo: packet.PubKeyAlgoRSA,
|
||||||
Hash: crypto.SHA256,
|
Hash: crypto.SHA256,
|
||||||
@ -421,10 +419,10 @@ func NewEntity(rand io.Reader, currentTimeSecs int64, name, comment, email strin
|
|||||||
|
|
||||||
e.Subkeys = make([]Subkey, 1)
|
e.Subkeys = make([]Subkey, 1)
|
||||||
e.Subkeys[0] = Subkey{
|
e.Subkeys[0] = Subkey{
|
||||||
PublicKey: packet.NewRSAPublicKey(t, &encryptingPriv.PublicKey, true /* is a subkey */ ),
|
PublicKey: packet.NewRSAPublicKey(currentTime, &encryptingPriv.PublicKey, true /* is a subkey */ ),
|
||||||
PrivateKey: packet.NewRSAPrivateKey(t, encryptingPriv, true /* is a subkey */ ),
|
PrivateKey: packet.NewRSAPrivateKey(currentTime, encryptingPriv, true /* is a subkey */ ),
|
||||||
Sig: &packet.Signature{
|
Sig: &packet.Signature{
|
||||||
CreationTime: t,
|
CreationTime: currentTime,
|
||||||
SigType: packet.SigTypeSubkeyBinding,
|
SigType: packet.SigTypeSubkeyBinding,
|
||||||
PubKeyAlgo: packet.PubKeyAlgoRSA,
|
PubKeyAlgo: packet.PubKeyAlgoRSA,
|
||||||
Hash: crypto.SHA256,
|
Hash: crypto.SHA256,
|
||||||
@ -533,7 +531,7 @@ func (e *Entity) SignIdentity(identity string, signer *Entity) error {
|
|||||||
SigType: packet.SigTypeGenericCert,
|
SigType: packet.SigTypeGenericCert,
|
||||||
PubKeyAlgo: signer.PrivateKey.PubKeyAlgo,
|
PubKeyAlgo: signer.PrivateKey.PubKeyAlgo,
|
||||||
Hash: crypto.SHA256,
|
Hash: crypto.SHA256,
|
||||||
CreationTime: uint32(time.Seconds()),
|
CreationTime: time.Now(),
|
||||||
IssuerKeyId: &signer.PrivateKey.KeyId,
|
IssuerKeyId: &signer.PrivateKey.KeyId,
|
||||||
}
|
}
|
||||||
if err := sig.SignKey(e.PrimaryKey, signer.PrivateKey); err != nil {
|
if err := sig.SignKey(e.PrimaryKey, signer.PrivateKey); err != nil {
|
||||||
|
@ -17,6 +17,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math/big"
|
"math/big"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PrivateKey represents a possibly encrypted private key. See RFC 4880,
|
// PrivateKey represents a possibly encrypted private key. See RFC 4880,
|
||||||
@ -32,9 +33,9 @@ type PrivateKey struct {
|
|||||||
iv []byte
|
iv []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRSAPrivateKey(currentTimeSecs uint32, priv *rsa.PrivateKey, isSubkey bool) *PrivateKey {
|
func NewRSAPrivateKey(currentTime time.Time, priv *rsa.PrivateKey, isSubkey bool) *PrivateKey {
|
||||||
pk := new(PrivateKey)
|
pk := new(PrivateKey)
|
||||||
pk.PublicKey = *NewRSAPublicKey(currentTimeSecs, &priv.PublicKey, isSubkey)
|
pk.PublicKey = *NewRSAPublicKey(currentTime, &priv.PublicKey, isSubkey)
|
||||||
pk.PrivateKey = priv
|
pk.PrivateKey = priv
|
||||||
return pk
|
return pk
|
||||||
}
|
}
|
||||||
|
@ -6,19 +6,20 @@ package packet
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var privateKeyTests = []struct {
|
var privateKeyTests = []struct {
|
||||||
privateKeyHex string
|
privateKeyHex string
|
||||||
creationTime uint32
|
creationTime time.Time
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
privKeyRSAHex,
|
privKeyRSAHex,
|
||||||
0x4cc349a8,
|
time.Unix(0x4cc349a8, 0),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
privKeyElGamalHex,
|
privKeyElGamalHex,
|
||||||
0x4df9ee1a,
|
time.Unix(0x4df9ee1a, 0),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,7 +44,7 @@ func TestPrivateKeyRead(t *testing.T) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if privKey.CreationTime != test.creationTime || privKey.Encrypted {
|
if !privKey.CreationTime.Equal(test.creationTime) || privKey.Encrypted {
|
||||||
t.Errorf("#%d: bad result, got: %#v", i, privKey)
|
t.Errorf("#%d: bad result, got: %#v", i, privKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,11 +16,12 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PublicKey represents an OpenPGP public key. See RFC 4880, section 5.5.2.
|
// PublicKey represents an OpenPGP public key. See RFC 4880, section 5.5.2.
|
||||||
type PublicKey struct {
|
type PublicKey struct {
|
||||||
CreationTime uint32 // seconds since the epoch
|
CreationTime time.Time
|
||||||
PubKeyAlgo PublicKeyAlgorithm
|
PubKeyAlgo PublicKeyAlgorithm
|
||||||
PublicKey interface{} // Either a *rsa.PublicKey or *dsa.PublicKey
|
PublicKey interface{} // Either a *rsa.PublicKey or *dsa.PublicKey
|
||||||
Fingerprint [20]byte
|
Fingerprint [20]byte
|
||||||
@ -38,9 +39,9 @@ func fromBig(n *big.Int) parsedMPI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewRSAPublicKey returns a PublicKey that wraps the given rsa.PublicKey.
|
// NewRSAPublicKey returns a PublicKey that wraps the given rsa.PublicKey.
|
||||||
func NewRSAPublicKey(creationTimeSecs uint32, pub *rsa.PublicKey, isSubkey bool) *PublicKey {
|
func NewRSAPublicKey(creationTime time.Time, pub *rsa.PublicKey, isSubkey bool) *PublicKey {
|
||||||
pk := &PublicKey{
|
pk := &PublicKey{
|
||||||
CreationTime: creationTimeSecs,
|
CreationTime: creationTime,
|
||||||
PubKeyAlgo: PubKeyAlgoRSA,
|
PubKeyAlgo: PubKeyAlgoRSA,
|
||||||
PublicKey: pub,
|
PublicKey: pub,
|
||||||
IsSubkey: isSubkey,
|
IsSubkey: isSubkey,
|
||||||
@ -62,7 +63,7 @@ func (pk *PublicKey) parse(r io.Reader) (err error) {
|
|||||||
if buf[0] != 4 {
|
if buf[0] != 4 {
|
||||||
return error_.UnsupportedError("public key version")
|
return error_.UnsupportedError("public key version")
|
||||||
}
|
}
|
||||||
pk.CreationTime = uint32(buf[1])<<24 | uint32(buf[2])<<16 | uint32(buf[3])<<8 | uint32(buf[4])
|
pk.CreationTime = time.Unix(int64(uint32(buf[1])<<24|uint32(buf[2])<<16|uint32(buf[3])<<8|uint32(buf[4])), 0)
|
||||||
pk.PubKeyAlgo = PublicKeyAlgorithm(buf[5])
|
pk.PubKeyAlgo = PublicKeyAlgorithm(buf[5])
|
||||||
switch pk.PubKeyAlgo {
|
switch pk.PubKeyAlgo {
|
||||||
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
|
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
|
||||||
@ -234,10 +235,11 @@ func (pk *PublicKey) Serialize(w io.Writer) (err error) {
|
|||||||
func (pk *PublicKey) serializeWithoutHeaders(w io.Writer) (err error) {
|
func (pk *PublicKey) serializeWithoutHeaders(w io.Writer) (err error) {
|
||||||
var buf [6]byte
|
var buf [6]byte
|
||||||
buf[0] = 4
|
buf[0] = 4
|
||||||
buf[1] = byte(pk.CreationTime >> 24)
|
t := uint32(pk.CreationTime.Unix())
|
||||||
buf[2] = byte(pk.CreationTime >> 16)
|
buf[1] = byte(t >> 24)
|
||||||
buf[3] = byte(pk.CreationTime >> 8)
|
buf[2] = byte(t >> 16)
|
||||||
buf[4] = byte(pk.CreationTime)
|
buf[3] = byte(t >> 8)
|
||||||
|
buf[4] = byte(t)
|
||||||
buf[5] = byte(pk.PubKeyAlgo)
|
buf[5] = byte(pk.PubKeyAlgo)
|
||||||
|
|
||||||
_, err = w.Write(buf[:])
|
_, err = w.Write(buf[:])
|
||||||
|
@ -8,19 +8,20 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var pubKeyTests = []struct {
|
var pubKeyTests = []struct {
|
||||||
hexData string
|
hexData string
|
||||||
hexFingerprint string
|
hexFingerprint string
|
||||||
creationTime uint32
|
creationTime time.Time
|
||||||
pubKeyAlgo PublicKeyAlgorithm
|
pubKeyAlgo PublicKeyAlgorithm
|
||||||
keyId uint64
|
keyId uint64
|
||||||
keyIdString string
|
keyIdString string
|
||||||
keyIdShort string
|
keyIdShort string
|
||||||
}{
|
}{
|
||||||
{rsaPkDataHex, rsaFingerprintHex, 0x4d3c5c10, PubKeyAlgoRSA, 0xa34d7e18c20c31bb, "A34D7E18C20C31BB", "C20C31BB"},
|
{rsaPkDataHex, rsaFingerprintHex, time.Unix(0x4d3c5c10, 0), PubKeyAlgoRSA, 0xa34d7e18c20c31bb, "A34D7E18C20C31BB", "C20C31BB"},
|
||||||
{dsaPkDataHex, dsaFingerprintHex, 0x4d432f89, PubKeyAlgoDSA, 0x8e8fbe54062f19ed, "8E8FBE54062F19ED", "062F19ED"},
|
{dsaPkDataHex, dsaFingerprintHex, time.Unix(0x4d432f89, 0), PubKeyAlgoDSA, 0x8e8fbe54062f19ed, "8E8FBE54062F19ED", "062F19ED"},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPublicKeyRead(t *testing.T) {
|
func TestPublicKeyRead(t *testing.T) {
|
||||||
@ -38,8 +39,8 @@ func TestPublicKeyRead(t *testing.T) {
|
|||||||
if pk.PubKeyAlgo != test.pubKeyAlgo {
|
if pk.PubKeyAlgo != test.pubKeyAlgo {
|
||||||
t.Errorf("#%d: bad public key algorithm got:%x want:%x", i, pk.PubKeyAlgo, test.pubKeyAlgo)
|
t.Errorf("#%d: bad public key algorithm got:%x want:%x", i, pk.PubKeyAlgo, test.pubKeyAlgo)
|
||||||
}
|
}
|
||||||
if pk.CreationTime != test.creationTime {
|
if !pk.CreationTime.Equal(test.creationTime) {
|
||||||
t.Errorf("#%d: bad creation time got:%x want:%x", i, pk.CreationTime, test.creationTime)
|
t.Errorf("#%d: bad creation time got:%v want:%v", i, pk.CreationTime, test.creationTime)
|
||||||
}
|
}
|
||||||
expectedFingerprint, _ := hex.DecodeString(test.hexFingerprint)
|
expectedFingerprint, _ := hex.DecodeString(test.hexFingerprint)
|
||||||
if !bytes.Equal(expectedFingerprint, pk.Fingerprint[:]) {
|
if !bytes.Equal(expectedFingerprint, pk.Fingerprint[:]) {
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
"hash"
|
"hash"
|
||||||
"io"
|
"io"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Signature represents a signature. See RFC 4880, section 5.2.
|
// Signature represents a signature. See RFC 4880, section 5.2.
|
||||||
@ -28,7 +29,7 @@ type Signature struct {
|
|||||||
// HashTag contains the first two bytes of the hash for fast rejection
|
// HashTag contains the first two bytes of the hash for fast rejection
|
||||||
// of bad signed data.
|
// of bad signed data.
|
||||||
HashTag [2]byte
|
HashTag [2]byte
|
||||||
CreationTime uint32 // Unix epoch time
|
CreationTime time.Time
|
||||||
|
|
||||||
RSASignature parsedMPI
|
RSASignature parsedMPI
|
||||||
DSASigR, DSASigS parsedMPI
|
DSASigR, DSASigS parsedMPI
|
||||||
@ -151,7 +152,7 @@ func parseSignatureSubpackets(sig *Signature, subpackets []byte, isHashed bool)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if sig.CreationTime == 0 {
|
if sig.CreationTime.IsZero() {
|
||||||
err = error_.StructuralError("no creation time in signature")
|
err = error_.StructuralError("no creation time in signature")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,7 +224,12 @@ func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (r
|
|||||||
err = error_.StructuralError("signature creation time not four bytes")
|
err = error_.StructuralError("signature creation time not four bytes")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sig.CreationTime = binary.BigEndian.Uint32(subpacket)
|
t := binary.BigEndian.Uint32(subpacket)
|
||||||
|
if t == 0 {
|
||||||
|
sig.CreationTime = time.Time{}
|
||||||
|
} else {
|
||||||
|
sig.CreationTime = time.Unix(int64(t), 0)
|
||||||
|
}
|
||||||
case signatureExpirationSubpacket:
|
case signatureExpirationSubpacket:
|
||||||
// Signature expiration time, section 5.2.3.10
|
// Signature expiration time, section 5.2.3.10
|
||||||
if !isHashed {
|
if !isHashed {
|
||||||
@ -541,10 +547,7 @@ type outputSubpacket struct {
|
|||||||
|
|
||||||
func (sig *Signature) buildSubpackets() (subpackets []outputSubpacket) {
|
func (sig *Signature) buildSubpackets() (subpackets []outputSubpacket) {
|
||||||
creationTime := make([]byte, 4)
|
creationTime := make([]byte, 4)
|
||||||
creationTime[0] = byte(sig.CreationTime >> 24)
|
binary.BigEndian.PutUint32(creationTime, uint32(sig.CreationTime.Unix()))
|
||||||
creationTime[1] = byte(sig.CreationTime >> 16)
|
|
||||||
creationTime[2] = byte(sig.CreationTime >> 8)
|
|
||||||
creationTime[3] = byte(sig.CreationTime)
|
|
||||||
subpackets = append(subpackets, outputSubpacket{true, creationTimeSubpacket, false, creationTime})
|
subpackets = append(subpackets, outputSubpacket{true, creationTimeSubpacket, false, creationTime})
|
||||||
|
|
||||||
if sig.IssuerKeyId != nil {
|
if sig.IssuerKeyId != nil {
|
||||||
|
@ -68,7 +68,7 @@ func detachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.S
|
|||||||
sig.SigType = sigType
|
sig.SigType = sigType
|
||||||
sig.PubKeyAlgo = signer.PrivateKey.PubKeyAlgo
|
sig.PubKeyAlgo = signer.PrivateKey.PubKeyAlgo
|
||||||
sig.Hash = crypto.SHA256
|
sig.Hash = crypto.SHA256
|
||||||
sig.CreationTime = uint32(time.Seconds())
|
sig.CreationTime = time.Now()
|
||||||
sig.IssuerKeyId = &signer.PrivateKey.KeyId
|
sig.IssuerKeyId = &signer.PrivateKey.KeyId
|
||||||
|
|
||||||
h, wrappedHash, err := hashForSignature(sig.Hash, sig.SigType)
|
h, wrappedHash, err := hashForSignature(sig.Hash, sig.SigType)
|
||||||
@ -95,8 +95,8 @@ type FileHints struct {
|
|||||||
// file should not be written to disk. It may be equal to "_CONSOLE" to
|
// file should not be written to disk. It may be equal to "_CONSOLE" to
|
||||||
// suggest the data should not be written to disk.
|
// suggest the data should not be written to disk.
|
||||||
FileName string
|
FileName string
|
||||||
// EpochSeconds contains the modification time of the file, or 0 if not applicable.
|
// ModTime contains the modification time of the file, or the zero time if not applicable.
|
||||||
EpochSeconds uint32
|
ModTime time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
// SymmetricallyEncrypt acts like gpg -c: it encrypts a file with a passphrase.
|
// SymmetricallyEncrypt acts like gpg -c: it encrypts a file with a passphrase.
|
||||||
@ -115,7 +115,11 @@ func SymmetricallyEncrypt(ciphertext io.Writer, passphrase []byte, hints *FileHi
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, hints.EpochSeconds)
|
var epochSeconds uint32
|
||||||
|
if !hints.ModTime.IsZero() {
|
||||||
|
epochSeconds = uint32(hints.ModTime.Unix())
|
||||||
|
}
|
||||||
|
return packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, epochSeconds)
|
||||||
}
|
}
|
||||||
|
|
||||||
// intersectPreferences mutates and returns a prefix of a that contains only
|
// intersectPreferences mutates and returns a prefix of a that contains only
|
||||||
@ -243,7 +247,11 @@ func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHint
|
|||||||
w = noOpCloser{encryptedData}
|
w = noOpCloser{encryptedData}
|
||||||
|
|
||||||
}
|
}
|
||||||
literalData, err := packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, hints.EpochSeconds)
|
var epochSeconds uint32
|
||||||
|
if !hints.ModTime.IsZero() {
|
||||||
|
epochSeconds = uint32(hints.ModTime.Unix())
|
||||||
|
}
|
||||||
|
literalData, err := packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, epochSeconds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -275,7 +283,7 @@ func (s signatureWriter) Close() error {
|
|||||||
SigType: packet.SigTypeBinary,
|
SigType: packet.SigTypeBinary,
|
||||||
PubKeyAlgo: s.signer.PubKeyAlgo,
|
PubKeyAlgo: s.signer.PubKeyAlgo,
|
||||||
Hash: s.hashType,
|
Hash: s.hashType,
|
||||||
CreationTime: uint32(time.Seconds()),
|
CreationTime: time.Now(),
|
||||||
IssuerKeyId: &s.signer.KeyId,
|
IssuerKeyId: &s.signer.KeyId,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ func TestNewEntity(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
e, err := NewEntity(rand.Reader, time.Seconds(), "Test User", "test", "test@example.com")
|
e, err := NewEntity(rand.Reader, time.Now(), "Test User", "test", "test@example.com")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("failed to create entity: %s", err)
|
t.Errorf("failed to create entity: %s", err)
|
||||||
return
|
return
|
||||||
|
@ -100,7 +100,7 @@ func (r *reader) Read(b []byte) (n int, err error) {
|
|||||||
// t = encrypt(time)
|
// t = encrypt(time)
|
||||||
// dst = encrypt(t^seed)
|
// dst = encrypt(t^seed)
|
||||||
// seed = encrypt(t^dst)
|
// seed = encrypt(t^dst)
|
||||||
ns := time.Nanoseconds()
|
ns := time.Now().UnixNano()
|
||||||
r.time[0] = byte(ns >> 56)
|
r.time[0] = byte(ns >> 56)
|
||||||
r.time[1] = byte(ns >> 48)
|
r.time[1] = byte(ns >> 48)
|
||||||
r.time[2] = byte(ns >> 40)
|
r.time[2] = byte(ns >> 40)
|
||||||
|
@ -121,7 +121,7 @@ type Config struct {
|
|||||||
|
|
||||||
// Time returns the current time as the number of seconds since the epoch.
|
// Time returns the current time as the number of seconds since the epoch.
|
||||||
// If Time is nil, TLS uses the system time.Seconds.
|
// If Time is nil, TLS uses the system time.Seconds.
|
||||||
Time func() int64
|
Time func() time.Time
|
||||||
|
|
||||||
// Certificates contains one or more certificate chains
|
// Certificates contains one or more certificate chains
|
||||||
// to present to the other side of the connection.
|
// to present to the other side of the connection.
|
||||||
@ -175,10 +175,10 @@ func (c *Config) rand() io.Reader {
|
|||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) time() int64 {
|
func (c *Config) time() time.Time {
|
||||||
t := c.Time
|
t := c.Time
|
||||||
if t == nil {
|
if t == nil {
|
||||||
t = time.Seconds
|
t = time.Now
|
||||||
}
|
}
|
||||||
return t()
|
return t()
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ func (c *Conn) clientHandshake() error {
|
|||||||
nextProtoNeg: len(c.config.NextProtos) > 0,
|
nextProtoNeg: len(c.config.NextProtos) > 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
t := uint32(c.config.time())
|
t := uint32(c.config.time().Unix())
|
||||||
hello.random[0] = byte(t >> 24)
|
hello.random[0] = byte(t >> 24)
|
||||||
hello.random[1] = byte(t >> 16)
|
hello.random[1] = byte(t >> 16)
|
||||||
hello.random[2] = byte(t >> 8)
|
hello.random[2] = byte(t >> 8)
|
||||||
|
@ -95,7 +95,7 @@ FindCipherSuite:
|
|||||||
|
|
||||||
hello.vers = vers
|
hello.vers = vers
|
||||||
hello.cipherSuite = suite.id
|
hello.cipherSuite = suite.id
|
||||||
t := uint32(config.time())
|
t := uint32(config.time().Unix())
|
||||||
hello.random = make([]byte, 32)
|
hello.random = make([]byte, 32)
|
||||||
hello.random[0] = byte(t >> 24)
|
hello.random[0] = byte(t >> 24)
|
||||||
hello.random[1] = byte(t >> 16)
|
hello.random[1] = byte(t >> 16)
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type zeroSource struct{}
|
type zeroSource struct{}
|
||||||
@ -31,7 +32,7 @@ var testConfig *Config
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
testConfig = new(Config)
|
testConfig = new(Config)
|
||||||
testConfig.Time = func() int64 { return 0 }
|
testConfig.Time = func() time.Time { return time.Unix(0, 0) }
|
||||||
testConfig.Rand = zeroSource{}
|
testConfig.Rand = zeroSource{}
|
||||||
testConfig.Certificates = make([]Certificate, 1)
|
testConfig.Certificates = make([]Certificate, 1)
|
||||||
testConfig.Certificates[0].Certificate = [][]byte{testCertificate}
|
testConfig.Certificates[0].Certificate = [][]byte{testCertificate}
|
||||||
|
@ -142,10 +142,9 @@ type CertificateList struct {
|
|||||||
SignatureValue asn1.BitString
|
SignatureValue asn1.BitString
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasExpired returns true iff currentTimeSeconds is past the expiry time of
|
// HasExpired returns true iff now is past the expiry time of certList.
|
||||||
// certList.
|
func (certList *CertificateList) HasExpired(now time.Time) bool {
|
||||||
func (certList *CertificateList) HasExpired(currentTimeSeconds int64) bool {
|
return now.After(certList.TBSCertList.NextUpdate)
|
||||||
return certList.TBSCertList.NextUpdate.Seconds() <= currentTimeSeconds
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TBSCertificateList represents the ASN.1 structure of the same name. See RFC
|
// TBSCertificateList represents the ASN.1 structure of the same name. See RFC
|
||||||
@ -155,8 +154,8 @@ type TBSCertificateList struct {
|
|||||||
Version int `asn1:"optional,default:2"`
|
Version int `asn1:"optional,default:2"`
|
||||||
Signature AlgorithmIdentifier
|
Signature AlgorithmIdentifier
|
||||||
Issuer RDNSequence
|
Issuer RDNSequence
|
||||||
ThisUpdate *time.Time
|
ThisUpdate time.Time
|
||||||
NextUpdate *time.Time
|
NextUpdate time.Time
|
||||||
RevokedCertificates []RevokedCertificate `asn1:"optional"`
|
RevokedCertificates []RevokedCertificate `asn1:"optional"`
|
||||||
Extensions []Extension `asn1:"tag:0,optional,explicit"`
|
Extensions []Extension `asn1:"tag:0,optional,explicit"`
|
||||||
}
|
}
|
||||||
@ -165,6 +164,6 @@ type TBSCertificateList struct {
|
|||||||
// 5280, section 5.1.
|
// 5280, section 5.1.
|
||||||
type RevokedCertificate struct {
|
type RevokedCertificate struct {
|
||||||
SerialNumber *big.Int
|
SerialNumber *big.Int
|
||||||
RevocationTime *time.Time
|
RevocationTime time.Time
|
||||||
Extensions []Extension `asn1:"optional"`
|
Extensions []Extension `asn1:"optional"`
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ type VerifyOptions struct {
|
|||||||
DNSName string
|
DNSName string
|
||||||
Intermediates *CertPool
|
Intermediates *CertPool
|
||||||
Roots *CertPool
|
Roots *CertPool
|
||||||
CurrentTime int64 // if 0, the current system time is used.
|
CurrentTime time.Time // if zero, the current time is used
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -87,8 +87,11 @@ const (
|
|||||||
|
|
||||||
// isValid performs validity checks on the c.
|
// isValid performs validity checks on the c.
|
||||||
func (c *Certificate) isValid(certType int, opts *VerifyOptions) error {
|
func (c *Certificate) isValid(certType int, opts *VerifyOptions) error {
|
||||||
if opts.CurrentTime < c.NotBefore.Seconds() ||
|
now := opts.CurrentTime
|
||||||
opts.CurrentTime > c.NotAfter.Seconds() {
|
if now.IsZero() {
|
||||||
|
now = time.Now()
|
||||||
|
}
|
||||||
|
if now.Before(c.NotBefore) || now.After(c.NotAfter) {
|
||||||
return CertificateInvalidError{c, Expired}
|
return CertificateInvalidError{c, Expired}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,9 +139,6 @@ func (c *Certificate) isValid(certType int, opts *VerifyOptions) error {
|
|||||||
//
|
//
|
||||||
// WARNING: this doesn't do any revocation checking.
|
// WARNING: this doesn't do any revocation checking.
|
||||||
func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) {
|
func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) {
|
||||||
if opts.CurrentTime == 0 {
|
|
||||||
opts.CurrentTime = time.Seconds()
|
|
||||||
}
|
|
||||||
err = c.isValid(leafCertificate, &opts)
|
err = c.isValid(leafCertificate, &opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type verifyTest struct {
|
type verifyTest struct {
|
||||||
@ -133,7 +134,7 @@ func TestVerify(t *testing.T) {
|
|||||||
Roots: NewCertPool(),
|
Roots: NewCertPool(),
|
||||||
Intermediates: NewCertPool(),
|
Intermediates: NewCertPool(),
|
||||||
DNSName: test.dnsName,
|
DNSName: test.dnsName,
|
||||||
CurrentTime: test.currentTime,
|
CurrentTime: time.Unix(test.currentTime, 0),
|
||||||
}
|
}
|
||||||
|
|
||||||
for j, root := range test.roots {
|
for j, root := range test.roots {
|
||||||
|
@ -107,7 +107,7 @@ type dsaSignature struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type validity struct {
|
type validity struct {
|
||||||
NotBefore, NotAfter *time.Time
|
NotBefore, NotAfter time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
type publicKeyInfo struct {
|
type publicKeyInfo struct {
|
||||||
@ -303,7 +303,7 @@ type Certificate struct {
|
|||||||
SerialNumber *big.Int
|
SerialNumber *big.Int
|
||||||
Issuer pkix.Name
|
Issuer pkix.Name
|
||||||
Subject pkix.Name
|
Subject pkix.Name
|
||||||
NotBefore, NotAfter *time.Time // Validity bounds.
|
NotBefore, NotAfter time.Time // Validity bounds.
|
||||||
KeyUsage KeyUsage
|
KeyUsage KeyUsage
|
||||||
|
|
||||||
ExtKeyUsage []ExtKeyUsage // Sequence of extended key usages.
|
ExtKeyUsage []ExtKeyUsage // Sequence of extended key usages.
|
||||||
@ -1005,7 +1005,7 @@ func ParseDERCRL(derBytes []byte) (certList *pkix.CertificateList, err error) {
|
|||||||
|
|
||||||
// CreateCRL returns a DER encoded CRL, signed by this Certificate, that
|
// CreateCRL returns a DER encoded CRL, signed by this Certificate, that
|
||||||
// contains the given list of revoked certificates.
|
// contains the given list of revoked certificates.
|
||||||
func (c *Certificate) CreateCRL(rand io.Reader, priv *rsa.PrivateKey, revokedCerts []pkix.RevokedCertificate, now, expiry *time.Time) (crlBytes []byte, err error) {
|
func (c *Certificate) CreateCRL(rand io.Reader, priv *rsa.PrivateKey, revokedCerts []pkix.RevokedCertificate, now, expiry time.Time) (crlBytes []byte, err error) {
|
||||||
tbsCertList := pkix.TBSCertificateList{
|
tbsCertList := pkix.TBSCertificateList{
|
||||||
Version: 2,
|
Version: 2,
|
||||||
Signature: pkix.AlgorithmIdentifier{
|
Signature: pkix.AlgorithmIdentifier{
|
||||||
|
@ -250,8 +250,8 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
|
|||||||
CommonName: commonName,
|
CommonName: commonName,
|
||||||
Organization: []string{"Acme Co"},
|
Organization: []string{"Acme Co"},
|
||||||
},
|
},
|
||||||
NotBefore: time.SecondsToUTC(1000),
|
NotBefore: time.Unix(1000, 0),
|
||||||
NotAfter: time.SecondsToUTC(100000),
|
NotAfter: time.Unix(100000, 0),
|
||||||
|
|
||||||
SubjectKeyId: []byte{1, 2, 3, 4},
|
SubjectKeyId: []byte{1, 2, 3, 4},
|
||||||
KeyUsage: KeyUsageCertSign,
|
KeyUsage: KeyUsageCertSign,
|
||||||
@ -396,8 +396,8 @@ func TestCRLCreation(t *testing.T) {
|
|||||||
block, _ = pem.Decode([]byte(pemCertificate))
|
block, _ = pem.Decode([]byte(pemCertificate))
|
||||||
cert, _ := ParseCertificate(block.Bytes)
|
cert, _ := ParseCertificate(block.Bytes)
|
||||||
|
|
||||||
now := time.SecondsToUTC(1000)
|
now := time.Unix(1000, 0)
|
||||||
expiry := time.SecondsToUTC(10000)
|
expiry := time.Unix(10000, 0)
|
||||||
|
|
||||||
revokedCerts := []pkix.RevokedCertificate{
|
revokedCerts := []pkix.RevokedCertificate{
|
||||||
{
|
{
|
||||||
@ -443,7 +443,7 @@ func TestParseDERCRL(t *testing.T) {
|
|||||||
t.Errorf("bad number of revoked certificates. got: %d want: %d", numCerts, expected)
|
t.Errorf("bad number of revoked certificates. got: %d want: %d", numCerts, expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
if certList.HasExpired(1302517272) {
|
if certList.HasExpired(time.Unix(1302517272, 0)) {
|
||||||
t.Errorf("CRL has expired (but shouldn't have)")
|
t.Errorf("CRL has expired (but shouldn't have)")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -463,7 +463,7 @@ func TestParsePEMCRL(t *testing.T) {
|
|||||||
t.Errorf("bad number of revoked certificates. got: %d want: %d", numCerts, expected)
|
t.Errorf("bad number of revoked certificates. got: %d want: %d", numCerts, expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
if certList.HasExpired(1302517272) {
|
if certList.HasExpired(time.Unix(1302517272, 0)) {
|
||||||
t.Errorf("CRL has expired (but shouldn't have)")
|
t.Errorf("CRL has expired (but shouldn't have)")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,7 +247,7 @@ func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, err error)
|
|||||||
|
|
||||||
// UTCTime
|
// UTCTime
|
||||||
|
|
||||||
func parseUTCTime(bytes []byte) (ret *time.Time, err error) {
|
func parseUTCTime(bytes []byte) (ret time.Time, err error) {
|
||||||
s := string(bytes)
|
s := string(bytes)
|
||||||
ret, err = time.Parse("0601021504Z0700", s)
|
ret, err = time.Parse("0601021504Z0700", s)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -259,7 +259,7 @@ func parseUTCTime(bytes []byte) (ret *time.Time, err error) {
|
|||||||
|
|
||||||
// parseGeneralizedTime parses the GeneralizedTime from the given byte slice
|
// parseGeneralizedTime parses the GeneralizedTime from the given byte slice
|
||||||
// and returns the resulting time.
|
// and returns the resulting time.
|
||||||
func parseGeneralizedTime(bytes []byte) (ret *time.Time, err error) {
|
func parseGeneralizedTime(bytes []byte) (ret time.Time, err error) {
|
||||||
return time.Parse("20060102150405Z0700", string(bytes))
|
return time.Parse("20060102150405Z0700", string(bytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -450,7 +450,7 @@ var (
|
|||||||
objectIdentifierType = reflect.TypeOf(ObjectIdentifier{})
|
objectIdentifierType = reflect.TypeOf(ObjectIdentifier{})
|
||||||
enumeratedType = reflect.TypeOf(Enumerated(0))
|
enumeratedType = reflect.TypeOf(Enumerated(0))
|
||||||
flagType = reflect.TypeOf(Flag(false))
|
flagType = reflect.TypeOf(Flag(false))
|
||||||
timeType = reflect.TypeOf(&time.Time{})
|
timeType = reflect.TypeOf(time.Time{})
|
||||||
rawValueType = reflect.TypeOf(RawValue{})
|
rawValueType = reflect.TypeOf(RawValue{})
|
||||||
rawContentsType = reflect.TypeOf(RawContent(nil))
|
rawContentsType = reflect.TypeOf(RawContent(nil))
|
||||||
bigIntType = reflect.TypeOf(new(big.Int))
|
bigIntType = reflect.TypeOf(new(big.Int))
|
||||||
@ -647,7 +647,7 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
|
|||||||
err = err1
|
err = err1
|
||||||
return
|
return
|
||||||
case timeType:
|
case timeType:
|
||||||
var time *time.Time
|
var time time.Time
|
||||||
var err1 error
|
var err1 error
|
||||||
if universalTag == tagUTCTime {
|
if universalTag == tagUTCTime {
|
||||||
time, err1 = parseUTCTime(innerBytes)
|
time, err1 = parseUTCTime(innerBytes)
|
||||||
@ -799,7 +799,7 @@ func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) {
|
|||||||
//
|
//
|
||||||
// An ASN.1 ENUMERATED can be written to an Enumerated.
|
// An ASN.1 ENUMERATED can be written to an Enumerated.
|
||||||
//
|
//
|
||||||
// An ASN.1 UTCTIME or GENERALIZEDTIME can be written to a *time.Time.
|
// An ASN.1 UTCTIME or GENERALIZEDTIME can be written to a time.Time.
|
||||||
//
|
//
|
||||||
// An ASN.1 PrintableString or IA5String can be written to a string.
|
// An ASN.1 PrintableString or IA5String can be written to a string.
|
||||||
//
|
//
|
||||||
|
@ -202,22 +202,22 @@ func TestObjectIdentifier(t *testing.T) {
|
|||||||
type timeTest struct {
|
type timeTest struct {
|
||||||
in string
|
in string
|
||||||
ok bool
|
ok bool
|
||||||
out *time.Time
|
out time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
var utcTestData = []timeTest{
|
var utcTestData = []timeTest{
|
||||||
{"910506164540-0700", true, &time.Time{1991, 05, 06, 16, 45, 40, 0, -7 * 60 * 60, ""}},
|
{"910506164540-0700", true, time.Date(1991, 05, 06, 16, 45, 40, 0, time.FixedZone("", -7*60*60))},
|
||||||
{"910506164540+0730", true, &time.Time{1991, 05, 06, 16, 45, 40, 0, 7*60*60 + 30*60, ""}},
|
{"910506164540+0730", true, time.Date(1991, 05, 06, 16, 45, 40, 0, time.FixedZone("", 7*60*60+30*60))},
|
||||||
{"910506234540Z", true, &time.Time{1991, 05, 06, 23, 45, 40, 0, 0, "UTC"}},
|
{"910506234540Z", true, time.Date(1991, 05, 06, 23, 45, 40, 0, time.UTC)},
|
||||||
{"9105062345Z", true, &time.Time{1991, 05, 06, 23, 45, 0, 0, 0, "UTC"}},
|
{"9105062345Z", true, time.Date(1991, 05, 06, 23, 45, 0, 0, time.UTC)},
|
||||||
{"a10506234540Z", false, nil},
|
{"a10506234540Z", false, time.Time{}},
|
||||||
{"91a506234540Z", false, nil},
|
{"91a506234540Z", false, time.Time{}},
|
||||||
{"9105a6234540Z", false, nil},
|
{"9105a6234540Z", false, time.Time{}},
|
||||||
{"910506a34540Z", false, nil},
|
{"910506a34540Z", false, time.Time{}},
|
||||||
{"910506334a40Z", false, nil},
|
{"910506334a40Z", false, time.Time{}},
|
||||||
{"91050633444aZ", false, nil},
|
{"91050633444aZ", false, time.Time{}},
|
||||||
{"910506334461Z", false, nil},
|
{"910506334461Z", false, time.Time{}},
|
||||||
{"910506334400Za", false, nil},
|
{"910506334400Za", false, time.Time{}},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUTCTime(t *testing.T) {
|
func TestUTCTime(t *testing.T) {
|
||||||
@ -235,10 +235,10 @@ func TestUTCTime(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var generalizedTimeTestData = []timeTest{
|
var generalizedTimeTestData = []timeTest{
|
||||||
{"20100102030405Z", true, &time.Time{2010, 01, 02, 03, 04, 05, 0, 0, "UTC"}},
|
{"20100102030405Z", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.UTC)},
|
||||||
{"20100102030405", false, nil},
|
{"20100102030405", false, time.Time{}},
|
||||||
{"20100102030405+0607", true, &time.Time{2010, 01, 02, 03, 04, 05, 0, 6*60*60 + 7*60, ""}},
|
{"20100102030405+0607", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.FixedZone("", 6*60*60+7*60))},
|
||||||
{"20100102030405-0607", true, &time.Time{2010, 01, 02, 03, 04, 05, 0, -6*60*60 - 7*60, ""}},
|
{"20100102030405-0607", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.FixedZone("", -6*60*60-7*60))},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGeneralizedTime(t *testing.T) {
|
func TestGeneralizedTime(t *testing.T) {
|
||||||
@ -407,7 +407,7 @@ type AttributeTypeAndValue struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Validity struct {
|
type Validity struct {
|
||||||
NotBefore, NotAfter *time.Time
|
NotBefore, NotAfter time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
type PublicKeyInfo struct {
|
type PublicKeyInfo struct {
|
||||||
@ -475,7 +475,10 @@ var derEncodedSelfSignedCert = Certificate{
|
|||||||
RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 3}, Value: "false.example.com"}},
|
RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 3}, Value: "false.example.com"}},
|
||||||
RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}, Value: "false@example.com"}},
|
RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}, Value: "false@example.com"}},
|
||||||
},
|
},
|
||||||
Validity: Validity{NotBefore: &time.Time{Year: 2009, Month: 10, Day: 8, Hour: 0, Minute: 25, Second: 53, ZoneOffset: 0, Zone: "UTC"}, NotAfter: &time.Time{Year: 2010, Month: 10, Day: 8, Hour: 0, Minute: 25, Second: 53, ZoneOffset: 0, Zone: "UTC"}},
|
Validity: Validity{
|
||||||
|
NotBefore: time.Date(2009, 10, 8, 00, 25, 53, 0, time.UTC),
|
||||||
|
NotAfter: time.Date(2010, 10, 8, 00, 25, 53, 0, time.UTC),
|
||||||
|
},
|
||||||
Subject: RDNSequence{
|
Subject: RDNSequence{
|
||||||
RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 6}, Value: "XX"}},
|
RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 6}, Value: "XX"}},
|
||||||
RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 8}, Value: "Some-State"}},
|
RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 8}, Value: "Some-State"}},
|
||||||
|
@ -288,52 +288,58 @@ func marshalTwoDigits(out *forkableWriter, v int) (err error) {
|
|||||||
return out.WriteByte(byte('0' + v%10))
|
return out.WriteByte(byte('0' + v%10))
|
||||||
}
|
}
|
||||||
|
|
||||||
func marshalUTCTime(out *forkableWriter, t *time.Time) (err error) {
|
func marshalUTCTime(out *forkableWriter, t time.Time) (err error) {
|
||||||
|
utc := t.UTC()
|
||||||
|
year, month, day := utc.Date()
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case 1950 <= t.Year && t.Year < 2000:
|
case 1950 <= year && year < 2000:
|
||||||
err = marshalTwoDigits(out, int(t.Year-1900))
|
err = marshalTwoDigits(out, int(year-1900))
|
||||||
case 2000 <= t.Year && t.Year < 2050:
|
case 2000 <= year && year < 2050:
|
||||||
err = marshalTwoDigits(out, int(t.Year-2000))
|
err = marshalTwoDigits(out, int(year-2000))
|
||||||
default:
|
default:
|
||||||
return StructuralError{"Cannot represent time as UTCTime"}
|
return StructuralError{"Cannot represent time as UTCTime"}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = marshalTwoDigits(out, t.Month)
|
err = marshalTwoDigits(out, int(month))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = marshalTwoDigits(out, t.Day)
|
err = marshalTwoDigits(out, day)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = marshalTwoDigits(out, t.Hour)
|
hour, min, sec := utc.Clock()
|
||||||
|
|
||||||
|
err = marshalTwoDigits(out, hour)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = marshalTwoDigits(out, t.Minute)
|
err = marshalTwoDigits(out, min)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = marshalTwoDigits(out, t.Second)
|
err = marshalTwoDigits(out, sec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_, offset := t.Zone()
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case t.ZoneOffset/60 == 0:
|
case offset/60 == 0:
|
||||||
err = out.WriteByte('Z')
|
err = out.WriteByte('Z')
|
||||||
return
|
return
|
||||||
case t.ZoneOffset > 0:
|
case offset > 0:
|
||||||
err = out.WriteByte('+')
|
err = out.WriteByte('+')
|
||||||
case t.ZoneOffset < 0:
|
case offset < 0:
|
||||||
err = out.WriteByte('-')
|
err = out.WriteByte('-')
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -341,7 +347,7 @@ func marshalUTCTime(out *forkableWriter, t *time.Time) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
offsetMinutes := t.ZoneOffset / 60
|
offsetMinutes := offset / 60
|
||||||
if offsetMinutes < 0 {
|
if offsetMinutes < 0 {
|
||||||
offsetMinutes = -offsetMinutes
|
offsetMinutes = -offsetMinutes
|
||||||
}
|
}
|
||||||
@ -366,7 +372,7 @@ func stripTagAndLength(in []byte) []byte {
|
|||||||
func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameters) (err error) {
|
func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameters) (err error) {
|
||||||
switch value.Type() {
|
switch value.Type() {
|
||||||
case timeType:
|
case timeType:
|
||||||
return marshalUTCTime(out, value.Interface().(*time.Time))
|
return marshalUTCTime(out, value.Interface().(time.Time))
|
||||||
case bitStringType:
|
case bitStringType:
|
||||||
return marshalBitString(out, value.Interface().(BitString))
|
return marshalBitString(out, value.Interface().(BitString))
|
||||||
case objectIdentifierType:
|
case objectIdentifierType:
|
||||||
|
@ -51,10 +51,7 @@ type optionalRawValueTest struct {
|
|||||||
|
|
||||||
type testSET []int
|
type testSET []int
|
||||||
|
|
||||||
func setPST(t *time.Time) *time.Time {
|
var PST = time.FixedZone("PST", -8*60*60)
|
||||||
t.ZoneOffset = -28800
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
type marshalTest struct {
|
type marshalTest struct {
|
||||||
in interface{}
|
in interface{}
|
||||||
@ -73,9 +70,9 @@ var marshalTests = []marshalTest{
|
|||||||
{[]byte{1, 2, 3}, "0403010203"},
|
{[]byte{1, 2, 3}, "0403010203"},
|
||||||
{implicitTagTest{64}, "3003850140"},
|
{implicitTagTest{64}, "3003850140"},
|
||||||
{explicitTagTest{64}, "3005a503020140"},
|
{explicitTagTest{64}, "3005a503020140"},
|
||||||
{time.SecondsToUTC(0), "170d3730303130313030303030305a"},
|
{time.Unix(0, 0).UTC(), "170d3730303130313030303030305a"},
|
||||||
{time.SecondsToUTC(1258325776), "170d3039313131353232353631365a"},
|
{time.Unix(1258325776, 0).UTC(), "170d3039313131353232353631365a"},
|
||||||
{setPST(time.SecondsToUTC(1258325776)), "17113039313131353232353631362d30383030"},
|
{time.Unix(1258325776, 0).In(PST), "17113039313131353232353631362d30383030"},
|
||||||
{BitString{[]byte{0x80}, 1}, "03020780"},
|
{BitString{[]byte{0x80}, 1}, "03020780"},
|
||||||
{BitString{[]byte{0x81, 0xf0}, 12}, "03030481f0"},
|
{BitString{[]byte{0x81, 0xf0}, 12}, "03030481f0"},
|
||||||
{ObjectIdentifier([]int{1, 2, 3, 4}), "06032a0304"},
|
{ObjectIdentifier([]int{1, 2, 3, 4}), "06032a0304"},
|
||||||
@ -123,7 +120,8 @@ func TestMarshal(t *testing.T) {
|
|||||||
}
|
}
|
||||||
out, _ := hex.DecodeString(test.out)
|
out, _ := hex.DecodeString(test.out)
|
||||||
if bytes.Compare(out, data) != 0 {
|
if bytes.Compare(out, data) != 0 {
|
||||||
t.Errorf("#%d got: %x want %x", i, data, out)
|
t.Errorf("#%d got: %x want %x\n\t%q\n\t%q", i, data, out, data, out)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,16 +58,16 @@ func testPath(t *testing.T, path string) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
const maxTime = 3e9 // maximum allotted testing time in ns
|
const maxTime = 3 * time.Second
|
||||||
|
|
||||||
func testDir(t *testing.T, dir string, endTime int64) (nimports int) {
|
func testDir(t *testing.T, dir string, endTime time.Time) (nimports int) {
|
||||||
dirname := filepath.Join(pkgRoot, dir)
|
dirname := filepath.Join(pkgRoot, dir)
|
||||||
list, err := ioutil.ReadDir(dirname)
|
list, err := ioutil.ReadDir(dirname)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("testDir(%s): %s", dirname, err)
|
t.Errorf("testDir(%s): %s", dirname, err)
|
||||||
}
|
}
|
||||||
for _, f := range list {
|
for _, f := range list {
|
||||||
if time.Nanoseconds() >= endTime {
|
if time.Now().After(endTime) {
|
||||||
t.Log("testing time used up")
|
t.Log("testing time used up")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -96,6 +96,6 @@ func TestGcImport(t *testing.T) {
|
|||||||
if testPath(t, "./testdata/exports") {
|
if testPath(t, "./testdata/exports") {
|
||||||
nimports++
|
nimports++
|
||||||
}
|
}
|
||||||
nimports += testDir(t, "", time.Nanoseconds()+maxTime) // installed packages
|
nimports += testDir(t, "", time.Now().Add(maxTime)) // installed packages
|
||||||
t.Logf("tested %d imports", nimports)
|
t.Logf("tested %d imports", nimports)
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Build produces a build Script for the given package.
|
// Build produces a build Script for the given package.
|
||||||
@ -150,7 +151,7 @@ func (s *Script) Run() error {
|
|||||||
|
|
||||||
// Stale returns true if the build's inputs are newer than its outputs.
|
// Stale returns true if the build's inputs are newer than its outputs.
|
||||||
func (s *Script) Stale() bool {
|
func (s *Script) Stale() bool {
|
||||||
var latest int64
|
var latest time.Time
|
||||||
// get latest mtime of outputs
|
// get latest mtime of outputs
|
||||||
for _, file := range s.Output {
|
for _, file := range s.Output {
|
||||||
fi, err := os.Stat(file)
|
fi, err := os.Stat(file)
|
||||||
@ -158,13 +159,13 @@ func (s *Script) Stale() bool {
|
|||||||
// any error reading output files means stale
|
// any error reading output files means stale
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if m := fi.Mtime_ns; m > latest {
|
if fi.ModTime.After(latest) {
|
||||||
latest = m
|
latest = fi.ModTime
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, file := range s.Input {
|
for _, file := range s.Input {
|
||||||
fi, err := os.Stat(file)
|
fi, err := os.Stat(file)
|
||||||
if err != nil || fi.Mtime_ns > latest {
|
if err != nil || fi.ModTime.After(latest) {
|
||||||
// any error reading input files means stale
|
// any error reading input files means stale
|
||||||
// (attempt to rebuild to figure out why)
|
// (attempt to rebuild to figure out why)
|
||||||
return true
|
return true
|
||||||
|
@ -18,7 +18,7 @@ import (
|
|||||||
var rand uint32
|
var rand uint32
|
||||||
|
|
||||||
func reseed() uint32 {
|
func reseed() uint32 {
|
||||||
return uint32(time.Nanoseconds() + int64(os.Getpid()))
|
return uint32(time.Now().UnixNano() + int64(os.Getpid()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func nextSuffix() string {
|
func nextSuffix() string {
|
||||||
|
@ -83,27 +83,28 @@ func itoa(buf *bytes.Buffer, i int, wid int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Logger) formatHeader(buf *bytes.Buffer, ns int64, file string, line int) {
|
func (l *Logger) formatHeader(buf *bytes.Buffer, t time.Time, file string, line int) {
|
||||||
buf.WriteString(l.prefix)
|
buf.WriteString(l.prefix)
|
||||||
if l.flag&(Ldate|Ltime|Lmicroseconds) != 0 {
|
if l.flag&(Ldate|Ltime|Lmicroseconds) != 0 {
|
||||||
t := time.SecondsToLocalTime(ns / 1e9)
|
|
||||||
if l.flag&Ldate != 0 {
|
if l.flag&Ldate != 0 {
|
||||||
itoa(buf, int(t.Year), 4)
|
year, month, day := t.Date()
|
||||||
|
itoa(buf, year, 4)
|
||||||
buf.WriteByte('/')
|
buf.WriteByte('/')
|
||||||
itoa(buf, int(t.Month), 2)
|
itoa(buf, int(month), 2)
|
||||||
buf.WriteByte('/')
|
buf.WriteByte('/')
|
||||||
itoa(buf, int(t.Day), 2)
|
itoa(buf, day, 2)
|
||||||
buf.WriteByte(' ')
|
buf.WriteByte(' ')
|
||||||
}
|
}
|
||||||
if l.flag&(Ltime|Lmicroseconds) != 0 {
|
if l.flag&(Ltime|Lmicroseconds) != 0 {
|
||||||
itoa(buf, int(t.Hour), 2)
|
hour, min, sec := t.Clock()
|
||||||
|
itoa(buf, hour, 2)
|
||||||
buf.WriteByte(':')
|
buf.WriteByte(':')
|
||||||
itoa(buf, int(t.Minute), 2)
|
itoa(buf, min, 2)
|
||||||
buf.WriteByte(':')
|
buf.WriteByte(':')
|
||||||
itoa(buf, int(t.Second), 2)
|
itoa(buf, sec, 2)
|
||||||
if l.flag&Lmicroseconds != 0 {
|
if l.flag&Lmicroseconds != 0 {
|
||||||
buf.WriteByte('.')
|
buf.WriteByte('.')
|
||||||
itoa(buf, int(ns%1e9)/1e3, 6)
|
itoa(buf, t.Nanosecond()/1e3, 6)
|
||||||
}
|
}
|
||||||
buf.WriteByte(' ')
|
buf.WriteByte(' ')
|
||||||
}
|
}
|
||||||
@ -133,7 +134,7 @@ func (l *Logger) formatHeader(buf *bytes.Buffer, ns int64, file string, line int
|
|||||||
// provided for generality, although at the moment on all pre-defined
|
// provided for generality, although at the moment on all pre-defined
|
||||||
// paths it will be 2.
|
// paths it will be 2.
|
||||||
func (l *Logger) Output(calldepth int, s string) error {
|
func (l *Logger) Output(calldepth int, s string) error {
|
||||||
now := time.Nanoseconds() // get this early.
|
now := time.Now() // get this early.
|
||||||
var file string
|
var file string
|
||||||
var line int
|
var line int
|
||||||
l.mu.Lock()
|
l.mu.Lock()
|
||||||
|
@ -22,14 +22,14 @@ import (
|
|||||||
var calibrate = flag.Bool("calibrate", false, "run calibration test")
|
var calibrate = flag.Bool("calibrate", false, "run calibration test")
|
||||||
|
|
||||||
// measure returns the time to run f
|
// measure returns the time to run f
|
||||||
func measure(f func()) int64 {
|
func measure(f func()) time.Duration {
|
||||||
const N = 100
|
const N = 100
|
||||||
start := time.Nanoseconds()
|
start := time.Now()
|
||||||
for i := N; i > 0; i-- {
|
for i := N; i > 0; i-- {
|
||||||
f()
|
f()
|
||||||
}
|
}
|
||||||
stop := time.Nanoseconds()
|
stop := time.Now()
|
||||||
return (stop - start) / N
|
return stop.Sub(start) / N
|
||||||
}
|
}
|
||||||
|
|
||||||
func computeThresholds() {
|
func computeThresholds() {
|
||||||
@ -46,7 +46,7 @@ func computeThresholds() {
|
|||||||
th1 := -1
|
th1 := -1
|
||||||
th2 := -1
|
th2 := -1
|
||||||
|
|
||||||
var deltaOld int64
|
var deltaOld time.Duration
|
||||||
for count := -1; count != 0; count-- {
|
for count := -1; count != 0; count-- {
|
||||||
// determine Tk, the work load execution time using Karatsuba multiplication
|
// determine Tk, the work load execution time using Karatsuba multiplication
|
||||||
karatsubaThreshold = n // enable karatsuba
|
karatsubaThreshold = n // enable karatsuba
|
||||||
|
@ -29,7 +29,7 @@ func exchange(cfg *dnsConfig, c Conn, name string, qtype uint16) (*dnsMsg, error
|
|||||||
return nil, &DNSError{Err: "name too long", Name: name}
|
return nil, &DNSError{Err: "name too long", Name: name}
|
||||||
}
|
}
|
||||||
out := new(dnsMsg)
|
out := new(dnsMsg)
|
||||||
out.id = uint16(rand.Int()) ^ uint16(time.Nanoseconds())
|
out.id = uint16(rand.Int()) ^ uint16(time.Now().UnixNano())
|
||||||
out.question = []dnsQuestion{
|
out.question = []dnsQuestion{
|
||||||
{name, qtype, dnsClassINET},
|
{name, qtype, dnsClassINET},
|
||||||
}
|
}
|
||||||
|
@ -171,7 +171,7 @@ func (s *pollServer) WakeFD(fd *netFD, mode int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *pollServer) Now() int64 {
|
func (s *pollServer) Now() int64 {
|
||||||
return time.Nanoseconds()
|
return time.Now().UnixNano()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *pollServer) CheckDeadlines() {
|
func (s *pollServer) CheckDeadlines() {
|
||||||
|
@ -172,11 +172,12 @@ func (s *ioSrv) ExecIO(oi anOpIface, deadline_delta int64) (n int, err error) {
|
|||||||
return 0, &OpError{oi.Name(), o.fd.net, o.fd.laddr, e}
|
return 0, &OpError{oi.Name(), o.fd.net, o.fd.laddr, e}
|
||||||
}
|
}
|
||||||
// Wait for our request to complete.
|
// Wait for our request to complete.
|
||||||
|
// TODO(rsc): This should stop the timer.
|
||||||
var r ioResult
|
var r ioResult
|
||||||
if deadline_delta > 0 {
|
if deadline_delta > 0 {
|
||||||
select {
|
select {
|
||||||
case r = <-o.resultc:
|
case r = <-o.resultc:
|
||||||
case <-time.After(deadline_delta):
|
case <-time.After(time.Duration(deadline_delta) * time.Nanosecond):
|
||||||
s.canchan <- oi
|
s.canchan <- oi
|
||||||
<-o.errnoc
|
<-o.errnoc
|
||||||
r = <-o.resultc
|
r = <-o.resultc
|
||||||
|
@ -11,7 +11,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
const cacheMaxAge = int64(300) // 5 minutes.
|
const cacheMaxAge = 5 * time.Minute
|
||||||
|
|
||||||
// hostsPath points to the file with static IP/address entries.
|
// hostsPath points to the file with static IP/address entries.
|
||||||
var hostsPath = "/etc/hosts"
|
var hostsPath = "/etc/hosts"
|
||||||
@ -21,14 +21,14 @@ var hosts struct {
|
|||||||
sync.Mutex
|
sync.Mutex
|
||||||
byName map[string][]string
|
byName map[string][]string
|
||||||
byAddr map[string][]string
|
byAddr map[string][]string
|
||||||
time int64
|
expire time.Time
|
||||||
path string
|
path string
|
||||||
}
|
}
|
||||||
|
|
||||||
func readHosts() {
|
func readHosts() {
|
||||||
now := time.Seconds()
|
now := time.Now()
|
||||||
hp := hostsPath
|
hp := hostsPath
|
||||||
if len(hosts.byName) == 0 || hosts.time+cacheMaxAge <= now || hosts.path != hp {
|
if len(hosts.byName) == 0 || now.After(hosts.expire) || hosts.path != hp {
|
||||||
hs := make(map[string][]string)
|
hs := make(map[string][]string)
|
||||||
is := make(map[string][]string)
|
is := make(map[string][]string)
|
||||||
var file *file
|
var file *file
|
||||||
@ -51,7 +51,7 @@ func readHosts() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Update the data cache.
|
// Update the data cache.
|
||||||
hosts.time = time.Seconds()
|
hosts.expire = time.Now().Add(cacheMaxAge)
|
||||||
hosts.path = hp
|
hosts.path = hp
|
||||||
hosts.byName = hs
|
hosts.byName = hs
|
||||||
hosts.byAddr = is
|
hosts.byAddr = is
|
||||||
|
@ -365,7 +365,7 @@ func TestCopyError(t *testing.T) {
|
|||||||
|
|
||||||
tries := 0
|
tries := 0
|
||||||
for tries < 15 && childRunning() {
|
for tries < 15 && childRunning() {
|
||||||
time.Sleep(50e6 * int64(tries))
|
time.Sleep(50 * time.Millisecond * time.Duration(tries))
|
||||||
tries++
|
tries++
|
||||||
}
|
}
|
||||||
if childRunning() {
|
if childRunning() {
|
||||||
|
@ -115,7 +115,7 @@ func readSetCookies(h Header) []*Cookie {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.Expires = *exptime
|
c.Expires = exptime.UTC()
|
||||||
continue
|
continue
|
||||||
case "path":
|
case "path":
|
||||||
c.Path = val
|
c.Path = val
|
||||||
@ -146,8 +146,8 @@ func (c *Cookie) String() string {
|
|||||||
if len(c.Domain) > 0 {
|
if len(c.Domain) > 0 {
|
||||||
fmt.Fprintf(&b, "; Domain=%s", sanitizeValue(c.Domain))
|
fmt.Fprintf(&b, "; Domain=%s", sanitizeValue(c.Domain))
|
||||||
}
|
}
|
||||||
if len(c.Expires.Zone) > 0 {
|
if c.Expires.Unix() > 0 {
|
||||||
fmt.Fprintf(&b, "; Expires=%s", c.Expires.Format(time.RFC1123))
|
fmt.Fprintf(&b, "; Expires=%s", c.Expires.UTC().Format(time.RFC1123))
|
||||||
}
|
}
|
||||||
if c.MaxAge > 0 {
|
if c.MaxAge > 0 {
|
||||||
fmt.Fprintf(&b, "; Max-Age=%d", c.MaxAge)
|
fmt.Fprintf(&b, "; Max-Age=%d", c.MaxAge)
|
||||||
|
@ -123,7 +123,7 @@ var readSetCookiesTests = []struct {
|
|||||||
Path: "/",
|
Path: "/",
|
||||||
Domain: ".google.ch",
|
Domain: ".google.ch",
|
||||||
HttpOnly: true,
|
HttpOnly: true,
|
||||||
Expires: time.Time{Year: 2011, Month: 11, Day: 23, Hour: 1, Minute: 5, Second: 3, ZoneOffset: 0, Zone: "GMT"},
|
Expires: time.Date(2011, 11, 23, 1, 5, 3, 0, time.UTC),
|
||||||
RawExpires: "Wed, 23-Nov-2011 01:05:03 GMT",
|
RawExpires: "Wed, 23-Nov-2011 01:05:03 GMT",
|
||||||
Raw: "NID=99=YsDT5i3E-CXax-; expires=Wed, 23-Nov-2011 01:05:03 GMT; path=/; domain=.google.ch; HttpOnly",
|
Raw: "NID=99=YsDT5i3E-CXax-; expires=Wed, 23-Nov-2011 01:05:03 GMT; path=/; domain=.google.ch; HttpOnly",
|
||||||
}},
|
}},
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
package http
|
package http
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
func (t *Transport) IdleConnKeysForTesting() (keys []string) {
|
func (t *Transport) IdleConnKeysForTesting() (keys []string) {
|
||||||
keys = make([]string, 0)
|
keys = make([]string, 0)
|
||||||
t.lk.Lock()
|
t.lk.Lock()
|
||||||
@ -33,8 +35,8 @@ func (t *Transport) IdleConnCountForTesting(cacheKey string) int {
|
|||||||
return len(conns)
|
return len(conns)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTestTimeoutHandler(handler Handler, ch <-chan int64) Handler {
|
func NewTestTimeoutHandler(handler Handler, ch <-chan time.Time) Handler {
|
||||||
f := func() <-chan int64 {
|
f := func() <-chan time.Time {
|
||||||
return ch
|
return ch
|
||||||
}
|
}
|
||||||
return &timeoutHandler{handler, f, ""}
|
return &timeoutHandler{handler, f, ""}
|
||||||
|
@ -103,7 +103,7 @@ func (r *response) WriteHeader(code int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if r.header.Get("Date") == "" {
|
if r.header.Get("Date") == "" {
|
||||||
r.header.Set("Date", time.UTC().Format(http.TimeFormat))
|
r.header.Set("Date", time.Now().UTC().Format(http.TimeFormat))
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(r.w, "Status: %d %s\r\n", code, http.StatusText(code))
|
fmt.Fprintf(r.w, "Status: %d %s\r\n", code, http.StatusText(code))
|
||||||
|
@ -148,11 +148,11 @@ func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirec
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if t, _ := time.Parse(TimeFormat, r.Header.Get("If-Modified-Since")); t != nil && d.Mtime_ns/1e9 <= t.Seconds() {
|
if t, err := time.Parse(TimeFormat, r.Header.Get("If-Modified-Since")); err == nil && !d.ModTime.After(t) {
|
||||||
w.WriteHeader(StatusNotModified)
|
w.WriteHeader(StatusNotModified)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.Header().Set("Last-Modified", time.SecondsToUTC(d.Mtime_ns/1e9).Format(TimeFormat))
|
w.Header().Set("Last-Modified", d.ModTime.UTC().Format(TimeFormat))
|
||||||
|
|
||||||
// use contents of index.html for directory, if present
|
// use contents of index.html for directory, if present
|
||||||
if d.IsDirectory() {
|
if d.IsDirectory() {
|
||||||
|
@ -7,14 +7,12 @@
|
|||||||
package httptest
|
package httptest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// A Server is an HTTP server listening on a system-chosen port on the
|
// A Server is an HTTP server listening on a system-chosen port on the
|
||||||
@ -113,8 +111,6 @@ func (s *Server) StartTLS() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s.TLS = &tls.Config{
|
s.TLS = &tls.Config{
|
||||||
Rand: rand.Reader,
|
|
||||||
Time: time.Seconds,
|
|
||||||
NextProtos: []string{"http/1.1"},
|
NextProtos: []string{"http/1.1"},
|
||||||
Certificates: []tls.Certificate{cert},
|
Certificates: []tls.Certificate{cert},
|
||||||
}
|
}
|
||||||
|
@ -31,11 +31,11 @@ type ReverseProxy struct {
|
|||||||
// If nil, http.DefaultTransport is used.
|
// If nil, http.DefaultTransport is used.
|
||||||
Transport http.RoundTripper
|
Transport http.RoundTripper
|
||||||
|
|
||||||
// FlushInterval specifies the flush interval, in
|
// FlushInterval specifies the flush interval
|
||||||
// nanoseconds, to flush to the client while
|
// to flush to the client while copying the
|
||||||
// coping the response body.
|
// response body.
|
||||||
// If zero, no periodic flushing is done.
|
// If zero, no periodic flushing is done.
|
||||||
FlushInterval int64
|
FlushInterval time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func singleJoiningSlash(a, b string) string {
|
func singleJoiningSlash(a, b string) string {
|
||||||
@ -135,7 +135,7 @@ type writeFlusher interface {
|
|||||||
|
|
||||||
type maxLatencyWriter struct {
|
type maxLatencyWriter struct {
|
||||||
dst writeFlusher
|
dst writeFlusher
|
||||||
latency int64 // nanos
|
latency time.Duration
|
||||||
|
|
||||||
lk sync.Mutex // protects init of done, as well Write + Flush
|
lk sync.Mutex // protects init of done, as well Write + Flush
|
||||||
done chan bool
|
done chan bool
|
||||||
|
@ -80,7 +80,7 @@ func Profile(w http.ResponseWriter, r *http.Request) {
|
|||||||
fmt.Fprintf(w, "Could not enable CPU profiling: %s\n", err)
|
fmt.Fprintf(w, "Could not enable CPU profiling: %s\n", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
time.Sleep(sec * 1e9)
|
time.Sleep(time.Duration(sec) * time.Second)
|
||||||
pprof.StopCPUProfile()
|
pprof.StopCPUProfile()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,19 +266,19 @@ func TestServerTimeouts(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Slow client that should timeout.
|
// Slow client that should timeout.
|
||||||
t1 := time.Nanoseconds()
|
t1 := time.Now()
|
||||||
conn, err := net.Dial("tcp", addr.String())
|
conn, err := net.Dial("tcp", addr.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Dial: %v", err)
|
t.Fatalf("Dial: %v", err)
|
||||||
}
|
}
|
||||||
buf := make([]byte, 1)
|
buf := make([]byte, 1)
|
||||||
n, err := conn.Read(buf)
|
n, err := conn.Read(buf)
|
||||||
latency := time.Nanoseconds() - t1
|
latency := time.Now().Sub(t1)
|
||||||
if n != 0 || err != io.EOF {
|
if n != 0 || err != io.EOF {
|
||||||
t.Errorf("Read = %v, %v, wanted %v, %v", n, err, 0, io.EOF)
|
t.Errorf("Read = %v, %v, wanted %v, %v", n, err, 0, io.EOF)
|
||||||
}
|
}
|
||||||
if latency < second*0.20 /* fudge from 0.25 above */ {
|
if latency < 200*time.Millisecond /* fudge from 0.25 above */ {
|
||||||
t.Errorf("got EOF after %d ns, want >= %d", latency, second*0.20)
|
t.Errorf("got EOF after %s, want >= %s", latency, 200*time.Millisecond)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hit the HTTP server successfully again, verifying that the
|
// Hit the HTTP server successfully again, verifying that the
|
||||||
@ -760,7 +760,7 @@ func TestTimeoutHandler(t *testing.T) {
|
|||||||
_, werr := w.Write([]byte("hi"))
|
_, werr := w.Write([]byte("hi"))
|
||||||
writeErrors <- werr
|
writeErrors <- werr
|
||||||
})
|
})
|
||||||
timeout := make(chan int64, 1) // write to this to force timeouts
|
timeout := make(chan time.Time, 1) // write to this to force timeouts
|
||||||
ts := httptest.NewServer(NewTestTimeoutHandler(sayHi, timeout))
|
ts := httptest.NewServer(NewTestTimeoutHandler(sayHi, timeout))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
@ -782,7 +782,7 @@ func TestTimeoutHandler(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Times out:
|
// Times out:
|
||||||
timeout <- 1
|
timeout <- time.Time{}
|
||||||
res, err = Get(ts.URL)
|
res, err = Get(ts.URL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
|
@ -347,7 +347,7 @@ func (w *response) WriteHeader(code int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := w.header["Date"]; !ok {
|
if _, ok := w.header["Date"]; !ok {
|
||||||
w.Header().Set("Date", time.UTC().Format(TimeFormat))
|
w.Header().Set("Date", time.Now().UTC().Format(TimeFormat))
|
||||||
}
|
}
|
||||||
|
|
||||||
te := w.header.Get("Transfer-Encoding")
|
te := w.header.Get("Transfer-Encoding")
|
||||||
@ -1084,7 +1084,6 @@ func (s *Server) ListenAndServeTLS(certFile, keyFile string) error {
|
|||||||
}
|
}
|
||||||
config := &tls.Config{
|
config := &tls.Config{
|
||||||
Rand: rand.Reader,
|
Rand: rand.Reader,
|
||||||
Time: time.Seconds,
|
|
||||||
NextProtos: []string{"http/1.1"},
|
NextProtos: []string{"http/1.1"},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1112,9 +1111,9 @@ func (s *Server) ListenAndServeTLS(certFile, keyFile string) error {
|
|||||||
// (If msg is empty, a suitable default message will be sent.)
|
// (If msg is empty, a suitable default message will be sent.)
|
||||||
// After such a timeout, writes by h to its ResponseWriter will return
|
// After such a timeout, writes by h to its ResponseWriter will return
|
||||||
// ErrHandlerTimeout.
|
// ErrHandlerTimeout.
|
||||||
func TimeoutHandler(h Handler, ns int64, msg string) Handler {
|
func TimeoutHandler(h Handler, dt time.Duration, msg string) Handler {
|
||||||
f := func() <-chan int64 {
|
f := func() <-chan time.Time {
|
||||||
return time.After(ns)
|
return time.After(dt)
|
||||||
}
|
}
|
||||||
return &timeoutHandler{h, f, msg}
|
return &timeoutHandler{h, f, msg}
|
||||||
}
|
}
|
||||||
@ -1125,7 +1124,7 @@ var ErrHandlerTimeout = errors.New("http: Handler timeout")
|
|||||||
|
|
||||||
type timeoutHandler struct {
|
type timeoutHandler struct {
|
||||||
handler Handler
|
handler Handler
|
||||||
timeout func() <-chan int64 // returns channel producing a timeout
|
timeout func() <-chan time.Time // returns channel producing a timeout
|
||||||
body string
|
body string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,7 +263,7 @@ func TestTransportServerClosingUnexpectedly(t *testing.T) {
|
|||||||
t.Fatalf(format, arg...)
|
t.Fatalf(format, arg...)
|
||||||
}
|
}
|
||||||
t.Logf("retrying shortly after expected error: "+format, arg...)
|
t.Logf("retrying shortly after expected error: "+format, arg...)
|
||||||
time.Sleep(1e9 / int64(retries))
|
time.Sleep(time.Second / time.Duration(retries))
|
||||||
}
|
}
|
||||||
for retries >= 0 {
|
for retries >= 0 {
|
||||||
retries--
|
retries--
|
||||||
|
@ -89,14 +89,14 @@ func init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseDate(date string) (*time.Time, error) {
|
func parseDate(date string) (time.Time, error) {
|
||||||
for _, layout := range dateLayouts {
|
for _, layout := range dateLayouts {
|
||||||
t, err := time.Parse(layout, date)
|
t, err := time.Parse(layout, date)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return t, nil
|
return t, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, errors.New("mail: header could not be parsed")
|
return time.Time{}, errors.New("mail: header could not be parsed")
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Header represents the key-value pairs in a mail message header.
|
// A Header represents the key-value pairs in a mail message header.
|
||||||
@ -111,10 +111,10 @@ func (h Header) Get(key string) string {
|
|||||||
var ErrHeaderNotPresent = errors.New("mail: header not in message")
|
var ErrHeaderNotPresent = errors.New("mail: header not in message")
|
||||||
|
|
||||||
// Date parses the Date header field.
|
// Date parses the Date header field.
|
||||||
func (h Header) Date() (*time.Time, error) {
|
func (h Header) Date() (time.Time, error) {
|
||||||
hdr := h.Get("Date")
|
hdr := h.Get("Date")
|
||||||
if hdr == "" {
|
if hdr == "" {
|
||||||
return nil, ErrHeaderNotPresent
|
return time.Time{}, ErrHeaderNotPresent
|
||||||
}
|
}
|
||||||
return parseDate(hdr)
|
return parseDate(hdr)
|
||||||
}
|
}
|
||||||
|
@ -82,34 +82,18 @@ func headerEq(a, b Header) bool {
|
|||||||
func TestDateParsing(t *testing.T) {
|
func TestDateParsing(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
dateStr string
|
dateStr string
|
||||||
exp *time.Time
|
exp time.Time
|
||||||
}{
|
}{
|
||||||
// RFC 5322, Appendix A.1.1
|
// RFC 5322, Appendix A.1.1
|
||||||
{
|
{
|
||||||
"Fri, 21 Nov 1997 09:55:06 -0600",
|
"Fri, 21 Nov 1997 09:55:06 -0600",
|
||||||
&time.Time{
|
time.Date(1997, 11, 21, 9, 55, 6, 0, time.FixedZone("", -6*60*60)),
|
||||||
Year: 1997,
|
|
||||||
Month: 11,
|
|
||||||
Day: 21,
|
|
||||||
Hour: 9,
|
|
||||||
Minute: 55,
|
|
||||||
Second: 6,
|
|
||||||
ZoneOffset: -6 * 60 * 60,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
// RFC5322, Appendix A.6.2
|
// RFC5322, Appendix A.6.2
|
||||||
// Obsolete date.
|
// Obsolete date.
|
||||||
{
|
{
|
||||||
"21 Nov 97 09:55:06 GMT",
|
"21 Nov 97 09:55:06 GMT",
|
||||||
&time.Time{
|
time.Date(1997, 11, 21, 9, 55, 6, 0, time.FixedZone("GMT", 0)),
|
||||||
Year: 1997,
|
|
||||||
Month: 11,
|
|
||||||
Day: 21,
|
|
||||||
Hour: 9,
|
|
||||||
Minute: 55,
|
|
||||||
Second: 6,
|
|
||||||
Zone: "GMT",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
|
@ -17,7 +17,7 @@ func testTimeout(t *testing.T, network, addr string, readFrom bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer fd.Close()
|
defer fd.Close()
|
||||||
t0 := time.Nanoseconds()
|
t0 := time.Now()
|
||||||
fd.SetReadTimeout(1e8) // 100ms
|
fd.SetReadTimeout(1e8) // 100ms
|
||||||
var b [100]byte
|
var b [100]byte
|
||||||
var n int
|
var n int
|
||||||
@ -27,7 +27,7 @@ func testTimeout(t *testing.T, network, addr string, readFrom bool) {
|
|||||||
} else {
|
} else {
|
||||||
n, err1 = fd.Read(b[0:])
|
n, err1 = fd.Read(b[0:])
|
||||||
}
|
}
|
||||||
t1 := time.Nanoseconds()
|
t1 := time.Now()
|
||||||
what := "Read"
|
what := "Read"
|
||||||
if readFrom {
|
if readFrom {
|
||||||
what = "ReadFrom"
|
what = "ReadFrom"
|
||||||
@ -35,8 +35,8 @@ func testTimeout(t *testing.T, network, addr string, readFrom bool) {
|
|||||||
if n != 0 || err1 == nil || !err1.(Error).Timeout() {
|
if n != 0 || err1 == nil || !err1.(Error).Timeout() {
|
||||||
t.Errorf("fd.%s on %s %s did not return 0, timeout: %v, %v", what, network, addr, n, err1)
|
t.Errorf("fd.%s on %s %s did not return 0, timeout: %v, %v", what, network, addr, n, err1)
|
||||||
}
|
}
|
||||||
if t1-t0 < 0.5e8 || t1-t0 > 1.5e8 {
|
if dt := t1.Sub(t0); dt < 50*time.Millisecond || dt > 150*time.Millisecond {
|
||||||
t.Errorf("fd.%s on %s %s took %f seconds, expected 0.1", what, network, addr, float64(t1-t0)/1e9)
|
t.Errorf("fd.%s on %s %s took %s, expected 0.1s", what, network, addr, dt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,8 +129,8 @@ func (ed *encDec) encode(hdr *header, payloadType int, payload interface{}) erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
// See the comment for Exporter.Drain.
|
// See the comment for Exporter.Drain.
|
||||||
func (cs *clientSet) drain(timeout int64) error {
|
func (cs *clientSet) drain(timeout time.Duration) error {
|
||||||
startTime := time.Nanoseconds()
|
deadline := time.Now().Add(timeout)
|
||||||
for {
|
for {
|
||||||
pending := false
|
pending := false
|
||||||
cs.mu.Lock()
|
cs.mu.Lock()
|
||||||
@ -152,7 +152,7 @@ func (cs *clientSet) drain(timeout int64) error {
|
|||||||
if !pending {
|
if !pending {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if timeout > 0 && time.Nanoseconds()-startTime >= timeout {
|
if timeout > 0 && time.Now().After(deadline) {
|
||||||
return errors.New("timeout")
|
return errors.New("timeout")
|
||||||
}
|
}
|
||||||
time.Sleep(100 * 1e6) // 100 milliseconds
|
time.Sleep(100 * 1e6) // 100 milliseconds
|
||||||
@ -161,8 +161,8 @@ func (cs *clientSet) drain(timeout int64) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// See the comment for Exporter.Sync.
|
// See the comment for Exporter.Sync.
|
||||||
func (cs *clientSet) sync(timeout int64) error {
|
func (cs *clientSet) sync(timeout time.Duration) error {
|
||||||
startTime := time.Nanoseconds()
|
deadline := time.Now().Add(timeout)
|
||||||
// seq remembers the clients and their seqNum at point of entry.
|
// seq remembers the clients and their seqNum at point of entry.
|
||||||
seq := make(map[unackedCounter]int64)
|
seq := make(map[unackedCounter]int64)
|
||||||
for client := range cs.clients {
|
for client := range cs.clients {
|
||||||
@ -185,7 +185,7 @@ func (cs *clientSet) sync(timeout int64) error {
|
|||||||
if !pending {
|
if !pending {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if timeout > 0 && time.Nanoseconds()-startTime >= timeout {
|
if timeout > 0 && time.Now().After(deadline) {
|
||||||
return errors.New("timeout")
|
return errors.New("timeout")
|
||||||
}
|
}
|
||||||
time.Sleep(100 * 1e6) // 100 milliseconds
|
time.Sleep(100 * 1e6) // 100 milliseconds
|
||||||
|
@ -29,6 +29,7 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Export
|
// Export
|
||||||
@ -322,9 +323,9 @@ func (exp *Exporter) delClient(client *expClient) {
|
|||||||
// those not yet sent to any client and possibly including those sent while
|
// those not yet sent to any client and possibly including those sent while
|
||||||
// Drain was executing, have been received by the importer. In short, it
|
// Drain was executing, have been received by the importer. In short, it
|
||||||
// waits until all the exporter's messages have been received by a client.
|
// waits until all the exporter's messages have been received by a client.
|
||||||
// If the timeout (measured in nanoseconds) is positive and Drain takes
|
// If the timeout is positive and Drain takes longer than that to complete,
|
||||||
// longer than that to complete, an error is returned.
|
// an error is returned.
|
||||||
func (exp *Exporter) Drain(timeout int64) error {
|
func (exp *Exporter) Drain(timeout time.Duration) error {
|
||||||
// This wrapper function is here so the method's comment will appear in godoc.
|
// This wrapper function is here so the method's comment will appear in godoc.
|
||||||
return exp.clientSet.drain(timeout)
|
return exp.clientSet.drain(timeout)
|
||||||
}
|
}
|
||||||
@ -332,10 +333,9 @@ func (exp *Exporter) Drain(timeout int64) error {
|
|||||||
// Sync waits until all clients of the exporter have received the messages
|
// Sync waits until all clients of the exporter have received the messages
|
||||||
// that were sent at the time Sync was invoked. Unlike Drain, it does not
|
// that were sent at the time Sync was invoked. Unlike Drain, it does not
|
||||||
// wait for messages sent while it is running or messages that have not been
|
// wait for messages sent while it is running or messages that have not been
|
||||||
// dispatched to any client. If the timeout (measured in nanoseconds) is
|
// dispatched to any client. If the timeout is positive and Sync takes longer
|
||||||
// positive and Sync takes longer than that to complete, an error is
|
// than that to complete, an error is returned.
|
||||||
// returned.
|
func (exp *Exporter) Sync(timeout time.Duration) error {
|
||||||
func (exp *Exporter) Sync(timeout int64) error {
|
|
||||||
// This wrapper function is here so the method's comment will appear in godoc.
|
// This wrapper function is here so the method's comment will appear in godoc.
|
||||||
return exp.clientSet.sync(timeout)
|
return exp.clientSet.sync(timeout)
|
||||||
}
|
}
|
||||||
|
@ -276,9 +276,9 @@ func (imp *Importer) unackedCount() int64 {
|
|||||||
// If the timeout (measured in nanoseconds) is positive and Drain takes
|
// If the timeout (measured in nanoseconds) is positive and Drain takes
|
||||||
// longer than that to complete, an error is returned.
|
// longer than that to complete, an error is returned.
|
||||||
func (imp *Importer) Drain(timeout int64) error {
|
func (imp *Importer) Drain(timeout int64) error {
|
||||||
startTime := time.Nanoseconds()
|
deadline := time.Now().Add(time.Duration(timeout))
|
||||||
for imp.unackedCount() > 0 {
|
for imp.unackedCount() > 0 {
|
||||||
if timeout > 0 && time.Nanoseconds()-startTime >= timeout {
|
if timeout > 0 && time.Now().After(deadline) {
|
||||||
return errors.New("timeout")
|
return errors.New("timeout")
|
||||||
}
|
}
|
||||||
time.Sleep(100 * 1e6)
|
time.Sleep(100 * 1e6)
|
||||||
|
@ -8,6 +8,7 @@ package os
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func sigpipe() // implemented in package runtime
|
func sigpipe() // implemented in package runtime
|
||||||
@ -181,11 +182,12 @@ func (file *File) Sync() (err error) {
|
|||||||
// Chtimes changes the access and modification times of the named
|
// Chtimes changes the access and modification times of the named
|
||||||
// file, similar to the Unix utime() or utimes() functions.
|
// file, similar to the Unix utime() or utimes() functions.
|
||||||
//
|
//
|
||||||
// The argument times are in nanoseconds, although the underlying
|
// The underlying filesystem may truncate or round the values to a
|
||||||
// filesystem may truncate or round the values to a more
|
// less precise time unit.
|
||||||
// coarse time unit.
|
func Chtimes(name string, atime time.Time, mtime time.Time) error {
|
||||||
func Chtimes(name string, atime_ns int64, mtime_ns int64) error {
|
|
||||||
var utimes [2]syscall.Timeval
|
var utimes [2]syscall.Timeval
|
||||||
|
atime_ns := atime.Unix()*1e9 + int64(atime.Nanosecond())
|
||||||
|
mtime_ns := mtime.Unix()*1e9 + int64(mtime.Nanosecond())
|
||||||
utimes[0] = syscall.NsecToTimeval(atime_ns)
|
utimes[0] = syscall.NsecToTimeval(atime_ns)
|
||||||
utimes[1] = syscall.NsecToTimeval(mtime_ns)
|
utimes[1] = syscall.NsecToTimeval(mtime_ns)
|
||||||
if e := syscall.Utimes(name, utimes[0:]); e != nil {
|
if e := syscall.Utimes(name, utimes[0:]); e != nil {
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var dot = []string{
|
var dot = []string{
|
||||||
@ -719,8 +720,7 @@ func TestChtimes(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Move access and modification time back a second
|
// Move access and modification time back a second
|
||||||
const OneSecond = 1e9 // in nanoseconds
|
err = Chtimes(f.Name(), preStat.AccessTime.Add(-time.Second), preStat.ModTime.Add(-time.Second))
|
||||||
err = Chtimes(f.Name(), preStat.Atime_ns-OneSecond, preStat.Mtime_ns-OneSecond)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Chtimes %s: %s", f.Name(), err)
|
t.Fatalf("Chtimes %s: %s", f.Name(), err)
|
||||||
}
|
}
|
||||||
@ -734,16 +734,16 @@ func TestChtimes(t *testing.T) {
|
|||||||
Mtime is the time of the last change of content. Similarly, atime is set whenever the
|
Mtime is the time of the last change of content. Similarly, atime is set whenever the
|
||||||
contents are accessed; also, it is set whenever mtime is set.
|
contents are accessed; also, it is set whenever mtime is set.
|
||||||
*/
|
*/
|
||||||
if postStat.Atime_ns >= preStat.Atime_ns && syscall.OS != "plan9" {
|
if !postStat.AccessTime.Before(preStat.AccessTime) && syscall.OS != "plan9" {
|
||||||
t.Errorf("Atime_ns didn't go backwards; was=%d, after=%d",
|
t.Errorf("AccessTime didn't go backwards; was=%d, after=%d",
|
||||||
preStat.Atime_ns,
|
preStat.AccessTime,
|
||||||
postStat.Atime_ns)
|
postStat.AccessTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
if postStat.Mtime_ns >= preStat.Mtime_ns {
|
if !postStat.ModTime.Before(preStat.ModTime) {
|
||||||
t.Errorf("Mtime_ns didn't go backwards; was=%d, after=%d",
|
t.Errorf("ModTime didn't go backwards; was=%d, after=%d",
|
||||||
preStat.Mtime_ns,
|
preStat.ModTime,
|
||||||
postStat.Mtime_ns)
|
postStat.ModTime)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,10 @@
|
|||||||
|
|
||||||
package os
|
package os
|
||||||
|
|
||||||
import "syscall"
|
import (
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
func isSymlink(stat *syscall.Stat_t) bool {
|
func isSymlink(stat *syscall.Stat_t) bool {
|
||||||
return stat.Mode&syscall.S_IFMT == syscall.S_IFLNK
|
return stat.Mode&syscall.S_IFMT == syscall.S_IFLNK
|
||||||
@ -21,12 +24,16 @@ func fileInfoFromStat(name string, fi *FileInfo, lstat, stat *syscall.Stat_t) *F
|
|||||||
fi.Size = stat.Size
|
fi.Size = stat.Size
|
||||||
fi.Blksize = int64(stat.Blksize)
|
fi.Blksize = int64(stat.Blksize)
|
||||||
fi.Blocks = stat.Blocks
|
fi.Blocks = stat.Blocks
|
||||||
fi.Atime_ns = syscall.TimespecToNsec(stat.Atimespec)
|
fi.AccessTime = timespecToTime(stat.Atimespec)
|
||||||
fi.Mtime_ns = syscall.TimespecToNsec(stat.Mtimespec)
|
fi.ModTime = timespecToTime(stat.Mtimespec)
|
||||||
fi.Ctime_ns = syscall.TimespecToNsec(stat.Ctimespec)
|
fi.ChangeTime = timespecToTime(stat.Ctimespec)
|
||||||
fi.Name = basename(name)
|
fi.Name = basename(name)
|
||||||
if isSymlink(lstat) && !isSymlink(stat) {
|
if isSymlink(lstat) && !isSymlink(stat) {
|
||||||
fi.FollowedSymlink = true
|
fi.FollowedSymlink = true
|
||||||
}
|
}
|
||||||
return fi
|
return fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func timespecToTime(ts syscall.Timespec) time.Time {
|
||||||
|
return time.Unix(int64(ts.Sec), int64(ts.Nsec))
|
||||||
|
}
|
||||||
|
@ -4,7 +4,10 @@
|
|||||||
|
|
||||||
package os
|
package os
|
||||||
|
|
||||||
import "syscall"
|
import (
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
func isSymlink(stat *syscall.Stat_t) bool {
|
func isSymlink(stat *syscall.Stat_t) bool {
|
||||||
return stat.Mode&syscall.S_IFMT == syscall.S_IFLNK
|
return stat.Mode&syscall.S_IFMT == syscall.S_IFLNK
|
||||||
@ -21,12 +24,16 @@ func fileInfoFromStat(name string, fi *FileInfo, lstat, stat *syscall.Stat_t) *F
|
|||||||
fi.Size = int64(stat.Size)
|
fi.Size = int64(stat.Size)
|
||||||
fi.Blksize = int64(stat.Blksize)
|
fi.Blksize = int64(stat.Blksize)
|
||||||
fi.Blocks = stat.Blocks
|
fi.Blocks = stat.Blocks
|
||||||
fi.Atime_ns = syscall.TimespecToNsec(stat.Atimespec)
|
fi.AccessTime = timespecToTime(stat.Atimespec)
|
||||||
fi.Mtime_ns = syscall.TimespecToNsec(stat.Mtimespec)
|
fi.ModTime = timespecToTime(stat.Mtimespec)
|
||||||
fi.Ctime_ns = syscall.TimespecToNsec(stat.Ctimespec)
|
fi.ChangeTime = timespecToTime(stat.Ctimespec)
|
||||||
fi.Name = basename(name)
|
fi.Name = basename(name)
|
||||||
if isSymlink(lstat) && !isSymlink(stat) {
|
if isSymlink(lstat) && !isSymlink(stat) {
|
||||||
fi.FollowedSymlink = true
|
fi.FollowedSymlink = true
|
||||||
}
|
}
|
||||||
return fi
|
return fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func timespecToTime(ts syscall.Timespec) time.Time {
|
||||||
|
return time.Unix(int64(ts.Sec), int64(ts.Nsec))
|
||||||
|
}
|
||||||
|
@ -4,7 +4,10 @@
|
|||||||
|
|
||||||
package os
|
package os
|
||||||
|
|
||||||
import "syscall"
|
import (
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
func isSymlink(stat *syscall.Stat_t) bool {
|
func isSymlink(stat *syscall.Stat_t) bool {
|
||||||
return stat.Mode&syscall.S_IFMT == syscall.S_IFLNK
|
return stat.Mode&syscall.S_IFMT == syscall.S_IFLNK
|
||||||
@ -21,12 +24,16 @@ func fileInfoFromStat(name string, fi *FileInfo, lstat, stat *syscall.Stat_t) *F
|
|||||||
fi.Size = stat.Size
|
fi.Size = stat.Size
|
||||||
fi.Blksize = int64(stat.Blksize)
|
fi.Blksize = int64(stat.Blksize)
|
||||||
fi.Blocks = stat.Blocks
|
fi.Blocks = stat.Blocks
|
||||||
fi.Atime_ns = syscall.TimespecToNsec(stat.Atim)
|
fi.AccessTime = timespecToTime(stat.Atim)
|
||||||
fi.Mtime_ns = syscall.TimespecToNsec(stat.Mtim)
|
fi.ModTime = timespecToTime(stat.Mtim)
|
||||||
fi.Ctime_ns = syscall.TimespecToNsec(stat.Ctim)
|
fi.ChangeTime = timespecToTime(stat.Ctim)
|
||||||
fi.Name = basename(name)
|
fi.Name = basename(name)
|
||||||
if isSymlink(lstat) && !isSymlink(stat) {
|
if isSymlink(lstat) && !isSymlink(stat) {
|
||||||
fi.FollowedSymlink = true
|
fi.FollowedSymlink = true
|
||||||
}
|
}
|
||||||
return fi
|
return fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func timespecToTime(ts syscall.Timespec) time.Time {
|
||||||
|
return time.Unix(int64(ts.Sec), int64(ts.Nsec))
|
||||||
|
}
|
||||||
|
@ -4,7 +4,10 @@
|
|||||||
|
|
||||||
package os
|
package os
|
||||||
|
|
||||||
import "syscall"
|
import (
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
func isSymlink(stat *syscall.Stat_t) bool {
|
func isSymlink(stat *syscall.Stat_t) bool {
|
||||||
return stat.Mode&syscall.S_IFMT == syscall.S_IFLNK
|
return stat.Mode&syscall.S_IFMT == syscall.S_IFLNK
|
||||||
@ -21,12 +24,16 @@ func fileInfoFromStat(name string, fi *FileInfo, lstat, stat *syscall.Stat_t) *F
|
|||||||
fi.Size = int64(stat.Size)
|
fi.Size = int64(stat.Size)
|
||||||
fi.Blksize = int64(stat.Blksize)
|
fi.Blksize = int64(stat.Blksize)
|
||||||
fi.Blocks = stat.Blocks
|
fi.Blocks = stat.Blocks
|
||||||
fi.Atime_ns = syscall.TimespecToNsec(stat.Atim)
|
fi.AccessTime = timespecToTime(stat.Atim)
|
||||||
fi.Mtime_ns = syscall.TimespecToNsec(stat.Mtim)
|
fi.ModTime = timespecToTime(stat.Mtim)
|
||||||
fi.Ctime_ns = syscall.TimespecToNsec(stat.Ctim)
|
fi.ChangeTime = timespecToTime(stat.Ctim)
|
||||||
fi.Name = basename(name)
|
fi.Name = basename(name)
|
||||||
if isSymlink(lstat) && !isSymlink(stat) {
|
if isSymlink(lstat) && !isSymlink(stat) {
|
||||||
fi.FollowedSymlink = true
|
fi.FollowedSymlink = true
|
||||||
}
|
}
|
||||||
return fi
|
return fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func timespecToTime(ts syscall.Timespec) time.Time {
|
||||||
|
return time.Unix(int64(ts.Sec), int64(ts.Nsec))
|
||||||
|
}
|
||||||
|
@ -6,6 +6,7 @@ package os
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -91,8 +92,8 @@ func setFileInfo(fi *FileInfo, name string, fa, sizehi, sizelo uint32, ctime, at
|
|||||||
fi.Size = int64(sizehi)<<32 + int64(sizelo)
|
fi.Size = int64(sizehi)<<32 + int64(sizelo)
|
||||||
fi.Name = name
|
fi.Name = name
|
||||||
fi.FollowedSymlink = false
|
fi.FollowedSymlink = false
|
||||||
fi.Atime_ns = atime.Nanoseconds()
|
fi.AccessTime = time.Unix(0, atime.Nanoseconds())
|
||||||
fi.Mtime_ns = wtime.Nanoseconds()
|
fi.ModTime = time.Unix(0, wtime.Nanoseconds())
|
||||||
fi.Ctime_ns = ctime.Nanoseconds()
|
fi.ChangeTime = time.Unix(0, ctime.Nanoseconds())
|
||||||
return fi
|
return fi
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,10 @@
|
|||||||
|
|
||||||
package os
|
package os
|
||||||
|
|
||||||
import "syscall"
|
import (
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
// An operating-system independent representation of Unix data structures.
|
// An operating-system independent representation of Unix data structures.
|
||||||
// OS-specific routines in this directory convert the OS-local versions to these.
|
// OS-specific routines in this directory convert the OS-local versions to these.
|
||||||
@ -14,21 +17,21 @@ func Getpagesize() int { return syscall.Getpagesize() }
|
|||||||
|
|
||||||
// A FileInfo describes a file and is returned by Stat, Fstat, and Lstat
|
// A FileInfo describes a file and is returned by Stat, Fstat, and Lstat
|
||||||
type FileInfo struct {
|
type FileInfo struct {
|
||||||
Dev uint64 // device number of file system holding file.
|
Dev uint64 // device number of file system holding file.
|
||||||
Ino uint64 // inode number.
|
Ino uint64 // inode number.
|
||||||
Nlink uint64 // number of hard links.
|
Nlink uint64 // number of hard links.
|
||||||
Mode uint32 // permission and mode bits.
|
Mode uint32 // permission and mode bits.
|
||||||
Uid int // user id of owner.
|
Uid int // user id of owner.
|
||||||
Gid int // group id of owner.
|
Gid int // group id of owner.
|
||||||
Rdev uint64 // device type for special file.
|
Rdev uint64 // device type for special file.
|
||||||
Size int64 // length in bytes.
|
Size int64 // length in bytes.
|
||||||
Blksize int64 // size of blocks, in bytes.
|
Blksize int64 // size of blocks, in bytes.
|
||||||
Blocks int64 // number of blocks allocated for file.
|
Blocks int64 // number of blocks allocated for file.
|
||||||
Atime_ns int64 // access time; nanoseconds since epoch.
|
AccessTime time.Time // access time
|
||||||
Mtime_ns int64 // modified time; nanoseconds since epoch.
|
ModTime time.Time // modification time
|
||||||
Ctime_ns int64 // status change time; nanoseconds since epoch.
|
ChangeTime time.Time // status change time
|
||||||
Name string // base name of the file name provided in Open, Stat, etc.
|
Name string // base name of the file name provided in Open, Stat, etc.
|
||||||
FollowedSymlink bool // followed a symlink to get this information
|
FollowedSymlink bool // followed a symlink to get this information
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsFifo reports whether the FileInfo describes a FIFO file.
|
// IsFifo reports whether the FileInfo describes a FIFO file.
|
||||||
|
@ -27,17 +27,19 @@ type InternalBenchmark struct {
|
|||||||
type B struct {
|
type B struct {
|
||||||
N int
|
N int
|
||||||
benchmark InternalBenchmark
|
benchmark InternalBenchmark
|
||||||
ns int64
|
ns time.Duration
|
||||||
bytes int64
|
bytes int64
|
||||||
start int64
|
start time.Time
|
||||||
|
timerOn bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// StartTimer starts timing a test. This function is called automatically
|
// StartTimer starts timing a test. This function is called automatically
|
||||||
// before a benchmark starts, but it can also used to resume timing after
|
// before a benchmark starts, but it can also used to resume timing after
|
||||||
// a call to StopTimer.
|
// a call to StopTimer.
|
||||||
func (b *B) StartTimer() {
|
func (b *B) StartTimer() {
|
||||||
if b.start == 0 {
|
if !b.timerOn {
|
||||||
b.start = time.Nanoseconds()
|
b.start = time.Now()
|
||||||
|
b.timerOn = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,17 +47,17 @@ func (b *B) StartTimer() {
|
|||||||
// while performing complex initialization that you don't
|
// while performing complex initialization that you don't
|
||||||
// want to measure.
|
// want to measure.
|
||||||
func (b *B) StopTimer() {
|
func (b *B) StopTimer() {
|
||||||
if b.start > 0 {
|
if b.timerOn {
|
||||||
b.ns += time.Nanoseconds() - b.start
|
b.ns += time.Now().Sub(b.start)
|
||||||
|
b.timerOn = false
|
||||||
}
|
}
|
||||||
b.start = 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResetTimer sets the elapsed benchmark time to zero.
|
// ResetTimer sets the elapsed benchmark time to zero.
|
||||||
// It does not affect whether the timer is running.
|
// It does not affect whether the timer is running.
|
||||||
func (b *B) ResetTimer() {
|
func (b *B) ResetTimer() {
|
||||||
if b.start > 0 {
|
if b.timerOn {
|
||||||
b.start = time.Nanoseconds()
|
b.start = time.Now()
|
||||||
}
|
}
|
||||||
b.ns = 0
|
b.ns = 0
|
||||||
}
|
}
|
||||||
@ -68,7 +70,7 @@ func (b *B) nsPerOp() int64 {
|
|||||||
if b.N <= 0 {
|
if b.N <= 0 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return b.ns / int64(b.N)
|
return b.ns.Nanoseconds() / int64(b.N)
|
||||||
}
|
}
|
||||||
|
|
||||||
// runN runs a single benchmark for the specified number of iterations.
|
// runN runs a single benchmark for the specified number of iterations.
|
||||||
@ -134,14 +136,14 @@ func (b *B) run() BenchmarkResult {
|
|||||||
n := 1
|
n := 1
|
||||||
b.runN(n)
|
b.runN(n)
|
||||||
// Run the benchmark for at least the specified amount of time.
|
// Run the benchmark for at least the specified amount of time.
|
||||||
time := int64(*benchTime * 1e9)
|
d := time.Duration(*benchTime * float64(time.Second))
|
||||||
for b.ns < time && n < 1e9 {
|
for b.ns < d && n < 1e9 {
|
||||||
last := n
|
last := n
|
||||||
// Predict iterations/sec.
|
// Predict iterations/sec.
|
||||||
if b.nsPerOp() == 0 {
|
if b.nsPerOp() == 0 {
|
||||||
n = 1e9
|
n = 1e9
|
||||||
} else {
|
} else {
|
||||||
n = int(time / b.nsPerOp())
|
n = int(d.Nanoseconds() / b.nsPerOp())
|
||||||
}
|
}
|
||||||
// Run more iterations than we think we'll need for a second (1.5x).
|
// Run more iterations than we think we'll need for a second (1.5x).
|
||||||
// Don't grow too fast in case we had timing errors previously.
|
// Don't grow too fast in case we had timing errors previously.
|
||||||
@ -156,23 +158,23 @@ func (b *B) run() BenchmarkResult {
|
|||||||
|
|
||||||
// The results of a benchmark run.
|
// The results of a benchmark run.
|
||||||
type BenchmarkResult struct {
|
type BenchmarkResult struct {
|
||||||
N int // The number of iterations.
|
N int // The number of iterations.
|
||||||
Ns int64 // The total time taken.
|
T time.Duration // The total time taken.
|
||||||
Bytes int64 // Bytes processed in one iteration.
|
Bytes int64 // Bytes processed in one iteration.
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r BenchmarkResult) NsPerOp() int64 {
|
func (r BenchmarkResult) NsPerOp() int64 {
|
||||||
if r.N <= 0 {
|
if r.N <= 0 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return r.Ns / int64(r.N)
|
return r.T.Nanoseconds() / int64(r.N)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r BenchmarkResult) mbPerSec() float64 {
|
func (r BenchmarkResult) mbPerSec() float64 {
|
||||||
if r.Bytes <= 0 || r.Ns <= 0 || r.N <= 0 {
|
if r.Bytes <= 0 || r.T <= 0 || r.N <= 0 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return float64(r.Bytes) * float64(r.N) / float64(r.Ns) * 1e3
|
return (float64(r.Bytes) * float64(r.N) / 1e6) / r.T.Seconds()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r BenchmarkResult) String() string {
|
func (r BenchmarkResult) String() string {
|
||||||
@ -187,9 +189,9 @@ func (r BenchmarkResult) String() string {
|
|||||||
// The format specifiers here make sure that
|
// The format specifiers here make sure that
|
||||||
// the ones digits line up for all three possible formats.
|
// the ones digits line up for all three possible formats.
|
||||||
if nsop < 10 {
|
if nsop < 10 {
|
||||||
ns = fmt.Sprintf("%13.2f ns/op", float64(r.Ns)/float64(r.N))
|
ns = fmt.Sprintf("%13.2f ns/op", float64(r.T.Nanoseconds())/float64(r.N))
|
||||||
} else {
|
} else {
|
||||||
ns = fmt.Sprintf("%12.1f ns/op", float64(r.Ns)/float64(r.N))
|
ns = fmt.Sprintf("%12.1f ns/op", float64(r.T.Nanoseconds())/float64(r.N))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%8d\t%s%s", r.N, ns, mb)
|
return fmt.Sprintf("%8d\t%s%s", r.N, ns, mb)
|
||||||
|
@ -56,9 +56,9 @@ func RunExamples(examples []InternalExample) (ok bool) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
// run example
|
// run example
|
||||||
ns := -time.Nanoseconds()
|
t0 := time.Now()
|
||||||
eg.F()
|
eg.F()
|
||||||
ns += time.Nanoseconds()
|
dt := time.Now().Sub(t0)
|
||||||
|
|
||||||
// close pipe, restore stdout/stderr, get output
|
// close pipe, restore stdout/stderr, get output
|
||||||
w.Close()
|
w.Close()
|
||||||
@ -66,7 +66,7 @@ func RunExamples(examples []InternalExample) (ok bool) {
|
|||||||
out := <-outC
|
out := <-outC
|
||||||
|
|
||||||
// report any errors
|
// report any errors
|
||||||
tstr := fmt.Sprintf("(%.2f seconds)", float64(ns)/1e9)
|
tstr := fmt.Sprintf("(%.2f seconds)", dt.Seconds())
|
||||||
if out != eg.Output {
|
if out != eg.Output {
|
||||||
fmt.Printf(
|
fmt.Printf(
|
||||||
"--- FAIL: %s %s\ngot:\n%s\nwant:\n%s\n",
|
"--- FAIL: %s %s\ngot:\n%s\nwant:\n%s\n",
|
||||||
|
@ -111,12 +111,13 @@ func decorate(s string, addFileLine bool) string {
|
|||||||
// T is a type passed to Test functions to manage test state and support formatted test logs.
|
// T is a type passed to Test functions to manage test state and support formatted test logs.
|
||||||
// Logs are accumulated during execution and dumped to standard error when done.
|
// Logs are accumulated during execution and dumped to standard error when done.
|
||||||
type T struct {
|
type T struct {
|
||||||
name string // Name of test.
|
name string // Name of test.
|
||||||
errors string // Error string from test.
|
errors string // Error string from test.
|
||||||
failed bool // Test has failed.
|
failed bool // Test has failed.
|
||||||
ch chan *T // Output for serial tests.
|
ch chan *T // Output for serial tests.
|
||||||
startParallel chan bool // Parallel tests will wait on this.
|
startParallel chan bool // Parallel tests will wait on this.
|
||||||
ns int64 // Duration of test in nanoseconds.
|
start time.Time // Time test started
|
||||||
|
dt time.Duration // Length of test
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fail marks the Test function as having failed but continues execution.
|
// Fail marks the Test function as having failed but continues execution.
|
||||||
@ -128,7 +129,7 @@ func (t *T) Failed() bool { return t.failed }
|
|||||||
// FailNow marks the Test function as having failed and stops its execution.
|
// FailNow marks the Test function as having failed and stops its execution.
|
||||||
// Execution will continue at the next Test.
|
// Execution will continue at the next Test.
|
||||||
func (t *T) FailNow() {
|
func (t *T) FailNow() {
|
||||||
t.ns = time.Nanoseconds() - t.ns
|
t.dt = time.Now().Sub(t.start)
|
||||||
t.Fail()
|
t.Fail()
|
||||||
t.ch <- t
|
t.ch <- t
|
||||||
runtime.Goexit()
|
runtime.Goexit()
|
||||||
@ -184,9 +185,9 @@ type InternalTest struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func tRunner(t *T, test *InternalTest) {
|
func tRunner(t *T, test *InternalTest) {
|
||||||
t.ns = time.Nanoseconds()
|
t.start = time.Now()
|
||||||
test.F(t)
|
test.F(t)
|
||||||
t.ns = time.Nanoseconds() - t.ns
|
t.dt = time.Now().Sub(t.start)
|
||||||
t.ch <- t
|
t.ch <- t
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,7 +212,7 @@ func Main(matchString func(pat, str string) (bool, error), tests []InternalTest,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func report(t *T) {
|
func report(t *T) {
|
||||||
tstr := fmt.Sprintf("(%.2f seconds)", float64(t.ns)/1e9)
|
tstr := fmt.Sprintf("(%.2f seconds)", t.dt.Seconds())
|
||||||
format := "--- %s: %s %s\n%s"
|
format := "--- %s: %s %s\n%s"
|
||||||
if t.failed {
|
if t.failed {
|
||||||
fmt.Printf(format, "FAIL", t.name, tstr, t.errors)
|
fmt.Printf(format, "FAIL", t.name, tstr, t.errors)
|
||||||
|
@ -19,9 +19,8 @@ func f() {
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
go f()
|
go f()
|
||||||
time.Nanoseconds()
|
time.Now()
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user