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 <dsterba@suse.com>
This commit is contained in:
David Sterba 2024-07-17 03:35:09 +02:00
parent 1de113eb0c
commit 3d2e879463
3 changed files with 56 additions and 54 deletions

View File

@ -19,7 +19,6 @@
#include "kerncompat.h" #include "kerncompat.h"
#include <limits.h> #include <limits.h>
#include <time.h> #include <time.h>
#include <ctype.h>
#include <errno.h> #include <errno.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
@ -29,6 +28,7 @@
#include "common/messages.h" #include "common/messages.h"
#include "common/send-stream.h" #include "common/send-stream.h"
#include "common/path-utils.h" #include "common/path-utils.h"
#include "common/string-utils.h"
#include "cmds/receive-dump.h" #include "cmds/receive-dump.h"
#define PATH_CAT_OR_RET(function_name, outpath, path1, path2, ret) \ #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 { enum print_mode {
PRINT_DUMP_NORMAL, PRINT_DUMP_NORMAL,
PRINT_DUMP_SUBVOLUME, PRINT_DUMP_SUBVOLUME,
@ -115,7 +70,7 @@ static int __print_dump(enum print_mode mode, void *user, const char *path,
/* Unified header */ /* Unified header */
printf("%-16s", title); printf("%-16s", title);
ret = print_path_escaped(out_path); ret = string_print_escape_special(out_path);
if (!fmt) { if (!fmt) {
putchar('\n'); putchar('\n');
return 0; 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) static int print_symlink(const char *path, const char *lnk, void *user)
{ {
PRINT_DUMP_NO_NEWLINE(user, path, "symlink", "dest="); PRINT_DUMP_NO_NEWLINE(user, path, "symlink", "dest=");
print_path_escaped(lnk); string_print_escape_special(lnk);
putchar('\n'); putchar('\n');
return 0; 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); PATH_CAT_OR_RET("rename", full_to, r->full_subvol_path, to, ret);
PRINT_DUMP_NO_NEWLINE(user, from, "rename", "dest="); PRINT_DUMP_NO_NEWLINE(user, from, "rename", "dest=");
print_path_escaped(full_to); string_print_escape_special(full_to);
putchar('\n'); putchar('\n');
return 0; 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) static int print_link(const char *path, const char *lnk, void *user)
{ {
PRINT_DUMP_NO_NEWLINE(user, path, "link", "dest="); PRINT_DUMP_NO_NEWLINE(user, path, "link", "dest=");
print_path_escaped(lnk); string_print_escape_special(lnk);
putchar('\n'); putchar('\n');
return 0; 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); 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_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(' '); putchar(' ');
printf("clone_offset=%llu\n", clone_offset); printf("clone_offset=%llu\n", clone_offset);
return 0; return 0;
@ -271,9 +226,9 @@ static int print_set_xattr(const char *path, const char *name,
const void *data, int len, void *user) const void *data, int len, void *user)
{ {
PRINT_DUMP_NO_NEWLINE(user, path, "set_xattr", "name="); PRINT_DUMP_NO_NEWLINE(user, path, "set_xattr", "name=");
print_path_escaped(name); string_print_escape_special(name);
putchar(' '); putchar(' ');
print_path_escaped_len((char *)data, len); string_print_escape_special_len((const char *)data, len);
putchar(' '); putchar(' ');
printf("len=%d\n", len); printf("len=%d\n", len);
return 0; 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_DUMP_NO_NEWLINE(user, path, "remove_xattr", "name=");
print_path_escaped(name); string_print_escape_special(name);
putchar('\n'); putchar('\n');
return 0; return 0;
} }

View File

@ -18,6 +18,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <limits.h> #include <limits.h>
#include <ctype.h>
#include "common/string-utils.h" #include "common/string-utils.h"
#include "common/messages.h" #include "common/messages.h"
#include "common/parse-utils.h" #include "common/parse-utils.h"
@ -64,6 +65,46 @@ char *strncpy_null(char *dest, const char *src, size_t n)
return dest; 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 * 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(). * error to its caller and rather exit directly just like usage().

View File

@ -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); 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 * 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 * to be used when parsing command line options where the immediate exit is valid