linux/fs/cifs/cifs_unicode.c
<<
>>
Prefs
   1/*
   2 *   fs/cifs/cifs_unicode.c
   3 *
   4 *   Copyright (c) International Business Machines  Corp., 2000,2009
   5 *   Modified by Steve French (sfrench@us.ibm.com)
   6 *
   7 *   This program is free software;  you can redistribute it and/or modify
   8 *   it under the terms of the GNU General Public License as published by
   9 *   the Free Software Foundation; either version 2 of the License, or
  10 *   (at your option) any later version.
  11 *
  12 *   This program is distributed in the hope that it will be useful,
  13 *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
  14 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
  15 *   the GNU General Public License for more details.
  16 *
  17 *   You should have received a copy of the GNU General Public License
  18 *   along with this program;  if not, write to the Free Software
  19 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  20 */
  21#include <linux/fs.h>
  22#include <linux/slab.h>
  23#include "cifs_unicode.h"
  24#include "cifs_uniupr.h"
  25#include "cifspdu.h"
  26#include "cifsglob.h"
  27#include "cifs_debug.h"
  28
  29/*
  30 * cifs_utf16_bytes - how long will a string be after conversion?
  31 * @utf16 - pointer to input string
  32 * @maxbytes - don't go past this many bytes of input string
  33 * @codepage - destination codepage
  34 *
  35 * Walk a utf16le string and return the number of bytes that the string will
  36 * be after being converted to the given charset, not including any null
  37 * termination required. Don't walk past maxbytes in the source buffer.
  38 */
  39int
  40cifs_utf16_bytes(const __le16 *from, int maxbytes,
  41                const struct nls_table *codepage)
  42{
  43        int i;
  44        int charlen, outlen = 0;
  45        int maxwords = maxbytes / 2;
  46        char tmp[NLS_MAX_CHARSET_SIZE];
  47        __u16 ftmp;
  48
  49        for (i = 0; i < maxwords; i++) {
  50                ftmp = get_unaligned_le16(&from[i]);
  51                if (ftmp == 0)
  52                        break;
  53
  54                charlen = codepage->uni2char(ftmp, tmp, NLS_MAX_CHARSET_SIZE);
  55                if (charlen > 0)
  56                        outlen += charlen;
  57                else
  58                        outlen++;
  59        }
  60
  61        return outlen;
  62}
  63
  64/*
  65 * cifs_mapchar - convert a host-endian char to proper char in codepage
  66 * @target - where converted character should be copied
  67 * @src_char - 2 byte host-endian source character
  68 * @cp - codepage to which character should be converted
  69 * @mapchar - should character be mapped according to mapchars mount option?
  70 *
  71 * This function handles the conversion of a single character. It is the
  72 * responsibility of the caller to ensure that the target buffer is large
  73 * enough to hold the result of the conversion (at least NLS_MAX_CHARSET_SIZE).
  74 */
  75static int
  76cifs_mapchar(char *target, const __u16 src_char, const struct nls_table *cp,
  77             bool mapchar)
  78{
  79        int len = 1;
  80
  81        if (!mapchar)
  82                goto cp_convert;
  83
  84        /*
  85         * BB: Cannot handle remapping UNI_SLASH until all the calls to
  86         *     build_path_from_dentry are modified, as they use slash as
  87         *     separator.
  88         */
  89        switch (src_char) {
  90        case UNI_COLON:
  91                *target = ':';
  92                break;
  93        case UNI_ASTERISK:
  94                *target = '*';
  95                break;
  96        case UNI_QUESTION:
  97                *target = '?';
  98                break;
  99        case UNI_PIPE:
 100                *target = '|';
 101                break;
 102        case UNI_GRTRTHAN:
 103                *target = '>';
 104                break;
 105        case UNI_LESSTHAN:
 106                *target = '<';
 107                break;
 108        default:
 109                goto cp_convert;
 110        }
 111
 112out:
 113        return len;
 114
 115cp_convert:
 116        len = cp->uni2char(src_char, target, NLS_MAX_CHARSET_SIZE);
 117        if (len <= 0) {
 118                *target = '?';
 119                len = 1;
 120        }
 121        goto out;
 122}
 123
 124/*
 125 * cifs_from_utf16 - convert utf16le string to local charset
 126 * @to - destination buffer
 127 * @from - source buffer
 128 * @tolen - destination buffer size (in bytes)
 129 * @fromlen - source buffer size (in bytes)
 130 * @codepage - codepage to which characters should be converted
 131 * @mapchar - should characters be remapped according to the mapchars option?
 132 *
 133 * Convert a little-endian utf16le string (as sent by the server) to a string
 134 * in the provided codepage. The tolen and fromlen parameters are to ensure
 135 * that the code doesn't walk off of the end of the buffer (which is always
 136 * a danger if the alignment of the source buffer is off). The destination
 137 * string is always properly null terminated and fits in the destination
 138 * buffer. Returns the length of the destination string in bytes (including
 139 * null terminator).
 140 *
 141 * Note that some windows versions actually send multiword UTF-16 characters
 142 * instead of straight UTF16-2. The linux nls routines however aren't able to
 143 * deal with those characters properly. In the event that we get some of
 144 * those characters, they won't be translated properly.
 145 */
 146int
 147cifs_from_utf16(char *to, const __le16 *from, int tolen, int fromlen,
 148                 const struct nls_table *codepage, bool mapchar)
 149{
 150        int i, charlen, safelen;
 151        int outlen = 0;
 152        int nullsize = nls_nullsize(codepage);
 153        int fromwords = fromlen / 2;
 154        char tmp[NLS_MAX_CHARSET_SIZE];
 155        __u16 ftmp;
 156
 157        /*
 158         * because the chars can be of varying widths, we need to take care
 159         * not to overflow the destination buffer when we get close to the
 160         * end of it. Until we get to this offset, we don't need to check
 161         * for overflow however.
 162         */
 163        safelen = tolen - (NLS_MAX_CHARSET_SIZE + nullsize);
 164
 165        for (i = 0; i < fromwords; i++) {
 166                ftmp = get_unaligned_le16(&from[i]);
 167                if (ftmp == 0)
 168                        break;
 169
 170                /*
 171                 * check to see if converting this character might make the
 172                 * conversion bleed into the null terminator
 173                 */
 174                if (outlen >= safelen) {
 175                        charlen = cifs_mapchar(tmp, ftmp, codepage, mapchar);
 176                        if ((outlen + charlen) > (tolen - nullsize))
 177                                break;
 178                }
 179
 180                /* put converted char into 'to' buffer */
 181                charlen = cifs_mapchar(&to[outlen], ftmp, codepage, mapchar);
 182                outlen += charlen;
 183        }
 184
 185        /* properly null-terminate string */
 186        for (i = 0; i < nullsize; i++)
 187                to[outlen++] = 0;
 188
 189        return outlen;
 190}
 191
 192/*
 193 * NAME:        cifs_strtoUTF16()
 194 *
 195 * FUNCTION:    Convert character string to unicode string
 196 *
 197 */
 198int
 199cifs_strtoUTF16(__le16 *to, const char *from, int len,
 200              const struct nls_table *codepage)
 201{
 202        int charlen;
 203        int i;
 204        wchar_t wchar_to; /* needed to quiet sparse */
 205
 206        /* special case for utf8 to handle no plane0 chars */
 207        if (!strcmp(codepage->charset, "utf8")) {
 208                /*
 209                 * convert utf8 -> utf16, we assume we have enough space
 210                 * as caller should have assumed conversion does not overflow
 211                 * in destination len is length in wchar_t units (16bits)
 212                 */
 213                i  = utf8s_to_utf16s(from, len, UTF16_LITTLE_ENDIAN,
 214                                       (wchar_t *) to, len);
 215
 216                /* if success terminate and exit */
 217                if (i >= 0)
 218                        goto success;
 219                /*
 220                 * if fails fall back to UCS encoding as this
 221                 * function should not return negative values
 222                 * currently can fail only if source contains
 223                 * invalid encoded characters
 224                 */
 225        }
 226
 227        for (i = 0; len && *from; i++, from += charlen, len -= charlen) {
 228                charlen = codepage->char2uni(from, len, &wchar_to);
 229                if (charlen < 1) {
 230                        cERROR(1, "strtoUTF16: char2uni of 0x%x returned %d",
 231                                *from, charlen);
 232                        /* A question mark */
 233                        wchar_to = 0x003f;
 234                        charlen = 1;
 235                }
 236                put_unaligned_le16(wchar_to, &to[i]);
 237        }
 238
 239success:
 240        put_unaligned_le16(0, &to[i]);
 241        return i;
 242}
 243
 244/*
 245 * cifs_strndup_from_utf16 - copy a string from wire format to the local
 246 * codepage
 247 * @src - source string
 248 * @maxlen - don't walk past this many bytes in the source string
 249 * @is_unicode - is this a unicode string?
 250 * @codepage - destination codepage
 251 *
 252 * Take a string given by the server, convert it to the local codepage and
 253 * put it in a new buffer. Returns a pointer to the new string or NULL on
 254 * error.
 255 */
 256char *
 257cifs_strndup_from_utf16(const char *src, const int maxlen,
 258                        const bool is_unicode, const struct nls_table *codepage)
 259{
 260        int len;
 261        char *dst;
 262
 263        if (is_unicode) {
 264                len = cifs_utf16_bytes((__le16 *) src, maxlen, codepage);
 265                len += nls_nullsize(codepage);
 266                dst = kmalloc(len, GFP_KERNEL);
 267                if (!dst)
 268                        return NULL;
 269                cifs_from_utf16(dst, (__le16 *) src, len, maxlen, codepage,
 270                               false);
 271        } else {
 272                len = strnlen(src, maxlen);
 273                len++;
 274                dst = kmalloc(len, GFP_KERNEL);
 275                if (!dst)
 276                        return NULL;
 277                strlcpy(dst, src, len);
 278        }
 279
 280        return dst;
 281}
 282
 283/*
 284 * Convert 16 bit Unicode pathname to wire format from string in current code
 285 * page. Conversion may involve remapping up the six characters that are
 286 * only legal in POSIX-like OS (if they are present in the string). Path
 287 * names are little endian 16 bit Unicode on the wire
 288 */
 289int
 290cifsConvertToUTF16(__le16 *target, const char *source, int srclen,
 291                 const struct nls_table *cp, int mapChars)
 292{
 293        int i, j, charlen;
 294        char src_char;
 295        __le16 dst_char;
 296        wchar_t tmp;
 297
 298        if (!mapChars)
 299                return cifs_strtoUTF16(target, source, PATH_MAX, cp);
 300
 301        for (i = 0, j = 0; i < srclen; j++) {
 302                src_char = source[i];
 303                charlen = 1;
 304                switch (src_char) {
 305                case 0:
 306                        put_unaligned(0, &target[j]);
 307                        goto ctoUTF16_out;
 308                case ':':
 309                        dst_char = cpu_to_le16(UNI_COLON);
 310                        break;
 311                case '*':
 312                        dst_char = cpu_to_le16(UNI_ASTERISK);
 313                        break;
 314                case '?':
 315                        dst_char = cpu_to_le16(UNI_QUESTION);
 316                        break;
 317                case '<':
 318                        dst_char = cpu_to_le16(UNI_LESSTHAN);
 319                        break;
 320                case '>':
 321                        dst_char = cpu_to_le16(UNI_GRTRTHAN);
 322                        break;
 323                case '|':
 324                        dst_char = cpu_to_le16(UNI_PIPE);
 325                        break;
 326                /*
 327                 * FIXME: We can not handle remapping backslash (UNI_SLASH)
 328                 * until all the calls to build_path_from_dentry are modified,
 329                 * as they use backslash as separator.
 330                 */
 331                default:
 332                        charlen = cp->char2uni(source + i, srclen - i, &tmp);
 333                        dst_char = cpu_to_le16(tmp);
 334
 335                        /*
 336                         * if no match, use question mark, which at least in
 337                         * some cases serves as wild card
 338                         */
 339                        if (charlen < 1) {
 340                                dst_char = cpu_to_le16(0x003f);
 341                                charlen = 1;
 342                        }
 343                }
 344                /*
 345                 * character may take more than one byte in the source string,
 346                 * but will take exactly two bytes in the target string
 347                 */
 348                i += charlen;
 349                put_unaligned(dst_char, &target[j]);
 350        }
 351
 352ctoUTF16_out:
 353        return j;
 354}
 355
 356#ifdef CONFIG_CIFS_SMB2
 357/*
 358 * cifs_local_to_utf16_bytes - how long will a string be after conversion?
 359 * @from - pointer to input string
 360 * @maxbytes - don't go past this many bytes of input string
 361 * @codepage - source codepage
 362 *
 363 * Walk a string and return the number of bytes that the string will
 364 * be after being converted to the given charset, not including any null
 365 * termination required. Don't walk past maxbytes in the source buffer.
 366 */
 367
 368static int
 369cifs_local_to_utf16_bytes(const char *from, int len,
 370                          const struct nls_table *codepage)
 371{
 372        int charlen;
 373        int i;
 374        wchar_t wchar_to;
 375
 376        for (i = 0; len && *from; i++, from += charlen, len -= charlen) {
 377                charlen = codepage->char2uni(from, len, &wchar_to);
 378                /* Failed conversion defaults to a question mark */
 379                if (charlen < 1)
 380                        charlen = 1;
 381        }
 382        return 2 * i; /* UTF16 characters are two bytes */
 383}
 384
 385/*
 386 * cifs_strndup_to_utf16 - copy a string to wire format from the local codepage
 387 * @src - source string
 388 * @maxlen - don't walk past this many bytes in the source string
 389 * @utf16_len - the length of the allocated string in bytes (including null)
 390 * @cp - source codepage
 391 * @remap - map special chars
 392 *
 393 * Take a string convert it from the local codepage to UTF16 and
 394 * put it in a new buffer. Returns a pointer to the new string or NULL on
 395 * error.
 396 */
 397__le16 *
 398cifs_strndup_to_utf16(const char *src, const int maxlen, int *utf16_len,
 399                      const struct nls_table *cp, int remap)
 400{
 401        int len;
 402        __le16 *dst;
 403
 404        len = cifs_local_to_utf16_bytes(src, maxlen, cp);
 405        len += 2; /* NULL */
 406        dst = kmalloc(len, GFP_KERNEL);
 407        if (!dst) {
 408                *utf16_len = 0;
 409                return NULL;
 410        }
 411        cifsConvertToUTF16(dst, src, strlen(src), cp, remap);
 412        *utf16_len = len;
 413        return dst;
 414}
 415#endif /* CONFIG_CIFS_SMB2 */
 416
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.