L4Re/departure

Annotated libext2fs/lib/libe2p/feature.c

212:c0651b3b711f
2021-10-09 Paul Boddie Updated libext2fs to version 1.46.2, also introducing some notes about the process of adapting the library for L4Re, together with a tool to generate a configuration from an existing, external "host" build of the library.
paul@181 1
/*
paul@181 2
 * feature.c --- convert between features and strings
paul@181 3
 *
paul@181 4
 * Copyright (C) 1999  Theodore Ts'o <tytso@mit.edu>
paul@181 5
 *
paul@181 6
 * %Begin-Header%
paul@181 7
 * This file may be redistributed under the terms of the GNU Library
paul@181 8
 * General Public License, version 2.
paul@181 9
 * %End-Header%
paul@181 10
 */
paul@181 11
paul@181 12
#include "config.h"
paul@181 13
#include <stdio.h>
paul@181 14
#include <stdlib.h>
paul@181 15
#include <string.h>
paul@181 16
#include <ctype.h>
paul@181 17
#include <errno.h>
paul@181 18
paul@181 19
#include "e2p.h"
paul@181 20
#include <ext2fs/ext2fs.h>
paul@181 21
#include <ext2fs/kernel-jbd.h>
paul@181 22
paul@181 23
struct feature {
paul@181 24
	int		compat;
paul@181 25
	unsigned int	mask;
paul@181 26
	const char	*string;
paul@181 27
};
paul@181 28
paul@181 29
static struct feature feature_list[] = {
paul@181 30
	{	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_PREALLOC,
paul@181 31
			"dir_prealloc" },
paul@181 32
	{	E2P_FEATURE_COMPAT, EXT3_FEATURE_COMPAT_HAS_JOURNAL,
paul@181 33
			"has_journal" },
paul@181 34
	{	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_IMAGIC_INODES,
paul@181 35
			"imagic_inodes" },
paul@181 36
	{	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_EXT_ATTR,
paul@181 37
			"ext_attr" },
paul@181 38
	{	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_INDEX,
paul@181 39
			"dir_index" },
paul@181 40
	{	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_RESIZE_INODE,
paul@181 41
			"resize_inode" },
paul@181 42
	{	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_LAZY_BG,
paul@181 43
			"lazy_bg" },
paul@181 44
	{	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_EXCLUDE_BITMAP,
paul@181 45
			"snapshot_bitmap" },
paul@181 46
	{	E2P_FEATURE_COMPAT, EXT4_FEATURE_COMPAT_SPARSE_SUPER2,
paul@181 47
			"sparse_super2" },
paul@212 48
	{	E2P_FEATURE_COMPAT, EXT4_FEATURE_COMPAT_FAST_COMMIT,
paul@212 49
			"fast_commit" },
paul@212 50
	{	E2P_FEATURE_COMPAT, EXT4_FEATURE_COMPAT_STABLE_INODES,
paul@212 51
			"stable_inodes" },
paul@181 52
paul@181 53
	{	E2P_FEATURE_RO_INCOMPAT, EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER,
paul@181 54
			"sparse_super" },
paul@181 55
	{	E2P_FEATURE_RO_INCOMPAT, EXT2_FEATURE_RO_COMPAT_LARGE_FILE,
paul@181 56
			"large_file" },
paul@181 57
	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_HUGE_FILE,
paul@181 58
			"huge_file" },
paul@181 59
	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_GDT_CSUM,
paul@181 60
			"uninit_bg" },
paul@181 61
	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_GDT_CSUM,
paul@181 62
			"uninit_groups" },
paul@181 63
	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_DIR_NLINK,
paul@181 64
			"dir_nlink" },
paul@181 65
	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE,
paul@181 66
			"extra_isize" },
paul@181 67
	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_QUOTA,
paul@181 68
			"quota" },
paul@181 69
	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_BIGALLOC,
paul@181 70
			"bigalloc"},
paul@181 71
	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_METADATA_CSUM,
paul@181 72
			"metadata_csum"},
paul@181 73
	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_REPLICA,
paul@181 74
			"replica" },
paul@181 75
	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_READONLY,
paul@181 76
			"read-only" },
