1 /*        $NetBSD: stat_flags.c,v 1.3 2022/04/19 20:32:17 rillig Exp $          */
2 
3 /*-
4  * Copyright (c) 1993
5  *        The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #if HAVE_NBTOOL_CONFIG_H
33 #include "nbtool_config.h"
34 #else
35 #define HAVE_STRUCT_STAT_ST_FLAGS 1
36 #endif
37 
38 #include <sys/cdefs.h>
39 #if !defined(lint)
40 #if 0
41 static char sccsid[] = "@(#)stat_flags.c          8.2 (Berkeley) 7/28/94";
42 #else
43 __RCSID("$NetBSD: stat_flags.c,v 1.3 2022/04/19 20:32:17 rillig Exp $");
44 #endif
45 #endif /* not lint */
46 
47 #include <sys/types.h>
48 #include <sys/stat.h>
49 #include <fts.h>
50 #include <stddef.h>
51 #include <string.h>
52 #include <stdlib.h>
53 
54 #include "util.h"
55 
56 #define   SAPPEND(s) do {                                                                 \
57           if (prefix != NULL)                                                   \
58                     (void)strlcat(string, prefix, sizeof(string));              \
59           (void)strlcat(string, s, sizeof(string));                             \
60           prefix = ",";                                                                   \
61 } while (0)
62 
63 /*
64  * flags_to_string --
65  *        Convert stat flags to a comma-separated string.  If no flags
66  *        are set, return the default string.
67  */
68 char *
flags_to_string(u_long flags,const char * def)69 flags_to_string(u_long flags, const char *def)
70 {
71           char string[128];
72           const char *prefix;
73 
74           string[0] = '\0';
75           prefix = NULL;
76 #if HAVE_STRUCT_STAT_ST_FLAGS
77           if (flags & UF_APPEND)
78                     SAPPEND("uappnd");
79           if (flags & UF_IMMUTABLE)
80                     SAPPEND("uchg");
81           if (flags & UF_NODUMP)
82                     SAPPEND("nodump");
83           if (flags & UF_OPAQUE)
84                     SAPPEND("opaque");
85           if (flags & SF_APPEND)
86                     SAPPEND("sappnd");
87           if (flags & SF_ARCHIVED)
88                     SAPPEND("arch");
89           if (flags & SF_IMMUTABLE)
90                     SAPPEND("schg");
91 #ifdef SF_SNAPSHOT
92           if (flags & SF_SNAPSHOT)
93                     SAPPEND("snap");
94 #endif
95 #endif
96           if (prefix != NULL)
97                     return strdup(string);
98           return strdup(def);
99 }
100 
101 #define   TEST(a, b, f) {                                                                 \
102           if (!strcmp(a, b)) {                                                            \
103                     if (clear) {                                                          \
104                               if (clrp)                                         \
105                                         *clrp |= (f);                                     \
106                               if (setp)                                         \
107                                         *setp &= ~(f);                                    \
108                     } else {                                                    \
109                               if (setp)                                         \
110                                         *setp |= (f);                                     \
111                               if (clrp)                                         \
112                                         *clrp &= ~(f);                                    \
113                     }                                                                     \
114                     break;                                                                \
115           }                                                                               \
116 }
117 
118 /*
119  * string_to_flags --
120  *        Take string of arguments and return stat flags.  Return 0 on
121  *        success, 1 on failure.  On failure, stringp is set to point
122  *        to the offending token.
123  */
124 int
string_to_flags(char ** stringp,u_long * setp,u_long * clrp)125 string_to_flags(char **stringp, u_long *setp, u_long *clrp)
126 {
127           int clear;
128           char *string, *p;
129 
130           if (setp)
131                     *setp = 0;
132           if (clrp)
133                     *clrp = 0;
134 
135 #if HAVE_STRUCT_STAT_ST_FLAGS
136           string = *stringp;
137           while ((p = strsep(&string, "\t ,")) != NULL) {
138                     clear = 0;
139                     *stringp = p;
140                     if (*p == '\0')
141                               continue;
142                     if (p[0] == 'n' && p[1] == 'o') {
143                               clear = 1;
144                               p += 2;
145                     }
146                     switch (p[0]) {
147                     case 'a':
148                               TEST(p, "arch", SF_ARCHIVED);
149                               TEST(p, "archived", SF_ARCHIVED);
150                               return (1);
151                     case 'd':
152                               clear = !clear;
153                               TEST(p, "dump", UF_NODUMP);
154                               return (1);
155                     case 'n':
156                                         /*
157                                          * Support `nonodump'. Note that
158                                          * the state of clear is not changed.
159                                          */
160                               TEST(p, "nodump", UF_NODUMP);
161                               return (1);
162                     case 'o':
163                               TEST(p, "opaque", UF_OPAQUE);
164                               return (1);
165                     case 's':
166                               TEST(p, "sappnd", SF_APPEND);
167                               TEST(p, "sappend", SF_APPEND);
168                               TEST(p, "schg", SF_IMMUTABLE);
169                               TEST(p, "schange", SF_IMMUTABLE);
170                               TEST(p, "simmutable", SF_IMMUTABLE);
171                               return (1);
172                     case 'u':
173                               TEST(p, "uappnd", UF_APPEND);
174                               TEST(p, "uappend", UF_APPEND);
175                               TEST(p, "uchg", UF_IMMUTABLE);
176                               TEST(p, "uchange", UF_IMMUTABLE);
177                               TEST(p, "uimmutable", UF_IMMUTABLE);
178                               return (1);
179                     default:
180                               return (1);
181                     }
182           }
183 #endif
184 
185           return (0);
186 }
187