Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag '6.6-rc-smb3-client-fixes-part1' of git://git.samba.org/sfrench/cifs-2.6

Pull smb client updates from Steve French:

- fixes for excessive stack usage

- multichannel reconnect improvements

- DFS fix and cleanup patches

- move UCS-2 conversion code to fs/nls and update cifs and jfs to use
them

- cleanup patch for compounding, one to fix confusing function name

- inode number collision fix

- reparse point fixes (including avoiding an extra unneeded query on
symlinks) and a minor cleanup

- directory lease (caching) improvement

* tag '6.6-rc-smb3-client-fixes-part1' of git://git.samba.org/sfrench/cifs-2.6: (24 commits)
fs/jfs: Use common ucs2 upper case table
fs/smb/client: Use common code in client
fs/smb: Swing unicode common code from smb->NLS
fs/smb: Remove unicode 'lower' tables
SMB3: rename macro CIFS_SERVER_IS_CHAN to avoid confusion
[SMB3] send channel sequence number in SMB3 requests after reconnects
cifs: update desired access while requesting for directory lease
smb: client: reduce stack usage in smb2_query_reparse_point()
smb: client: reduce stack usage in smb2_query_info_compound()
smb: client: reduce stack usage in smb2_set_ea()
smb: client: reduce stack usage in smb_send_rqst()
smb: client: reduce stack usage in cifs_demultiplex_thread()
smb: client: reduce stack usage in cifs_try_adding_channels()
smb: cilent: set reparse mount points as automounts
smb: client: query reparse points in older dialects
smb: client: do not query reparse points twice on symlinks
smb: client: parse reparse point flag in create response
smb: client: get rid of dfs code dep in namespace.c
smb: client: get rid of dfs naming in automount code
smb: client: rename cifs_dfs_ref.c to namespace.c
...

