Пример #1
0
/* Maintenance of the shared handle open on the database.  */
enum nss_status
_nss_db_setnetgrent (const char *group, struct __netgrent *result)
{
  struct nss_db_map state;
  enum nss_status status = internal_setent (DBFILE, &state);

  if (status == NSS_STATUS_SUCCESS)
    {
      const struct nss_db_header *header = state.header;
      const stridx_t *hashtable
	= (const stridx_t *) ((const char *) header
			      + header->dbs[0].hashoffset);
      const char *valstrtab = (const char *) header + header->valstroffset;
      uint32_t hashval = __hash_string (group);
      size_t grouplen = strlen (group);
      size_t hidx = hashval % header->dbs[0].hashsize;
      size_t hval2 = 1 + hashval % (header->dbs[0].hashsize - 2);

      status = NSS_STATUS_NOTFOUND;
      while (hashtable[hidx] != ~((stridx_t) 0))
	{
	  const char *valstr = valstrtab + hashtable[hidx];

	  if (strncmp (valstr, group, grouplen) == 0
	      && isblank (valstr[grouplen]))
	    {
	      const char *cp = &valstr[grouplen + 1];
	      while (isblank (*cp))
		++cp;
	      if (*cp != '\0')
		{
		  result->data = strdup (cp);
		  if (result->data == NULL)
		    status = NSS_STATUS_TRYAGAIN;
		  else
		    {
		      status = NSS_STATUS_SUCCESS;
		      result->cursor = result->data;
		    }
		  break;
		}
	    }

	  if ((hidx += hval2) >= header->dbs[0].hashsize)
	    hidx -= header->dbs[0].hashsize;
	}

      internal_endent (&state);
    }

  return status;

}
Пример #2
0
/*
 * strhash_assign: assign hash entry.
 *
 *	i)	sh	STRHASH structure
 *	i)	name	name
 *	i)	force	if entry not found, create it.
 *	r)		pointer of the entry
 *
 * If specified entry is found then it is returned, else if the force == 1
 * then new allocated entry is returned.
 * This procedure doesn't operate the contents of entry->value.
 */
struct sh_entry *
strhash_assign(STRHASH *sh, const char *name, int force)
{
	struct sh_head *head = &sh->htab[__hash_string(name) % sh->buckets];
	struct sh_entry *entry;

	/*
	 * Lookup the name's entry.
	 */
	SLIST_FOREACH(entry, head, ptr)
		if (strcmp(entry->name, name) == 0)
			break;
	/*
	 * If not found, allocate an entry.
	 */
	if (entry == NULL && force) {
		entry = pool_malloc(sh->pool, sizeof(struct sh_entry));
		entry->name = pool_strdup(sh->pool, name, 0);
		entry->value = NULL;
		SLIST_INSERT_HEAD(head, entry, ptr);
		sh->entries++;
	}
	return entry;
}
Пример #3
0
static int
internal_function
find_module_idx (const char *str, size_t *idxp)
{
  unsigned int idx;
  unsigned int hval;
  unsigned int hval2;
  const struct gconvcache_header *header;
  const char *strtab;
  const struct hash_entry *hashtab;
  unsigned int limit;

  header = (const struct gconvcache_header *) gconv_cache;
  strtab = (char *) gconv_cache + header->string_offset;
  hashtab = (struct hash_entry *) ((char *) gconv_cache
				   + header->hash_offset);

  hval = __hash_string (str);
  idx = hval % header->hash_size;
  hval2 = 1 + hval % (header->hash_size - 2);

  limit = cache_size - header->string_offset;
  while (hashtab[idx].string_offset != 0)
    if (hashtab[idx].string_offset < limit
	&& strcmp (str, strtab + hashtab[idx].string_offset) == 0)
      {
	*idxp = hashtab[idx].module_idx;
	return 0;
      }
    else
      if ((idx += hval2) >= header->hash_size)
	idx -= header->hash_size;

  /* Nothing found.  */
  return -1;
}
Пример #4
0
/* Load the message catalogs specified by FILENAME.  If it is no valid
   message catalog do nothing.  */
void
internal_function
_nl_load_domain (struct loaded_l10nfile *domain_file,
		 struct binding *domainbinding)
{
  __libc_lock_define_initialized_recursive (static, lock)
  int fd = -1;
  size_t size;
#ifdef _LIBC
  struct stat64 st;
#else
  struct stat st;
#endif
  struct mo_file_header *data = (struct mo_file_header *) -1;
  int use_mmap = 0;
  struct loaded_domain *domain;
  int revision;
  const char *nullentry;
  size_t nullentrylen;

