You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6: (31 commits) [CIFS] Remove redundant test [CIFS] make sure that DFS pathnames are properly formed Remove an already-checked error condition in SendReceiveBlockingLock Streamline SendReceiveBlockingLock: Use "goto out:" in an error condition Streamline SendReceiveBlockingLock: Use "goto out:" in an error condition [CIFS] Streamline SendReceive[2] by using "goto out:" in an error condition Slightly streamline SendReceive[2] Check the return value of cifs_sign_smb[2] [CIFS] Cleanup: Move the check for too large R/W requests [CIFS] Slightly simplify wait_for_free_request(), remove an unnecessary "else" branch Simplify allocate_mid() slightly: Remove some unnecessary "else" branches [CIFS] In SendReceive, move consistency check out of the mutexed region cifs: store password in tcon cifs: have calc_lanman_hash take more granular args cifs: zero out session password before freeing it cifs: fix wait_for_response to time out sleeping processes correctly [CIFS] Can not mount with prefixpath if root directory of share is inaccessible [CIFS] various minor cleanups pointed out by checkpatch script [CIFS] fix typo [CIFS] remove sparse warning ... Fix trivial conflict in fs/cifs/cifs_fs_sb.h due to comment changes for the CIFS_MOUNT_xyz bit definitions between cifs updates and security updates.
This commit is contained in:
@@ -36,7 +36,9 @@ Miklos Szeredi
|
||||
Kazeon team for various fixes especially for 2.4 version.
|
||||
Asser Ferno (Change Notify support)
|
||||
Shaggy (Dave Kleikamp) for inumerable small fs suggestions and some good cleanup
|
||||
Gunter Kukkukk (testing and suggestions for support of old servers)
|
||||
Igor Mammedov (DFS support)
|
||||
Jeff Layton (many, many fixes, as well as great work on the cifs Kerberos code)
|
||||
|
||||
Test case and Bug Report contributors
|
||||
-------------------------------------
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
Version 1.56
|
||||
------------
|
||||
Add "forcemandatorylock" mount option to allow user to use mandatory
|
||||
rather than posix (advisory) byte range locks, even though server would
|
||||
support posix byte range locks. Fix query of root inode when prefixpath
|
||||
specified and user does not have access to query information about the
|
||||
top of the share. Fix problem in 2.6.28 resolving DFS paths to
|
||||
Samba servers (worked to Windows).
|
||||
|
||||
Version 1.55
|
||||
------------
|
||||
Various fixes to make delete of open files behavior more predictable
|
||||
|
||||
+11
-1
@@ -463,9 +463,19 @@ A partial list of the supported mount options follows:
|
||||
with cifs style mandatory byte range locks (and most
|
||||
cifs servers do not yet support requesting advisory
|
||||
byte range locks).
|
||||
forcemandatorylock Even if the server supports posix (advisory) byte range
|
||||
locking, send only mandatory lock requests. For some
|
||||
(presumably rare) applications, originally coded for
|
||||
DOS/Windows, which require Windows style mandatory byte range
|
||||
locking, they may be able to take advantage of this option,
|
||||
forcing the cifs client to only send mandatory locks
|
||||
even if the cifs server would support posix advisory locks.
|
||||
"forcemand" is accepted as a shorter form of this mount
|
||||
option.
|
||||
nodfs Disable DFS (global name space support) even if the
|
||||
server claims to support it. This can help work around
|
||||
a problem with parsing of DFS paths with Samba 3.0.24 server.
|
||||
a problem with parsing of DFS paths with Samba server
|
||||
versions 3.0.24 and 3.0.25.
|
||||
remount remount the share (often used to change from ro to rw mounts
|
||||
or vice versa)
|
||||
cifsacl Report mode bits (e.g. on stat) based on the Windows ACL for
|
||||
|
||||
+36
-12
@@ -122,7 +122,7 @@ static char *compose_mount_options(const char *sb_mountdata,
|
||||
char **devname)
|
||||
{
|
||||
int rc;
|
||||
char *mountdata;
|
||||
char *mountdata = NULL;
|
||||
int md_len;
|
||||
char *tkn_e;
|
||||
char *srvIP = NULL;
|
||||
@@ -136,10 +136,9 @@ static char *compose_mount_options(const char *sb_mountdata,
|
||||
*devname = cifs_get_share_name(ref->node_name);
|
||||
rc = dns_resolve_server_name_to_ip(*devname, &srvIP);
|
||||
if (rc != 0) {
|
||||
cERROR(1, ("%s: Failed to resolve server part of %s to IP",
|
||||
__func__, *devname));
|
||||
mountdata = ERR_PTR(rc);
|
||||
goto compose_mount_options_out;
|
||||
cERROR(1, ("%s: Failed to resolve server part of %s to IP: %d",
|
||||
__func__, *devname, rc));;
|
||||
goto compose_mount_options_err;
|
||||
}
|
||||
/* md_len = strlen(...) + 12 for 'sep+prefixpath='
|
||||
* assuming that we have 'unc=' and 'ip=' in
|
||||
@@ -149,8 +148,8 @@ static char *compose_mount_options(const char *sb_mountdata,
|
||||
strlen(ref->node_name) + 12;
|
||||
mountdata = kzalloc(md_len+1, GFP_KERNEL);
|
||||
if (mountdata == NULL) {
|
||||
mountdata = ERR_PTR(-ENOMEM);
|
||||
goto compose_mount_options_out;
|
||||
rc = -ENOMEM;
|
||||
goto compose_mount_options_err;
|
||||
}
|
||||
|
||||
/* copy all options except of unc,ip,prefixpath */
|
||||
@@ -197,18 +196,32 @@ static char *compose_mount_options(const char *sb_mountdata,
|
||||
|
||||
/* find & copy prefixpath */
|
||||
tkn_e = strchr(ref->node_name + 2, '\\');
|
||||
if (tkn_e == NULL) /* invalid unc, missing share name*/
|
||||
goto compose_mount_options_out;
|
||||
if (tkn_e == NULL) {
|
||||
/* invalid unc, missing share name*/
|
||||
rc = -EINVAL;
|
||||
goto compose_mount_options_err;
|
||||
}
|
||||
|
||||
/*
|
||||
* this function gives us a path with a double backslash prefix. We
|
||||
* require a single backslash for DFS. Temporarily increment fullpath
|
||||
* to put it in the proper form and decrement before freeing it.
|
||||
*/
|
||||
fullpath = build_path_from_dentry(dentry);
|
||||
if (!fullpath) {
|
||||
rc = -ENOMEM;
|
||||
goto compose_mount_options_err;
|
||||
}
|
||||
++fullpath;
|
||||
tkn_e = strchr(tkn_e + 1, '\\');
|
||||
if (tkn_e || strlen(fullpath) - (ref->path_consumed)) {
|
||||
if (tkn_e || (strlen(fullpath) - ref->path_consumed)) {
|
||||
strncat(mountdata, &sep, 1);
|
||||
strcat(mountdata, "prefixpath=");
|
||||
if (tkn_e)
|
||||
strcat(mountdata, tkn_e + 1);
|
||||
strcat(mountdata, fullpath + (ref->path_consumed));
|
||||
strcat(mountdata, fullpath + ref->path_consumed);
|
||||
}
|
||||
--fullpath;
|
||||
kfree(fullpath);
|
||||
|
||||
/*cFYI(1,("%s: parent mountdata: %s", __func__,sb_mountdata));*/
|
||||
@@ -217,6 +230,11 @@ static char *compose_mount_options(const char *sb_mountdata,
|
||||
compose_mount_options_out:
|
||||
kfree(srvIP);
|
||||
return mountdata;
|
||||
|
||||
compose_mount_options_err:
|
||||
kfree(mountdata);
|
||||
mountdata = ERR_PTR(rc);
|
||||
goto compose_mount_options_out;
|
||||
}
|
||||
|
||||
|
||||
@@ -309,13 +327,19 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
full_path = build_path_from_dentry(dentry);
|
||||
if (full_path == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
rc = get_dfs_path(xid, ses , full_path, cifs_sb->local_nls,
|
||||
rc = get_dfs_path(xid, ses , full_path + 1, cifs_sb->local_nls,
|
||||
&num_referrals, &referrals,
|
||||
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
#define CIFS_MOUNT_NO_PERM 1 /* do not do client vfs_perm check */
|
||||
#define CIFS_MOUNT_SET_UID 2 /* set current's euid in create etc. */
|
||||
#define CIFS_MOUNT_SERVER_INUM 4 /* inode numbers from uniqueid from server */
|
||||
#define CIFS_MOUNT_SERVER_INUM 4 /* inode numbers from uniqueid from server */
|
||||
#define CIFS_MOUNT_DIRECT_IO 8 /* do not write nor read through page cache */
|
||||
#define CIFS_MOUNT_NO_XATTR 0x10 /* if set - disable xattr support */
|
||||
#define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */
|
||||
@@ -30,7 +30,8 @@
|
||||
#define CIFS_MOUNT_CIFS_ACL 0x200 /* send ACL requests to non-POSIX srv */
|
||||
#define CIFS_MOUNT_OVERR_UID 0x400 /* override uid returned from server */
|
||||
#define CIFS_MOUNT_OVERR_GID 0x800 /* override gid returned from server */
|
||||
#define CIFS_MOUNT_DYNPERM 0x1000 /* allow in-memory only mode setting */
|
||||
#define CIFS_MOUNT_DYNPERM 0x1000 /* allow in-memory only mode setting */
|
||||
#define CIFS_MOUNT_NOPOSIXBRL 0x2000 /* mandatory not posix byte range lock */
|
||||
|
||||
struct cifs_sb_info {
|
||||
struct cifsTconInfo *tcon; /* primary mount */
|
||||
|
||||
+13
-15
@@ -37,7 +37,7 @@
|
||||
|
||||
extern void mdfour(unsigned char *out, unsigned char *in, int n);
|
||||
extern void E_md4hash(const unsigned char *passwd, unsigned char *p16);
|
||||
extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
|
||||
extern void SMBencrypt(unsigned char *passwd, const unsigned char *c8,
|
||||
unsigned char *p24);
|
||||
|
||||
static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu,
|
||||
@@ -280,25 +280,22 @@ int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *ses,
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_WEAK_PW_HASH
|
||||
void calc_lanman_hash(struct cifsSesInfo *ses, char *lnm_session_key)
|
||||
void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt,
|
||||
char *lnm_session_key)
|
||||
{
|
||||
int i;
|
||||
char password_with_pad[CIFS_ENCPWD_SIZE];
|
||||
|
||||
if (ses->server == NULL)
|
||||
return;
|
||||
|
||||
memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
|
||||
if (ses->password)
|
||||
strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE);
|
||||
if (password)
|
||||
strncpy(password_with_pad, password, CIFS_ENCPWD_SIZE);
|
||||
|
||||
if ((ses->server->secMode & SECMODE_PW_ENCRYPT) == 0)
|
||||
if (extended_security & CIFSSEC_MAY_PLNTXT) {
|
||||
memset(lnm_session_key, 0, CIFS_SESS_KEY_SIZE);
|
||||
memcpy(lnm_session_key, password_with_pad,
|
||||
CIFS_ENCPWD_SIZE);
|
||||
return;
|
||||
}
|
||||
if (!encrypt && extended_security & CIFSSEC_MAY_PLNTXT) {
|
||||
memset(lnm_session_key, 0, CIFS_SESS_KEY_SIZE);
|
||||
memcpy(lnm_session_key, password_with_pad,
|
||||
CIFS_ENCPWD_SIZE);
|
||||
return;
|
||||
}
|
||||
|
||||
/* calculate old style session key */
|
||||
/* calling toupper is less broken than repeatedly
|
||||
@@ -314,7 +311,8 @@ void calc_lanman_hash(struct cifsSesInfo *ses, char *lnm_session_key)
|
||||
for (i = 0; i < CIFS_ENCPWD_SIZE; i++)
|
||||
password_with_pad[i] = toupper(password_with_pad[i]);
|
||||
|
||||
SMBencrypt(password_with_pad, ses->server->cryptKey, lnm_session_key);
|
||||
SMBencrypt(password_with_pad, cryptkey, lnm_session_key);
|
||||
|
||||
/* clear password before we return/free memory */
|
||||
memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
|
||||
}
|
||||
|
||||
@@ -26,7 +26,8 @@
|
||||
extern void mdfour(unsigned char *out, unsigned char *in, int n);
|
||||
/* smbdes.c */
|
||||
extern void E_P16(unsigned char *p14, unsigned char *p16);
|
||||
extern void E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24);
|
||||
extern void E_P24(unsigned char *p21, const unsigned char *c8,
|
||||
unsigned char *p24);
|
||||
|
||||
|
||||
|
||||
|
||||
+50
-25
@@ -66,7 +66,9 @@ unsigned int sign_CIFS_PDUs = 1;
|
||||
extern struct task_struct *oplockThread; /* remove sparse warning */
|
||||
struct task_struct *oplockThread = NULL;
|
||||
/* extern struct task_struct * dnotifyThread; remove sparse warning */
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
static struct task_struct *dnotifyThread = NULL;
|
||||
#endif
|
||||
static const struct super_operations cifs_super_ops;
|
||||
unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE;
|
||||
module_param(CIFSMaxBufSize, int, 0);
|
||||
@@ -337,39 +339,58 @@ static int
|
||||
cifs_show_options(struct seq_file *s, struct vfsmount *m)
|
||||
{
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
struct cifsTconInfo *tcon;
|
||||
struct TCP_Server_Info *server;
|
||||
|
||||
cifs_sb = CIFS_SB(m->mnt_sb);
|
||||
|
||||
if (cifs_sb) {
|
||||
if (cifs_sb->tcon) {
|
||||
/* BB add prepath to mount options displayed */
|
||||
tcon = cifs_sb->tcon;
|
||||
if (tcon) {
|
||||
seq_printf(s, ",unc=%s", cifs_sb->tcon->treeName);
|
||||
if (cifs_sb->tcon->ses) {
|
||||
if (cifs_sb->tcon->ses->userName)
|
||||
if (tcon->ses) {
|
||||
if (tcon->ses->userName)
|
||||
seq_printf(s, ",username=%s",
|
||||
cifs_sb->tcon->ses->userName);
|
||||
if (cifs_sb->tcon->ses->domainName)
|
||||
tcon->ses->userName);
|
||||
if (tcon->ses->domainName)
|
||||
seq_printf(s, ",domain=%s",
|
||||
cifs_sb->tcon->ses->domainName);
|
||||
tcon->ses->domainName);
|
||||
server = tcon->ses->server;
|
||||
if (server) {
|
||||
seq_printf(s, ",addr=");
|
||||
switch (server->addr.sockAddr6.
|
||||
sin6_family) {
|
||||
case AF_INET6:
|
||||
seq_printf(s, NIP6_FMT,
|
||||
NIP6(server->addr.sockAddr6.sin6_addr));
|
||||
break;
|
||||
case AF_INET:
|
||||
seq_printf(s, NIPQUAD_FMT,
|
||||
NIPQUAD(server->addr.sockAddr.sin_addr.s_addr));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) ||
|
||||
!(cifs_sb->tcon->unix_ext))
|
||||
!(tcon->unix_ext))
|
||||
seq_printf(s, ",uid=%d", cifs_sb->mnt_uid);
|
||||
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) ||
|
||||
!(cifs_sb->tcon->unix_ext))
|
||||
!(tcon->unix_ext))
|
||||
seq_printf(s, ",gid=%d", cifs_sb->mnt_gid);
|
||||
if (!cifs_sb->tcon->unix_ext) {
|
||||
if (!tcon->unix_ext) {
|
||||
seq_printf(s, ",file_mode=0%o,dir_mode=0%o",
|
||||
cifs_sb->mnt_file_mode,
|
||||
cifs_sb->mnt_dir_mode);
|
||||
}
|
||||
if (cifs_sb->tcon->seal)
|
||||
if (tcon->seal)
|
||||
seq_printf(s, ",seal");
|
||||
if (cifs_sb->tcon->nocase)
|
||||
if (tcon->nocase)
|
||||
seq_printf(s, ",nocase");
|
||||
if (cifs_sb->tcon->retry)
|
||||
if (tcon->retry)
|
||||
seq_printf(s, ",hard");
|
||||
}
|
||||
if (cifs_sb->prepath)
|
||||
seq_printf(s, ",prepath=%s", cifs_sb->prepath);
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
|
||||
seq_printf(s, ",posixpaths");
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)
|
||||
@@ -417,9 +438,8 @@ int cifs_xquota_set(struct super_block *sb, int quota_type, qid_t qid,
|
||||
xid = GetXid();
|
||||
if (pTcon) {
|
||||
cFYI(1, ("set type: 0x%x id: %d", quota_type, qid));
|
||||
} else {
|
||||
} else
|
||||
rc = -EIO;
|
||||
}
|
||||
|
||||
FreeXid(xid);
|
||||
return rc;
|
||||
@@ -441,9 +461,8 @@ int cifs_xquota_get(struct super_block *sb, int quota_type, qid_t qid,
|
||||
xid = GetXid();
|
||||
if (pTcon) {
|
||||
cFYI(1, ("set type: 0x%x id: %d", quota_type, qid));
|
||||
} else {
|
||||
} else
|
||||
rc = -EIO;
|
||||
}
|
||||
|
||||
FreeXid(xid);
|
||||
return rc;
|
||||
@@ -464,9 +483,8 @@ int cifs_xstate_set(struct super_block *sb, unsigned int flags, int operation)
|
||||
xid = GetXid();
|
||||
if (pTcon) {
|
||||
cFYI(1, ("flags: 0x%x operation: 0x%x", flags, operation));
|
||||
} else {
|
||||
} else
|
||||
rc = -EIO;
|
||||
}
|
||||
|
||||
FreeXid(xid);
|
||||
return rc;
|
||||
@@ -479,17 +497,16 @@ int cifs_xstate_get(struct super_block *sb, struct fs_quota_stat *qstats)
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
||||
struct cifsTconInfo *pTcon;
|
||||
|
||||
if (cifs_sb) {
|
||||
if (cifs_sb)
|
||||
pTcon = cifs_sb->tcon;
|
||||
} else {
|
||||
else
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
xid = GetXid();
|
||||
if (pTcon) {
|
||||
cFYI(1, ("pqstats %p", qstats));
|
||||
} else {
|
||||
} else
|
||||
rc = -EIO;
|
||||
}
|
||||
|
||||
FreeXid(xid);
|
||||
return rc;
|
||||
@@ -1029,6 +1046,7 @@ static int cifs_oplock_thread(void *dummyarg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
static int cifs_dnotify_thread(void *dummyarg)
|
||||
{
|
||||
struct list_head *tmp;
|
||||
@@ -1054,6 +1072,7 @@ static int cifs_dnotify_thread(void *dummyarg)
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int __init
|
||||
init_cifs(void)
|
||||
@@ -1131,16 +1150,20 @@ init_cifs(void)
|
||||
goto out_unregister_dfs_key_type;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
dnotifyThread = kthread_run(cifs_dnotify_thread, NULL, "cifsdnotifyd");
|
||||
if (IS_ERR(dnotifyThread)) {
|
||||
rc = PTR_ERR(dnotifyThread);
|
||||
cERROR(1, ("error %d create dnotify thread", rc));
|
||||
goto out_stop_oplock_thread;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
out_stop_oplock_thread:
|
||||
#endif
|
||||
kthread_stop(oplockThread);
|
||||
out_unregister_dfs_key_type:
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
@@ -1179,8 +1202,10 @@ exit_cifs(void)
|
||||
cifs_destroy_inodecache();
|
||||
cifs_destroy_mids();
|
||||
cifs_destroy_request_bufs();
|
||||
kthread_stop(oplockThread);
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
kthread_stop(dnotifyThread);
|
||||
#endif
|
||||
kthread_stop(oplockThread);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>");
|
||||
|
||||
+1
-1
@@ -101,5 +101,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
|
||||
extern const struct export_operations cifs_export_ops;
|
||||
#endif /* EXPERIMENTAL */
|
||||
|
||||
#define CIFS_VERSION "1.55"
|
||||
#define CIFS_VERSION "1.56"
|
||||
#endif /* _CIFSFS_H */
|
||||
|
||||
+9
-6
@@ -47,7 +47,11 @@
|
||||
*/
|
||||
#define CIFS_MAX_REQ 50
|
||||
|
||||
#define SERVER_NAME_LENGTH 15
|
||||
#define RFC1001_NAME_LEN 15
|
||||
#define RFC1001_NAME_LEN_WITH_NULL (RFC1001_NAME_LEN + 1)
|
||||
|
||||
/* currently length of NIP6_FMT */
|
||||
#define SERVER_NAME_LENGTH 40
|
||||
#define SERVER_NAME_LEN_WITH_NULL (SERVER_NAME_LENGTH + 1)
|
||||
|
||||
/* used to define string lengths for reversing unicode strings */
|
||||
@@ -125,8 +129,7 @@ struct TCP_Server_Info {
|
||||
struct list_head smb_ses_list;
|
||||
int srv_count; /* reference counter */
|
||||
/* 15 character server name + 0x20 16th byte indicating type = srv */
|
||||
char server_RFC1001_name[SERVER_NAME_LEN_WITH_NULL];
|
||||
char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2];
|
||||
char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
|
||||
char *hostname; /* hostname portion of UNC string */
|
||||
struct socket *ssocket;
|
||||
union {
|
||||
@@ -151,7 +154,7 @@ struct TCP_Server_Info {
|
||||
atomic_t num_waiters; /* blocked waiting to get in sendrecv */
|
||||
#endif
|
||||
enum statusEnum tcpStatus; /* what we think the status is */
|
||||
struct semaphore tcpSem;
|
||||
struct mutex srv_mutex;
|
||||
struct task_struct *tsk;
|
||||
char server_GUID[16];
|
||||
char secMode;
|
||||
@@ -171,7 +174,7 @@ struct TCP_Server_Info {
|
||||
__u16 CurrentMid; /* multiplex id - rotating counter */
|
||||
char cryptKey[CIFS_CRYPTO_KEY_SIZE];
|
||||
/* 16th byte of RFC1001 workstation name is always null */
|
||||
char workstation_RFC1001_name[SERVER_NAME_LEN_WITH_NULL];
|
||||
char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
|
||||
__u32 sequence_number; /* needed for CIFS PDU signature */
|
||||
struct mac_key mac_signing_key;
|
||||
char ntlmv2_hash[16];
|
||||
@@ -239,6 +242,7 @@ struct cifsTconInfo {
|
||||
struct cifsSesInfo *ses; /* pointer to session associated with */
|
||||
char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */
|
||||
char *nativeFileSystem;
|
||||
char *password; /* for share-level security */
|
||||
__u16 tid; /* The 2 byte tree id */
|
||||
__u16 Flags; /* optional support bits */
|
||||
enum statusEnum tidStatus;
|
||||
@@ -422,7 +426,6 @@ struct mid_q_entry {
|
||||
unsigned long when_sent; /* time when smb send finished */
|
||||
unsigned long when_received; /* when demux complete (taken off wire) */
|
||||
#endif
|
||||
struct cifsSesInfo *ses; /* smb was sent to this server */
|
||||
struct task_struct *tsk; /* task waiting for response */
|
||||
struct smb_hdr *resp_buf; /* response buffer */
|
||||
int midState; /* wish this were enum but can not pass to wait_event */
|
||||
|
||||
+1
-1
@@ -1922,7 +1922,7 @@ typedef struct smb_com_transaction2_get_dfs_refer_req {
|
||||
/* DFS server target type */
|
||||
#define DFS_TYPE_LINK 0x0000 /* also for sysvol targets */
|
||||
#define DFS_TYPE_ROOT 0x0001
|
||||
|
||||
|
||||
/* Referral Entry Flags */
|
||||
#define DFS_NAME_LIST_REF 0x0200
|
||||
|
||||
|
||||
+2
-1
@@ -330,7 +330,8 @@ extern void CalcNTLMv2_response(const struct cifsSesInfo *, char *);
|
||||
extern void setup_ntlmv2_rsp(struct cifsSesInfo *, char *,
|
||||
const struct nls_table *);
|
||||
#ifdef CONFIG_CIFS_WEAK_PW_HASH
|
||||
extern void calc_lanman_hash(struct cifsSesInfo *ses, char *lnm_session_key);
|
||||
extern void calc_lanman_hash(const char *password, const char *cryptkey,
|
||||
bool encrypt, char *lnm_session_key);
|
||||
#endif /* CIFS_WEAK_PW_HASH */
|
||||
extern int CIFSSMBCopy(int xid,
|
||||
struct cifsTconInfo *source_tcon,
|
||||
|
||||
+27
-22
@@ -1382,13 +1382,13 @@ openRetry:
|
||||
if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
|
||||
*pOplock |= CIFS_CREATE_ACTION;
|
||||
if (pfile_info) {
|
||||
memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
|
||||
36 /* CreationTime to Attributes */);
|
||||
/* the file_info buf is endian converted by caller */
|
||||
pfile_info->AllocationSize = pSMBr->AllocationSize;
|
||||
pfile_info->EndOfFile = pSMBr->EndOfFile;
|
||||
pfile_info->NumberOfLinks = cpu_to_le32(1);
|
||||
pfile_info->DeletePending = 0;
|
||||
memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
|
||||
36 /* CreationTime to Attributes */);
|
||||
/* the file_info buf is endian converted by caller */
|
||||
pfile_info->AllocationSize = pSMBr->AllocationSize;
|
||||
pfile_info->EndOfFile = pSMBr->EndOfFile;
|
||||
pfile_info->NumberOfLinks = cpu_to_le32(1);
|
||||
pfile_info->DeletePending = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1414,8 +1414,13 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
|
||||
cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
|
||||
if (tcon->ses->capabilities & CAP_LARGE_FILES)
|
||||
wct = 12;
|
||||
else
|
||||
else {
|
||||
wct = 10; /* old style read */
|
||||
if ((lseek >> 32) > 0) {
|
||||
/* can not handle this big offset for old */
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
*nbytes = 0;
|
||||
rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
|
||||
@@ -1431,8 +1436,6 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
|
||||
pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
|
||||
if (wct == 12)
|
||||
pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
|
||||
else if ((lseek >> 32) > 0) /* can not handle this big offset for old */
|
||||
return -EIO;
|
||||
|
||||
pSMB->Remaining = 0;
|
||||
pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
|
||||
@@ -1519,8 +1522,13 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
|
||||
|
||||
if (tcon->ses->capabilities & CAP_LARGE_FILES)
|
||||
wct = 14;
|
||||
else
|
||||
else {
|
||||
wct = 12;
|
||||
if ((offset >> 32) > 0) {
|
||||
/* can not handle big offset for old srv */
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
|
||||
(void **) &pSMBr);
|
||||
@@ -1535,8 +1543,6 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
|
||||
pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
|
||||
if (wct == 14)
|
||||
pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
|
||||
else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
|
||||
return -EIO;
|
||||
|
||||
pSMB->Reserved = 0xFFFFFFFF;
|
||||
pSMB->WriteMode = 0;
|
||||
@@ -1558,7 +1564,7 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
|
||||
pSMB->DataOffset =
|
||||
cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
|
||||
if (buf)
|
||||
memcpy(pSMB->Data, buf, bytes_sent);
|
||||
memcpy(pSMB->Data, buf, bytes_sent);
|
||||
else if (ubuf) {
|
||||
if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
|
||||
cifs_buf_release(pSMB);
|
||||
@@ -1621,10 +1627,15 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
|
||||
|
||||
cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
|
||||
|
||||
if (tcon->ses->capabilities & CAP_LARGE_FILES)
|
||||
if (tcon->ses->capabilities & CAP_LARGE_FILES) {
|
||||
wct = 14;
|
||||
else
|
||||
} else {
|
||||
wct = 12;
|
||||
if ((offset >> 32) > 0) {
|
||||
/* can not handle big offset for old srv */
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
|
||||
if (rc)
|
||||
return rc;
|
||||
@@ -1637,8 +1648,6 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
|
||||
pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
|
||||
if (wct == 14)
|
||||
pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
|
||||
else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
|
||||
return -EIO;
|
||||
pSMB->Reserved = 0xFFFFFFFF;
|
||||
pSMB->WriteMode = 0;
|
||||
pSMB->Remaining = 0;
|
||||
@@ -1862,10 +1871,6 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
|
||||
rc = -EIO; /* bad smb */
|
||||
goto plk_err_exit;
|
||||
}
|
||||
if (pLockData == NULL) {
|
||||
rc = -EINVAL;
|
||||
goto plk_err_exit;
|
||||
}
|
||||
data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
|
||||
data_count = le16_to_cpu(pSMBr->t2.DataCount);
|
||||
if (data_count < sizeof(struct cifs_posix_lock)) {
|
||||
|
||||
+370
-311
File diff suppressed because it is too large
Load Diff
+4
-5
@@ -483,7 +483,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
|
||||
|
||||
xid = GetXid();
|
||||
|
||||
cFYI(1, (" parent inode = 0x%p name is: %s and dentry = 0x%p",
|
||||
cFYI(1, ("parent inode = 0x%p name is: %s and dentry = 0x%p",
|
||||
parent_dir_inode, direntry->d_name.name, direntry));
|
||||
|
||||
/* check whether path exists */
|
||||
@@ -515,12 +515,11 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
|
||||
}
|
||||
|
||||
if (direntry->d_inode != NULL) {
|
||||
cFYI(1, (" non-NULL inode in lookup"));
|
||||
cFYI(1, ("non-NULL inode in lookup"));
|
||||
} else {
|
||||
cFYI(1, (" NULL inode in lookup"));
|
||||
cFYI(1, ("NULL inode in lookup"));
|
||||
}
|
||||
cFYI(1,
|
||||
(" Full path: %s inode = 0x%p", full_path, direntry->d_inode));
|
||||
cFYI(1, ("Full path: %s inode = 0x%p", full_path, direntry->d_inode));
|
||||
|
||||
if (pTcon->unix_ext)
|
||||
rc = cifs_get_inode_info_unix(&newInode, full_path,
|
||||
|
||||
+13
-12
@@ -644,10 +644,10 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
|
||||
__u64 length;
|
||||
bool wait_flag = false;
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
struct cifsTconInfo *pTcon;
|
||||
struct cifsTconInfo *tcon;
|
||||
__u16 netfid;
|
||||
__u8 lockType = LOCKING_ANDX_LARGE_FILES;
|
||||
bool posix_locking;
|
||||
bool posix_locking = 0;
|
||||
|
||||
length = 1 + pfLock->fl_end - pfLock->fl_start;
|
||||
rc = -EACCES;
|
||||
@@ -698,7 +698,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
|
||||
cFYI(1, ("Unknown type of lock"));
|
||||
|
||||
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
|
||||
pTcon = cifs_sb->tcon;
|
||||
tcon = cifs_sb->tcon;
|
||||
|
||||
if (file->private_data == NULL) {
|
||||
FreeXid(xid);
|
||||
@@ -706,9 +706,10 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
|
||||
}
|
||||
netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
|
||||
|
||||
posix_locking = (cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
|
||||
(CIFS_UNIX_FCNTL_CAP & le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability));
|
||||
|
||||
if ((tcon->ses->capabilities & CAP_UNIX) &&
|
||||
(CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
|
||||
((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
|
||||
posix_locking = 1;
|
||||
/* BB add code here to normalize offset and length to
|
||||
account for negative length which we can not accept over the
|
||||
wire */
|
||||
@@ -719,7 +720,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
|
||||
posix_lock_type = CIFS_RDLCK;
|
||||
else
|
||||
posix_lock_type = CIFS_WRLCK;
|
||||
rc = CIFSSMBPosixLock(xid, pTcon, netfid, 1 /* get */,
|
||||
rc = CIFSSMBPosixLock(xid, tcon, netfid, 1 /* get */,
|
||||
length, pfLock,
|
||||
posix_lock_type, wait_flag);
|
||||
FreeXid(xid);
|
||||
@@ -727,10 +728,10 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
|
||||
}
|
||||
|
||||
/* BB we could chain these into one lock request BB */
|
||||
rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start,
|
||||
rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start,
|
||||
0, 1, lockType, 0 /* wait flag */ );
|
||||
if (rc == 0) {
|
||||
rc = CIFSSMBLock(xid, pTcon, netfid, length,
|
||||
rc = CIFSSMBLock(xid, tcon, netfid, length,
|
||||
pfLock->fl_start, 1 /* numUnlock */ ,
|
||||
0 /* numLock */ , lockType,
|
||||
0 /* wait flag */ );
|
||||
@@ -767,7 +768,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
|
||||
if (numUnlock == 1)
|
||||
posix_lock_type = CIFS_UNLCK;
|
||||
|
||||
rc = CIFSSMBPosixLock(xid, pTcon, netfid, 0 /* set */,
|
||||
rc = CIFSSMBPosixLock(xid, tcon, netfid, 0 /* set */,
|
||||
length, pfLock,
|
||||
posix_lock_type, wait_flag);
|
||||
} else {
|
||||
@@ -775,7 +776,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
|
||||
(struct cifsFileInfo *)file->private_data;
|
||||
|
||||
if (numLock) {
|
||||
rc = CIFSSMBLock(xid, pTcon, netfid, length,
|
||||
rc = CIFSSMBLock(xid, tcon, netfid, length,
|
||||
pfLock->fl_start,
|
||||
0, numLock, lockType, wait_flag);
|
||||
|
||||
@@ -796,7 +797,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
|
||||
if (pfLock->fl_start <= li->offset &&
|
||||
(pfLock->fl_start + length) >=
|
||||
(li->offset + li->length)) {
|
||||
stored_rc = CIFSSMBLock(xid, pTcon,
|
||||
stored_rc = CIFSSMBLock(xid, tcon,
|
||||
netfid,
|
||||
li->length, li->offset,
|
||||
1, 0, li->type, false);
|
||||
|
||||
+53
-5
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* fs/cifs/inode.c
|
||||
*
|
||||
* Copyright (C) International Business Machines Corp., 2002,2007
|
||||
* Copyright (C) International Business Machines Corp., 2002,2008
|
||||
* Author(s): Steve French (sfrench@us.ibm.com)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
@@ -621,6 +621,47 @@ static const struct inode_operations cifs_ipc_inode_ops = {
|
||||
.lookup = cifs_lookup,
|
||||
};
|
||||
|
||||
static char *build_path_to_root(struct cifs_sb_info *cifs_sb)
|
||||
{
|
||||
int pplen = cifs_sb->prepathlen;
|
||||
int dfsplen;
|
||||
char *full_path = NULL;
|
||||
|
||||
/* if no prefix path, simply set path to the root of share to "" */
|
||||
if (pplen == 0) {
|
||||
full_path = kmalloc(1, GFP_KERNEL);
|
||||
if (full_path)
|
||||
full_path[0] = 0;
|
||||
return full_path;
|
||||
}
|
||||
|
||||
if (cifs_sb->tcon && (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS))
|
||||
dfsplen = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE + 1);
|
||||
else
|
||||
dfsplen = 0;
|
||||
|
||||
full_path = kmalloc(dfsplen + pplen + 1, GFP_KERNEL);
|
||||
if (full_path == NULL)
|
||||
return full_path;
|
||||
|
||||
if (dfsplen) {
|
||||
strncpy(full_path, cifs_sb->tcon->treeName, dfsplen);
|
||||
/* switch slash direction in prepath depending on whether
|
||||
* windows or posix style path names
|
||||
*/
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
|
||||
int i;
|
||||
for (i = 0; i < dfsplen; i++) {
|
||||
if (full_path[i] == '\\')
|
||||
full_path[i] = '/';
|
||||
}
|
||||
}
|
||||
}
|
||||
strncpy(full_path + dfsplen, cifs_sb->prepath, pplen);
|
||||
full_path[dfsplen + pplen] = 0; /* add trailing null */
|
||||
return full_path;
|
||||
}
|
||||
|
||||
/* gets root inode */
|
||||
struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
|
||||
{
|
||||
@@ -628,6 +669,7 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
struct inode *inode;
|
||||
long rc;
|
||||
char *full_path;
|
||||
|
||||
inode = iget_locked(sb, ino);
|
||||
if (!inode)
|
||||
@@ -636,13 +678,17 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
|
||||
return inode;
|
||||
|
||||
cifs_sb = CIFS_SB(inode->i_sb);
|
||||
xid = GetXid();
|
||||
full_path = build_path_to_root(cifs_sb);
|
||||
if (full_path == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
xid = GetXid();
|
||||
if (cifs_sb->tcon->unix_ext)
|
||||
rc = cifs_get_inode_info_unix(&inode, "", inode->i_sb, xid);
|
||||
rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb,
|
||||
xid);
|
||||
else
|
||||
rc = cifs_get_inode_info(&inode, "", NULL, inode->i_sb, xid,
|
||||
NULL);
|
||||
rc = cifs_get_inode_info(&inode, full_path, NULL, inode->i_sb,
|
||||
xid, NULL);
|
||||
if (rc && cifs_sb->tcon->ipc) {
|
||||
cFYI(1, ("ipc connection - fake read inode"));
|
||||
inode->i_mode |= S_IFDIR;
|
||||
@@ -652,6 +698,7 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
|
||||
inode->i_uid = cifs_sb->mnt_uid;
|
||||
inode->i_gid = cifs_sb->mnt_gid;
|
||||
} else if (rc) {
|
||||
kfree(full_path);
|
||||
_FreeXid(xid);
|
||||
iget_failed(inode);
|
||||
return ERR_PTR(rc);
|
||||
@@ -659,6 +706,7 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
|
||||
|
||||
unlock_new_inode(inode);
|
||||
|
||||
kfree(full_path);
|
||||
/* can not call macro FreeXid here since in a void func
|
||||
* TODO: This is no longer true
|
||||
*/
|
||||
|
||||
+8
-1
@@ -97,7 +97,10 @@ sesInfoFree(struct cifsSesInfo *buf_to_free)
|
||||
kfree(buf_to_free->serverOS);
|
||||
kfree(buf_to_free->serverDomain);
|
||||
kfree(buf_to_free->serverNOS);
|
||||
kfree(buf_to_free->password);
|
||||
if (buf_to_free->password) {
|
||||
memset(buf_to_free->password, 0, strlen(buf_to_free->password));
|
||||
kfree(buf_to_free->password);
|
||||
}
|
||||
kfree(buf_to_free->domainName);
|
||||
kfree(buf_to_free);
|
||||
}
|
||||
@@ -129,6 +132,10 @@ tconInfoFree(struct cifsTconInfo *buf_to_free)
|
||||
}
|
||||
atomic_dec(&tconInfoAllocCount);
|
||||
kfree(buf_to_free->nativeFileSystem);
|
||||
if (buf_to_free->password) {
|
||||
memset(buf_to_free->password, 0, strlen(buf_to_free->password));
|
||||
kfree(buf_to_free->password);
|
||||
}
|
||||
kfree(buf_to_free);
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -417,7 +417,10 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
|
||||
/* BB calculate hash with password */
|
||||
/* and copy into bcc */
|
||||
|
||||
calc_lanman_hash(ses, lnm_session_key);
|
||||
calc_lanman_hash(ses->password, ses->server->cryptKey,
|
||||
ses->server->secMode & SECMODE_PW_ENCRYPT ?
|
||||
true : false, lnm_session_key);
|
||||
|
||||
ses->flags |= CIFS_SES_LANMAN;
|
||||
memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_SESS_KEY_SIZE);
|
||||
bcc_ptr += CIFS_SESS_KEY_SIZE;
|
||||
|
||||
+3
-2
@@ -318,7 +318,8 @@ str_to_key(unsigned char *str, unsigned char *key)
|
||||
}
|
||||
|
||||
static void
|
||||
smbhash(unsigned char *out, unsigned char *in, unsigned char *key, int forw)
|
||||
smbhash(unsigned char *out, const unsigned char *in, unsigned char *key,
|
||||
int forw)
|
||||
{
|
||||
int i;
|
||||
char *outb; /* outb[64] */
|
||||
@@ -363,7 +364,7 @@ E_P16(unsigned char *p14, unsigned char *p16)
|
||||
}
|
||||
|
||||
void
|
||||
E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24)
|
||||
E_P24(unsigned char *p21, const unsigned char *c8, unsigned char *p24)
|
||||
{
|
||||
smbhash(p24, c8, p21, 1);
|
||||
smbhash(p24 + 8, c8, p21 + 7, 1);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user