Beispiel #1
0
static gboolean
collect_locales_from_localebin (void)
{
        gboolean found_locales = FALSE;
        const gchar *argv[] = { "locale", "-a", NULL };
        gchar **linep;
        g_auto (GStrv) lines = NULL;
        g_autofree gchar *output = NULL;

        if (g_spawn_sync (NULL, (gchar **) argv, NULL,
                          G_SPAWN_SEARCH_PATH|G_SPAWN_STDERR_TO_DEV_NULL,
                          NULL, NULL, &output, NULL, NULL, NULL) == FALSE)
                return FALSE;

        g_return_val_if_fail (output != NULL, FALSE);

        lines = g_strsplit (output, "\n", 0);
        if (lines) {
                linep = lines;
                while (*linep) {
                        if (*linep[0] && add_locale (*linep, TRUE))
                                found_locales = TRUE;
                        linep++;
                }
        }

        return found_locales;
}
Beispiel #2
0
static gboolean
collect_locales_from_directory (void)
{
        gboolean found_locales = FALSE;
        struct dirent **dirents;
        int             ndirents;
        int             cnt;

        ndirents = scandir (LIBLOCALEDIR, &dirents, select_dirs, alphasort);

        for (cnt = 0; cnt < ndirents; ++cnt) {
                if (add_locale (dirents[cnt]->d_name, TRUE))
                        found_locales = TRUE;
        }

        if (ndirents > 0) {
                free (dirents);
        }
        return found_locales;
}
static void
enlarge_archive (struct locarhandle *ah, const struct locarhead *head)
{
  struct stat64 st;
  int fd;
  struct locarhead newhead;
  size_t total;
  void *p;
  unsigned int cnt, loccnt;
  struct namehashent *oldnamehashtab;
  struct locrecent *oldlocrectab;
  struct locarhandle new_ah;
  struct oldlocrecent *oldlocrecarray;
  size_t prefix_len = output_prefix ? strlen (output_prefix) : 0;
  char archivefname[prefix_len + sizeof (ARCHIVE_NAME)];
  char fname[prefix_len + sizeof (ARCHIVE_NAME) + sizeof (".XXXXXX") - 1];

  if (output_prefix)
    memcpy (archivefname, output_prefix, prefix_len);
  strcpy (archivefname + prefix_len, ARCHIVE_NAME);
  strcpy (stpcpy (fname, archivefname), ".XXXXXX");

  /* Not all of the old file has to be mapped.  Change this now this
     we will have to access the whole content.  */
  if (fstat64 (ah->fd, &st) != 0)
  enomap:
    error (EXIT_FAILURE, errno, _("cannot map locale archive file"));

  if (st.st_size < ah->reserved)
    ah->addr = mmap64 (ah->addr, st.st_size, PROT_READ | PROT_WRITE,
		       MAP_SHARED | MAP_FIXED, ah->fd, 0);
  else
    {
      munmap (ah->addr, ah->reserved);
      ah->addr = mmap64 (NULL, st.st_size, PROT_READ | PROT_WRITE,
			 MAP_SHARED, ah->fd, 0);
      ah->reserved = st.st_size;
      head = ah->addr;
    }
  if (ah->addr == MAP_FAILED)
    goto enomap;
  ah->mmaped = st.st_size;

  /* Create a temporary file in the correct directory.  */
  fd = mkstemp (fname);
  if (fd == -1)
    error (EXIT_FAILURE, errno, _("cannot create temporary file"));

  /* Copy the existing head information.  */
  newhead = *head;

  /* Create the new archive header.  The sizes of the various tables
     should be double from what is currently used.  */
  newhead.namehash_size = MAX (next_prime (2 * newhead.namehash_used),
			       newhead.namehash_size);
  if (verbose)
    printf ("name: size: %u, used: %d, new: size: %u\n",
	    head->namehash_size, head->namehash_used, newhead.namehash_size);

  newhead.string_offset = (newhead.namehash_offset
			   + (newhead.namehash_size
			      * sizeof (struct namehashent)));
  /* Keep the string table size aligned to 4 bytes, so that
     all the struct { uint32_t } types following are happy.  */
  newhead.string_size = MAX ((2 * newhead.string_used + 3) & -4,
			     newhead.string_size);

  newhead.locrectab_offset = newhead.string_offset + newhead.string_size;
  newhead.locrectab_size = MAX (2 * newhead.locrectab_used,
				newhead.locrectab_size);

  newhead.sumhash_offset = (newhead.locrectab_offset
			    + (newhead.locrectab_size
			       * sizeof (struct locrecent)));
  newhead.sumhash_size = MAX (next_prime (2 * newhead.sumhash_used),
			      newhead.sumhash_size);

  total = (newhead.sumhash_offset
	   + newhead.sumhash_size * sizeof (struct sumhashent));

  /* The new file is empty now.  */
  newhead.namehash_used = 0;
  newhead.string_used = 0;
  newhead.locrectab_used = 0;
  newhead.sumhash_used = 0;

  /* Write out the header and create room for the other data structures.  */
  if (TEMP_FAILURE_RETRY (write (fd, &newhead, sizeof (newhead)))
      != sizeof (newhead))
    {
      int errval = errno;
      unlink (fname);
      error (EXIT_FAILURE, errval, _("cannot initialize archive file"));
    }

  if (ftruncate64 (fd, total) != 0)
    {
      int errval = errno;
      unlink (fname);
      error (EXIT_FAILURE, errval, _("cannot resize archive file"));
    }

  /* To prepare for enlargements of the mmaped area reserve some
     address space.  */
  size_t reserved = RESERVE_MMAP_SIZE;
  int xflags = 0;
  if (total < reserved
      && ((p = mmap64 (NULL, reserved, PROT_NONE, MAP_PRIVATE | MAP_ANON,
		       -1, 0)) != MAP_FAILED))
    xflags = MAP_FIXED;
  else
    {
      p = NULL;
      reserved = total;
    }

  /* Map the header and all the administration data structures.  */
  p = mmap64 (p, total, PROT_READ | PROT_WRITE, MAP_SHARED | xflags, fd, 0);
  if (p == MAP_FAILED)
    {
      int errval = errno;
      unlink (fname);
      error (EXIT_FAILURE, errval, _("cannot map archive header"));
    }

  /* Lock the new file.  */
  if (lockf64 (fd, F_LOCK, total) != 0)
    {
      int errval = errno;
      unlink (fname);
      error (EXIT_FAILURE, errval, _("cannot lock new archive"));
    }

  new_ah.mmaped = total;
  new_ah.addr = p;
  new_ah.fd = fd;
  new_ah.reserved = reserved;

  /* Walk through the hash name hash table to find out what data is
     still referenced and transfer it into the new file.  */
  oldnamehashtab = (struct namehashent *) ((char *) ah->addr
					   + head->namehash_offset);
  oldlocrectab = (struct locrecent *) ((char *) ah->addr
				       + head->locrectab_offset);

  /* Sort the old locrec table in order of data position.  */
  oldlocrecarray = alloca (sizeof (*oldlocrecarray) * head->namehash_size);
  for (cnt = 0, loccnt = 0; cnt < head->namehash_size; ++cnt)
    if (oldnamehashtab[cnt].locrec_offset != 0)
      {
	oldlocrecarray[loccnt].cnt = cnt;
	oldlocrecarray[loccnt++].locrec
	  = (struct locrecent *) ((char *) ah->addr
				  + oldnamehashtab[cnt].locrec_offset);
      }
  qsort (oldlocrecarray, loccnt, sizeof (struct oldlocrecent),
	 oldlocrecentcmp);

  uint32_t last_locrec_offset = 0;
  for (cnt = 0; cnt < loccnt; ++cnt)
    {
      /* Insert this entry in the new hash table.  */
      locale_data_t old_data;
      unsigned int idx;
      struct locrecent *oldlocrec = oldlocrecarray[cnt].locrec;

      for (idx = 0; idx < __LC_LAST; ++idx)
	if (idx != LC_ALL)
	  {
	    old_data[idx].size = oldlocrec->record[idx].len;
	    old_data[idx].addr
	      = ((char *) ah->addr + oldlocrec->record[idx].offset);

	    __md5_buffer (old_data[idx].addr, old_data[idx].size,
			  old_data[idx].sum);
	  }

      if (cnt > 0 && oldlocrecarray[cnt - 1].locrec == oldlocrec)
	{
	  const char *oldname
	    = ((char *) ah->addr
	       + oldnamehashtab[oldlocrecarray[cnt - 1].cnt].name_offset);

	  add_alias (&new_ah,
		     ((char *) ah->addr
		      + oldnamehashtab[oldlocrecarray[cnt].cnt].name_offset),
		     0, oldname, &last_locrec_offset);
	  continue;
	}

      last_locrec_offset =
	add_locale (&new_ah,
		    ((char *) ah->addr
		     + oldnamehashtab[oldlocrecarray[cnt].cnt].name_offset),
		    old_data, 0);
      if (last_locrec_offset == 0)
	error (EXIT_FAILURE, 0, _("cannot extend locale archive file"));
    }

  /* Make the file globally readable.  */
  if (fchmod (fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) == -1)
    {
      int errval = errno;
      unlink (fname);
      error (EXIT_FAILURE, errval,
	     _("cannot change mode of resized locale archive"));
    }

  /* Rename the new file.  */
  if (rename (fname, archivefname) != 0)
    {
      int errval = errno;
      unlink (fname);
      error (EXIT_FAILURE, errval, _("cannot rename new archive"));
    }

  /* Close the old file.  */
  close_archive (ah);

  /* Add the information for the new one.  */
  *ah = new_ah;
}