123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- /* Key to pathname encoder
- *
- * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public Licence
- * as published by the Free Software Foundation; either version
- * 2 of the Licence, or (at your option) any later version.
- */
- #include <linux/slab.h>
- #include "internal.h"
- static const char cachefiles_charmap[64] =
- "0123456789" /* 0 - 9 */
- "abcdefghijklmnopqrstuvwxyz" /* 10 - 35 */
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ" /* 36 - 61 */
- "_-" /* 62 - 63 */
- ;
- static const char cachefiles_filecharmap[256] = {
- /* we skip space and tab and control chars */
- [33 ... 46] = 1, /* '!' -> '.' */
- /* we skip '/' as it's significant to pathwalk */
- [48 ... 127] = 1, /* '0' -> '~' */
- };
- /*
- * turn the raw key into something cooked
- * - the raw key should include the length in the two bytes at the front
- * - the key may be up to 514 bytes in length (including the length word)
- * - "base64" encode the strange keys, mapping 3 bytes of raw to four of
- * cooked
- * - need to cut the cooked key into 252 char lengths (189 raw bytes)
- */
- char *cachefiles_cook_key(const u8 *raw, int keylen, uint8_t type)
- {
- unsigned char csum, ch;
- unsigned int acc;
- char *key;
- int loop, len, max, seg, mark, print;
- _enter(",%d", keylen);
- BUG_ON(keylen < 2 || keylen > 514);
- csum = raw[0] + raw[1];
- print = 1;
- for (loop = 2; loop < keylen; loop++) {
- ch = raw[loop];
- csum += ch;
- print &= cachefiles_filecharmap[ch];
- }
- if (print) {
- /* if the path is usable ASCII, then we render it directly */
- max = keylen - 2;
- max += 2; /* two base64'd length chars on the front */
- max += 5; /* @checksum/M */
- max += 3 * 2; /* maximum number of segment dividers (".../M")
- * is ((514 + 251) / 252) = 3
- */
- max += 1; /* NUL on end */
- } else {
- /* calculate the maximum length of the cooked key */
- keylen = (keylen + 2) / 3;
- max = keylen * 4;
- max += 5; /* @checksum/M */
- max += 3 * 2; /* maximum number of segment dividers (".../M")
- * is ((514 + 188) / 189) = 3
- */
- max += 1; /* NUL on end */
- }
- max += 1; /* 2nd NUL on end */
- _debug("max: %d", max);
- key = kmalloc(max, cachefiles_gfp);
- if (!key)
- return NULL;
- len = 0;
- /* build the cooked key */
- sprintf(key, "@%02x%c+", (unsigned) csum, 0);
- len = 5;
- mark = len - 1;
- if (print) {
- acc = *(uint16_t *) raw;
- raw += 2;
- key[len + 1] = cachefiles_charmap[acc & 63];
- acc >>= 6;
- key[len] = cachefiles_charmap[acc & 63];
- len += 2;
- seg = 250;
- for (loop = keylen; loop > 0; loop--) {
- if (seg <= 0) {
- key[len++] = '\0';
- mark = len;
- key[len++] = '+';
- seg = 252;
- }
- key[len++] = *raw++;
- ASSERT(len < max);
- }
- switch (type) {
- case FSCACHE_COOKIE_TYPE_INDEX: type = 'I'; break;
- case FSCACHE_COOKIE_TYPE_DATAFILE: type = 'D'; break;
- default: type = 'S'; break;
- }
- } else {
- seg = 252;
- for (loop = keylen; loop > 0; loop--) {
- if (seg <= 0) {
- key[len++] = '\0';
- mark = len;
- key[len++] = '+';
- seg = 252;
- }
- acc = *raw++;
- acc |= *raw++ << 8;
- acc |= *raw++ << 16;
- _debug("acc: %06x", acc);
- key[len++] = cachefiles_charmap[acc & 63];
- acc >>= 6;
- key[len++] = cachefiles_charmap[acc & 63];
- acc >>= 6;
- key[len++] = cachefiles_charmap[acc & 63];
- acc >>= 6;
- key[len++] = cachefiles_charmap[acc & 63];
- ASSERT(len < max);
- }
- switch (type) {
- case FSCACHE_COOKIE_TYPE_INDEX: type = 'J'; break;
- case FSCACHE_COOKIE_TYPE_DATAFILE: type = 'E'; break;
- default: type = 'T'; break;
- }
- }
- key[mark] = type;
- key[len++] = 0;
- key[len] = 0;
- _leave(" = %p %d", key, len);
- return key;
- }
|