1 /* Functions to read locale data files.
2 Copyright (C) 1996-2018 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
6 The GNU C Library is free software; you can redistribute it and/or
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.
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
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, see
18 <http://www.gnu.org/licenses/>. */
27 #ifdef _POSIX_MAPPED_FILES
28 # include <sys/mman.h>
32 #include <not-cancel.h>
33 #include "localeinfo.h"
36 static const size_t _nl_category_num_items
[] =
38 #define DEFINE_CATEGORY(category, category_name, items, a) \
39 [category] = _NL_ITEM_INDEX (_NL_NUM_##category),
40 #include "categories.def"
41 #undef DEFINE_CATEGORY
45 #define NO_PAREN(arg, rest...) arg, ##rest
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. */
50 #define DEFINE_CATEGORY(category, category_name, items, a) \
51 static const enum value_type _nl_value_type_##category \
52 [_NL_ITEM_INDEX (_NL_NUM_##category)] = { NO_PAREN items };
53 #define DEFINE_ELEMENT(element, element_name, optstd, type, rest...) \
54 [_NL_ITEM_INDEX (element)] = type,
55 #include "categories.def"
56 #undef DEFINE_CATEGORY
58 static const enum value_type
*const _nl_value_types
[] =
60 #define DEFINE_CATEGORY(category, category_name, items, a) \
61 [category] = _nl_value_type_##category,
62 #include "categories.def"
63 #undef DEFINE_CATEGORY
67 struct __locale_data
*
68 _nl_intern_locale_data (int category
, const void *data
, size_t datasize
)
73 unsigned int nstrings
;
74 unsigned int strindex
[0];
75 } *const filedata
= data
;
76 struct __locale_data
*newdata
;
79 if (__builtin_expect (datasize
< sizeof *filedata
, 0)
80 || __builtin_expect (filedata
->magic
!= LIMAGIC (category
), 0))
87 if (__builtin_expect (filedata
->nstrings
< _nl_category_num_items
[category
],
89 || (__builtin_expect (sizeof *filedata
90 + filedata
->nstrings
* sizeof (unsigned int)
93 /* Insufficient data. */
98 newdata
= malloc (sizeof *newdata
99 + filedata
->nstrings
* sizeof (union locale_data_value
));
103 newdata
->filedata
= (void *) filedata
;
104 newdata
->filesize
= datasize
;
105 newdata
->private.data
= NULL
;
106 newdata
->private.cleanup
= NULL
;
107 newdata
->usage_count
= 0;
108 newdata
->use_translit
= 0;
109 newdata
->nstrings
= filedata
->nstrings
;
110 for (cnt
= 0; cnt
< newdata
->nstrings
; ++cnt
)
112 size_t idx
= filedata
->strindex
[cnt
];
113 if (__glibc_unlikely (idx
> (size_t) newdata
->filesize
))
117 __set_errno (EINVAL
);
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. */
126 #define CATTEST(cat) \
128 if (cnt >= (sizeof (_nl_value_type_LC_##cat) \
129 / sizeof (_nl_value_type_LC_##cat[0]))) \
141 CATTEST (MEASUREMENT
);
142 CATTEST (IDENTIFICATION
);
144 assert (category
== LC_CTYPE
);
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
;
155 if (!LOCFILE_ALIGNED_P (idx
))
157 newdata
->values
[cnt
].word
=
158 *((const uint32_t *) (newdata
->filedata
+ idx
));
166 _nl_load_locale (struct loaded_l10nfile
*file
, int category
)
171 struct __locale_data
*newdata
;
173 int alloc
= ld_mapped
;
178 fd
= __open_nocancel (file
->filename
, O_RDONLY
| O_CLOEXEC
);
179 if (__builtin_expect (fd
, 0) < 0)
180 /* Cannot open the file. */
183 if (__builtin_expect (__fxstat64 (_STAT_VER
, fd
, &st
), 0) < 0)
186 __close_nocancel_nostatus (fd
);
189 if (__glibc_unlikely (S_ISDIR (st
.st_mode
)))
191 /* LOCALE/LC_foo is a directory; open LOCALE/LC_foo/SYS_LC_foo
196 __close_nocancel_nostatus (fd
);
198 filenamelen
= strlen (file
->filename
);
199 newp
= (char *) alloca (filenamelen
200 + 5 + _nl_category_name_sizes
[category
] + 1);
201 __mempcpy (__mempcpy (__mempcpy (newp
, file
->filename
, filenamelen
),
203 _nl_category_names
.str
+ _nl_category_name_idxs
[category
],
204 _nl_category_name_sizes
[category
] + 1);
206 fd
= __open_nocancel (newp
, O_RDONLY
| O_CLOEXEC
);
207 if (__builtin_expect (fd
, 0) < 0)
210 if (__builtin_expect (__fxstat64 (_STAT_VER
, fd
, &st
), 0) < 0)
214 /* Map in the file's data. */
216 #ifdef _POSIX_MAPPED_FILES
218 /* Linux seems to lack read-only copy-on-write. */
219 # define MAP_COPY MAP_PRIVATE
222 /* Some systems do not have this flag; it is superfluous. */
225 filedata
= __mmap ((caddr_t
) 0, st
.st_size
,
226 PROT_READ
, MAP_FILE
|MAP_COPY
, fd
, 0);
227 if (__glibc_unlikely (filedata
== MAP_FAILED
))
230 if (__builtin_expect (errno
, ENOSYS
) == ENOSYS
)
232 #endif /* _POSIX_MAPPED_FILES */
233 /* No mmap; allocate a buffer and read from the file. */
235 filedata
= malloc (st
.st_size
);
236 if (filedata
!= NULL
)
238 off_t to_read
= st
.st_size
;
240 char *p
= (char *) filedata
;
243 nread
= __read_nocancel (fd
, p
, to_read
);
244 if (__builtin_expect (nread
, 1) <= 0)
248 __set_errno (EINVAL
); /* Bizarreness going on. */
254 __set_errno (save_err
);
256 #ifdef _POSIX_MAPPED_FILES
259 #endif /* _POSIX_MAPPED_FILES */
261 /* We have mapped the data, so we no longer need the descriptor. */
262 __close_nocancel_nostatus (fd
);
264 if (__glibc_unlikely (filedata
== NULL
))
265 /* We failed to map or read the data. */
268 newdata
= _nl_intern_locale_data (category
, filedata
, st
.st_size
);
269 if (__glibc_unlikely (newdata
== NULL
))
272 #ifdef _POSIX_MAPPED_FILES
273 if (alloc
== ld_mapped
)
274 __munmap ((caddr_t
) filedata
, st
.st_size
);
279 /* _nl_intern_locale_data leaves us these fields to initialize. */
280 newdata
->name
= NULL
; /* This will be filled if necessary in findlocale.c. */
281 newdata
->alloc
= alloc
;
283 file
->data
= newdata
;
287 _nl_unload_locale (struct __locale_data
*locale
)
289 if (locale
->private.cleanup
)
290 (*locale
->private.cleanup
) (locale
);
292 switch (__builtin_expect (locale
->alloc
, ld_mapped
))
295 free ((void *) locale
->filedata
);
298 #ifdef _POSIX_MAPPED_FILES
299 __munmap ((caddr_t
) locale
->filedata
, locale
->filesize
);
302 case ld_archive
: /* Nothing to do. */
306 if (__builtin_expect (locale
->alloc
, ld_mapped
) != ld_archive
)
307 free ((char *) locale
->name
);