Source file
src/time/zoneinfo_read.go
1
2
3
4
5
6
7
8
9
10 package time
11
12 import (
13 "errors"
14 "internal/bytealg"
15 "runtime"
16 "syscall"
17 _ "unsafe"
18 )
19
20
21
22
23
24 func registerLoadFromEmbeddedTZData(f func(string) (string, error)) {
25 loadFromEmbeddedTZData = f
26 }
27
28
29
30
31
32 var loadFromEmbeddedTZData func(zipname string) (string, error)
33
34
35
36
37 const maxFileSize = 10 << 20
38
39 type fileSizeError string
40
41 func (f fileSizeError) Error() string {
42 return "time: file " + string(f) + " is too large"
43 }
44
45
46 const (
47 seekStart = 0
48 seekCurrent = 1
49 seekEnd = 2
50 )
51
52
53 type dataIO struct {
54 p []byte
55 error bool
56 }
57
58 func (d *dataIO) read(n int) []byte {
59 if len(d.p) < n {
60 d.p = nil
61 d.error = true
62 return nil
63 }
64 p := d.p[0:n]
65 d.p = d.p[n:]
66 return p
67 }
68
69 func (d *dataIO) big4() (n uint32, ok bool) {
70 p := d.read(4)
71 if len(p) < 4 {
72 d.error = true
73 return 0, false
74 }
75 return uint32(p[3]) | uint32(p[2])<<8 | uint32(p[1])<<16 | uint32(p[0])<<24, true
76 }
77
78 func (d *dataIO) big8() (n uint64, ok bool) {
79 n1, ok1 := d.big4()
80 n2, ok2 := d.big4()
81 if !ok1 || !ok2 {
82 d.error = true
83 return 0, false
84 }
85 return (uint64(n1) << 32) | uint64(n2), true
86 }
87
88 func (d *dataIO) byte() (n byte, ok bool) {
89 p := d.read(1)
90 if len(p) < 1 {
91 d.error = true
92 return 0, false
93 }
94 return p[0], true
95 }
96
97
98 func (d *dataIO) rest() []byte {
99 r := d.p
100 d.p = nil
101 return r
102 }
103
104
105 func byteString(p []byte) string {
106 if i := bytealg.IndexByte(p, 0); i != -1 {
107 p = p[:i]
108 }
109 return string(p)
110 }
111
112 var errBadData = errors.New("malformed time zone information")
113
114
115
116
117
118 func LoadLocationFromTZData(name string, data []byte) (*Location, error) {
119 d := dataIO{data, false}
120
121
122 if magic := d.read(4); string(magic) != "TZif" {
123 return nil, errBadData
124 }
125
126
127 var version int
128 var p []byte
129 if p = d.read(16); len(p) != 16 {
130 return nil, errBadData
131 } else {
132 switch p[0] {
133 case 0:
134 version = 1
135 case '2':
136 version = 2
137 case '3':
138 version = 3
139 default:
140 return nil, errBadData
141 }
142 }
143
144
145
146
147
148
149
150
151 const (
152 NUTCLocal = iota
153 NStdWall
154 NLeap
155 NTime
156 NZone
157 NChar
158 )
159 var n [6]int
160 for i := 0; i < 6; i++ {
161 nn, ok := d.big4()
162 if !ok {
163 return nil, errBadData
164 }
165 if uint32(int(nn)) != nn {
166 return nil, errBadData
167 }
168 n[i] = int(nn)
169 }
170
171
172
173
174
175
176 is64 := false
177 if version > 1 {
178
179 skip := n[NTime]*4 +
180 n[NTime] +
181 n[NZone]*6 +
182 n[NChar] +
183 n[NLeap]*8 +
184 n[NStdWall] +
185 n[NUTCLocal]
186
187 skip += 4 + 16
188 d.read(skip)
189
190 is64 = true
191
192
193 for i := 0; i < 6; i++ {
194 nn, ok := d.big4()
195 if !ok {
196 return nil, errBadData
197 }
198 if uint32(int(nn)) != nn {
199 return nil, errBadData
200 }
201 n[i] = int(nn)
202 }
203 }
204
205 size := 4
206 if is64 {
207 size = 8
208 }
209
210
211 txtimes := dataIO{d.read(n[NTime] * size), false}
212
213
214 txzones := d.read(n[NTime])
215
216
217 zonedata := dataIO{d.read(n[NZone] * 6), false}
218
219
220 abbrev := d.read(n[NChar])
221
222
223 d.read(n[NLeap] * (size + 4))
224
225
226
227 isstd := d.read(n[NStdWall])
228
229
230
231 isutc := d.read(n[NUTCLocal])
232
233 if d.error {
234 return nil, errBadData
235 }
236
237 var extend string
238 rest := d.rest()
239 if len(rest) > 2 && rest[0] == '\n' && rest[len(rest)-1] == '\n' {
240 extend = string(rest[1 : len(rest)-1])
241 }
242
243
244
245
246 nzone := n[NZone]
247 if nzone == 0 {
248
249
250 return nil, errBadData
251 }
252 zones := make([]zone, nzone)
253 for i := range zones {
254 var ok bool
255 var n uint32
256 if n, ok = zonedata.big4(); !ok {
257 return nil, errBadData
258 }
259 if uint32(int(n)) != n {
260 return nil, errBadData
261 }
262 zones[i].offset = int(int32(n))
263 var b byte
264 if b, ok = zonedata.byte(); !ok {
265 return nil, errBadData
266 }
267 zones[i].isDST = b != 0
268 if b, ok = zonedata.byte(); !ok || int(b) >= len(abbrev) {
269 return nil, errBadData
270 }
271 zones[i].name = byteString(abbrev[b:])
272 if runtime.GOOS == "aix" && len(name) > 8 && (name[:8] == "Etc/GMT+" || name[:8] == "Etc/GMT-") {
273
274
275 if name != "Etc/GMT+0" {
276
277 zones[i].name = name[4:]
278 }
279 }
280 }
281
282
283 tx := make([]zoneTrans, n[NTime])
284 for i := range tx {
285 var n int64
286 if !is64 {
287 if n4, ok := txtimes.big4(); !ok {
288 return nil, errBadData
289 } else {
290 n = int64(int32(n4))
291 }
292 } else {
293 if n8, ok := txtimes.big8(); !ok {
294 return nil, errBadData
295 } else {
296 n = int64(n8)
297 }
298 }
299 tx[i].when = n
300 if int(txzones[i]) >= len(zones) {
301 return nil, errBadData
302 }
303 tx[i].index = txzones[i]
304 if i < len(isstd) {
305 tx[i].isstd = isstd[i] != 0
306 }
307 if i < len(isutc) {
308 tx[i].isutc = isutc[i] != 0
309 }
310 }
311
312 if len(tx) == 0 {
313
314
315 tx = append(tx, zoneTrans{when: alpha, index: 0})
316 }
317
318
319 l := &Location{zone: zones, tx: tx, name: name, extend: extend}
320
321
322
323 sec, _, _ := now()
324 for i := range tx {
325 if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) {
326 l.cacheStart = tx[i].when
327 l.cacheEnd = omega
328 l.cacheZone = &l.zone[tx[i].index]
329 if i+1 < len(tx) {
330 l.cacheEnd = tx[i+1].when
331 } else if l.extend != "" {
332
333
334 if name, offset, estart, eend, isDST, ok := tzset(l.extend, l.cacheStart, sec); ok {
335 l.cacheStart = estart
336 l.cacheEnd = eend
337
338 if zoneIdx := findZone(l.zone, name, offset, isDST); zoneIdx != -1 {
339 l.cacheZone = &l.zone[zoneIdx]
340 } else {
341 l.cacheZone = &zone{
342 name: name,
343 offset: offset,
344 isDST: isDST,
345 }
346 }
347 }
348 }
349 break
350 }
351 }
352
353 return l, nil
354 }
355
356 func findZone(zones []zone, name string, offset int, isDST bool) int {
357 for i, z := range zones {
358 if z.name == name && z.offset == offset && z.isDST == isDST {
359 return i
360 }
361 }
362 return -1
363 }
364
365
366
367 func loadTzinfoFromDirOrZip(dir, name string) ([]byte, error) {
368 if len(dir) > 4 && dir[len(dir)-4:] == ".zip" {
369 return loadTzinfoFromZip(dir, name)
370 }
371 if dir != "" {
372 name = dir + "/" + name
373 }
374 return readFile(name)
375 }
376
377
378
379
380
381
382
383
384
385
386 func get4(b []byte) int {
387 if len(b) < 4 {
388 return 0
389 }
390 return int(b[0]) | int(b[1])<<8 | int(b[2])<<16 | int(b[3])<<24
391 }
392
393
394 func get2(b []byte) int {
395 if len(b) < 2 {
396 return 0
397 }
398 return int(b[0]) | int(b[1])<<8
399 }
400
401
402
403 func loadTzinfoFromZip(zipfile, name string) ([]byte, error) {
404 fd, err := open(zipfile)
405 if err != nil {
406 return nil, err
407 }
408 defer closefd(fd)
409
410 const (
411 zecheader = 0x06054b50
412 zcheader = 0x02014b50
413 ztailsize = 22
414
415 zheadersize = 30
416 zheader = 0x04034b50
417 )
418
419 buf := make([]byte, ztailsize)
420 if err := preadn(fd, buf, -ztailsize); err != nil || get4(buf) != zecheader {
421 return nil, errors.New("corrupt zip file " + zipfile)
422 }
423 n := get2(buf[10:])
424 size := get4(buf[12:])
425 off := get4(buf[16:])
426
427 buf = make([]byte, size)
428 if err := preadn(fd, buf, off); err != nil {
429 return nil, errors.New("corrupt zip file " + zipfile)
430 }
431
432 for i := 0; i < n; i++ {
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456 if get4(buf) != zcheader {
457 break
458 }
459 meth := get2(buf[10:])
460 size := get4(buf[24:])
461 namelen := get2(buf[28:])
462 xlen := get2(buf[30:])
463 fclen := get2(buf[32:])
464 off := get4(buf[42:])
465 zname := buf[46 : 46+namelen]
466 buf = buf[46+namelen+xlen+fclen:]
467 if string(zname) != name {
468 continue
469 }
470 if meth != 0 {
471 return nil, errors.New("unsupported compression for " + name + " in " + zipfile)
472 }
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490 buf = make([]byte, zheadersize+namelen)
491 if err := preadn(fd, buf, off); err != nil ||
492 get4(buf) != zheader ||
493 get2(buf[8:]) != meth ||
494 get2(buf[26:]) != namelen ||
495 string(buf[30:30+namelen]) != name {
496 return nil, errors.New("corrupt zip file " + zipfile)
497 }
498 xlen = get2(buf[28:])
499
500 buf = make([]byte, size)
501 if err := preadn(fd, buf, off+30+namelen+xlen); err != nil {
502 return nil, errors.New("corrupt zip file " + zipfile)
503 }
504
505 return buf, nil
506 }
507
508 return nil, syscall.ENOENT
509 }
510
511
512
513
514 var loadTzinfoFromTzdata func(file, name string) ([]byte, error)
515
516
517
518
519
520 func loadTzinfo(name string, source string) ([]byte, error) {
521 if len(source) >= 6 && source[len(source)-6:] == "tzdata" {
522 return loadTzinfoFromTzdata(source, name)
523 }
524 return loadTzinfoFromDirOrZip(source, name)
525 }
526
527
528
529
530
531 func loadLocation(name string, sources []string) (z *Location, firstErr error) {
532 for _, source := range sources {
533 zoneData, err := loadTzinfo(name, source)
534 if err == nil {
535 if z, err = LoadLocationFromTZData(name, zoneData); err == nil {
536 return z, nil
537 }
538 }
539 if firstErr == nil && err != syscall.ENOENT {
540 firstErr = err
541 }
542 }
543 if loadFromEmbeddedTZData != nil {
544 zoneData, err := loadFromEmbeddedTZData(name)
545 if err == nil {
546 if z, err = LoadLocationFromTZData(name, []byte(zoneData)); err == nil {
547 return z, nil
548 }
549 }
550 if firstErr == nil && err != syscall.ENOENT {
551 firstErr = err
552 }
553 }
554 if source, ok := gorootZoneSource(runtime.GOROOT()); ok {
555 zoneData, err := loadTzinfo(name, source)
556 if err == nil {
557 if z, err = LoadLocationFromTZData(name, zoneData); err == nil {
558 return z, nil
559 }
560 }
561 if firstErr == nil && err != syscall.ENOENT {
562 firstErr = err
563 }
564 }
565 if firstErr != nil {
566 return nil, firstErr
567 }
568 return nil, errors.New("unknown time zone " + name)
569 }
570
571
572
573
574
575 func readFile(name string) ([]byte, error) {
576 f, err := open(name)
577 if err != nil {
578 return nil, err
579 }
580 defer closefd(f)
581 var (
582 buf [4096]byte
583 ret []byte
584 n int
585 )
586 for {
587 n, err = read(f, buf[:])
588 if n > 0 {
589 ret = append(ret, buf[:n]...)
590 }
591 if n == 0 || err != nil {
592 break
593 }
594 if len(ret) > maxFileSize {
595 return nil, fileSizeError(name)
596 }
597 }
598 return ret, err
599 }
600
View as plain text