Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/fs/cachefiles/key.c
15109 views
1
/* Key to pathname encoder
2
*
3
* Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4
* Written by David Howells ([email protected])
5
*
6
* This program is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU General Public Licence
8
* as published by the Free Software Foundation; either version
9
* 2 of the Licence, or (at your option) any later version.
10
*/
11
12
#include <linux/slab.h>
13
#include "internal.h"
14
15
static const char cachefiles_charmap[64] =
16
"0123456789" /* 0 - 9 */
17
"abcdefghijklmnopqrstuvwxyz" /* 10 - 35 */
18
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" /* 36 - 61 */
19
"_-" /* 62 - 63 */
20
;
21
22
static const char cachefiles_filecharmap[256] = {
23
/* we skip space and tab and control chars */
24
[33 ... 46] = 1, /* '!' -> '.' */
25
/* we skip '/' as it's significant to pathwalk */
26
[48 ... 127] = 1, /* '0' -> '~' */
27
};
28
29
/*
30
* turn the raw key into something cooked
31
* - the raw key should include the length in the two bytes at the front
32
* - the key may be up to 514 bytes in length (including the length word)
33
* - "base64" encode the strange keys, mapping 3 bytes of raw to four of
34
* cooked
35
* - need to cut the cooked key into 252 char lengths (189 raw bytes)
36
*/
37
char *cachefiles_cook_key(const u8 *raw, int keylen, uint8_t type)
38
{
39
unsigned char csum, ch;
40
unsigned int acc;
41
char *key;
42
int loop, len, max, seg, mark, print;
43
44
_enter(",%d", keylen);
45
46
BUG_ON(keylen < 2 || keylen > 514);
47
48
csum = raw[0] + raw[1];
49
print = 1;
50
for (loop = 2; loop < keylen; loop++) {
51
ch = raw[loop];
52
csum += ch;
53
print &= cachefiles_filecharmap[ch];
54
}
55
56
if (print) {
57
/* if the path is usable ASCII, then we render it directly */
58
max = keylen - 2;
59
max += 2; /* two base64'd length chars on the front */
60
max += 5; /* @checksum/M */
61
max += 3 * 2; /* maximum number of segment dividers (".../M")
62
* is ((514 + 251) / 252) = 3
63
*/
64
max += 1; /* NUL on end */
65
} else {
66
/* calculate the maximum length of the cooked key */
67
keylen = (keylen + 2) / 3;
68
69
max = keylen * 4;
70
max += 5; /* @checksum/M */
71
max += 3 * 2; /* maximum number of segment dividers (".../M")
72
* is ((514 + 188) / 189) = 3
73
*/
74
max += 1; /* NUL on end */
75
}
76
77
max += 1; /* 2nd NUL on end */
78
79
_debug("max: %d", max);
80
81
key = kmalloc(max, GFP_KERNEL);
82
if (!key)
83
return NULL;
84
85
len = 0;
86
87
/* build the cooked key */
88
sprintf(key, "@%02x%c+", (unsigned) csum, 0);
89
len = 5;
90
mark = len - 1;
91
92
if (print) {
93
acc = *(uint16_t *) raw;
94
raw += 2;
95
96
key[len + 1] = cachefiles_charmap[acc & 63];
97
acc >>= 6;
98
key[len] = cachefiles_charmap[acc & 63];
99
len += 2;
100
101
seg = 250;
102
for (loop = keylen; loop > 0; loop--) {
103
if (seg <= 0) {
104
key[len++] = '\0';
105
mark = len;
106
key[len++] = '+';
107
seg = 252;
108
}
109
110
key[len++] = *raw++;
111
ASSERT(len < max);
112
}
113
114
switch (type) {
115
case FSCACHE_COOKIE_TYPE_INDEX: type = 'I'; break;
116
case FSCACHE_COOKIE_TYPE_DATAFILE: type = 'D'; break;
117
default: type = 'S'; break;
118
}
119
} else {
120
seg = 252;
121
for (loop = keylen; loop > 0; loop--) {
122
if (seg <= 0) {
123
key[len++] = '\0';
124
mark = len;
125
key[len++] = '+';
126
seg = 252;
127
}
128
129
acc = *raw++;
130
acc |= *raw++ << 8;
131
acc |= *raw++ << 16;
132
133
_debug("acc: %06x", acc);
134
135
key[len++] = cachefiles_charmap[acc & 63];
136
acc >>= 6;
137
key[len++] = cachefiles_charmap[acc & 63];
138
acc >>= 6;
139
key[len++] = cachefiles_charmap[acc & 63];
140
acc >>= 6;
141
key[len++] = cachefiles_charmap[acc & 63];
142
143
ASSERT(len < max);
144
}
145
146
switch (type) {
147
case FSCACHE_COOKIE_TYPE_INDEX: type = 'J'; break;
148
case FSCACHE_COOKIE_TYPE_DATAFILE: type = 'E'; break;
149
default: type = 'T'; break;
150
}
151
}
152
153
key[mark] = type;
154
key[len++] = 0;
155
key[len] = 0;
156
157
_leave(" = %p %d", key, len);
158
return key;
159
}
160
161