diff options
-rw-r--r-- | fs/cifs/cifs_dfs_ref.c | 3 | ||||
-rw-r--r-- | fs/cifs/cifs_unicode.c | 182 | ||||
-rw-r--r-- | fs/cifs/cifsfs.c | 2 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 4 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 23 | ||||
-rw-r--r-- | fs/cifs/connect.c | 3 | ||||
-rw-r--r-- | fs/cifs/dir.c | 3 | ||||
-rw-r--r-- | fs/cifs/file.c | 7 | ||||
-rw-r--r-- | fs/cifs/inode.c | 31 | ||||
-rw-r--r-- | fs/cifs/link.c | 3 | ||||
-rw-r--r-- | fs/cifs/readdir.c | 2 | ||||
-rw-r--r-- | fs/cifs/smb1ops.c | 3 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.c | 2 |
13 files changed, 194 insertions, 74 deletions
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index 430e0348c99e..7dc886c9a78f 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include "cifsfs.h" | 24 | #include "cifsfs.h" |
25 | #include "dns_resolve.h" | 25 | #include "dns_resolve.h" |
26 | #include "cifs_debug.h" | 26 | #include "cifs_debug.h" |
27 | #include "cifs_unicode.h" | ||
27 | 28 | ||
28 | static LIST_HEAD(cifs_dfs_automount_list); | 29 | static LIST_HEAD(cifs_dfs_automount_list); |
29 | 30 | ||
@@ -312,7 +313,7 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt) | |||
312 | xid = get_xid(); | 313 | xid = get_xid(); |
313 | rc = get_dfs_path(xid, ses, full_path + 1, cifs_sb->local_nls, | 314 | rc = get_dfs_path(xid, ses, full_path + 1, cifs_sb->local_nls, |
314 | &num_referrals, &referrals, | 315 | &num_referrals, &referrals, |
315 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 316 | cifs_remap(cifs_sb)); |
316 | free_xid(xid); | 317 | free_xid(xid); |
317 | 318 | ||
318 | cifs_put_tlink(tlink); | 319 | cifs_put_tlink(tlink); |
diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c index 0303c6793d90..5a53ac6b1e02 100644 --- a/fs/cifs/cifs_unicode.c +++ b/fs/cifs/cifs_unicode.c | |||
@@ -27,41 +27,6 @@ | |||
27 | #include "cifsglob.h" | 27 | #include "cifsglob.h" |
28 | #include "cifs_debug.h" | 28 | #include "cifs_debug.h" |
29 | 29 | ||
30 | /* | ||
31 | * cifs_utf16_bytes - how long will a string be after conversion? | ||
32 | * @utf16 - pointer to input string | ||
33 | * @maxbytes - don't go past this many bytes of input string | ||
34 | * @codepage - destination codepage | ||
35 | * | ||
36 | * Walk a utf16le string and return the number of bytes that the string will | ||
37 | * be after being converted to the given charset, not including any null | ||
38 | * termination required. Don't walk past maxbytes in the source buffer. | ||
39 | */ | ||
40 | int | ||
41 | cifs_utf16_bytes(const __le16 *from, int maxbytes, | ||
42 | const struct nls_table *codepage) | ||
43 | { | ||
44 | int i; | ||
45 | int charlen, outlen = 0; | ||
46 | int maxwords = maxbytes / 2; | ||
47 | char tmp[NLS_MAX_CHARSET_SIZE]; | ||
48 | __u16 ftmp; | ||
49 | |||
50 | for (i = 0; i < maxwords; i++) { | ||
51 | ftmp = get_unaligned_le16(&from[i]); | ||
52 | if (ftmp == 0) | ||
53 | break; | ||
54 | |||
55 | charlen = codepage->uni2char(ftmp, tmp, NLS_MAX_CHARSET_SIZE); | ||
56 | if (charlen > 0) | ||
57 | outlen += charlen; | ||
58 | else | ||
59 | outlen++; | ||
60 | } | ||
61 | |||
62 | return outlen; | ||
63 | } | ||
64 | |||
65 | int cifs_remap(struct cifs_sb_info *cifs_sb) | 30 | int cifs_remap(struct cifs_sb_info *cifs_sb) |
66 | { | 31 | { |
67 | int map_type; | 32 | int map_type; |
@@ -155,10 +120,13 @@ convert_sfm_char(const __u16 src_char, char *target) | |||
155 | * enough to hold the result of the conversion (at least NLS_MAX_CHARSET_SIZE). | 120 | * enough to hold the result of the conversion (at least NLS_MAX_CHARSET_SIZE). |
156 | */ | 121 | */ |
157 | static int | 122 | static int |
158 | cifs_mapchar(char *target, const __u16 src_char, const struct nls_table *cp, | 123 | cifs_mapchar(char *target, const __u16 *from, const struct nls_table *cp, |
159 | int maptype) | 124 | int maptype) |
160 | { | 125 | { |
161 | int len = 1; | 126 | int len = 1; |
127 | __u16 src_char; | ||
128 | |||
129 | src_char = *from; | ||
162 | 130 | ||
163 | if ((maptype == SFM_MAP_UNI_RSVD) && convert_sfm_char(src_char, target)) | 131 | if ((maptype == SFM_MAP_UNI_RSVD) && convert_sfm_char(src_char, target)) |
164 | return len; | 132 | return len; |
@@ -168,10 +136,23 @@ cifs_mapchar(char *target, const __u16 src_char, const struct nls_table *cp, | |||
168 | 136 | ||
169 | /* if character not one of seven in special remap set */ | 137 | /* if character not one of seven in special remap set */ |
170 | len = cp->uni2char(src_char, target, NLS_MAX_CHARSET_SIZE); | 138 | len = cp->uni2char(src_char, target, NLS_MAX_CHARSET_SIZE); |
171 | if (len <= 0) { | 139 | if (len <= 0) |
172 | *target = '?'; | 140 | goto surrogate_pair; |
173 | len = 1; | 141 | |
174 | } | 142 | return len; |
143 | |||
144 | surrogate_pair: | ||
145 | /* convert SURROGATE_PAIR and IVS */ | ||
146 | if (strcmp(cp->charset, "utf8")) | ||
147 | goto unknown; | ||
148 | len = utf16s_to_utf8s(from, 3, UTF16_LITTLE_ENDIAN, target, 6); | ||
149 | if (len <= 0) | ||
150 | goto unknown; | ||
151 | return len; | ||
152 | |||
153 | unknown: | ||
154 | *target = '?'; | ||
155 | len = 1; | ||
175 | return len; | 156 | return len; |
176 | } | 157 | } |
177 | 158 | ||
@@ -206,7 +187,7 @@ cifs_from_utf16(char *to, const __le16 *from, int tolen, int fromlen, | |||
206 | int nullsize = nls_nullsize(codepage); | 187 | int nullsize = nls_nullsize(codepage); |
207 | int fromwords = fromlen / 2; | 188 | int fromwords = fromlen / 2; |
208 | char tmp[NLS_MAX_CHARSET_SIZE]; | 189 | char tmp[NLS_MAX_CHARSET_SIZE]; |
209 | __u16 ftmp; | 190 | __u16 ftmp[3]; /* ftmp[3] = 3array x 2bytes = 6bytes UTF-16 */ |
210 | 191 | ||
211 | /* | 192 | /* |
212 | * because the chars can be of varying widths, we need to take care | 193 | * because the chars can be of varying widths, we need to take care |
@@ -217,9 +198,17 @@ cifs_from_utf16(char *to, const __le16 *from, int tolen, int fromlen, | |||
217 | safelen = tolen - (NLS_MAX_CHARSET_SIZE + nullsize); | 198 | safelen = tolen - (NLS_MAX_CHARSET_SIZE + nullsize); |
218 | 199 | ||
219 | for (i = 0; i < fromwords; i++) { | 200 | for (i = 0; i < fromwords; i++) { |
220 | ftmp = get_unaligned_le16(&from[i]); | 201 | ftmp[0] = get_unaligned_le16(&from[i]); |
221 | if (ftmp == 0) | 202 | if (ftmp[0] == 0) |
222 | break; | 203 | break; |
204 | if (i + 1 < fromwords) | ||
205 | ftmp[1] = get_unaligned_le16(&from[i + 1]); | ||
206 | else | ||
207 | ftmp[1] = 0; | ||
208 | if (i + 2 < fromwords) | ||
209 | ftmp[2] = get_unaligned_le16(&from[i + 2]); | ||
210 | else | ||
211 | ftmp[2] = 0; | ||
223 | 212 | ||
224 | /* | 213 | /* |
225 | * check to see if converting this character might make the | 214 | * check to see if converting this character might make the |
@@ -234,6 +223,17 @@ cifs_from_utf16(char *to, const __le16 *from, int tolen, int fromlen, | |||
234 | /* put converted char into 'to' buffer */ | 223 | /* put converted char into 'to' buffer */ |
235 | charlen = cifs_mapchar(&to[outlen], ftmp, codepage, map_type); | 224 | charlen = cifs_mapchar(&to[outlen], ftmp, codepage, map_type); |
236 | outlen += charlen; | 225 | outlen += charlen; |
226 | |||
227 | /* charlen (=bytes of UTF-8 for 1 character) | ||
228 | * 4bytes UTF-8(surrogate pair) is charlen=4 | ||
229 | * (4bytes UTF-16 code) | ||
230 | * 7-8bytes UTF-8(IVS) is charlen=3+4 or 4+4 | ||
231 | * (2 UTF-8 pairs divided to 2 UTF-16 pairs) */ | ||
232 | if (charlen == 4) | ||
233 | i++; | ||
234 | else if (charlen >= 5) | ||
235 | /* 5-6bytes UTF-8 */ | ||
236 | i += 2; | ||
237 | } | 237 | } |
238 | 238 | ||
239 | /* properly null-terminate string */ | 239 | /* properly null-terminate string */ |
@@ -296,6 +296,46 @@ success: | |||
296 | } | 296 | } |
297 | 297 | ||
298 | /* | 298 | /* |
299 | * cifs_utf16_bytes - how long will a string be after conversion? | ||
300 | * @utf16 - pointer to input string | ||
301 | * @maxbytes - don't go past this many bytes of input string | ||
302 | * @codepage - destination codepage | ||
303 | * | ||
304 | * Walk a utf16le string and return the number of bytes that the string will | ||
305 | * be after being converted to the given charset, not including any null | ||
306 | * termination required. Don't walk past maxbytes in the source buffer. | ||
307 | */ | ||
308 | int | ||
309 | cifs_utf16_bytes(const __le16 *from, int maxbytes, | ||
310 | const struct nls_table *codepage) | ||
311 | { | ||
312 | int i; | ||
313 | int charlen, outlen = 0; | ||
314 | int maxwords = maxbytes / 2; | ||
315 | char tmp[NLS_MAX_CHARSET_SIZE]; | ||
316 | __u16 ftmp[3]; | ||
317 | |||
318 | for (i = 0; i < maxwords; i++) { | ||
319 | ftmp[0] = get_unaligned_le16(&from[i]); | ||
320 | if (ftmp[0] == 0) | ||
321 | break; | ||
322 | if (i + 1 < maxwords) | ||
323 | ftmp[1] = get_unaligned_le16(&from[i + 1]); | ||
324 | else | ||
325 | ftmp[1] = 0; | ||
326 | if (i + 2 < maxwords) | ||
327 | ftmp[2] = get_unaligned_le16(&from[i + 2]); | ||
328 | else | ||
329 | ftmp[2] = 0; | ||
330 | |||
331 | charlen = cifs_mapchar(tmp, ftmp, codepage, NO_MAP_UNI_RSVD); | ||
332 | outlen += charlen; | ||
333 | } | ||
334 | |||
335 | return outlen; | ||
336 | } | ||
337 | |||
338 | /* | ||
299 | * cifs_strndup_from_utf16 - copy a string from wire format to the local | 339 | * cifs_strndup_from_utf16 - copy a string from wire format to the local |
300 | * codepage | 340 | * codepage |
301 | * @src - source string | 341 | * @src - source string |
@@ -409,10 +449,15 @@ cifsConvertToUTF16(__le16 *target, const char *source, int srclen, | |||
409 | char src_char; | 449 | char src_char; |
410 | __le16 dst_char; | 450 | __le16 dst_char; |
411 | wchar_t tmp; | 451 | wchar_t tmp; |
452 | wchar_t *wchar_to; /* UTF-16 */ | ||
453 | int ret; | ||
454 | unicode_t u; | ||
412 | 455 | ||
413 | if (map_chars == NO_MAP_UNI_RSVD) | 456 | if (map_chars == NO_MAP_UNI_RSVD) |
414 | return cifs_strtoUTF16(target, source, PATH_MAX, cp); | 457 | return cifs_strtoUTF16(target, source, PATH_MAX, cp); |
415 | 458 | ||
459 | wchar_to = kzalloc(6, GFP_KERNEL); | ||
460 | |||
416 | for (i = 0; i < srclen; j++) { | 461 | for (i = 0; i < srclen; j++) { |
417 | src_char = source[i]; | 462 | src_char = source[i]; |
418 | charlen = 1; | 463 | charlen = 1; |
@@ -441,11 +486,55 @@ cifsConvertToUTF16(__le16 *target, const char *source, int srclen, | |||
441 | * if no match, use question mark, which at least in | 486 | * if no match, use question mark, which at least in |
442 | * some cases serves as wild card | 487 | * some cases serves as wild card |
443 | */ | 488 | */ |
444 | if (charlen < 1) { | 489 | if (charlen > 0) |
445 | dst_char = cpu_to_le16(0x003f); | 490 | goto ctoUTF16; |
446 | charlen = 1; | 491 | |
492 | /* convert SURROGATE_PAIR */ | ||
493 | if (strcmp(cp->charset, "utf8") || !wchar_to) | ||
494 | goto unknown; | ||
495 | if (*(source + i) & 0x80) { | ||
496 | charlen = utf8_to_utf32(source + i, 6, &u); | ||
497 | if (charlen < 0) | ||
498 | goto unknown; | ||
499 | } else | ||
500 | goto unknown; | ||
501 | ret = utf8s_to_utf16s(source + i, charlen, | ||
502 | UTF16_LITTLE_ENDIAN, | ||
503 | wchar_to, 6); | ||
504 | if (ret < 0) | ||
505 | goto unknown; | ||
506 | |||
507 | i += charlen; | ||
508 | dst_char = cpu_to_le16(*wchar_to); | ||
509 | if (charlen <= 3) | ||
510 | /* 1-3bytes UTF-8 to 2bytes UTF-16 */ | ||
511 | put_unaligned(dst_char, &target[j]); | ||
512 | else if (charlen == 4) { | ||
513 | /* 4bytes UTF-8(surrogate pair) to 4bytes UTF-16 | ||
514 | * 7-8bytes UTF-8(IVS) divided to 2 UTF-16 | ||
515 | * (charlen=3+4 or 4+4) */ | ||
516 | put_unaligned(dst_char, &target[j]); | ||
517 | dst_char = cpu_to_le16(*(wchar_to + 1)); | ||
518 | j++; | ||
519 | put_unaligned(dst_char, &target[j]); | ||
520 | } else if (charlen >= 5) { | ||
521 | /* 5-6bytes UTF-8 to 6bytes UTF-16 */ | ||
522 | put_unaligned(dst_char, &target[j]); | ||
523 | dst_char = cpu_to_le16(*(wchar_to + 1)); | ||
524 | j++; | ||
525 | put_unaligned(dst_char, &target[j]); | ||
526 | dst_char = cpu_to_le16(*(wchar_to + 2)); | ||
527 | j++; | ||
528 | put_unaligned(dst_char, &target[j]); | ||
447 | } | 529 | } |
530 | continue; | ||
531 | |||
532 | unknown: | ||
533 | dst_char = cpu_to_le16(0x003f); | ||
534 | charlen = 1; | ||
448 | } | 535 | } |
536 | |||
537 | ctoUTF16: | ||
449 | /* | 538 | /* |
450 | * character may take more than one byte in the source string, | 539 | * character may take more than one byte in the source string, |
451 | * but will take exactly two bytes in the target string | 540 | * but will take exactly two bytes in the target string |
@@ -456,6 +545,7 @@ cifsConvertToUTF16(__le16 *target, const char *source, int srclen, | |||
456 | 545 | ||
457 | ctoUTF16_out: | 546 | ctoUTF16_out: |
458 | put_unaligned(0, &target[j]); /* Null terminate target unicode string */ | 547 | put_unaligned(0, &target[j]); /* Null terminate target unicode string */ |
548 | kfree(wchar_to); | ||
459 | return j; | 549 | return j; |
460 | } | 550 | } |
461 | 551 | ||
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index f5089bde3635..0a9fb6b53126 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -469,6 +469,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root) | |||
469 | seq_puts(s, ",nouser_xattr"); | 469 | seq_puts(s, ",nouser_xattr"); |
470 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR) | 470 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR) |
471 | seq_puts(s, ",mapchars"); | 471 | seq_puts(s, ",mapchars"); |
472 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SFM_CHR) | ||
473 | seq_puts(s, ",mapposix"); | ||
472 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) | 474 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) |
473 | seq_puts(s, ",sfu"); | 475 | seq_puts(s, ",sfu"); |
474 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | 476 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index c31ce98c1704..c63fd1dde25b 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -361,11 +361,11 @@ extern int CIFSUnixCreateHardLink(const unsigned int xid, | |||
361 | extern int CIFSUnixCreateSymLink(const unsigned int xid, | 361 | extern int CIFSUnixCreateSymLink(const unsigned int xid, |
362 | struct cifs_tcon *tcon, | 362 | struct cifs_tcon *tcon, |
363 | const char *fromName, const char *toName, | 363 | const char *fromName, const char *toName, |
364 | const struct nls_table *nls_codepage); | 364 | const struct nls_table *nls_codepage, int remap); |
365 | extern int CIFSSMBUnixQuerySymLink(const unsigned int xid, | 365 | extern int CIFSSMBUnixQuerySymLink(const unsigned int xid, |
366 | struct cifs_tcon *tcon, | 366 | struct cifs_tcon *tcon, |
367 | const unsigned char *searchName, char **syminfo, | 367 | const unsigned char *searchName, char **syminfo, |
368 | const struct nls_table *nls_codepage); | 368 | const struct nls_table *nls_codepage, int remap); |
369 | extern int CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, | 369 | extern int CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, |
370 | __u16 fid, char **symlinkinfo, | 370 | __u16 fid, char **symlinkinfo, |
371 | const struct nls_table *nls_codepage); | 371 | const struct nls_table *nls_codepage); |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 84650a51c7c4..f26ffbfc64d8 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -2784,7 +2784,7 @@ copyRetry: | |||
2784 | int | 2784 | int |
2785 | CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon, | 2785 | CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon, |
2786 | const char *fromName, const char *toName, | 2786 | const char *fromName, const char *toName, |
2787 | const struct nls_table *nls_codepage) | 2787 | const struct nls_table *nls_codepage, int remap) |
2788 | { | 2788 | { |
2789 | TRANSACTION2_SPI_REQ *pSMB = NULL; | 2789 | TRANSACTION2_SPI_REQ *pSMB = NULL; |
2790 | TRANSACTION2_SPI_RSP *pSMBr = NULL; | 2790 | TRANSACTION2_SPI_RSP *pSMBr = NULL; |
@@ -2804,9 +2804,9 @@ createSymLinkRetry: | |||
2804 | 2804 | ||
2805 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 2805 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { |
2806 | name_len = | 2806 | name_len = |
2807 | cifs_strtoUTF16((__le16 *) pSMB->FileName, fromName, | 2807 | cifsConvertToUTF16((__le16 *) pSMB->FileName, fromName, |
2808 | /* find define for this maxpathcomponent */ | 2808 | /* find define for this maxpathcomponent */ |
2809 | PATH_MAX, nls_codepage); | 2809 | PATH_MAX, nls_codepage, remap); |
2810 | name_len++; /* trailing null */ | 2810 | name_len++; /* trailing null */ |
2811 | name_len *= 2; | 2811 | name_len *= 2; |
2812 | 2812 | ||
@@ -2828,9 +2828,9 @@ createSymLinkRetry: | |||
2828 | data_offset = (char *) (&pSMB->hdr.Protocol) + offset; | 2828 | data_offset = (char *) (&pSMB->hdr.Protocol) + offset; |
2829 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 2829 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { |
2830 | name_len_target = | 2830 | name_len_target = |
2831 | cifs_strtoUTF16((__le16 *) data_offset, toName, PATH_MAX | 2831 | cifsConvertToUTF16((__le16 *) data_offset, toName, |
2832 | /* find define for this maxpathcomponent */ | 2832 | /* find define for this maxpathcomponent */ |
2833 | , nls_codepage); | 2833 | PATH_MAX, nls_codepage, remap); |
2834 | name_len_target++; /* trailing null */ | 2834 | name_len_target++; /* trailing null */ |
2835 | name_len_target *= 2; | 2835 | name_len_target *= 2; |
2836 | } else { /* BB improve the check for buffer overruns BB */ | 2836 | } else { /* BB improve the check for buffer overruns BB */ |
@@ -3034,7 +3034,7 @@ winCreateHardLinkRetry: | |||
3034 | int | 3034 | int |
3035 | CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, | 3035 | CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, |
3036 | const unsigned char *searchName, char **symlinkinfo, | 3036 | const unsigned char *searchName, char **symlinkinfo, |
3037 | const struct nls_table *nls_codepage) | 3037 | const struct nls_table *nls_codepage, int remap) |
3038 | { | 3038 | { |
3039 | /* SMB_QUERY_FILE_UNIX_LINK */ | 3039 | /* SMB_QUERY_FILE_UNIX_LINK */ |
3040 | TRANSACTION2_QPI_REQ *pSMB = NULL; | 3040 | TRANSACTION2_QPI_REQ *pSMB = NULL; |
@@ -3055,8 +3055,9 @@ querySymLinkRetry: | |||
3055 | 3055 | ||
3056 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 3056 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { |
3057 | name_len = | 3057 | name_len = |
3058 | cifs_strtoUTF16((__le16 *) pSMB->FileName, searchName, | 3058 | cifsConvertToUTF16((__le16 *) pSMB->FileName, |
3059 | PATH_MAX, nls_codepage); | 3059 | searchName, PATH_MAX, nls_codepage, |
3060 | remap); | ||
3060 | name_len++; /* trailing null */ | 3061 | name_len++; /* trailing null */ |
3061 | name_len *= 2; | 3062 | name_len *= 2; |
3062 | } else { /* BB improve the check for buffer overruns BB */ | 3063 | } else { /* BB improve the check for buffer overruns BB */ |
@@ -4917,7 +4918,7 @@ getDFSRetry: | |||
4917 | strncpy(pSMB->RequestFileName, search_name, name_len); | 4918 | strncpy(pSMB->RequestFileName, search_name, name_len); |
4918 | } | 4919 | } |
4919 | 4920 | ||
4920 | if (ses->server && ses->server->sign) | 4921 | if (ses->server->sign) |
4921 | pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | 4922 | pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; |
4922 | 4923 | ||
4923 | pSMB->hdr.Uid = ses->Suid; | 4924 | pSMB->hdr.Uid = ses->Suid; |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index f3bfe08e177b..8383d5ea4202 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -386,6 +386,7 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
386 | rc = generic_ip_connect(server); | 386 | rc = generic_ip_connect(server); |
387 | if (rc) { | 387 | if (rc) { |
388 | cifs_dbg(FYI, "reconnect error %d\n", rc); | 388 | cifs_dbg(FYI, "reconnect error %d\n", rc); |
389 | mutex_unlock(&server->srv_mutex); | ||
389 | msleep(3000); | 390 | msleep(3000); |
390 | } else { | 391 | } else { |
391 | atomic_inc(&tcpSesReconnectCount); | 392 | atomic_inc(&tcpSesReconnectCount); |
@@ -393,8 +394,8 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
393 | if (server->tcpStatus != CifsExiting) | 394 | if (server->tcpStatus != CifsExiting) |
394 | server->tcpStatus = CifsNeedNegotiate; | 395 | server->tcpStatus = CifsNeedNegotiate; |
395 | spin_unlock(&GlobalMid_Lock); | 396 | spin_unlock(&GlobalMid_Lock); |
397 | mutex_unlock(&server->srv_mutex); | ||
396 | } | 398 | } |
397 | mutex_unlock(&server->srv_mutex); | ||
398 | } while (server->tcpStatus == CifsNeedReconnect); | 399 | } while (server->tcpStatus == CifsNeedReconnect); |
399 | 400 | ||
400 | return rc; | 401 | return rc; |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 338d56936f6a..c3eb998a99bd 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -620,8 +620,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode, | |||
620 | } | 620 | } |
621 | rc = CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args, | 621 | rc = CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args, |
622 | cifs_sb->local_nls, | 622 | cifs_sb->local_nls, |
623 | cifs_sb->mnt_cifs_flags & | 623 | cifs_remap(cifs_sb)); |
624 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
625 | if (rc) | 624 | if (rc) |
626 | goto mknod_out; | 625 | goto mknod_out; |
627 | 626 | ||
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index cafbf10521d5..3f50cee79df9 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -140,8 +140,7 @@ int cifs_posix_open(char *full_path, struct inode **pinode, | |||
140 | posix_flags = cifs_posix_convert_flags(f_flags); | 140 | posix_flags = cifs_posix_convert_flags(f_flags); |
141 | rc = CIFSPOSIXCreate(xid, tcon, posix_flags, mode, pnetfid, presp_data, | 141 | rc = CIFSPOSIXCreate(xid, tcon, posix_flags, mode, pnetfid, presp_data, |
142 | poplock, full_path, cifs_sb->local_nls, | 142 | poplock, full_path, cifs_sb->local_nls, |
143 | cifs_sb->mnt_cifs_flags & | 143 | cifs_remap(cifs_sb)); |
144 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
145 | cifs_put_tlink(tlink); | 144 | cifs_put_tlink(tlink); |
146 | 145 | ||
147 | if (rc) | 146 | if (rc) |
@@ -1553,8 +1552,8 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u32 type, | |||
1553 | rc = server->ops->mand_unlock_range(cfile, flock, xid); | 1552 | rc = server->ops->mand_unlock_range(cfile, flock, xid); |
1554 | 1553 | ||
1555 | out: | 1554 | out: |
1556 | if (flock->fl_flags & FL_POSIX) | 1555 | if (flock->fl_flags & FL_POSIX && !rc) |
1557 | posix_lock_file_wait(file, flock); | 1556 | rc = posix_lock_file_wait(file, flock); |
1558 | return rc; | 1557 | return rc; |
1559 | } | 1558 | } |
1560 | 1559 | ||
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 55b58112d122..f621b44cb800 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -373,8 +373,7 @@ int cifs_get_inode_info_unix(struct inode **pinode, | |||
373 | 373 | ||
374 | /* could have done a find first instead but this returns more info */ | 374 | /* could have done a find first instead but this returns more info */ |
375 | rc = CIFSSMBUnixQPathInfo(xid, tcon, full_path, &find_data, | 375 | rc = CIFSSMBUnixQPathInfo(xid, tcon, full_path, &find_data, |
376 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & | 376 | cifs_sb->local_nls, cifs_remap(cifs_sb)); |
377 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
378 | cifs_put_tlink(tlink); | 377 | cifs_put_tlink(tlink); |
379 | 378 | ||
380 | if (!rc) { | 379 | if (!rc) { |
@@ -402,9 +401,25 @@ int cifs_get_inode_info_unix(struct inode **pinode, | |||
402 | rc = -ENOMEM; | 401 | rc = -ENOMEM; |
403 | } else { | 402 | } else { |
404 | /* we already have inode, update it */ | 403 | /* we already have inode, update it */ |
404 | |||
405 | /* if uniqueid is different, return error */ | ||
406 | if (unlikely(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM && | ||
407 | CIFS_I(*pinode)->uniqueid != fattr.cf_uniqueid)) { | ||
408 | rc = -ESTALE; | ||
409 | goto cgiiu_exit; | ||
410 | } | ||
411 | |||
412 | /* if filetype is different, return error */ | ||
413 | if (unlikely(((*pinode)->i_mode & S_IFMT) != | ||
414 | (fattr.cf_mode & S_IFMT))) { | ||
415 | rc = -ESTALE; | ||
416 | goto cgiiu_exit; | ||
417 | } | ||
418 | |||
405 | cifs_fattr_to_inode(*pinode, &fattr); | 419 | cifs_fattr_to_inode(*pinode, &fattr); |
406 | } | 420 | } |
407 | 421 | ||
422 | cgiiu_exit: | ||
408 | return rc; | 423 | return rc; |
409 | } | 424 | } |
410 | 425 | ||
@@ -839,6 +854,15 @@ cifs_get_inode_info(struct inode **inode, const char *full_path, | |||
839 | if (!*inode) | 854 | if (!*inode) |
840 | rc = -ENOMEM; | 855 | rc = -ENOMEM; |
841 | } else { | 856 | } else { |
857 | /* we already have inode, update it */ | ||
858 | |||
859 | /* if filetype is different, return error */ | ||
860 | if (unlikely(((*inode)->i_mode & S_IFMT) != | ||
861 | (fattr.cf_mode & S_IFMT))) { | ||
862 | rc = -ESTALE; | ||
863 | goto cgii_exit; | ||
864 | } | ||
865 | |||
842 | cifs_fattr_to_inode(*inode, &fattr); | 866 | cifs_fattr_to_inode(*inode, &fattr); |
843 | } | 867 | } |
844 | 868 | ||
@@ -2215,8 +2239,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) | |||
2215 | pTcon = tlink_tcon(tlink); | 2239 | pTcon = tlink_tcon(tlink); |
2216 | rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args, | 2240 | rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args, |
2217 | cifs_sb->local_nls, | 2241 | cifs_sb->local_nls, |
2218 | cifs_sb->mnt_cifs_flags & | 2242 | cifs_remap(cifs_sb)); |
2219 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
2220 | cifs_put_tlink(tlink); | 2243 | cifs_put_tlink(tlink); |
2221 | } | 2244 | } |
2222 | 2245 | ||
diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 252e672d5604..e6c707cc62b3 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c | |||
@@ -717,7 +717,8 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) | |||
717 | rc = create_mf_symlink(xid, pTcon, cifs_sb, full_path, symname); | 717 | rc = create_mf_symlink(xid, pTcon, cifs_sb, full_path, symname); |
718 | else if (pTcon->unix_ext) | 718 | else if (pTcon->unix_ext) |
719 | rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname, | 719 | rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname, |
720 | cifs_sb->local_nls); | 720 | cifs_sb->local_nls, |
721 | cifs_remap(cifs_sb)); | ||
721 | /* else | 722 | /* else |
722 | rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName, | 723 | rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName, |
723 | cifs_sb_target->local_nls); */ | 724 | cifs_sb_target->local_nls); */ |
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index b4a47237486b..b1eede3678a9 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c | |||
@@ -90,6 +90,8 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name, | |||
90 | if (dentry) { | 90 | if (dentry) { |
91 | inode = d_inode(dentry); | 91 | inode = d_inode(dentry); |
92 | if (inode) { | 92 | if (inode) { |
93 | if (d_mountpoint(dentry)) | ||
94 | goto out; | ||
93 | /* | 95 | /* |
94 | * If we're generating inode numbers, then we don't | 96 | * If we're generating inode numbers, then we don't |
95 | * want to clobber the existing one with the one that | 97 | * want to clobber the existing one with the one that |
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c index 7bfdd6066276..fc537c29044e 100644 --- a/fs/cifs/smb1ops.c +++ b/fs/cifs/smb1ops.c | |||
@@ -960,7 +960,8 @@ cifs_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, | |||
960 | /* Check for unix extensions */ | 960 | /* Check for unix extensions */ |
961 | if (cap_unix(tcon->ses)) { | 961 | if (cap_unix(tcon->ses)) { |
962 | rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, target_path, | 962 | rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, target_path, |
963 | cifs_sb->local_nls); | 963 | cifs_sb->local_nls, |
964 | cifs_remap(cifs_sb)); | ||
964 | if (rc == -EREMOTE) | 965 | if (rc == -EREMOTE) |
965 | rc = cifs_unix_dfs_readlink(xid, tcon, full_path, | 966 | rc = cifs_unix_dfs_readlink(xid, tcon, full_path, |
966 | target_path, | 967 | target_path, |
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 65cd7a84c8bc..54cbe19d9c08 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c | |||
@@ -110,7 +110,7 @@ smb2_hdr_assemble(struct smb2_hdr *hdr, __le16 smb2_cmd /* command */ , | |||
110 | 110 | ||
111 | /* GLOBAL_CAP_LARGE_MTU will only be set if dialect > SMB2.02 */ | 111 | /* GLOBAL_CAP_LARGE_MTU will only be set if dialect > SMB2.02 */ |
112 | /* See sections 2.2.4 and 3.2.4.1.5 of MS-SMB2 */ | 112 | /* See sections 2.2.4 and 3.2.4.1.5 of MS-SMB2 */ |
113 | if ((tcon->ses) && | 113 | if ((tcon->ses) && (tcon->ses->server) && |
114 | (tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU)) | 114 | (tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU)) |
115 | hdr->CreditCharge = cpu_to_le16(1); | 115 | hdr->CreditCharge = cpu_to_le16(1); |
116 | /* else CreditCharge MBZ */ | 116 | /* else CreditCharge MBZ */ |