Updated to fedora-glibc-20061025T1857
[kopensolaris-gnu/glibc.git] / time / tzfile.c
index e2d9f50..e95fd55 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991-1993, 1995-2001, 2003 Free Software Foundation, Inc.
+/* Copyright (C) 1991-1993,1995-2001,2003,2004 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
+#include <sys/stat.h>
 
 #define        NOID
 #include <timezone/tzfile.h>
 
 int __use_tzfile;
+static dev_t tzfile_dev;
+static ino64_t tzfile_ino;
+static time_t tzfile_mtime;
 
 struct ttinfo
   {
@@ -97,19 +101,16 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
   size_t total_size;
   size_t types_idx;
   size_t leaps_idx;
+  int was_using_tzfile = __use_tzfile;
 
   __use_tzfile = 0;
 
-  if (transitions != NULL)
-    free ((void *) transitions);
-  transitions = NULL;
-
   if (file == NULL)
     /* No user specification; use the site-wide default.  */
     file = TZDEFAULT;
   else if (*file == '\0')
     /* User specified the empty string; use UTC with no leap seconds.  */
-    return;
+    goto ret_free_transitions;
   else
     {
       /* We must not allow to read an arbitrary file in a setuid
@@ -123,7 +124,7 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
              || strstr (file, "../") != NULL))
        /* This test is certainly a bit too restrictive but it should
           catch all critical cases.  */
-       return;
+       goto ret_free_transitions;
     }
 
   if (*file != '/')
@@ -148,11 +149,38 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
       file = new;
     }
 
+  /* If we were already using tzfile, check whether the file changed.  */
+  struct stat64 st;
+  if (was_using_tzfile
+      && stat64 (file, &st) == 0
+      && tzfile_ino == st.st_ino && tzfile_dev == st.st_dev
+      && tzfile_mtime == st.st_mtime)
+    {
+      /* Nothing to do.  */
+      __use_tzfile = 1;
+      return;
+    }
+
   /* Note the file is opened with cancellation in the I/O functions
      disabled.  */
   f = fopen (file, "rc");
   if (f == NULL)
-    return;
+    goto ret_free_transitions;
+
+  /* Get information about the file we are actually using.  */
+  if (fstat64 (fileno (f), &st) != 0)
+    {
+      fclose (f);
+      goto ret_free_transitions;
+    }
+
+  free ((void *) transitions);
+  transitions = NULL;
+
+  /* Remember the inode and device number and modification time.  */
+  tzfile_dev = st.st_dev;
+  tzfile_ino = st.st_ino;
+  tzfile_mtime = st.st_mtime;
 
   /* No threads reading this stream.  */
   __fsetlocking (f, FSETLOCKING_BYCALLER);
@@ -358,6 +386,9 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
 
  lose:
   fclose (f);
+ ret_free_transitions:
+  free ((void *) transitions);
+  transitions = NULL;
 }
 \f
 /* The user specified a hand-made timezone, but not its DST rules.
@@ -424,6 +455,12 @@ __tzfile_default (const char *std, const char *dst,
       isdst = trans_type->isdst;
     }
 
+  /* Now that we adjusted the transitions to the requested offsets,
+     reset the rule_stdoff and rule_dstoff values appropriately.  They
+     are used elsewhere.  */
+  rule_stdoff = stdoff;
+  rule_dstoff = dstoff;
+
   /* Reset types 0 and 1 to describe the user's settings.  */
   types[0].idx = 0;
   types[0].offset = stdoff;