#include #include /* * Access local time entries of zoneinfo files. * Formats 0 and 2 are supported, and 4-byte timestamps * * Copyright © 2008 M. Teichgräber * Contributed under the MIT license used in the rest of the distribution. */ #include "zoneinfo.h" static struct Zoneinfo { int timecnt; /* # of transition times */ int typecnt; /* # of local time types */ int charcnt; /* # of characters of time zone abbreviation strings */ uchar *ptime; uchar *ptype; uchar *ptt; uchar *pzone; } z; static uchar *tzdata; static uchar* readtzfile(char *file) { uchar *p; int fd; Dir *d; fd = open(file, OREAD); if (fd<0) return nil; d = dirfstat(fd); if (d==nil) return nil; p = malloc(d->length); if (p!=nil) readn(fd, p, d->length); free(d); close(fd); return p; } static char *zonefile; void tzfile(char *f) { if (tzdata!=nil) { free(tzdata); tzdata = nil; } z.timecnt = 0; zonefile = f; } static long get4(uchar *p) { return (p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]; } enum { TTinfosz = 4+1+1, }; static int parsehead(void) { uchar *p; int ver; ver = tzdata[4]; if (ver!=0) if (ver!='2') return -1; p = tzdata + 4 + 1 + 15; z.timecnt = get4(p+3*4); z.typecnt = get4(p+4*4); if (z.typecnt==0) return -1; z.charcnt = get4(p+5*4); z.ptime = p+6*4; z.ptype = z.ptime + z.timecnt*4; z.ptt = z.ptype + z.timecnt; z.pzone = z.ptt + z.typecnt*TTinfosz; return 0; } static void ttinfo(Tinfo *ti, int tti) { uchar *p; int i; i = z.ptype[tti]; assert(itzoff = get4(p); ti->dlflag = p[4]; assert(p[5]zone = (char*)z.pzone + p[5]; } static void readtimezone(void) { char *tmp; z.timecnt = 0; if(zonefile==nil) { if ((tmp=getenv("timezone"))!=nil) { tzdata = readtzfile(tmp); free(tmp); goto havedata; } zonefile = "/etc/localtime"; } tzdata = readtzfile(zonefile); if (tzdata==nil) return; havedata: if (strncmp("TZif", (char*)tzdata, 4)!=0) goto errfree; if (parsehead()==-1) { errfree: free(tzdata); tzdata = nil; z.timecnt = 0; return; } } static tlong gett4(uchar *p) { long l; l = get4(p); if (l<0) return 0; return l; } int zonetinfo(Tinfo *ti, int i) { if (tzdata==nil) readtimezone(); if (i<0 || i>=z.timecnt) return -1; ti->t = gett4(z.ptime + 4*i); ttinfo(ti, i); return i; } int zonelookuptinfo(Tinfo *ti, tlong t) { uchar *p; int i; tlong oldtt, tt; if (tzdata==nil) readtimezone(); oldtt = 0; p = z.ptime; for (i=0; i0) { ttinfo(ti, i-1); ti->t = oldtt; // fprint(2, "t:%ld off:%d dflag:%d %s\n", (long)ti->t, ti->tzoff, ti->dlflag, ti->zone); return i-1; } return -1; } void zonedump(int fd) { int i; uchar *p; tlong t; Tinfo ti; if (tzdata==nil) readtimezone(); p = z.ptime; for (i=0; i