fdwalk should return 0 on an empty directory
[kopensolaris-gnu/glibc.git] / nis / nis_subr.c
1 /* Copyright (c) 1997,1999,2000,2004,2005,2006 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
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 <errno.h>
21 #include <string.h>
22 #include <rpcsvc/nis.h>
23
24 nis_name
25 nis_leaf_of (const_nis_name name)
26 {
27   static char result[NIS_MAXNAMELEN + 1];
28
29   return nis_leaf_of_r (name, result, NIS_MAXNAMELEN);
30 }
31
32 nis_name
33 nis_leaf_of_r (const_nis_name name, char *buffer, size_t buflen)
34 {
35   size_t i = 0;
36
37   buffer[0] = '\0';
38
39   while (name[i] != '.' && name[i] != '\0')
40     i++;
41
42   if (__builtin_expect (i >= buflen, 0))
43     {
44       __set_errno (ERANGE);
45       return NULL;
46     }
47
48   *((char *) __mempcpy (buffer, name, i)) = '\0';
49
50   return buffer;
51 }
52 libnsl_hidden_def (nis_leaf_of_r)
53
54 nis_name
55 nis_name_of (const_nis_name name)
56 {
57   static char result[NIS_MAXNAMELEN + 1];
58
59   return nis_name_of_r (name, result, NIS_MAXNAMELEN);
60 }
61
62 nis_name
63 nis_name_of_r (const_nis_name name, char *buffer, size_t buflen)
64 {
65   char *local_domain;
66   int diff;
67
68   local_domain = nis_local_directory ();
69
70   diff = strlen (name) - strlen (local_domain);
71   if (diff <= 0)
72     return NULL;
73
74   if (strcmp (&name[diff], local_domain) != 0)
75     return NULL;
76
77   if ((size_t) diff >= buflen)
78     {
79       __set_errno (ERANGE);
80       return NULL;
81     }
82
83   *((char *) __mempcpy (buffer, name, diff - 1)) = '\0';
84
85   if (diff - 1 == 0)
86     return NULL;
87
88   return buffer;
89 }
90 libnsl_hidden_def (nis_name_of_r)
91
92 static int __always_inline
93 count_dots (const_nis_name str)
94 {
95   int count = 0;
96
97   for (size_t i = 0; str[i] != '\0'; ++i)
98     if (str[i] == '.')
99       ++count;
100
101   return count;
102 }
103
104 /* If we run out of memory, we don't give already allocated memory
105    free. The overhead for bringing getnames back in a safe state to
106    free it is to big. */
107 nis_name *
108 nis_getnames (const_nis_name name)
109 {
110   const char *local_domain = nis_local_directory ();
111   size_t local_domain_len = strlen (local_domain);
112   size_t name_len = strlen (name);
113   char *path;
114   int pos = 0;
115   char *saveptr = NULL;
116   int have_point;
117   const char *cp;
118   const char *cp2;
119
120   int count = 2;
121   nis_name *getnames = malloc ((count + 1) * sizeof (char *));
122   if (__builtin_expect (getnames == NULL, 0))
123       return NULL;
124
125   /* Do we have a fully qualified NIS+ name ? If yes, give it back */
126   if (name[name_len - 1] == '.')
127     {
128       if ((getnames[0] = strdup (name)) == NULL)
129         {
130         free_null:
131           while (pos-- > 0)
132             free (getnames[pos]);
133           free (getnames);
134           return NULL;
135         }
136
137       getnames[1] = NULL;
138
139       return getnames;
140     }
141
142   /* If the passed NAME is shared a suffix (the latter of course with
143      a final dot) with each other we pass back NAME with a final
144      dot.  */
145   if (local_domain_len > 2)
146     {
147       have_point = 0;
148       cp = &local_domain[local_domain_len - 2];
149       cp2 = &name[name_len - 1];
150
151       while (*cp == *cp2)
152         {
153           if (*cp == '.')
154             have_point = 1;
155           --cp;
156           --cp2;
157           if (cp < local_domain)
158             {
159               have_point = cp2 < name || *cp2 == '.';
160               break;
161             }
162           if (cp2 < name)
163             {
164               have_point = *cp == '.';
165               break;
166             }
167         }
168
169       if (have_point)
170         {
171           getnames[0] = malloc (name_len + 2);
172           if (getnames[0] == NULL)
173             goto free_null;
174
175           strcpy (stpcpy (getnames[0], name), ".");
176           ++pos;
177         }
178     }
179
180   /* Get the search path, where we have to search "name" */
181   path = getenv ("NIS_PATH");
182   if (path == NULL)
183     path = strdupa ("$");
184   else
185     path = strdupa (path);
186
187   have_point = strchr (name, '.') != NULL;
188
189   cp = __strtok_r (path, ":", &saveptr);
190   while (cp)
191     {
192       if (strcmp (cp, "$") == 0)
193         {
194           const char *cptr = local_domain;
195           char *tmp;
196
197           while (*cptr != '\0' && count_dots (cptr) >= 2)
198             {
199               if (pos >= count)
200                 {
201                   count += 5;
202                   nis_name *newp = realloc (getnames,
203                                             (count + 1) * sizeof (char *));
204                   if (__builtin_expect (newp == NULL, 0))
205                     goto free_null;
206                   getnames = newp;
207                 }
208               tmp = malloc (strlen (cptr) + local_domain_len + name_len + 2);
209               if (__builtin_expect (tmp == NULL, 0))
210                 goto free_null;
211
212               getnames[pos] = tmp;
213               tmp = stpcpy (tmp, name);
214               *tmp++ = '.';
215               if (cptr[1] != '\0')
216                 stpcpy (tmp, cptr);
217               else
218                 ++cptr;
219
220               ++pos;
221
222               while (*cptr != '.' && *cptr != '\0')
223                 ++cptr;
224               if (cptr[0] != '\0' && cptr[1] != '\0')
225                 /* If we have only ".", don't remove the "." */
226                 ++cptr;
227             }
228         }
229       else
230         {
231           char *tmp;
232           size_t cplen = strlen (cp);
233
234           if (cp[cplen - 1] == '$')
235             {
236               char *p;
237
238               tmp = malloc (cplen + local_domain_len + name_len + 2);
239               if (__builtin_expect (tmp == NULL, 0))
240                 goto free_null;
241
242               p = __stpcpy (tmp, name);
243               *p++ = '.';
244               p = __mempcpy (p, cp, cplen);
245               --p;
246               if (p[-1] != '.')
247                 *p++ = '.';
248               __stpcpy (p, local_domain);
249             }
250           else
251             {
252               char *p;
253
254               tmp = malloc (cplen + name_len + 3);
255               if (__builtin_expect (tmp == NULL, 0))
256                 goto free_null;
257
258               p = __mempcpy (tmp, name, name_len);
259               *p++ = '.';
260               p = __mempcpy (p, cp, cplen);
261               if (p[-1] != '.')
262                 *p++ = '.';
263               *p = '\0';
264             }
265
266           if (pos >= count)
267             {
268               count += 5;
269               nis_name *newp = realloc (getnames,
270                                         (count + 1) * sizeof (char *));
271               if (__builtin_expect (newp == NULL, 0))
272                 goto free_null;
273               getnames = newp;
274             }
275           getnames[pos] = tmp;
276           ++pos;
277         }
278       cp = __strtok_r (NULL, ":", &saveptr);
279     }
280
281   if (pos == 0
282       && __asprintf (&getnames[pos++], "%s%s%s%s",
283                      name, name[name_len - 1] == '.' ? "" : ".",
284                      local_domain,
285                      local_domain[local_domain_len - 1] == '.' ? "" : ".") < 0)
286     goto free_null;
287
288   getnames[pos] = NULL;
289
290   return getnames;
291 }
292 libnsl_hidden_def (nis_getnames)
293
294 void
295 nis_freenames (nis_name *names)
296 {
297   int i = 0;
298
299   while (names[i] != NULL)
300     {
301       free (names[i]);
302       ++i;
303     }
304
305   free (names);
306 }
307 libnsl_hidden_def  (nis_freenames)
308
309 name_pos
310 nis_dir_cmp (const_nis_name n1, const_nis_name n2)
311 {
312   int len1, len2;
313
314   len1 = strlen (n1);
315   len2 = strlen (n2);
316
317   if (len1 == len2)
318     {
319       if (strcmp (n1, n2) == 0)
320         return SAME_NAME;
321       else
322         return NOT_SEQUENTIAL;
323     }
324
325   if (len1 < len2)
326     {
327       if (n2[len2 - len1 - 1] != '.')
328         return NOT_SEQUENTIAL;
329       else if (strcmp (&n2[len2 - len1], n1) == 0)
330         return HIGHER_NAME;
331       else
332         return NOT_SEQUENTIAL;
333     }
334   else
335     {
336       if (n1[len1 - len2 - 1] != '.')
337         return NOT_SEQUENTIAL;
338       else if (strcmp (&n1[len1 - len2], n2) == 0)
339         return LOWER_NAME;
340       else
341         return NOT_SEQUENTIAL;
342
343     }
344 }
345 libnsl_hidden_def (nis_dir_cmp)
346
347 void
348 nis_destroy_object (nis_object *obj)
349 {
350   nis_free_object (obj);
351 }
352 libnsl_hidden_def (nis_destroy_object)