paul@181 77
	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_PROJECT,
paul@181 78
			"project"},
paul@181 79
	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_SHARED_BLOCKS,
paul@181 80
			"shared_blocks"},
paul@181 81
	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_VERITY,
paul@181 82
			"verity"},
paul@181 83
paul@181 84
	{	E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_COMPRESSION,
paul@181 85
			"compression" },
paul@181 86
	{	E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_FILETYPE,
paul@181 87
			"filetype" },
paul@181 88
	{	E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_RECOVER,
paul@181 89
			"needs_recovery" },
paul@181 90
	{	E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_JOURNAL_DEV,
paul@181 91
			"journal_dev" },
paul@181 92
	{	E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_EXTENTS,
paul@181 93
			"extent" },
paul@181 94
	{	E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_EXTENTS,
paul@181 95
			"extents" },
paul@181 96
	{	E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_META_BG,
paul@181 97
			"meta_bg" },
paul@181 98
	{	E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_64BIT,
paul@181 99
			"64bit" },
paul@181 100
	{       E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_MMP,
paul@181 101
			"mmp" },
paul@181 102
	{       E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_FLEX_BG,
paul@181 103
			"flex_bg"},
paul@181 104
	{       E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_EA_INODE,
paul@181 105
			"ea_inode"},
paul@181 106
	{       E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_DIRDATA,
paul@181 107
			"dirdata"},
paul@181 108
	{       E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_CSUM_SEED,
paul@181 109
			"metadata_csum_seed"},
paul@181 110
	{       E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_LARGEDIR,
paul@181 111
			"large_dir"},
paul@181 112
	{       E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_INLINE_DATA,
paul@181 113
			"inline_data"},
paul@181 114
	{       E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_ENCRYPT,
paul@181 115
			"encrypt"},
paul@212 116
	{       E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_CASEFOLD,
paul@212 117
			"casefold"},
paul@212 118
	{       E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_CASEFOLD,
paul@212 119
			"fname_encoding"},
paul@181 120
	{	0, 0, 0 },
paul@181 121
};
paul@181 122
paul@181 123
static struct feature jrnl_feature_list[] = {
paul@212 124
       {       E2P_FEATURE_COMPAT, JBD2_FEATURE_COMPAT_CHECKSUM,
paul@181 125
                       "journal_checksum" },
paul@181 126
paul@212 127
       {       E2P_FEATURE_INCOMPAT, JBD2_FEATURE_INCOMPAT_REVOKE,
paul@181 128
                       "journal_incompat_revoke" },
paul@212 129
       {       E2P_FEATURE_INCOMPAT, JBD2_FEATURE_INCOMPAT_64BIT,
paul@181 130
                       "journal_64bit" },
paul@212 131
       {       E2P_FEATURE_INCOMPAT, JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT,
paul@181 132
                       "journal_async_commit" },
paul@212 133
       {       E2P_FEATURE_INCOMPAT, JBD2_FEATURE_INCOMPAT_CSUM_V2,
paul@181 134
                       "journal_checksum_v2" },
paul@212 135
       {       E2P_FEATURE_INCOMPAT, JBD2_FEATURE_INCOMPAT_CSUM_V3,
paul@181 136
                       "journal_checksum_v3" },
paul@181 137
       {       0, 0, 0 },
paul@181 138
};
paul@181 139
paul@212 140
void e2p_feature_to_string(int compat, unsigned int mask, char *buf,
paul@212 141
                           size_t buf_len)
