Initial public busybox upstream commit
[busybox4maemo] / e2fsprogs / old_e2fsprogs / e2p / feature.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * feature.c --- convert between features and strings
4  *
5  * Copyright (C) 1999  Theodore Ts'o <tytso@mit.edu>
6  *
7  * This file can be redistributed under the terms of the GNU Library General
8  * Public License
9  *
10  */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <ctype.h>
16 #include <errno.h>
17
18 #include "e2p.h"
19
20 struct feature {
21         int             compat;
22         unsigned int    mask;
23         const char      *string;
24 };
25
26 static const struct feature feature_list[] = {
27         {       E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_PREALLOC,
28                         "dir_prealloc" },
29         {       E2P_FEATURE_COMPAT, EXT3_FEATURE_COMPAT_HAS_JOURNAL,
30                         "has_journal" },
31         {       E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_IMAGIC_INODES,
32                         "imagic_inodes" },
33         {       E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_EXT_ATTR,
34                         "ext_attr" },
35         {       E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_INDEX,
36                         "dir_index" },
37         {       E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_RESIZE_INODE,
38                         "resize_inode" },
39         {       E2P_FEATURE_RO_INCOMPAT, EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER,
40                         "sparse_super" },
41         {       E2P_FEATURE_RO_INCOMPAT, EXT2_FEATURE_RO_COMPAT_LARGE_FILE,
42                         "large_file" },
43         {       E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_COMPRESSION,
44                         "compression" },
45         {       E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_FILETYPE,
46                         "filetype" },
47         {       E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_RECOVER,
48                         "needs_recovery" },
49         {       E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_JOURNAL_DEV,
50                         "journal_dev" },
51         {       E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_EXTENTS,
52                         "extents" },
53         {       E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_META_BG,
54                         "meta_bg" },
55         {       0, 0, 0 },
56 };
57
58 const char *e2p_feature2string(int compat, unsigned int mask)
59 {
60         const struct feature *f;
61         static char buf[20];
62         char fchar;
63         int fnum;
64
65         for (f = feature_list; f->string; f++) {
66                 if ((compat == f->compat) &&
67                     (mask == f->mask))
68                         return f->string;
69         }
70         switch (compat) {
71         case E2P_FEATURE_COMPAT:
72                 fchar = 'C';
73                 break;
74         case E2P_FEATURE_INCOMPAT:
75                 fchar = 'I';
76                 break;
77         case E2P_FEATURE_RO_INCOMPAT:
78                 fchar = 'R';
79                 break;
80         default:
81                 fchar = '?';
82                 break;
83         }
84         for (fnum = 0; mask >>= 1; fnum++);
85                 sprintf(buf, "FEATURE_%c%d", fchar, fnum);
86         return buf;
87 }
88
89 int e2p_string2feature(char *string, int *compat_type, unsigned int *mask)
90 {
91         const struct feature *f;
92         char *eptr;
93         int num;
94
95         for (f = feature_list; f->string; f++) {
96                 if (!strcasecmp(string, f->string)) {
97                         *compat_type = f->compat;
98                         *mask = f->mask;
99                         return 0;
100                 }
101         }
102         if (strncasecmp(string, "FEATURE_", 8))
103                 return 1;
104
105         switch (string[8]) {
106         case 'c':
107         case 'C':
108                 *compat_type = E2P_FEATURE_COMPAT;
109                 break;
110         case 'i':
111         case 'I':
112                 *compat_type = E2P_FEATURE_INCOMPAT;
113                 break;
114         case 'r':
115         case 'R':
116                 *compat_type = E2P_FEATURE_RO_INCOMPAT;
117                 break;
118         default:
119                 return 1;
120         }
121         if (string[9] == 0)
122                 return 1;
123         num = strtol(string+9, &eptr, 10);
124         if (num > 32 || num < 0)
125                 return 1;
126         if (*eptr)
127                 return 1;
128         *mask = 1 << num;
129         return 0;
130 }
131
132 static inline char *skip_over_blanks(char *cp)
133 {
134         while (*cp && isspace(*cp))
135                 cp++;
136         return cp;
137 }
138
139 static inline char *skip_over_word(char *cp)
140 {
141         while (*cp && !isspace(*cp) && *cp != ',')
142                 cp++;
143         return cp;
144 }
145
146 /*
147  * Edit a feature set array as requested by the user.  The ok_array,
148  * if set, allows the application to limit what features the user is
149  * allowed to set or clear using this function.
150  */
151 int e2p_edit_feature(const char *str, __u32 *compat_array, __u32 *ok_array)
152 {
153         char    *cp, *buf, *next;
154         int     neg;
155         unsigned int    mask;
156         int             compat_type;
157
158         buf = xstrdup(str);
159         cp = buf;
160         while (cp && *cp) {
161                 neg = 0;
162                 cp = skip_over_blanks(cp);
163                 next = skip_over_word(cp);
164                 if (*next == 0)
165                         next = 0;
166                 else
167                         *next = 0;
168                 switch (*cp) {
169                 case '-':
170                 case '^':
171                         neg++;
172                 case '+':
173                         cp++;
174                         break;
175                 }
176                 if (e2p_string2feature(cp, &compat_type, &mask))
177                         return 1;
178                 if (ok_array && !(ok_array[compat_type] & mask))
179                         return 1;
180                 if (neg)
181                         compat_array[compat_type] &= ~mask;
182                 else
183                         compat_array[compat_type] |= mask;
184                 cp = next ? next+1 : 0;
185         }
186         return 0;
187 }