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        for (i = 0; len && *from; i++, from += charlen, len -= charlen) {
 207                charlen = codepage->char2uni(from, len, &wchar_to);
 208                if (charlen < 1) {
 209                        cERROR(1, "strtoUTF16: char2uni of 0x%x returned %d",
 210                                *from, charlen);
 211                        /* A question mark */
 212                        wchar_to = 0x003f;
 213                        charlen = 1;
 214                }
 215                put_unaligned_le16(wchar_to, &to[i]);
 216        }
 217
 218        put_unaligned_le16(0, &to[i]);
 219        return i;
 220}
 221
 222/*
 223 * cifs_strndup_from_utf16 - copy a string from wire format to the local
 224 * codepage
 225 * @src - source string
 226 * @maxlen - don't walk past this many bytes in the source string
 227 * @is_unicode - is this a unicode string?
 228 * @codepage - destination codepage
 229 *
 230 * Take a string given by the server, convert it to the local codepage and
 231 * put it in a new buffer. Returns a pointer to the new string or NULL on
 232 * error.
 233 */
 234char *
 235cifs_strndup_from_utf16(const char *src, const int maxlen,
 236                        const bool is_unicode, const struct nls_table *codepage)
 237{
 238        int len;
 239        char *dst;
 240
 241        if (is_unicode) {
 242                len = cifs_utf16_bytes((__le16 *) src, maxlen, codepage);
 243                len += nls_nullsize(codepage);
 244                dst = kmalloc(len, GFP_KERNEL);
 245                if (!dst)
 246                        return NULL;
 247                cifs_from_utf16(dst, (__le16 *) src, len, maxlen, codepage,
 248                               false);
 249        } else {
 250                len = strnlen(src, maxlen);
 251                len++;
 252                dst = kmalloc(len, GFP_KERNEL);
 253                if (!dst)
 254                        return NULL;
 255                strlcpy(dst, src, len);
 256        }
 257
 258        return dst;
 259}
 260
 261/*
 262 * Convert 16 bit Unicode pathname to wire format from string in current code
 263 * page. Conversion may involve remapping up the six characters that are
 264 * only legal in POSIX-like OS (if they are present in the string). Path
 265 * names are little endian 16 bit Unicode on the wire
 266 */
 267int
 268cifsConvertToUTF16(__le16 *target, const char *source, int srclen,
 269                 const struct nls_table *cp, int mapChars)
 270{
 271        int i, j, charlen;
 272        char src_char;
 273        __le16 dst_char;
 274        wchar_t tmp;
 275
 276        if (!mapChars)
 277                return cifs_strtoUTF16(target, source, PATH_MAX, cp);
 278
 279        for (i = 0, j = 0; i < srclen; j++) {
 280                src_char = source[i];
 281                charlen = 1;
 282                switch (src_char) {
 283                case 0:
 284                        put_unaligned(0, &target[j]);
 285                        goto ctoUTF16_out;
 286                case ':':
 287                        dst_char = cpu_to_le16(UNI_COLON);
 288                        break;
 289                case '*':
 290                        dst_char = cpu_to_le16(UNI_ASTERISK);
 291                        break;
 292                case '?':
 293                        dst_char = cpu_to_le16(UNI_QUESTION);
 294                        break;
 295                case '<':
 296                        dst_char = cpu_to_le16(UNI_LESSTHAN);
 297                        break;
 298                case '>':
 299                        dst_char = cpu_to_le16(UNI_GRTRTHAN);
 300                        break;
 301                case '|':
 302                        dst_char = cpu_to_le16(UNI_PIPE);
 303                        break;
 304                /*
 305                 * FIXME: We can not handle remapping backslash (UNI_SLASH)
 306                 * until all the calls to build_path_from_dentry are modified,
 307                 * as they use backslash as separator.
 308                 */
 309                default:
 310                        charlen = cp->char2uni(source + i, srclen - i, &tmp);
 311                        dst_char = cpu_to_le16(tmp);
 312
 313                        /*
 314                         * if no match, use question mark, which at least in
 315                         * some cases serves as wild card
 316                         */
 317                        if (charlen < 1) {
 318                                dst_char = cpu_to_le16(0x003f);
 319                                charlen = 1;
 320                        }
 321                }
 322                /*
 323                 * character may take more than one byte in the source string,
 324                 * but will take exactly two bytes in the target string
 325                 */
 326                i += charlen;
 327                put_unaligned(dst_char, &target[j]);
 328        }
 329
 330ctoUTF16_out:
 331        return j;
 332}
 333
 334#ifdef CONFIG_CIFS_SMB2
 335/*
 336 * cifs_local_to_utf16_bytes - how long will a string be after conversion?
 337 * @from - pointer to input string
 338 * @maxbytes - don't go past this many bytes of input string
 339 * @codepage - source codepage
 340 *
 341 * Walk a string and return the number of bytes that the string will
 342 * be after being converted to the given charset, not including any null
 343 * termination required. Don't walk past maxbytes in the source buffer.
 344 */
 345
 346static int
 347cifs_local_to_utf16_bytes(const char *from, int len,
 348                          const struct nls_table *codepage)
 349{
 350        int charlen;
 351        int i;
 352        wchar_t wchar_to;
 353
 354        for (i = 0; len && *from; i++, from += charlen, len -= charlen) {
 355                charlen = codepage->char2uni(from, len, &wchar_to);
 356                /* Failed conversion defaults to a question mark */
 357                if (charlen < 1)
 358                        charlen = 1;
 359        }
 360        return 2 * i; /* UTF16 characters are two bytes */
 361}
 362
 363/*
 364 * cifs_strndup_to_utf16 - copy a string to wire format from the local codepage
 365 * @src - source string
 366 * @maxlen - don't walk past this many bytes in the source string
 367 * @utf16_len - the length of the allocated string in bytes (including null)
 368 * @cp - source codepage
 369 * @remap - map special chars
 370 *
 371 * Take a string convert it from the local codepage to UTF16 and
 372 * put it in a new buffer. Returns a pointer to the new string or NULL on
 373 * error.
 374 */
 375__le16 *
 376cifs_strndup_to_utf16(const char *src, const int maxlen, int *utf16_len,
 377                      const struct nls_table *cp, int remap)
 378{
 379        int len;
 380        __le16 *dst;
 381
 382        len = cifs_local_to_utf16_bytes(src, maxlen, cp);
 383        len += 2; /* NULL */
 384        dst = kmalloc(len, GFP_KERNEL);
 385        if (!dst) {
 386                *utf16_len = 0;
 387                return NULL;
 388        }
 389        cifsConvertToUTF16(dst, src, strlen(src), cp, remap);
 390        *utf16_len = len;
 391        return dst;
 392}
 393#endif /* CONFIG_CIFS_SMB2 */
 394
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.