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