(linenum→info "unix/slp.c:2238")

glibc/2.7/catgets/open_catalog.c

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