paul@181 142
{
paul@181 143
	struct feature  *f;
paul@181 144
	char	fchar;
paul@181 145
	int	fnum;
paul@181 146
paul@181 147
	for (f = feature_list; f->string; f++) {
paul@181 148
		if ((compat == f->compat) &&
paul@212 149
		    (mask == f->mask)) {
paul@212 150
			strncpy(buf, f->string, buf_len);
paul@212 151
			buf[buf_len - 1] = 0;
paul@212 152
			return;
paul@212 153
		}
paul@181 154
	}
paul@181 155
	switch (compat) {
paul@181 156
	case  E2P_FEATURE_COMPAT:
paul@181 157
		fchar = 'C';
paul@181 158
		break;
paul@181 159
	case E2P_FEATURE_INCOMPAT:
paul@181 160
		fchar = 'I';
paul@181 161
		break;
paul@181 162
	case E2P_FEATURE_RO_INCOMPAT:
paul@181 163
		fchar = 'R';
paul@181 164
		break;
paul@181 165
	default:
paul@181 166
		fchar = '?';
paul@181 167
		break;
paul@181 168
	}
paul@181 169
	for (fnum = 0; mask >>= 1; fnum++);
paul@181 170
	sprintf(buf, "FEATURE_%c%d", fchar, fnum);
paul@212 171
}
paul@212 172
paul@212 173
const char *e2p_feature2string(int compat, unsigned int mask)
paul@212 174
{
paul@212 175
	static char buf[20];
paul@212 176
paul@212 177
	e2p_feature_to_string(compat, mask, buf, sizeof(buf) / sizeof(buf[0]));
paul@181 178
	return buf;
paul@181 179
}
paul@181 180
paul@181 181
int e2p_string2feature(char *string, int *compat_type, unsigned int *mask)
paul@181 182
{
paul@181 183
	struct feature  *f;
paul@181 184
	char		*eptr;
paul@181 185
	int		num;
paul@181 186
paul@181 187
	for (f = feature_list; f->string; f++) {
paul@181 188
		if (!strcasecmp(string, f->string)) {
paul@181 189
			*compat_type = f->compat;
paul@181 190
			*mask = f->mask;
paul@181 191
			return 0;
paul@181 192
		}
paul@181 193
	}
paul@181 194
	if (strncasecmp(string, "FEATURE_", 8))
paul@181 195
		return 1;
paul@181 196
paul@181 197
	switch (string[8]) {
paul@181 198
	case 'c':
paul@181 199
	case 'C':
paul@181 200
		*compat_type = E2P_FEATURE_COMPAT;
paul@181 201
		break;
paul@181 202
	case 'i':
paul@181 203
	case 'I':
paul@181 204
		*compat_type = E2P_FEATURE_INCOMPAT;
paul@181 205
		break;
paul@181 206
	case 'r':
paul@181 207
	case 'R':
paul@181 208
		*compat_type = E2P_FEATURE_RO_INCOMPAT;
paul@181 209
		break;
paul@181 210
	default:
paul@181 211
		return 1;
paul@181 212
	}
paul@181 213
	if (string[9] == 0)
paul@181 214
		return 1;
paul@181 215
	num = strtol(string+9, &eptr, 10);
paul@181 216
	if (num > 31 || num < 0)
paul@181 217
		return 1;
paul@181 218
	if (*eptr)
paul@181 219
		return 1;
paul@181 220
	*mask = 1 << num;
paul@181 221
	return 0;
paul@181 222
}
paul@181 223
paul@181 224
const char *e2p_jrnl_feature2string(int compat, unsigned int mask)
paul@181 225
{
paul@181 226
	struct feature  *f;
paul@181 227
	static char buf[20];
paul@181 228
	char	fchar;
paul@181 229
	int	fnum;
paul@181 230
paul@181 231
	for (f = jrnl_feature_list; f->string; f++) {
paul@181 232
		if ((compat == f->compat) &&
paul@181 233
		    (mask == f->mask))
paul@181 234
			return f->string;
paul@181 235
	}
paul@181 236
	switch (compat) {
paul@181 237
	case  E2P_FEATURE_COMPAT:
paul@181 238
		fchar = 'C';
paul@181 239
		break;
paul@181 240
	case E2P_FEATURE_INCOMPAT:
paul@181 241
		fchar = 'I';
paul@181 242
		break;
paul@181 243
	case E2P_FEATURE_RO_INCOMPAT:
paul@181 244
		fchar = 'R';
paul@181 245
		break;
paul@181 246
	default:
paul@181 247
		fchar = '?';
paul@181 248
		break;
paul@181 249
	}
paul@181 250
	for (fnum = 0; mask >>= 1; fnum++);
paul@181 251
	sprintf(buf, "FEATURE_%c%d", fchar, fnum);
paul@181 252
	return buf;
paul@181 253
}
paul@181 254
paul@181 255
int e2p_jrnl_string2feature(char *string, int *compat_type, unsigned int *mask)
paul@181 256
{
paul@181 257
	struct feature  *f;
paul@181 258
	char		*eptr;
paul@181 259
	int		num;
paul@181 260
paul@181 261
	for (f = jrnl_feature_list; f->string; f++) {
paul@181 262
		if (!strcasecmp(string, f->string)) {
paul@181 263
			*compat_type = f->compat;
paul@181 264
			*mask = f->mask;
paul@181 265
			return 0;
paul@181 266
		}
paul@181 267
	}
paul@181 268
	if (strncasecmp(string, "FEATURE_", 8))
paul@181 269
		return 1;
paul@181 270
paul@181 271
	switch (string[8]) {
paul@181 272
	case 'c':
paul@181 273
	case 'C':
paul@181 274
		*compat_type = E2P_FEATURE_COMPAT;
paul@181 275
		break;
paul@181 276
	case 'i':
paul@181 277
	case 'I':
paul@181 278
		*compat_type = E2P_FEATURE_INCOMPAT;
paul@181 279
		break;
paul@181 280
	case 'r':
paul@181 281
	case 'R':
paul@181 282
		*compat_type = E2P_FEATURE_RO_INCOMPAT;
paul@181 283
		break;
paul@181 284
	default:
paul@181 285
		return 1;
paul@181 286
	}
paul@181 287
	if (string[9] == 0)
paul@181 288
		return 1;
paul@181 289
	num = strtol(string+9, &eptr, 10);
paul@181 290
	if (num > 31 || num < 0)
paul@181 291
		return 1;
paul@181 292
	if (*eptr)
paul@181 293
		return 1;
paul@181 294
	*mask = 1 << num;
paul@181 295
	return 0;
paul@181 296
}
paul@181 297
static char *skip_over_blanks(char *cp)
paul@181 298
{
paul@181 299
	while (*cp && isspace(*cp))
paul@181 300
		cp++;
paul@181 301
	return cp;
paul@181 302
}
paul@181 303
paul@181 304
static char *skip_over_word(char *cp)
paul@181 305
{
paul@181 306
	while (*cp && !isspace(*cp) && *cp != ',')
paul@181 307
		cp++;
paul@181 308
	return cp;
paul@181 309
}
paul@181 310
paul@181 311
/*
paul@181 312
 * Edit a feature set array as requested by the user.  The ok_array,
paul@181 313
 * if set, allows the application to limit what features the user is
paul@181 314
 * allowed to set or clear using this function.  If clear_ok_array is set,
paul@181 315
 * then use it tell whether or not it is OK to clear a filesystem feature.
paul@181 316
 */