  __libc_lock_lock_recursive (lock);
  if (domain_file->decided != 0)
    {
      /* There are two possibilities:

	 + this is the same thread calling again during this initialization
	   via _nl_find_msg.  We have initialized everything this call needs.

	 + this is another thread which tried to initialize this object.
	   Not necessary anymore since if the lock is available this
	   is finished.
      */
      goto done;
    }

  domain_file->decided = -1;
  domain_file->data = NULL;

  /* Note that it would be useless to store domainbinding in domain_file
     because domainbinding might be == NULL now but != NULL later (after
     a call to bind_textdomain_codeset).  */

  /* If the record does not represent a valid locale the FILENAME
     might be NULL.  This can happen when according to the given
     specification the locale file name is different for XPG and CEN
     syntax.  */
  if (domain_file->filename == NULL)
    goto out;

  /* Try to open the addressed file.  */
  fd = open (domain_file->filename, O_RDONLY | O_BINARY);
  if (fd == -1)
    goto out;

  /* We must know about the size of the file.  */
  if (
#ifdef _LIBC
      __builtin_expect (fstat64 (fd, &st) != 0, 0)
#else
      __builtin_expect (fstat (fd, &st) != 0, 0)
#endif
      || __builtin_expect ((size = (size_t) st.st_size) != st.st_size, 0)
      || __builtin_expect (size < sizeof (struct mo_file_header), 0))
    /* Something went wrong.  */
    goto out;

#ifdef HAVE_MMAP
  /* Now we are ready to load the file.  If mmap() is available we try
     this first.  If not available or it failed we try to load it.  */
  data = (struct mo_file_header *) mmap (NULL, size, PROT_READ,
					 MAP_PRIVATE, fd, 0);

  if (__builtin_expect (data != (struct mo_file_header *) -1, 1))
    {
      /* mmap() call was successful.  */
      close (fd);
      fd = -1;
      use_mmap = 1;
    }
#endif

  /* If the data is not yet available (i.e. mmap'ed) we try to load
     it manually.  */
  if (data == (struct mo_file_header *) -1)
    {
      size_t to_read;
      char *read_ptr;

      data = (struct mo_file_header *) malloc (size);
      if (data == NULL)
	goto out;

      to_read = size;
      read_ptr = (char *) data;
      do
	{
	  long int nb = (long int) read (fd, read_ptr, to_read);
	  if (nb <= 0)
	    {
#ifdef EINTR
	      if (nb == -1 && errno == EINTR)
		continue;
#endif
	      goto out;
	    }
	  read_ptr += nb;
	  to_read -= nb;
	}
      while (to_read > 0);

      close (fd);
      fd = -1;
    }

  /* Using the magic number we can test whether it really is a message
     catalog file.  */
  if (__builtin_expect (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED,
			0))
    {
      /* The magic number is wrong: not a message catalog file.  */
#ifdef HAVE_MMAP
      if (use_mmap)
	munmap ((caddr_t) data, size);
      else
#endif
	free (data);
      goto out;
    }

  domain = (struct loaded_domain *) malloc (sizeof (struct loaded_domain));
  if (domain == NULL)
    goto out;
  domain_file->data = domain;

  domain->data = (char *) data;
  domain->use_mmap = use_mmap;
  domain->mmap_size = size;
  domain->must_swap = data->magic != _MAGIC;
  domain->malloced = NULL;

