mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-28 16:56:26 +00:00
22 smb3/cifs client fixes and two related changes (for unicode mapping)
-----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAmTvk44ACgkQiiy9cAdy T1GT+wwAkiM+BFVoW0QhLK9ztPptYofGiTKr1AySV09AWos9Fwdhv0aS4LDKhauW PVsORfnFcLdyAHtgX2DlhJHMpLWDz3Z51KWiUSo7AAZjIp/4K0yEarg4WKPtUPN0 PMET2OuqAfIfYLCxSZYFjiGK6xgSJEz+xIhX0qJPRZsyJp50WlFlyZRUfFa+6hXt pguatCVw4qhP9hkdcklCY8rwlFDdWEHj9wD/PB2Qschw4gzxDUMwOJjDgT6PNxjA SAC6J+NQVtMcnASd5pn0+Mbc+vNfKZ0PM+KZcDrJphcBz+arY6Hu57v3/yu2y++L DqRI6QtEwVmHzytM51x5JaWFE0Asj/NsH69LVm4bXVIkkcXBut6lLhrd/KVSP+xN LY4EcYEoufAAaecrQrMO4x2Tm10f+GMi1Fh9NvpLZVRrUXy4rdxLP2aC+q+i3uY3 34FaAbpjQ7NJq2yZTL8xDOdCvi8E3t58DsBv4jA9Y/SYGWYao8Kw0vxhCt0SVZPc HaoMfkxl =CtQO -----END PGP SIGNATURE----- Merge tag '6.6-rc-smb3-client-fixes-part1' of git://git.samba.org/sfrench/cifs-2.6 Pull smb client updates from Steve French: - fixes for excessive stack usage - multichannel reconnect improvements - DFS fix and cleanup patches - move UCS-2 conversion code to fs/nls and update cifs and jfs to use them - cleanup patch for compounding, one to fix confusing function name - inode number collision fix - reparse point fixes (including avoiding an extra unneeded query on symlinks) and a minor cleanup - directory lease (caching) improvement * tag '6.6-rc-smb3-client-fixes-part1' of git://git.samba.org/sfrench/cifs-2.6: (24 commits) fs/jfs: Use common ucs2 upper case table fs/smb/client: Use common code in client fs/smb: Swing unicode common code from smb->NLS fs/smb: Remove unicode 'lower' tables SMB3: rename macro CIFS_SERVER_IS_CHAN to avoid confusion [SMB3] send channel sequence number in SMB3 requests after reconnects cifs: update desired access while requesting for directory lease smb: client: reduce stack usage in smb2_query_reparse_point() smb: client: reduce stack usage in smb2_query_info_compound() smb: client: reduce stack usage in smb2_set_ea() smb: client: reduce stack usage in smb_send_rqst() smb: client: reduce stack usage in cifs_demultiplex_thread() smb: client: reduce stack usage in cifs_try_adding_channels() smb: cilent: set reparse mount points as automounts smb: client: query reparse points in older dialects smb: client: do not query reparse points twice on symlinks smb: client: parse reparse point flag in create response smb: client: get rid of dfs code dep in namespace.c smb: client: get rid of dfs naming in automount code smb: client: rename cifs_dfs_ref.c to namespace.c ...
This commit is contained in:
commit
b97d64c722
@ -3,6 +3,7 @@ config JFS_FS
|
||||
tristate "JFS filesystem support"
|
||||
select BUFFER_HEAD
|
||||
select NLS
|
||||
select NLS_UCS2_UTILS
|
||||
select CRC32
|
||||
select LEGACY_DIRECT_IO
|
||||
help
|
||||
|
@ -9,7 +9,7 @@ jfs-y := super.o file.o inode.o namei.o jfs_mount.o jfs_umount.o \
|
||||
jfs_xtree.o jfs_imap.o jfs_debug.o jfs_dmap.o \
|
||||
jfs_unicode.o jfs_dtree.o jfs_inode.o jfs_discard.o \
|
||||
jfs_extent.o symlink.o jfs_metapage.o \
|
||||
jfs_logmgr.o jfs_txnmgr.o jfs_uniupr.o \
|
||||
jfs_logmgr.o jfs_txnmgr.o \
|
||||
resize.o xattr.o ioctl.o
|
||||
|
||||
jfs-$(CONFIG_JFS_POSIX_ACL) += acl.o
|
||||
|
@ -8,16 +8,9 @@
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include "../nls/nls_ucs2_data.h"
|
||||
#include "jfs_types.h"
|
||||
|
||||
typedef struct {
|
||||
wchar_t start;
|
||||
wchar_t end;
|
||||
signed char *table;
|
||||
} UNICASERANGE;
|
||||
|
||||
extern signed char UniUpperTable[512];
|
||||
extern UNICASERANGE UniUpperRange[];
|
||||
extern int get_UCSname(struct component_name *, struct dentry *);
|
||||
extern int jfs_strfromUCS_le(char *, const __le16 *, int, struct nls_table *);
|
||||
|
||||
@ -107,12 +100,12 @@ static inline wchar_t *UniStrncpy_from_le(wchar_t * ucs1, const __le16 * ucs2,
|
||||
*/
|
||||
static inline wchar_t UniToupper(wchar_t uc)
|
||||
{
|
||||
UNICASERANGE *rp;
|
||||
const struct UniCaseRange *rp;
|
||||
|
||||
if (uc < sizeof(UniUpperTable)) { /* Latin characters */
|
||||
return uc + UniUpperTable[uc]; /* Use base tables */
|
||||
if (uc < sizeof(NlsUniUpperTable)) { /* Latin characters */
|
||||
return uc + NlsUniUpperTable[uc]; /* Use base tables */
|
||||
} else {
|
||||
rp = UniUpperRange; /* Use range tables */
|
||||
rp = NlsUniUpperRange; /* Use range tables */
|
||||
while (rp->start) {
|
||||
if (uc < rp->start) /* Before start of range */
|
||||
return uc; /* Uppercase = input */
|
||||
|
@ -1,121 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) International Business Machines Corp., 2000-2002
|
||||
*/
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include "jfs_unicode.h"
|
||||
|
||||
/*
|
||||
* Latin upper case
|
||||
*/
|
||||
signed char UniUpperTable[512] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 000-00f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 010-01f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 020-02f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 030-03f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 040-04f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 050-05f */
|
||||
0,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* 060-06f */
|
||||
-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, 0, 0, 0, 0, 0, /* 070-07f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 080-08f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 090-09f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0a0-0af */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0b0-0bf */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0c0-0cf */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0d0-0df */
|
||||
-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* 0e0-0ef */
|
||||
-32,-32,-32,-32,-32,-32,-32, 0,-32,-32,-32,-32,-32,-32,-32,121, /* 0f0-0ff */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 100-10f */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 110-11f */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 120-12f */
|
||||
0, 0, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, 0, /* 130-13f */
|
||||
-1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, /* 140-14f */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 150-15f */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 160-16f */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, 0, /* 170-17f */
|
||||
0, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, /* 180-18f */
|
||||
0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, /* 190-19f */
|
||||
0, -1, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, /* 1a0-1af */
|
||||
-1, 0, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, /* 1b0-1bf */
|
||||
0, 0, 0, 0, 0, -1, -2, 0, -1, -2, 0, -1, -2, 0, -1, 0, /* 1c0-1cf */
|
||||
-1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1,-79, 0, -1, /* 1d0-1df */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e0-1ef */
|
||||
0, 0, -1, -2, 0, -1, 0, 0, 0, -1, 0, -1, 0, -1, 0, -1, /* 1f0-1ff */
|
||||
};
|
||||
|
||||
/* Upper case range - Greek */
|
||||
static signed char UniCaseRangeU03a0[47] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-38,-37,-37,-37, /* 3a0-3af */
|
||||
0,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* 3b0-3bf */
|
||||
-32,-32,-31,-32,-32,-32,-32,-32,-32,-32,-32,-32,-64,-63,-63,
|
||||
};
|
||||
|
||||
/* Upper case range - Cyrillic */
|
||||
static signed char UniCaseRangeU0430[48] = {
|
||||
-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* 430-43f */
|
||||
-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* 440-44f */
|
||||
0,-80,-80,-80,-80,-80,-80,-80,-80,-80,-80,-80,-80, 0,-80,-80, /* 450-45f */
|
||||
};
|
||||
|
||||
/* Upper case range - Extended cyrillic */
|
||||
static signed char UniCaseRangeU0490[61] = {
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 490-49f */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 4a0-4af */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 4b0-4bf */
|
||||
0, 0, -1, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1,
|
||||
};
|
||||
|
||||
/* Upper case range - Extended latin and greek */
|
||||
static signed char UniCaseRangeU1e00[509] = {
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e00-1e0f */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e10-1e1f */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e20-1e2f */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e30-1e3f */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e40-1e4f */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e50-1e5f */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e60-1e6f */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e70-1e7f */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e80-1e8f */
|
||||
0, -1, 0, -1, 0, -1, 0, 0, 0, 0, 0,-59, 0, -1, 0, -1, /* 1e90-1e9f */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ea0-1eaf */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1eb0-1ebf */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ec0-1ecf */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ed0-1edf */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ee0-1eef */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, 0, 0, 0, 0, /* 1ef0-1eff */
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f00-1f0f */
|
||||
8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f10-1f1f */
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f20-1f2f */
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f30-1f3f */
|
||||
8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f40-1f4f */
|
||||
0, 8, 0, 8, 0, 8, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f50-1f5f */
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f60-1f6f */
|
||||
74, 74, 86, 86, 86, 86,100,100, 0, 0,112,112,126,126, 0, 0, /* 1f70-1f7f */
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f80-1f8f */
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f90-1f9f */
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fa0-1faf */
|
||||
8, 8, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fb0-1fbf */
|
||||
0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fc0-1fcf */
|
||||
8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fd0-1fdf */
|
||||
8, 8, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fe0-1fef */
|
||||
0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
/* Upper case range - Wide latin */
|
||||
static signed char UniCaseRangeUff40[27] = {
|
||||
0,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* ff40-ff4f */
|
||||
-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,
|
||||
};
|
||||
|
||||
/*
|
||||
* Upper Case Range
|
||||
*/
|
||||
UNICASERANGE UniUpperRange[] = {
|
||||
{ 0x03a0, 0x03ce, UniCaseRangeU03a0 },
|
||||
{ 0x0430, 0x045f, UniCaseRangeU0430 },
|
||||
{ 0x0490, 0x04cc, UniCaseRangeU0490 },
|
||||
{ 0x1e00, 0x1ffc, UniCaseRangeU1e00 },
|
||||
{ 0xff40, 0xff5a, UniCaseRangeUff40 },
|
||||
{ 0 }
|
||||
};
|
@ -617,4 +617,12 @@ config NLS_UTF8
|
||||
input/output character sets. Say Y here for the UTF-8 encoding of
|
||||
the Unicode/ISO9646 universal character set.
|
||||
|
||||
config NLS_UCS2_UTILS
|
||||
tristate "NLS UCS-2 UTILS"
|
||||
help
|
||||
Set of older UCS-2 conversion utilities and tables used by some
|
||||
filesystems including SMB/CIFS. This includes upper case conversion
|
||||
tables. This will automatically be selected when the filesystem
|
||||
that uses it is selected.
|
||||
|
||||
endif # NLS
|
||||
|
@ -54,3 +54,4 @@ obj-$(CONFIG_NLS_MAC_INUIT) += mac-inuit.o
|
||||
obj-$(CONFIG_NLS_MAC_ROMANIAN) += mac-romanian.o
|
||||
obj-$(CONFIG_NLS_MAC_ROMAN) += mac-roman.o
|
||||
obj-$(CONFIG_NLS_MAC_TURKISH) += mac-turkish.o
|
||||
obj-$(CONFIG_NLS_UCS2_UTILS) += nls_ucs2_utils.o
|
||||
|
15
fs/nls/nls_ucs2_data.h
Normal file
15
fs/nls/nls_ucs2_data.h
Normal file
@ -0,0 +1,15 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#ifndef _NLS_UCS2_DATA_H
|
||||
#define _NLS_UCS2_DATA_H
|
||||
|
||||
struct UniCaseRange {
|
||||
wchar_t start;
|
||||
wchar_t end;
|
||||
signed char *table;
|
||||
};
|
||||
|
||||
extern signed char NlsUniUpperTable[512];
|
||||
extern const struct UniCaseRange NlsUniUpperRange[];
|
||||
|
||||
#endif /* _NLS_UCS2_DATA_H */
|
@ -1,19 +1,27 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Some of the source code in this file came from fs/cifs/uniupr.h
|
||||
* Copyright (c) International Business Machines Corp., 2000,2002
|
||||
*
|
||||
* uniupr.h - Unicode compressed case ranges
|
||||
* Some of the source code in this file came from fs/cifs/cifs_unicode.c
|
||||
*
|
||||
* Copyright (c) International Business Machines Corp., 2000,2009
|
||||
* Modified by Steve French (sfrench@us.ibm.com)
|
||||
* Modified by Namjae Jeon (linkinjeon@kernel.org)
|
||||
*
|
||||
*/
|
||||
#ifndef __KSMBD_UNIUPR_H
|
||||
#define __KSMBD_UNIUPR_H
|
||||
#include <linux/fs.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include "nls_ucs2_utils.h"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#ifndef UNIUPR_NOUPPER
|
||||
/*
|
||||
* Latin upper case
|
||||
*/
|
||||
signed char SmbUniUpperTable[512] = {
|
||||
signed char NlsUniUpperTable[512] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 000-00f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 010-01f */
|
||||
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] = {
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e0-1ef */
|
||||
0, 0, -1, -2, 0, -1, 0, 0, 0, -1, 0, -1, 0, -1, 0, -1, /* 1f0-1ff */
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(NlsUniUpperTable);
|
||||
|
||||
/* Upper case range - Greek */
|
||||
static signed char UniCaseRangeU03a0[47] = {
|
||||
@ -126,7 +135,7 @@ static signed char UniCaseRangeUff40[27] = {
|
||||
/*
|
||||
* Upper Case Range
|
||||
*/
|
||||
const struct UniCaseRange SmbUniUpperRange[] = {
|
||||
const struct UniCaseRange NlsUniUpperRange[] = {
|
||||
{0x03a0, 0x03ce, UniCaseRangeU03a0},
|
||||
{0x0430, 0x045f, UniCaseRangeU0430},
|
||||
{0x0490, 0x04cc, UniCaseRangeU0490},
|
||||
@ -134,135 +143,4 @@ const struct UniCaseRange SmbUniUpperRange[] = {
|
||||
{0xff40, 0xff5a, UniCaseRangeUff40},
|
||||
{0}
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef UNIUPR_NOLOWER
|
||||
/*
|
||||
* Latin lower case
|
||||
*/
|
||||
signed char CifsUniLowerTable[512] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 000-00f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 010-01f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 020-02f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 030-03f */
|
||||
0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
|
||||
32, 32, 32, /* 040-04f */
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 0, 0,
|
||||
0, 0, 0, /* 050-05f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 060-06f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 070-07f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 080-08f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 090-09f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0a0-0af */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0b0-0bf */
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
|
||||
32, 32, 32, 32, /* 0c0-0cf */
|
||||
32, 32, 32, 32, 32, 32, 32, 0, 32, 32, 32, 32,
|
||||
32, 32, 32, 0, /* 0d0-0df */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0e0-0ef */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0f0-0ff */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 100-10f */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 110-11f */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 120-12f */
|
||||
0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, /* 130-13f */
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, /* 140-14f */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 150-15f */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 160-16f */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, -121, 1, 0, 1, 0, 1, 0,
|
||||
0, /* 170-17f */
|
||||
0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 79,
|
||||
0, /* 180-18f */
|
||||
0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, /* 190-19f */
|
||||
1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, /* 1a0-1af */
|
||||
0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, /* 1b0-1bf */
|
||||
0, 0, 0, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 1, 0, 1, /* 1c0-1cf */
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, /* 1d0-1df */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e0-1ef */
|
||||
0, 2, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1f0-1ff */
|
||||
};
|
||||
|
||||
/* Lower case range - Greek */
|
||||
static signed char UniCaseRangeL0380[44] = {
|
||||
0, 0, 0, 0, 0, 0, 38, 0, 37, 37, 37, 0, 64, 0, 63, 63, /* 380-38f */
|
||||
0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
|
||||
32, 32, 32, /* 390-39f */
|
||||
32, 32, 0, 32, 32, 32, 32, 32, 32, 32, 32, 32,
|
||||
};
|
||||
|
||||
/* Lower case range - Cyrillic */
|
||||
static signed char UniCaseRangeL0400[48] = {
|
||||
0, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
|
||||
0, 80, 80, /* 400-40f */
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
|
||||
32, 32, 32, /* 410-41f */
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
|
||||
32, 32, 32, /* 420-42f */
|
||||
};
|
||||
|
||||
/* Lower case range - Extended cyrillic */
|
||||
static signed char UniCaseRangeL0490[60] = {
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 490-49f */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 4a0-4af */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 4b0-4bf */
|
||||
0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1,
|
||||
};
|
||||
|
||||
/* Lower case range - Extended latin and greek */
|
||||
static signed char UniCaseRangeL1e00[504] = {
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e00-1e0f */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e10-1e1f */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e20-1e2f */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e30-1e3f */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e40-1e4f */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e50-1e5f */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e60-1e6f */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e70-1e7f */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e80-1e8f */
|
||||
1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 1e90-1e9f */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ea0-1eaf */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1eb0-1ebf */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ec0-1ecf */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ed0-1edf */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ee0-1eef */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, /* 1ef0-1eff */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f00-1f0f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, 0, 0, /* 1f10-1f1f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f20-1f2f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f30-1f3f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, 0, 0, /* 1f40-1f4f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, -8, 0, -8, 0, -8, 0, -8, /* 1f50-1f5f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f60-1f6f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f70-1f7f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f80-1f8f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f90-1f9f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1fa0-1faf */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -74, -74, -9, 0, 0, 0, /* 1fb0-1fbf */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, -86, -86, -86, -86, -9, 0,
|
||||
0, 0, /* 1fc0-1fcf */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -100, -100, 0, 0, 0, 0, /* 1fd0-1fdf */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -112, -112, -7, 0,
|
||||
0, 0, /* 1fe0-1fef */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
/* Lower case range - Wide latin */
|
||||
static signed char UniCaseRangeLff20[27] = {
|
||||
0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
|
||||
32, /* ff20-ff2f */
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
|
||||
};
|
||||
|
||||
/*
|
||||
* Lower Case Range
|
||||
*/
|
||||
const struct UniCaseRange CifsUniLowerRange[] = {
|
||||
{0x0380, 0x03ab, UniCaseRangeL0380},
|
||||
{0x0400, 0x042f, UniCaseRangeL0400},
|
||||
{0x0490, 0x04cb, UniCaseRangeL0490},
|
||||
{0x1e00, 0x1ff7, UniCaseRangeL1e00},
|
||||
{0xff20, 0xff3a, UniCaseRangeLff20},
|
||||
{0}
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* __KSMBD_UNIUPR_H */
|
||||
EXPORT_SYMBOL_GPL(NlsUniUpperRange);
|
285
fs/nls/nls_ucs2_utils.h
Normal file
285
fs/nls/nls_ucs2_utils.h
Normal file
@ -0,0 +1,285 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Some of the source code in this file came from fs/cifs/cifs_unicode.c
|
||||
* and then via server/unicode.c
|
||||
* cifs_unicode: Unicode kernel case support
|
||||
*
|
||||
* Function:
|
||||
* Convert a unicode character to upper or lower case using
|
||||
* compressed tables.
|
||||
*
|
||||
* Copyright (c) International Business Machines Corp., 2000,2009
|
||||
*
|
||||
*
|
||||
* Notes:
|
||||
* These APIs are based on the C library functions. The semantics
|
||||
* should match the C functions but with expanded size operands.
|
||||
*
|
||||
* The upper/lower functions are based on a table created by mkupr.
|
||||
* This is a compressed table of upper and lower case conversion.
|
||||
*
|
||||
*/
|
||||
#ifndef _NLS_UCS2_UTILS_H
|
||||
#define _NLS_UCS2_UTILS_H
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/nls.h>
|
||||
#include <linux/unicode.h>
|
||||
#include "nls_ucs2_data.h"
|
||||
|
||||
/*
|
||||
* Windows maps these to the user defined 16 bit Unicode range since they are
|
||||
* reserved symbols (along with \ and /), otherwise illegal to store
|
||||
* in filenames in NTFS
|
||||
*/
|
||||
#define UNI_ASTERISK ((__u16)('*' + 0xF000))
|
||||
#define UNI_QUESTION ((__u16)('?' + 0xF000))
|
||||
#define UNI_COLON ((__u16)(':' + 0xF000))
|
||||
#define UNI_GRTRTHAN ((__u16)('>' + 0xF000))
|
||||
#define UNI_LESSTHAN ((__u16)('<' + 0xF000))
|
||||
#define UNI_PIPE ((__u16)('|' + 0xF000))
|
||||
#define UNI_SLASH ((__u16)('\\' + 0xF000))
|
||||
|
||||
/*
|
||||
* UniStrcat: Concatenate the second string to the first
|
||||
*
|
||||
* Returns:
|
||||
* Address of the first string
|
||||
*/
|
||||
static inline wchar_t *UniStrcat(wchar_t *ucs1, const wchar_t *ucs2)
|
||||
{
|
||||
wchar_t *anchor = ucs1; /* save a pointer to start of ucs1 */
|
||||
|
||||
while (*ucs1++)
|
||||
/*NULL*/; /* To end of first string */
|
||||
ucs1--; /* Return to the null */
|
||||
while ((*ucs1++ = *ucs2++))
|
||||
/*NULL*/; /* copy string 2 over */
|
||||
return anchor;
|
||||
}
|
||||
|
||||
/*
|
||||
* UniStrchr: Find a character in a string
|
||||
*
|
||||
* Returns:
|
||||
* Address of first occurrence of character in string
|
||||
* or NULL if the character is not in the string
|
||||
*/
|
||||
static inline wchar_t *UniStrchr(const wchar_t *ucs, wchar_t uc)
|
||||
{
|
||||
while ((*ucs != uc) && *ucs)
|
||||
ucs++;
|
||||
|
||||
if (*ucs == uc)
|
||||
return (wchar_t *)ucs;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* UniStrcmp: Compare two strings
|
||||
*
|
||||
* Returns:
|
||||
* < 0: First string is less than second
|
||||
* = 0: Strings are equal
|
||||
* > 0: First string is greater than second
|
||||
*/
|
||||
static inline int UniStrcmp(const wchar_t *ucs1, const wchar_t *ucs2)
|
||||
{
|
||||
while ((*ucs1 == *ucs2) && *ucs1) {
|
||||
ucs1++;
|
||||
ucs2++;
|
||||
}
|
||||
return (int)*ucs1 - (int)*ucs2;
|
||||
}
|
||||
|
||||
/*
|
||||
* UniStrcpy: Copy a string
|
||||
*/
|
||||
static inline wchar_t *UniStrcpy(wchar_t *ucs1, const wchar_t *ucs2)
|
||||
{
|
||||
wchar_t *anchor = ucs1; /* save the start of result string */
|
||||
|
||||
while ((*ucs1++ = *ucs2++))
|
||||
/*NULL*/;
|
||||
return anchor;
|
||||
}
|
||||
|
||||
/*
|
||||
* UniStrlen: Return the length of a string (in 16 bit Unicode chars not bytes)
|
||||
*/
|
||||
static inline size_t UniStrlen(const wchar_t *ucs1)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (*ucs1++)
|
||||
i++;
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* UniStrnlen: Return the length (in 16 bit Unicode chars not bytes) of a
|
||||
* string (length limited)
|
||||
*/
|
||||
static inline size_t UniStrnlen(const wchar_t *ucs1, int maxlen)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (*ucs1++) {
|
||||
i++;
|
||||
if (i >= maxlen)
|
||||
break;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* UniStrncat: Concatenate length limited string
|
||||
*/
|
||||
static inline wchar_t *UniStrncat(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
|
||||
{
|
||||
wchar_t *anchor = ucs1; /* save pointer to string 1 */
|
||||
|
||||
while (*ucs1++)
|
||||
/*NULL*/;
|
||||
ucs1--; /* point to null terminator of s1 */
|
||||
while (n-- && (*ucs1 = *ucs2)) { /* copy s2 after s1 */
|
||||
ucs1++;
|
||||
ucs2++;
|
||||
}
|
||||
*ucs1 = 0; /* Null terminate the result */
|
||||
return anchor;
|
||||
}
|
||||
|
||||
/*
|
||||
* UniStrncmp: Compare length limited string
|
||||
*/
|
||||
static inline int UniStrncmp(const wchar_t *ucs1, const wchar_t *ucs2, size_t n)
|
||||
{
|
||||
if (!n)
|
||||
return 0; /* Null strings are equal */
|
||||
while ((*ucs1 == *ucs2) && *ucs1 && --n) {
|
||||
ucs1++;
|
||||
ucs2++;
|
||||
}
|
||||
return (int)*ucs1 - (int)*ucs2;
|
||||
}
|
||||
|
||||
/*
|
||||
* UniStrncmp_le: Compare length limited string - native to little-endian
|
||||
*/
|
||||
static inline int
|
||||
UniStrncmp_le(const wchar_t *ucs1, const wchar_t *ucs2, size_t n)
|
||||
{
|
||||
if (!n)
|
||||
return 0; /* Null strings are equal */
|
||||
while ((*ucs1 == __le16_to_cpu(*ucs2)) && *ucs1 && --n) {
|
||||
ucs1++;
|
||||
ucs2++;
|
||||
}
|
||||
return (int)*ucs1 - (int)__le16_to_cpu(*ucs2);
|
||||
}
|
||||
|
||||
/*
|
||||
* UniStrncpy: Copy length limited string with pad
|
||||
*/
|
||||
static inline wchar_t *UniStrncpy(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
|
||||
{
|
||||
wchar_t *anchor = ucs1;
|
||||
|
||||
while (n-- && *ucs2) /* Copy the strings */
|
||||
*ucs1++ = *ucs2++;
|
||||
|
||||
n++;
|
||||
while (n--) /* Pad with nulls */
|
||||
*ucs1++ = 0;
|
||||
return anchor;
|
||||
}
|
||||
|
||||
/*
|
||||
* UniStrncpy_le: Copy length limited string with pad to little-endian
|
||||
*/
|
||||
static inline wchar_t *UniStrncpy_le(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
|
||||
{
|
||||
wchar_t *anchor = ucs1;
|
||||
|
||||
while (n-- && *ucs2) /* Copy the strings */
|
||||
*ucs1++ = __le16_to_cpu(*ucs2++);
|
||||
|
||||
n++;
|
||||
while (n--) /* Pad with nulls */
|
||||
*ucs1++ = 0;
|
||||
return anchor;
|
||||
}
|
||||
|
||||
/*
|
||||
* UniStrstr: Find a string in a string
|
||||
*
|
||||
* Returns:
|
||||
* Address of first match found
|
||||
* NULL if no matching string is found
|
||||
*/
|
||||
static inline wchar_t *UniStrstr(const wchar_t *ucs1, const wchar_t *ucs2)
|
||||
{
|
||||
const wchar_t *anchor1 = ucs1;
|
||||
const wchar_t *anchor2 = ucs2;
|
||||
|
||||
while (*ucs1) {
|
||||
if (*ucs1 == *ucs2) {
|
||||
/* Partial match found */
|
||||
ucs1++;
|
||||
ucs2++;
|
||||
} else {
|
||||
if (!*ucs2) /* Match found */
|
||||
return (wchar_t *)anchor1;
|
||||
ucs1 = ++anchor1; /* No match */
|
||||
ucs2 = anchor2;
|
||||
}
|
||||
}
|
||||
|
||||
if (!*ucs2) /* Both end together */
|
||||
return (wchar_t *)anchor1; /* Match found */
|
||||
return NULL; /* No match */
|
||||
}
|
||||
|
||||
#ifndef UNIUPR_NOUPPER
|
||||
/*
|
||||
* UniToupper: Convert a unicode character to upper case
|
||||
*/
|
||||
static inline wchar_t UniToupper(register wchar_t uc)
|
||||
{
|
||||
register const struct UniCaseRange *rp;
|
||||
|
||||
if (uc < sizeof(NlsUniUpperTable)) {
|
||||
/* Latin characters */
|
||||
return uc + NlsUniUpperTable[uc]; /* Use base tables */
|
||||
}
|
||||
|
||||
rp = NlsUniUpperRange; /* Use range tables */
|
||||
while (rp->start) {
|
||||
if (uc < rp->start) /* Before start of range */
|
||||
return uc; /* Uppercase = input */
|
||||
if (uc <= rp->end) /* In range */
|
||||
return uc + rp->table[uc - rp->start];
|
||||
rp++; /* Try next range */
|
||||
}
|
||||
return uc; /* Past last range */
|
||||
}
|
||||
|
||||
/*
|
||||
* UniStrupr: Upper case a unicode string
|
||||
*/
|
||||
static inline __le16 *UniStrupr(register __le16 *upin)
|
||||
{
|
||||
register __le16 *up;
|
||||
|
||||
up = upin;
|
||||
while (*up) { /* For all characters */
|
||||
*up = cpu_to_le16(UniToupper(le16_to_cpu(*up)));
|
||||
up++;
|
||||
}
|
||||
return upin; /* Return input pointer */
|
||||
}
|
||||
#endif /* UNIUPR_NOUPPER */
|
||||
|
||||
#endif /* _NLS_UCS2_UTILS_H */
|
@ -3,6 +3,7 @@ config CIFS
|
||||
tristate "SMB3 and CIFS support (advanced network filesystem)"
|
||||
depends on INET
|
||||
select NLS
|
||||
select NLS_UCS2_UTILS
|
||||
select CRYPTO
|
||||
select CRYPTO_MD5
|
||||
select CRYPTO_SHA256
|
||||
|
@ -11,7 +11,8 @@ cifs-y := trace.o cifsfs.o cifs_debug.o connect.o dir.o file.o \
|
||||
readdir.o ioctl.o sess.o export.o unc.o winucase.o \
|
||||
smb2ops.o smb2maperror.o smb2transport.o \
|
||||
smb2misc.o smb2pdu.o smb2inode.o smb2file.o cifsacl.o fs_context.o \
|
||||
dns_resolve.o cifs_spnego_negtokeninit.asn1.o asn1.o
|
||||
dns_resolve.o cifs_spnego_negtokeninit.asn1.o asn1.o \
|
||||
namespace.o
|
||||
|
||||
$(obj)/asn1.o: $(obj)/cifs_spnego_negtokeninit.asn1.h
|
||||
|
||||
@ -21,7 +22,7 @@ cifs-$(CONFIG_CIFS_XATTR) += xattr.o
|
||||
|
||||
cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o
|
||||
|
||||
cifs-$(CONFIG_CIFS_DFS_UPCALL) += cifs_dfs_ref.o dfs_cache.o dfs.o
|
||||
cifs-$(CONFIG_CIFS_DFS_UPCALL) += dfs_cache.o dfs.o
|
||||
|
||||
cifs-$(CONFIG_CIFS_SWN_UPCALL) += netlink.o cifs_swn.o
|
||||
|
||||
|
@ -218,7 +218,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
|
||||
.tcon = tcon,
|
||||
.path = path,
|
||||
.create_options = cifs_create_options(cifs_sb, CREATE_NOT_FILE),
|
||||
.desired_access = FILE_READ_ATTRIBUTES,
|
||||
.desired_access = FILE_READ_DATA | FILE_READ_ATTRIBUTES,
|
||||
.disposition = FILE_OPEN,
|
||||
.fid = pfid,
|
||||
};
|
||||
|
@ -331,7 +331,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
|
||||
spin_lock(&cifs_tcp_ses_lock);
|
||||
list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
|
||||
/* channel info will be printed as a part of sessions below */
|
||||
if (CIFS_SERVER_IS_CHAN(server))
|
||||
if (SERVER_IS_CHAN(server))
|
||||
continue;
|
||||
|
||||
c++;
|
||||
|
@ -8,7 +8,6 @@
|
||||
#include <linux/slab.h>
|
||||
#include "cifs_fs_sb.h"
|
||||
#include "cifs_unicode.h"
|
||||
#include "cifs_uniupr.h"
|
||||
#include "cifspdu.h"
|
||||
#include "cifsglob.h"
|
||||
#include "cifs_debug.h"
|
||||
|
@ -21,21 +21,7 @@
|
||||
#include <asm/byteorder.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/nls.h>
|
||||
|
||||
#define UNIUPR_NOLOWER /* Example to not expand lower case tables */
|
||||
|
||||
/*
|
||||
* Windows maps these to the user defined 16 bit Unicode range since they are
|
||||
* reserved symbols (along with \ and /), otherwise illegal to store
|
||||
* in filenames in NTFS
|
||||
*/
|
||||
#define UNI_ASTERISK (__u16) ('*' + 0xF000)
|
||||
#define UNI_QUESTION (__u16) ('?' + 0xF000)
|
||||
#define UNI_COLON (__u16) (':' + 0xF000)
|
||||
#define UNI_GRTRTHAN (__u16) ('>' + 0xF000)
|
||||
#define UNI_LESSTHAN (__u16) ('<' + 0xF000)
|
||||
#define UNI_PIPE (__u16) ('|' + 0xF000)
|
||||
#define UNI_SLASH (__u16) ('\\' + 0xF000)
|
||||
#include "../../nls/nls_ucs2_utils.h"
|
||||
|
||||
/*
|
||||
* Macs use an older "SFM" mapping of the symbols above. Fortunately it does
|
||||
@ -68,27 +54,6 @@
|
||||
#define SFM_MAP_UNI_RSVD 1
|
||||
#define SFU_MAP_UNI_RSVD 2
|
||||
|
||||
/* Just define what we want from uniupr.h. We don't want to define the tables
|
||||
* in each source file.
|
||||
*/
|
||||
#ifndef UNICASERANGE_DEFINED
|
||||
struct UniCaseRange {
|
||||
wchar_t start;
|
||||
wchar_t end;
|
||||
signed char *table;
|
||||
};
|
||||
#endif /* UNICASERANGE_DEFINED */
|
||||
|
||||
#ifndef UNIUPR_NOUPPER
|
||||
extern signed char CifsUniUpperTable[512];
|
||||
extern const struct UniCaseRange CifsUniUpperRange[];
|
||||
#endif /* UNIUPR_NOUPPER */
|
||||
|
||||
#ifndef UNIUPR_NOLOWER
|
||||
extern signed char CifsUniLowerTable[512];
|
||||
extern const struct UniCaseRange CifsUniLowerRange[];
|
||||
#endif /* UNIUPR_NOLOWER */
|
||||
|
||||
#ifdef __KERNEL__
|
||||
int cifs_from_utf16(char *to, const __le16 *from, int tolen, int fromlen,
|
||||
const struct nls_table *cp, int map_type);
|
||||
@ -108,297 +73,4 @@ extern __le16 *cifs_strndup_to_utf16(const char *src, const int maxlen,
|
||||
|
||||
wchar_t cifs_toupper(wchar_t in);
|
||||
|
||||
/*
|
||||
* UniStrcat: Concatenate the second string to the first
|
||||
*
|
||||
* Returns:
|
||||
* Address of the first string
|
||||
*/
|
||||
static inline __le16 *
|
||||
UniStrcat(__le16 *ucs1, const __le16 *ucs2)
|
||||
{
|
||||
__le16 *anchor = ucs1; /* save a pointer to start of ucs1 */
|
||||
|
||||
while (*ucs1++) ; /* To end of first string */
|
||||
ucs1--; /* Return to the null */
|
||||
while ((*ucs1++ = *ucs2++)) ; /* copy string 2 over */
|
||||
return anchor;
|
||||
}
|
||||
|
||||
/*
|
||||
* UniStrchr: Find a character in a string
|
||||
*
|
||||
* Returns:
|
||||
* Address of first occurrence of character in string
|
||||
* or NULL if the character is not in the string
|
||||
*/
|
||||
static inline wchar_t *
|
||||
UniStrchr(const wchar_t *ucs, wchar_t uc)
|
||||
{
|
||||
while ((*ucs != uc) && *ucs)
|
||||
ucs++;
|
||||
|
||||
if (*ucs == uc)
|
||||
return (wchar_t *) ucs;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* UniStrcmp: Compare two strings
|
||||
*
|
||||
* Returns:
|
||||
* < 0: First string is less than second
|
||||
* = 0: Strings are equal
|
||||
* > 0: First string is greater than second
|
||||
*/
|
||||
static inline int
|
||||
UniStrcmp(const wchar_t *ucs1, const wchar_t *ucs2)
|
||||
{
|
||||
while ((*ucs1 == *ucs2) && *ucs1) {
|
||||
ucs1++;
|
||||
ucs2++;
|
||||
}
|
||||
return (int) *ucs1 - (int) *ucs2;
|
||||
}
|
||||
|
||||
/*
|
||||
* UniStrcpy: Copy a string
|
||||
*/
|
||||
static inline wchar_t *
|
||||
UniStrcpy(wchar_t *ucs1, const wchar_t *ucs2)
|
||||
{
|
||||
wchar_t *anchor = ucs1; /* save the start of result string */
|
||||
|
||||
while ((*ucs1++ = *ucs2++)) ;
|
||||
return anchor;
|
||||
}
|
||||
|
||||
/*
|
||||
* UniStrlen: Return the length of a string (in 16 bit Unicode chars not bytes)
|
||||
*/
|
||||
static inline size_t
|
||||
UniStrlen(const wchar_t *ucs1)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (*ucs1++)
|
||||
i++;
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* UniStrnlen: Return the length (in 16 bit Unicode chars not bytes) of a
|
||||
* string (length limited)
|
||||
*/
|
||||
static inline size_t
|
||||
UniStrnlen(const wchar_t *ucs1, int maxlen)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (*ucs1++) {
|
||||
i++;
|
||||
if (i >= maxlen)
|
||||
break;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* UniStrncat: Concatenate length limited string
|
||||
*/
|
||||
static inline wchar_t *
|
||||
UniStrncat(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
|
||||
{
|
||||
wchar_t *anchor = ucs1; /* save pointer to string 1 */
|
||||
|
||||
while (*ucs1++) ;
|
||||
ucs1--; /* point to null terminator of s1 */
|
||||
while (n-- && (*ucs1 = *ucs2)) { /* copy s2 after s1 */
|
||||
ucs1++;
|
||||
ucs2++;
|
||||
}
|
||||
*ucs1 = 0; /* Null terminate the result */
|
||||
return (anchor);
|
||||
}
|
||||
|
||||
/*
|
||||
* UniStrncmp: Compare length limited string
|
||||
*/
|
||||
static inline int
|
||||
UniStrncmp(const wchar_t *ucs1, const wchar_t *ucs2, size_t n)
|
||||
{
|
||||
if (!n)
|
||||
return 0; /* Null strings are equal */
|
||||
while ((*ucs1 == *ucs2) && *ucs1 && --n) {
|
||||
ucs1++;
|
||||
ucs2++;
|
||||
}
|
||||
return (int) *ucs1 - (int) *ucs2;
|
||||
}
|
||||
|
||||
/*
|
||||
* UniStrncmp_le: Compare length limited string - native to little-endian
|
||||
*/
|
||||
static inline int
|
||||
UniStrncmp_le(const wchar_t *ucs1, const wchar_t *ucs2, size_t n)
|
||||
{
|
||||
if (!n)
|
||||
return 0; /* Null strings are equal */
|
||||
while ((*ucs1 == __le16_to_cpu(*ucs2)) && *ucs1 && --n) {
|
||||
ucs1++;
|
||||
ucs2++;
|
||||
}
|
||||
return (int) *ucs1 - (int) __le16_to_cpu(*ucs2);
|
||||
}
|
||||
|
||||
/*
|
||||
* UniStrncpy: Copy length limited string with pad
|
||||
*/
|
||||
static inline wchar_t *
|
||||
UniStrncpy(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
|
||||
{
|
||||
wchar_t *anchor = ucs1;
|
||||
|
||||
while (n-- && *ucs2) /* Copy the strings */
|
||||
*ucs1++ = *ucs2++;
|
||||
|
||||
n++;
|
||||
while (n--) /* Pad with nulls */
|
||||
*ucs1++ = 0;
|
||||
return anchor;
|
||||
}
|
||||
|
||||
/*
|
||||
* UniStrncpy_le: Copy length limited string with pad to little-endian
|
||||
*/
|
||||
static inline wchar_t *
|
||||
UniStrncpy_le(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
|
||||
{
|
||||
wchar_t *anchor = ucs1;
|
||||
|
||||
while (n-- && *ucs2) /* Copy the strings */
|
||||
*ucs1++ = __le16_to_cpu(*ucs2++);
|
||||
|
||||
n++;
|
||||
while (n--) /* Pad with nulls */
|
||||
*ucs1++ = 0;
|
||||
return anchor;
|
||||
}
|
||||
|
||||
/*
|
||||
* UniStrstr: Find a string in a string
|
||||
*
|
||||
* Returns:
|
||||
* Address of first match found
|
||||
* NULL if no matching string is found
|
||||
*/
|
||||
static inline wchar_t *
|
||||
UniStrstr(const wchar_t *ucs1, const wchar_t *ucs2)
|
||||
{
|
||||
const wchar_t *anchor1 = ucs1;
|
||||
const wchar_t *anchor2 = ucs2;
|
||||
|
||||
while (*ucs1) {
|
||||
if (*ucs1 == *ucs2) {
|
||||
/* Partial match found */
|
||||
ucs1++;
|
||||
ucs2++;
|
||||
} else {
|
||||
if (!*ucs2) /* Match found */
|
||||
return (wchar_t *) anchor1;
|
||||
ucs1 = ++anchor1; /* No match */
|
||||
ucs2 = anchor2;
|
||||
}
|
||||
}
|
||||
|
||||
if (!*ucs2) /* Both end together */
|
||||
return (wchar_t *) anchor1; /* Match found */
|
||||
return NULL; /* No match */
|
||||
}
|
||||
|
||||
#ifndef UNIUPR_NOUPPER
|
||||
/*
|
||||
* UniToupper: Convert a unicode character to upper case
|
||||
*/
|
||||
static inline wchar_t
|
||||
UniToupper(register wchar_t uc)
|
||||
{
|
||||
register const struct UniCaseRange *rp;
|
||||
|
||||
if (uc < sizeof(CifsUniUpperTable)) {
|
||||
/* Latin characters */
|
||||
return uc + CifsUniUpperTable[uc]; /* Use base tables */
|
||||
} else {
|
||||
rp = CifsUniUpperRange; /* Use range tables */
|
||||
while (rp->start) {
|
||||
if (uc < rp->start) /* Before start of range */
|
||||
return uc; /* Uppercase = input */
|
||||
if (uc <= rp->end) /* In range */
|
||||
return uc + rp->table[uc - rp->start];
|
||||
rp++; /* Try next range */
|
||||
}
|
||||
}
|
||||
return uc; /* Past last range */
|
||||
}
|
||||
|
||||
/*
|
||||
* UniStrupr: Upper case a unicode string
|
||||
*/
|
||||
static inline __le16 *
|
||||
UniStrupr(register __le16 *upin)
|
||||
{
|
||||
register __le16 *up;
|
||||
|
||||
up = upin;
|
||||
while (*up) { /* For all characters */
|
||||
*up = cpu_to_le16(UniToupper(le16_to_cpu(*up)));
|
||||
up++;
|
||||
}
|
||||
return upin; /* Return input pointer */
|
||||
}
|
||||
#endif /* UNIUPR_NOUPPER */
|
||||
|
||||
#ifndef UNIUPR_NOLOWER
|
||||
/*
|
||||
* UniTolower: Convert a unicode character to lower case
|
||||
*/
|
||||
static inline wchar_t
|
||||
UniTolower(register wchar_t uc)
|
||||
{
|
||||
register const struct UniCaseRange *rp;
|
||||
|
||||
if (uc < sizeof(CifsUniLowerTable)) {
|
||||
/* Latin characters */
|
||||
return uc + CifsUniLowerTable[uc]; /* Use base tables */
|
||||
} else {
|
||||
rp = CifsUniLowerRange; /* Use range tables */
|
||||
while (rp->start) {
|
||||
if (uc < rp->start) /* Before start of range */
|
||||
return uc; /* Uppercase = input */
|
||||
if (uc <= rp->end) /* In range */
|
||||
return uc + rp->table[uc - rp->start];
|
||||
rp++; /* Try next range */
|
||||
}
|
||||
}
|
||||
return uc; /* Past last range */
|
||||
}
|
||||
|
||||
/*
|
||||
* UniStrlwr: Lower case a unicode string
|
||||
*/
|
||||
static inline wchar_t *
|
||||
UniStrlwr(register wchar_t *upin)
|
||||
{
|
||||
register wchar_t *up;
|
||||
|
||||
up = upin;
|
||||
while (*up) { /* For all characters */
|
||||
*up = UniTolower(*up);
|
||||
up++;
|
||||
}
|
||||
return upin; /* Return input pointer */
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _CIFS_UNICODE_H */
|
||||
|
@ -1,239 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (c) International Business Machines Corp., 2000,2002
|
||||
*
|
||||
* uniupr.h - Unicode compressed case ranges
|
||||
*/
|
||||
|
||||
#ifndef UNIUPR_NOUPPER
|
||||
/*
|
||||
* Latin upper case
|
||||
*/
|
||||
signed char CifsUniUpperTable[512] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 000-00f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 010-01f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 020-02f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 030-03f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 040-04f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 050-05f */
|
||||
0, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 060-06f */
|
||||
-32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, 0, 0, 0, 0, 0, /* 070-07f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 080-08f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 090-09f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0a0-0af */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0b0-0bf */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0c0-0cf */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0d0-0df */
|
||||
-32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 0e0-0ef */
|
||||
-32, -32, -32, -32, -32, -32, -32, 0, -32, -32, -32, -32, -32, -32, -32, 121, /* 0f0-0ff */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 100-10f */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 110-11f */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 120-12f */
|
||||
0, 0, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, 0, /* 130-13f */
|
||||
-1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, /* 140-14f */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 150-15f */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 160-16f */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, 0, /* 170-17f */
|
||||
0, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, /* 180-18f */
|
||||
0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, /* 190-19f */
|
||||
0, -1, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, /* 1a0-1af */
|
||||
-1, 0, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, /* 1b0-1bf */
|
||||
0, 0, 0, 0, 0, -1, -2, 0, -1, -2, 0, -1, -2, 0, -1, 0, /* 1c0-1cf */
|
||||
-1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, -79, 0, -1, /* 1d0-1df */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e0-1ef */
|
||||
0, 0, -1, -2, 0, -1, 0, 0, 0, -1, 0, -1, 0, -1, 0, -1, /* 1f0-1ff */
|
||||
};
|
||||
|
||||
/* Upper case range - Greek */
|
||||
static signed char UniCaseRangeU03a0[47] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -38, -37, -37, -37, /* 3a0-3af */
|
||||
0, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 3b0-3bf */
|
||||
-32, -32, -31, -32, -32, -32, -32, -32, -32, -32, -32, -32, -64,
|
||||
-63, -63,
|
||||
};
|
||||
|
||||
/* Upper case range - Cyrillic */
|
||||
static signed char UniCaseRangeU0430[48] = {
|
||||
-32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 430-43f */
|
||||
-32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 440-44f */
|
||||
0, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, 0, -80, -80, /* 450-45f */
|
||||
};
|
||||
|
||||
/* Upper case range - Extended cyrillic */
|
||||
static signed char UniCaseRangeU0490[61] = {
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 490-49f */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 4a0-4af */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 4b0-4bf */
|
||||
0, 0, -1, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1,
|
||||
};
|
||||
|
||||
/* Upper case range - Extended latin and greek */
|
||||
static signed char UniCaseRangeU1e00[509] = {
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e00-1e0f */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e10-1e1f */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e20-1e2f */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e30-1e3f */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e40-1e4f */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e50-1e5f */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e60-1e6f */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e70-1e7f */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e80-1e8f */
|
||||
0, -1, 0, -1, 0, -1, 0, 0, 0, 0, 0, -59, 0, -1, 0, -1, /* 1e90-1e9f */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ea0-1eaf */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1eb0-1ebf */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ec0-1ecf */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ed0-1edf */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ee0-1eef */
|
||||
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, 0, 0, 0, 0, /* 1ef0-1eff */
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f00-1f0f */
|
||||
8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f10-1f1f */
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f20-1f2f */
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f30-1f3f */
|
||||
8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f40-1f4f */
|
||||
0, 8, 0, 8, 0, 8, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f50-1f5f */
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f60-1f6f */
|
||||
74, 74, 86, 86, 86, 86, 100, 100, 0, 0, 112, 112, 126, 126, 0, 0, /* 1f70-1f7f */
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f80-1f8f */
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f90-1f9f */
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fa0-1faf */
|
||||
8, 8, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fb0-1fbf */
|
||||
0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fc0-1fcf */
|
||||
8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fd0-1fdf */
|
||||
8, 8, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fe0-1fef */
|
||||
0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
/* Upper case range - Wide latin */
|
||||
static signed char UniCaseRangeUff40[27] = {
|
||||
0, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* ff40-ff4f */
|
||||
-32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32,
|
||||
};
|
||||
|
||||
/*
|
||||
* Upper Case Range
|
||||
*/
|
||||
const struct UniCaseRange CifsUniUpperRange[] = {
|
||||
{0x03a0, 0x03ce, UniCaseRangeU03a0},
|
||||
{0x0430, 0x045f, UniCaseRangeU0430},
|
||||
{0x0490, 0x04cc, UniCaseRangeU0490},
|
||||
{0x1e00, 0x1ffc, UniCaseRangeU1e00},
|
||||
{0xff40, 0xff5a, UniCaseRangeUff40},
|
||||
{0}
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef UNIUPR_NOLOWER
|
||||
/*
|
||||
* Latin lower case
|
||||
*/
|
||||
signed char CifsUniLowerTable[512] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 000-00f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 010-01f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 020-02f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 030-03f */
|
||||
0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 040-04f */
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 0, 0, 0, 0, 0, /* 050-05f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 060-06f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 070-07f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 080-08f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 090-09f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0a0-0af */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0b0-0bf */
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 0c0-0cf */
|
||||
32, 32, 32, 32, 32, 32, 32, 0, 32, 32, 32, 32, 32, 32, 32, 0, /* 0d0-0df */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0e0-0ef */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0f0-0ff */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 100-10f */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 110-11f */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 120-12f */
|
||||
0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, /* 130-13f */
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, /* 140-14f */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 150-15f */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 160-16f */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, -121, 1, 0, 1, 0, 1, 0, 0, /* 170-17f */
|
||||
0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 79, 0, /* 180-18f */
|
||||
0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, /* 190-19f */
|
||||
1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, /* 1a0-1af */
|
||||
0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, /* 1b0-1bf */
|
||||
0, 0, 0, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 1, 0, 1, /* 1c0-1cf */
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, /* 1d0-1df */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e0-1ef */
|
||||
0, 2, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1f0-1ff */
|
||||
};
|
||||
|
||||
/* Lower case range - Greek */
|
||||
static signed char UniCaseRangeL0380[44] = {
|
||||
0, 0, 0, 0, 0, 0, 38, 0, 37, 37, 37, 0, 64, 0, 63, 63, /* 380-38f */
|
||||
0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 390-39f */
|
||||
32, 32, 0, 32, 32, 32, 32, 32, 32, 32, 32, 32,
|
||||
};
|
||||
|
||||
/* Lower case range - Cyrillic */
|
||||
static signed char UniCaseRangeL0400[48] = {
|
||||
0, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 0, 80, 80, /* 400-40f */
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 410-41f */
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 420-42f */
|
||||
};
|
||||
|
||||
/* Lower case range - Extended cyrillic */
|
||||
static signed char UniCaseRangeL0490[60] = {
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 490-49f */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 4a0-4af */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 4b0-4bf */
|
||||
0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1,
|
||||
};
|
||||
|
||||
/* Lower case range - Extended latin and greek */
|
||||
static signed char UniCaseRangeL1e00[504] = {
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e00-1e0f */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e10-1e1f */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e20-1e2f */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e30-1e3f */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e40-1e4f */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e50-1e5f */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e60-1e6f */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e70-1e7f */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e80-1e8f */
|
||||
1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 1e90-1e9f */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ea0-1eaf */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1eb0-1ebf */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ec0-1ecf */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ed0-1edf */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ee0-1eef */
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, /* 1ef0-1eff */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f00-1f0f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, 0, 0, /* 1f10-1f1f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f20-1f2f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f30-1f3f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, 0, 0, /* 1f40-1f4f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, -8, 0, -8, 0, -8, 0, -8, /* 1f50-1f5f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f60-1f6f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f70-1f7f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f80-1f8f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f90-1f9f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1fa0-1faf */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -74, -74, -9, 0, 0, 0, /* 1fb0-1fbf */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, -86, -86, -86, -86, -9, 0, 0, 0, /* 1fc0-1fcf */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -100, -100, 0, 0, 0, 0, /* 1fd0-1fdf */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -112, -112, -7, 0, 0, 0, /* 1fe0-1fef */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
/* Lower case range - Wide latin */
|
||||
static signed char UniCaseRangeLff20[27] = {
|
||||
0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* ff20-ff2f */
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
|
||||
};
|
||||
|
||||
/*
|
||||
* Lower Case Range
|
||||
*/
|
||||
const struct UniCaseRange CifsUniLowerRange[] = {
|
||||
{0x0380, 0x03ab, UniCaseRangeL0380},
|
||||
{0x0400, 0x042f, UniCaseRangeL0400},
|
||||
{0x0490, 0x04cb, UniCaseRangeL0490},
|
||||
{0x1e00, 0x1ff7, UniCaseRangeL1e00},
|
||||
{0xff20, 0xff3a, UniCaseRangeLff20},
|
||||
{0}
|
||||
};
|
||||
#endif
|
@ -1805,7 +1805,7 @@ exit_cifs(void)
|
||||
cifs_dbg(NOISY, "exit_smb3\n");
|
||||
unregister_filesystem(&cifs_fs_type);
|
||||
unregister_filesystem(&smb3_fs_type);
|
||||
cifs_dfs_release_automount_timer();
|
||||
cifs_release_automount_timer();
|
||||
exit_cifs_idmap();
|
||||
#ifdef CONFIG_CIFS_SWN_UPCALL
|
||||
cifs_genl_exit();
|
||||
|
@ -81,7 +81,7 @@ extern int cifs_fiemap(struct inode *, struct fiemap_extent_info *, u64 start,
|
||||
|
||||
extern const struct inode_operations cifs_file_inode_ops;
|
||||
extern const struct inode_operations cifs_symlink_inode_ops;
|
||||
extern const struct inode_operations cifs_dfs_referral_inode_operations;
|
||||
extern const struct inode_operations cifs_namespace_inode_operations;
|
||||
|
||||
|
||||
/* Functions related to files and directories */
|
||||
@ -118,14 +118,7 @@ extern void cifs_pages_write_redirty(struct inode *inode, loff_t start, unsigned
|
||||
extern const struct dentry_operations cifs_dentry_ops;
|
||||
extern const struct dentry_operations cifs_ci_dentry_ops;
|
||||
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
extern struct vfsmount *cifs_dfs_d_automount(struct path *path);
|
||||
#else
|
||||
static inline struct vfsmount *cifs_dfs_d_automount(struct path *path)
|
||||
{
|
||||
return ERR_PTR(-EREMOTE);
|
||||
}
|
||||
#endif
|
||||
extern struct vfsmount *cifs_d_automount(struct path *path);
|
||||
|
||||
/* Functions related to symlinks */
|
||||
extern const char *cifs_get_link(struct dentry *, struct inode *,
|
||||
|
@ -186,6 +186,12 @@ struct cifs_cred {
|
||||
};
|
||||
|
||||
struct cifs_open_info_data {
|
||||
bool adjust_tz;
|
||||
union {
|
||||
bool reparse_point;
|
||||
bool symlink;
|
||||
};
|
||||
__u32 reparse_tag;
|
||||
char *symlink_target;
|
||||
union {
|
||||
struct smb2_file_all_info fi;
|
||||
@ -193,6 +199,10 @@ struct cifs_open_info_data {
|
||||
};
|
||||
};
|
||||
|
||||
#define cifs_open_data_reparse(d) \
|
||||
((d)->reparse_point || \
|
||||
(le32_to_cpu((d)->fi.Attributes) & ATTR_REPARSE))
|
||||
|
||||
static inline void cifs_free_open_info(struct cifs_open_info_data *data)
|
||||
{
|
||||
kfree(data->symlink_target);
|
||||
@ -318,16 +328,21 @@ struct smb_version_operations {
|
||||
int (*is_path_accessible)(const unsigned int, struct cifs_tcon *,
|
||||
struct cifs_sb_info *, const char *);
|
||||
/* query path data from the server */
|
||||
int (*query_path_info)(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb, const char *full_path,
|
||||
struct cifs_open_info_data *data, bool *adjust_tz, bool *reparse);
|
||||
int (*query_path_info)(const unsigned int xid,
|
||||
struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb,
|
||||
const char *full_path,
|
||||
struct cifs_open_info_data *data);
|
||||
/* query file data from the server */
|
||||
int (*query_file_info)(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifsFileInfo *cfile, struct cifs_open_info_data *data);
|
||||
/* query reparse tag from srv to determine which type of special file */
|
||||
int (*query_reparse_tag)(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb, const char *path,
|
||||
__u32 *reparse_tag);
|
||||
/* query reparse point to determine which type of special file */
|
||||
int (*query_reparse_point)(const unsigned int xid,
|
||||
struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb,
|
||||
const char *full_path,
|
||||
u32 *tag, struct kvec *rsp,
|
||||
int *rsp_buftype);
|
||||
/* get server index number */
|
||||
int (*get_srv_inum)(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb, const char *full_path, u64 *uniqueid,
|
||||
@ -376,9 +391,12 @@ struct smb_version_operations {
|
||||
const char *, const char *,
|
||||
struct cifs_sb_info *);
|
||||
/* query symlink target */
|
||||
int (*query_symlink)(const unsigned int, struct cifs_tcon *,
|
||||
struct cifs_sb_info *, const char *,
|
||||
char **, bool);
|
||||
int (*query_symlink)(const unsigned int xid,
|
||||
struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb,
|
||||
const char *full_path,
|
||||
char **target_path,
|
||||
struct kvec *rsp_iov);
|
||||
/* open a file for non-posix mounts */
|
||||
int (*open)(const unsigned int xid, struct cifs_open_parms *oparms, __u32 *oplock,
|
||||
void *buf);
|
||||
@ -727,8 +745,9 @@ struct TCP_Server_Info {
|
||||
* primary_server holds the ref-counted
|
||||
* pointer to primary channel connection for the session.
|
||||
*/
|
||||
#define CIFS_SERVER_IS_CHAN(server) (!!(server)->primary_server)
|
||||
#define SERVER_IS_CHAN(server) (!!(server)->primary_server)
|
||||
struct TCP_Server_Info *primary_server;
|
||||
__u16 channel_sequence_num; /* incremented on primary channel on each chan reconnect */
|
||||
|
||||
#ifdef CONFIG_CIFS_SWN_UPCALL
|
||||
bool use_swn_dstaddr;
|
||||
@ -1076,7 +1095,7 @@ cap_unix(struct cifs_ses *ses)
|
||||
* inode with new info
|
||||
*/
|
||||
|
||||
#define CIFS_FATTR_DFS_REFERRAL 0x1
|
||||
#define CIFS_FATTR_JUNCTION 0x1
|
||||
#define CIFS_FATTR_DELETE_PENDING 0x2
|
||||
#define CIFS_FATTR_NEED_REVAL 0x4
|
||||
#define CIFS_FATTR_INO_COLLISION 0x8
|
||||
@ -1721,11 +1740,23 @@ struct cifs_mount_ctx {
|
||||
struct list_head dfs_ses_list;
|
||||
};
|
||||
|
||||
static inline void __free_dfs_info_param(struct dfs_info3_param *param)
|
||||
{
|
||||
kfree(param->path_name);
|
||||
kfree(param->node_name);
|
||||
}
|
||||
|
||||
static inline void free_dfs_info_param(struct dfs_info3_param *param)
|
||||
{
|
||||
if (param)
|
||||
__free_dfs_info_param(param);
|
||||
}
|
||||
|
||||
static inline void zfree_dfs_info_param(struct dfs_info3_param *param)
|
||||
{
|
||||
if (param) {
|
||||
kfree(param->path_name);
|
||||
kfree(param->node_name);
|
||||
__free_dfs_info_param(param);
|
||||
memset(param, 0, sizeof(*param));
|
||||
}
|
||||
}
|
||||
|
||||
@ -2184,4 +2215,17 @@ static inline void cifs_sg_set_buf(struct sg_table *sgtable,
|
||||
}
|
||||
}
|
||||
|
||||
struct smb2_compound_vars {
|
||||
struct cifs_open_parms oparms;
|
||||
struct kvec rsp_iov[3];
|
||||
struct smb_rqst rqst[3];
|
||||
struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
|
||||
struct kvec qi_iov;
|
||||
struct kvec io_iov[SMB2_IOCTL_IOV_SIZE];
|
||||
struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE];
|
||||
struct kvec close_iov;
|
||||
struct smb2_file_rename_info rename_info;
|
||||
struct smb2_file_link_info link_info;
|
||||
};
|
||||
|
||||
#endif /* _CIFS_GLOB_H */
|
||||
|
@ -207,6 +207,9 @@ extern struct inode *cifs_iget(struct super_block *sb,
|
||||
int cifs_get_inode_info(struct inode **inode, const char *full_path,
|
||||
struct cifs_open_info_data *data, struct super_block *sb, int xid,
|
||||
const struct cifs_fid *fid);
|
||||
bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb,
|
||||
struct cifs_fattr *fattr,
|
||||
u32 tag);
|
||||
extern int smb311_posix_get_inode_info(struct inode **pinode, const char *search_path,
|
||||
struct super_block *sb, unsigned int xid);
|
||||
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,
|
||||
int from_reconnect);
|
||||
extern void cifs_put_tcon(struct cifs_tcon *tcon);
|
||||
|
||||
#if IS_ENABLED(CONFIG_CIFS_DFS_UPCALL)
|
||||
extern void cifs_dfs_release_automount_timer(void);
|
||||
#else /* ! IS_ENABLED(CONFIG_CIFS_DFS_UPCALL) */
|
||||
#define cifs_dfs_release_automount_timer() do { } while (0)
|
||||
#endif /* ! IS_ENABLED(CONFIG_CIFS_DFS_UPCALL) */
|
||||
extern void cifs_release_automount_timer(void);
|
||||
|
||||
void cifs_proc_init(void);
|
||||
void cifs_proc_clean(void);
|
||||
|
@ -154,7 +154,7 @@ cifs_signal_cifsd_for_reconnect(struct TCP_Server_Info *server,
|
||||
int i;
|
||||
|
||||
/* If server is a channel, select the primary channel */
|
||||
pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
|
||||
pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
|
||||
|
||||
spin_lock(&pserver->srv_lock);
|
||||
if (!all_channels) {
|
||||
@ -202,7 +202,7 @@ cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server,
|
||||
cifs_dbg(FYI, "%s: marking necessary sessions and tcons for reconnect\n", __func__);
|
||||
|
||||
/* If server is a channel, select the primary channel */
|
||||
pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
|
||||
pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
|
||||
|
||||
|
||||
spin_lock(&cifs_tcp_ses_lock);
|
||||
@ -453,10 +453,10 @@ static int reconnect_target_unlocked(struct TCP_Server_Info *server, struct dfs_
|
||||
|
||||
static int reconnect_dfs_server(struct TCP_Server_Info *server)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dfs_cache_tgt_list tl = DFS_CACHE_TGT_LIST_INIT(tl);
|
||||
struct dfs_cache_tgt_iterator *target_hint = NULL;
|
||||
DFS_CACHE_TGT_LIST(tl);
|
||||
int num_targets = 0;
|
||||
int rc = 0;
|
||||
|
||||
/*
|
||||
* 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)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void clean_demultiplex_info(struct TCP_Server_Info *server)
|
||||
static noinline_for_stack void
|
||||
clean_demultiplex_info(struct TCP_Server_Info *server)
|
||||
{
|
||||
int length;
|
||||
|
||||
@ -1551,7 +1551,7 @@ cifs_find_tcp_session(struct smb3_fs_context *ctx)
|
||||
* Skip ses channels since they're only handled in lower layers
|
||||
* (e.g. cifs_send_recv).
|
||||
*/
|
||||
if (CIFS_SERVER_IS_CHAN(server) ||
|
||||
if (SERVER_IS_CHAN(server) ||
|
||||
!match_server(server, ctx, false)) {
|
||||
spin_unlock(&server->srv_lock);
|
||||
continue;
|
||||
@ -1587,7 +1587,7 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
|
||||
spin_unlock(&cifs_tcp_ses_lock);
|
||||
|
||||
/* For secondary channels, we pick up ref-count on the primary server */
|
||||
if (CIFS_SERVER_IS_CHAN(server))
|
||||
if (SERVER_IS_CHAN(server))
|
||||
cifs_put_tcp_session(server->primary_server, from_reconnect);
|
||||
|
||||
cancel_delayed_work_sync(&server->echo);
|
||||
@ -1686,6 +1686,7 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx,
|
||||
ctx->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
|
||||
tcp_ses->session_estab = false;
|
||||
tcp_ses->sequence_number = 0;
|
||||
tcp_ses->channel_sequence_num = 0; /* only tracked for primary channel */
|
||||
tcp_ses->reconnect_instance = 1;
|
||||
tcp_ses->lstrp = jiffies;
|
||||
tcp_ses->compress_algorithm = cpu_to_le16(ctx->compression);
|
||||
@ -1792,7 +1793,7 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx,
|
||||
|
||||
out_err:
|
||||
if (tcp_ses) {
|
||||
if (CIFS_SERVER_IS_CHAN(tcp_ses))
|
||||
if (SERVER_IS_CHAN(tcp_ses))
|
||||
cifs_put_tcp_session(tcp_ses->primary_server, false);
|
||||
kfree(tcp_ses->hostname);
|
||||
kfree(tcp_ses->leaf_fullpath);
|
||||
@ -3813,7 +3814,7 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
|
||||
struct nls_table *nls_info)
|
||||
{
|
||||
int rc = -ENOSYS;
|
||||
struct TCP_Server_Info *pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
|
||||
struct TCP_Server_Info *pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
|
||||
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&pserver->dstaddr;
|
||||
struct sockaddr_in *addr = (struct sockaddr_in *)&pserver->dstaddr;
|
||||
bool is_binding = false;
|
||||
|
@ -3,7 +3,6 @@
|
||||
* Copyright (c) 2022 Paulo Alcantara <palcantara@suse.de>
|
||||
*/
|
||||
|
||||
#include <linux/namei.h>
|
||||
#include "cifsproto.h"
|
||||
#include "cifs_debug.h"
|
||||
#include "dns_resolve.h"
|
||||
@ -96,51 +95,134 @@ static int add_root_smb_session(struct cifs_mount_ctx *mnt_ctx)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_dfs_conn(struct cifs_mount_ctx *mnt_ctx, const char *ref_path, const char *full_path,
|
||||
const struct dfs_cache_tgt_iterator *tit)
|
||||
static inline int parse_dfs_target(struct smb3_fs_context *ctx,
|
||||
struct dfs_ref_walk *rw,
|
||||
struct dfs_info3_param *tgt)
|
||||
{
|
||||
int rc;
|
||||
const char *fpath = ref_walk_fpath(rw) + 1;
|
||||
|
||||
rc = ref_walk_get_tgt(rw, tgt);
|
||||
if (!rc)
|
||||
rc = dfs_parse_target_referral(fpath, tgt, ctx);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int set_ref_paths(struct cifs_mount_ctx *mnt_ctx,
|
||||
struct dfs_info3_param *tgt,
|
||||
struct dfs_ref_walk *rw)
|
||||
{
|
||||
struct smb3_fs_context *ctx = mnt_ctx->fs_ctx;
|
||||
struct dfs_info3_param ref = {};
|
||||
bool is_refsrv;
|
||||
int rc, rc2;
|
||||
struct cifs_sb_info *cifs_sb = mnt_ctx->cifs_sb;
|
||||
char *ref_path, *full_path;
|
||||
int rc;
|
||||
|
||||
rc = dfs_cache_get_tgt_referral(ref_path + 1, tit, &ref);
|
||||
if (rc)
|
||||
full_path = smb3_fs_context_fullpath(ctx, CIFS_DIR_SEP(cifs_sb));
|
||||
if (IS_ERR(full_path))
|
||||
return PTR_ERR(full_path);
|
||||
|
||||
if (!tgt || (tgt->server_type == DFS_TYPE_LINK &&
|
||||
DFS_INTERLINK(tgt->flags)))
|
||||
ref_path = dfs_get_path(cifs_sb, ctx->UNC);
|
||||
else
|
||||
ref_path = dfs_get_path(cifs_sb, full_path);
|
||||
if (IS_ERR(ref_path)) {
|
||||
rc = PTR_ERR(ref_path);
|
||||
kfree(full_path);
|
||||
return rc;
|
||||
|
||||
rc = dfs_parse_target_referral(full_path + 1, &ref, ctx);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
cifs_mount_put_conns(mnt_ctx);
|
||||
rc = get_session(mnt_ctx, ref_path);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
is_refsrv = !!(ref.flags & DFSREF_REFERRAL_SERVER);
|
||||
|
||||
rc = -EREMOTE;
|
||||
if (ref.flags & DFSREF_STORAGE_SERVER) {
|
||||
rc = cifs_mount_get_tcon(mnt_ctx);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
/* some servers may not advertise referral capability under ref.flags */
|
||||
is_refsrv |= is_tcon_dfs(mnt_ctx->tcon);
|
||||
|
||||
rc = cifs_is_path_remote(mnt_ctx);
|
||||
}
|
||||
ref_walk_path(rw) = ref_path;
|
||||
ref_walk_fpath(rw) = full_path;
|
||||
return 0;
|
||||
}
|
||||
|
||||
dfs_cache_noreq_update_tgthint(ref_path + 1, tit);
|
||||
static int __dfs_referral_walk(struct cifs_mount_ctx *mnt_ctx,
|
||||
struct dfs_ref_walk *rw)
|
||||
{
|
||||
struct smb3_fs_context *ctx = mnt_ctx->fs_ctx;
|
||||
struct dfs_info3_param tgt = {};
|
||||
bool is_refsrv;
|
||||
int rc = -ENOENT;
|
||||
|
||||
if (rc == -EREMOTE && is_refsrv) {
|
||||
rc2 = add_root_smb_session(mnt_ctx);
|
||||
if (rc2)
|
||||
rc = rc2;
|
||||
}
|
||||
again:
|
||||
do {
|
||||
if (ref_walk_empty(rw)) {
|
||||
rc = dfs_get_referral(mnt_ctx, ref_walk_path(rw) + 1,
|
||||
NULL, ref_walk_tl(rw));
|
||||
if (rc) {
|
||||
rc = cifs_mount_get_tcon(mnt_ctx);
|
||||
if (!rc)
|
||||
rc = cifs_is_path_remote(mnt_ctx);
|
||||
continue;
|
||||
}
|
||||
if (!ref_walk_num_tgts(rw)) {
|
||||
rc = -ENOENT;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
while (ref_walk_next_tgt(rw)) {
|
||||
rc = parse_dfs_target(ctx, rw, &tgt);
|
||||
if (rc)
|
||||
continue;
|
||||
|
||||
cifs_mount_put_conns(mnt_ctx);
|
||||
rc = get_session(mnt_ctx, ref_walk_path(rw));
|
||||
if (rc)
|
||||
continue;
|
||||
|
||||
is_refsrv = tgt.server_type == DFS_TYPE_ROOT ||
|
||||
DFS_INTERLINK(tgt.flags);
|
||||
ref_walk_set_tgt_hint(rw);
|
||||
|
||||
if (tgt.flags & DFSREF_STORAGE_SERVER) {
|
||||
rc = cifs_mount_get_tcon(mnt_ctx);
|
||||
if (!rc)
|
||||
rc = cifs_is_path_remote(mnt_ctx);
|
||||
if (!rc)
|
||||
break;
|
||||
if (rc != -EREMOTE)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_refsrv) {
|
||||
rc = add_root_smb_session(mnt_ctx);
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = ref_walk_advance(rw);
|
||||
if (!rc) {
|
||||
rc = set_ref_paths(mnt_ctx, &tgt, rw);
|
||||
if (!rc) {
|
||||
rc = -EREMOTE;
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
if (rc != -ELOOP)
|
||||
goto out;
|
||||
}
|
||||
} while (rc && ref_walk_descend(rw));
|
||||
|
||||
out:
|
||||
free_dfs_info_param(&ref);
|
||||
free_dfs_info_param(&tgt);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int dfs_referral_walk(struct cifs_mount_ctx *mnt_ctx)
|
||||
{
|
||||
struct dfs_ref_walk *rw;
|
||||
int rc;
|
||||
|
||||
rw = ref_walk_alloc();
|
||||
if (IS_ERR(rw))
|
||||
return PTR_ERR(rw);
|
||||
|
||||
ref_walk_init(rw);
|
||||
rc = set_ref_paths(mnt_ctx, NULL, rw);
|
||||
if (!rc)
|
||||
rc = __dfs_referral_walk(mnt_ctx, rw);
|
||||
ref_walk_free(rw);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -148,105 +230,48 @@ static int __dfs_mount_share(struct cifs_mount_ctx *mnt_ctx)
|
||||
{
|
||||
struct cifs_sb_info *cifs_sb = mnt_ctx->cifs_sb;
|
||||
struct smb3_fs_context *ctx = mnt_ctx->fs_ctx;
|
||||
char *ref_path = NULL, *full_path = NULL;
|
||||
struct dfs_cache_tgt_iterator *tit;
|
||||
struct cifs_tcon *tcon;
|
||||
char *origin_fullpath = NULL;
|
||||
char sep = CIFS_DIR_SEP(cifs_sb);
|
||||
int num_links = 0;
|
||||
char *origin_fullpath;
|
||||
int rc;
|
||||
|
||||
ref_path = dfs_get_path(cifs_sb, ctx->UNC);
|
||||
if (IS_ERR(ref_path))
|
||||
return PTR_ERR(ref_path);
|
||||
origin_fullpath = dfs_get_path(cifs_sb, ctx->source);
|
||||
if (IS_ERR(origin_fullpath))
|
||||
return PTR_ERR(origin_fullpath);
|
||||
|
||||
full_path = smb3_fs_context_fullpath(ctx, sep);
|
||||
if (IS_ERR(full_path)) {
|
||||
rc = PTR_ERR(full_path);
|
||||
full_path = NULL;
|
||||
rc = dfs_referral_walk(mnt_ctx);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
tcon = mnt_ctx->tcon;
|
||||
spin_lock(&tcon->tc_lock);
|
||||
if (!tcon->origin_fullpath) {
|
||||
tcon->origin_fullpath = origin_fullpath;
|
||||
origin_fullpath = NULL;
|
||||
}
|
||||
spin_unlock(&tcon->tc_lock);
|
||||
|
||||
origin_fullpath = kstrdup(full_path, GFP_KERNEL);
|
||||
if (!origin_fullpath) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
do {
|
||||
struct dfs_cache_tgt_list tl = DFS_CACHE_TGT_LIST_INIT(tl);
|
||||
|
||||
rc = dfs_get_referral(mnt_ctx, ref_path + 1, NULL, &tl);
|
||||
if (rc) {
|
||||
rc = cifs_mount_get_tcon(mnt_ctx);
|
||||
if (!rc)
|
||||
rc = cifs_is_path_remote(mnt_ctx);
|
||||
break;
|
||||
}
|
||||
|
||||
tit = dfs_cache_get_tgt_iterator(&tl);
|
||||
if (!tit) {
|
||||
cifs_dbg(VFS, "%s: dfs referral (%s) with no targets\n", __func__,
|
||||
ref_path + 1);
|
||||
rc = -ENOENT;
|
||||
dfs_cache_free_tgts(&tl);
|
||||
break;
|
||||
}
|
||||
|
||||
do {
|
||||
rc = get_dfs_conn(mnt_ctx, ref_path, full_path, tit);
|
||||
if (!rc)
|
||||
break;
|
||||
if (rc == -EREMOTE) {
|
||||
if (++num_links > MAX_NESTED_LINKS) {
|
||||
rc = -ELOOP;
|
||||
break;
|
||||
}
|
||||
kfree(ref_path);
|
||||
kfree(full_path);
|
||||
ref_path = full_path = NULL;
|
||||
|
||||
full_path = smb3_fs_context_fullpath(ctx, sep);
|
||||
if (IS_ERR(full_path)) {
|
||||
rc = PTR_ERR(full_path);
|
||||
full_path = NULL;
|
||||
} else {
|
||||
ref_path = dfs_get_path(cifs_sb, full_path);
|
||||
if (IS_ERR(ref_path)) {
|
||||
rc = PTR_ERR(ref_path);
|
||||
ref_path = NULL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
} while ((tit = dfs_cache_get_next_tgt(&tl, tit)));
|
||||
dfs_cache_free_tgts(&tl);
|
||||
} while (rc == -EREMOTE);
|
||||
|
||||
if (!rc) {
|
||||
tcon = mnt_ctx->tcon;
|
||||
|
||||
spin_lock(&tcon->tc_lock);
|
||||
if (!tcon->origin_fullpath) {
|
||||
tcon->origin_fullpath = origin_fullpath;
|
||||
origin_fullpath = NULL;
|
||||
}
|
||||
spin_unlock(&tcon->tc_lock);
|
||||
|
||||
if (list_empty(&tcon->dfs_ses_list)) {
|
||||
list_replace_init(&mnt_ctx->dfs_ses_list,
|
||||
&tcon->dfs_ses_list);
|
||||
queue_delayed_work(dfscache_wq, &tcon->dfs_cache_work,
|
||||
dfs_cache_get_ttl() * HZ);
|
||||
} else {
|
||||
dfs_put_root_smb_sessions(&mnt_ctx->dfs_ses_list);
|
||||
}
|
||||
if (list_empty(&tcon->dfs_ses_list)) {
|
||||
list_replace_init(&mnt_ctx->dfs_ses_list, &tcon->dfs_ses_list);
|
||||
queue_delayed_work(dfscache_wq, &tcon->dfs_cache_work,
|
||||
dfs_cache_get_ttl() * HZ);
|
||||
} else {
|
||||
dfs_put_root_smb_sessions(&mnt_ctx->dfs_ses_list);
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(origin_fullpath);
|
||||
kfree(ref_path);
|
||||
kfree(full_path);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Resolve UNC hostname in @ctx->source and set ip addr in @ctx->dstaddr */
|
||||
static int update_fs_context_dstaddr(struct smb3_fs_context *ctx)
|
||||
{
|
||||
struct sockaddr *addr = (struct sockaddr *)&ctx->dstaddr;
|
||||
int rc;
|
||||
|
||||
rc = dns_resolve_server_name_to_ip(ctx->source, addr, NULL);
|
||||
if (!rc)
|
||||
cifs_set_port(addr, ctx->port);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -256,6 +281,10 @@ int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx, bool *isdfs)
|
||||
bool nodfs = ctx->nodfs;
|
||||
int rc;
|
||||
|
||||
rc = update_fs_context_dstaddr(ctx);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
*isdfs = false;
|
||||
rc = get_session(mnt_ctx, NULL);
|
||||
if (rc)
|
||||
@ -426,7 +455,7 @@ static int __tree_connect_dfs_target(const unsigned int xid, struct cifs_tcon *t
|
||||
/* Try to tree connect to all dfs targets */
|
||||
for (; tit; tit = dfs_cache_get_next_tgt(tl, tit)) {
|
||||
const char *target = dfs_cache_get_tgt_name(tit);
|
||||
struct dfs_cache_tgt_list ntl = DFS_CACHE_TGT_LIST_INIT(ntl);
|
||||
DFS_CACHE_TGT_LIST(ntl);
|
||||
|
||||
kfree(share);
|
||||
kfree(prefix);
|
||||
@ -520,7 +549,7 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const stru
|
||||
int rc;
|
||||
struct TCP_Server_Info *server = tcon->ses->server;
|
||||
const struct smb_version_operations *ops = server->ops;
|
||||
struct dfs_cache_tgt_list tl = DFS_CACHE_TGT_LIST_INIT(tl);
|
||||
DFS_CACHE_TGT_LIST(tl);
|
||||
struct cifs_sb_info *cifs_sb = NULL;
|
||||
struct super_block *sb = NULL;
|
||||
struct dfs_info3_param ref = {0};
|
||||
|
@ -9,6 +9,110 @@
|
||||
#include "cifsglob.h"
|
||||
#include "fs_context.h"
|
||||
#include "cifs_unicode.h"
|
||||
#include <linux/namei.h>
|
||||
|
||||
#define DFS_INTERLINK(v) \
|
||||
(((v) & DFSREF_REFERRAL_SERVER) && !((v) & DFSREF_STORAGE_SERVER))
|
||||
|
||||
struct dfs_ref {
|
||||
char *path;
|
||||
char *full_path;
|
||||
struct dfs_cache_tgt_list tl;
|
||||
struct dfs_cache_tgt_iterator *tit;
|
||||
};
|
||||
|
||||
struct dfs_ref_walk {
|
||||
struct dfs_ref *ref;
|
||||
struct dfs_ref refs[MAX_NESTED_LINKS];
|
||||
};
|
||||
|
||||
#define ref_walk_start(w) ((w)->refs)
|
||||
#define ref_walk_end(w) (&(w)->refs[ARRAY_SIZE((w)->refs) - 1])
|
||||
#define ref_walk_cur(w) ((w)->ref)
|
||||
#define ref_walk_descend(w) (--ref_walk_cur(w) >= ref_walk_start(w))
|
||||
|
||||
#define ref_walk_tit(w) (ref_walk_cur(w)->tit)
|
||||
#define ref_walk_empty(w) (!ref_walk_tit(w))
|
||||
#define ref_walk_path(w) (ref_walk_cur(w)->path)
|
||||
#define ref_walk_fpath(w) (ref_walk_cur(w)->full_path)
|
||||
#define ref_walk_tl(w) (&ref_walk_cur(w)->tl)
|
||||
|
||||
static inline struct dfs_ref_walk *ref_walk_alloc(void)
|
||||
{
|
||||
struct dfs_ref_walk *rw;
|
||||
|
||||
rw = kmalloc(sizeof(*rw), GFP_KERNEL);
|
||||
if (!rw)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
return rw;
|
||||
}
|
||||
|
||||
static inline void ref_walk_init(struct dfs_ref_walk *rw)
|
||||
{
|
||||
memset(rw, 0, sizeof(*rw));
|
||||
ref_walk_cur(rw) = ref_walk_start(rw);
|
||||
}
|
||||
|
||||
static inline void __ref_walk_free(struct dfs_ref *ref)
|
||||
{
|
||||
kfree(ref->path);
|
||||
kfree(ref->full_path);
|
||||
dfs_cache_free_tgts(&ref->tl);
|
||||
memset(ref, 0, sizeof(*ref));
|
||||
}
|
||||
|
||||
static inline void ref_walk_free(struct dfs_ref_walk *rw)
|
||||
{
|
||||
struct dfs_ref *ref = ref_walk_start(rw);
|
||||
|
||||
for (; ref <= ref_walk_end(rw); ref++)
|
||||
__ref_walk_free(ref);
|
||||
kfree(rw);
|
||||
}
|
||||
|
||||
static inline int ref_walk_advance(struct dfs_ref_walk *rw)
|
||||
{
|
||||
struct dfs_ref *ref = ref_walk_cur(rw) + 1;
|
||||
|
||||
if (ref > ref_walk_end(rw))
|
||||
return -ELOOP;
|
||||
__ref_walk_free(ref);
|
||||
ref_walk_cur(rw) = ref;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct dfs_cache_tgt_iterator *
|
||||
ref_walk_next_tgt(struct dfs_ref_walk *rw)
|
||||
{
|
||||
struct dfs_cache_tgt_iterator *tit;
|
||||
struct dfs_ref *ref = ref_walk_cur(rw);
|
||||
|
||||
if (!ref->tit)
|
||||
tit = dfs_cache_get_tgt_iterator(&ref->tl);
|
||||
else
|
||||
tit = dfs_cache_get_next_tgt(&ref->tl, ref->tit);
|
||||
ref->tit = tit;
|
||||
return tit;
|
||||
}
|
||||
|
||||
static inline int ref_walk_get_tgt(struct dfs_ref_walk *rw,
|
||||
struct dfs_info3_param *tgt)
|
||||
{
|
||||
zfree_dfs_info_param(tgt);
|
||||
return dfs_cache_get_tgt_referral(ref_walk_path(rw) + 1,
|
||||
ref_walk_tit(rw), tgt);
|
||||
}
|
||||
|
||||
static inline int ref_walk_num_tgts(struct dfs_ref_walk *rw)
|
||||
{
|
||||
return dfs_cache_get_nr_tgts(ref_walk_tl(rw));
|
||||
}
|
||||
|
||||
static inline void ref_walk_set_tgt_hint(struct dfs_ref_walk *rw)
|
||||
{
|
||||
dfs_cache_noreq_update_tgthint(ref_walk_path(rw) + 1,
|
||||
ref_walk_tit(rw));
|
||||
}
|
||||
|
||||
struct dfs_root_ses {
|
||||
struct list_head list;
|
||||
@ -34,43 +138,6 @@ static inline int dfs_get_referral(struct cifs_mount_ctx *mnt_ctx, const char *p
|
||||
cifs_remap(cifs_sb), path, ref, tl);
|
||||
}
|
||||
|
||||
/* Return DFS full path out of a dentry set for automount */
|
||||
static inline char *dfs_get_automount_devname(struct dentry *dentry, void *page)
|
||||
{
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb);
|
||||
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
|
||||
size_t len;
|
||||
char *s;
|
||||
|
||||
spin_lock(&tcon->tc_lock);
|
||||
if (unlikely(!tcon->origin_fullpath)) {
|
||||
spin_unlock(&tcon->tc_lock);
|
||||
return ERR_PTR(-EREMOTE);
|
||||
}
|
||||
spin_unlock(&tcon->tc_lock);
|
||||
|
||||
s = dentry_path_raw(dentry, page, PATH_MAX);
|
||||
if (IS_ERR(s))
|
||||
return s;
|
||||
/* for root, we want "" */
|
||||
if (!s[1])
|
||||
s++;
|
||||
|
||||
spin_lock(&tcon->tc_lock);
|
||||
len = strlen(tcon->origin_fullpath);
|
||||
if (s < (char *)page + len) {
|
||||
spin_unlock(&tcon->tc_lock);
|
||||
return ERR_PTR(-ENAMETOOLONG);
|
||||
}
|
||||
|
||||
s -= len;
|
||||
memcpy(s, tcon->origin_fullpath, len);
|
||||
spin_unlock(&tcon->tc_lock);
|
||||
convert_delimiter(s, '/');
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static inline void dfs_put_root_smb_sessions(struct list_head *head)
|
||||
{
|
||||
struct dfs_root_ses *root, *tmp;
|
||||
|
@ -29,8 +29,6 @@
|
||||
#define CACHE_MIN_TTL 120 /* 2 minutes */
|
||||
#define CACHE_DEFAULT_TTL 300 /* 5 minutes */
|
||||
|
||||
#define IS_DFS_INTERLINK(v) (((v) & DFSREF_REFERRAL_SERVER) && !((v) & DFSREF_STORAGE_SERVER))
|
||||
|
||||
struct cache_dfs_tgt {
|
||||
char *name;
|
||||
int path_consumed;
|
||||
@ -174,7 +172,7 @@ static int dfscache_proc_show(struct seq_file *m, void *v)
|
||||
"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",
|
||||
ce->path, ce->srvtype == DFS_TYPE_ROOT ? "root" : "link",
|
||||
ce->ttl, ce->etime.tv_nsec, ce->hdr_flags, ce->ref_flags,
|
||||
IS_DFS_INTERLINK(ce->hdr_flags) ? "yes" : "no",
|
||||
DFS_INTERLINK(ce->hdr_flags) ? "yes" : "no",
|
||||
ce->path_consumed, cache_entry_expired(ce) ? "yes" : "no");
|
||||
|
||||
list_for_each_entry(t, &ce->tlist, list) {
|
||||
@ -243,7 +241,7 @@ static inline void dump_ce(const struct cache_entry *ce)
|
||||
ce->srvtype == DFS_TYPE_ROOT ? "root" : "link", ce->ttl,
|
||||
ce->etime.tv_nsec,
|
||||
ce->hdr_flags, ce->ref_flags,
|
||||
IS_DFS_INTERLINK(ce->hdr_flags) ? "yes" : "no",
|
||||
DFS_INTERLINK(ce->hdr_flags) ? "yes" : "no",
|
||||
ce->path_consumed,
|
||||
cache_entry_expired(ce) ? "yes" : "no");
|
||||
dump_tgts(ce);
|
||||
@ -1177,9 +1175,9 @@ static bool is_ses_good(struct cifs_ses *ses)
|
||||
/* Refresh dfs referral of tcon and mark it for reconnect if needed */
|
||||
static int __refresh_tcon(const char *path, struct cifs_ses *ses, bool force_refresh)
|
||||
{
|
||||
struct dfs_cache_tgt_list old_tl = DFS_CACHE_TGT_LIST_INIT(old_tl);
|
||||
struct dfs_cache_tgt_list new_tl = DFS_CACHE_TGT_LIST_INIT(new_tl);
|
||||
struct TCP_Server_Info *server = ses->server;
|
||||
DFS_CACHE_TGT_LIST(old_tl);
|
||||
DFS_CACHE_TGT_LIST(new_tl);
|
||||
bool needs_refresh = false;
|
||||
struct cache_entry *ce;
|
||||
unsigned int xid;
|
||||
|
@ -16,7 +16,11 @@
|
||||
extern struct workqueue_struct *dfscache_wq;
|
||||
extern atomic_t dfs_cache_ttl;
|
||||
|
||||
#define DFS_CACHE_TGT_LIST_INIT(var) { .tl_numtgts = 0, .tl_list = LIST_HEAD_INIT((var).tl_list), }
|
||||
#define DFS_CACHE_TGT_LIST_INIT(var) \
|
||||
{ .tl_numtgts = 0, .tl_list = LIST_HEAD_INIT((var).tl_list), }
|
||||
|
||||
#define DFS_CACHE_TGT_LIST(var) \
|
||||
struct dfs_cache_tgt_list var = DFS_CACHE_TGT_LIST_INIT(var)
|
||||
|
||||
struct dfs_cache_tgt_list {
|
||||
int tl_numtgts;
|
||||
@ -51,8 +55,8 @@ static inline struct dfs_cache_tgt_iterator *
|
||||
dfs_cache_get_next_tgt(struct dfs_cache_tgt_list *tl,
|
||||
struct dfs_cache_tgt_iterator *it)
|
||||
{
|
||||
if (!tl || list_empty(&tl->tl_list) || !it ||
|
||||
list_is_last(&it->it_list, &tl->tl_list))
|
||||
if (!tl || !tl->tl_numtgts || list_empty(&tl->tl_list) ||
|
||||
!it || list_is_last(&it->it_list, &tl->tl_list))
|
||||
return NULL;
|
||||
return list_next_entry(it, it_list);
|
||||
}
|
||||
@ -71,7 +75,7 @@ static inline void dfs_cache_free_tgts(struct dfs_cache_tgt_list *tl)
|
||||
{
|
||||
struct dfs_cache_tgt_iterator *it, *nit;
|
||||
|
||||
if (!tl || list_empty(&tl->tl_list))
|
||||
if (!tl || !tl->tl_numtgts || list_empty(&tl->tl_list))
|
||||
return;
|
||||
list_for_each_entry_safe(it, nit, &tl->tl_list, it_list) {
|
||||
list_del(&it->it_list);
|
||||
|
@ -797,7 +797,7 @@ cifs_d_revalidate(struct dentry *direntry, unsigned int flags)
|
||||
|
||||
const struct dentry_operations cifs_dentry_ops = {
|
||||
.d_revalidate = cifs_d_revalidate,
|
||||
.d_automount = cifs_dfs_d_automount,
|
||||
.d_automount = cifs_d_automount,
|
||||
/* d_delete: cifs_d_delete, */ /* not needed except for debugging */
|
||||
};
|
||||
|
||||
@ -872,5 +872,5 @@ const struct dentry_operations cifs_ci_dentry_ops = {
|
||||
.d_revalidate = cifs_d_revalidate,
|
||||
.d_hash = cifs_ci_hash,
|
||||
.d_compare = cifs_ci_compare,
|
||||
.d_automount = cifs_dfs_d_automount,
|
||||
.d_automount = cifs_d_automount,
|
||||
};
|
||||
|
@ -58,13 +58,9 @@ static void cifs_set_ops(struct inode *inode)
|
||||
inode->i_data.a_ops = &cifs_addr_ops;
|
||||
break;
|
||||
case S_IFDIR:
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
if (IS_AUTOMOUNT(inode)) {
|
||||
inode->i_op = &cifs_dfs_referral_inode_operations;
|
||||
inode->i_op = &cifs_namespace_inode_operations;
|
||||
} else {
|
||||
#else /* NO DFS support, treat as a directory */
|
||||
{
|
||||
#endif
|
||||
inode->i_op = &cifs_dir_inode_ops;
|
||||
inode->i_fop = &cifs_dir_ops;
|
||||
}
|
||||
@ -218,7 +214,7 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
|
||||
}
|
||||
spin_unlock(&inode->i_lock);
|
||||
|
||||
if (fattr->cf_flags & CIFS_FATTR_DFS_REFERRAL)
|
||||
if (fattr->cf_flags & CIFS_FATTR_JUNCTION)
|
||||
inode->i_flags |= S_AUTOMOUNT;
|
||||
if (inode->i_state & I_NEW)
|
||||
cifs_set_ops(inode);
|
||||
@ -327,14 +323,14 @@ cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info,
|
||||
*
|
||||
* Needed to setup cifs_fattr data for the directory which is the
|
||||
* junction to the new submount (ie to setup the fake directory
|
||||
* which represents a DFS referral).
|
||||
* which represents a DFS referral or reparse mount point).
|
||||
*/
|
||||
static void
|
||||
cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb)
|
||||
static void cifs_create_junction_fattr(struct cifs_fattr *fattr,
|
||||
struct super_block *sb)
|
||||
{
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
||||
|
||||
cifs_dbg(FYI, "creating fake fattr for DFS referral\n");
|
||||
cifs_dbg(FYI, "%s: creating fake fattr\n", __func__);
|
||||
|
||||
memset(fattr, 0, sizeof(*fattr));
|
||||
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)
|
||||
ktime_get_coarse_real_ts64(&fattr->cf_mtime);
|
||||
fattr->cf_atime = fattr->cf_ctime = fattr->cf_mtime;
|
||||
fattr->cf_nlink = 2;
|
||||
fattr->cf_flags = CIFS_FATTR_DFS_REFERRAL;
|
||||
fattr->cf_flags = CIFS_FATTR_JUNCTION;
|
||||
}
|
||||
|
||||
/* Update inode with final fattr data */
|
||||
static int update_inode_info(struct super_block *sb,
|
||||
struct cifs_fattr *fattr,
|
||||
struct inode **inode)
|
||||
{
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
||||
int rc = 0;
|
||||
|
||||
if (!*inode) {
|
||||
*inode = cifs_iget(sb, fattr);
|
||||
if (!*inode)
|
||||
rc = -ENOMEM;
|
||||
return rc;
|
||||
}
|
||||
/* We already have inode, update it.
|
||||
*
|
||||
* If file type or uniqueid is different, return error.
|
||||
*/
|
||||
if (unlikely((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) &&
|
||||
CIFS_I(*inode)->uniqueid != fattr->cf_uniqueid)) {
|
||||
CIFS_I(*inode)->time = 0; /* force reval */
|
||||
return -ESTALE;
|
||||
}
|
||||
return cifs_fattr_to_inode(*inode, fattr);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
|
||||
@ -373,7 +395,7 @@ cifs_get_file_info_unix(struct file *filp)
|
||||
if (!rc) {
|
||||
cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb);
|
||||
} else if (rc == -EREMOTE) {
|
||||
cifs_create_dfs_fattr(&fattr, inode->i_sb);
|
||||
cifs_create_junction_fattr(&fattr, inode->i_sb);
|
||||
rc = 0;
|
||||
} else
|
||||
goto cifs_gfiunix_out;
|
||||
@ -385,17 +407,18 @@ cifs_get_file_info_unix(struct file *filp)
|
||||
return rc;
|
||||
}
|
||||
|
||||
int cifs_get_inode_info_unix(struct inode **pinode,
|
||||
const unsigned char *full_path,
|
||||
struct super_block *sb, unsigned int xid)
|
||||
static int cifs_get_unix_fattr(const unsigned char *full_path,
|
||||
struct super_block *sb,
|
||||
struct cifs_fattr *fattr,
|
||||
struct inode **pinode,
|
||||
const unsigned int xid)
|
||||
{
|
||||
int rc;
|
||||
FILE_UNIX_BASIC_INFO find_data;
|
||||
struct cifs_fattr fattr;
|
||||
struct cifs_tcon *tcon;
|
||||
struct TCP_Server_Info *server;
|
||||
struct tcon_link *tlink;
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
||||
FILE_UNIX_BASIC_INFO find_data;
|
||||
struct cifs_tcon *tcon;
|
||||
struct tcon_link *tlink;
|
||||
int rc, tmprc;
|
||||
|
||||
cifs_dbg(FYI, "Getting info on %s\n", full_path);
|
||||
|
||||
@ -412,59 +435,61 @@ int cifs_get_inode_info_unix(struct inode **pinode,
|
||||
cifs_put_tlink(tlink);
|
||||
|
||||
if (!rc) {
|
||||
cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb);
|
||||
cifs_unix_basic_to_fattr(fattr, &find_data, cifs_sb);
|
||||
} else if (rc == -EREMOTE) {
|
||||
cifs_create_dfs_fattr(&fattr, sb);
|
||||
cifs_create_junction_fattr(fattr, sb);
|
||||
rc = 0;
|
||||
} else {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (!*pinode)
|
||||
cifs_fill_uniqueid(sb, fattr);
|
||||
|
||||
/* check for Minshall+French symlinks */
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
|
||||
int tmprc = check_mf_symlink(xid, tcon, cifs_sb, &fattr,
|
||||
full_path);
|
||||
if (tmprc)
|
||||
cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
|
||||
tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path);
|
||||
cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
|
||||
}
|
||||
|
||||
if (S_ISLNK(fattr.cf_mode) && !fattr.cf_symlink_target) {
|
||||
if (S_ISLNK(fattr->cf_mode) && !fattr->cf_symlink_target) {
|
||||
if (!server->ops->query_symlink)
|
||||
return -EOPNOTSUPP;
|
||||
rc = server->ops->query_symlink(xid, tcon, cifs_sb, full_path,
|
||||
&fattr.cf_symlink_target, false);
|
||||
if (rc) {
|
||||
cifs_dbg(FYI, "%s: query_symlink: %d\n", __func__, rc);
|
||||
goto cgiiu_exit;
|
||||
}
|
||||
rc = server->ops->query_symlink(xid, tcon,
|
||||
cifs_sb, full_path,
|
||||
&fattr->cf_symlink_target,
|
||||
NULL);
|
||||
cifs_dbg(FYI, "%s: query_symlink: %d\n", __func__, rc);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (*pinode == NULL) {
|
||||
/* get new inode */
|
||||
cifs_fill_uniqueid(sb, &fattr);
|
||||
*pinode = cifs_iget(sb, &fattr);
|
||||
if (!*pinode)
|
||||
rc = -ENOMEM;
|
||||
} else {
|
||||
/* we already have inode, update it */
|
||||
int cifs_get_inode_info_unix(struct inode **pinode,
|
||||
const unsigned char *full_path,
|
||||
struct super_block *sb, unsigned int xid)
|
||||
{
|
||||
struct cifs_fattr fattr = {};
|
||||
int rc;
|
||||
|
||||
/* if uniqueid is different, return error */
|
||||
if (unlikely(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM &&
|
||||
CIFS_I(*pinode)->uniqueid != fattr.cf_uniqueid)) {
|
||||
CIFS_I(*pinode)->time = 0; /* force reval */
|
||||
rc = -ESTALE;
|
||||
goto cgiiu_exit;
|
||||
}
|
||||
rc = cifs_get_unix_fattr(full_path, sb, &fattr, pinode, xid);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
/* if filetype is different, return error */
|
||||
rc = cifs_fattr_to_inode(*pinode, &fattr);
|
||||
}
|
||||
|
||||
cgiiu_exit:
|
||||
rc = update_inode_info(sb, &fattr, pinode);
|
||||
out:
|
||||
kfree(fattr.cf_symlink_target);
|
||||
return rc;
|
||||
}
|
||||
#else
|
||||
static inline int cifs_get_unix_fattr(const unsigned char *full_path,
|
||||
struct super_block *sb,
|
||||
struct cifs_fattr *fattr,
|
||||
struct inode **pinode,
|
||||
const unsigned int xid)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
int cifs_get_inode_info_unix(struct inode **pinode,
|
||||
const unsigned char *full_path,
|
||||
struct super_block *sb, unsigned int xid)
|
||||
@ -632,10 +657,11 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path,
|
||||
}
|
||||
|
||||
/* Fill a cifs_fattr struct with info from POSIX info struct */
|
||||
static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr, struct cifs_open_info_data *data,
|
||||
static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr,
|
||||
struct cifs_open_info_data *data,
|
||||
struct cifs_sid *owner,
|
||||
struct cifs_sid *group,
|
||||
struct super_block *sb, bool adjust_tz, bool symlink)
|
||||
struct super_block *sb)
|
||||
{
|
||||
struct smb311_posix_qinfo *info = &data->posix_fi;
|
||||
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
|
||||
fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime);
|
||||
fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime);
|
||||
|
||||
if (adjust_tz) {
|
||||
if (data->adjust_tz) {
|
||||
fattr->cf_ctime.tv_sec += tcon->ses->server->timeAdj;
|
||||
fattr->cf_mtime.tv_sec += tcon->ses->server->timeAdj;
|
||||
}
|
||||
@ -669,7 +695,7 @@ static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr, struct cifs_ope
|
||||
/* The srv fs device id is overridden on network mount so setting rdev isn't needed here */
|
||||
/* fattr->cf_rdev = le32_to_cpu(info->DeviceId); */
|
||||
|
||||
if (symlink) {
|
||||
if (data->symlink) {
|
||||
fattr->cf_mode |= S_IFLNK;
|
||||
fattr->cf_dtype = DT_LNK;
|
||||
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
|
||||
fattr->cf_mode, fattr->cf_uniqueid, fattr->cf_nlink);
|
||||
}
|
||||
|
||||
static void cifs_open_info_to_fattr(struct cifs_fattr *fattr, struct cifs_open_info_data *data,
|
||||
struct super_block *sb, bool adjust_tz, bool symlink,
|
||||
u32 reparse_tag)
|
||||
bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb,
|
||||
struct cifs_fattr *fattr,
|
||||
u32 tag)
|
||||
{
|
||||
switch (tag) {
|
||||
case IO_REPARSE_TAG_LX_SYMLINK:
|
||||
fattr->cf_mode |= S_IFLNK | cifs_sb->ctx->file_mode;
|
||||
fattr->cf_dtype = DT_LNK;
|
||||
break;
|
||||
case IO_REPARSE_TAG_LX_FIFO:
|
||||
fattr->cf_mode |= S_IFIFO | cifs_sb->ctx->file_mode;
|
||||
fattr->cf_dtype = DT_FIFO;
|
||||
break;
|
||||
case IO_REPARSE_TAG_AF_UNIX:
|
||||
fattr->cf_mode |= S_IFSOCK | cifs_sb->ctx->file_mode;
|
||||
fattr->cf_dtype = DT_SOCK;
|
||||
break;
|
||||
case IO_REPARSE_TAG_LX_CHR:
|
||||
fattr->cf_mode |= S_IFCHR | cifs_sb->ctx->file_mode;
|
||||
fattr->cf_dtype = DT_CHR;
|
||||
break;
|
||||
case IO_REPARSE_TAG_LX_BLK:
|
||||
fattr->cf_mode |= S_IFBLK | cifs_sb->ctx->file_mode;
|
||||
fattr->cf_dtype = DT_BLK;
|
||||
break;
|
||||
case 0: /* SMB1 symlink */
|
||||
case IO_REPARSE_TAG_SYMLINK:
|
||||
case IO_REPARSE_TAG_NFS:
|
||||
fattr->cf_mode = S_IFLNK;
|
||||
fattr->cf_dtype = DT_LNK;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void cifs_open_info_to_fattr(struct cifs_fattr *fattr,
|
||||
struct cifs_open_info_data *data,
|
||||
struct super_block *sb)
|
||||
{
|
||||
struct smb2_file_all_info *info = &data->fi;
|
||||
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
|
||||
fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime);
|
||||
fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime);
|
||||
|
||||
if (adjust_tz) {
|
||||
if (data->adjust_tz) {
|
||||
fattr->cf_ctime.tv_sec += tcon->ses->server->timeAdj;
|
||||
fattr->cf_mtime.tv_sec += tcon->ses->server->timeAdj;
|
||||
}
|
||||
@ -719,28 +782,13 @@ static void cifs_open_info_to_fattr(struct cifs_fattr *fattr, struct cifs_open_i
|
||||
fattr->cf_eof = le64_to_cpu(info->EndOfFile);
|
||||
fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
|
||||
fattr->cf_createtime = le64_to_cpu(info->CreationTime);
|
||||
|
||||
fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
|
||||
if (reparse_tag == IO_REPARSE_TAG_LX_SYMLINK) {
|
||||
fattr->cf_mode |= S_IFLNK | cifs_sb->ctx->file_mode;
|
||||
fattr->cf_dtype = DT_LNK;
|
||||
} else if (reparse_tag == IO_REPARSE_TAG_LX_FIFO) {
|
||||
fattr->cf_mode |= S_IFIFO | cifs_sb->ctx->file_mode;
|
||||
fattr->cf_dtype = DT_FIFO;
|
||||
} else if (reparse_tag == IO_REPARSE_TAG_AF_UNIX) {
|
||||
fattr->cf_mode |= S_IFSOCK | cifs_sb->ctx->file_mode;
|
||||
fattr->cf_dtype = DT_SOCK;
|
||||
} else if (reparse_tag == IO_REPARSE_TAG_LX_CHR) {
|
||||
fattr->cf_mode |= S_IFCHR | cifs_sb->ctx->file_mode;
|
||||
fattr->cf_dtype = DT_CHR;
|
||||
} else if (reparse_tag == IO_REPARSE_TAG_LX_BLK) {
|
||||
fattr->cf_mode |= S_IFBLK | cifs_sb->ctx->file_mode;
|
||||
fattr->cf_dtype = DT_BLK;
|
||||
} else if (symlink || reparse_tag == IO_REPARSE_TAG_SYMLINK ||
|
||||
reparse_tag == IO_REPARSE_TAG_NFS) {
|
||||
fattr->cf_mode = S_IFLNK;
|
||||
fattr->cf_dtype = DT_LNK;
|
||||
} else if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
|
||||
|
||||
if (cifs_open_data_reparse(data) &&
|
||||
cifs_reparse_point_to_fattr(cifs_sb, fattr, data->reparse_tag))
|
||||
goto out_reparse;
|
||||
|
||||
if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
|
||||
fattr->cf_mode = S_IFDIR | cifs_sb->ctx->dir_mode;
|
||||
fattr->cf_dtype = DT_DIR;
|
||||
/*
|
||||
@ -769,6 +817,7 @@ static void cifs_open_info_to_fattr(struct cifs_fattr *fattr, struct cifs_open_i
|
||||
}
|
||||
}
|
||||
|
||||
out_reparse:
|
||||
if (S_ISLNK(fattr->cf_mode)) {
|
||||
fattr->cf_symlink_target = data->symlink_target;
|
||||
data->symlink_target = NULL;
|
||||
@ -789,8 +838,6 @@ cifs_get_file_info(struct file *filp)
|
||||
struct cifsFileInfo *cfile = filp->private_data;
|
||||
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
|
||||
struct TCP_Server_Info *server = tcon->ses->server;
|
||||
bool symlink = false;
|
||||
u32 tag = 0;
|
||||
|
||||
if (!server->ops->query_file_info)
|
||||
return -ENOSYS;
|
||||
@ -800,14 +847,15 @@ cifs_get_file_info(struct file *filp)
|
||||
switch (rc) {
|
||||
case 0:
|
||||
/* TODO: add support to query reparse tag */
|
||||
data.adjust_tz = false;
|
||||
if (data.symlink_target) {
|
||||
symlink = true;
|
||||
tag = IO_REPARSE_TAG_SYMLINK;
|
||||
data.symlink = true;
|
||||
data.reparse_tag = IO_REPARSE_TAG_SYMLINK;
|
||||
}
|
||||
cifs_open_info_to_fattr(&fattr, &data, inode->i_sb, false, symlink, tag);
|
||||
cifs_open_info_to_fattr(&fattr, &data, inode->i_sb);
|
||||
break;
|
||||
case -EREMOTE:
|
||||
cifs_create_dfs_fattr(&fattr, inode->i_sb);
|
||||
cifs_create_junction_fattr(&fattr, inode->i_sb);
|
||||
rc = 0;
|
||||
break;
|
||||
case -EOPNOTSUPP:
|
||||
@ -960,22 +1008,66 @@ static inline bool is_inode_cache_good(struct inode *ino)
|
||||
return ino && CIFS_CACHE_READ(CIFS_I(ino)) && CIFS_I(ino)->time != 0;
|
||||
}
|
||||
|
||||
int cifs_get_inode_info(struct inode **inode, const char *full_path,
|
||||
struct cifs_open_info_data *data, struct super_block *sb, int xid,
|
||||
const struct cifs_fid *fid)
|
||||
static int reparse_info_to_fattr(struct cifs_open_info_data *data,
|
||||
struct super_block *sb,
|
||||
const unsigned int xid,
|
||||
struct cifs_tcon *tcon,
|
||||
const char *full_path,
|
||||
struct cifs_fattr *fattr)
|
||||
{
|
||||
struct TCP_Server_Info *server = tcon->ses->server;
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
||||
struct kvec rsp_iov, *iov = NULL;
|
||||
int rsp_buftype = CIFS_NO_BUFFER;
|
||||
u32 tag = data->reparse_tag;
|
||||
int rc = 0;
|
||||
|
||||
if (!tag && server->ops->query_reparse_point) {
|
||||
rc = server->ops->query_reparse_point(xid, tcon, cifs_sb,
|
||||
full_path, &tag,
|
||||
&rsp_iov, &rsp_buftype);
|
||||
if (!rc)
|
||||
iov = &rsp_iov;
|
||||
}
|
||||
switch ((data->reparse_tag = tag)) {
|
||||
case 0: /* SMB1 symlink */
|
||||
iov = NULL;
|
||||
fallthrough;
|
||||
case IO_REPARSE_TAG_NFS:
|
||||
case IO_REPARSE_TAG_SYMLINK:
|
||||
if (!data->symlink_target && server->ops->query_symlink) {
|
||||
rc = server->ops->query_symlink(xid, tcon,
|
||||
cifs_sb, full_path,
|
||||
&data->symlink_target,
|
||||
iov);
|
||||
}
|
||||
break;
|
||||
case IO_REPARSE_TAG_MOUNT_POINT:
|
||||
cifs_create_junction_fattr(fattr, sb);
|
||||
goto out;
|
||||
}
|
||||
|
||||
cifs_open_info_to_fattr(fattr, data, sb);
|
||||
out:
|
||||
free_rsp_buf(rsp_buftype, rsp_iov.iov_base);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int cifs_get_fattr(struct cifs_open_info_data *data,
|
||||
struct super_block *sb, int xid,
|
||||
const struct cifs_fid *fid,
|
||||
struct cifs_fattr *fattr,
|
||||
struct inode **inode,
|
||||
const char *full_path)
|
||||
{
|
||||
struct cifs_open_info_data tmp_data = {};
|
||||
struct cifs_tcon *tcon;
|
||||
struct TCP_Server_Info *server;
|
||||
struct tcon_link *tlink;
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
||||
bool adjust_tz = false;
|
||||
struct cifs_fattr fattr = {0};
|
||||
bool is_reparse_point = false;
|
||||
struct cifs_open_info_data tmp_data = {};
|
||||
void *smb1_backup_rsp_buf = NULL;
|
||||
int rc = 0;
|
||||
int tmprc = 0;
|
||||
__u32 reparse_tag = 0;
|
||||
|
||||
tlink = cifs_sb_tlink(cifs_sb);
|
||||
if (IS_ERR(tlink))
|
||||
@ -988,12 +1080,8 @@ int cifs_get_inode_info(struct inode **inode, const char *full_path,
|
||||
*/
|
||||
|
||||
if (!data) {
|
||||
if (is_inode_cache_good(*inode)) {
|
||||
cifs_dbg(FYI, "No need to revalidate cached inode sizes\n");
|
||||
goto out;
|
||||
}
|
||||
rc = server->ops->query_path_info(xid, tcon, cifs_sb, full_path, &tmp_data,
|
||||
&adjust_tz, &is_reparse_point);
|
||||
rc = server->ops->query_path_info(xid, tcon, cifs_sb,
|
||||
full_path, &tmp_data);
|
||||
data = &tmp_data;
|
||||
}
|
||||
|
||||
@ -1008,28 +1096,16 @@ int cifs_get_inode_info(struct inode **inode, const char *full_path,
|
||||
* since we have to check if its reparse tag matches a known
|
||||
* special file type e.g. symlink or fifo or char etc.
|
||||
*/
|
||||
if (is_reparse_point && data->symlink_target) {
|
||||
reparse_tag = IO_REPARSE_TAG_SYMLINK;
|
||||
} else if ((le32_to_cpu(data->fi.Attributes) & ATTR_REPARSE) &&
|
||||
server->ops->query_reparse_tag) {
|
||||
tmprc = server->ops->query_reparse_tag(xid, tcon, cifs_sb, full_path,
|
||||
&reparse_tag);
|
||||
if (tmprc)
|
||||
cifs_dbg(FYI, "%s: query_reparse_tag: rc = %d\n", __func__, tmprc);
|
||||
if (server->ops->query_symlink) {
|
||||
tmprc = server->ops->query_symlink(xid, tcon, cifs_sb, full_path,
|
||||
&data->symlink_target,
|
||||
is_reparse_point);
|
||||
if (tmprc)
|
||||
cifs_dbg(FYI, "%s: query_symlink: rc = %d\n", __func__,
|
||||
tmprc);
|
||||
}
|
||||
if (cifs_open_data_reparse(data)) {
|
||||
rc = reparse_info_to_fattr(data, sb, xid, tcon,
|
||||
full_path, fattr);
|
||||
} else {
|
||||
cifs_open_info_to_fattr(fattr, data, sb);
|
||||
}
|
||||
cifs_open_info_to_fattr(&fattr, data, sb, adjust_tz, is_reparse_point, reparse_tag);
|
||||
break;
|
||||
case -EREMOTE:
|
||||
/* DFS link, no metadata available on this server */
|
||||
cifs_create_dfs_fattr(&fattr, sb);
|
||||
cifs_create_junction_fattr(fattr, sb);
|
||||
rc = 0;
|
||||
break;
|
||||
case -EACCES:
|
||||
@ -1059,8 +1135,8 @@ int cifs_get_inode_info(struct inode **inode, const char *full_path,
|
||||
fdi = (FILE_DIRECTORY_INFO *)fi;
|
||||
si = (SEARCH_ID_FULL_DIR_INFO *)fi;
|
||||
|
||||
cifs_dir_info_to_fattr(&fattr, fdi, cifs_sb);
|
||||
fattr.cf_uniqueid = le64_to_cpu(si->UniqueId);
|
||||
cifs_dir_info_to_fattr(fattr, fdi, cifs_sb);
|
||||
fattr->cf_uniqueid = le64_to_cpu(si->UniqueId);
|
||||
/* uniqueid set, skip get inum step */
|
||||
goto handle_mnt_opt;
|
||||
} else {
|
||||
@ -1077,10 +1153,10 @@ int cifs_get_inode_info(struct inode **inode, const char *full_path,
|
||||
}
|
||||
|
||||
/*
|
||||
* 3. Get or update inode number (fattr.cf_uniqueid)
|
||||
* 3. Get or update inode number (fattr->cf_uniqueid)
|
||||
*/
|
||||
|
||||
cifs_set_fattr_ino(xid, tcon, sb, inode, full_path, data, &fattr);
|
||||
cifs_set_fattr_ino(xid, tcon, sb, inode, full_path, data, fattr);
|
||||
|
||||
/*
|
||||
* 4. Tweak fattr based on mount options
|
||||
@ -1089,17 +1165,17 @@ int cifs_get_inode_info(struct inode **inode, const char *full_path,
|
||||
handle_mnt_opt:
|
||||
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
|
||||
/* query for SFU type info if supported and needed */
|
||||
if (fattr.cf_cifsattrs & ATTR_SYSTEM &&
|
||||
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
|
||||
tmprc = cifs_sfu_type(&fattr, full_path, cifs_sb, xid);
|
||||
if ((fattr->cf_cifsattrs & ATTR_SYSTEM) &&
|
||||
(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) {
|
||||
tmprc = cifs_sfu_type(fattr, full_path, cifs_sb, xid);
|
||||
if (tmprc)
|
||||
cifs_dbg(FYI, "cifs_sfu_type failed: %d\n", tmprc);
|
||||
}
|
||||
|
||||
/* fill in 0777 bits from ACL */
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) {
|
||||
rc = cifs_acl_to_fattr(cifs_sb, &fattr, *inode, true,
|
||||
full_path, fid);
|
||||
rc = cifs_acl_to_fattr(cifs_sb, fattr, *inode,
|
||||
true, full_path, fid);
|
||||
if (rc == -EREMOTE)
|
||||
rc = 0;
|
||||
if (rc) {
|
||||
@ -1108,8 +1184,8 @@ int cifs_get_inode_info(struct inode **inode, const char *full_path,
|
||||
goto out;
|
||||
}
|
||||
} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
|
||||
rc = cifs_acl_to_fattr(cifs_sb, &fattr, *inode, false,
|
||||
full_path, fid);
|
||||
rc = cifs_acl_to_fattr(cifs_sb, fattr, *inode,
|
||||
false, full_path, fid);
|
||||
if (rc == -EREMOTE)
|
||||
rc = 0;
|
||||
if (rc) {
|
||||
@ -1121,60 +1197,57 @@ int cifs_get_inode_info(struct inode **inode, const char *full_path,
|
||||
|
||||
/* fill in remaining high mode bits e.g. SUID, VTX */
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
|
||||
cifs_sfu_mode(&fattr, full_path, cifs_sb, xid);
|
||||
cifs_sfu_mode(fattr, full_path, cifs_sb, xid);
|
||||
|
||||
/* check for Minshall+French symlinks */
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
|
||||
tmprc = check_mf_symlink(xid, tcon, cifs_sb, &fattr,
|
||||
full_path);
|
||||
if (tmprc)
|
||||
cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
|
||||
tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path);
|
||||
cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
|
||||
}
|
||||
|
||||
/*
|
||||
* 5. Update inode with final fattr data
|
||||
*/
|
||||
|
||||
if (!*inode) {
|
||||
*inode = cifs_iget(sb, &fattr);
|
||||
if (!*inode)
|
||||
rc = -ENOMEM;
|
||||
} else {
|
||||
/* we already have inode, update it */
|
||||
|
||||
/* if uniqueid is different, return error */
|
||||
if (unlikely(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM &&
|
||||
CIFS_I(*inode)->uniqueid != fattr.cf_uniqueid)) {
|
||||
CIFS_I(*inode)->time = 0; /* force reval */
|
||||
rc = -ESTALE;
|
||||
goto out;
|
||||
}
|
||||
/* if filetype is different, return error */
|
||||
rc = cifs_fattr_to_inode(*inode, &fattr);
|
||||
}
|
||||
out:
|
||||
cifs_buf_release(smb1_backup_rsp_buf);
|
||||
cifs_put_tlink(tlink);
|
||||
cifs_free_open_info(&tmp_data);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int cifs_get_inode_info(struct inode **inode,
|
||||
const char *full_path,
|
||||
struct cifs_open_info_data *data,
|
||||
struct super_block *sb, int xid,
|
||||
const struct cifs_fid *fid)
|
||||
{
|
||||
struct cifs_fattr fattr = {};
|
||||
int rc;
|
||||
|
||||
if (is_inode_cache_good(*inode)) {
|
||||
cifs_dbg(FYI, "No need to revalidate cached inode sizes\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = cifs_get_fattr(data, sb, xid, fid, &fattr, inode, full_path);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
rc = update_inode_info(sb, &fattr, inode);
|
||||
out:
|
||||
kfree(fattr.cf_symlink_target);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
smb311_posix_get_inode_info(struct inode **inode,
|
||||
const char *full_path,
|
||||
struct super_block *sb, unsigned int xid)
|
||||
static int smb311_posix_get_fattr(struct cifs_fattr *fattr,
|
||||
const char *full_path,
|
||||
struct super_block *sb,
|
||||
const unsigned int xid)
|
||||
{
|
||||
struct cifs_open_info_data data = {};
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
||||
struct cifs_tcon *tcon;
|
||||
struct tcon_link *tlink;
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
||||
bool adjust_tz = false;
|
||||
struct cifs_fattr fattr = {0};
|
||||
bool symlink = false;
|
||||
struct cifs_open_info_data data = {};
|
||||
struct cifs_sid owner, group;
|
||||
int rc = 0;
|
||||
int tmprc = 0;
|
||||
int tmprc;
|
||||
int rc;
|
||||
|
||||
tlink = cifs_sb_tlink(cifs_sb);
|
||||
if (IS_ERR(tlink))
|
||||
@ -1185,14 +1258,9 @@ smb311_posix_get_inode_info(struct inode **inode,
|
||||
* 1. Fetch file metadata
|
||||
*/
|
||||
|
||||
if (is_inode_cache_good(*inode)) {
|
||||
cifs_dbg(FYI, "No need to revalidate cached inode sizes\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = smb311_posix_query_path_info(xid, tcon, cifs_sb, full_path, &data,
|
||||
&owner, &group, &adjust_tz,
|
||||
&symlink);
|
||||
rc = smb311_posix_query_path_info(xid, tcon, cifs_sb,
|
||||
full_path, &data,
|
||||
&owner, &group);
|
||||
|
||||
/*
|
||||
* 2. Convert it to internal cifs metadata (fattr)
|
||||
@ -1200,12 +1268,11 @@ smb311_posix_get_inode_info(struct inode **inode,
|
||||
|
||||
switch (rc) {
|
||||
case 0:
|
||||
smb311_posix_info_to_fattr(&fattr, &data, &owner, &group,
|
||||
sb, adjust_tz, symlink);
|
||||
smb311_posix_info_to_fattr(fattr, &data, &owner, &group, sb);
|
||||
break;
|
||||
case -EREMOTE:
|
||||
/* DFS link, no metadata available on this server */
|
||||
cifs_create_dfs_fattr(&fattr, sb);
|
||||
cifs_create_junction_fattr(fattr, sb);
|
||||
rc = 0;
|
||||
break;
|
||||
case -EACCES:
|
||||
@ -1221,48 +1288,41 @@ smb311_posix_get_inode_info(struct inode **inode,
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 3. Tweak fattr based on mount options
|
||||
*/
|
||||
|
||||
/* check for Minshall+French symlinks */
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
|
||||
tmprc = check_mf_symlink(xid, tcon, cifs_sb, &fattr,
|
||||
full_path);
|
||||
if (tmprc)
|
||||
cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
|
||||
tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path);
|
||||
cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
|
||||
}
|
||||
|
||||
/*
|
||||
* 4. Update inode with final fattr data
|
||||
*/
|
||||
|
||||
if (!*inode) {
|
||||
*inode = cifs_iget(sb, &fattr);
|
||||
if (!*inode)
|
||||
rc = -ENOMEM;
|
||||
} else {
|
||||
/* we already have inode, update it */
|
||||
|
||||
/* if uniqueid is different, return error */
|
||||
if (unlikely(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM &&
|
||||
CIFS_I(*inode)->uniqueid != fattr.cf_uniqueid)) {
|
||||
CIFS_I(*inode)->time = 0; /* force reval */
|
||||
rc = -ESTALE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* if filetype is different, return error */
|
||||
rc = cifs_fattr_to_inode(*inode, &fattr);
|
||||
}
|
||||
out:
|
||||
cifs_put_tlink(tlink);
|
||||
cifs_free_open_info(&data);
|
||||
kfree(fattr.cf_symlink_target);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int smb311_posix_get_inode_info(struct inode **inode, const char *full_path,
|
||||
struct super_block *sb, const unsigned int xid)
|
||||
{
|
||||
struct cifs_fattr fattr = {};
|
||||
int rc;
|
||||
|
||||
if (is_inode_cache_good(*inode)) {
|
||||
cifs_dbg(FYI, "No need to revalidate cached inode sizes\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = smb311_posix_get_fattr(&fattr, full_path, sb, xid);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
rc = update_inode_info(sb, &fattr, inode);
|
||||
out:
|
||||
kfree(fattr.cf_symlink_target);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static const struct inode_operations cifs_ipc_inode_ops = {
|
||||
.lookup = cifs_lookup,
|
||||
@ -1367,13 +1427,14 @@ cifs_iget(struct super_block *sb, struct cifs_fattr *fattr)
|
||||
/* gets root inode */
|
||||
struct inode *cifs_root_iget(struct super_block *sb)
|
||||
{
|
||||
unsigned int xid;
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
||||
struct inode *inode = NULL;
|
||||
long rc;
|
||||
struct cifs_fattr fattr = {};
|
||||
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
|
||||
struct inode *inode = NULL;
|
||||
unsigned int xid;
|
||||
char *path = NULL;
|
||||
int len;
|
||||
int rc;
|
||||
|
||||
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH)
|
||||
&& cifs_sb->prepath) {
|
||||
@ -1391,21 +1452,29 @@ struct inode *cifs_root_iget(struct super_block *sb)
|
||||
|
||||
xid = get_xid();
|
||||
if (tcon->unix_ext) {
|
||||
rc = cifs_get_inode_info_unix(&inode, path, sb, xid);
|
||||
rc = cifs_get_unix_fattr(path, sb, &fattr, &inode, xid);
|
||||
/* some servers mistakenly claim POSIX support */
|
||||
if (rc != -EOPNOTSUPP)
|
||||
goto iget_no_retry;
|
||||
goto iget_root;
|
||||
cifs_dbg(VFS, "server does not support POSIX extensions\n");
|
||||
tcon->unix_ext = false;
|
||||
}
|
||||
|
||||
convert_delimiter(path, CIFS_DIR_SEP(cifs_sb));
|
||||
if (tcon->posix_extensions)
|
||||
rc = smb311_posix_get_inode_info(&inode, path, sb, xid);
|
||||
rc = smb311_posix_get_fattr(&fattr, path, sb, xid);
|
||||
else
|
||||
rc = cifs_get_inode_info(&inode, path, NULL, sb, xid, NULL);
|
||||
rc = cifs_get_fattr(NULL, sb, xid, NULL, &fattr, &inode, path);
|
||||
|
||||
iget_root:
|
||||
if (!rc) {
|
||||
if (fattr.cf_flags & CIFS_FATTR_JUNCTION) {
|
||||
fattr.cf_flags &= ~CIFS_FATTR_JUNCTION;
|
||||
cifs_autodisable_serverino(cifs_sb);
|
||||
}
|
||||
inode = cifs_iget(sb, &fattr);
|
||||
}
|
||||
|
||||
iget_no_retry:
|
||||
if (!inode) {
|
||||
inode = ERR_PTR(rc);
|
||||
goto out;
|
||||
@ -1429,6 +1498,7 @@ struct inode *cifs_root_iget(struct super_block *sb)
|
||||
out:
|
||||
kfree(path);
|
||||
free_xid(xid);
|
||||
kfree(fattr.cf_symlink_target);
|
||||
return inode;
|
||||
}
|
||||
|
||||
|
@ -476,7 +476,7 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
|
||||
return false;
|
||||
|
||||
/* If server is a channel, select the primary channel */
|
||||
pserver = CIFS_SERVER_IS_CHAN(srv) ? srv->primary_server : srv;
|
||||
pserver = SERVER_IS_CHAN(srv) ? srv->primary_server : srv;
|
||||
|
||||
/* look up tcon based on tid & uid */
|
||||
spin_lock(&cifs_tcp_ses_lock);
|
||||
|
@ -1,12 +1,12 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Contains the CIFS DFS referral mounting routines used for handling
|
||||
* traversal via DFS junction point
|
||||
* Contains mounting routines used for handling traversal via SMB junctions.
|
||||
*
|
||||
* Copyright (c) 2007 Igor Mammedov
|
||||
* Copyright (C) International Business Machines Corp., 2008
|
||||
* Author(s): Igor Mammedov (niallain@gmail.com)
|
||||
* Steve French (sfrench@us.ibm.com)
|
||||
* Copyright (c) 2023 Paulo Alcantara <palcantara@suse.de>
|
||||
*/
|
||||
|
||||
#include <linux/dcache.h>
|
||||
@ -19,32 +19,31 @@
|
||||
#include "cifsglob.h"
|
||||
#include "cifsproto.h"
|
||||
#include "cifsfs.h"
|
||||
#include "dns_resolve.h"
|
||||
#include "cifs_debug.h"
|
||||
#include "dfs.h"
|
||||
#include "fs_context.h"
|
||||
|
||||
static LIST_HEAD(cifs_dfs_automount_list);
|
||||
static LIST_HEAD(cifs_automount_list);
|
||||
|
||||
static void cifs_dfs_expire_automounts(struct work_struct *work);
|
||||
static DECLARE_DELAYED_WORK(cifs_dfs_automount_task,
|
||||
cifs_dfs_expire_automounts);
|
||||
static int cifs_dfs_mountpoint_expiry_timeout = 500 * HZ;
|
||||
static void cifs_expire_automounts(struct work_struct *work);
|
||||
static DECLARE_DELAYED_WORK(cifs_automount_task,
|
||||
cifs_expire_automounts);
|
||||
static int cifs_mountpoint_expiry_timeout = 500 * HZ;
|
||||
|
||||
static void cifs_dfs_expire_automounts(struct work_struct *work)
|
||||
static void cifs_expire_automounts(struct work_struct *work)
|
||||
{
|
||||
struct list_head *list = &cifs_dfs_automount_list;
|
||||
struct list_head *list = &cifs_automount_list;
|
||||
|
||||
mark_mounts_for_expiry(list);
|
||||
if (!list_empty(list))
|
||||
schedule_delayed_work(&cifs_dfs_automount_task,
|
||||
cifs_dfs_mountpoint_expiry_timeout);
|
||||
schedule_delayed_work(&cifs_automount_task,
|
||||
cifs_mountpoint_expiry_timeout);
|
||||
}
|
||||
|
||||
void cifs_dfs_release_automount_timer(void)
|
||||
void cifs_release_automount_timer(void)
|
||||
{
|
||||
BUG_ON(!list_empty(&cifs_dfs_automount_list));
|
||||
cancel_delayed_work_sync(&cifs_dfs_automount_task);
|
||||
if (WARN_ON(!list_empty(&cifs_automount_list)))
|
||||
return;
|
||||
cancel_delayed_work_sync(&cifs_automount_task);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -118,26 +117,53 @@ cifs_build_devname(char *nodename, const char *prepath)
|
||||
return dev;
|
||||
}
|
||||
|
||||
static int set_dest_addr(struct smb3_fs_context *ctx)
|
||||
/* Return full path out of a dentry set for automount */
|
||||
static char *automount_fullpath(struct dentry *dentry, void *page)
|
||||
{
|
||||
struct sockaddr *addr = (struct sockaddr *)&ctx->dstaddr;
|
||||
int rc;
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb);
|
||||
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
|
||||
size_t len;
|
||||
char *s;
|
||||
|
||||
rc = dns_resolve_server_name_to_ip(ctx->source, addr, NULL);
|
||||
if (!rc)
|
||||
cifs_set_port(addr, ctx->port);
|
||||
return rc;
|
||||
spin_lock(&tcon->tc_lock);
|
||||
if (!tcon->origin_fullpath) {
|
||||
spin_unlock(&tcon->tc_lock);
|
||||
return build_path_from_dentry_optional_prefix(dentry,
|
||||
page,
|
||||
true);
|
||||
}
|
||||
spin_unlock(&tcon->tc_lock);
|
||||
|
||||
s = dentry_path_raw(dentry, page, PATH_MAX);
|
||||
if (IS_ERR(s))
|
||||
return s;
|
||||
/* for root, we want "" */
|
||||
if (!s[1])
|
||||
s++;
|
||||
|
||||
spin_lock(&tcon->tc_lock);
|
||||
len = strlen(tcon->origin_fullpath);
|
||||
if (s < (char *)page + len) {
|
||||
spin_unlock(&tcon->tc_lock);
|
||||
return ERR_PTR(-ENAMETOOLONG);
|
||||
}
|
||||
|
||||
s -= len;
|
||||
memcpy(s, tcon->origin_fullpath, len);
|
||||
spin_unlock(&tcon->tc_lock);
|
||||
convert_delimiter(s, '/');
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a vfsmount that we can automount
|
||||
*/
|
||||
static struct vfsmount *cifs_dfs_do_automount(struct path *path)
|
||||
static struct vfsmount *cifs_do_automount(struct path *path)
|
||||
{
|
||||
int rc;
|
||||
struct dentry *mntpt = path->dentry;
|
||||
struct fs_context *fc;
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
void *page = NULL;
|
||||
struct smb3_fs_context *ctx, *cur_ctx;
|
||||
struct smb3_fs_context tmp;
|
||||
@ -147,17 +173,7 @@ static struct vfsmount *cifs_dfs_do_automount(struct path *path)
|
||||
if (IS_ROOT(mntpt))
|
||||
return ERR_PTR(-ESTALE);
|
||||
|
||||
/*
|
||||
* The MSDFS spec states that paths in DFS referral requests and
|
||||
* responses must be prefixed by a single '\' character instead of
|
||||
* the double backslashes usually used in the UNC. This function
|
||||
* gives us the latter, so we must adjust the result.
|
||||
*/
|
||||
cifs_sb = CIFS_SB(mntpt->d_sb);
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS)
|
||||
return ERR_PTR(-EREMOTE);
|
||||
|
||||
cur_ctx = cifs_sb->ctx;
|
||||
cur_ctx = CIFS_SB(mntpt->d_sb)->ctx;
|
||||
|
||||
fc = fs_context_for_submount(path->mnt->mnt_sb->s_type, mntpt);
|
||||
if (IS_ERR(fc))
|
||||
@ -166,7 +182,7 @@ static struct vfsmount *cifs_dfs_do_automount(struct path *path)
|
||||
ctx = smb3_fc2context(fc);
|
||||
|
||||
page = alloc_dentry_path();
|
||||
full_path = dfs_get_automount_devname(mntpt, page);
|
||||
full_path = automount_fullpath(mntpt, page);
|
||||
if (IS_ERR(full_path)) {
|
||||
mnt = ERR_CAST(full_path);
|
||||
goto out;
|
||||
@ -196,15 +212,10 @@ static struct vfsmount *cifs_dfs_do_automount(struct path *path)
|
||||
ctx->source = NULL;
|
||||
goto out;
|
||||
}
|
||||
cifs_dbg(FYI, "%s: ctx: source=%s UNC=%s prepath=%s dstaddr=%pISpc\n",
|
||||
__func__, ctx->source, ctx->UNC, ctx->prepath, &ctx->dstaddr);
|
||||
|
||||
rc = set_dest_addr(ctx);
|
||||
if (!rc)
|
||||
mnt = fc_mount(fc);
|
||||
else
|
||||
mnt = ERR_PTR(rc);
|
||||
cifs_dbg(FYI, "%s: ctx: source=%s UNC=%s prepath=%s\n",
|
||||
__func__, ctx->source, ctx->UNC, ctx->prepath);
|
||||
|
||||
mnt = fc_mount(fc);
|
||||
out:
|
||||
put_fs_context(fc);
|
||||
free_dentry_path(page);
|
||||
@ -214,25 +225,25 @@ static struct vfsmount *cifs_dfs_do_automount(struct path *path)
|
||||
/*
|
||||
* Attempt to automount the referral
|
||||
*/
|
||||
struct vfsmount *cifs_dfs_d_automount(struct path *path)
|
||||
struct vfsmount *cifs_d_automount(struct path *path)
|
||||
{
|
||||
struct vfsmount *newmnt;
|
||||
|
||||
cifs_dbg(FYI, "%s: %pd\n", __func__, path->dentry);
|
||||
|
||||
newmnt = cifs_dfs_do_automount(path);
|
||||
newmnt = cifs_do_automount(path);
|
||||
if (IS_ERR(newmnt)) {
|
||||
cifs_dbg(FYI, "leaving %s [automount failed]\n" , __func__);
|
||||
return newmnt;
|
||||
}
|
||||
|
||||
mntget(newmnt); /* prevent immediate expiration */
|
||||
mnt_set_expiry(newmnt, &cifs_dfs_automount_list);
|
||||
schedule_delayed_work(&cifs_dfs_automount_task,
|
||||
cifs_dfs_mountpoint_expiry_timeout);
|
||||
mnt_set_expiry(newmnt, &cifs_automount_list);
|
||||
schedule_delayed_work(&cifs_automount_task,
|
||||
cifs_mountpoint_expiry_timeout);
|
||||
cifs_dbg(FYI, "leaving %s [ok]\n" , __func__);
|
||||
return newmnt;
|
||||
}
|
||||
|
||||
const struct inode_operations cifs_dfs_referral_inode_operations = {
|
||||
const struct inode_operations cifs_namespace_inode_operations = {
|
||||
};
|
@ -143,6 +143,7 @@ static bool reparse_file_needs_reval(const struct cifs_fattr *fattr)
|
||||
case IO_REPARSE_TAG_DFSR:
|
||||
case IO_REPARSE_TAG_SYMLINK:
|
||||
case IO_REPARSE_TAG_NFS:
|
||||
case IO_REPARSE_TAG_MOUNT_POINT:
|
||||
case 0:
|
||||
return true;
|
||||
}
|
||||
@ -163,29 +164,19 @@ cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
|
||||
* TODO: go through all documented reparse tags to see if we can
|
||||
* reasonably map some of them to directories vs. files vs. symlinks
|
||||
*/
|
||||
if ((fattr->cf_cifsattrs & ATTR_REPARSE) &&
|
||||
cifs_reparse_point_to_fattr(cifs_sb, fattr, fattr->cf_cifstag))
|
||||
goto out_reparse;
|
||||
|
||||
if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
|
||||
fattr->cf_mode = S_IFDIR | cifs_sb->ctx->dir_mode;
|
||||
fattr->cf_dtype = DT_DIR;
|
||||
} else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_SYMLINK) {
|
||||
fattr->cf_mode |= S_IFLNK | cifs_sb->ctx->file_mode;
|
||||
fattr->cf_dtype = DT_LNK;
|
||||
} else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_FIFO) {
|
||||
fattr->cf_mode |= S_IFIFO | cifs_sb->ctx->file_mode;
|
||||
fattr->cf_dtype = DT_FIFO;
|
||||
} else if (fattr->cf_cifstag == IO_REPARSE_TAG_AF_UNIX) {
|
||||
fattr->cf_mode |= S_IFSOCK | cifs_sb->ctx->file_mode;
|
||||
fattr->cf_dtype = DT_SOCK;
|
||||
} else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_CHR) {
|
||||
fattr->cf_mode |= S_IFCHR | cifs_sb->ctx->file_mode;
|
||||
fattr->cf_dtype = DT_CHR;
|
||||
} else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_BLK) {
|
||||
fattr->cf_mode |= S_IFBLK | cifs_sb->ctx->file_mode;
|
||||
fattr->cf_dtype = DT_BLK;
|
||||
} else { /* TODO: should we mark some other reparse points (like DFSR) as directories? */
|
||||
} else {
|
||||
fattr->cf_mode = S_IFREG | cifs_sb->ctx->file_mode;
|
||||
fattr->cf_dtype = DT_REG;
|
||||
}
|
||||
|
||||
out_reparse:
|
||||
/*
|
||||
* We need to revalidate it further to make a decision about whether it
|
||||
* 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)
|
||||
ses->chans[chan_index].iface = iface;
|
||||
|
||||
/* No iface is found. if secondary chan, drop connection */
|
||||
if (!iface && CIFS_SERVER_IS_CHAN(server))
|
||||
if (!iface && SERVER_IS_CHAN(server))
|
||||
ses->chans[chan_index].server = NULL;
|
||||
|
||||
spin_unlock(&ses->chan_lock);
|
||||
|
||||
if (!iface && CIFS_SERVER_IS_CHAN(server))
|
||||
if (!iface && SERVER_IS_CHAN(server))
|
||||
cifs_put_tcp_session(server, false);
|
||||
|
||||
return rc;
|
||||
@ -360,11 +360,11 @@ cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
|
||||
{
|
||||
struct TCP_Server_Info *chan_server;
|
||||
struct cifs_chan *chan;
|
||||
struct smb3_fs_context ctx = {NULL};
|
||||
struct smb3_fs_context *ctx;
|
||||
static const char unc_fmt[] = "\\%s\\foo";
|
||||
char unc[sizeof(unc_fmt)+SERVER_NAME_LEN_WITH_NULL] = {0};
|
||||
struct sockaddr_in *ipv4 = (struct sockaddr_in *)&iface->sockaddr;
|
||||
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)&iface->sockaddr;
|
||||
size_t len;
|
||||
int rc;
|
||||
unsigned int xid = get_xid();
|
||||
|
||||
@ -388,54 +388,64 @@ cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
|
||||
* the session and server without caring about memory
|
||||
* management.
|
||||
*/
|
||||
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
|
||||
if (!ctx) {
|
||||
rc = -ENOMEM;
|
||||
goto out_free_xid;
|
||||
}
|
||||
|
||||
/* Always make new connection for now (TODO?) */
|
||||
ctx.nosharesock = true;
|
||||
ctx->nosharesock = true;
|
||||
|
||||
/* Auth */
|
||||
ctx.domainauto = ses->domainAuto;
|
||||
ctx.domainname = ses->domainName;
|
||||
ctx->domainauto = ses->domainAuto;
|
||||
ctx->domainname = ses->domainName;
|
||||
|
||||
/* no hostname for extra channels */
|
||||
ctx.server_hostname = "";
|
||||
ctx->server_hostname = "";
|
||||
|
||||
ctx.username = ses->user_name;
|
||||
ctx.password = ses->password;
|
||||
ctx.sectype = ses->sectype;
|
||||
ctx.sign = ses->sign;
|
||||
ctx->username = ses->user_name;
|
||||
ctx->password = ses->password;
|
||||
ctx->sectype = ses->sectype;
|
||||
ctx->sign = ses->sign;
|
||||
|
||||
/* UNC and paths */
|
||||
/* XXX: Use ses->server->hostname? */
|
||||
sprintf(unc, unc_fmt, ses->ip_addr);
|
||||
ctx.UNC = unc;
|
||||
ctx.prepath = "";
|
||||
len = sizeof(unc_fmt) + SERVER_NAME_LEN_WITH_NULL;
|
||||
ctx->UNC = kzalloc(len, GFP_KERNEL);
|
||||
if (!ctx->UNC) {
|
||||
rc = -ENOMEM;
|
||||
goto out_free_ctx;
|
||||
}
|
||||
scnprintf(ctx->UNC, len, unc_fmt, ses->ip_addr);
|
||||
ctx->prepath = "";
|
||||
|
||||
/* Reuse same version as master connection */
|
||||
ctx.vals = ses->server->vals;
|
||||
ctx.ops = ses->server->ops;
|
||||
ctx->vals = ses->server->vals;
|
||||
ctx->ops = ses->server->ops;
|
||||
|
||||
ctx.noblocksnd = ses->server->noblocksnd;
|
||||
ctx.noautotune = ses->server->noautotune;
|
||||
ctx.sockopt_tcp_nodelay = ses->server->tcp_nodelay;
|
||||
ctx.echo_interval = ses->server->echo_interval / HZ;
|
||||
ctx.max_credits = ses->server->max_credits;
|
||||
ctx->noblocksnd = ses->server->noblocksnd;
|
||||
ctx->noautotune = ses->server->noautotune;
|
||||
ctx->sockopt_tcp_nodelay = ses->server->tcp_nodelay;
|
||||
ctx->echo_interval = ses->server->echo_interval / HZ;
|
||||
ctx->max_credits = ses->server->max_credits;
|
||||
|
||||
/*
|
||||
* This will be used for encoding/decoding user/domain/pw
|
||||
* during sess setup auth.
|
||||
*/
|
||||
ctx.local_nls = cifs_sb->local_nls;
|
||||
ctx->local_nls = cifs_sb->local_nls;
|
||||
|
||||
/* Use RDMA if possible */
|
||||
ctx.rdma = iface->rdma_capable;
|
||||
memcpy(&ctx.dstaddr, &iface->sockaddr, sizeof(struct sockaddr_storage));
|
||||
ctx->rdma = iface->rdma_capable;
|
||||
memcpy(&ctx->dstaddr, &iface->sockaddr, sizeof(ctx->dstaddr));
|
||||
|
||||
/* reuse master con client guid */
|
||||
memcpy(&ctx.client_guid, ses->server->client_guid,
|
||||
SMB2_CLIENT_GUID_SIZE);
|
||||
ctx.use_client_guid = true;
|
||||
memcpy(&ctx->client_guid, ses->server->client_guid,
|
||||
sizeof(ctx->client_guid));
|
||||
ctx->use_client_guid = true;
|
||||
|
||||
chan_server = cifs_get_tcp_session(&ctx, ses->server);
|
||||
chan_server = cifs_get_tcp_session(ctx, ses->server);
|
||||
|
||||
spin_lock(&ses->chan_lock);
|
||||
chan = &ses->chans[ses->chan_count];
|
||||
@ -497,6 +507,10 @@ cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
|
||||
cifs_put_tcp_session(chan->server, 0);
|
||||
}
|
||||
|
||||
kfree(ctx->UNC);
|
||||
out_free_ctx:
|
||||
kfree(ctx);
|
||||
out_free_xid:
|
||||
free_xid(xid);
|
||||
return rc;
|
||||
}
|
||||
|
@ -542,14 +542,17 @@ cifs_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int cifs_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb, const char *full_path,
|
||||
struct cifs_open_info_data *data, bool *adjustTZ, bool *symlink)
|
||||
static int cifs_query_path_info(const unsigned int xid,
|
||||
struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb,
|
||||
const char *full_path,
|
||||
struct cifs_open_info_data *data)
|
||||
{
|
||||
int rc;
|
||||
FILE_ALL_INFO fi = {};
|
||||
|
||||
*symlink = false;
|
||||
data->symlink = false;
|
||||
data->adjust_tz = false;
|
||||
|
||||
/* could do find first instead but this returns more info */
|
||||
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,
|
||||
if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
|
||||
rc = SMBQueryInformation(xid, tcon, full_path, &fi, cifs_sb->local_nls,
|
||||
cifs_remap(cifs_sb));
|
||||
*adjustTZ = true;
|
||||
data->adjust_tz = true;
|
||||
}
|
||||
|
||||
if (!rc) {
|
||||
@ -589,7 +592,7 @@ static int cifs_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
/* Need to check if this is a symbolic link or not */
|
||||
tmprc = CIFS_open(xid, &oparms, &oplock, NULL);
|
||||
if (tmprc == -EOPNOTSUPP)
|
||||
*symlink = true;
|
||||
data->symlink = true;
|
||||
else if (tmprc == 0)
|
||||
CIFSSMBClose(xid, tcon, fid.netfid);
|
||||
}
|
||||
@ -969,13 +972,16 @@ cifs_unix_dfs_readlink(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
cifs_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb, const char *full_path,
|
||||
char **target_path, bool is_reparse_point)
|
||||
static int cifs_query_symlink(const unsigned int xid,
|
||||
struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb,
|
||||
const char *full_path,
|
||||
char **target_path,
|
||||
struct kvec *rsp_iov)
|
||||
{
|
||||
int rc;
|
||||
int oplock = 0;
|
||||
bool is_reparse_point = !!rsp_iov;
|
||||
struct cifs_fid fid;
|
||||
struct cifs_open_parms oparms;
|
||||
|
||||
|
@ -35,34 +35,22 @@ free_set_inf_compound(struct smb_rqst *rqst)
|
||||
SMB2_close_free(&rqst[2]);
|
||||
}
|
||||
|
||||
|
||||
struct cop_vars {
|
||||
struct cifs_open_parms oparms;
|
||||
struct kvec rsp_iov[3];
|
||||
struct smb_rqst rqst[3];
|
||||
struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
|
||||
struct kvec qi_iov[1];
|
||||
struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE];
|
||||
struct kvec close_iov[1];
|
||||
struct smb2_file_rename_info rename_info;
|
||||
struct smb2_file_link_info link_info;
|
||||
};
|
||||
|
||||
/*
|
||||
* note: If cfile is passed, the reference to it is dropped here.
|
||||
* So make sure that you do not reuse cfile after return from this func.
|
||||
*
|
||||
* If passing @err_iov and @err_buftype, ensure to make them both large enough (>= 3) to hold all
|
||||
* error responses. Caller is also responsible for freeing them up.
|
||||
* If passing @out_iov and @out_buftype, ensure to make them both large enough
|
||||
* (>= 3) to hold all compounded responses. Caller is also responsible for
|
||||
* freeing them up with free_rsp_buf().
|
||||
*/
|
||||
static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb, const char *full_path,
|
||||
__u32 desired_access, __u32 create_disposition, __u32 create_options,
|
||||
umode_t mode, void *ptr, int command, struct cifsFileInfo *cfile,
|
||||
__u8 **extbuf, size_t *extbuflen,
|
||||
struct kvec *err_iov, int *err_buftype)
|
||||
struct kvec *out_iov, int *out_buftype)
|
||||
{
|
||||
struct cop_vars *vars = NULL;
|
||||
struct smb2_compound_vars *vars = NULL;
|
||||
struct kvec *rsp_iov;
|
||||
struct smb_rqst *rqst;
|
||||
int rc;
|
||||
@ -133,7 +121,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
/* Operation */
|
||||
switch (command) {
|
||||
case SMB2_OP_QUERY_INFO:
|
||||
rqst[num_rqst].rq_iov = &vars->qi_iov[0];
|
||||
rqst[num_rqst].rq_iov = &vars->qi_iov;
|
||||
rqst[num_rqst].rq_nvec = 1;
|
||||
|
||||
if (cfile)
|
||||
@ -167,7 +155,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
full_path);
|
||||
break;
|
||||
case SMB2_OP_POSIX_QUERY_INFO:
|
||||
rqst[num_rqst].rq_iov = &vars->qi_iov[0];
|
||||
rqst[num_rqst].rq_iov = &vars->qi_iov;
|
||||
rqst[num_rqst].rq_nvec = 1;
|
||||
|
||||
if (cfile)
|
||||
@ -375,7 +363,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
goto after_close;
|
||||
/* Close */
|
||||
flags |= CIFS_CP_CREATE_CLOSE_OP;
|
||||
rqst[num_rqst].rq_iov = &vars->close_iov[0];
|
||||
rqst[num_rqst].rq_iov = &vars->close_iov;
|
||||
rqst[num_rqst].rq_nvec = 1;
|
||||
rc = SMB2_close_init(tcon, server,
|
||||
&rqst[num_rqst], COMPOUND_FID,
|
||||
@ -529,9 +517,9 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
if (cfile)
|
||||
cifsFileInfo_put(cfile);
|
||||
|
||||
if (rc && err_iov && err_buftype) {
|
||||
memcpy(err_iov, rsp_iov, 3 * sizeof(*err_iov));
|
||||
memcpy(err_buftype, resp_buftype, 3 * sizeof(*err_buftype));
|
||||
if (out_iov && out_buftype) {
|
||||
memcpy(out_iov, rsp_iov, 3 * sizeof(*out_iov));
|
||||
memcpy(out_buftype, resp_buftype, 3 * sizeof(*out_buftype));
|
||||
} else {
|
||||
free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
|
||||
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,
|
||||
return rc;
|
||||
}
|
||||
|
||||
int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb, const char *full_path,
|
||||
struct cifs_open_info_data *data, bool *adjust_tz, bool *reparse)
|
||||
static int parse_create_response(struct cifs_open_info_data *data,
|
||||
struct cifs_sb_info *cifs_sb,
|
||||
const struct kvec *iov)
|
||||
{
|
||||
struct smb2_create_rsp *rsp = iov->iov_base;
|
||||
bool reparse_point = false;
|
||||
u32 tag = 0;
|
||||
int rc = 0;
|
||||
|
||||
switch (rsp->hdr.Status) {
|
||||
case STATUS_STOPPED_ON_SYMLINK:
|
||||
rc = smb2_parse_symlink_response(cifs_sb, iov,
|
||||
&data->symlink_target);
|
||||
if (rc)
|
||||
return rc;
|
||||
tag = IO_REPARSE_TAG_SYMLINK;
|
||||
reparse_point = true;
|
||||
break;
|
||||
case STATUS_SUCCESS:
|
||||
reparse_point = !!(rsp->Flags & SMB2_CREATE_FLAG_REPARSEPOINT);
|
||||
break;
|
||||
}
|
||||
data->reparse_point = reparse_point;
|
||||
data->reparse_tag = tag;
|
||||
return rc;
|
||||
}
|
||||
|
||||
int smb2_query_path_info(const unsigned int xid,
|
||||
struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb,
|
||||
const char *full_path,
|
||||
struct cifs_open_info_data *data)
|
||||
{
|
||||
__u32 create_options = 0;
|
||||
struct cifsFileInfo *cfile;
|
||||
struct cached_fid *cfid = NULL;
|
||||
struct kvec err_iov[3] = {};
|
||||
int err_buftype[3] = {};
|
||||
struct smb2_hdr *hdr;
|
||||
struct kvec out_iov[3] = {};
|
||||
int out_buftype[3] = {};
|
||||
bool islink;
|
||||
int rc, rc2;
|
||||
|
||||
*adjust_tz = false;
|
||||
*reparse = false;
|
||||
data->adjust_tz = false;
|
||||
data->reparse_point = false;
|
||||
|
||||
if (strcmp(full_path, ""))
|
||||
rc = -ENOENT;
|
||||
@ -575,69 +593,73 @@ int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
cifs_get_readable_path(tcon, full_path, &cfile);
|
||||
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES, FILE_OPEN,
|
||||
create_options, ACL_NO_MODE, data, SMB2_OP_QUERY_INFO, cfile,
|
||||
NULL, NULL, err_iov, err_buftype);
|
||||
if (rc) {
|
||||
struct smb2_hdr *hdr = err_iov[0].iov_base;
|
||||
NULL, NULL, out_iov, out_buftype);
|
||||
hdr = out_iov[0].iov_base;
|
||||
/*
|
||||
* If first iov is unset, then SMB session was dropped or we've got a
|
||||
* cached open file (@cfile).
|
||||
*/
|
||||
if (!hdr || out_buftype[0] == CIFS_NO_BUFFER)
|
||||
goto out;
|
||||
|
||||
if (unlikely(!hdr || err_buftype[0] == CIFS_NO_BUFFER))
|
||||
switch (rc) {
|
||||
case 0:
|
||||
case -EOPNOTSUPP:
|
||||
rc = parse_create_response(data, cifs_sb, &out_iov[0]);
|
||||
if (rc || !data->reparse_point)
|
||||
goto out;
|
||||
if (rc == -EOPNOTSUPP && hdr->Command == SMB2_CREATE &&
|
||||
hdr->Status == STATUS_STOPPED_ON_SYMLINK) {
|
||||
rc = smb2_parse_symlink_response(cifs_sb, err_iov,
|
||||
&data->symlink_target);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
*reparse = true;
|
||||
create_options |= OPEN_REPARSE_POINT;
|
||||
|
||||
/* Failed on a symbolic link - query a reparse point info */
|
||||
cifs_get_readable_path(tcon, full_path, &cfile);
|
||||
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
|
||||
FILE_READ_ATTRIBUTES, FILE_OPEN,
|
||||
create_options, ACL_NO_MODE, data,
|
||||
SMB2_OP_QUERY_INFO, cfile, NULL, NULL,
|
||||
NULL, NULL);
|
||||
create_options |= OPEN_REPARSE_POINT;
|
||||
/* Failed on a symbolic link - query a reparse point info */
|
||||
cifs_get_readable_path(tcon, full_path, &cfile);
|
||||
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
|
||||
FILE_READ_ATTRIBUTES, FILE_OPEN,
|
||||
create_options, ACL_NO_MODE, data,
|
||||
SMB2_OP_QUERY_INFO, cfile, NULL, NULL,
|
||||
NULL, NULL);
|
||||
break;
|
||||
case -EREMOTE:
|
||||
break;
|
||||
default:
|
||||
if (hdr->Status != STATUS_OBJECT_NAME_INVALID)
|
||||
break;
|
||||
rc2 = cifs_inval_name_dfs_link_error(xid, tcon, cifs_sb,
|
||||
full_path, &islink);
|
||||
if (rc2) {
|
||||
rc = rc2;
|
||||
goto out;
|
||||
} else if (rc != -EREMOTE && hdr->Status == STATUS_OBJECT_NAME_INVALID) {
|
||||
rc2 = cifs_inval_name_dfs_link_error(xid, tcon, cifs_sb,
|
||||
full_path, &islink);
|
||||
if (rc2) {
|
||||
rc = rc2;
|
||||
goto out;
|
||||
}
|
||||
if (islink)
|
||||
rc = -EREMOTE;
|
||||
}
|
||||
if (islink)
|
||||
rc = -EREMOTE;
|
||||
}
|
||||
|
||||
out:
|
||||
free_rsp_buf(err_buftype[0], err_iov[0].iov_base);
|
||||
free_rsp_buf(err_buftype[1], err_iov[1].iov_base);
|
||||
free_rsp_buf(err_buftype[2], err_iov[2].iov_base);
|
||||
free_rsp_buf(out_buftype[0], out_iov[0].iov_base);
|
||||
free_rsp_buf(out_buftype[1], out_iov[1].iov_base);
|
||||
free_rsp_buf(out_buftype[2], out_iov[2].iov_base);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb, const char *full_path,
|
||||
int smb311_posix_query_path_info(const unsigned int xid,
|
||||
struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb,
|
||||
const char *full_path,
|
||||
struct cifs_open_info_data *data,
|
||||
struct cifs_sid *owner,
|
||||
struct cifs_sid *group,
|
||||
bool *adjust_tz, bool *reparse)
|
||||
struct cifs_sid *group)
|
||||
{
|
||||
int rc;
|
||||
__u32 create_options = 0;
|
||||
struct cifsFileInfo *cfile;
|
||||
struct kvec err_iov[3] = {};
|
||||
int err_buftype[3] = {};
|
||||
struct kvec out_iov[3] = {};
|
||||
int out_buftype[3] = {};
|
||||
__u8 *sidsbuf = NULL;
|
||||
__u8 *sidsbuf_end = NULL;
|
||||
size_t sidsbuflen = 0;
|
||||
size_t owner_len, group_len;
|
||||
|
||||
*adjust_tz = false;
|
||||
*reparse = false;
|
||||
data->adjust_tz = false;
|
||||
data->reparse_point = false;
|
||||
|
||||
/*
|
||||
* 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,
|
||||
cifs_get_readable_path(tcon, full_path, &cfile);
|
||||
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES, FILE_OPEN,
|
||||
create_options, ACL_NO_MODE, data, SMB2_OP_POSIX_QUERY_INFO, cfile,
|
||||
&sidsbuf, &sidsbuflen, err_iov, err_buftype);
|
||||
if (rc == -EOPNOTSUPP) {
|
||||
/* BB TODO: When support for special files added to Samba re-verify this path */
|
||||
if (err_iov[0].iov_base && err_buftype[0] != CIFS_NO_BUFFER &&
|
||||
((struct smb2_hdr *)err_iov[0].iov_base)->Command == SMB2_CREATE &&
|
||||
((struct smb2_hdr *)err_iov[0].iov_base)->Status == STATUS_STOPPED_ON_SYMLINK) {
|
||||
rc = smb2_parse_symlink_response(cifs_sb, err_iov, &data->symlink_target);
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
*reparse = true;
|
||||
create_options |= OPEN_REPARSE_POINT;
|
||||
&sidsbuf, &sidsbuflen, out_iov, out_buftype);
|
||||
/*
|
||||
* If first iov is unset, then SMB session was dropped or we've got a
|
||||
* cached open file (@cfile).
|
||||
*/
|
||||
if (!out_iov[0].iov_base || out_buftype[0] == CIFS_NO_BUFFER)
|
||||
goto out;
|
||||
|
||||
switch (rc) {
|
||||
case 0:
|
||||
case -EOPNOTSUPP:
|
||||
/* BB TODO: When support for special files added to Samba re-verify this path */
|
||||
rc = parse_create_response(data, cifs_sb, &out_iov[0]);
|
||||
if (rc || !data->reparse_point)
|
||||
goto out;
|
||||
|
||||
create_options |= OPEN_REPARSE_POINT;
|
||||
/* Failed on a symbolic link - query a reparse point info */
|
||||
cifs_get_readable_path(tcon, full_path, &cfile);
|
||||
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES,
|
||||
FILE_OPEN, create_options, ACL_NO_MODE, data,
|
||||
SMB2_OP_POSIX_QUERY_INFO, cfile,
|
||||
&sidsbuf, &sidsbuflen, NULL, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
if (rc == 0) {
|
||||
sidsbuf_end = sidsbuf + sidsbuflen;
|
||||
|
||||
@ -689,11 +717,10 @@ int smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
memcpy(group, sidsbuf + owner_len, group_len);
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(sidsbuf);
|
||||
free_rsp_buf(err_buftype[0], err_iov[0].iov_base);
|
||||
free_rsp_buf(err_buftype[1], err_iov[1].iov_base);
|
||||
free_rsp_buf(err_buftype[2], err_iov[2].iov_base);
|
||||
free_rsp_buf(out_buftype[0], out_iov[0].iov_base);
|
||||
free_rsp_buf(out_buftype[1], out_iov[1].iov_base);
|
||||
free_rsp_buf(out_buftype[2], out_iov[2].iov_base);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -145,7 +145,7 @@ smb2_check_message(char *buf, unsigned int len, struct TCP_Server_Info *server)
|
||||
__u64 mid;
|
||||
|
||||
/* If server is a channel, select the primary channel */
|
||||
pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
|
||||
pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
|
||||
|
||||
/*
|
||||
* 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)
|
||||
cifs_dbg(FYI, "Checking for lease break\n");
|
||||
|
||||
/* If server is a channel, select the primary channel */
|
||||
pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
|
||||
pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
|
||||
|
||||
/* look up tcon based on tid & uid */
|
||||
spin_lock(&cifs_tcp_ses_lock);
|
||||
@ -698,7 +698,7 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
|
||||
cifs_dbg(FYI, "oplock level 0x%x\n", rsp->OplockLevel);
|
||||
|
||||
/* If server is a channel, select the primary channel */
|
||||
pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
|
||||
pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
|
||||
|
||||
/* look up tcon based on tid & uid */
|
||||
spin_lock(&cifs_tcp_ses_lock);
|
||||
|
@ -172,8 +172,17 @@ smb2_set_credits(struct TCP_Server_Info *server, const int val)
|
||||
|
||||
spin_lock(&server->req_lock);
|
||||
server->credits = val;
|
||||
if (val == 1)
|
||||
if (val == 1) {
|
||||
server->reconnect_instance++;
|
||||
/*
|
||||
* ChannelSequence updated for all channels in primary channel so that consistent
|
||||
* across SMB3 requests sent on any channel. See MS-SMB2 3.2.4.1 and 3.2.7.1
|
||||
*/
|
||||
if (SERVER_IS_CHAN(server))
|
||||
server->primary_server->channel_sequence_num++;
|
||||
else
|
||||
server->channel_sequence_num++;
|
||||
}
|
||||
scredits = server->credits;
|
||||
in_flight = server->in_flight;
|
||||
spin_unlock(&server->req_lock);
|
||||
@ -1075,31 +1084,28 @@ smb2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
const char *path, const char *ea_name, const void *ea_value,
|
||||
const __u16 ea_value_len, const struct nls_table *nls_codepage,
|
||||
struct cifs_sb_info *cifs_sb)
|
||||
{
|
||||
struct smb2_compound_vars *vars;
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
struct TCP_Server_Info *server = cifs_pick_channel(ses);
|
||||
struct smb_rqst *rqst;
|
||||
struct kvec *rsp_iov;
|
||||
__le16 *utf16_path = NULL;
|
||||
int ea_name_len = strlen(ea_name);
|
||||
int flags = CIFS_CP_CREATE_CLOSE_OP;
|
||||
int len;
|
||||
struct smb_rqst rqst[3];
|
||||
int resp_buftype[3];
|
||||
struct kvec rsp_iov[3];
|
||||
struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
|
||||
struct cifs_open_parms oparms;
|
||||
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
||||
struct cifs_fid fid;
|
||||
struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE];
|
||||
unsigned int size[1];
|
||||
void *data[1];
|
||||
struct smb2_file_full_ea_info *ea = NULL;
|
||||
struct kvec close_iov[1];
|
||||
struct smb2_query_info_rsp *rsp;
|
||||
int rc, used_len = 0;
|
||||
|
||||
@ -1113,9 +1119,14 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
if (!utf16_path)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(rqst, 0, sizeof(rqst));
|
||||
resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
|
||||
memset(rsp_iov, 0, sizeof(rsp_iov));
|
||||
vars = kzalloc(sizeof(*vars), GFP_KERNEL);
|
||||
if (!vars) {
|
||||
rc = -ENOMEM;
|
||||
goto out_free_path;
|
||||
}
|
||||
rqst = vars->rqst;
|
||||
rsp_iov = vars->rsp_iov;
|
||||
|
||||
if (ses->server->ops->query_all_EAs) {
|
||||
if (!ea_value) {
|
||||
@ -1160,8 +1171,7 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
}
|
||||
|
||||
/* Open */
|
||||
memset(&open_iov, 0, sizeof(open_iov));
|
||||
rqst[0].rq_iov = open_iov;
|
||||
rqst[0].rq_iov = vars->open_iov;
|
||||
rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
|
||||
|
||||
oparms = (struct cifs_open_parms) {
|
||||
@ -1181,8 +1191,7 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
|
||||
|
||||
/* Set Info */
|
||||
memset(&si_iov, 0, sizeof(si_iov));
|
||||
rqst[1].rq_iov = si_iov;
|
||||
rqst[1].rq_iov = vars->si_iov;
|
||||
rqst[1].rq_nvec = 1;
|
||||
|
||||
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,
|
||||
smb2_set_next_command(tcon, &rqst[1]);
|
||||
smb2_set_related(&rqst[1]);
|
||||
|
||||
|
||||
/* Close */
|
||||
memset(&close_iov, 0, sizeof(close_iov));
|
||||
rqst[2].rq_iov = close_iov;
|
||||
rqst[2].rq_iov = &vars->close_iov;
|
||||
rqst[2].rq_nvec = 1;
|
||||
rc = SMB2_close_init(tcon, server,
|
||||
&rqst[2], COMPOUND_FID, COMPOUND_FID, false);
|
||||
@ -1228,13 +1235,15 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
|
||||
sea_exit:
|
||||
kfree(ea);
|
||||
kfree(utf16_path);
|
||||
SMB2_open_free(&rqst[0]);
|
||||
SMB2_set_info_free(&rqst[1]);
|
||||
SMB2_close_free(&rqst[2]);
|
||||
free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
|
||||
free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
|
||||
free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
|
||||
kfree(vars);
|
||||
out_free_path:
|
||||
kfree(utf16_path);
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
@ -1446,16 +1455,6 @@ SMB2_request_res_key(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
return rc;
|
||||
}
|
||||
|
||||
struct iqi_vars {
|
||||
struct smb_rqst rqst[3];
|
||||
struct kvec rsp_iov[3];
|
||||
struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
|
||||
struct kvec qi_iov[1];
|
||||
struct kvec io_iov[SMB2_IOCTL_IOV_SIZE];
|
||||
struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE];
|
||||
struct kvec close_iov[1];
|
||||
};
|
||||
|
||||
static int
|
||||
smb2_ioctl_query_info(const unsigned int xid,
|
||||
struct cifs_tcon *tcon,
|
||||
@ -1463,7 +1462,7 @@ smb2_ioctl_query_info(const unsigned int xid,
|
||||
__le16 *path, int is_dir,
|
||||
unsigned long p)
|
||||
{
|
||||
struct iqi_vars *vars;
|
||||
struct smb2_compound_vars *vars;
|
||||
struct smb_rqst *rqst;
|
||||
struct kvec *rsp_iov;
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
@ -1581,7 +1580,7 @@ smb2_ioctl_query_info(const unsigned int xid,
|
||||
rc = -EINVAL;
|
||||
goto free_open_req;
|
||||
}
|
||||
rqst[1].rq_iov = &vars->si_iov[0];
|
||||
rqst[1].rq_iov = vars->si_iov;
|
||||
rqst[1].rq_nvec = 1;
|
||||
|
||||
/* MS-FSCC 2.4.13 FileEndOfFileInformation */
|
||||
@ -1593,7 +1592,7 @@ smb2_ioctl_query_info(const unsigned int xid,
|
||||
SMB2_O_INFO_FILE, 0, data, size);
|
||||
free_req1_func = SMB2_set_info_free;
|
||||
} else if (qi.flags == PASSTHRU_QUERY_INFO) {
|
||||
rqst[1].rq_iov = &vars->qi_iov[0];
|
||||
rqst[1].rq_iov = &vars->qi_iov;
|
||||
rqst[1].rq_nvec = 1;
|
||||
|
||||
rc = SMB2_query_info_init(tcon, server,
|
||||
@ -1615,7 +1614,7 @@ smb2_ioctl_query_info(const unsigned int xid,
|
||||
smb2_set_related(&rqst[1]);
|
||||
|
||||
/* Close */
|
||||
rqst[2].rq_iov = &vars->close_iov[0];
|
||||
rqst[2].rq_iov = &vars->close_iov;
|
||||
rqst[2].rq_nvec = 1;
|
||||
|
||||
rc = SMB2_close_init(tcon, server,
|
||||
@ -2408,7 +2407,7 @@ smb2_is_network_name_deleted(char *buf, struct TCP_Server_Info *server)
|
||||
return false;
|
||||
|
||||
/* If server is a channel, select the primary channel */
|
||||
pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
|
||||
pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
|
||||
|
||||
spin_lock(&cifs_tcp_ses_lock);
|
||||
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,
|
||||
struct kvec *rsp, int *buftype,
|
||||
struct cifs_sb_info *cifs_sb)
|
||||
{
|
||||
struct smb2_compound_vars *vars;
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
struct TCP_Server_Info *server = cifs_pick_channel(ses);
|
||||
int flags = CIFS_CP_CREATE_CLOSE_OP;
|
||||
struct smb_rqst rqst[3];
|
||||
struct smb_rqst *rqst;
|
||||
int resp_buftype[3];
|
||||
struct kvec rsp_iov[3];
|
||||
struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
|
||||
struct kvec qi_iov[1];
|
||||
struct kvec close_iov[1];
|
||||
struct kvec *rsp_iov;
|
||||
u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
||||
struct cifs_open_parms oparms;
|
||||
struct cifs_fid fid;
|
||||
@ -2549,9 +2546,14 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
||||
memset(rqst, 0, sizeof(rqst));
|
||||
resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
|
||||
memset(rsp_iov, 0, sizeof(rsp_iov));
|
||||
vars = kzalloc(sizeof(*vars), GFP_KERNEL);
|
||||
if (!vars) {
|
||||
rc = -ENOMEM;
|
||||
goto out_free_path;
|
||||
}
|
||||
rqst = vars->rqst;
|
||||
rsp_iov = vars->rsp_iov;
|
||||
|
||||
/*
|
||||
* 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,
|
||||
open_cached_dir(xid, tcon, path, cifs_sb, false,
|
||||
&cfid); /* cfid null if open dir failed */
|
||||
|
||||
memset(&open_iov, 0, sizeof(open_iov));
|
||||
rqst[0].rq_iov = open_iov;
|
||||
rqst[0].rq_iov = vars->open_iov;
|
||||
rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
|
||||
|
||||
oparms = (struct cifs_open_parms) {
|
||||
@ -2579,8 +2580,7 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
goto qic_exit;
|
||||
smb2_set_next_command(tcon, &rqst[0]);
|
||||
|
||||
memset(&qi_iov, 0, sizeof(qi_iov));
|
||||
rqst[1].rq_iov = qi_iov;
|
||||
rqst[1].rq_iov = &vars->qi_iov;
|
||||
rqst[1].rq_nvec = 1;
|
||||
|
||||
if (cfid) {
|
||||
@ -2607,8 +2607,7 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
smb2_set_related(&rqst[1]);
|
||||
}
|
||||
|
||||
memset(&close_iov, 0, sizeof(close_iov));
|
||||
rqst[2].rq_iov = close_iov;
|
||||
rqst[2].rq_iov = &vars->close_iov;
|
||||
rqst[2].rq_nvec = 1;
|
||||
|
||||
rc = SMB2_close_init(tcon, server,
|
||||
@ -2639,7 +2638,6 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
*buftype = resp_buftype[1];
|
||||
|
||||
qic_exit:
|
||||
kfree(utf16_path);
|
||||
SMB2_open_free(&rqst[0]);
|
||||
SMB2_query_info_free(&rqst[1]);
|
||||
SMB2_close_free(&rqst[2]);
|
||||
@ -2647,6 +2645,9 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
|
||||
if (cfid)
|
||||
close_cached_dir(cfid);
|
||||
kfree(vars);
|
||||
out_free_path:
|
||||
kfree(utf16_path);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -2949,154 +2950,32 @@ parse_reparse_point(struct reparse_data_buffer *buf,
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb, const char *full_path,
|
||||
char **target_path, bool is_reparse_point)
|
||||
static int smb2_query_symlink(const unsigned int xid,
|
||||
struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb,
|
||||
const char *full_path,
|
||||
char **target_path,
|
||||
struct kvec *rsp_iov)
|
||||
{
|
||||
int rc;
|
||||
__le16 *utf16_path = NULL;
|
||||
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
||||
struct cifs_open_parms oparms;
|
||||
struct cifs_fid fid;
|
||||
struct kvec err_iov = {NULL, 0};
|
||||
struct TCP_Server_Info *server = cifs_pick_channel(tcon->ses);
|
||||
int flags = CIFS_CP_CREATE_CLOSE_OP;
|
||||
struct smb_rqst rqst[3];
|
||||
int resp_buftype[3];
|
||||
struct kvec rsp_iov[3];
|
||||
struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
|
||||
struct kvec io_iov[SMB2_IOCTL_IOV_SIZE];
|
||||
struct kvec close_iov[1];
|
||||
struct smb2_create_rsp *create_rsp;
|
||||
struct smb2_ioctl_rsp *ioctl_rsp;
|
||||
struct reparse_data_buffer *reparse_buf;
|
||||
int create_options = is_reparse_point ? OPEN_REPARSE_POINT : 0;
|
||||
u32 plen;
|
||||
struct reparse_data_buffer *buf;
|
||||
struct smb2_ioctl_rsp *io = rsp_iov->iov_base;
|
||||
u32 plen = le32_to_cpu(io->OutputCount);
|
||||
|
||||
cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
|
||||
|
||||
*target_path = NULL;
|
||||
|
||||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
||||
memset(rqst, 0, sizeof(rqst));
|
||||
resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
|
||||
memset(rsp_iov, 0, sizeof(rsp_iov));
|
||||
|
||||
utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
|
||||
if (!utf16_path)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Open */
|
||||
memset(&open_iov, 0, sizeof(open_iov));
|
||||
rqst[0].rq_iov = open_iov;
|
||||
rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
|
||||
|
||||
oparms = (struct cifs_open_parms) {
|
||||
.tcon = tcon,
|
||||
.path = full_path,
|
||||
.desired_access = FILE_READ_ATTRIBUTES,
|
||||
.disposition = FILE_OPEN,
|
||||
.create_options = cifs_create_options(cifs_sb, create_options),
|
||||
.fid = &fid,
|
||||
};
|
||||
|
||||
rc = SMB2_open_init(tcon, server,
|
||||
&rqst[0], &oplock, &oparms, utf16_path);
|
||||
if (rc)
|
||||
goto querty_exit;
|
||||
smb2_set_next_command(tcon, &rqst[0]);
|
||||
|
||||
|
||||
/* IOCTL */
|
||||
memset(&io_iov, 0, sizeof(io_iov));
|
||||
rqst[1].rq_iov = io_iov;
|
||||
rqst[1].rq_nvec = SMB2_IOCTL_IOV_SIZE;
|
||||
|
||||
rc = SMB2_ioctl_init(tcon, server,
|
||||
&rqst[1], fid.persistent_fid,
|
||||
fid.volatile_fid, FSCTL_GET_REPARSE_POINT, NULL, 0,
|
||||
CIFSMaxBufSize -
|
||||
MAX_SMB2_CREATE_RESPONSE_SIZE -
|
||||
MAX_SMB2_CLOSE_RESPONSE_SIZE);
|
||||
if (rc)
|
||||
goto querty_exit;
|
||||
|
||||
smb2_set_next_command(tcon, &rqst[1]);
|
||||
smb2_set_related(&rqst[1]);
|
||||
|
||||
|
||||
/* Close */
|
||||
memset(&close_iov, 0, sizeof(close_iov));
|
||||
rqst[2].rq_iov = close_iov;
|
||||
rqst[2].rq_nvec = 1;
|
||||
|
||||
rc = SMB2_close_init(tcon, server,
|
||||
&rqst[2], COMPOUND_FID, COMPOUND_FID, false);
|
||||
if (rc)
|
||||
goto querty_exit;
|
||||
|
||||
smb2_set_related(&rqst[2]);
|
||||
|
||||
rc = compound_send_recv(xid, tcon->ses, server,
|
||||
flags, 3, rqst,
|
||||
resp_buftype, rsp_iov);
|
||||
|
||||
create_rsp = rsp_iov[0].iov_base;
|
||||
if (create_rsp && create_rsp->hdr.Status)
|
||||
err_iov = rsp_iov[0];
|
||||
ioctl_rsp = rsp_iov[1].iov_base;
|
||||
|
||||
/*
|
||||
* Open was successful and we got an ioctl response.
|
||||
*/
|
||||
if ((rc == 0) && (is_reparse_point)) {
|
||||
/* See MS-FSCC 2.3.23 */
|
||||
|
||||
reparse_buf = (struct reparse_data_buffer *)
|
||||
((char *)ioctl_rsp +
|
||||
le32_to_cpu(ioctl_rsp->OutputOffset));
|
||||
plen = le32_to_cpu(ioctl_rsp->OutputCount);
|
||||
|
||||
if (plen + le32_to_cpu(ioctl_rsp->OutputOffset) >
|
||||
rsp_iov[1].iov_len) {
|
||||
cifs_tcon_dbg(VFS, "srv returned invalid ioctl len: %d\n",
|
||||
plen);
|
||||
rc = -EIO;
|
||||
goto querty_exit;
|
||||
}
|
||||
|
||||
rc = parse_reparse_point(reparse_buf, plen, target_path,
|
||||
cifs_sb);
|
||||
goto querty_exit;
|
||||
}
|
||||
|
||||
if (!rc || !err_iov.iov_base) {
|
||||
rc = -ENOENT;
|
||||
goto querty_exit;
|
||||
}
|
||||
|
||||
rc = smb2_parse_symlink_response(cifs_sb, &err_iov, target_path);
|
||||
|
||||
querty_exit:
|
||||
cifs_dbg(FYI, "query symlink rc %d\n", rc);
|
||||
kfree(utf16_path);
|
||||
SMB2_open_free(&rqst[0]);
|
||||
SMB2_ioctl_free(&rqst[1]);
|
||||
SMB2_close_free(&rqst[2]);
|
||||
free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
|
||||
free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
|
||||
free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
|
||||
return rc;
|
||||
buf = (struct reparse_data_buffer *)((u8 *)io +
|
||||
le32_to_cpu(io->OutputOffset));
|
||||
return parse_reparse_point(buf, plen, target_path, cifs_sb);
|
||||
}
|
||||
|
||||
int
|
||||
smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb, const char *full_path,
|
||||
__u32 *tag)
|
||||
static int smb2_query_reparse_point(const unsigned int xid,
|
||||
struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb,
|
||||
const char *full_path,
|
||||
u32 *tag, struct kvec *rsp,
|
||||
int *rsp_buftype)
|
||||
{
|
||||
struct smb2_compound_vars *vars;
|
||||
int rc;
|
||||
__le16 *utf16_path = NULL;
|
||||
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
||||
@ -3104,12 +2983,9 @@ smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifs_fid fid;
|
||||
struct TCP_Server_Info *server = cifs_pick_channel(tcon->ses);
|
||||
int flags = CIFS_CP_CREATE_CLOSE_OP;
|
||||
struct smb_rqst rqst[3];
|
||||
struct smb_rqst *rqst;
|
||||
int resp_buftype[3];
|
||||
struct kvec rsp_iov[3];
|
||||
struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
|
||||
struct kvec io_iov[SMB2_IOCTL_IOV_SIZE];
|
||||
struct kvec close_iov[1];
|
||||
struct kvec *rsp_iov;
|
||||
struct smb2_ioctl_rsp *ioctl_rsp;
|
||||
struct reparse_data_buffer *reparse_buf;
|
||||
u32 plen;
|
||||
@ -3119,20 +2995,24 @@ smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
||||
memset(rqst, 0, sizeof(rqst));
|
||||
resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
|
||||
memset(rsp_iov, 0, sizeof(rsp_iov));
|
||||
|
||||
utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
|
||||
if (!utf16_path)
|
||||
return -ENOMEM;
|
||||
|
||||
resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
|
||||
vars = kzalloc(sizeof(*vars), GFP_KERNEL);
|
||||
if (!vars) {
|
||||
rc = -ENOMEM;
|
||||
goto out_free_path;
|
||||
}
|
||||
rqst = vars->rqst;
|
||||
rsp_iov = vars->rsp_iov;
|
||||
|
||||
/*
|
||||
* setup smb2open - TODO add optimization to call cifs_get_readable_path
|
||||
* to see if there is a handle already open that we can use
|
||||
*/
|
||||
memset(&open_iov, 0, sizeof(open_iov));
|
||||
rqst[0].rq_iov = open_iov;
|
||||
rqst[0].rq_iov = vars->open_iov;
|
||||
rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
|
||||
|
||||
oparms = (struct cifs_open_parms) {
|
||||
@ -3152,8 +3032,7 @@ smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
|
||||
|
||||
/* IOCTL */
|
||||
memset(&io_iov, 0, sizeof(io_iov));
|
||||
rqst[1].rq_iov = io_iov;
|
||||
rqst[1].rq_iov = vars->io_iov;
|
||||
rqst[1].rq_nvec = SMB2_IOCTL_IOV_SIZE;
|
||||
|
||||
rc = SMB2_ioctl_init(tcon, server,
|
||||
@ -3168,10 +3047,8 @@ smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
smb2_set_next_command(tcon, &rqst[1]);
|
||||
smb2_set_related(&rqst[1]);
|
||||
|
||||
|
||||
/* Close */
|
||||
memset(&close_iov, 0, sizeof(close_iov));
|
||||
rqst[2].rq_iov = close_iov;
|
||||
rqst[2].rq_iov = &vars->close_iov;
|
||||
rqst[2].rq_nvec = 1;
|
||||
|
||||
rc = SMB2_close_init(tcon, server,
|
||||
@ -3206,16 +3083,21 @@ smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
goto query_rp_exit;
|
||||
}
|
||||
*tag = le32_to_cpu(reparse_buf->ReparseTag);
|
||||
*rsp = rsp_iov[1];
|
||||
*rsp_buftype = resp_buftype[1];
|
||||
resp_buftype[1] = CIFS_NO_BUFFER;
|
||||
}
|
||||
|
||||
query_rp_exit:
|
||||
kfree(utf16_path);
|
||||
SMB2_open_free(&rqst[0]);
|
||||
SMB2_ioctl_free(&rqst[1]);
|
||||
SMB2_close_free(&rqst[2]);
|
||||
free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
|
||||
free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
|
||||
free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
|
||||
kfree(vars);
|
||||
out_free_path:
|
||||
kfree(utf16_path);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -4401,7 +4283,7 @@ smb2_get_enc_key(struct TCP_Server_Info *server, __u64 ses_id, int enc, u8 *key)
|
||||
u8 *ses_enc_key;
|
||||
|
||||
/* If server is a channel, select the primary channel */
|
||||
pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
|
||||
pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
|
||||
|
||||
spin_lock(&cifs_tcp_ses_lock);
|
||||
list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
|
||||
@ -5299,6 +5181,7 @@ struct smb_version_operations smb20_operations = {
|
||||
.can_echo = smb2_can_echo,
|
||||
.echo = SMB2_echo,
|
||||
.query_path_info = smb2_query_path_info,
|
||||
.query_reparse_point = smb2_query_reparse_point,
|
||||
.get_srv_inum = smb2_get_srv_inum,
|
||||
.query_file_info = smb2_query_file_info,
|
||||
.set_path_size = smb2_set_path_size,
|
||||
@ -5400,6 +5283,7 @@ struct smb_version_operations smb21_operations = {
|
||||
.can_echo = smb2_can_echo,
|
||||
.echo = SMB2_echo,
|
||||
.query_path_info = smb2_query_path_info,
|
||||
.query_reparse_point = smb2_query_reparse_point,
|
||||
.get_srv_inum = smb2_get_srv_inum,
|
||||
.query_file_info = smb2_query_file_info,
|
||||
.set_path_size = smb2_set_path_size,
|
||||
@ -5504,7 +5388,7 @@ struct smb_version_operations smb30_operations = {
|
||||
.echo = SMB2_echo,
|
||||
.query_path_info = smb2_query_path_info,
|
||||
/* WSL tags introduced long after smb2.1, enable for SMB3, 3.11 only */
|
||||
.query_reparse_tag = smb2_query_reparse_tag,
|
||||
.query_reparse_point = smb2_query_reparse_point,
|
||||
.get_srv_inum = smb2_get_srv_inum,
|
||||
.query_file_info = smb2_query_file_info,
|
||||
.set_path_size = smb2_set_path_size,
|
||||
@ -5617,7 +5501,7 @@ struct smb_version_operations smb311_operations = {
|
||||
.can_echo = smb2_can_echo,
|
||||
.echo = SMB2_echo,
|
||||
.query_path_info = smb2_query_path_info,
|
||||
.query_reparse_tag = smb2_query_reparse_tag,
|
||||
.query_reparse_point = smb2_query_reparse_point,
|
||||
.get_srv_inum = smb2_get_srv_inum,
|
||||
.query_file_info = smb2_query_file_info,
|
||||
.set_path_size = smb2_set_path_size,
|
||||
|
@ -88,9 +88,20 @@ smb2_hdr_assemble(struct smb2_hdr *shdr, __le16 smb2_cmd,
|
||||
const struct cifs_tcon *tcon,
|
||||
struct TCP_Server_Info *server)
|
||||
{
|
||||
struct smb3_hdr_req *smb3_hdr;
|
||||
shdr->ProtocolId = SMB2_PROTO_NUMBER;
|
||||
shdr->StructureSize = cpu_to_le16(64);
|
||||
shdr->Command = smb2_cmd;
|
||||
if (server->dialect >= SMB30_PROT_ID) {
|
||||
/* After reconnect SMB3 must set ChannelSequence on subsequent reqs */
|
||||
smb3_hdr = (struct smb3_hdr_req *)shdr;
|
||||
/* if primary channel is not set yet, use default channel for chan sequence num */
|
||||
if (SERVER_IS_CHAN(server))
|
||||
smb3_hdr->ChannelSequence =
|
||||
cpu_to_le16(server->primary_server->channel_sequence_num);
|
||||
else
|
||||
smb3_hdr->ChannelSequence = cpu_to_le16(server->channel_sequence_num);
|
||||
}
|
||||
if (server) {
|
||||
spin_lock(&server->req_lock);
|
||||
/* Request up to 10 credits but don't go over the limit. */
|
||||
@ -553,7 +564,7 @@ assemble_neg_contexts(struct smb2_negotiate_req *req,
|
||||
* secondary channels don't have the hostname field populated
|
||||
* use the hostname field in the primary channel instead
|
||||
*/
|
||||
pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
|
||||
pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
|
||||
cifs_server_lock(pserver);
|
||||
hostname = pserver->hostname;
|
||||
if (hostname && (hostname[0] != 0)) {
|
||||
@ -2570,8 +2581,8 @@ alloc_path_with_tree_prefix(__le16 **out_path, int *out_size, int *out_len,
|
||||
|
||||
/* Do not append the separator if the path is empty */
|
||||
if (path[0] != cpu_to_le16(0x0000)) {
|
||||
UniStrcat(*out_path, sep);
|
||||
UniStrcat(*out_path, path);
|
||||
UniStrcat((wchar_t *)*out_path, (wchar_t *)sep);
|
||||
UniStrcat((wchar_t *)*out_path, (wchar_t *)path);
|
||||
}
|
||||
|
||||
unload_nls(cp);
|
||||
@ -3785,7 +3796,7 @@ void smb2_reconnect_server(struct work_struct *work)
|
||||
bool resched = false;
|
||||
|
||||
/* If server is a channel, select the primary channel */
|
||||
pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
|
||||
pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
|
||||
|
||||
/* Prevent simultaneous reconnects that can corrupt tcon->rlist list */
|
||||
mutex_lock(&pserver->reconnect_mutex);
|
||||
|
@ -56,9 +56,11 @@ extern int smb3_handle_read_data(struct TCP_Server_Info *server,
|
||||
extern int smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb, const char *path,
|
||||
__u32 *reparse_tag);
|
||||
int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb, const char *full_path,
|
||||
struct cifs_open_info_data *data, bool *adjust_tz, bool *reparse);
|
||||
int smb2_query_path_info(const unsigned int xid,
|
||||
struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb,
|
||||
const char *full_path,
|
||||
struct cifs_open_info_data *data);
|
||||
extern int smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
const char *full_path, __u64 size,
|
||||
struct cifs_sb_info *cifs_sb, bool set_alloc);
|
||||
@ -275,12 +277,13 @@ extern int smb2_query_info_compound(const unsigned int xid,
|
||||
struct kvec *rsp, int *buftype,
|
||||
struct cifs_sb_info *cifs_sb);
|
||||
/* query path info from the server using SMB311 POSIX extensions*/
|
||||
int smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb, const char *full_path,
|
||||
int smb311_posix_query_path_info(const unsigned int xid,
|
||||
struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb,
|
||||
const char *full_path,
|
||||
struct cifs_open_info_data *data,
|
||||
struct cifs_sid *owner,
|
||||
struct cifs_sid *group,
|
||||
bool *adjust_tz, bool *reparse);
|
||||
struct cifs_sid *group);
|
||||
int posix_info_parse(const void *beg, const void *end,
|
||||
struct smb2_posix_info_parsed *out);
|
||||
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)
|
||||
spin_lock(&cifs_tcp_ses_lock);
|
||||
|
||||
/* If server is a channel, select the primary channel */
|
||||
pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
|
||||
pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
|
||||
|
||||
list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
|
||||
if (ses->Suid == ses_id)
|
||||
@ -149,7 +149,7 @@ smb2_find_smb_ses_unlocked(struct TCP_Server_Info *server, __u64 ses_id)
|
||||
struct cifs_ses *ses;
|
||||
|
||||
/* If server is a channel, select the primary channel */
|
||||
pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
|
||||
pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
|
||||
|
||||
list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
|
||||
if (ses->Suid != ses_id)
|
||||
|
@ -416,13 +416,19 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
|
||||
return rc;
|
||||
}
|
||||
|
||||
struct send_req_vars {
|
||||
struct smb2_transform_hdr tr_hdr;
|
||||
struct smb_rqst rqst[MAX_COMPOUND];
|
||||
struct kvec iov;
|
||||
};
|
||||
|
||||
static int
|
||||
smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
|
||||
struct smb_rqst *rqst, int flags)
|
||||
{
|
||||
struct kvec iov;
|
||||
struct smb2_transform_hdr *tr_hdr;
|
||||
struct smb_rqst cur_rqst[MAX_COMPOUND];
|
||||
struct send_req_vars *vars;
|
||||
struct smb_rqst *cur_rqst;
|
||||
struct kvec *iov;
|
||||
int rc;
|
||||
|
||||
if (!(flags & CIFS_TRANSFORM_REQ))
|
||||
@ -436,16 +442,15 @@ smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
tr_hdr = kzalloc(sizeof(*tr_hdr), GFP_NOFS);
|
||||
if (!tr_hdr)
|
||||
vars = kzalloc(sizeof(*vars), GFP_NOFS);
|
||||
if (!vars)
|
||||
return -ENOMEM;
|
||||
cur_rqst = vars->rqst;
|
||||
iov = &vars->iov;
|
||||
|
||||
memset(&cur_rqst[0], 0, sizeof(cur_rqst));
|
||||
memset(&iov, 0, sizeof(iov));
|
||||
|
||||
iov.iov_base = tr_hdr;
|
||||
iov.iov_len = sizeof(*tr_hdr);
|
||||
cur_rqst[0].rq_iov = &iov;
|
||||
iov->iov_base = &vars->tr_hdr;
|
||||
iov->iov_len = sizeof(vars->tr_hdr);
|
||||
cur_rqst[0].rq_iov = iov;
|
||||
cur_rqst[0].rq_nvec = 1;
|
||||
|
||||
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,
|
||||
rc = __smb_send_rqst(server, num_rqst + 1, &cur_rqst[0]);
|
||||
smb3_free_compound_rqst(num_rqst, &cur_rqst[1]);
|
||||
out:
|
||||
kfree(tr_hdr);
|
||||
kfree(vars);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -153,6 +153,28 @@ struct smb2_hdr {
|
||||
__u8 Signature[16];
|
||||
} __packed;
|
||||
|
||||
struct smb3_hdr_req {
|
||||
__le32 ProtocolId; /* 0xFE 'S' 'M' 'B' */
|
||||
__le16 StructureSize; /* 64 */
|
||||
__le16 CreditCharge; /* MBZ */
|
||||
__le16 ChannelSequence; /* See MS-SMB2 3.2.4.1 and 3.2.7.1 */
|
||||
__le16 Reserved;
|
||||
__le16 Command;
|
||||
__le16 CreditRequest; /* CreditResponse */
|
||||
__le32 Flags;
|
||||
__le32 NextCommand;
|
||||
__le64 MessageId;
|
||||
union {
|
||||
struct {
|
||||
__le32 ProcessId;
|
||||
__le32 TreeId;
|
||||
} __packed SyncId;
|
||||
__le64 AsyncId;
|
||||
} __packed Id;
|
||||
__le64 SessionId;
|
||||
__u8 Signature[16];
|
||||
} __packed;
|
||||
|
||||
struct smb2_pdu {
|
||||
struct smb2_hdr hdr;
|
||||
__le16 StructureSize2; /* size of wct area (varies, request specific) */
|
||||
|
@ -5,6 +5,7 @@ config SMB_SERVER
|
||||
depends on FILE_LOCKING
|
||||
select NLS
|
||||
select NLS_UTF8
|
||||
select NLS_UCS2_UTILS
|
||||
select CRYPTO
|
||||
select CRYPTO_MD5
|
||||
select CRYPTO_HMAC
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include <asm/unaligned.h>
|
||||
#include "glob.h"
|
||||
#include "unicode.h"
|
||||
#include "uniupr.h"
|
||||
#include "smb_common.h"
|
||||
|
||||
/*
|
||||
|
@ -18,49 +18,14 @@
|
||||
* This is a compressed table of upper and lower case conversion.
|
||||
*
|
||||
*/
|
||||
#ifndef _CIFS_UNICODE_H
|
||||
#define _CIFS_UNICODE_H
|
||||
#ifndef _SMB_UNICODE_H
|
||||
#define _SMB_UNICODE_H
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/nls.h>
|
||||
#include <linux/unicode.h>
|
||||
|
||||
#define UNIUPR_NOLOWER /* Example to not expand lower case tables */
|
||||
|
||||
/*
|
||||
* Windows maps these to the user defined 16 bit Unicode range since they are
|
||||
* reserved symbols (along with \ and /), otherwise illegal to store
|
||||
* in filenames in NTFS
|
||||
*/
|
||||
#define UNI_ASTERISK ((__u16)('*' + 0xF000))
|
||||
#define UNI_QUESTION ((__u16)('?' + 0xF000))
|
||||
#define UNI_COLON ((__u16)(':' + 0xF000))
|
||||
#define UNI_GRTRTHAN ((__u16)('>' + 0xF000))
|
||||
#define UNI_LESSTHAN ((__u16)('<' + 0xF000))
|
||||
#define UNI_PIPE ((__u16)('|' + 0xF000))
|
||||
#define UNI_SLASH ((__u16)('\\' + 0xF000))
|
||||
|
||||
/* Just define what we want from uniupr.h. We don't want to define the tables
|
||||
* in each source file.
|
||||
*/
|
||||
#ifndef UNICASERANGE_DEFINED
|
||||
struct UniCaseRange {
|
||||
wchar_t start;
|
||||
wchar_t end;
|
||||
signed char *table;
|
||||
};
|
||||
#endif /* UNICASERANGE_DEFINED */
|
||||
|
||||
#ifndef UNIUPR_NOUPPER
|
||||
extern signed char SmbUniUpperTable[512];
|
||||
extern const struct UniCaseRange SmbUniUpperRange[];
|
||||
#endif /* UNIUPR_NOUPPER */
|
||||
|
||||
#ifndef UNIUPR_NOLOWER
|
||||
extern signed char CifsUniLowerTable[512];
|
||||
extern const struct UniCaseRange CifsUniLowerRange[];
|
||||
#endif /* UNIUPR_NOLOWER */
|
||||
#include "../../nls/nls_ucs2_utils.h"
|
||||
|
||||
#ifdef __KERNEL__
|
||||
int smb_strtoUTF16(__le16 *to, const char *from, int len,
|
||||
@ -73,286 +38,4 @@ int smbConvertToUTF16(__le16 *target, const char *source, int srclen,
|
||||
char *ksmbd_extract_sharename(struct unicode_map *um, const char *treename);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* UniStrcat: Concatenate the second string to the first
|
||||
*
|
||||
* Returns:
|
||||
* Address of the first string
|
||||
*/
|
||||
static inline wchar_t *UniStrcat(wchar_t *ucs1, const wchar_t *ucs2)
|
||||
{
|
||||
wchar_t *anchor = ucs1; /* save a pointer to start of ucs1 */
|
||||
|
||||
while (*ucs1++)
|
||||
/*NULL*/; /* To end of first string */
|
||||
ucs1--; /* Return to the null */
|
||||
while ((*ucs1++ = *ucs2++))
|
||||
/*NULL*/; /* copy string 2 over */
|
||||
return anchor;
|
||||
}
|
||||
|
||||
/*
|
||||
* UniStrchr: Find a character in a string
|
||||
*
|
||||
* Returns:
|
||||
* Address of first occurrence of character in string
|
||||
* or NULL if the character is not in the string
|
||||
*/
|
||||
static inline wchar_t *UniStrchr(const wchar_t *ucs, wchar_t uc)
|
||||
{
|
||||
while ((*ucs != uc) && *ucs)
|
||||
ucs++;
|
||||
|
||||
if (*ucs == uc)
|
||||
return (wchar_t *)ucs;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* UniStrcmp: Compare two strings
|
||||
*
|
||||
* Returns:
|
||||
* < 0: First string is less than second
|
||||
* = 0: Strings are equal
|
||||
* > 0: First string is greater than second
|
||||
*/
|
||||
static inline int UniStrcmp(const wchar_t *ucs1, const wchar_t *ucs2)
|
||||
{
|
||||
while ((*ucs1 == *ucs2) && *ucs1) {
|
||||
ucs1++;
|
||||
ucs2++;
|
||||
}
|
||||
return (int)*ucs1 - (int)*ucs2;
|
||||
}
|
||||
|
||||
/*
|
||||
* UniStrcpy: Copy a string
|
||||
*/
|
||||
static inline wchar_t *UniStrcpy(wchar_t *ucs1, const wchar_t *ucs2)
|
||||
{
|
||||
wchar_t *anchor = ucs1; /* save the start of result string */
|
||||
|
||||
while ((*ucs1++ = *ucs2++))
|
||||
/*NULL*/;
|
||||
return anchor;
|
||||
}
|
||||
|
||||
/*
|
||||
* UniStrlen: Return the length of a string (in 16 bit Unicode chars not bytes)
|
||||
*/
|
||||
static inline size_t UniStrlen(const wchar_t *ucs1)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (*ucs1++)
|
||||
i++;
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* UniStrnlen: Return the length (in 16 bit Unicode chars not bytes) of a
|
||||
* string (length limited)
|
||||
*/
|
||||
static inline size_t UniStrnlen(const wchar_t *ucs1, int maxlen)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (*ucs1++) {
|
||||
i++;
|
||||
if (i >= maxlen)
|
||||
break;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* UniStrncat: Concatenate length limited string
|
||||
*/
|
||||
static inline wchar_t *UniStrncat(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
|
||||
{
|
||||
wchar_t *anchor = ucs1; /* save pointer to string 1 */
|
||||
|
||||
while (*ucs1++)
|
||||
/*NULL*/;
|
||||
ucs1--; /* point to null terminator of s1 */
|
||||
while (n-- && (*ucs1 = *ucs2)) { /* copy s2 after s1 */
|
||||
ucs1++;
|
||||
ucs2++;
|
||||
}
|
||||
*ucs1 = 0; /* Null terminate the result */
|
||||
return anchor;
|
||||
}
|
||||
|
||||
/*
|
||||
* UniStrncmp: Compare length limited string
|
||||
*/
|
||||
static inline int UniStrncmp(const wchar_t *ucs1, const wchar_t *ucs2, size_t n)
|
||||
{
|
||||
if (!n)
|
||||
return 0; /* Null strings are equal */
|
||||
while ((*ucs1 == *ucs2) && *ucs1 && --n) {
|
||||
ucs1++;
|
||||
ucs2++;
|
||||
}
|
||||
return (int)*ucs1 - (int)*ucs2;
|
||||
}
|
||||
|
||||
/*
|
||||
* UniStrncmp_le: Compare length limited string - native to little-endian
|
||||
*/
|
||||
static inline int
|
||||
UniStrncmp_le(const wchar_t *ucs1, const wchar_t *ucs2, size_t n)
|
||||
{
|
||||
if (!n)
|
||||
return 0; /* Null strings are equal */
|
||||
while ((*ucs1 == __le16_to_cpu(*ucs2)) && *ucs1 && --n) {
|
||||
ucs1++;
|
||||
ucs2++;
|
||||
}
|
||||
return (int)*ucs1 - (int)__le16_to_cpu(*ucs2);
|
||||
}
|
||||
|
||||
/*
|
||||
* UniStrncpy: Copy length limited string with pad
|
||||
*/
|
||||
static inline wchar_t *UniStrncpy(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
|
||||
{
|
||||
wchar_t *anchor = ucs1;
|
||||
|
||||
while (n-- && *ucs2) /* Copy the strings */
|
||||
*ucs1++ = *ucs2++;
|
||||
|
||||
n++;
|
||||
while (n--) /* Pad with nulls */
|
||||
*ucs1++ = 0;
|
||||
return anchor;
|
||||
}
|
||||
|
||||
/*
|
||||
* UniStrncpy_le: Copy length limited string with pad to little-endian
|
||||
*/
|
||||
static inline wchar_t *UniStrncpy_le(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
|
||||
{
|
||||
wchar_t *anchor = ucs1;
|
||||
|
||||
while (n-- && *ucs2) /* Copy the strings */
|
||||
*ucs1++ = __le16_to_cpu(*ucs2++);
|
||||
|
||||
n++;
|
||||
while (n--) /* Pad with nulls */
|
||||
*ucs1++ = 0;
|
||||
return anchor;
|
||||
}
|
||||
|
||||
/*
|
||||
* UniStrstr: Find a string in a string
|
||||
*
|
||||
* Returns:
|
||||
* Address of first match found
|
||||
* NULL if no matching string is found
|
||||
*/
|
||||
static inline wchar_t *UniStrstr(const wchar_t *ucs1, const wchar_t *ucs2)
|
||||
{
|
||||
const wchar_t *anchor1 = ucs1;
|
||||
const wchar_t *anchor2 = ucs2;
|
||||
|
||||
while (*ucs1) {
|
||||
if (*ucs1 == *ucs2) {
|
||||
/* Partial match found */
|
||||
ucs1++;
|
||||
ucs2++;
|
||||
} else {
|
||||
if (!*ucs2) /* Match found */
|
||||
return (wchar_t *)anchor1;
|
||||
ucs1 = ++anchor1; /* No match */
|
||||
ucs2 = anchor2;
|
||||
}
|
||||
}
|
||||
|
||||
if (!*ucs2) /* Both end together */
|
||||
return (wchar_t *)anchor1; /* Match found */
|
||||
return NULL; /* No match */
|
||||
}
|
||||
|
||||
#ifndef UNIUPR_NOUPPER
|
||||
/*
|
||||
* UniToupper: Convert a unicode character to upper case
|
||||
*/
|
||||
static inline wchar_t UniToupper(register wchar_t uc)
|
||||
{
|
||||
register const struct UniCaseRange *rp;
|
||||
|
||||
if (uc < sizeof(SmbUniUpperTable)) {
|
||||
/* Latin characters */
|
||||
return uc + SmbUniUpperTable[uc]; /* Use base tables */
|
||||
}
|
||||
|
||||
rp = SmbUniUpperRange; /* Use range tables */
|
||||
while (rp->start) {
|
||||
if (uc < rp->start) /* Before start of range */
|
||||
return uc; /* Uppercase = input */
|
||||
if (uc <= rp->end) /* In range */
|
||||
return uc + rp->table[uc - rp->start];
|
||||
rp++; /* Try next range */
|
||||
}
|
||||
return uc; /* Past last range */
|
||||
}
|
||||
|
||||
/*
|
||||
* UniStrupr: Upper case a unicode string
|
||||
*/
|
||||
static inline __le16 *UniStrupr(register __le16 *upin)
|
||||
{
|
||||
register __le16 *up;
|
||||
|
||||
up = upin;
|
||||
while (*up) { /* For all characters */
|
||||
*up = cpu_to_le16(UniToupper(le16_to_cpu(*up)));
|
||||
up++;
|
||||
}
|
||||
return upin; /* Return input pointer */
|
||||
}
|
||||
#endif /* UNIUPR_NOUPPER */
|
||||
|
||||
#ifndef UNIUPR_NOLOWER
|
||||
/*
|
||||
* UniTolower: Convert a unicode character to lower case
|
||||
*/
|
||||
static inline wchar_t UniTolower(register wchar_t uc)
|
||||
{
|
||||
register const struct UniCaseRange *rp;
|
||||
|
||||
if (uc < sizeof(CifsUniLowerTable)) {
|
||||
/* Latin characters */
|
||||
return uc + CifsUniLowerTable[uc]; /* Use base tables */
|
||||
}
|
||||
|
||||
rp = CifsUniLowerRange; /* Use range tables */
|
||||
while (rp->start) {
|
||||
if (uc < rp->start) /* Before start of range */
|
||||
return uc; /* Uppercase = input */
|
||||
if (uc <= rp->end) /* In range */
|
||||
return uc + rp->table[uc - rp->start];
|
||||
rp++; /* Try next range */
|
||||
}
|
||||
return uc; /* Past last range */
|
||||
}
|
||||
|
||||
/*
|
||||
* UniStrlwr: Lower case a unicode string
|
||||
*/
|
||||
static inline wchar_t *UniStrlwr(register wchar_t *upin)
|
||||
{
|
||||
register wchar_t *up;
|
||||
|
||||
up = upin;
|
||||
while (*up) { /* For all characters */
|
||||
*up = UniTolower(*up);
|
||||
up++;
|
||||
}
|
||||
return upin; /* Return input pointer */
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _CIFS_UNICODE_H */
|
||||
#endif /* _SMB_UNICODE_H */
|
||||
|
Loading…
Reference in New Issue
Block a user