+1384 -2028
+1
fs/jfs/Kconfig
··· 3 3 tristate "JFS filesystem support" 4 4 select BUFFER_HEAD 5 5 select NLS 6 + select NLS_UCS2_UTILS 6 7 select CRC32 7 8 select LEGACY_DIRECT_IO 8 9 help
+1 -1
fs/jfs/Makefile
··· 9 9 jfs_xtree.o jfs_imap.o jfs_debug.o jfs_dmap.o \ 10 10 jfs_unicode.o jfs_dtree.o jfs_inode.o jfs_discard.o \ 11 11 jfs_extent.o symlink.o jfs_metapage.o \ 12 - jfs_logmgr.o jfs_txnmgr.o jfs_uniupr.o \ 12 + jfs_logmgr.o jfs_txnmgr.o \ 13 13 resize.o xattr.o ioctl.o 14 14 15 15 jfs-$(CONFIG_JFS_POSIX_ACL) += acl.o
+5 -12
fs/jfs/jfs_unicode.h
··· 8 8 9 9 #include <linux/slab.h> 10 10 #include <asm/byteorder.h> 11 + #include "../nls/nls_ucs2_data.h" 11 12 #include "jfs_types.h" 12 13 13 - typedef struct { 14 - wchar_t start; 15 - wchar_t end; 16 - signed char *table; 17 - } UNICASERANGE; 18 - 19 - extern signed char UniUpperTable[512]; 20 - extern UNICASERANGE UniUpperRange[]; 21 14 extern int get_UCSname(struct component_name *, struct dentry *); 22 15 extern int jfs_strfromUCS_le(char *, const __le16 *, int, struct nls_table *); 23 16 ··· 100 107 */ 101 108 static inline wchar_t UniToupper(wchar_t uc) 102 109 { 103 - UNICASERANGE *rp; 110 + const struct UniCaseRange *rp; 104 111 105 - if (uc < sizeof(UniUpperTable)) { /* Latin characters */ 106 - return uc + UniUpperTable[uc]; /* Use base tables */ 112 + if (uc < sizeof(NlsUniUpperTable)) { /* Latin characters */ 113 + return uc + NlsUniUpperTable[uc]; /* Use base tables */ 107 114 } else { 108 - rp = UniUpperRange; /* Use range tables */ 115 + rp = NlsUniUpperRange; /* Use range tables */ 109 116 while (rp->start) { 110 117 if (uc < rp->start) /* Before start of range */ 111 118 return uc; /* Uppercase = input */
-121
fs/jfs/jfs_uniupr.c
··· 1 - // SPDX-License-Identifier: GPL-2.0-or-later 2 - /* 3 - * Copyright (C) International Business Machines Corp., 2000-2002 4 - */ 5 - 6 - #include <linux/fs.h> 7 - #include "jfs_unicode.h" 8 - 9 - /* 10 - * Latin upper case 11 - */ 12 - signed char UniUpperTable[512] = { 13 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 000-00f */ 14 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 010-01f */ 15 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 020-02f */ 16 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 030-03f */ 17 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 040-04f */ 18 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 050-05f */ 19 - 0,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* 060-06f */ 20 - -32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, 0, 0, 0, 0, 0, /* 070-07f */ 21 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 080-08f */ 22 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 090-09f */ 23 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0a0-0af */ 24 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0b0-0bf */ 25 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0c0-0cf */ 26 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0d0-0df */ 27 - -32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* 0e0-0ef */ 28 - -32,-32,-32,-32,-32,-32,-32, 0,-32,-32,-32,-32,-32,-32,-32,121, /* 0f0-0ff */ 29 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 100-10f */ 30 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 110-11f */ 31 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 120-12f */ 32 - 0, 0, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, 0, /* 130-13f */ 33 - -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, /* 140-14f */ 34 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 150-15f */ 35 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 160-16f */ 36 - 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, 0, /* 170-17f */ 37 - 0, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, /* 180-18f */ 38 - 0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, /* 190-19f */ 39 - 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, /* 1a0-1af */ 40 - -1, 0, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, /* 1b0-1bf */ 41 - 0, 0, 0, 0, 0, -1, -2, 0, -1, -2, 0, -1, -2, 0, -1, 0, /* 1c0-1cf */ 42 - -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1,-79, 0, -1, /* 1d0-1df */ 43 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e0-1ef */ 44 - 0, 0, -1, -2, 0, -1, 0, 0, 0, -1, 0, -1, 0, -1, 0, -1, /* 1f0-1ff */ 45 - }; 46 - 47 - /* Upper case range - Greek */ 48 - static signed char UniCaseRangeU03a0[47] = { 49 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-38,-37,-37,-37, /* 3a0-3af */ 50 - 0,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* 3b0-3bf */ 51 - -32,-32,-31,-32,-32,-32,-32,-32,-32,-32,-32,-32,-64,-63,-63, 52 - }; 53 - 54 - /* Upper case range - Cyrillic */ 55 - static signed char UniCaseRangeU0430[48] = { 56 - -32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* 430-43f */ 57 - -32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* 440-44f */ 58 - 0,-80,-80,-80,-80,-80,-80,-80,-80,-80,-80,-80,-80, 0,-80,-80, /* 450-45f */ 59 - }; 60 - 61 - /* Upper case range - Extended cyrillic */ 62 - static signed char UniCaseRangeU0490[61] = { 63 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 490-49f */ 64 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 4a0-4af */ 65 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 4b0-4bf */ 66 - 0, 0, -1, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1, 67 - }; 68 - 69 - /* Upper case range - Extended latin and greek */ 70 - static signed char UniCaseRangeU1e00[509] = { 71 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e00-1e0f */ 72 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e10-1e1f */ 73 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e20-1e2f */ 74 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e30-1e3f */ 75 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e40-1e4f */ 76 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e50-1e5f */ 77 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e60-1e6f */ 78 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e70-1e7f */ 79 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e80-1e8f */ 80 - 0, -1, 0, -1, 0, -1, 0, 0, 0, 0, 0,-59, 0, -1, 0, -1, /* 1e90-1e9f */ 81 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ea0-1eaf */ 82 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1eb0-1ebf */ 83 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ec0-1ecf */ 84 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ed0-1edf */ 85 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ee0-1eef */ 86 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, 0, 0, 0, 0, /* 1ef0-1eff */ 87 - 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f00-1f0f */ 88 - 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f10-1f1f */ 89 - 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f20-1f2f */ 90 - 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f30-1f3f */ 91 - 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f40-1f4f */ 92 - 0, 8, 0, 8, 0, 8, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f50-1f5f */ 93 - 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f60-1f6f */ 94 - 74, 74, 86, 86, 86, 86,100,100, 0, 0,112,112,126,126, 0, 0, /* 1f70-1f7f */ 95 - 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f80-1f8f */ 96 - 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f90-1f9f */ 97 - 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fa0-1faf */ 98 - 8, 8, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fb0-1fbf */ 99 - 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fc0-1fcf */ 100 - 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fd0-1fdf */ 101 - 8, 8, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fe0-1fef */ 102 - 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103 - }; 104 - 105 - /* Upper case range - Wide latin */ 106 - static signed char UniCaseRangeUff40[27] = { 107 - 0,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* ff40-ff4f */ 108 - -32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, 109 - }; 110 - 111 - /* 112 - * Upper Case Range 113 - */ 114 - UNICASERANGE UniUpperRange[] = { 115 - { 0x03a0, 0x03ce, UniCaseRangeU03a0 }, 116 - { 0x0430, 0x045f, UniCaseRangeU0430 }, 117 - { 0x0490, 0x04cc, UniCaseRangeU0490 }, 118 - { 0x1e00, 0x1ffc, UniCaseRangeU1e00 }, 119 - { 0xff40, 0xff5a, UniCaseRangeUff40 }, 120 - { 0 } 121 - };
+8
fs/nls/Kconfig
··· 617 617 input/output character sets. Say Y here for the UTF-8 encoding of 618 618 the Unicode/ISO9646 universal character set. 619 619 620 + config NLS_UCS2_UTILS 621 + tristate "NLS UCS-2 UTILS" 622 + help 623 + Set of older UCS-2 conversion utilities and tables used by some 624 + filesystems including SMB/CIFS. This includes upper case conversion 625 + tables. This will automatically be selected when the filesystem 626 + that uses it is selected. 627 + 620 628 endif # NLS
+1
fs/nls/Makefile
··· 54 54 obj-$(CONFIG_NLS_MAC_ROMANIAN) += mac-romanian.o 55 55 obj-$(CONFIG_NLS_MAC_ROMAN) += mac-roman.o 56 56 obj-$(CONFIG_NLS_MAC_TURKISH) += mac-turkish.o 57 + obj-$(CONFIG_NLS_UCS2_UTILS) += nls_ucs2_utils.o
+15
fs/nls/nls_ucs2_data.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 + 3 + #ifndef _NLS_UCS2_DATA_H 4 + #define _NLS_UCS2_DATA_H 5 + 6 + struct UniCaseRange { 7 + wchar_t start; 8 + wchar_t end; 9 + signed char *table; 10 + }; 11 + 12 + extern signed char NlsUniUpperTable[512]; 13 + extern const struct UniCaseRange NlsUniUpperRange[]; 14 + 15 + #endif /* _NLS_UCS2_DATA_H */
+285
fs/nls/nls_ucs2_utils.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 + /* 3 + * Some of the source code in this file came from fs/cifs/cifs_unicode.c 4 + * and then via server/unicode.c 5 + * cifs_unicode: Unicode kernel case support 6 + * 7 + * Function: 8 + * Convert a unicode character to upper or lower case using 9 + * compressed tables. 10 + * 11 + * Copyright (c) International Business Machines Corp., 2000,2009 12 + * 13 + * 14 + * Notes: 15 + * These APIs are based on the C library functions. The semantics 16 + * should match the C functions but with expanded size operands. 17 + * 18 + * The upper/lower functions are based on a table created by mkupr. 19 + * This is a compressed table of upper and lower case conversion. 20 + * 21 + */ 22 + #ifndef _NLS_UCS2_UTILS_H 23 + #define _NLS_UCS2_UTILS_H 24 + 25 + #include <asm/byteorder.h> 26 + #include <linux/types.h> 27 + #include <linux/nls.h> 28 + #include <linux/unicode.h> 29 + #include "nls_ucs2_data.h" 30 + 31 + /* 32 + * Windows maps these to the user defined 16 bit Unicode range since they are 33 + * reserved symbols (along with \ and /), otherwise illegal to store 34 + * in filenames in NTFS 35 + */ 36 + #define UNI_ASTERISK ((__u16)('*' + 0xF000)) 37 + #define UNI_QUESTION ((__u16)('?' + 0xF000)) 38 + #define UNI_COLON ((__u16)(':' + 0xF000)) 39 + #define UNI_GRTRTHAN ((__u16)('>' + 0xF000)) 40 + #define UNI_LESSTHAN ((__u16)('<' + 0xF000)) 41 + #define UNI_PIPE ((__u16)('|' + 0xF000)) 42 + #define UNI_SLASH ((__u16)('\\' + 0xF000)) 43 + 44 + /* 45 + * UniStrcat: Concatenate the second string to the first 46 + * 47 + * Returns: 48 + * Address of the first string 49 + */ 50 + static inline wchar_t *UniStrcat(wchar_t *ucs1, const wchar_t *ucs2) 51 + { 52 + wchar_t *anchor = ucs1; /* save a pointer to start of ucs1 */ 53 + 54 + while (*ucs1++) 55 + /*NULL*/; /* To end of first string */ 56 + ucs1--; /* Return to the null */ 57 + while ((*ucs1++ = *ucs2++)) 58 + /*NULL*/; /* copy string 2 over */ 59 + return anchor; 60 + } 61 + 62 + /* 63 + * UniStrchr: Find a character in a string 64 + * 65 + * Returns: 66 + * Address of first occurrence of character in string 67 + * or NULL if the character is not in the string 68 + */ 69 + static inline wchar_t *UniStrchr(const wchar_t *ucs, wchar_t uc) 70 + { 71 + while ((*ucs != uc) && *ucs) 72 + ucs++; 73 + 74 + if (*ucs == uc) 75 + return (wchar_t *)ucs; 76 + return NULL; 77 + } 78 + 79 + /* 80 + * UniStrcmp: Compare two strings 81 + * 82 + * Returns: 83 + * < 0: First string is less than second 84 + * = 0: Strings are equal 85 + * > 0: First string is greater than second 86 + */ 87 + static inline int UniStrcmp(const wchar_t *ucs1, const wchar_t *ucs2) 88 + { 89 + while ((*ucs1 == *ucs2) && *ucs1) { 90 + ucs1++; 91 + ucs2++; 92 + } 93 + return (int)*ucs1 - (int)*ucs2; 94 + } 95 + 96 + /* 97 + * UniStrcpy: Copy a string 98 + */ 99 + static inline wchar_t *UniStrcpy(wchar_t *ucs1, const wchar_t *ucs2) 100 + { 101 + wchar_t *anchor = ucs1; /* save the start of result string */ 102 + 103 + while ((*ucs1++ = *ucs2++)) 104 + /*NULL*/; 105 + return anchor; 106 + } 107 + 108 + /* 109 + * UniStrlen: Return the length of a string (in 16 bit Unicode chars not bytes) 110 + */ 111 + static inline size_t UniStrlen(const wchar_t *ucs1) 112 + { 113 + int i = 0; 114 + 115 + while (*ucs1++) 116 + i++; 117 + return i; 118 + } 119 + 120 + /* 121 + * UniStrnlen: Return the length (in 16 bit Unicode chars not bytes) of a 122 + * string (length limited) 123 + */ 124 + static inline size_t UniStrnlen(const wchar_t *ucs1, int maxlen) 125 + { 126 + int i = 0; 127 + 128 + while (*ucs1++) { 129 + i++; 130 + if (i >= maxlen) 131 + break; 132 + } 133 + return i; 134 + } 135 + 136 + /* 137 + * UniStrncat: Concatenate length limited string 138 + */ 139 + static inline wchar_t *UniStrncat(wchar_t *ucs1, const wchar_t *ucs2, size_t n) 140 + { 141 + wchar_t *anchor = ucs1; /* save pointer to string 1 */ 142 + 143 + while (*ucs1++) 144 + /*NULL*/; 145 + ucs1--; /* point to null terminator of s1 */ 146 + while (n-- && (*ucs1 = *ucs2)) { /* copy s2 after s1 */ 147 + ucs1++; 148 + ucs2++; 149 + } 150 + *ucs1 = 0; /* Null terminate the result */ 151 + return anchor; 152 + } 153 + 154 + /* 155 + * UniStrncmp: Compare length limited string 156 + */ 157 + static inline int UniStrncmp(const wchar_t *ucs1, const wchar_t *ucs2, size_t n) 158 + { 159 + if (!n) 160 + return 0; /* Null strings are equal */ 161 + while ((*ucs1 == *ucs2) && *ucs1 && --n) { 162 + ucs1++; 163 + ucs2++; 164 + } 165 + return (int)*ucs1 - (int)*ucs2; 166 + } 167 + 168 + /* 169 + * UniStrncmp_le: Compare length limited string - native to little-endian 170 + */ 171 + static inline int 172 + UniStrncmp_le(const wchar_t *ucs1, const wchar_t *ucs2, size_t n) 173 + { 174 + if (!n) 175 + return 0; /* Null strings are equal */ 176 + while ((*ucs1 == __le16_to_cpu(*ucs2)) && *ucs1 && --n) { 177 + ucs1++; 178 + ucs2++; 179 + } 180 + return (int)*ucs1 - (int)__le16_to_cpu(*ucs2); 181 + } 182 + 183 + /* 184 + * UniStrncpy: Copy length limited string with pad 185 + */ 186 + static inline wchar_t *UniStrncpy(wchar_t *ucs1, const wchar_t *ucs2, size_t n) 187 + { 188 + wchar_t *anchor = ucs1; 189 + 190 + while (n-- && *ucs2) /* Copy the strings */ 191 + *ucs1++ = *ucs2++; 192 + 193 + n++; 194 + while (n--) /* Pad with nulls */ 195 + *ucs1++ = 0; 196 + return anchor; 197 + } 198 + 199 + /* 200 + * UniStrncpy_le: Copy length limited string with pad to little-endian 201 + */ 202 + static inline wchar_t *UniStrncpy_le(wchar_t *ucs1, const wchar_t *ucs2, size_t n) 203 + { 204 + wchar_t *anchor = ucs1; 205 + 206 + while (n-- && *ucs2) /* Copy the strings */ 207 + *ucs1++ = __le16_to_cpu(*ucs2++); 208 + 209 + n++; 210 + while (n--) /* Pad with nulls */ 211 + *ucs1++ = 0; 212 + return anchor; 213 + } 214 + 215 + /* 216 + * UniStrstr: Find a string in a string 217 + * 218 + * Returns: 219 + * Address of first match found 220 + * NULL if no matching string is found 221 + */ 222 + static inline wchar_t *UniStrstr(const wchar_t *ucs1, const wchar_t *ucs2) 223 + { 224 + const wchar_t *anchor1 = ucs1; 225 + const wchar_t *anchor2 = ucs2; 226 + 227 + while (*ucs1) { 228 + if (*ucs1 == *ucs2) { 229 + /* Partial match found */ 230 + ucs1++; 231 + ucs2++; 232 + } else { 233 + if (!*ucs2) /* Match found */ 234 + return (wchar_t *)anchor1; 235 + ucs1 = ++anchor1; /* No match */ 236 + ucs2 = anchor2; 237 + } 238 + } 239 + 240 + if (!*ucs2) /* Both end together */ 241 + return (wchar_t *)anchor1; /* Match found */ 242 + return NULL; /* No match */ 243 + } 244 + 245 + #ifndef UNIUPR_NOUPPER 246 + /* 247 + * UniToupper: Convert a unicode character to upper case 248 + */ 249 + static inline wchar_t UniToupper(register wchar_t uc) 250 + { 251 + register const struct UniCaseRange *rp; 252 + 253 + if (uc < sizeof(NlsUniUpperTable)) { 254 + /* Latin characters */ 255 + return uc + NlsUniUpperTable[uc]; /* Use base tables */ 256 + } 257 + 258 + rp = NlsUniUpperRange; /* Use range tables */ 259 + while (rp->start) { 260 + if (uc < rp->start) /* Before start of range */ 261 + return uc; /* Uppercase = input */ 262 + if (uc <= rp->end) /* In range */ 263 + return uc + rp->table[uc - rp->start]; 264 + rp++; /* Try next range */ 265 + } 266 + return uc; /* Past last range */ 267 + } 268 + 269 + /* 270 + * UniStrupr: Upper case a unicode string 271 + */ 272 + static inline __le16 *UniStrupr(register __le16 *upin) 273 + { 274 + register __le16 *up; 275 + 276 + up = upin; 277 + while (*up) { /* For all characters */ 278 + *up = cpu_to_le16(UniToupper(le16_to_cpu(*up))); 279 + up++; 280 + } 281 + return upin; /* Return input pointer */ 282 + } 283 + #endif /* UNIUPR_NOUPPER */ 284 + 285 + #endif /* _NLS_UCS2_UTILS_H */
+1
fs/smb/client/Kconfig
··· 3 3 tristate "SMB3 and CIFS support (advanced network filesystem)" 4 4 depends on INET 5 5 select NLS 6 + select NLS_UCS2_UTILS 6 7 select CRYPTO 7 8 select CRYPTO_MD5 8 9 select CRYPTO_SHA256
+3 -2
fs/smb/client/Makefile
··· 11 11 readdir.o ioctl.o sess.o export.o unc.o winucase.o \ 12 12 smb2ops.o smb2maperror.o smb2transport.o \ 13 13 smb2misc.o smb2pdu.o smb2inode.o smb2file.o cifsacl.o fs_context.o \ 14 - dns_resolve.o cifs_spnego_negtokeninit.asn1.o asn1.o 14 + dns_resolve.o cifs_spnego_negtokeninit.asn1.o asn1.o \ 15 + namespace.o 15 16 16 17 $(obj)/asn1.o: $(obj)/cifs_spnego_negtokeninit.asn1.h 17 18 ··· 22 21 23 22 cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o 24 23 25 - cifs-$(CONFIG_CIFS_DFS_UPCALL) += cifs_dfs_ref.o dfs_cache.o dfs.o 24 + cifs-$(CONFIG_CIFS_DFS_UPCALL) += dfs_cache.o dfs.o 26 25 27 26 cifs-$(CONFIG_CIFS_SWN_UPCALL) += netlink.o cifs_swn.o 28 27
+1 -1
fs/smb/client/cached_dir.c
··· 218 218 .tcon = tcon, 219 219 .path = path, 220 220 .create_options = cifs_create_options(cifs_sb, CREATE_NOT_FILE), 221 - .desired_access = FILE_READ_ATTRIBUTES, 221 + .desired_access = FILE_READ_DATA | FILE_READ_ATTRIBUTES, 222 222 .disposition = FILE_OPEN, 223 223 .fid = pfid, 224 224 };
+1 -1
fs/smb/client/cifs_debug.c
··· 331 331 spin_lock(&cifs_tcp_ses_lock); 332 332 list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) { 333 333 /* channel info will be printed as a part of sessions below */ 334 - if (CIFS_SERVER_IS_CHAN(server)) 334 + if (SERVER_IS_CHAN(server)) 335 335 continue; 336 336 337 337 c++;
+62 -51
fs/smb/client/cifs_dfs_ref.c fs/smb/client/namespace.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0-or-later 2 2 /* 3 - * Contains the CIFS DFS referral mounting routines used for handling 4 - * traversal via DFS junction point 3 + * Contains mounting routines used for handling traversal via SMB junctions. 5 4 * 6 5 * Copyright (c) 2007 Igor Mammedov 7 6 * Copyright (C) International Business Machines Corp., 2008 8 7 * Author(s): Igor Mammedov (niallain@gmail.com) 9 8 * Steve French (sfrench@us.ibm.com) 9 + * Copyright (c) 2023 Paulo Alcantara <palcantara@suse.de> 10 10 */ 11 11 12 12 #include <linux/dcache.h> ··· 19 19 #include "cifsglob.h" 20 20 #include "cifsproto.h" 21 21 #include "cifsfs.h" 22 - #include "dns_resolve.h" 23 22 #include "cifs_debug.h" 24 - #include "dfs.h" 25 23 #include "fs_context.h" 26 24 27 - static LIST_HEAD(cifs_dfs_automount_list); 25 + static LIST_HEAD(cifs_automount_list); 28 26 29 - static void cifs_dfs_expire_automounts(struct work_struct *work); 30 - static DECLARE_DELAYED_WORK(cifs_dfs_automount_task, 31 - cifs_dfs_expire_automounts); 32 - static int cifs_dfs_mountpoint_expiry_timeout = 500 * HZ; 27 + static void cifs_expire_automounts(struct work_struct *work); 28 + static DECLARE_DELAYED_WORK(cifs_automount_task, 29 + cifs_expire_automounts); 30 + static int cifs_mountpoint_expiry_timeout = 500 * HZ; 33 31 34 - static void cifs_dfs_expire_automounts(struct work_struct *work) 32 + static void cifs_expire_automounts(struct work_struct *work) 35 33 { 36 - struct list_head *list = &cifs_dfs_automount_list; 34 + struct list_head *list = &cifs_automount_list; 37 35 38 36 mark_mounts_for_expiry(list); 39 37 if (!list_empty(list)) 40 - schedule_delayed_work(&cifs_dfs_automount_task, 41 - cifs_dfs_mountpoint_expiry_timeout); 38 + schedule_delayed_work(&cifs_automount_task, 39 + cifs_mountpoint_expiry_timeout); 42 40 } 43 41 44 - void cifs_dfs_release_automount_timer(void) 42 + void cifs_release_automount_timer(void) 45 43 { 46 - BUG_ON(!list_empty(&cifs_dfs_automount_list)); 47 - cancel_delayed_work_sync(&cifs_dfs_automount_task); 44 + if (WARN_ON(!list_empty(&cifs_automount_list))) 45 + return; 46 + cancel_delayed_work_sync(&cifs_automount_task); 48 47 } 49 48 50 49 /** ··· 117 118 return dev; 118 119 } 119 120 120 - static int set_dest_addr(struct smb3_fs_context *ctx) 121 + /* Return full path out of a dentry set for automount */ 122 + static char *automount_fullpath(struct dentry *dentry, void *page) 121 123 { 122 - struct sockaddr *addr = (struct sockaddr *)&ctx->dstaddr; 123 - int rc; 124 + struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb); 125 + struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 126 + size_t len; 127 + char *s; 124 128 125 - rc = dns_resolve_server_name_to_ip(ctx->source, addr, NULL); 126 - if (!rc) 127 - cifs_set_port(addr, ctx->port); 128 - return rc; 129 + spin_lock(&tcon->tc_lock); 130 + if (!tcon->origin_fullpath) { 131 + spin_unlock(&tcon->tc_lock); 132 + return build_path_from_dentry_optional_prefix(dentry, 133 + page, 134 + true); 135 + } 136 + spin_unlock(&tcon->tc_lock); 137 + 138 + s = dentry_path_raw(dentry, page, PATH_MAX); 139 + if (IS_ERR(s)) 140 + return s; 141 + /* for root, we want "" */ 142 + if (!s[1]) 143 + s++; 144 + 145 + spin_lock(&tcon->tc_lock); 146 + len = strlen(tcon->origin_fullpath); 147 + if (s < (char *)page + len) { 148 + spin_unlock(&tcon->tc_lock); 149 + return ERR_PTR(-ENAMETOOLONG); 150 + } 151 + 152 + s -= len; 153 + memcpy(s, tcon->origin_fullpath, len); 154 + spin_unlock(&tcon->tc_lock); 155 + convert_delimiter(s, '/'); 156 + 157 + return s; 129 158 } 130 159 131 160 /* 132 161 * Create a vfsmount that we can automount 133 162 */ 134 - static struct vfsmount *cifs_dfs_do_automount(struct path *path) 163 + static struct vfsmount *cifs_do_automount(struct path *path) 135 164 { 136 165 int rc; 137 166 struct dentry *mntpt = path->dentry; 138 167 struct fs_context *fc; 139 - struct cifs_sb_info *cifs_sb; 140 168 void *page = NULL; 141 169 struct smb3_fs_context *ctx, *cur_ctx; 142 170 struct smb3_fs_context tmp; ··· 173 147 if (IS_ROOT(mntpt)) 174 148 return ERR_PTR(-ESTALE); 175 149 176 - /* 177 - * The MSDFS spec states that paths in DFS referral requests and 178 - * responses must be prefixed by a single '\' character instead of 179 - * the double backslashes usually used in the UNC. This function 180 - * gives us the latter, so we must adjust the result. 181 - */ 182 - cifs_sb = CIFS_SB(mntpt->d_sb); 183 - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS) 184 - return ERR_PTR(-EREMOTE); 185 - 186 - cur_ctx = cifs_sb->ctx; 150 + cur_ctx = CIFS_SB(mntpt->d_sb)->ctx; 187 151 188 152 fc = fs_context_for_submount(path->mnt->mnt_sb->s_type, mntpt); 189 153 if (IS_ERR(fc)) ··· 182 166 ctx = smb3_fc2context(fc); 183 167 184 168 page = alloc_dentry_path(); 185 - full_path = dfs_get_automount_devname(mntpt, page); 169 + full_path = automount_fullpath(mntpt, page); 186 170 if (IS_ERR(full_path)) { 187 171 mnt = ERR_CAST(full_path); 188 172 goto out; ··· 212 196 ctx->source = NULL; 213 197 goto out; 214 198 } 215 - cifs_dbg(FYI, "%s: ctx: source=%s UNC=%s prepath=%s dstaddr=%pISpc\n", 216 - __func__, ctx->source, ctx->UNC, ctx->prepath, &ctx->dstaddr); 199 + cifs_dbg(FYI, "%s: ctx: source=%s UNC=%s prepath=%s\n", 200 + __func__, ctx->source, ctx->UNC, ctx->prepath); 217 201 218 - rc = set_dest_addr(ctx); 219 - if (!rc) 220 - mnt = fc_mount(fc); 221 - else 222 - mnt = ERR_PTR(rc); 223 - 202 + mnt = fc_mount(fc); 224 203 out: 225 204 put_fs_context(fc); 226 205 free_dentry_path(page); ··· 225 214 /* 226 215 * Attempt to automount the referral 227 216 */ 228 - struct vfsmount *cifs_dfs_d_automount(struct path *path) 217 + struct vfsmount *cifs_d_automount(struct path *path) 229 218 { 230 219 struct vfsmount *newmnt; 231 220 232 221 cifs_dbg(FYI, "%s: %pd\n", __func__, path->dentry); 233 222 234 - newmnt = cifs_dfs_do_automount(path); 223 + newmnt = cifs_do_automount(path); 235 224 if (IS_ERR(newmnt)) { 236 225 cifs_dbg(FYI, "leaving %s [automount failed]\n" , __func__); 237 226 return newmnt; 238 227 } 239 228 240 229 mntget(newmnt); /* prevent immediate expiration */ 241 - mnt_set_expiry(newmnt, &cifs_dfs_automount_list); 242 - schedule_delayed_work(&cifs_dfs_automount_task, 243 - cifs_dfs_mountpoint_expiry_timeout); 230 + mnt_set_expiry(newmnt, &cifs_automount_list); 231 + schedule_delayed_work(&cifs_automount_task, 232 + cifs_mountpoint_expiry_timeout); 244 233 cifs_dbg(FYI, "leaving %s [ok]\n" , __func__); 245 234 return newmnt; 246 235 } 247 236 248 - const struct inode_operations cifs_dfs_referral_inode_operations = { 237 + const struct inode_operations cifs_namespace_inode_operations = { 249 238 };
-1
fs/smb/client/cifs_unicode.c
··· 8 8 #include <linux/slab.h> 9 9 #include "cifs_fs_sb.h" 10 10 #include "cifs_unicode.h" 11 - #include "cifs_uniupr.h" 12 11 #include "cifspdu.h" 13 12 #include "cifsglob.h" 14 13 #include "cifs_debug.h"
+1 -329
fs/smb/client/cifs_unicode.h
··· 21 21 #include <asm/byteorder.h> 22 22 #include <linux/types.h> 23 23 #include <linux/nls.h> 24 - 25 - #define UNIUPR_NOLOWER /* Example to not expand lower case tables */ 26 - 27 - /* 28 - * Windows maps these to the user defined 16 bit Unicode range since they are 29 - * reserved symbols (along with \ and /), otherwise illegal to store 30 - * in filenames in NTFS 31 - */ 32 - #define UNI_ASTERISK (__u16) ('*' + 0xF000) 33 - #define UNI_QUESTION (__u16) ('?' + 0xF000) 34 - #define UNI_COLON (__u16) (':' + 0xF000) 35 - #define UNI_GRTRTHAN (__u16) ('>' + 0xF000) 36 - #define UNI_LESSTHAN (__u16) ('<' + 0xF000) 37 - #define UNI_PIPE (__u16) ('|' + 0xF000) 38 - #define UNI_SLASH (__u16) ('\\' + 0xF000) 24 + #include "../../nls/nls_ucs2_utils.h" 39 25 40 26 /* 41 27 * Macs use an older "SFM" mapping of the symbols above. Fortunately it does ··· 54 68 #define SFM_MAP_UNI_RSVD 1 55 69 #define SFU_MAP_UNI_RSVD 2 56 70 57 - /* Just define what we want from uniupr.h. We don't want to define the tables 58 - * in each source file. 59 - */ 60 - #ifndef UNICASERANGE_DEFINED 61 - struct UniCaseRange { 62 - wchar_t start; 63 - wchar_t end; 64 - signed char *table; 65 - }; 66 - #endif /* UNICASERANGE_DEFINED */ 67 - 68 - #ifndef UNIUPR_NOUPPER 69 - extern signed char CifsUniUpperTable[512]; 70 - extern const struct UniCaseRange CifsUniUpperRange[]; 71 - #endif /* UNIUPR_NOUPPER */ 72 - 73 - #ifndef UNIUPR_NOLOWER 74 - extern signed char CifsUniLowerTable[512]; 75 - extern const struct UniCaseRange CifsUniLowerRange[]; 76 - #endif /* UNIUPR_NOLOWER */ 77 - 78 71 #ifdef __KERNEL__ 79 72 int cifs_from_utf16(char *to, const __le16 *from, int tolen, int fromlen, 80 73 const struct nls_table *cp, int map_type); ··· 72 107 #endif 73 108 74 109 wchar_t cifs_toupper(wchar_t in); 75 - 76 - /* 77 - * UniStrcat: Concatenate the second string to the first 78 - * 79 - * Returns: 80 - * Address of the first string 81 - */ 82 - static inline __le16 * 83 - UniStrcat(__le16 *ucs1, const __le16 *ucs2) 84 - { 85 - __le16 *anchor = ucs1; /* save a pointer to start of ucs1 */ 86 - 87 - while (*ucs1++) ; /* To end of first string */ 88 - ucs1--; /* Return to the null */ 89 - while ((*ucs1++ = *ucs2++)) ; /* copy string 2 over */ 90 - return anchor; 91 - } 92 - 93 - /* 94 - * UniStrchr: Find a character in a string 95 - * 96 - * Returns: 97 - * Address of first occurrence of character in string 98 - * or NULL if the character is not in the string 99 - */ 100 - static inline wchar_t * 101 - UniStrchr(const wchar_t *ucs, wchar_t uc) 102 - { 103 - while ((*ucs != uc) && *ucs) 104 - ucs++; 105 - 106 - if (*ucs == uc) 107 - return (wchar_t *) ucs; 108 - return NULL; 109 - } 110 - 111 - /* 112 - * UniStrcmp: Compare two strings 113 - * 114 - * Returns: 115 - * < 0: First string is less than second 116 - * = 0: Strings are equal 117 - * > 0: First string is greater than second 118 - */ 119 - static inline int 120 - UniStrcmp(const wchar_t *ucs1, const wchar_t *ucs2) 121 - { 122 - while ((*ucs1 == *ucs2) && *ucs1) { 123 - ucs1++; 124 - ucs2++; 125 - } 126 - return (int) *ucs1 - (int) *ucs2; 127 - } 128 - 129 - /* 130 - * UniStrcpy: Copy a string 131 - */ 132 - static inline wchar_t * 133 - UniStrcpy(wchar_t *ucs1, const wchar_t *ucs2) 134 - { 135 - wchar_t *anchor = ucs1; /* save the start of result string */ 136 - 137 - while ((*ucs1++ = *ucs2++)) ; 138 - return anchor; 139 - } 140 - 141 - /* 142 - * UniStrlen: Return the length of a string (in 16 bit Unicode chars not bytes) 143 - */ 144 - static inline size_t 145 - UniStrlen(const wchar_t *ucs1) 146 - { 147 - int i = 0; 148 - 149 - while (*ucs1++) 150 - i++; 151 - return i; 152 - } 153 - 154 - /* 155 - * UniStrnlen: Return the length (in 16 bit Unicode chars not bytes) of a 156 - * string (length limited) 157 - */ 158 - static inline size_t 159 - UniStrnlen(const wchar_t *ucs1, int maxlen) 160 - { 161 - int i = 0; 162 - 163 - while (*ucs1++) { 164 - i++; 165 - if (i >= maxlen) 166 - break; 167 - } 168 - return i; 169 - } 170 - 171 - /* 172 - * UniStrncat: Concatenate length limited string 173 - */ 174 - static inline wchar_t * 175 - UniStrncat(wchar_t *ucs1, const wchar_t *ucs2, size_t n) 176 - { 177 - wchar_t *anchor = ucs1; /* save pointer to string 1 */ 178 - 179 - while (*ucs1++) ; 180 - ucs1--; /* point to null terminator of s1 */ 181 - while (n-- && (*ucs1 = *ucs2)) { /* copy s2 after s1 */ 182 - ucs1++; 183 - ucs2++; 184 - } 185 - *ucs1 = 0; /* Null terminate the result */ 186 - return (anchor); 187 - } 188 - 189 - /* 190 - * UniStrncmp: Compare length limited string 191 - */ 192 - static inline int 193 - UniStrncmp(const wchar_t *ucs1, const wchar_t *ucs2, size_t n) 194 - { 195 - if (!n) 196 - return 0; /* Null strings are equal */ 197 - while ((*ucs1 == *ucs2) && *ucs1 && --n) { 198 - ucs1++; 199 - ucs2++; 200 - } 201 - return (int) *ucs1 - (int) *ucs2; 202 - } 203 - 204 - /* 205 - * UniStrncmp_le: Compare length limited string - native to little-endian 206 - */ 207 - static inline int 208 - UniStrncmp_le(const wchar_t *ucs1, const wchar_t *ucs2, size_t n) 209 - { 210 - if (!n) 211 - return 0; /* Null strings are equal */ 212 - while ((*ucs1 == __le16_to_cpu(*ucs2)) && *ucs1 && --n) { 213 - ucs1++; 214 - ucs2++; 215 - } 216 - return (int) *ucs1 - (int) __le16_to_cpu(*ucs2); 217 - } 218 - 219 - /* 220 - * UniStrncpy: Copy length limited string with pad 221 - */ 222 - static inline wchar_t * 223 - UniStrncpy(wchar_t *ucs1, const wchar_t *ucs2, size_t n) 224 - { 225 - wchar_t *anchor = ucs1; 226 - 227 - while (n-- && *ucs2) /* Copy the strings */ 228 - *ucs1++ = *ucs2++; 229 - 230 - n++; 231 - while (n--) /* Pad with nulls */ 232 - *ucs1++ = 0; 233 - return anchor; 234 - } 235 - 236 - /* 237 - * UniStrncpy_le: Copy length limited string with pad to little-endian 238 - */ 239 - static inline wchar_t * 240 - UniStrncpy_le(wchar_t *ucs1, const wchar_t *ucs2, size_t n) 241 - { 242 - wchar_t *anchor = ucs1; 243 - 244 - while (n-- && *ucs2) /* Copy the strings */ 245 - *ucs1++ = __le16_to_cpu(*ucs2++); 246 - 247 - n++; 248 - while (n--) /* Pad with nulls */ 249 - *ucs1++ = 0; 250 - return anchor; 251 - } 252 - 253 - /* 254 - * UniStrstr: Find a string in a string 255 - * 256 - * Returns: 257 - * Address of first match found 258 - * NULL if no matching string is found 259 - */ 260 - static inline wchar_t * 261 - UniStrstr(const wchar_t *ucs1, const wchar_t *ucs2) 262 - { 263 - const wchar_t *anchor1 = ucs1; 264 - const wchar_t *anchor2 = ucs2; 265 - 266 - while (*ucs1) { 267 - if (*ucs1 == *ucs2) { 268 - /* Partial match found */ 269 - ucs1++; 270 - ucs2++; 271 - } else { 272 - if (!*ucs2) /* Match found */ 273 - return (wchar_t *) anchor1; 274 - ucs1 = ++anchor1; /* No match */ 275 - ucs2 = anchor2; 276 - } 277 - } 278 - 279 - if (!*ucs2) /* Both end together */ 280 - return (wchar_t *) anchor1; /* Match found */ 281 - return NULL; /* No match */ 282 - } 283 - 284 - #ifndef UNIUPR_NOUPPER 285 - /* 286 - * UniToupper: Convert a unicode character to upper case 287 - */ 288 - static inline wchar_t 289 - UniToupper(register wchar_t uc) 290 - { 291 - register const struct UniCaseRange *rp; 292 - 293 - if (uc < sizeof(CifsUniUpperTable)) { 294 - /* Latin characters */ 295 - return uc + CifsUniUpperTable[uc]; /* Use base tables */ 296 - } else { 297 - rp = CifsUniUpperRange; /* Use range tables */ 298 - while (rp->start) { 299 - if (uc < rp->start) /* Before start of range */ 300 - return uc; /* Uppercase = input */ 301 - if (uc <= rp->end) /* In range */ 302 - return uc + rp->table[uc - rp->start]; 303 - rp++; /* Try next range */ 304 - } 305 - } 306 - return uc; /* Past last range */ 307 - } 308 - 309 - /* 310 - * UniStrupr: Upper case a unicode string 311 - */ 312 - static inline __le16 * 313 - UniStrupr(register __le16 *upin) 314 - { 315 - register __le16 *up; 316 - 317 - up = upin; 318 - while (*up) { /* For all characters */ 319 - *up = cpu_to_le16(UniToupper(le16_to_cpu(*up))); 320 - up++; 321 - } 322 - return upin; /* Return input pointer */ 323 - } 324 - #endif /* UNIUPR_NOUPPER */ 325 - 326 - #ifndef UNIUPR_NOLOWER 327 - /* 328 - * UniTolower: Convert a unicode character to lower case 329 - */ 330 - static inline wchar_t 331 - UniTolower(register wchar_t uc) 332 - { 333 - register const struct UniCaseRange *rp; 334 - 335 - if (uc < sizeof(CifsUniLowerTable)) { 336 - /* Latin characters */ 337 - return uc + CifsUniLowerTable[uc]; /* Use base tables */ 338 - } else { 339 - rp = CifsUniLowerRange; /* Use range tables */ 340 - while (rp->start) { 341 - if (uc < rp->start) /* Before start of range */ 342 - return uc; /* Uppercase = input */ 343 - if (uc <= rp->end) /* In range */ 344 - return uc + rp->table[uc - rp->start]; 345 - rp++; /* Try next range */ 346 - } 347 - } 348 - return uc; /* Past last range */ 349 - } 350 - 351 - /* 352 - * UniStrlwr: Lower case a unicode string 353 - */ 354 - static inline wchar_t * 355 - UniStrlwr(register wchar_t *upin) 356 - { 357 - register wchar_t *up; 358 - 359 - up = upin; 360 - while (*up) { /* For all characters */ 361 - *up = UniTolower(*up); 362 - up++; 363 - } 364 - return upin; /* Return input pointer */ 365 - } 366 - 367 - #endif 368 110 369 111 #endif /* _CIFS_UNICODE_H */
-239
fs/smb/client/cifs_uniupr.h
··· 1 - /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 - /* 3 - * Copyright (c) International Business Machines Corp., 2000,2002 4 - * 5 - * uniupr.h - Unicode compressed case ranges 6 - */ 7 - 8 - #ifndef UNIUPR_NOUPPER 9 - /* 10 - * Latin upper case 11 - */ 12 - signed char CifsUniUpperTable[512] = { 13 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 000-00f */ 14 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 010-01f */ 15 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 020-02f */ 16 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 030-03f */ 17 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 040-04f */ 18 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 050-05f */ 19 - 0, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 060-06f */ 20 - -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, 0, 0, 0, 0, 0, /* 070-07f */ 21 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 080-08f */ 22 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 090-09f */ 23 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0a0-0af */ 24 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0b0-0bf */ 25 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0c0-0cf */ 26 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0d0-0df */ 27 - -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 0e0-0ef */ 28 - -32, -32, -32, -32, -32, -32, -32, 0, -32, -32, -32, -32, -32, -32, -32, 121, /* 0f0-0ff */ 29 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 100-10f */ 30 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 110-11f */ 31 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 120-12f */ 32 - 0, 0, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, 0, /* 130-13f */ 33 - -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, /* 140-14f */ 34 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 150-15f */ 35 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 160-16f */ 36 - 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, 0, /* 170-17f */ 37 - 0, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, /* 180-18f */ 38 - 0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, /* 190-19f */ 39 - 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, /* 1a0-1af */ 40 - -1, 0, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, /* 1b0-1bf */ 41 - 0, 0, 0, 0, 0, -1, -2, 0, -1, -2, 0, -1, -2, 0, -1, 0, /* 1c0-1cf */ 42 - -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, -79, 0, -1, /* 1d0-1df */ 43 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e0-1ef */ 44 - 0, 0, -1, -2, 0, -1, 0, 0, 0, -1, 0, -1, 0, -1, 0, -1, /* 1f0-1ff */ 45 - }; 46 - 47 - /* Upper case range - Greek */ 48 - static signed char UniCaseRangeU03a0[47] = { 49 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -38, -37, -37, -37, /* 3a0-3af */ 50 - 0, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 3b0-3bf */ 51 - -32, -32, -31, -32, -32, -32, -32, -32, -32, -32, -32, -32, -64, 52 - -63, -63, 53 - }; 54 - 55 - /* Upper case range - Cyrillic */ 56 - static signed char UniCaseRangeU0430[48] = { 57 - -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 430-43f */ 58 - -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 440-44f */ 59 - 0, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, 0, -80, -80, /* 450-45f */ 60 - }; 61 - 62 - /* Upper case range - Extended cyrillic */ 63 - static signed char UniCaseRangeU0490[61] = { 64 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 490-49f */ 65 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 4a0-4af */ 66 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 4b0-4bf */ 67 - 0, 0, -1, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1, 68 - }; 69 - 70 - /* Upper case range - Extended latin and greek */ 71 - static signed char UniCaseRangeU1e00[509] = { 72 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e00-1e0f */ 73 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e10-1e1f */ 74 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e20-1e2f */ 75 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e30-1e3f */ 76 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e40-1e4f */ 77 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e50-1e5f */ 78 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e60-1e6f */ 79 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e70-1e7f */ 80 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e80-1e8f */ 81 - 0, -1, 0, -1, 0, -1, 0, 0, 0, 0, 0, -59, 0, -1, 0, -1, /* 1e90-1e9f */ 82 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ea0-1eaf */ 83 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1eb0-1ebf */ 84 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ec0-1ecf */ 85 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ed0-1edf */ 86 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ee0-1eef */ 87 - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, 0, 0, 0, 0, /* 1ef0-1eff */ 88 - 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f00-1f0f */ 89 - 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f10-1f1f */ 90 - 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f20-1f2f */ 91 - 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f30-1f3f */ 92 - 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f40-1f4f */ 93 - 0, 8, 0, 8, 0, 8, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f50-1f5f */ 94 - 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f60-1f6f */ 95 - 74, 74, 86, 86, 86, 86, 100, 100, 0, 0, 112, 112, 126, 126, 0, 0, /* 1f70-1f7f */ 96 - 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f80-1f8f */ 97 - 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f90-1f9f */ 98 - 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fa0-1faf */ 99 - 8, 8, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fb0-1fbf */ 100 - 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fc0-1fcf */ 101 - 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fd0-1fdf */ 102 - 8, 8, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fe0-1fef */ 103 - 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 104 - }; 105 - 106 - /* Upper case range - Wide latin */ 107 - static signed char UniCaseRangeUff40[27] = { 108 - 0, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* ff40-ff4f */ 109 - -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, 110 - }; 111 - 112 - /* 113 - * Upper Case Range 114 - */ 115 - const struct UniCaseRange CifsUniUpperRange[] = { 116 - {0x03a0, 0x03ce, UniCaseRangeU03a0}, 117 - {0x0430, 0x045f, UniCaseRangeU0430}, 118 - {0x0490, 0x04cc, UniCaseRangeU0490}, 119 - {0x1e00, 0x1ffc, UniCaseRangeU1e00}, 120 - {0xff40, 0xff5a, UniCaseRangeUff40}, 121 - {0} 122 - }; 123 - #endif 124 - 125 - #ifndef UNIUPR_NOLOWER 126 - /* 127 - * Latin lower case 128 - */ 129 - signed char CifsUniLowerTable[512] = { 130 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 000-00f */ 131 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 010-01f */ 132 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 020-02f */ 133 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 030-03f */ 134 - 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 040-04f */ 135 - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 0, 0, 0, 0, 0, /* 050-05f */ 136 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 060-06f */ 137 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 070-07f */ 138 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 080-08f */ 139 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 090-09f */ 140 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0a0-0af */ 141 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0b0-0bf */ 142 - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 0c0-0cf */ 143 - 32, 32, 32, 32, 32, 32, 32, 0, 32, 32, 32, 32, 32, 32, 32, 0, /* 0d0-0df */ 144 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0e0-0ef */ 145 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0f0-0ff */ 146 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 100-10f */ 147 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 110-11f */ 148 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 120-12f */ 149 - 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, /* 130-13f */ 150 - 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, /* 140-14f */ 151 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 150-15f */ 152 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 160-16f */ 153 - 1, 0, 1, 0, 1, 0, 1, 0, -121, 1, 0, 1, 0, 1, 0, 0, /* 170-17f */ 154 - 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 79, 0, /* 180-18f */ 155 - 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, /* 190-19f */ 156 - 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, /* 1a0-1af */ 157 - 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, /* 1b0-1bf */ 158 - 0, 0, 0, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 1, 0, 1, /* 1c0-1cf */ 159 - 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, /* 1d0-1df */ 160 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e0-1ef */ 161 - 0, 2, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1f0-1ff */ 162 - }; 163 - 164 - /* Lower case range - Greek */ 165 - static signed char UniCaseRangeL0380[44] = { 166 - 0, 0, 0, 0, 0, 0, 38, 0, 37, 37, 37, 0, 64, 0, 63, 63, /* 380-38f */ 167 - 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 390-39f */ 168 - 32, 32, 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 169 - }; 170 - 171 - /* Lower case range - Cyrillic */ 172 - static signed char UniCaseRangeL0400[48] = { 173 - 0, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 0, 80, 80, /* 400-40f */ 174 - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 410-41f */ 175 - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 420-42f */ 176 - }; 177 - 178 - /* Lower case range - Extended cyrillic */ 179 - static signed char UniCaseRangeL0490[60] = { 180 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 490-49f */ 181 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 4a0-4af */ 182 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 4b0-4bf */ 183 - 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 184 - }; 185 - 186 - /* Lower case range - Extended latin and greek */ 187 - static signed char UniCaseRangeL1e00[504] = { 188 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e00-1e0f */ 189 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e10-1e1f */ 190 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e20-1e2f */ 191 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e30-1e3f */ 192 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e40-1e4f */ 193 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e50-1e5f */ 194 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e60-1e6f */ 195 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e70-1e7f */ 196 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e80-1e8f */ 197 - 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 1e90-1e9f */ 198 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ea0-1eaf */ 199 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1eb0-1ebf */ 200 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ec0-1ecf */ 201 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ed0-1edf */ 202 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ee0-1eef */ 203 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, /* 1ef0-1eff */ 204 - 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f00-1f0f */ 205 - 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, 0, 0, /* 1f10-1f1f */ 206 - 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f20-1f2f */ 207 - 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f30-1f3f */ 208 - 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, 0, 0, /* 1f40-1f4f */ 209 - 0, 0, 0, 0, 0, 0, 0, 0, 0, -8, 0, -8, 0, -8, 0, -8, /* 1f50-1f5f */ 210 - 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f60-1f6f */ 211 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f70-1f7f */ 212 - 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f80-1f8f */ 213 - 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f90-1f9f */ 214 - 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1fa0-1faf */ 215 - 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -74, -74, -9, 0, 0, 0, /* 1fb0-1fbf */ 216 - 0, 0, 0, 0, 0, 0, 0, 0, -86, -86, -86, -86, -9, 0, 0, 0, /* 1fc0-1fcf */ 217 - 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -100, -100, 0, 0, 0, 0, /* 1fd0-1fdf */ 218 - 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -112, -112, -7, 0, 0, 0, /* 1fe0-1fef */ 219 - 0, 0, 0, 0, 0, 0, 0, 0, 220 - }; 221 - 222 - /* Lower case range - Wide latin */ 223 - static signed char UniCaseRangeLff20[27] = { 224 - 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* ff20-ff2f */ 225 - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 226 - }; 227 - 228 - /* 229 - * Lower Case Range 230 - */ 231 - const struct UniCaseRange CifsUniLowerRange[] = { 232 - {0x0380, 0x03ab, UniCaseRangeL0380}, 233 - {0x0400, 0x042f, UniCaseRangeL0400}, 234 - {0x0490, 0x04cb, UniCaseRangeL0490}, 235 - {0x1e00, 0x1ff7, UniCaseRangeL1e00}, 236 - {0xff20, 0xff3a, UniCaseRangeLff20}, 237 - {0} 238 - }; 239 - #endif
+1 -1
fs/smb/client/cifsfs.c
··· 1805 1805 cifs_dbg(NOISY, "exit_smb3\n"); 1806 1806 unregister_filesystem(&cifs_fs_type); 1807 1807 unregister_filesystem(&smb3_fs_type); 1808 - cifs_dfs_release_automount_timer(); 1808 + cifs_release_automount_timer(); 1809 1809 exit_cifs_idmap(); 1810 1810 #ifdef CONFIG_CIFS_SWN_UPCALL 1811 1811 cifs_genl_exit();
+2 -9
fs/smb/client/cifsfs.h
··· 81 81 82 82 extern const struct inode_operations cifs_file_inode_ops; 83 83 extern const struct inode_operations cifs_symlink_inode_ops; 84 - extern const struct inode_operations cifs_dfs_referral_inode_operations; 84 + extern const struct inode_operations cifs_namespace_inode_operations; 85 85 86 86 87 87 /* Functions related to files and directories */ ··· 118 118 extern const struct dentry_operations cifs_dentry_ops; 119 119 extern const struct dentry_operations cifs_ci_dentry_ops; 120 120 121 - #ifdef CONFIG_CIFS_DFS_UPCALL 122 - extern struct vfsmount *cifs_dfs_d_automount(struct path *path); 123 - #else 124 - static inline struct vfsmount *cifs_dfs_d_automount(struct path *path) 125 - { 126 - return ERR_PTR(-EREMOTE); 127 - } 128 - #endif 121 + extern struct vfsmount *cifs_d_automount(struct path *path); 129 122 130 123 /* Functions related to symlinks */ 131 124 extern const char *cifs_get_link(struct dentry *, struct inode *,
+58 -14
fs/smb/client/cifsglob.h
··· 186 186 }; 187 187 188 188 struct cifs_open_info_data { 189 + bool adjust_tz; 190 + union { 191 + bool reparse_point; 192 + bool symlink; 193 + }; 194 + __u32 reparse_tag; 189 195 char *symlink_target; 190 196 union { 191 197 struct smb2_file_all_info fi; 192 198 struct smb311_posix_qinfo posix_fi; 193 199 }; 194 200 }; 201 + 202 + #define cifs_open_data_reparse(d) \ 203 + ((d)->reparse_point || \ 204 + (le32_to_cpu((d)->fi.Attributes) & ATTR_REPARSE)) 195 205 196 206 static inline void cifs_free_open_info(struct cifs_open_info_data *data) 197 207 { ··· 328 318 int (*is_path_accessible)(const unsigned int, struct cifs_tcon *, 329 319 struct cifs_sb_info *, const char *); 330 320 /* query path data from the server */ 331 - int (*query_path_info)(const unsigned int xid, struct cifs_tcon *tcon, 332 - struct cifs_sb_info *cifs_sb, const char *full_path, 333 - struct cifs_open_info_data *data, bool *adjust_tz, bool *reparse); 321 + int (*query_path_info)(const unsigned int xid, 322 + struct cifs_tcon *tcon, 323 + struct cifs_sb_info *cifs_sb, 324 + const char *full_path, 325 + struct cifs_open_info_data *data); 334 326 /* query file data from the server */ 335 327 int (*query_file_info)(const unsigned int xid, struct cifs_tcon *tcon, 336 328 struct cifsFileInfo *cfile, struct cifs_open_info_data *data); 337 - /* query reparse tag from srv to determine which type of special file */ 338 - int (*query_reparse_tag)(const unsigned int xid, struct cifs_tcon *tcon, 339 - struct cifs_sb_info *cifs_sb, const char *path, 340 - __u32 *reparse_tag); 329 + /* query reparse point to determine which type of special file */ 330 + int (*query_reparse_point)(const unsigned int xid, 331 + struct cifs_tcon *tcon, 332 + struct cifs_sb_info *cifs_sb, 333 + const char *full_path, 334 + u32 *tag, struct kvec *rsp, 335 + int *rsp_buftype); 341 336 /* get server index number */ 342 337 int (*get_srv_inum)(const unsigned int xid, struct cifs_tcon *tcon, 343 338 struct cifs_sb_info *cifs_sb, const char *full_path, u64 *uniqueid, ··· 391 376 const char *, const char *, 392 377 struct cifs_sb_info *); 393 378 /* query symlink target */ 394 - int (*query_symlink)(const unsigned int, struct cifs_tcon *, 395 - struct cifs_sb_info *, const char *, 396 - char **, bool); 379 + int (*query_symlink)(const unsigned int xid, 380 + struct cifs_tcon *tcon, 381 + struct cifs_sb_info *cifs_sb, 382 + const char *full_path, 383 + char **target_path, 384 + struct kvec *rsp_iov); 397 385 /* open a file for non-posix mounts */ 398 386 int (*open)(const unsigned int xid, struct cifs_open_parms *oparms, __u32 *oplock, 399 387 void *buf); ··· 745 727 * primary_server holds the ref-counted 746 728 * pointer to primary channel connection for the session. 747 729 */ 748 - #define CIFS_SERVER_IS_CHAN(server) (!!(server)->primary_server) 730 + #define SERVER_IS_CHAN(server) (!!(server)->primary_server) 749 731 struct TCP_Server_Info *primary_server; 732 + __u16 channel_sequence_num; /* incremented on primary channel on each chan reconnect */ 750 733 751 734 #ifdef CONFIG_CIFS_SWN_UPCALL 752 735 bool use_swn_dstaddr; ··· 1095 1076 * inode with new info 1096 1077 */ 1097 1078 1098 - #define CIFS_FATTR_DFS_REFERRAL 0x1 1079 + #define CIFS_FATTR_JUNCTION 0x1 1099 1080 #define CIFS_FATTR_DELETE_PENDING 0x2 1100 1081 #define CIFS_FATTR_NEED_REVAL 0x4 1101 1082 #define CIFS_FATTR_INO_COLLISION 0x8 ··· 1740 1721 struct list_head dfs_ses_list; 1741 1722 }; 1742 1723 1724 + static inline void __free_dfs_info_param(struct dfs_info3_param *param) 1725 + { 1726 + kfree(param->path_name); 1727 + kfree(param->node_name); 1728 + } 1729 + 1743 1730 static inline void free_dfs_info_param(struct dfs_info3_param *param) 1744 1731 { 1732 + if (param) 1733 + __free_dfs_info_param(param); 1734 + } 1735 + 1736 + static inline void zfree_dfs_info_param(struct dfs_info3_param *param) 1737 + { 1745 1738 if (param) { 1746 - kfree(param->path_name); 1747 - kfree(param->node_name); 1739 + __free_dfs_info_param(param); 1740 + memset(param, 0, sizeof(*param)); 1748 1741 } 1749 1742 } 1750 1743 ··· 2214 2183 virt_to_page((void *)addr), buflen, off); 2215 2184 } 2216 2185 } 2186 + 2187 + struct smb2_compound_vars { 2188 + struct cifs_open_parms oparms; 2189 + struct kvec rsp_iov[3]; 2190 + struct smb_rqst rqst[3]; 2191 + struct kvec open_iov[SMB2_CREATE_IOV_SIZE]; 2192 + struct kvec qi_iov; 2193 + struct kvec io_iov[SMB2_IOCTL_IOV_SIZE]; 2194 + struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE]; 2195 + struct kvec close_iov; 2196 + struct smb2_file_rename_info rename_info; 2197 + struct smb2_file_link_info link_info; 2198 + }; 2217 2199 2218 2200 #endif /* _CIFS_GLOB_H */
+4 -5
fs/smb/client/cifsproto.h
··· 207 207 int cifs_get_inode_info(struct inode **inode, const char *full_path, 208 208 struct cifs_open_info_data *data, struct super_block *sb, int xid, 209 209 const struct cifs_fid *fid); 210 + bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb, 211 + struct cifs_fattr *fattr, 212 + u32 tag); 210 213 extern int smb311_posix_get_inode_info(struct inode **pinode, const char *search_path, 211 214 struct super_block *sb, unsigned int xid); 212 215 extern int cifs_get_inode_info_unix(struct inode **pinode, ··· 298 295 int from_reconnect); 299 296 extern void cifs_put_tcon(struct cifs_tcon *tcon); 300 297 301 - #if IS_ENABLED(CONFIG_CIFS_DFS_UPCALL) 302 - extern void cifs_dfs_release_automount_timer(void); 303 - #else /* ! IS_ENABLED(CONFIG_CIFS_DFS_UPCALL) */ 304 - #define cifs_dfs_release_automount_timer() do { } while (0) 305 - #endif /* ! IS_ENABLED(CONFIG_CIFS_DFS_UPCALL) */ 298 + extern void cifs_release_automount_timer(void); 306 299 307 300 void cifs_proc_init(void); 308 301 void cifs_proc_clean(void);
+11 -10
fs/smb/client/connect.c
··· 154 154 int i; 155 155 156 156 /* If server is a channel, select the primary channel */ 157 - pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server; 157 + pserver = SERVER_IS_CHAN(server) ? server->primary_server : server; 158 158 159 159 spin_lock(&pserver->srv_lock); 160 160 if (!all_channels) { ··· 202 202 cifs_dbg(FYI, "%s: marking necessary sessions and tcons for reconnect\n", __func__); 203 203 204 204 /* If server is a channel, select the primary channel */ 205 - pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server; 205 + pserver = SERVER_IS_CHAN(server) ? server->primary_server : server; 206 206 207 207 208 208 spin_lock(&cifs_tcp_ses_lock); ··· 453 453 454 454 static int reconnect_dfs_server(struct TCP_Server_Info *server) 455 455 { 456 - int rc = 0; 457 - struct dfs_cache_tgt_list tl = DFS_CACHE_TGT_LIST_INIT(tl); 458 456 struct dfs_cache_tgt_iterator *target_hint = NULL; 457 + DFS_CACHE_TGT_LIST(tl); 459 458 int num_targets = 0; 459 + int rc = 0; 460 460 461 461 /* 462 462 * Determine the number of dfs targets the referral path in @cifs_sb resolves to. ··· 911 911 return 0; 912 912 } 913 913 914 - 915 - static void clean_demultiplex_info(struct TCP_Server_Info *server) 914 + static noinline_for_stack void 915 + clean_demultiplex_info(struct TCP_Server_Info *server) 916 916 { 917 917 int length; 918 918 ··· 1551 1551 * Skip ses channels since they're only handled in lower layers 1552 1552 * (e.g. cifs_send_recv). 1553 1553 */ 1554 - if (CIFS_SERVER_IS_CHAN(server) || 1554 + if (SERVER_IS_CHAN(server) || 1555 1555 !match_server(server, ctx, false)) { 1556 1556 spin_unlock(&server->srv_lock); 1557 1557 continue; ··· 1587 1587 spin_unlock(&cifs_tcp_ses_lock); 1588 1588 1589 1589 /* For secondary channels, we pick up ref-count on the primary server */ 1590 - if (CIFS_SERVER_IS_CHAN(server)) 1590 + if (SERVER_IS_CHAN(server)) 1591 1591 cifs_put_tcp_session(server->primary_server, from_reconnect); 1592 1592 1593 1593 cancel_delayed_work_sync(&server->echo); ··· 1686 1686 ctx->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL); 1687 1687 tcp_ses->session_estab = false; 1688 1688 tcp_ses->sequence_number = 0; 1689 + tcp_ses->channel_sequence_num = 0; /* only tracked for primary channel */ 1689 1690 tcp_ses->reconnect_instance = 1; 1690 1691 tcp_ses->lstrp = jiffies; 1691 1692 tcp_ses->compress_algorithm = cpu_to_le16(ctx->compression); ··· 1793 1792 1794 1793 out_err: 1795 1794 if (tcp_ses) { 1796 - if (CIFS_SERVER_IS_CHAN(tcp_ses)) 1795 + if (SERVER_IS_CHAN(tcp_ses)) 1797 1796 cifs_put_tcp_session(tcp_ses->primary_server, false); 1798 1797 kfree(tcp_ses->hostname); 1799 1798 kfree(tcp_ses->leaf_fullpath); ··· 3814 3813 struct nls_table *nls_info) 3815 3814 { 3816 3815 int rc = -ENOSYS; 3817 - struct TCP_Server_Info *pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server; 3816 + struct TCP_Server_Info *pserver = SERVER_IS_CHAN(server) ? server->primary_server : server; 3818 3817 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&pserver->dstaddr; 3819 3818 struct sockaddr_in *addr = (struct sockaddr_in *)&pserver->dstaddr; 3820 3819 bool is_binding = false;
+156 -127
fs/smb/client/dfs.c
··· 3 3 * Copyright (c) 2022 Paulo Alcantara <palcantara@suse.de> 4 4 */ 5 5 6 - #include <linux/namei.h> 7 6 #include "cifsproto.h" 8 7 #include "cifs_debug.h" 9 8 #include "dns_resolve.h" ··· 95 96 return 0; 96 97 } 97 98 98 - static int get_dfs_conn(struct cifs_mount_ctx *mnt_ctx, const char *ref_path, const char *full_path, 99 - const struct dfs_cache_tgt_iterator *tit) 99 + static inline int parse_dfs_target(struct smb3_fs_context *ctx, 100 + struct dfs_ref_walk *rw, 101 + struct dfs_info3_param *tgt) 102 + { 103 + int rc; 104 + const char *fpath = ref_walk_fpath(rw) + 1; 105 + 106 + rc = ref_walk_get_tgt(rw, tgt); 107 + if (!rc) 108 + rc = dfs_parse_target_referral(fpath, tgt, ctx); 109 + return rc; 110 + } 111 + 112 + static int set_ref_paths(struct cifs_mount_ctx *mnt_ctx, 113 + struct dfs_info3_param *tgt, 114 + struct dfs_ref_walk *rw) 100 115 { 101 116 struct smb3_fs_context *ctx = mnt_ctx->fs_ctx; 102 - struct dfs_info3_param ref = {}; 103 - bool is_refsrv; 104 - int rc, rc2; 117 + struct cifs_sb_info *cifs_sb = mnt_ctx->cifs_sb; 118 + char *ref_path, *full_path; 119 + int rc; 105 120 106 - rc = dfs_cache_get_tgt_referral(ref_path + 1, tit, &ref); 107 - if (rc) 121 + full_path = smb3_fs_context_fullpath(ctx, CIFS_DIR_SEP(cifs_sb)); 122 + if (IS_ERR(full_path)) 123 + return PTR_ERR(full_path); 124 + 125 + if (!tgt || (tgt->server_type == DFS_TYPE_LINK && 126 + DFS_INTERLINK(tgt->flags))) 127 + ref_path = dfs_get_path(cifs_sb, ctx->UNC); 128 + else 129 + ref_path = dfs_get_path(cifs_sb, full_path); 130 + if (IS_ERR(ref_path)) { 131 + rc = PTR_ERR(ref_path); 132 + kfree(full_path); 108 133 return rc; 109 - 110 - rc = dfs_parse_target_referral(full_path + 1, &ref, ctx); 111 - if (rc) 112 - goto out; 113 - 114 - cifs_mount_put_conns(mnt_ctx); 115 - rc = get_session(mnt_ctx, ref_path); 116 - if (rc) 117 - goto out; 118 - 119 - is_refsrv = !!(ref.flags & DFSREF_REFERRAL_SERVER); 120 - 121 - rc = -EREMOTE; 122 - if (ref.flags & DFSREF_STORAGE_SERVER) { 123 - rc = cifs_mount_get_tcon(mnt_ctx); 124 - if (rc) 125 - goto out; 126 - 127 - /* some servers may not advertise referral capability under ref.flags */ 128 - is_refsrv |= is_tcon_dfs(mnt_ctx->tcon); 129 - 130 - rc = cifs_is_path_remote(mnt_ctx); 131 134 } 135 + ref_walk_path(rw) = ref_path; 136 + ref_walk_fpath(rw) = full_path; 137 + return 0; 138 + } 132 139 133 - dfs_cache_noreq_update_tgthint(ref_path + 1, tit); 140 + static int __dfs_referral_walk(struct cifs_mount_ctx *mnt_ctx, 141 + struct dfs_ref_walk *rw) 142 + { 143 + struct smb3_fs_context *ctx = mnt_ctx->fs_ctx; 144 + struct dfs_info3_param tgt = {}; 145 + bool is_refsrv; 146 + int rc = -ENOENT; 134 147 135 - if (rc == -EREMOTE && is_refsrv) { 136 - rc2 = add_root_smb_session(mnt_ctx); 137 - if (rc2) 138 - rc = rc2; 139 - } 148 + again: 149 + do { 150 + if (ref_walk_empty(rw)) { 151 + rc = dfs_get_referral(mnt_ctx, ref_walk_path(rw) + 1, 152 + NULL, ref_walk_tl(rw)); 153 + if (rc) { 154 + rc = cifs_mount_get_tcon(mnt_ctx); 155 + if (!rc) 156 + rc = cifs_is_path_remote(mnt_ctx); 157 + continue; 158 + } 159 + if (!ref_walk_num_tgts(rw)) { 160 + rc = -ENOENT; 161 + continue; 162 + } 163 + } 164 + 165 + while (ref_walk_next_tgt(rw)) { 166 + rc = parse_dfs_target(ctx, rw, &tgt); 167 + if (rc) 168 + continue; 169 + 170 + cifs_mount_put_conns(mnt_ctx); 171 + rc = get_session(mnt_ctx, ref_walk_path(rw)); 172 + if (rc) 173 + continue; 174 + 175 + is_refsrv = tgt.server_type == DFS_TYPE_ROOT || 176 + DFS_INTERLINK(tgt.flags); 177 + ref_walk_set_tgt_hint(rw); 178 + 179 + if (tgt.flags & DFSREF_STORAGE_SERVER) { 180 + rc = cifs_mount_get_tcon(mnt_ctx); 181 + if (!rc) 182 + rc = cifs_is_path_remote(mnt_ctx); 183 + if (!rc) 184 + break; 185 + if (rc != -EREMOTE) 186 + continue; 187 + } 188 + 189 + if (is_refsrv) { 190 + rc = add_root_smb_session(mnt_ctx); 191 + if (rc) 192 + goto out; 193 + } 194 + 195 + rc = ref_walk_advance(rw); 196 + if (!rc) { 197 + rc = set_ref_paths(mnt_ctx, &tgt, rw); 198 + if (!rc) { 199 + rc = -EREMOTE; 200 + goto again; 201 + } 202 + } 203 + if (rc != -ELOOP) 204 + goto out; 205 + } 206 + } while (rc && ref_walk_descend(rw)); 140 207 141 208 out: 142 - free_dfs_info_param(&ref); 209 + free_dfs_info_param(&tgt); 210 + return rc; 211 + } 212 + 213 + static int dfs_referral_walk(struct cifs_mount_ctx *mnt_ctx) 214 + { 215 + struct dfs_ref_walk *rw; 216 + int rc; 217 + 218 + rw = ref_walk_alloc(); 219 + if (IS_ERR(rw)) 220 + return PTR_ERR(rw); 221 + 222 + ref_walk_init(rw); 223 + rc = set_ref_paths(mnt_ctx, NULL, rw); 224 + if (!rc) 225 + rc = __dfs_referral_walk(mnt_ctx, rw); 226 + ref_walk_free(rw); 143 227 return rc; 144 228 } 145 229 ··· 230 148 { 231 149 struct cifs_sb_info *cifs_sb = mnt_ctx->cifs_sb; 232 150 struct smb3_fs_context *ctx = mnt_ctx->fs_ctx; 233 - char *ref_path = NULL, *full_path = NULL; 234 - struct dfs_cache_tgt_iterator *tit; 235 151 struct cifs_tcon *tcon; 236 - char *origin_fullpath = NULL; 237 - char sep = CIFS_DIR_SEP(cifs_sb); 238 - int num_links = 0; 152 + char *origin_fullpath; 239 153 int rc; 240 154 241 - ref_path = dfs_get_path(cifs_sb, ctx->UNC); 242 - if (IS_ERR(ref_path)) 243 - return PTR_ERR(ref_path); 155 + origin_fullpath = dfs_get_path(cifs_sb, ctx->source); 156 + if (IS_ERR(origin_fullpath)) 157 + return PTR_ERR(origin_fullpath); 244 158 245 - full_path = smb3_fs_context_fullpath(ctx, sep); 246 - if (IS_ERR(full_path)) { 247 - rc = PTR_ERR(full_path); 248 - full_path = NULL; 159 + rc = dfs_referral_walk(mnt_ctx); 160 + if (rc) 249 161 goto out; 162 + 163 + tcon = mnt_ctx->tcon; 164 + spin_lock(&tcon->tc_lock); 165 + if (!tcon->origin_fullpath) { 166 + tcon->origin_fullpath = origin_fullpath; 167 + origin_fullpath = NULL; 250 168 } 169 + spin_unlock(&tcon->tc_lock); 251 170 252 - origin_fullpath = kstrdup(full_path, GFP_KERNEL); 253 - if (!origin_fullpath) { 254 - rc = -ENOMEM; 255 - goto out; 256 - } 257 - 258 - do { 259 - struct dfs_cache_tgt_list tl = DFS_CACHE_TGT_LIST_INIT(tl); 260 - 261 - rc = dfs_get_referral(mnt_ctx, ref_path + 1, NULL, &tl); 262 - if (rc) { 263 - rc = cifs_mount_get_tcon(mnt_ctx); 264 - if (!rc) 265 - rc = cifs_is_path_remote(mnt_ctx); 266 - break; 267 - } 268 - 269 - tit = dfs_cache_get_tgt_iterator(&tl); 270 - if (!tit) { 271 - cifs_dbg(VFS, "%s: dfs referral (%s) with no targets\n", __func__, 272 - ref_path + 1); 273 - rc = -ENOENT; 274 - dfs_cache_free_tgts(&tl); 275 - break; 276 - } 277 - 278 - do { 279 - rc = get_dfs_conn(mnt_ctx, ref_path, full_path, tit); 280 - if (!rc) 281 - break; 282 - if (rc == -EREMOTE) { 283 - if (++num_links > MAX_NESTED_LINKS) { 284 - rc = -ELOOP; 285 - break; 286 - } 287 - kfree(ref_path); 288 - kfree(full_path); 289 - ref_path = full_path = NULL; 290 - 291 - full_path = smb3_fs_context_fullpath(ctx, sep); 292 - if (IS_ERR(full_path)) { 293 - rc = PTR_ERR(full_path); 294 - full_path = NULL; 295 - } else { 296 - ref_path = dfs_get_path(cifs_sb, full_path); 297 - if (IS_ERR(ref_path)) { 298 - rc = PTR_ERR(ref_path); 299 - ref_path = NULL; 300 - } 301 - } 302 - break; 303 - } 304 - } while ((tit = dfs_cache_get_next_tgt(&tl, tit))); 305 - dfs_cache_free_tgts(&tl); 306 - } while (rc == -EREMOTE); 307 - 308 - if (!rc) { 309 - tcon = mnt_ctx->tcon; 310 - 311 - spin_lock(&tcon->tc_lock); 312 - if (!tcon->origin_fullpath) { 313 - tcon->origin_fullpath = origin_fullpath; 314 - origin_fullpath = NULL; 315 - } 316 - spin_unlock(&tcon->tc_lock); 317 - 318 - if (list_empty(&tcon->dfs_ses_list)) { 319 - list_replace_init(&mnt_ctx->dfs_ses_list, 320 - &tcon->dfs_ses_list); 321 - queue_delayed_work(dfscache_wq, &tcon->dfs_cache_work, 322 - dfs_cache_get_ttl() * HZ); 323 - } else { 324 - dfs_put_root_smb_sessions(&mnt_ctx->dfs_ses_list); 325 - } 171 + if (list_empty(&tcon->dfs_ses_list)) { 172 + list_replace_init(&mnt_ctx->dfs_ses_list, &tcon->dfs_ses_list); 173 + queue_delayed_work(dfscache_wq, &tcon->dfs_cache_work, 174 + dfs_cache_get_ttl() * HZ); 175 + } else { 176 + dfs_put_root_smb_sessions(&mnt_ctx->dfs_ses_list); 326 177 } 327 178 328 179 out: 329 180 kfree(origin_fullpath); 330 - kfree(ref_path); 331 - kfree(full_path); 181 + return rc; 182 + } 183 + 184 + /* Resolve UNC hostname in @ctx->source and set ip addr in @ctx->dstaddr */ 185 + static int update_fs_context_dstaddr(struct smb3_fs_context *ctx) 186 + { 187 + struct sockaddr *addr = (struct sockaddr *)&ctx->dstaddr; 188 + int rc; 189 + 190 + rc = dns_resolve_server_name_to_ip(ctx->source, addr, NULL); 191 + if (!rc) 192 + cifs_set_port(addr, ctx->port); 332 193 return rc; 333 194 } 334 195 ··· 280 255 struct smb3_fs_context *ctx = mnt_ctx->fs_ctx; 281 256 bool nodfs = ctx->nodfs; 282 257 int rc; 258 + 259 + rc = update_fs_context_dstaddr(ctx); 260 + if (rc) 261 + return rc; 283 262 284 263 *isdfs = false; 285 264 rc = get_session(mnt_ctx, NULL); ··· 455 426 /* Try to tree connect to all dfs targets */ 456 427 for (; tit; tit = dfs_cache_get_next_tgt(tl, tit)) { 457 428 const char *target = dfs_cache_get_tgt_name(tit); 458 - struct dfs_cache_tgt_list ntl = DFS_CACHE_TGT_LIST_INIT(ntl); 429 + DFS_CACHE_TGT_LIST(ntl); 459 430 460 431 kfree(share); 461 432 kfree(prefix); ··· 549 520 int rc; 550 521 struct TCP_Server_Info *server = tcon->ses->server; 551 522 const struct smb_version_operations *ops = server->ops; 552 - struct dfs_cache_tgt_list tl = DFS_CACHE_TGT_LIST_INIT(tl); 523 + DFS_CACHE_TGT_LIST(tl); 553 524 struct cifs_sb_info *cifs_sb = NULL; 554 525 struct super_block *sb = NULL; 555 526 struct dfs_info3_param ref = {0};
+104 -37
fs/smb/client/dfs.h
··· 9 9 #include "cifsglob.h" 10 10 #include "fs_context.h" 11 11 #include "cifs_unicode.h" 12 + #include <linux/namei.h> 13 + 14 + #define DFS_INTERLINK(v) \ 15 + (((v) & DFSREF_REFERRAL_SERVER) && !((v) & DFSREF_STORAGE_SERVER)) 16 + 17 + struct dfs_ref { 18 + char *path; 19 + char *full_path; 20 + struct dfs_cache_tgt_list tl; 21 + struct dfs_cache_tgt_iterator *tit; 22 + }; 23 + 24 + struct dfs_ref_walk { 25 + struct dfs_ref *ref; 26 + struct dfs_ref refs[MAX_NESTED_LINKS]; 27 + }; 28 + 29 + #define ref_walk_start(w) ((w)->refs) 30 + #define ref_walk_end(w) (&(w)->refs[ARRAY_SIZE((w)->refs) - 1]) 31 + #define ref_walk_cur(w) ((w)->ref) 32 + #define ref_walk_descend(w) (--ref_walk_cur(w) >= ref_walk_start(w)) 33 + 34 + #define ref_walk_tit(w) (ref_walk_cur(w)->tit) 35 + #define ref_walk_empty(w) (!ref_walk_tit(w)) 36 + #define ref_walk_path(w) (ref_walk_cur(w)->path) 37 + #define ref_walk_fpath(w) (ref_walk_cur(w)->full_path) 38 + #define ref_walk_tl(w) (&ref_walk_cur(w)->tl) 39 + 40 + static inline struct dfs_ref_walk *ref_walk_alloc(void) 41 + { 42 + struct dfs_ref_walk *rw; 43 + 44 + rw = kmalloc(sizeof(*rw), GFP_KERNEL); 45 + if (!rw) 46 + return ERR_PTR(-ENOMEM); 47 + return rw; 48 + } 49 + 50 + static inline void ref_walk_init(struct dfs_ref_walk *rw) 51 + { 52 + memset(rw, 0, sizeof(*rw)); 53 + ref_walk_cur(rw) = ref_walk_start(rw); 54 + } 55 + 56 + static inline void __ref_walk_free(struct dfs_ref *ref) 57 + { 58 + kfree(ref->path); 59 + kfree(ref->full_path); 60 + dfs_cache_free_tgts(&ref->tl); 61 + memset(ref, 0, sizeof(*ref)); 62 + } 63 + 64 + static inline void ref_walk_free(struct dfs_ref_walk *rw) 65 + { 66 + struct dfs_ref *ref = ref_walk_start(rw); 67 + 68 + for (; ref <= ref_walk_end(rw); ref++) 69 + __ref_walk_free(ref); 70 + kfree(rw); 71 + } 72 + 73 + static inline int ref_walk_advance(struct dfs_ref_walk *rw) 74 + { 75 + struct dfs_ref *ref = ref_walk_cur(rw) + 1; 76 + 77 + if (ref > ref_walk_end(rw)) 78 + return -ELOOP; 79 + __ref_walk_free(ref); 80 + ref_walk_cur(rw) = ref; 81 + return 0; 82 + } 83 + 84 + static inline struct dfs_cache_tgt_iterator * 85 + ref_walk_next_tgt(struct dfs_ref_walk *rw) 86 + { 87 + struct dfs_cache_tgt_iterator *tit; 88 + struct dfs_ref *ref = ref_walk_cur(rw); 89 + 90 + if (!ref->tit) 91 + tit = dfs_cache_get_tgt_iterator(&ref->tl); 92 + else 93 + tit = dfs_cache_get_next_tgt(&ref->tl, ref->tit); 94 + ref->tit = tit; 95 + return tit; 96 + } 97 + 98 + static inline int ref_walk_get_tgt(struct dfs_ref_walk *rw, 99 + struct dfs_info3_param *tgt) 100 + { 101 + zfree_dfs_info_param(tgt); 102 + return dfs_cache_get_tgt_referral(ref_walk_path(rw) + 1, 103 + ref_walk_tit(rw), tgt); 104 + } 105 + 106 + static inline int ref_walk_num_tgts(struct dfs_ref_walk *rw) 107 + { 108 + return dfs_cache_get_nr_tgts(ref_walk_tl(rw)); 109 + } 110 + 111 + static inline void ref_walk_set_tgt_hint(struct dfs_ref_walk *rw) 112 + { 113 + dfs_cache_noreq_update_tgthint(ref_walk_path(rw) + 1, 114 + ref_walk_tit(rw)); 115 + } 12 116 13 117 struct dfs_root_ses { 14 118 struct list_head list; ··· 136 32 137 33 return dfs_cache_find(mnt_ctx->xid, ctx->dfs_root_ses, cifs_sb->local_nls, 138 34 cifs_remap(cifs_sb), path, ref, tl); 139 - } 140 - 141 - /* Return DFS full path out of a dentry set for automount */ 142 - static inline char *dfs_get_automount_devname(struct dentry *dentry, void *page) 143 - { 144 - struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb); 145 - struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 146 - size_t len; 147 - char *s; 148 - 149 - spin_lock(&tcon->tc_lock); 150 - if (unlikely(!tcon->origin_fullpath)) { 151 - spin_unlock(&tcon->tc_lock); 152 - return ERR_PTR(-EREMOTE); 153 - } 154 - spin_unlock(&tcon->tc_lock); 155 - 156 - s = dentry_path_raw(dentry, page, PATH_MAX); 157 - if (IS_ERR(s)) 158 - return s; 159 - /* for root, we want "" */ 160 - if (!s[1]) 161 - s++; 162 - 163 - spin_lock(&tcon->tc_lock); 164 - len = strlen(tcon->origin_fullpath); 165 - if (s < (char *)page + len) { 166 - spin_unlock(&tcon->tc_lock); 167 - return ERR_PTR(-ENAMETOOLONG); 168 - } 169 - 170 - s -= len; 171 - memcpy(s, tcon->origin_fullpath, len); 172 - spin_unlock(&tcon->tc_lock); 173 - convert_delimiter(s, '/'); 174 - 175 - return s; 176 35 } 177 36 178 37 static inline void dfs_put_root_smb_sessions(struct list_head *head)
+4 -6
fs/smb/client/dfs_cache.c
··· 29 29 #define CACHE_MIN_TTL 120 /* 2 minutes */ 30 30 #define CACHE_DEFAULT_TTL 300 /* 5 minutes */ 31 31 32 - #define IS_DFS_INTERLINK(v) (((v) & DFSREF_REFERRAL_SERVER) && !((v) & DFSREF_STORAGE_SERVER)) 33 - 34 32 struct cache_dfs_tgt { 35 33 char *name; 36 34 int path_consumed; ··· 172 174 "cache entry: path=%s,type=%s,ttl=%d,etime=%ld,hdr_flags=0x%x,ref_flags=0x%x,interlink=%s,path_consumed=%d,expired=%s\n", 173 175 ce->path, ce->srvtype == DFS_TYPE_ROOT ? "root" : "link", 174 176 ce->ttl, ce->etime.tv_nsec, ce->hdr_flags, ce->ref_flags, 175 - IS_DFS_INTERLINK(ce->hdr_flags) ? "yes" : "no", 177 + DFS_INTERLINK(ce->hdr_flags) ? "yes" : "no", 176 178 ce->path_consumed, cache_entry_expired(ce) ? "yes" : "no"); 177 179 178 180 list_for_each_entry(t, &ce->tlist, list) { ··· 241 243 ce->srvtype == DFS_TYPE_ROOT ? "root" : "link", ce->ttl, 242 244 ce->etime.tv_nsec, 243 245 ce->hdr_flags, ce->ref_flags, 244 - IS_DFS_INTERLINK(ce->hdr_flags) ? "yes" : "no", 246 + DFS_INTERLINK(ce->hdr_flags) ? "yes" : "no", 245 247 ce->path_consumed, 246 248 cache_entry_expired(ce) ? "yes" : "no"); 247 249 dump_tgts(ce); ··· 1175 1177 /* Refresh dfs referral of tcon and mark it for reconnect if needed */ 1176 1178 static int __refresh_tcon(const char *path, struct cifs_ses *ses, bool force_refresh) 1177 1179 { 1178 - struct dfs_cache_tgt_list old_tl = DFS_CACHE_TGT_LIST_INIT(old_tl); 1179 - struct dfs_cache_tgt_list new_tl = DFS_CACHE_TGT_LIST_INIT(new_tl); 1180 1180 struct TCP_Server_Info *server = ses->server; 1181 + DFS_CACHE_TGT_LIST(old_tl); 1182 + DFS_CACHE_TGT_LIST(new_tl); 1181 1183 bool needs_refresh = false; 1182 1184 struct cache_entry *ce; 1183 1185 unsigned int xid;
+8 -4
fs/smb/client/dfs_cache.h
··· 16 16 extern struct workqueue_struct *dfscache_wq; 17 17 extern atomic_t dfs_cache_ttl; 18 18 19 - #define DFS_CACHE_TGT_LIST_INIT(var) { .tl_numtgts = 0, .tl_list = LIST_HEAD_INIT((var).tl_list), } 19 + #define DFS_CACHE_TGT_LIST_INIT(var) \ 20 + { .tl_numtgts = 0, .tl_list = LIST_HEAD_INIT((var).tl_list), } 21 + 22 + #define DFS_CACHE_TGT_LIST(var) \ 23 + struct dfs_cache_tgt_list var = DFS_CACHE_TGT_LIST_INIT(var) 20 24 21 25 struct dfs_cache_tgt_list { 22 26 int tl_numtgts; ··· 55 51 dfs_cache_get_next_tgt(struct dfs_cache_tgt_list *tl, 56 52 struct dfs_cache_tgt_iterator *it) 57 53 { 58 - if (!tl || list_empty(&tl->tl_list) || !it || 59 - list_is_last(&it->it_list, &tl->tl_list)) 54 + if (!tl || !tl->tl_numtgts || list_empty(&tl->tl_list) || 55 + !it || list_is_last(&it->it_list, &tl->tl_list)) 60 56 return NULL; 61 57 return list_next_entry(it, it_list); 62 58 } ··· 75 71 { 76 72 struct dfs_cache_tgt_iterator *it, *nit; 77 73 78 - if (!tl || list_empty(&tl->tl_list)) 74 + if (!tl || !tl->tl_numtgts || list_empty(&tl->tl_list)) 79 75 return; 80 76 list_for_each_entry_safe(it, nit, &tl->tl_list, it_list) { 81 77 list_del(&it->it_list);
+2 -2
fs/smb/client/dir.c
··· 797 797 798 798 const struct dentry_operations cifs_dentry_ops = { 799 799 .d_revalidate = cifs_d_revalidate, 800 - .d_automount = cifs_dfs_d_automount, 800 + .d_automount = cifs_d_automount, 801 801 /* d_delete: cifs_d_delete, */ /* not needed except for debugging */ 802 802 }; 803 803 ··· 872 872 .d_revalidate = cifs_d_revalidate, 873 873 .d_hash = cifs_ci_hash, 874 874 .d_compare = cifs_ci_compare, 875 - .d_automount = cifs_dfs_d_automount, 875 + .d_automount = cifs_d_automount, 876 876 };
+286 -216
fs/smb/client/inode.c
··· 58 58 inode->i_data.a_ops = &cifs_addr_ops; 59 59 break; 60 60 case S_IFDIR: 61 - #ifdef CONFIG_CIFS_DFS_UPCALL 62 61 if (IS_AUTOMOUNT(inode)) { 63 - inode->i_op = &cifs_dfs_referral_inode_operations; 62 + inode->i_op = &cifs_namespace_inode_operations; 64 63 } else { 65 - #else /* NO DFS support, treat as a directory */ 66 - { 67 - #endif 68 64 inode->i_op = &cifs_dir_inode_ops; 69 65 inode->i_fop = &cifs_dir_ops; 70 66 } ··· 214 218 } 215 219 spin_unlock(&inode->i_lock); 216 220 217 - if (fattr->cf_flags & CIFS_FATTR_DFS_REFERRAL) 221 + if (fattr->cf_flags & CIFS_FATTR_JUNCTION) 218 222 inode->i_flags |= S_AUTOMOUNT; 219 223 if (inode->i_state & I_NEW) 220 224 cifs_set_ops(inode); ··· 323 327 * 324 328 * Needed to setup cifs_fattr data for the directory which is the 325 329 * junction to the new submount (ie to setup the fake directory 326 - * which represents a DFS referral). 330 + * which represents a DFS referral or reparse mount point). 327 331 */ 328 - static void 329 - cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb) 332 + static void cifs_create_junction_fattr(struct cifs_fattr *fattr, 333 + struct super_block *sb) 330 334 { 331 335 struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 332 336 333 - cifs_dbg(FYI, "creating fake fattr for DFS referral\n"); 337 + cifs_dbg(FYI, "%s: creating fake fattr\n", __func__); 334 338 335 339 memset(fattr, 0, sizeof(*fattr)); 336 340 fattr->cf_mode = S_IFDIR | S_IXUGO | S_IRWXU; ··· 339 343 ktime_get_coarse_real_ts64(&fattr->cf_mtime); 340 344 fattr->cf_atime = fattr->cf_ctime = fattr->cf_mtime; 341 345 fattr->cf_nlink = 2; 342 - fattr->cf_flags = CIFS_FATTR_DFS_REFERRAL; 346 + fattr->cf_flags = CIFS_FATTR_JUNCTION; 347 + } 348 + 349 + /* Update inode with final fattr data */ 350 + static int update_inode_info(struct super_block *sb, 351 + struct cifs_fattr *fattr, 352 + struct inode **inode) 353 + { 354 + struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 355 + int rc = 0; 356 + 357 + if (!*inode) { 358 + *inode = cifs_iget(sb, fattr); 359 + if (!*inode) 360 + rc = -ENOMEM; 361 + return rc; 362 + } 363 + /* We already have inode, update it. 364 + * 365 + * If file type or uniqueid is different, return error. 366 + */ 367 + if (unlikely((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) && 368 + CIFS_I(*inode)->uniqueid != fattr->cf_uniqueid)) { 369 + CIFS_I(*inode)->time = 0; /* force reval */ 370 + return -ESTALE; 371 + } 372 + return cifs_fattr_to_inode(*inode, fattr); 343 373 } 344 374 345 375 #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY ··· 395 373 if (!rc) { 396 374 cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb); 397 375 } else if (rc == -EREMOTE) { 398 - cifs_create_dfs_fattr(&fattr, inode->i_sb); 376 + cifs_create_junction_fattr(&fattr, inode->i_sb); 399 377 rc = 0; 400 378 } else 401 379 goto cifs_gfiunix_out; ··· 407 385 return rc; 408 386 } 409 387 410 - int cifs_get_inode_info_unix(struct inode **pinode, 411 - const unsigned char *full_path, 412 - struct super_block *sb, unsigned int xid) 388 + static int cifs_get_unix_fattr(const unsigned char *full_path, 389 + struct super_block *sb, 390 + struct cifs_fattr *fattr, 391 + struct inode **pinode, 392 + const unsigned int xid) 413 393 { 414 - int rc; 415 - FILE_UNIX_BASIC_INFO find_data; 416 - struct cifs_fattr fattr; 417 - struct cifs_tcon *tcon; 418 394 struct TCP_Server_Info *server; 419 - struct tcon_link *tlink; 420 395 struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 396 + FILE_UNIX_BASIC_INFO find_data; 397 + struct cifs_tcon *tcon; 398 + struct tcon_link *tlink; 399 + int rc, tmprc; 421 400 422 401 cifs_dbg(FYI, "Getting info on %s\n", full_path); 423 402 ··· 435 412 cifs_put_tlink(tlink); 436 413 437 414 if (!rc) { 438 - cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb); 415 + cifs_unix_basic_to_fattr(fattr, &find_data, cifs_sb); 439 416 } else if (rc == -EREMOTE) { 440 - cifs_create_dfs_fattr(&fattr, sb); 417 + cifs_create_junction_fattr(fattr, sb); 441 418 rc = 0; 442 419 } else { 443 420 return rc; 444 421 } 445 422 423 + if (!*pinode) 424 + cifs_fill_uniqueid(sb, fattr); 425 + 446 426 /* check for Minshall+French symlinks */ 447 427 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) { 448 - int tmprc = check_mf_symlink(xid, tcon, cifs_sb, &fattr, 449 - full_path); 450 - if (tmprc) 451 - cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc); 428 + tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path); 429 + cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc); 452 430 } 453 431 454 - if (S_ISLNK(fattr.cf_mode) && !fattr.cf_symlink_target) { 432 + if (S_ISLNK(fattr->cf_mode) && !fattr->cf_symlink_target) { 455 433 if (!server->ops->query_symlink) 456 434 return -EOPNOTSUPP; 457 - rc = server->ops->query_symlink(xid, tcon, cifs_sb, full_path, 458 - &fattr.cf_symlink_target, false); 459 - if (rc) { 460 - cifs_dbg(FYI, "%s: query_symlink: %d\n", __func__, rc); 461 - goto cgiiu_exit; 462 - } 435 + rc = server->ops->query_symlink(xid, tcon, 436 + cifs_sb, full_path, 437 + &fattr->cf_symlink_target, 438 + NULL); 439 + cifs_dbg(FYI, "%s: query_symlink: %d\n", __func__, rc); 463 440 } 441 + return rc; 442 + } 464 443 465 - if (*pinode == NULL) { 466 - /* get new inode */ 467 - cifs_fill_uniqueid(sb, &fattr); 468 - *pinode = cifs_iget(sb, &fattr); 469 - if (!*pinode) 470 - rc = -ENOMEM; 471 - } else { 472 - /* we already have inode, update it */ 444 + int cifs_get_inode_info_unix(struct inode **pinode, 445 + const unsigned char *full_path, 446 + struct super_block *sb, unsigned int xid) 447 + { 448 + struct cifs_fattr fattr = {}; 449 + int rc; 473 450 474 - /* if uniqueid is different, return error */ 475 - if (unlikely(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM && 476 - CIFS_I(*pinode)->uniqueid != fattr.cf_uniqueid)) { 477 - CIFS_I(*pinode)->time = 0; /* force reval */ 478 - rc = -ESTALE; 479 - goto cgiiu_exit; 480 - } 451 + rc = cifs_get_unix_fattr(full_path, sb, &fattr, pinode, xid); 452 + if (rc) 453 + goto out; 481 454 482 - /* if filetype is different, return error */ 483 - rc = cifs_fattr_to_inode(*pinode, &fattr); 484 - } 485 - 486 - cgiiu_exit: 455 + rc = update_inode_info(sb, &fattr, pinode); 456 + out: 487 457 kfree(fattr.cf_symlink_target); 488 458 return rc; 489 459 } 490 460 #else 461 + static inline int cifs_get_unix_fattr(const unsigned char *full_path, 462 + struct super_block *sb, 463 + struct cifs_fattr *fattr, 464 + struct inode **pinode, 465 + const unsigned int xid) 466 + { 467 + return -EOPNOTSUPP; 468 + } 469 + 491 470 int cifs_get_inode_info_unix(struct inode **pinode, 492 471 const unsigned char *full_path, 493 472 struct super_block *sb, unsigned int xid) ··· 657 632 } 658 633 659 634 /* Fill a cifs_fattr struct with info from POSIX info struct */ 660 - static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr, struct cifs_open_info_data *data, 635 + static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr, 636 + struct cifs_open_info_data *data, 661 637 struct cifs_sid *owner, 662 638 struct cifs_sid *group, 663 - struct super_block *sb, bool adjust_tz, bool symlink) 639 + struct super_block *sb) 664 640 { 665 641 struct smb311_posix_qinfo *info = &data->posix_fi; 666 642 struct cifs_sb_info *cifs_sb = CIFS_SB(sb); ··· 681 655 fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime); 682 656 fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); 683 657 684 - if (adjust_tz) { 658 + if (data->adjust_tz) { 685 659 fattr->cf_ctime.tv_sec += tcon->ses->server->timeAdj; 686 660 fattr->cf_mtime.tv_sec += tcon->ses->server->timeAdj; 687 661 } ··· 695 669 /* The srv fs device id is overridden on network mount so setting rdev isn't needed here */ 696 670 /* fattr->cf_rdev = le32_to_cpu(info->DeviceId); */ 697 671 698 - if (symlink) { 672 + if (data->symlink) { 699 673 fattr->cf_mode |= S_IFLNK; 700 674 fattr->cf_dtype = DT_LNK; 701 675 fattr->cf_symlink_target = data->symlink_target; ··· 716 690 fattr->cf_mode, fattr->cf_uniqueid, fattr->cf_nlink); 717 691 } 718 692 719 - static void cifs_open_info_to_fattr(struct cifs_fattr *fattr, struct cifs_open_info_data *data, 720 - struct super_block *sb, bool adjust_tz, bool symlink, 721 - u32 reparse_tag) 693 + bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb, 694 + struct cifs_fattr *fattr, 695 + u32 tag) 696 + { 697 + switch (tag) { 698 + case IO_REPARSE_TAG_LX_SYMLINK: 699 + fattr->cf_mode |= S_IFLNK | cifs_sb->ctx->file_mode; 700 + fattr->cf_dtype = DT_LNK; 701 + break; 702 + case IO_REPARSE_TAG_LX_FIFO: 703 + fattr->cf_mode |= S_IFIFO | cifs_sb->ctx->file_mode; 704 + fattr->cf_dtype = DT_FIFO; 705 + break; 706 + case IO_REPARSE_TAG_AF_UNIX: 707 + fattr->cf_mode |= S_IFSOCK | cifs_sb->ctx->file_mode; 708 + fattr->cf_dtype = DT_SOCK; 709 + break; 710 + case IO_REPARSE_TAG_LX_CHR: 711 + fattr->cf_mode |= S_IFCHR | cifs_sb->ctx->file_mode; 712 + fattr->cf_dtype = DT_CHR; 713 + break; 714 + case IO_REPARSE_TAG_LX_BLK: 715 + fattr->cf_mode |= S_IFBLK | cifs_sb->ctx->file_mode; 716 + fattr->cf_dtype = DT_BLK; 717 + break; 718 + case 0: /* SMB1 symlink */ 719 + case IO_REPARSE_TAG_SYMLINK: 720 + case IO_REPARSE_TAG_NFS: 721 + fattr->cf_mode = S_IFLNK; 722 + fattr->cf_dtype = DT_LNK; 723 + break; 724 + default: 725 + return false; 726 + } 727 + return true; 728 + } 729 + 730 + static void cifs_open_info_to_fattr(struct cifs_fattr *fattr, 731 + struct cifs_open_info_data *data, 732 + struct super_block *sb) 722 733 { 723 734 struct smb2_file_all_info *info = &data->fi; 724 735 struct cifs_sb_info *cifs_sb = CIFS_SB(sb); ··· 774 711 fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime); 775 712 fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); 776 713 777 - if (adjust_tz) { 714 + if (data->adjust_tz) { 778 715 fattr->cf_ctime.tv_sec += tcon->ses->server->timeAdj; 779 716 fattr->cf_mtime.tv_sec += tcon->ses->server->timeAdj; 780 717 } ··· 782 719 fattr->cf_eof = le64_to_cpu(info->EndOfFile); 783 720 fattr->cf_bytes = le64_to_cpu(info->AllocationSize); 784 721 fattr->cf_createtime = le64_to_cpu(info->CreationTime); 785 - 786 722 fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks); 787 - if (reparse_tag == IO_REPARSE_TAG_LX_SYMLINK) { 788 - fattr->cf_mode |= S_IFLNK | cifs_sb->ctx->file_mode; 789 - fattr->cf_dtype = DT_LNK; 790 - } else if (reparse_tag == IO_REPARSE_TAG_LX_FIFO) { 791 - fattr->cf_mode |= S_IFIFO | cifs_sb->ctx->file_mode; 792 - fattr->cf_dtype = DT_FIFO; 793 - } else if (reparse_tag == IO_REPARSE_TAG_AF_UNIX) { 794 - fattr->cf_mode |= S_IFSOCK | cifs_sb->ctx->file_mode; 795 - fattr->cf_dtype = DT_SOCK; 796 - } else if (reparse_tag == IO_REPARSE_TAG_LX_CHR) { 797 - fattr->cf_mode |= S_IFCHR | cifs_sb->ctx->file_mode; 798 - fattr->cf_dtype = DT_CHR; 799 - } else if (reparse_tag == IO_REPARSE_TAG_LX_BLK) { 800 - fattr->cf_mode |= S_IFBLK | cifs_sb->ctx->file_mode; 801 - fattr->cf_dtype = DT_BLK; 802 - } else if (symlink || reparse_tag == IO_REPARSE_TAG_SYMLINK || 803 - reparse_tag == IO_REPARSE_TAG_NFS) { 804 - fattr->cf_mode = S_IFLNK; 805 - fattr->cf_dtype = DT_LNK; 806 - } else if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { 723 + 724 + if (cifs_open_data_reparse(data) && 725 + cifs_reparse_point_to_fattr(cifs_sb, fattr, data->reparse_tag)) 726 + goto out_reparse; 727 + 728 + if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { 807 729 fattr->cf_mode = S_IFDIR | cifs_sb->ctx->dir_mode; 808 730 fattr->cf_dtype = DT_DIR; 809 731 /* ··· 817 769 } 818 770 } 819 771 772 + out_reparse: 820 773 if (S_ISLNK(fattr->cf_mode)) { 821 774 fattr->cf_symlink_target = data->symlink_target; 822 775 data->symlink_target = NULL; ··· 838 789 struct cifsFileInfo *cfile = filp->private_data; 839 790 struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); 840 791 struct TCP_Server_Info *server = tcon->ses->server; 841 - bool symlink = false; 842 - u32 tag = 0; 843 792 844 793 if (!server->ops->query_file_info) 845 794 return -ENOSYS; ··· 847 800 switch (rc) { 848 801 case 0: 849 802 /* TODO: add support to query reparse tag */ 803 + data.adjust_tz = false; 850 804 if (data.symlink_target) { 851 - symlink = true; 852 - tag = IO_REPARSE_TAG_SYMLINK; 805 + data.symlink = true; 806 + data.reparse_tag = IO_REPARSE_TAG_SYMLINK; 853 807 } 854 - cifs_open_info_to_fattr(&fattr, &data, inode->i_sb, false, symlink, tag); 808 + cifs_open_info_to_fattr(&fattr, &data, inode->i_sb); 855 809 break; 856 810 case -EREMOTE: 857 - cifs_create_dfs_fattr(&fattr, inode->i_sb); 811 + cifs_create_junction_fattr(&fattr, inode->i_sb); 858 812 rc = 0; 859 813 break; 860 814 case -EOPNOTSUPP: ··· 1008 960 return ino && CIFS_CACHE_READ(CIFS_I(ino)) && CIFS_I(ino)->time != 0; 1009 961 } 1010 962 1011 - int cifs_get_inode_info(struct inode **inode, const char *full_path, 1012 - struct cifs_open_info_data *data, struct super_block *sb, int xid, 1013 - const struct cifs_fid *fid) 963 + static int reparse_info_to_fattr(struct cifs_open_info_data *data, 964 + struct super_block *sb, 965 + const unsigned int xid, 966 + struct cifs_tcon *tcon, 967 + const char *full_path, 968 + struct cifs_fattr *fattr) 1014 969 { 970 + struct TCP_Server_Info *server = tcon->ses->server; 971 + struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 972 + struct kvec rsp_iov, *iov = NULL; 973 + int rsp_buftype = CIFS_NO_BUFFER; 974 + u32 tag = data->reparse_tag; 975 + int rc = 0; 976 + 977 + if (!tag && server->ops->query_reparse_point) { 978 + rc = server->ops->query_reparse_point(xid, tcon, cifs_sb, 979 + full_path, &tag, 980 + &rsp_iov, &rsp_buftype); 981 + if (!rc) 982 + iov = &rsp_iov; 983 + } 984 + switch ((data->reparse_tag = tag)) { 985 + case 0: /* SMB1 symlink */ 986 + iov = NULL; 987 + fallthrough; 988 + case IO_REPARSE_TAG_NFS: 989 + case IO_REPARSE_TAG_SYMLINK: 990 + if (!data->symlink_target && server->ops->query_symlink) { 991 + rc = server->ops->query_symlink(xid, tcon, 992 + cifs_sb, full_path, 993 + &data->symlink_target, 994 + iov); 995 + } 996 + break; 997 + case IO_REPARSE_TAG_MOUNT_POINT: 998 + cifs_create_junction_fattr(fattr, sb); 999 + goto out; 1000 + } 1001 + 1002 + cifs_open_info_to_fattr(fattr, data, sb); 1003 + out: 1004 + free_rsp_buf(rsp_buftype, rsp_iov.iov_base); 1005 + return rc; 1006 + } 1007 + 1008 + static int cifs_get_fattr(struct cifs_open_info_data *data, 1009 + struct super_block *sb, int xid, 1010 + const struct cifs_fid *fid, 1011 + struct cifs_fattr *fattr, 1012 + struct inode **inode, 1013 + const char *full_path) 1014 + { 1015 + struct cifs_open_info_data tmp_data = {}; 1015 1016 struct cifs_tcon *tcon; 1016 1017 struct TCP_Server_Info *server; 1017 1018 struct tcon_link *tlink; 1018 1019 struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 1019 - bool adjust_tz = false; 1020 - struct cifs_fattr fattr = {0}; 1021 - bool is_reparse_point = false; 1022 - struct cifs_open_info_data tmp_data = {}; 1023 1020 void *smb1_backup_rsp_buf = NULL; 1024 1021 int rc = 0; 1025 1022 int tmprc = 0; 1026 - __u32 reparse_tag = 0; 1027 1023 1028 1024 tlink = cifs_sb_tlink(cifs_sb); 1029 1025 if (IS_ERR(tlink)) ··· 1080 988 */ 1081 989 1082 990 if (!data) { 1083 - if (is_inode_cache_good(*inode)) { 1084 - cifs_dbg(FYI, "No need to revalidate cached inode sizes\n"); 1085 - goto out; 1086 - } 1087 - rc = server->ops->query_path_info(xid, tcon, cifs_sb, full_path, &tmp_data, 1088 - &adjust_tz, &is_reparse_point); 991 + rc = server->ops->query_path_info(xid, tcon, cifs_sb, 992 + full_path, &tmp_data); 1089 993 data = &tmp_data; 1090 994 } 1091 995 ··· 1096 1008 * since we have to check if its reparse tag matches a known 1097 1009 * special file type e.g. symlink or fifo or char etc. 1098 1010 */ 1099 - if (is_reparse_point && data->symlink_target) { 1100 - reparse_tag = IO_REPARSE_TAG_SYMLINK; 1101 - } else if ((le32_to_cpu(data->fi.Attributes) & ATTR_REPARSE) && 1102 - server->ops->query_reparse_tag) { 1103 - tmprc = server->ops->query_reparse_tag(xid, tcon, cifs_sb, full_path, 1104 - &reparse_tag); 1105 - if (tmprc) 1106 - cifs_dbg(FYI, "%s: query_reparse_tag: rc = %d\n", __func__, tmprc); 1107 - if (server->ops->query_symlink) { 1108 - tmprc = server->ops->query_symlink(xid, tcon, cifs_sb, full_path, 1109 - &data->symlink_target, 1110 - is_reparse_point); 1111 - if (tmprc) 1112 - cifs_dbg(FYI, "%s: query_symlink: rc = %d\n", __func__, 1113 - tmprc); 1114 - } 1011 + if (cifs_open_data_reparse(data)) { 1012 + rc = reparse_info_to_fattr(data, sb, xid, tcon, 1013 + full_path, fattr); 1014 + } else { 1015 + cifs_open_info_to_fattr(fattr, data, sb); 1115 1016 } 1116 - cifs_open_info_to_fattr(&fattr, data, sb, adjust_tz, is_reparse_point, reparse_tag); 1117 1017 break; 1118 1018 case -EREMOTE: 1119 1019 /* DFS link, no metadata available on this server */ 1120 - cifs_create_dfs_fattr(&fattr, sb); 1020 + cifs_create_junction_fattr(fattr, sb); 1121 1021 rc = 0; 1122 1022 break; 1123 1023 case -EACCES: ··· 1135 1059 fdi = (FILE_DIRECTORY_INFO *)fi; 1136 1060 si = (SEARCH_ID_FULL_DIR_INFO *)fi; 1137 1061 1138 - cifs_dir_info_to_fattr(&fattr, fdi, cifs_sb); 1139 - fattr.cf_uniqueid = le64_to_cpu(si->UniqueId); 1062 + cifs_dir_info_to_fattr(fattr, fdi, cifs_sb); 1063 + fattr->cf_uniqueid = le64_to_cpu(si->UniqueId); 1140 1064 /* uniqueid set, skip get inum step */ 1141 1065 goto handle_mnt_opt; 1142 1066 } else { ··· 1153 1077 } 1154 1078 1155 1079 /* 1156 - * 3. Get or update inode number (fattr.cf_uniqueid) 1080 + * 3. Get or update inode number (fattr->cf_uniqueid) 1157 1081 */ 1158 1082 1159 - cifs_set_fattr_ino(xid, tcon, sb, inode, full_path, data, &fattr); 1083 + cifs_set_fattr_ino(xid, tcon, sb, inode, full_path, data, fattr); 1160 1084 1161 1085 /* 1162 1086 * 4. Tweak fattr based on mount options ··· 1165 1089 handle_mnt_opt: 1166 1090 #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 1167 1091 /* query for SFU type info if supported and needed */ 1168 - if (fattr.cf_cifsattrs & ATTR_SYSTEM && 1169 - cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { 1170 - tmprc = cifs_sfu_type(&fattr, full_path, cifs_sb, xid); 1092 + if ((fattr->cf_cifsattrs & ATTR_SYSTEM) && 1093 + (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) { 1094 + tmprc = cifs_sfu_type(fattr, full_path, cifs_sb, xid); 1171 1095 if (tmprc) 1172 1096 cifs_dbg(FYI, "cifs_sfu_type failed: %d\n", tmprc); 1173 1097 } 1174 1098 1175 1099 /* fill in 0777 bits from ACL */ 1176 1100 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) { 1177 - rc = cifs_acl_to_fattr(cifs_sb, &fattr, *inode, true, 1178 - full_path, fid); 1101 + rc = cifs_acl_to_fattr(cifs_sb, fattr, *inode, 1102 + true, full_path, fid); 1179 1103 if (rc == -EREMOTE) 1180 1104 rc = 0; 1181 1105 if (rc) { ··· 1184 1108 goto out; 1185 1109 } 1186 1110 } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { 1187 - rc = cifs_acl_to_fattr(cifs_sb, &fattr, *inode, false, 1188 - full_path, fid); 1111 + rc = cifs_acl_to_fattr(cifs_sb, fattr, *inode, 1112 + false, full_path, fid); 1189 1113 if (rc == -EREMOTE) 1190 1114 rc = 0; 1191 1115 if (rc) { ··· 1197 1121 1198 1122 /* fill in remaining high mode bits e.g. SUID, VTX */ 1199 1123 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) 1200 - cifs_sfu_mode(&fattr, full_path, cifs_sb, xid); 1124 + cifs_sfu_mode(fattr, full_path, cifs_sb, xid); 1201 1125 1202 1126 /* check for Minshall+French symlinks */ 1203 1127 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) { 1204 - tmprc = check_mf_symlink(xid, tcon, cifs_sb, &fattr, 1205 - full_path); 1206 - if (tmprc) 1207 - cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc); 1128 + tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path); 1129 + cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc); 1208 1130 } 1209 1131 1210 - /* 1211 - * 5. Update inode with final fattr data 1212 - */ 1213 - 1214 - if (!*inode) { 1215 - *inode = cifs_iget(sb, &fattr); 1216 - if (!*inode) 1217 - rc = -ENOMEM; 1218 - } else { 1219 - /* we already have inode, update it */ 1220 - 1221 - /* if uniqueid is different, return error */ 1222 - if (unlikely(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM && 1223 - CIFS_I(*inode)->uniqueid != fattr.cf_uniqueid)) { 1224 - CIFS_I(*inode)->time = 0; /* force reval */ 1225 - rc = -ESTALE; 1226 - goto out; 1227 - } 1228 - /* if filetype is different, return error */ 1229 - rc = cifs_fattr_to_inode(*inode, &fattr); 1230 - } 1231 1132 out: 1232 1133 cifs_buf_release(smb1_backup_rsp_buf); 1233 1134 cifs_put_tlink(tlink); 1234 1135 cifs_free_open_info(&tmp_data); 1136 + return rc; 1137 + } 1138 + 1139 + int cifs_get_inode_info(struct inode **inode, 1140 + const char *full_path, 1141 + struct cifs_open_info_data *data, 1142 + struct super_block *sb, int xid, 1143 + const struct cifs_fid *fid) 1144 + { 1145 + struct cifs_fattr fattr = {}; 1146 + int rc; 1147 + 1148 + if (is_inode_cache_good(*inode)) { 1149 + cifs_dbg(FYI, "No need to revalidate cached inode sizes\n"); 1150 + return 0; 1151 + } 1152 + 1153 + rc = cifs_get_fattr(data, sb, xid, fid, &fattr, inode, full_path); 1154 + if (rc) 1155 + goto out; 1156 + 1157 + rc = update_inode_info(sb, &fattr, inode); 1158 + out: 1235 1159 kfree(fattr.cf_symlink_target); 1236 1160 return rc; 1237 1161 } 1238 1162 1239 - int 1240 - smb311_posix_get_inode_info(struct inode **inode, 1241 - const char *full_path, 1242 - struct super_block *sb, unsigned int xid) 1163 + static int smb311_posix_get_fattr(struct cifs_fattr *fattr, 1164 + const char *full_path, 1165 + struct super_block *sb, 1166 + const unsigned int xid) 1243 1167 { 1168 + struct cifs_open_info_data data = {}; 1169 + struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 1244 1170 struct cifs_tcon *tcon; 1245 1171 struct tcon_link *tlink; 1246 - struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 1247 - bool adjust_tz = false; 1248 - struct cifs_fattr fattr = {0}; 1249 - bool symlink = false; 1250 - struct cifs_open_info_data data = {}; 1251 1172 struct cifs_sid owner, group; 1252 - int rc = 0; 1253 - int tmprc = 0; 1173 + int tmprc; 1174 + int rc; 1254 1175 1255 1176 tlink = cifs_sb_tlink(cifs_sb); 1256 1177 if (IS_ERR(tlink)) ··· 1258 1185 * 1. Fetch file metadata 1259 1186 */ 1260 1187 1261 - if (is_inode_cache_good(*inode)) { 1262 - cifs_dbg(FYI, "No need to revalidate cached inode sizes\n"); 1263 - goto out; 1264 - } 1265 - 1266 - rc = smb311_posix_query_path_info(xid, tcon, cifs_sb, full_path, &data, 1267 - &owner, &group, &adjust_tz, 1268 - &symlink); 1188 + rc = smb311_posix_query_path_info(xid, tcon, cifs_sb, 1189 + full_path, &data, 1190 + &owner, &group); 1269 1191 1270 1192 /* 1271 1193 * 2. Convert it to internal cifs metadata (fattr) ··· 1268 1200 1269 1201 switch (rc) { 1270 1202 case 0: 1271 - smb311_posix_info_to_fattr(&fattr, &data, &owner, &group, 1272 - sb, adjust_tz, symlink); 1203 + smb311_posix_info_to_fattr(fattr, &data, &owner, &group, sb); 1273 1204 break; 1274 1205 case -EREMOTE: 1275 1206 /* DFS link, no metadata available on this server */ 1276 - cifs_create_dfs_fattr(&fattr, sb); 1207 + cifs_create_junction_fattr(fattr, sb); 1277 1208 rc = 0; 1278 1209 break; 1279 1210 case -EACCES: ··· 1288 1221 goto out; 1289 1222 } 1290 1223 1291 - 1292 1224 /* 1293 1225 * 3. Tweak fattr based on mount options 1294 1226 */ 1295 - 1296 1227 /* check for Minshall+French symlinks */ 1297 1228 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) { 1298 - tmprc = check_mf_symlink(xid, tcon, cifs_sb, &fattr, 1299 - full_path); 1300 - if (tmprc) 1301 - cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc); 1229 + tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path); 1230 + cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc); 1302 1231 } 1303 1232 1304 - /* 1305 - * 4. Update inode with final fattr data 1306 - */ 1307 - 1308 - if (!*inode) { 1309 - *inode = cifs_iget(sb, &fattr); 1310 - if (!*inode) 1311 - rc = -ENOMEM; 1312 - } else { 1313 - /* we already have inode, update it */ 1314 - 1315 - /* if uniqueid is different, return error */ 1316 - if (unlikely(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM && 1317 - CIFS_I(*inode)->uniqueid != fattr.cf_uniqueid)) { 1318 - CIFS_I(*inode)->time = 0; /* force reval */ 1319 - rc = -ESTALE; 1320 - goto out; 1321 - } 1322 - 1323 - /* if filetype is different, return error */ 1324 - rc = cifs_fattr_to_inode(*inode, &fattr); 1325 - } 1326 1233 out: 1327 1234 cifs_put_tlink(tlink); 1328 1235 cifs_free_open_info(&data); 1329 - kfree(fattr.cf_symlink_target); 1330 1236 return rc; 1331 1237 } 1332 1238 1239 + int smb311_posix_get_inode_info(struct inode **inode, const char *full_path, 1240 + struct super_block *sb, const unsigned int xid) 1241 + { 1242 + struct cifs_fattr fattr = {}; 1243 + int rc; 1244 + 1245 + if (is_inode_cache_good(*inode)) { 1246 + cifs_dbg(FYI, "No need to revalidate cached inode sizes\n"); 1247 + return 0; 1248 + } 1249 + 1250 + rc = smb311_posix_get_fattr(&fattr, full_path, sb, xid); 1251 + if (rc) 1252 + goto out; 1253 + 1254 + rc = update_inode_info(sb, &fattr, inode); 1255 + out: 1256 + kfree(fattr.cf_symlink_target); 1257 + return rc; 1258 + } 1333 1259 1334 1260 static const struct inode_operations cifs_ipc_inode_ops = { 1335 1261 .lookup = cifs_lookup, ··· 1427 1367 /* gets root inode */ 1428 1368 struct inode *cifs_root_iget(struct super_block *sb) 1429 1369 { 1430 - unsigned int xid; 1431 1370 struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 1432 - struct inode *inode = NULL; 1433 - long rc; 1371 + struct cifs_fattr fattr = {}; 1434 1372 struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 1373 + struct inode *inode = NULL; 1374 + unsigned int xid; 1435 1375 char *path = NULL; 1436 1376 int len; 1377 + int rc; 1437 1378 1438 1379 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) 1439 1380 && cifs_sb->prepath) { ··· 1452 1391 1453 1392 xid = get_xid(); 1454 1393 if (tcon->unix_ext) { 1455 - rc = cifs_get_inode_info_unix(&inode, path, sb, xid); 1394 + rc = cifs_get_unix_fattr(path, sb, &fattr, &inode, xid); 1456 1395 /* some servers mistakenly claim POSIX support */ 1457 1396 if (rc != -EOPNOTSUPP) 1458 - goto iget_no_retry; 1397 + goto iget_root; 1459 1398 cifs_dbg(VFS, "server does not support POSIX extensions\n"); 1460 1399 tcon->unix_ext = false; 1461 1400 } 1462 1401 1463 1402 convert_delimiter(path, CIFS_DIR_SEP(cifs_sb)); 1464 1403 if (tcon->posix_extensions) 1465 - rc = smb311_posix_get_inode_info(&inode, path, sb, xid); 1404 + rc = smb311_posix_get_fattr(&fattr, path, sb, xid); 1466 1405 else 1467 - rc = cifs_get_inode_info(&inode, path, NULL, sb, xid, NULL); 1406 + rc = cifs_get_fattr(NULL, sb, xid, NULL, &fattr, &inode, path); 1468 1407 1469 - iget_no_retry: 1408 + iget_root: 1409 + if (!rc) { 1410 + if (fattr.cf_flags & CIFS_FATTR_JUNCTION) { 1411 + fattr.cf_flags &= ~CIFS_FATTR_JUNCTION; 1412 + cifs_autodisable_serverino(cifs_sb); 1413 + } 1414 + inode = cifs_iget(sb, &fattr); 1415 + } 1416 + 1470 1417 if (!inode) { 1471 1418 inode = ERR_PTR(rc); 1472 1419 goto out; ··· 1498 1429 out: 1499 1430 kfree(path); 1500 1431 free_xid(xid); 1432 + kfree(fattr.cf_symlink_target); 1501 1433 return inode; 1502 1434 } 1503 1435
+1 -1
fs/smb/client/misc.c
··· 476 476 return false; 477 477 478 478 /* If server is a channel, select the primary channel */ 479 - pserver = CIFS_SERVER_IS_CHAN(srv) ? srv->primary_server : srv; 479 + pserver = SERVER_IS_CHAN(srv) ? srv->primary_server : srv; 480 480 481 481 /* look up tcon based on tid & uid */ 482 482 spin_lock(&cifs_tcp_ses_lock);
+7 -16
fs/smb/client/readdir.c
··· 143 143 case IO_REPARSE_TAG_DFSR: 144 144 case IO_REPARSE_TAG_SYMLINK: 145 145 case IO_REPARSE_TAG_NFS: 146 + case IO_REPARSE_TAG_MOUNT_POINT: 146 147 case 0: 147 148 return true; 148 149 } ··· 164 163 * TODO: go through all documented reparse tags to see if we can 165 164 * reasonably map some of them to directories vs. files vs. symlinks 166 165 */ 166 + if ((fattr->cf_cifsattrs & ATTR_REPARSE) && 167 + cifs_reparse_point_to_fattr(cifs_sb, fattr, fattr->cf_cifstag)) 168 + goto out_reparse; 169 + 167 170 if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { 168 171 fattr->cf_mode = S_IFDIR | cifs_sb->ctx->dir_mode; 169 172 fattr->cf_dtype = DT_DIR; 170 - } else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_SYMLINK) { 171 - fattr->cf_mode |= S_IFLNK | cifs_sb->ctx->file_mode; 172 - fattr->cf_dtype = DT_LNK; 173 - } else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_FIFO) { 174 - fattr->cf_mode |= S_IFIFO | cifs_sb->ctx->file_mode; 175 - fattr->cf_dtype = DT_FIFO; 176 - } else if (fattr->cf_cifstag == IO_REPARSE_TAG_AF_UNIX) { 177 - fattr->cf_mode |= S_IFSOCK | cifs_sb->ctx->file_mode; 178 - fattr->cf_dtype = DT_SOCK; 179 - } else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_CHR) { 180 - fattr->cf_mode |= S_IFCHR | cifs_sb->ctx->file_mode; 181 - fattr->cf_dtype = DT_CHR; 182 - } else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_BLK) { 183 - fattr->cf_mode |= S_IFBLK | cifs_sb->ctx->file_mode; 184 - fattr->cf_dtype = DT_BLK; 185 - } else { /* TODO: should we mark some other reparse points (like DFSR) as directories? */ 173 + } else { 186 174 fattr->cf_mode = S_IFREG | cifs_sb->ctx->file_mode; 187 175 fattr->cf_dtype = DT_REG; 188 176 } 189 177 178 + out_reparse: 190 179 /* 191 180 * We need to revalidate it further to make a decision about whether it 192 181 * is a symbolic link, DFS referral or a reparse point with a direct
+43 -29
fs/smb/client/sess.c
··· 323 323 ses->chans[chan_index].iface = iface; 324 324 325 325 /* No iface is found. if secondary chan, drop connection */ 326 - if (!iface && CIFS_SERVER_IS_CHAN(server)) 326 + if (!iface && SERVER_IS_CHAN(server)) 327 327 ses->chans[chan_index].server = NULL; 328 328 329 329 spin_unlock(&ses->chan_lock); 330 330 331 - if (!iface && CIFS_SERVER_IS_CHAN(server)) 331 + if (!iface && SERVER_IS_CHAN(server)) 332 332 cifs_put_tcp_session(server, false); 333 333 334 334 return rc; ··· 360 360 { 361 361 struct TCP_Server_Info *chan_server; 362 362 struct cifs_chan *chan; 363 - struct smb3_fs_context ctx = {NULL}; 363 + struct smb3_fs_context *ctx; 364 364 static const char unc_fmt[] = "\\%s\\foo"; 365 - char unc[sizeof(unc_fmt)+SERVER_NAME_LEN_WITH_NULL] = {0}; 366 365 struct sockaddr_in *ipv4 = (struct sockaddr_in *)&iface->sockaddr; 367 366 struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)&iface->sockaddr; 367 + size_t len; 368 368 int rc; 369 369 unsigned int xid = get_xid(); 370 370 ··· 388 388 * the session and server without caring about memory 389 389 * management. 390 390 */ 391 + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 392 + if (!ctx) { 393 + rc = -ENOMEM; 394 + goto out_free_xid; 395 + } 391 396 392 397 /* Always make new connection for now (TODO?) */ 393 - ctx.nosharesock = true; 398 + ctx->nosharesock = true; 394 399 395 400 /* Auth */ 396 - ctx.domainauto = ses->domainAuto; 397 - ctx.domainname = ses->domainName; 401 + ctx->domainauto = ses->domainAuto; 402 + ctx->domainname = ses->domainName; 398 403 399 404 /* no hostname for extra channels */ 400 - ctx.server_hostname = ""; 405 + ctx->server_hostname = ""; 401 406 402 - ctx.username = ses->user_name; 403 - ctx.password = ses->password; 404 - ctx.sectype = ses->sectype; 405 - ctx.sign = ses->sign; 407 + ctx->username = ses->user_name; 408 + ctx->password = ses->password; 409 + ctx->sectype = ses->sectype; 410 + ctx->sign = ses->sign; 406 411 407 412 /* UNC and paths */ 408 413 /* XXX: Use ses->server->hostname? */ 409 - sprintf(unc, unc_fmt, ses->ip_addr); 410 - ctx.UNC = unc; 411 - ctx.prepath = ""; 414 + len = sizeof(unc_fmt) + SERVER_NAME_LEN_WITH_NULL; 415 + ctx->UNC = kzalloc(len, GFP_KERNEL); 416 + if (!ctx->UNC) { 417 + rc = -ENOMEM; 418 + goto out_free_ctx; 419 + } 420 + scnprintf(ctx->UNC, len, unc_fmt, ses->ip_addr); 421 + ctx->prepath = ""; 412 422 413 423 /* Reuse same version as master connection */ 414 - ctx.vals = ses->server->vals; 415 - ctx.ops = ses->server->ops; 424 + ctx->vals = ses->server->vals; 425 + ctx->ops = ses->server->ops; 416 426 417 - ctx.noblocksnd = ses->server->noblocksnd; 418 - ctx.noautotune = ses->server->noautotune; 419 - ctx.sockopt_tcp_nodelay = ses->server->tcp_nodelay; 420 - ctx.echo_interval = ses->server->echo_interval / HZ; 421 - ctx.max_credits = ses->server->max_credits; 427 + ctx->noblocksnd = ses->server->noblocksnd; 428 + ctx->noautotune = ses->server->noautotune; 429 + ctx->sockopt_tcp_nodelay = ses->server->tcp_nodelay; 430 + ctx->echo_interval = ses->server->echo_interval / HZ; 431 + ctx->max_credits = ses->server->max_credits; 422 432 423 433 /* 424 434 * This will be used for encoding/decoding user/domain/pw 425 435 * during sess setup auth. 426 436 */ 427 - ctx.local_nls = cifs_sb->local_nls; 437 + ctx->local_nls = cifs_sb->local_nls; 428 438 429 439 /* Use RDMA if possible */ 430 - ctx.rdma = iface->rdma_capable; 431 - memcpy(&ctx.dstaddr, &iface->sockaddr, sizeof(struct sockaddr_storage)); 440 + ctx->rdma = iface->rdma_capable; 441 + memcpy(&ctx->dstaddr, &iface->sockaddr, sizeof(ctx->dstaddr)); 432 442 433 443 /* reuse master con client guid */ 434 - memcpy(&ctx.client_guid, ses->server->client_guid, 435 - SMB2_CLIENT_GUID_SIZE); 436 - ctx.use_client_guid = true; 444 + memcpy(&ctx->client_guid, ses->server->client_guid, 445 + sizeof(ctx->client_guid)); 446 + ctx->use_client_guid = true; 437 447 438 - chan_server = cifs_get_tcp_session(&ctx, ses->server); 448 + chan_server = cifs_get_tcp_session(ctx, ses->server); 439 449 440 450 spin_lock(&ses->chan_lock); 441 451 chan = &ses->chans[ses->chan_count]; ··· 507 497 cifs_put_tcp_session(chan->server, 0); 508 498 } 509 499 500 + kfree(ctx->UNC); 501 + out_free_ctx: 502 + kfree(ctx); 503 + out_free_xid: 510 504 free_xid(xid); 511 505 return rc; 512 506 }
+16 -10
fs/smb/client/smb1ops.c
··· 542 542 return rc; 543 543 } 544 544 545 - static int cifs_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, 546 - struct cifs_sb_info *cifs_sb, const char *full_path, 547 - struct cifs_open_info_data *data, bool *adjustTZ, bool *symlink) 545 + static int cifs_query_path_info(const unsigned int xid, 546 + struct cifs_tcon *tcon, 547 + struct cifs_sb_info *cifs_sb, 548 + const char *full_path, 549 + struct cifs_open_info_data *data) 548 550 { 549 551 int rc; 550 552 FILE_ALL_INFO fi = {}; 551 553 552 - *symlink = false; 554 + data->symlink = false; 555 + data->adjust_tz = false; 553 556 554 557 /* could do find first instead but this returns more info */ 555 558 rc = CIFSSMBQPathInfo(xid, tcon, full_path, &fi, 0 /* not legacy */, cifs_sb->local_nls, ··· 565 562 if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) { 566 563 rc = SMBQueryInformation(xid, tcon, full_path, &fi, cifs_sb->local_nls, 567 564 cifs_remap(cifs_sb)); 568 - *adjustTZ = true; 565 + data->adjust_tz = true; 569 566 } 570 567 571 568 if (!rc) { ··· 592 589 /* Need to check if this is a symbolic link or not */ 593 590 tmprc = CIFS_open(xid, &oparms, &oplock, NULL); 594 591 if (tmprc == -EOPNOTSUPP) 595 - *symlink = true; 592 + data->symlink = true; 596 593 else if (tmprc == 0) 597 594 CIFSSMBClose(xid, tcon, fid.netfid); 598 595 } ··· 972 969 #endif 973 970 } 974 971 975 - static int 976 - cifs_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, 977 - struct cifs_sb_info *cifs_sb, const char *full_path, 978 - char **target_path, bool is_reparse_point) 972 + static int cifs_query_symlink(const unsigned int xid, 973 + struct cifs_tcon *tcon, 974 + struct cifs_sb_info *cifs_sb, 975 + const char *full_path, 976 + char **target_path, 977 + struct kvec *rsp_iov) 979 978 { 980 979 int rc; 981 980 int oplock = 0; 981 + bool is_reparse_point = !!rsp_iov; 982 982 struct cifs_fid fid; 983 983 struct cifs_open_parms oparms; 984 984
+114 -87
fs/smb/client/smb2inode.c
··· 35 35 SMB2_close_free(&rqst[2]); 36 36 } 37 37 38 - 39 - struct cop_vars { 40 - struct cifs_open_parms oparms; 41 - struct kvec rsp_iov[3]; 42 - struct smb_rqst rqst[3]; 43 - struct kvec open_iov[SMB2_CREATE_IOV_SIZE]; 44 - struct kvec qi_iov[1]; 45 - struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE]; 46 - struct kvec close_iov[1]; 47 - struct smb2_file_rename_info rename_info; 48 - struct smb2_file_link_info link_info; 49 - }; 50 - 51 38 /* 52 39 * note: If cfile is passed, the reference to it is dropped here. 53 40 * So make sure that you do not reuse cfile after return from this func. 54 41 * 55 - * If passing @err_iov and @err_buftype, ensure to make them both large enough (>= 3) to hold all 56 - * error responses. Caller is also responsible for freeing them up. 42 + * If passing @out_iov and @out_buftype, ensure to make them both large enough 43 + * (>= 3) to hold all compounded responses. Caller is also responsible for 44 + * freeing them up with free_rsp_buf(). 57 45 */ 58 46 static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, 59 47 struct cifs_sb_info *cifs_sb, const char *full_path, 60 48 __u32 desired_access, __u32 create_disposition, __u32 create_options, 61 49 umode_t mode, void *ptr, int command, struct cifsFileInfo *cfile, 62 50 __u8 **extbuf, size_t *extbuflen, 63 - struct kvec *err_iov, int *err_buftype) 51 + struct kvec *out_iov, int *out_buftype) 64 52 { 65 - struct cop_vars *vars = NULL; 53 + struct smb2_compound_vars *vars = NULL; 66 54 struct kvec *rsp_iov; 67 55 struct smb_rqst *rqst; 68 56 int rc; ··· 121 133 /* Operation */ 122 134 switch (command) { 123 135 case SMB2_OP_QUERY_INFO: 124 - rqst[num_rqst].rq_iov = &vars->qi_iov[0]; 136 + rqst[num_rqst].rq_iov = &vars->qi_iov; 125 137 rqst[num_rqst].rq_nvec = 1; 126 138 127 139 if (cfile) ··· 155 167 full_path); 156 168 break; 157 169 case SMB2_OP_POSIX_QUERY_INFO: 158 - rqst[num_rqst].rq_iov = &vars->qi_iov[0]; 170 + rqst[num_rqst].rq_iov = &vars->qi_iov; 159 171 rqst[num_rqst].rq_nvec = 1; 160 172 161 173 if (cfile) ··· 363 375 goto after_close; 364 376 /* Close */ 365 377 flags |= CIFS_CP_CREATE_CLOSE_OP; 366 - rqst[num_rqst].rq_iov = &vars->close_iov[0]; 378 + rqst[num_rqst].rq_iov = &vars->close_iov; 367 379 rqst[num_rqst].rq_nvec = 1; 368 380 rc = SMB2_close_init(tcon, server, 369 381 &rqst[num_rqst], COMPOUND_FID, ··· 517 529 if (cfile) 518 530 cifsFileInfo_put(cfile); 519 531 520 - if (rc && err_iov && err_buftype) { 521 - memcpy(err_iov, rsp_iov, 3 * sizeof(*err_iov)); 522 - memcpy(err_buftype, resp_buftype, 3 * sizeof(*err_buftype)); 532 + if (out_iov && out_buftype) { 533 + memcpy(out_iov, rsp_iov, 3 * sizeof(*out_iov)); 534 + memcpy(out_buftype, resp_buftype, 3 * sizeof(*out_buftype)); 523 535 } else { 524 536 free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base); 525 537 free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base); ··· 529 541 return rc; 530 542 } 531 543 532 - int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, 533 - struct cifs_sb_info *cifs_sb, const char *full_path, 534 - struct cifs_open_info_data *data, bool *adjust_tz, bool *reparse) 544 + static int parse_create_response(struct cifs_open_info_data *data, 545 + struct cifs_sb_info *cifs_sb, 546 + const struct kvec *iov) 547 + { 548 + struct smb2_create_rsp *rsp = iov->iov_base; 549 + bool reparse_point = false; 550 + u32 tag = 0; 551 + int rc = 0; 552 + 553 + switch (rsp->hdr.Status) { 554 + case STATUS_STOPPED_ON_SYMLINK: 555 + rc = smb2_parse_symlink_response(cifs_sb, iov, 556 + &data->symlink_target); 557 + if (rc) 558 + return rc; 559 + tag = IO_REPARSE_TAG_SYMLINK; 560 + reparse_point = true; 561 + break; 562 + case STATUS_SUCCESS: 563 + reparse_point = !!(rsp->Flags & SMB2_CREATE_FLAG_REPARSEPOINT); 564 + break; 565 + } 566 + data->reparse_point = reparse_point; 567 + data->reparse_tag = tag; 568 + return rc; 569 + } 570 + 571 + int smb2_query_path_info(const unsigned int xid, 572 + struct cifs_tcon *tcon, 573 + struct cifs_sb_info *cifs_sb, 574 + const char *full_path, 575 + struct cifs_open_info_data *data) 535 576 { 536 577 __u32 create_options = 0; 537 578 struct cifsFileInfo *cfile; 538 579 struct cached_fid *cfid = NULL; 539 - struct kvec err_iov[3] = {}; 540 - int err_buftype[3] = {}; 580 + struct smb2_hdr *hdr; 581 + struct kvec out_iov[3] = {}; 582 + int out_buftype[3] = {}; 541 583 bool islink; 542 584 int rc, rc2; 543 585 544 - *adjust_tz = false; 545 - *reparse = false; 586 + data->adjust_tz = false; 587 + data->reparse_point = false; 546 588 547 589 if (strcmp(full_path, "")) 548 590 rc = -ENOENT; ··· 593 575 cifs_get_readable_path(tcon, full_path, &cfile); 594 576 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES, FILE_OPEN, 595 577 create_options, ACL_NO_MODE, data, SMB2_OP_QUERY_INFO, cfile, 596 - NULL, NULL, err_iov, err_buftype); 597 - if (rc) { 598 - struct smb2_hdr *hdr = err_iov[0].iov_base; 578 + NULL, NULL, out_iov, out_buftype); 579 + hdr = out_iov[0].iov_base; 580 + /* 581 + * If first iov is unset, then SMB session was dropped or we've got a 582 + * cached open file (@cfile). 583 + */ 584 + if (!hdr || out_buftype[0] == CIFS_NO_BUFFER) 585 + goto out; 599 586 600 - if (unlikely(!hdr || err_buftype[0] == CIFS_NO_BUFFER)) 587 + switch (rc) { 588 + case 0: 589 + case -EOPNOTSUPP: 590 + rc = parse_create_response(data, cifs_sb, &out_iov[0]); 591 + if (rc || !data->reparse_point) 601 592 goto out; 602 - if (rc == -EOPNOTSUPP && hdr->Command == SMB2_CREATE && 603 - hdr->Status == STATUS_STOPPED_ON_SYMLINK) { 604 - rc = smb2_parse_symlink_response(cifs_sb, err_iov, 605 - &data->symlink_target); 606 - if (rc) 607 - goto out; 608 593 609 - *reparse = true; 610 - create_options |= OPEN_REPARSE_POINT; 611 - 612 - /* Failed on a symbolic link - query a reparse point info */ 613 - cifs_get_readable_path(tcon, full_path, &cfile); 614 - rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 615 - FILE_READ_ATTRIBUTES, FILE_OPEN, 616 - create_options, ACL_NO_MODE, data, 617 - SMB2_OP_QUERY_INFO, cfile, NULL, NULL, 618 - NULL, NULL); 594 + create_options |= OPEN_REPARSE_POINT; 595 + /* Failed on a symbolic link - query a reparse point info */ 596 + cifs_get_readable_path(tcon, full_path, &cfile); 597 + rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 598 + FILE_READ_ATTRIBUTES, FILE_OPEN, 599 + create_options, ACL_NO_MODE, data, 600 + SMB2_OP_QUERY_INFO, cfile, NULL, NULL, 601 + NULL, NULL); 602 + break; 603 + case -EREMOTE: 604 + break; 605 + default: 606 + if (hdr->Status != STATUS_OBJECT_NAME_INVALID) 607 + break; 608 + rc2 = cifs_inval_name_dfs_link_error(xid, tcon, cifs_sb, 609 + full_path, &islink); 610 + if (rc2) { 611 + rc = rc2; 619 612 goto out; 620 - } else if (rc != -EREMOTE && hdr->Status == STATUS_OBJECT_NAME_INVALID) { 621 - rc2 = cifs_inval_name_dfs_link_error(xid, tcon, cifs_sb, 622 - full_path, &islink); 623 - if (rc2) { 624 - rc = rc2; 625 - goto out; 626 - } 627 - if (islink) 628 - rc = -EREMOTE; 629 613 } 614 + if (islink) 615 + rc = -EREMOTE; 630 616 } 631 617 632 618 out: 633 - free_rsp_buf(err_buftype[0], err_iov[0].iov_base); 634 - free_rsp_buf(err_buftype[1], err_iov[1].iov_base); 635 - free_rsp_buf(err_buftype[2], err_iov[2].iov_base); 619 + free_rsp_buf(out_buftype[0], out_iov[0].iov_base); 620 + free_rsp_buf(out_buftype[1], out_iov[1].iov_base); 621 + free_rsp_buf(out_buftype[2], out_iov[2].iov_base); 636 622 return rc; 637 623 } 638 624 639 - 640 - int smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, 641 - struct cifs_sb_info *cifs_sb, const char *full_path, 625 + int smb311_posix_query_path_info(const unsigned int xid, 626 + struct cifs_tcon *tcon, 627 + struct cifs_sb_info *cifs_sb, 628 + const char *full_path, 642 629 struct cifs_open_info_data *data, 643 630 struct cifs_sid *owner, 644 - struct cifs_sid *group, 645 - bool *adjust_tz, bool *reparse) 631 + struct cifs_sid *group) 646 632 { 647 633 int rc; 648 634 __u32 create_options = 0; 649 635 struct cifsFileInfo *cfile; 650 - struct kvec err_iov[3] = {}; 651 - int err_buftype[3] = {}; 636 + struct kvec out_iov[3] = {}; 637 + int out_buftype[3] = {}; 652 638 __u8 *sidsbuf = NULL; 653 639 __u8 *sidsbuf_end = NULL; 654 640 size_t sidsbuflen = 0; 655 641 size_t owner_len, group_len; 656 642 657 - *adjust_tz = false; 658 - *reparse = false; 643 + data->adjust_tz = false; 644 + data->reparse_point = false; 659 645 660 646 /* 661 647 * BB TODO: Add support for using the cached root handle. ··· 671 649 cifs_get_readable_path(tcon, full_path, &cfile); 672 650 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES, FILE_OPEN, 673 651 create_options, ACL_NO_MODE, data, SMB2_OP_POSIX_QUERY_INFO, cfile, 674 - &sidsbuf, &sidsbuflen, err_iov, err_buftype); 675 - if (rc == -EOPNOTSUPP) { 676 - /* BB TODO: When support for special files added to Samba re-verify this path */ 677 - if (err_iov[0].iov_base && err_buftype[0] != CIFS_NO_BUFFER && 678 - ((struct smb2_hdr *)err_iov[0].iov_base)->Command == SMB2_CREATE && 679 - ((struct smb2_hdr *)err_iov[0].iov_base)->Status == STATUS_STOPPED_ON_SYMLINK) { 680 - rc = smb2_parse_symlink_response(cifs_sb, err_iov, &data->symlink_target); 681 - if (rc) 682 - goto out; 683 - } 684 - *reparse = true; 685 - create_options |= OPEN_REPARSE_POINT; 652 + &sidsbuf, &sidsbuflen, out_iov, out_buftype); 653 + /* 654 + * If first iov is unset, then SMB session was dropped or we've got a 655 + * cached open file (@cfile). 656 + */ 657 + if (!out_iov[0].iov_base || out_buftype[0] == CIFS_NO_BUFFER) 658 + goto out; 686 659 660 + switch (rc) { 661 + case 0: 662 + case -EOPNOTSUPP: 663 + /* BB TODO: When support for special files added to Samba re-verify this path */ 664 + rc = parse_create_response(data, cifs_sb, &out_iov[0]); 665 + if (rc || !data->reparse_point) 666 + goto out; 667 + 668 + create_options |= OPEN_REPARSE_POINT; 687 669 /* Failed on a symbolic link - query a reparse point info */ 688 670 cifs_get_readable_path(tcon, full_path, &cfile); 689 671 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES, 690 672 FILE_OPEN, create_options, ACL_NO_MODE, data, 691 673 SMB2_OP_POSIX_QUERY_INFO, cfile, 692 674 &sidsbuf, &sidsbuflen, NULL, NULL); 675 + break; 693 676 } 694 677 678 + out: 695 679 if (rc == 0) { 696 680 sidsbuf_end = sidsbuf + sidsbuflen; 697 681 ··· 717 689 memcpy(group, sidsbuf + owner_len, group_len); 718 690 } 719 691 720 - out: 721 692 kfree(sidsbuf); 722 - free_rsp_buf(err_buftype[0], err_iov[0].iov_base); 723 - free_rsp_buf(err_buftype[1], err_iov[1].iov_base); 724 - free_rsp_buf(err_buftype[2], err_iov[2].iov_base); 693 + free_rsp_buf(out_buftype[0], out_iov[0].iov_base); 694 + free_rsp_buf(out_buftype[1], out_iov[1].iov_base); 695 + free_rsp_buf(out_buftype[2], out_iov[2].iov_base); 725 696 return rc; 726 697 } 727 698
+3 -3
fs/smb/client/smb2misc.c
··· 145 145 __u64 mid; 146 146 147 147 /* If server is a channel, select the primary channel */ 148 - pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server; 148 + pserver = SERVER_IS_CHAN(server) ? server->primary_server : server; 149 149 150 150 /* 151 151 * Add function to do table lookup of StructureSize by command ··· 623 623 cifs_dbg(FYI, "Checking for lease break\n"); 624 624 625 625 /* If server is a channel, select the primary channel */ 626 - pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server; 626 + pserver = SERVER_IS_CHAN(server) ? server->primary_server : server; 627 627 628 628 /* look up tcon based on tid & uid */ 629 629 spin_lock(&cifs_tcp_ses_lock); ··· 698 698 cifs_dbg(FYI, "oplock level 0x%x\n", rsp->OplockLevel); 699 699 700 700 /* If server is a channel, select the primary channel */ 701 - pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server; 701 + pserver = SERVER_IS_CHAN(server) ? server->primary_server : server; 702 702 703 703 /* look up tcon based on tid & uid */ 704 704 spin_lock(&cifs_tcp_ses_lock);
+91 -207
fs/smb/client/smb2ops.c
··· 172 172 173 173 spin_lock(&server->req_lock); 174 174 server->credits = val; 175 - if (val == 1) 175 + if (val == 1) { 176 176 server->reconnect_instance++; 177 + /* 178 + * ChannelSequence updated for all channels in primary channel so that consistent 179 + * across SMB3 requests sent on any channel. See MS-SMB2 3.2.4.1 and 3.2.7.1 180 + */ 181 + if (SERVER_IS_CHAN(server)) 182 + server->primary_server->channel_sequence_num++; 183 + else 184 + server->channel_sequence_num++; 185 + } 177 186 scredits = server->credits; 178 187 in_flight = server->in_flight; 179 188 spin_unlock(&server->req_lock); ··· 1084 1075 return rc; 1085 1076 } 1086 1077 1087 - 1088 1078 static int 1089 1079 smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, 1090 1080 const char *path, const char *ea_name, const void *ea_value, 1091 1081 const __u16 ea_value_len, const struct nls_table *nls_codepage, 1092 1082 struct cifs_sb_info *cifs_sb) 1093 1083 { 1084 + struct smb2_compound_vars *vars; 1094 1085 struct cifs_ses *ses = tcon->ses; 1095 1086 struct TCP_Server_Info *server = cifs_pick_channel(ses); 1087 + struct smb_rqst *rqst; 1088 + struct kvec *rsp_iov; 1096 1089 __le16 *utf16_path = NULL; 1097 1090 int ea_name_len = strlen(ea_name); 1098 1091 int flags = CIFS_CP_CREATE_CLOSE_OP; 1099 1092 int len; 1100 - struct smb_rqst rqst[3]; 1101 1093 int resp_buftype[3]; 1102 - struct kvec rsp_iov[3]; 1103 - struct kvec open_iov[SMB2_CREATE_IOV_SIZE]; 1104 1094 struct cifs_open_parms oparms; 1105 1095 __u8 oplock = SMB2_OPLOCK_LEVEL_NONE; 1106 1096 struct cifs_fid fid; 1107 - struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE]; 1108 1097 unsigned int size[1]; 1109 1098 void *data[1]; 1110 1099 struct smb2_file_full_ea_info *ea = NULL; 1111 - struct kvec close_iov[1]; 1112 1100 struct smb2_query_info_rsp *rsp; 1113 1101 int rc, used_len = 0; 1114 1102 ··· 1119 1113 if (!utf16_path) 1120 1114 return -ENOMEM; 1121 1115 1122 - memset(rqst, 0, sizeof(rqst)); 1123 1116 resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER; 1124 - memset(rsp_iov, 0, sizeof(rsp_iov)); 1117 + vars = kzalloc(sizeof(*vars), GFP_KERNEL); 1118 + if (!vars) { 1119 + rc = -ENOMEM; 1120 + goto out_free_path; 1121 + } 1122 + rqst = vars->rqst; 1123 + rsp_iov = vars->rsp_iov; 1125 1124 1126 1125 if (ses->server->ops->query_all_EAs) { 1127 1126 if (!ea_value) { ··· 1171 1160 } 1172 1161 1173 1162 /* Open */ 1174 - memset(&open_iov, 0, sizeof(open_iov)); 1175 - rqst[0].rq_iov = open_iov; 1163 + rqst[0].rq_iov = vars->open_iov; 1176 1164 rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE; 1177 1165 1178 1166 oparms = (struct cifs_open_parms) { ··· 1191 1181 1192 1182 1193 1183 /* Set Info */ 1194 - memset(&si_iov, 0, sizeof(si_iov)); 1195 - rqst[1].rq_iov = si_iov; 1184 + rqst[1].rq_iov = vars->si_iov; 1196 1185 rqst[1].rq_nvec = 1; 1197 1186 1198 1187 len = sizeof(*ea) + ea_name_len + ea_value_len + 1; ··· 1219 1210 smb2_set_next_command(tcon, &rqst[1]); 1220 1211 smb2_set_related(&rqst[1]); 1221 1212 1222 - 1223 1213 /* Close */ 1224 - memset(&close_iov, 0, sizeof(close_iov)); 1225 - rqst[2].rq_iov = close_iov; 1214 + rqst[2].rq_iov = &vars->close_iov; 1226 1215 rqst[2].rq_nvec = 1; 1227 1216 rc = SMB2_close_init(tcon, server, 1228 1217 &rqst[2], COMPOUND_FID, COMPOUND_FID, false); ··· 1235 1228 1236 1229 sea_exit: 1237 1230 kfree(ea); 1238 - kfree(utf16_path); 1239 1231 SMB2_open_free(&rqst[0]); 1240 1232 SMB2_set_info_free(&rqst[1]); 1241 1233 SMB2_close_free(&rqst[2]); 1242 1234 free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base); 1243 1235 free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base); 1244 1236 free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base); 1237 + kfree(vars); 1238 + out_free_path: 1239 + kfree(utf16_path); 1245 1240 return rc; 1246 1241 } 1247 1242 #endif ··· 1455 1446 return rc; 1456 1447 } 1457 1448 1458 - struct iqi_vars { 1459 - struct smb_rqst rqst[3]; 1460 - struct kvec rsp_iov[3]; 1461 - struct kvec open_iov[SMB2_CREATE_IOV_SIZE]; 1462 - struct kvec qi_iov[1]; 1463 - struct kvec io_iov[SMB2_IOCTL_IOV_SIZE]; 1464 - struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE]; 1465 - struct kvec close_iov[1]; 1466 - }; 1467 - 1468 1449 static int 1469 1450 smb2_ioctl_query_info(const unsigned int xid, 1470 1451 struct cifs_tcon *tcon, ··· 1462 1463 __le16 *path, int is_dir, 1463 1464 unsigned long p) 1464 1465 { 1465 - struct iqi_vars *vars; 1466 + struct smb2_compound_vars *vars; 1466 1467 struct smb_rqst *rqst; 1467 1468 struct kvec *rsp_iov; 1468 1469 struct cifs_ses *ses = tcon->ses; ··· 1580 1581 rc = -EINVAL; 1581 1582 goto free_open_req; 1582 1583 } 1583 - rqst[1].rq_iov = &vars->si_iov[0]; 1584 + rqst[1].rq_iov = vars->si_iov; 1584 1585 rqst[1].rq_nvec = 1; 1585 1586 1586 1587 /* MS-FSCC 2.4.13 FileEndOfFileInformation */ ··· 1592 1593 SMB2_O_INFO_FILE, 0, data, size); 1593 1594 free_req1_func = SMB2_set_info_free; 1594 1595 } else if (qi.flags == PASSTHRU_QUERY_INFO) { 1595 - rqst[1].rq_iov = &vars->qi_iov[0]; 1596 + rqst[1].rq_iov = &vars->qi_iov; 1596 1597 rqst[1].rq_nvec = 1; 1597 1598 1598 1599 rc = SMB2_query_info_init(tcon, server, ··· 1614 1615 smb2_set_related(&rqst[1]); 1615 1616 1616 1617 /* Close */ 1617 - rqst[2].rq_iov = &vars->close_iov[0]; 1618 + rqst[2].rq_iov = &vars->close_iov; 1618 1619 rqst[2].rq_nvec = 1; 1619 1620 1620 1621 rc = SMB2_close_init(tcon, server, ··· 2407 2408 return false; 2408 2409 2409 2410 /* If server is a channel, select the primary channel */ 2410 - pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server; 2411 + pserver = SERVER_IS_CHAN(server) ? server->primary_server : server; 2411 2412 2412 2413 spin_lock(&cifs_tcp_ses_lock); 2413 2414 list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) { ··· 2523 2524 struct kvec *rsp, int *buftype, 2524 2525 struct cifs_sb_info *cifs_sb) 2525 2526 { 2527 + struct smb2_compound_vars *vars; 2526 2528 struct cifs_ses *ses = tcon->ses; 2527 2529 struct TCP_Server_Info *server = cifs_pick_channel(ses); 2528 2530 int flags = CIFS_CP_CREATE_CLOSE_OP; 2529 - struct smb_rqst rqst[3]; 2531 + struct smb_rqst *rqst; 2530 2532 int resp_buftype[3]; 2531 - struct kvec rsp_iov[3]; 2532 - struct kvec open_iov[SMB2_CREATE_IOV_SIZE]; 2533 - struct kvec qi_iov[1]; 2534 - struct kvec close_iov[1]; 2533 + struct kvec *rsp_iov; 2535 2534 u8 oplock = SMB2_OPLOCK_LEVEL_NONE; 2536 2535 struct cifs_open_parms oparms; 2537 2536 struct cifs_fid fid; ··· 2546 2549 if (smb3_encryption_required(tcon)) 2547 2550 flags |= CIFS_TRANSFORM_REQ; 2548 2551 2549 - memset(rqst, 0, sizeof(rqst)); 2550 2552 resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER; 2551 - memset(rsp_iov, 0, sizeof(rsp_iov)); 2553 + vars = kzalloc(sizeof(*vars), GFP_KERNEL); 2554 + if (!vars) { 2555 + rc = -ENOMEM; 2556 + goto out_free_path; 2557 + } 2558 + rqst = vars->rqst; 2559 + rsp_iov = vars->rsp_iov; 2552 2560 2553 2561 /* 2554 2562 * We can only call this for things we know are directories. ··· 2562 2560 open_cached_dir(xid, tcon, path, cifs_sb, false, 2563 2561 &cfid); /* cfid null if open dir failed */ 2564 2562 2565 - memset(&open_iov, 0, sizeof(open_iov)); 2566 - rqst[0].rq_iov = open_iov; 2563 + rqst[0].rq_iov = vars->open_iov; 2567 2564 rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE; 2568 2565 2569 2566 oparms = (struct cifs_open_parms) { ··· 2580 2579 goto qic_exit; 2581 2580 smb2_set_next_command(tcon, &rqst[0]); 2582 2581 2583 - memset(&qi_iov, 0, sizeof(qi_iov)); 2584 - rqst[1].rq_iov = qi_iov; 2582 + rqst[1].rq_iov = &vars->qi_iov; 2585 2583 rqst[1].rq_nvec = 1; 2586 2584 2587 2585 if (cfid) { ··· 2607 2607 smb2_set_related(&rqst[1]); 2608 2608 } 2609 2609 2610 - memset(&close_iov, 0, sizeof(close_iov)); 2611 - rqst[2].rq_iov = close_iov; 2610 + rqst[2].rq_iov = &vars->close_iov; 2612 2611 rqst[2].rq_nvec = 1; 2613 2612 2614 2613 rc = SMB2_close_init(tcon, server, ··· 2638 2639 *buftype = resp_buftype[1]; 2639 2640 2640 2641 qic_exit: 2641 - kfree(utf16_path); 2642 2642 SMB2_open_free(&rqst[0]); 2643 2643 SMB2_query_info_free(&rqst[1]); 2644 2644 SMB2_close_free(&rqst[2]); ··· 2645 2647 free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base); 2646 2648 if (cfid) 2647 2649 close_cached_dir(cfid); 2650 + kfree(vars); 2651 + out_free_path: 2652 + kfree(utf16_path); 2648 2653 return rc; 2649 2654 } 2650 2655 ··· 2950 2949 } 2951 2950 } 2952 2951 2953 - static int 2954 - smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, 2955 - struct cifs_sb_info *cifs_sb, const char *full_path, 2956 - char **target_path, bool is_reparse_point) 2952 + static int smb2_query_symlink(const unsigned int xid, 2953 + struct cifs_tcon *tcon, 2954 + struct cifs_sb_info *cifs_sb, 2955 + const char *full_path, 2956 + char **target_path, 2957 + struct kvec *rsp_iov) 2957 2958 { 2958 - int rc; 2959 - __le16 *utf16_path = NULL; 2960 - __u8 oplock = SMB2_OPLOCK_LEVEL_NONE; 2961 - struct cifs_open_parms oparms; 2962 - struct cifs_fid fid; 2963 - struct kvec err_iov = {NULL, 0}; 2964 - struct TCP_Server_Info *server = cifs_pick_channel(tcon->ses); 2965 - int flags = CIFS_CP_CREATE_CLOSE_OP; 2966 - struct smb_rqst rqst[3]; 2967 - int resp_buftype[3]; 2968 - struct kvec rsp_iov[3]; 2969 - struct kvec open_iov[SMB2_CREATE_IOV_SIZE]; 2970 - struct kvec io_iov[SMB2_IOCTL_IOV_SIZE]; 2971 - struct kvec close_iov[1]; 2972 - struct smb2_create_rsp *create_rsp; 2973 - struct smb2_ioctl_rsp *ioctl_rsp; 2974 - struct reparse_data_buffer *reparse_buf; 2975 - int create_options = is_reparse_point ? OPEN_REPARSE_POINT : 0; 2976 - u32 plen; 2959 + struct reparse_data_buffer *buf; 2960 + struct smb2_ioctl_rsp *io = rsp_iov->iov_base; 2961 + u32 plen = le32_to_cpu(io->OutputCount); 2977 2962 2978 2963 cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path); 2979 2964 2980 - *target_path = NULL; 2981 - 2982 - if (smb3_encryption_required(tcon)) 2983 - flags |= CIFS_TRANSFORM_REQ; 2984 - 2985 - memset(rqst, 0, sizeof(rqst)); 2986 - resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER; 2987 - memset(rsp_iov, 0, sizeof(rsp_iov)); 2988 - 2989 - utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb); 2990 - if (!utf16_path) 2991 - return -ENOMEM; 2992 - 2993 - /* Open */ 2994 - memset(&open_iov, 0, sizeof(open_iov)); 2995 - rqst[0].rq_iov = open_iov; 2996 - rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE; 2997 - 2998 - oparms = (struct cifs_open_parms) { 2999 - .tcon = tcon, 3000 - .path = full_path, 3001 - .desired_access = FILE_READ_ATTRIBUTES, 3002 - .disposition = FILE_OPEN, 3003 - .create_options = cifs_create_options(cifs_sb, create_options), 3004 - .fid = &fid, 3005 - }; 3006 - 3007 - rc = SMB2_open_init(tcon, server, 3008 - &rqst[0], &oplock, &oparms, utf16_path); 3009 - if (rc) 3010 - goto querty_exit; 3011 - smb2_set_next_command(tcon, &rqst[0]); 3012 - 3013 - 3014 - /* IOCTL */ 3015 - memset(&io_iov, 0, sizeof(io_iov)); 3016 - rqst[1].rq_iov = io_iov; 3017 - rqst[1].rq_nvec = SMB2_IOCTL_IOV_SIZE; 3018 - 3019 - rc = SMB2_ioctl_init(tcon, server, 3020 - &rqst[1], fid.persistent_fid, 3021 - fid.volatile_fid, FSCTL_GET_REPARSE_POINT, NULL, 0, 3022 - CIFSMaxBufSize - 3023 - MAX_SMB2_CREATE_RESPONSE_SIZE - 3024 - MAX_SMB2_CLOSE_RESPONSE_SIZE); 3025 - if (rc) 3026 - goto querty_exit; 3027 - 3028 - smb2_set_next_command(tcon, &rqst[1]); 3029 - smb2_set_related(&rqst[1]); 3030 - 3031 - 3032 - /* Close */ 3033 - memset(&close_iov, 0, sizeof(close_iov)); 3034 - rqst[2].rq_iov = close_iov; 3035 - rqst[2].rq_nvec = 1; 3036 - 3037 - rc = SMB2_close_init(tcon, server, 3038 - &rqst[2], COMPOUND_FID, COMPOUND_FID, false); 3039 - if (rc) 3040 - goto querty_exit; 3041 - 3042 - smb2_set_related(&rqst[2]); 3043 - 3044 - rc = compound_send_recv(xid, tcon->ses, server, 3045 - flags, 3, rqst, 3046 - resp_buftype, rsp_iov); 3047 - 3048 - create_rsp = rsp_iov[0].iov_base; 3049 - if (create_rsp && create_rsp->hdr.Status) 3050 - err_iov = rsp_iov[0]; 3051 - ioctl_rsp = rsp_iov[1].iov_base; 3052 - 3053 - /* 3054 - * Open was successful and we got an ioctl response. 3055 - */ 3056 - if ((rc == 0) && (is_reparse_point)) { 3057 - /* See MS-FSCC 2.3.23 */ 3058 - 3059 - reparse_buf = (struct reparse_data_buffer *) 3060 - ((char *)ioctl_rsp + 3061 - le32_to_cpu(ioctl_rsp->OutputOffset)); 3062 - plen = le32_to_cpu(ioctl_rsp->OutputCount); 3063 - 3064 - if (plen + le32_to_cpu(ioctl_rsp->OutputOffset) > 3065 - rsp_iov[1].iov_len) { 3066 - cifs_tcon_dbg(VFS, "srv returned invalid ioctl len: %d\n", 3067 - plen); 3068 - rc = -EIO; 3069 - goto querty_exit; 3070 - } 3071 - 3072 - rc = parse_reparse_point(reparse_buf, plen, target_path, 3073 - cifs_sb); 3074 - goto querty_exit; 3075 - } 3076 - 3077 - if (!rc || !err_iov.iov_base) { 3078 - rc = -ENOENT; 3079 - goto querty_exit; 3080 - } 3081 - 3082 - rc = smb2_parse_symlink_response(cifs_sb, &err_iov, target_path); 3083 - 3084 - querty_exit: 3085 - cifs_dbg(FYI, "query symlink rc %d\n", rc); 3086 - kfree(utf16_path); 3087 - SMB2_open_free(&rqst[0]); 3088 - SMB2_ioctl_free(&rqst[1]); 3089 - SMB2_close_free(&rqst[2]); 3090 - free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base); 3091 - free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base); 3092 - free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base); 3093 - return rc; 2965 + buf = (struct reparse_data_buffer *)((u8 *)io + 2966 + le32_to_cpu(io->OutputOffset)); 2967 + return parse_reparse_point(buf, plen, target_path, cifs_sb); 3094 2968 } 3095 2969 3096 - int 3097 - smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon, 3098 - struct cifs_sb_info *cifs_sb, const char *full_path, 3099 - __u32 *tag) 2970 + static int smb2_query_reparse_point(const unsigned int xid, 2971 + struct cifs_tcon *tcon, 2972 + struct cifs_sb_info *cifs_sb, 2973 + const char *full_path, 2974 + u32 *tag, struct kvec *rsp, 2975 + int *rsp_buftype) 3100 2976 { 2977 + struct smb2_compound_vars *vars; 3101 2978 int rc; 3102 2979 __le16 *utf16_path = NULL; 3103 2980 __u8 oplock = SMB2_OPLOCK_LEVEL_NONE; ··· 2983 3104 struct cifs_fid fid; 2984 3105 struct TCP_Server_Info *server = cifs_pick_channel(tcon->ses); 2985 3106 int flags = CIFS_CP_CREATE_CLOSE_OP; 2986 - struct smb_rqst rqst[3]; 3107 + struct smb_rqst *rqst; 2987 3108 int resp_buftype[3]; 2988 - struct kvec rsp_iov[3]; 2989 - struct kvec open_iov[SMB2_CREATE_IOV_SIZE]; 2990 - struct kvec io_iov[SMB2_IOCTL_IOV_SIZE]; 2991 - struct kvec close_iov[1]; 3109 + struct kvec *rsp_iov; 2992 3110 struct smb2_ioctl_rsp *ioctl_rsp; 2993 3111 struct reparse_data_buffer *reparse_buf; 2994 3112 u32 plen; ··· 2995 3119 if (smb3_encryption_required(tcon)) 2996 3120 flags |= CIFS_TRANSFORM_REQ; 2997 3121 2998 - memset(rqst, 0, sizeof(rqst)); 2999 - resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER; 3000 - memset(rsp_iov, 0, sizeof(rsp_iov)); 3001 - 3002 3122 utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb); 3003 3123 if (!utf16_path) 3004 3124 return -ENOMEM; 3125 + 3126 + resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER; 3127 + vars = kzalloc(sizeof(*vars), GFP_KERNEL); 3128 + if (!vars) { 3129 + rc = -ENOMEM; 3130 + goto out_free_path; 3131 + } 3132 + rqst = vars->rqst; 3133 + rsp_iov = vars->rsp_iov; 3005 3134 3006 3135 /* 3007 3136 * setup smb2open - TODO add optimization to call cifs_get_readable_path 3008 3137 * to see if there is a handle already open that we can use 3009 3138 */ 3010 - memset(&open_iov, 0, sizeof(open_iov)); 3011 - rqst[0].rq_iov = open_iov; 3139 + rqst[0].rq_iov = vars->open_iov; 3012 3140 rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE; 3013 3141 3014 3142 oparms = (struct cifs_open_parms) { ··· 3032 3152 3033 3153 3034 3154 /* IOCTL */ 3035 - memset(&io_iov, 0, sizeof(io_iov)); 3036 - rqst[1].rq_iov = io_iov; 3155 + rqst[1].rq_iov = vars->io_iov; 3037 3156 rqst[1].rq_nvec = SMB2_IOCTL_IOV_SIZE; 3038 3157 3039 3158 rc = SMB2_ioctl_init(tcon, server, ··· 3047 3168 smb2_set_next_command(tcon, &rqst[1]); 3048 3169 smb2_set_related(&rqst[1]); 3049 3170 3050 - 3051 3171 /* Close */ 3052 - memset(&close_iov, 0, sizeof(close_iov)); 3053 - rqst[2].rq_iov = close_iov; 3172 + rqst[2].rq_iov = &vars->close_iov; 3054 3173 rqst[2].rq_nvec = 1; 3055 3174 3056 3175 rc = SMB2_close_init(tcon, server, ··· 3083 3206 goto query_rp_exit; 3084 3207 } 3085 3208 *tag = le32_to_cpu(reparse_buf->ReparseTag); 3209 + *rsp = rsp_iov[1]; 3210 + *rsp_buftype = resp_buftype[1]; 3211 + resp_buftype[1] = CIFS_NO_BUFFER; 3086 3212 } 3087 3213 3088 3214 query_rp_exit: 3089 - kfree(utf16_path); 3090 3215 SMB2_open_free(&rqst[0]); 3091 3216 SMB2_ioctl_free(&rqst[1]); 3092 3217 SMB2_close_free(&rqst[2]); 3093 3218 free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base); 3094 3219 free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base); 3095 3220 free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base); 3221 + kfree(vars); 3222 + out_free_path: 3223 + kfree(utf16_path); 3096 3224 return rc; 3097 3225 } 3098 3226 ··· 4283 4401 u8 *ses_enc_key; 4284 4402 4285 4403 /* If server is a channel, select the primary channel */ 4286 - pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server; 4404 + pserver = SERVER_IS_CHAN(server) ? server->primary_server : server; 4287 4405 4288 4406 spin_lock(&cifs_tcp_ses_lock); 4289 4407 list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) { ··· 5181 5299 .can_echo = smb2_can_echo, 5182 5300 .echo = SMB2_echo, 5183 5301 .query_path_info = smb2_query_path_info, 5302 + .query_reparse_point = smb2_query_reparse_point, 5184 5303 .get_srv_inum = smb2_get_srv_inum, 5185 5304 .query_file_info = smb2_query_file_info, 5186 5305 .set_path_size = smb2_set_path_size, ··· 5283 5400 .can_echo = smb2_can_echo, 5284 5401 .echo = SMB2_echo, 5285 5402 .query_path_info = smb2_query_path_info, 5403 + .query_reparse_point = smb2_query_reparse_point, 5286 5404 .get_srv_inum = smb2_get_srv_inum, 5287 5405 .query_file_info = smb2_query_file_info, 5288 5406 .set_path_size = smb2_set_path_size, ··· 5388 5504 .echo = SMB2_echo, 5389 5505 .query_path_info = smb2_query_path_info, 5390 5506 /* WSL tags introduced long after smb2.1, enable for SMB3, 3.11 only */ 5391 - .query_reparse_tag = smb2_query_reparse_tag, 5507 + .query_reparse_point = smb2_query_reparse_point, 5392 5508 .get_srv_inum = smb2_get_srv_inum, 5393 5509 .query_file_info = smb2_query_file_info, 5394 5510 .set_path_size = smb2_set_path_size, ··· 5501 5617 .can_echo = smb2_can_echo, 5502 5618 .echo = SMB2_echo, 5503 5619 .query_path_info = smb2_query_path_info, 5504 - .query_reparse_tag = smb2_query_reparse_tag, 5620 + .query_reparse_point = smb2_query_reparse_point, 5505 5621 .get_srv_inum = smb2_get_srv_inum, 5506 5622 .query_file_info = smb2_query_file_info, 5507 5623 .set_path_size = smb2_set_path_size,
+15 -4
fs/smb/client/smb2pdu.c
··· 88 88 const struct cifs_tcon *tcon, 89 89 struct TCP_Server_Info *server) 90 90 { 91 + struct smb3_hdr_req *smb3_hdr; 91 92 shdr->ProtocolId = SMB2_PROTO_NUMBER; 92 93 shdr->StructureSize = cpu_to_le16(64); 93 94 shdr->Command = smb2_cmd; 95 + if (server->dialect >= SMB30_PROT_ID) { 96 + /* After reconnect SMB3 must set ChannelSequence on subsequent reqs */ 97 + smb3_hdr = (struct smb3_hdr_req *)shdr; 98 + /* if primary channel is not set yet, use default channel for chan sequence num */ 99 + if (SERVER_IS_CHAN(server)) 100 + smb3_hdr->ChannelSequence = 101 + cpu_to_le16(server->primary_server->channel_sequence_num); 102 + else 103 + smb3_hdr->ChannelSequence = cpu_to_le16(server->channel_sequence_num); 104 + } 94 105 if (server) { 95 106 spin_lock(&server->req_lock); 96 107 /* Request up to 10 credits but don't go over the limit. */ ··· 564 553 * secondary channels don't have the hostname field populated 565 554 * use the hostname field in the primary channel instead 566 555 */ 567 - pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server; 556 + pserver = SERVER_IS_CHAN(server) ? server->primary_server : server; 568 557 cifs_server_lock(pserver); 569 558 hostname = pserver->hostname; 570 559 if (hostname && (hostname[0] != 0)) { ··· 2581 2570 2582 2571 /* Do not append the separator if the path is empty */ 2583 2572 if (path[0] != cpu_to_le16(0x0000)) { 2584 - UniStrcat(*out_path, sep); 2585 - UniStrcat(*out_path, path); 2573 + UniStrcat((wchar_t *)*out_path, (wchar_t *)sep); 2574 + UniStrcat((wchar_t *)*out_path, (wchar_t *)path); 2586 2575 } 2587 2576 2588 2577 unload_nls(cp); ··· 3796 3785 bool resched = false; 3797 3786 3798 3787 /* If server is a channel, select the primary channel */ 3799 - pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server; 3788 + pserver = SERVER_IS_CHAN(server) ? server->primary_server : server; 3800 3789 3801 3790 /* Prevent simultaneous reconnects that can corrupt tcon->rlist list */ 3802 3791 mutex_lock(&pserver->reconnect_mutex);
+10 -7
fs/smb/client/smb2proto.h
··· 56 56 extern int smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon, 57 57 struct cifs_sb_info *cifs_sb, const char *path, 58 58 __u32 *reparse_tag); 59 - int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, 60 - struct cifs_sb_info *cifs_sb, const char *full_path, 61 - struct cifs_open_info_data *data, bool *adjust_tz, bool *reparse); 59 + int smb2_query_path_info(const unsigned int xid, 60 + struct cifs_tcon *tcon, 61 + struct cifs_sb_info *cifs_sb, 62 + const char *full_path, 63 + struct cifs_open_info_data *data); 62 64 extern int smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon, 63 65 const char *full_path, __u64 size, 64 66 struct cifs_sb_info *cifs_sb, bool set_alloc); ··· 277 275 struct kvec *rsp, int *buftype, 278 276 struct cifs_sb_info *cifs_sb); 279 277 /* query path info from the server using SMB311 POSIX extensions*/ 280 - int smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, 281 - struct cifs_sb_info *cifs_sb, const char *full_path, 278 + int smb311_posix_query_path_info(const unsigned int xid, 279 + struct cifs_tcon *tcon, 280 + struct cifs_sb_info *cifs_sb, 281 + const char *full_path, 282 282 struct cifs_open_info_data *data, 283 283 struct cifs_sid *owner, 284 - struct cifs_sid *group, 285 - bool *adjust_tz, bool *reparse); 284 + struct cifs_sid *group); 286 285 int posix_info_parse(const void *beg, const void *end, 287 286 struct smb2_posix_info_parsed *out); 288 287 int posix_info_sid_size(const void *beg, const void *end);
+2 -2
fs/smb/client/smb2transport.c
··· 86 86 spin_lock(&cifs_tcp_ses_lock); 87 87 88 88 /* If server is a channel, select the primary channel */ 89 - pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server; 89 + pserver = SERVER_IS_CHAN(server) ? server->primary_server : server; 90 90 91 91 list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) { 92 92 if (ses->Suid == ses_id) ··· 149 149 struct cifs_ses *ses; 150 150 151 151 /* If server is a channel, select the primary channel */ 152 - pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server; 152 + pserver = SERVER_IS_CHAN(server) ? server->primary_server : server; 153 153 154 154 list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) { 155 155 if (ses->Suid != ses_id)
+17 -12
fs/smb/client/transport.c
··· 416 416 return rc; 417 417 } 418 418 419 + struct send_req_vars { 420 + struct smb2_transform_hdr tr_hdr; 421 + struct smb_rqst rqst[MAX_COMPOUND]; 422 + struct kvec iov; 423 + }; 424 + 419 425 static int 420 426 smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, 421 427 struct smb_rqst *rqst, int flags) 422 428 { 423 - struct kvec iov; 424 - struct smb2_transform_hdr *tr_hdr; 425 - struct smb_rqst cur_rqst[MAX_COMPOUND]; 429 + struct send_req_vars *vars; 430 + struct smb_rqst *cur_rqst; 431 + struct kvec *iov; 426 432 int rc; 427 433 428 434 if (!(flags & CIFS_TRANSFORM_REQ)) ··· 442 436 return -EIO; 443 437 } 444 438 445 - tr_hdr = kzalloc(sizeof(*tr_hdr), GFP_NOFS); 446 - if (!tr_hdr) 439 + vars = kzalloc(sizeof(*vars), GFP_NOFS); 440 + if (!vars) 447 441 return -ENOMEM; 442 + cur_rqst = vars->rqst; 443 + iov = &vars->iov; 448 444 449 - memset(&cur_rqst[0], 0, sizeof(cur_rqst)); 450 - memset(&iov, 0, sizeof(iov)); 451 - 452 - iov.iov_base = tr_hdr; 453 - iov.iov_len = sizeof(*tr_hdr); 454 - cur_rqst[0].rq_iov = &iov; 445 + iov->iov_base = &vars->tr_hdr; 446 + iov->iov_len = sizeof(vars->tr_hdr); 447 + cur_rqst[0].rq_iov = iov; 455 448 cur_rqst[0].rq_nvec = 1; 456 449 457 450 rc = server->ops->init_transform_rq(server, num_rqst + 1, ··· 461 456 rc = __smb_send_rqst(server, num_rqst + 1, &cur_rqst[0]); 462 457 smb3_free_compound_rqst(num_rqst, &cur_rqst[1]); 463 458 out: 464 - kfree(tr_hdr); 459 + kfree(vars); 465 460 return rc; 466 461 } 467 462
+22
fs/smb/common/smb2pdu.h
··· 153 153 __u8 Signature[16]; 154 154 } __packed; 155 155 156 + struct smb3_hdr_req { 157 + __le32 ProtocolId; /* 0xFE 'S' 'M' 'B' */ 158 + __le16 StructureSize; /* 64 */ 159 + __le16 CreditCharge; /* MBZ */ 160 + __le16 ChannelSequence; /* See MS-SMB2 3.2.4.1 and 3.2.7.1 */ 161 + __le16 Reserved; 162 + __le16 Command; 163 + __le16 CreditRequest; /* CreditResponse */ 164 + __le32 Flags; 165 + __le32 NextCommand; 166 + __le64 MessageId; 167 + union { 168 + struct { 169 + __le32 ProcessId; 170 + __le32 TreeId; 171 + } __packed SyncId; 172 + __le64 AsyncId; 173 + } __packed Id; 174 + __le64 SessionId; 175 + __u8 Signature[16]; 176 + } __packed; 177 + 156 178 struct smb2_pdu { 157 179 struct smb2_hdr hdr; 158 180 __le16 StructureSize2; /* size of wct area (varies, request specific) */
+1
fs/smb/server/Kconfig
··· 5 5 depends on FILE_LOCKING 6 6 select NLS 7 7 select NLS_UTF8 8 + select NLS_UCS2_UTILS 8 9 select CRYPTO 9 10 select CRYPTO_MD5 10 11 select CRYPTO_HMAC
-1
fs/smb/server/unicode.c
··· 11 11 #include <asm/unaligned.h> 12 12 #include "glob.h" 13 13 #include "unicode.h" 14 - #include "uniupr.h" 15 14 #include "smb_common.h" 16 15 17 16 /*
+4 -321
fs/smb/server/unicode.h
··· 18 18 * This is a compressed table of upper and lower case conversion. 19 19 * 20 20 */ 21 - #ifndef _CIFS_UNICODE_H 22 - #define _CIFS_UNICODE_H 21 + #ifndef _SMB_UNICODE_H 22 + #define _SMB_UNICODE_H 23 23 24 24 #include <asm/byteorder.h> 25 25 #include <linux/types.h> 26 26 #include <linux/nls.h> 27 27 #include <linux/unicode.h> 28 - 29 - #define UNIUPR_NOLOWER /* Example to not expand lower case tables */ 30 - 31 - /* 32 - * Windows maps these to the user defined 16 bit Unicode range since they are 33 - * reserved symbols (along with \ and /), otherwise illegal to store 34 - * in filenames in NTFS 35 - */ 36 - #define UNI_ASTERISK ((__u16)('*' + 0xF000)) 37 - #define UNI_QUESTION ((__u16)('?' + 0xF000)) 38 - #define UNI_COLON ((__u16)(':' + 0xF000)) 39 - #define UNI_GRTRTHAN ((__u16)('>' + 0xF000)) 40 - #define UNI_LESSTHAN ((__u16)('<' + 0xF000)) 41 - #define UNI_PIPE ((__u16)('|' + 0xF000)) 42 - #define UNI_SLASH ((__u16)('\\' + 0xF000)) 43 - 44 - /* Just define what we want from uniupr.h. We don't want to define the tables 45 - * in each source file. 46 - */ 47 - #ifndef UNICASERANGE_DEFINED 48 - struct UniCaseRange { 49 - wchar_t start; 50 - wchar_t end; 51 - signed char *table; 52 - }; 53 - #endif /* UNICASERANGE_DEFINED */ 54 - 55 - #ifndef UNIUPR_NOUPPER 56 - extern signed char SmbUniUpperTable[512]; 57 - extern const struct UniCaseRange SmbUniUpperRange[]; 58 - #endif /* UNIUPR_NOUPPER */ 59 - 60 - #ifndef UNIUPR_NOLOWER 61 - extern signed char CifsUniLowerTable[512]; 62 - extern const struct UniCaseRange CifsUniLowerRange[]; 63 - #endif /* UNIUPR_NOLOWER */ 28 + #include "../../nls/nls_ucs2_utils.h" 64 29 65 30 #ifdef __KERNEL__ 66 31 int smb_strtoUTF16(__le16 *to, const char *from, int len, ··· 38 73 char *ksmbd_extract_sharename(struct unicode_map *um, const char *treename); 39 74 #endif 40 75 41 - /* 42 - * UniStrcat: Concatenate the second string to the first 43 - * 44 - * Returns: 45 - * Address of the first string 46 - */ 47 - static inline wchar_t *UniStrcat(wchar_t *ucs1, const wchar_t *ucs2) 48 - { 49 - wchar_t *anchor = ucs1; /* save a pointer to start of ucs1 */ 50 - 51 - while (*ucs1++) 52 - /*NULL*/; /* To end of first string */ 53 - ucs1--; /* Return to the null */ 54 - while ((*ucs1++ = *ucs2++)) 55 - /*NULL*/; /* copy string 2 over */ 56 - return anchor; 57 - } 58 - 59 - /* 60 - * UniStrchr: Find a character in a string 61 - * 62 - * Returns: 63 - * Address of first occurrence of character in string 64 - * or NULL if the character is not in the string 65 - */ 66 - static inline wchar_t *UniStrchr(const wchar_t *ucs, wchar_t uc) 67 - { 68 - while ((*ucs != uc) && *ucs) 69 - ucs++; 70 - 71 - if (*ucs == uc) 72 - return (wchar_t *)ucs; 73 - return NULL; 74 - } 75 - 76 - /* 77 - * UniStrcmp: Compare two strings 78 - * 79 - * Returns: 80 - * < 0: First string is less than second 81 - * = 0: Strings are equal 82 - * > 0: First string is greater than second 83 - */ 84 - static inline int UniStrcmp(const wchar_t *ucs1, const wchar_t *ucs2) 85 - { 86 - while ((*ucs1 == *ucs2) && *ucs1) { 87 - ucs1++; 88 - ucs2++; 89 - } 90 - return (int)*ucs1 - (int)*ucs2; 91 - } 92 - 93 - /* 94 - * UniStrcpy: Copy a string 95 - */ 96 - static inline wchar_t *UniStrcpy(wchar_t *ucs1, const wchar_t *ucs2) 97 - { 98 - wchar_t *anchor = ucs1; /* save the start of result string */ 99 - 100 - while ((*ucs1++ = *ucs2++)) 101 - /*NULL*/; 102 - return anchor; 103 - } 104 - 105 - /* 106 - * UniStrlen: Return the length of a string (in 16 bit Unicode chars not bytes) 107 - */ 108 - static inline size_t UniStrlen(const wchar_t *ucs1) 109 - { 110 - int i = 0; 111 - 112 - while (*ucs1++) 113 - i++; 114 - return i; 115 - } 116 - 117 - /* 118 - * UniStrnlen: Return the length (in 16 bit Unicode chars not bytes) of a 119 - * string (length limited) 120 - */ 121 - static inline size_t UniStrnlen(const wchar_t *ucs1, int maxlen) 122 - { 123 - int i = 0; 124 - 125 - while (*ucs1++) { 126 - i++; 127 - if (i >= maxlen) 128 - break; 129 - } 130 - return i; 131 - } 132 - 133 - /* 134 - * UniStrncat: Concatenate length limited string 135 - */ 136 - static inline wchar_t *UniStrncat(wchar_t *ucs1, const wchar_t *ucs2, size_t n) 137 - { 138 - wchar_t *anchor = ucs1; /* save pointer to string 1 */ 139 - 140 - while (*ucs1++) 141 - /*NULL*/; 142 - ucs1--; /* point to null terminator of s1 */ 143 - while (n-- && (*ucs1 = *ucs2)) { /* copy s2 after s1 */ 144 - ucs1++; 145 - ucs2++; 146 - } 147 - *ucs1 = 0; /* Null terminate the result */ 148 - return anchor; 149 - } 150 - 151 - /* 152 - * UniStrncmp: Compare length limited string 153 - */ 154 - static inline int UniStrncmp(const wchar_t *ucs1, const wchar_t *ucs2, size_t n) 155 - { 156 - if (!n) 157 - return 0; /* Null strings are equal */ 158 - while ((*ucs1 == *ucs2) && *ucs1 && --n) { 159 - ucs1++; 160 - ucs2++; 161 - } 162 - return (int)*ucs1 - (int)*ucs2; 163 - } 164 - 165 - /* 166 - * UniStrncmp_le: Compare length limited string - native to little-endian 167 - */ 168 - static inline int 169 - UniStrncmp_le(const wchar_t *ucs1, const wchar_t *ucs2, size_t n) 170 - { 171 - if (!n) 172 - return 0; /* Null strings are equal */ 173 - while ((*ucs1 == __le16_to_cpu(*ucs2)) && *ucs1 && --n) { 174 - ucs1++; 175 - ucs2++; 176 - } 177 - return (int)*ucs1 - (int)__le16_to_cpu(*ucs2); 178 - } 179 - 180 - /* 181 - * UniStrncpy: Copy length limited string with pad 182 - */ 183 - static inline wchar_t *UniStrncpy(wchar_t *ucs1, const wchar_t *ucs2, size_t n) 184 - { 185 - wchar_t *anchor = ucs1; 186 - 187 - while (n-- && *ucs2) /* Copy the strings */ 188 - *ucs1++ = *ucs2++; 189 - 190 - n++; 191 - while (n--) /* Pad with nulls */ 192 - *ucs1++ = 0; 193 - return anchor; 194 - } 195 - 196 - /* 197 - * UniStrncpy_le: Copy length limited string with pad to little-endian 198 - */ 199 - static inline wchar_t *UniStrncpy_le(wchar_t *ucs1, const wchar_t *ucs2, size_t n) 200 - { 201 - wchar_t *anchor = ucs1; 202 - 203 - while (n-- && *ucs2) /* Copy the strings */ 204 - *ucs1++ = __le16_to_cpu(*ucs2++); 205 - 206 - n++; 207 - while (n--) /* Pad with nulls */ 208 - *ucs1++ = 0; 209 - return anchor; 210 - } 211 - 212 - /* 213 - * UniStrstr: Find a string in a string 214 - * 215 - * Returns: 216 - * Address of first match found 217 - * NULL if no matching string is found 218 - */ 219 - static inline wchar_t *UniStrstr(const wchar_t *ucs1, const wchar_t *ucs2) 220 - { 221 - const wchar_t *anchor1 = ucs1; 222 - const wchar_t *anchor2 = ucs2; 223 - 224 - while (*ucs1) { 225 - if (*ucs1 == *ucs2) { 226 - /* Partial match found */ 227 - ucs1++; 228 - ucs2++; 229 - } else { 230 - if (!*ucs2) /* Match found */ 231 - return (wchar_t *)anchor1; 232 - ucs1 = ++anchor1; /* No match */ 233 - ucs2 = anchor2; 234 - } 235 - } 236 - 237 - if (!*ucs2) /* Both end together */ 238 - return (wchar_t *)anchor1; /* Match found */ 239 - return NULL; /* No match */ 240 - } 241 - 242 - #ifndef UNIUPR_NOUPPER 243 - /* 244 - * UniToupper: Convert a unicode character to upper case 245 - */ 246 - static inline wchar_t UniToupper(register wchar_t uc) 247 - { 248 - register const struct UniCaseRange *rp; 249 - 250 - if (uc < sizeof(SmbUniUpperTable)) { 251 - /* Latin characters */ 252 - return uc + SmbUniUpperTable[uc]; /* Use base tables */ 253 - } 254 - 255 - rp = SmbUniUpperRange; /* Use range tables */ 256 - while (rp->start) { 257 - if (uc < rp->start) /* Before start of range */ 258 - return uc; /* Uppercase = input */ 259 - if (uc <= rp->end) /* In range */ 260 - return uc + rp->table[uc - rp->start]; 261 - rp++; /* Try next range */ 262 - } 263 - return uc; /* Past last range */ 264 - } 265 - 266 - /* 267 - * UniStrupr: Upper case a unicode string 268 - */ 269 - static inline __le16 *UniStrupr(register __le16 *upin) 270 - { 271 - register __le16 *up; 272 - 273 - up = upin; 274 - while (*up) { /* For all characters */ 275 - *up = cpu_to_le16(UniToupper(le16_to_cpu(*up))); 276 - up++; 277 - } 278 - return upin; /* Return input pointer */ 279 - } 280 - #endif /* UNIUPR_NOUPPER */ 281 - 282 - #ifndef UNIUPR_NOLOWER 283 - /* 284 - * UniTolower: Convert a unicode character to lower case 285 - */ 286 - static inline wchar_t UniTolower(register wchar_t uc) 287 - { 288 - register const struct UniCaseRange *rp; 289 - 290 - if (uc < sizeof(CifsUniLowerTable)) { 291 - /* Latin characters */ 292 - return uc + CifsUniLowerTable[uc]; /* Use base tables */ 293 - } 294 - 295 - rp = CifsUniLowerRange; /* Use range tables */ 296 - while (rp->start) { 297 - if (uc < rp->start) /* Before start of range */ 298 - return uc; /* Uppercase = input */ 299 - if (uc <= rp->end) /* In range */ 300 - return uc + rp->table[uc - rp->start]; 301 - rp++; /* Try next range */ 302 - } 303 - return uc; /* Past last range */ 304 - } 305 - 306 - /* 307 - * UniStrlwr: Lower case a unicode string 308 - */ 309 - static inline wchar_t *UniStrlwr(register wchar_t *upin) 310 - { 311 - register wchar_t *up; 312 - 313 - up = upin; 314 - while (*up) { /* For all characters */ 315 - *up = UniTolower(*up); 316 - up++; 317 - } 318 - return upin; /* Return input pointer */ 319 - } 320 - 321 - #endif 322 - 323 - #endif /* _CIFS_UNICODE_H */ 76 + #endif /* _SMB_UNICODE_H */
+17 -139
fs/smb/server/uniupr.h fs/nls/nls_ucs2_utils.c
··· 1 - /* SPDX-License-Identifier: GPL-2.0-or-later */ 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 2 /* 3 3 * Some of the source code in this file came from fs/cifs/uniupr.h 4 4 * Copyright (c) International Business Machines Corp., 2000,2002 5 5 * 6 - * uniupr.h - Unicode compressed case ranges 6 + * Some of the source code in this file came from fs/cifs/cifs_unicode.c 7 + * 8 + * Copyright (c) International Business Machines Corp., 2000,2009 9 + * Modified by Steve French (sfrench@us.ibm.com) 10 + * Modified by Namjae Jeon (linkinjeon@kernel.org) 7 11 * 8 12 */ 9 - #ifndef __KSMBD_UNIUPR_H 10 - #define __KSMBD_UNIUPR_H 13 + #include <linux/fs.h> 14 + #include <linux/module.h> 15 + #include <linux/slab.h> 16 + #include <asm/unaligned.h> 17 + #include "nls_ucs2_utils.h" 11 18 12 - #ifndef UNIUPR_NOUPPER 19 + MODULE_LICENSE("GPL"); 20 + 13 21 /* 14 22 * Latin upper case 15 23 */ 16 - signed char SmbUniUpperTable[512] = { 24 + signed char NlsUniUpperTable[512] = { 17 25 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 000-00f */ 18 26 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 010-01f */ 19 27 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 020-02f */ ··· 59 51 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e0-1ef */ 60 52 0, 0, -1, -2, 0, -1, 0, 0, 0, -1, 0, -1, 0, -1, 0, -1, /* 1f0-1ff */ 61 53 }; 54 + EXPORT_SYMBOL_GPL(NlsUniUpperTable); 62 55 63 56 /* Upper case range - Greek */ 64 57 static signed char UniCaseRangeU03a0[47] = { ··· 135 126 /* 136 127 * Upper Case Range 137 128 */ 138 - const struct UniCaseRange SmbUniUpperRange[] = { 129 + const struct UniCaseRange NlsUniUpperRange[] = { 139 130 {0x03a0, 0x03ce, UniCaseRangeU03a0}, 140 131 {0x0430, 0x045f, UniCaseRangeU0430}, 141 132 {0x0490, 0x04cc, UniCaseRangeU0490}, ··· 143 134 {0xff40, 0xff5a, UniCaseRangeUff40}, 144 135 {0} 145 136 }; 146 - #endif 147 - 148 - #ifndef UNIUPR_NOLOWER 149 - /* 150 - * Latin lower case 151 - */ 152 - signed char CifsUniLowerTable[512] = { 153 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 000-00f */ 154 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 010-01f */ 155 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 020-02f */ 156 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 030-03f */ 157 - 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 158 - 32, 32, 32, /* 040-04f */ 159 - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 0, 0, 160 - 0, 0, 0, /* 050-05f */ 161 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 060-06f */ 162 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 070-07f */ 163 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 080-08f */ 164 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 090-09f */ 165 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0a0-0af */ 166 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0b0-0bf */ 167 - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 168 - 32, 32, 32, 32, /* 0c0-0cf */ 169 - 32, 32, 32, 32, 32, 32, 32, 0, 32, 32, 32, 32, 170 - 32, 32, 32, 0, /* 0d0-0df */ 171 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0e0-0ef */ 172 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0f0-0ff */ 173 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 100-10f */ 174 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 110-11f */ 175 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 120-12f */ 176 - 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, /* 130-13f */ 177 - 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, /* 140-14f */ 178 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 150-15f */ 179 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 160-16f */ 180 - 1, 0, 1, 0, 1, 0, 1, 0, -121, 1, 0, 1, 0, 1, 0, 181 - 0, /* 170-17f */ 182 - 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 79, 183 - 0, /* 180-18f */ 184 - 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, /* 190-19f */ 185 - 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, /* 1a0-1af */ 186 - 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, /* 1b0-1bf */ 187 - 0, 0, 0, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 1, 0, 1, /* 1c0-1cf */ 188 - 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, /* 1d0-1df */ 189 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e0-1ef */ 190 - 0, 2, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1f0-1ff */ 191 - }; 192 - 193 - /* Lower case range - Greek */ 194 - static signed char UniCaseRangeL0380[44] = { 195 - 0, 0, 0, 0, 0, 0, 38, 0, 37, 37, 37, 0, 64, 0, 63, 63, /* 380-38f */ 196 - 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 197 - 32, 32, 32, /* 390-39f */ 198 - 32, 32, 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 199 - }; 200 - 201 - /* Lower case range - Cyrillic */ 202 - static signed char UniCaseRangeL0400[48] = { 203 - 0, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 204 - 0, 80, 80, /* 400-40f */ 205 - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 206 - 32, 32, 32, /* 410-41f */ 207 - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 208 - 32, 32, 32, /* 420-42f */ 209 - }; 210 - 211 - /* Lower case range - Extended cyrillic */ 212 - static signed char UniCaseRangeL0490[60] = { 213 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 490-49f */ 214 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 4a0-4af */ 215 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 4b0-4bf */ 216 - 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 217 - }; 218 - 219 - /* Lower case range - Extended latin and greek */ 220 - static signed char UniCaseRangeL1e00[504] = { 221 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e00-1e0f */ 222 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e10-1e1f */ 223 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e20-1e2f */ 224 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e30-1e3f */ 225 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e40-1e4f */ 226 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e50-1e5f */ 227 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e60-1e6f */ 228 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e70-1e7f */ 229 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e80-1e8f */ 230 - 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 1e90-1e9f */ 231 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ea0-1eaf */ 232 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1eb0-1ebf */ 233 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ec0-1ecf */ 234 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ed0-1edf */ 235 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ee0-1eef */ 236 - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, /* 1ef0-1eff */ 237 - 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f00-1f0f */ 238 - 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, 0, 0, /* 1f10-1f1f */ 239 - 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f20-1f2f */ 240 - 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f30-1f3f */ 241 - 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, 0, 0, /* 1f40-1f4f */ 242 - 0, 0, 0, 0, 0, 0, 0, 0, 0, -8, 0, -8, 0, -8, 0, -8, /* 1f50-1f5f */ 243 - 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f60-1f6f */ 244 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f70-1f7f */ 245 - 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f80-1f8f */ 246 - 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f90-1f9f */ 247 - 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1fa0-1faf */ 248 - 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -74, -74, -9, 0, 0, 0, /* 1fb0-1fbf */ 249 - 0, 0, 0, 0, 0, 0, 0, 0, -86, -86, -86, -86, -9, 0, 250 - 0, 0, /* 1fc0-1fcf */ 251 - 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -100, -100, 0, 0, 0, 0, /* 1fd0-1fdf */ 252 - 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -112, -112, -7, 0, 253 - 0, 0, /* 1fe0-1fef */ 254 - 0, 0, 0, 0, 0, 0, 0, 0, 255 - }; 256 - 257 - /* Lower case range - Wide latin */ 258 - static signed char UniCaseRangeLff20[27] = { 259 - 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 260 - 32, /* ff20-ff2f */ 261 - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 262 - }; 263 - 264 - /* 265 - * Lower Case Range 266 - */ 267 - const struct UniCaseRange CifsUniLowerRange[] = { 268 - {0x0380, 0x03ab, UniCaseRangeL0380}, 269 - {0x0400, 0x042f, UniCaseRangeL0400}, 270 - {0x0490, 0x04cb, UniCaseRangeL0490}, 271 - {0x1e00, 0x1ff7, UniCaseRangeL1e00}, 272 - {0xff20, 0xff3a, UniCaseRangeLff20}, 273 - {0} 274 - }; 275 - #endif 276 - 277 - #endif /* __KSMBD_UNIUPR_H */ 137 + EXPORT_SYMBOL_GPL(NlsUniUpperRange);