1 /* Functions to read locale data files.
2 Copyright (C) 1996-2022 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
26 #ifdef _POSIX_MAPPED_FILES
27 # include <sys/mman.h>
31 #include <not-cancel.h>
32 #include "localeinfo.h"
35 static const size_t _nl_category_num_items
[] =
37 #define DEFINE_CATEGORY(category, category_name, items, a) \
38 [category] = _NL_ITEM_INDEX (_NL_NUM_##category),
39 #include "categories.def"
40 #undef DEFINE_CATEGORY
44 #define NO_PAREN(arg, rest...) arg, ##rest
46 /* The size of the array must be specified explicitly because some of
47 the 'items' may be subarrays, which will cause the compiler to deduce
48 an incorrect size from the initializer. */
49 #define DEFINE_CATEGORY(category, category_name, items, a) \
50 static const enum value_type _nl_value_type_##category \
51 [_NL_ITEM_INDEX (_NL_NUM_##category)] = { NO_PAREN items };
52 #define DEFINE_ELEMENT(element, element_name, optstd, type, rest...) \
53 [_NL_ITEM_INDEX (element)] = type,
54 #include "categories.def"
55 #undef DEFINE_CATEGORY
57 static const enum value_type
*const _nl_value_types
[] =
59 #define DEFINE_CATEGORY(category, category_name, items, a) \
60 [category] = _nl_value_type_##category,
61 #include "categories.def"
62 #undef DEFINE_CATEGORY
66 struct __locale_data
*
67 _nl_intern_locale_data (int category
, const void *data
, size_t datasize
)
72 unsigned int nstrings
;
73 unsigned int strindex
[0];
74 } *const filedata
= data
;
75 struct __locale_data
*newdata
;
78 if (__builtin_expect (datasize
< sizeof *filedata
, 0)
79 || __builtin_expect (filedata
->magic
!= LIMAGIC (category
), 0))
86 if (__builtin_expect (filedata
->nstrings
< _nl_category_num_items
[category
],
88 || (__builtin_expect (sizeof *filedata
89 + filedata
->nstrings
* sizeof (unsigned int)
92 /* Insufficient data. */
97 newdata
= malloc (sizeof *newdata
98 + filedata
->nstrings
* sizeof (union locale_data_value
));
102 newdata
->filedata
= (void *) filedata
;
103 newdata
->filesize
= datasize
;
104 newdata
->private.data
= NULL
;
105 newdata
->private.cleanup
= NULL
;
106 newdata
->usage_count
= 0;
107 newdata
->use_translit
= 0;
108 newdata
->nstrings
= filedata
->nstrings
;
109 for (cnt
= 0; cnt
< newdata
->nstrings
; ++cnt
)
111 size_t idx
= filedata
->strindex
[cnt
];
112 if (__glibc_unlikely (idx
> (size_t) newdata
->filesize
))
116 __set_errno (EINVAL
);
120 /* Determine the type. There is one special case: the LC_CTYPE
121 category can have more elements than there are in the
122 _nl_value_type_LC_XYZ array. There are all pointers. */
125 #define CATTEST(cat) \
127 if (cnt >= (sizeof (_nl_value_type_LC_##cat) \
128 / sizeof (_nl_value_type_LC_##cat[0]))) \
140 CATTEST (MEASUREMENT
);
141 CATTEST (IDENTIFICATION
);
143 assert (category
== LC_CTYPE
);
147 if ((category
== LC_CTYPE
148 && cnt
>= (sizeof (_nl_value_type_LC_CTYPE
)
149 / sizeof (_nl_value_type_LC_CTYPE
[0])))
150 || __builtin_expect (_nl_value_types
[category
][cnt
] != word
, 1))
151 newdata
->values
[cnt
].string
= newdata
->filedata
+ idx
;
154 if (!LOCFILE_ALIGNED_P (idx
))
156 newdata
->values
[cnt
].word
=
157 *((const uint32_t *) (newdata
->filedata
+ idx
));
165 _nl_load_locale (struct loaded_l10nfile
*file
, int category
)
169 struct __stat64_t64 st
;
170 struct __locale_data
*newdata
;
172 int alloc
= ld_mapped
;
177 fd
= __open_nocancel (file
->filename
, O_RDONLY
| O_CLOEXEC
);
178 if (__builtin_expect (fd
, 0) < 0)
179 /* Cannot open the file. */
182 if (__glibc_unlikely (__fstat64_time64 (fd
, &st
) < 0))
185 __close_nocancel_nostatus (fd
);
188 if (__glibc_unlikely (S_ISDIR (st
.st_mode
)))
190 /* LOCALE/LC_foo is a directory; open LOCALE/LC_foo/SYS_LC_foo
195 __close_nocancel_nostatus (fd
);
197 filenamelen
= strlen (file
->filename
);
198 newp
= (char *) alloca (filenamelen
199 + 5 + _nl_category_name_sizes
[category
] + 1);
200 __mempcpy (__mempcpy (__mempcpy (newp
, file
->filename
, filenamelen
),
201 "/SYS_", 5), _nl_category_names_get (category
),
202 _nl_category_name_sizes
[category
] + 1);
204 fd
= __open_nocancel (newp
, O_RDONLY
| O_CLOEXEC
);
205 if (__builtin_expect (fd
, 0) < 0)
208 if (__glibc_unlikely (__fstat64_time64 (fd
, &st
) < 0))
212 /* Map in the file's data. */
214 #ifdef _POSIX_MAPPED_FILES
216 /* Linux seems to lack read-only copy-on-write. */
217 # define MAP_COPY MAP_PRIVATE
220 /* Some systems do not have this flag; it is superfluous. */
223 filedata
= __mmap ((caddr_t
) 0, st
.st_size
,
224 PROT_READ
, MAP_FILE
|MAP_COPY
, fd
, 0);
225 if (__glibc_unlikely (filedata
== MAP_FAILED
))
228 if (__builtin_expect (errno
, ENOSYS
) == ENOSYS
)
230 #endif /* _POSIX_MAPPED_FILES */
231 /* No mmap; allocate a buffer and read from the file. */
233 filedata
= malloc (st
.st_size
);
234 if (filedata
!= NULL
)
236 off_t to_read
= st
.st_size
;
238 char *p
= (char *) filedata
;
241 nread
= __read_nocancel (fd
, p
, to_read
);
242 if (__builtin_expect (nread
, 1) <= 0)
246 __set_errno (EINVAL
); /* Bizarreness going on. */
252 __set_errno (save_err
);
254 #ifdef _POSIX_MAPPED_FILES
257 #endif /* _POSIX_MAPPED_FILES */
259 /* We have mapped the data, so we no longer need the descriptor. */
260 __close_nocancel_nostatus (fd
);
262 if (__glibc_unlikely (filedata
== NULL
))
263 /* We failed to map or read the data. */
266 newdata
= _nl_intern_locale_data (category
, filedata
, st
.st_size
);
267 if (__glibc_unlikely (newdata
== NULL
))
270 #ifdef _POSIX_MAPPED_FILES
271 if (alloc
== ld_mapped
)
272 __munmap ((caddr_t
) filedata
, st
.st_size
);
277 /* _nl_intern_locale_data leaves us these fields to initialize. */
278 newdata
->name
= NULL
; /* This will be filled if necessary in findlocale.c. */
279 newdata
->alloc
= alloc
;
281 file
->data
= newdata
;
285 _nl_unload_locale (struct __locale_data
*locale
)
287 if (locale
->private.cleanup
)
288 (*locale
->private.cleanup
) (locale
);
290 switch (__builtin_expect (locale
->alloc
, ld_mapped
))
293 free ((void *) locale
->filedata
);
296 #ifdef _POSIX_MAPPED_FILES
297 __munmap ((caddr_t
) locale
->filedata
, locale
->filesize
);
300 case ld_archive
: /* Nothing to do. */
304 if (__builtin_expect (locale
->alloc
, ld_mapped
) != ld_archive
)
305 free ((char *) locale
->name
);