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