aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2017-11-15 17:53:30 +0000
committerRuss Cox <rsc@golang.org>2017-11-16 14:58:12 +0000
commit02298ae11a0d63afe42431791dad92dcf9714c3d (patch)
treec1897e6de024bf1bb297605d9eecf9e4db3f32db /src
parentc09ee9d1ce63300d97ea1a102e9917dabbe87803 (diff)
downloadgo-02298ae11a0d63afe42431791dad92dcf9714c3d.tar.xz
Revert "time: enable ZONEINFO tzdata file support and error reporting"
This reverts commit 630d176e7d5e42e21d176d1b9d48de0e03e7cec8. Reason for revert: the CL moves a parser for what appears to be an Android-specific file format into the main code and makes it available on all platforms. Android-specific file formats should be limited to Android. Change-Id: I3f19fe03673d65ed1446a0dcf95e5986053e10c0 Reviewed-on: https://go-review.googlesource.com/77950 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Run-TryBot: Russ Cox <rsc@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
Diffstat (limited to 'src')
-rw-r--r--src/time/zoneinfo.go13
-rw-r--r--src/time/zoneinfo_android.go55
-rw-r--r--src/time/zoneinfo_read.go71
3 files changed, 77 insertions, 62 deletions
diff --git a/src/time/zoneinfo.go b/src/time/zoneinfo.go
index 4e2a207200..4424b44106 100644
--- a/src/time/zoneinfo.go
+++ b/src/time/zoneinfo.go
@@ -272,7 +272,7 @@ var zoneinfoOnce sync.Once
//
// The time zone database needed by LoadLocation may not be
// present on all systems, especially non-Unix systems.
-// LoadLocation looks in the directory, uncompressed zip file, or tzdata file
+// LoadLocation looks in the directory or uncompressed zip file
// named by the ZONEINFO environment variable, if any, then looks in
// known installation locations on Unix systems,
// and finally looks in $GOROOT/lib/time/zoneinfo.zip.
@@ -292,13 +292,14 @@ func LoadLocation(name string) (*Location, error) {
env, _ := syscall.Getenv("ZONEINFO")
zoneinfo = &env
})
- sources := zoneSources
if *zoneinfo != "" {
- sources = make([]string, len(zoneSources)+1)
- sources[0] = *zoneinfo
- copy(sources[1:], zoneSources)
+ if zoneData, err := loadTzinfoFromDirOrZip(*zoneinfo, name); err == nil {
+ if z, err := newLocationFromTzinfo(name, zoneData); err == nil {
+ return z, nil
+ }
+ }
}
- return loadLocation(name, sources)
+ return loadLocation(name, zoneSources)
}
// containsDotDot reports whether s contains "..".
diff --git a/src/time/zoneinfo_android.go b/src/time/zoneinfo_android.go
index 677b06e7e5..40c8ae04ea 100644
--- a/src/time/zoneinfo_android.go
+++ b/src/time/zoneinfo_android.go
@@ -9,6 +9,7 @@
package time
import (
+ "errors"
"runtime"
)
@@ -22,3 +23,57 @@ func initLocal() {
// TODO(elias.naur): getprop persist.sys.timezone
localLoc = *UTC
}
+
+func init() {
+ loadTzinfoFromTzdata = androidLoadTzinfoFromTzdata
+}
+
+func androidLoadTzinfoFromTzdata(file, name string) ([]byte, error) {
+ const (
+ headersize = 12 + 3*4
+ namesize = 40
+ entrysize = namesize + 3*4
+ )
+ if len(name) > namesize {
+ return nil, errors.New(name + " is longer than the maximum zone name length (40 bytes)")
+ }
+ fd, err := open(file)
+ if err != nil {
+ return nil, err
+ }
+ defer closefd(fd)
+
+ buf := make([]byte, headersize)
+ if err := preadn(fd, buf, 0); err != nil {
+ return nil, errors.New("corrupt tzdata file " + file)
+ }
+ d := data{buf, false}
+ if magic := d.read(6); string(magic) != "tzdata" {
+ return nil, errors.New("corrupt tzdata file " + file)
+ }
+ d = data{buf[12:], false}
+ indexOff, _ := d.big4()
+ dataOff, _ := d.big4()
+ indexSize := dataOff - indexOff
+ entrycount := indexSize / entrysize
+ buf = make([]byte, indexSize)
+ if err := preadn(fd, buf, int(indexOff)); err != nil {
+ return nil, errors.New("corrupt tzdata file " + file)
+ }
+ for i := 0; i < int(entrycount); i++ {
+ entry := buf[i*entrysize : (i+1)*entrysize]
+ // len(name) <= namesize is checked at function entry
+ if string(entry[:len(name)]) != name {
+ continue
+ }
+ d := data{entry[namesize:], false}
+ off, _ := d.big4()
+ size, _ := d.big4()
+ buf := make([]byte, size)
+ if err := preadn(fd, buf, int(off+dataOff)); err != nil {
+ return nil, errors.New("corrupt tzdata file " + file)
+ }
+ return buf, nil
+ }
+ return nil, errors.New("cannot find " + name + " in tzdata file " + file)
+}
diff --git a/src/time/zoneinfo_read.go b/src/time/zoneinfo_read.go
index 22658fc28a..eaaaf1f2b4 100644
--- a/src/time/zoneinfo_read.go
+++ b/src/time/zoneinfo_read.go
@@ -220,6 +220,18 @@ func newLocationFromTzinfo(name string, Tzinfo []byte) (*Location, error) {
return l, nil
}
+// loadTzinfoFromDirOrZip returns the contents of the file with the given name
+// in dir. dir can either be an uncompressed zip file, or a directory.
+func loadTzinfoFromDirOrZip(dir, name string) ([]byte, error) {
+ if len(dir) > 4 && dir[len(dir)-4:] == ".zip" {
+ return loadTzinfoFromZip(dir, name)
+ }
+ if dir != "" {
+ name = dir + "/" + name
+ }
+ return readFile(name)
+}
+
// There are 500+ zoneinfo files. Rather than distribute them all
// individually, we ship them in an uncompressed zip file.
// Used this way, the zip file format serves as a commonly readable
@@ -351,61 +363,13 @@ func loadTzinfoFromZip(zipfile, name string) ([]byte, error) {
return buf, nil
}
- return nil, syscall.ENOENT
+ return nil, errors.New("cannot find " + name + " in zip file " + zipfile)
}
// loadTzinfoFromTzdata returns the time zone information of the time zone
// with the given name, from a tzdata database file as they are typically
// found on android.
-func loadTzinfoFromTzdata(file, name string) ([]byte, error) {
- const (
- headersize = 12 + 3*4
- namesize = 40
- entrysize = namesize + 3*4
- )
- if len(name) > namesize {
- return nil, errors.New(name + " is longer than the maximum zone name length (40 bytes)")
- }
- fd, err := open(file)
- if err != nil {
- return nil, err
- }
- defer closefd(fd)
-
- buf := make([]byte, headersize)
- if err := preadn(fd, buf, 0); err != nil {
- return nil, errors.New("corrupt tzdata file " + file)
- }
- d := data{buf, false}
- if magic := d.read(6); string(magic) != "tzdata" {
- return nil, errors.New("corrupt tzdata file " + file)
- }
- d = data{buf[12:], false}
- indexOff, _ := d.big4()
- dataOff, _ := d.big4()
- indexSize := dataOff - indexOff
- entrycount := indexSize / entrysize
- buf = make([]byte, indexSize)
- if err := preadn(fd, buf, int(indexOff)); err != nil {
- return nil, errors.New("corrupt tzdata file " + file)
- }
- for i := 0; i < int(entrycount); i++ {
- entry := buf[i*entrysize : (i+1)*entrysize]
- // len(name) <= namesize is checked at function entry
- if string(entry[:len(name)]) != name {
- continue
- }
- d := data{entry[namesize:], false}
- off, _ := d.big4()
- size, _ := d.big4()
- buf := make([]byte, size)
- if err := preadn(fd, buf, int(off+dataOff)); err != nil {
- return nil, errors.New("corrupt tzdata file " + file)
- }
- return buf, nil
- }
- return nil, syscall.ENOENT
-}
+var loadTzinfoFromTzdata func(file, name string) ([]byte, error)
// loadTzinfo returns the time zone information of the time zone
// with the given name, from a given source. A source may be a
@@ -414,13 +378,8 @@ func loadTzinfoFromTzdata(file, name string) ([]byte, error) {
func loadTzinfo(name string, source string) ([]byte, error) {
if len(source) >= 6 && source[len(source)-6:] == "tzdata" {
return loadTzinfoFromTzdata(source, name)
- } else if len(source) > 4 && source[len(source)-4:] == ".zip" {
- return loadTzinfoFromZip(source, name)
- }
- if source != "" {
- name = source + "/" + name
}
- return readFile(name)
+ return loadTzinfoFromDirOrZip(source, name)
}
// loadLocation returns the Location with the given name from one of