• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * feature.c --- convert between features and strings
3  *
4  * Copyright (C) 1999  Theodore Ts'o <tytso@mit.edu>
5  *
6  * This file can be redistributed under the terms of the GNU Library General
7  * Public License
8  *
9  */
10 
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <ctype.h>
15 #include <errno.h>
16 
17 #include "e2p.h"
18 
19 struct feature {
20 	int		compat;
21 	unsigned int	mask;
22 	const char	*string;
23 };
24 
25 static struct feature feature_list[] = {
26 	{	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_PREALLOC,
27 			"dir_prealloc" },
28 	{	E2P_FEATURE_COMPAT, EXT3_FEATURE_COMPAT_HAS_JOURNAL,
29 			"has_journal" },
30 	{	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_IMAGIC_INODES,
31 			"imagic_inodes" },
32 	{	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_EXT_ATTR,
33 			"ext_attr" },
34 	{	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_INDEX,
35 			"dir_index" },
36 	{	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_RESIZE_INODE,
37 			"resize_inode" },
38 	{	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_LAZY_BG,
39 			"lazy_bg" },
40 
41 	{	E2P_FEATURE_RO_INCOMPAT, EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER,
42 			"sparse_super" },
43 	{	E2P_FEATURE_RO_INCOMPAT, EXT2_FEATURE_RO_COMPAT_LARGE_FILE,
44 			"large_file" },
45 	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_HUGE_FILE,
46 			"huge_file" },
47 	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_GDT_CSUM,
48 			"gdt_checksum" },
49 	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_DIR_NLINK,
50 			"dir_nlink" },
51 	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE,
52 			"extra_isize" },
53 
54 	{	E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_COMPRESSION,
55 			"compression" },
56 	{	E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_FILETYPE,
57 			"filetype" },
58 	{	E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_RECOVER,
59 			"needs_recovery" },
60 	{	E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_JOURNAL_DEV,
61 			"journal_dev" },
62 	{	E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_EXTENTS,
63 			"extents" },
64 	{	E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_META_BG,
65 			"meta_bg" },
66 	{	E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_EXTENTS,
67 			"extent" },
68 	{	E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_64BIT,
69 			"64bit" },
70 	{	0, 0, 0 },
71 };
72 
e2p_feature2string(int compat,unsigned int mask)73 const char *e2p_feature2string(int compat, unsigned int mask)
74 {
75 	struct feature  *f;
76 	static char buf[20];
77 	char	fchar;
78 	int	fnum;
79 
80 	for (f = feature_list; f->string; f++) {
81 		if ((compat == f->compat) &&
82 		    (mask == f->mask))
83 			return f->string;
84 	}
85 	switch (compat) {
86 	case  E2P_FEATURE_COMPAT:
87 		fchar = 'C';
88 		break;
89 	case E2P_FEATURE_INCOMPAT:
90 		fchar = 'I';
91 		break;
92 	case E2P_FEATURE_RO_INCOMPAT:
93 		fchar = 'R';
94 		break;
95 	default:
96 		fchar = '?';
97 		break;
98 	}
99 	for (fnum = 0; mask >>= 1; fnum++);
100 	sprintf(buf, "FEATURE_%c%d", fchar, fnum);
101 	return buf;
102 }
103 
e2p_string2feature(char * string,int * compat_type,unsigned int * mask)104 int e2p_string2feature(char *string, int *compat_type, unsigned int *mask)
105 {
106 	struct feature  *f;
107 	char		*eptr;
108 	int		num;
109 
110 	for (f = feature_list; f->string; f++) {
111 		if (!strcasecmp(string, f->string)) {
112 			*compat_type = f->compat;
113 			*mask = f->mask;
114 			return 0;
115 		}
116 	}
117 	if (strncasecmp(string, "FEATURE_", 8))
118 		return 1;
119 
120 	switch (string[8]) {
121 	case 'c':
122 	case 'C':
123 		*compat_type = E2P_FEATURE_COMPAT;
124 		break;
125 	case 'i':
126 	case 'I':
127 		*compat_type = E2P_FEATURE_INCOMPAT;
128 		break;
129 	case 'r':
130 	case 'R':
131 		*compat_type = E2P_FEATURE_RO_INCOMPAT;
132 		break;
133 	default:
134 		return 1;
135 	}
136 	if (string[9] == 0)
137 		return 1;
138 	num = strtol(string+9, &eptr, 10);
139 	if (num > 32 || num < 0)
140 		return 1;
141 	if (*eptr)
142 		return 1;
143 	*mask = 1 << num;
144 	return 0;
145 }
146 
skip_over_blanks(char * cp)147 static char *skip_over_blanks(char *cp)
148 {
149 	while (*cp && isspace(*cp))
150 		cp++;
151 	return cp;
152 }
153 
skip_over_word(char * cp)154 static char *skip_over_word(char *cp)
155 {
156 	while (*cp && !isspace(*cp) && *cp != ',')
157 		cp++;
158 	return cp;
159 }
160 
161 /*
162  * Edit a feature set array as requested by the user.  The ok_array,
163  * if set, allows the application to limit what features the user is
164  * allowed to set or clear using this function.  If clear_ok_array is set,
165  * then use it tell whether or not it is OK to clear a filesystem feature.
166  */
e2p_edit_feature2(const char * str,__u32 * compat_array,__u32 * ok_array,__u32 * clear_ok_array,int * type_err,unsigned int * mask_err)167 int e2p_edit_feature2(const char *str, __u32 *compat_array, __u32 *ok_array,
168 		      __u32 *clear_ok_array, int *type_err,
169 		      unsigned int *mask_err)
170 {
171 	char		*cp, *buf, *next;
172 	int		neg;
173 	unsigned int	mask;
174 	int		compat_type;
175 	int		rc = 0;
176 
177 	if (!clear_ok_array)
178 		clear_ok_array = ok_array;
179 
180 	if (type_err)
181 		*type_err = 0;
182 	if (mask_err)
183 		*mask_err = 0;
184 
185 	buf = malloc(strlen(str)+1);
186 	if (!buf)
187 		return 1;
188 	strcpy(buf, str);
189 	for (cp = buf; cp && *cp; cp = next ? next+1 : 0) {
190 		neg = 0;
191 		cp = skip_over_blanks(cp);
192 		next = skip_over_word(cp);
193 
194 		if (*next == 0)
195 			next = 0;
196 		else
197 			*next = 0;
198 
199 		if ((strcasecmp(cp, "none") == 0) ||
200 		    (strcasecmp(cp, "clear") == 0)) {
201 			compat_array[0] = 0;
202 			compat_array[1] = 0;
203 			compat_array[2] = 0;
204 			continue;
205 		}
206 
207 		switch (*cp) {
208 		case '-':
209 		case '^':
210 			neg++;
211 		case '+':
212 			cp++;
213 			break;
214 		}
215 		if (e2p_string2feature(cp, &compat_type, &mask)) {
216 			rc = 1;
217 			break;
218 		}
219 		if (neg) {
220 			if (clear_ok_array &&
221 			    !(clear_ok_array[compat_type] & mask)) {
222 				rc = 1;
223 				if (type_err)
224 					*type_err = (compat_type |
225 						     E2P_FEATURE_NEGATE_FLAG);
226 				if (mask_err)
227 					*mask_err = mask;
228 				break;
229 			}
230 			compat_array[compat_type] &= ~mask;
231 		} else {
232 			if (ok_array && !(ok_array[compat_type] & mask)) {
233 				rc = 1;
234 				if (type_err)
235 					*type_err = compat_type;
236 				if (mask_err)
237 					*mask_err = mask;
238 				break;
239 			}
240 			compat_array[compat_type] |= mask;
241 		}
242 	}
243 	free(buf);
244 	return rc;
245 }
246 
e2p_edit_feature(const char * str,__u32 * compat_array,__u32 * ok_array)247 int e2p_edit_feature(const char *str, __u32 *compat_array, __u32 *ok_array)
248 {
249 	return e2p_edit_feature2(str, compat_array, ok_array, 0, 0, 0);
250 }
251