Linux Audio

Check our new training course

Loading...
v5.9
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/* Key to pathname encoder
  3 *
  4 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
  5 * Written by David Howells (dhowells@redhat.com)
  6 */
  7
  8#include <linux/slab.h>
  9#include "internal.h"
 10
 11static const char cachefiles_charmap[64] =
 12	"0123456789"			/* 0 - 9 */
 13	"abcdefghijklmnopqrstuvwxyz"	/* 10 - 35 */
 14	"ABCDEFGHIJKLMNOPQRSTUVWXYZ"	/* 36 - 61 */
 15	"_-"				/* 62 - 63 */
 16	;
 17
 18static const char cachefiles_filecharmap[256] = {
 19	/* we skip space and tab and control chars */
 20	[33 ... 46] = 1,		/* '!' -> '.' */
 21	/* we skip '/' as it's significant to pathwalk */
 22	[48 ... 127] = 1,		/* '0' -> '~' */
 23};
 24
 
 
 
 
 
 25/*
 26 * turn the raw key into something cooked
 27 * - the raw key should include the length in the two bytes at the front
 28 * - the key may be up to 514 bytes in length (including the length word)
 29 *   - "base64" encode the strange keys, mapping 3 bytes of raw to four of
 30 *     cooked
 31 *   - need to cut the cooked key into 252 char lengths (189 raw bytes)
 32 */
 33char *cachefiles_cook_key(const u8 *raw, int keylen, uint8_t type)
 34{
 35	unsigned char csum, ch;
 36	unsigned int acc;
 37	char *key;
 38	int loop, len, max, seg, mark, print;
 
 39
 40	_enter(",%d", keylen);
 41
 42	BUG_ON(keylen < 2 || keylen > 514);
 43
 44	csum = raw[0] + raw[1];
 45	print = 1;
 46	for (loop = 2; loop < keylen; loop++) {
 47		ch = raw[loop];
 48		csum += ch;
 49		print &= cachefiles_filecharmap[ch];
 50	}
 51
 
 52	if (print) {
 53		/* if the path is usable ASCII, then we render it directly */
 54		max = keylen - 2;
 55		max += 2;	/* two base64'd length chars on the front */
 56		max += 5;	/* @checksum/M */
 57		max += 3 * 2;	/* maximum number of segment dividers (".../M")
 58				 * is ((514 + 251) / 252) = 3
 59				 */
 60		max += 1;	/* NUL on end */
 61	} else {
 62		/* calculate the maximum length of the cooked key */
 63		keylen = (keylen + 2) / 3;
 64
 65		max = keylen * 4;
 66		max += 5;	/* @checksum/M */
 67		max += 3 * 2;	/* maximum number of segment dividers (".../M")
 68				 * is ((514 + 188) / 189) = 3
 69				 */
 70		max += 1;	/* NUL on end */
 71	}
 72
 73	max += 1;	/* 2nd NUL on end */
 74
 75	_debug("max: %d", max);
 76
 77	key = kmalloc(max, cachefiles_gfp);
 78	if (!key)
 79		return NULL;
 80
 81	len = 0;
 82
 83	/* build the cooked key */
 84	sprintf(key, "@%02x%c+", (unsigned) csum, 0);
 85	len = 5;
 86	mark = len - 1;
 87
 88	if (print) {
 89		acc = *(uint16_t *) raw;
 90		raw += 2;
 91
 92		key[len + 1] = cachefiles_charmap[acc & 63];
 93		acc >>= 6;
 94		key[len] = cachefiles_charmap[acc & 63];
 95		len += 2;
 96
 97		seg = 250;
 98		for (loop = keylen; loop > 0; loop--) {
 99			if (seg <= 0) {
100				key[len++] = '\0';
101				mark = len;
102				key[len++] = '+';
103				seg = 252;
104			}
105
106			key[len++] = *raw++;
107			ASSERT(len < max);
108		}
109
110		switch (type) {
111		case FSCACHE_COOKIE_TYPE_INDEX:		type = 'I';	break;
112		case FSCACHE_COOKIE_TYPE_DATAFILE:	type = 'D';	break;
113		default:				type = 'S';	break;
114		}
115	} else {
116		seg = 252;
117		for (loop = keylen; loop > 0; loop--) {
118			if (seg <= 0) {
119				key[len++] = '\0';
120				mark = len;
121				key[len++] = '+';
122				seg = 252;
123			}
124
125			acc = *raw++;
126			acc |= *raw++ << 8;
127			acc |= *raw++ << 16;
128
129			_debug("acc: %06x", acc);
130
131			key[len++] = cachefiles_charmap[acc & 63];
132			acc >>= 6;
133			key[len++] = cachefiles_charmap[acc & 63];
134			acc >>= 6;
135			key[len++] = cachefiles_charmap[acc & 63];
136			acc >>= 6;
137			key[len++] = cachefiles_charmap[acc & 63];
138
139			ASSERT(len < max);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140		}
 
 
141
142		switch (type) {
143		case FSCACHE_COOKIE_TYPE_INDEX:		type = 'J';	break;
144		case FSCACHE_COOKIE_TYPE_DATAFILE:	type = 'E';	break;
145		default:				type = 'T';	break;
 
 
 
 
 
 
 
 
 
 
 
146		}
147	}
148
149	key[mark] = type;
150	key[len++] = 0;
151	key[len] = 0;
 
 
 
 
 
152
153	_leave(" = %p %d", key, len);
154	return key;
 
 
 
 
155}
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/* Key to pathname encoder
  3 *
  4 * Copyright (C) 2021 Red Hat, Inc. All Rights Reserved.
  5 * Written by David Howells (dhowells@redhat.com)
  6 */
  7
  8#include <linux/slab.h>
  9#include "internal.h"
 10
 11static const char cachefiles_charmap[64] =
 12	"0123456789"			/* 0 - 9 */
 13	"abcdefghijklmnopqrstuvwxyz"	/* 10 - 35 */
 14	"ABCDEFGHIJKLMNOPQRSTUVWXYZ"	/* 36 - 61 */
 15	"_-"				/* 62 - 63 */
 16	;
 17
 18static const char cachefiles_filecharmap[256] = {
 19	/* we skip space and tab and control chars */
 20	[33 ... 46] = 1,		/* '!' -> '.' */
 21	/* we skip '/' as it's significant to pathwalk */
 22	[48 ... 127] = 1,		/* '0' -> '~' */
 23};
 24
 25static inline unsigned int how_many_hex_digits(unsigned int x)
 26{
 27	return x ? round_up(ilog2(x) + 1, 4) / 4 : 0;
 28}
 29
 30/*
 31 * turn the raw key into something cooked
 32 * - the key may be up to NAME_MAX 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 */
 37bool cachefiles_cook_key(struct cachefiles_object *object)
 38{
 39	const u8 *key = fscache_get_key(object->cookie), *kend;
 40	unsigned char ch;
 41	unsigned int acc, i, n, nle, nbe, keylen = object->cookie->key_len;
 42	unsigned int b64len, len, print, pad;
 43	char *name, sep;
 44
 45	_enter(",%u,%*phN", keylen, keylen, key);
 46
 47	BUG_ON(keylen > NAME_MAX - 3);
 48
 
 49	print = 1;
 50	for (i = 0; i < keylen; i++) {
 51		ch = key[i];
 
 52		print &= cachefiles_filecharmap[ch];
 53	}
 54
 55	/* If the path is usable ASCII, then we render it directly */
 56	if (print) {
 57		len = 1 + keylen;
 58		name = kmalloc(len + 1, GFP_KERNEL);
 59		if (!name)
 60			return false;
 61
 62		name[0] = 'D'; /* Data object type, string encoding */
 63		memcpy(name + 1, key, keylen);
 64		goto success;
 
 
 
 
 
 
 
 
 
 
 65	}
 66
 67	/* See if it makes sense to encode it as "hex,hex,hex" for each 32-bit
 68	 * chunk.  We rely on the key having been padded out to a whole number
 69	 * of 32-bit words.
 70	 */
 71	n = round_up(keylen, 4);
 72	nbe = nle = 0;
 73	for (i = 0; i < n; i += 4) {
 74		u32 be = be32_to_cpu(*(__be32 *)(key + i));
 75		u32 le = le32_to_cpu(*(__le32 *)(key + i));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 76
 77		nbe += 1 + how_many_hex_digits(be);
 78		nle += 1 + how_many_hex_digits(le);
 79	}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 80
 81	b64len = DIV_ROUND_UP(keylen, 3);
 82	pad = b64len * 3 - keylen;
 83	b64len = 2 + b64len * 4; /* Length if we base64-encode it */
 84	_debug("len=%u nbe=%u nle=%u b64=%u", keylen, nbe, nle, b64len);
 85	if (nbe < b64len || nle < b64len) {
 86		unsigned int nlen = min(nbe, nle) + 1;
 87		name = kmalloc(nlen, GFP_KERNEL);
 88		if (!name)
 89			return false;
 90		sep = (nbe <= nle) ? 'S' : 'T'; /* Encoding indicator */
 91		len = 0;
 92		for (i = 0; i < n; i += 4) {
 93			u32 x;
 94			if (nbe <= nle)
 95				x = be32_to_cpu(*(__be32 *)(key + i));
 96			else
 97				x = le32_to_cpu(*(__le32 *)(key + i));
 98			name[len++] = sep;
 99			if (x != 0)
100				len += snprintf(name + len, nlen - len, "%x", x);
101			sep = ',';
102		}
103		goto success;
104	}
105
106	/* We need to base64-encode it */
107	name = kmalloc(b64len + 1, GFP_KERNEL);
108	if (!name)
109		return false;
110
111	name[0] = 'E';
112	name[1] = '0' + pad;
113	len = 2;
114	kend = key + keylen;
115	do {
116		acc  = *key++;
117		if (key < kend) {
118			acc |= *key++ << 8;
119			if (key < kend)
120				acc |= *key++ << 16;
121		}
 
122
123		name[len++] = cachefiles_charmap[acc & 63];
124		acc >>= 6;
125		name[len++] = cachefiles_charmap[acc & 63];
126		acc >>= 6;
127		name[len++] = cachefiles_charmap[acc & 63];
128		acc >>= 6;
129		name[len++] = cachefiles_charmap[acc & 63];
130	} while (key < kend);
131
132success:
133	name[len] = 0;
134	object->d_name = name;
135	object->d_name_len = len;
136	_leave(" = %s", object->d_name);
137	return true;
138}