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 | 3 | tristate "JFS filesystem support" |
| 4 | 4 | select BUFFER_HEAD |
| 5 | 5 | select NLS |
| 6 | + select NLS_UCS2_UTILS | |
| 6 | 7 | select CRC32 |
| 7 | 8 | select LEGACY_DIRECT_IO |
| 8 | 9 | help |
| @@ -9,7 +9,7 @@ jfs-y := super.o file.o inode.o namei.o jfs_mount.o jfs_umount.o \ · 8 unmodified lines | ||
| 9 | 9 | jfs_xtree.o jfs_imap.o jfs_debug.o jfs_dmap.o \ |
| 10 | 10 | jfs_unicode.o jfs_dtree.o jfs_inode.o jfs_discard.o \ |
| 11 | 11 | jfs_extent.o symlink.o jfs_metapage.o \ |
| 12 | − jfs_logmgr.o jfs_txnmgr.o jfs_uniupr.o \ | |
| 12 | + jfs_logmgr.o jfs_txnmgr.o \ | |
| 13 | 13 | resize.o xattr.o ioctl.o |
| 14 | 14 | |
| 15 | 15 | jfs-$(CONFIG_JFS_POSIX_ACL) += acl.o |
| @@ -8,16 +8,9 @@ · 7 unmodified lines | ||
| 8 | 8 | |
| 9 | 9 | #include <linux/slab.h> |
| 10 | 10 | #include <asm/byteorder.h> |
| 11 | +#include "../nls/nls_ucs2_data.h" | |
| 11 | 12 | #include "jfs_types.h" |
| 12 | 13 | |
| 13 | −typedef struct { | |
| 14 | − wchar_t start; | |
| 15 | − wchar_t end; | |
| 16 | − signed char *table; | |
| 17 | −} UNICASERANGE; | |
| 18 | − | |
| 19 | −extern signed char UniUpperTable[512]; | |
| 20 | −extern UNICASERANGE UniUpperRange[]; | |
| 21 | 14 | extern int get_UCSname(struct component_name *, struct dentry *); |
| 22 | 15 | extern int jfs_strfromUCS_le(char *, const __le16 *, int, struct nls_table *); |
| 23 | 16 | |
| @@ -107,12 +100,12 @@ static inline wchar_t *UniStrncpy_from_le(wchar_t * ucs1, const __le16 * ucs2, · 83 unmodified lines | ||
| 107 | 100 | */ |
| 108 | 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 */ | |
| 113 | − return uc + UniUpperTable[uc]; /* Use base tables */ | |
| 105 | + if (uc < sizeof(NlsUniUpperTable)) { /* Latin characters */ | |
| 106 | + return uc + NlsUniUpperTable[uc]; /* Use base tables */ | |
| 114 | 107 | } else { |
| 115 | − rp = UniUpperRange; /* Use range tables */ | |
| 108 | + rp = NlsUniUpperRange; /* Use range tables */ | |
| 116 | 109 | while (rp->start) { |
| 117 | 110 | if (uc < rp->start) /* Before start of range */ |
| 118 | 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 | 617 | input/output character sets. Say Y here for the UTF-8 encoding of |
| 618 | 618 | the Unicode/ISO9646 universal character set. |
| 619 | 619 | |
| 620 | +config NLS_UCS2_UTILS | |
| 621 | + tristate "NLS UCS-2 UTILS" | |
| 622 | + help | |
| 623 | + Set of older UCS-2 conversion utilities and tables used by some | |
| 624 | + filesystems including SMB/CIFS. This includes upper case conversion | |
| 625 | + tables. This will automatically be selected when the filesystem | |
| 626 | + that uses it is selected. | |
| 627 | + | |
| 620 | 628 | endif # NLS |
| @@ -54,3 +54,4 @@ obj-$(CONFIG_NLS_MAC_INUIT) += mac-inuit.o · 53 unmodified lines | ||
| 54 | 54 | obj-$(CONFIG_NLS_MAC_ROMANIAN) += mac-romanian.o |
| 55 | 55 | obj-$(CONFIG_NLS_MAC_ROMAN) += mac-roman.o |
| 56 | 56 | obj-$(CONFIG_NLS_MAC_TURKISH) += mac-turkish.o |
| 57 | +obj-$(CONFIG_NLS_UCS2_UTILS) += nls_ucs2_utils.o | |
| @@ -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 | 3 | * Some of the source code in this file came from fs/cifs/uniupr.h |
| 4 | 4 | * Copyright (c) International Business Machines Corp., 2000,2002 |
| 5 | 5 | * |
| 6 | − * uniupr.h - Unicode compressed case ranges | |
| 6 | + * Some of the source code in this file came from fs/cifs/cifs_unicode.c | |
| 7 | + * | |
| 8 | + * Copyright (c) International Business Machines Corp., 2000,2009 | |
| 9 | + * Modified by Steve French (sfrench@us.ibm.com) | |
| 10 | + * Modified by Namjae Jeon (linkinjeon@kernel.org) | |
| 7 | 11 | * |
| 8 | 12 | */ |
| 9 | −#ifndef __KSMBD_UNIUPR_H | |
| 10 | −#define __KSMBD_UNIUPR_H | |
| 13 | +#include <linux/fs.h> | |
| 14 | +#include <linux/module.h> | |
| 15 | +#include <linux/slab.h> | |
| 16 | +#include <asm/unaligned.h> | |
| 17 | +#include "nls_ucs2_utils.h" | |
| 18 | + | |
| 19 | +MODULE_LICENSE("GPL"); | |
| 11 | 20 | |
| 12 | −#ifndef UNIUPR_NOUPPER | |
| 13 | 21 | /* |
| 14 | 22 | * Latin upper case |
| 15 | 23 | */ |
| 16 | −signed char SmbUniUpperTable[512] = { | |
| 24 | +signed char NlsUniUpperTable[512] = { | |
| 17 | 25 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 000-00f */ |
| 18 | 26 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 010-01f */ |
| 19 | 27 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 020-02f */ |
| @@ -51,6 +59,7 @@ signed char SmbUniUpperTable[512] = { · 31 unmodified lines | ||
| 51 | 59 | 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e0-1ef */ |
| 52 | 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 | 64 | /* Upper case range - Greek */ |
| 56 | 65 | static signed char UniCaseRangeU03a0[47] = { |
| @@ -126,7 +135,7 @@ static signed char UniCaseRangeUff40[27] = { · 69 unmodified lines | ||
| 126 | 135 | /* |
| 127 | 136 | * Upper Case Range |
| 128 | 137 | */ |
| 129 | −const struct UniCaseRange SmbUniUpperRange[] = { | |
| 138 | +const struct UniCaseRange NlsUniUpperRange[] = { | |
| 130 | 139 | {0x03a0, 0x03ce, UniCaseRangeU03a0}, |
| 131 | 140 | {0x0430, 0x045f, UniCaseRangeU0430}, |
| 132 | 141 | {0x0490, 0x04cc, UniCaseRangeU0490}, |
| @@ -134,135 +143,4 @@ const struct UniCaseRange SmbUniUpperRange[] = { · 1 unmodified line | ||
| 134 | 143 | {0xff40, 0xff5a, UniCaseRangeUff40}, |
| 135 | 144 | {0} |
| 136 | 145 | }; |
| 137 | −#endif | |
| 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 */ | |
| 146 | +EXPORT_SYMBOL_GPL(NlsUniUpperRange); | |
| @@ -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 | 3 | tristate "SMB3 and CIFS support (advanced network filesystem)" |
| 4 | 4 | depends on INET |
| 5 | 5 | select NLS |
| 6 | + select NLS_UCS2_UTILS | |
| 6 | 7 | select CRYPTO |
| 7 | 8 | select CRYPTO_MD5 |
| 8 | 9 | select CRYPTO_SHA256 |
| @@ -11,7 +11,8 @@ cifs-y := trace.o cifsfs.o cifs_debug.o connect.o dir.o file.o \ · 10 unmodified lines | ||
| 11 | 11 | readdir.o ioctl.o sess.o export.o unc.o winucase.o \ |
| 12 | 12 | smb2ops.o smb2maperror.o smb2transport.o \ |
| 13 | 13 | smb2misc.o smb2pdu.o smb2inode.o smb2file.o cifsacl.o fs_context.o \ |
| 14 | − dns_resolve.o cifs_spnego_negtokeninit.asn1.o asn1.o | |
| 14 | + dns_resolve.o cifs_spnego_negtokeninit.asn1.o asn1.o \ | |
| 15 | + namespace.o | |
| 15 | 16 | |
| 16 | 17 | $(obj)/asn1.o: $(obj)/cifs_spnego_negtokeninit.asn1.h |
| 17 | 18 | |
| @@ -21,7 +22,7 @@ cifs-$(CONFIG_CIFS_XATTR) += xattr.o · 3 unmodified lines | ||
| 21 | 22 | |
| 22 | 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 | 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 | 218 | .tcon = tcon, |
| 219 | 219 | .path = path, |
| 220 | 220 | .create_options = cifs_create_options(cifs_sb, CREATE_NOT_FILE), |
| 221 | − .desired_access = FILE_READ_ATTRIBUTES, | |
| 221 | + .desired_access = FILE_READ_DATA | FILE_READ_ATTRIBUTES, | |
| 222 | 222 | .disposition = FILE_OPEN, |
| 223 | 223 | .fid = pfid, |
| 224 | 224 | }; |
| @@ -331,7 +331,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) · 330 unmodified lines | ||
| 331 | 331 | spin_lock(&cifs_tcp_ses_lock); |
| 332 | 332 | list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) { |
| 333 | 333 | /* channel info will be printed as a part of sessions below */ |
| 334 | − if (CIFS_SERVER_IS_CHAN(server)) | |
| 334 | + if (SERVER_IS_CHAN(server)) | |
| 335 | 335 | continue; |
| 336 | 336 | |
| 337 | 337 | c++; |
| @@ -8,7 +8,6 @@ · 7 unmodified lines | ||
| 8 | 8 | #include <linux/slab.h> |
| 9 | 9 | #include "cifs_fs_sb.h" |
| 10 | 10 | #include "cifs_unicode.h" |
| 11 | −#include "cifs_uniupr.h" | |
| 12 | 11 | #include "cifspdu.h" |
| 13 | 12 | #include "cifsglob.h" |
| 14 | 13 | #include "cifs_debug.h" |
| @@ -21,21 +21,7 @@ · 20 unmodified lines | ||
| 21 | 21 | #include <asm/byteorder.h> |
| 22 | 22 | #include <linux/types.h> |
| 23 | 23 | #include <linux/nls.h> |
| 24 | − | |
| 25 | −#define UNIUPR_NOLOWER /* Example to not expand lower case tables */ | |
| 26 | − | |
| 27 | −/* | |
| 28 | − * Windows maps these to the user defined 16 bit Unicode range since they are | |
| 29 | − * reserved symbols (along with \ and /), otherwise illegal to store | |
| 30 | − * in filenames in NTFS | |
| 31 | − */ | |
| 32 | −#define UNI_ASTERISK (__u16) ('*' + 0xF000) | |
| 33 | −#define UNI_QUESTION (__u16) ('?' + 0xF000) | |
| 34 | −#define UNI_COLON (__u16) (':' + 0xF000) | |
| 35 | −#define UNI_GRTRTHAN (__u16) ('>' + 0xF000) | |
| 36 | −#define UNI_LESSTHAN (__u16) ('<' + 0xF000) | |
| 37 | −#define UNI_PIPE (__u16) ('|' + 0xF000) | |
| 38 | −#define UNI_SLASH (__u16) ('\\' + 0xF000) | |
| 24 | +#include "../../nls/nls_ucs2_utils.h" | |
| 39 | 25 | |
| 40 | 26 | /* |
| 41 | 27 | * Macs use an older "SFM" mapping of the symbols above. Fortunately it does |
| @@ -68,27 +54,6 @@ · 26 unmodified lines | ||
| 68 | 54 | #define SFM_MAP_UNI_RSVD 1 |
| 69 | 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 | 57 | #ifdef __KERNEL__ |
| 93 | 58 | int cifs_from_utf16(char *to, const __le16 *from, int tolen, int fromlen, |
| 94 | 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 | 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 | 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 | 1805 | cifs_dbg(NOISY, "exit_smb3\n"); |
| 1806 | 1806 | unregister_filesystem(&cifs_fs_type); |
| 1807 | 1807 | unregister_filesystem(&smb3_fs_type); |
| 1808 | − cifs_dfs_release_automount_timer(); | |
| 1808 | + cifs_release_automount_timer(); | |
| 1809 | 1809 | exit_cifs_idmap(); |
| 1810 | 1810 | #ifdef CONFIG_CIFS_SWN_UPCALL |
| 1811 | 1811 | cifs_genl_exit(); |
| @@ -81,7 +81,7 @@ extern int cifs_fiemap(struct inode *, struct fiemap_extent_info *, u64 start, · 80 unmodified lines | ||
| 81 | 81 | |
| 82 | 82 | extern const struct inode_operations cifs_file_inode_ops; |
| 83 | 83 | extern const struct inode_operations cifs_symlink_inode_ops; |
| 84 | −extern const struct inode_operations cifs_dfs_referral_inode_operations; | |
| 84 | +extern const struct inode_operations cifs_namespace_inode_operations; | |
| 85 | 85 | |
| 86 | 86 | |
| 87 | 87 | /* Functions related to files and directories */ |
| @@ -118,14 +118,7 @@ extern void cifs_pages_write_redirty(struct inode *inode, loff_t start, unsigned · 30 unmodified lines | ||
| 118 | 118 | extern const struct dentry_operations cifs_dentry_ops; |
| 119 | 119 | extern const struct dentry_operations cifs_ci_dentry_ops; |
| 120 | 120 | |
| 121 | −#ifdef CONFIG_CIFS_DFS_UPCALL | |
| 122 | −extern struct vfsmount *cifs_dfs_d_automount(struct path *path); | |
| 123 | −#else | |
| 124 | −static inline struct vfsmount *cifs_dfs_d_automount(struct path *path) | |
| 125 | −{ | |
| 126 | − return ERR_PTR(-EREMOTE); | |
| 127 | −} | |
| 128 | −#endif | |
| 121 | +extern struct vfsmount *cifs_d_automount(struct path *path); | |
| 129 | 122 | |
| 130 | 123 | /* Functions related to symlinks */ |
| 131 | 124 | extern const char *cifs_get_link(struct dentry *, struct inode *, |
| @@ -186,6 +186,12 @@ struct cifs_cred { · 185 unmodified lines | ||
| 186 | 186 | }; |
| 187 | 187 | |
| 188 | 188 | struct cifs_open_info_data { |
| 189 | + bool adjust_tz; | |
| 190 | + union { | |
| 191 | + bool reparse_point; | |
| 192 | + bool symlink; | |
| 193 | + }; | |
| 194 | + __u32 reparse_tag; | |
| 189 | 195 | char *symlink_target; |
| 190 | 196 | union { |
| 191 | 197 | struct smb2_file_all_info fi; |
| @@ -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 | 206 | static inline void cifs_free_open_info(struct cifs_open_info_data *data) |
| 197 | 207 | { |
| 198 | 208 | kfree(data->symlink_target); |
| @@ -318,16 +328,21 @@ struct smb_version_operations { · 119 unmodified lines | ||
| 318 | 328 | int (*is_path_accessible)(const unsigned int, struct cifs_tcon *, |
| 319 | 329 | struct cifs_sb_info *, const char *); |
| 320 | 330 | /* query path data from the server */ |
| 321 | − int (*query_path_info)(const unsigned int xid, struct cifs_tcon *tcon, | |
| 322 | − struct cifs_sb_info *cifs_sb, const char *full_path, | |
| 323 | − struct cifs_open_info_data *data, bool *adjust_tz, bool *reparse); | |
| 331 | + int (*query_path_info)(const unsigned int xid, | |
| 332 | + struct cifs_tcon *tcon, | |
| 333 | + struct cifs_sb_info *cifs_sb, | |
| 334 | + const char *full_path, | |
| 335 | + struct cifs_open_info_data *data); | |
| 324 | 336 | /* query file data from the server */ |
| 325 | 337 | int (*query_file_info)(const unsigned int xid, struct cifs_tcon *tcon, |
| 326 | 338 | struct cifsFileInfo *cfile, struct cifs_open_info_data *data); |
| 327 | − /* query reparse tag from srv to determine which type of special file */ | |
| 328 | − int (*query_reparse_tag)(const unsigned int xid, struct cifs_tcon *tcon, | |
| 329 | − struct cifs_sb_info *cifs_sb, const char *path, | |
| 330 | − __u32 *reparse_tag); | |
| 339 | + /* query reparse point to determine which type of special file */ | |
| 340 | + int (*query_reparse_point)(const unsigned int xid, | |
| 341 | + struct cifs_tcon *tcon, | |
| 342 | + struct cifs_sb_info *cifs_sb, | |
| 343 | + const char *full_path, | |
| 344 | + u32 *tag, struct kvec *rsp, | |
| 345 | + int *rsp_buftype); | |
| 331 | 346 | /* get server index number */ |
| 332 | 347 | int (*get_srv_inum)(const unsigned int xid, struct cifs_tcon *tcon, |
| 333 | 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 | 391 | const char *, const char *, |
| 377 | 392 | struct cifs_sb_info *); |
| 378 | 393 | /* query symlink target */ |
| 379 | − int (*query_symlink)(const unsigned int, struct cifs_tcon *, | |
| 380 | − struct cifs_sb_info *, const char *, | |
| 381 | − char **, bool); | |
| 394 | + int (*query_symlink)(const unsigned int xid, | |
| 395 | + struct cifs_tcon *tcon, | |
| 396 | + struct cifs_sb_info *cifs_sb, | |
| 397 | + const char *full_path, | |
| 398 | + char **target_path, | |
| 399 | + struct kvec *rsp_iov); | |
| 382 | 400 | /* open a file for non-posix mounts */ |
| 383 | 401 | int (*open)(const unsigned int xid, struct cifs_open_parms *oparms, __u32 *oplock, |
| 384 | 402 | void *buf); |
| @@ -727,8 +745,9 @@ struct TCP_Server_Info { · 342 unmodified lines | ||
| 727 | 745 | * primary_server holds the ref-counted |
| 728 | 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 | 749 | struct TCP_Server_Info *primary_server; |
| 750 | + __u16 channel_sequence_num; /* incremented on primary channel on each chan reconnect */ | |
| 732 | 751 | |
| 733 | 752 | #ifdef CONFIG_CIFS_SWN_UPCALL |
| 734 | 753 | bool use_swn_dstaddr; |
| @@ -1076,7 +1095,7 @@ cap_unix(struct cifs_ses *ses) · 341 unmodified lines | ||
| 1076 | 1095 | * inode with new info |
| 1077 | 1096 | */ |
| 1078 | 1097 | |
| 1079 | −#define CIFS_FATTR_DFS_REFERRAL 0x1 | |
| 1098 | +#define CIFS_FATTR_JUNCTION 0x1 | |
| 1080 | 1099 | #define CIFS_FATTR_DELETE_PENDING 0x2 |
| 1081 | 1100 | #define CIFS_FATTR_NEED_REVAL 0x4 |
| 1082 | 1101 | #define CIFS_FATTR_INO_COLLISION 0x8 |
| @@ -1721,11 +1740,23 @@ struct cifs_mount_ctx { · 638 unmodified lines | ||
| 1721 | 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 | 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 | 1757 | if (param) { |
| 1727 | − kfree(param->path_name); | |
| 1728 | − kfree(param->node_name); | |
| 1758 | + __free_dfs_info_param(param); | |
| 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 | 2231 | #endif /* _CIFS_GLOB_H */ |
| @@ -207,6 +207,9 @@ extern struct inode *cifs_iget(struct super_block *sb, · 206 unmodified lines | ||
| 207 | 207 | int cifs_get_inode_info(struct inode **inode, const char *full_path, |
| 208 | 208 | struct cifs_open_info_data *data, struct super_block *sb, int xid, |
| 209 | 209 | const struct cifs_fid *fid); |
| 210 | +bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb, | |
| 211 | + struct cifs_fattr *fattr, | |
| 212 | + u32 tag); | |
| 210 | 213 | extern int smb311_posix_get_inode_info(struct inode **pinode, const char *search_path, |
| 211 | 214 | struct super_block *sb, unsigned int xid); |
| 212 | 215 | extern int cifs_get_inode_info_unix(struct inode **pinode, |
| @@ -295,11 +298,7 @@ extern void cifs_put_tcp_session(struct TCP_Server_Info *server, · 82 unmodified lines | ||
| 295 | 298 | int from_reconnect); |
| 296 | 299 | extern void cifs_put_tcon(struct cifs_tcon *tcon); |
| 297 | 300 | |
| 298 | −#if IS_ENABLED(CONFIG_CIFS_DFS_UPCALL) | |
| 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) */ | |
| 301 | +extern void cifs_release_automount_timer(void); | |
| 303 | 302 | |
| 304 | 303 | void cifs_proc_init(void); |
| 305 | 304 | void cifs_proc_clean(void); |
| @@ -154,7 +154,7 @@ cifs_signal_cifsd_for_reconnect(struct TCP_Server_Info *server, · 153 unmodified lines | ||
| 154 | 154 | int i; |
| 155 | 155 | |
| 156 | 156 | /* If server is a channel, select the primary channel */ |
| 157 | − pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server; | |
| 157 | + pserver = SERVER_IS_CHAN(server) ? server->primary_server : server; | |
| 158 | 158 | |
| 159 | 159 | spin_lock(&pserver->srv_lock); |
| 160 | 160 | if (!all_channels) { |
| @@ -202,7 +202,7 @@ cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server, · 41 unmodified lines | ||
| 202 | 202 | cifs_dbg(FYI, "%s: marking necessary sessions and tcons for reconnect\n", __func__); |
| 203 | 203 | |
| 204 | 204 | /* If server is a channel, select the primary channel */ |
| 205 | − pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server; | |
| 205 | + pserver = SERVER_IS_CHAN(server) ? server->primary_server : server; | |
| 206 | 206 | |
| 207 | 207 | |
| 208 | 208 | spin_lock(&cifs_tcp_ses_lock); |
| @@ -453,10 +453,10 @@ static int reconnect_target_unlocked(struct TCP_Server_Info *server, struct dfs_ · 244 unmodified lines | ||
| 453 | 453 | |
| 454 | 454 | static int reconnect_dfs_server(struct TCP_Server_Info *server) |
| 455 | 455 | { |
| 456 | − int rc = 0; | |
| 457 | − struct dfs_cache_tgt_list tl = DFS_CACHE_TGT_LIST_INIT(tl); | |
| 458 | 456 | struct dfs_cache_tgt_iterator *target_hint = NULL; |
| 457 | + DFS_CACHE_TGT_LIST(tl); | |
| 459 | 458 | int num_targets = 0; |
| 459 | + int rc = 0; | |
| 460 | 460 | |
| 461 | 461 | /* |
| 462 | 462 | * Determine the number of dfs targets the referral path in @cifs_sb resolves to. |
| @@ -911,8 +911,8 @@ cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required) · 448 unmodified lines | ||
| 911 | 911 | return 0; |
| 912 | 912 | } |
| 913 | 913 | |
| 914 | − | |
| 915 | −static void clean_demultiplex_info(struct TCP_Server_Info *server) | |
| 914 | +static noinline_for_stack void | |
| 915 | +clean_demultiplex_info(struct TCP_Server_Info *server) | |
| 916 | 916 | { |
| 917 | 917 | int length; |
| 918 | 918 | |
| @@ -1551,7 +1551,7 @@ cifs_find_tcp_session(struct smb3_fs_context *ctx) · 632 unmodified lines | ||
| 1551 | 1551 | * Skip ses channels since they're only handled in lower layers |
| 1552 | 1552 | * (e.g. cifs_send_recv). |
| 1553 | 1553 | */ |
| 1554 | − if (CIFS_SERVER_IS_CHAN(server) || | |
| 1554 | + if (SERVER_IS_CHAN(server) || | |
| 1555 | 1555 | !match_server(server, ctx, false)) { |
| 1556 | 1556 | spin_unlock(&server->srv_lock); |
| 1557 | 1557 | continue; |
| @@ -1587,7 +1587,7 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect) · 29 unmodified lines | ||
| 1587 | 1587 | spin_unlock(&cifs_tcp_ses_lock); |
| 1588 | 1588 | |
| 1589 | 1589 | /* For secondary channels, we pick up ref-count on the primary server */ |
| 1590 | − if (CIFS_SERVER_IS_CHAN(server)) | |
| 1590 | + if (SERVER_IS_CHAN(server)) | |
| 1591 | 1591 | cifs_put_tcp_session(server->primary_server, from_reconnect); |
| 1592 | 1592 | |
| 1593 | 1593 | cancel_delayed_work_sync(&server->echo); |
| @@ -1686,6 +1686,7 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx, · 92 unmodified lines | ||
| 1686 | 1686 | ctx->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL); |
| 1687 | 1687 | tcp_ses->session_estab = false; |
| 1688 | 1688 | tcp_ses->sequence_number = 0; |
| 1689 | + tcp_ses->channel_sequence_num = 0; /* only tracked for primary channel */ | |
| 1689 | 1690 | tcp_ses->reconnect_instance = 1; |
| 1690 | 1691 | tcp_ses->lstrp = jiffies; |
| 1691 | 1692 | tcp_ses->compress_algorithm = cpu_to_le16(ctx->compression); |
| @@ -1792,7 +1793,7 @@ out_err_crypto_release: · 100 unmodified lines | ||
| 1792 | 1793 | |
| 1793 | 1794 | out_err: |
| 1794 | 1795 | if (tcp_ses) { |
| 1795 | − if (CIFS_SERVER_IS_CHAN(tcp_ses)) | |
| 1796 | + if (SERVER_IS_CHAN(tcp_ses)) | |
| 1796 | 1797 | cifs_put_tcp_session(tcp_ses->primary_server, false); |
| 1797 | 1798 | kfree(tcp_ses->hostname); |
| 1798 | 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 | 3814 | struct nls_table *nls_info) |
| 3814 | 3815 | { |
| 3815 | 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 | 3818 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&pserver->dstaddr; |
| 3818 | 3819 | struct sockaddr_in *addr = (struct sockaddr_in *)&pserver->dstaddr; |
| 3819 | 3820 | bool is_binding = false; |
| @@ -3,7 +3,6 @@ · 2 unmodified lines | ||
| 3 | 3 | * Copyright (c) 2022 Paulo Alcantara <palcantara@suse.de> |
| 4 | 4 | */ |
| 5 | 5 | |
| 6 | −#include <linux/namei.h> | |
| 7 | 6 | #include "cifsproto.h" |
| 8 | 7 | #include "cifs_debug.h" |
| 9 | 8 | #include "dns_resolve.h" |
| @@ -96,51 +95,134 @@ static int add_root_smb_session(struct cifs_mount_ctx *mnt_ctx) · 86 unmodified lines | ||
| 96 | 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, | |
| 100 | − const struct dfs_cache_tgt_iterator *tit) | |
| 98 | +static inline int parse_dfs_target(struct smb3_fs_context *ctx, | |
| 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 | 115 | struct smb3_fs_context *ctx = mnt_ctx->fs_ctx; |
| 103 | − struct dfs_info3_param ref = {}; | |
| 104 | − bool is_refsrv; | |
| 105 | − int rc, rc2; | |
| 116 | + struct cifs_sb_info *cifs_sb = mnt_ctx->cifs_sb; | |
| 117 | + char *ref_path, *full_path; | |
| 118 | + int rc; | |
| 106 | 119 | |
| 107 | − rc = dfs_cache_get_tgt_referral(ref_path + 1, tit, &ref); | |
| 108 | − if (rc) | |
| 120 | + full_path = smb3_fs_context_fullpath(ctx, CIFS_DIR_SEP(cifs_sb)); | |
| 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 | 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); | |
| 112 | − if (rc) | |
| 113 | − goto out; | |
| 139 | +static int __dfs_referral_walk(struct cifs_mount_ctx *mnt_ctx, | |
| 140 | + struct dfs_ref_walk *rw) | |
| 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); | |
| 116 | − rc = get_session(mnt_ctx, ref_path); | |
| 117 | − if (rc) | |
| 118 | − goto out; | |
| 147 | +again: | |
| 148 | + do { | |
| 149 | + if (ref_walk_empty(rw)) { | |
| 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; | |
| 123 | − if (ref.flags & DFSREF_STORAGE_SERVER) { | |
| 124 | − rc = cifs_mount_get_tcon(mnt_ctx); | |
| 125 | − if (rc) | |
| 126 | − goto out; | |
| 169 | + cifs_mount_put_conns(mnt_ctx); | |
| 170 | + rc = get_session(mnt_ctx, ref_walk_path(rw)); | |
| 171 | + if (rc) | |
| 172 | + continue; | |
| 127 | 173 | |
| 128 | − /* some servers may not advertise referral capability under ref.flags */ | |
| 129 | − is_refsrv |= is_tcon_dfs(mnt_ctx->tcon); | |
| 174 | + is_refsrv = tgt.server_type == DFS_TYPE_ROOT || | |
| 175 | + DFS_INTERLINK(tgt.flags); | |
| 176 | + ref_walk_set_tgt_hint(rw); | |
| 130 | 177 | |
| 131 | − rc = cifs_is_path_remote(mnt_ctx); | |
| 132 | − } | |
| 178 | + if (tgt.flags & DFSREF_STORAGE_SERVER) { | |
| 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) { | |
| 137 | − rc2 = add_root_smb_session(mnt_ctx); | |
| 138 | − if (rc2) | |
| 139 | − rc = rc2; | |
| 140 | − } | |
| 194 | + rc = ref_walk_advance(rw); | |
| 195 | + if (!rc) { | |
| 196 | + rc = set_ref_paths(mnt_ctx, &tgt, rw); | |
| 197 | + if (!rc) { | |
| 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 | 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 | 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 | 231 | struct cifs_sb_info *cifs_sb = mnt_ctx->cifs_sb; |
| 150 | 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 | 233 | struct cifs_tcon *tcon; |
| 154 | − char *origin_fullpath = NULL; | |
| 155 | − char sep = CIFS_DIR_SEP(cifs_sb); | |
| 156 | − int num_links = 0; | |
| 234 | + char *origin_fullpath; | |
| 157 | 235 | int rc; |
| 158 | 236 | |
| 159 | − ref_path = dfs_get_path(cifs_sb, ctx->UNC); | |
| 160 | − if (IS_ERR(ref_path)) | |
| 161 | − return PTR_ERR(ref_path); | |
| 237 | + origin_fullpath = dfs_get_path(cifs_sb, ctx->source); | |
| 238 | + if (IS_ERR(origin_fullpath)) | |
| 239 | + return PTR_ERR(origin_fullpath); | |
| 162 | 240 | |
| 163 | − full_path = smb3_fs_context_fullpath(ctx, sep); | |
| 164 | − if (IS_ERR(full_path)) { | |
| 165 | − rc = PTR_ERR(full_path); | |
| 166 | − full_path = NULL; | |
| 241 | + rc = dfs_referral_walk(mnt_ctx); | |
| 242 | + if (rc) | |
| 167 | 243 | goto out; |
| 168 | − } | |
| 169 | 244 | |
| 170 | − origin_fullpath = kstrdup(full_path, GFP_KERNEL); | |
| 171 | − if (!origin_fullpath) { | |
| 172 | − rc = -ENOMEM; | |
| 173 | − goto out; | |
| 245 | + tcon = mnt_ctx->tcon; | |
| 246 | + spin_lock(&tcon->tc_lock); | |
| 247 | + if (!tcon->origin_fullpath) { | |
| 248 | + tcon->origin_fullpath = origin_fullpath; | |
| 249 | + origin_fullpath = NULL; | |
| 174 | 250 | } |
| 251 | + spin_unlock(&tcon->tc_lock); | |
| 175 | 252 | |
| 176 | − do { | |
| 177 | − struct dfs_cache_tgt_list tl = DFS_CACHE_TGT_LIST_INIT(tl); | |
| 178 | − | |
| 179 | − rc = dfs_get_referral(mnt_ctx, ref_path + 1, NULL, &tl); | |
| 180 | − if (rc) { | |
| 181 | − rc = cifs_mount_get_tcon(mnt_ctx); | |
| 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 | − } | |
| 253 | + if (list_empty(&tcon->dfs_ses_list)) { | |
| 254 | + list_replace_init(&mnt_ctx->dfs_ses_list, &tcon->dfs_ses_list); | |
| 255 | + queue_delayed_work(dfscache_wq, &tcon->dfs_cache_work, | |
| 256 | + dfs_cache_get_ttl() * HZ); | |
| 257 | + } else { | |
| 258 | + dfs_put_root_smb_sessions(&mnt_ctx->dfs_ses_list); | |
| 244 | 259 | } |
| 245 | 260 | |
| 246 | 261 | out: |
| 247 | 262 | kfree(origin_fullpath); |
| 248 | − kfree(ref_path); | |
| 249 | − kfree(full_path); | |
| 263 | + return rc; | |
| 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 | 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 | 281 | bool nodfs = ctx->nodfs; |
| 257 | 282 | int rc; |
| 258 | 283 | |
| 284 | + rc = update_fs_context_dstaddr(ctx); | |
| 285 | + if (rc) | |
| 286 | + return rc; | |
| 287 | + | |
| 259 | 288 | *isdfs = false; |
| 260 | 289 | rc = get_session(mnt_ctx, NULL); |
| 261 | 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 | 455 | /* Try to tree connect to all dfs targets */ |
| 427 | 456 | for (; tit; tit = dfs_cache_get_next_tgt(tl, tit)) { |
| 428 | 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 | 460 | kfree(share); |
| 432 | 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 | 549 | int rc; |
| 521 | 550 | struct TCP_Server_Info *server = tcon->ses->server; |
| 522 | 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 | 553 | struct cifs_sb_info *cifs_sb = NULL; |
| 525 | 554 | struct super_block *sb = NULL; |
| 526 | 555 | struct dfs_info3_param ref = {0}; |
| @@ -9,6 +9,110 @@ · 8 unmodified lines | ||
| 9 | 9 | #include "cifsglob.h" |
| 10 | 10 | #include "fs_context.h" |
| 11 | 11 | #include "cifs_unicode.h" |
| 12 | +#include <linux/namei.h> | |
| 13 | + | |
| 14 | +#define DFS_INTERLINK(v) \ | |
| 15 | + (((v) & DFSREF_REFERRAL_SERVER) && !((v) & DFSREF_STORAGE_SERVER)) | |
| 16 | + | |
| 17 | +struct dfs_ref { | |
| 18 | + char *path; | |
| 19 | + char *full_path; | |
| 20 | + struct dfs_cache_tgt_list tl; | |
| 21 | + struct dfs_cache_tgt_iterator *tit; | |
| 22 | +}; | |
| 23 | + | |
| 24 | +struct dfs_ref_walk { | |
| 25 | + struct dfs_ref *ref; | |
| 26 | + struct dfs_ref refs[MAX_NESTED_LINKS]; | |
| 27 | +}; | |
| 28 | + | |
| 29 | +#define ref_walk_start(w) ((w)->refs) | |
| 30 | +#define ref_walk_end(w) (&(w)->refs[ARRAY_SIZE((w)->refs) - 1]) | |
| 31 | +#define ref_walk_cur(w) ((w)->ref) | |
| 32 | +#define ref_walk_descend(w) (--ref_walk_cur(w) >= ref_walk_start(w)) | |
| 33 | + | |
| 34 | +#define ref_walk_tit(w) (ref_walk_cur(w)->tit) | |
| 35 | +#define ref_walk_empty(w) (!ref_walk_tit(w)) | |
| 36 | +#define ref_walk_path(w) (ref_walk_cur(w)->path) | |
| 37 | +#define ref_walk_fpath(w) (ref_walk_cur(w)->full_path) | |
| 38 | +#define ref_walk_tl(w) (&ref_walk_cur(w)->tl) | |
| 39 | + | |
| 40 | +static inline struct dfs_ref_walk *ref_walk_alloc(void) | |
| 41 | +{ | |
| 42 | + struct dfs_ref_walk *rw; | |
| 43 | + | |
| 44 | + rw = kmalloc(sizeof(*rw), GFP_KERNEL); | |
| 45 | + if (!rw) | |
| 46 | + return ERR_PTR(-ENOMEM); | |
| 47 | + return rw; | |
| 48 | +} | |
| 49 | + | |
| 50 | +static inline void ref_walk_init(struct dfs_ref_walk *rw) | |
| 51 | +{ | |
| 52 | + memset(rw, 0, sizeof(*rw)); | |
| 53 | + ref_walk_cur(rw) = ref_walk_start(rw); | |
| 54 | +} | |
| 55 | + | |
| 56 | +static inline void __ref_walk_free(struct dfs_ref *ref) | |
| 57 | +{ | |
| 58 | + kfree(ref->path); | |
| 59 | + kfree(ref->full_path); | |
| 60 | + dfs_cache_free_tgts(&ref->tl); | |
| 61 | + memset(ref, 0, sizeof(*ref)); | |
| 62 | +} | |
| 63 | + | |
| 64 | +static inline void ref_walk_free(struct dfs_ref_walk *rw) | |
| 65 | +{ | |
| 66 | + struct dfs_ref *ref = ref_walk_start(rw); | |
| 67 | + | |
| 68 | + for (; ref <= ref_walk_end(rw); ref++) | |
| 69 | + __ref_walk_free(ref); | |
| 70 | + kfree(rw); | |
| 71 | +} | |
| 72 | + | |
| 73 | +static inline int ref_walk_advance(struct dfs_ref_walk *rw) | |
| 74 | +{ | |
| 75 | + struct dfs_ref *ref = ref_walk_cur(rw) + 1; | |
| 76 | + | |
| 77 | + if (ref > ref_walk_end(rw)) | |
| 78 | + return -ELOOP; | |
| 79 | + __ref_walk_free(ref); | |
| 80 | + ref_walk_cur(rw) = ref; | |
| 81 | + return 0; | |
| 82 | +} | |
| 83 | + | |
| 84 | +static inline struct dfs_cache_tgt_iterator * | |
| 85 | +ref_walk_next_tgt(struct dfs_ref_walk *rw) | |
| 86 | +{ | |
| 87 | + struct dfs_cache_tgt_iterator *tit; | |
| 88 | + struct dfs_ref *ref = ref_walk_cur(rw); | |
| 89 | + | |
| 90 | + if (!ref->tit) | |
| 91 | + tit = dfs_cache_get_tgt_iterator(&ref->tl); | |
| 92 | + else | |
| 93 | + tit = dfs_cache_get_next_tgt(&ref->tl, ref->tit); | |
| 94 | + ref->tit = tit; | |
| 95 | + return tit; | |
| 96 | +} | |
| 97 | + | |
| 98 | +static inline int ref_walk_get_tgt(struct dfs_ref_walk *rw, | |
| 99 | + struct dfs_info3_param *tgt) | |
| 100 | +{ | |
| 101 | + zfree_dfs_info_param(tgt); | |
| 102 | + return dfs_cache_get_tgt_referral(ref_walk_path(rw) + 1, | |
| 103 | + ref_walk_tit(rw), tgt); | |
| 104 | +} | |
| 105 | + | |
| 106 | +static inline int ref_walk_num_tgts(struct dfs_ref_walk *rw) | |
| 107 | +{ | |
| 108 | + return dfs_cache_get_nr_tgts(ref_walk_tl(rw)); | |
| 109 | +} | |
| 110 | + | |
| 111 | +static inline void ref_walk_set_tgt_hint(struct dfs_ref_walk *rw) | |
| 112 | +{ | |
| 113 | + dfs_cache_noreq_update_tgthint(ref_walk_path(rw) + 1, | |
| 114 | + ref_walk_tit(rw)); | |
| 115 | +} | |
| 12 | 116 | |
| 13 | 117 | struct dfs_root_ses { |
| 14 | 118 | struct list_head list; |
| @@ -34,43 +138,6 @@ static inline int dfs_get_referral(struct cifs_mount_ctx *mnt_ctx, const char *p · 19 unmodified lines | ||
| 34 | 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 | 141 | static inline void dfs_put_root_smb_sessions(struct list_head *head) |
| 75 | 142 | { |
| 76 | 143 | struct dfs_root_ses *root, *tmp; |
| @@ -29,8 +29,6 @@ · 28 unmodified lines | ||
| 29 | 29 | #define CACHE_MIN_TTL 120 /* 2 minutes */ |
| 30 | 30 | #define CACHE_DEFAULT_TTL 300 /* 5 minutes */ |
| 31 | 31 | |
| 32 | −#define IS_DFS_INTERLINK(v) (((v) & DFSREF_REFERRAL_SERVER) && !((v) & DFSREF_STORAGE_SERVER)) | |
| 33 | − | |
| 34 | 32 | struct cache_dfs_tgt { |
| 35 | 33 | char *name; |
| 36 | 34 | int path_consumed; |
| @@ -174,7 +172,7 @@ static int dfscache_proc_show(struct seq_file *m, void *v) · 137 unmodified lines | ||
| 174 | 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 | 173 | ce->path, ce->srvtype == DFS_TYPE_ROOT ? "root" : "link", |
| 176 | 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 | 176 | ce->path_consumed, cache_entry_expired(ce) ? "yes" : "no"); |
| 179 | 177 | |
| 180 | 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 | 241 | ce->srvtype == DFS_TYPE_ROOT ? "root" : "link", ce->ttl, |
| 244 | 242 | ce->etime.tv_nsec, |
| 245 | 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 | 245 | ce->path_consumed, |
| 248 | 246 | cache_entry_expired(ce) ? "yes" : "no"); |
| 249 | 247 | dump_tgts(ce); |
| @@ -1177,9 +1175,9 @@ static bool is_ses_good(struct cifs_ses *ses) · 927 unmodified lines | ||
| 1177 | 1175 | /* Refresh dfs referral of tcon and mark it for reconnect if needed */ |
| 1178 | 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 | 1178 | struct TCP_Server_Info *server = ses->server; |
| 1179 | + DFS_CACHE_TGT_LIST(old_tl); | |
| 1180 | + DFS_CACHE_TGT_LIST(new_tl); | |
| 1183 | 1181 | bool needs_refresh = false; |
| 1184 | 1182 | struct cache_entry *ce; |
| 1185 | 1183 | unsigned int xid; |
| @@ -16,7 +16,11 @@ · 15 unmodified lines | ||
| 16 | 16 | extern struct workqueue_struct *dfscache_wq; |
| 17 | 17 | extern atomic_t dfs_cache_ttl; |
| 18 | 18 | |
| 19 | −#define DFS_CACHE_TGT_LIST_INIT(var) { .tl_numtgts = 0, .tl_list = LIST_HEAD_INIT((var).tl_list), } | |
| 19 | +#define DFS_CACHE_TGT_LIST_INIT(var) \ | |
| 20 | + { .tl_numtgts = 0, .tl_list = LIST_HEAD_INIT((var).tl_list), } | |
| 21 | + | |
| 22 | +#define DFS_CACHE_TGT_LIST(var) \ | |
| 23 | + struct dfs_cache_tgt_list var = DFS_CACHE_TGT_LIST_INIT(var) | |
| 20 | 24 | |
| 21 | 25 | struct dfs_cache_tgt_list { |
| 22 | 26 | int tl_numtgts; |
| @@ -51,8 +55,8 @@ static inline struct dfs_cache_tgt_iterator * · 28 unmodified lines | ||
| 51 | 55 | dfs_cache_get_next_tgt(struct dfs_cache_tgt_list *tl, |
| 52 | 56 | struct dfs_cache_tgt_iterator *it) |
| 53 | 57 | { |
| 54 | − if (!tl || list_empty(&tl->tl_list) || !it || | |
| 55 | − list_is_last(&it->it_list, &tl->tl_list)) | |
| 58 | + if (!tl || !tl->tl_numtgts || list_empty(&tl->tl_list) || | |
| 59 | + !it || list_is_last(&it->it_list, &tl->tl_list)) | |
| 56 | 60 | return NULL; |
| 57 | 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 | 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 | 79 | return; |
| 76 | 80 | list_for_each_entry_safe(it, nit, &tl->tl_list, it_list) { |
| 77 | 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 | 798 | const struct dentry_operations cifs_dentry_ops = { |
| 799 | 799 | .d_revalidate = cifs_d_revalidate, |
| 800 | − .d_automount = cifs_dfs_d_automount, | |
| 800 | + .d_automount = cifs_d_automount, | |
| 801 | 801 | /* d_delete: cifs_d_delete, */ /* not needed except for debugging */ |
| 802 | 802 | }; |
| 803 | 803 | |
| @@ -872,5 +872,5 @@ const struct dentry_operations cifs_ci_dentry_ops = { · 68 unmodified lines | ||
| 872 | 872 | .d_revalidate = cifs_d_revalidate, |
| 873 | 873 | .d_hash = cifs_ci_hash, |
| 874 | 874 | .d_compare = cifs_ci_compare, |
| 875 | − .d_automount = cifs_dfs_d_automount, | |
| 875 | + .d_automount = cifs_d_automount, | |
| 876 | 876 | }; |
| @@ -58,13 +58,9 @@ static void cifs_set_ops(struct inode *inode) · 57 unmodified lines | ||
| 58 | 58 | inode->i_data.a_ops = &cifs_addr_ops; |
| 59 | 59 | break; |
| 60 | 60 | case S_IFDIR: |
| 61 | −#ifdef CONFIG_CIFS_DFS_UPCALL | |
| 62 | 61 | if (IS_AUTOMOUNT(inode)) { |
| 63 | − inode->i_op = &cifs_dfs_referral_inode_operations; | |
| 62 | + inode->i_op = &cifs_namespace_inode_operations; | |
| 64 | 63 | } else { |
| 65 | −#else /* NO DFS support, treat as a directory */ | |
| 66 | − { | |
| 67 | −#endif | |
| 68 | 64 | inode->i_op = &cifs_dir_inode_ops; |
| 69 | 65 | inode->i_fop = &cifs_dir_ops; |
| 70 | 66 | } |
| @@ -218,7 +214,7 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr) · 147 unmodified lines | ||
| 218 | 214 | } |
| 219 | 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 | 218 | inode->i_flags |= S_AUTOMOUNT; |
| 223 | 219 | if (inode->i_state & I_NEW) |
| 224 | 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 | 324 | * Needed to setup cifs_fattr data for the directory which is the |
| 329 | 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 | |
| 333 | −cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb) | |
| 328 | +static void cifs_create_junction_fattr(struct cifs_fattr *fattr, | |
| 329 | + struct super_block *sb) | |
| 334 | 330 | { |
| 335 | 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 | 335 | memset(fattr, 0, sizeof(*fattr)); |
| 340 | 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 | 339 | ktime_get_coarse_real_ts64(&fattr->cf_mtime); |
| 344 | 340 | fattr->cf_atime = fattr->cf_ctime = fattr->cf_mtime; |
| 345 | 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 | 371 | #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY |
| @@ -373,7 +395,7 @@ cifs_get_file_info_unix(struct file *filp) · 23 unmodified lines | ||
| 373 | 395 | if (!rc) { |
| 374 | 396 | cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb); |
| 375 | 397 | } else if (rc == -EREMOTE) { |
| 376 | − cifs_create_dfs_fattr(&fattr, inode->i_sb); | |
| 398 | + cifs_create_junction_fattr(&fattr, inode->i_sb); | |
| 377 | 399 | rc = 0; |
| 378 | 400 | } else |
| 379 | 401 | goto cifs_gfiunix_out; |
| @@ -385,17 +407,18 @@ cifs_gfiunix_out: · 5 unmodified lines | ||
| 385 | 407 | return rc; |
| 386 | 408 | } |
| 387 | 409 | |
| 388 | −int cifs_get_inode_info_unix(struct inode **pinode, | |
| 389 | − const unsigned char *full_path, | |
| 390 | − struct super_block *sb, unsigned int xid) | |
| 410 | +static int cifs_get_unix_fattr(const unsigned char *full_path, | |
| 411 | + struct super_block *sb, | |
| 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 | 418 | FILE_UNIX_BASIC_INFO find_data; |
| 394 | − struct cifs_fattr fattr; | |
| 395 | 419 | struct cifs_tcon *tcon; |
| 396 | − struct TCP_Server_Info *server; | |
| 397 | 420 | struct tcon_link *tlink; |
| 398 | − struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | |
| 421 | + int rc, tmprc; | |
| 399 | 422 | |
| 400 | 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 | 435 | cifs_put_tlink(tlink); |
| 413 | 436 | |
| 414 | 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 | 439 | } else if (rc == -EREMOTE) { |
| 417 | − cifs_create_dfs_fattr(&fattr, sb); | |
| 440 | + cifs_create_junction_fattr(fattr, sb); | |
| 418 | 441 | rc = 0; |
| 419 | 442 | } else { |
| 420 | 443 | return rc; |
| 421 | 444 | } |
| 422 | 445 | |
| 446 | + if (!*pinode) | |
| 447 | + cifs_fill_uniqueid(sb, fattr); | |
| 448 | + | |
| 423 | 449 | /* check for Minshall+French symlinks */ |
| 424 | 450 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) { |
| 425 | − int tmprc = check_mf_symlink(xid, tcon, cifs_sb, &fattr, | |
| 426 | − full_path); | |
| 427 | − if (tmprc) | |
| 428 | − cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc); | |
| 451 | + tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path); | |
| 452 | + 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 | 456 | if (!server->ops->query_symlink) |
| 433 | 457 | return -EOPNOTSUPP; |
| 434 | − rc = server->ops->query_symlink(xid, tcon, cifs_sb, full_path, | |
| 435 | − &fattr.cf_symlink_target, false); | |
| 436 | − if (rc) { | |
| 437 | − cifs_dbg(FYI, "%s: query_symlink: %d\n", __func__, rc); | |
| 438 | − goto cgiiu_exit; | |
| 439 | − } | |
| 458 | + rc = server->ops->query_symlink(xid, tcon, | |
| 459 | + cifs_sb, full_path, | |
| 460 | + &fattr->cf_symlink_target, | |
| 461 | + NULL); | |
| 462 | + cifs_dbg(FYI, "%s: query_symlink: %d\n", __func__, rc); | |
| 440 | 463 | } |
| 464 | + return rc; | |
| 465 | +} | |
| 441 | 466 | |
| 442 | − if (*pinode == NULL) { | |
| 443 | − /* get new inode */ | |
| 444 | − cifs_fill_uniqueid(sb, &fattr); | |
| 445 | − *pinode = cifs_iget(sb, &fattr); | |
| 446 | − if (!*pinode) | |
| 447 | − rc = -ENOMEM; | |
| 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 | − } | |
| 467 | +int cifs_get_inode_info_unix(struct inode **pinode, | |
| 468 | + const unsigned char *full_path, | |
| 469 | + struct super_block *sb, unsigned int xid) | |
| 470 | +{ | |
| 471 | + struct cifs_fattr fattr = {}; | |
| 472 | + int rc; | |
| 458 | 473 | |
| 459 | − /* if filetype is different, return error */ | |
| 460 | − rc = cifs_fattr_to_inode(*pinode, &fattr); | |
| 461 | − } | |
| 474 | + rc = cifs_get_unix_fattr(full_path, sb, &fattr, pinode, xid); | |
| 475 | + if (rc) | |
| 476 | + goto out; | |
| 462 | 477 | |
| 463 | −cgiiu_exit: | |
| 478 | + rc = update_inode_info(sb, &fattr, pinode); | |
| 479 | +out: | |
| 464 | 480 | kfree(fattr.cf_symlink_target); |
| 465 | 481 | return rc; |
| 466 | 482 | } |
| 467 | 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 | 493 | int cifs_get_inode_info_unix(struct inode **pinode, |
| 469 | 494 | const unsigned char *full_path, |
| 470 | 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 | 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 | 662 | struct cifs_sid *owner, |
| 637 | 663 | struct cifs_sid *group, |
| 638 | − struct super_block *sb, bool adjust_tz, bool symlink) | |
| 664 | + struct super_block *sb) | |
| 639 | 665 | { |
| 640 | 666 | struct smb311_posix_qinfo *info = &data->posix_fi; |
| 641 | 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 | 681 | fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime); |
| 656 | 682 | fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); |
| 657 | 683 | |
| 658 | − if (adjust_tz) { | |
| 684 | + if (data->adjust_tz) { | |
| 659 | 685 | fattr->cf_ctime.tv_sec += tcon->ses->server->timeAdj; |
| 660 | 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 | 695 | /* The srv fs device id is overridden on network mount so setting rdev isn't needed here */ |
| 670 | 696 | /* fattr->cf_rdev = le32_to_cpu(info->DeviceId); */ |
| 671 | 697 | |
| 672 | − if (symlink) { | |
| 698 | + if (data->symlink) { | |
| 673 | 699 | fattr->cf_mode |= S_IFLNK; |
| 674 | 700 | fattr->cf_dtype = DT_LNK; |
| 675 | 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 | 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, | |
| 694 | − struct super_block *sb, bool adjust_tz, bool symlink, | |
| 695 | − u32 reparse_tag) | |
| 719 | +bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb, | |
| 720 | + struct cifs_fattr *fattr, | |
| 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 | 760 | struct smb2_file_all_info *info = &data->fi; |
| 698 | 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 | 774 | fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime); |
| 712 | 775 | fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); |
| 713 | 776 | |
| 714 | − if (adjust_tz) { | |
| 777 | + if (data->adjust_tz) { | |
| 715 | 778 | fattr->cf_ctime.tv_sec += tcon->ses->server->timeAdj; |
| 716 | 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 | 782 | fattr->cf_eof = le64_to_cpu(info->EndOfFile); |
| 720 | 783 | fattr->cf_bytes = le64_to_cpu(info->AllocationSize); |
| 721 | 784 | fattr->cf_createtime = le64_to_cpu(info->CreationTime); |
| 722 | − | |
| 723 | 785 | fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks); |
| 724 | − if (reparse_tag == IO_REPARSE_TAG_LX_SYMLINK) { | |
| 725 | − fattr->cf_mode |= S_IFLNK | cifs_sb->ctx->file_mode; | |
| 726 | − fattr->cf_dtype = DT_LNK; | |
| 727 | − } else if (reparse_tag == IO_REPARSE_TAG_LX_FIFO) { | |
| 728 | − fattr->cf_mode |= S_IFIFO | cifs_sb->ctx->file_mode; | |
| 729 | − fattr->cf_dtype = DT_FIFO; | |
| 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) { | |
| 786 | + | |
| 787 | + if (cifs_open_data_reparse(data) && | |
| 788 | + cifs_reparse_point_to_fattr(cifs_sb, fattr, data->reparse_tag)) | |
| 789 | + goto out_reparse; | |
| 790 | + | |
| 791 | + if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { | |
| 744 | 792 | fattr->cf_mode = S_IFDIR | cifs_sb->ctx->dir_mode; |
| 745 | 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 | 821 | if (S_ISLNK(fattr->cf_mode)) { |
| 773 | 822 | fattr->cf_symlink_target = data->symlink_target; |
| 774 | 823 | data->symlink_target = NULL; |
| @@ -789,8 +838,6 @@ cifs_get_file_info(struct file *filp) · 14 unmodified lines | ||
| 789 | 838 | struct cifsFileInfo *cfile = filp->private_data; |
| 790 | 839 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); |
| 791 | 840 | struct TCP_Server_Info *server = tcon->ses->server; |
| 792 | − bool symlink = false; | |
| 793 | − u32 tag = 0; | |
| 794 | 841 | |
| 795 | 842 | if (!server->ops->query_file_info) |
| 796 | 843 | return -ENOSYS; |
| @@ -800,14 +847,15 @@ cifs_get_file_info(struct file *filp) · 3 unmodified lines | ||
| 800 | 847 | switch (rc) { |
| 801 | 848 | case 0: |
| 802 | 849 | /* TODO: add support to query reparse tag */ |
| 850 | + data.adjust_tz = false; | |
| 803 | 851 | if (data.symlink_target) { |
| 804 | − symlink = true; | |
| 805 | − tag = IO_REPARSE_TAG_SYMLINK; | |
| 852 | + data.symlink = true; | |
| 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 | 856 | break; |
| 809 | 857 | case -EREMOTE: |
| 810 | − cifs_create_dfs_fattr(&fattr, inode->i_sb); | |
| 858 | + cifs_create_junction_fattr(&fattr, inode->i_sb); | |
| 811 | 859 | rc = 0; |
| 812 | 860 | break; |
| 813 | 861 | case -EOPNOTSUPP: |
| @@ -960,22 +1008,66 @@ static inline bool is_inode_cache_good(struct inode *ino) · 146 unmodified lines | ||
| 960 | 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, | |
| 964 | − struct cifs_open_info_data *data, struct super_block *sb, int xid, | |
| 965 | − const struct cifs_fid *fid) | |
| 1011 | +static int reparse_info_to_fattr(struct cifs_open_info_data *data, | |
| 1012 | + struct super_block *sb, | |
| 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 | 1064 | struct cifs_tcon *tcon; |
| 968 | 1065 | struct TCP_Server_Info *server; |
| 969 | 1066 | struct tcon_link *tlink; |
| 970 | 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 | 1068 | void *smb1_backup_rsp_buf = NULL; |
| 976 | 1069 | int rc = 0; |
| 977 | 1070 | int tmprc = 0; |
| 978 | − __u32 reparse_tag = 0; | |
| 979 | 1071 | |
| 980 | 1072 | tlink = cifs_sb_tlink(cifs_sb); |
| 981 | 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 | 1082 | if (!data) { |
| 991 | − if (is_inode_cache_good(*inode)) { | |
| 992 | − cifs_dbg(FYI, "No need to revalidate cached inode sizes\n"); | |
| 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); | |
| 1083 | + rc = server->ops->query_path_info(xid, tcon, cifs_sb, | |
| 1084 | + full_path, &tmp_data); | |
| 997 | 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 | 1096 | * since we have to check if its reparse tag matches a known |
| 1009 | 1097 | * special file type e.g. symlink or fifo or char etc. |
| 1010 | 1098 | */ |
| 1011 | − if (is_reparse_point && data->symlink_target) { | |
| 1012 | − reparse_tag = IO_REPARSE_TAG_SYMLINK; | |
| 1013 | − } else if ((le32_to_cpu(data->fi.Attributes) & ATTR_REPARSE) && | |
| 1014 | − server->ops->query_reparse_tag) { | |
| 1015 | − tmprc = server->ops->query_reparse_tag(xid, tcon, cifs_sb, full_path, | |
| 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 | − } | |
| 1099 | + if (cifs_open_data_reparse(data)) { | |
| 1100 | + rc = reparse_info_to_fattr(data, sb, xid, tcon, | |
| 1101 | + full_path, fattr); | |
| 1102 | + } else { | |
| 1103 | + cifs_open_info_to_fattr(fattr, data, sb); | |
| 1027 | 1104 | } |
| 1028 | − cifs_open_info_to_fattr(&fattr, data, sb, adjust_tz, is_reparse_point, reparse_tag); | |
| 1029 | 1105 | break; |
| 1030 | 1106 | case -EREMOTE: |
| 1031 | 1107 | /* DFS link, no metadata available on this server */ |
| 1032 | − cifs_create_dfs_fattr(&fattr, sb); | |
| 1108 | + cifs_create_junction_fattr(fattr, sb); | |
| 1033 | 1109 | rc = 0; |
| 1034 | 1110 | break; |
| 1035 | 1111 | case -EACCES: |
| @@ -1059,8 +1135,8 @@ int cifs_get_inode_info(struct inode **inode, const char *full_path, · 23 unmodified lines | ||
| 1059 | 1135 | fdi = (FILE_DIRECTORY_INFO *)fi; |
| 1060 | 1136 | si = (SEARCH_ID_FULL_DIR_INFO *)fi; |
| 1061 | 1137 | |
| 1062 | − cifs_dir_info_to_fattr(&fattr, fdi, cifs_sb); | |
| 1063 | − fattr.cf_uniqueid = le64_to_cpu(si->UniqueId); | |
| 1138 | + cifs_dir_info_to_fattr(fattr, fdi, cifs_sb); | |
| 1139 | + fattr->cf_uniqueid = le64_to_cpu(si->UniqueId); | |
| 1064 | 1140 | /* uniqueid set, skip get inum step */ |
| 1065 | 1141 | goto handle_mnt_opt; |
| 1066 | 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 | 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 | 1165 | handle_mnt_opt: |
| 1090 | 1166 | #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ |
| 1091 | 1167 | /* query for SFU type info if supported and needed */ |
| 1092 | − if (fattr.cf_cifsattrs & ATTR_SYSTEM && | |
| 1093 | − cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { | |
| 1094 | − tmprc = cifs_sfu_type(&fattr, full_path, cifs_sb, xid); | |
| 1168 | + if ((fattr->cf_cifsattrs & ATTR_SYSTEM) && | |
| 1169 | + (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) { | |
| 1170 | + tmprc = cifs_sfu_type(fattr, full_path, cifs_sb, xid); | |
| 1095 | 1171 | if (tmprc) |
| 1096 | 1172 | cifs_dbg(FYI, "cifs_sfu_type failed: %d\n", tmprc); |
| 1097 | 1173 | } |
| 1098 | 1174 | |
| 1099 | 1175 | /* fill in 0777 bits from ACL */ |
| 1100 | 1176 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) { |
| 1101 | − rc = cifs_acl_to_fattr(cifs_sb, &fattr, *inode, true, | |
| 1102 | − full_path, fid); | |
| 1177 | + rc = cifs_acl_to_fattr(cifs_sb, fattr, *inode, | |
| 1178 | + true, full_path, fid); | |
| 1103 | 1179 | if (rc == -EREMOTE) |
| 1104 | 1180 | rc = 0; |
| 1105 | 1181 | if (rc) { |
| @@ -1108,8 +1184,8 @@ handle_mnt_opt: · 2 unmodified lines | ||
| 1108 | 1184 | goto out; |
| 1109 | 1185 | } |
| 1110 | 1186 | } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { |
| 1111 | − rc = cifs_acl_to_fattr(cifs_sb, &fattr, *inode, false, | |
| 1112 | − full_path, fid); | |
| 1187 | + rc = cifs_acl_to_fattr(cifs_sb, fattr, *inode, | |
| 1188 | + false, full_path, fid); | |
| 1113 | 1189 | if (rc == -EREMOTE) |
| 1114 | 1190 | rc = 0; |
| 1115 | 1191 | if (rc) { |
| @@ -1121,60 +1197,57 @@ handle_mnt_opt: · 5 unmodified lines | ||
| 1121 | 1197 | |
| 1122 | 1198 | /* fill in remaining high mode bits e.g. SUID, VTX */ |
| 1123 | 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 | 1202 | /* check for Minshall+French symlinks */ |
| 1127 | 1203 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) { |
| 1128 | − tmprc = check_mf_symlink(xid, tcon, cifs_sb, &fattr, | |
| 1129 | − full_path); | |
| 1130 | − if (tmprc) | |
| 1131 | − cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc); | |
| 1204 | + tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path); | |
| 1205 | + 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 | 1208 | out: |
| 1156 | 1209 | cifs_buf_release(smb1_backup_rsp_buf); |
| 1157 | 1210 | cifs_put_tlink(tlink); |
| 1158 | 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 | 1235 | kfree(fattr.cf_symlink_target); |
| 1160 | 1236 | return rc; |
| 1161 | 1237 | } |
| 1162 | 1238 | |
| 1163 | −int | |
| 1164 | −smb311_posix_get_inode_info(struct inode **inode, | |
| 1165 | − const char *full_path, | |
| 1166 | − struct super_block *sb, unsigned int xid) | |
| 1239 | +static int smb311_posix_get_fattr(struct cifs_fattr *fattr, | |
| 1240 | + const char *full_path, | |
| 1241 | + struct super_block *sb, | |
| 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 | 1246 | struct cifs_tcon *tcon; |
| 1169 | 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 | 1248 | struct cifs_sid owner, group; |
| 1176 | − int rc = 0; | |
| 1177 | − int tmprc = 0; | |
| 1249 | + int tmprc; | |
| 1250 | + int rc; | |
| 1178 | 1251 | |
| 1179 | 1252 | tlink = cifs_sb_tlink(cifs_sb); |
| 1180 | 1253 | if (IS_ERR(tlink)) |
| @@ -1185,14 +1258,9 @@ smb311_posix_get_inode_info(struct inode **inode, · 4 unmodified lines | ||
| 1185 | 1258 | * 1. Fetch file metadata |
| 1186 | 1259 | */ |
| 1187 | 1260 | |
| 1188 | − if (is_inode_cache_good(*inode)) { | |
| 1189 | − cifs_dbg(FYI, "No need to revalidate cached inode sizes\n"); | |
| 1190 | − goto out; | |
| 1191 | − } | |
| 1192 | − | |
| 1193 | − rc = smb311_posix_query_path_info(xid, tcon, cifs_sb, full_path, &data, | |
| 1194 | − &owner, &group, &adjust_tz, | |
| 1195 | − &symlink); | |
| 1261 | + rc = smb311_posix_query_path_info(xid, tcon, cifs_sb, | |
| 1262 | + full_path, &data, | |
| 1263 | + &owner, &group); | |
| 1196 | 1264 | |
| 1197 | 1265 | /* |
| 1198 | 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 | 1269 | switch (rc) { |
| 1202 | 1270 | case 0: |
| 1203 | − smb311_posix_info_to_fattr(&fattr, &data, &owner, &group, | |
| 1204 | − sb, adjust_tz, symlink); | |
| 1271 | + smb311_posix_info_to_fattr(fattr, &data, &owner, &group, sb); | |
| 1205 | 1272 | break; |
| 1206 | 1273 | case -EREMOTE: |
| 1207 | 1274 | /* DFS link, no metadata available on this server */ |
| 1208 | − cifs_create_dfs_fattr(&fattr, sb); | |
| 1275 | + cifs_create_junction_fattr(fattr, sb); | |
| 1209 | 1276 | rc = 0; |
| 1210 | 1277 | break; |
| 1211 | 1278 | case -EACCES: |
| @@ -1221,49 +1288,42 @@ smb311_posix_get_inode_info(struct inode **inode, · 9 unmodified lines | ||
| 1221 | 1288 | goto out; |
| 1222 | 1289 | } |
| 1223 | 1290 | |
| 1224 | − | |
| 1225 | 1291 | /* |
| 1226 | 1292 | * 3. Tweak fattr based on mount options |
| 1227 | 1293 | */ |
| 1228 | − | |
| 1229 | 1294 | /* check for Minshall+French symlinks */ |
| 1230 | 1295 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) { |
| 1231 | − tmprc = check_mf_symlink(xid, tcon, cifs_sb, &fattr, | |
| 1232 | − full_path); | |
| 1233 | − if (tmprc) | |
| 1234 | − cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc); | |
| 1296 | + tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path); | |
| 1297 | + cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc); | |
| 1235 | 1298 | } |
| 1236 | 1299 | |
| 1237 | − /* | |
| 1238 | − * 4. Update inode with final fattr data | |
| 1239 | − */ | |
| 1240 | − | |
| 1241 | − if (!*inode) { | |
| 1242 | − *inode = cifs_iget(sb, &fattr); | |
| 1243 | − if (!*inode) | |
| 1244 | − rc = -ENOMEM; | |
| 1245 | − } else { | |
| 1246 | − /* we already have inode, update it */ | |
| 1300 | +out: | |
| 1301 | + cifs_put_tlink(tlink); | |
| 1302 | + cifs_free_open_info(&data); | |
| 1303 | + return rc; | |
| 1304 | +} | |
| 1247 | 1305 | |
| 1248 | − /* if uniqueid is different, return error */ | |
| 1249 | − if (unlikely(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM && | |
| 1250 | − CIFS_I(*inode)->uniqueid != fattr.cf_uniqueid)) { | |
| 1251 | − CIFS_I(*inode)->time = 0; /* force reval */ | |
| 1252 | − rc = -ESTALE; | |
| 1253 | − goto out; | |
| 1254 | − } | |
| 1306 | +int smb311_posix_get_inode_info(struct inode **inode, const char *full_path, | |
| 1307 | + struct super_block *sb, const unsigned int xid) | |
| 1308 | +{ | |
| 1309 | + struct cifs_fattr fattr = {}; | |
| 1310 | + int rc; | |
| 1255 | 1311 | |
| 1256 | − /* if filetype is different, return error */ | |
| 1257 | − rc = cifs_fattr_to_inode(*inode, &fattr); | |
| 1312 | + if (is_inode_cache_good(*inode)) { | |
| 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 | 1322 | out: |
| 1260 | − cifs_put_tlink(tlink); | |
| 1261 | − cifs_free_open_info(&data); | |
| 1262 | 1323 | kfree(fattr.cf_symlink_target); |
| 1263 | 1324 | return rc; |
| 1264 | 1325 | } |
| 1265 | 1326 | |
| 1266 | − | |
| 1267 | 1327 | static const struct inode_operations cifs_ipc_inode_ops = { |
| 1268 | 1328 | .lookup = cifs_lookup, |
| 1269 | 1329 | }; |
| @@ -1367,13 +1427,14 @@ retry_iget5_locked: · 97 unmodified lines | ||
| 1367 | 1427 | /* gets root inode */ |
| 1368 | 1428 | struct inode *cifs_root_iget(struct super_block *sb) |
| 1369 | 1429 | { |
| 1370 | − unsigned int xid; | |
| 1371 | 1430 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
| 1372 | − struct inode *inode = NULL; | |
| 1373 | − long rc; | |
| 1431 | + struct cifs_fattr fattr = {}; | |
| 1374 | 1432 | struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); |
| 1433 | + struct inode *inode = NULL; | |
| 1434 | + unsigned int xid; | |
| 1375 | 1435 | char *path = NULL; |
| 1376 | 1436 | int len; |
| 1437 | + int rc; | |
| 1377 | 1438 | |
| 1378 | 1439 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) |
| 1379 | 1440 | && cifs_sb->prepath) { |
| @@ -1391,21 +1452,29 @@ struct inode *cifs_root_iget(struct super_block *sb) · 11 unmodified lines | ||
| 1391 | 1452 | |
| 1392 | 1453 | xid = get_xid(); |
| 1393 | 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 | 1456 | /* some servers mistakenly claim POSIX support */ |
| 1396 | 1457 | if (rc != -EOPNOTSUPP) |
| 1397 | − goto iget_no_retry; | |
| 1458 | + goto iget_root; | |
| 1398 | 1459 | cifs_dbg(VFS, "server does not support POSIX extensions\n"); |
| 1399 | 1460 | tcon->unix_ext = false; |
| 1400 | 1461 | } |
| 1401 | 1462 | |
| 1402 | 1463 | convert_delimiter(path, CIFS_DIR_SEP(cifs_sb)); |
| 1403 | 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 | 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 | 1478 | if (!inode) { |
| 1410 | 1479 | inode = ERR_PTR(rc); |
| 1411 | 1480 | goto out; |
| @@ -1429,6 +1498,7 @@ iget_no_retry: · 17 unmodified lines | ||
| 1429 | 1498 | out: |
| 1430 | 1499 | kfree(path); |
| 1431 | 1500 | free_xid(xid); |
| 1501 | + kfree(fattr.cf_symlink_target); | |
| 1432 | 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 | 476 | return false; |
| 477 | 477 | |
| 478 | 478 | /* If server is a channel, select the primary channel */ |
| 479 | − pserver = CIFS_SERVER_IS_CHAN(srv) ? srv->primary_server : srv; | |
| 479 | + pserver = SERVER_IS_CHAN(srv) ? srv->primary_server : srv; | |
| 480 | 480 | |
| 481 | 481 | /* look up tcon based on tid & uid */ |
| 482 | 482 | spin_lock(&cifs_tcp_ses_lock); |
| @@ -1,12 +1,12 @@ | ||
| 1 | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 2 | 2 | /* |
| 3 | − * Contains the CIFS DFS referral mounting routines used for handling | |
| 4 | − * traversal via DFS junction point | |
| 3 | + * Contains mounting routines used for handling traversal via SMB junctions. | |
| 5 | 4 | * |
| 6 | 5 | * Copyright (c) 2007 Igor Mammedov |
| 7 | 6 | * Copyright (C) International Business Machines Corp., 2008 |
| 8 | 7 | * Author(s): Igor Mammedov (niallain@gmail.com) |
| 9 | 8 | * Steve French (sfrench@us.ibm.com) |
| 9 | + * Copyright (c) 2023 Paulo Alcantara <palcantara@suse.de> | |
| 10 | 10 | */ |
| 11 | 11 | |
| 12 | 12 | #include <linux/dcache.h> |
| @@ -19,32 +19,31 @@ · 6 unmodified lines | ||
| 19 | 19 | #include "cifsglob.h" |
| 20 | 20 | #include "cifsproto.h" |
| 21 | 21 | #include "cifsfs.h" |
| 22 | −#include "dns_resolve.h" | |
| 23 | 22 | #include "cifs_debug.h" |
| 24 | −#include "dfs.h" | |
| 25 | 23 | #include "fs_context.h" |
| 26 | 24 | |
| 27 | −static LIST_HEAD(cifs_dfs_automount_list); | |
| 25 | +static LIST_HEAD(cifs_automount_list); | |
| 28 | 26 | |
| 29 | −static void cifs_dfs_expire_automounts(struct work_struct *work); | |
| 30 | −static DECLARE_DELAYED_WORK(cifs_dfs_automount_task, | |
| 31 | − cifs_dfs_expire_automounts); | |
| 32 | −static int cifs_dfs_mountpoint_expiry_timeout = 500 * HZ; | |
| 27 | +static void cifs_expire_automounts(struct work_struct *work); | |
| 28 | +static DECLARE_DELAYED_WORK(cifs_automount_task, | |
| 29 | + cifs_expire_automounts); | |
| 30 | +static int cifs_mountpoint_expiry_timeout = 500 * HZ; | |
| 33 | 31 | |
| 34 | −static void cifs_dfs_expire_automounts(struct work_struct *work) | |
| 32 | +static void cifs_expire_automounts(struct work_struct *work) | |
| 35 | 33 | { |
| 36 | − struct list_head *list = &cifs_dfs_automount_list; | |
| 34 | + struct list_head *list = &cifs_automount_list; | |
| 37 | 35 | |
| 38 | 36 | mark_mounts_for_expiry(list); |
| 39 | 37 | if (!list_empty(list)) |
| 40 | − schedule_delayed_work(&cifs_dfs_automount_task, | |
| 41 | − cifs_dfs_mountpoint_expiry_timeout); | |
| 38 | + schedule_delayed_work(&cifs_automount_task, | |
| 39 | + cifs_mountpoint_expiry_timeout); | |
| 42 | 40 | } |
| 43 | 41 | |
| 44 | −void cifs_dfs_release_automount_timer(void) | |
| 42 | +void cifs_release_automount_timer(void) | |
| 45 | 43 | { |
| 46 | − BUG_ON(!list_empty(&cifs_dfs_automount_list)); | |
| 47 | − cancel_delayed_work_sync(&cifs_dfs_automount_task); | |
| 44 | + if (WARN_ON(!list_empty(&cifs_automount_list))) | |
| 45 | + return; | |
| 46 | + cancel_delayed_work_sync(&cifs_automount_task); | |
| 48 | 47 | } |
| 49 | 48 | |
| 50 | 49 | /** |
| @@ -118,26 +117,53 @@ cifs_build_devname(char *nodename, const char *prepath) · 67 unmodified lines | ||
| 118 | 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; | |
| 124 | − int rc; | |
| 123 | + struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb); | |
| 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); | |
| 127 | − if (!rc) | |
| 128 | − cifs_set_port(addr, ctx->port); | |
| 129 | − return rc; | |
| 156 | + return s; | |
| 130 | 157 | } |
| 131 | 158 | |
| 132 | 159 | /* |
| 133 | 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 | 164 | int rc; |
| 138 | 165 | struct dentry *mntpt = path->dentry; |
| 139 | 166 | struct fs_context *fc; |
| 140 | − struct cifs_sb_info *cifs_sb; | |
| 141 | 167 | void *page = NULL; |
| 142 | 168 | struct smb3_fs_context *ctx, *cur_ctx; |
| 143 | 169 | struct smb3_fs_context tmp; |
| @@ -147,17 +173,7 @@ static struct vfsmount *cifs_dfs_do_automount(struct path *path) · 3 unmodified lines | ||
| 147 | 173 | if (IS_ROOT(mntpt)) |
| 148 | 174 | return ERR_PTR(-ESTALE); |
| 149 | 175 | |
| 150 | − /* | |
| 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; | |
| 176 | + cur_ctx = CIFS_SB(mntpt->d_sb)->ctx; | |
| 161 | 177 | |
| 162 | 178 | fc = fs_context_for_submount(path->mnt->mnt_sb->s_type, mntpt); |
| 163 | 179 | if (IS_ERR(fc)) |
| @@ -166,7 +182,7 @@ static struct vfsmount *cifs_dfs_do_automount(struct path *path) · 2 unmodified lines | ||
| 166 | 182 | ctx = smb3_fc2context(fc); |
| 167 | 183 | |
| 168 | 184 | page = alloc_dentry_path(); |
| 169 | − full_path = dfs_get_automount_devname(mntpt, page); | |
| 185 | + full_path = automount_fullpath(mntpt, page); | |
| 170 | 186 | if (IS_ERR(full_path)) { |
| 171 | 187 | mnt = ERR_CAST(full_path); |
| 172 | 188 | goto out; |
| @@ -196,15 +212,10 @@ static struct vfsmount *cifs_dfs_do_automount(struct path *path) · 23 unmodified lines | ||
| 196 | 212 | ctx->source = NULL; |
| 197 | 213 | goto out; |
| 198 | 214 | } |
| 199 | − cifs_dbg(FYI, "%s: ctx: source=%s UNC=%s prepath=%s dstaddr=%pISpc\n", | |
| 200 | − __func__, ctx->source, ctx->UNC, ctx->prepath, &ctx->dstaddr); | |
| 201 | − | |
| 202 | − rc = set_dest_addr(ctx); | |
| 203 | − if (!rc) | |
| 204 | − mnt = fc_mount(fc); | |
| 205 | − else | |
| 206 | − mnt = ERR_PTR(rc); | |
| 215 | + cifs_dbg(FYI, "%s: ctx: source=%s UNC=%s prepath=%s\n", | |
| 216 | + __func__, ctx->source, ctx->UNC, ctx->prepath); | |
| 207 | 217 | |
| 218 | + mnt = fc_mount(fc); | |
| 208 | 219 | out: |
| 209 | 220 | put_fs_context(fc); |
| 210 | 221 | free_dentry_path(page); |
| @@ -214,25 +225,25 @@ out: · 3 unmodified lines | ||
| 214 | 225 | /* |
| 215 | 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 | 230 | struct vfsmount *newmnt; |
| 220 | 231 | |
| 221 | 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 | 235 | if (IS_ERR(newmnt)) { |
| 225 | 236 | cifs_dbg(FYI, "leaving %s [automount failed]\n" , __func__); |
| 226 | 237 | return newmnt; |
| 227 | 238 | } |
| 228 | 239 | |
| 229 | 240 | mntget(newmnt); /* prevent immediate expiration */ |
| 230 | − mnt_set_expiry(newmnt, &cifs_dfs_automount_list); | |
| 231 | − schedule_delayed_work(&cifs_dfs_automount_task, | |
| 232 | − cifs_dfs_mountpoint_expiry_timeout); | |
| 241 | + mnt_set_expiry(newmnt, &cifs_automount_list); | |
| 242 | + schedule_delayed_work(&cifs_automount_task, | |
| 243 | + cifs_mountpoint_expiry_timeout); | |
| 233 | 244 | cifs_dbg(FYI, "leaving %s [ok]\n" , __func__); |
| 234 | 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 | 143 | case IO_REPARSE_TAG_DFSR: |
| 144 | 144 | case IO_REPARSE_TAG_SYMLINK: |
| 145 | 145 | case IO_REPARSE_TAG_NFS: |
| 146 | + case IO_REPARSE_TAG_MOUNT_POINT: | |
| 146 | 147 | case 0: |
| 147 | 148 | return true; |
| 148 | 149 | } |
| @@ -163,29 +164,19 @@ cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb) · 14 unmodified lines | ||
| 163 | 164 | * TODO: go through all documented reparse tags to see if we can |
| 164 | 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 | 171 | if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { |
| 167 | 172 | fattr->cf_mode = S_IFDIR | cifs_sb->ctx->dir_mode; |
| 168 | 173 | fattr->cf_dtype = DT_DIR; |
| 169 | − } else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_SYMLINK) { | |
| 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? */ | |
| 174 | + } else { | |
| 185 | 175 | fattr->cf_mode = S_IFREG | cifs_sb->ctx->file_mode; |
| 186 | 176 | fattr->cf_dtype = DT_REG; |
| 187 | 177 | } |
| 188 | 178 | |
| 179 | +out_reparse: | |
| 189 | 180 | /* |
| 190 | 181 | * We need to revalidate it further to make a decision about whether it |
| 191 | 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 | 323 | ses->chans[chan_index].iface = iface; |
| 324 | 324 | |
| 325 | 325 | /* No iface is found. if secondary chan, drop connection */ |
| 326 | − if (!iface && CIFS_SERVER_IS_CHAN(server)) | |
| 326 | + if (!iface && SERVER_IS_CHAN(server)) | |
| 327 | 327 | ses->chans[chan_index].server = NULL; |
| 328 | 328 | |
| 329 | 329 | spin_unlock(&ses->chan_lock); |
| 330 | 330 | |
| 331 | − if (!iface && CIFS_SERVER_IS_CHAN(server)) | |
| 331 | + if (!iface && SERVER_IS_CHAN(server)) | |
| 332 | 332 | cifs_put_tcp_session(server, false); |
| 333 | 333 | |
| 334 | 334 | return rc; |
| @@ -360,11 +360,11 @@ cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses, · 25 unmodified lines | ||
| 360 | 360 | { |
| 361 | 361 | struct TCP_Server_Info *chan_server; |
| 362 | 362 | struct cifs_chan *chan; |
| 363 | − struct smb3_fs_context ctx = {NULL}; | |
| 363 | + struct smb3_fs_context *ctx; | |
| 364 | 364 | static const char unc_fmt[] = "\\%s\\foo"; |
| 365 | − char unc[sizeof(unc_fmt)+SERVER_NAME_LEN_WITH_NULL] = {0}; | |
| 366 | 365 | struct sockaddr_in *ipv4 = (struct sockaddr_in *)&iface->sockaddr; |
| 367 | 366 | struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)&iface->sockaddr; |
| 367 | + size_t len; | |
| 368 | 368 | int rc; |
| 369 | 369 | unsigned int xid = get_xid(); |
| 370 | 370 | |
| @@ -388,54 +388,64 @@ cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses, · 17 unmodified lines | ||
| 388 | 388 | * the session and server without caring about memory |
| 389 | 389 | * management. |
| 390 | 390 | */ |
| 391 | + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); | |
| 392 | + if (!ctx) { | |
| 393 | + rc = -ENOMEM; | |
| 394 | + goto out_free_xid; | |
| 395 | + } | |
| 391 | 396 | |
| 392 | 397 | /* Always make new connection for now (TODO?) */ |
| 393 | − ctx.nosharesock = true; | |
| 398 | + ctx->nosharesock = true; | |
| 394 | 399 | |
| 395 | 400 | /* Auth */ |
| 396 | − ctx.domainauto = ses->domainAuto; | |
| 397 | − ctx.domainname = ses->domainName; | |
| 401 | + ctx->domainauto = ses->domainAuto; | |
| 402 | + ctx->domainname = ses->domainName; | |
| 398 | 403 | |
| 399 | 404 | /* no hostname for extra channels */ |
| 400 | − ctx.server_hostname = ""; | |
| 405 | + ctx->server_hostname = ""; | |
| 401 | 406 | |
| 402 | − ctx.username = ses->user_name; | |
| 403 | − ctx.password = ses->password; | |
| 404 | − ctx.sectype = ses->sectype; | |
| 405 | − ctx.sign = ses->sign; | |
| 407 | + ctx->username = ses->user_name; | |
| 408 | + ctx->password = ses->password; | |
| 409 | + ctx->sectype = ses->sectype; | |
| 410 | + ctx->sign = ses->sign; | |
| 406 | 411 | |
| 407 | 412 | /* UNC and paths */ |
| 408 | 413 | /* XXX: Use ses->server->hostname? */ |
| 409 | − sprintf(unc, unc_fmt, ses->ip_addr); | |
| 410 | − ctx.UNC = unc; | |
| 411 | − ctx.prepath = ""; | |
| 414 | + len = sizeof(unc_fmt) + SERVER_NAME_LEN_WITH_NULL; | |
| 415 | + ctx->UNC = kzalloc(len, GFP_KERNEL); | |
| 416 | + if (!ctx->UNC) { | |
| 417 | + rc = -ENOMEM; | |
| 418 | + goto out_free_ctx; | |
| 419 | + } | |
| 420 | + scnprintf(ctx->UNC, len, unc_fmt, ses->ip_addr); | |
| 421 | + ctx->prepath = ""; | |
| 412 | 422 | |
| 413 | 423 | /* Reuse same version as master connection */ |
| 414 | − ctx.vals = ses->server->vals; | |
| 415 | − ctx.ops = ses->server->ops; | |
| 424 | + ctx->vals = ses->server->vals; | |
| 425 | + ctx->ops = ses->server->ops; | |
| 416 | 426 | |
| 417 | − ctx.noblocksnd = ses->server->noblocksnd; | |
| 418 | − ctx.noautotune = ses->server->noautotune; | |
| 419 | − ctx.sockopt_tcp_nodelay = ses->server->tcp_nodelay; | |
| 420 | − ctx.echo_interval = ses->server->echo_interval / HZ; | |
| 421 | − ctx.max_credits = ses->server->max_credits; | |
| 427 | + ctx->noblocksnd = ses->server->noblocksnd; | |
| 428 | + ctx->noautotune = ses->server->noautotune; | |
| 429 | + ctx->sockopt_tcp_nodelay = ses->server->tcp_nodelay; | |
| 430 | + ctx->echo_interval = ses->server->echo_interval / HZ; | |
| 431 | + ctx->max_credits = ses->server->max_credits; | |
| 422 | 432 | |
| 423 | 433 | /* |
| 424 | 434 | * This will be used for encoding/decoding user/domain/pw |
| 425 | 435 | * during sess setup auth. |
| 426 | 436 | */ |
| 427 | − ctx.local_nls = cifs_sb->local_nls; | |
| 437 | + ctx->local_nls = cifs_sb->local_nls; | |
| 428 | 438 | |
| 429 | 439 | /* Use RDMA if possible */ |
| 430 | − ctx.rdma = iface->rdma_capable; | |
| 431 | − memcpy(&ctx.dstaddr, &iface->sockaddr, sizeof(struct sockaddr_storage)); | |
| 440 | + ctx->rdma = iface->rdma_capable; | |
| 441 | + memcpy(&ctx->dstaddr, &iface->sockaddr, sizeof(ctx->dstaddr)); | |
| 432 | 442 | |
| 433 | 443 | /* reuse master con client guid */ |
| 434 | − memcpy(&ctx.client_guid, ses->server->client_guid, | |
| 435 | − SMB2_CLIENT_GUID_SIZE); | |
| 436 | − ctx.use_client_guid = true; | |
| 444 | + memcpy(&ctx->client_guid, ses->server->client_guid, | |
| 445 | + sizeof(ctx->client_guid)); | |
| 446 | + ctx->use_client_guid = true; | |
| 437 | 447 | |
| 438 | − chan_server = cifs_get_tcp_session(&ctx, ses->server); | |
| 448 | + chan_server = cifs_get_tcp_session(ctx, ses->server); | |
| 439 | 449 | |
| 440 | 450 | spin_lock(&ses->chan_lock); |
| 441 | 451 | chan = &ses->chans[ses->chan_count]; |
| @@ -497,6 +507,10 @@ out: · 55 unmodified lines | ||
| 497 | 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 | 514 | free_xid(xid); |
| 501 | 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 | 542 | return rc; |
| 543 | 543 | } |
| 544 | 544 | |
| 545 | −static int cifs_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, | |
| 546 | − struct cifs_sb_info *cifs_sb, const char *full_path, | |
| 547 | − struct cifs_open_info_data *data, bool *adjustTZ, bool *symlink) | |
| 545 | +static int cifs_query_path_info(const unsigned int xid, | |
| 546 | + struct cifs_tcon *tcon, | |
| 547 | + struct cifs_sb_info *cifs_sb, | |
| 548 | + const char *full_path, | |
| 549 | + struct cifs_open_info_data *data) | |
| 548 | 550 | { |
| 549 | 551 | int rc; |
| 550 | 552 | FILE_ALL_INFO fi = {}; |
| 551 | 553 | |
| 552 | − *symlink = false; | |
| 554 | + data->symlink = false; | |
| 555 | + data->adjust_tz = false; | |
| 553 | 556 | |
| 554 | 557 | /* could do find first instead but this returns more info */ |
| 555 | 558 | rc = CIFSSMBQPathInfo(xid, tcon, full_path, &fi, 0 /* not legacy */, cifs_sb->local_nls, |
| @@ -562,7 +565,7 @@ static int cifs_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, · 6 unmodified lines | ||
| 562 | 565 | if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) { |
| 563 | 566 | rc = SMBQueryInformation(xid, tcon, full_path, &fi, cifs_sb->local_nls, |
| 564 | 567 | cifs_remap(cifs_sb)); |
| 565 | − *adjustTZ = true; | |
| 568 | + data->adjust_tz = true; | |
| 566 | 569 | } |
| 567 | 570 | |
| 568 | 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 | 592 | /* Need to check if this is a symbolic link or not */ |
| 590 | 593 | tmprc = CIFS_open(xid, &oparms, &oplock, NULL); |
| 591 | 594 | if (tmprc == -EOPNOTSUPP) |
| 592 | − *symlink = true; | |
| 595 | + data->symlink = true; | |
| 593 | 596 | else if (tmprc == 0) |
| 594 | 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 | 972 | #endif |
| 970 | 973 | } |
| 971 | 974 | |
| 972 | −static int | |
| 973 | −cifs_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, | |
| 974 | − struct cifs_sb_info *cifs_sb, const char *full_path, | |
| 975 | − char **target_path, bool is_reparse_point) | |
| 975 | +static int cifs_query_symlink(const unsigned int xid, | |
| 976 | + struct cifs_tcon *tcon, | |
| 977 | + struct cifs_sb_info *cifs_sb, | |
| 978 | + const char *full_path, | |
| 979 | + char **target_path, | |
| 980 | + struct kvec *rsp_iov) | |
| 976 | 981 | { |
| 977 | 982 | int rc; |
| 978 | 983 | int oplock = 0; |
| 984 | + bool is_reparse_point = !!rsp_iov; | |
| 979 | 985 | struct cifs_fid fid; |
| 980 | 986 | struct cifs_open_parms oparms; |
| 981 | 987 | |
| @@ -35,34 +35,22 @@ free_set_inf_compound(struct smb_rqst *rqst) · 34 unmodified lines | ||
| 35 | 35 | SMB2_close_free(&rqst[2]); |
| 36 | 36 | } |
| 37 | 37 | |
| 38 | − | |
| 39 | −struct cop_vars { | |
| 40 | − struct cifs_open_parms oparms; | |
| 41 | − struct kvec rsp_iov[3]; | |
| 42 | − struct smb_rqst rqst[3]; | |
| 43 | − struct kvec open_iov[SMB2_CREATE_IOV_SIZE]; | |
| 44 | − struct kvec qi_iov[1]; | |
| 45 | − struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE]; | |
| 46 | − struct kvec close_iov[1]; | |
| 47 | − struct smb2_file_rename_info rename_info; | |
| 48 | − struct smb2_file_link_info link_info; | |
| 49 | −}; | |
| 50 | − | |
| 51 | 38 | /* |
| 52 | 39 | * note: If cfile is passed, the reference to it is dropped here. |
| 53 | 40 | * So make sure that you do not reuse cfile after return from this func. |
| 54 | 41 | * |
| 55 | − * If passing @err_iov and @err_buftype, ensure to make them both large enough (>= 3) to hold all | |
| 56 | − * error responses. Caller is also responsible for freeing them up. | |
| 42 | + * If passing @out_iov and @out_buftype, ensure to make them both large enough | |
| 43 | + * (>= 3) to hold all compounded responses. Caller is also responsible for | |
| 44 | + * freeing them up with free_rsp_buf(). | |
| 57 | 45 | */ |
| 58 | 46 | static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, |
| 59 | 47 | struct cifs_sb_info *cifs_sb, const char *full_path, |
| 60 | 48 | __u32 desired_access, __u32 create_disposition, __u32 create_options, |
| 61 | 49 | umode_t mode, void *ptr, int command, struct cifsFileInfo *cfile, |
| 62 | 50 | __u8 **extbuf, size_t *extbuflen, |
| 63 | − struct kvec *err_iov, int *err_buftype) | |
| 51 | + struct kvec *out_iov, int *out_buftype) | |
| 64 | 52 | { |
| 65 | − struct cop_vars *vars = NULL; | |
| 53 | + struct smb2_compound_vars *vars = NULL; | |
| 66 | 54 | struct kvec *rsp_iov; |
| 67 | 55 | struct smb_rqst *rqst; |
| 68 | 56 | int rc; |
| @@ -133,7 +121,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, · 64 unmodified lines | ||
| 133 | 121 | /* Operation */ |
| 134 | 122 | switch (command) { |
| 135 | 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 | 125 | rqst[num_rqst].rq_nvec = 1; |
| 138 | 126 | |
| 139 | 127 | if (cfile) |
| @@ -167,7 +155,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, · 27 unmodified lines | ||
| 167 | 155 | full_path); |
| 168 | 156 | break; |
| 169 | 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 | 159 | rqst[num_rqst].rq_nvec = 1; |
| 172 | 160 | |
| 173 | 161 | if (cfile) |
| @@ -375,7 +363,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, · 201 unmodified lines | ||
| 375 | 363 | goto after_close; |
| 376 | 364 | /* Close */ |
| 377 | 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 | 367 | rqst[num_rqst].rq_nvec = 1; |
| 380 | 368 | rc = SMB2_close_init(tcon, server, |
| 381 | 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 | 517 | if (cfile) |
| 530 | 518 | cifsFileInfo_put(cfile); |
| 531 | 519 | |
| 532 | − if (rc && err_iov && err_buftype) { | |
| 533 | − memcpy(err_iov, rsp_iov, 3 * sizeof(*err_iov)); | |
| 534 | − memcpy(err_buftype, resp_buftype, 3 * sizeof(*err_buftype)); | |
| 520 | + if (out_iov && out_buftype) { | |
| 521 | + memcpy(out_iov, rsp_iov, 3 * sizeof(*out_iov)); | |
| 522 | + memcpy(out_buftype, resp_buftype, 3 * sizeof(*out_buftype)); | |
| 535 | 523 | } else { |
| 536 | 524 | free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base); |
| 537 | 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 | 529 | return rc; |
| 542 | 530 | } |
| 543 | 531 | |
| 544 | −int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, | |
| 545 | − struct cifs_sb_info *cifs_sb, const char *full_path, | |
| 546 | − struct cifs_open_info_data *data, bool *adjust_tz, bool *reparse) | |
| 532 | +static int parse_create_response(struct cifs_open_info_data *data, | |
| 533 | + struct cifs_sb_info *cifs_sb, | |
| 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 | 565 | __u32 create_options = 0; |
| 549 | 566 | struct cifsFileInfo *cfile; |
| 550 | 567 | struct cached_fid *cfid = NULL; |
| 551 | − struct kvec err_iov[3] = {}; | |
| 552 | − int err_buftype[3] = {}; | |
| 568 | + struct smb2_hdr *hdr; | |
| 569 | + struct kvec out_iov[3] = {}; | |
| 570 | + int out_buftype[3] = {}; | |
| 553 | 571 | bool islink; |
| 554 | 572 | int rc, rc2; |
| 555 | 573 | |
| 556 | − *adjust_tz = false; | |
| 557 | − *reparse = false; | |
| 574 | + data->adjust_tz = false; | |
| 575 | + data->reparse_point = false; | |
| 558 | 576 | |
| 559 | 577 | if (strcmp(full_path, "")) |
| 560 | 578 | rc = -ENOENT; |
| @@ -575,69 +593,73 @@ int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, · 14 unmodified lines | ||
| 575 | 593 | cifs_get_readable_path(tcon, full_path, &cfile); |
| 576 | 594 | rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES, FILE_OPEN, |
| 577 | 595 | create_options, ACL_NO_MODE, data, SMB2_OP_QUERY_INFO, cfile, |
| 578 | − NULL, NULL, err_iov, err_buftype); | |
| 579 | − if (rc) { | |
| 580 | − struct smb2_hdr *hdr = err_iov[0].iov_base; | |
| 581 | − | |
| 582 | − if (unlikely(!hdr || err_buftype[0] == CIFS_NO_BUFFER)) | |
| 596 | + NULL, NULL, out_iov, out_buftype); | |
| 597 | + hdr = out_iov[0].iov_base; | |
| 598 | + /* | |
| 599 | + * If first iov is unset, then SMB session was dropped or we've got a | |
| 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 | 610 | goto out; |
| 584 | − if (rc == -EOPNOTSUPP && hdr->Command == SMB2_CREATE && | |
| 585 | − hdr->Status == STATUS_STOPPED_ON_SYMLINK) { | |
| 586 | − rc = smb2_parse_symlink_response(cifs_sb, err_iov, | |
| 587 | − &data->symlink_target); | |
| 588 | − if (rc) | |
| 589 | − goto out; | |
| 590 | − | |
| 591 | − *reparse = true; | |
| 592 | − create_options |= OPEN_REPARSE_POINT; | |
| 593 | − | |
| 594 | − /* Failed on a symbolic link - query a reparse point info */ | |
| 595 | − cifs_get_readable_path(tcon, full_path, &cfile); | |
| 596 | − rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, | |
| 597 | − FILE_READ_ATTRIBUTES, FILE_OPEN, | |
| 598 | − create_options, ACL_NO_MODE, data, | |
| 599 | − SMB2_OP_QUERY_INFO, cfile, NULL, NULL, | |
| 600 | − NULL, NULL); | |
| 611 | + | |
| 612 | + create_options |= OPEN_REPARSE_POINT; | |
| 613 | + /* Failed on a symbolic link - query a reparse point info */ | |
| 614 | + cifs_get_readable_path(tcon, full_path, &cfile); | |
| 615 | + rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, | |
| 616 | + FILE_READ_ATTRIBUTES, FILE_OPEN, | |
| 617 | + create_options, ACL_NO_MODE, data, | |
| 618 | + SMB2_OP_QUERY_INFO, cfile, NULL, NULL, | |
| 619 | + NULL, NULL); | |
| 620 | + break; | |
| 621 | + case -EREMOTE: | |
| 622 | + break; | |
| 623 | + default: | |
| 624 | + if (hdr->Status != STATUS_OBJECT_NAME_INVALID) | |
| 625 | + break; | |
| 626 | + rc2 = cifs_inval_name_dfs_link_error(xid, tcon, cifs_sb, | |
| 627 | + full_path, &islink); | |
| 628 | + if (rc2) { | |
| 629 | + rc = rc2; | |
| 601 | 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 | 636 | out: |
| 615 | − free_rsp_buf(err_buftype[0], err_iov[0].iov_base); | |
| 616 | − free_rsp_buf(err_buftype[1], err_iov[1].iov_base); | |
| 617 | − free_rsp_buf(err_buftype[2], err_iov[2].iov_base); | |
| 637 | + free_rsp_buf(out_buftype[0], out_iov[0].iov_base); | |
| 638 | + free_rsp_buf(out_buftype[1], out_iov[1].iov_base); | |
| 639 | + free_rsp_buf(out_buftype[2], out_iov[2].iov_base); | |
| 618 | 640 | return rc; |
| 619 | 641 | } |
| 620 | 642 | |
| 621 | − | |
| 622 | −int smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, | |
| 623 | − struct cifs_sb_info *cifs_sb, const char *full_path, | |
| 643 | +int smb311_posix_query_path_info(const unsigned int xid, | |
| 644 | + struct cifs_tcon *tcon, | |
| 645 | + struct cifs_sb_info *cifs_sb, | |
| 646 | + const char *full_path, | |
| 624 | 647 | struct cifs_open_info_data *data, |
| 625 | 648 | struct cifs_sid *owner, |
| 626 | − struct cifs_sid *group, | |
| 627 | − bool *adjust_tz, bool *reparse) | |
| 649 | + struct cifs_sid *group) | |
| 628 | 650 | { |
| 629 | 651 | int rc; |
| 630 | 652 | __u32 create_options = 0; |
| 631 | 653 | struct cifsFileInfo *cfile; |
| 632 | − struct kvec err_iov[3] = {}; | |
| 633 | − int err_buftype[3] = {}; | |
| 654 | + struct kvec out_iov[3] = {}; | |
| 655 | + int out_buftype[3] = {}; | |
| 634 | 656 | __u8 *sidsbuf = NULL; |
| 635 | 657 | __u8 *sidsbuf_end = NULL; |
| 636 | 658 | size_t sidsbuflen = 0; |
| 637 | 659 | size_t owner_len, group_len; |
| 638 | 660 | |
| 639 | − *adjust_tz = false; | |
| 640 | − *reparse = false; | |
| 661 | + data->adjust_tz = false; | |
| 662 | + data->reparse_point = false; | |
| 641 | 663 | |
| 642 | 664 | /* |
| 643 | 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 | 671 | cifs_get_readable_path(tcon, full_path, &cfile); |
| 650 | 672 | rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES, FILE_OPEN, |
| 651 | 673 | create_options, ACL_NO_MODE, data, SMB2_OP_POSIX_QUERY_INFO, cfile, |
| 652 | − &sidsbuf, &sidsbuflen, err_iov, err_buftype); | |
| 653 | − if (rc == -EOPNOTSUPP) { | |
| 674 | + &sidsbuf, &sidsbuflen, out_iov, out_buftype); | |
| 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 | 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 && | |
| 656 | − ((struct smb2_hdr *)err_iov[0].iov_base)->Command == SMB2_CREATE && | |
| 657 | − ((struct smb2_hdr *)err_iov[0].iov_base)->Status == STATUS_STOPPED_ON_SYMLINK) { | |
| 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; | |
| 686 | + rc = parse_create_response(data, cifs_sb, &out_iov[0]); | |
| 687 | + if (rc || !data->reparse_point) | |
| 688 | + goto out; | |
| 664 | 689 | |
| 690 | + create_options |= OPEN_REPARSE_POINT; | |
| 665 | 691 | /* Failed on a symbolic link - query a reparse point info */ |
| 666 | 692 | cifs_get_readable_path(tcon, full_path, &cfile); |
| 667 | 693 | rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES, |
| 668 | 694 | FILE_OPEN, create_options, ACL_NO_MODE, data, |
| 669 | 695 | SMB2_OP_POSIX_QUERY_INFO, cfile, |
| 670 | 696 | &sidsbuf, &sidsbuflen, NULL, NULL); |
| 697 | + break; | |
| 671 | 698 | } |
| 672 | 699 | |
| 700 | +out: | |
| 673 | 701 | if (rc == 0) { |
| 674 | 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 | 717 | memcpy(group, sidsbuf + owner_len, group_len); |
| 690 | 718 | } |
| 691 | 719 | |
| 692 | −out: | |
| 693 | 720 | kfree(sidsbuf); |
| 694 | − free_rsp_buf(err_buftype[0], err_iov[0].iov_base); | |
| 695 | − free_rsp_buf(err_buftype[1], err_iov[1].iov_base); | |
| 696 | − free_rsp_buf(err_buftype[2], err_iov[2].iov_base); | |
| 721 | + free_rsp_buf(out_buftype[0], out_iov[0].iov_base); | |
| 722 | + free_rsp_buf(out_buftype[1], out_iov[1].iov_base); | |
| 723 | + free_rsp_buf(out_buftype[2], out_iov[2].iov_base); | |
| 697 | 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 | 145 | __u64 mid; |
| 146 | 146 | |
| 147 | 147 | /* If server is a channel, select the primary channel */ |
| 148 | − pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server; | |
| 148 | + pserver = SERVER_IS_CHAN(server) ? server->primary_server : server; | |
| 149 | 149 | |
| 150 | 150 | /* |
| 151 | 151 | * Add function to do table lookup of StructureSize by command |
| @@ -623,7 +623,7 @@ smb2_is_valid_lease_break(char *buffer, struct TCP_Server_Info *server) · 471 unmodified lines | ||
| 623 | 623 | cifs_dbg(FYI, "Checking for lease break\n"); |
| 624 | 624 | |
| 625 | 625 | /* If server is a channel, select the primary channel */ |
| 626 | − pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server; | |
| 626 | + pserver = SERVER_IS_CHAN(server) ? server->primary_server : server; | |
| 627 | 627 | |
| 628 | 628 | /* look up tcon based on tid & uid */ |
| 629 | 629 | spin_lock(&cifs_tcp_ses_lock); |
| @@ -698,7 +698,7 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server) · 68 unmodified lines | ||
| 698 | 698 | cifs_dbg(FYI, "oplock level 0x%x\n", rsp->OplockLevel); |
| 699 | 699 | |
| 700 | 700 | /* If server is a channel, select the primary channel */ |
| 701 | − pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server; | |
| 701 | + pserver = SERVER_IS_CHAN(server) ? server->primary_server : server; | |
| 702 | 702 | |
| 703 | 703 | /* look up tcon based on tid & uid */ |
| 704 | 704 | spin_lock(&cifs_tcp_ses_lock); |
| @@ -172,8 +172,17 @@ smb2_set_credits(struct TCP_Server_Info *server, const int val) · 171 unmodified lines | ||
| 172 | 172 | |
| 173 | 173 | spin_lock(&server->req_lock); |
| 174 | 174 | server->credits = val; |
| 175 | − if (val == 1) | |
| 175 | + if (val == 1) { | |
| 176 | 176 | server->reconnect_instance++; |
| 177 | + /* | |
| 178 | + * ChannelSequence updated for all channels in primary channel so that consistent | |
| 179 | + * across SMB3 requests sent on any channel. See MS-SMB2 3.2.4.1 and 3.2.7.1 | |
| 180 | + */ | |
| 181 | + if (SERVER_IS_CHAN(server)) | |
| 182 | + server->primary_server->channel_sequence_num++; | |
| 183 | + else | |
| 184 | + server->channel_sequence_num++; | |
| 185 | + } | |
| 177 | 186 | scredits = server->credits; |
| 178 | 187 | in_flight = server->in_flight; |
| 179 | 188 | spin_unlock(&server->req_lock); |
| @@ -1075,31 +1084,28 @@ smb2_query_eas(const unsigned int xid, struct cifs_tcon *tcon, · 895 unmodified lines | ||
| 1075 | 1084 | return rc; |
| 1076 | 1085 | } |
| 1077 | 1086 | |
| 1078 | − | |
| 1079 | 1087 | static int |
| 1080 | 1088 | smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, |
| 1081 | 1089 | const char *path, const char *ea_name, const void *ea_value, |
| 1082 | 1090 | const __u16 ea_value_len, const struct nls_table *nls_codepage, |
| 1083 | 1091 | struct cifs_sb_info *cifs_sb) |
| 1084 | 1092 | { |
| 1093 | + struct smb2_compound_vars *vars; | |
| 1085 | 1094 | struct cifs_ses *ses = tcon->ses; |
| 1086 | 1095 | struct TCP_Server_Info *server = cifs_pick_channel(ses); |
| 1096 | + struct smb_rqst *rqst; | |
| 1097 | + struct kvec *rsp_iov; | |
| 1087 | 1098 | __le16 *utf16_path = NULL; |
| 1088 | 1099 | int ea_name_len = strlen(ea_name); |
| 1089 | 1100 | int flags = CIFS_CP_CREATE_CLOSE_OP; |
| 1090 | 1101 | int len; |
| 1091 | − struct smb_rqst rqst[3]; | |
| 1092 | 1102 | int resp_buftype[3]; |
| 1093 | − struct kvec rsp_iov[3]; | |
| 1094 | − struct kvec open_iov[SMB2_CREATE_IOV_SIZE]; | |
| 1095 | 1103 | struct cifs_open_parms oparms; |
| 1096 | 1104 | __u8 oplock = SMB2_OPLOCK_LEVEL_NONE; |
| 1097 | 1105 | struct cifs_fid fid; |
| 1098 | − struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE]; | |
| 1099 | 1106 | unsigned int size[1]; |
| 1100 | 1107 | void *data[1]; |
| 1101 | 1108 | struct smb2_file_full_ea_info *ea = NULL; |
| 1102 | − struct kvec close_iov[1]; | |
| 1103 | 1109 | struct smb2_query_info_rsp *rsp; |
| 1104 | 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 | 1119 | if (!utf16_path) |
| 1114 | 1120 | return -ENOMEM; |
| 1115 | 1121 | |
| 1116 | − memset(rqst, 0, sizeof(rqst)); | |
| 1117 | 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 | 1131 | if (ses->server->ops->query_all_EAs) { |
| 1121 | 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 | 1173 | /* Open */ |
| 1163 | − memset(&open_iov, 0, sizeof(open_iov)); | |
| 1164 | − rqst[0].rq_iov = open_iov; | |
| 1174 | + rqst[0].rq_iov = vars->open_iov; | |
| 1165 | 1175 | rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE; |
| 1166 | 1176 | |
| 1167 | 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 | 1193 | /* Set Info */ |
| 1184 | − memset(&si_iov, 0, sizeof(si_iov)); | |
| 1185 | − rqst[1].rq_iov = si_iov; | |
| 1194 | + rqst[1].rq_iov = vars->si_iov; | |
| 1186 | 1195 | rqst[1].rq_nvec = 1; |
| 1187 | 1196 | |
| 1188 | 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 | 1219 | smb2_set_next_command(tcon, &rqst[1]); |
| 1211 | 1220 | smb2_set_related(&rqst[1]); |
| 1212 | 1221 | |
| 1213 | − | |
| 1214 | 1222 | /* Close */ |
| 1215 | − memset(&close_iov, 0, sizeof(close_iov)); | |
| 1216 | − rqst[2].rq_iov = close_iov; | |
| 1223 | + rqst[2].rq_iov = &vars->close_iov; | |
| 1217 | 1224 | rqst[2].rq_nvec = 1; |
| 1218 | 1225 | rc = SMB2_close_init(tcon, server, |
| 1219 | 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 | 1236 | sea_exit: |
| 1230 | 1237 | kfree(ea); |
| 1231 | − kfree(utf16_path); | |
| 1232 | 1238 | SMB2_open_free(&rqst[0]); |
| 1233 | 1239 | SMB2_set_info_free(&rqst[1]); |
| 1234 | 1240 | SMB2_close_free(&rqst[2]); |
| 1235 | 1241 | free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base); |
| 1236 | 1242 | free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base); |
| 1237 | 1243 | free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base); |
| 1244 | + kfree(vars); | |
| 1245 | +out_free_path: | |
| 1246 | + kfree(utf16_path); | |
| 1238 | 1247 | return rc; |
| 1239 | 1248 | } |
| 1240 | 1249 | #endif |
| @@ -1446,16 +1455,6 @@ req_res_key_exit: · 205 unmodified lines | ||
| 1446 | 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 | 1458 | static int |
| 1460 | 1459 | smb2_ioctl_query_info(const unsigned int xid, |
| 1461 | 1460 | struct cifs_tcon *tcon, |
| @@ -1463,7 +1462,7 @@ smb2_ioctl_query_info(const unsigned int xid, · 1 unmodified line | ||
| 1463 | 1462 | __le16 *path, int is_dir, |
| 1464 | 1463 | unsigned long p) |
| 1465 | 1464 | { |
| 1466 | − struct iqi_vars *vars; | |
| 1465 | + struct smb2_compound_vars *vars; | |
| 1467 | 1466 | struct smb_rqst *rqst; |
| 1468 | 1467 | struct kvec *rsp_iov; |
| 1469 | 1468 | struct cifs_ses *ses = tcon->ses; |
| @@ -1581,7 +1580,7 @@ smb2_ioctl_query_info(const unsigned int xid, · 111 unmodified lines | ||
| 1581 | 1580 | rc = -EINVAL; |
| 1582 | 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 | 1584 | rqst[1].rq_nvec = 1; |
| 1586 | 1585 | |
| 1587 | 1586 | /* MS-FSCC 2.4.13 FileEndOfFileInformation */ |
| @@ -1593,7 +1592,7 @@ smb2_ioctl_query_info(const unsigned int xid, · 5 unmodified lines | ||
| 1593 | 1592 | SMB2_O_INFO_FILE, 0, data, size); |
| 1594 | 1593 | free_req1_func = SMB2_set_info_free; |
| 1595 | 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 | 1596 | rqst[1].rq_nvec = 1; |
| 1598 | 1597 | |
| 1599 | 1598 | rc = SMB2_query_info_init(tcon, server, |
| @@ -1615,7 +1614,7 @@ smb2_ioctl_query_info(const unsigned int xid, · 15 unmodified lines | ||
| 1615 | 1614 | smb2_set_related(&rqst[1]); |
| 1616 | 1615 | |
| 1617 | 1616 | /* Close */ |
| 1618 | − rqst[2].rq_iov = &vars->close_iov[0]; | |
| 1617 | + rqst[2].rq_iov = &vars->close_iov; | |
| 1619 | 1618 | rqst[2].rq_nvec = 1; |
| 1620 | 1619 | |
| 1621 | 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 | 2407 | return false; |
| 2409 | 2408 | |
| 2410 | 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 | 2412 | spin_lock(&cifs_tcp_ses_lock); |
| 2414 | 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 | 2523 | struct kvec *rsp, int *buftype, |
| 2525 | 2524 | struct cifs_sb_info *cifs_sb) |
| 2526 | 2525 | { |
| 2526 | + struct smb2_compound_vars *vars; | |
| 2527 | 2527 | struct cifs_ses *ses = tcon->ses; |
| 2528 | 2528 | struct TCP_Server_Info *server = cifs_pick_channel(ses); |
| 2529 | 2529 | int flags = CIFS_CP_CREATE_CLOSE_OP; |
| 2530 | − struct smb_rqst rqst[3]; | |
| 2530 | + struct smb_rqst *rqst; | |
| 2531 | 2531 | int resp_buftype[3]; |
| 2532 | − struct kvec rsp_iov[3]; | |
| 2533 | − struct kvec open_iov[SMB2_CREATE_IOV_SIZE]; | |
| 2534 | − struct kvec qi_iov[1]; | |
| 2535 | − struct kvec close_iov[1]; | |
| 2532 | + struct kvec *rsp_iov; | |
| 2536 | 2533 | u8 oplock = SMB2_OPLOCK_LEVEL_NONE; |
| 2537 | 2534 | struct cifs_open_parms oparms; |
| 2538 | 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 | 2546 | if (smb3_encryption_required(tcon)) |
| 2550 | 2547 | flags |= CIFS_TRANSFORM_REQ; |
| 2551 | 2548 | |
| 2552 | − memset(rqst, 0, sizeof(rqst)); | |
| 2553 | 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 | 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 | 2562 | open_cached_dir(xid, tcon, path, cifs_sb, false, |
| 2561 | 2563 | &cfid); /* cfid null if open dir failed */ |
| 2562 | 2564 | |
| 2563 | − memset(&open_iov, 0, sizeof(open_iov)); | |
| 2564 | − rqst[0].rq_iov = open_iov; | |
| 2565 | + rqst[0].rq_iov = vars->open_iov; | |
| 2565 | 2566 | rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE; |
| 2566 | 2567 | |
| 2567 | 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 | 2580 | goto qic_exit; |
| 2580 | 2581 | smb2_set_next_command(tcon, &rqst[0]); |
| 2581 | 2582 | |
| 2582 | − memset(&qi_iov, 0, sizeof(qi_iov)); | |
| 2583 | − rqst[1].rq_iov = qi_iov; | |
| 2583 | + rqst[1].rq_iov = &vars->qi_iov; | |
| 2584 | 2584 | rqst[1].rq_nvec = 1; |
| 2585 | 2585 | |
| 2586 | 2586 | if (cfid) { |
| @@ -2607,8 +2607,7 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon, · 20 unmodified lines | ||
| 2607 | 2607 | smb2_set_related(&rqst[1]); |
| 2608 | 2608 | } |
| 2609 | 2609 | |
| 2610 | − memset(&close_iov, 0, sizeof(close_iov)); | |
| 2611 | − rqst[2].rq_iov = close_iov; | |
| 2610 | + rqst[2].rq_iov = &vars->close_iov; | |
| 2612 | 2611 | rqst[2].rq_nvec = 1; |
| 2613 | 2612 | |
| 2614 | 2613 | rc = SMB2_close_init(tcon, server, |
| @@ -2639,7 +2638,6 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon, · 24 unmodified lines | ||
| 2639 | 2638 | *buftype = resp_buftype[1]; |
| 2640 | 2639 | |
| 2641 | 2640 | qic_exit: |
| 2642 | − kfree(utf16_path); | |
| 2643 | 2641 | SMB2_open_free(&rqst[0]); |
| 2644 | 2642 | SMB2_query_info_free(&rqst[1]); |
| 2645 | 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 | 2645 | free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base); |
| 2648 | 2646 | if (cfid) |
| 2649 | 2647 | close_cached_dir(cfid); |
| 2648 | + kfree(vars); | |
| 2649 | +out_free_path: | |
| 2650 | + kfree(utf16_path); | |
| 2650 | 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 | −smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, | |
| 2954 | − struct cifs_sb_info *cifs_sb, const char *full_path, | |
| 2955 | − char **target_path, bool is_reparse_point) | |
| 2953 | +static int smb2_query_symlink(const unsigned int xid, | |
| 2954 | + struct cifs_tcon *tcon, | |
| 2955 | + struct cifs_sb_info *cifs_sb, | |
| 2956 | + const char *full_path, | |
| 2957 | + char **target_path, | |
| 2958 | + struct kvec *rsp_iov) | |
| 2956 | 2959 | { |
| 2957 | − int rc; | |
| 2958 | − __le16 *utf16_path = NULL; | |
| 2959 | − __u8 oplock = SMB2_OPLOCK_LEVEL_NONE; | |
| 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; | |
| 2960 | + struct reparse_data_buffer *buf; | |
| 2961 | + struct smb2_ioctl_rsp *io = rsp_iov->iov_base; | |
| 2962 | + u32 plen = le32_to_cpu(io->OutputCount); | |
| 2976 | 2963 | |
| 2977 | 2964 | cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path); |
| 2978 | 2965 | |
| 2979 | − *target_path = NULL; | |
| 2980 | − | |
| 2981 | − if (smb3_encryption_required(tcon)) | |
| 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; | |
| 2966 | + buf = (struct reparse_data_buffer *)((u8 *)io + | |
| 2967 | + le32_to_cpu(io->OutputOffset)); | |
| 2968 | + return parse_reparse_point(buf, plen, target_path, cifs_sb); | |
| 3093 | 2969 | } |
| 3094 | 2970 | |
| 3095 | −int | |
| 3096 | −smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon, | |
| 3097 | − struct cifs_sb_info *cifs_sb, const char *full_path, | |
| 3098 | − __u32 *tag) | |
| 2971 | +static int smb2_query_reparse_point(const unsigned int xid, | |
| 2972 | + struct cifs_tcon *tcon, | |
| 2973 | + struct cifs_sb_info *cifs_sb, | |
| 2974 | + const char *full_path, | |
| 2975 | + u32 *tag, struct kvec *rsp, | |
| 2976 | + int *rsp_buftype) | |
| 3099 | 2977 | { |
| 2978 | + struct smb2_compound_vars *vars; | |
| 3100 | 2979 | int rc; |
| 3101 | 2980 | __le16 *utf16_path = NULL; |
| 3102 | 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 | 2983 | struct cifs_fid fid; |
| 3105 | 2984 | struct TCP_Server_Info *server = cifs_pick_channel(tcon->ses); |
| 3106 | 2985 | int flags = CIFS_CP_CREATE_CLOSE_OP; |
| 3107 | − struct smb_rqst rqst[3]; | |
| 2986 | + struct smb_rqst *rqst; | |
| 3108 | 2987 | int resp_buftype[3]; |
| 3109 | − struct kvec rsp_iov[3]; | |
| 3110 | − struct kvec open_iov[SMB2_CREATE_IOV_SIZE]; | |
| 3111 | − struct kvec io_iov[SMB2_IOCTL_IOV_SIZE]; | |
| 3112 | − struct kvec close_iov[1]; | |
| 2988 | + struct kvec *rsp_iov; | |
| 3113 | 2989 | struct smb2_ioctl_rsp *ioctl_rsp; |
| 3114 | 2990 | struct reparse_data_buffer *reparse_buf; |
| 3115 | 2991 | u32 plen; |
| @@ -3119,20 +2995,24 @@ smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon, · 3 unmodified lines | ||
| 3119 | 2995 | if (smb3_encryption_required(tcon)) |
| 3120 | 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 | 2998 | utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb); |
| 3127 | 2999 | if (!utf16_path) |
| 3128 | 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 | 3012 | * setup smb2open - TODO add optimization to call cifs_get_readable_path |
| 3132 | 3013 | * to see if there is a handle already open that we can use |
| 3133 | 3014 | */ |
| 3134 | − memset(&open_iov, 0, sizeof(open_iov)); | |
| 3135 | − rqst[0].rq_iov = open_iov; | |
| 3015 | + rqst[0].rq_iov = vars->open_iov; | |
| 3136 | 3016 | rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE; |
| 3137 | 3017 | |
| 3138 | 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 | 3034 | /* IOCTL */ |
| 3155 | − memset(&io_iov, 0, sizeof(io_iov)); | |
| 3156 | − rqst[1].rq_iov = io_iov; | |
| 3035 | + rqst[1].rq_iov = vars->io_iov; | |
| 3157 | 3036 | rqst[1].rq_nvec = SMB2_IOCTL_IOV_SIZE; |
| 3158 | 3037 | |
| 3159 | 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 | 3047 | smb2_set_next_command(tcon, &rqst[1]); |
| 3169 | 3048 | smb2_set_related(&rqst[1]); |
| 3170 | 3049 | |
| 3171 | − | |
| 3172 | 3050 | /* Close */ |
| 3173 | − memset(&close_iov, 0, sizeof(close_iov)); | |
| 3174 | − rqst[2].rq_iov = close_iov; | |
| 3051 | + rqst[2].rq_iov = &vars->close_iov; | |
| 3175 | 3052 | rqst[2].rq_nvec = 1; |
| 3176 | 3053 | |
| 3177 | 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 | 3083 | goto query_rp_exit; |
| 3207 | 3084 | } |
| 3208 | 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 | 3091 | query_rp_exit: |
| 3212 | − kfree(utf16_path); | |
| 3213 | 3092 | SMB2_open_free(&rqst[0]); |
| 3214 | 3093 | SMB2_ioctl_free(&rqst[1]); |
| 3215 | 3094 | SMB2_close_free(&rqst[2]); |
| 3216 | 3095 | free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base); |
| 3217 | 3096 | free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base); |
| 3218 | 3097 | free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base); |
| 3098 | + kfree(vars); | |
| 3099 | +out_free_path: | |
| 3100 | + kfree(utf16_path); | |
| 3219 | 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 | 4283 | u8 *ses_enc_key; |
| 4402 | 4284 | |
| 4403 | 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 | 4288 | spin_lock(&cifs_tcp_ses_lock); |
| 4407 | 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 | 5181 | .can_echo = smb2_can_echo, |
| 5300 | 5182 | .echo = SMB2_echo, |
| 5301 | 5183 | .query_path_info = smb2_query_path_info, |
| 5184 | + .query_reparse_point = smb2_query_reparse_point, | |
| 5302 | 5185 | .get_srv_inum = smb2_get_srv_inum, |
| 5303 | 5186 | .query_file_info = smb2_query_file_info, |
| 5304 | 5187 | .set_path_size = smb2_set_path_size, |
| @@ -5400,6 +5283,7 @@ struct smb_version_operations smb21_operations = { · 95 unmodified lines | ||
| 5400 | 5283 | .can_echo = smb2_can_echo, |
| 5401 | 5284 | .echo = SMB2_echo, |
| 5402 | 5285 | .query_path_info = smb2_query_path_info, |
| 5286 | + .query_reparse_point = smb2_query_reparse_point, | |
| 5403 | 5287 | .get_srv_inum = smb2_get_srv_inum, |
| 5404 | 5288 | .query_file_info = smb2_query_file_info, |
| 5405 | 5289 | .set_path_size = smb2_set_path_size, |
| @@ -5504,7 +5388,7 @@ struct smb_version_operations smb30_operations = { · 98 unmodified lines | ||
| 5504 | 5388 | .echo = SMB2_echo, |
| 5505 | 5389 | .query_path_info = smb2_query_path_info, |
| 5506 | 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 | 5392 | .get_srv_inum = smb2_get_srv_inum, |
| 5509 | 5393 | .query_file_info = smb2_query_file_info, |
| 5510 | 5394 | .set_path_size = smb2_set_path_size, |
| @@ -5617,7 +5501,7 @@ struct smb_version_operations smb311_operations = { · 106 unmodified lines | ||
| 5617 | 5501 | .can_echo = smb2_can_echo, |
| 5618 | 5502 | .echo = SMB2_echo, |
| 5619 | 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 | 5505 | .get_srv_inum = smb2_get_srv_inum, |
| 5622 | 5506 | .query_file_info = smb2_query_file_info, |
| 5623 | 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 | 88 | const struct cifs_tcon *tcon, |
| 89 | 89 | struct TCP_Server_Info *server) |
| 90 | 90 | { |
| 91 | + struct smb3_hdr_req *smb3_hdr; | |
| 91 | 92 | shdr->ProtocolId = SMB2_PROTO_NUMBER; |
| 92 | 93 | shdr->StructureSize = cpu_to_le16(64); |
| 93 | 94 | shdr->Command = smb2_cmd; |
| 95 | + if (server->dialect >= SMB30_PROT_ID) { | |
| 96 | + /* After reconnect SMB3 must set ChannelSequence on subsequent reqs */ | |
| 97 | + smb3_hdr = (struct smb3_hdr_req *)shdr; | |
| 98 | + /* if primary channel is not set yet, use default channel for chan sequence num */ | |
| 99 | + if (SERVER_IS_CHAN(server)) | |
| 100 | + smb3_hdr->ChannelSequence = | |
| 101 | + cpu_to_le16(server->primary_server->channel_sequence_num); | |
| 102 | + else | |
| 103 | + smb3_hdr->ChannelSequence = cpu_to_le16(server->channel_sequence_num); | |
| 104 | + } | |
| 94 | 105 | if (server) { |
| 95 | 106 | spin_lock(&server->req_lock); |
| 96 | 107 | /* Request up to 10 credits but don't go over the limit. */ |
| @@ -553,7 +564,7 @@ assemble_neg_contexts(struct smb2_negotiate_req *req, · 456 unmodified lines | ||
| 553 | 564 | * secondary channels don't have the hostname field populated |
| 554 | 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 | 568 | cifs_server_lock(pserver); |
| 558 | 569 | hostname = pserver->hostname; |
| 559 | 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 | 2582 | /* Do not append the separator if the path is empty */ |
| 2572 | 2583 | if (path[0] != cpu_to_le16(0x0000)) { |
| 2573 | − UniStrcat(*out_path, sep); | |
| 2574 | − UniStrcat(*out_path, path); | |
| 2584 | + UniStrcat((wchar_t *)*out_path, (wchar_t *)sep); | |
| 2585 | + UniStrcat((wchar_t *)*out_path, (wchar_t *)path); | |
| 2575 | 2586 | } |
| 2576 | 2587 | |
| 2577 | 2588 | unload_nls(cp); |
| @@ -3785,7 +3796,7 @@ void smb2_reconnect_server(struct work_struct *work) · 1207 unmodified lines | ||
| 3785 | 3796 | bool resched = false; |
| 3786 | 3797 | |
| 3787 | 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 | 3801 | /* Prevent simultaneous reconnects that can corrupt tcon->rlist list */ |
| 3791 | 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 | 56 | extern int smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon, |
| 57 | 57 | struct cifs_sb_info *cifs_sb, const char *path, |
| 58 | 58 | __u32 *reparse_tag); |
| 59 | −int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, | |
| 60 | − struct cifs_sb_info *cifs_sb, const char *full_path, | |
| 61 | − struct cifs_open_info_data *data, bool *adjust_tz, bool *reparse); | |
| 59 | +int smb2_query_path_info(const unsigned int xid, | |
| 60 | + struct cifs_tcon *tcon, | |
| 61 | + struct cifs_sb_info *cifs_sb, | |
| 62 | + const char *full_path, | |
| 63 | + struct cifs_open_info_data *data); | |
| 62 | 64 | extern int smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon, |
| 63 | 65 | const char *full_path, __u64 size, |
| 64 | 66 | struct cifs_sb_info *cifs_sb, bool set_alloc); |
| @@ -275,12 +277,13 @@ extern int smb2_query_info_compound(const unsigned int xid, · 210 unmodified lines | ||
| 275 | 277 | struct kvec *rsp, int *buftype, |
| 276 | 278 | struct cifs_sb_info *cifs_sb); |
| 277 | 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, | |
| 279 | − struct cifs_sb_info *cifs_sb, const char *full_path, | |
| 280 | +int smb311_posix_query_path_info(const unsigned int xid, | |
| 281 | + struct cifs_tcon *tcon, | |
| 282 | + struct cifs_sb_info *cifs_sb, | |
| 283 | + const char *full_path, | |
| 280 | 284 | struct cifs_open_info_data *data, |
| 281 | 285 | struct cifs_sid *owner, |
| 282 | − struct cifs_sid *group, | |
| 283 | − bool *adjust_tz, bool *reparse); | |
| 286 | + struct cifs_sid *group); | |
| 284 | 287 | int posix_info_parse(const void *beg, const void *end, |
| 285 | 288 | struct smb2_posix_info_parsed *out); |
| 286 | 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 | 86 | spin_lock(&cifs_tcp_ses_lock); |
| 87 | 87 | |
| 88 | 88 | /* If server is a channel, select the primary channel */ |
| 89 | − pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server; | |
| 89 | + pserver = SERVER_IS_CHAN(server) ? server->primary_server : server; | |
| 90 | 90 | |
| 91 | 91 | list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) { |
| 92 | 92 | if (ses->Suid == ses_id) |
| @@ -149,7 +149,7 @@ smb2_find_smb_ses_unlocked(struct TCP_Server_Info *server, __u64 ses_id) · 56 unmodified lines | ||
| 149 | 149 | struct cifs_ses *ses; |
| 150 | 150 | |
| 151 | 151 | /* If server is a channel, select the primary channel */ |
| 152 | − pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server; | |
| 152 | + pserver = SERVER_IS_CHAN(server) ? server->primary_server : server; | |
| 153 | 153 | |
| 154 | 154 | list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) { |
| 155 | 155 | if (ses->Suid != ses_id) |
| @@ -416,13 +416,19 @@ out: · 415 unmodified lines | ||
| 416 | 416 | return rc; |
| 417 | 417 | } |
| 418 | 418 | |
| 419 | +struct send_req_vars { | |
| 420 | + struct smb2_transform_hdr tr_hdr; | |
| 421 | + struct smb_rqst rqst[MAX_COMPOUND]; | |
| 422 | + struct kvec iov; | |
| 423 | +}; | |
| 424 | + | |
| 419 | 425 | static int |
| 420 | 426 | smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, |
| 421 | 427 | struct smb_rqst *rqst, int flags) |
| 422 | 428 | { |
| 423 | − struct kvec iov; | |
| 424 | − struct smb2_transform_hdr *tr_hdr; | |
| 425 | − struct smb_rqst cur_rqst[MAX_COMPOUND]; | |
| 429 | + struct send_req_vars *vars; | |
| 430 | + struct smb_rqst *cur_rqst; | |
| 431 | + struct kvec *iov; | |
| 426 | 432 | int rc; |
| 427 | 433 | |
| 428 | 434 | if (!(flags & CIFS_TRANSFORM_REQ)) |
| @@ -436,16 +442,15 @@ smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, · 7 unmodified lines | ||
| 436 | 442 | return -EIO; |
| 437 | 443 | } |
| 438 | 444 | |
| 439 | − tr_hdr = kzalloc(sizeof(*tr_hdr), GFP_NOFS); | |
| 440 | − if (!tr_hdr) | |
| 445 | + vars = kzalloc(sizeof(*vars), GFP_NOFS); | |
| 446 | + if (!vars) | |
| 441 | 447 | return -ENOMEM; |
| 448 | + cur_rqst = vars->rqst; | |
| 449 | + iov = &vars->iov; | |
| 442 | 450 | |
| 443 | − memset(&cur_rqst[0], 0, sizeof(cur_rqst)); | |
| 444 | − memset(&iov, 0, sizeof(iov)); | |
| 445 | − | |
| 446 | − iov.iov_base = tr_hdr; | |
| 447 | − iov.iov_len = sizeof(*tr_hdr); | |
| 448 | − cur_rqst[0].rq_iov = &iov; | |
| 451 | + iov->iov_base = &vars->tr_hdr; | |
| 452 | + iov->iov_len = sizeof(vars->tr_hdr); | |
| 453 | + cur_rqst[0].rq_iov = iov; | |
| 449 | 454 | cur_rqst[0].rq_nvec = 1; |
| 450 | 455 | |
| 451 | 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 | 461 | rc = __smb_send_rqst(server, num_rqst + 1, &cur_rqst[0]); |
| 457 | 462 | smb3_free_compound_rqst(num_rqst, &cur_rqst[1]); |
| 458 | 463 | out: |
| 459 | − kfree(tr_hdr); | |
| 464 | + kfree(vars); | |
| 460 | 465 | return rc; |
| 461 | 466 | } |
| 462 | 467 | |
| @@ -153,6 +153,28 @@ struct smb2_hdr { · 152 unmodified lines | ||
| 153 | 153 | __u8 Signature[16]; |
| 154 | 154 | } __packed; |
| 155 | 155 | |
| 156 | +struct smb3_hdr_req { | |
| 157 | + __le32 ProtocolId; /* 0xFE 'S' 'M' 'B' */ | |
| 158 | + __le16 StructureSize; /* 64 */ | |
| 159 | + __le16 CreditCharge; /* MBZ */ | |
| 160 | + __le16 ChannelSequence; /* See MS-SMB2 3.2.4.1 and 3.2.7.1 */ | |
| 161 | + __le16 Reserved; | |
| 162 | + __le16 Command; | |
| 163 | + __le16 CreditRequest; /* CreditResponse */ | |
| 164 | + __le32 Flags; | |
| 165 | + __le32 NextCommand; | |
| 166 | + __le64 MessageId; | |
| 167 | + union { | |
| 168 | + struct { | |
| 169 | + __le32 ProcessId; | |
| 170 | + __le32 TreeId; | |
| 171 | + } __packed SyncId; | |
| 172 | + __le64 AsyncId; | |
| 173 | + } __packed Id; | |
| 174 | + __le64 SessionId; | |
| 175 | + __u8 Signature[16]; | |
| 176 | +} __packed; | |
| 177 | + | |
| 156 | 178 | struct smb2_pdu { |
| 157 | 179 | struct smb2_hdr hdr; |
| 158 | 180 | __le16 StructureSize2; /* size of wct area (varies, request specific) */ |
| @@ -5,6 +5,7 @@ config SMB_SERVER · 4 unmodified lines | ||
| 5 | 5 | depends on FILE_LOCKING |
| 6 | 6 | select NLS |
| 7 | 7 | select NLS_UTF8 |
| 8 | + select NLS_UCS2_UTILS | |
| 8 | 9 | select CRYPTO |
| 9 | 10 | select CRYPTO_MD5 |
| 10 | 11 | select CRYPTO_HMAC |
| @@ -11,7 +11,6 @@ · 10 unmodified lines | ||
| 11 | 11 | #include <asm/unaligned.h> |
| 12 | 12 | #include "glob.h" |
| 13 | 13 | #include "unicode.h" |
| 14 | −#include "uniupr.h" | |
| 15 | 14 | #include "smb_common.h" |
| 16 | 15 | |
| 17 | 16 | /* |
| @@ -18,49 +18,14 @@ · 17 unmodified lines | ||
| 18 | 18 | * This is a compressed table of upper and lower case conversion. |
| 19 | 19 | * |
| 20 | 20 | */ |
| 21 | −#ifndef _CIFS_UNICODE_H | |
| 22 | −#define _CIFS_UNICODE_H | |
| 21 | +#ifndef _SMB_UNICODE_H | |
| 22 | +#define _SMB_UNICODE_H | |
| 23 | 23 | |
| 24 | 24 | #include <asm/byteorder.h> |
| 25 | 25 | #include <linux/types.h> |
| 26 | 26 | #include <linux/nls.h> |
| 27 | 27 | #include <linux/unicode.h> |
| 28 | − | |
| 29 | −#define UNIUPR_NOLOWER /* Example to not expand lower case tables */ | |
| 30 | − | |
| 31 | −/* | |
| 32 | − * Windows maps these to the user defined 16 bit Unicode range since they are | |
| 33 | − * reserved symbols (along with \ and /), otherwise illegal to store | |
| 34 | − * in filenames in NTFS | |
| 35 | − */ | |
| 36 | −#define UNI_ASTERISK ((__u16)('*' + 0xF000)) | |
| 37 | −#define UNI_QUESTION ((__u16)('?' + 0xF000)) | |
| 38 | −#define UNI_COLON ((__u16)(':' + 0xF000)) | |
| 39 | −#define UNI_GRTRTHAN ((__u16)('>' + 0xF000)) | |
| 40 | −#define UNI_LESSTHAN ((__u16)('<' + 0xF000)) | |
| 41 | −#define UNI_PIPE ((__u16)('|' + 0xF000)) | |
| 42 | −#define UNI_SLASH ((__u16)('\\' + 0xF000)) | |
| 43 | − | |
| 44 | −/* Just define what we want from uniupr.h. We don't want to define the tables | |
| 45 | − * in each source file. | |
| 46 | − */ | |
| 47 | −#ifndef UNICASERANGE_DEFINED | |
| 48 | −struct UniCaseRange { | |
| 49 | − wchar_t start; | |
| 50 | − wchar_t end; | |
| 51 | − signed char *table; | |
| 52 | −}; | |
| 53 | −#endif /* UNICASERANGE_DEFINED */ | |
| 54 | − | |
| 55 | −#ifndef UNIUPR_NOUPPER | |
| 56 | −extern signed char SmbUniUpperTable[512]; | |
| 57 | −extern const struct UniCaseRange SmbUniUpperRange[]; | |
| 58 | −#endif /* UNIUPR_NOUPPER */ | |
| 59 | − | |
| 60 | −#ifndef UNIUPR_NOLOWER | |
| 61 | −extern signed char CifsUniLowerTable[512]; | |
| 62 | −extern const struct UniCaseRange CifsUniLowerRange[]; | |
| 63 | −#endif /* UNIUPR_NOLOWER */ | |
| 28 | +#include "../../nls/nls_ucs2_utils.h" | |
| 64 | 29 | |
| 65 | 30 | #ifdef __KERNEL__ |
| 66 | 31 | int smb_strtoUTF16(__le16 *to, const char *from, int len, |
| @@ -73,286 +38,4 @@ int smbConvertToUTF16(__le16 *target, const char *source, int srclen, · 6 unmodified lines | ||
| 73 | 38 | char *ksmbd_extract_sharename(struct unicode_map *um, const char *treename); |
| 74 | 39 | #endif |
| 75 | 40 | |
| 76 | −/* | |
| 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 */ | |
| 41 | +#endif /* _SMB_UNICODE_H */ | |