aboutsummaryrefslogtreecommitdiff
path: root/locale
diff options
context:
space:
mode:
Diffstat (limited to 'locale')
-rw-r--r--locale/Makefile9
-rw-r--r--locale/hashval.h41
-rw-r--r--locale/locarchive.h97
-rw-r--r--locale/programs/ld-address.c2
-rw-r--r--locale/programs/ld-collate.c4
-rw-r--r--locale/programs/ld-ctype.c3
-rw-r--r--locale/programs/ld-identification.c3
-rw-r--r--locale/programs/ld-measurement.c2
-rw-r--r--locale/programs/ld-messages.c2
-rw-r--r--locale/programs/ld-monetary.c2
-rw-r--r--locale/programs/ld-name.c2
-rw-r--r--locale/programs/ld-numeric.c2
-rw-r--r--locale/programs/ld-paper.c2
-rw-r--r--locale/programs/ld-telephone.c2
-rw-r--r--locale/programs/ld-time.c2
-rw-r--r--locale/programs/localedef.c95
-rw-r--r--locale/programs/localedef.h28
-rw-r--r--locale/programs/locarchive.c931
-rw-r--r--locale/programs/locfile.c61
-rw-r--r--locale/programs/locfile.h8
-rw-r--r--locale/programs/simple-hash.c30
-rw-r--r--locale/programs/simple-hash.h4
22 files changed, 1268 insertions, 64 deletions
diff --git a/locale/Makefile b/locale/Makefile
index 03ed1b66fa..7a773f104f 100644
--- a/locale/Makefile
+++ b/locale/Makefile
@@ -1,4 +1,4 @@
-# Copyright (C) 1991, 92, 1995-1999, 2000, 2001 Free Software Foundation, Inc.
+# Copyright (C) 1991,92,1995-1999,2000,2001,2002 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
@@ -26,6 +26,7 @@ distribute = localeinfo.h categories.def iso-639.def iso-3166.def \
iso-4217.def weight.h weightwc.h strlen-hash.h elem-hash.h \
indigits.h indigitswc.h outdigits.h outdigitswc.h \
coll-lookup.h C-translit.h.in C-translit.h gen-translit.pl \
+ locarchive.h \
$(addprefix programs/, \
locale.c localedef.c \
$(localedef-modules:=.c) $(locale-modules:=.c) \
@@ -33,7 +34,7 @@ distribute = localeinfo.h categories.def iso-639.def iso-3166.def \
charmap-kw.gperf charmap-kw.h locfile-token.h \
locfile-kw.gperf locfile-kw.h linereader.h \
locfile.h charmap.h repertoire.h localedef.h \
- 3level.h charmap-dir.h)
+ 3level.h charmap-dir.h locarchive.c)
routines = setlocale findlocale loadlocale localeconv nl_langinfo \
nl_langinfo_l mb_cur_max \
newlocale duplocale freelocale
@@ -54,12 +55,12 @@ extra-libs-others = $(extra-libs)
libBrokenLocale-routines = broken_cur_max
subdir-dirs = programs
-vpath %.c programs
+vpath %.c programs ../crypt
vpath %.h programs
vpath %.gperf programs
localedef-modules := $(categories:%=ld-%) charmap linereader locfile \
- repertoire
+ repertoire md5 locarchive
locale-modules := locale-spec
lib-modules := charmap-dir simple-hash xmalloc xstrdup
diff --git a/locale/hashval.h b/locale/hashval.h
new file mode 100644
index 0000000000..15ec1244cf
--- /dev/null
+++ b/locale/hashval.h
@@ -0,0 +1,41 @@
+/* Implement simple hashing table with string based keys.
+ Copyright (C) 1994-1997, 2000, 2001, 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, October 1994.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+unsigned long
+compute_hashval (key, keylen)
+ const void *key;
+ size_t keylen;
+{
+ size_t cnt;
+ unsigned long int hval;
+
+ /* Compute the hash value for the given string. The algorithm
+ is taken from [Aho,Sethi,Ullman], modified to reduce the number of
+ collisions for short strings with very varied bit patterns.
+ See http://www.clisp.org/haible/hashfunc.html. */
+ cnt = 0;
+ hval = keylen;
+ while (cnt < keylen)
+ {
+ hval = (hval << 9) | (hval >> (LONGBITS - 9));
+ hval += (unsigned long int) *(((char *) key) + cnt++);
+ }
+ return hval != 0 ? hval : ~((unsigned long) 0);
+}
diff --git a/locale/locarchive.h b/locale/locarchive.h
new file mode 100644
index 0000000000..2005989598
--- /dev/null
+++ b/locale/locarchive.h
@@ -0,0 +1,97 @@
+/* Definitions for locale archive handling.
+ Copyright (C) 2002 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
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _LOCARCHIVE_H
+#define _LOCARCHIVE_H 1
+
+#include <stdint.h>
+
+
+#define AR_MAGIC 0xde020109
+
+struct locarhead
+{
+ uint32_t magic;
+ /* Serial number. */
+ uint32_t serial;
+ /* Name hash table. */
+ uint32_t namehash_offset;
+ uint32_t namehash_used;
+ uint32_t namehash_size;
+ /* String table. */
+ uint32_t string_offset;
+ uint32_t string_used;
+ uint32_t string_size;
+ /* Table with locale records. */
+ uint32_t locrectab_offset;
+ uint32_t locrectab_used;
+ uint32_t locrectab_size;
+ /* MD5 sum hash table. */
+ uint32_t sumhash_offset;
+ uint32_t sumhash_used;
+ uint32_t sumhash_size;
+};
+
+
+struct namehashent
+{
+ /* Hash value of the name. */
+ uint32_t hashval;
+ /* Offset of the name in the string table. */
+ uint32_t name_offset;
+ /* Offset of the locale record. */
+ uint32_t locrec_offset;
+};
+
+
+struct sumhashent
+{
+ /* MD5 sum. */
+ char sum[16];
+ /* Offset of the file in the archive. */
+ uint32_t file_offset;
+};
+
+struct locrecent
+{
+ struct
+ {
+ uint32_t offset;
+ uint32_t len;
+ } record[__LC_LAST];
+};
+
+
+struct locarhandle
+{
+ int fd;
+ void *addr;
+ size_t len;
+};
+
+
+/* In memory data for the locales with their checksums. */
+typedef struct
+{
+ off64_t size;
+ void *addr;
+ char sum[16];
+} locale_data_t[__LC_LAST];
+
+#endif /* locarchive.h */
diff --git a/locale/programs/ld-address.c b/locale/programs/ld-address.c
index 52b91cfc28..5c8efaa282 100644
--- a/locale/programs/ld-address.c
+++ b/locale/programs/ld-address.c
@@ -422,7 +422,7 @@ address_output (struct localedef_t *locale, const struct charmap_t *charmap,
assert (cnt == 3 + _NL_ITEM_INDEX (_NL_NUM_LC_ADDRESS));
- write_locale_data (output_path, "LC_ADDRESS",
+ write_locale_data (output_path, LC_ADDRESS, "LC_ADDRESS",
3 + _NL_ITEM_INDEX (_NL_NUM_LC_ADDRESS), iov);
}
diff --git a/locale/programs/ld-collate.c b/locale/programs/ld-collate.c
index 191194799d..ca58266839 100644
--- a/locale/programs/ld-collate.c
+++ b/locale/programs/ld-collate.c
@@ -1987,7 +1987,7 @@ collate_output (struct localedef_t *locale, const struct charmap_t *charmap,
assert (cnt == _NL_ITEM_INDEX (_NL_NUM_LC_COLLATE));
- write_locale_data (output_path, "LC_COLLATE", 2 + cnt, iov);
+ write_locale_data (output_path, LC_COLLATE, "LC_COLLATE", 2 + cnt, iov);
return;
}
@@ -2571,7 +2571,7 @@ collate_output (struct localedef_t *locale, const struct charmap_t *charmap,
assert (cnt == _NL_ITEM_INDEX (_NL_NUM_LC_COLLATE));
- write_locale_data (output_path, "LC_COLLATE", 2 + cnt, iov);
+ write_locale_data (output_path, LC_COLLATE, "LC_COLLATE", 2 + cnt, iov);
obstack_free (&weightpool, NULL);
obstack_free (&extrapool, NULL);
diff --git a/locale/programs/ld-ctype.c b/locale/programs/ld-ctype.c
index 1026133dc2..eed2e94732 100644
--- a/locale/programs/ld-ctype.c
+++ b/locale/programs/ld-ctype.c
@@ -1214,7 +1214,8 @@ ctype_output (struct localedef_t *locale, const struct charmap_t *charmap,
assert (2 + elem + offset == (nelems + 2 * ctype->nr_charclass
+ ctype->map_collection_nr + 4 + 2));
- write_locale_data (output_path, "LC_CTYPE", 2 + elem + offset, iov);
+ write_locale_data (output_path, LC_CTYPE, "LC_CTYPE", 2 + elem + offset,
+ iov);
}
diff --git a/locale/programs/ld-identification.c b/locale/programs/ld-identification.c
index 481e4e79c4..ae5ea6fb16 100644
--- a/locale/programs/ld-identification.c
+++ b/locale/programs/ld-identification.c
@@ -291,7 +291,8 @@ identification_output (struct localedef_t *locale,
assert (cnt == (2 + _NL_ITEM_INDEX (_NL_NUM_LC_IDENTIFICATION)
+ (__LC_LAST - 2)));
- write_locale_data (output_path, "LC_IDENTIFICATION", cnt, iov);
+ write_locale_data (output_path, LC_IDENTIFICATION, "LC_IDENTIFICATION", cnt,
+ iov);
}
diff --git a/locale/programs/ld-measurement.c b/locale/programs/ld-measurement.c
index 75219bdf9f..2aa75b47dc 100644
--- a/locale/programs/ld-measurement.c
+++ b/locale/programs/ld-measurement.c
@@ -150,7 +150,7 @@ measurement_output (struct localedef_t *locale,
assert (cnt == 2 + _NL_ITEM_INDEX (_NL_NUM_LC_MEASUREMENT));
- write_locale_data (output_path, "LC_MEASUREMENT",
+ write_locale_data (output_path, LC_MEASUREMENT, "LC_MEASUREMENT",
2 + _NL_ITEM_INDEX (_NL_NUM_LC_MEASUREMENT), iov);
}
diff --git a/locale/programs/ld-messages.c b/locale/programs/ld-messages.c
index fadf82757f..d5cc393e4b 100644
--- a/locale/programs/ld-messages.c
+++ b/locale/programs/ld-messages.c
@@ -226,7 +226,7 @@ messages_output (struct localedef_t *locale, const struct charmap_t *charmap,
assert (cnt + 1 == 2 + _NL_ITEM_INDEX (_NL_NUM_LC_MESSAGES));
- write_locale_data (output_path, "LC_MESSAGES",
+ write_locale_data (output_path, LC_MESSAGES, "LC_MESSAGES",
2 + _NL_ITEM_INDEX (_NL_NUM_LC_MESSAGES), iov);
}
diff --git a/locale/programs/ld-monetary.c b/locale/programs/ld-monetary.c
index 4bb7c0bba4..4c36c505ba 100644
--- a/locale/programs/ld-monetary.c
+++ b/locale/programs/ld-monetary.c
@@ -612,7 +612,7 @@ monetary_output (struct localedef_t *locale, const struct charmap_t *charmap,
assert (cnt == 3 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY));
- write_locale_data (output_path, "LC_MONETARY",
+ write_locale_data (output_path, LC_MONETARY, "LC_MONETARY",
3 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY), iov);
}
diff --git a/locale/programs/ld-name.c b/locale/programs/ld-name.c
index 11e0ace7d6..80b42f7048 100644
--- a/locale/programs/ld-name.c
+++ b/locale/programs/ld-name.c
@@ -210,7 +210,7 @@ name_output (struct localedef_t *locale, const struct charmap_t *charmap,
assert (cnt == 2 + _NL_ITEM_INDEX (_NL_NUM_LC_NAME));
- write_locale_data (output_path, "LC_NAME",
+ write_locale_data (output_path, LC_NAME, "LC_NAME",
2 + _NL_ITEM_INDEX (_NL_NUM_LC_NAME), iov);
}
diff --git a/locale/programs/ld-numeric.c b/locale/programs/ld-numeric.c
index 6e385f2be6..594c0c8c1b 100644
--- a/locale/programs/ld-numeric.c
+++ b/locale/programs/ld-numeric.c
@@ -187,7 +187,7 @@ numeric_output (struct localedef_t *locale, const struct charmap_t *charmap,
assert (cnt + 1 == 3 + _NL_ITEM_INDEX (_NL_NUM_LC_NUMERIC));
- write_locale_data (output_path, "LC_NUMERIC",
+ write_locale_data (output_path, LC_NUMERIC, "LC_NUMERIC",
3 + _NL_ITEM_INDEX (_NL_NUM_LC_NUMERIC), iov);
}
diff --git a/locale/programs/ld-paper.c b/locale/programs/ld-paper.c
index 2dce9ca8da..2910954f04 100644
--- a/locale/programs/ld-paper.c
+++ b/locale/programs/ld-paper.c
@@ -154,7 +154,7 @@ paper_output (struct localedef_t *locale, const struct charmap_t *charmap,
assert (cnt == 2 + _NL_ITEM_INDEX (_NL_NUM_LC_PAPER));
- write_locale_data (output_path, "LC_PAPER",
+ write_locale_data (output_path, LC_PAPER, "LC_PAPER",
2 + _NL_ITEM_INDEX (_NL_NUM_LC_PAPER), iov);
}
diff --git a/locale/programs/ld-telephone.c b/locale/programs/ld-telephone.c
index 01dcf36008..5a60c016b0 100644
--- a/locale/programs/ld-telephone.c
+++ b/locale/programs/ld-telephone.c
@@ -218,7 +218,7 @@ telephone_output (struct localedef_t *locale, const struct charmap_t *charmap,
assert (cnt == 2 + _NL_ITEM_INDEX (_NL_NUM_LC_TELEPHONE));
- write_locale_data (output_path, "LC_TELEPHONE",
+ write_locale_data (output_path, LC_TELEPHONE, "LC_TELEPHONE",
2 + _NL_ITEM_INDEX (_NL_NUM_LC_TELEPHONE), iov);
}
diff --git a/locale/programs/ld-time.c b/locale/programs/ld-time.c
index 32d9dad971..2ff56b0034 100644
--- a/locale/programs/ld-time.c
+++ b/locale/programs/ld-time.c
@@ -906,7 +906,7 @@ time_output (struct localedef_t *locale, const struct charmap_t *charmap,
+ 2 + time->num_era * 10 - 1));
assert (last_idx == _NL_ITEM_INDEX (_NL_NUM_LC_TIME));
- write_locale_data (output_path, "LC_TIME", 2 + cnt, iov);
+ write_locale_data (output_path, LC_TIME, "LC_TIME", 2 + cnt, iov);
}
diff --git a/locale/programs/localedef.c b/locale/programs/localedef.c
index 3c159560e9..526f2025e7 100644
--- a/locale/programs/localedef.c
+++ b/locale/programs/localedef.c
@@ -27,6 +27,7 @@
#include <libintl.h>
#include <locale.h>
#include <mcheck.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -56,7 +57,8 @@ int verbose;
/* If not zero suppress warnings and information messages. */
int be_quiet;
-/* If not zero, produce old-style hash table instead of 3-level access tables. */
+/* If not zero, produce old-style hash table instead of 3-level access
+ tables. */
int oldstyle_tables;
/* If not zero force output even if warning were issued. */
@@ -77,15 +79,38 @@ const char *repertoire_global;
/* List of all locales. */
static struct localedef_t *locales;
+/* If true don't add locale data to archive. */
+bool no_archive;
+
+/* If true add named locales to archive. */
+static bool add_to_archive;
+
+/* If true delete named locales from archive. */
+static bool delete_from_archive;
+
+/* If true replace archive content when adding. */
+static bool replace_archive;
+
+/* If true list archive content. */
+static bool list_archive;
+
+/* Maximum number of retries when opening the locale archive. */
+int max_locarchive_open_retry = 10;
+
/* Name and version of program. */
static void print_version (FILE *stream, struct argp_state *state);
void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
-#define OPT_POSIX 1
-#define OPT_QUIET 2
-#define OPT_OLDSTYLE 3
-#define OPT_PREFIX 4
+#define OPT_POSIX 301
+#define OPT_QUIET 302
+#define OPT_OLDSTYLE 303
+#define OPT_PREFIX 304
+#define OPT_NO_ARCHIVE 305
+#define OPT_ADD_TO_ARCHIVE 306
+#define OPT_REPLACE 307
+#define OPT_DELETE_FROM_ARCHIVE 308
+#define OPT_LIST_ARCHIVE 309
/* Definitions of arguments for argp functions. */
static const struct argp_option options[] =
@@ -106,6 +131,15 @@ static const struct argp_option options[] =
{ "quiet", OPT_QUIET, NULL, 0,
N_("Suppress warnings and information messages") },
{ "verbose", 'v', NULL, 0, N_("Print more messages") },
+ { NULL, 0, NULL, 0, N_("Archive control:") },
+ { "no-archive", OPT_NO_ARCHIVE, NULL, 0,
+ N_("Don't add new data to archive") },
+ { "add-to-archive", OPT_ADD_TO_ARCHIVE, NULL, 0,
+ N_("Add locales named by parameters to archive") },
+ { "replace", OPT_REPLACE, NULL, 0, N_("Replace existing archive content") },
+ { "delete-from-archive", OPT_DELETE_FROM_ARCHIVE, NULL, 0,
+ N_("Remove locales named by parameters from archive") },
+ { "list-archive", OPT_LIST_ARCHIVE, NULL, 0, N_("List content of archive") },
{ NULL, 0, NULL, 0, NULL }
};
@@ -113,7 +147,10 @@ static const struct argp_option options[] =
static const char doc[] = N_("Compile locale specification");
/* Strings for arguments in help texts. */
-static const char args_doc[] = N_("NAME");
+static const char args_doc[] = N_("\
+NAME\n\
+[--add-to-archive|--delete-from-archive] FILE...\n\
+--list-archive [FILE]");
/* Prototype for option handler. */
static error_t parse_opt (int key, char *arg, struct argp_state *state);
@@ -163,6 +200,15 @@ main (int argc, char *argv[])
argp_err_exit_status = 4;
argp_parse (&argp, argc, argv, 0, &remaining, NULL);
+ /* Handle a few special cases. */
+ if (list_archive)
+ show_archive_content ();
+ if (add_to_archive)
+ return add_locales_to_archive (argc - remaining, &argv[remaining],
+ replace_archive);
+ if (delete_from_archive)
+ return delete_locales_from_archive (argc - remaining, &argv[remaining]);
+
/* POSIX.2 requires to be verbose about missing characters in the
character map. */
verbose |= posix_conformance;
@@ -177,10 +223,18 @@ main (int argc, char *argv[])
/* The parameter describes the output path of the constructed files.
If the described files cannot be written return a NULL pointer. */
- output_path = construct_output_path (argv[remaining]);
- if (output_path == NULL)
- error (4, errno, _("cannot create directory for output files"));
- cannot_write_why = errno;
+ if (no_archive)
+ {
+ output_path = construct_output_path (argv[remaining]);
+ if (output_path == NULL)
+ error (4, errno, _("cannot create directory for output files"));
+ cannot_write_why = errno;
+ }
+ else
+ {
+ output_path = NULL;
+ cannot_write_why = 0; /* Just to shut the compiler up. */
+ }
/* Now that the parameters are processed we have to reset the local
ctype locale. (P1003.2 4.35.5.2) */
@@ -235,7 +289,7 @@ cannot open locale definition file `%s'"), runp->name));
WITH_CUR_LOCALE (error (4, cannot_write_why, _("\
cannot write output files to `%s'"), output_path));
else
- write_all_categories (locales, charmap, output_path);
+ write_all_categories (locales, charmap, argv[remaining], output_path);
}
else
WITH_CUR_LOCALE (error (4, 0, _("\
@@ -264,6 +318,21 @@ parse_opt (int key, char *arg, struct argp_state *state)
case OPT_PREFIX:
output_prefix = arg;
break;
+ case OPT_NO_ARCHIVE:
+ no_archive = true;
+ break;
+ case OPT_ADD_TO_ARCHIVE:
+ add_to_archive = true;
+ break;
+ case OPT_REPLACE:
+ replace_archive = true;
+ break;
+ case OPT_DELETE_FROM_ARCHIVE:
+ delete_from_archive = true;
+ break;
+ case OPT_LIST_ARCHIVE:
+ list_archive = true;
+ break;
case 'c':
force_output = 1;
break;
@@ -392,6 +461,10 @@ construct_output_path (char *path)
size_t len = strlen (path) + 1;
result = xmalloc (len + 1);
endp = mempcpy (result, path, len) - 1;
+
+ /* If the user specified an output path we cannot add the output
+ to the archive. */
+ no_archive = true;
}
errno = 0;
diff --git a/locale/programs/localedef.h b/locale/programs/localedef.h
index 717962e10b..9567845080 100644
--- a/locale/programs/localedef.h
+++ b/locale/programs/localedef.h
@@ -1,5 +1,5 @@
/* General definitions for localedef(1).
- Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
@@ -22,11 +22,13 @@
#define _LOCALEDEF_H 1
/* Get the basic locale definitions. */
+#include <errno.h>
#include <locale.h>
+#include <stdbool.h>
#include <stddef.h>
-#include <errno.h>
#include "repertoire.h"
+#include "../locarchive.h"
/* We need a bitmask for the locales. */
@@ -114,6 +116,8 @@ extern int verbose;
extern int be_quiet;
extern int oldstyle_tables;
extern const char *repertoire_global;
+extern int max_locarchive_open_retry;
+extern bool no_archive;
/* Prototypes for a few program-wide used functions. */
@@ -153,4 +157,24 @@ extern struct localedef_t *load_locale (int locale, const char *name,
const struct charmap_t *charmap,
struct localedef_t *copy_locale);
+
+/* Open the locale archive. */
+extern void open_archive (struct locarhandle *ah);
+
+/* Close the locale archive. */
+extern void close_archive (struct locarhandle *ah);
+
+/* Add given locale data to the archive. */
+extern int add_locale_to_archive (struct locarhandle *ah, const char *name,
+ locale_data_t data, bool replace);
+
+/* Add content of named directories to locale archive. */
+extern int add_locales_to_archive (size_t nlist, char *list[], bool replace);
+
+/* Removed named locales from archive. */
+extern int delete_locales_from_archive (size_t nlist, char *list[]);
+
+/* List content of locale archive. */
+extern void show_archive_content (void);
+
#endif /* localedef.h */
diff --git a/locale/programs/locarchive.c b/locale/programs/locarchive.c
new file mode 100644
index 0000000000..861dd5bd68
--- /dev/null
+++ b/locale/programs/locarchive.c
@@ -0,0 +1,931 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <libintl.h>
+#include <locale.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include "../../crypt/md5.h"
+#include "../localeinfo.h"
+#include "../locarchive.h"
+#include "simple-hash.h"
+#include "localedef.h"
+
+
+static const char archivefname[] = LOCALEDIR "/locale-archive";
+
+static const char *locnames[] =
+ {
+#define DEFINE_CATEGORY(category, category_name, items, a) \
+ [category] = category_name,
+#include "categories.def"
+#undef DEFINE_CATEGORY
+ };
+
+
+/* Size of the initial archive header. */
+#define INITIAL_NUM_NANES 450
+#define INITIAL_SIZE_STRINGS 3500
+#define INITIAL_NUM_LOCREC 350
+#define INITIAL_NUM_SUMS 2000
+
+
+static void
+create_archive (struct locarhandle *ah)
+{
+ int fd;
+ char fname[] = LOCALEDIR "/locale-archive.XXXXXX";
+ struct locarhead head;
+ void *p;
+ size_t total;
+
+ /* Create a temporary file in the correct directory. */
+ fd = mkstemp (fname);
+ if (fd == -1)
+ error (EXIT_FAILURE, errno, _("cannot create temporary file"));
+
+ /* Create the initial content of the archive. */
+ head.magic = AR_MAGIC;
+ head.namehash_offset = sizeof (struct locarhead);
+ head.namehash_used = 0;
+ head.namehash_size = next_prime (INITIAL_NUM_NANES);
+
+ head.string_offset = (head.namehash_offset
+ + head.namehash_size * sizeof (struct namehashent));
+ head.string_used = 0;
+ head.string_size = INITIAL_SIZE_STRINGS;
+
+ head.locrectab_offset = head.string_offset + head.string_size;
+ head.locrectab_used = 0;
+ head.locrectab_size = INITIAL_NUM_LOCREC;
+
+ head.sumhash_offset = (head.locrectab_offset
+ + head.locrectab_size * sizeof (struct locrecent));
+ head.sumhash_used = 0;
+ head.sumhash_size = next_prime (INITIAL_NUM_SUMS);
+
+ total = head.sumhash_offset + head.sumhash_size * sizeof (struct sumhashent);
+
+ /* Write out the header and create room for the other data structures. */
+ if (TEMP_FAILURE_RETRY (write (fd, &head, sizeof (head))) != sizeof (head))
+ {
+ 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"));
+ }
+
+ /* Map the header and all the administration data structures. */
+ p = mmap64 (NULL, total, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (p == MAP_FAILED)
+ {
+ int errval = errno;
+ unlink (fname);
+ error (EXIT_FAILURE, errval, _("cannot map archive header"));
+ }
+
+ /* Now try to rename it. We don't use the rename function since
+ this would overwrite a file which has been created in
+ parallel. */
+ if (link (fname, archivefname) == -1)
+ {
+ int errval = errno;
+
+ /* We cannot use the just created file. */
+ close (fd);
+ unlink (fname);
+
+ if (errval == EEXIST)
+ {
+ /* There is already an archive. Must have been a localedef run
+ which happened in parallel. Simply open this file then. */
+ open_archive (ah);
+ return;
+ }
+
+ error (EXIT_FAILURE, errval, _("failed to create new locale archive"));
+ }
+
+ /* Remove the temporary name. */
+ unlink (fname);
+
+ /* Make the file globally readable. */
+ if (fchmod (fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) == -1)
+ {
+ int errval = errno;
+ unlink (archivefname);
+ error (EXIT_FAILURE, errval,
+ _("cannot change mode of new locale archive"));
+ }
+
+ ah->fd = fd;
+ ah->addr = p;
+ ah->len = total;
+}
+
+
+static void
+enlarge_archive (struct locarhandle *ah, const struct locarhead *head)
+{
+ struct stat64 st;
+ int fd;
+ char fname[] = LOCALEDIR "/locale-archive.XXXXXX";
+ struct locarhead newhead;
+ size_t total;
+ void *p;
+ unsigned int cnt;
+ struct namehashent *oldnamehashtab;
+ struct locrecent *oldlocrectab;
+ struct locarhandle new_ah;
+
+ /* 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
+ || (ah->addr = mmap64 (NULL, st.st_size, PROT_READ | PROT_WRITE,
+ MAP_SHARED, ah->fd, 0)) == MAP_FAILED)
+ error (EXIT_FAILURE, errno, _("cannot map locale archive file"));
+ ah->len = 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);
+ 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)));
+ newhead.string_size = MAX (2 * newhead.string_used, 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"));
+ }
+
+ /* Map the header and all the administration data structures. */
+ p = mmap64 (NULL, total, PROT_READ | PROT_WRITE, MAP_SHARED, 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.len = total;
+ new_ah.addr = p;
+ new_ah.fd = fd;
+
+ /* 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);
+ for (cnt = 0; cnt < head->namehash_size; ++cnt)
+ if (oldnamehashtab[cnt].locrec_offset != 0)
+ {
+ /* Insert this entry in the new hash table. */
+ locale_data_t old_data;
+ unsigned int idx;
+ struct locrecent *oldlocrec;
+
+ oldlocrec = (struct locrecent *) ((char *) ah->addr
+ + oldnamehashtab[cnt].locrec_offset);
+
+ 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 (add_locale_to_archive (&new_ah,
+ ((char *) ah->addr
+ + oldnamehashtab[cnt].name_offset),
+ old_data, 0) != 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;
+}
+
+
+void
+open_archive (struct locarhandle *ah)
+{
+ struct stat64 st;
+ struct stat64 st2;
+ int fd;
+ struct locarhead head;
+ int retry = 0;
+
+ again:
+ /* Open the archive. We must have exclusive write access. */
+ fd = open64 (archivefname, O_RDWR);
+ if (fd == -1)
+ {
+ /* Maybe the file does not yet exist. */
+ if (errno == ENOENT)
+ {
+ create_archive (ah);
+ return;
+ }
+ else
+ error (EXIT_FAILURE, errno, _("cannot open locale archive \"%s\""),
+ archivefname);
+ }
+
+ if (fstat64 (fd, &st) < 0)
+ error (EXIT_FAILURE, errno, _("cannot stat locale archive \"%s\""),
+ archivefname);
+
+ if (lockf64 (fd, F_LOCK, st.st_size) == -1)
+ {
+ close (fd);
+
+ if (retry++ < max_locarchive_open_retry)
+ {
+ struct timespec req;
+
+ /* Wait for a bit. */
+ req.tv_sec = 0;
+ req.tv_nsec = 1000000 * (random () % 500 + 1);
+ (void) nanosleep (&req, NULL);
+
+ goto again;
+ }
+
+ error (EXIT_FAILURE, errno, _("cannot lock locale archive \"%s\""),
+ archivefname);
+ }
+
+ /* One more check. Maybe another process replaced the archive file
+ with a new, larger one since we opened the file. */
+ if (stat64 (archivefname, &st2) == -1
+ || st.st_dev != st2.st_dev
+ || st.st_ino != st2.st_ino)
+ {
+ close (fd);
+ goto again;
+ }
+
+ /* Read the header. */
+ if (TEMP_FAILURE_RETRY (read (fd, &head, sizeof (head))) != sizeof (head))
+ error (EXIT_FAILURE, errno, _("cannot read archive header"));
+
+ ah->fd = fd;
+ ah->len = (head.sumhash_offset
+ + head.sumhash_size * sizeof (struct sumhashent));
+
+ /* Now we know how large the administrative information part is.
+ Map all of it. */
+ ah->addr = mmap64 (NULL, ah->len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (ah->addr == MAP_FAILED)
+ error (EXIT_FAILURE, errno, _("cannot map archive header"));
+}
+
+
+void
+close_archive (struct locarhandle *ah)
+{
+ munmap (ah->addr, ah->len);
+ close (ah->fd);
+}
+
+
+/* Check the content of the archive for duplicates. Add the content
+ of the files if necessary. Add all the names, possibly overwriting
+ old files. */
+int
+add_locale_to_archive (ah, name, data, replace)
+ struct locarhandle *ah;
+ const char *name;
+ locale_data_t data;
+ bool replace;
+{
+ /* First look for the name. If it already exists and we are not
+ supposed to replace it don't do anything. If it does not exist
+ we have to allocate a new locale record. */
+ size_t name_len = strlen (name);
+ uint32_t file_offsets[__LC_LAST];
+ unsigned int num_new_offsets = 0;
+ struct sumhashent *sumhashtab;
+ uint32_t hval;
+ unsigned int cnt;
+ unsigned int idx;
+ unsigned int insert_idx;
+ struct locarhead *head;
+ struct namehashent *namehashtab;
+ struct namehashent *namehashent;
+ unsigned int incr;
+ struct locrecent *locrecent;
+
+ head = ah->addr;
+ sumhashtab = (struct sumhashent *) ((char *) ah->addr
+ + head->sumhash_offset);
+ namehashtab = (struct namehashent *) ((char *) ah->addr
+ + head->namehash_offset);
+
+
+ /* For each locale category data set determine whether the same data
+ is already somewhere in the archive. */
+ for (cnt = 0; cnt < __LC_LAST; ++cnt)
+ if (cnt != LC_ALL)
+ {
+ /* By default signal that we have no data. */
+ file_offsets[cnt] = 0;
+ ++num_new_offsets;
+
+ /* Compute the hash value of the checksum to determine a
+ starting point for the search in the MD5 hash value
+ table. */
+ hval = compute_hashval (data[cnt].sum, 16);
+
+ idx = hval % head->sumhash_size;
+ incr = 1 + hval % (head->sumhash_size - 2);
+
+ while (sumhashtab[idx].file_offset != 0)
+ {
+ if (memcmp (data[cnt].sum, sumhashtab[idx].sum, 16) == 0)
+ {
+ /* Found it. */
+ file_offsets[cnt] = sumhashtab[idx].file_offset;
+ --num_new_offsets;
+ break;
+ }
+
+ idx += incr;
+ if (idx >= head->sumhash_size)
+ idx -= head->sumhash_size;
+ }
+ }
+
+
+ /* Hash value of the locale name. */
+ hval = compute_hashval (name, name_len);
+
+ insert_idx = -1;
+ idx = hval % head->namehash_size;
+ incr = 1 + hval % (head->namehash_size - 2);
+
+ /* If the name_offset field is zero this means this is no
+ deleted entry and therefore no entry can be found. */
+ while (namehashtab[idx].name_offset != 0)
+ {
+ if (namehashtab[idx].hashval == hval
+ && strcmp (name,
+ (char *) ah->addr + namehashtab[idx].name_offset) == 0)
+ {
+ /* Found the entry. */
+ if (! replace)
+ {
+ if (! be_quiet)
+ error (0, 0, _("locale '%s' already exists"), name);
+ return 1;
+ }
+
+ break;
+ }
+
+ /* Remember the first place we can insert the new entry. */
+ if (namehashtab[idx].locrec_offset == 0 && insert_idx == -1)
+ insert_idx = idx;
+
+ idx += incr;
+ if (idx >= head->namehash_size)
+ idx -= head->namehash_size;
+ }
+
+ /* Add as early as possible. */
+ if (insert_idx != -1)
+ idx = insert_idx;
+
+ namehashent = &namehashtab[idx];
+
+ /* Determine whether we have to resize the file. */
+ if (100 * (head->sumhash_used + num_new_offsets) > 75 * head->sumhash_size
+ || (namehashent->locrec_offset == 0
+ && (head->locrectab_used == head->locrectab_size
+ || head->string_used + name_len + 1 > head->string_size
+ || 100 * head->namehash_used > 75 * head->namehash_size)))
+ {
+ /* The current archive is not large enough. */
+ enlarge_archive (ah, head);
+ return add_locale_to_archive (ah, name, data, replace);
+ }
+
+ /* Add the locale data which is not yet in the archive. */
+ for (cnt = 0; cnt < __LC_LAST; ++cnt)
+ if (cnt != LC_ALL && file_offsets[cnt] == 0)
+ {
+ /* The data for this section is not yet available in the
+ archive. Append it. */
+ off64_t lastpos;
+ uint32_t md5hval;
+
+ lastpos = lseek64 (ah->fd, 0, SEEK_END);
+ if (lastpos == (off64_t) -1)
+ error (EXIT_FAILURE, errno, _("cannot add to locale archive"));
+
+ /* Align all data to a 16 byte boundary. */
+ if ((lastpos & 15) != 0)
+ {
+ static const char zeros[15] = { 0, };
+
+ if (TEMP_FAILURE_RETRY (write (ah->fd, zeros, 16 - (lastpos & 15)))
+ != 16 - (lastpos & 15))
+ error (EXIT_FAILURE, errno, _("cannot add to locale archive"));
+
+ lastpos += 16 - (lastpos & 15);
+ }
+
+ /* Remember the position. */
+ file_offsets[cnt] = lastpos;
+
+ /* Write the data. */
+ if (TEMP_FAILURE_RETRY (write (ah->fd, data[cnt].addr, data[cnt].size))
+ != data[cnt].size)
+ error (EXIT_FAILURE, errno, _("cannot add to locale archive"));
+
+ /* Add the hash value to the hash table. */
+ md5hval = compute_hashval (data[cnt].sum, 16);
+
+ idx = md5hval % head->sumhash_size;
+ incr = 1 + md5hval % (head->sumhash_size - 2);
+
+ while (sumhashtab[idx].file_offset != 0)
+ {
+ idx += incr;
+ if (idx >= head->sumhash_size)
+ idx -= head->sumhash_size;
+ }
+
+ memcpy (sumhashtab[idx].sum, data[cnt].sum, 16);
+ sumhashtab[idx].file_offset = file_offsets[cnt];
+
+ ++head->sumhash_used;
+ }
+
+
+ if (namehashent->locrec_offset == 0)
+ {
+ /* Add the name string. */
+ memcpy ((char *) ah->addr + head->string_offset + head->string_used,
+ name, name_len + 1);
+ namehashent->name_offset = head->string_offset + head->string_used;
+ head->string_used += name_len + 1;
+
+ /* Allocate a name location record. */
+ namehashent->locrec_offset = (head->locrectab_offset
+ + (head->locrectab_used++
+ * sizeof (struct locrecent)));
+
+ namehashent->hashval = hval;
+
+ ++head->namehash_used;
+ }
+
+
+ /* Fill in the table with the locations of the locale data. */
+ locrecent = (struct locrecent *) ((char *) ah->addr
+ + namehashent->locrec_offset);
+ for (cnt = 0; cnt < __LC_LAST; ++cnt)
+ if (cnt != LC_ALL)
+ {
+ locrecent->record[cnt].offset = file_offsets[cnt];
+ locrecent->record[cnt].len = data[cnt].size;
+ }
+
+
+ /* Read the locale.alias file to see whether any matching record is
+ found. If an entry is available check whether it is already in
+ the archive. If this is the case check whether the new locale's
+ name is more specific than the one currently referred to by the
+ alias. */
+
+
+ return 0;
+}
+
+
+int
+add_locales_to_archive (nlist, list, replace)
+ size_t nlist;
+ char *list[];
+ bool replace;
+{
+ struct locarhandle ah;
+ int result = 0;
+
+ /* Open the archive. This call never returns if we cannot
+ successfully open the archive. */
+ open_archive (&ah);
+
+ while (nlist-- > 0)
+ {
+ const char *fname = *list++;
+ size_t fnamelen = strlen (fname);
+ struct stat64 st;
+ DIR *dirp;
+ struct dirent64 *d;
+ int seen;
+ locale_data_t data;
+ int cnt;
+
+ if (! be_quiet)
+ printf (_("Adding %s\n"), fname);
+
+ /* First see whether this really is a directory and whether it
+ contains all the require locale category files. */
+ if (stat64 (fname, &st) < 0)
+ {
+ error (0, 0, _("stat of \"%s\" failed: %s: ignored"), fname,
+ strerror (errno));
+ continue;
+ }
+ if (!S_ISDIR (st.st_mode))
+ {
+ error (0, 0, _("\"%s\" is no directory; ignored"), fname);
+ continue;
+ }
+
+ dirp = opendir (fname);
+ if (dirp == NULL)
+ {
+ error (0, 0, _("cannot open directory \"%s\": %s: ignored"),
+ fname, strerror (errno));
+ continue;
+ }
+
+ seen = 0;
+ while ((d = readdir64 (dirp)) != NULL)
+ {
+ for (cnt = 0; cnt < __LC_LAST; ++cnt)
+ if (cnt != LC_ALL)
+ if (strcmp (d->d_name, locnames[cnt]) == 0)
+ {
+ unsigned char d_type;
+
+ /* We have an object of the required name. If it's
+ a directory we have to look at a file with the
+ prefix "SYS_". Otherwise we have found what we
+ are looking for. */
+#ifdef _DIRENT_HAVE_D_TYPE
+ d_type = d->d_type;
+
+ if (d_type != DT_REG)
+#endif
+ {
+ char fullname[fnamelen + 2 * strlen (d->d_name) + 7];
+
+#ifdef _DIRENT_HAVE_D_TYPE
+ if (d_type == DT_UNKNOWN)
+#endif
+ {
+ strcpy (stpcpy (stpcpy (fullname, fname), "/"),
+ d->d_name);
+
+ if (stat64 (fullname, &st) == -1)
+ /* We cannot stat the file, ignore it. */
+ break;
+
+ d_type = IFTODT (st.st_mode);
+ }
+
+ if (d_type == DT_DIR)
+ {
+ /* We have to do more tests. The file is a
+ directory and it therefore must contain a
+ regular file with the same name except a
+ "SYS_" prefix. */
+ strcpy (stpcpy (stpcpy (stpcpy (stpcpy (fullname,
+ fname),
+ "/"),
+ d->d_name),
+ "/SYS_"),
+ d->d_name);
+
+ if (stat64 (fullname, &st) == -1)
+ /* There is no SYS_* file or we cannot
+ access it. */
+ break;
+
+ d_type = IFTODT (st.st_mode);
+ }
+ }
+
+ /* If we found a regular file (eventually after
+ following a symlink) we are successful. */
+ if (d_type == DT_REG)
+ ++seen;
+ break;
+ }
+ }
+
+ closedir (dirp);
+
+ if (seen != __LC_LAST - 1)
+ {
+ /* We don't have all locale category files. Ignore the name. */
+ error (0, 0, _("incomplete set of locale files in \"%s\""),
+ fname);
+ continue;
+ }
+
+ /* Add the files to the archive. To do this we first compute
+ sizes and the MD5 sums of all the files. */
+ for (cnt = 0; cnt < __LC_LAST; ++cnt)
+ if (cnt != LC_ALL)
+ {
+ char fullname[fnamelen + 2 * strlen (locnames[cnt]) + 7];
+ int fd;
+
+ strcpy (stpcpy (stpcpy (fullname, fname), "/"), locnames[cnt]);
+ fd = open64 (fullname, O_RDONLY);
+ if (fd == -1 || fstat64 (fd, &st) == -1)
+ {
+ /* Cannot read the file. */
+ if (fd != -1)
+ close (fd);
+ break;
+ }
+
+ if (S_ISDIR (st.st_mode))
+ {
+ close (fd);
+ strcpy (stpcpy (stpcpy (stpcpy (stpcpy (fullname, fname),
+ "/"),
+ locnames[cnt]),
+ "/SYS_"),
+ locnames[cnt]);
+
+ fd = open64 (fullname, O_RDONLY);
+ if (fd == -1 || fstat64 (fd, &st) == -1
+ || !S_ISREG (st.st_mode))
+ {
+ if (fd != -1)
+ close (fd);
+ break;
+ }
+ }
+
+ /* Map the file. */
+ data[cnt].addr = mmap64 (NULL, st.st_size, PROT_READ, MAP_SHARED,
+ fd, 0);
+ if (data[cnt].addr == MAP_FAILED)
+ {
+ /* Cannot map it. */
+ close (fd);
+ break;
+ }
+
+ data[cnt].size = st.st_size;
+ __md5_buffer (data[cnt].addr, st.st_size, data[cnt].sum);
+
+ /* We don't need the file descriptor anymore. */
+ close (fd);
+ }
+
+ if (cnt != __LC_LAST)
+ {
+ while (cnt-- > 0)
+ if (cnt != LC_ALL)
+ munmap (data[cnt].addr, data[cnt].size);
+
+ error (0, 0, _("cannot read all files in \"%s\": ignored"), fname);
+
+ continue;
+ }
+
+ result |= add_locale_to_archive (&ah, basename (fname), data, replace);
+
+ for (cnt = 0; cnt < __LC_LAST; ++cnt)
+ if (cnt != LC_ALL)
+ munmap (data[cnt].addr, data[cnt].size);
+ }
+
+ /* We are done. */
+ close_archive (&ah);
+
+ return result;
+}
+
+
+int
+delete_locales_from_archive (nlist, list)
+ size_t nlist;
+ char *list[];
+{
+ struct locarhandle ah;
+ struct locarhead *head;
+ struct namehashent *namehashtab;
+
+ /* Open the archive. This call never returns if we cannot
+ successfully open the archive. */
+ open_archive (&ah);
+
+ head = ah.addr;
+ namehashtab = (struct namehashent *) ((char *) ah.addr
+ + head->namehash_offset);
+
+ while (nlist-- > 0)
+ {
+ const char *locname = *list++;
+ uint32_t hval;
+ unsigned int idx;
+ unsigned int incr;
+
+ /* Search for this locale in the archive. */
+ hval = compute_hashval (locname, strlen (locname));
+
+ idx = hval % head->namehash_size;
+ incr = 1 + hval % (head->namehash_size - 2);
+
+ /* If the name_offset field is zero this means this is no
+ deleted entry and therefore no entry can be found. */
+ while (namehashtab[idx].name_offset != 0)
+ {
+ if (namehashtab[idx].hashval == hval
+ && (strcmp (locname,
+ (char *) ah.addr + namehashtab[idx].name_offset)
+ == 0))
+ {
+ /* Found the entry. Now mark it as removed by zero-ing
+ the reference to the locale record. */
+ namehashtab[idx].locrec_offset = 0;
+ --head->namehash_used;
+ break;
+ }
+
+ idx += incr;
+ if (idx >= head->namehash_size)
+ idx -= head->namehash_size;
+ }
+
+ if (namehashtab[idx].name_offset == 0 && ! be_quiet)
+ error (0, 0, _("locale \"%s\" not in archive"), locname);
+ }
+
+ close_archive (&ah);
+
+ return 0;
+}
+
+
+static int
+xstrcmp (const void *a, const void *b)
+{
+ return strcmp (*(const char **) a, *(const char **) b);
+}
+
+
+void
+show_archive_content (void)
+{
+ struct locarhandle ah;
+ struct locarhead *head;
+ struct namehashent *namehashtab;
+ int cnt;
+ char **names;
+ int used;
+
+ /* Open the archive. This call never returns if we cannot
+ successfully open the archive. */
+ open_archive (&ah);
+
+ head = ah.addr;
+
+ names = (char **) xmalloc (head->namehash_used * sizeof (char *));
+
+ namehashtab = (struct namehashent *) ((char *) ah.addr
+ + head->namehash_offset);
+ for (cnt = used = 0; cnt < head->namehash_size; ++cnt)
+ if (namehashtab[cnt].locrec_offset != 0)
+ {
+ assert (used < head->namehash_used);
+ names[used++] = ah.addr + namehashtab[cnt].name_offset;
+ }
+
+ /* Sort the names. */
+ qsort (names, used, sizeof (char *), xstrcmp);
+
+ for (cnt = 0; cnt < used; ++cnt)
+ puts (names[cnt]);
+
+ close_archive (&ah);
+
+ exit (EXIT_SUCCESS);
+}
diff --git a/locale/programs/locfile.c b/locale/programs/locfile.c
index 07a65bbb54..4d978d12a1 100644
--- a/locale/programs/locfile.c
+++ b/locale/programs/locfile.c
@@ -30,12 +30,18 @@
#include <sys/param.h>
#include <sys/stat.h>
+#include "../../crypt/md5.h"
#include "localedef.h"
#include "locfile.h"
+#include "simple-hash.h"
#include "locfile-kw.h"
+/* Temporary storage of the locale data before writing it to the archive. */
+static locale_data_t to_archive;
+
+
int
locfile_read (struct localedef_t *result, const struct charmap_t *charmap)
{
@@ -312,9 +318,10 @@ static void (*const write_funcs[]) (struct localedef_t *,
[LC_IDENTIFICATION] = identification_output
};
+
void
write_all_categories (struct localedef_t *definitions,
- const struct charmap_t *charmap,
+ const struct charmap_t *charmap, const char *locname,
const char *output_path)
{
int cnt;
@@ -322,8 +329,25 @@ write_all_categories (struct localedef_t *definitions,
for (cnt = 0; cnt < sizeof (write_funcs) / sizeof (write_funcs[0]); ++cnt)
if (write_funcs[cnt] != NULL)
write_funcs[cnt] (definitions, charmap, output_path);
+
+ if (! no_archive)
+ {
+ /* The data has to be added to the archive. Do this now. */
+ struct locarhandle ah;
+
+ /* Open the archive. This call never returns if we cannot
+ successfully open the archive. */
+ open_archive (&ah);
+
+ if (add_locale_to_archive (&ah, locname, to_archive, true) != 0)
+ error (EXIT_FAILURE, errno, _("cannot add to locale archive"));
+
+ /* We are done. */
+ close_archive (&ah);
+ }
}
+
/* Return a NULL terminated list of the directories next to output_path
that have the same owner, group, permissions and device as output_path. */
static const char **
@@ -408,6 +432,7 @@ siblings_uncached (const char *output_path)
return elems;
}
+
/* Return a NULL terminated list of the directories next to output_path
that have the same owner, group, permissions and device as output_path.
Cache the result for future calls. */
@@ -434,6 +459,7 @@ siblings (const char *output_path)
return last_result;
}
+
/* Read as many bytes from a file descriptor as possible. */
static ssize_t
full_read (int fd, void *bufarea, size_t nbyte)
@@ -457,6 +483,7 @@ full_read (int fd, void *bufarea, size_t nbyte)
return buf - (char *) bufarea;
}
+
/* Compare the contents of two regular files of the same size. Return 0
if they are equal, 1 if they are different, or -1 if an error occurs. */
static int
@@ -506,9 +533,10 @@ compare_files (const char *filename1, const char *filename2, size_t size,
return ret;
}
+
/* Write a locale file, with contents given by N_ELEM and VEC. */
void
-write_locale_data (const char *output_path, const char *category,
+write_locale_data (const char *output_path, int catidx, const char *category,
size_t n_elem, struct iovec *vec)
{
size_t cnt, step, maxiov;
@@ -516,6 +544,32 @@ write_locale_data (const char *output_path, const char *category,
char *fname;
const char **other_paths;
+ if (! no_archive)
+ {
+ /* The data will be added to the archive. For now we simply
+ generate the image which will be written. First determine
+ the size. */
+ int cnt;
+ void *endp;
+
+ to_archive[catidx].size = 0;
+ for (cnt = 0; cnt < n_elem; ++cnt)
+ to_archive[catidx].size += vec[cnt].iov_len;
+
+ /* Allocate the memory for it. */
+ to_archive[catidx].addr = xmalloc (to_archive[catidx].size);
+
+ /* Fill it in. */
+ for (cnt = 0, endp = to_archive[catidx].addr; cnt < n_elem; ++cnt)
+ endp = mempcpy (endp, vec[cnt].iov_base, vec[cnt].iov_len);
+
+ /* Compute the MD5 sum for the data. */
+ __md5_buffer (to_archive[catidx].addr, to_archive[catidx].size,
+ to_archive[catidx].sum);
+
+ return;
+ }
+
fname = xmalloc (strlen (output_path) + 2 * strlen (category) + 7);
/* Normally we write to the directory pointed to by the OUTPUT_PATH.
@@ -680,8 +734,7 @@ failure while writing data for category `%s'"), category));
char * tmp_fname =
(char *) xmalloc (strlen (fname) + 4 + 1);
- strcpy (tmp_fname, fname);
- strcat (tmp_fname, ".tmp");
+ strcpy (stpcpy (tmp_fname, fname), ".tmp");
if (link (other_fname, tmp_fname) >= 0)
{
diff --git a/locale/programs/locfile.h b/locale/programs/locfile.h
index 4f6c8fee3e..2e96c62ec7 100644
--- a/locale/programs/locfile.h
+++ b/locale/programs/locfile.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996,1997,1998,1999,2000,2001 Free Software Foundation, Inc.
+/* Copyright (C) 1996-2001, 2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@gnu.org>, 1996.
@@ -115,11 +115,13 @@ extern void check_all_categories (struct localedef_t *definitions,
/* Write out all locale categories. */
extern void write_all_categories (struct localedef_t *definitions,
const struct charmap_t *charmap,
+ const char *locname,
const char *output_path);
/* Write out the data. */
-extern void write_locale_data (const char *output_path, const char *category,
- size_t n_elem, struct iovec *vec);
+extern void write_locale_data (const char *output_path, int catidx,
+ const char *category, size_t n_elem,
+ struct iovec *vec);
/* Entrypoints for the parsers of the individual categories. */
diff --git a/locale/programs/simple-hash.c b/locale/programs/simple-hash.c
index e501038a1a..b52b5593d0 100644
--- a/locale/programs/simple-hash.c
+++ b/locale/programs/simple-hash.c
@@ -1,5 +1,5 @@
/* Implement simple hashing table with string based keys.
- Copyright (C) 1994-1997, 2000, 2001 Free Software Foundation, Inc.
+ Copyright (C) 1994-1997, 2000, 2001, 2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, October 1994.
@@ -54,6 +54,8 @@
# define bcopy(s, d, n) memcpy ((d), (s), (n))
#endif
+#include "hashval.h"
+
extern void *xmalloc (size_t __n);
extern void *xcalloc (size_t __n, size_t __m);
@@ -72,7 +74,6 @@ static void insert_entry_2 (hash_table *htab, const void *key, size_t keylen,
unsigned long hval, size_t idx, void *data);
static size_t lookup (const hash_table *htab, const void *key, size_t keylen,
unsigned long int hval);
-static unsigned long compute_hashval (const void *key, size_t keylen);
static int is_prime (unsigned long int candidate);
@@ -297,30 +298,7 @@ lookup (htab, key, keylen, hval)
}
-static unsigned long
-compute_hashval (key, keylen)
- const void *key;
- size_t keylen;
-{
- size_t cnt;
- unsigned long int hval;
-
- /* Compute the hash value for the given string. The algorithm
- is taken from [Aho,Sethi,Ullman], modified to reduce the number of
- collisions for short strings with very varied bit patterns.
- See http://www.clisp.org/haible/hashfunc.html. */
- cnt = 0;
- hval = keylen;
- while (cnt < keylen)
- {
- hval = (hval << 9) | (hval >> (LONGBITS - 9));
- hval += (unsigned long int) *(((char *) key) + cnt++);
- }
- return hval != 0 ? hval : ~((unsigned long) 0);
-}
-
-
-unsigned long
+unsigned long int
next_prime (seed)
unsigned long int seed;
{
diff --git a/locale/programs/simple-hash.h b/locale/programs/simple-hash.h
index b811a6fd4d..469caedc19 100644
--- a/locale/programs/simple-hash.h
+++ b/locale/programs/simple-hash.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1995, 1996, 1997, 1998, 1999, 2001 Free Software Foundation, Inc.
+/* Copyright (C) 1995-1999, 2001, 2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@gnu.org>, 1995.
@@ -46,6 +46,8 @@ extern int iterate_table (const hash_table *htab, void **ptr,
const void **key, size_t *keylen, void **data)
__THROW;
+extern unsigned long int compute_hashval (const void *key, size_t keylen)
+ __THROW;
extern unsigned long int next_prime (unsigned long int seed) __THROW;
#endif /* simple-hash.h */