  /* Fill in the information about the available tables.  */
  revision = W (domain->must_swap, data->revision);
  /* We support only the major revisions 0 and 1.  */
  switch (revision >> 16)
    {
    case 0:
    case 1:
      domain->nstrings = W (domain->must_swap, data->nstrings);
      domain->orig_tab = (const struct string_desc *)
	((char *) data + W (domain->must_swap, data->orig_tab_offset));
      domain->trans_tab = (const struct string_desc *)
	((char *) data + W (domain->must_swap, data->trans_tab_offset));
      domain->hash_size = W (domain->must_swap, data->hash_tab_size);
      domain->hash_tab =
	(domain->hash_size > 2
	 ? (const nls_uint32 *)
	   ((char *) data + W (domain->must_swap, data->hash_tab_offset))
	 : NULL);
      domain->must_swap_hash_tab = domain->must_swap;

      /* Now dispatch on the minor revision.  */
      switch (revision & 0xffff)
	{
	case 0:
	  domain->n_sysdep_strings = 0;
	  domain->orig_sysdep_tab = NULL;
	  domain->trans_sysdep_tab = NULL;
	  break;
	case 1:
	default:
	  {
	    nls_uint32 n_sysdep_strings;

	    if (domain->hash_tab == NULL)
	      /* This is invalid.  These minor revisions need a hash table.  */
	      goto invalid;

	    n_sysdep_strings =
	      W (domain->must_swap, data->n_sysdep_strings);
	    if (n_sysdep_strings > 0)
	      {
		nls_uint32 n_sysdep_segments;
		const struct sysdep_segment *sysdep_segments;
		const char **sysdep_segment_values;
		const nls_uint32 *orig_sysdep_tab;
		const nls_uint32 *trans_sysdep_tab;
		nls_uint32 n_inmem_sysdep_strings;
		size_t memneed;
		char *mem;
		struct sysdep_string_desc *inmem_orig_sysdep_tab;
		struct sysdep_string_desc *inmem_trans_sysdep_tab;
		nls_uint32 *inmem_hash_tab;
		unsigned int i, j;

		/* Get the values of the system dependent segments.  */
		n_sysdep_segments =
		  W (domain->must_swap, data->n_sysdep_segments);
		sysdep_segments = (const struct sysdep_segment *)
		  ((char *) data
		   + W (domain->must_swap, data->sysdep_segments_offset));
		sysdep_segment_values =
		  (const char **)
		  alloca (n_sysdep_segments * sizeof (const char *));
		for (i = 0; i < n_sysdep_segments; i++)
		  {
		    const char *name =
		      (char *) data
		      + W (domain->must_swap, sysdep_segments[i].offset);
		    nls_uint32 namelen =
		      W (domain->must_swap, sysdep_segments[i].length);

		    if (!(namelen > 0 && name[namelen - 1] == '\0'))
		      {
			freea (sysdep_segment_values);
			goto invalid;
		      }

		    sysdep_segment_values[i] = get_sysdep_segment_value (name);
		  }

		orig_sysdep_tab = (const nls_uint32 *)
		  ((char *) data
		   + W (domain->must_swap, data->orig_sysdep_tab_offset));
		trans_sysdep_tab = (const nls_uint32 *)
		  ((char *) data
		   + W (domain->must_swap, data->trans_sysdep_tab_offset));

		/* Compute the amount of additional memory needed for the
		   system dependent strings and the augmented hash table.
		   At the same time, also drop string pairs which refer to
		   an undefined system dependent segment.  */
		n_inmem_sysdep_strings = 0;
		memneed = domain->hash_size * sizeof (nls_uint32);
		for (i = 0; i < n_sysdep_strings; i++)
		  {
		    int valid = 1;
		    size_t needs[2];

		    for (j = 0; j < 2; j++)
		      {
			const struct sysdep_string *sysdep_string =
			  (const struct sysdep_string *)
			  ((char *) data
			   + W (domain->must_swap,
				j == 0
				? orig_sysdep_tab[i]
				: trans_sysdep_tab[i]));
			size_t need = 0;
			const struct segment_pair *p = sysdep_string->segments;

			if (W (domain->must_swap, p->sysdepref) != SEGMENTS_END)
			  for (p = sysdep_string->segments;; p++)
			    {
			      nls_uint32 sysdepref;

			      need += W (domain->must_swap, p->segsize);

			      sysdepref = W (domain->must_swap, p->sysdepref);
			      if (sysdepref == SEGMENTS_END)
				break;

			      if (sysdepref >= n_sysdep_segments)
				{
				  /* Invalid.  */
				  freea (sysdep_segment_values);
				  goto invalid;
				}

			      if (sysdep_segment_values[sysdepref] == NULL)
				{
				  /* This particular string pair is invalid.  */
				  valid = 0;
				  break;
				}

			      need += strlen (sysdep_segment_values[sysdepref]);
			    }

			needs[j] = need;
			if (!valid)
			  break;
		      }

		    if (valid)
		      {
			n_inmem_sysdep_strings++;
			memneed += needs[0] + needs[1];
		      }
		  }
		memneed += 2 * n_inmem_sysdep_strings
			   * sizeof (struct sysdep_string_desc);

		if (n_inmem_sysdep_strings > 0)
		  {
		    unsigned int k;

		    /* Allocate additional memory.  */
		    mem = (char *) malloc (memneed);
		    if (mem == NULL)
		      goto invalid;

		    domain->malloced = mem;
		    inmem_orig_sysdep_tab = (struct sysdep_string_desc *) mem;
		    mem += n_inmem_sysdep_strings
			   * sizeof (struct sysdep_string_desc);
		    inmem_trans_sysdep_tab = (struct sysdep_string_desc *) mem;
		    mem += n_inmem_sysdep_strings
			   * sizeof (struct sysdep_string_desc);
		    inmem_hash_tab = (nls_uint32 *) mem;
		    mem += domain->hash_size * sizeof (nls_uint32);

		    /* Compute the system dependent strings.  */
		    k = 0;
		    for (i = 0; i < n_sysdep_strings; i++)
		      {
			int valid = 1;

			for (j = 0; j < 2; j++)
			  {
			    const struct sysdep_string *sysdep_string =
			      (const struct sysdep_string *)
			      ((char *) data
			       + W (domain->must_swap,
				    j == 0
				    ? orig_sysdep_tab[i]
				    : trans_sysdep_tab[i]));
			    const struct segment_pair *p =
			      sysdep_string->segments;

			    if (W (domain->must_swap, p->sysdepref)
				!= SEGMENTS_END)
			      for (p = sysdep_string->segments;; p++)
				{
				  nls_uint32 sysdepref;

				  sysdepref =
				    W (domain->must_swap, p->sysdepref);
				  if (sysdepref == SEGMENTS_END)
				    break;

				  if (sysdep_segment_values[sysdepref] == NULL)
				    {
				      /* This particular string pair is
					 invalid.  */
				      valid = 0;
				      break;
				    }
				}

			    if (!valid)
			      break;
			  }

			if (valid)
			  {
			    for (j = 0; j < 2; j++)
			      {
				const struct sysdep_string *sysdep_string =
				  (const struct sysdep_string *)
				  ((char *) data
				   + W (domain->must_swap,
					j == 0
					? orig_sysdep_tab[i]
					: trans_sysdep_tab[i]));
				const char *static_segments =
				  (char *) data
				  + W (domain->must_swap, sysdep_string->offset);
				const struct segment_pair *p =
				  sysdep_string->segments;

				/* Concatenate the segments, and fill
				   inmem_orig_sysdep_tab[k] (for j == 0) and
				   inmem_trans_sysdep_tab[k] (for j == 1).  */

				struct sysdep_string_desc *inmem_tab_entry =
				  (j == 0
				   ? inmem_orig_sysdep_tab
				   : inmem_trans_sysdep_tab)
				  + k;

				if (W (domain->must_swap, p->sysdepref)
				    == SEGMENTS_END)
				  {
				    /* Only one static segment.  */
				    inmem_tab_entry->length =
				      W (domain->must_swap, p->segsize);
				    inmem_tab_entry->pointer = static_segments;
				  }
				else
				  {
				    inmem_tab_entry->pointer = mem;

				    for (p = sysdep_string->segments;; p++)
				      {
					nls_uint32 segsize =
					  W (domain->must_swap, p->segsize);
					nls_uint32 sysdepref =
					  W (domain->must_swap, p->sysdepref);
					size_t n;

					if (segsize > 0)
					  {
					    memcpy (mem, static_segments, segsize);
					    mem += segsize;
					    static_segments += segsize;
					  }

					if (sysdepref == SEGMENTS_END)
					  break;

					n = strlen (sysdep_segment_values[sysdepref]);
					memcpy (mem, sysdep_segment_values[sysdepref], n);
					mem += n;
				      }

				    inmem_tab_entry->length =
				      mem - inmem_tab_entry->pointer;
				  }
			      }

			    k++;
			  }
		      }
		    if (k != n_inmem_sysdep_strings)
		      abort ();

		    /* Compute the augmented hash table.  */
		    for (i = 0; i < domain->hash_size; i++)
		      inmem_hash_tab[i] =
			W (domain->must_swap_hash_tab, domain->hash_tab[i]);
		    for (i = 0; i < n_inmem_sysdep_strings; i++)
		      {
			const char *msgid = inmem_orig_sysdep_tab[i].pointer;
			nls_uint32 hash_val = __hash_string (msgid);
			nls_uint32 idx = hash_val % domain->hash_size;
			nls_uint32 incr =
			  1 + (hash_val % (domain->hash_size - 2));

			for (;;)
			  {
			    if (inmem_hash_tab[idx] == 0)
			      {
				/* Hash table entry is empty.  Use it.  */
				inmem_hash_tab[idx] = 1 + domain->nstrings + i;
				break;
			      }

			    if (idx >= domain->hash_size - incr)
			      idx -= domain->hash_size - incr;
			    else
			      idx += incr;
			  }
		      }

		    domain->n_sysdep_strings = n_inmem_sysdep_strings;
		    domain->orig_sysdep_tab = inmem_orig_sysdep_tab;
		    domain->trans_sysdep_tab = inmem_trans_sysdep_tab;

		    domain->hash_tab = inmem_hash_tab;
		    domain->must_swap_hash_tab = 0;
		  }
		else
		  {
		    domain->n_sysdep_strings = 0;
		    domain->orig_sysdep_tab = NULL;
		    domain->trans_sysdep_tab = NULL;
		  }

		freea (sysdep_segment_values);
	      }
	    else
	      {
		domain->n_sysdep_strings = 0;
		domain->orig_sysdep_tab = NULL;
		domain->trans_sysdep_tab = NULL;
	      }
	  }
	  break;
	}
      break;
    default:
      /* This is an invalid revision.  */
    invalid:
      /* This is an invalid .mo file.  */
      if (domain->malloced)
	free (domain->malloced);
#ifdef HAVE_MMAP
      if (use_mmap)
	munmap ((caddr_t) data, size);
      else
#endif
	free (data);
      free (domain);
      domain_file->data = NULL;
      goto out;
    }

