Commit 5cf11daf authored by Linus Torvalds's avatar Linus Torvalds

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: (21 commits)
  [CIFS] Remove debug statement
  Fix possible access to undefined memory region.
  [CIFS] Enable DFS support for Windows query path info
  [CIFS] Enable DFS support for Unix query path info
  [CIFS] add missing seq_printf to cifs_show_options for hard mount option
  [CIFS] add more complete mount options to cifs_show_options
  [CIFS] Add missing defines for DFS
  CIFSGetDFSRefer cleanup + dfs_referral_level_3 fixed to conform REFERRAL_V3 the MS-DFSC spec.
  Fixed DFS code to work with new 'build_path_from_dentry', that returns full path if share in the dfs, now.
  [CIFS] enable parsing for transport encryption mount parm
  [CIFS] Finishup DFS code
  [CIFS] BKL-removal: convert CIFS over to unlocked_ioctl
  [CIFS] suppress duplicate warning
  [CIFS] Fix paths when share is in DFS to include proper prefix
  add function to convert access flags to legacy open mode
  clarify return value of cifs_convert_flags()
  [CIFS] don't explicitly do a FindClose on rewind when directory search has ended
  [CIFS] cleanup old checkpatch warnings
  [CIFS] CIFSSMBPosixLock should return -EINVAL on error
  fix memory leak in CIFSFindNext
  ...
