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_ucs2_bytes - how long will a string be after conversion?
  31 * @ucs - pointer to input string
  32 * @maxbytes - don't go past this many bytes of input string
  33 * @codepage - destination codepage
  34 *
  35 * Walk a ucs2le 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_ucs2_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_ucs2 - 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 ucs2le 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 UCS-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_ucs2(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_strtoUCS()
 194 *
 195 * FUNCTION:    Convert character string to unicode string
 196 *
 197 */
 198int
 199cifs_strtoUCS(__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, "strtoUCS: 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_ucs - copy a string from wire format to the local codepage
 224 * @src - source string
 225 * @maxlen - don't walk past this many bytes in the source string
 226 * @is_unicode - is this a unicode string?
 227 * @codepage - destination codepage
 228 *
 229 * Take a string given by the server, convert it to the local codepage and
 230 * put it in a new buffer. Returns a pointer to the new string or NULL on
 231 * error.
 232 */
 233char *
 234cifs_strndup_from_ucs(const char *src, const int maxlen, const bool is_unicode,
 235             const struct nls_table *codepage)
 236{
 237        int len;
 238        char *dst;
 239
 240        if (is_unicode) {
 241                len = cifs_ucs2_bytes((__le16 *) src, maxlen, codepage);
 242                len += nls_nullsize(codepage);
 243                dst = kmalloc(len, GFP_KERNEL);
 244                if (!dst)
 245                        return NULL;
 246                cifs_from_ucs2(dst, (__le16 *) src, len, maxlen, codepage,
 247                               false);
 248        } else {
 249                len = strnlen(src, maxlen);
 250                len++;
 251                dst = kmalloc(len, GFP_KERNEL);
 252                if (!dst)
 253                        return NULL;
 254                strlcpy(dst, src, len);
 255        }
 256
 257        return dst;
 258}
 259
 260/*
 261 * Convert 16 bit Unicode pathname to wire format from string in current code
 262 * page. Conversion may involve remapping up the six characters that are
 263 * only legal in POSIX-like OS (if they are present in the string). Path
 264 * names are little endian 16 bit Unicode on the wire
 265 */
 266int
 267cifsConvertToUCS(__le16 *target, const char *source, int srclen,
 268                 const struct nls_table *cp, int mapChars)
 269{
 270        int i, j, charlen;
 271        char src_char;
 272        __le16 dst_char;
 273        wchar_t tmp;
 274
 275        if (!mapChars)
 276                return cifs_strtoUCS(target, source, PATH_MAX, cp);
 277
 278        for (i = 0, j = 0; i < srclen; j++) {
 279                src_char = source[i];
 280                charlen = 1;
 281                switch (src_char) {
 282                case 0:
 283                        put_unaligned(0, &target[j]);
 284                        goto ctoUCS_out;
 285                case ':':
 286                        dst_char = cpu_to_le16(UNI_COLON);
 287                        break;
 288                case '*':
 289                        dst_char = cpu_to_le16(UNI_ASTERISK);
 290                        break;
 291                case '?':
 292                        dst_char = cpu_to_le16(UNI_QUESTION);
 293                        break;
 294                case '<':
 295                        dst_char = cpu_to_le16(UNI_LESSTHAN);
 296                        break;
 297                case '>':
 298                        dst_char = cpu_to_le16(UNI_GRTRTHAN);
 299                        break;
 300                case '|':
 301                        dst_char = cpu_to_le16(UNI_PIPE);
 302                        break;
 303                /*
 304                 * FIXME: We can not handle remapping backslash (UNI_SLASH)
 305                 * until all the calls to build_path_from_dentry are modified,
 306                 * as they use backslash as separator.
 307                 */
 308                default:
 309                        charlen = cp->char2uni(source + i, srclen - i, &tmp);
 310                        dst_char = cpu_to_le16(tmp);
 311
 312                        /*
 313                         * if no match, use question mark, which at least in
 314                         * some cases serves as wild card
 315                         */
 316                        if (charlen < 1) {
 317                                dst_char = cpu_to_le16(0x003f);
 318                                charlen = 1;
 319                        }
 320                }
 321                /*
 322                 * character may take more than one byte in the source string,
 323                 * but will take exactly two bytes in the target string
 324                 */
 325                i += charlen;
 326                put_unaligned(dst_char, &target[j]);
 327        }
 328
 329ctoUCS_out:
 330        return i;
 331}
 332
 333