]> git.ipfire.org Git - thirdparty/glibc.git/blame - catgets/open_catalog.c
Use glibc_likely instead __builtin_expect.
[thirdparty/glibc.git] / catgets / open_catalog.c
CommitLineData
d4697bc9 1/* Copyright (C) 1996-2014 Free Software Foundation, Inc.
2c6fe0bd 2 This file is part of the GNU C Library.
390500b1 3 Contributed by Ulrich Drepper, <drepper@gnu.org>.
a641835a 4
2c6fe0bd 5 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
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.
a641835a 9
2c6fe0bd
UD
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
41bdb6e2 13 Lesser General Public License for more details.
a641835a 14
41bdb6e2 15 You should have received a copy of the GNU Lesser General Public
59ba27a6
PE
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
a641835a 18
d553bbf2 19#include <byteswap.h>
a641835a 20#include <endian.h>
b0610668 21#include <errno.h>
a641835a
RM
22#include <fcntl.h>
23#include <string.h>
24#include <stdlib.h>
25#include <unistd.h>
7cabd57c
UD
26#ifdef _POSIX_MAPPED_FILES
27# include <sys/mman.h>
28#endif
a641835a
RM
29#include <sys/stat.h>
30
31#include "catgetsinfo.h"
73299943 32#include <not-cancel.h>
a641835a
RM
33
34
d553bbf2 35#define SWAPU32(w) bswap_32 (w)
a641835a
RM
36
37
ca130fe4
UD
38int
39__open_catalog (const char *cat_name, const char *nlspath, const char *env_var,
40 __nl_catd catalog)
a641835a 41{
310b3460 42 int fd = -1;
417bafec 43 struct stat64 st;
a641835a 44 int swapping;
b0610668
UD
45 size_t cnt;
46 size_t max_offset;
47 size_t tab_size;
48 const char *lastp;
ca130fe4 49 int result = -1;
a641835a 50
ca130fe4 51 if (strchr (cat_name, '/') != NULL || nlspath == NULL)
73299943 52 fd = open_not_cancel_2 (cat_name, O_RDONLY);
a641835a
RM
53 else
54 {
ca130fe4 55 const char *run_nlspath = nlspath;
a641835a 56#define ENOUGH(n) \
a1ffb40e 57 if (__glibc_unlikely (bufact + (n) >= bufmax)) \
a641835a
RM
58 { \
59 char *old_buf = buf; \
60 bufmax += 256 + (n); \
61 buf = (char *) alloca (bufmax); \
62 memcpy (buf, old_buf, bufact); \
63 }
64
65 /* The RUN_NLSPATH variable contains a colon separated list of
66 descriptions where we expect to find catalogs. We have to
67 recognize certain % substitutions and stop when we found the
68 first existing file. */
69 char *buf;
70 size_t bufact;
71 size_t bufmax;
d553bbf2 72 size_t len;
a641835a
RM
73
74 buf = NULL;
75 bufmax = 0;
76
77 fd = -1;
78 while (*run_nlspath != '\0')
79 {
80 bufact = 0;
b6aa34eb
UD
81
82 if (*run_nlspath == ':')
83 {
84 /* Leading colon or adjacent colons - treat same as %N. */
ca130fe4 85 len = strlen (cat_name);
b6aa34eb 86 ENOUGH (len);
ca130fe4 87 memcpy (&buf[bufact], cat_name, len);
b6aa34eb
UD
88 bufact += len;
89 }
90 else
91 while (*run_nlspath != ':' && *run_nlspath != '\0')
92 if (*run_nlspath == '%')
93 {
94 const char *tmp;
95
96 ++run_nlspath; /* We have seen the `%'. */
97 switch (*run_nlspath++)
98 {
99 case 'N':
100 /* Use the catalog name. */
ca130fe4 101 len = strlen (cat_name);
b6aa34eb 102 ENOUGH (len);
ca130fe4 103 memcpy (&buf[bufact], cat_name, len);
b6aa34eb
UD
104 bufact += len;
105 break;
106 case 'L':
107 /* Use the current locale category value. */
ca130fe4 108 len = strlen (env_var);
b6aa34eb 109 ENOUGH (len);
ca130fe4 110 memcpy (&buf[bufact], env_var, len);
b6aa34eb
UD
111 bufact += len;
112 break;
113 case 'l':
114 /* Use language element of locale category value. */
ca130fe4 115 tmp = env_var;
b6aa34eb
UD
116 do
117 {
118 ENOUGH (1);
119 buf[bufact++] = *tmp++;
120 }
121 while (*tmp != '\0' && *tmp != '_' && *tmp != '.');
122 break;
123 case 't':
124 /* Use territory element of locale category value. */
ca130fe4 125 tmp = env_var;
b6aa34eb 126 do
a641835a 127 ++tmp;
b6aa34eb
UD
128 while (*tmp != '\0' && *tmp != '_' && *tmp != '.');
129 if (*tmp == '_')
130 {
131 ++tmp;
132 do
133 {
134 ENOUGH (1);
135 buf[bufact++] = *tmp++;
136 }
137 while (*tmp != '\0' && *tmp != '.');
138 }
139 break;
140 case 'c':
141 /* Use code set element of locale category value. */
ca130fe4 142 tmp = env_var;
b6aa34eb 143 do
a641835a 144 ++tmp;
b6aa34eb
UD
145 while (*tmp != '\0' && *tmp != '.');
146 if (*tmp == '.')
147 {
148 ++tmp;
149 do
150 {
151 ENOUGH (1);
152 buf[bufact++] = *tmp++;
153 }
154 while (*tmp != '\0');
155 }
156 break;
157 case '%':
158 ENOUGH (1);
159 buf[bufact++] = '%';
160 break;
161 default:
162 /* Unknown variable: ignore this path element. */
163 bufact = 0;
164 while (*run_nlspath != '\0' && *run_nlspath != ':')
165 ++run_nlspath;
166 break;
167 }
168 }
169 else
170 {
171 ENOUGH (1);
172 buf[bufact++] = *run_nlspath++;
173 }
174
a641835a
RM
175 ENOUGH (1);
176 buf[bufact] = '\0';
177
178 if (bufact != 0)
179 {
73299943 180 fd = open_not_cancel_2 (buf, O_RDONLY);
a641835a
RM
181 if (fd >= 0)
182 break;
183 }
184
185 ++run_nlspath;
186 }
187 }
188
310b3460 189 /* Avoid dealing with directories and block devices */
e84e339f 190 if (__builtin_expect (fd, 0) < 0)
ca130fe4 191 return -1;
390500b1 192
417bafec 193 if (__builtin_expect (__fxstat64 (_STAT_VER, fd, &st), 0) < 0)
ca130fe4
UD
194 goto close_unlock_return;
195
e84e339f 196 if (__builtin_expect (!S_ISREG (st.st_mode), 0)
6dd67bd5 197 || (size_t) st.st_size < sizeof (struct catalog_obj))
b0610668
UD
198 {
199 /* `errno' is not set correctly but the file is not usable.
200 Use an reasonable error value. */
201 __set_errno (EINVAL);
390500b1 202 goto close_unlock_return;
b0610668 203 }
a641835a 204
7cabd57c
UD
205 catalog->file_size = st.st_size;
206#ifdef _POSIX_MAPPED_FILES
207# ifndef MAP_COPY
a641835a 208 /* Linux seems to lack read-only copy-on-write. */
7cabd57c
UD
209# define MAP_COPY MAP_PRIVATE
210# endif
211# ifndef MAP_FILE
a641835a 212 /* Some systems do not have this flag; it is superfluous. */
7cabd57c 213# define MAP_FILE 0
7cabd57c 214# endif
a641835a 215 catalog->file_ptr =
a5113b14 216 (struct catalog_obj *) __mmap (NULL, st.st_size, PROT_READ,
946860b1 217 MAP_FILE|MAP_COPY, fd, 0);
e84e339f
UD
218 if (__builtin_expect (catalog->file_ptr != (struct catalog_obj *) MAP_FAILED,
219 1))
a641835a 220 /* Tell the world we managed to mmap the file. */
6d52618b 221 catalog->status = mmapped;
a641835a 222 else
7cabd57c 223#endif /* _POSIX_MAPPED_FILES */
a641835a
RM
224 {
225 /* mmap failed perhaps because the system call is not
226 implemented. Try to load the file. */
227 size_t todo;
228 catalog->file_ptr = malloc (st.st_size);
229 if (catalog->file_ptr == NULL)
ca130fe4
UD
230 goto close_unlock_return;
231
a641835a
RM
232 todo = st.st_size;
233 /* Save read, handle partial reads. */
234 do
235 {
73299943
UD
236 size_t now = read_not_cancel (fd, (((char *) catalog->file_ptr)
237 + (st.st_size - todo)), todo);
17c389fc 238 if (now == 0 || now == (size_t) -1)
a641835a 239 {
17c389fc
UD
240#ifdef EINTR
241 if (now == (size_t) -1 && errno == EINTR)
242 continue;
243#endif
a641835a 244 free ((void *) catalog->file_ptr);
390500b1 245 goto close_unlock_return;
a641835a
RM
246 }
247 todo -= now;
248 }
249 while (todo > 0);
250 catalog->status = malloced;
251 }
252
a641835a
RM
253 /* Determine whether the file is a catalog file and if yes whether
254 it is written using the correct byte order. Else we have to swap
255 the values. */
a1ffb40e 256 if (__glibc_likely (catalog->file_ptr->magic == CATGETS_MAGIC))
a641835a
RM
257 swapping = 0;
258 else if (catalog->file_ptr->magic == SWAPU32 (CATGETS_MAGIC))
259 swapping = 1;
260 else
261 {
b0610668 262 invalid_file:
d553bbf2 263 /* Invalid file. Free the resources and mark catalog as not
a641835a 264 usable. */
7cabd57c 265#ifdef _POSIX_MAPPED_FILES
6d52618b 266 if (catalog->status == mmapped)
a5113b14 267 __munmap ((void *) catalog->file_ptr, catalog->file_size);
a641835a 268 else
7cabd57c 269#endif /* _POSIX_MAPPED_FILES */
a641835a 270 free (catalog->file_ptr);
390500b1 271 goto close_unlock_return;
a641835a
RM
272 }
273
274#define SWAP(x) (swapping ? SWAPU32 (x) : (x))
275
276 /* Get dimensions of the used hashing table. */
277 catalog->plane_size = SWAP (catalog->file_ptr->plane_size);
278 catalog->plane_depth = SWAP (catalog->file_ptr->plane_depth);
279
280 /* The file contains two versions of the pointer tables. Pick the
281 right one for the local byte order. */
282#if __BYTE_ORDER == __LITTLE_ENDIAN
283 catalog->name_ptr = &catalog->file_ptr->name_ptr[0];
284#elif __BYTE_ORDER == __BIG_ENDIAN
285 catalog->name_ptr = &catalog->file_ptr->name_ptr[catalog->plane_size
286 * catalog->plane_depth
287 * 3];
288#else
289# error Cannot handle __BYTE_ORDER byte order
290#endif
291
292 /* The rest of the file contains all the strings. They are
293 addressed relative to the position of the first string. */
294 catalog->strings =
295 (const char *) &catalog->file_ptr->name_ptr[catalog->plane_size
296 * catalog->plane_depth * 3 * 2];
39e16978 297
b0610668
UD
298 /* Determine the largest string offset mentioned in the table. */
299 max_offset = 0;
300 tab_size = 3 * catalog->plane_size * catalog->plane_depth;
301 for (cnt = 2; cnt < tab_size; cnt += 3)
302 if (catalog->name_ptr[cnt] > max_offset)
303 max_offset = catalog->name_ptr[cnt];
304
305 /* Now we can check whether the file is large enough to contain the
306 tables it says it contains. */
6dd67bd5
UD
307 if ((size_t) st.st_size
308 <= (sizeof (struct catalog_obj) + 2 * tab_size + max_offset))
b0610668
UD
309 /* The last string is not contained in the file. */
310 goto invalid_file;
311
312 lastp = catalog->strings + max_offset;
313 max_offset = (st.st_size
314 - sizeof (struct catalog_obj) + 2 * tab_size + max_offset);
315 while (*lastp != '\0')
316 {
317 if (--max_offset == 0)
318 goto invalid_file;
319 ++lastp;
320 }
321
ca130fe4
UD
322 /* We succeeded. */
323 result = 0;
324
39e16978 325 /* Release the lock again. */
390500b1 326 close_unlock_return:
73299943 327 close_not_cancel_no_status (fd);
ca130fe4
UD
328
329 return result;
a641835a 330}
37ba7d66 331libc_hidden_def (__open_catalog)