paul@181 317
int e2p_edit_feature2(const char *str, __u32 *compat_array, __u32 *ok_array,
paul@181 318
		      __u32 *clear_ok_array, int *type_err,
paul@181 319
		      unsigned int *mask_err)
paul@181 320
{
paul@181 321
	char		*cp, *buf, *next;
paul@181 322
	int		neg;
paul@181 323
	unsigned int	mask;
paul@181 324
	int		compat_type;
paul@181 325
	int		rc = 0;
paul@181 326
paul@181 327
	if (!clear_ok_array)
paul@181 328
		clear_ok_array = ok_array;
paul@181 329
paul@181 330
	if (type_err)
paul@181 331
		*type_err = 0;
paul@181 332
	if (mask_err)
paul@181 333
		*mask_err = 0;
paul@181 334
paul@181 335
	buf = malloc(strlen(str)+1);
paul@181 336
	if (!buf)
paul@181 337
		return 1;
paul@181 338
	strcpy(buf, str);
paul@181 339
	for (cp = buf; cp && *cp; cp = next ? next+1 : 0) {
paul@181 340
		neg = 0;
paul@181 341
		cp = skip_over_blanks(cp);
paul@181 342
		next = skip_over_word(cp);
paul@181 343
paul@181 344
		if (*next == 0)
paul@181 345
			next = 0;
paul@181 346
		else
paul@181 347
			*next = 0;
paul@181 348
paul@181 349
		if ((strcasecmp(cp, "none") == 0) ||
paul@181 350
		    (strcasecmp(cp, "clear") == 0)) {
paul@181 351
			compat_array[0] = 0;
paul@181 352
			compat_array[1] = 0;
paul@181 353
			compat_array[2] = 0;
paul@181 354
			continue;
paul@181 355
		}
paul@181 356
paul@181 357
		switch (*cp) {
paul@181 358
		case '-':
paul@181 359
		case '^':
paul@181 360
			neg++;
paul@181 361
			/* fallthrough */
paul@181 362
		case '+':
paul@181 363
			cp++;
paul@181 364
			break;
paul@181 365
		}
paul@181 366
		if (e2p_string2feature(cp, &compat_type, &mask)) {
paul@181 367
			rc = 1;
paul@181 368
			break;
paul@181 369
		}
paul@181 370
		if (neg) {
paul@181 371
			if (clear_ok_array &&
paul@181 372
			    !(clear_ok_array[compat_type] & mask)) {
paul@181 373
				rc = 1;
paul@181 374
				if (type_err)
paul@181 375
					*type_err = (compat_type |
paul@181 376
						     E2P_FEATURE_NEGATE_FLAG);
paul@181 377
				if (mask_err)
paul@181 378
					*mask_err = mask;
paul@181 379
				break;
paul@181 380
			}
paul@181 381
			compat_array[compat_type] &= ~mask;
paul@181 382
		} else {
paul@181 383
			if (ok_array && !(ok_array[compat_type] & mask)) {
paul@181 384
				rc = 1;
paul@181 385
				if (type_err)
paul@181 386
					*type_err = compat_type;
paul@181 387
				if (mask_err)
paul@181 388
					*mask_err = mask;
paul@181 389
				break;
paul@181 390
			}
paul@181 391
			compat_array[compat_type] |= mask;
paul@181 392
		}
paul@181 393
	}
paul@181 394
	free(buf);
paul@181 395
	return rc;
paul@181 396
}
paul@181 397
paul@181 398
int e2p_edit_feature(const char *str, __u32 *compat_array, __u32 *ok_array)
paul@181 399
{
paul@181 400
	return e2p_edit_feature2(str, compat_array, ok_array, 0, 0, 0);
paul@181 401
}
paul@181 402
paul@181 403
#ifdef TEST_PROGRAM
paul@181 404
int main(int argc, char **argv)
paul@181 405
{
paul@181 406
	int compat, compat2, i;
paul@181 407
	unsigned int mask, mask2;
paul@181 408
	const char *str;
paul@181 409
	struct feature *f;
paul@181 410
paul@181 411
	for (i = 0; i < 2; i++) {
paul@181 412
		if (i == 0) {
paul@181 413
			f = feature_list;
paul@181 414
			printf("Feature list:\n");
paul@181 415
		} else {
paul@181 416
			printf("\nJournal feature list:\n");
paul@181 417
			f = jrnl_feature_list;
paul@181 418
		}
paul@181 419
		for (; f->string; f++) {
paul@181 420
			if (i == 0) {
paul@181 421
				e2p_string2feature((char *)f->string, &compat,
paul@181 422
						   &mask);
paul@181 423
				str = e2p_feature2string(compat, mask);
paul@181 424
			} else {
paul@181 425
				e2p_jrnl_string2feature((char *)f->string,
paul@181 426
							&compat, &mask);
paul@181 427
				str = e2p_jrnl_feature2string(compat, mask);
paul@181 428
			}
paul@181 429
paul@181 430
			printf("\tCompat = %d, Mask = %u, %s\n",
paul@181 431
			       compat, mask, f->string);
paul@181 432
			if (strcmp(f->string, str)) {
paul@181 433
				if (e2p_string2feature((char *) str, &compat2,
paul@181 434
						       &mask2) ||
paul@181 435
				    (compat2 != compat) ||
paul@181 436
				    (mask2 != mask)) {
paul@181 437
					fprintf(stderr, "Failure!\n");
paul@181 438
					exit(1);
paul@181 439
				}
paul@181 440
			}
paul@181 441
		}
paul@181 442
	}
paul@181 443
	exit(0);
paul@181 444
}
paul@181 445
#endif