From 464df1d5e5ab1322e2dd0a7796939fff1aeefa9a Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 17:49:25 +0200 Subject: Adding upstream version 1.47.0. Signed-off-by: Daniel Baumann --- lib/e2p/feature.c | 449 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 449 insertions(+) create mode 100644 lib/e2p/feature.c (limited to 'lib/e2p/feature.c') diff --git a/lib/e2p/feature.c b/lib/e2p/feature.c new file mode 100644 index 0000000..29b7b15 --- /dev/null +++ b/lib/e2p/feature.c @@ -0,0 +1,449 @@ +/* + * feature.c --- convert between features and strings + * + * Copyright (C) 1999 Theodore Ts'o + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#include +#include +#include + +#include "e2p.h" +#include +#include + +struct feature { + int compat; + unsigned int mask; + const char *string; +}; + +static struct feature feature_list[] = { + { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_PREALLOC, + "dir_prealloc" }, + { E2P_FEATURE_COMPAT, EXT3_FEATURE_COMPAT_HAS_JOURNAL, + "has_journal" }, + { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_IMAGIC_INODES, + "imagic_inodes" }, + { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_EXT_ATTR, + "ext_attr" }, + { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_INDEX, + "dir_index" }, + { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_RESIZE_INODE, + "resize_inode" }, + { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_LAZY_BG, + "lazy_bg" }, + { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_EXCLUDE_BITMAP, + "snapshot_bitmap" }, + { E2P_FEATURE_COMPAT, EXT4_FEATURE_COMPAT_SPARSE_SUPER2, + "sparse_super2" }, + { E2P_FEATURE_COMPAT, EXT4_FEATURE_COMPAT_FAST_COMMIT, + "fast_commit" }, + { E2P_FEATURE_COMPAT, EXT4_FEATURE_COMPAT_STABLE_INODES, + "stable_inodes" }, + { E2P_FEATURE_COMPAT, EXT4_FEATURE_COMPAT_ORPHAN_FILE, + "orphan_file" }, + + { E2P_FEATURE_RO_INCOMPAT, EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER, + "sparse_super" }, + { E2P_FEATURE_RO_INCOMPAT, EXT2_FEATURE_RO_COMPAT_LARGE_FILE, + "large_file" }, + { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_HUGE_FILE, + "huge_file" }, + { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_GDT_CSUM, + "uninit_bg" }, + { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_GDT_CSUM, + "uninit_groups" }, + { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_DIR_NLINK, + "dir_nlink" }, + { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE, + "extra_isize" }, + { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_QUOTA, + "quota" }, + { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_BIGALLOC, + "bigalloc"}, + { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_METADATA_CSUM, + "metadata_csum"}, + { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_REPLICA, + "replica" }, + { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_READONLY, + "read-only" }, + { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_PROJECT, + "project"}, + { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_SHARED_BLOCKS, + "shared_blocks"}, + { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_VERITY, + "verity"}, + { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_ORPHAN_PRESENT, + "orphan_present" }, + + { E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_COMPRESSION, + "compression" }, + { E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_FILETYPE, + "filetype" }, + { E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_RECOVER, + "needs_recovery" }, + { E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_JOURNAL_DEV, + "journal_dev" }, + { E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_EXTENTS, + "extent" }, + { E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_EXTENTS, + "extents" }, + { E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_META_BG, + "meta_bg" }, + { E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_64BIT, + "64bit" }, + { E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_MMP, + "mmp" }, + { E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_FLEX_BG, + "flex_bg"}, + { E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_EA_INODE, + "ea_inode"}, + { E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_DIRDATA, + "dirdata"}, + { E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_CSUM_SEED, + "metadata_csum_seed"}, + { E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_LARGEDIR, + "large_dir"}, + { E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_INLINE_DATA, + "inline_data"}, + { E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_ENCRYPT, + "encrypt"}, + { E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_CASEFOLD, + "casefold"}, + { E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_CASEFOLD, + "fname_encoding"}, + { 0, 0, 0 }, +}; + +static struct feature jrnl_feature_list[] = { + { E2P_FEATURE_COMPAT, JBD2_FEATURE_COMPAT_CHECKSUM, + "journal_checksum" }, + + { E2P_FEATURE_INCOMPAT, JBD2_FEATURE_INCOMPAT_REVOKE, + "journal_incompat_revoke" }, + { E2P_FEATURE_INCOMPAT, JBD2_FEATURE_INCOMPAT_64BIT, + "journal_64bit" }, + { E2P_FEATURE_INCOMPAT, JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT, + "journal_async_commit" }, + { E2P_FEATURE_INCOMPAT, JBD2_FEATURE_INCOMPAT_CSUM_V2, + "journal_checksum_v2" }, + { E2P_FEATURE_INCOMPAT, JBD2_FEATURE_INCOMPAT_CSUM_V3, + "journal_checksum_v3" }, + { 0, 0, 0 }, +}; + +void e2p_feature_to_string(int compat, unsigned int mask, char *buf, + size_t buf_len) +{ + struct feature *f; + char fchar; + int fnum; + + for (f = feature_list; f->string; f++) { + if ((compat == f->compat) && + (mask == f->mask)) { + strncpy(buf, f->string, buf_len); + buf[buf_len - 1] = 0; + return; + } + } + switch (compat) { + case E2P_FEATURE_COMPAT: + fchar = 'C'; + break; + case E2P_FEATURE_INCOMPAT: + fchar = 'I'; + break; + case E2P_FEATURE_RO_INCOMPAT: + fchar = 'R'; + break; + default: + fchar = '?'; + break; + } + for (fnum = 0; mask >>= 1; fnum++); + sprintf(buf, "FEATURE_%c%d", fchar, fnum); +} + +const char *e2p_feature2string(int compat, unsigned int mask) +{ + static char buf[20]; + + e2p_feature_to_string(compat, mask, buf, sizeof(buf) / sizeof(buf[0])); + return buf; +} + +int e2p_string2feature(char *string, int *compat_type, unsigned int *mask) +{ + struct feature *f; + char *eptr; + int num; + + for (f = feature_list; f->string; f++) { + if (!strcasecmp(string, f->string)) { + *compat_type = f->compat; + *mask = f->mask; + return 0; + } + } + if (strncasecmp(string, "FEATURE_", 8)) + return 1; + + switch (string[8]) { + case 'c': + case 'C': + *compat_type = E2P_FEATURE_COMPAT; + break; + case 'i': + case 'I': + *compat_type = E2P_FEATURE_INCOMPAT; + break; + case 'r': + case 'R': + *compat_type = E2P_FEATURE_RO_INCOMPAT; + break; + default: + return 1; + } + if (string[9] == 0) + return 1; + num = strtol(string+9, &eptr, 10); + if (num > 31 || num < 0) + return 1; + if (*eptr) + return 1; + *mask = 1 << num; + return 0; +} + +const char *e2p_jrnl_feature2string(int compat, unsigned int mask) +{ + struct feature *f; + static char buf[20]; + char fchar; + int fnum; + + for (f = jrnl_feature_list; f->string; f++) { + if ((compat == f->compat) && + (mask == f->mask)) + return f->string; + } + switch (compat) { + case E2P_FEATURE_COMPAT: + fchar = 'C'; + break; + case E2P_FEATURE_INCOMPAT: + fchar = 'I'; + break; + case E2P_FEATURE_RO_INCOMPAT: + fchar = 'R'; + break; + default: + fchar = '?'; + break; + } + for (fnum = 0; mask >>= 1; fnum++); + sprintf(buf, "FEATURE_%c%d", fchar, fnum); + return buf; +} + +int e2p_jrnl_string2feature(char *string, int *compat_type, unsigned int *mask) +{ + struct feature *f; + char *eptr; + int num; + + for (f = jrnl_feature_list; f->string; f++) { + if (!strcasecmp(string, f->string)) { + *compat_type = f->compat; + *mask = f->mask; + return 0; + } + } + if (strncasecmp(string, "FEATURE_", 8)) + return 1; + + switch (string[8]) { + case 'c': + case 'C': + *compat_type = E2P_FEATURE_COMPAT; + break; + case 'i': + case 'I': + *compat_type = E2P_FEATURE_INCOMPAT; + break; + case 'r': + case 'R': + *compat_type = E2P_FEATURE_RO_INCOMPAT; + break; + default: + return 1; + } + if (string[9] == 0) + return 1; + num = strtol(string+9, &eptr, 10); + if (num > 31 || num < 0) + return 1; + if (*eptr) + return 1; + *mask = 1 << num; + return 0; +} +static char *skip_over_blanks(char *cp) +{ + while (*cp && isspace(*cp)) + cp++; + return cp; +} + +static char *skip_over_word(char *cp) +{ + while (*cp && !isspace(*cp) && *cp != ',') + cp++; + return cp; +} + +/* + * Edit a feature set array as requested by the user. The ok_array, + * if set, allows the application to limit what features the user is + * allowed to set or clear using this function. If clear_ok_array is set, + * then use it tell whether or not it is OK to clear a filesystem feature. + */ +int e2p_edit_feature2(const char *str, __u32 *compat_array, __u32 *ok_array, + __u32 *clear_ok_array, int *type_err, + unsigned int *mask_err) +{ + char *cp, *buf, *next; + int neg; + unsigned int mask; + int compat_type; + int rc = 0; + + if (!clear_ok_array) + clear_ok_array = ok_array; + + if (type_err) + *type_err = 0; + if (mask_err) + *mask_err = 0; + + buf = malloc(strlen(str)+1); + if (!buf) + return 1; + strcpy(buf, str); + for (cp = buf; cp && *cp; cp = next ? next+1 : 0) { + neg = 0; + cp = skip_over_blanks(cp); + next = skip_over_word(cp); + + if (*next == 0) + next = 0; + else + *next = 0; + + if ((strcasecmp(cp, "none") == 0) || + (strcasecmp(cp, "clear") == 0)) { + compat_array[0] = 0; + compat_array[1] = 0; + compat_array[2] = 0; + continue; + } + + switch (*cp) { + case '-': + case '^': + neg++; + /* fallthrough */ + case '+': + cp++; + break; + } + if (e2p_string2feature(cp, &compat_type, &mask)) { + rc = 1; + break; + } + if (neg) { + if (clear_ok_array && + !(clear_ok_array[compat_type] & mask)) { + rc = 1; + if (type_err) + *type_err = (compat_type | + E2P_FEATURE_NEGATE_FLAG); + if (mask_err) + *mask_err = mask; + break; + } + compat_array[compat_type] &= ~mask; + } else { + if (ok_array && !(ok_array[compat_type] & mask)) { + rc = 1; + if (type_err) + *type_err = compat_type; + if (mask_err) + *mask_err = mask; + break; + } + compat_array[compat_type] |= mask; + } + } + free(buf); + return rc; +} + +int e2p_edit_feature(const char *str, __u32 *compat_array, __u32 *ok_array) +{ + return e2p_edit_feature2(str, compat_array, ok_array, 0, 0, 0); +} + +#ifdef TEST_PROGRAM +int main(int argc, char **argv) +{ + int compat, compat2, i; + unsigned int mask, mask2; + const char *str; + struct feature *f; + + for (i = 0; i < 2; i++) { + if (i == 0) { + f = feature_list; + printf("Feature list:\n"); + } else { + printf("\nJournal feature list:\n"); + f = jrnl_feature_list; + } + for (; f->string; f++) { + if (i == 0) { + e2p_string2feature((char *)f->string, &compat, + &mask); + str = e2p_feature2string(compat, mask); + } else { + e2p_jrnl_string2feature((char *)f->string, + &compat, &mask); + str = e2p_jrnl_feature2string(compat, mask); + } + + printf("\tCompat = %d, Mask = %u, %s\n", + compat, mask, f->string); + if (strcmp(f->string, str)) { + if (e2p_string2feature((char *) str, &compat2, + &mask2) || + (compat2 != compat) || + (mask2 != mask)) { + fprintf(stderr, "Failure!\n"); + exit(1); + } + } + } + } + exit(0); +} +#endif -- cgit v1.2.3