1// Copyright 2016 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5// Parse the "tzdata" packed timezone file used on Android. 6// The format is lifted from ZoneInfoDB.java and ZoneInfo.java in 7// java/libcore/util in the AOSP. 8 9package time 10 11import ( 12 "errors" 13 "syscall" 14) 15 16var platformZoneSources = []string{ 17 "/system/usr/share/zoneinfo/tzdata", 18 "/data/misc/zoneinfo/current/tzdata", 19} 20 21func initLocal() { 22 // TODO(elias.naur): getprop persist.sys.timezone 23 localLoc = *UTC 24} 25 26func init() { 27 loadTzinfoFromTzdata = androidLoadTzinfoFromTzdata 28} 29 30var allowGorootSource = true 31 32func gorootZoneSource(goroot string) (string, bool) { 33 if goroot == "" || !allowGorootSource { 34 return "", false 35 } 36 return goroot + "/lib/time/zoneinfo.zip", true 37} 38 39func androidLoadTzinfoFromTzdata(file, name string) ([]byte, error) { 40 const ( 41 headersize = 12 + 3*4 42 namesize = 40 43 entrysize = namesize + 3*4 44 ) 45 if len(name) > namesize { 46 return nil, errors.New(name + " is longer than the maximum zone name length (40 bytes)") 47 } 48 fd, err := open(file) 49 if err != nil { 50 return nil, err 51 } 52 defer closefd(fd) 53 54 buf := make([]byte, headersize) 55 if err := preadn(fd, buf, 0); err != nil { 56 return nil, errors.New("corrupt tzdata file " + file) 57 } 58 d := dataIO{buf, false} 59 if magic := d.read(6); string(magic) != "tzdata" { 60 return nil, errors.New("corrupt tzdata file " + file) 61 } 62 d = dataIO{buf[12:], false} 63 indexOff, _ := d.big4() 64 dataOff, _ := d.big4() 65 indexSize := dataOff - indexOff 66 entrycount := indexSize / entrysize 67 buf = make([]byte, indexSize) 68 if err := preadn(fd, buf, int(indexOff)); err != nil { 69 return nil, errors.New("corrupt tzdata file " + file) 70 } 71 for i := 0; i < int(entrycount); i++ { 72 entry := buf[i*entrysize : (i+1)*entrysize] 73 // len(name) <= namesize is checked at function entry 74 if string(entry[:len(name)]) != name { 75 continue 76 } 77 d := dataIO{entry[namesize:], false} 78 off, _ := d.big4() 79 size, _ := d.big4() 80 buf := make([]byte, size) 81 if err := preadn(fd, buf, int(off+dataOff)); err != nil { 82 return nil, errors.New("corrupt tzdata file " + file) 83 } 84 return buf, nil 85 } 86 return nil, syscall.ENOENT 87} 88