Commit b97d64c7 authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents 47d154eb f3a9b375
......@@ -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 */
......
// 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
/* 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 */
/* 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);
/* 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 */
This diff is collapsed.
......@@ -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;
}
ref_walk_path(rw) = ref_path;
ref_walk_fpath(rw) = full_path;
return 0;
}
rc = dfs_parse_target_referral(full_path + 1, &ref, ctx);
if (rc)
goto out;
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;
cifs_mount_put_conns(mnt_ctx);
rc = get_session(mnt_ctx, ref_path);
if (rc)
goto out;
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;
}
}
is_refsrv = !!(ref.flags & DFSREF_REFERRAL_SERVER);
while (ref_walk_next_tgt(rw)) {
rc = parse_dfs_target(ctx, rw, &tgt);
if (rc)
continue;
rc = -EREMOTE;
if (ref.flags & DFSREF_STORAGE_SERVER) {
rc = cifs_mount_get_tcon(mnt_ctx);
if (rc)
goto out;
cifs_mount_put_conns(mnt_ctx);
rc = get_session(mnt_ctx, ref_walk_path(rw));
if (rc)
continue;
/* some servers may not advertise referral capability under ref.flags */
is_refsrv |= is_tcon_dfs(mnt_ctx->tcon);
is_refsrv = tgt.server_type == DFS_TYPE_ROOT ||
DFS_INTERLINK(tgt.flags);
ref_walk_set_tgt_hint(rw);
rc = cifs_is_path_remote(mnt_ctx);
}
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;
}
dfs_cache_noreq_update_tgthint(ref_path + 1, tit);
if (is_refsrv) {
rc = add_root_smb_session(mnt_ctx);
if (rc)
goto out;
}
if (rc == -EREMOTE && is_refsrv) {
rc2 = add_root_smb_session(mnt_ctx);
if (rc2)
rc = rc2;
}
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;
}
origin_fullpath = kstrdup(full_path, GFP_KERNEL);
if (!origin_fullpath) {
rc = -ENOMEM;
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);
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,
};
This diff is collapsed.
......@@ -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);
......
// 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;
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, '/');
rc = dns_resolve_server_name_to_ip(ctx->source, addr, NULL);
if (!rc)
cifs_set_port(addr, ctx->port);
return rc;
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;
......
This diff is collapsed.
......@@ -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);
......
This diff is collapsed.
......@@ -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 */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment