Whamcloud - gitweb
AOSP: ANDROID: tune2fs: Allow setting the casefold feature
authorDaniel Rosenberg <drosen@google.com>
Thu, 11 Jun 2020 04:18:44 +0000 (21:18 -0700)
committerTheodore Ts'o <tytso@mit.edu>
Thu, 28 Jan 2021 04:35:09 +0000 (23:35 -0500)
This allows tune2fs to enable casefolding on an existing filesystem.
At the moment, casefolding is incompatible with encryption.

Signed-off-by: Daniel Rosenberg <drosen@google.com>
Google-Bug-Id: 138322712
Test: Create fs without casefold and enable it via tune2fs
Change-Id: Ic9ed63180ef28c36e083cee85ade432e4bfcc654
From AOSP commit: eb5b168decac07058e90ead191350be80c75aff4

misc/tune2fs.8.in
misc/tune2fs.c

index 3cf1f5e..7b0776a 100644 (file)
@@ -218,6 +218,30 @@ directories.  Valid algorithms accepted are:
 and
 .IR tea .
 .TP
+.BI encoding= encoding-name
+Enable the
+.I casefold
+feature in the super block and set
+.I encoding-name
+as the encoding to be used.  If
+.I encoding-name
+is not specified, utf8 is used. The encoding cannot be altered if casefold
+was previously enabled.
+.TP
+.BI encoding_flags= encoding-flags
+Define parameters for file name character encoding operations.  If a
+flag is not changed using this parameter, its default value is used.
+.I encoding-flags
+should be a comma-separated lists of flags to be enabled.  The flags cannot be
+altered if casefold was previously enabled.
+
+The only flag that can be set right now is
+.I strict
+which means that invalid strings should be rejected by the file system.
+In the default configuration, the
+.I strict
+flag is disabled.
+.TP
 .BI mount_opts= mount_option_string
 Set a set of default mount options which will be used when the file
 system is mounted.  Unlike the bitmask-based default mount options which
@@ -542,6 +566,11 @@ The following filesystem features can be set or cleared using
 .B 64bit
 Enable the file system to be larger than 2^32 blocks.
 .TP
+.B casefold
+Enable support for file system level casefolding.
+.B Tune2fs
+currently only supports setting this filesystem feature.
+.TP
 .B dir_index
 Use hashed b-trees to speed up lookups for large directories.
 .TP
index 48b8ce8..15fa36f 100644 (file)
@@ -101,6 +101,7 @@ static int rewrite_checksums;
 static int feature_64bit;
 static int fsck_requested;
 static char *undo_file;
+int enabling_casefold;
 
 int journal_size, journal_flags;
 char *journal_device;
@@ -159,7 +160,8 @@ static __u32 ok_features[3] = {
                EXT4_FEATURE_INCOMPAT_64BIT |
                EXT4_FEATURE_INCOMPAT_ENCRYPT |
                EXT4_FEATURE_INCOMPAT_CSUM_SEED |
-               EXT4_FEATURE_INCOMPAT_LARGEDIR,
+               EXT4_FEATURE_INCOMPAT_LARGEDIR |
+               EXT4_FEATURE_INCOMPAT_CASEFOLD,
        /* R/O compat */
        EXT2_FEATURE_RO_COMPAT_LARGE_FILE |
                EXT4_FEATURE_RO_COMPAT_HUGE_FILE|
@@ -1429,6 +1431,23 @@ mmp_error:
                        EXT4_ENCRYPTION_MODE_AES_256_CTS;
        }
 
