acl_support_nfs4.c revision 194955
1/*-
2 * Copyright (c) 2008, 2009 Edward Tomasz Napiera��a <trasz@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/lib/libc/posix1e/acl_support_nfs4.c 194955 2009-06-25 12:46:59Z trasz $");
29
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <assert.h>
34#include <err.h>
35#include <sys/acl.h>
36#include "acl_support.h"
37
38struct flagnames_struct {
39	uint32_t	flag;
40	const char	*name;
41	char		letter;
42};
43
44struct flagnames_struct a_flags[] =
45    {{ ACL_ENTRY_FILE_INHERIT, "file_inherit", 'f'},
46     { ACL_ENTRY_DIRECTORY_INHERIT, "dir_inherit", 'd'},
47     { ACL_ENTRY_INHERIT_ONLY, "inherit_only", 'i'},
48     { ACL_ENTRY_NO_PROPAGATE_INHERIT, "no_propagate", 'n'},
49     { ACL_ENTRY_SUCCESSFUL_ACCESS, "successfull_access", 'S'},
50     { ACL_ENTRY_FAILED_ACCESS, "failed_access", 'F'},
51     /*
52      * There is no ACE_IDENTIFIER_GROUP here - SunOS does not show it
53      * in the "flags" field.  There is no ACE_OWNER, ACE_GROUP or
54      * ACE_EVERYONE either, for obvious reasons.
55      */
56     { 0, 0, 0}};
57
58struct flagnames_struct a_access_masks[] =
59    {{ ACL_READ_DATA, "read_data", 'r'},
60     { ACL_WRITE_DATA, "write_data", 'w'},
61     { ACL_EXECUTE, "execute", 'x'},
62     { ACL_APPEND_DATA, "append_data", 'p'},
63     { ACL_DELETE_CHILD, "delete_child", 'D'},
64     { ACL_DELETE, "delete", 'd'},
65     { ACL_READ_ATTRIBUTES, "read_attributes", 'a'},
66     { ACL_WRITE_ATTRIBUTES, "write_attributes", 'A'},
67     { ACL_READ_NAMED_ATTRS, "read_xattr", 'R'},
68     { ACL_WRITE_NAMED_ATTRS, "write_xattr", 'W'},
69     { ACL_READ_ACL, "read_acl", 'c'},
70     { ACL_WRITE_ACL, "write_acl", 'C'},
71     { ACL_WRITE_OWNER, "write_owner", 'o'},
72     { ACL_SYNCHRONIZE, "synchronize", 's'},
73     { 0, 0, 0}};
74
75static const char *
76format_flag(uint32_t *var, const struct flagnames_struct *flags)
77{
78
79	for (; flags->name != 0; flags++) {
80		if ((flags->flag & *var) == 0)
81			continue;
82
83		*var &= ~flags->flag;
84		return (flags->name);
85	}
86
87	return (NULL);
88}
89
90static int
91format_flags_verbose(char *str, size_t size, uint32_t var,
92    const struct flagnames_struct *flags)
93{
94	size_t off = 0;
95	const char *tmp;
96
97	while ((tmp = format_flag(&var, flags)) != NULL) {
98		off += snprintf(str + off, size - off, "%s/", tmp);
99		assert (off < size);
100	}
101
102	/* If there were any flags added... */
103	if (off > 0) {
104		off--;
105		/* ... then remove the last slash. */
106		assert(str[off] == '/');
107	}
108
109	str[off] = '\0';
110
111	return (0);
112}
113
114static int
115format_flags_compact(char *str, size_t size, uint32_t var,
116    const struct flagnames_struct *flags)
117{
118	size_t i;
119
120	for (i = 0; flags[i].name != NULL; i++) {
121		assert(i < size);
122		if ((flags[i].flag & var) == 0)
123			str[i] = '-';
124		else
125			str[i] = flags[i].letter;
126	}
127
128	str[i] = '\0';
129
130	return (0);
131}
132
133static int
134parse_flags_verbose(const char *strp, uint32_t *var,
135    const struct flagnames_struct *flags, const char *flags_name,
136    int *try_compact)
137{
138	int i, found, ever_found = 0;
139	char *str, *flag;
140
141	str = strdup(strp);
142	*try_compact = 0;
143	*var = 0;
144
145	while (str != NULL) {
146		flag = strsep(&str, "/:");
147
148		found = 0;
149		for (i = 0; flags[i].name != NULL; i++) {
150			if (strcmp(flags[i].name, flag) == 0) {
151				*var |= flags[i].flag;
152				found = 1;
153				ever_found = 1;
154			}
155		}
156
157		if (!found) {
158			if (ever_found)
159				warnx("malformed ACL: \"%s\" field contains "
160				    "invalid flag \"%s\"", flags_name, flag);
161			else
162				*try_compact = 1;
163			free(str);
164			return (-1);
165		}
166	}
167
168	free(str);
169	return (0);
170}
171
172static int
173parse_flags_compact(const char *str, uint32_t *var,
174    const struct flagnames_struct *flags, const char *flags_name)
175{
176	int i, j, found;
177
178	*var = 0;
179
180	for (i = 0;; i++) {
181		if (str[i] == '\0')
182			return (0);
183
184		/* Ignore minus signs. */
185		if (str[i] == '-')
186			continue;
187
188		found = 0;
189
190		for (j = 0; flags[j].name != NULL; j++) {
191			if (flags[j].letter == str[i]) {
192				*var |= flags[j].flag;
193				found = 1;
194				break;
195			}
196		}
197
198		if (!found) {
199			warnx("malformed ACL: \"%s\" field contains "
200			    "invalid flag \"%c\"", flags_name, str[i]);
201			return (-1);
202		}
203	}
204}
205
206int
207_nfs4_format_flags(char *str, size_t size, acl_flag_t var, int verbose)
208{
209
210	if (verbose)
211		return (format_flags_verbose(str, size, var, a_flags));
212
213	return (format_flags_compact(str, size, var, a_flags));
214}
215
216int
217_nfs4_format_access_mask(char *str, size_t size, acl_perm_t var, int verbose)
218{
219
220	if (verbose)
221		return (format_flags_verbose(str, size, var, a_access_masks));
222
223	return (format_flags_compact(str, size, var, a_access_masks));
224}
225
226int
227_nfs4_parse_flags(const char *str, acl_flag_t *flags)
228{
229	int error, try_compact;
230	int tmpflags;
231
232	error = parse_flags_verbose(str, &tmpflags, a_flags, "flags", &try_compact);
233	if (error && try_compact)
234		error = parse_flags_compact(str, &tmpflags, a_flags, "flags");
235
236	*flags = tmpflags;
237
238	return (error);
239}
240
241int
242_nfs4_parse_access_mask(const char *str, acl_perm_t *perms)
243{
244	int error, try_compact;
245	int tmpperms;
246
247	error = parse_flags_verbose(str, &tmpperms, a_access_masks,
248	    "access permissions", &try_compact);
249	if (error && try_compact)
250		error = parse_flags_compact(str, &tmpperms,
251		    a_access_masks, "access permissions");
252
253	*perms = tmpperms;
254
255	return (error);
256}
257/*-
258 * Copyright (c) 2008, 2009 Edward Tomasz Napiera��a <trasz@FreeBSD.org>
259 * All rights reserved.
260 *
261 * Redistribution and use in source and binary forms, with or without
262 * modification, are permitted provided that the following conditions
263 * are met:
264 * 1. Redistributions of source code must retain the above copyright
265 *    notice, this list of conditions and the following disclaimer.
266 * 2. Redistributions in binary form must reproduce the above copyright
267 *    notice, this list of conditions and the following disclaimer in the
268 *    documentation and/or other materials provided with the distribution.
269 *
270 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
271 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
272 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
273 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
274 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
275 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
276 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
277 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
278 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
279 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
280 * SUCH DAMAGE.
281 */
282
283#include <sys/cdefs.h>
284__FBSDID("$FreeBSD: head/lib/libc/posix1e/acl_support_nfs4.c 194955 2009-06-25 12:46:59Z trasz $");
285
286#include <stdio.h>
287#include <stdlib.h>
288#include <string.h>
289#include <assert.h>
290#include <err.h>
291#include <sys/acl.h>
292#include "acl_support.h"
293
294struct flagnames_struct {
295	uint32_t	flag;
296	const char	*name;
297	char		letter;
298};
299
300struct flagnames_struct a_flags[] =
301    {{ ACL_ENTRY_FILE_INHERIT, "file_inherit", 'f'},
302     { ACL_ENTRY_DIRECTORY_INHERIT, "dir_inherit", 'd'},
303     { ACL_ENTRY_INHERIT_ONLY, "inherit_only", 'i'},
304     { ACL_ENTRY_NO_PROPAGATE_INHERIT, "no_propagate", 'n'},
305     { ACL_ENTRY_SUCCESSFUL_ACCESS, "successfull_access", 'S'},
306     { ACL_ENTRY_FAILED_ACCESS, "failed_access", 'F'},
307     /*
308      * There is no ACE_IDENTIFIER_GROUP here - SunOS does not show it
309      * in the "flags" field.  There is no ACE_OWNER, ACE_GROUP or
310      * ACE_EVERYONE either, for obvious reasons.
311      */
312     { 0, 0, 0}};
313
314struct flagnames_struct a_access_masks[] =
315    {{ ACL_READ_DATA, "read_data", 'r'},
316     { ACL_WRITE_DATA, "write_data", 'w'},
317     { ACL_EXECUTE, "execute", 'x'},
318     { ACL_APPEND_DATA, "append_data", 'p'},
319     { ACL_DELETE_CHILD, "delete_child", 'D'},
320     { ACL_DELETE, "delete", 'd'},
321     { ACL_READ_ATTRIBUTES, "read_attributes", 'a'},
322     { ACL_WRITE_ATTRIBUTES, "write_attributes", 'A'},
323     { ACL_READ_NAMED_ATTRS, "read_xattr", 'R'},
324     { ACL_WRITE_NAMED_ATTRS, "write_xattr", 'W'},
325     { ACL_READ_ACL, "read_acl", 'c'},
326     { ACL_WRITE_ACL, "write_acl", 'C'},
327     { ACL_WRITE_OWNER, "write_owner", 'o'},
328     { ACL_SYNCHRONIZE, "synchronize", 's'},
329     { 0, 0, 0}};
330
331static const char *
332format_flag(uint32_t *var, const struct flagnames_struct *flags)
333{
334
335	for (; flags->name != 0; flags++) {
336		if ((flags->flag & *var) == 0)
337			continue;
338
339		*var &= ~flags->flag;
340		return (flags->name);
341	}
342
343	return (NULL);
344}
345
346static int
347format_flags_verbose(char *str, size_t size, uint32_t var,
348    const struct flagnames_struct *flags)
349{
350	size_t off = 0;
351	const char *tmp;
352
353	while ((tmp = format_flag(&var, flags)) != NULL) {
354		off += snprintf(str + off, size - off, "%s/", tmp);
355		assert (off < size);
356	}
357
358	/* If there were any flags added... */
359	if (off > 0) {
360		off--;
361		/* ... then remove the last slash. */
362		assert(str[off] == '/');
363	}
364
365	str[off] = '\0';
366
367	return (0);
368}
369
370static int
371format_flags_compact(char *str, size_t size, uint32_t var,
372    const struct flagnames_struct *flags)
373{
374	size_t i;
375
376	for (i = 0; flags[i].name != NULL; i++) {
377		assert(i < size);
378		if ((flags[i].flag & var) == 0)
379			str[i] = '-';
380		else
381			str[i] = flags[i].letter;
382	}
383
384	str[i] = '\0';
385
386	return (0);
387}
388
389static int
390parse_flags_verbose(const char *strp, uint32_t *var,
391    const struct flagnames_struct *flags, const char *flags_name,
392    int *try_compact)
393{
394	int i, found, ever_found = 0;
395	char *str, *flag;
396
397	str = strdup(strp);
398	*try_compact = 0;
399	*var = 0;
400
401	while (str != NULL) {
402		flag = strsep(&str, "/:");
403
404		found = 0;
405		for (i = 0; flags[i].name != NULL; i++) {
406			if (strcmp(flags[i].name, flag) == 0) {
407				*var |= flags[i].flag;
408				found = 1;
409				ever_found = 1;
410			}
411		}
412
413		if (!found) {
414			if (ever_found)
415				warnx("malformed ACL: \"%s\" field contains "
416				    "invalid flag \"%s\"", flags_name, flag);
417			else
418				*try_compact = 1;
419			free(str);
420			return (-1);
421		}
422	}
423
424	free(str);
425	return (0);
426}
427
428static int
429parse_flags_compact(const char *str, uint32_t *var,
430    const struct flagnames_struct *flags, const char *flags_name)
431{
432	int i, j, found;
433
434	*var = 0;
435
436	for (i = 0;; i++) {
437		if (str[i] == '\0')
438			return (0);
439
440		/* Ignore minus signs. */
441		if (str[i] == '-')
442			continue;
443
444		found = 0;
445
446		for (j = 0; flags[j].name != NULL; j++) {
447			if (flags[j].letter == str[i]) {
448				*var |= flags[j].flag;
449				found = 1;
450				break;
451			}
452		}
453
454		if (!found) {
455			warnx("malformed ACL: \"%s\" field contains "
456			    "invalid flag \"%c\"", flags_name, str[i]);
457			return (-1);
458		}
459	}
460}
461
462int
463_nfs4_format_flags(char *str, size_t size, acl_flag_t var, int verbose)
464{
465
466	if (verbose)
467		return (format_flags_verbose(str, size, var, a_flags));
468
469	return (format_flags_compact(str, size, var, a_flags));
470}
471
472int
473_nfs4_format_access_mask(char *str, size_t size, acl_perm_t var, int verbose)
474{
475
476	if (verbose)
477		return (format_flags_verbose(str, size, var, a_access_masks));
478
479	return (format_flags_compact(str, size, var, a_access_masks));
480}
481
482int
483_nfs4_parse_flags(const char *str, acl_flag_t *flags)
484{
485	int error, try_compact;
486	int tmpflags;
487
488	error = parse_flags_verbose(str, &tmpflags, a_flags, "flags", &try_compact);
489	if (error && try_compact)
490		error = parse_flags_compact(str, &tmpflags, a_flags, "flags");
491
492	*flags = tmpflags;
493
494	return (error);
495}
496
497int
498_nfs4_parse_access_mask(const char *str, acl_perm_t *perms)
499{
500	int error, try_compact;
501	int tmpperms;
502
503	error = parse_flags_verbose(str, &tmpperms, a_access_masks,
504	    "access permissions", &try_compact);
505	if (error && try_compact)
506		error = parse_flags_compact(str, &tmpperms,
507		    a_access_masks, "access permissions");
508
509	*perms = tmpperms;
510
511	return (error);
512}
513/*-
514 * Copyright (c) 2008, 2009 Edward Tomasz Napiera��a <trasz@FreeBSD.org>
515 * All rights reserved.
516 *
517 * Redistribution and use in source and binary forms, with or without
518 * modification, are permitted provided that the following conditions
519 * are met:
520 * 1. Redistributions of source code must retain the above copyright
521 *    notice, this list of conditions and the following disclaimer.
522 * 2. Redistributions in binary form must reproduce the above copyright
523 *    notice, this list of conditions and the following disclaimer in the
524 *    documentation and/or other materials provided with the distribution.
525 *
526 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
527 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
528 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
529 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
530 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
531 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
532 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
533 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
534 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
535 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
536 * SUCH DAMAGE.
537 */
538
539#include <sys/cdefs.h>
540__FBSDID("$FreeBSD: head/lib/libc/posix1e/acl_support_nfs4.c 194955 2009-06-25 12:46:59Z trasz $");
541
542#include <stdio.h>
543#include <stdlib.h>
544#include <string.h>
545#include <assert.h>
546#include <err.h>
547#include <sys/acl.h>
548#include "acl_support.h"
549
550struct flagnames_struct {
551	uint32_t	flag;
552	const char	*name;
553	char		letter;
554};
555
556struct flagnames_struct a_flags[] =
557    {{ ACL_ENTRY_FILE_INHERIT, "file_inherit", 'f'},
558     { ACL_ENTRY_DIRECTORY_INHERIT, "dir_inherit", 'd'},
559     { ACL_ENTRY_INHERIT_ONLY, "inherit_only", 'i'},
560     { ACL_ENTRY_NO_PROPAGATE_INHERIT, "no_propagate", 'n'},
561     { ACL_ENTRY_SUCCESSFUL_ACCESS, "successfull_access", 'S'},
562     { ACL_ENTRY_FAILED_ACCESS, "failed_access", 'F'},
563     /*
564      * There is no ACE_IDENTIFIER_GROUP here - SunOS does not show it
565      * in the "flags" field.  There is no ACE_OWNER, ACE_GROUP or
566      * ACE_EVERYONE either, for obvious reasons.
567      */
568     { 0, 0, 0}};
569
570struct flagnames_struct a_access_masks[] =
571    {{ ACL_READ_DATA, "read_data", 'r'},
572     { ACL_WRITE_DATA, "write_data", 'w'},
573     { ACL_EXECUTE, "execute", 'x'},
574     { ACL_APPEND_DATA, "append_data", 'p'},
575     { ACL_DELETE_CHILD, "delete_child", 'D'},
576     { ACL_DELETE, "delete", 'd'},
577     { ACL_READ_ATTRIBUTES, "read_attributes", 'a'},
578     { ACL_WRITE_ATTRIBUTES, "write_attributes", 'A'},
579     { ACL_READ_NAMED_ATTRS, "read_xattr", 'R'},
580     { ACL_WRITE_NAMED_ATTRS, "write_xattr", 'W'},
581     { ACL_READ_ACL, "read_acl", 'c'},
582     { ACL_WRITE_ACL, "write_acl", 'C'},
583     { ACL_WRITE_OWNER, "write_owner", 'o'},
584     { ACL_SYNCHRONIZE, "synchronize", 's'},
585     { 0, 0, 0}};
586
587static const char *
588format_flag(uint32_t *var, const struct flagnames_struct *flags)
589{
590
591	for (; flags->name != 0; flags++) {
592		if ((flags->flag & *var) == 0)
593			continue;
594
595		*var &= ~flags->flag;
596		return (flags->name);
597	}
598
599	return (NULL);
600}
601
602static int
603format_flags_verbose(char *str, size_t size, uint32_t var,
604    const struct flagnames_struct *flags)
605{
606	size_t off = 0;
607	const char *tmp;
608
609	while ((tmp = format_flag(&var, flags)) != NULL) {
610		off += snprintf(str + off, size - off, "%s/", tmp);
611		assert (off < size);
612	}
613
614	/* If there were any flags added... */
615	if (off > 0) {
616		off--;
617		/* ... then remove the last slash. */
618		assert(str[off] == '/');
619	}
620
621	str[off] = '\0';
622
623	return (0);
624}
625
626static int
627format_flags_compact(char *str, size_t size, uint32_t var,
628    const struct flagnames_struct *flags)
629{
630	size_t i;
631
632	for (i = 0; flags[i].name != NULL; i++) {
633		assert(i < size);
634		if ((flags[i].flag & var) == 0)
635			str[i] = '-';
636		else
637			str[i] = flags[i].letter;
638	}
639
640	str[i] = '\0';
641
642	return (0);
643}
644
645static int
646parse_flags_verbose(const char *strp, uint32_t *var,
647    const struct flagnames_struct *flags, const char *flags_name,
648    int *try_compact)
649{
650	int i, found, ever_found = 0;
651	char *str, *flag;
652
653	str = strdup(strp);
654	*try_compact = 0;
655	*var = 0;
656
657	while (str != NULL) {
658		flag = strsep(&str, "/:");
659
660		found = 0;
661		for (i = 0; flags[i].name != NULL; i++) {
662			if (strcmp(flags[i].name, flag) == 0) {
663				*var |= flags[i].flag;
664				found = 1;
665				ever_found = 1;
666			}
667		}
668
669		if (!found) {
670			if (ever_found)
671				warnx("malformed ACL: \"%s\" field contains "
672				    "invalid flag \"%s\"", flags_name, flag);
673			else
674				*try_compact = 1;
675			free(str);
676			return (-1);
677		}
678	}
679
680	free(str);
681	return (0);
682}
683
684static int
685parse_flags_compact(const char *str, uint32_t *var,
686    const struct flagnames_struct *flags, const char *flags_name)
687{
688	int i, j, found;
689
690	*var = 0;
691
692	for (i = 0;; i++) {
693		if (str[i] == '\0')
694			return (0);
695
696		/* Ignore minus signs. */
697		if (str[i] == '-')
698			continue;
699
700		found = 0;
701
702		for (j = 0; flags[j].name != NULL; j++) {
703			if (flags[j].letter == str[i]) {
704				*var |= flags[j].flag;
705				found = 1;
706				break;
707			}
708		}
709
710		if (!found) {
711			warnx("malformed ACL: \"%s\" field contains "
712			    "invalid flag \"%c\"", flags_name, str[i]);
713			return (-1);
714		}
715	}
716}
717
718int
719_nfs4_format_flags(char *str, size_t size, acl_flag_t var, int verbose)
720{
721
722	if (verbose)
723		return (format_flags_verbose(str, size, var, a_flags));
724
725	return (format_flags_compact(str, size, var, a_flags));
726}
727
728int
729_nfs4_format_access_mask(char *str, size_t size, acl_perm_t var, int verbose)
730{
731
732	if (verbose)
733		return (format_flags_verbose(str, size, var, a_access_masks));
734
735	return (format_flags_compact(str, size, var, a_access_masks));
736}
737
738int
739_nfs4_parse_flags(const char *str, acl_flag_t *flags)
740{
741	int error, try_compact;
742	int tmpflags;
743
744	error = parse_flags_verbose(str, &tmpflags, a_flags, "flags", &try_compact);
745	if (error && try_compact)
746		error = parse_flags_compact(str, &tmpflags, a_flags, "flags");
747
748	*flags = tmpflags;
749
750	return (error);
751}
752
753int
754_nfs4_parse_access_mask(const char *str, acl_perm_t *perms)
755{
756	int error, try_compact;
757	int tmpperms;
758
759	error = parse_flags_verbose(str, &tmpperms, a_access_masks,
760	    "access permissions", &try_compact);
761	if (error && try_compact)
762		error = parse_flags_compact(str, &tmpperms,
763		    a_access_masks, "access permissions");
764
765	*perms = tmpperms;
766
767	return (error);
768}
769