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; }
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; }