From 3d2e8794632bf83796c9ddf4d607e5d3ed875c10 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Wed, 17 Jul 2024 03:35:09 +0200 Subject: [PATCH] btrfs-progs: factor string escaping helpers from receive dump The string escaping functionality is more generic and can be used in other commands (e.g. in dump-tree). Move it to the string utils. Signed-off-by: David Sterba --- cmds/receive-dump.c | 63 +++++++------------------------------------ common/string-utils.c | 41 ++++++++++++++++++++++++++++ common/string-utils.h | 6 +++++ 3 files changed, 56 insertions(+), 54 deletions(-) diff --git a/cmds/receive-dump.c b/cmds/receive-dump.c index 503da329..d62eaad9 100644 --- a/cmds/receive-dump.c +++ b/cmds/receive-dump.c @@ -19,7 +19,6 @@ #include "kerncompat.h" #include #include -#include #include #include #include @@ -29,6 +28,7 @@ #include "common/messages.h" #include "common/send-stream.h" #include "common/path-utils.h" +#include "common/string-utils.h" #include "cmds/receive-dump.h" #define PATH_CAT_OR_RET(function_name, outpath, path1, path2, ret) \ @@ -40,51 +40,6 @@ } \ }) -/* - * Print path and escape characters (in a C way) that could break the line. - * Returns the length of the escaped characters. Unprintable characters are - * escaped as octals. - */ -static int print_path_escaped_len(const char *path, size_t path_len) -{ - size_t i; - int len = 0; - - for (i = 0; i < path_len; i++) { - char c = path[i]; - - len++; - switch (c) { - case '\a': putchar('\\'); putchar('a'); len++; break; - case '\b': putchar('\\'); putchar('b'); len++; break; - case '\e': putchar('\\'); putchar('e'); len++; break; - case '\f': putchar('\\'); putchar('f'); len++; break; - case '\n': putchar('\\'); putchar('n'); len++; break; - case '\r': putchar('\\'); putchar('r'); len++; break; - case '\t': putchar('\\'); putchar('t'); len++; break; - case '\v': putchar('\\'); putchar('v'); len++; break; - case ' ': putchar('\\'); putchar(' '); len++; break; - case '\\': putchar('\\'); putchar('\\'); len++; break; - default: - if (!isprint(c)) { - printf("\\%c%c%c", - '0' + ((c & 0300) >> 6), - '0' + ((c & 070) >> 3), - '0' + (c & 07)); - len += 3; - } else { - putchar(c); - } - } - } - return len; -} - -static int print_path_escaped(const char *path) -{ - return print_path_escaped_len(path, strlen(path)); -} - enum print_mode { PRINT_DUMP_NORMAL, PRINT_DUMP_SUBVOLUME, @@ -115,7 +70,7 @@ static int __print_dump(enum print_mode mode, void *user, const char *path, /* Unified header */ printf("%-16s", title); - ret = print_path_escaped(out_path); + ret = string_print_escape_special(out_path); if (!fmt) { putchar('\n'); return 0; @@ -203,7 +158,7 @@ static int print_mksock(const char *path, void *user) static int print_symlink(const char *path, const char *lnk, void *user) { PRINT_DUMP_NO_NEWLINE(user, path, "symlink", "dest="); - print_path_escaped(lnk); + string_print_escape_special(lnk); putchar('\n'); return 0; } @@ -216,7 +171,7 @@ static int print_rename(const char *from, const char *to, void *user) PATH_CAT_OR_RET("rename", full_to, r->full_subvol_path, to, ret); PRINT_DUMP_NO_NEWLINE(user, from, "rename", "dest="); - print_path_escaped(full_to); + string_print_escape_special(full_to); putchar('\n'); return 0; } @@ -224,7 +179,7 @@ static int print_rename(const char *from, const char *to, void *user) static int print_link(const char *path, const char *lnk, void *user) { PRINT_DUMP_NO_NEWLINE(user, path, "link", "dest="); - print_path_escaped(lnk); + string_print_escape_special(lnk); putchar('\n'); return 0; } @@ -257,7 +212,7 @@ static int print_clone(const char *path, u64 offset, u64 len, PATH_CAT_OR_RET("clone", full_path, r->full_subvol_path, clone_path, ret); PRINT_DUMP_NO_NEWLINE(user, path, "clone", "offset=%llu len=%llu from=", offset, len); - print_path_escaped(full_path); + string_print_escape_special(full_path); putchar(' '); printf("clone_offset=%llu\n", clone_offset); return 0; @@ -271,9 +226,9 @@ static int print_set_xattr(const char *path, const char *name, const void *data, int len, void *user) { PRINT_DUMP_NO_NEWLINE(user, path, "set_xattr", "name="); - print_path_escaped(name); + string_print_escape_special(name); putchar(' '); - print_path_escaped_len((char *)data, len); + string_print_escape_special_len((const char *)data, len); putchar(' '); printf("len=%d\n", len); return 0; @@ -283,7 +238,7 @@ static int print_remove_xattr(const char *path, const char *name, void *user) { PRINT_DUMP_NO_NEWLINE(user, path, "remove_xattr", "name="); - print_path_escaped(name); + string_print_escape_special(name); putchar('\n'); return 0; } diff --git a/common/string-utils.c b/common/string-utils.c index d03f51c1..e55c10c5 100644 --- a/common/string-utils.c +++ b/common/string-utils.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "common/string-utils.h" #include "common/messages.h" #include "common/parse-utils.h" @@ -64,6 +65,46 @@ char *strncpy_null(char *dest, const char *src, size_t n) return dest; } +/* + * Print a string and escape characters (in a C way) that could break the line. + * Returns the length of the escaped characters. Unprintable characters are + * escaped as octals. Usable for paths or text-like data like xattrs. + */ +int string_print_escape_special_len(const char *str, size_t str_len) +{ + size_t i; + int len = 0; + + for (i = 0; i < str_len; i++) { + char c = str[i]; + + len++; + switch (c) { + case '\a': putchar('\\'); putchar('a'); len++; break; + case '\b': putchar('\\'); putchar('b'); len++; break; + case '\e': putchar('\\'); putchar('e'); len++; break; + case '\f': putchar('\\'); putchar('f'); len++; break; + case '\n': putchar('\\'); putchar('n'); len++; break; + case '\r': putchar('\\'); putchar('r'); len++; break; + case '\t': putchar('\\'); putchar('t'); len++; break; + case '\v': putchar('\\'); putchar('v'); len++; break; + case ' ': putchar('\\'); putchar(' '); len++; break; + case '\\': putchar('\\'); putchar('\\'); len++; break; + default: + if (!isprint(c)) { + printf("\\%c%c%c", + '0' + ((c & 0300) >> 6), + '0' + ((c & 070) >> 3), + '0' + (c & 07)); + len += 3; + } else { + putchar(c); + } + } + } + return len; +} + /* * This function should be only used when parsing command arg, it won't return * error to its caller and rather exit directly just like usage(). diff --git a/common/string-utils.h b/common/string-utils.h index 7b4225e4..99cf0c50 100644 --- a/common/string-utils.h +++ b/common/string-utils.h @@ -24,6 +24,12 @@ int string_has_prefix(const char *str, const char *prefix); char *strncpy_null(char *dest, const char *src, size_t n); +int string_print_escape_special_len(const char *str, size_t len); +static inline int string_print_escape_special(const char *str) +{ + return string_print_escape_special_len(str, strlen(str)); +} + /* * Helpers prefixed by arg_* can exit if the argument is invalid and are supposed * to be used when parsing command line options where the immediate exit is valid