@ -105,7 +105,7 @@ static int addtype(zic_t, char const *, bool, bool, bool);
static void leapadd ( zic_t , bool , int , int ) ;
static void adjleap ( void ) ;
static void associate ( void ) ;
static void dolink ( const char * fromfield , const char * tofield ) ;
static void dolink ( const char * , const char * , bool ) ;
static char * * getfields ( char * buf ) ;
static zic_t gethms ( const char * string , const char * errstring ,
bool ) ;
@ -119,7 +119,7 @@ static bool inzsub(char **, int, bool);
static int itsdir ( const char * name ) ;
static bool is_alpha ( char a ) ;
static char lowerit ( char ) ;
static bool mkdirs ( char * ) ;
static void mkdirs ( char const * , bool ) ;
static void newabbr ( const char * abbr ) ;
static zic_t oadd ( zic_t t1 , zic_t t2 ) ;
static void outzone ( const struct zone * zp , int ntzones ) ;
@ -136,6 +136,15 @@ enum
{
PERCENT_Z_LEN_BOUND = sizeof " +995959 " - 1 } ;
/* If true, work around a bug in Qt 5.6.1 and earlier, which mishandles
tz binary files whose POSIX - TZ - style strings contain ' < ' ; see
QTBUG - 53071 < https : //bugreports.qt.io/browse/QTBUG-53071>. This
workaround will no longer be needed when Qt 5.6 .1 and earlier are
obsolete , say in the year 2021. */
enum
{
WORK_AROUND_QTBUG_53071 = true } ;
static int charcnt ;
static bool errors ;
static bool warnings ;
@ -346,6 +355,7 @@ static const int len_years[2] = {
static struct attype
{
zic_t at ;
bool dontmerge ;
unsigned char type ;
} * attypes ;
static zic_t gmtoffs [ TZ_MAX_TYPES ] ;
@ -410,7 +420,8 @@ growalloc(void *ptr, size_t itemsize, int nitems, int *nitems_alloc)
return ptr ;
else
{
int amax = INT_MAX < SIZE_MAX ? INT_MAX : SIZE_MAX ;
int nitems_max = INT_MAX - WORK_AROUND_QTBUG_53071 ;
int amax = nitems_max < SIZE_MAX ? nitems_max : SIZE_MAX ;
if ( ( amax - 1 ) / 3 * 2 < * nitems_alloc )
memory_exhausted ( _ ( " int overflow " ) ) ;
@ -478,17 +489,17 @@ warning(const char *string,...)
}
static void
close_file ( FILE * stream , char const * name )
close_file ( FILE * stream , char const * dir , char const * name )
{
char const * e = ( ferror ( stream ) ? _ ( " I/O error " )
: fclose ( stream ) ! = 0 ? strerror ( errno ) : NULL ) ;
if ( e )
{
fprintf ( stderr , " %s: " , progname ) ;
if ( name )
fprintf ( stderr , " %s: " , name ) ;
fprintf ( stderr , " %s \n " , e ) ;
fprintf ( stderr , " %s: %s%s%s%s%s \n " , progname ,
dir ? dir : " " , dir ? " / " : " " ,
name ? name : " " , name ? " : " : " " ,
e ) ;
exit ( EXIT_FAILURE ) ;
}
}
@ -503,10 +514,34 @@ usage(FILE *stream, int status)
" Report bugs to %s. \n " ) ,
progname , progname , PACKAGE_BUGREPORT ) ;
if ( status = = EXIT_SUCCESS )
close_file ( stream , NULL ) ;
close_file ( stream , NULL , NULL ) ;
exit ( status ) ;
}
/* Change the working directory to DIR, possibly creating DIR and its
ancestors . After this is done , all files are accessed with names
relative to DIR . */
static void
change_directory ( char const * dir )
{
if ( chdir ( dir ) ! = 0 )
{
int chdir_errno = errno ;
if ( chdir_errno = = ENOENT )
{
mkdirs ( dir , false ) ;
chdir_errno = chdir ( dir ) = = 0 ? 0 : errno ;
}
if ( chdir_errno ! = 0 )
{
fprintf ( stderr , _ ( " %s: Can't chdir to %s: %s \n " ) ,
progname , dir , strerror ( chdir_errno ) ) ;
exit ( EXIT_FAILURE ) ;
}
}
}
static const char * psxrules ;
static const char * lcltime ;
static const char * directory ;
@ -534,7 +569,7 @@ main(int argc, char *argv[])
if ( strcmp ( argv [ i ] , " --version " ) = = 0 )
{
printf ( " zic %s \n " , PG_VERSION ) ;
close_file ( stdout , NULL ) ;
close_file ( stdout , NULL , NULL ) ;
return EXIT_SUCCESS ;
}
else if ( strcmp ( argv [ i ] , " --help " ) = = 0 )
@ -630,6 +665,7 @@ main(int argc, char *argv[])
if ( errors )
return EXIT_FAILURE ;
associate ( ) ;
change_directory ( directory ) ;
for ( i = 0 ; i < nzones ; i = j )
{
/*
@ -646,7 +682,7 @@ main(int argc, char *argv[])
for ( i = 0 ; i < nlinks ; + + i )
{
eat ( links [ i ] . l_filename , links [ i ] . l_linenum ) ;
dolink ( links [ i ] . l_from , links [ i ] . l_to ) ;
dolink ( links [ i ] . l_from , links [ i ] . l_to , false ) ;
if ( noise )
for ( j = 0 ; j < nlinks ; + + j )
if ( strcmp ( links [ i ] . l_to ,
@ -656,12 +692,12 @@ main(int argc, char *argv[])
if ( lcltime ! = NULL )
{
eat ( _ ( " command line " ) , 1 ) ;
dolink ( lcltime , TZDEFAULT ) ;
dolink ( lcltime , TZDEFAULT , true ) ;
}
if ( psxrules ! = NULL )
{
eat ( _ ( " command line " ) , 1 ) ;
dolink ( psxrules , TZDEFRULES ) ;
dolink ( psxrules , TZDEFRULES , true ) ;
}
if ( warnings & & ( ferror ( stderr ) | | fclose ( stderr ) ! = 0 ) )
return EXIT_FAILURE ;
@ -751,131 +787,117 @@ namecheck(const char *name)
return componentcheck ( name , component , cp ) ;
}
static char *
relname ( char const * dir , char const * base )
{
if ( * base = = ' / ' )
return ecpyalloc ( base ) ;
else
{
size_t dir_len = strlen ( dir ) ;
bool needs_slash = dir_len & & dir [ dir_len - 1 ] ! = ' / ' ;
char * result = emalloc ( dir_len + needs_slash + strlen ( base ) + 1 ) ;
result [ dir_len ] = ' / ' ;
strcpy ( result + dir_len + needs_slash , base ) ;
return memcpy ( result , dir , dir_len ) ;
}
}
static void
dolink ( char const * fromfield , char const * tofield )
dolink ( char const * fromfield , char const * tofield , bool staysymlink )
{
char * fromname ;
char * toname ;
int fromisdir ;
fromname = relname ( directory , fromfield ) ;
toname = relname ( directory , tofield ) ;
bool todirs_made = false ;
int link_errno ;
/*
* We get to be careful here since there ' s a fair chance of root running
* us .
*/
fromisdir = itsdir ( fromname ) ;
fromisdir = itsdir ( fromfield ) ;
if ( fromisdir )
{
char const * e = strerror ( fromisdir < 0 ? errno : EPERM ) ;
fprintf ( stderr , _ ( " %s: link from %s failed: %s " ) ,
progname , fromname , e ) ;
fprintf ( stderr , _ ( " %s: link from %s/%s failed: %s \n " ) ,
progname , directory , fromfield , e ) ;
exit ( EXIT_FAILURE ) ;
}
if ( link ( fromname , toname ) ! = 0 )
if ( staysymlink )
staysymlink = itsdir ( tofield ) = = 2 ;
if ( remove ( tofield ) = = 0 )
todirs_made = true ;
else if ( errno ! = ENOENT )
{
int link_errno = errno ;
bool retry_if_link_supported = false ;
char const * e = strerror ( errno ) ;
if ( link_errno = = ENOENT | | link_errno = = ENOTSUP )
fprintf ( stderr , _ ( " %s: Can't remove %s/%s: %s \n " ) ,
progname , directory , tofield , e ) ;
exit ( EXIT_FAILURE ) ;
}
link_errno = ( staysymlink ? ENOTSUP
: link ( fromfield , tofield ) = = 0 ? 0 : errno ) ;
if ( link_errno = = ENOENT & & ! todirs_made )
{
mkdirs ( tofield , true ) ;
todirs_made = true ;
link_errno = link ( fromfield , tofield ) = = 0 ? 0 : errno ;
}
if ( link_errno ! = 0 )
{
# ifdef HAVE_SYMLINK
const char * s = fromfield ;
const char * t ;
char * p ;
size_t dotdots = 0 ;
char * symlinkcontents ;
int symlink_errno ;
do
t = s ;
while ( ( s = strchr ( s , ' / ' ) )
& & strncmp ( fromfield , tofield , + + s - fromfield ) = = 0 ) ;
for ( s = tofield + ( t - fromfield ) ; * s ; s + + )
dotdots + = * s = = ' / ' ;
symlinkcontents = emalloc ( 3 * dotdots + strlen ( t ) + 1 ) ;
for ( p = symlinkcontents ; dotdots - - ! = 0 ; p + = 3 )
memcpy ( p , " ../ " , 3 ) ;
strcpy ( p , t ) ;
symlink_errno = symlink ( symlinkcontents , tofield ) = = 0 ? 0 : errno ;
if ( symlink_errno = = ENOENT & & ! todirs_made )
{
if ( ! mkdirs ( toname ) )
exit ( EXIT_FAILURE ) ;
retry_if_link_supported = true ;
mkdirs ( tofield , true ) ;
symlink_errno = symlink ( symlinkcontents , tofield ) = = 0 ? 0 : errno ;
}
if ( ( link_errno = = EEXIST | | link_errno = = ENOTSUP )
& & itsdir ( toname ) = = 0
& & ( remove ( toname ) = = 0 | | errno = = ENOENT ) )
retry_if_link_supported = true ;
if ( retry_if_link_supported & & link_errno ! = ENOTSUP )
link_errno = link ( fromname , toname ) = = 0 ? 0 : errno ;
if ( link_errno ! = 0 )
free ( symlinkcontents ) ;
if ( symlink_errno = = 0 )
{
# ifdef HAVE_SYMLINK
const char * s = fromfield ;
const char * t ;
char * p ;
size_t dotdots = 0 ;
char * symlinkcontents ;
int symlink_result ;
do
t = s ;
while ( ( s = strchr ( s , ' / ' ) )
& & strncmp ( fromfield , tofield , + + s - fromfield ) = = 0 ) ;
for ( s = tofield + ( t - fromfield ) ; * s ; s + + )
dotdots + = * s = = ' / ' ;
symlinkcontents = emalloc ( 3 * dotdots + strlen ( t ) + 1 ) ;
for ( p = symlinkcontents ; dotdots - - ! = 0 ; p + = 3 )
memcpy ( p , " ../ " , 3 ) ;
strcpy ( p , t ) ;
symlink_result = symlink ( symlinkcontents , toname ) ;
free ( symlinkcontents ) ;
if ( symlink_result = = 0 )
{
if ( link_errno ! = ENOTSUP )
warning ( _ ( " symbolic link used because hard link failed: %s " ) ,
strerror ( link_errno ) ) ;
}
else
if ( link_errno ! = ENOTSUP )
warning ( _ ( " symbolic link used because hard link failed: %s " ) ,
strerror ( link_errno ) ) ;
}
else
# endif /* HAVE_SYMLINK */
{
FILE * fp ,
* tp ;
int c ;
{
FILE * fp ,
* tp ;
int c ;
fp = fopen ( fromname , " rb " ) ;
if ( ! fp )
{
const char * e = strerror ( errno ) ;
fp = fopen ( fromfield , " rb " ) ;
if ( ! fp )
{
char const * e = strerror ( errno ) ;
fprintf ( stderr ,
_ ( " %s: Can't read %s: %s \n " ) ,
progname , fromname , e ) ;
exit ( EXIT_FAILURE ) ;
}
tp = fopen ( toname , " wb " ) ;
if ( ! tp )
{
const char * e = strerror ( errno ) ;
fprintf ( stderr , _ ( " %s: Can't read %s/%s: %s \n " ) ,
progname , directory , fromfield , e ) ;
exit ( EXIT_FAILURE ) ;
}
tp = fopen ( tofield , " wb " ) ;
if ( ! tp )
{
char const * e = strerror ( errno ) ;
fprintf ( stderr ,
_ ( " %s: Can't create %s: %s \n " ) ,
progname , toname , e ) ;
exit ( EXIT_FAILURE ) ;
}
while ( ( c = getc ( fp ) ) ! = EOF )
putc ( c , tp ) ;
close_file ( fp , fromname ) ;
close_file ( tp , toname ) ;
if ( link_errno ! = ENOTSUP )
warning ( _ ( " copy used because hard link failed: %s " ) ,
strerror ( link_errno ) ) ;
fprintf ( stderr , _ ( " %s: Can't create %s/%s: %s \n " ) ,
progname , directory , tofield , e ) ;
exit ( EXIT_FAILURE ) ;
}
while ( ( c = getc ( fp ) ) ! = EOF )
putc ( c , tp ) ;
close_file ( fp , directory , fromfield ) ;
close_file ( tp , directory , tofield ) ;
if ( link_errno ! = ENOTSUP )
warning ( _ ( " copy used because hard link failed: %s " ) ,
strerror ( link_errno ) ) ;
else if ( symlink_errno ! = ENOTSUP )
warning ( _ ( " copy used because symbolic link failed: %s " ) ,
strerror ( symlink_errno ) ) ;
}
}
free ( fromname ) ;
free ( toname ) ;
}
# define TIME_T_BITS_IN_FILE 64
@ -888,10 +910,6 @@ static zic_t const max_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE);
* rounded downward to the negation of a power of two that is
* comfortably outside the error bounds .
*
* zic does not output time stamps before this , partly because they
* are physically suspect , and partly because GNOME mishandles them ; see
* GNOME bug 730332 < https : //bugzilla.gnome.org/show_bug.cgi?id=730332>.
*
* For the time of the Big Bang , see :
*
* Ade PAR , Aghanim N , Armitage - Caplan C et al . Planck 2013 results .
@ -913,26 +931,45 @@ static zic_t const max_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE);
# define BIG_BANG (- (((zic_t) 1) << 59))
# endif
static const zic_t big_bang_time = BIG_BANG ;
/* If true, work around GNOME bug 730332
< https : //bugzilla.gnome.org/show_bug.cgi?id=730332>
by refusing to output time stamps before BIG_BANG .
Such time stamps are physically suspect anyway .
/* Return 1 if NAME is a directory, 0 if it's something else, -1 if trouble. */
The GNOME bug is scheduled to be fixed in GNOME 3.22 , and if so
this workaround will no longer be needed when GNOME 3.21 and
earlier are obsolete , say in the year 2021. */
enum
{
WORK_AROUND_GNOME_BUG_730332 = true } ;
static const zic_t early_time = ( WORK_AROUND_GNOME_BUG_730332
? BIG_BANG
: MINVAL ( zic_t , TIME_T_BITS_IN_FILE ) ) ;
/* Return 1 if NAME is a directory, 2 if a symbolic link, 0 if
something else , - 1 ( setting errno ) if trouble . */
static int
itsdir ( char const * name )
{
struct stat st ;
int res = stat ( name , & st ) ;
int res = l stat( name , & st ) ;
# ifdef S_ISDIR
if ( res = = 0 )
return S_ISDIR ( st . st_mode ) ! = 0 ;
# endif
if ( res = = 0 | | errno = = EOVERFLOW )
{
char * nameslashdot = relname ( name , " . " ) ;
bool dir = stat ( nameslashdot , & st ) = = 0 | | errno = = EOVERFLOW ;
# ifdef S_ISDIR
return S_ISDIR ( st . st_mode ) ? 1 : S_ISLNK ( st . st_mode ) ? 2 : 0 ;
# else
size_t n = strlen ( name ) ;
char * nameslashdot = emalloc ( n + 3 ) ;
bool dir ;
memcpy ( nameslashdot , name , n ) ;
strcpy ( & nameslashdot [ n ] , & " /. " [ ! ( n & & name [ n - 1 ] ! = ' / ' ) ] ) ;
dir = lstat ( nameslashdot , & st ) = = 0 ;
free ( nameslashdot ) ;
return dir ;
# endif
}
return - 1 ;
}
@ -1129,7 +1166,7 @@ infile(const char *name)
}
free ( fields ) ;
}
close_file ( fp , filename ) ;
close_file ( fp , NULL , filename ) ;
if ( wantcont )
error ( _ ( " expected continuation line not found " ) ) ;
}
@ -1313,7 +1350,7 @@ inzsub(char **fields, int nfields, bool iscont)
z . z_filename = filename ;
z . z_linenum = linenum ;
z . z_gmtoff = gethms ( fields [ i_gmtoff ] , _ ( " invalid UT offset " ) , true ) ;
if ( ( cp = strchr ( fields [ i_format ] , ' % ' ) ) ! = 0 )
if ( ( cp = strchr ( fields [ i_format ] , ' % ' ) ) ! = NULL )
{
if ( ( * + + cp ! = ' s ' & & * cp ! = ' z ' ) | | strchr ( cp , ' % ' )
| | strchr ( fields [ i_format ] , ' / ' ) )
@ -1491,7 +1528,7 @@ inleap(char **fields, int nfields)
return ;
}
t = tadd ( t , tod ) ;
if ( t < big_bang _time)
if ( t < early _time)
{
error ( _ ( " leap second precedes Big Bang " ) ) ;
return ;
@ -1764,11 +1801,14 @@ writezone(const char *const name, const char *const string, char version)
int timecnt32 ,
timei32 ;
int pass ;
char * fullname ;
static const struct tzhead tzh0 ;
static struct tzhead tzh ;
zic_t * ats = emalloc ( size_product ( timecnt , sizeof * ats + 1 ) ) ;
void * typesptr = ats + timecnt ;
bool dir_checked = false ;
zic_t one = 1 ;
zic_t y2038_boundary = one < < 31 ;
int nats = timecnt + WORK_AROUND_QTBUG_53071 ;
zic_t * ats = emalloc ( size_product ( nats , sizeof * ats + 1 ) ) ;
void * typesptr = ats + nats ;
unsigned char * types = typesptr ;
/*
@ -1786,7 +1826,7 @@ writezone(const char *const name, const char *const string, char version)
toi = 0 ;
fromi = 0 ;
while ( fromi < timecnt & & attypes [ fromi ] . at < big_bang _time)
while ( fromi < timecnt & & attypes [ fromi ] . at < early _time)
+ + fromi ;
for ( ; fromi < timecnt ; + + fromi )
{
@ -1799,8 +1839,9 @@ writezone(const char *const name, const char *const string, char version)
attypes [ fromi ] . type ;
continue ;
}
if ( toi = = 0 | |
attypes [ toi - 1 ] . type ! = attypes [ fromi ] . type )
if ( toi = = 0
| | attypes [ fromi ] . dontmerge
| | attypes [ toi - 1 ] . type ! = attypes [ fromi ] . type )
attypes [ toi + + ] = attypes [ fromi ] ;
}
timecnt = toi ;
@ -1818,6 +1859,20 @@ writezone(const char *const name, const char *const string, char version)
types [ i ] = attypes [ i ] . type ;
}
/*
* Work around QTBUG - 53071 for time stamps less than y2038_boundary - 1 ,
* by inserting a no - op transition at time y2038_boundary - 1. This works
* only for timestamps before the boundary , which should be good enough in
* practice as QTBUG - 53071 should be long - dead by 2038.
*/
if ( WORK_AROUND_QTBUG_53071 & & timecnt ! = 0
& & ats [ timecnt - 1 ] < y2038_boundary - 1 & & strchr ( string , ' < ' ) )
{
ats [ timecnt ] = y2038_boundary - 1 ;
types [ timecnt ] = types [ timecnt - 1 ] ;
timecnt + + ;
}
/*
* Correct for leap seconds .
*/
@ -1862,29 +1917,35 @@ writezone(const char *const name, const char *const string, char version)
- - leapcnt32 ;
+ + leapi32 ;
}
fullname = relname ( directory , name ) ;
/*
* Remove old file , if any , to snap links .
*/
if ( itsdir ( fullname ) = = 0 & & remove ( fullname ) ! = 0 & & errno ! = ENOENT )
if ( remove ( name ) = = 0 )
dir_checked = true ;
else if ( errno ! = ENOENT )
{
const char * e = strerror ( errno ) ;
fprintf ( stderr , _ ( " %s: Cannot remove %s: %s \n " ) ,
progname , full name, e ) ;
fprintf ( stderr , _ ( " %s: Cannot remove %s/%s : %s \n " ) ,
progname , directory , name , e ) ;
exit ( EXIT_FAILURE ) ;
}
if ( ( fp = fopen ( fullname , " wb " ) ) = = NULL )
fp = fopen ( name , " wb " ) ;
if ( ! fp )
{
if ( ! mkdirs ( fullname ) )
exit ( EXIT_FAILURE ) ;
if ( ( fp = fopen ( fullname , " wb " ) ) = = NULL )
{
const char * e = strerror ( errno ) ;
int fopen_errno = errno ;
fprintf ( stderr , _ ( " %s: Cannot create %s: %s \n " ) ,
progname , fullname , e ) ;
if ( fopen_errno = = ENOENT & & ! dir_checked )
{
mkdirs ( name , true ) ;
fp = fopen ( name , " wb " ) ;
fopen_errno = errno ;
}
if ( ! fp )
{
fprintf ( stderr , _ ( " %s: Cannot create %s/%s: %s \n " ) ,
progname , directory , name , strerror ( fopen_errno ) ) ;
exit ( EXIT_FAILURE ) ;
}
}
@ -2130,9 +2191,8 @@ writezone(const char *const name, const char *const string, char version)
putc ( ttisgmts [ i ] , fp ) ;
}
fprintf ( fp , " \n %s \n " , string ) ;
close_file ( fp , full name) ;
close_file ( fp , directory , name ) ;
free ( ats ) ;
free ( fullname ) ;
}
static char const *
@ -2527,6 +2587,7 @@ outzone(const struct zone * zpfirst, int zonecount)
int compat ;
bool do_extend ;
char version ;
int lastatmax = - 1 ;
max_abbr_len = 2 + max_format_len + max_abbrvar_len ;
max_envvar_len = 2 * max_abbr_len + 5 * 9 ;
@ -2649,9 +2710,9 @@ outzone(const struct zone * zpfirst, int zonecount)
*/
stdoff = 0 ;
zp = & zpfirst [ i ] ;
usestart = i > 0 & & ( zp - 1 ) - > z_untiltime > big_bang _time;
usestart = i > 0 & & ( zp - 1 ) - > z_untiltime > early _time;
useuntil = i < ( zonecount - 1 ) ;
if ( useuntil & & zp - > z_untiltime < = big_bang _time)
if ( useuntil & & zp - > z_untiltime < = early _time)
continue ;
gmtoff = zp - > z_gmtoff ;
eat ( zp - > z_filename , zp - > z_linenum ) ;
@ -2670,7 +2731,7 @@ outzone(const struct zone * zpfirst, int zonecount)
usestart = false ;
}
else
addtt ( big_bang _time, type ) ;
addtt ( early _time, type ) ;
}
else
for ( year = min_year ; year < = max_year ; + + year )
@ -2792,6 +2853,10 @@ outzone(const struct zone * zpfirst, int zonecount)
offset = oadd ( zp - > z_gmtoff , rp - > r_stdoff ) ;
type = addtype ( offset , ab , rp - > r_stdoff ! = 0 ,
rp - > r_todisstd , rp - > r_todisgmt ) ;
if ( rp - > r_hiyear = = ZIC_MAX
& & ! ( 0 < = lastatmax
& & ktime < attypes [ lastatmax ] . at ) )
lastatmax = timecnt ;
addtt ( ktime , type ) ;
}
}
@ -2827,6 +2892,8 @@ outzone(const struct zone * zpfirst, int zonecount)
starttime = tadd ( starttime , - gmtoff ) ;
}
}
if ( 0 < = lastatmax )
attypes [ lastatmax ] . dontmerge = true ;
if ( do_extend )
{
/*
@ -2850,22 +2917,8 @@ outzone(const struct zone * zpfirst, int zonecount)
lastat = & attypes [ i ] ;
if ( lastat - > at < rpytime ( & xr , max_year - 1 ) )
{
/*
* Create new type code for the redundant entry , to prevent it
* being optimized away .
*/
if ( typecnt > = TZ_MAX_TYPES )
{
error ( _ ( " too many local time types " ) ) ;
exit ( EXIT_FAILURE ) ;
}
gmtoffs [ typecnt ] = gmtoffs [ lastat - > type ] ;
isdsts [ typecnt ] = isdsts [ lastat - > type ] ;
ttisstds [ typecnt ] = ttisstds [ lastat - > type ] ;
ttisgmts [ typecnt ] = ttisgmts [ lastat - > type ] ;
abbrinds [ typecnt ] = abbrinds [ lastat - > type ] ;
+ + typecnt ;
addtt ( rpytime ( & xr , max_year + 1 ) , typecnt - 1 ) ;
attypes [ timecnt - 1 ] . dontmerge = true ;
}
}
writezone ( zpfirst - > z_name , envvar , version ) ;
@ -2877,8 +2930,8 @@ outzone(const struct zone * zpfirst, int zonecount)
static void
addtt ( zic_t starttime , int type )
{
if ( starttime < = big_bang_time | |
( timecnt = = 1 & & attypes [ 0 ] . at < big_bang _time) )
if ( starttime < = early_time
| | ( timecnt = = 1 & & attypes [ 0 ] . at < early _time) )
{
gmtoffs [ 0 ] = gmtoffs [ type ] ;
isdsts [ 0 ] = isdsts [ type ] ;
@ -2894,6 +2947,7 @@ addtt(zic_t starttime, int type)
}
attypes = growalloc ( attypes , sizeof * attypes , timecnt , & timecnt_alloc ) ;
attypes [ timecnt ] . at = starttime ;
attypes [ timecnt ] . dontmerge = false ;
attypes [ timecnt ] . type = type ;
+ + timecnt ;
}
@ -3441,53 +3495,51 @@ newabbr(const char *string)
charcnt + = i ;
}
static bool
mkdirs ( char * argname )
/* Ensure that the directories of ARGNAME exist, by making any missing
ones . If ANCESTORS , do this only for ARGNAME ' s ancestors ; otherwise ,
do it for ARGNAME too . Exit with failure if there is trouble . */
static void
mkdirs ( char const * argname , bool ancestors )
{
char * name ;
char * cp ;
if ( argname = = NULL | | * argname = = ' \0 ' )
return true ;
cp = name = ecpyalloc ( argname ) ;
while ( ( cp = strchr ( cp + 1 , ' / ' ) ) ! = NULL )
{
* cp = ' \0 ' ;
/* Do not mkdir a root directory, as it must exist. */
# ifdef WIN32
if ( is_alpha ( name [ 0 ] ) & & name [ 1 ] = = ' : ' )
cp + = 2 ;
# endif
while ( * cp = = ' / ' )
cp + + ;
/*
* DOS drive specifier ?
*/
if ( is_alpha ( name [ 0 ] ) & & name [ 1 ] = = ' : ' & & name [ 2 ] = = ' \0 ' )
{
* cp = ' / ' ;
continue ;
}
# endif /* WIN32 */
while ( cp & & ( ( cp = strchr ( cp , ' / ' ) ) | | ! ancestors ) )
{
if ( cp )
* cp = ' \0 ' ;
/*
* Try to create it . It ' s OK if creation fails because the directory
* already exists , perhaps because some other process just created it .
* For simplicity do not check first whether it already exists , as
* that is checked anyway if the mkdir fails .
*/
if ( mkdir ( name , MKDIR_UMASK ) ! = 0 )
{
int err = errno ;
if ( itsdir ( name ) < = 0 )
if ( err ! = EEXIST & & itsdir ( name ) < 0 )
{
char const * e = strerror ( err ) ;
warning ( _ ( " %s: Can't create directory "
" %s: %s " ) ,
progname , name , e ) ;
free ( name ) ;
return false ;
error ( _ ( " %s: Cannot create directory %s: %s " ) ,
progname , name , strerror ( err ) ) ;
exit ( EXIT_FAILURE ) ;
}
}
* cp = ' / ' ;
if ( cp )
* cp + + = ' / ' ;
}
free ( name ) ;
return true ;
}