about summary refs log tree commit diff
path: root/locale/loadarchive.c
diff options
context:
space:
mode:
authorRoland McGrath <roland@gnu.org>2002-08-15 08:29:16 +0000
committerRoland McGrath <roland@gnu.org>2002-08-15 08:29:16 +0000
commit5bb9991493ae15a5acf56da410a1403afef957e5 (patch)
tree86e875cf20786e46a562dda35d204e01c40fbc50 /locale/loadarchive.c
parent26e9beb46e2c0b87ba4373be120e3c56d5164312 (diff)
downloadglibc-5bb9991493ae15a5acf56da410a1403afef957e5.tar.gz
glibc-5bb9991493ae15a5acf56da410a1403afef957e5.tar.xz
glibc-5bb9991493ae15a5acf56da410a1403afef957e5.zip
2002-08-15 Roland McGrath <roland@redhat.com>
	* locale/loadarchive.c (_nl_load_locale_from_archive): Don't read the
	header separately, just map an initial window of 2MB from the file
	and remap if that is not large enough to cover the whole header.
Diffstat (limited to 'locale/loadarchive.c')
-rw-r--r--locale/loadarchive.c78
1 files changed, 42 insertions, 36 deletions
diff --git a/locale/loadarchive.c b/locale/loadarchive.c
index 59ac916e29..845b9b0774 100644
--- a/locale/loadarchive.c
+++ b/locale/loadarchive.c
@@ -41,6 +41,10 @@
 /* Name of the locale archive file.  */
 static const char archfname[] = LOCALEDIR "/locale-archive";
 
+/* Size of initial mapping window, optimal if large enough to
+   cover the header plus the initial locale.  */
+#define ARCHIVE_MAPPING_WINDOW	(2 * 1024 * 1024)
+
 
 /* Record of contiguous pages already mapped from the locale archive.  */
 struct archmapped
@@ -174,6 +178,9 @@ _nl_load_locale_from_archive (int category, const char **namep)
   /* Make sure the archive is loaded.  */
   if (archmapped == NULL)
     {
+      void *result;
+      size_t headsize, mapsize;
+
       /* We do this early as a sign that we have tried to open the archive.
 	 If headmap.ptr remains null, that's an indication that we tried
 	 and failed, so we won't try again.  */
@@ -193,49 +200,48 @@ _nl_load_locale_from_archive (int category, const char **namep)
 	  return NULL;
 	}
 
-      if (sizeof (void *) > 4)
-	{
-	  /* We will just map the whole file, what the hell.  */
-	  void *result = __mmap64 (NULL, archive_stat.st_size,
-				   PROT_READ, MAP_SHARED, fd, 0);
-	  if (result == MAP_FAILED)
-	    goto close_and_out;
-	  /* Check whether the file is large enough for the sizes given in the
-	     header.  */
-	  if (calculate_head_size ((const struct locarhead *) result)
-	      > archive_stat.st_size)
-	    {
-	      (void) __munmap (result, archive_stat.st_size);
-	      goto close_and_out;
-	    }
-	  __close (fd);
-	  fd = -1;
 
-	  headmap.ptr = result;
-	  /* headmap.from already initialized to zero.  */
-	  headmap.len = archive_stat.st_size;
-	}
-      else
-	{
-	  struct locarhead head;
-	  off_t head_size;
-	  void *result;
+      /* Map an initial window probably large enough to cover the header
+	 and the first locale's data.  With a large address space, we can
+	 just map the whole file and be sure everything is covered.  */
 
-	  if (TEMP_FAILURE_RETRY (__read (fd, &head, sizeof (head)))
-	      != sizeof (head))
-	    goto close_and_out;
-	  head_size = calculate_head_size (&head);
-	  if (head_size > archive_stat.st_size)
+      mapsize = (sizeof (void *) > 4 ? archive_stat.st_size
+		 : MAX (archive_stat.st_size, ARCHIVE_MAPPING_WINDOW));
+
+      result = __mmap64 (NULL, mapsize, PROT_READ, MAP_SHARED, fd, 0);
+      if (result == MAP_FAILED)
+	goto close_and_out;
+
+      /* Check whether the file is large enough for the sizes given in
+	 the header.  Theoretically an archive could be so large that
+	 just the header fails to fit in our initial mapping window.  */
+      headsize = calculate_head_size ((const struct locarhead *) result);
+      if (headsize > mapsize)
+	{
+	  (void) __munmap (result, mapsize);
+	  if (sizeof (void *) > 4 || headsize > archive_stat.st_size)
+	    /* The file is not big enough for the header.  Bogus.  */
 	    goto close_and_out;
-	  result = __mmap64 (NULL, head_size, PROT_READ, MAP_SHARED, fd, 0);
+
+	  /* Freakishly long header.  */
+	  /* XXX could use mremap when available */
+	  mapsize = (headsize + ps - 1) & ~(ps - 1);
+	  result = __mmap64 (NULL, mapsize, PROT_READ, MAP_SHARED, fd, 0);
 	  if (result == MAP_FAILED)
 	    goto close_and_out;
+	}
 
-	  /* Record that we have mapped the initial pages of the file.  */
-	  headmap.ptr = result;
-	  headmap.len = MIN ((head_size + ps - 1) & ~(ps - 1),
-			     archive_stat.st_size);
+      if (sizeof (void *) > 4 || mapsize >= archive_stat.st_size)
+	{
+	  /* We've mapped the whole file already, so we can be
+	     sure we won't need this file descriptor later.  */
+	  __close (fd);
+	  fd = -1;
 	}
+
+      headmap.ptr = result;
+      /* headmap.from already initialized to zero.  */
+      headmap.len = mapsize;
     }
 
   /* If there is no archive or it cannot be loaded for some reason fail.  */