]> git.ipfire.org Git - thirdparty/glibc.git/blame - locale/loadlocale.c
szl_PL locale: Spelling corrections (bug 24652).
[thirdparty/glibc.git] / locale / loadlocale.c
CommitLineData
ce4d8b66 1/* Functions to read locale data files.
04277e02 2 Copyright (C) 1996-2019 Free Software Foundation, Inc.
c84142e8 3 This file is part of the GNU C Library.
4b10dd6c 4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
933e73fa 5
c84142e8 6 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
933e73fa 10
c84142e8
UD
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41bdb6e2 14 Lesser General Public License for more details.
933e73fa 15
41bdb6e2 16 You should have received a copy of the GNU Lesser General Public
59ba27a6
PE
17 License along with the GNU C Library; if not, see
18 <http://www.gnu.org/licenses/>. */
933e73fa 19
e43e0dd6 20#include <assert.h>
933e73fa
RM
21#include <errno.h>
22#include <fcntl.h>
3e154a6f 23#include <locale.h>
933e73fa
RM
24#include <stdlib.h>
25#include <string.h>
7a12c6bb 26#include <unistd.h>
b6aa34eb
UD
27#ifdef _POSIX_MAPPED_FILES
28# include <sys/mman.h>
29#endif
7a12c6bb
RM
30#include <sys/stat.h>
31
72ef277e 32#include <not-cancel.h>
933e73fa
RM
33#include "localeinfo.h"
34
7a12c6bb
RM
35
36static const size_t _nl_category_num_items[] =
19bc17a9 37{
4b10dd6c 38#define DEFINE_CATEGORY(category, category_name, items, a) \
19bc17a9 39 [category] = _NL_ITEM_INDEX (_NL_NUM_##category),
933e73fa
RM
40#include "categories.def"
41#undef DEFINE_CATEGORY
19bc17a9
RM
42};
43
44
45#define NO_PAREN(arg, rest...) arg, ##rest
46
f301e533
RL
47/* The size of the array must be specified explicitly because some of
48 the 'items' may be subarrays, which will cause the compiler to deduce
49 an incorrect size from the initializer. */
4b10dd6c 50#define DEFINE_CATEGORY(category, category_name, items, a) \
f301e533
RL
51static const enum value_type _nl_value_type_##category \
52 [_NL_ITEM_INDEX (_NL_NUM_##category)] = { NO_PAREN items };
19bc17a9
RM
53#define DEFINE_ELEMENT(element, element_name, optstd, type, rest...) \
54 [_NL_ITEM_INDEX (element)] = type,
55#include "categories.def"
56#undef DEFINE_CATEGORY
57
aa87e915 58static const enum value_type *const _nl_value_types[] =
19bc17a9 59{
4b10dd6c 60#define DEFINE_CATEGORY(category, category_name, items, a) \
19bc17a9
RM
61 [category] = _nl_value_type_##category,
62#include "categories.def"
63#undef DEFINE_CATEGORY
64};
65
933e73fa 66
f095bb72 67struct __locale_data *
cb09a2cd 68_nl_intern_locale_data (int category, const void *data, size_t datasize)
933e73fa 69{
cb09a2cd 70 const struct
933e73fa
RM
71 {
72 unsigned int magic;
73 unsigned int nstrings;
74 unsigned int strindex[0];
cb09a2cd 75 } *const filedata = data;
f095bb72 76 struct __locale_data *newdata;
cb09a2cd
RM
77 size_t cnt;
78
79 if (__builtin_expect (datasize < sizeof *filedata, 0)
80 || __builtin_expect (filedata->magic != LIMAGIC (category), 0))
81 {
82 /* Bad data file. */
83 __set_errno (EINVAL);
84 return NULL;
85 }
86
87 if (__builtin_expect (filedata->nstrings < _nl_category_num_items[category],
88 0)
89 || (__builtin_expect (sizeof *filedata
90 + filedata->nstrings * sizeof (unsigned int)
91 >= datasize, 0)))
92 {
93 /* Insufficient data. */
94 __set_errno (EINVAL);
95 return NULL;
96 }
97
98 newdata = malloc (sizeof *newdata
99 + filedata->nstrings * sizeof (union locale_data_value));
100 if (newdata == NULL)
101 return NULL;
102
103 newdata->filedata = (void *) filedata;
104 newdata->filesize = datasize;
df9f41c9
RM
105 newdata->private.data = NULL;
106 newdata->private.cleanup = NULL;
cb09a2cd
RM
107 newdata->usage_count = 0;
108 newdata->use_translit = 0;
109 newdata->nstrings = filedata->nstrings;
110 for (cnt = 0; cnt < newdata->nstrings; ++cnt)
111 {
112 size_t idx = filedata->strindex[cnt];
a1ffb40e 113 if (__glibc_unlikely (idx > (size_t) newdata->filesize))
cb09a2cd
RM
114 {
115 puntdata:
116 free (newdata);
117 __set_errno (EINVAL);
118 return NULL;
119 }
fe6ce170
UD
120
121 /* Determine the type. There is one special case: the LC_CTYPE
122 category can have more elements than there are in the
123 _nl_value_type_LC_XYZ array. There are all pointers. */
124 switch (category)
125 {
126#define CATTEST(cat) \
0062ace2
LC
127 case LC_##cat: \
128 if (cnt >= (sizeof (_nl_value_type_LC_##cat) \
129 / sizeof (_nl_value_type_LC_##cat[0]))) \
130 goto puntdata; \
fe6ce170
UD
131 break
132 CATTEST (NUMERIC);
133 CATTEST (TIME);
134 CATTEST (COLLATE);
135 CATTEST (MONETARY);
136 CATTEST (MESSAGES);
137 CATTEST (PAPER);
138 CATTEST (NAME);
139 CATTEST (ADDRESS);
140 CATTEST (TELEPHONE);
141 CATTEST (MEASUREMENT);
142 CATTEST (IDENTIFICATION);
143 default:
144 assert (category == LC_CTYPE);
145 break;
146 }
147
148 if ((category == LC_CTYPE
149 && cnt >= (sizeof (_nl_value_type_LC_CTYPE)
150 / sizeof (_nl_value_type_LC_CTYPE[0])))
151 || __builtin_expect (_nl_value_types[category][cnt] != word, 1))
152 newdata->values[cnt].string = newdata->filedata + idx;
153 else
cb09a2cd 154 {
7602d070 155 if (!LOCFILE_ALIGNED_P (idx))
cb09a2cd
RM
156 goto puntdata;
157 newdata->values[cnt].word =
d9fee042 158 *((const uint32_t *) (newdata->filedata + idx));
cb09a2cd 159 }
cb09a2cd
RM
160 }
161
162 return newdata;
163}
164
165void
cb09a2cd
RM
166_nl_load_locale (struct loaded_l10nfile *file, int category)
167{
168 int fd;
169 void *filedata;
8edf6e0d 170 struct stat64 st;
f095bb72 171 struct __locale_data *newdata;
7a12c6bb 172 int save_err;
cb09a2cd 173 int alloc = ld_mapped;
933e73fa 174
7a12c6bb
RM
175 file->decided = 1;
176 file->data = NULL;
177
c2284574 178 fd = __open_nocancel (file->filename, O_RDONLY | O_CLOEXEC);
3a31f6f4 179 if (__builtin_expect (fd, 0) < 0)
7a12c6bb
RM
180 /* Cannot open the file. */
181 return;
182
8edf6e0d 183 if (__builtin_expect (__fxstat64 (_STAT_VER, fd, &st), 0) < 0)
cb09a2cd
RM
184 {
185 puntfd:
c181840c 186 __close_nocancel_nostatus (fd);
cb09a2cd
RM
187 return;
188 }
a1ffb40e 189 if (__glibc_unlikely (S_ISDIR (st.st_mode)))
933e73fa 190 {
7a12c6bb 191 /* LOCALE/LC_foo is a directory; open LOCALE/LC_foo/SYS_LC_foo
f095bb72 192 instead. */
7a12c6bb 193 char *newp;
b6aa34eb 194 size_t filenamelen;
036cc82f 195
c181840c 196 __close_nocancel_nostatus (fd);
7a12c6bb 197
b6aa34eb
UD
198 filenamelen = strlen (file->filename);
199 newp = (char *) alloca (filenamelen
7a12c6bb 200 + 5 + _nl_category_name_sizes[category] + 1);
b6aa34eb
UD
201 __mempcpy (__mempcpy (__mempcpy (newp, file->filename, filenamelen),
202 "/SYS_", 5),
9446614c 203 _nl_category_names.str + _nl_category_name_idxs[category],
b6aa34eb 204 _nl_category_name_sizes[category] + 1);
7a12c6bb 205
c2284574 206 fd = __open_nocancel (newp, O_RDONLY | O_CLOEXEC);
3a31f6f4 207 if (__builtin_expect (fd, 0) < 0)
7a12c6bb
RM
208 return;
209
8edf6e0d 210 if (__builtin_expect (__fxstat64 (_STAT_VER, fd, &st), 0) < 0)
7a12c6bb 211 goto puntfd;
933e73fa
RM
212 }
213
7a12c6bb
RM
214 /* Map in the file's data. */
215 save_err = errno;
b6aa34eb
UD
216#ifdef _POSIX_MAPPED_FILES
217# ifndef MAP_COPY
7a12c6bb 218 /* Linux seems to lack read-only copy-on-write. */
b6aa34eb
UD
219# define MAP_COPY MAP_PRIVATE
220# endif
221# ifndef MAP_FILE
7a12c6bb 222 /* Some systems do not have this flag; it is superfluous. */
b6aa34eb
UD
223# define MAP_FILE 0
224# endif
cb09a2cd
RM
225 filedata = __mmap ((caddr_t) 0, st.st_size,
226 PROT_READ, MAP_FILE|MAP_COPY, fd, 0);
a1ffb40e 227 if (__glibc_unlikely (filedata == MAP_FAILED))
7a12c6bb 228 {
8b2f25c2 229 filedata = NULL;
3a31f6f4 230 if (__builtin_expect (errno, ENOSYS) == ENOSYS)
7a12c6bb 231 {
b6aa34eb 232#endif /* _POSIX_MAPPED_FILES */
7a12c6bb 233 /* No mmap; allocate a buffer and read from the file. */
cb09a2cd 234 alloc = ld_malloced;
7a12c6bb
RM
235 filedata = malloc (st.st_size);
236 if (filedata != NULL)
237 {
238 off_t to_read = st.st_size;
239 ssize_t nread;
240 char *p = (char *) filedata;
241 while (to_read > 0)
242 {
a748eb31 243 nread = __read_nocancel (fd, p, to_read);
3a31f6f4 244 if (__builtin_expect (nread, 1) <= 0)
7a12c6bb
RM
245 {
246 free (filedata);
247 if (nread == 0)
c4029823 248 __set_errno (EINVAL); /* Bizarreness going on. */
7a12c6bb
RM
249 goto puntfd;
250 }
251 p += nread;
252 to_read -= nread;
253 }
cb09a2cd 254 __set_errno (save_err);
7a12c6bb 255 }
b6aa34eb 256#ifdef _POSIX_MAPPED_FILES
7a12c6bb 257 }
7a12c6bb 258 }
b6aa34eb 259#endif /* _POSIX_MAPPED_FILES */
933e73fa 260
cb09a2cd 261 /* We have mapped the data, so we no longer need the descriptor. */
c181840c 262 __close_nocancel_nostatus (fd);
cb09a2cd 263
a1ffb40e 264 if (__glibc_unlikely (filedata == NULL))
cb09a2cd
RM
265 /* We failed to map or read the data. */
266 return;
267
268 newdata = _nl_intern_locale_data (category, filedata, st.st_size);
a1ffb40e 269 if (__glibc_unlikely (newdata == NULL))
cb09a2cd 270 /* Bad data. */
933e73fa 271 {
b6aa34eb 272#ifdef _POSIX_MAPPED_FILES
cb09a2cd
RM
273 if (alloc == ld_mapped)
274 __munmap ((caddr_t) filedata, st.st_size);
b6aa34eb 275#endif
4a33c2f5 276 return;
933e73fa
RM
277 }
278
cb09a2cd 279 /* _nl_intern_locale_data leaves us these fields to initialize. */
7a12c6bb 280 newdata->name = NULL; /* This will be filled if necessary in findlocale.c. */
cb09a2cd 281 newdata->alloc = alloc;
933e73fa 282
7a12c6bb 283 file->data = newdata;
933e73fa 284}
a5a0310d
UD
285
286void
f095bb72 287_nl_unload_locale (struct __locale_data *locale)
a5a0310d 288{
df9f41c9
RM
289 if (locale->private.cleanup)
290 (*locale->private.cleanup) (locale);
291
cb09a2cd
RM
292 switch (__builtin_expect (locale->alloc, ld_mapped))
293 {
294 case ld_malloced:
295 free ((void *) locale->filedata);
296 break;
297 case ld_mapped:
b6aa34eb 298#ifdef _POSIX_MAPPED_FILES
cb09a2cd
RM
299 __munmap ((caddr_t) locale->filedata, locale->filesize);
300 break;
b6aa34eb 301#endif
cb09a2cd
RM
302 case ld_archive: /* Nothing to do. */
303 break;
304 }
305
306 if (__builtin_expect (locale->alloc, ld_mapped) != ld_archive)
307 free ((char *) locale->name);
a5a0310d
UD
308
309 free (locale);
310}