parents d40ace0c 397d71dd
...@@ -36,6 +36,7 @@ Miklos Szeredi ...@@ -36,6 +36,7 @@ Miklos Szeredi
Kazeon team for various fixes especially for 2.4 version. Kazeon team for various fixes especially for 2.4 version.
Asser Ferno (Change Notify support) Asser Ferno (Change Notify support)
Shaggy (Dave Kleikamp) for inumerable small fs suggestions and some good cleanup Shaggy (Dave Kleikamp) for inumerable small fs suggestions and some good cleanup
Igor Mammedov (DFS support)
Test case and Bug Report contributors Test case and Bug Report contributors
------------------------------------- -------------------------------------
......
Version 1.53 Version 1.53
------------ ------------
DFS support added (Microsoft Distributed File System client support needed
for referrals which enable a hierarchical name space among servers).
Version 1.52 Version 1.52
------------ ------------
...@@ -12,7 +14,8 @@ Add ability to modify cifs acls for handling chmod (when mounted with ...@@ -12,7 +14,8 @@ Add ability to modify cifs acls for handling chmod (when mounted with
cifsacl flag). Fix prefixpath path separator so we can handle mounts cifsacl flag). Fix prefixpath path separator so we can handle mounts
with prefixpaths longer than one directory (one path component) when with prefixpaths longer than one directory (one path component) when
mounted to Windows servers. Fix slow file open when cifsacl mounted to Windows servers. Fix slow file open when cifsacl
enabled. enabled. Fix memory leak in FindNext when the SMB call returns -EBADF.
Version 1.51 Version 1.51
------------ ------------
......
...@@ -483,6 +483,11 @@ A partial list of the supported mount options follows: ...@@ -483,6 +483,11 @@ A partial list of the supported mount options follows:
sign Must use packet signing (helps avoid unwanted data modification sign Must use packet signing (helps avoid unwanted data modification
by intermediate systems in the route). Note that signing by intermediate systems in the route). Note that signing
does not work with lanman or plaintext authentication. does not work with lanman or plaintext authentication.
seal Must seal (encrypt) all data on this mounted share before
sending on the network. Requires support for Unix Extensions.
Note that this differs from the sign mount option in that it
causes encryption of data sent over this mounted share but other
shares mounted to the same server are unaffected.
sec Security mode. Allowed values are: sec Security mode. Allowed values are:
none attempt to connection as a null user (no name) none attempt to connection as a null user (no name)
krb5 Use Kerberos version 5 authentication krb5 Use Kerberos version 5 authentication
......
Version 1.52 January 3, 2008 Version 1.53 May 20, 2008
A Partial List of Missing Features A Partial List of Missing Features
================================== ==================================
...@@ -20,20 +20,21 @@ d) Cleanup now unneeded SessSetup code in ...@@ -20,20 +20,21 @@ d) Cleanup now unneeded SessSetup code in
fs/cifs/connect.c and add back in NTLMSSP code if any servers fs/cifs/connect.c and add back in NTLMSSP code if any servers
need it need it
e) ms-dfs and ms-dfs host name resolution cleanup e) fix NTLMv2 signing when two mounts with different users to same
f) fix NTLMv2 signing when two mounts with different users to same
server. server.
g) Directory entry caching relies on a 1 second timer, rather than f) Directory entry caching relies on a 1 second timer, rather than
using FindNotify or equivalent. - (started) using FindNotify or equivalent. - (started)
h) quota support (needs minor kernel change since quota calls g) quota support (needs minor kernel change since quota calls
to make it to network filesystems or deviceless filesystems) to make it to network filesystems or deviceless filesystems)
i) investigate sync behavior (including syncpage) and check h) investigate sync behavior (including syncpage) and check
for proper behavior of intr/nointr for proper behavior of intr/nointr
i) improve support for very old servers (OS/2 and Win9x for example)
Including support for changing the time remotely (utimes command).
j) hook lower into the sockets api (as NFS/SunRPC does) to avoid the j) hook lower into the sockets api (as NFS/SunRPC does) to avoid the
extra copy in/out of the socket buffers in some cases. extra copy in/out of the socket buffers in some cases.
......
...@@ -219,53 +219,6 @@ static struct vfsmount *cifs_dfs_do_refmount(const struct vfsmount *mnt_parent, ...@@ -219,53 +219,6 @@ static struct vfsmount *cifs_dfs_do_refmount(const struct vfsmount *mnt_parent,
} }
static char *build_full_dfs_path_from_dentry(struct dentry *dentry)
{
char *full_path = NULL;
char *search_path;
char *tmp_path;
size_t l_max_len;
struct cifs_sb_info *cifs_sb;
if (dentry->d_inode == NULL)
return NULL;
cifs_sb = CIFS_SB(dentry->d_inode->i_sb);
if (cifs_sb->tcon == NULL)
return NULL;
search_path = build_path_from_dentry(dentry);
if (search_path == NULL)
return NULL;
if (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS) {
int i;
/* we should use full path name for correct working with DFS */
l_max_len = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE+1) +
strnlen(search_path, MAX_PATHCONF) + 1;
tmp_path = kmalloc(l_max_len, GFP_KERNEL);
if (tmp_path == NULL) {
kfree(search_path);
return NULL;
}
strncpy(tmp_path, cifs_sb->tcon->treeName, l_max_len);
tmp_path[l_max_len-1] = 0;
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
for (i = 0; i < l_max_len; i++) {
if (tmp_path[i] == '\\')
tmp_path[i] = '/';
}
strncat(tmp_path, search_path, l_max_len - strlen(tmp_path));
full_path = tmp_path;
kfree(search_path);
} else {
full_path = search_path;
}
return full_path;
}
static int add_mount_helper(struct vfsmount *newmnt, struct nameidata *nd, static int add_mount_helper(struct vfsmount *newmnt, struct nameidata *nd,
struct list_head *mntlist) struct list_head *mntlist)
{ {
...@@ -333,7 +286,7 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) ...@@ -333,7 +286,7 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
goto out_err; goto out_err;
} }
full_path = build_full_dfs_path_from_dentry(dentry); full_path = build_path_from_dentry(dentry);
if (full_path == NULL) { if (full_path == NULL) {
rc = -ENOMEM; rc = -ENOMEM;
goto out_err; goto out_err;
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#define CIFS_MOUNT_CIFS_ACL 0x200 /* send ACL requests to non-POSIX srv */ #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_UID 0x400 /* override uid returned from server */
#define CIFS_MOUNT_OVERR_GID 0x800 /* override gid 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 */
struct cifs_sb_info { struct cifs_sb_info {
struct cifsTconInfo *tcon; /* primary mount */ struct cifsTconInfo *tcon; /* primary mount */
......
/* /*
* fs/cifs/cifsfs.c * fs/cifs/cifsfs.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) * Author(s): Steve French (sfrench@us.ibm.com)
* *
* Common Internet FileSystem (CIFS) client * Common Internet FileSystem (CIFS) client
...@@ -353,9 +353,41 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m) ...@@ -353,9 +353,41 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m)
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) || if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) ||
!(cifs_sb->tcon->unix_ext)) !(cifs_sb->tcon->unix_ext))
seq_printf(s, ",gid=%d", cifs_sb->mnt_gid); seq_printf(s, ",gid=%d", cifs_sb->mnt_gid);
if (!cifs_sb->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)
seq_printf(s, ",seal");
if (cifs_sb->tcon->nocase)
seq_printf(s, ",nocase");
if (cifs_sb->tcon->retry)
seq_printf(s, ",hard");
} }
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
seq_printf(s, ",posixpaths"); seq_printf(s, ",posixpaths");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)
seq_printf(s, ",setuids");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
seq_printf(s, ",serverino");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
seq_printf(s, ",directio");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
seq_printf(s, ",nouser_xattr");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR)
seq_printf(s, ",mapchars");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
seq_printf(s, ",sfu");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
seq_printf(s, ",nobrl");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
seq_printf(s, ",cifsacl");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
seq_printf(s, ",dynperm");
if (m->mnt_sb->s_flags & MS_POSIXACL)
seq_printf(s, ",acl");
seq_printf(s, ",rsize=%d", cifs_sb->rsize); seq_printf(s, ",rsize=%d", cifs_sb->rsize);
seq_printf(s, ",wsize=%d", cifs_sb->wsize); seq_printf(s, ",wsize=%d", cifs_sb->wsize);
} }
...@@ -657,7 +689,7 @@ const struct file_operations cifs_file_ops = { ...@@ -657,7 +689,7 @@ const struct file_operations cifs_file_ops = {
.splice_read = generic_file_splice_read, .splice_read = generic_file_splice_read,
.llseek = cifs_llseek, .llseek = cifs_llseek,
#ifdef CONFIG_CIFS_POSIX #ifdef CONFIG_CIFS_POSIX
.ioctl = cifs_ioctl, .unlocked_ioctl = cifs_ioctl,
#endif /* CONFIG_CIFS_POSIX */ #endif /* CONFIG_CIFS_POSIX */
#ifdef CONFIG_CIFS_EXPERIMENTAL #ifdef CONFIG_CIFS_EXPERIMENTAL
...@@ -677,7 +709,7 @@ const struct file_operations cifs_file_direct_ops = { ...@@ -677,7 +709,7 @@ const struct file_operations cifs_file_direct_ops = {
.flush = cifs_flush, .flush = cifs_flush,
.splice_read = generic_file_splice_read, .splice_read = generic_file_splice_read,
#ifdef CONFIG_CIFS_POSIX #ifdef CONFIG_CIFS_POSIX
.ioctl = cifs_ioctl, .unlocked_ioctl = cifs_ioctl,
#endif /* CONFIG_CIFS_POSIX */ #endif /* CONFIG_CIFS_POSIX */
.llseek = cifs_llseek, .llseek = cifs_llseek,
#ifdef CONFIG_CIFS_EXPERIMENTAL #ifdef CONFIG_CIFS_EXPERIMENTAL
...@@ -697,7 +729,7 @@ const struct file_operations cifs_file_nobrl_ops = { ...@@ -697,7 +729,7 @@ const struct file_operations cifs_file_nobrl_ops = {
.splice_read = generic_file_splice_read, .splice_read = generic_file_splice_read,
.llseek = cifs_llseek, .llseek = cifs_llseek,
#ifdef CONFIG_CIFS_POSIX #ifdef CONFIG_CIFS_POSIX
.ioctl = cifs_ioctl, .unlocked_ioctl = cifs_ioctl,
#endif /* CONFIG_CIFS_POSIX */ #endif /* CONFIG_CIFS_POSIX */
#ifdef CONFIG_CIFS_EXPERIMENTAL #ifdef CONFIG_CIFS_EXPERIMENTAL
...@@ -716,7 +748,7 @@ const struct file_operations cifs_file_direct_nobrl_ops = { ...@@ -716,7 +748,7 @@ const struct file_operations cifs_file_direct_nobrl_ops = {
.flush = cifs_flush, .flush = cifs_flush,
.splice_read = generic_file_splice_read, .splice_read = generic_file_splice_read,
#ifdef CONFIG_CIFS_POSIX #ifdef CONFIG_CIFS_POSIX
.ioctl = cifs_ioctl, .unlocked_ioctl = cifs_ioctl,
#endif /* CONFIG_CIFS_POSIX */ #endif /* CONFIG_CIFS_POSIX */
.llseek = cifs_llseek, .llseek = cifs_llseek,
#ifdef CONFIG_CIFS_EXPERIMENTAL #ifdef CONFIG_CIFS_EXPERIMENTAL
...@@ -731,7 +763,7 @@ const struct file_operations cifs_dir_ops = { ...@@ -731,7 +763,7 @@ const struct file_operations cifs_dir_ops = {
#ifdef CONFIG_CIFS_EXPERIMENTAL #ifdef CONFIG_CIFS_EXPERIMENTAL
.dir_notify = cifs_dir_notify, .dir_notify = cifs_dir_notify,
#endif /* CONFIG_CIFS_EXPERIMENTAL */ #endif /* CONFIG_CIFS_EXPERIMENTAL */
.ioctl = cifs_ioctl, .unlocked_ioctl = cifs_ioctl,
}; };
static void static void
......
...@@ -95,8 +95,7 @@ extern int cifs_setxattr(struct dentry *, const char *, const void *, ...@@ -95,8 +95,7 @@ extern int cifs_setxattr(struct dentry *, const char *, const void *,
size_t, int); size_t, int);
extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t);
extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
extern int cifs_ioctl(struct inode *inode, struct file *filep, extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
unsigned int command, unsigned long arg);
#ifdef CONFIG_CIFS_EXPERIMENTAL #ifdef CONFIG_CIFS_EXPERIMENTAL
extern const struct export_operations cifs_export_ops; extern const struct export_operations cifs_export_ops;
......
...@@ -281,6 +281,7 @@ struct cifsTconInfo { ...@@ -281,6 +281,7 @@ struct cifsTconInfo {
bool ipc:1; /* set if connection to IPC$ eg for RPC/PIPES */ bool ipc:1; /* set if connection to IPC$ eg for RPC/PIPES */
bool retry:1; bool retry:1;
bool nocase:1; bool nocase:1;
bool seal:1; /* transport encryption for this mounted share */
bool unix_ext:1; /* if false disable Linux extensions to CIFS protocol bool unix_ext:1; /* if false disable Linux extensions to CIFS protocol
for this mount even if server would support */ for this mount even if server would support */
/* BB add field for back pointer to sb struct(s)? */ /* BB add field for back pointer to sb struct(s)? */
......
...@@ -1904,19 +1904,26 @@ typedef struct smb_com_transaction2_get_dfs_refer_req { ...@@ -1904,19 +1904,26 @@ typedef struct smb_com_transaction2_get_dfs_refer_req {
char RequestFileName[1]; char RequestFileName[1];
} __attribute__((packed)) TRANSACTION2_GET_DFS_REFER_REQ; } __attribute__((packed)) TRANSACTION2_GET_DFS_REFER_REQ;
#define DFS_VERSION cpu_to_le16(0x0003)
/* 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
typedef struct dfs_referral_level_3 { typedef struct dfs_referral_level_3 {
__le16 VersionNumber; __le16 VersionNumber;
__le16 ReferralSize; __le16 Size;
__le16 ServerType; /* 0x0001 = CIFS server */ __le16 ServerType; /* 0x0001 = root targets; 0x0000 = link targets */
__le16 ReferralFlags; /* or proximity - not clear which since it is __le16 ReferralEntryFlags; /* 0x0200 bit set only for domain
always set to zero - SNIA spec says 0x01 or DC referral responce */
means strip off PathConsumed chars before __le32 TimeToLive;
submitting RequestFileName to remote node */
__le16 TimeToLive;
__le16 Proximity;
__le16 DfsPathOffset; __le16 DfsPathOffset;
__le16 DfsAlternatePathOffset; __le16 DfsAlternatePathOffset;
__le16 NetworkAddressOffset; __le16 NetworkAddressOffset; /* offset of the link target */
__le16 ServiceSiteGuid;
} __attribute__((packed)) REFERRAL3; } __attribute__((packed)) REFERRAL3;
typedef struct smb_com_transaction_get_dfs_refer_rsp { typedef struct smb_com_transaction_get_dfs_refer_rsp {
......
...@@ -93,7 +93,7 @@ extern struct timespec cnvrtDosUnixTm(__u16 date, __u16 time); ...@@ -93,7 +93,7 @@ extern struct timespec cnvrtDosUnixTm(__u16 date, __u16 time);
extern int cifs_get_inode_info(struct inode **pinode, extern int cifs_get_inode_info(struct inode **pinode,
const unsigned char *search_path, const unsigned char *search_path,
FILE_ALL_INFO * pfile_info, FILE_ALL_INFO *pfile_info,
struct super_block *sb, int xid, const __u16 *pfid); struct super_block *sb, int xid, const __u16 *pfid);
extern int cifs_get_inode_info_unix(struct inode **pinode, extern int cifs_get_inode_info_unix(struct inode **pinode,
const unsigned char *search_path, const unsigned char *search_path,
...@@ -130,7 +130,7 @@ extern int CIFSFindClose(const int, struct cifsTconInfo *tcon, ...@@ -130,7 +130,7 @@ extern int CIFSFindClose(const int, struct cifsTconInfo *tcon,
extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName, const unsigned char *searchName,
FILE_ALL_INFO * findData, FILE_ALL_INFO *findData,
int legacy /* whether to use old info level */, int legacy /* whether to use old info level */,
const struct nls_table *nls_codepage, int remap); const struct nls_table *nls_codepage, int remap);
extern int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon, extern int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
...@@ -141,18 +141,15 @@ extern int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon, ...@@ -141,18 +141,15 @@ extern int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
extern int CIFSSMBUnixQPathInfo(const int xid, extern int CIFSSMBUnixQPathInfo(const int xid,
struct cifsTconInfo *tcon, struct cifsTconInfo *tcon,
const unsigned char *searchName, const unsigned char *searchName,
FILE_UNIX_BASIC_INFO * pFindData, FILE_UNIX_BASIC_INFO *pFindData,
const struct nls_table *nls_codepage, int remap); const struct nls_table *nls_codepage, int remap);
extern int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, extern int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
const unsigned char *searchName, const unsigned char *searchName,
unsigned char **targetUNCs, struct dfs_info3_param **target_nodes,
unsigned int *number_of_UNC_in_array, unsigned int *number_of_nodes_in_array,
const struct nls_table *nls_codepage, int remap); const struct nls_table *nls_codepage, int remap);
extern int connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
const char *old_path,
const struct nls_table *nls_codepage, int remap);
extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
const char *old_path, const char *old_path,
const struct nls_table *nls_codepage, const struct nls_table *nls_codepage,
......
...@@ -81,6 +81,40 @@ static struct { ...@@ -81,6 +81,40 @@ static struct {
#endif /* CONFIG_CIFS_WEAK_PW_HASH */ #endif /* CONFIG_CIFS_WEAK_PW_HASH */
#endif /* CIFS_POSIX */ #endif /* CIFS_POSIX */
/* Allocates buffer into dst and copies smb string from src to it.
* caller is responsible for freeing dst if function returned 0.
* returns:
* on success - 0
* on failure - errno
*/
static int
cifs_strncpy_to_host(char **dst, const char *src, const int maxlen,
const bool is_unicode, const struct nls_table *nls_codepage)
{
int plen;
if (is_unicode) {
plen = UniStrnlen((wchar_t *)src, maxlen);
*dst = kmalloc(plen + 2, GFP_KERNEL);
if (!*dst)
goto cifs_strncpy_to_host_ErrExit;
cifs_strfromUCS_le(*dst, (__le16 *)src, plen, nls_codepage);
} else {
plen = strnlen(src, maxlen);
*dst = kmalloc(plen + 2, GFP_KERNEL);
if (!*dst)
goto cifs_strncpy_to_host_ErrExit;
strncpy(*dst, src, plen);
}
(*dst)[plen] = 0;
(*dst)[plen+1] = 0; /* harmless for ASCII case, needed for Unicode */
return 0;
cifs_strncpy_to_host_ErrExit:
cERROR(1, ("Failed to allocate buffer for string\n"));
return -ENOMEM;
}
/* Mark as invalid, all open files on tree connections since they /* Mark as invalid, all open files on tree connections since they
were closed when session to server was lost */ were closed when session to server was lost */
...@@ -1166,6 +1200,20 @@ static __u16 convert_disposition(int disposition) ...@@ -1166,6 +1200,20 @@ static __u16 convert_disposition(int disposition)
return ofun; return ofun;
} }
static int
access_flags_to_smbopen_mode(const int access_flags)
{
int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
if (masked_flags == GENERIC_READ)
return SMBOPEN_READ;
else if (masked_flags == GENERIC_WRITE)
return SMBOPEN_WRITE;
/* just go for read/write */
return SMBOPEN_READWRITE;
}
int int
SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon, SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
const char *fileName, const int openDisposition, const char *fileName, const int openDisposition,
...@@ -1207,13 +1255,7 @@ SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon, ...@@ -1207,13 +1255,7 @@ SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK); pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO); pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
/* BB fixme add conversion for access_flags to bits 0 - 2 of mode */ pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
/* 0 = read
1 = write
2 = rw
3 = execute
*/
pSMB->Mode = cpu_to_le16(2);
pSMB->Mode |= cpu_to_le16(0x40); /* deny none */ pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
/* set file as system file if special file such /* set file as system file if special file such
as fifo and server expecting SFU style and as fifo and server expecting SFU style and
...@@ -1247,7 +1289,7 @@ SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon, ...@@ -1247,7 +1289,7 @@ SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
} else { } else {
/* BB verify if wct == 15 */ /* BB verify if wct == 15 */
/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */ /* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
*netfid = pSMBr->Fid; /* cifs fid stays in le */ *netfid = pSMBr->Fid; /* cifs fid stays in le */
/* Let caller know file was created so we can set the mode. */ /* Let caller know file was created so we can set the mode. */
...@@ -1767,7 +1809,7 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, ...@@ -1767,7 +1809,7 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
cFYI(1, ("Posix Lock")); cFYI(1, ("Posix Lock"));
if (pLockData == NULL) if (pLockData == NULL)
return EINVAL; return -EINVAL;
rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB); rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
...@@ -1944,7 +1986,7 @@ CIFSSMBRename(const int xid, struct cifsTconInfo *tcon, ...@@ -1944,7 +1986,7 @@ CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
/* protocol requires ASCII signature byte on Unicode string */ /* protocol requires ASCII signature byte on Unicode string */
pSMB->OldFileName[name_len + 1] = 0x00; pSMB->OldFileName[name_len + 1] = 0x00;
name_len2 = name_len2 =
cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2], cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
toName, PATH_MAX, nls_codepage, remap); toName, PATH_MAX, nls_codepage, remap);
name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
name_len2 *= 2; /* convert to bytes */ name_len2 *= 2; /* convert to bytes */
...@@ -2925,7 +2967,8 @@ CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon, ...@@ -2925,7 +2967,8 @@ CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
} }
params = 6 + name_len; params = 6 + name_len;
pSMB->MaxParameterCount = cpu_to_le16(2); pSMB->MaxParameterCount = cpu_to_le16(2);
pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */ /* BB find max SMB size from sess */
pSMB->MaxDataCount = cpu_to_le16(1000);
pSMB->MaxSetupCount = 0; pSMB->MaxSetupCount = 0;
pSMB->Reserved = 0; pSMB->Reserved = 0;
pSMB->Flags = 0; pSMB->Flags = 0;
...@@ -3322,7 +3365,8 @@ CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, ...@@ -3322,7 +3365,8 @@ CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */; params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
pSMB->TotalDataCount = 0; pSMB->TotalDataCount = 0;
pSMB->MaxParameterCount = cpu_to_le16(2); pSMB->MaxParameterCount = cpu_to_le16(2);
pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */ /* BB find exact max SMB PDU from sess structure BB */
pSMB->MaxDataCount = cpu_to_le16(4000);
pSMB->MaxSetupCount = 0; pSMB->MaxSetupCount = 0;
pSMB->Reserved = 0; pSMB->Reserved = 0;
pSMB->Flags = 0; pSMB->Flags = 0;
...@@ -3388,7 +3432,7 @@ CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, ...@@ -3388,7 +3432,7 @@ CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
int int
CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon, CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName, const unsigned char *searchName,
FILE_UNIX_BASIC_INFO * pFindData, FILE_UNIX_BASIC_INFO *pFindData,
const struct nls_table *nls_codepage, int remap) const struct nls_table *nls_codepage, int remap)
{ {
/* SMB_QUERY_FILE_UNIX_BASIC */ /* SMB_QUERY_FILE_UNIX_BASIC */
...@@ -3679,6 +3723,7 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, ...@@ -3679,6 +3723,7 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
if (rc) { if (rc) {
if (rc == -EBADF) { if (rc == -EBADF) {
psrch_inf->endOfSearch = true; psrch_inf->endOfSearch = true;
cifs_buf_release(pSMB);
rc = 0; /* search probably was closed at end of search*/ rc = 0; /* search probably was closed at end of search*/
} else } else
cFYI(1, ("FindNext returned = %d", rc)); cFYI(1, ("FindNext returned = %d", rc));
...@@ -3856,25 +3901,112 @@ CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, ...@@ -3856,25 +3901,112 @@ CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
return rc; return rc;
} }
/* parses DFS refferal V3 structure
* caller is responsible for freeing target_nodes
* returns:
* on success - 0
* on failure - errno
*/
static int
parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
unsigned int *num_of_nodes,
struct dfs_info3_param **target_nodes,
const struct nls_table *nls_codepage)
{
int i, rc = 0;
char *data_end;
bool is_unicode;
struct dfs_referral_level_3 *ref;
is_unicode = pSMBr->hdr.Flags2 & SMBFLG2_UNICODE;
*num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
if (*num_of_nodes < 1) {
cERROR(1, ("num_referrals: must be at least > 0,"
"but we get num_referrals = %d\n", *num_of_nodes));
rc = -EINVAL;
goto parse_DFS_referrals_exit;
}
ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
if (ref->VersionNumber != 3) {
cERROR(1, ("Referrals of V%d version are not supported,"
"should be V3", ref->VersionNumber));
rc = -EINVAL;
goto parse_DFS_referrals_exit;
}
/* get the upper boundary of the resp buffer */
data_end = (char *)(&(pSMBr->PathConsumed)) +
le16_to_cpu(pSMBr->t2.DataCount);
cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n",
*num_of_nodes,
le16_to_cpu(pSMBr->DFSFlags)));
*target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
*num_of_nodes, GFP_KERNEL);
if (*target_nodes == NULL) {
cERROR(1, ("Failed to allocate buffer for target_nodes\n"));
rc = -ENOMEM;
goto parse_DFS_referrals_exit;
}
/* collect neccessary data from referrals */
for (i = 0; i < *num_of_nodes; i++) {
char *temp;
int max_len;
struct dfs_info3_param *node = (*target_nodes)+i;
node->flags = le16_to_cpu(pSMBr->DFSFlags);
node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
node->server_type = le16_to_cpu(ref->ServerType);
node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
/* copy DfsPath */
temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
max_len = data_end - temp;
rc = cifs_strncpy_to_host(&(node->path_name), temp,
max_len, is_unicode, nls_codepage);
if (rc)
goto parse_DFS_referrals_exit;
/* copy link target UNC */
temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
max_len = data_end - temp;
rc = cifs_strncpy_to_host(&(node->node_name), temp,
max_len, is_unicode, nls_codepage);
if (rc)
goto parse_DFS_referrals_exit;
ref += ref->Size;
}
parse_DFS_referrals_exit:
if (rc) {
free_dfs_info_array(*target_nodes, *num_of_nodes);
*target_nodes = NULL;
*num_of_nodes = 0;
}
return rc;
}
int int
CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
const unsigned char *searchName, const unsigned char *searchName,
unsigned char **targetUNCs, struct dfs_info3_param **target_nodes,
unsigned int *number_of_UNC_in_array, unsigned int *num_of_nodes,
const struct nls_table *nls_codepage, int remap) const struct nls_table *nls_codepage, int remap)
{ {
/* TRANS2_GET_DFS_REFERRAL */ /* TRANS2_GET_DFS_REFERRAL */
TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL; TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL; TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
struct dfs_referral_level_3 *referrals = NULL;
int rc = 0; int rc = 0;
int bytes_returned; int bytes_returned;
int name_len; int name_len;
unsigned int i;
char *temp;
__u16 params, byte_count; __u16 params, byte_count;
*number_of_UNC_in_array = 0; *num_of_nodes = 0;
*targetUNCs = NULL; *target_nodes = NULL;
cFYI(1, ("In GetDFSRefer the path %s", searchName)); cFYI(1, ("In GetDFSRefer the path %s", searchName));
if (ses == NULL) if (ses == NULL)
...@@ -3921,7 +4053,8 @@ CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, ...@@ -3921,7 +4053,8 @@ CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
pSMB->DataCount = 0; pSMB->DataCount = 0;
pSMB->DataOffset = 0; pSMB->DataOffset = 0;
pSMB->MaxParameterCount = 0; pSMB->MaxParameterCount = 0;
pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */ /* BB find exact max SMB PDU from sess structure BB */
pSMB->MaxDataCount = cpu_to_le16(4000);
pSMB->MaxSetupCount = 0; pSMB->MaxSetupCount = 0;
pSMB->Reserved = 0; pSMB->Reserved = 0;
pSMB->Flags = 0; pSMB->Flags = 0;
...@@ -3943,100 +4076,24 @@ CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, ...@@ -3943,100 +4076,24 @@ CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
(struct smb_hdr *) pSMBr, &bytes_returned, 0); (struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc) { if (rc) {
cFYI(1, ("Send error in GetDFSRefer = %d", rc)); cFYI(1, ("Send error in GetDFSRefer = %d", rc));
} else { /* decode response */ goto GetDFSRefExit;
/* BB Add logic to parse referrals here */ }
rc = validate_t2((struct smb_t2_rsp *)pSMBr); rc = validate_t2((struct smb_t2_rsp *)pSMBr);
/* BB Also check if enough total bytes returned? */ /* BB Also check if enough total bytes returned? */
if (rc || (pSMBr->ByteCount < 17)) if (rc || (pSMBr->ByteCount < 17)) {
rc = -EIO; /* bad smb */ rc = -EIO; /* bad smb */
else { goto GetDFSRefExit;
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); }
__u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
cFYI(1, cFYI(1, ("Decoding GetDFSRefer response BCC: %d Offset %d",
("Decoding GetDFSRefer response BCC: %d Offset %d", pSMBr->ByteCount,
pSMBr->ByteCount, data_offset)); le16_to_cpu(pSMBr->t2.DataOffset)));
referrals =
(struct dfs_referral_level_3 *)
(8 /* sizeof start of data block */ +
data_offset +
(char *) &pSMBr->hdr.Protocol);
cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n"
"for referral one refer size: 0x%x srv "
"type: 0x%x refer flags: 0x%x ttl: 0x%x",
le16_to_cpu(pSMBr->NumberOfReferrals),
le16_to_cpu(pSMBr->DFSFlags),
le16_to_cpu(referrals->ReferralSize),
le16_to_cpu(referrals->ServerType),
le16_to_cpu(referrals->ReferralFlags),
le16_to_cpu(referrals->TimeToLive)));
/* BB This field is actually two bytes in from start of
data block so we could do safety check that DataBlock
begins at address of pSMBr->NumberOfReferrals */
*number_of_UNC_in_array =
le16_to_cpu(pSMBr->NumberOfReferrals);
/* BB Fix below so can return more than one referral */
if (*number_of_UNC_in_array > 1)
*number_of_UNC_in_array = 1;
/* get the length of the strings describing refs */
name_len = 0;
for (i = 0; i < *number_of_UNC_in_array; i++) {
/* make sure that DfsPathOffset not past end */
__u16 offset =
le16_to_cpu(referrals->DfsPathOffset);
if (offset > data_count) {
/* if invalid referral, stop here and do
not try to copy any more */
*number_of_UNC_in_array = i;
break;
}
temp = ((char *)referrals) + offset;
if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { /* parse returned result into more usable form */
name_len += UniStrnlen((wchar_t *)temp, rc = parse_DFS_referrals(pSMBr, num_of_nodes,
data_count); target_nodes, nls_codepage);
} else {
name_len += strnlen(temp, data_count);
}
referrals++;
/* BB add check that referral pointer does
not fall off end PDU */
}
/* BB add check for name_len bigger than bcc */
*targetUNCs =
kmalloc(name_len+1+(*number_of_UNC_in_array),
GFP_KERNEL);
if (*targetUNCs == NULL) {
rc = -ENOMEM;
goto GetDFSRefExit;
}
/* copy the ref strings */
referrals = (struct dfs_referral_level_3 *)
(8 /* sizeof data hdr */ + data_offset +
(char *) &pSMBr->hdr.Protocol);
for (i = 0; i < *number_of_UNC_in_array; i++) {
temp = ((char *)referrals) +
le16_to_cpu(referrals->DfsPathOffset);
if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
cifs_strfromUCS_le(*targetUNCs,
(__le16 *) temp,
name_len,
nls_codepage);
} else {
strncpy(*targetUNCs, temp, name_len);
}
/* BB update target_uncs pointers */
referrals++;
}
temp = *targetUNCs;
temp[name_len] = 0;
}
}
GetDFSRefExit: GetDFSRefExit:
if (pSMB) if (pSMB)
cifs_buf_release(pSMB); cifs_buf_release(pSMB);
...@@ -4229,7 +4286,8 @@ CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon) ...@@ -4229,7 +4286,8 @@ CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
params = 2; /* level */ params = 2; /* level */
pSMB->TotalDataCount = 0; pSMB->TotalDataCount = 0;
pSMB->MaxParameterCount = cpu_to_le16(2); pSMB->MaxParameterCount = cpu_to_le16(2);
pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ /* BB find exact max SMB PDU from sess structure BB */
pSMB->MaxDataCount = cpu_to_le16(1000);
pSMB->MaxSetupCount = 0; pSMB->MaxSetupCount = 0;
pSMB->Reserved = 0; pSMB->Reserved = 0;
pSMB->Flags = 0; pSMB->Flags = 0;
...@@ -4298,7 +4356,8 @@ CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon) ...@@ -4298,7 +4356,8 @@ CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
params = 2; /* level */ params = 2; /* level */
pSMB->TotalDataCount = 0; pSMB->TotalDataCount = 0;
pSMB->MaxParameterCount = cpu_to_le16(2); pSMB->MaxParameterCount = cpu_to_le16(2);
pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ /* BB find exact max SMB PDU from sess structure BB */
pSMB->MaxDataCount = cpu_to_le16(1000);
pSMB->MaxSetupCount = 0; pSMB->MaxSetupCount = 0;
pSMB->Reserved = 0; pSMB->Reserved = 0;
pSMB->Flags = 0; pSMB->Flags = 0;
...@@ -4369,7 +4428,8 @@ CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon) ...@@ -4369,7 +4428,8 @@ CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
pSMB->DataCount = 0; pSMB->DataCount = 0;
pSMB->DataOffset = 0; pSMB->DataOffset = 0;
pSMB->MaxParameterCount = cpu_to_le16(2); pSMB->MaxParameterCount = cpu_to_le16(2);
pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */ /* BB find exact max SMB PDU from sess structure BB */
pSMB->MaxDataCount = cpu_to_le16(100);
pSMB->MaxSetupCount = 0; pSMB->MaxSetupCount = 0;
pSMB->Reserved = 0; pSMB->Reserved = 0;
pSMB->Flags = 0; pSMB->Flags = 0;
...@@ -4444,7 +4504,8 @@ CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap) ...@@ -4444,7 +4504,8 @@ CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
offset = param_offset + params; offset = param_offset + params;
pSMB->MaxParameterCount = cpu_to_le16(4); pSMB->MaxParameterCount = cpu_to_le16(4);
pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */ /* BB find exact max SMB PDU from sess structure BB */
pSMB->MaxDataCount = cpu_to_le16(100);
pSMB->SetupCount = 1; pSMB->SetupCount = 1;
pSMB->Reserved3 = 0; pSMB->Reserved3 = 0;
pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION); pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
...@@ -4512,7 +4573,8 @@ CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon, ...@@ -4512,7 +4573,8 @@ CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
pSMB->DataCount = 0; pSMB->DataCount = 0;
pSMB->DataOffset = 0; pSMB->DataOffset = 0;
pSMB->MaxParameterCount = cpu_to_le16(2); pSMB->MaxParameterCount = cpu_to_le16(2);
pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */ /* BB find exact max SMB PDU from sess structure BB */
pSMB->MaxDataCount = cpu_to_le16(100);
pSMB->MaxSetupCount = 0; pSMB->MaxSetupCount = 0;
pSMB->Reserved = 0; pSMB->Reserved = 0;
pSMB->Flags = 0; pSMB->Flags = 0;
...@@ -4702,7 +4764,8 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, ...@@ -4702,7 +4764,8 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
count = sizeof(struct file_end_of_file_info); count = sizeof(struct file_end_of_file_info);
pSMB->MaxParameterCount = cpu_to_le16(2); pSMB->MaxParameterCount = cpu_to_le16(2);
pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */ /* BB find exact max SMB PDU from sess structure BB */
pSMB->MaxDataCount = cpu_to_le16(1000);
pSMB->SetupCount = 1; pSMB->SetupCount = 1;
pSMB->Reserved3 = 0; pSMB->Reserved3 = 0;
pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
...@@ -4789,7 +4852,8 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, ...@@ -4789,7 +4852,8 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
count = sizeof(FILE_BASIC_INFO); count = sizeof(FILE_BASIC_INFO);
pSMB->MaxParameterCount = cpu_to_le16(2); pSMB->MaxParameterCount = cpu_to_le16(2);
pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */ /* BB find max SMB PDU from sess */
pSMB->MaxDataCount = cpu_to_le16(1000);
pSMB->SetupCount = 1; pSMB->SetupCount = 1;
pSMB->Reserved3 = 0; pSMB->Reserved3 = 0;
pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
...@@ -4856,7 +4920,8 @@ CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName, ...@@ -4856,7 +4920,8 @@ CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
params = 6 + name_len; params = 6 + name_len;
count = sizeof(FILE_BASIC_INFO); count = sizeof(FILE_BASIC_INFO);
pSMB->MaxParameterCount = cpu_to_le16(2); pSMB->MaxParameterCount = cpu_to_le16(2);
pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ /* BB find max SMB PDU from sess structure BB */
pSMB->MaxDataCount = cpu_to_le16(1000);
pSMB->MaxSetupCount = 0; pSMB->MaxSetupCount = 0;
pSMB->Reserved = 0; pSMB->Reserved = 0;
pSMB->Flags = 0; pSMB->Flags = 0;
...@@ -4986,7 +5051,8 @@ CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon, ...@@ -4986,7 +5051,8 @@ CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
params = 6 + name_len; params = 6 + name_len;
count = sizeof(FILE_UNIX_BASIC_INFO); count = sizeof(FILE_UNIX_BASIC_INFO);
pSMB->MaxParameterCount = cpu_to_le16(2); pSMB->MaxParameterCount = cpu_to_le16(2);
pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ /* BB find max SMB PDU from sess structure BB */
pSMB->MaxDataCount = cpu_to_le16(1000);
pSMB->MaxSetupCount = 0; pSMB->MaxSetupCount = 0;
pSMB->Reserved = 0; pSMB->Reserved = 0;
pSMB->Flags = 0; pSMB->Flags = 0;
...@@ -5169,7 +5235,8 @@ CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, ...@@ -5169,7 +5235,8 @@ CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */; params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
pSMB->TotalDataCount = 0; pSMB->TotalDataCount = 0;
pSMB->MaxParameterCount = cpu_to_le16(2); pSMB->MaxParameterCount = cpu_to_le16(2);
pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */ /* BB find exact max SMB PDU from sess structure BB */
pSMB->MaxDataCount = cpu_to_le16(4000);
pSMB->MaxSetupCount = 0; pSMB->MaxSetupCount = 0;
pSMB->Reserved = 0; pSMB->Reserved = 0;
pSMB->Flags = 0; pSMB->Flags = 0;
...@@ -5317,7 +5384,8 @@ ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon, ...@@ -5317,7 +5384,8 @@ ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */; params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
pSMB->TotalDataCount = 0; pSMB->TotalDataCount = 0;
pSMB->MaxParameterCount = cpu_to_le16(2); pSMB->MaxParameterCount = cpu_to_le16(2);
pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */ /* BB find exact max SMB PDU from sess structure BB */
pSMB->MaxDataCount = cpu_to_le16(4000);
pSMB->MaxSetupCount = 0; pSMB->MaxSetupCount = 0;
pSMB->Reserved = 0; pSMB->Reserved = 0;
pSMB->Flags = 0; pSMB->Flags = 0;
...@@ -5475,7 +5543,8 @@ CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName, ...@@ -5475,7 +5543,8 @@ CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
count = sizeof(*parm_data) + ea_value_len + name_len; count = sizeof(*parm_data) + ea_value_len + name_len;
pSMB->MaxParameterCount = cpu_to_le16(2); pSMB->MaxParameterCount = cpu_to_le16(2);
pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */ /* BB find max SMB PDU from sess */
pSMB->MaxDataCount = cpu_to_le16(1000);
pSMB->MaxSetupCount = 0; pSMB->MaxSetupCount = 0;
pSMB->Reserved = 0; pSMB->Reserved = 0;
pSMB->Flags = 0; pSMB->Flags = 0;
......
...@@ -60,7 +60,7 @@ struct smb_vol { ...@@ -60,7 +60,7 @@ struct smb_vol {
char *domainname; char *domainname;
char *UNC; char *UNC;
char *UNCip; char *UNCip;
char *in6_addr; /* ipv6 address as human readable form of in6_addr */ char *in6_addr; /* ipv6 address as human readable form of in6_addr */
char *iocharset; /* local code page for mapping to and from Unicode */ char *iocharset; /* local code page for mapping to and from Unicode */
char source_rfc1001_name[16]; /* netbios name of client */ char source_rfc1001_name[16]; /* netbios name of client */
char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */ char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */
...@@ -75,19 +75,21 @@ struct smb_vol { ...@@ -75,19 +75,21 @@ struct smb_vol {
bool setuids:1; bool setuids:1;
bool override_uid:1; bool override_uid:1;
bool override_gid:1; bool override_gid:1;
bool dynperm:1;
bool noperm:1; bool noperm:1;
bool no_psx_acl:1; /* set if posix acl support should be disabled */ bool no_psx_acl:1; /* set if posix acl support should be disabled */
bool cifs_acl:1; bool cifs_acl:1;
bool no_xattr:1; /* set if xattr (EA) support should be disabled*/ bool no_xattr:1; /* set if xattr (EA) support should be disabled*/
bool server_ino:1; /* use inode numbers from server ie UniqueId */ bool server_ino:1; /* use inode numbers from server ie UniqueId */
bool direct_io:1; bool direct_io:1;
bool remap:1; /* set to remap seven reserved chars in filenames */ bool remap:1; /* set to remap seven reserved chars in filenames */
bool posix_paths:1; /* unset to not ask for posix pathnames. */ bool posix_paths:1; /* unset to not ask for posix pathnames. */
bool no_linux_ext:1; bool no_linux_ext:1;
bool sfu_emul:1; bool sfu_emul:1;
bool nullauth:1; /* attempt to authenticate with null user */ bool nullauth:1; /* attempt to authenticate with null user */
unsigned nocase; /* request case insensitive filenames */ bool nocase:1; /* request case insensitive filenames */
unsigned nobrl; /* disable sending byte range locks to srv */ bool nobrl:1; /* disable sending byte range locks to srv */
bool seal:1; /* request transport encryption on share */
unsigned int rsize; unsigned int rsize;
unsigned int wsize; unsigned int wsize;
unsigned int sockopt; unsigned int sockopt;
...@@ -1246,6 +1248,10 @@ cifs_parse_mount_options(char *options, const char *devname, ...@@ -1246,6 +1248,10 @@ cifs_parse_mount_options(char *options, const char *devname,
vol->setuids = 1; vol->setuids = 1;
} else if (strnicmp(data, "nosetuids", 9) == 0) { } else if (strnicmp(data, "nosetuids", 9) == 0) {
vol->setuids = 0; vol->setuids = 0;
} else if (strnicmp(data, "dynperm", 7) == 0) {
vol->dynperm = true;
} else if (strnicmp(data, "nodynperm", 9) == 0) {
vol->dynperm = false;
} else if (strnicmp(data, "nohard", 6) == 0) { } else if (strnicmp(data, "nohard", 6) == 0) {
vol->retry = 0; vol->retry = 0;
} else if (strnicmp(data, "nosoft", 6) == 0) { } else if (strnicmp(data, "nosoft", 6) == 0) {
...@@ -1268,8 +1274,12 @@ cifs_parse_mount_options(char *options, const char *devname, ...@@ -1268,8 +1274,12 @@ cifs_parse_mount_options(char *options, const char *devname,
vol->no_psx_acl = 1; vol->no_psx_acl = 1;
} else if (strnicmp(data, "sign", 4) == 0) { } else if (strnicmp(data, "sign", 4) == 0) {
vol->secFlg |= CIFSSEC_MUST_SIGN; vol->secFlg |= CIFSSEC_MUST_SIGN;
/* } else if (strnicmp(data, "seal",4) == 0) { } else if (strnicmp(data, "seal", 4) == 0) {
vol->secFlg |= CIFSSEC_MUST_SEAL; */ /* we do not do the following in secFlags because seal
is a per tree connection (mount) not a per socket
or per-smb connection option in the protocol */
/* vol->secFlg |= CIFSSEC_MUST_SEAL; */
vol->seal = 1;
} else if (strnicmp(data, "direct", 6) == 0) { } else if (strnicmp(data, "direct", 6) == 0) {
vol->direct_io = 1; vol->direct_io = 1;
} else if (strnicmp(data, "forcedirectio", 13) == 0) { } else if (strnicmp(data, "forcedirectio", 13) == 0) {
...@@ -1413,27 +1423,6 @@ find_unc(__be32 new_target_ip_addr, char *uncName, char *userName) ...@@ -1413,27 +1423,6 @@ find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
return NULL; return NULL;
} }
int
connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
const char *old_path, const struct nls_table *nls_codepage,
int remap)
{
struct dfs_info3_param *referrals = NULL;
unsigned int num_referrals;
int rc = 0;
rc = get_dfs_path(xid, pSesInfo, old_path, nls_codepage,
&num_referrals, &referrals, remap);
/* BB Add in code to: if valid refrl, if not ip address contact
the helper that resolves tcp names, mount to it, try to
tcon to it unmount it if fail */
kfree(referrals);
return rc;
}
int int
get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
const struct nls_table *nls_codepage, unsigned int *pnum_referrals, const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
...@@ -1441,7 +1430,6 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, ...@@ -1441,7 +1430,6 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
{ {
char *temp_unc; char *temp_unc;
int rc = 0; int rc = 0;
unsigned char *targetUNCs;
*pnum_referrals = 0; *pnum_referrals = 0;
*preferrals = NULL; *preferrals = NULL;
...@@ -1464,7 +1452,7 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, ...@@ -1464,7 +1452,7 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
kfree(temp_unc); kfree(temp_unc);
} }
if (rc == 0) if (rc == 0)
rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, &targetUNCs, rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
pnum_referrals, nls_codepage, remap); pnum_referrals, nls_codepage, remap);
/* BB map targetUNCs to dfs_info3 structures, here or /* BB map targetUNCs to dfs_info3 structures, here or
in CIFSGetDFSRefer BB */ in CIFSGetDFSRefer BB */
...@@ -1815,7 +1803,7 @@ convert_delimiter(char *path, char delim) ...@@ -1815,7 +1803,7 @@ convert_delimiter(char *path, char delim)
if (path == NULL) if (path == NULL)
return; return;
if (delim == '/') if (delim == '/')
old_delim = '\\'; old_delim = '\\';
else else
old_delim = '/'; old_delim = '/';
...@@ -2125,6 +2113,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -2125,6 +2113,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID; cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
if (volume_info.override_gid) if (volume_info.override_gid)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID; cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
if (volume_info.dynperm)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
if (volume_info.direct_io) { if (volume_info.direct_io) {
cFYI(1, ("mounting share using direct i/o")); cFYI(1, ("mounting share using direct i/o"));
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
...@@ -2141,6 +2131,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -2141,6 +2131,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
for the retry flag is used */ for the retry flag is used */
tcon->retry = volume_info.retry; tcon->retry = volume_info.retry;
tcon->nocase = volume_info.nocase; tcon->nocase = volume_info.nocase;
if (tcon->seal != volume_info.seal)
cERROR(1, ("transport encryption setting "
"conflicts with existing tid"));
} else { } else {
tcon = tconInfoAlloc(); tcon = tconInfoAlloc();
if (tcon == NULL) if (tcon == NULL)
...@@ -2154,10 +2147,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -2154,10 +2147,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
if ((strchr(volume_info.UNC + 3, '\\') == NULL) if ((strchr(volume_info.UNC + 3, '\\') == NULL)
&& (strchr(volume_info.UNC + 3, '/') == && (strchr(volume_info.UNC + 3, '/') ==
NULL)) { NULL)) {
rc = connect_to_dfs_path(xid, pSesInfo, /* rc = connect_to_dfs_path(xid, pSesInfo,
"", cifs_sb->local_nls, "", cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);*/
cFYI(1, ("DFS root not supported"));
rc = -ENODEV; rc = -ENODEV;
goto out; goto out;
} else { } else {
...@@ -2173,6 +2167,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -2173,6 +2167,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
atomic_inc(&pSesInfo->inUse); atomic_inc(&pSesInfo->inUse);
tcon->retry = volume_info.retry; tcon->retry = volume_info.retry;
tcon->nocase = volume_info.nocase; tcon->nocase = volume_info.nocase;
tcon->seal = volume_info.seal;
} }
} }
} }
...@@ -2314,9 +2309,10 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, ...@@ -2314,9 +2309,10 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
user = ses->userName; user = ses->userName;
domain = ses->domainName; domain = ses->domainName;
smb_buffer = cifs_buf_get(); smb_buffer = cifs_buf_get();
if (smb_buffer == NULL) {
if (smb_buffer == NULL)
return -ENOMEM; return -ENOMEM;
}
smb_buffer_response = smb_buffer; smb_buffer_response = smb_buffer;
pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer; pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
......
...@@ -49,18 +49,25 @@ build_path_from_dentry(struct dentry *direntry) ...@@ -49,18 +49,25 @@ build_path_from_dentry(struct dentry *direntry)
struct dentry *temp; struct dentry *temp;
int namelen; int namelen;
int pplen; int pplen;
int dfsplen;
char *full_path; char *full_path;
char dirsep; char dirsep;
struct cifs_sb_info *cifs_sb;
if (direntry == NULL) if (direntry == NULL)
return NULL; /* not much we can do if dentry is freed and return NULL; /* not much we can do if dentry is freed and
we need to reopen the file after it was closed implicitly we need to reopen the file after it was closed implicitly
when the server crashed */ when the server crashed */
dirsep = CIFS_DIR_SEP(CIFS_SB(direntry->d_sb)); cifs_sb = CIFS_SB(direntry->d_sb);
pplen = CIFS_SB(direntry->d_sb)->prepathlen; dirsep = CIFS_DIR_SEP(cifs_sb);
pplen = cifs_sb->prepathlen;
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;
cifs_bp_rename_retry: cifs_bp_rename_retry:
namelen = pplen; namelen = pplen + dfsplen;
for (temp = direntry; !IS_ROOT(temp);) { for (temp = direntry; !IS_ROOT(temp);) {
namelen += (1 + temp->d_name.len); namelen += (1 + temp->d_name.len);
temp = temp->d_parent; temp = temp->d_parent;
...@@ -91,7 +98,7 @@ build_path_from_dentry(struct dentry *direntry) ...@@ -91,7 +98,7 @@ build_path_from_dentry(struct dentry *direntry)
return NULL; return NULL;
} }
} }
if (namelen != pplen) { if (namelen != pplen + dfsplen) {
cERROR(1, cERROR(1,
("did not end path lookup where expected namelen is %d", ("did not end path lookup where expected namelen is %d",
namelen)); namelen));
...@@ -107,7 +114,18 @@ build_path_from_dentry(struct dentry *direntry) ...@@ -107,7 +114,18 @@ build_path_from_dentry(struct dentry *direntry)
since the '\' is a valid posix character so we can not switch since the '\' is a valid posix character so we can not switch
those safely to '/' if any are found in the middle of the prepath */ those safely to '/' if any are found in the middle of the prepath */
/* BB test paths to Windows with '/' in the midst of prepath */ /* BB test paths to Windows with '/' in the midst of prepath */
strncpy(full_path, CIFS_SB(direntry->d_sb)->prepath, pplen);
if (dfsplen) {
strncpy(full_path, cifs_sb->tcon->treeName, dfsplen);
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(direntry->d_sb)->prepath, pplen);
return full_path; return full_path;
} }
...@@ -590,7 +608,7 @@ static int cifs_ci_compare(struct dentry *dentry, struct qstr *a, ...@@ -590,7 +608,7 @@ static int cifs_ci_compare(struct dentry *dentry, struct qstr *a,
* case take precedence. If a is not a negative dentry, this * case take precedence. If a is not a negative dentry, this
* should have no side effects * should have no side effects
*/ */
memcpy(a->name, b->name, a->len); memcpy((void *)a->name, b->name, a->len);
return 0; return 0;
} }
return 1; return 1;
......
...@@ -134,10 +134,6 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr) ...@@ -134,10 +134,6 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
rkey = request_key(&key_type_dns_resolver, name, ""); rkey = request_key(&key_type_dns_resolver, name, "");
if (!IS_ERR(rkey)) { if (!IS_ERR(rkey)) {
data = rkey->payload.data; data = rkey->payload.data;
cFYI(1, ("%s: resolved: %s to %s", __func__,
rkey->description,
*ip_addr
));
} else { } else {
cERROR(1, ("%s: unable to resolve: %s", __func__, name)); cERROR(1, ("%s: unable to resolve: %s", __func__, name));
goto out; goto out;
...@@ -150,6 +146,11 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr) ...@@ -150,6 +146,11 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
if (*ip_addr) { if (*ip_addr) {
memcpy(*ip_addr, data, len); memcpy(*ip_addr, data, len);
(*ip_addr)[len] = '\0'; (*ip_addr)[len] = '\0';
if (!IS_ERR(rkey))
cFYI(1, ("%s: resolved: %s to %s", __func__,
name,
*ip_addr
));
rc = 0; rc = 0;
} else { } else {
rc = -ENOMEM; rc = -ENOMEM;
......
...@@ -75,7 +75,11 @@ static inline int cifs_convert_flags(unsigned int flags) ...@@ -75,7 +75,11 @@ static inline int cifs_convert_flags(unsigned int flags)
return (GENERIC_READ | GENERIC_WRITE); return (GENERIC_READ | GENERIC_WRITE);
} }
return 0x20197; return (READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES |
FILE_WRITE_EA | FILE_APPEND_DATA | FILE_WRITE_DATA |
FILE_READ_DATA);
} }
static inline int cifs_get_disposition(unsigned int flags) static inline int cifs_get_disposition(unsigned int flags)
......
...@@ -161,118 +161,115 @@ static void cifs_unix_info_to_inode(struct inode *inode, ...@@ -161,118 +161,115 @@ static void cifs_unix_info_to_inode(struct inode *inode,
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
} }
static const unsigned char *cifs_get_search_path(struct cifs_sb_info *cifs_sb,
const char *search_path)
{
int tree_len;
int path_len;
int i;
char *tmp_path;
struct cifsTconInfo *pTcon = cifs_sb->tcon;
if (!(pTcon->Flags & SMB_SHARE_IS_IN_DFS))
return search_path;
/* use full path name for working with DFS */ /*
tree_len = strnlen(pTcon->treeName, MAX_TREE_SIZE + 1); * Needed to setup inode data for the directory which is the
path_len = strnlen(search_path, MAX_PATHCONF); * junction to the new submount (ie to setup the fake directory
* which represents a DFS referral)
tmp_path = kmalloc(tree_len+path_len+1, GFP_KERNEL); */
if (tmp_path == NULL) static void fill_fake_finddataunix(FILE_UNIX_BASIC_INFO *pfnd_dat,
return search_path; struct super_block *sb)
{
struct inode *pinode = NULL;
memset(pfnd_dat, sizeof(FILE_UNIX_BASIC_INFO), 0);
/* __le64 pfnd_dat->EndOfFile = cpu_to_le64(0);
__le64 pfnd_dat->NumOfBytes = cpu_to_le64(0);
__u64 UniqueId = 0; */
pfnd_dat->LastStatusChange =
cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
pfnd_dat->LastAccessTime =
cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
pfnd_dat->LastModificationTime =
cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
pfnd_dat->Type = cpu_to_le32(UNIX_DIR);
pfnd_dat->Permissions = cpu_to_le64(S_IXUGO | S_IRWXU);
pfnd_dat->Nlinks = cpu_to_le64(2);
if (sb->s_root)
pinode = sb->s_root->d_inode;
if (pinode == NULL)
return;
strncpy(tmp_path, pTcon->treeName, tree_len); /* fill in default values for the remaining based on root
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) inode since we can not query the server for this inode info */
for (i = 0; i < tree_len; i++) { pfnd_dat->DevMajor = cpu_to_le64(MAJOR(pinode->i_rdev));
if (tmp_path[i] == '\\') pfnd_dat->DevMinor = cpu_to_le64(MINOR(pinode->i_rdev));
tmp_path[i] = '/'; pfnd_dat->Uid = cpu_to_le64(pinode->i_uid);
} pfnd_dat->Gid = cpu_to_le64(pinode->i_gid);
strncpy(tmp_path+tree_len, search_path, path_len);
tmp_path[tree_len+path_len] = 0;
return tmp_path;
} }
int cifs_get_inode_info_unix(struct inode **pinode, int cifs_get_inode_info_unix(struct inode **pinode,
const unsigned char *search_path, struct super_block *sb, int xid) const unsigned char *full_path, struct super_block *sb, int xid)
{ {
int rc = 0; int rc = 0;
FILE_UNIX_BASIC_INFO findData; FILE_UNIX_BASIC_INFO find_data;
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
struct inode *inode; struct inode *inode;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb); struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
const unsigned char *full_path;
bool is_dfs_referral = false; bool is_dfs_referral = false;
struct cifsInodeInfo *cifsInfo;
__u64 num_of_bytes;
__u64 end_of_file;
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
cFYI(1, ("Getting info on %s", search_path)); cFYI(1, ("Getting info on %s", full_path));
full_path = cifs_get_search_path(cifs_sb, search_path);
try_again_CIFSSMBUnixQPathInfo:
/* could have done a find first instead but this returns more info */ /* could have done a find first instead but this returns more info */
rc = CIFSSMBUnixQPathInfo(xid, pTcon, full_path, &findData, rc = CIFSSMBUnixQPathInfo(xid, pTcon, full_path, &find_data,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
/* dump_mem("\nUnixQPathInfo return data", &findData,
sizeof(findData)); */
if (rc) { if (rc) {
if (rc == -EREMOTE && !is_dfs_referral) { if (rc == -EREMOTE && !is_dfs_referral) {
is_dfs_referral = true; is_dfs_referral = true;
if (full_path != search_path) { cFYI(DBG2, ("DFS ref"));
kfree(full_path); /* for DFS, server does not give us real inode data */
full_path = search_path; fill_fake_finddataunix(&find_data, sb);
} rc = 0;
goto try_again_CIFSSMBUnixQPathInfo;
} }
goto cgiiu_exit; }
} else { num_of_bytes = le64_to_cpu(find_data.NumOfBytes);
struct cifsInodeInfo *cifsInfo; end_of_file = le64_to_cpu(find_data.EndOfFile);
__u64 num_of_bytes = le64_to_cpu(findData.NumOfBytes);
__u64 end_of_file = le64_to_cpu(findData.EndOfFile);
/* get new inode */ /* get new inode */
if (*pinode == NULL) {
*pinode = new_inode(sb);
if (*pinode == NULL) { if (*pinode == NULL) {
*pinode = new_inode(sb); rc = -ENOMEM;
if (*pinode == NULL) { goto cgiiu_exit;
rc = -ENOMEM;
goto cgiiu_exit;
}
/* Is an i_ino of zero legal? */
/* Are there sanity checks we can use to ensure that
the server is really filling in that field? */
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
(*pinode)->i_ino =
(unsigned long)findData.UniqueId;
} /* note ino incremented to unique num in new_inode */
if (sb->s_flags & MS_NOATIME)
(*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
insert_inode_hash(*pinode);
} }
/* Is an i_ino of zero legal? */
/* note ino incremented to unique num in new_inode */
/* Are there sanity checks we can use to ensure that
the server is really filling in that field? */
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
(*pinode)->i_ino = (unsigned long)find_data.UniqueId;
inode = *pinode; if (sb->s_flags & MS_NOATIME)
cifsInfo = CIFS_I(inode); (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
cFYI(1, ("Old time %ld", cifsInfo->time)); insert_inode_hash(*pinode);
cifsInfo->time = jiffies; }
cFYI(1, ("New time %ld", cifsInfo->time));
/* this is ok to set on every inode revalidate */
atomic_set(&cifsInfo->inUse, 1);
cifs_unix_info_to_inode(inode, &findData, 0); inode = *pinode;
cifsInfo = CIFS_I(inode);
cFYI(1, ("Old time %ld", cifsInfo->time));
cifsInfo->time = jiffies;
cFYI(1, ("New time %ld", cifsInfo->time));
/* this is ok to set on every inode revalidate */
atomic_set(&cifsInfo->inUse, 1);
if (num_of_bytes < end_of_file) cifs_unix_info_to_inode(inode, &find_data, 0);
cFYI(1, ("allocation size less than end of file"));
cFYI(1, ("Size %ld and blocks %llu",
(unsigned long) inode->i_size,
(unsigned long long)inode->i_blocks));
cifs_set_ops(inode, is_dfs_referral); if (num_of_bytes < end_of_file)
} cFYI(1, ("allocation size less than end of file"));
cFYI(1, ("Size %ld and blocks %llu",
(unsigned long) inode->i_size,
(unsigned long long)inode->i_blocks));
cifs_set_ops(inode, is_dfs_referral);
cgiiu_exit: cgiiu_exit:
if (full_path != search_path)
kfree(full_path);
return rc; return rc;
} }
...@@ -379,21 +376,51 @@ static int get_sfu_mode(struct inode *inode, ...@@ -379,21 +376,51 @@ static int get_sfu_mode(struct inode *inode,
#endif #endif
} }
/*
* Needed to setup inode data for the directory which is the
* junction to the new submount (ie to setup the fake directory
* which represents a DFS referral)
*/
static void fill_fake_finddata(FILE_ALL_INFO *pfnd_dat,
struct super_block *sb)
{
memset(pfnd_dat, sizeof(FILE_ALL_INFO), 0);
/* __le64 pfnd_dat->AllocationSize = cpu_to_le64(0);
__le64 pfnd_dat->EndOfFile = cpu_to_le64(0);
__u8 pfnd_dat->DeletePending = 0;
__u8 pfnd_data->Directory = 0;
__le32 pfnd_dat->EASize = 0;
__u64 pfnd_dat->IndexNumber = 0;
__u64 pfnd_dat->IndexNumber1 = 0; */
pfnd_dat->CreationTime =
cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
pfnd_dat->LastAccessTime =
cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
pfnd_dat->LastWriteTime =
cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
pfnd_dat->ChangeTime =
cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
pfnd_dat->Attributes = cpu_to_le32(ATTR_DIRECTORY);
pfnd_dat->NumberOfLinks = cpu_to_le32(2);
}
int cifs_get_inode_info(struct inode **pinode, int cifs_get_inode_info(struct inode **pinode,
const unsigned char *search_path, FILE_ALL_INFO *pfindData, const unsigned char *full_path, FILE_ALL_INFO *pfindData,
struct super_block *sb, int xid, const __u16 *pfid) struct super_block *sb, int xid, const __u16 *pfid)
{ {
int rc = 0; int rc = 0;
__u32 attr;
struct cifsInodeInfo *cifsInfo;
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
struct inode *inode; struct inode *inode;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb); struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
const unsigned char *full_path = NULL;
char *buf = NULL; char *buf = NULL;
bool adjustTZ = false; bool adjustTZ = false;
bool is_dfs_referral = false; bool is_dfs_referral = false;
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
cFYI(1, ("Getting info on %s", search_path)); cFYI(1, ("Getting info on %s", full_path));
if ((pfindData == NULL) && (*pinode != NULL)) { if ((pfindData == NULL) && (*pinode != NULL)) {
if (CIFS_I(*pinode)->clientCanCacheRead) { if (CIFS_I(*pinode)->clientCanCacheRead) {
...@@ -409,9 +436,6 @@ int cifs_get_inode_info(struct inode **pinode, ...@@ -409,9 +436,6 @@ int cifs_get_inode_info(struct inode **pinode,
return -ENOMEM; return -ENOMEM;
pfindData = (FILE_ALL_INFO *)buf; pfindData = (FILE_ALL_INFO *)buf;
full_path = cifs_get_search_path(cifs_sb, search_path);
try_again_CIFSSMBQPathInfo:
/* could do find first instead but this returns more info */ /* could do find first instead but this returns more info */
rc = CIFSSMBQPathInfo(xid, pTcon, full_path, pfindData, rc = CIFSSMBQPathInfo(xid, pTcon, full_path, pfindData,
0 /* not legacy */, 0 /* not legacy */,
...@@ -429,178 +453,168 @@ int cifs_get_inode_info(struct inode **pinode, ...@@ -429,178 +453,168 @@ int cifs_get_inode_info(struct inode **pinode,
} }
} }
/* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */ /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
if (rc) { if (rc == -EREMOTE) {
if (rc == -EREMOTE && !is_dfs_referral) { is_dfs_referral = true;
is_dfs_referral = true; fill_fake_finddata(pfindData, sb);
if (full_path != search_path) { rc = 0;
kfree(full_path); } else if (rc)
full_path = search_path;
}
goto try_again_CIFSSMBQPathInfo;
}
goto cgii_exit; goto cgii_exit;
} else {
struct cifsInodeInfo *cifsInfo;
__u32 attr = le32_to_cpu(pfindData->Attributes);
/* get new inode */ attr = le32_to_cpu(pfindData->Attributes);
if (*pinode == NULL) {
*pinode = new_inode(sb);
if (*pinode == NULL) {
rc = -ENOMEM;
goto cgii_exit;
}
/* Is an i_ino of zero legal? Can we use that to check
if the server supports returning inode numbers? Are
there other sanity checks we can use to ensure that
the server is really filling in that field? */
/* We can not use the IndexNumber field by default from /* get new inode */
Windows or Samba (in ALL_INFO buf) but we can request if (*pinode == NULL) {
it explicitly. It may not be unique presumably if *pinode = new_inode(sb);
the server has multiple devices mounted under one if (*pinode == NULL) {
share */ rc = -ENOMEM;
goto cgii_exit;
/* There may be higher info levels that work but are }
there Windows server or network appliances for which /* Is an i_ino of zero legal? Can we use that to check
IndexNumber field is not guaranteed unique? */ if the server supports returning inode numbers? Are
there other sanity checks we can use to ensure that
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { the server is really filling in that field? */
int rc1 = 0;
__u64 inode_num; /* We can not use the IndexNumber field by default from
Windows or Samba (in ALL_INFO buf) but we can request
rc1 = CIFSGetSrvInodeNumber(xid, pTcon, it explicitly. It may not be unique presumably if
search_path, &inode_num, the server has multiple devices mounted under one share */
/* There may be higher info levels that work but are
there Windows server or network appliances for which
IndexNumber field is not guaranteed unique? */
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
int rc1 = 0;
__u64 inode_num;
rc1 = CIFSGetSrvInodeNumber(xid, pTcon,
full_path, &inode_num,
cifs_sb->local_nls, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc1) { if (rc1) {
cFYI(1, ("GetSrvInodeNum rc %d", rc1)); cFYI(1, ("GetSrvInodeNum rc %d", rc1));
/* BB EOPNOSUPP disable SERVER_INUM? */ /* BB EOPNOSUPP disable SERVER_INUM? */
} else /* do we need cast or hash to ino? */ } else /* do we need cast or hash to ino? */
(*pinode)->i_ino = inode_num; (*pinode)->i_ino = inode_num;
} /* else ino incremented to unique num in new_inode*/ } /* else ino incremented to unique num in new_inode*/
if (sb->s_flags & MS_NOATIME) if (sb->s_flags & MS_NOATIME)
(*pinode)->i_flags |= S_NOATIME | S_NOCMTIME; (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
insert_inode_hash(*pinode); insert_inode_hash(*pinode);
} }
inode = *pinode; inode = *pinode;
cifsInfo = CIFS_I(inode); cifsInfo = CIFS_I(inode);
cifsInfo->cifsAttrs = attr; cifsInfo->cifsAttrs = attr;
cFYI(1, ("Old time %ld", cifsInfo->time)); cFYI(1, ("Old time %ld", cifsInfo->time));
cifsInfo->time = jiffies; cifsInfo->time = jiffies;
cFYI(1, ("New time %ld", cifsInfo->time)); cFYI(1, ("New time %ld", cifsInfo->time));
/* blksize needs to be multiple of two. So safer to default to /* blksize needs to be multiple of two. So safer to default to
blksize and blkbits set in superblock so 2**blkbits and blksize blksize and blkbits set in superblock so 2**blkbits and blksize
will match rather than setting to: will match rather than setting to:
(pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/ (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
/* Linux can not store file creation time so ignore it */ /* Linux can not store file creation time so ignore it */
if (pfindData->LastAccessTime) if (pfindData->LastAccessTime)
inode->i_atime = cifs_NTtimeToUnix inode->i_atime = cifs_NTtimeToUnix
(le64_to_cpu(pfindData->LastAccessTime)); (le64_to_cpu(pfindData->LastAccessTime));
else /* do not need to use current_fs_time - time not stored */ else /* do not need to use current_fs_time - time not stored */
inode->i_atime = CURRENT_TIME; inode->i_atime = CURRENT_TIME;
inode->i_mtime = inode->i_mtime =
cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
inode->i_ctime = inode->i_ctime =
cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
cFYI(0, ("Attributes came in as 0x%x", attr)); cFYI(DBG2, ("Attributes came in as 0x%x", attr));
if (adjustTZ && (pTcon->ses) && (pTcon->ses->server)) { if (adjustTZ && (pTcon->ses) && (pTcon->ses->server)) {
inode->i_ctime.tv_sec += pTcon->ses->server->timeAdj; inode->i_ctime.tv_sec += pTcon->ses->server->timeAdj;
inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj; inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj;
} }
/* set default mode. will override for dirs below */ /* set default mode. will override for dirs below */
if (atomic_read(&cifsInfo->inUse) == 0) if (atomic_read(&cifsInfo->inUse) == 0)
/* new inode, can safely set these fields */ /* new inode, can safely set these fields */
inode->i_mode = cifs_sb->mnt_file_mode; inode->i_mode = cifs_sb->mnt_file_mode;
else /* since we set the inode type below we need to mask off else /* since we set the inode type below we need to mask off
to avoid strange results if type changes and both to avoid strange results if type changes and both
get orred in */ get orred in */
inode->i_mode &= ~S_IFMT; inode->i_mode &= ~S_IFMT;
/* if (attr & ATTR_REPARSE) */ /* if (attr & ATTR_REPARSE) */
/* We no longer handle these as symlinks because we could not /* We no longer handle these as symlinks because we could not
follow them due to the absolute path with drive letter */ follow them due to the absolute path with drive letter */
if (attr & ATTR_DIRECTORY) { if (attr & ATTR_DIRECTORY) {
/* override default perms since we do not do byte range locking /* override default perms since we do not do byte range locking
on dirs */ on dirs */
inode->i_mode = cifs_sb->mnt_dir_mode; inode->i_mode = cifs_sb->mnt_dir_mode;
inode->i_mode |= S_IFDIR; inode->i_mode |= S_IFDIR;
} else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
(cifsInfo->cifsAttrs & ATTR_SYSTEM) && (cifsInfo->cifsAttrs & ATTR_SYSTEM) &&
/* No need to le64 convert size of zero */ /* No need to le64 convert size of zero */
(pfindData->EndOfFile == 0)) { (pfindData->EndOfFile == 0)) {
inode->i_mode = cifs_sb->mnt_file_mode; inode->i_mode = cifs_sb->mnt_file_mode;
inode->i_mode |= S_IFIFO; inode->i_mode |= S_IFIFO;
/* BB Finish for SFU style symlinks and devices */ /* BB Finish for SFU style symlinks and devices */
} else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
(cifsInfo->cifsAttrs & ATTR_SYSTEM)) { (cifsInfo->cifsAttrs & ATTR_SYSTEM)) {
if (decode_sfu_inode(inode, if (decode_sfu_inode(inode, le64_to_cpu(pfindData->EndOfFile),
le64_to_cpu(pfindData->EndOfFile), full_path, cifs_sb, xid))
search_path, cFYI(1, ("Unrecognized sfu inode type"));
cifs_sb, xid))
cFYI(1, ("Unrecognized sfu inode type"));
cFYI(1, ("sfu mode 0%o", inode->i_mode));
} else {
inode->i_mode |= S_IFREG;
/* treat the dos attribute of read-only as read-only
mode e.g. 555 */
if (cifsInfo->cifsAttrs & ATTR_READONLY)
inode->i_mode &= ~(S_IWUGO);
else if ((inode->i_mode & S_IWUGO) == 0)
/* the ATTR_READONLY flag may have been */
/* changed on server -- set any w bits */
/* allowed by mnt_file_mode */
inode->i_mode |= (S_IWUGO &
cifs_sb->mnt_file_mode);
/* BB add code here -
validate if device or weird share or device type? */
}
spin_lock(&inode->i_lock); cFYI(1, ("sfu mode 0%o", inode->i_mode));
if (is_size_safe_to_change(cifsInfo, } else {
le64_to_cpu(pfindData->EndOfFile))) { inode->i_mode |= S_IFREG;
/* can not safely shrink the file size here if the /* treat dos attribute of read-only as read-only mode eg 555 */
client is writing to it due to potential races */ if (cifsInfo->cifsAttrs & ATTR_READONLY)
i_size_write(inode, le64_to_cpu(pfindData->EndOfFile)); inode->i_mode &= ~(S_IWUGO);
else if ((inode->i_mode & S_IWUGO) == 0)
/* 512 bytes (2**9) is the fake blocksize that must be /* the ATTR_READONLY flag may have been */
used for this calculation */ /* changed on server -- set any w bits */
inode->i_blocks = (512 - 1 + le64_to_cpu( /* allowed by mnt_file_mode */
pfindData->AllocationSize)) >> 9; inode->i_mode |= (S_IWUGO & cifs_sb->mnt_file_mode);
} /* BB add code to validate if device or weird share or device type? */
spin_unlock(&inode->i_lock); }
spin_lock(&inode->i_lock);
if (is_size_safe_to_change(cifsInfo,
le64_to_cpu(pfindData->EndOfFile))) {
/* can not safely shrink the file size here if the
client is writing to it due to potential races */
i_size_write(inode, le64_to_cpu(pfindData->EndOfFile));
/* 512 bytes (2**9) is the fake blocksize that must be
used for this calculation */
inode->i_blocks = (512 - 1 + le64_to_cpu(
pfindData->AllocationSize)) >> 9;
}
spin_unlock(&inode->i_lock);
inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks); inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks);
/* BB fill in uid and gid here? with help from winbind? /* BB fill in uid and gid here? with help from winbind?
or retrieve from NTFS stream extended attribute */ or retrieve from NTFS stream extended attribute */
#ifdef CONFIG_CIFS_EXPERIMENTAL #ifdef CONFIG_CIFS_EXPERIMENTAL
/* fill in 0777 bits from ACL */ /* fill in 0777 bits from ACL */
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
cFYI(1, ("Getting mode bits from ACL")); cFYI(1, ("Getting mode bits from ACL"));
acl_to_uid_mode(inode, search_path, pfid); acl_to_uid_mode(inode, full_path, pfid);
} }
#endif #endif
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
/* fill in remaining high mode bits e.g. SUID, VTX */ /* fill in remaining high mode bits e.g. SUID, VTX */
get_sfu_mode(inode, search_path, cifs_sb, xid); get_sfu_mode(inode, full_path, cifs_sb, xid);
} else if (atomic_read(&cifsInfo->inUse) == 0) { } else if (atomic_read(&cifsInfo->inUse) == 0) {
inode->i_uid = cifs_sb->mnt_uid; inode->i_uid = cifs_sb->mnt_uid;
inode->i_gid = cifs_sb->mnt_gid; inode->i_gid = cifs_sb->mnt_gid;
/* set so we do not keep refreshing these fields with /* set so we do not keep refreshing these fields with
bad data after user has changed them in memory */ bad data after user has changed them in memory */
atomic_set(&cifsInfo->inUse, 1); atomic_set(&cifsInfo->inUse, 1);
}
cifs_set_ops(inode, is_dfs_referral);
} }
cifs_set_ops(inode, is_dfs_referral);
cgii_exit: cgii_exit:
if (full_path != search_path)
kfree(full_path);
kfree(buf); kfree(buf);
return rc; return rc;
} }
...@@ -1502,8 +1516,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -1502,8 +1516,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
int oplock = 0; int oplock = 0;
rc = SMBLegacyOpen(xid, pTcon, full_path, rc = SMBLegacyOpen(xid, pTcon, full_path,
FILE_OPEN, FILE_OPEN, GENERIC_WRITE,
SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
CREATE_NOT_DIR, &netfid, &oplock, CREATE_NOT_DIR, &netfid, &oplock,
NULL, cifs_sb->local_nls, NULL, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
......
...@@ -30,9 +30,9 @@ ...@@ -30,9 +30,9 @@
#define CIFS_IOC_CHECKUMOUNT _IO(0xCF, 2) #define CIFS_IOC_CHECKUMOUNT _IO(0xCF, 2)
int cifs_ioctl(struct inode *inode, struct file *filep, long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
unsigned int command, unsigned long arg)
{ {
struct inode *inode = filep->f_dentry->d_inode;
int rc = -ENOTTY; /* strange error - but the precedent */ int rc = -ENOTTY; /* strange error - but the precedent */
int xid; int xid;
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
......
...@@ -234,7 +234,6 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen) ...@@ -234,7 +234,6 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
char *full_path = NULL; char *full_path = NULL;
char *tmp_path = NULL;
char *tmpbuffer; char *tmpbuffer;
int len; int len;
__u16 fid; __u16 fid;
...@@ -295,45 +294,9 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen) ...@@ -295,45 +294,9 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
cFYI(1, ("Error closing junction point " cFYI(1, ("Error closing junction point "
"(open for ioctl)")); "(open for ioctl)"));
} }
/* BB unwind this long, nested function, or remove BB */ /* If it is a DFS junction earlier we would have gotten
if (rc == -EIO) { PATH_NOT_COVERED returned from server so we do
/* Query if DFS Junction */ not need to request the DFS info here */
unsigned int num_referrals = 0;
struct dfs_info3_param *refs = NULL;
tmp_path =
kmalloc(MAX_TREE_SIZE + MAX_PATHCONF + 1,
GFP_KERNEL);
if (tmp_path) {
strncpy(tmp_path, pTcon->treeName,
MAX_TREE_SIZE);
strncat(tmp_path, full_path,
MAX_PATHCONF);
rc = get_dfs_path(xid, pTcon->ses,
tmp_path,
cifs_sb->local_nls,
&num_referrals, &refs,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
cFYI(1, ("Get DFS for %s rc = %d ",
tmp_path, rc));
if ((num_referrals == 0) && (rc == 0))
rc = -EACCES;
else {
cFYI(1, ("num referral: %d",
num_referrals));
if (refs && refs->path_name) {
strncpy(tmpbuffer,
refs->path_name,
len-1);
}
}
kfree(refs);
kfree(tmp_path);
}
/* BB add code like else decode referrals
then memcpy to tmpbuffer and free referrals
string array BB */
}
} }
} }
/* BB Anything else to do to handle recursive links? */ /* BB Anything else to do to handle recursive links? */
......
...@@ -141,11 +141,11 @@ cifs_inet_pton(const int address_family, const char *cp, void *dst) ...@@ -141,11 +141,11 @@ cifs_inet_pton(const int address_family, const char *cp, void *dst)
int ret = 0; int ret = 0;
/* calculate length by finding first slash or NULL */ /* calculate length by finding first slash or NULL */
if (address_family == AF_INET) { if (address_family == AF_INET)
ret = in4_pton(cp, -1 /* len */, dst, '\\', NULL); ret = in4_pton(cp, -1 /* len */, dst, '\\', NULL);
} else if (address_family == AF_INET6) { else if (address_family == AF_INET6)
ret = in6_pton(cp, -1 /* len */, dst , '\\', NULL); ret = in6_pton(cp, -1 /* len */, dst , '\\', NULL);
}
cFYI(DBG2, ("address conversion returned %d for %s", ret, cp)); cFYI(DBG2, ("address conversion returned %d for %s", ret, cp));
if (ret > 0) if (ret > 0)
ret = 1; ret = 1;
......
...@@ -64,7 +64,7 @@ typedef struct _SECURITY_BUFFER { ...@@ -64,7 +64,7 @@ typedef struct _SECURITY_BUFFER {
} __attribute__((packed)) SECURITY_BUFFER; } __attribute__((packed)) SECURITY_BUFFER;
typedef struct _NEGOTIATE_MESSAGE { typedef struct _NEGOTIATE_MESSAGE {
__u8 Signature[sizeof (NTLMSSP_SIGNATURE)]; __u8 Signature[sizeof(NTLMSSP_SIGNATURE)];
__le32 MessageType; /* 1 */ __le32 MessageType; /* 1 */
__le32 NegotiateFlags; __le32 NegotiateFlags;
SECURITY_BUFFER DomainName; /* RFC 1001 style and ASCII */ SECURITY_BUFFER DomainName; /* RFC 1001 style and ASCII */
...@@ -74,7 +74,7 @@ typedef struct _NEGOTIATE_MESSAGE { ...@@ -74,7 +74,7 @@ typedef struct _NEGOTIATE_MESSAGE {
} __attribute__((packed)) NEGOTIATE_MESSAGE, *PNEGOTIATE_MESSAGE; } __attribute__((packed)) NEGOTIATE_MESSAGE, *PNEGOTIATE_MESSAGE;
typedef struct _CHALLENGE_MESSAGE { typedef struct _CHALLENGE_MESSAGE {
__u8 Signature[sizeof (NTLMSSP_SIGNATURE)]; __u8 Signature[sizeof(NTLMSSP_SIGNATURE)];
__le32 MessageType; /* 2 */ __le32 MessageType; /* 2 */
SECURITY_BUFFER TargetName; SECURITY_BUFFER TargetName;
__le32 NegotiateFlags; __le32 NegotiateFlags;
......
...@@ -670,8 +670,11 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, ...@@ -670,8 +670,11 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
(index_to_find < first_entry_in_buffer)) { (index_to_find < first_entry_in_buffer)) {
/* close and restart search */ /* close and restart search */
cFYI(1, ("search backing up - close and restart search")); cFYI(1, ("search backing up - close and restart search"));
cifsFile->invalidHandle = true; if (!cifsFile->srch_inf.endOfSearch &&
CIFSFindClose(xid, pTcon, cifsFile->netfid); !cifsFile->invalidHandle) {
cifsFile->invalidHandle = true;
CIFSFindClose(xid, pTcon, cifsFile->netfid);
}
kfree(cifsFile->search_resume_name); kfree(cifsFile->search_resume_name);
cifsFile->search_resume_name = NULL; cifsFile->search_resume_name = NULL;
if (cifsFile->srch_inf.ntwrk_buf_start) { if (cifsFile->srch_inf.ntwrk_buf_start) {
......
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