  /* No caches of converted translations so far.  */
  domain->conversions = NULL;
  domain->nconversions = 0;
  gl_rwlock_init (domain->conversions_lock);

  /* Get the header entry and look for a plural specification.  */
#ifdef IN_LIBGLOCALE
  nullentry =
    _nl_find_msg (domain_file, domainbinding, NULL, "", &nullentrylen);
#else
  nullentry = _nl_find_msg (domain_file, domainbinding, "", 0, &nullentrylen);
#endif
  EXTRACT_PLURAL_EXPRESSION (nullentry, &domain->plural, &domain->nplurals);

 out:
  if (fd != -1)
    close (fd);

  domain_file->decided = 1;

 done:
  __libc_lock_unlock_recursive (lock);
}
Пример #5
0
enum nss_status
_nss_db_initgroups_dyn (const char *user, gid_t group, long int *start,
			long int *size, gid_t **groupsp, long int limit,
			int *errnop)
{
  struct nss_db_map state = { NULL, 0 };
  enum nss_status status = internal_setent (_PATH_VARDB "group.db", &state);
  if (status != NSS_STATUS_SUCCESS)
    {
      *errnop = errno;
      return status;
    }

  const struct nss_db_header *header = state.header;
  int i;
  for (i = 0; i < header->ndbs; ++i)
    if (header->dbs[i].id == ':')
      break;
  if (i == header->ndbs)
    {
      status = NSS_STATUS_UNAVAIL;
      goto out;
    }

  const stridx_t *hashtable
    = (const stridx_t *) ((const char *) header
			  + header->dbs[i].hashoffset);
  const char *valstrtab = (const char *) header + header->valstroffset;
  size_t userlen = strlen (user);
  uint32_t hashval = __hash_string (user);
  size_t hidx = hashval % header->dbs[i].hashsize;
  size_t hval2 = 1 + hashval % (header->dbs[i].hashsize - 2);

  gid_t *groups = *groupsp;

  status = NSS_STATUS_NOTFOUND;
  while (hashtable[hidx] != ~((stridx_t) 0))
    {
      const char *valstr = valstrtab + hashtable[hidx];
      while (isblank (*valstr))
	++valstr;

      if (strncmp (valstr, user, userlen) == 0 && isblank (valstr[userlen]))
	{
	  valstr += userlen + 1;
	  while (isblank (*valstr))
	    ++valstr;

	  while (*valstr != '\0')
	    {
	      errno = 0;
	      char *endp;
	      unsigned long int n = strtoul (valstr, &endp, 10);
	      if (*endp != ',' && *endp != '\0')
		break;
	      valstr = *endp == '\0' ? endp : endp + 1;

	      if (n != ULONG_MAX || errno != ERANGE)
		{
		  /* Insert the group.  */
		  if (*start == *size)
		    {
		      /* Need a bigger buffer.  */
		      if (limit > 0 && *size == limit)
			{
			  /* We reached the maximum.  */
			  status = NSS_STATUS_SUCCESS;
			  goto out;
			}

		      long int newsize;
		      if (limit <= 0)
			newsize = 2 * *size;
		      else
			newsize = MIN (limit, 2 * *size);

		      gid_t *newgroups = realloc (groups,
						  newsize * sizeof (*groups));
		      if (newgroups == NULL)
			{
			  *errnop = ENOMEM;
			  status = NSS_STATUS_TRYAGAIN;
			  goto out;
			}

		      *groupsp = groups = newgroups;
		      *size = newsize;
		    }

		  groups[*start] = n;
		  *start += 1;
		}
	    }

	  status = NSS_STATUS_SUCCESS;
	  break;
	}

      if ((hidx += hval2) >= header->dbs[i].hashsize)
	hidx -= header->dbs[i].hashsize;
    }

 out:
  internal_endent (&state);

  return status;
}