+       if (FEATURE_ON(E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_CASEFOLD)) {
+               if (ext2fs_has_feature_encrypt(sb)) {
+                       fputs(_("Cannot enable casefold feature on filesystems "
+                               "with the encrypt feature enabled.\n"),
+                             stderr);
+                       return 1;
+               }
+               if (mount_flags & EXT2_MF_MOUNTED) {
+                       fputs(_("The casefold feature may only be enabled when "
+                               "the filesystem is unmounted.\n"), stderr);
+                       return 1;
+               }
+               fs->super->s_encoding = EXT4_ENC_UTF8_12_1;
+               fs->super->s_encoding_flags = e2p_get_encoding_flags(EXT4_ENC_UTF8_12_1);
+               enabling_casefold = 1;
+       }
+
        if (FEATURE_ON(E2P_FEATURE_INCOMPAT,
                EXT4_FEATURE_INCOMPAT_CSUM_SEED)) {
                if (!ext2fs_has_feature_metadata_csum(sb)) {
@@ -2035,9 +2054,12 @@ void do_findfs(int argc, char **argv)
 
 static int parse_extended_opts(ext2_filsys fs, const char *opts)
 {
+       struct ext2_super_block *sb = fs->super;
        char    *buf, *token, *next, *p, *arg;
        int     len, hash_alg;
        int     r_usage = 0;
+       int encoding = 0;
+       char    *encoding_flags = NULL;
 
        len = strlen(opts);
        buf = malloc(len+1);
@@ -2090,18 +2112,18 @@ static int parse_extended_opts(ext2_filsys fs, const char *opts)
                                  "Setting multiple mount protection update "
                                  "interval to %lu seconds\n", intv),
                               intv);
-                       fs->super->s_mmp_update_interval = intv;
+                       sb->s_mmp_update_interval = intv;
                        ext2fs_mark_super_dirty(fs);
                } else if (!strcmp(token, "force_fsck")) {
-                       fs->super->s_state |= EXT2_ERROR_FS;
+                       sb->s_state |= EXT2_ERROR_FS;
                        printf(_("Setting filesystem error flag to force fsck.\n"));
                        ext2fs_mark_super_dirty(fs);
                } else if (!strcmp(token, "test_fs")) {
-                       fs->super->s_flags |= EXT2_FLAGS_TEST_FILESYS;
+                       sb->s_flags |= EXT2_FLAGS_TEST_FILESYS;
                        printf("Setting test filesystem flag\n");
                        ext2fs_mark_super_dirty(fs);
                } else if (!strcmp(token, "^test_fs")) {
-                       fs->super->s_flags &= ~EXT2_FLAGS_TEST_FILESYS;
+                       sb->s_flags &= ~EXT2_FLAGS_TEST_FILESYS;
                        printf("Clearing test filesystem flag\n");
                        ext2fs_mark_super_dirty(fs);
                } else if (strcmp(token, "stride") == 0) {
@@ -2147,7 +2169,7 @@ static int parse_extended_opts(ext2_filsys fs, const char *opts)
                                r_usage++;
                                continue;
                        }
-                       fs->super->s_def_hash_version = hash_alg;
+                       sb->s_def_hash_version = hash_alg;
                        printf(_("Setting default hash algorithm "
                                 "to %s (%d)\n"),
                               arg, hash_alg);
@@ -2163,9 +2185,68 @@ static int parse_extended_opts(ext2_filsys fs, const char *opts)
                                continue;
                        }
                        ext_mount_opts = strdup(arg);
+               } else if (!strcmp(token, "encoding")) {
+                       if (!arg) {
+                               r_usage++;
+                               continue;
+                       }
+                       if (ext2fs_has_feature_encrypt(sb)) {
+                               fprintf(stderr, _("error: Cannot enable casefolding if encryption is set\n"));
+                               r_usage++;
+                               continue;
+                       }
+                       if (mount_flags & EXT2_MF_MOUNTED) {
+                               fputs(_("The casefold feature may only be enabled when "
+                                       "the filesystem is unmounted.\n"), stderr);
+                               r_usage++;
+                               continue;
+                       }
+                       if (ext2fs_has_feature_casefold(sb) && !enabling_casefold) {
+                               fprintf(stderr, _("Cannot alter existing encoding\n"));
+                               r_usage++;
+                               continue;
+                       }
+                       encoding = e2p_str2encoding(arg);
+                       if (encoding < 0) {
+                               fprintf(stderr, _("Invalid encoding: %s\n"), arg);
+                               r_usage++;
+                               continue;
+                       }
+                       enabling_casefold = 1;
+                       sb->s_encoding = encoding;
+                       printf(_("Setting encoding to '%s'\n"), arg);
+                       sb->s_encoding_flags =
+                               e2p_get_encoding_flags(sb->s_encoding);
+               } else if (!strcmp(token, "encoding_flags")) {
+                       if (!arg) {
+                               r_usage++;
+                               continue;
+                       }
+                       encoding_flags = arg;
                } else
                        r_usage++;
        }
+
+       if (encoding > 0 && !r_usage) {
+               sb->s_encoding_flags =
+                       e2p_get_encoding_flags(sb->s_encoding);
+
+               if (encoding_flags &&
+                   e2p_str2encoding_flags(sb->s_encoding, encoding_flags,
+                                          &sb->s_encoding_flags)) {
+                       fprintf(stderr, _("error: Invalid encoding flag: %s\n"),
+                                       encoding_flags);
+                       r_usage++;
+               } else if (encoding_flags)
+                       printf(_("Setting encoding_flags to '%s'\n"),
+                                encoding_flags);
+               ext2fs_set_feature_casefold(sb);
+               ext2fs_mark_super_dirty(fs);
+       } else if (encoding_flags && !r_usage) {
+               fprintf(stderr, _("error: An encoding must be explicitly "
+                                 "specified when passing encoding-flags\n"));
+               r_usage++;
+       }
        if (r_usage) {
                fprintf(stderr, "%s", _("\nBad options specified.\n\n"
                        "Extended options are separated by commas, "
@@ -2180,7 +2261,9 @@ static int parse_extended_opts(ext2_filsys fs, const char *opts)
                        "\tstripe_width=<RAID stride*data disks in blocks>\n"
                        "\tforce_fsck\n"
                        "\ttest_fs\n"
-                       "\t^test_fs\n"));
+                       "\t^test_fs\n"
+                       "\tencoding=<encoding>\n"
+                       "\tencoding_flags=<flags>\n"));
                free(buf);
                return 1;
        }