[System] Collections from CoreFX
[mono-project.git] / support / grp.c
blob827bc550d938fa91252db4ca620d739b939cb508
1 /*
2 * <grp.h> wrapper functions.
4 * Authors:
5 * Jonathan Pryor (jonpryor@vt.edu)
7 * Copyright (C) 2004-2005 Jonathan Pryor
8 */
10 #include <sys/types.h>
11 #ifdef HAVE_SYS_PARAM_H
12 #include <sys/param.h>
13 #endif
14 #include <grp.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <errno.h>
18 #include <string.h>
19 #include <unistd.h> /* for setgroups on Mac OS X */
21 #include "map.h"
22 #include "mph.h"
24 G_BEGIN_DECLS
26 static void
27 count_members (char **gr_mem, int *count, size_t *mem)
29 char *cur;
30 *count = 0;
32 // ensure that later (*mem)+1 doesn't result in integer overflow
33 if (*mem > INT_MAX - 1)
34 return;
36 for (cur = *gr_mem; cur != NULL; cur = *++gr_mem) {
37 size_t len;
38 len = strlen (cur);
40 if (!(len < INT_MAX - ((*mem) + 1)))
41 break;
43 ++(*count);
44 *mem += (len + 1);
48 static int
49 copy_group (struct Mono_Posix_Syscall__Group *to, struct group *from)
51 size_t nlen, plen, buflen;
52 int i, count;
53 char *cur, **to_mem;
55 to->gr_gid = from->gr_gid;
57 to->gr_name = NULL;
58 to->gr_passwd = NULL;
59 to->gr_mem = NULL;
60 to->_gr_buf_ = NULL;
62 nlen = strlen (from->gr_name);
63 plen = strlen (from->gr_passwd);
65 buflen = 2;
67 if (!(nlen < INT_MAX - buflen))
68 return -1;
69 buflen += nlen;
71 if (!(plen < INT_MAX - buflen))
72 return -1;
73 buflen += plen;
75 count = 0;
76 count_members (from->gr_mem, &count, &buflen);
78 to->_gr_nmem_ = count;
79 cur = to->_gr_buf_ = (char*) malloc (buflen);
80 to_mem = to->gr_mem = malloc (sizeof(char*)*(count+1));
81 if (to->_gr_buf_ == NULL || to->gr_mem == NULL) {
82 free (to->_gr_buf_);
83 free (to->gr_mem);
84 return -1;
87 to->gr_name = strcpy (cur, from->gr_name);
88 cur += (nlen + 1);
89 to->gr_passwd = strcpy (cur, from->gr_passwd);
90 cur += (plen + 1);
92 for (i = 0; i != count; ++i) {
93 to_mem [i] = strcpy (cur, from->gr_mem[i]);
94 cur += (strlen (from->gr_mem[i])+1);
96 to_mem [i] = NULL;
98 return 0;
101 gint32
102 Mono_Posix_Syscall_getgrnam (const char *name, struct Mono_Posix_Syscall__Group *gbuf)
104 struct group *_gbuf;
106 if (gbuf == NULL) {
107 errno = EFAULT;
108 return -1;
111 errno = 0;
112 _gbuf = getgrnam (name);
113 if (_gbuf == NULL)
114 return -1;
116 if (copy_group (gbuf, _gbuf) == -1) {
117 errno = ENOMEM;
118 return -1;
120 return 0;
123 gint32
124 Mono_Posix_Syscall_getgrgid (mph_gid_t gid, struct Mono_Posix_Syscall__Group *gbuf)
126 struct group *_gbuf;
128 if (gbuf == NULL) {
129 errno = EFAULT;
130 return -1;
133 errno = 0;
134 _gbuf = getgrgid (gid);
135 if (_gbuf == NULL)
136 return -1;
138 if (copy_group (gbuf, _gbuf) == -1) {
139 errno = ENOMEM;
140 return -1;
142 return 0;
145 #ifdef HAVE_GETGRNAM_R
146 gint32
147 Mono_Posix_Syscall_getgrnam_r (const char *name,
148 struct Mono_Posix_Syscall__Group *gbuf,
149 void **gbufp)
151 char *buf, *buf2;
152 size_t buflen;
153 int r;
154 struct group _grbuf;
156 if (gbuf == NULL) {
157 errno = EFAULT;
158 return -1;
161 buf = buf2 = NULL;
162 buflen = 2;
164 do {
165 buf2 = realloc (buf, buflen *= 2);
166 if (buf2 == NULL) {
167 free (buf);
168 errno = ENOMEM;
169 return -1;
171 buf = buf2;
172 errno = 0;
173 } while ((r = getgrnam_r (name, &_grbuf, buf, buflen, (struct group**) gbufp)) &&
174 recheck_range (r));
176 /* On Solaris, this function returns 0 even if the entry was not found */
177 if (r == 0 && !(*gbufp))
178 r = errno = ENOENT;
180 if (r == 0 && copy_group (gbuf, &_grbuf) == -1)
181 r = errno = ENOMEM;
182 free (buf);
184 return r;
186 #endif /* ndef HAVE_GETGRNAM_R */
188 #ifdef HAVE_GETGRGID_R
189 gint32
190 Mono_Posix_Syscall_getgrgid_r (mph_gid_t gid,
191 struct Mono_Posix_Syscall__Group *gbuf,
192 void **gbufp)
194 char *buf, *buf2;
195 size_t buflen;
196 int r;
197 struct group _grbuf;
199 if (gbuf == NULL) {
200 errno = EFAULT;
201 return -1;
204 buf = buf2 = NULL;
205 buflen = 2;
207 do {
208 buf2 = realloc (buf, buflen *= 2);
209 if (buf2 == NULL) {
210 free (buf);
211 errno = ENOMEM;
212 return -1;
214 buf = buf2;
215 errno = 0;
216 } while ((r = getgrgid_r (gid, &_grbuf, buf, buflen, (struct group**) gbufp)) &&
217 recheck_range (r));
219 /* On Solaris, this function returns 0 even if the entry was not found */
220 if (r == 0 && !(*gbufp))
221 r = errno = ENOENT;
223 if (r == 0 && copy_group (gbuf, &_grbuf) == -1)
224 r = errno = ENOMEM;
225 free (buf);
227 return r;
229 #endif /* ndef HAVE_GETGRGID_R */
231 #if HAVE_GETGRENT
232 gint32
233 Mono_Posix_Syscall_getgrent (struct Mono_Posix_Syscall__Group *grbuf)
235 struct group *gr;
237 if (grbuf == NULL) {
238 errno = EFAULT;
239 return -1;
242 errno = 0;
243 gr = getgrent ();
244 if (gr == NULL)
245 return -1;
247 if (copy_group (grbuf, gr) == -1) {
248 errno = ENOMEM;
249 return -1;
251 return 0;
253 #endif /* def HAVE_GETGRENT */
255 #ifdef HAVE_FGETGRENT
256 gint32
257 Mono_Posix_Syscall_fgetgrent (void *stream, struct Mono_Posix_Syscall__Group *grbuf)
259 struct group *gr;
261 if (grbuf == NULL) {
262 errno = EFAULT;
263 return -1;
266 errno = 0;
267 gr = fgetgrent ((FILE*) stream);
268 if (gr == NULL)
269 return -1;
271 if (copy_group (grbuf, gr) == -1) {
272 errno = ENOMEM;
273 return -1;
275 return 0;
277 #endif /* ndef HAVE_FGETGRENT */
279 #if HAVE_SETGROUPS
280 gint32
281 Mono_Posix_Syscall_setgroups (mph_size_t size, mph_gid_t *list)
283 mph_return_if_size_t_overflow (size);
284 return setgroups ((size_t) size, list);
286 #endif /* def HAVE_SETGROUPS */
288 #if HAVE_SETGRENT
290 Mono_Posix_Syscall_setgrent (void)
292 errno = 0;
293 do {
294 setgrent ();
295 } while (errno == EINTR);
296 mph_return_if_val_in_list5(errno, EIO, EMFILE, ENFILE, ENOMEM, ERANGE);
297 return 0;
299 #endif /* def HAVE_SETGRENT */
301 #if HAVE_ENDGRENT
303 Mono_Posix_Syscall_endgrent (void)
305 endgrent();
306 return 0;
308 #endif /* def HAVE_ENDGRENT */
311 G_END_DECLS
314 * vim: noexpandtab