Coverage Report

Created: 2025-07-18 06:51

/src/util-linux/lib/mangle.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Functions for \oct encoding used in mtab/fstab/swaps/etc.
3
 *
4
 * No copyright is claimed.  This code is in the public domain; do with
5
 * it what you wish.
6
 *
7
 * Written by Karel Zak <kzak@redhat.com> [2010]
8
 */
9
#include <stdio.h>
10
#include <stdlib.h>
11
#include <string.h>
12
#include <ctype.h>
13
14
#include "mangle.h"
15
#include "c.h"
16
17
5.12M
#define isoctal(a)    (((a) & ~7) == '0')
18
19
0
#define from_hex(c)   (isdigit(c) ? c - '0' : tolower(c) - 'a' + 10)
20
21
0
#define is_unwanted_char(x) (strchr(" \t\n\\", (unsigned int) x) != NULL)
22
23
24
char *mangle(const char *s)
25
0
{
26
0
  char *ss, *sp;
27
28
0
  if (!s)
29
0
    return NULL;
30
31
0
  ss = sp = malloc(4 * strlen(s) + 1);
32
0
  if (!sp)
33
0
    return NULL;
34
0
  while(1) {
35
0
    if (!*s) {
36
0
      *sp = '\0';
37
0
      break;
38
0
    }
39
0
    if (is_unwanted_char(*s)) {
40
0
      *sp++ = '\\';
41
0
      *sp++ = '0' + ((*s & 0300) >> 6);
42
0
      *sp++ = '0' + ((*s & 070) >> 3);
43
0
      *sp++ = '0' + (*s & 07);
44
0
    } else
45
0
      *sp++ = *s;
46
0
    s++;
47
0
  }
48
0
  return ss;
49
0
}
50
51
52
void unmangle_to_buffer(const char *s, char *buf, size_t len)
53
212k
{
54
212k
  size_t sz = 0;
55
56
212k
  if (!s)
57
0
    return;
58
59
2.62M
  while(*s && sz < len - 1) {
60
2.41M
    if (*s == '\\' && sz + 3 < len - 1 && isoctal(s[1]) &&
61
2.41M
        isoctal(s[2]) && isoctal(s[3])) {
62
63
478
      *buf++ = 64*(s[1] & 7) + 8*(s[2] & 7) + (s[3] & 7);
64
478
      s += 4;
65
478
      sz += 4;
66
2.41M
    } else {
67
2.41M
      *buf++ = *s++;
68
2.41M
      sz++;
69
2.41M
    }
70
2.41M
  }
71
212k
  *buf = '\0';
72
212k
}
73
74
size_t unhexmangle_to_buffer(const char *s, char *buf, size_t len)
75
0
{
76
0
  size_t sz = 0;
77
0
  const char *buf0 = buf;
78
79
0
  if (!s)
80
0
    return 0;
81
82
0
  while(*s && sz < len - 1) {
83
0
    if (*s == '\\' && sz + 3 < len - 1 && s[1] == 'x' &&
84
0
        isxdigit(s[2]) && isxdigit(s[3])) {
85
86
0
      *buf++ = from_hex(s[2]) << 4 | from_hex(s[3]);
87
0
      s += 4;
88
0
      sz += 4;
89
0
    } else {
90
0
      *buf++ = *s++;
91
0
      sz++;
92
0
    }
93
0
  }
94
0
  *buf = '\0';
95
0
  return buf - buf0 + 1;
96
0
}
97
98
size_t unescape_to_buffer(const char *s, const char *wanted, char *buf, size_t len)
99
0
{
100
0
  size_t sz = 0;
101
0
  const char *buf0 = buf;
102
103
0
  while (*s && sz < len - 1) {
104
0
    if (*s == '\\' && sz + 1 < len - 1 && strchr(wanted, s[1])) {
105
0
      *buf++ = s[1];
106
0
      s += 2;
107
0
      sz += 2;
108
0
    } else {
109
0
      *buf++ = *s++;;
110
0
      sz++;
111
0
    }
112
0
  }
113
0
  *buf = '\0';
114
0
  return buf - buf0 + 1;
115
0
}
116
117
static inline const char *skip_nonspaces(const char *s)
118
256k
{
119
2.67M
  while (s && *s && !(*s == ' ' || *s == '\t'))
120
2.41M
    s++;
121
256k
  return s;
122
256k
}
123
124
/*
125
 * Returns mallocated buffer or NULL in case of error.
126
 */
127
char *unmangle(const char *s, const char **end)
128
256k
{
129
256k
  char *buf;
130
256k
  const char *e;
131
256k
  size_t sz;
132
133
256k
  if (!s)
134
0
    return NULL;
135
136
256k
  e = skip_nonspaces(s);
137
256k
  sz = e - s + 1;
138
139
256k
  if (end)
140
256k
    *end = e;
141
256k
  if (e == s)
142
44.3k
    return NULL;  /* empty string */
143
144
212k
  buf = malloc(sz);
145
212k
  if (!buf)
146
0
    return NULL;
147
148
212k
  unmangle_to_buffer(s, buf, sz);
149
212k
  return buf;
150
212k
}
151
152
#ifdef TEST_PROGRAM_MANGLE
153
#include <errno.h>
154
int main(int argc, char *argv[])
155
{
156
  char *p = NULL;
157
  if (argc < 3) {
158
    fprintf(stderr, "usage: %s --mangle|unmangle|unescape <string>\n",
159
            program_invocation_short_name);
160
    return EXIT_FAILURE;
161
  }
162
163
  if (!strcmp(argv[1], "--mangle")) {
164
    p = mangle(argv[2]);
165
    printf("mangled: '%s'\n", p);
166
    free(p);
167
  }
168
169
  else if (!strcmp(argv[1], "--unmangle")) {
170
    char *x = unmangle(argv[2], NULL);
171
172
    if (x) {
173
      printf("unmangled: '%s'\n", x);
174
      free(x);
175
    }
176
177
    x = strdup(argv[2]);
178
    if (x) {
179
      unmangle_to_buffer(x, x, strlen(x) + 1);
180
181
      printf("self-unmangled: '%s'\n", x);
182
      free(x);
183
    }
184
  }
185
186
  else if (!strcmp(argv[1], "--unescape")) {
187
    char *x = strdup(argv[2]);
188
    if (x) {
189
      unescape_to_buffer(x, ",\"", x, strlen(x) + 1);
190
191
      printf("self-unescaped: '%s'\n", x);
192
      free(x);
193
    }
194
  }
195
196
  return EXIT_SUCCESS;
197
}
198
#endif /* TEST_PROGRAM_MANGLE */